Skip to content

Commit

Permalink
feat: about page
Browse files Browse the repository at this point in the history
  • Loading branch information
jpnurmi committed Jul 14, 2023
1 parent 966f7a2 commit 78eaadb
Show file tree
Hide file tree
Showing 16 changed files with 295 additions and 97 deletions.
Binary file added assets/2.0x/app-store.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/app-store.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions assets/app-store.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion lib/about.dart
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export 'src/about/about_dialog.dart';
export 'src/about/about_page.dart';
3 changes: 3 additions & 0 deletions lib/src/widgets/constants.dart → lib/constants.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import 'package:flutter/material.dart';

const kAppName = 'App Store';
const kGitHubRepo = 'ubuntu/software';

const kNaviRailWidth = 205.0;

const kGridDelegate = SliverGridDelegateWithMaxCrossAxisExtent(
Expand Down
68 changes: 0 additions & 68 deletions lib/src/about/about_dialog.dart

This file was deleted.

229 changes: 229 additions & 0 deletions lib/src/about/about_page.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
import 'package:flutter/material.dart';
import 'package:flutter_markdown/flutter_markdown.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:github/github.dart';
import 'package:shimmer/shimmer.dart';
import 'package:url_launcher/url_launcher_string.dart';
import 'package:yaru_icons/yaru_icons.dart';
import 'package:yaru_widgets/yaru_widgets.dart';

import '/constants.dart';
import '/l10n.dart';
import 'about_providers.dart';

class AboutPage extends StatelessWidget {
const AboutPage({super.key});

static IconData icon(bool selected) =>
selected ? YaruIcons.question_filled : YaruIcons.question;
static String label(BuildContext context) =>
AppLocalizations.of(context).aboutPageLabel;

@override
Widget build(BuildContext context) {
return CustomScrollView(
slivers: [
const SliverPadding(
padding: EdgeInsets.all(kYaruPagePadding),
sliver: SliverToBoxAdapter(child: _AboutHeader()),
),
SliverPadding(
padding: const EdgeInsets.all(kYaruPagePadding),
sliver: SliverToBoxAdapter(
child: Align(
alignment: AlignmentDirectional.topStart,
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 500),
child: const _ContributorView(repo: kGitHubRepo),
),
),
),
),
const SliverPadding(
padding: EdgeInsets.all(kYaruPagePadding),
sliver: SliverToBoxAdapter(child: _CommunityView()),
),
const SliverFillRemaining(
hasScrollBody: false,
child: Padding(
padding: EdgeInsets.all(kYaruPagePadding),
child: _AboutFooter(),
),
),
],
);
}
}

class _AboutHeader extends ConsumerWidget {
const _AboutHeader();

@override
Widget build(BuildContext context, WidgetRef ref) {
final l10n = AppLocalizations.of(context);
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.asset('assets/app-store.png'),
const SizedBox(width: 32),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
kAppName,
style: Theme.of(context).textTheme.headlineSmall,
),
const SizedBox(height: 8),
ref.watch(versionProvider).maybeWhen(
data: (v) => Text(l10n.aboutPageVersionLabel(v)),
orElse: () => const SizedBox.shrink(),
),
],
),
],
);
}
}

class _AboutFooter extends StatelessWidget {
const _AboutFooter();

@override
Widget build(BuildContext context) {
// TODO: terms and conditions, privacy policy
return Align(
alignment: AlignmentDirectional.bottomStart,
child: MarkdownBody(
data: '©️ ${DateTime.now().year} Canonical Ltd.',
),
);
}
}

class _ContributorView extends ConsumerWidget {
const _ContributorView({required this.repo});

final String repo;

@override
Widget build(BuildContext context, WidgetRef ref) {
final l10n = AppLocalizations.of(context);
final state = ref.watch(contributorsProvider(repo));
final light = Theme.of(context).brightness == Brightness.light;

return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(l10n.aboutPageContributorTitle),
const SizedBox(height: 8),
state.when(
data: (contributors) => _ContributorWrap(contributors),
error: (error, stackTrace) => ErrorWidget(error),
loading: () => Shimmer.fromColors(
baseColor: light ? kShimmerBaseLight : kShimmerBaseDark,
highlightColor:
light ? kShimmerHighLightLight : kShimmerHighLightDark,
child: _ContributorWrap(List<Contributor?>.filled(36, null)),
),
),
],
);
}
}

class _ContributorWrap extends StatelessWidget {
const _ContributorWrap(this.contributors);

final List<Contributor?> contributors;

@override
Widget build(BuildContext context) {
return Wrap(
spacing: 8,
runSpacing: 8,
children: [
for (final contributor in contributors)
Tooltip(
message: contributor?.login ?? '',
child: InkWell(
customBorder: const CircleBorder(),
onTap: contributor?.htmlUrl != null
? () => launchUrlString(contributor?.htmlUrl ?? '')
: null,
child: CircleAvatar(
radius: 16,
backgroundImage: contributor?.avatarUrl != null
? NetworkImage(contributor!.avatarUrl!)
: null,
),
),
),
],
);
}
}

class _CommunityView extends StatelessWidget {
const _CommunityView();

@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context);
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(l10n.aboutPageCommunityTitle),
const SizedBox(height: 8),
Row(
children: [
Expanded(
child: _CommunityTile(
title: l10n.aboutPageContributeLabel,
subtitle: l10n.aboutPageGitHubLabel,
href: 'https://github.com/$kGitHubRepo',
),
),
const SizedBox(width: 16),
Expanded(
child: _CommunityTile(
title: l10n.aboutPagePublishLabel,
subtitle: l10n.aboutPageLearnMoreLabel,
href: 'https://snapcraft.io/docs/snapcraft',
),
),
],
),
],
);
}
}

class _CommunityTile extends StatelessWidget {
const _CommunityTile({
required this.title,
required this.subtitle,
required this.href,
});

final String title;
final String subtitle;
final String href;

@override
Widget build(BuildContext context) {
return YaruTile(
// TODO: icon
leading: const Placeholder(fallbackWidth: 28, fallbackHeight: 28),
title: Text(
title,
overflow: TextOverflow.ellipsis,
),
subtitle: MarkdownBody(
data: '[$subtitle]($href)',
onTapLink: (_, href, __) => launchUrlString(href!),
),
padding: EdgeInsets.zero,
);
}
}
11 changes: 0 additions & 11 deletions lib/src/about/about_provider.dart

This file was deleted.

31 changes: 31 additions & 0 deletions lib/src/about/about_providers.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:github/github.dart';
import 'package:package_info_plus/package_info_plus.dart';

import 'package:ubuntu_service/ubuntu_service.dart';

final contributorsProvider =
FutureProvider.autoDispose.family((ref, String repo) async {
const designers = {'anasereijo', 'elioqoshi'};
const exclude = {'weblate'};
final contributors = await getService<GitHub>()
.repositories
.listContributors(RepositorySlug.full(repo))
.where((c) =>
c.type == 'User' &&
!designers.contains(c.login) &&
!exclude.contains(c.login))
.toList();
return [
...designers.map((d) => Contributor(
login: d,
htmlUrl: 'https://github.com/$d',
avatarUrl: 'https://avatars.githubusercontent.com/$d',
)),
...contributors
];
});

final versionProvider = FutureProvider.autoDispose((ref) {
return PackageInfo.fromPlatform().then((info) => info.version);
});
17 changes: 15 additions & 2 deletions lib/src/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,19 @@
}
}
},
"aboutDialogLabel": "About",
"aboutDialogTitle": "About App Store"
"aboutPageLabel": "About",
"aboutPageVersionLabel": "Version {version}",
"@aboutPageVersionLabel": {
"placeholders": {
"version": {
"type": "String"
}
}
},
"aboutPageContributorTitle": "Designed and developed by:",
"aboutPageCommunityTitle": "Be part of the community:",
"aboutPageContributeLabel": "Contribute or report bug",
"aboutPageGitHubLabel": "Find us on GitHub",
"aboutPagePublishLabel": "Publish to the Snap Store",
"aboutPageLearnMoreLabel": "Learn more"
}
Loading

0 comments on commit 78eaadb

Please sign in to comment.