Skip to content

Commit d08dcd3

Browse files
committed
fix: show top-level dialog as global singleton in home page wrapper
Move UpdateCubit listener with `showDialog` from outside MaterialApp to the builder of StatefulShellRoute, the HomePage there is a global singleton that carries global singleton listeners, as we did before.
1 parent ba1be30 commit d08dcd3

File tree

3 files changed

+106
-95
lines changed

3 files changed

+106
-95
lines changed

lib/app.dart

Lines changed: 0 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,11 @@
11
import 'dart:async';
2-
import 'dart:math' as math;
32

43
import 'package:flutter/material.dart';
54
import 'package:flutter_bloc/flutter_bloc.dart';
65
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
76
import 'package:flutter_localizations/flutter_localizations.dart';
8-
import 'package:flutter_markdown/flutter_markdown.dart';
97
import 'package:flutter_styled_toast/flutter_styled_toast.dart';
10-
import 'package:go_router/go_router.dart';
11-
import 'package:tsdm_client/constants/layout.dart';
128
import 'package:tsdm_client/extensions/build_context.dart';
13-
import 'package:tsdm_client/extensions/string.dart';
149
import 'package:tsdm_client/features/authentication/repository/authentication_repository.dart';
1510
import 'package:tsdm_client/features/cache/bloc/image_cache_trigger_cubit.dart';
1611
import 'package:tsdm_client/features/cache/repository/image_cache_repository.dart';
@@ -31,7 +26,6 @@ import 'package:tsdm_client/features/notification/repository/notification_reposi
3126
import 'package:tsdm_client/features/profile/repository/profile_repository.dart';
3227
import 'package:tsdm_client/features/root/bloc/points_changes_cubit.dart';
3328
import 'package:tsdm_client/features/root/bloc/root_location_cubit.dart';
34-
import 'package:tsdm_client/features/root/view/root_page.dart';
3529
import 'package:tsdm_client/features/settings/bloc/settings_bloc.dart';
3630
import 'package:tsdm_client/features/settings/repositories/settings_repository.dart';
3731
import 'package:tsdm_client/features/theme/cubit/theme_cubit.dart';
@@ -47,12 +41,10 @@ import 'package:tsdm_client/shared/providers/storage_provider/storage_provider.d
4741
import 'package:tsdm_client/shared/repositories/forum_home_repository/forum_home_repository.dart';
4842
import 'package:tsdm_client/shared/repositories/fragments_repository/fragments_repository.dart';
4943
import 'package:tsdm_client/themes/app_themes.dart';
50-
import 'package:tsdm_client/utils/git_info.dart';
5144
import 'package:tsdm_client/utils/logger.dart';
5245
import 'package:tsdm_client/utils/platform.dart';
5346
import 'package:tsdm_client/utils/show_dialog.dart';
5447
import 'package:tsdm_client/utils/show_toast.dart';
55-
import 'package:tsdm_client/widgets/custom_alert_dialog.dart';
5648
import 'package:window_manager/window_manager.dart';
5749

5850
extension _SignedInteger on int {
@@ -369,69 +361,6 @@ class _AppState extends State<App> with WindowListener, LoggerMixin {
369361
}
370362
},
371363
),
372-
BlocListener<UpdateCubit, UpdateCubitState>(
373-
listenWhen: (prev, curr) => !curr.loading && prev.loading,
374-
listener: (context, state) async {
375-
final info = state.latestVersionInfo;
376-
final tr = context.t.updatePage;
377-
if (info == null) {
378-
error('failed to check update state');
379-
if (state.notice) {
380-
showSnackBar(context: context, message: tr.failed);
381-
}
382-
return;
383-
}
384-
385-
final inUpdatePage = context.read<RootLocationCubit>().isIn(ScreenPaths.update);
386-
387-
if (info.versionCode <= appVersion.split('+').last.parseToInt()!) {
388-
// Only show the already latest message in update page.
389-
if (inUpdatePage) {
390-
showSnackBar(context: context, message: tr.alreadyLatest);
391-
}
392-
} else {
393-
final gotoUpdatePage = await showDialog<bool>(
394-
context: context,
395-
builder: (context) {
396-
final size = MediaQuery.sizeOf(context);
397-
return RootPage(
398-
DialogPaths.updateNotice,
399-
CustomAlertDialog.sync(
400-
title: Text(tr.availableDialog.title),
401-
content: SizedBox(
402-
width: math.min(size.width * 0.8, 800),
403-
height: math.min(size.height * 0.6, 600),
404-
child: Column(
405-
crossAxisAlignment: CrossAxisAlignment.start,
406-
children: [
407-
Text(
408-
tr.availableDialog.version(version: info.version),
409-
style: Theme.of(
410-
context,
411-
).textTheme.labelMedium?.copyWith(color: Theme.of(context).colorScheme.primary),
412-
),
413-
sizedBoxW8H8,
414-
Expanded(child: Markdown(data: info.changelog)),
415-
],
416-
),
417-
),
418-
actions: [
419-
TextButton(child: Text(context.t.general.cancel), onPressed: () => context.pop(false)),
420-
TextButton(
421-
child: Text(context.t.settingsPage.othersSection.update),
422-
onPressed: () => context.pop(true),
423-
),
424-
],
425-
),
426-
);
427-
},
428-
);
429-
if (true == gotoUpdatePage && context.mounted && !inUpdatePage) {
430-
await router.pushNamed(ScreenPaths.update);
431-
}
432-
}
433-
},
434-
),
435364
BlocListener<PointsChangesCubit, PointsChangesValue>(
436365
listenWhen: (prev, curr) => prev != curr && curr != PointsChangesValue.empty,
437366
listener: (context, state) {

lib/features/home/view/home_page.dart

Lines changed: 105 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
import 'dart:async';
2+
import 'dart:math' as math;
23

34
import 'package:flutter/material.dart';
45
import 'package:flutter_bloc/flutter_bloc.dart';
56
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
7+
import 'package:flutter_markdown/flutter_markdown.dart';
68
import 'package:go_router/go_router.dart';
79
import 'package:responsive_framework/responsive_framework.dart';
810
import 'package:tsdm_client/constants/layout.dart';
11+
import 'package:tsdm_client/extensions/string.dart';
912
import 'package:tsdm_client/features/authentication/repository/authentication_repository.dart';
1013
import 'package:tsdm_client/features/home/cubit/home_cubit.dart';
1114
import 'package:tsdm_client/features/home/cubit/init_cubit.dart';
@@ -14,16 +17,24 @@ import 'package:tsdm_client/features/local_notice/keys.dart';
1417
import 'package:tsdm_client/features/local_notice/stream.dart';
1518
import 'package:tsdm_client/features/notification/models/models.dart';
1619
import 'package:tsdm_client/features/root/bloc/root_location_cubit.dart';
20+
import 'package:tsdm_client/features/root/view/root_page.dart';
21+
import 'package:tsdm_client/features/update/cubit/update_cubit.dart';
1722
import 'package:tsdm_client/i18n/strings.g.dart';
1823
import 'package:tsdm_client/instance.dart';
24+
import 'package:tsdm_client/routes/app_routes.dart';
1925
import 'package:tsdm_client/routes/screen_paths.dart';
26+
import 'package:tsdm_client/utils/git_info.dart';
2027
import 'package:tsdm_client/utils/logger.dart';
2128
import 'package:tsdm_client/utils/platform.dart';
29+
import 'package:tsdm_client/utils/show_toast.dart';
30+
import 'package:tsdm_client/widgets/custom_alert_dialog.dart';
2231
import 'package:tsdm_client/widgets/indicator.dart';
2332

2433
const _drawerWidth = 250.0;
2534

2635
/// Page of the homepage of the app.
36+
///
37+
// Partial global singleton page, provides global functionalities.
2738
class HomePage extends StatefulWidget {
2839
/// Constructor.
2940
const HomePage({required this.showNavigationBar, required this.child, super.key});
@@ -146,30 +157,100 @@ class _HomePageState extends State<HomePage> with LoggerMixin {
146157

147158
return MultiBlocProvider(
148159
providers: [BlocProvider(create: (_) => HomeCubit())],
149-
child: BlocBuilder<InitCubit, InitState>(
150-
builder: (context, state) {
151-
if (state.clearingOutdatedImageCache) {
152-
return const CenteredCircularIndicator();
153-
}
154-
155-
if (ResponsiveBreakpoints.of(context).largerThan(WindowSize.expanded.name)) {
156-
return _buildDrawerBody(context);
157-
} else if (ResponsiveBreakpoints.of(context).largerThan(WindowSize.compact.name)) {
158-
return Scaffold(
159-
body: Row(
160-
children: [
161-
if (widget.showNavigationBar) const HomeNavigationRail(),
162-
Expanded(child: widget.child),
163-
],
164-
),
165-
);
166-
} else {
167-
return Scaffold(
168-
body: widget.child,
169-
bottomNavigationBar: widget.showNavigationBar ? const HomeNavigationBar() : null,
170-
);
171-
}
172-
},
160+
child: MultiBlocListener(
161+
listeners: [
162+
BlocListener<UpdateCubit, UpdateCubitState>(
163+
listenWhen: (prev, curr) => !curr.loading && prev.loading,
164+
listener: (context, state) async {
165+
final info = state.latestVersionInfo;
166+
final tr = context.t.updatePage;
167+
if (info == null) {
168+
error('failed to check update state');
169+
if (state.notice) {
170+
showSnackBar(context: context, message: tr.failed);
171+
}
172+
return;
173+
}
174+
175+
final inUpdatePage = context.read<RootLocationCubit>().isIn(ScreenPaths.update);
176+
177+
if (info.versionCode <= appVersion.split('+').last.parseToInt()!) {
178+
// Only show the already latest message in update page.
179+
if (inUpdatePage) {
180+
showSnackBar(context: context, message: tr.alreadyLatest);
181+
}
182+
} else {
183+
final gotoUpdatePage = await showDialog<bool>(
184+
context: context,
185+
builder: (context) {
186+
final size = MediaQuery.sizeOf(context);
187+
return RootPage(
188+
DialogPaths.updateNotice,
189+
CustomAlertDialog.sync(
190+
title: Text(tr.availableDialog.title),
191+
content: SizedBox(
192+
width: math.min(size.width * 0.8, 800),
193+
height: math.min(size.height * 0.6, 600),
194+
child: Column(
195+
crossAxisAlignment: CrossAxisAlignment.start,
196+
children: [
197+
Text(
198+
tr.availableDialog.version(version: info.version),
199+
style: Theme.of(
200+
context,
201+
).textTheme.labelMedium?.copyWith(color: Theme.of(context).colorScheme.primary),
202+
),
203+
sizedBoxW8H8,
204+
Expanded(child: Markdown(data: info.changelog)),
205+
],
206+
),
207+
),
208+
actions: [
209+
TextButton(
210+
child: Text(context.t.general.cancel),
211+
onPressed: () => context.pop(false),
212+
),
213+
TextButton(
214+
child: Text(context.t.settingsPage.othersSection.update),
215+
onPressed: () => context.pop(true),
216+
),
217+
],
218+
),
219+
);
220+
},
221+
);
222+
if (true == gotoUpdatePage && context.mounted && !inUpdatePage) {
223+
await router.pushNamed(ScreenPaths.update);
224+
}
225+
}
226+
},
227+
),
228+
],
229+
child: BlocBuilder<InitCubit, InitState>(
230+
builder: (context, state) {
231+
if (state.clearingOutdatedImageCache) {
232+
return const CenteredCircularIndicator();
233+
}
234+
235+
if (ResponsiveBreakpoints.of(context).largerThan(WindowSize.expanded.name)) {
236+
return _buildDrawerBody(context);
237+
} else if (ResponsiveBreakpoints.of(context).largerThan(WindowSize.compact.name)) {
238+
return Scaffold(
239+
body: Row(
240+
children: [
241+
if (widget.showNavigationBar) const HomeNavigationRail(),
242+
Expanded(child: widget.child),
243+
],
244+
),
245+
);
246+
} else {
247+
return Scaffold(
248+
body: widget.child,
249+
bottomNavigationBar: widget.showNavigationBar ? const HomeNavigationBar() : null,
250+
);
251+
}
252+
},
253+
),
173254
),
174255
);
175256
}

lib/routes/app_routes.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ final List<RouteBase> _appRoutes = [
6060
StatefulShellRoute.indexedStack(
6161
builder: (context, router, navigator) {
6262
final hideNavigationBarPages = [ScreenPaths.settingsThreadAppearance.fullPath];
63+
// Partial global singleton page here.
6364
return HomePage(showNavigationBar: !hideNavigationBarPages.contains(router.fullPath), child: navigator);
6465
},
6566
branches: [

0 commit comments

Comments
 (0)