292 lines
11 KiB
Dart
292 lines
11 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:url_launcher/url_launcher.dart';
|
|
import 'package:flutter_in_store_app_version_checker/flutter_in_store_app_version_checker.dart';
|
|
import 'package:on_field_work/helpers/services/app_logger.dart';
|
|
import 'package:on_field_work/helpers/utils/mixins/ui_mixin.dart';
|
|
import 'package:on_field_work/images.dart';
|
|
import 'package:on_field_work/helpers/widgets/wave_background.dart';
|
|
|
|
class MandatoryUpdateScreen extends StatefulWidget {
|
|
final String newVersion;
|
|
final InStoreAppVersionCheckerResult? updateResult;
|
|
|
|
const MandatoryUpdateScreen({
|
|
super.key,
|
|
required this.newVersion,
|
|
this.updateResult,
|
|
});
|
|
|
|
@override
|
|
State<MandatoryUpdateScreen> createState() => _MandatoryUpdateScreenState();
|
|
}
|
|
|
|
class _MandatoryUpdateScreenState extends State<MandatoryUpdateScreen>
|
|
with SingleTickerProviderStateMixin, UIMixin {
|
|
late AnimationController _controller;
|
|
late Animation<double> _logoAnimation;
|
|
|
|
static const double _kMaxContentWidth = 480.0;
|
|
|
|
Color get _primaryColor => contentTheme.primary;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_controller = AnimationController(
|
|
vsync: this,
|
|
duration: const Duration(milliseconds: 800),
|
|
);
|
|
_logoAnimation = CurvedAnimation(
|
|
parent: _controller,
|
|
curve: Curves.elasticOut,
|
|
);
|
|
_controller.forward();
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_controller.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
Future<void> _launchStoreUrl() async {
|
|
final url = widget.updateResult?.appURL;
|
|
if (url != null && url.isNotEmpty) {
|
|
final uri = Uri.parse(url);
|
|
try {
|
|
if (await canLaunchUrl(uri)) {
|
|
await launchUrl(uri, mode: LaunchMode.externalApplication);
|
|
} else {
|
|
logSafe("Could not launch store URL: $url");
|
|
}
|
|
} catch (e, stack) {
|
|
logSafe(
|
|
"Error launching store URL: $url",
|
|
error: e,
|
|
stackTrace: stack,
|
|
level: LogLevel.error,
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: Scaffold(
|
|
body: Stack(
|
|
children: [
|
|
RedWaveBackground(brandRed: _primaryColor),
|
|
|
|
SafeArea(
|
|
child: Center(
|
|
child: ConstrainedBox(
|
|
constraints:
|
|
const BoxConstraints(maxWidth: _kMaxContentWidth),
|
|
child: SingleChildScrollView(
|
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
const SizedBox(height: 32),
|
|
|
|
ScaleTransition(
|
|
scale: _logoAnimation,
|
|
child: Container(
|
|
width: 100,
|
|
height: 100,
|
|
decoration: BoxDecoration(
|
|
color: Colors.white,
|
|
shape: BoxShape.circle,
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: Colors.black.withOpacity(0.1),
|
|
blurRadius: 20,
|
|
offset: const Offset(0, 8),
|
|
),
|
|
],
|
|
),
|
|
padding: const EdgeInsets.all(20),
|
|
child: Image.asset(Images.logoDark),
|
|
),
|
|
),
|
|
|
|
const SizedBox(height: 32),
|
|
|
|
Container(
|
|
decoration: BoxDecoration(
|
|
color: Colors.white,
|
|
borderRadius: BorderRadius.circular(16),
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: Colors.black.withOpacity(0.05),
|
|
blurRadius: 10,
|
|
offset: const Offset(0, 5),
|
|
),
|
|
],
|
|
),
|
|
padding: const EdgeInsets.all(32),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
children: [
|
|
// Title
|
|
Text(
|
|
"Update Required",
|
|
textAlign: TextAlign.center,
|
|
style: Theme.of(context)
|
|
.textTheme
|
|
.headlineMedium
|
|
?.copyWith(
|
|
fontWeight: FontWeight.bold,
|
|
color: Colors.black87,
|
|
),
|
|
),
|
|
const SizedBox(height: 12),
|
|
|
|
// Subtitle/Message
|
|
Text(
|
|
"A mandatory update (version ${widget.newVersion}) is available to continue using the application. Please update now for uninterrupted access.",
|
|
textAlign: TextAlign.center,
|
|
style: Theme.of(context)
|
|
.textTheme
|
|
.bodyLarge
|
|
?.copyWith(
|
|
color: Colors.black54,
|
|
height: 1.4,
|
|
),
|
|
),
|
|
|
|
const SizedBox(height: 32),
|
|
|
|
// Prominent Action Button
|
|
ElevatedButton.icon(
|
|
onPressed: _launchStoreUrl,
|
|
icon: const Icon(
|
|
Icons.system_update_alt,
|
|
color: Colors.white,
|
|
),
|
|
label: Text(
|
|
"UPDATE NOW",
|
|
style: Theme.of(context)
|
|
.textTheme
|
|
.labelLarge
|
|
?.copyWith(
|
|
fontWeight: FontWeight.w700,
|
|
color: Colors.white,
|
|
fontSize: 16,
|
|
),
|
|
),
|
|
style: ElevatedButton.styleFrom(
|
|
padding:
|
|
const EdgeInsets.symmetric(vertical: 18),
|
|
backgroundColor: _primaryColor,
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(10),
|
|
),
|
|
elevation: 5,
|
|
),
|
|
),
|
|
|
|
const SizedBox(height: 32),
|
|
|
|
// Why Update Section
|
|
Text(
|
|
"Why updating is important:",
|
|
textAlign: TextAlign.start,
|
|
style: Theme.of(context)
|
|
.textTheme
|
|
.titleMedium
|
|
?.copyWith(
|
|
fontWeight: FontWeight.w600,
|
|
color: Colors.black87,
|
|
),
|
|
),
|
|
const SizedBox(height: 12),
|
|
|
|
const Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
BulletPoint(
|
|
text:
|
|
"Access new features and improvements"),
|
|
BulletPoint(
|
|
text:
|
|
"Fix critical bugs and security issues"),
|
|
BulletPoint(
|
|
text:
|
|
"Ensure smooth app performance and stability"),
|
|
BulletPoint(
|
|
text:
|
|
"Stay compatible with latest operating system and services"),
|
|
],
|
|
),
|
|
|
|
const SizedBox(height: 12),
|
|
|
|
Text(
|
|
"Thank you for keeping your app up to date!",
|
|
textAlign: TextAlign.center,
|
|
style: Theme.of(context)
|
|
.textTheme
|
|
.bodySmall
|
|
?.copyWith(
|
|
color: Colors.black45,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class BulletPoint extends StatelessWidget {
|
|
final String text;
|
|
final Color bulletColor;
|
|
|
|
const BulletPoint({
|
|
super.key,
|
|
required this.text,
|
|
this.bulletColor = const Color(0xFF555555),
|
|
});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Padding(
|
|
padding: const EdgeInsets.only(bottom: 8),
|
|
child: Row(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Padding(
|
|
padding: const EdgeInsets.only(right: 8, top: 4),
|
|
child: Icon(
|
|
Icons.circle,
|
|
size: 6,
|
|
color: bulletColor,
|
|
),
|
|
),
|
|
Expanded(
|
|
child: Text(
|
|
text,
|
|
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
|
color: Colors.black87,
|
|
height: 1.4,
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|