mirror of
https://github.com/block/buzz.git
synced 2026-11-06 09:21:45 +00:00
fix(mobile): group section view controls with readable selection
Replace disconnected chips with full-width segments, tighten the sheet header and give Apply clear contrast. Stack choices at enlarged text sizes and keep draft controls scrollable. Co-authored-by: Carl <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@buzz.block.builderlab.xyz> Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
This commit is contained in:
@@ -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<T>(
|
||||
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',
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -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<ChoiceChip>(
|
||||
find.ancestor(of: find.text('All'), matching: find.byType(ChoiceChip)),
|
||||
final all = tester.widget<SegmentedButton<ChannelFilterMode>>(
|
||||
find.ancestor(
|
||||
of: find.text('All'),
|
||||
matching: find.byType(SegmentedButton<ChannelFilterMode>),
|
||||
),
|
||||
);
|
||||
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<ChoiceChip>(
|
||||
final days = tester.widget<SegmentedButton<int>>(
|
||||
find.ancestor(
|
||||
of: find.text('7 days'),
|
||||
matching: find.byType(ChoiceChip),
|
||||
matching: find.byType(SegmentedButton<int>),
|
||||
),
|
||||
);
|
||||
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<ChoiceChip>(
|
||||
final selected = tester.widget<SegmentedButton<int>>(
|
||||
find.ancestor(
|
||||
of: find.text('7 days'),
|
||||
matching: find.byType(ChoiceChip),
|
||||
matching: find.byType(SegmentedButton<int>),
|
||||
),
|
||||
);
|
||||
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<ChoiceChip>(
|
||||
find.ancestor(of: find.text('A–Z'), matching: find.byType(ChoiceChip)),
|
||||
final alpha = tester.widget<SegmentedButton<ChannelSortMode>>(
|
||||
find.ancestor(
|
||||
of: find.text('A–Z'),
|
||||
matching: find.byType(SegmentedButton<ChannelSortMode>),
|
||||
),
|
||||
);
|
||||
expect(alpha.selected, isTrue);
|
||||
expect(alpha.selected, {ChannelSortMode.alpha});
|
||||
await tester.tap(find.text('Cancel'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user