mirror of
https://github.com/GopeedLab/gopeed.git
synced 2026-11-10 18:40:27 +00:00
refactor(ui): simplify create task advanced disclosure
This commit is contained in:
1 parent
392ee36137
commit
07cbfbdade
3 files changed
+114
-38
No files matched your search
@@ -41,6 +41,7 @@ import '../../application/pending_download.dart';
|
||||
import '../../application/task_list_navigation.dart';
|
||||
import '../widgets/history_search_field.dart';
|
||||
import '../widgets/create_task_action_buttons.dart';
|
||||
import '../widgets/create_task_advanced_toggle.dart';
|
||||
import '../widgets/resolve_download_dialog.dart';
|
||||
|
||||
class CreateTaskWindowPage extends ConsumerStatefulWidget {
|
||||
@@ -560,20 +561,11 @@ class _CreateTaskWindowPageState extends ConsumerState<CreateTaskWindowPage> {
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: GestureDetector(
|
||||
onTap: _toggleAdvanced,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
context.l10n.advanced,
|
||||
style: TextStyle(color: palette.textPrimary, fontSize: 14, fontWeight: FontWeight.w600),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
_TripleChevronIcon(expanded: _showAdvanced, color: palette.textSecondary),
|
||||
],
|
||||
),
|
||||
alignment: AlignmentDirectional.centerStart,
|
||||
child: CreateTaskAdvancedToggle(
|
||||
key: const ValueKey('create-task-advanced-toggle'),
|
||||
expanded: _showAdvanced,
|
||||
onPressed: _toggleAdvanced,
|
||||
),
|
||||
),
|
||||
AnimatedCrossFade(
|
||||
@@ -1933,30 +1925,6 @@ class _MiniInputAction extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class _TripleChevronIcon extends StatelessWidget {
|
||||
const _TripleChevronIcon({required this.expanded, required this.color});
|
||||
|
||||
final bool expanded;
|
||||
final Color color;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final icon = expanded ? Icons.expand_less : Icons.expand_more;
|
||||
return SizedBox(
|
||||
width: 14,
|
||||
height: 18,
|
||||
child: Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
Positioned(top: 0, left: 0, child: Icon(icon, size: 14, color: color)),
|
||||
Positioned(top: 4, left: 0, child: Icon(icon, size: 14, color: color)),
|
||||
Positioned(top: 8, left: 0, child: Icon(icon, size: 14, color: color)),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _SegmentButton extends StatelessWidget {
|
||||
const _SegmentButton({required this.label, required this.active, required this.onTap});
|
||||
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
import 'package:shadcn_flutter/shadcn_flutter.dart';
|
||||
|
||||
import '../../../../l10n/l10n.dart';
|
||||
import '../../../../shared/theme/app_design_tokens.dart';
|
||||
import '../../../../shared/theme/app_palette.dart';
|
||||
|
||||
/// A quiet disclosure control with the same keyboard behavior as other buttons.
|
||||
class CreateTaskAdvancedToggle extends StatelessWidget {
|
||||
const CreateTaskAdvancedToggle({super.key, required this.expanded, required this.onPressed});
|
||||
|
||||
final bool expanded;
|
||||
final VoidCallback onPressed;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final palette = AppPalette.of(context);
|
||||
final reduceMotion = MediaQuery.disableAnimationsOf(context);
|
||||
return Semantics(
|
||||
expanded: expanded,
|
||||
child: ButtonStyleOverride.inherit(
|
||||
padding: (context, states, value) => const EdgeInsets.symmetric(vertical: AppDesignTokens.space12),
|
||||
child: GhostButton(
|
||||
onPressed: onPressed,
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(minHeight: 20),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Flexible(
|
||||
child: Text(
|
||||
context.l10n.advanced,
|
||||
style: TextStyle(color: palette.textPrimary, fontSize: 14, fontWeight: FontWeight.w600),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: AppDesignTokens.space8),
|
||||
AnimatedRotation(
|
||||
turns: expanded ? 0.5 : 0,
|
||||
duration: reduceMotion ? Duration.zero : const Duration(milliseconds: 180),
|
||||
curve: Curves.easeOutCubic,
|
||||
child: Icon(Icons.keyboard_arrow_down, size: 16, color: palette.textSecondary),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:gopeed/features/tasks/presentation/widgets/create_task_advanced_toggle.dart';
|
||||
import 'package:gopeed/shared/theme/app_component_themes.dart';
|
||||
import 'package:gopeed/shared/theme/app_theme.dart';
|
||||
import 'package:shadcn_flutter/shadcn_flutter.dart' as shad;
|
||||
|
||||
void main() {
|
||||
for (final width in [360.0, 768.0, 1024.0]) {
|
||||
testWidgets('advanced disclosure supports keyboard and touch at width $width', (tester) async {
|
||||
tester.view.physicalSize = Size(width, 768);
|
||||
tester.view.devicePixelRatio = 1;
|
||||
addTearDown(tester.view.resetPhysicalSize);
|
||||
addTearDown(tester.view.resetDevicePixelRatio);
|
||||
var expanded = false;
|
||||
await tester.pumpWidget(
|
||||
shad.ShadcnApp(
|
||||
theme: AppTheme.light(),
|
||||
materialTheme: AppTheme.materialLight(),
|
||||
home: AppComponentThemes(
|
||||
child: StatefulBuilder(
|
||||
builder: (context, setState) => Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: CreateTaskAdvancedToggle(
|
||||
expanded: expanded,
|
||||
onPressed: () => setState(() => expanded = !expanded),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
expect(tester.getSize(find.byType(shad.GhostButton)).height, greaterThanOrEqualTo(44));
|
||||
expect(
|
||||
find.byWidgetPredicate((widget) => widget is Semantics && widget.properties.expanded == false),
|
||||
findsOneWidget,
|
||||
);
|
||||
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
|
||||
await tester.pump();
|
||||
await tester.sendKeyEvent(LogicalKeyboardKey.enter);
|
||||
await tester.pumpAndSettle();
|
||||
expect(expanded, isTrue);
|
||||
expect(
|
||||
find.byWidgetPredicate((widget) => widget is Semantics && widget.properties.expanded == true),
|
||||
findsOneWidget,
|
||||
);
|
||||
await tester.tap(find.text('Advanced'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(expanded, isFalse);
|
||||
expect(tester.takeException(), isNull);
|
||||
await tester.pumpWidget(const SizedBox.shrink());
|
||||
await tester.pumpAndSettle();
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user