From c660a419e2e6bf2ef61ab0a663bf54c846cee3f1 Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Sun, 12 Oct 2025 00:06:48 +0800 Subject: [PATCH] :recycle: Optimize the creator hub --- lib/route.dart | 38 +- lib/screens/creators/hub.dart | 724 ++++++++++-------- lib/screens/creators/poll/poll_list.dart | 1 + .../creators/posts/post_manage_list.dart | 1 + lib/screens/creators/publishers_form.dart | 1 + .../creators/stickers/pack_detail.dart | 2 + lib/screens/creators/stickers/stickers.dart | 2 + .../creators/webfeed/webfeed_edit.dart | 3 + .../creators/webfeed/webfeed_list.dart | 1 + lib/screens/poll/poll_editor.dart | 1 + 10 files changed, 437 insertions(+), 337 deletions(-) diff --git a/lib/route.dart b/lib/route.dart index 7b6bfc06..051bd6a8 100644 --- a/lib/route.dart +++ b/lib/route.dart @@ -150,19 +150,15 @@ final routerProvider = Provider((ref) { return EventCalanderScreen(name: name); }, ), - ShellRoute( - builder: - (context, state, child) => CreatorHubShellScreen(child: child), + GoRoute( + name: 'creatorHub', + path: '/creators', + builder: (context, state) => const CreatorHubScreen(), routes: [ - GoRoute( - name: 'creatorHub', - path: '/creators', - builder: (context, state) => const CreatorHubScreen(), - ), // Web Feed Routes GoRoute( name: 'creatorFeeds', - path: '/creators/:name/feeds', + path: ':name/feeds', builder: (context, state) { final name = state.pathParameters['name']!; return WebFeedListScreen(pubName: name); @@ -191,7 +187,7 @@ final routerProvider = Provider((ref) { ), GoRoute( name: 'creatorPosts', - path: '/creators/:name/posts', + path: ':name/posts', builder: (context, state) { final name = state.pathParameters['name']!; return CreatorPostListScreen(pubName: name); @@ -200,7 +196,7 @@ final routerProvider = Provider((ref) { // Poll list route GoRoute( name: 'creatorPolls', - path: '/creators/:name/polls', + path: ':name/polls', builder: (context, state) { final name = state.pathParameters['name']!; return CreatorPollListScreen(pubName: name); @@ -209,7 +205,7 @@ final routerProvider = Provider((ref) { // Poll routes GoRoute( name: 'creatorPollNew', - path: '/creators/:name/polls/new', + path: ':name/polls/new', builder: (context, state) { final name = state.pathParameters['name']!; // initialPollId left null for create; initialPublisher prefilled @@ -218,7 +214,7 @@ final routerProvider = Provider((ref) { ), GoRoute( name: 'creatorPollEdit', - path: '/creators/:name/polls/:id/edit', + path: ':name/polls/:id/edit', builder: (context, state) { final name = state.pathParameters['name']!; final id = state.pathParameters['id']!; @@ -230,7 +226,7 @@ final routerProvider = Provider((ref) { ), GoRoute( name: 'creatorStickers', - path: '/creators/:name/stickers', + path: ':name/stickers', builder: (context, state) { final name = state.pathParameters['name']!; return StickersScreen(pubName: name); @@ -238,7 +234,7 @@ final routerProvider = Provider((ref) { ), GoRoute( name: 'creatorStickerPackNew', - path: '/creators/:name/stickers/new', + path: ':name/stickers/new', builder: (context, state) { final name = state.pathParameters['name']!; return NewStickerPacksScreen(pubName: name); @@ -246,7 +242,7 @@ final routerProvider = Provider((ref) { ), GoRoute( name: 'creatorStickerPackEdit', - path: '/creators/:name/stickers/:packId/edit', + path: ':name/stickers/:packId/edit', builder: (context, state) { final name = state.pathParameters['name']!; final packId = state.pathParameters['packId']!; @@ -255,7 +251,7 @@ final routerProvider = Provider((ref) { ), GoRoute( name: 'creatorStickerPackDetail', - path: '/creators/:name/stickers/:packId', + path: ':name/stickers/:packId', builder: (context, state) { final name = state.pathParameters['name']!; final packId = state.pathParameters['packId']!; @@ -264,7 +260,7 @@ final routerProvider = Provider((ref) { ), GoRoute( name: 'creatorStickerNew', - path: '/creators/:name/stickers/:packId/new', + path: ':name/stickers/:packId/new', builder: (context, state) { final packId = state.pathParameters['packId']!; return NewStickersScreen(packId: packId); @@ -272,7 +268,7 @@ final routerProvider = Provider((ref) { ), GoRoute( name: 'creatorStickerEdit', - path: '/creators/:name/stickers/:packId/:id/edit', + path: ':name/stickers/:packId/:id/edit', builder: (context, state) { final packId = state.pathParameters['packId']!; final id = state.pathParameters['id']!; @@ -281,12 +277,12 @@ final routerProvider = Provider((ref) { ), GoRoute( name: 'creatorNew', - path: '/creators/new', + path: 'new', builder: (context, state) => const NewPublisherScreen(), ), GoRoute( name: 'creatorEdit', - path: '/creators/:name/edit', + path: ':name/edit', builder: (context, state) { final name = state.pathParameters['name']!; return EditPublisherScreen(name: name); diff --git a/lib/screens/creators/hub.dart b/lib/screens/creators/hub.dart index 1fb10fd2..891a00cc 100644 --- a/lib/screens/creators/hub.dart +++ b/lib/screens/creators/hub.dart @@ -102,42 +102,167 @@ class PublisherMemberListNotifier extends _$PublisherMemberListNotifier } } -class CreatorHubShellScreen extends StatelessWidget { - final Widget child; - const CreatorHubShellScreen({super.key, required this.child}); +class PublisherSelector extends StatelessWidget { + final SnPublisher? currentPublisher; + final List> publishersMenu; + final ValueChanged? onChanged; + final bool isReadOnly; + + const PublisherSelector({ + required this.currentPublisher, + required this.publishersMenu, + this.onChanged, + this.isReadOnly = false, + }); @override Widget build(BuildContext context) { - final isWide = isWideScreen(context); - if (isWide) { - return AppBackground( - isRoot: true, - child: Row( - children: [ - Flexible(flex: 2, child: const CreatorHubScreen(isAside: true)), - const VerticalDivider(width: 1), - Flexible(flex: 3, child: child), - ], - ), - ); + if (isReadOnly || currentPublisher == null) { + return ProfilePictureWidget( + radius: 16, + fileId: currentPublisher?.picture?.id, + ).center().padding(right: 8); } - return AppBackground(isRoot: true, child: child); + + return DropdownButtonHideUnderline( + child: DropdownButton2( + value: currentPublisher, + hint: CircleAvatar( + radius: 16, + child: Icon( + Symbols.person, + color: Theme.of( + context, + ).colorScheme.onSecondaryContainer.withOpacity(0.9), + fill: 1, + ), + ).center().padding(right: 8), + items: publishersMenu, + onChanged: onChanged, + selectedItemBuilder: (context) { + return publishersMenu + .map( + (e) => ProfilePictureWidget( + radius: 16, + fileId: e.value?.picture?.id, + ).center().padding(right: 8), + ) + .toList(); + }, + buttonStyleData: ButtonStyleData( + height: 40, + padding: const EdgeInsets.only(left: 14, right: 8), + decoration: BoxDecoration(borderRadius: BorderRadius.circular(20)), + ), + dropdownStyleData: DropdownStyleData( + width: 320, + padding: const EdgeInsets.symmetric(vertical: 6), + decoration: BoxDecoration(borderRadius: BorderRadius.circular(4)), + ), + menuItemStyleData: const MenuItemStyleData( + height: 64, + padding: EdgeInsets.only(left: 14, right: 14), + ), + iconStyleData: IconStyleData( + icon: Icon(Icons.arrow_drop_down), + iconSize: 19, + iconEnabledColor: Theme.of(context).appBarTheme.foregroundColor!, + iconDisabledColor: Theme.of(context).appBarTheme.foregroundColor!, + ), + ), + ); + } +} + +class _PublisherUnselectedWidget extends HookConsumerWidget { + final ValueChanged onPublisherSelected; + + const _PublisherUnselectedWidget({required this.onPublisherSelected}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final publishers = ref.watch(publishersManagedProvider); + final publisherInvites = ref.watch(publisherInvitesProvider); + + final hasPublishers = publishers.value?.isNotEmpty ?? false; + + return Card( + margin: const EdgeInsets.all(16), + child: Column( + children: [ + if (!hasPublishers) ...[ + const Icon( + Symbols.info, + fill: 1, + size: 32, + ).padding(bottom: 6, top: 24), + Text( + 'creatorHubUnselectedHint', + textAlign: TextAlign.center, + style: Theme.of(context).textTheme.bodyLarge, + ).tr(), + const Gap(24), + ], + if (hasPublishers) + ...(publishers.value?.map( + (publisher) => ListTile( + shape: RoundedRectangleBorder( + borderRadius: const BorderRadius.all(Radius.circular(8)), + ), + leading: ProfilePictureWidget(file: publisher.picture), + title: Text(publisher.nick), + subtitle: Text('@${publisher.name}'), + onTap: () => onPublisherSelected(publisher), + ), + ) ?? + []), + const Divider(height: 1), + ListTile( + shape: RoundedRectangleBorder( + borderRadius: const BorderRadius.all(Radius.circular(8)), + ), + leading: const CircleAvatar(child: Icon(Symbols.mail)), + title: Text('publisherCollabInvitation').tr(), + subtitle: Text( + 'publisherCollabInvitationCount', + ).plural(publisherInvites.value?.length ?? 0), + trailing: const Icon(Symbols.chevron_right), + onTap: () { + showModalBottomSheet( + context: context, + isScrollControlled: true, + builder: (_) => const _PublisherInviteSheet(), + ); + }, + ), + ListTile( + shape: RoundedRectangleBorder( + borderRadius: const BorderRadius.all(Radius.circular(8)), + ), + leading: const CircleAvatar(child: Icon(Symbols.add)), + title: Text('createPublisher').tr(), + subtitle: Text('createPublisherHint').tr(), + trailing: const Icon(Symbols.chevron_right), + onTap: () { + context.pushNamed('creatorNew').then((value) { + if (value != null) { + ref.invalidate(publishersManagedProvider); + } + }); + }, + ), + ], + ), + ); } } class CreatorHubScreen extends HookConsumerWidget { - final bool isAside; - const CreatorHubScreen({super.key, this.isAside = false}); + const CreatorHubScreen({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { - final isWide = isWideScreen(context); - if (isWide && !isAside) { - return Container(color: Theme.of(context).colorScheme.surface); - } - final publishers = ref.watch(publishersManagedProvider); - final publisherInvites = ref.watch(publisherInvitesProvider); final currentPublisher = useState( publishers.value?.firstOrNull, ); @@ -207,299 +332,251 @@ class CreatorHubScreen extends HookConsumerWidget { publisherFeaturesProvider(currentPublisher.value?.name), ); + Widget buildNavigationWidget(bool isWide) { + final leftItems = [ + ListTile( + shape: RoundedRectangleBorder( + borderRadius: const BorderRadius.all(Radius.circular(8)), + ), + minTileHeight: 48, + title: Text('stickers').tr(), + trailing: Icon(Symbols.chevron_right), + leading: const Icon(Symbols.ar_stickers), + onTap: () { + context.pushNamed( + 'creatorStickers', + pathParameters: {'name': currentPublisher.value!.name}, + ); + }, + ), + ListTile( + shape: RoundedRectangleBorder( + borderRadius: const BorderRadius.all(Radius.circular(8)), + ), + minTileHeight: 48, + title: Text('posts').tr(), + trailing: Icon(Symbols.chevron_right), + leading: const Icon(Symbols.sticky_note_2), + onTap: () { + context.pushNamed( + 'creatorPosts', + pathParameters: {'name': currentPublisher.value!.name}, + ); + }, + ), + ListTile( + shape: RoundedRectangleBorder( + borderRadius: const BorderRadius.all(Radius.circular(8)), + ), + minTileHeight: 48, + title: Text('polls').tr(), + trailing: const Icon(Symbols.chevron_right), + leading: const Icon(Symbols.poll), + onTap: () { + context.pushNamed( + 'creatorPolls', + pathParameters: {'name': currentPublisher.value!.name}, + ); + }, + ), + ListTile( + shape: RoundedRectangleBorder( + borderRadius: const BorderRadius.all(Radius.circular(8)), + ), + minTileHeight: 48, + title: Text('publisherMembers').tr(), + trailing: const Icon(Symbols.chevron_right), + leading: const Icon(Symbols.group), + onTap: () { + showModalBottomSheet( + isScrollControlled: true, + context: context, + builder: + (context) => _PublisherMemberListSheet( + publisherUname: currentPublisher.value!.name, + ), + ); + }, + ), + ]; + + final rightItems = [ + ListTile( + shape: RoundedRectangleBorder( + borderRadius: const BorderRadius.all(Radius.circular(8)), + ), + minTileHeight: 48, + title: const Text('webFeeds').tr(), + trailing: const Icon(Symbols.chevron_right), + leading: const Icon(Symbols.rss_feed), + onTap: () { + context.push('/creators/${currentPublisher.value!.name}/feeds'); + }, + ), + ExpansionTile( + shape: RoundedRectangleBorder( + borderRadius: const BorderRadius.all(Radius.circular(8)), + ), + title: Text('publisherFeatures').tr(), + leading: const Icon(Symbols.flag), + tilePadding: const EdgeInsets.only(left: 16, right: 24), + minTileHeight: 48, + children: [ + ...publisherFeatures.when( + data: (data) { + return data.entries.map((entry) { + final keyPrefix = + 'publisherFeature${entry.key.capitalizeEachWord()}'; + return ListTile( + minTileHeight: 48, + contentPadding: const EdgeInsets.symmetric(horizontal: 16), + leading: Icon( + Symbols.circle, + color: entry.value ? Colors.green : Colors.red, + fill: 1, + size: 16, + ).padding(left: 2, top: 4), + title: Text(keyPrefix).tr(), + subtitle: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('${keyPrefix}Description').tr(), + if (!entry.value) Text('${keyPrefix}Hint').tr().bold(), + ], + ), + isThreeLine: true, + ); + }).toList(); + }, + error: (_, _) => [], + loading: () => [], + ), + ], + ), + ListTile( + shape: RoundedRectangleBorder( + borderRadius: const BorderRadius.all(Radius.circular(8)), + ), + minTileHeight: 48, + title: Text('editPublisher').tr(), + trailing: Icon(Symbols.chevron_right), + leading: const Icon(Symbols.edit), + onTap: updatePublisher, + ), + ListTile( + shape: RoundedRectangleBorder( + borderRadius: const BorderRadius.all(Radius.circular(8)), + ), + minTileHeight: 48, + title: Text('deletePublisher').tr(), + trailing: Icon(Symbols.chevron_right), + leading: const Icon(Symbols.delete), + onTap: deletePublisher, + ), + ]; + + if (isWide) { + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + spacing: 8, + children: [ + Expanded( + child: Card( + margin: EdgeInsets.zero, + child: Column(children: leftItems), + ), + ), + Expanded( + child: Card( + margin: EdgeInsets.zero, + child: Column(children: rightItems), + ), + ), + ], + ).padding(horizontal: 12); + } else { + return Card( + margin: const EdgeInsets.symmetric(horizontal: 16), + child: Column( + children: [...leftItems, const Divider(height: 8), ...rightItems], + ), + ); + } + } + return AppScaffold( + isNoBackground: false, appBar: AppBar( - leading: !isWide ? const PageBackButton() : null, + leading: const PageBackButton(), title: Text('creatorHub').tr(), actions: [ - DropdownButtonHideUnderline( - child: DropdownButton2( - alignment: Alignment.centerRight, - value: currentPublisher.value, - hint: CircleAvatar( - radius: 16, - child: Icon( - Symbols.person, - color: Theme.of( - context, - ).colorScheme.onSecondaryContainer.withOpacity(0.9), - fill: 1, - ), - ).center().padding(right: 8), - items: [...publishersMenu], + if (!isWideScreen(context)) + PublisherSelector( + currentPublisher: currentPublisher.value, + publishersMenu: publishersMenu, onChanged: (value) { currentPublisher.value = value; }, - selectedItemBuilder: (context) { - return [ - ...publishersMenu.map( - (e) => ProfilePictureWidget( - radius: 16, - fileId: e.value?.picture?.id, - ).center().padding(right: 8), - ), - ]; - }, - buttonStyleData: ButtonStyleData( - height: 40, - padding: const EdgeInsets.only(left: 14, right: 8), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20), - ), - ), - dropdownStyleData: DropdownStyleData( - width: 320, - padding: const EdgeInsets.symmetric(vertical: 6), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(4), - ), - ), - menuItemStyleData: const MenuItemStyleData( - height: 64, - padding: EdgeInsets.only(left: 14, right: 14), - ), - iconStyleData: IconStyleData( - icon: Icon(Icons.arrow_drop_down), - iconSize: 19, - iconEnabledColor: - Theme.of(context).appBarTheme.foregroundColor!, - iconDisabledColor: - Theme.of(context).appBarTheme.foregroundColor!, - ), ), - ), const Gap(8), ], ), - body: publisherStats.when( - data: - (stats) => SingleChildScrollView( - child: - currentPublisher.value == null - ? Column( - children: [ - const Gap(24), - const Icon(Symbols.info, size: 32).padding(bottom: 4), - Text( - 'creatorHubUnselectedHint', - textAlign: TextAlign.center, - ).tr(), - const Gap(24), - const Divider(height: 1), - ...(publishers.value?.map( - (publisher) => ListTile( - leading: ProfilePictureWidget( - file: publisher.picture, - ), - title: Text(publisher.nick), - subtitle: Text('@${publisher.name}'), - onTap: () { + body: LayoutBuilder( + builder: (context, constraints) { + final isWide = isWideScreen(context); + final maxWidth = isWide ? 800.0 : double.infinity; + + return Center( + child: ConstrainedBox( + constraints: BoxConstraints(maxWidth: maxWidth), + child: publisherStats.when( + data: + (stats) => SingleChildScrollView( + child: + currentPublisher.value == null + ? ConstrainedBox( + constraints: BoxConstraints(maxWidth: 640), + child: _PublisherUnselectedWidget( + onPublisherSelected: (publisher) { currentPublisher.value = publisher; }, ), - ) ?? - []), - ListTile( - leading: const CircleAvatar( - child: Icon(Symbols.mail), - ), - title: Text('publisherCollabInvitation').tr(), - subtitle: Text( - 'publisherCollabInvitationCount', - ).plural(publisherInvites.value?.length ?? 0), - trailing: const Icon(Symbols.chevron_right), - onTap: () { - showModalBottomSheet( - context: context, - isScrollControlled: true, - builder: (_) => const _PublisherInviteSheet(), - ); - }, - ), - ListTile( - leading: const CircleAvatar( - child: Icon(Symbols.add), - ), - title: Text('createPublisher').tr(), - subtitle: Text('createPublisherHint').tr(), - trailing: const Icon(Symbols.chevron_right), - onTap: () { - context.pushNamed('creatorNew').then((value) { - if (value != null) { - ref.invalidate(publishersManagedProvider); - } - }); - }, - ), - ], - ) - : Column( - children: [ - if (stats != null) - _PublisherStatsWidget( - stats: stats, - ).padding(vertical: 12, horizontal: 12), - ListTile( - minTileHeight: 48, - title: Text('stickers').tr(), - trailing: Icon(Symbols.chevron_right), - leading: const Icon(Symbols.ar_stickers), - contentPadding: EdgeInsets.symmetric( - horizontal: 24, - ), - onTap: () { - context.pushNamed( - 'creatorStickers', - pathParameters: { - 'name': currentPublisher.value!.name, - }, - ); - }, - ), - ListTile( - minTileHeight: 48, - title: Text('posts').tr(), - trailing: Icon(Symbols.chevron_right), - leading: const Icon(Symbols.sticky_note_2), - contentPadding: EdgeInsets.symmetric( - horizontal: 24, - ), - onTap: () { - context.pushNamed( - 'creatorPosts', - pathParameters: { - 'name': currentPublisher.value!.name, - }, - ); - }, - ), - ListTile( - minTileHeight: 48, - title: Text('polls').tr(), - trailing: const Icon(Symbols.chevron_right), - leading: const Icon(Symbols.poll), - contentPadding: const EdgeInsets.symmetric( - horizontal: 24, - ), - onTap: () { - context.pushNamed( - 'creatorPolls', - pathParameters: { - 'name': currentPublisher.value!.name, - }, - ); - }, - ), - ListTile( - minTileHeight: 48, - title: Text('publisherMembers').tr(), - trailing: const Icon(Symbols.chevron_right), - leading: const Icon(Symbols.group), - contentPadding: const EdgeInsets.symmetric( - horizontal: 24, - ), - onTap: () { - showModalBottomSheet( - isScrollControlled: true, - context: context, - builder: - (context) => _PublisherMemberListSheet( - publisherUname: - currentPublisher.value!.name, - ), - ); - }, - ), - ListTile( - minTileHeight: 48, - title: const Text('webFeeds').tr(), - trailing: const Icon(Symbols.chevron_right), - leading: const Icon(Symbols.rss_feed), - contentPadding: const EdgeInsets.symmetric( - horizontal: 24, - ), - onTap: () { - context.push( - '/creators/${currentPublisher.value!.name}/feeds', - ); - }, - ), - ExpansionTile( - title: Text('publisherFeatures').tr(), - leading: const Icon(Symbols.flag), - tilePadding: EdgeInsets.symmetric(horizontal: 24), - minTileHeight: 48, - children: [ - ...publisherFeatures.when( - data: (data) { - return data.entries.map((entry) { - final keyPrefix = - 'publisherFeature${entry.key.capitalizeEachWord()}'; - return ListTile( - minTileHeight: 48, - contentPadding: EdgeInsets.symmetric( - horizontal: 24, - ), - leading: Icon( - Symbols.circle, - color: - entry.value - ? Colors.green - : Colors.red, - fill: 1, - size: 16, - ).padding(left: 2, top: 4), - title: Text(keyPrefix).tr(), - subtitle: Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - Text('${keyPrefix}Description').tr(), - if (!entry.value) - Text( - '${keyPrefix}Hint', - ).tr().bold(), - ], - ), - isThreeLine: true, - ); - }).toList(); - }, - error: (_, _) => [], - loading: () => [], + ).center() + : isWide + ? Column( + spacing: 8, + children: [ + PublisherSelector( + currentPublisher: currentPublisher.value, + publishersMenu: publishersMenu, + onChanged: (value) { + currentPublisher.value = value; + }, + ), + if (stats != null) + _PublisherStatsWidget( + stats: stats, + ).padding(horizontal: 12), + buildNavigationWidget(true), + ], + ) + : Column( + spacing: 12, + children: [ + if (stats != null) + _PublisherStatsWidget( + stats: stats, + ).padding(horizontal: 16), + buildNavigationWidget(false), + ], ), - ], - ), - Divider(height: 1).padding(vertical: 8), - ListTile( - minTileHeight: 48, - title: Text('editPublisher').tr(), - trailing: Icon(Symbols.chevron_right), - leading: const Icon(Symbols.edit), - contentPadding: EdgeInsets.symmetric( - horizontal: 24, - ), - onTap: () { - updatePublisher(); - }, - ), - ListTile( - minTileHeight: 48, - title: Text('deletePublisher').tr(), - trailing: Icon(Symbols.chevron_right), - leading: const Icon(Symbols.delete), - contentPadding: EdgeInsets.symmetric( - horizontal: 24, - ), - onTap: () { - deletePublisher(); - }, - ), - ], - ), + ), + loading: () => const Center(child: CircularProgressIndicator()), + error: (_, _) => const SizedBox.shrink(), + ), ), - loading: () => const Center(child: CircularProgressIndicator()), - error: (_, _) => const SizedBox.shrink(), + ); + }, ), ); } @@ -576,21 +653,36 @@ class _PublisherStatsWidget extends StatelessWidget { height: 100, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 8), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - statValue, - style: Theme.of(context).textTheme.headlineMedium, - ), - const Gap(4), - Text( - statLabel, - maxLines: 1, - overflow: TextOverflow.ellipsis, - ).tr(), - ], + child: Tooltip( + richMessage: TextSpan( + text: statLabel.tr(), + style: TextStyle(fontWeight: FontWeight.bold), + children: [ + TextSpan(text: ' '), + TextSpan( + text: statValue, + style: TextStyle(fontWeight: FontWeight.normal), + ), + ], + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + statValue, + style: Theme.of(context).textTheme.headlineMedium, + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + const Gap(4), + Text( + statLabel, + maxLines: 1, + overflow: TextOverflow.ellipsis, + ).tr(), + ], + ), ), ), ), diff --git a/lib/screens/creators/poll/poll_list.dart b/lib/screens/creators/poll/poll_list.dart index 67b55f83..2fec8080 100644 --- a/lib/screens/creators/poll/poll_list.dart +++ b/lib/screens/creators/poll/poll_list.dart @@ -84,6 +84,7 @@ class CreatorPollListScreen extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { return AppScaffold( + isNoBackground: false, appBar: AppBar(title: const Text('Polls')), floatingActionButton: FloatingActionButton( onPressed: () => _createPoll(context), diff --git a/lib/screens/creators/posts/post_manage_list.dart b/lib/screens/creators/posts/post_manage_list.dart index 7a0dbb12..a0524d5c 100644 --- a/lib/screens/creators/posts/post_manage_list.dart +++ b/lib/screens/creators/posts/post_manage_list.dart @@ -61,6 +61,7 @@ class CreatorPostListScreen extends HookConsumerWidget { } return AppScaffold( + isNoBackground: false, appBar: AppBar(title: Text('posts').tr()), body: CustomScrollView( key: ValueKey(refreshKey.value), diff --git a/lib/screens/creators/publishers_form.dart b/lib/screens/creators/publishers_form.dart index e201a4e2..9a420975 100644 --- a/lib/screens/creators/publishers_form.dart +++ b/lib/screens/creators/publishers_form.dart @@ -178,6 +178,7 @@ class EditPublisherScreen extends HookConsumerWidget { } return AppScaffold( + isNoBackground: false, appBar: AppBar( title: Text(name == null ? 'createPublisher' : 'editPublisher').tr(), leading: const PageBackButton(), diff --git a/lib/screens/creators/stickers/pack_detail.dart b/lib/screens/creators/stickers/pack_detail.dart index 96eae9e4..54868fd6 100644 --- a/lib/screens/creators/stickers/pack_detail.dart +++ b/lib/screens/creators/stickers/pack_detail.dart @@ -68,6 +68,7 @@ class StickerPackDetailScreen extends HookConsumerWidget { } return AppScaffold( + isNoBackground: false, appBar: AppBar( title: Text(pack.value?.name ?? 'loading'.tr()), actions: [ @@ -396,6 +397,7 @@ class EditStickersScreen extends HookConsumerWidget { } return AppScaffold( + isNoBackground: false, appBar: AppBar( title: Text(id == null ? 'createSticker' : 'editSticker').tr(), ), diff --git a/lib/screens/creators/stickers/stickers.dart b/lib/screens/creators/stickers/stickers.dart index 6bd3d955..45115c0e 100644 --- a/lib/screens/creators/stickers/stickers.dart +++ b/lib/screens/creators/stickers/stickers.dart @@ -23,6 +23,7 @@ class StickersScreen extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { return AppScaffold( + isNoBackground: false, appBar: AppBar( title: const Text('stickers').tr(), actions: [ @@ -196,6 +197,7 @@ class EditStickerPacksScreen extends HookConsumerWidget { } return AppScaffold( + isNoBackground: false, appBar: AppBar( title: Text(packId == null ? 'createStickerPack' : 'editStickerPack').tr(), diff --git a/lib/screens/creators/webfeed/webfeed_edit.dart b/lib/screens/creators/webfeed/webfeed_edit.dart index 9f4a964b..91b65d62 100644 --- a/lib/screens/creators/webfeed/webfeed_edit.dart +++ b/lib/screens/creators/webfeed/webfeed_edit.dart @@ -115,10 +115,12 @@ class WebFeedEditScreen extends HookConsumerWidget { return feedAsync.when( loading: () => const AppScaffold( + isNoBackground: false, body: Center(child: CircularProgressIndicator()), ), error: (error, stack) => AppScaffold( + isNoBackground: false, appBar: AppBar(title: const Text('Error')), body: Center(child: Text('Error: $error')), ), @@ -186,6 +188,7 @@ class WebFeedEditScreen extends HookConsumerWidget { }, [pubName, feedId, ref, context]); return AppScaffold( + isNoBackground: false, appBar: AppBar( title: Text(hasFeedId ? 'Edit Web Feed' : 'New Web Feed'), actions: [ diff --git a/lib/screens/creators/webfeed/webfeed_list.dart b/lib/screens/creators/webfeed/webfeed_list.dart index a9b04d1b..b5ee67c7 100644 --- a/lib/screens/creators/webfeed/webfeed_list.dart +++ b/lib/screens/creators/webfeed/webfeed_list.dart @@ -17,6 +17,7 @@ class WebFeedListScreen extends ConsumerWidget { final feedsAsync = ref.watch(webFeedListProvider(pubName)); return AppScaffold( + isNoBackground: false, appBar: AppBar(title: const Text('Web Feeds')), floatingActionButton: FloatingActionButton( child: const Icon(Symbols.add), diff --git a/lib/screens/poll/poll_editor.dart b/lib/screens/poll/poll_editor.dart index f11ead30..b67149b3 100644 --- a/lib/screens/poll/poll_editor.dart +++ b/lib/screens/poll/poll_editor.dart @@ -416,6 +416,7 @@ class PollEditorScreen extends ConsumerWidget { } return AppScaffold( + isNoBackground: false, appBar: AppBar( title: Text(model.id == null ? 'pollCreate'.tr() : 'pollEdit'.tr()), actions: [