Skip to content

Commit 0d7c395

Browse files
committed
refactor(status): revamp UpdateRequiredPage for better usability
- Add platform-specific update buttons for iOS and Android - Implement conditional rendering for web platform - Improve UI with better spacing and styling - Remove dependency on AppBloc for update URLs - Update imports and remove unused packages
1 parent 88427cd commit 0d7c395

File tree

1 file changed

+86
-71
lines changed

1 file changed

+86
-71
lines changed

lib/status/view/update_required_page.dart

Lines changed: 86 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,87 +1,102 @@
1+
import 'package:flutter/foundation.dart' show kIsWeb;
12
import 'package:flutter/material.dart';
2-
import 'package:flutter_bloc/flutter_bloc.dart';
3-
import 'package:flutter_news_app_mobile_client_full_source_code/app/bloc/app_bloc.dart';
4-
import 'package:flutter_news_app_mobile_client_full_source_code/l10n/app_localizations.dart';
5-
import 'package:ui_kit/ui_kit.dart';
3+
import 'package:flutter_news_app_mobile_client_full_source_code/l10n/l10n.dart';
4+
import 'package:ui_kit/ui_kit.dart' hide UiKitL10n;
65
import 'package:url_launcher/url_launcher.dart';
76

8-
/// A page displayed to the user when a mandatory app update is required.
7+
/// {@template update_required_page}
8+
/// A full-screen page displayed when a mandatory application update is required.
99
///
10-
/// This page informs the user that they must update the application to the
11-
/// latest version to continue using it. It provides a button that links
12-
/// directly to the appropriate app store page by fetching the URL from the
13-
/// remote configuration.
10+
/// This page informs the user about the need to update and provides links
11+
/// to the appropriate app stores (iOS, Android). On web, it displays a
12+
/// generic message as direct app store links are not applicable.
13+
/// {@endtemplate}
1414
class UpdateRequiredPage extends StatelessWidget {
1515
/// {@macro update_required_page}
16-
const UpdateRequiredPage({super.key});
16+
const UpdateRequiredPage({
17+
required this.iosUpdateUrl,
18+
required this.androidUpdateUrl,
19+
super.key,
20+
});
1721

18-
/// Attempts to launch the given URL in an external application (e.g., browser
19-
/// or app store).
20-
///
21-
/// Shows a [SnackBar] with an error message if the URL cannot be launched.
22-
Future<void> _launchUrl(BuildContext context, String url) async {
23-
// Ensure the URL is not empty before attempting to parse.
24-
if (url.isEmpty) {
25-
ScaffoldMessenger.of(context)
26-
..hideCurrentSnackBar()
27-
..showSnackBar(
28-
// TODO(fulleni): localize later.
29-
const SnackBar(content: Text('Update URL is not available.')),
30-
);
31-
return;
32-
}
22+
/// The URL to open for iOS app updates.
23+
final String iosUpdateUrl;
3324

34-
final uri = Uri.parse(url);
35-
if (await canLaunchUrl(uri)) {
36-
// Launch the URL externally. This will open the App Store, Play Store,
37-
// or a browser.
38-
await launchUrl(uri, mode: LaunchMode.externalApplication);
39-
} else {
40-
// If the URL can't be launched, inform the user.
41-
// ignore: use_build_context_synchronously
42-
ScaffoldMessenger.of(context)
43-
..hideCurrentSnackBar()
44-
..showSnackBar(
45-
SnackBar(content: Text('Could not open update URL: $url')),
46-
);
47-
}
48-
}
25+
/// The URL to open for Android app updates.
26+
final String androidUpdateUrl;
4927

5028
@override
5129
Widget build(BuildContext context) {
52-
final l10n = AppLocalizations.of(context);
53-
54-
// This is the robust, production-ready way to get the update URL.
55-
// It uses BlocProvider.of(context) to access the AppBloc instance and
56-
// determines the correct URL based on the current platform (iOS/Android).
57-
// It falls back to an empty string if the remote config is not available.
58-
final appBloc = BlocProvider.of<AppBloc>(context);
59-
final updateUrl = Theme.of(context).platform == TargetPlatform.android
60-
? appBloc.state.remoteConfig?.appStatus.androidUpdateUrl
61-
: appBloc.state.remoteConfig?.appStatus.iosUpdateUrl;
30+
final l10n = context.l10n;
31+
final theme = Theme.of(context);
6232

6333
return Scaffold(
64-
body: Padding(
65-
padding: const EdgeInsets.all(AppSpacing.lg),
66-
child: Column(
67-
mainAxisAlignment: MainAxisAlignment.center,
68-
children: [
69-
// Reusing the InitialStateWidget for a consistent UI.
70-
InitialStateWidget(
71-
icon: Icons.system_update_alt,
72-
headline: l10n.updateRequiredHeadline,
73-
subheadline: l10n.updateRequiredSubheadline,
74-
),
75-
const SizedBox(height: AppSpacing.lg),
76-
// The button to direct the user to the app store.
77-
// It's disabled if the update URL is not available.
78-
ElevatedButton(
79-
onPressed: updateUrl != null && updateUrl.isNotEmpty
80-
? () => _launchUrl(context, updateUrl)
81-
: null,
82-
child: Text(l10n.updateRequiredButton),
83-
),
84-
],
34+
body: Center(
35+
child: Padding(
36+
padding: const EdgeInsets.all(AppSpacing.lg),
37+
child: Column(
38+
mainAxisAlignment: MainAxisAlignment.center,
39+
children: [
40+
Icon(
41+
Icons.system_update_alt,
42+
size: 80,
43+
color: theme.colorScheme.primary,
44+
),
45+
const SizedBox(height: AppSpacing.xl),
46+
Text(
47+
l10n.updateRequiredHeadline,
48+
style: theme.textTheme.headlineMedium,
49+
textAlign: TextAlign.center,
50+
),
51+
const SizedBox(height: AppSpacing.md),
52+
Text(
53+
l10n.updateRequiredSubheadline,
54+
style: theme.textTheme.bodyLarge,
55+
textAlign: TextAlign.center,
56+
),
57+
const SizedBox(height: AppSpacing.xl),
58+
if (!kIsWeb) ...[
59+
// Show platform-specific update buttons for mobile
60+
if (Theme.of(context).platform == TargetPlatform.iOS &&
61+
iosUpdateUrl.isNotEmpty)
62+
Padding(
63+
padding: const EdgeInsets.only(bottom: AppSpacing.md),
64+
child: ElevatedButton.icon(
65+
onPressed: () async {
66+
final url = Uri.parse(iosUpdateUrl);
67+
if (await canLaunchUrl(url)) {
68+
await launchUrl(url);
69+
}
70+
},
71+
icon: const Icon(Icons.apple),
72+
label: Text(l10n.updateRequiredButton),
73+
),
74+
),
75+
if (Theme.of(context).platform == TargetPlatform.android &&
76+
androidUpdateUrl.isNotEmpty)
77+
Padding(
78+
padding: const EdgeInsets.only(bottom: AppSpacing.md),
79+
child: ElevatedButton.icon(
80+
onPressed: () async {
81+
final url = Uri.parse(androidUpdateUrl);
82+
if (await canLaunchUrl(url)) {
83+
await launchUrl(url);
84+
}
85+
},
86+
icon: const Icon(Icons.shop),
87+
label: Text(l10n.updateRequiredButton),
88+
),
89+
),
90+
] else ...[
91+
// Generic message for web
92+
Text(
93+
l10n.updateRequiredButton,
94+
style: theme.textTheme.bodyMedium,
95+
textAlign: TextAlign.center,
96+
),
97+
],
98+
],
99+
),
85100
),
86101
),
87102
);

0 commit comments

Comments
 (0)