OTA Update attempt
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/foundation.dart' show kIsWeb;
|
||||
import '../theme/m3_motion.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
@@ -439,6 +440,14 @@ List<NavSection> _buildSections(String role) {
|
||||
icon: Icons.lock_open,
|
||||
selectedIcon: Icons.lock,
|
||||
),
|
||||
if (kIsWeb) ...[
|
||||
NavItem(
|
||||
label: 'App Update',
|
||||
route: '/settings/app-update',
|
||||
icon: Icons.system_update_alt,
|
||||
selectedIcon: Icons.system_update,
|
||||
),
|
||||
],
|
||||
NavItem(
|
||||
label: 'Logout',
|
||||
route: '',
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../models/app_version.dart';
|
||||
import '../services/app_update_service.dart';
|
||||
|
||||
/// A reusable dialog that can render both flexible and forced updates and
|
||||
/// report download progress. Callers should wrap this with `showDialog` and
|
||||
/// control ``barrierDismissible`` according to ``info.isForceUpdate``.
|
||||
class UpdateDialog extends StatefulWidget {
|
||||
final AppUpdateInfo info;
|
||||
|
||||
const UpdateDialog({required this.info, super.key});
|
||||
|
||||
@override
|
||||
State<UpdateDialog> createState() => _UpdateDialogState();
|
||||
}
|
||||
|
||||
class _UpdateDialogState extends State<UpdateDialog> {
|
||||
double _progress = 0;
|
||||
bool _downloading = false;
|
||||
bool _failed = false;
|
||||
|
||||
Future<void> _startDownload() async {
|
||||
setState(() {
|
||||
_downloading = true;
|
||||
_failed = false;
|
||||
});
|
||||
|
||||
try {
|
||||
await AppUpdateService.instance.downloadAndInstallApk(
|
||||
widget.info.latestVersion!.downloadUrl,
|
||||
onProgress: (p) => setState(() => _progress = p),
|
||||
);
|
||||
// once the installer launches the app is likely to be stopped; we
|
||||
// don't pop the dialog explicitly.
|
||||
} catch (err) {
|
||||
if (!mounted) return;
|
||||
setState(() {
|
||||
_failed = true;
|
||||
_downloading = false;
|
||||
});
|
||||
ScaffoldMessenger.of(
|
||||
context,
|
||||
).showSnackBar(SnackBar(content: Text('Download failed: $err')));
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final notes = widget.info.latestVersion?.releaseNotes ?? '';
|
||||
|
||||
// WillPopScope is deprecated in newer Flutter versions but PopScope
|
||||
// has a different API; to avoid breaking changes we continue to use the
|
||||
// old widget and suppress the warning.
|
||||
// ignore: deprecated_member_use
|
||||
return WillPopScope(
|
||||
onWillPop: () async {
|
||||
// prevent the user from dismissing when download is in progress or
|
||||
// when the dialog is forcing an update
|
||||
return !widget.info.isForceUpdate && !_downloading;
|
||||
},
|
||||
child: AlertDialog(
|
||||
title: const Text('Update Available'),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (notes.isNotEmpty) ...[Text(notes), const SizedBox(height: 12)],
|
||||
if (_downloading)
|
||||
Column(
|
||||
children: [
|
||||
LinearProgressIndicator(value: _progress),
|
||||
const SizedBox(height: 8),
|
||||
Text('${(_progress * 100).toStringAsFixed(0)}%'),
|
||||
],
|
||||
),
|
||||
if (_failed)
|
||||
const Text(
|
||||
'An error occurred while downloading. Please try again.',
|
||||
style: TextStyle(color: Colors.red),
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: _buildActions(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<Widget> _buildActions() {
|
||||
if (_downloading) {
|
||||
// don't show any actions while the apk is being fetched
|
||||
return <Widget>[];
|
||||
}
|
||||
|
||||
if (widget.info.isForceUpdate) {
|
||||
return [
|
||||
FilledButton(
|
||||
onPressed: _startDownload,
|
||||
child: const Text('Update Now'),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: const Text('Later'),
|
||||
),
|
||||
FilledButton(onPressed: _startDownload, child: const Text('Update Now')),
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user