@@ -8,7 +8,9 @@ class FotaWarningPage extends StatelessWidget {
88 const FotaWarningPage ({super .key});
99
1010 Future <void > _openGitHubLink () async {
11- final uri = Uri .parse ('https://github.com/OpenEarable/open-earable-2?tab=readme-ov-file#setup' );
11+ final uri = Uri .parse (
12+ 'https://github.com/OpenEarable/open-earable-2?tab=readme-ov-file#setup' ,
13+ );
1214 if (await canLaunchUrl (uri)) {
1315 await launchUrl (uri, mode: LaunchMode .platformDefault);
1416 } else {
@@ -20,6 +22,7 @@ class FotaWarningPage extends StatelessWidget {
2022 Widget build (BuildContext context) {
2123 final theme = Theme .of (context);
2224 final textTheme = theme.textTheme;
25+ final baseTextStyle = textTheme.bodyLarge; // one place to define size
2326
2427 return PlatformScaffold (
2528 appBar: PlatformAppBar (
@@ -31,130 +34,156 @@ class FotaWarningPage extends StatelessWidget {
3134 child: Center (
3235 child: ConstrainedBox (
3336 constraints: const BoxConstraints (maxWidth: 600 ),
34- child: Column (
35- crossAxisAlignment: CrossAxisAlignment .start,
36- children: [
37- // Header with warning icon
38- Row (
39- crossAxisAlignment: CrossAxisAlignment .center,
40- children: [
41- Icon (
42- Icons .warning_amber_rounded,
43- color: theme.colorScheme.error,
44- size: 32 ,
45- ),
46- const SizedBox (width: 12 ),
47- Text (
48- 'Warning' ,
49- style: textTheme.headlineSmall? .copyWith (
50- fontWeight: FontWeight .bold,
51- ),
52- ),
53- ],
54- ),
55- const SizedBox (height: 16 ),
56-
57- // First paragraph with hyperlink
58- Text .rich (
59- TextSpan (
60- style: textTheme.bodyMedium? .copyWith (fontSize: 16 ),
37+ child: DefaultTextStyle .merge ( // <<– base style for everything
38+ style: baseTextStyle ?? const TextStyle (fontSize: 16 ),
39+ child: Column (
40+ crossAxisAlignment: CrossAxisAlignment .start,
41+ children: [
42+ // Header with warning icon
43+ Row (
44+ crossAxisAlignment: CrossAxisAlignment .center,
6145 children: [
62- const TextSpan (
63- text :
64- 'Sometimes, updating OpenEarable over Bluetooth might not complete successfully. '
65- 'If that happens, you can easily perform a manual update with the help of a J-Link debugger (see ' ,
46+ Icon (
47+ Icons .warning_amber_rounded,
48+ color : theme.colorScheme.error,
49+ size : 32 ,
6650 ),
67- TextSpan (
68- text : 'GitHub instructions' ,
69- style : const TextStyle (
70- color : Colors .blue,
71- decoration : TextDecoration .underline,
72- ) ,
73- recognizer : TapGestureRecognizer ()
74- ..onTap = _openGitHubLink ,
51+ const SizedBox (width : 12 ),
52+ Text (
53+ 'Warning' ,
54+ style : (baseTextStyle ?? const TextStyle ())
55+ . copyWith (
56+ fontWeight : FontWeight .bold ,
57+ fontSize : (baseTextStyle ? .fontSize ?? 16 ) + 2 ,
58+ ) ,
7559 ),
76- const TextSpan (text: ').' ),
7760 ],
7861 ),
79- ),
80- const SizedBox (height: 16 ),
81-
82- Text (
83- 'To help ensure a smooth update, please:' ,
84- style: textTheme.bodyMedium? .copyWith (
85- fontSize: 16 ,
86- fontWeight: FontWeight .w600,
87- ),
88- ),
89- const SizedBox (height: 12 ),
62+ const SizedBox (height: 16 ),
9063
91- // Steps in a Card
92- Card (
93- elevation: 2 ,
94- margin: EdgeInsets .zero,
95- child: Padding (
96- padding: const EdgeInsets .symmetric (
97- horizontal: 16 ,
98- vertical: 12 ,
99- ),
100- child: Column (
101- crossAxisAlignment: CrossAxisAlignment .start,
102- children: const [
103- _NumberedStep (
104- number: '1.' ,
105- text:
106- 'Power cycle your OpenEarable once before you update.' ,
107- ),
108- SizedBox (height: 8 ),
109- _NumberedStep (
110- number: '2.' ,
111- text:
112- 'Keep the app open in the foreground and make sure your phone doesn’t enter power-saving mode.' ,
113- ),
114- SizedBox (height: 8 ),
115- _NumberedStep (
116- number: '3.' ,
117- text:
118- 'Charge your OpenEarable fully before starting.' ,
119- ),
120- SizedBox (height: 8 ),
121- _NumberedStep (
122- number: '4.' ,
64+ // First paragraph with hyperlink
65+ Text .rich (
66+ TextSpan (
67+ style: baseTextStyle,
68+ children: [
69+ const TextSpan (
12370 text:
124- 'If you have two devices, power off the one that’s not being updated.' ,
71+ 'Updating OpenEarable via Bluetooth is currently an experimental feature. '
72+ 'Hence, updating OpenEarable over Bluetooth might sometimes not complete successfully. '
73+ 'If that happens, you can easily perform a manual update with the help of a J-Link debugger (see ' ,
12574 ),
126- SizedBox (height: 8 ),
127- _NumberedStep (
128- number: '5.' ,
129- text:
130- 'After the firmware is uploaded, OpenEarable will automatically verify it. '
131- 'During this step, the device might seem unresponsive for up to 3 minutes. '
132- 'Don’t worry, this is normal. It will start blinking again once the process is complete. '
133- 'Don‘t reset the device via the button while the firmware is verified by OpenEarable.' ,
75+ TextSpan (
76+ text: 'GitHub instructions' ,
77+ style: const TextStyle (
78+ color: Colors .blue,
79+ decoration: TextDecoration .underline,
80+ fontWeight: FontWeight .w600,
81+ ),
82+ recognizer: TapGestureRecognizer ()
83+ ..onTap = _openGitHubLink,
13484 ),
85+ const TextSpan (text: ').' ),
13586 ],
13687 ),
13788 ),
138- ),
89+ const SizedBox (height : 16 ),
13990
140- const SizedBox (height: 24 ),
91+ Text (
92+ 'To help ensure a smooth update, please:' ,
93+ style: baseTextStyle? .copyWith (
94+ fontWeight: FontWeight .w600,
95+ ),
96+ ),
97+ const SizedBox (height: 12 ),
14198
142- // Proceed button
143- SizedBox (
144- width: double .infinity,
145- child: PlatformElevatedButton (
146- onPressed: () {
147- Navigator .of (context).push (
148- platformPageRoute (
149- context: context,
150- builder: (_) => const FirmwareUpdateWidget (),
151- ),
152- );
153- },
154- child: const Text ('Accept Risks and Proceed' ),
99+ // Steps in a Card
100+ Card (
101+ elevation: 2 ,
102+ margin: EdgeInsets .zero,
103+ child: Padding (
104+ padding: const EdgeInsets .symmetric (
105+ horizontal: 16 ,
106+ vertical: 12 ,
107+ ),
108+ child: Column (
109+ crossAxisAlignment: CrossAxisAlignment .start,
110+ children: const [
111+ _NumberedStep (
112+ number: '1.' ,
113+ text: TextSpan (
114+ text:
115+ 'Power cycle your OpenEarable once before you update.' ,
116+ ),
117+ ),
118+ SizedBox (height: 8 ),
119+ _NumberedStep (
120+ number: '2.' ,
121+ text: TextSpan (
122+ text:
123+ 'Keep the app open in the foreground and make sure your phone doesn’t enter power-saving mode.' ,
124+ ),
125+ ),
126+ SizedBox (height: 8 ),
127+ _NumberedStep (
128+ number: '3.' ,
129+ text: TextSpan (
130+ text:
131+ 'Charge your OpenEarable fully before starting.' ,
132+ ),
133+ ),
134+ SizedBox (height: 8 ),
135+ _NumberedStep (
136+ number: '4.' ,
137+ text: TextSpan (
138+ text:
139+ 'If you have two devices, power off the one that’s not being updated.' ,
140+ ),
141+ ),
142+ SizedBox (height: 8 ),
143+ _NumberedStep (
144+ number: '5.' ,
145+ text: TextSpan (
146+ children: [
147+ TextSpan (
148+ text:
149+ 'After the firmware is uploaded, OpenEarable will automatically verify it. '
150+ 'During this step, the device might seem unresponsive for up to 3 minutes. '
151+ 'Don’t worry, this is normal. It will start blinking again once the process is complete.\n ' ,
152+ ),
153+ TextSpan (
154+ text:
155+ 'Don‘t reset the device via the button while the firmware is verified by OpenEarable.' ,
156+ style: TextStyle (
157+ fontWeight: FontWeight .bold,
158+ ),
159+ ),
160+ ],
161+ ),
162+ ),
163+ ],
164+ ),
165+ ),
155166 ),
156- ),
157- ],
167+
168+ const SizedBox (height: 24 ),
169+
170+ // Proceed button
171+ SizedBox (
172+ width: double .infinity,
173+ child: PlatformElevatedButton (
174+ onPressed: () {
175+ Navigator .of (context).push (
176+ platformPageRoute (
177+ context: context,
178+ builder: (_) => const FirmwareUpdateWidget (),
179+ ),
180+ );
181+ },
182+ child: const Text ('Acknowledge and Proceed' ),
183+ ),
184+ ),
185+ ],
186+ ),
158187 ),
159188 ),
160189 ),
@@ -167,7 +196,7 @@ class FotaWarningPage extends StatelessWidget {
167196/// Helper widget for cleanly aligned numbered steps
168197class _NumberedStep extends StatelessWidget {
169198 final String number;
170- final String text;
199+ final InlineSpan text; // now accepts TextSpan / InlineSpan
171200
172201 const _NumberedStep ({
173202 required this .number,
@@ -176,19 +205,23 @@ class _NumberedStep extends StatelessWidget {
176205
177206 @override
178207 Widget build (BuildContext context) {
179- final textStyle = Theme .of (context).textTheme.bodyMedium? .copyWith (fontSize: 16 );
208+ final baseStyle = Theme .of (context).textTheme.bodyLarge ??
209+ const TextStyle (fontSize: 16 );
210+
180211 return Row (
181212 crossAxisAlignment: CrossAxisAlignment .start,
182213 children: [
183214 Text (
184215 number,
185- style: textStyle ? .copyWith (fontWeight: FontWeight .bold),
216+ style: baseStyle .copyWith (fontWeight: FontWeight .bold),
186217 ),
187218 const SizedBox (width: 8 ),
188219 Expanded (
189- child: Text (
190- text,
191- style: textStyle,
220+ child: RichText (
221+ text: TextSpan (
222+ style: baseStyle,
223+ children: [text],
224+ ),
192225 ),
193226 ),
194227 ],
0 commit comments