Skip to content

Commit 0611e0e

Browse files
committed
add manual verification handling
1 parent cc57e5b commit 0611e0e

2 files changed

Lines changed: 224 additions & 94 deletions

File tree

lib/ui/components/active_downloads_widget.dart

Lines changed: 112 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,16 @@ class ActiveDownloadsWidget extends ConsumerWidget {
6262
color: Theme.of(context).colorScheme.surface,
6363
borderRadius: BorderRadius.circular(12),
6464
border: Border.all(
65-
color: Theme.of(context).colorScheme.outline.withValues(alpha: 0.2),
65+
color:
66+
Theme.of(context).colorScheme.outline.withValues(alpha: 0.2),
6667
width: 1.5,
6768
),
6869
boxShadow: [
6970
BoxShadow(
70-
color: Theme.of(context).colorScheme.shadow.withValues(alpha: 0.08),
71+
color: Theme.of(context)
72+
.colorScheme
73+
.shadow
74+
.withValues(alpha: 0.08),
7175
blurRadius: 10,
7276
offset: const Offset(0, 3),
7377
),
@@ -79,7 +83,10 @@ class ActiveDownloadsWidget extends ConsumerWidget {
7983
Container(
8084
padding: const EdgeInsets.all(14.0),
8185
decoration: BoxDecoration(
82-
color: Theme.of(context).colorScheme.secondary.withValues(alpha: 0.1),
86+
color: Theme.of(context)
87+
.colorScheme
88+
.secondary
89+
.withValues(alpha: 0.1),
8390
borderRadius: const BorderRadius.only(
8491
topLeft: Radius.circular(12),
8592
topRight: Radius.circular(12),
@@ -103,7 +110,8 @@ class ActiveDownloadsWidget extends ConsumerWidget {
103110
),
104111
const SizedBox(width: 6),
105112
Container(
106-
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
113+
padding: const EdgeInsets.symmetric(
114+
horizontal: 8, vertical: 2),
107115
decoration: BoxDecoration(
108116
color: Theme.of(context).colorScheme.secondary,
109117
borderRadius: BorderRadius.circular(12),
@@ -132,7 +140,10 @@ class ActiveDownloadsWidget extends ConsumerWidget {
132140
separatorBuilder: (context, index) => Divider(
133141
height: 1,
134142
thickness: 0.5,
135-
color: Theme.of(context).colorScheme.outline.withValues(alpha: 0.2),
143+
color: Theme.of(context)
144+
.colorScheme
145+
.outline
146+
.withValues(alpha: 0.2),
136147
),
137148
itemBuilder: (context, index) {
138149
final task = downloads.values.elementAt(index);
@@ -154,7 +165,7 @@ class ActiveDownloadsWidget extends ConsumerWidget {
154165
}
155166
}
156167

157-
class _DownloadItem extends ConsumerWidget {
168+
class _DownloadItem extends ConsumerStatefulWidget {
158169
final DownloadTask task;
159170
final String Function(int) bytesToFileSize;
160171
final String Function(DownloadStatus) getStatusText;
@@ -166,8 +177,76 @@ class _DownloadItem extends ConsumerWidget {
166177
});
167178

168179
@override
169-
Widget build(BuildContext context, WidgetRef ref) {
180+
ConsumerState<_DownloadItem> createState() => _DownloadItemState();
181+
}
182+
183+
class _DownloadItemState extends ConsumerState<_DownloadItem> {
184+
// Track if auto-verification has been triggered
185+
bool _autoVerificationTriggered = false;
186+
187+
@override
188+
void initState() {
189+
super.initState();
190+
// Auto-trigger verification if manual verification is required
191+
_checkAndTriggerAutoVerification();
192+
}
193+
194+
@override
195+
void didUpdateWidget(_DownloadItem oldWidget) {
196+
super.didUpdateWidget(oldWidget);
197+
// Check again if task status changed
198+
if (oldWidget.task.status != widget.task.status) {
199+
_checkAndTriggerAutoVerification();
200+
}
201+
}
202+
203+
// Automatically trigger verification when manual verification is required
204+
void _checkAndTriggerAutoVerification() {
205+
if (_autoVerificationTriggered) return;
206+
207+
final task = widget.task;
208+
if (task.status == DownloadStatus.failed &&
209+
task.errorMessage?.contains('Manual verification required') == true &&
210+
task.mirrorUrl != null) {
211+
_autoVerificationTriggered = true;
212+
// Use post-frame callback to ensure context is ready
213+
WidgetsBinding.instance.addPostFrameCallback((_) {
214+
if (mounted) {
215+
_triggerVerification();
216+
}
217+
});
218+
}
219+
}
220+
221+
// Open webview for manual verification with visible countdown/CAPTCHA
222+
Future<void> _triggerVerification() async {
223+
final task = widget.task;
224+
if (task.mirrorUrl == null) return;
225+
226+
final downloadManager = ref.read(downloadManagerProvider);
227+
228+
final List<String>? mirrors = await Navigator.push(
229+
context,
230+
MaterialPageRoute(
231+
builder: (BuildContext context) => Webview(
232+
url: task.mirrorUrl!,
233+
showOverlay: false, // Show full page for CAPTCHA interaction
234+
),
235+
),
236+
);
237+
238+
if (mirrors != null && mirrors.isNotEmpty && mounted) {
239+
// Update task with fetched mirrors and restart download
240+
final updatedTask = task.copyWith(mirrors: mirrors);
241+
downloadManager.removeDownload(task.id);
242+
await downloadManager.addDownload(updatedTask);
243+
}
244+
}
245+
246+
@override
247+
Widget build(BuildContext context) {
170248
final downloadManager = ref.read(downloadManagerProvider);
249+
final task = widget.task;
171250

172251
return Padding(
173252
padding: const EdgeInsets.symmetric(horizontal: 14.0, vertical: 12.0),
@@ -182,7 +261,8 @@ class _DownloadItem extends ConsumerWidget {
182261
width: 36,
183262
height: 36,
184263
decoration: BoxDecoration(
185-
color: _getStatusColor(task.status, context).withValues(alpha: 0.15),
264+
color: _getStatusColor(task.status, context)
265+
.withValues(alpha: 0.15),
186266
borderRadius: BorderRadius.circular(8),
187267
),
188268
child: Center(
@@ -208,7 +288,7 @@ class _DownloadItem extends ConsumerWidget {
208288
Row(
209289
children: [
210290
Text(
211-
getStatusText(task.status),
291+
widget.getStatusText(task.status),
212292
style: TextStyle(
213293
fontSize: 11,
214294
fontWeight: FontWeight.w500,
@@ -254,7 +334,8 @@ class _DownloadItem extends ConsumerWidget {
254334
icon: Icon(
255335
Icons.close_rounded,
256336
size: 20,
257-
color: Theme.of(context).colorScheme.tertiary.withAlpha(170),
337+
color:
338+
Theme.of(context).colorScheme.tertiary.withAlpha(170),
258339
),
259340
onPressed: () {
260341
downloadManager.cancelDownload(task.id);
@@ -290,11 +371,12 @@ class _DownloadItem extends ConsumerWidget {
290371
),
291372
),
292373
Text(
293-
'${bytesToFileSize(task.downloadedBytes)} / ${bytesToFileSize(task.totalBytes)}',
374+
'${widget.bytesToFileSize(task.downloadedBytes)} / ${widget.bytesToFileSize(task.totalBytes)}',
294375
style: TextStyle(
295376
fontSize: 10,
296377
fontWeight: FontWeight.w500,
297-
color: Theme.of(context).colorScheme.tertiary.withAlpha(140),
378+
color:
379+
Theme.of(context).colorScheme.tertiary.withAlpha(140),
298380
),
299381
),
300382
],
@@ -313,10 +395,12 @@ class _DownloadItem extends ConsumerWidget {
313395
),
314396
),
315397
] else if (task.status == DownloadStatus.failed) ...[
316-
if (task.errorMessage?.contains('Manual verification required') == true) ...[
398+
if (task.errorMessage?.contains('Manual verification required') ==
399+
true) ...[
317400
// Show "Verify" button for manual verification required error
318401
Container(
319-
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6),
402+
padding:
403+
const EdgeInsets.symmetric(horizontal: 10, vertical: 6),
320404
decoration: BoxDecoration(
321405
color: Colors.orange.withValues(alpha: 0.1),
322406
borderRadius: BorderRadius.circular(6),
@@ -346,17 +430,22 @@ class _DownloadItem extends ConsumerWidget {
346430
const SizedBox(width: 8),
347431
TextButton(
348432
onPressed: () async {
349-
// Open webview for manual verification
433+
// Open webview for manual verification with full page visibility
350434
if (task.mirrorUrl != null) {
351435
final List<String>? mirrors = await Navigator.push(
352436
context,
353437
MaterialPageRoute(
354-
builder: (BuildContext context) =>
355-
Webview(url: task.mirrorUrl!),
438+
builder: (BuildContext context) => Webview(
439+
url: task.mirrorUrl!,
440+
showOverlay:
441+
false, // Show full page for CAPTCHA
442+
),
356443
),
357444
);
358-
359-
if (mirrors != null && mirrors.isNotEmpty && context.mounted) {
445+
446+
if (mirrors != null &&
447+
mirrors.isNotEmpty &&
448+
context.mounted) {
360449
// Update task with fetched mirrors and restart download
361450
final updatedTask = task.copyWith(mirrors: mirrors);
362451
downloadManager.removeDownload(task.id);
@@ -366,7 +455,8 @@ class _DownloadItem extends ConsumerWidget {
366455
},
367456
style: TextButton.styleFrom(
368457
backgroundColor: Colors.orange,
369-
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4),
458+
padding: const EdgeInsets.symmetric(
459+
horizontal: 12, vertical: 4),
370460
minimumSize: Size.zero,
371461
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
372462
),
@@ -385,7 +475,8 @@ class _DownloadItem extends ConsumerWidget {
385475
] else ...[
386476
// Show regular error for other failures
387477
Container(
388-
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6),
478+
padding:
479+
const EdgeInsets.symmetric(horizontal: 10, vertical: 6),
389480
decoration: BoxDecoration(
390481
color: Colors.red.withValues(alpha: 0.1),
391482
borderRadius: BorderRadius.circular(6),

0 commit comments

Comments
 (0)