diff --git a/lib/ui/router.dart b/lib/ui/router.dart index 7737510..9cefd7a 100644 --- a/lib/ui/router.dart +++ b/lib/ui/router.dart @@ -7,7 +7,6 @@ import 'screens/edit_account_screen.dart'; import 'screens/email_detail_screen.dart'; import 'screens/email_list_screen.dart'; import 'screens/mailbox_list_screen.dart'; -import 'screens/settings_screen.dart'; import 'screens/sync_log_screen.dart'; final router = GoRouter( @@ -71,9 +70,5 @@ final router = GoRouter( ); }, ), - GoRoute( - path: '/settings', - builder: (ctx, state) => const SettingsScreen(), - ), ], ); diff --git a/lib/ui/screens/account_list_screen.dart b/lib/ui/screens/account_list_screen.dart index 16118a3..fabec93 100644 --- a/lib/ui/screens/account_list_screen.dart +++ b/lib/ui/screens/account_list_screen.dart @@ -11,15 +11,7 @@ class AccountListScreen extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { return Scaffold( - appBar: AppBar( - title: const Text('SharedInbox'), - actions: [ - IconButton( - icon: const Icon(Icons.settings), - onPressed: () => context.push('/settings'), - ), - ], - ), + appBar: AppBar(title: const Text('SharedInbox')), body: StreamBuilder( stream: ref.watch(accountRepositoryProvider).observeAccounts(), builder: (ctx, snap) { @@ -104,6 +96,10 @@ class _AccountTile extends ConsumerWidget { value: _AccountAction.allMailboxes, child: Text('All mailboxes'), ), + PopupMenuItem( + value: _AccountAction.syncLog, + child: Text('Sync log'), + ), PopupMenuItem( value: _AccountAction.edit, child: Text('Edit'), @@ -127,6 +123,8 @@ class _AccountTile extends ConsumerWidget { switch (action) { case _AccountAction.allMailboxes: await context.push('/accounts/${account.id}/mailboxes'); + case _AccountAction.syncLog: + await context.push('/accounts/${account.id}/sync-log'); case _AccountAction.edit: await context.push('/accounts/${account.id}/edit'); case _AccountAction.delete: @@ -158,4 +156,4 @@ class _AccountTile extends ConsumerWidget { } } -enum _AccountAction { allMailboxes, edit, delete } +enum _AccountAction { allMailboxes, syncLog, edit, delete } diff --git a/lib/ui/screens/settings_screen.dart b/lib/ui/screens/settings_screen.dart deleted file mode 100644 index 000a88c..0000000 --- a/lib/ui/screens/settings_screen.dart +++ /dev/null @@ -1,76 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:go_router/go_router.dart'; - -import '../../di.dart'; - -class SettingsScreen extends ConsumerWidget { - const SettingsScreen({super.key}); - - @override - Widget build(BuildContext context, WidgetRef ref) { - final repo = ref.watch(accountRepositoryProvider); - return Scaffold( - appBar: AppBar(title: const Text('Settings')), - body: StreamBuilder( - stream: repo.observeAccounts(), - builder: (ctx, snap) { - final accounts = snap.data ?? []; - return ListView( - children: [ - const ListTile( - title: Text( - 'Accounts', - style: TextStyle(fontWeight: FontWeight.bold), - ), - ), - for (final a in accounts) - ListTile( - leading: const Icon(Icons.account_circle), - title: Text(a.displayName), - subtitle: Text(a.email), - trailing: Row( - mainAxisSize: MainAxisSize.min, - children: [ - IconButton( - icon: const Icon(Icons.history), - tooltip: 'Sync log', - onPressed: () => ctx.push('/accounts/${a.id}/sync-log'), - ), - IconButton( - icon: const Icon(Icons.delete), - onPressed: () async { - final confirm = await showDialog( - context: ctx, - builder: (ctx) => AlertDialog( - title: const Text('Remove account?'), - content: Text( - 'Remove ${a.displayName}? Local data will be deleted.', - ), - actions: [ - TextButton( - onPressed: () => Navigator.pop(ctx, false), - child: const Text('Cancel'), - ), - FilledButton( - onPressed: () => Navigator.pop(ctx, true), - child: const Text('Remove'), - ), - ], - ), - ); - if (confirm == true) { - await repo.removeAccount(a.id); - } - }, - ), - ], - ), - ), - ], - ); - }, - ), - ); - } -} diff --git a/test/widget/account_list_screen_test.dart b/test/widget/account_list_screen_test.dart index fdbd1b4..fc82c5b 100644 --- a/test/widget/account_list_screen_test.dart +++ b/test/widget/account_list_screen_test.dart @@ -85,18 +85,6 @@ void main() { expect(find.text('SharedInbox'), findsOneWidget); }); - testWidgets('tapping settings icon navigates to /settings', (tester) async { - await tester.pumpWidget( - buildApp(initialLocation: '/accounts', overrides: baseOverrides()), - ); - await tester.pumpAndSettle(); - - await tester.tap(find.byIcon(Icons.settings)); - await tester.pumpAndSettle(); - - expect(find.text('Settings'), findsOneWidget); - }); - testWidgets( '"Add account" button in empty state navigates to add-account screen', (tester) async { diff --git a/test/widget/helpers.dart b/test/widget/helpers.dart index 0eea50b..3b5c513 100644 --- a/test/widget/helpers.dart +++ b/test/widget/helpers.dart @@ -27,7 +27,6 @@ import 'package:sharedinbox/ui/screens/edit_account_screen.dart'; import 'package:sharedinbox/ui/screens/email_detail_screen.dart'; import 'package:sharedinbox/ui/screens/email_list_screen.dart'; import 'package:sharedinbox/ui/screens/mailbox_list_screen.dart'; -import 'package:sharedinbox/ui/screens/settings_screen.dart'; // --------------------------------------------------------------------------- // Fake repositories @@ -298,10 +297,6 @@ Widget buildApp({ ); }, ), - GoRoute( - path: '/settings', - builder: (ctx, state) => const SettingsScreen(), - ), ], ); diff --git a/test/widget/settings_screen_test.dart b/test/widget/settings_screen_test.dart deleted file mode 100644 index ddf36c7..0000000 --- a/test/widget/settings_screen_test.dart +++ /dev/null @@ -1,121 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import 'package:sharedinbox/di.dart'; - -import 'helpers.dart'; - -void main() { - group('SettingsScreen', () { - testWidgets('shows "Accounts" section header', (tester) async { - await tester.pumpWidget( - buildApp( - initialLocation: '/settings', - overrides: [ - accountRepositoryProvider - .overrideWithValue(FakeAccountRepository()), - mailboxRepositoryProvider - .overrideWithValue(FakeMailboxRepository()), - emailRepositoryProvider.overrideWithValue(FakeEmailRepository()), - ], - ), - ); - await tester.pumpAndSettle(); - - expect(find.text('Accounts'), findsOneWidget); - }); - - testWidgets('shows account tile when an account exists', (tester) async { - await tester.pumpWidget( - buildApp( - initialLocation: '/settings', - overrides: [ - accountRepositoryProvider - .overrideWithValue(FakeAccountRepository([kTestAccount])), - mailboxRepositoryProvider - .overrideWithValue(FakeMailboxRepository()), - emailRepositoryProvider.overrideWithValue(FakeEmailRepository()), - ], - ), - ); - await tester.pumpAndSettle(); - - expect(find.text('Alice'), findsOneWidget); - expect(find.text('alice@example.com'), findsOneWidget); - }); - - testWidgets('tapping delete icon shows confirmation dialog', - (tester) async { - await tester.pumpWidget( - buildApp( - initialLocation: '/settings', - overrides: [ - accountRepositoryProvider - .overrideWithValue(FakeAccountRepository([kTestAccount])), - mailboxRepositoryProvider - .overrideWithValue(FakeMailboxRepository()), - emailRepositoryProvider.overrideWithValue(FakeEmailRepository()), - ], - ), - ); - await tester.pumpAndSettle(); - - await tester.tap(find.byIcon(Icons.delete)); - await tester.pumpAndSettle(); - - expect(find.text('Remove account?'), findsOneWidget); - expect(find.text('Cancel'), findsOneWidget); - expect(find.text('Remove'), findsOneWidget); - }); - - testWidgets('tapping Remove in the confirmation dialog calls removeAccount', - (tester) async { - await tester.pumpWidget( - buildApp( - initialLocation: '/settings', - overrides: [ - accountRepositoryProvider - .overrideWithValue(FakeAccountRepository([kTestAccount])), - mailboxRepositoryProvider - .overrideWithValue(FakeMailboxRepository()), - emailRepositoryProvider.overrideWithValue(FakeEmailRepository()), - ], - ), - ); - await tester.pumpAndSettle(); - - await tester.tap(find.byIcon(Icons.delete)); - await tester.pumpAndSettle(); - await tester.tap(find.text('Remove')); - await tester.pumpAndSettle(); - - // Dialog dismissed after confirmation. - expect(find.text('Remove account?'), findsNothing); - }); - - testWidgets('tapping Cancel in the confirmation dialog dismisses it', - (tester) async { - await tester.pumpWidget( - buildApp( - initialLocation: '/settings', - overrides: [ - accountRepositoryProvider - .overrideWithValue(FakeAccountRepository([kTestAccount])), - mailboxRepositoryProvider - .overrideWithValue(FakeMailboxRepository()), - emailRepositoryProvider.overrideWithValue(FakeEmailRepository()), - ], - ), - ); - await tester.pumpAndSettle(); - - await tester.tap(find.byIcon(Icons.delete)); - await tester.pumpAndSettle(); - await tester.tap(find.text('Cancel')); - await tester.pumpAndSettle(); - - expect(find.text('Remove account?'), findsNothing); - expect(find.text('Alice'), findsOneWidget); // account still visible - }); - }); -}