diff --git a/mobile/lib/features/channels/channels_page/filters.dart b/mobile/lib/features/channels/channels_page/filters.dart index dd9b4e9278..09525c3983 100644 --- a/mobile/lib/features/channels/channels_page/filters.dart +++ b/mobile/lib/features/channels/channels_page/filters.dart @@ -137,22 +137,50 @@ class _SectionViewSheet extends HookConsumerWidget { children: [ Text(label, style: context.textTheme.titleSmall), const SizedBox(height: Grid.xxs), - Wrap( - spacing: Grid.xxs, - runSpacing: Grid.xxs, - children: [ + SegmentedButton( + segments: [ for (final entry in values.entries) - ChoiceChip( - label: Text(entry.value), - selected: entry.key == selected, - onSelected: change == null - ? null - : (_) { - dirty.value = true; - change(entry.key); - }, - ), + ButtonSegment(value: entry.key, label: Text(entry.value)), ], + selected: {selected}, + showSelectedIcon: false, + direction: MediaQuery.textScalerOf(context).scale(14) > 20 + ? Axis.vertical + : Axis.horizontal, + expandedInsets: MediaQuery.textScalerOf(context).scale(14) > 20 + ? null + : EdgeInsets.zero, + style: ButtonStyle( + foregroundColor: WidgetStateProperty.resolveWith( + (states) => states.contains(WidgetState.disabled) + ? context.colors.onSurface.withValues(alpha: 0.5) + : states.contains(WidgetState.selected) + ? context.colors.onSurface + : context.colors.onSurfaceVariant, + ), + backgroundColor: WidgetStateProperty.resolveWith( + (states) => states.contains(WidgetState.selected) + ? context.colors.surface + : context.colors.onSurface.withValues(alpha: 0.06), + ), + side: WidgetStatePropertyAll( + BorderSide(color: context.colors.outline.withValues(alpha: 0.25)), + ), + shape: WidgetStatePropertyAll( + RoundedRectangleBorder( + borderRadius: BorderRadius.circular(Radii.sm), + ), + ), + padding: const WidgetStatePropertyAll( + EdgeInsets.symmetric(horizontal: Grid.xxs, vertical: Grid.twelve), + ), + ), + onSelectionChanged: change == null + ? null + : (selection) { + dirty.value = true; + change(selection.single); + }, ), const SizedBox(height: Grid.xs), ], @@ -165,14 +193,24 @@ class _SectionViewSheet extends HookConsumerWidget { maxHeight: MediaQuery.sizeOf(context).height * 0.85, ), child: Padding( - padding: const EdgeInsets.all(Grid.xs), + padding: const EdgeInsets.fromLTRB( + Grid.gutter, + Grid.xxs, + Grid.gutter, + Grid.twelve, + ), child: Column( mainAxisSize: MainAxisSize.min, children: [ Row( children: [ Expanded( - child: Text(title, style: context.textTheme.titleLarge), + child: Text( + title, + style: context.textTheme.titleMedium?.copyWith( + fontWeight: FontWeight.w600, + ), + ), ), IconButton( tooltip: 'Close', @@ -259,28 +297,35 @@ class _SectionViewSheet extends HookConsumerWidget { ), ), const SizedBox(height: Grid.xxs), - Wrap( - alignment: WrapAlignment.end, - spacing: Grid.xxs, - runSpacing: Grid.xxs, - children: [ - TextButton( - onPressed: saving.value ? null : () => close(), - child: const Text('Cancel'), - ), - FilledButton( - onPressed: saving.value || manager?.busy == true - ? null - : apply, - child: Text( - saving.value - ? 'Saving…' - : failed.value - ? 'Retry' - : 'Apply', + Align( + alignment: Alignment.centerRight, + child: Wrap( + alignment: WrapAlignment.end, + spacing: Grid.xxs, + runSpacing: Grid.xxs, + children: [ + TextButton( + onPressed: saving.value ? null : () => close(), + child: const Text('Cancel'), ), - ), - ], + FilledButton( + style: FilledButton.styleFrom( + backgroundColor: context.colors.onSurface, + foregroundColor: context.colors.surface, + ), + onPressed: saving.value || manager?.busy == true + ? null + : apply, + child: Text( + saving.value + ? 'Saving…' + : failed.value + ? 'Retry' + : 'Apply', + ), + ), + ], + ), ), ], ), diff --git a/mobile/test/features/channels/channels_page_test.dart b/mobile/test/features/channels/channels_page_test.dart index d9cac02bc0..a4fe444452 100644 --- a/mobile/test/features/channels/channels_page_test.dart +++ b/mobile/test/features/channels/channels_page_test.dart @@ -1,3 +1,4 @@ +import 'package:buzz/features/channels/channel_sort/channel_sort_storage.dart'; import 'package:nostr/nostr.dart' as nostr; import 'package:buzz/features/channels/channel_filter/channel_filter_provider.dart'; import 'package:buzz/features/channels/channel_filter/channel_filter_manager.dart'; @@ -225,10 +226,13 @@ void main() { await tester.tap(find.byTooltip('Channels options')); await tester.pumpAndSettle(); expect(find.text('general'), findsNothing); - final all = tester.widget( - find.ancestor(of: find.text('All'), matching: find.byType(ChoiceChip)), + final all = tester.widget>( + find.ancestor( + of: find.text('All'), + matching: find.byType(SegmentedButton), + ), ); - expect(all.onSelected, isNull); + expect(all.onSelectionChanged, isNull); await tester.tap(find.text('Cancel')); await tester.pumpAndSettle(); await tester.tap(find.text('Show hidden channels · 1')); @@ -258,6 +262,7 @@ void main() { await tester.pumpAndSettle(); await tester.tap(find.text('Active')); await tester.pumpAndSettle(); + await tester.ensureVisible(find.text('7 days')); await tester.tap(find.text('7 days')); await tester.pumpAndSettle(); expect(manager.store.modeFor('channels'), ChannelFilterMode.all); @@ -267,13 +272,13 @@ void main() { expect(manager.store.windowFor('channels'), 7 * 86400); await tester.tap(find.byTooltip('Channels options')); await tester.pumpAndSettle(); - final days = tester.widget( + final days = tester.widget>( find.ancestor( of: find.text('7 days'), - matching: find.byType(ChoiceChip), + matching: find.byType(SegmentedButton), ), ); - expect(days.selected, isTrue); + expect(days.selected, {7}); await tester.tap(find.text('All')); await tester.tap(find.text('Cancel')); await tester.pumpAndSettle(); @@ -306,6 +311,7 @@ void main() { await tester.pumpAndSettle(); await tester.tap(find.text('Active')); await tester.pumpAndSettle(); + await tester.ensureVisible(find.text('7 days')); await tester.tap(find.text('7 days')); await tester.pumpAndSettle(); await tester.ensureVisible(find.text('Apply')); @@ -317,13 +323,13 @@ void main() { ), findsOneWidget, ); - final selected = tester.widget( + final selected = tester.widget>( find.ancestor( of: find.text('7 days'), - matching: find.byType(ChoiceChip), + matching: find.byType(SegmentedButton), ), ); - expect(selected.selected, isTrue); + expect(selected.selected, {7}); await tester.tap(find.text('Cancel')); await tester.pumpAndSettle(); expect(find.byType(AlertDialog), findsNothing); @@ -469,10 +475,13 @@ void main() { expect(find.text('A–Z'), findsOneWidget); expect(find.text('Show'), findsOneWidget); expect(find.byType(AlertDialog), findsNothing); - final alpha = tester.widget( - find.ancestor(of: find.text('A–Z'), matching: find.byType(ChoiceChip)), + final alpha = tester.widget>( + find.ancestor( + of: find.text('A–Z'), + matching: find.byType(SegmentedButton), + ), ); - expect(alpha.selected, isTrue); + expect(alpha.selected, {ChannelSortMode.alpha}); await tester.tap(find.text('Cancel')); await tester.pumpAndSettle();