Skip to content

Commit 8aff54a

Browse files
authored
Update navigation handling so pages keep state when switching between them. (#118)
* Update navigation handling so pages keep state when switching between them. * Change to refresh individual pages rather than app wide refresh. Add refresh on profile switch.
1 parent d14b50b commit 8aff54a

File tree

10 files changed

+71
-16
lines changed

10 files changed

+71
-16
lines changed

lib/src/app.dart

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,28 @@ class App extends StatefulWidget {
2626

2727
class _AppState extends State<App> {
2828
int _navIndex = 0;
29+
final PageController _pageController = PageController();
30+
Key _feedKey = UniqueKey();
31+
Key _exploreKey = UniqueKey();
32+
Key _accountKey = UniqueKey();
2933

3034
void _changeNav(int newIndex) {
3135
setState(() {
3236
_navIndex = newIndex;
3337
});
38+
_pageController.jumpToPage(_navIndex);
3439
}
3540

3641
@override
3742
Widget build(BuildContext context) {
3843
final appController = context.watch<AppController>();
44+
appController.refreshState = () {
45+
setState(() {
46+
_feedKey = UniqueKey();
47+
_exploreKey = UniqueKey();
48+
_accountKey = UniqueKey();
49+
});
50+
};
3951

4052
final intlLocale =
4153
intl_locale.Locale.tryParse(appController.profile.appLanguage);
@@ -189,12 +201,16 @@ class _AppState extends State<App> {
189201
width: 1,
190202
),
191203
Expanded(
192-
child: const [
193-
FeedScreen(),
194-
ExploreScreen(),
195-
AccountScreen(),
196-
SettingsScreen(),
197-
][_navIndex]),
204+
child: PageView(
205+
controller: _pageController,
206+
children: [
207+
FeedScreen(key: _feedKey),
208+
ExploreScreen(key: _exploreKey),
209+
AccountScreen(key: _accountKey),
210+
SettingsScreen(),
211+
],
212+
)
213+
),
198214
]),
199215
);
200216
},

lib/src/controller/controller.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,10 @@ class AppController with ChangeNotifier {
7272
late Map<String, FilterList> _filterLists;
7373
Map<String, FilterList> get filterLists => _filterLists;
7474

75+
late Function refreshState;
76+
7577
Future<void> init() async {
78+
refreshState = (){};
7679
final mainProfileTemp = await _mainProfileRecord.get(db) as String?;
7780
if (mainProfileTemp != null) {
7881
_mainProfile = mainProfileTemp;
@@ -134,6 +137,7 @@ class AppController with ChangeNotifier {
134137
_builtProfile = ProfileRequired.fromOptional(
135138
(await getProfile(_mainProfile)).merge(_selectedProfileValue),
136139
);
140+
refreshState();
137141
}
138142

139143
Future<void> updateProfile(ProfileOptional value) async {
@@ -346,6 +350,7 @@ class AppController with ChangeNotifier {
346350
magazineMentionCache.clear();
347351

348352
notifyListeners();
353+
refreshState();
349354

350355
await _selectedAccountRecord.put(db, _selectedAccount);
351356
}

lib/src/screens/account/account_screen.dart

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,14 @@ class AccountScreen extends StatefulWidget {
1717
State<AccountScreen> createState() => _AccountScreenState();
1818
}
1919

20-
class _AccountScreenState extends State<AccountScreen> {
20+
class _AccountScreenState extends State<AccountScreen> with AutomaticKeepAliveClientMixin<AccountScreen> {
21+
22+
@override
23+
bool get wantKeepAlive => true;
24+
2125
@override
2226
Widget build(BuildContext context) {
27+
super.build(context);
2328
return whenLoggedIn(
2429
context,
2530
context.read<AppController>().serverSoftware == ServerSoftware.lemmy

lib/src/screens/account/messages/messages_screen.dart

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,13 @@ class MessagesScreen extends StatefulWidget {
1616
State<MessagesScreen> createState() => _MessagesScreenState();
1717
}
1818

19-
class _MessagesScreenState extends State<MessagesScreen> {
19+
class _MessagesScreenState extends State<MessagesScreen> with AutomaticKeepAliveClientMixin<MessagesScreen> {
2020
final PagingController<String, MessageThreadModel> _pagingController =
2121
PagingController(firstPageKey: '');
2222

23+
@override
24+
bool get wantKeepAlive => true;
25+
2326
@override
2427
void initState() {
2528
super.initState();
@@ -51,6 +54,7 @@ class _MessagesScreenState extends State<MessagesScreen> {
5154

5255
@override
5356
Widget build(BuildContext context) {
57+
super.build(context);
5458
return RefreshIndicator(
5559
onRefresh: () => Future.sync(
5660
() => _pagingController.refresh(),

lib/src/screens/account/notification/notification_screen.dart

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,15 @@ class NotificationsScreen extends StatefulWidget {
2020
State<NotificationsScreen> createState() => _NotificationsScreenState();
2121
}
2222

23-
class _NotificationsScreenState extends State<NotificationsScreen> {
23+
class _NotificationsScreenState extends State<NotificationsScreen> with AutomaticKeepAliveClientMixin<NotificationsScreen> {
2424
NotificationsFilter filter = NotificationsFilter.all;
2525

2626
final PagingController<String, NotificationModel> _pagingController =
2727
PagingController(firstPageKey: '');
2828

29+
@override
30+
bool get wantKeepAlive => true;
31+
2932
@override
3033
void initState() {
3134
super.initState();
@@ -62,6 +65,7 @@ class _NotificationsScreenState extends State<NotificationsScreen> {
6265

6366
@override
6467
Widget build(BuildContext context) {
68+
super.build(context);
6569
final currentNotificationFilter =
6670
notificationFilterSelect(context).getOption(filter);
6771

lib/src/screens/account/self_feed.dart

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,12 @@ class SelfFeed extends StatefulWidget {
1212
State<SelfFeed> createState() => _SelfFeedState();
1313
}
1414

15-
class _SelfFeedState extends State<SelfFeed> {
15+
class _SelfFeedState extends State<SelfFeed> with AutomaticKeepAliveClientMixin<SelfFeed> {
1616
UserModel? _meUser;
1717

18+
@override
19+
bool get wantKeepAlive => true;
20+
1821
@override
1922
void initState() {
2023
super.initState();
@@ -33,6 +36,7 @@ class _SelfFeedState extends State<SelfFeed> {
3336

3437
@override
3538
Widget build(BuildContext context) {
39+
super.build(context);
3640
if (_meUser == null) {
3741
return const LoadingTemplate();
3842
}

lib/src/screens/explore/explore_screen.dart

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class ExploreScreen extends StatefulWidget {
2020
State<ExploreScreen> createState() => _ExploreScreenState();
2121
}
2222

23-
class _ExploreScreenState extends State<ExploreScreen> {
23+
class _ExploreScreenState extends State<ExploreScreen> with AutomaticKeepAliveClientMixin<ExploreScreen> {
2424
String search = '';
2525
final searchDebounce = Debouncer(duration: const Duration(milliseconds: 500));
2626

@@ -32,6 +32,9 @@ class _ExploreScreenState extends State<ExploreScreen> {
3232
final PagingController<String, dynamic> _pagingController =
3333
PagingController(firstPageKey: '');
3434

35+
@override
36+
bool get wantKeepAlive => true;
37+
3538
@override
3639
void initState() {
3740
super.initState();
@@ -132,6 +135,7 @@ class _ExploreScreenState extends State<ExploreScreen> {
132135

133136
@override
134137
Widget build(BuildContext context) {
138+
super.build(context);
135139
const chipPadding = EdgeInsets.symmetric(vertical: 6, horizontal: 4);
136140

137141
final currentExploreSort = exploreSortSelection(context).getOption(sort);

lib/src/screens/explore/user_screen.dart

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -466,10 +466,13 @@ class UserScreenBody extends StatefulWidget {
466466
State<UserScreenBody> createState() => _UserScreenBodyState();
467467
}
468468

469-
class _UserScreenBodyState extends State<UserScreenBody> {
469+
class _UserScreenBodyState extends State<UserScreenBody> with AutomaticKeepAliveClientMixin<UserScreenBody> {
470470
final PagingController<String, dynamic> _pagingController =
471471
PagingController(firstPageKey: '');
472472

473+
@override
474+
bool get wantKeepAlive => true;
475+
473476
@override
474477
void didUpdateWidget(covariant oldWidget) {
475478
super.didUpdateWidget(oldWidget);
@@ -577,6 +580,7 @@ class _UserScreenBodyState extends State<UserScreenBody> {
577580

578581
@override
579582
Widget build(BuildContext context) {
583+
super.build(context);
580584
return RefreshIndicator(
581585
onRefresh: () => Future.sync(() => _pagingController.refresh()),
582586
child: CustomScrollView(

lib/src/screens/feed/feed_screen.dart

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,16 @@ class FeedScreen extends StatefulWidget {
3939
State<FeedScreen> createState() => _FeedScreenState();
4040
}
4141

42-
class _FeedScreenState extends State<FeedScreen> {
42+
class _FeedScreenState extends State<FeedScreen> with AutomaticKeepAliveClientMixin<FeedScreen> {
4343
final _fabKey = GlobalKey<FloatingMenuState>();
4444
final List<GlobalKey<_FeedScreenBodyState>> _feedKeyList = [];
4545
late FeedSource _filter;
4646
late PostType _mode;
4747
FeedSort? _sort;
4848

49+
@override
50+
bool get wantKeepAlive => true;
51+
4952
_getFeedKey(int index) {
5053
while (index >= _feedKeyList.length) {
5154
_feedKeyList.add(GlobalKey());
@@ -73,6 +76,7 @@ class _FeedScreenState extends State<FeedScreen> {
7376

7477
@override
7578
Widget build(BuildContext context) {
79+
super.build(context);
7680
final sort = _sort ?? _defaultSortFromMode(_mode);
7781

7882
final currentFeedModeOption = feedTypeSelect(context).getOption(_mode);
@@ -574,7 +578,7 @@ class FeedScreenBody extends StatefulWidget {
574578
State<FeedScreenBody> createState() => _FeedScreenBodyState();
575579
}
576580

577-
class _FeedScreenBodyState extends State<FeedScreenBody> {
581+
class _FeedScreenBodyState extends State<FeedScreenBody> with AutomaticKeepAliveClientMixin<FeedScreenBody> {
578582
final _pagingController =
579583
PagingController<String, PostModel>(firstPageKey: '');
580584
final _scrollController = ScrollController();
@@ -590,6 +594,9 @@ class _FeedScreenBodyState extends State<FeedScreenBody> {
590594
_pagingController.addPageRequestListener(_fetchPage);
591595
}
592596

597+
@override
598+
bool get wantKeepAlive => true;
599+
593600
Future<void> _fetchPage(String pageKey) async {
594601
if (pageKey.isEmpty) _filterListWarnings.clear();
595602

@@ -700,6 +707,7 @@ class _FeedScreenBodyState extends State<FeedScreenBody> {
700707

701708
@override
702709
Widget build(BuildContext context) {
710+
super.build(context);
703711
return RefreshIndicator(
704712
onRefresh: () => Future.sync(
705713
() => _pagingController.refresh(),

lib/src/utils/utils.dart

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -197,13 +197,14 @@ class DefaultTabControllerListener extends StatefulWidget {
197197

198198
class _DefaultTabControllerListenerState
199199
extends State<DefaultTabControllerListener> {
200-
late final void Function()? _listener;
200+
void Function()? _listener;
201201
TabController? _tabController;
202202

203203
@override
204204
void initState() {
205205
super.initState();
206206
WidgetsBinding.instance.addPostFrameCallback((_) {
207+
if (!mounted) return;
207208
final tabController = DefaultTabController.of(context);
208209
_listener = () {
209210
if (tabController.indexIsChanging) {
@@ -228,7 +229,7 @@ class _DefaultTabControllerListenerState
228229
@override
229230
void dispose() {
230231
if (_listener != null && _tabController != null) {
231-
_tabController!.removeListener(_listener);
232+
_tabController!.removeListener(_listener!);
232233
}
233234
super.dispose();
234235
}

0 commit comments

Comments
 (0)