Skip to content

Commit 52a8954

Browse files
committed
app: On launch, go to the last visited account
Fixes: #524
1 parent f26d2fc commit 52a8954

File tree

5 files changed

+145
-16
lines changed

5 files changed

+145
-16
lines changed

lib/widgets/app.dart

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -211,14 +211,13 @@ class _ZulipAppState extends State<ZulipApp> with WidgetsBindingObserver {
211211
];
212212
}
213213

214-
final globalStore = GlobalStoreWidget.of(context);
215-
// TODO(#524) choose initial account as last one used
216-
final initialAccountId = globalStore.accounts.firstOrNull?.id;
214+
final lastAccountId = GlobalStoreWidget.settingsOf(context)
215+
.getInt(IntGlobalSetting.lastVisitedAccountId);
217216
return [
218-
if (initialAccountId == null)
217+
if (lastAccountId == null)
219218
MaterialWidgetRoute(page: const ChooseAccountPage())
220219
else
221-
HomePage.buildRoute(accountId: initialAccountId),
220+
HomePage.buildRoute(accountId: lastAccountId),
222221
];
223222
}
224223

test/notifications/open_test.dart

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import 'package:zulip/host/notifications.dart';
1010
import 'package:zulip/model/database.dart';
1111
import 'package:zulip/model/localizations.dart';
1212
import 'package:zulip/model/narrow.dart';
13+
import 'package:zulip/model/settings.dart';
1314
import 'package:zulip/notifications/open.dart';
1415
import 'package:zulip/notifications/receive.dart';
1516
import 'package:zulip/widgets/app.dart';
@@ -20,6 +21,7 @@ import 'package:zulip/widgets/page.dart';
2021
import '../example_data.dart' as eg;
2122
import '../model/binding.dart';
2223
import '../model/narrow_checks.dart';
24+
import '../model/store_checks.dart';
2325
import '../stdlib_checks.dart';
2426
import '../test_navigation.dart';
2527
import '../widgets/checks.dart';
@@ -190,23 +192,41 @@ void main() {
190192
testWidgets('stream message', (tester) async {
191193
addTearDown(testBinding.reset);
192194
await testBinding.globalStore.add(eg.selfAccount, eg.initialSnapshot());
195+
await testBinding.globalStore.settings
196+
.setInt(IntGlobalSetting.lastVisitedAccountId, eg.selfAccount.id);
193197
await prepare(tester);
194198
await checkOpenNotification(tester, eg.selfAccount, eg.streamMessage());
195199
}, variant: const TargetPlatformVariant({TargetPlatform.android, TargetPlatform.iOS}));
196200

197201
testWidgets('direct message', (tester) async {
198202
addTearDown(testBinding.reset);
199203
await testBinding.globalStore.add(eg.selfAccount, eg.initialSnapshot());
204+
await testBinding.globalStore.settings
205+
.setInt(IntGlobalSetting.lastVisitedAccountId, eg.selfAccount.id);
200206
await prepare(tester);
201207
await checkOpenNotification(tester, eg.selfAccount,
202208
eg.dmMessage(from: eg.otherUser, to: [eg.selfUser]));
203209
}, variant: const TargetPlatformVariant({TargetPlatform.android, TargetPlatform.iOS}));
204210

211+
testWidgets('changes last visited account', (tester) async {
212+
addTearDown(testBinding.reset);
213+
await testBinding.globalStore.add(eg.selfAccount, eg.initialSnapshot());
214+
await testBinding.globalStore.add(eg.otherAccount, eg.initialSnapshot());
215+
await testBinding.globalStore.settings
216+
.setInt(IntGlobalSetting.lastVisitedAccountId, eg.selfAccount.id);
217+
await prepare(tester);
218+
await checkOpenNotification(tester, eg.otherAccount, eg.streamMessage());
219+
check(testBinding.globalStore.settings)
220+
.getInt(IntGlobalSetting.lastVisitedAccountId).equals(eg.otherAccount.id);
221+
}, variant: const TargetPlatformVariant({TargetPlatform.android, TargetPlatform.iOS}));
222+
205223
testWidgets('account queried by realmUrl origin component', (tester) async {
206224
addTearDown(testBinding.reset);
207225
await testBinding.globalStore.add(
208226
eg.selfAccount.copyWith(realmUrl: Uri.parse('http://chat.example')),
209227
eg.initialSnapshot());
228+
await testBinding.globalStore.settings
229+
.setInt(IntGlobalSetting.lastVisitedAccountId, eg.selfAccount.id);
210230
await prepare(tester);
211231

212232
await checkOpenNotification(tester,
@@ -230,6 +250,8 @@ void main() {
230250
testWidgets('mismatching account', (tester) async {
231251
addTearDown(testBinding.reset);
232252
await testBinding.globalStore.add(eg.selfAccount, eg.initialSnapshot());
253+
await testBinding.globalStore.settings
254+
.setInt(IntGlobalSetting.lastVisitedAccountId, eg.selfAccount.id);
233255
await prepare(tester);
234256
await openNotification(tester, eg.otherAccount, eg.streamMessage());
235257
await tester.pump();
@@ -254,6 +276,8 @@ void main() {
254276
for (final account in accounts) {
255277
await testBinding.globalStore.add(account, eg.initialSnapshot());
256278
}
279+
await testBinding.globalStore.settings
280+
.setInt(IntGlobalSetting.lastVisitedAccountId, eg.selfAccount.id);
257281
await prepare(tester);
258282

259283
await checkOpenNotification(tester, accounts[0], eg.streamMessage());
@@ -265,6 +289,8 @@ void main() {
265289
testWidgets('wait for app to become ready', (tester) async {
266290
addTearDown(testBinding.reset);
267291
await testBinding.globalStore.add(eg.selfAccount, eg.initialSnapshot());
292+
await testBinding.globalStore.settings
293+
.setInt(IntGlobalSetting.lastVisitedAccountId, eg.selfAccount.id);
268294
await prepare(tester, early: true);
269295
final message = eg.streamMessage();
270296
await openNotification(tester, eg.selfAccount, message);

test/widgets/app_test.dart

Lines changed: 103 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import 'package:flutter_test/flutter_test.dart';
66
import 'package:zulip/log.dart';
77
import 'package:zulip/model/actions.dart';
88
import 'package:zulip/model/database.dart';
9+
import 'package:zulip/model/settings.dart';
910
import 'package:zulip/widgets/app.dart';
1011
import 'package:zulip/widgets/home.dart';
1112
import 'package:zulip/widgets/page.dart';
@@ -43,18 +44,31 @@ void main() {
4344
]);
4445
});
4546

46-
testWidgets('when have accounts, go to home page for first account', (tester) async {
47-
// We'll need per-account data for the account that a page will be opened
48-
// for, but not for the other account.
49-
await testBinding.globalStore.add(eg.selfAccount, eg.initialSnapshot());
50-
await testBinding.globalStore.insertAccount(eg.otherAccount.toCompanion(false));
51-
await prepare(tester);
47+
group('when have accounts', () {
48+
testWidgets('with no last account visited, go to choose account', (tester) async {
49+
await testBinding.globalStore.add(eg.selfAccount, eg.initialSnapshot());
50+
check(testBinding.globalStore.settings)
51+
.getInt(IntGlobalSetting.lastVisitedAccountId).isNull();
52+
await prepare(tester);
5253

53-
check(pushedRoutes).deepEquals(<Condition<Object?>>[
54-
(it) => it.isA<MaterialAccountWidgetRoute>()
55-
..accountId.equals(eg.selfAccount.id)
56-
..page.isA<HomePage>(),
57-
]);
54+
check(pushedRoutes).deepEquals(<Condition<Object?>>[
55+
(it) => it.isA<WidgetRoute>().page.isA<ChooseAccountPage>(),
56+
]);
57+
});
58+
59+
testWidgets('with last account visited, go to home page for last account', (tester) async {
60+
await testBinding.globalStore.add(eg.selfAccount, eg.initialSnapshot());
61+
await testBinding.globalStore.add(eg.otherAccount, eg.initialSnapshot());
62+
await testBinding.globalStore.settings
63+
.setInt(IntGlobalSetting.lastVisitedAccountId, eg.otherAccount.id);
64+
await prepare(tester);
65+
66+
check(pushedRoutes).deepEquals(<Condition<Object?>>[
67+
(it) => it.isA<MaterialAccountWidgetRoute>()
68+
..accountId.equals(eg.otherAccount.id)
69+
..page.isA<HomePage>(),
70+
]);
71+
});
5872
});
5973
});
6074

@@ -82,6 +96,8 @@ void main() {
8296

8397
testWidgets('push route when removing last route on stack', (tester) async {
8498
await testBinding.globalStore.add(eg.selfAccount, eg.initialSnapshot());
99+
await testBinding.globalStore.settings
100+
.setInt(IntGlobalSetting.lastVisitedAccountId, eg.selfAccount.id);
85101
await prepare(tester);
86102
// The navigator stack should contain only a home page route.
87103

@@ -99,6 +115,8 @@ void main() {
99115
testWidgets('push route when popping last route on stack', (tester) async {
100116
// Set up the loading of per-account data to fail.
101117
await testBinding.globalStore.insertAccount(eg.selfAccount.toCompanion(false));
118+
await testBinding.globalStore.settings
119+
.setInt(IntGlobalSetting.lastVisitedAccountId, eg.selfAccount.id);
102120
testBinding.globalStore.loadPerAccountDuration = Duration.zero;
103121
testBinding.globalStore.loadPerAccountException = eg.apiExceptionUnauthorized();
104122
await prepare(tester);
@@ -133,6 +151,8 @@ void main() {
133151
const loadPerAccountDuration = Duration(seconds: 30);
134152
assert(loadPerAccountDuration > kTryAnotherAccountWaitPeriod);
135153
await testBinding.globalStore.insertAccount(eg.selfAccount.toCompanion(false));
154+
await testBinding.globalStore.settings
155+
.setInt(IntGlobalSetting.lastVisitedAccountId, eg.selfAccount.id);
136156
testBinding.globalStore.loadPerAccountDuration = loadPerAccountDuration;
137157
testBinding.globalStore.loadPerAccountException = eg.apiExceptionUnauthorized();
138158
await prepare(tester);
@@ -282,6 +302,8 @@ void main() {
282302
addTearDown(testBinding.reset);
283303
await testBinding.globalStore.add(eg.selfAccount, eg.initialSnapshot());
284304
await testBinding.globalStore.add(eg.otherAccount, eg.initialSnapshot());
305+
await testBinding.globalStore.settings
306+
.setInt(IntGlobalSetting.lastVisitedAccountId, eg.selfAccount.id);
285307

286308
final pushedRoutes = <Route<void>>[];
287309
final poppedRoutes = <Route<void>>[];
@@ -318,6 +340,47 @@ void main() {
318340
..page.isA<HomePage>();
319341
});
320342

343+
group('choosing an account changes the last visited account', () {
344+
testWidgets('first null, then changes to the chosen account', (tester) async {
345+
addTearDown(testBinding.reset);
346+
await testBinding.globalStore.add(eg.selfAccount, eg.initialSnapshot());
347+
348+
await tester.pumpWidget(ZulipApp());
349+
await tester.pump();
350+
351+
check(testBinding.globalStore.settings)
352+
.getInt(IntGlobalSetting.lastVisitedAccountId).isNull();
353+
await tester.tap(find.text(eg.selfAccount.email));
354+
await tester.pump();
355+
check(testBinding.globalStore.settings)
356+
.getInt(IntGlobalSetting.lastVisitedAccountId).equals(eg.selfAccount.id);
357+
});
358+
359+
testWidgets('first non-null, then changes to the chosen account', (tester) async {
360+
addTearDown(testBinding.reset);
361+
await testBinding.globalStore.add(eg.selfAccount, eg.initialSnapshot());
362+
await testBinding.globalStore.add(eg.otherAccount, eg.initialSnapshot());
363+
await testBinding.globalStore.settings
364+
.setInt(IntGlobalSetting.lastVisitedAccountId, eg.selfAccount.id);
365+
366+
await tester.pumpWidget(ZulipApp());
367+
await tester.pump();
368+
369+
final navigator = await ZulipApp.navigator;
370+
unawaited(navigator.push(
371+
MaterialWidgetRoute(page: const ChooseAccountPage())));
372+
await tester.pump();
373+
await tester.pump();
374+
375+
check(testBinding.globalStore.settings)
376+
.getInt(IntGlobalSetting.lastVisitedAccountId).equals(eg.selfAccount.id);
377+
await tester.tap(find.text(eg.otherAccount.email));
378+
await tester.pump();
379+
check(testBinding.globalStore.settings)
380+
.getInt(IntGlobalSetting.lastVisitedAccountId).equals(eg.otherAccount.id);
381+
});
382+
});
383+
321384
group('log out', () {
322385
Future<(Widget, Widget)> prepare(WidgetTester tester, {
323386
required List<Account> accounts,
@@ -360,6 +423,35 @@ void main() {
360423
await tester.pumpAndSettle();
361424
check(testBinding.globalStore).accounts.deepEquals([eg.selfAccount]);
362425
});
426+
427+
group('last visited account', () {
428+
testWidgets('is the logged out one -> last account set to null', (tester) async {
429+
await testBinding.globalStore.settings
430+
.setInt(IntGlobalSetting.lastVisitedAccountId, eg.selfAccount.id);
431+
432+
final (actionButton, _) = await prepare(tester,
433+
accounts: [eg.selfAccount, eg.otherAccount], logoutAccount: eg.selfAccount);
434+
await tester.tap(find.byWidget(actionButton));
435+
await tester.pump(TestGlobalStore.removeAccountDuration);
436+
check(testBinding.globalStore)
437+
..accounts.deepEquals([eg.otherAccount])
438+
..settings.getInt(IntGlobalSetting.lastVisitedAccountId).isNull();
439+
});
440+
441+
testWidgets('is not the logged out one -> last account not changed', (tester) async {
442+
await testBinding.globalStore.settings
443+
.setInt(IntGlobalSetting.lastVisitedAccountId, eg.otherAccount.id);
444+
445+
final (actionButton, _) = await prepare(tester,
446+
accounts: [eg.selfAccount, eg.otherAccount], logoutAccount: eg.selfAccount);
447+
await tester.tap(find.byWidget(actionButton));
448+
await tester.pump(TestGlobalStore.removeAccountDuration);
449+
check(testBinding.globalStore)
450+
..accounts.deepEquals([eg.otherAccount])
451+
..settings.getInt(IntGlobalSetting.lastVisitedAccountId)
452+
.equals(eg.otherAccount.id);
453+
});
454+
});
363455
});
364456
});
365457

test/widgets/home_test.dart

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import 'package:flutter_checks/flutter_checks.dart';
44
import 'package:flutter_test/flutter_test.dart';
55
import 'package:zulip/model/actions.dart';
66
import 'package:zulip/model/narrow.dart';
7+
import 'package:zulip/model/settings.dart';
78
import 'package:zulip/model/store.dart';
89
import 'package:zulip/widgets/about_zulip.dart';
910
import 'package:zulip/widgets/app.dart';
@@ -277,6 +278,8 @@ void main () {
277278
pushedRoutes = [];
278279
lastPoppedRoute = null;
279280
await testBinding.globalStore.add(eg.selfAccount, eg.initialSnapshot());
281+
await testBinding.globalStore.settings
282+
.setInt(IntGlobalSetting.lastVisitedAccountId, eg.selfAccount.id);
280283

281284
await tester.pumpWidget(ZulipApp(navigatorObservers: [testNavObserver]));
282285
final store = await testBinding.globalStore.perAccount(eg.selfAccount.id);
@@ -334,6 +337,8 @@ void main () {
334337
lastPoppedRoute = null;
335338
await testBinding.globalStore.add(eg.selfAccount, eg.initialSnapshot());
336339
await testBinding.globalStore.add(eg.otherAccount, eg.initialSnapshot());
340+
await testBinding.globalStore.settings
341+
.setInt(IntGlobalSetting.lastVisitedAccountId, eg.selfAccount.id);
337342
await tester.pumpWidget(ZulipApp(navigatorObservers: [testNavObserver]));
338343
await tester.pump(Duration.zero); // wait for the loading page
339344
checkOnLoadingPage();
@@ -523,6 +528,8 @@ void main () {
523528
// Regression test for: https://github.com/zulip/zulip-flutter/issues/1219
524529
addTearDown(testBinding.reset);
525530
await testBinding.globalStore.add(eg.selfAccount, eg.initialSnapshot());
531+
await testBinding.globalStore.settings
532+
.setInt(IntGlobalSetting.lastVisitedAccountId, eg.selfAccount.id);
526533
await tester.pumpWidget(const ZulipApp());
527534
await tester.pump(); // wait for the loading page
528535
checkOnLoadingPage();
@@ -539,6 +546,8 @@ void main () {
539546
// Regression test for: https://github.com/zulip/zulip-flutter/issues/1219
540547
addTearDown(testBinding.reset);
541548
await testBinding.globalStore.add(eg.selfAccount, eg.initialSnapshot());
549+
await testBinding.globalStore.settings
550+
.setInt(IntGlobalSetting.lastVisitedAccountId, eg.selfAccount.id);
542551
await tester.pumpWidget(const ZulipApp());
543552
await tester.pump(); // wait for the loading page
544553
await tester.pump(); // wait for store

test/widgets/login_test.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import 'package:zulip/api/route/realm.dart';
1212
import 'package:zulip/model/binding.dart';
1313
import 'package:zulip/model/database.dart';
1414
import 'package:zulip/model/localizations.dart';
15+
import 'package:zulip/model/settings.dart';
1516
import 'package:zulip/widgets/app.dart';
1617
import 'package:zulip/widgets/home.dart';
1718
import 'package:zulip/widgets/login.dart';
@@ -262,6 +263,8 @@ void main() {
262263

263264
testWidgets('logging into a second account', (tester) async {
264265
await testBinding.globalStore.add(eg.selfAccount, eg.initialSnapshot());
266+
await testBinding.globalStore.settings
267+
.setInt(IntGlobalSetting.lastVisitedAccountId, eg.selfAccount.id);
265268
final serverSettings = eg.serverSettings();
266269
await prepare(tester, serverSettings);
267270
check(poppedRoutes).isEmpty();

0 commit comments

Comments
 (0)