From 0a8b3314ce98a4045949ecd3a4710a737c028b3c Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Thu, 6 Feb 2025 09:53:26 +0300 Subject: [PATCH] unsafe device added, swipe only added, force update added, --- ios/Runner/Runner.entitlements | 9 + lib/controllers/api_routes/urls.dart | 2 + .../providers/api/user_provider.dart | 1 + .../providers/settings/setting_provider.dart | 16 ++ lib/main.dart | 9 +- lib/models/user.dart | 7 +- lib/new_views/pages/splash_page.dart | 134 +++++++++++---- lib/new_views/pages/unsafe_device_view.dart | 80 +++++++++ .../swipe_module/swipe_history_view.dart | 1 - lib/new_views/swipe_module/swipe_view.dart | 159 ++++++++++++++++++ lib/views/pages/splash_screen.dart | 77 --------- lib/views/update_available_screen.dart | 54 ++++++ pubspec.lock | 8 + pubspec.yaml | 3 +- 14 files changed, 445 insertions(+), 115 deletions(-) create mode 100644 lib/new_views/pages/unsafe_device_view.dart create mode 100644 lib/new_views/swipe_module/swipe_view.dart delete mode 100644 lib/views/pages/splash_screen.dart create mode 100644 lib/views/update_available_screen.dart diff --git a/ios/Runner/Runner.entitlements b/ios/Runner/Runner.entitlements index b3fdc75e..9a632605 100644 --- a/ios/Runner/Runner.entitlements +++ b/ios/Runner/Runner.entitlements @@ -4,6 +4,15 @@ aps-environment development + com.apple.developer.networking.HotspotConfiguration + + com.apple.developer.networking.wifi-info + + com.apple.developer.nfc.readersession.formats + + NDEF + TAG + inter-app-audio diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index 137d2f3a..cf8cabe6 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -1,6 +1,7 @@ class URLs { URLs._(); + static const String appReleaseBuildNumber = "14"; // static const host1 = "https://atomsm.hmg.com"; // production url static const host1 = "https://atomsmdev.hmg.com"; // local UAT url @@ -19,6 +20,7 @@ class URLs { // API Routes static get login => "$_baseUrl/MobileAuth/Login"; // web login static get checkLoginValidation => "$_baseUrl/Account/Authenticate"; // web login + static get checkAppVersion => "$_baseUrl/Account/CheckAppVersion"; // web login //Reset Password Apis... static get sendForgetPasswordOtp => "$_baseUrl/Account/SendForgotPasswordOtp"; // send OTP. static get sendForgetPasswordValidateOtp => "$_baseUrl/Account/SendForgotPasswordValidateOtp"; // validate OTP. diff --git a/lib/controllers/providers/api/user_provider.dart b/lib/controllers/providers/api/user_provider.dart index 53ba507b..f5ae0bbf 100644 --- a/lib/controllers/providers/api/user_provider.dart +++ b/lib/controllers/providers/api/user_provider.dart @@ -313,6 +313,7 @@ class UserProvider extends ChangeNotifier { "userId": userId, "dateFrom": dateFrom.toIso8601String(), "dateTo": dateTo.toIso8601String(), + "IsSucces":true, }; try { response = await ApiManager.instance.post(URLs.getSwipeTransactionHistoryUrl, body: body); diff --git a/lib/controllers/providers/settings/setting_provider.dart b/lib/controllers/providers/settings/setting_provider.dart index cb97341c..bcfeb2ed 100644 --- a/lib/controllers/providers/settings/setting_provider.dart +++ b/lib/controllers/providers/settings/setting_provider.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'dart:convert'; import 'package:flutter/material.dart'; +import 'package:http/http.dart'; import 'package:local_auth/local_auth.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:test_sa/controllers/api_routes/api_manager.dart'; @@ -166,4 +167,19 @@ class SettingProvider extends ChangeNotifier { return false; } } + + Future checkAppUpdate(String buildNumber, String osType) async { + Response response; + bool isValid = false; + try { + Map body = {"buildNumber": buildNumber, "osType": osType}; + response = await ApiManager.instance.post(URLs.checkAppVersion, body: body); + if (response.statusCode >= 200 && response.statusCode < 300) { + isValid = (jsonDecode(response.body)["data"]); + } + return isValid; + } catch (error) { + return isValid; + } + } } diff --git a/lib/main.dart b/lib/main.dart index cff76122..b16998bd 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -30,8 +30,10 @@ import 'package:test_sa/new_views/pages/login_page.dart'; import 'package:test_sa/new_views/pages/report_bug_page.dart'; import 'package:test_sa/new_views/pages/settings_page.dart'; import 'package:test_sa/new_views/pages/splash_page.dart'; +import 'package:test_sa/new_views/pages/unsafe_device_view.dart'; import 'package:test_sa/new_views/swipe_module/swipe_history_view.dart'; import 'package:test_sa/new_views/swipe_module/swipe_success_view.dart'; +import 'package:test_sa/new_views/swipe_module/swipe_view.dart'; import 'package:test_sa/providers/asset_transfer/asset_transfer_status_provider.dart'; import 'package:test_sa/providers/department_provider.dart'; import 'package:test_sa/providers/gas_request_providers/cylinder_size_provider.dart'; @@ -93,6 +95,7 @@ import 'providers/service_request_providers/reject_reason_provider.dart'; import 'package:flutter_timezone/flutter_timezone.dart'; import 'package:timezone/data/latest_all.dart' as tz; import 'package:timezone/timezone.dart' as tz; +import 'package:test_sa/views/update_available_screen.dart'; void main() async { @@ -278,7 +281,11 @@ class MyApp extends StatelessWidget { routes: { SplashPage.routeName: (_) => const SplashPage(), LoginPage.routeName: (_) => const LoginPage(), - + UnsafeDeviceScreen.routeName: (_) => const UnsafeDeviceScreen(), + SwipeSuccessView.routeName: (_) => const SwipeSuccessView(), + SwipeHistoryView.routeName: (_) => SwipeHistoryView(), + SwipeView.routeName: (_) => const SwipeView(), + UpdateAvailableScreen.routeName: (_) => UpdateAvailableScreen(), ///todo deleted //old.LandPage.id: (_) => const old.LandPage(), LandPage.routeName: (_) => const LandPage(), diff --git a/lib/models/user.dart b/lib/models/user.dart index ac3ace61..7f6d3e83 100644 --- a/lib/models/user.dart +++ b/lib/models/user.dart @@ -9,6 +9,7 @@ class User { List? departmentId; List? departmentName; String? message; + String? username; String? userID; String? email; @@ -39,7 +40,8 @@ class User { bool? employeeIsHMG; bool? enableWifi; bool? enableNFC; - bool?enableQR; + bool? enableQR; + bool? onlySwipe; User({ this.clientId, @@ -76,6 +78,7 @@ class User { this.enableNFC, this.enableQR, this.enableWifi, + this.onlySwipe, }); bool get isLiveToken => tokenlife != null && (DateTime.tryParse(tokenlife!)?.isAfter(DateTime.now()) ?? false); @@ -162,6 +165,7 @@ class User { map['enableWifi'] = enableWifi; map['enableNFC'] = enableNFC; map['enableQR'] = enableQR; + map['onlySwipe'] = onlySwipe; return map; } @@ -223,6 +227,7 @@ class User { enableWifi = json['enableWifi']; enableNFC = json['enableNFC']; enableQR = json['enableQR']; + onlySwipe = json['onlySwipe']; } } diff --git a/lib/new_views/pages/splash_page.dart b/lib/new_views/pages/splash_page.dart index 8de05715..9cc574c8 100644 --- a/lib/new_views/pages/splash_page.dart +++ b/lib/new_views/pages/splash_page.dart @@ -2,14 +2,21 @@ import 'dart:io'; import 'package:firebase_core/firebase_core.dart'; import 'package:flare_flutter/flare_actor.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:local_auth/local_auth.dart'; import 'package:provider/provider.dart'; +import 'package:safe_device/safe_device.dart'; +import 'package:test_sa/controllers/api_routes/urls.dart'; +import 'package:test_sa/controllers/notification/firebase_notification_manger.dart'; import 'package:test_sa/controllers/providers/api/user_provider.dart'; import 'package:test_sa/controllers/providers/settings/setting_provider.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/new_views/pages/land_page/land_page.dart'; import 'package:test_sa/new_views/pages/login_page.dart'; +import 'package:test_sa/new_views/pages/unsafe_device_view.dart'; +import 'package:test_sa/new_views/swipe_module/swipe_view.dart'; +import 'package:test_sa/views/update_available_screen.dart'; import '../../models/size_config.dart'; @@ -54,20 +61,44 @@ class _SplashPageState extends State { loading = true; }); - bool isValid = await _settingProvider.checkUserTokenValidation(token); - setState(() { - loading = false; - }); - if (isValid && _settingProvider.isLocalAuthEnable) { - bool isSuccess = await checkDualAuthentication(); - if (isSuccess) { - _userProvider.setUser(_settingProvider.user!); - Navigator.of(context).pushNamedAndRemoveUntil(LandPage.routeName, (routes) => true); + String osType; + if (Platform.isIOS) { + osType = "IOS"; + } else { + if (await FirebaseNotificationManger.isGoogleServicesAvailable()) { + osType = "GOOGLE"; } else { - Navigator.of(context).pushNamedAndRemoveUntil(LoginPage.routeName, (routes) => true); + osType = "HUAWEI"; } + } + + bool isAppUpdateAvailable = await _settingProvider.checkAppUpdate(URLs.appReleaseBuildNumber, osType); + if (isAppUpdateAvailable) { + setState(() { + loading = false; + }); + Navigator.of(context).pushNamedAndRemoveUntil(UpdateAvailableScreen.routeName, (routes) => true); } else { - Navigator.of(context).pushNamedAndRemoveUntil(LoginPage.routeName, (routes) => true); + bool isValid = await _settingProvider.checkUserTokenValidation(token); + setState(() { + loading = false; + }); + if (isValid && _settingProvider.isLocalAuthEnable) { + bool isSuccess = await checkDualAuthentication(); + if (isSuccess) { + _userProvider.setUser(_settingProvider.user!); + + if (_userProvider.user!.onlySwipe!) { + Navigator.of(context).pushNamedAndRemoveUntil(SwipeView.routeName, (routes) => true); + } else { + Navigator.of(context).pushNamedAndRemoveUntil(LandPage.routeName, (routes) => true); + } + } else { + Navigator.of(context).pushNamedAndRemoveUntil(LoginPage.routeName, (routes) => true); + } + } else { + Navigator.of(context).pushNamedAndRemoveUntil(LoginPage.routeName, (routes) => true); + } } } @@ -100,33 +131,68 @@ class _SplashPageState extends State { )), SizedBox( width: MediaQuery.of(context).size.width / 1.1, - child: FlareActor( - "assets/rives/atoms_splash.flr", - fit: BoxFit.contain, - animation: "splash", - callback: (animation) async { - if (_settingProvider.isLoaded && (_settingProvider.user != null)) { - checkTokenValidity(_settingProvider.user!.token!); - } else { - Navigator.of(context).pushNamedAndRemoveUntil(LoginPage.routeName, (routes) => true); - } - - // if (_settingProvider.isLoaded && (_settingProvider.user?.isLiveToken ?? false)) { - // _userProvider.user = _settingProvider.user; - // Navigator.of(context).pushNamedAndRemoveUntil(LandPage.routeName, (routes) => true); - // // if(isnotificationCame) - // // Navigator.of(context).push(MaterialPageRoute( - // // builder: (_) => ServiceRequestDetailsPage( - // // serviceRequest: ServiceRequest(id: "72348"), - // // ))); - // /// The below line for the new design - // // Navigator.of(context).pushNamedAndRemoveUntil(LandPage.routeName, (routes) => true); - // } - }, + child: Hero( + tag: "logo", + child: FlareActor( + "assets/rives/atoms_splash.flr", + fit: BoxFit.contain, + animation: "splash", + callback: (animation) async { + bool isSafe = await checkDeviceSafety(); + print('is safe is ${isSafe}'); + if (!isSafe) { + Navigator.pushNamedAndRemoveUntil(context, UnsafeDeviceScreen.routeName, (_) => false); + } else { + if (_settingProvider.isLoaded && (_settingProvider.user != null)) { + checkTokenValidity(_settingProvider.user!.token!); + } else { + Navigator.of(context).pushNamedAndRemoveUntil(LoginPage.routeName, (routes) => true); + } + } + + // if (_settingProvider.isLoaded && (_settingProvider.user?.isLiveToken ?? false)) { + // _userProvider.user = _settingProvider.user; + // Navigator.of(context).pushNamedAndRemoveUntil(LandPage.routeName, (routes) => true); + // // if(isnotificationCame) + // // Navigator.of(context).push(MaterialPageRoute( + // // builder: (_) => ServiceRequestDetailsPage( + // // serviceRequest: ServiceRequest(id: "72348"), + // // ))); + // /// The below line for the new design + // // Navigator.of(context).pushNamedAndRemoveUntil(LandPage.routeName, (routes) => true); + // } + }, + ), ), ).center, ], ), ); } + + Future checkDeviceSafety() async { + if (!kReleaseMode) return true; + bool isOnExternalStorage = false; + bool isDevelopmentModeEnable = false; + bool isJailBroken = false; + bool isRealDevice = false; + + try { + isJailBroken = await SafeDevice.isJailBroken; + isRealDevice = await SafeDevice.isRealDevice; + if (Platform.isAndroid) { + isOnExternalStorage = await SafeDevice.isOnExternalStorage; + isDevelopmentModeEnable = await SafeDevice.isDevelopmentModeEnable; + } + //TODO correct isDevelopmentModeEnable when publish to prod... + if (isJailBroken || !isRealDevice || isOnExternalStorage || isDevelopmentModeEnable) { + return false; + } else { + return true; + } + } catch (error) { + print(error); + return false; + } + } } diff --git a/lib/new_views/pages/unsafe_device_view.dart b/lib/new_views/pages/unsafe_device_view.dart new file mode 100644 index 00000000..6b482553 --- /dev/null +++ b/lib/new_views/pages/unsafe_device_view.dart @@ -0,0 +1,80 @@ +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; + +class UnsafeDeviceScreen extends StatefulWidget { + const UnsafeDeviceScreen({Key? key}) : super(key: key); + static const String routeName = "/unSafeDevice"; + + + @override + State createState() => _UnsafeDeviceScreenState(); +} + +class _UnsafeDeviceScreenState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + body: SafeArea( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + 21.height, + // Center(child: Image.asset("assets/images/logos/main_mohemm_logo.png", width: 200, height: 50)), + "logo".toSvgAsset(height: 64), + 50.height, + "Sorry".heading5(context), + 21.height, + "You are using Atoms app on an unsafe device. To be able to use the app with all it's features, Please make sure that the below points are considered: " + .heading5(context).paddingOnly(start: 20, end: 20), + 48.height, + passwordConstraintsUI("The device is not jailbroken or rooted.", true).paddingOnly(start: 24, end: 5), + 8.height, + passwordConstraintsUI("The app is not installed on external storage.", true).paddingOnly(start: 24, end: 5), + 8.height, + passwordConstraintsUI("Development mode is disabled.", true).paddingOnly(start: 24, end: 5), + 21.height, + AppFilledButton(label: context.translation.done, maxWidth: true, onPressed: () async { + if (Platform.isAndroid) { + SystemChannels.platform.invokeMethod('SystemNavigator.pop'); + } else { + // MinimizeApp.minimizeApp(); + } + }).paddingAll(24), + // DefaultButton(LocaleKeys.ok.tr(), () async { + // if (Platform.isAndroid) { + // SystemChannels.platform.invokeMethod('SystemNavigator.pop'); + // } else { + // // MinimizeApp.minimizeApp(); + // } + // }) + ], + ), + ), + ); + } + + Widget passwordConstraintsUI(String description, bool check) { + return Row( + children: [ + 4.width, + SizedBox( + width: 12, + height: 12, + child: Checkbox(fillColor: MaterialStateProperty.all(AppColor.backgroundDark), shape: const CircleBorder(), value: check, onChanged: null), + ), + 8.width, + description.heading6(context) + ], + ); + } +} \ No newline at end of file diff --git a/lib/new_views/swipe_module/swipe_history_view.dart b/lib/new_views/swipe_module/swipe_history_view.dart index 84169833..5dbc1865 100644 --- a/lib/new_views/swipe_module/swipe_history_view.dart +++ b/lib/new_views/swipe_module/swipe_history_view.dart @@ -119,7 +119,6 @@ class _SwipeHistoryViewState extends State { ], ), 12.height, - AppFilledButton(label: context.translation.search, maxWidth: false, onPressed: getSwipeHistory), 8.height, const Divider(thickness: 2,color:AppColor.white60 ,), diff --git a/lib/new_views/swipe_module/swipe_view.dart b/lib/new_views/swipe_module/swipe_view.dart new file mode 100644 index 00000000..455b3cc0 --- /dev/null +++ b/lib/new_views/swipe_module/swipe_view.dart @@ -0,0 +1,159 @@ +import 'package:flutter/material.dart'; +import 'package:nfc_manager/nfc_manager.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/controllers/providers/api/user_provider.dart'; +import 'package:test_sa/controllers/providers/settings/setting_provider.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/app_drawer.dart'; +import 'package:test_sa/new_views/swipe_module/circular_animated_widget.dart'; +import 'package:test_sa/new_views/swipe_module/swipe_history_view.dart'; +import 'package:test_sa/new_views/swipe_module/utils/swipe_general_utils.dart'; +import 'package:test_sa/views/widgets/dialogs/dialog.dart'; + +class SwipeView extends StatefulWidget { + static const String routeName = "/swipe-view"; + + const SwipeView({ + Key? key, + }) : super(key: key); + + @override + State createState() => _SwipeViewState(); +} + +class _SwipeViewState extends State { + late UserProvider _userProvider; + final GlobalKey _scaffoldKey = GlobalKey(); + + @override + void initState() { + super.initState(); + _userProvider = Provider.of(context, listen: false); + if (_userProvider.user != null) { + WidgetsBinding.instance.addPostFrameCallback((_) { + _userProvider.getSwipeLastTransaction(userId: _userProvider.user!.userID!); + }); + } + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return WillPopScope( + onWillPop: () async { + bool result = await showDialog( + context: context, + builder: (_) => AAlertDialog(title: context.translation.signOut, content: context.translation.logoutAlert), + ); + if (result) { + Provider.of(context, listen: false).resetSettings(); + Provider.of(context, listen: false).reset(); + Navigator.of(context).pop(); + Navigator.of(context).pop(); + } + return false; + }, + child: Scaffold( + key: _scaffoldKey, + drawer: const AppDrawer(), + appBar: AppBar( + automaticallyImplyLeading: false, + backgroundColor: Theme.of(context).scaffoldBackgroundColor, + titleSpacing: 0, + title: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Consumer(builder: (context, snapshot, _) { + return CircleAvatar( + radius: 24, + backgroundColor: context.isDark ? AppColor.neutral50 : AppColor.neutral40, + child: Padding( + padding: const EdgeInsets.all(1), // Border radius + child: ClipOval( + child: snapshot.profileImage != null + ? Image.file(snapshot.profileImage!) + : (snapshot.user?.profilePhotoName?.isNotEmpty ?? false) + ? Image.network(snapshot.user!.profilePhotoName!) + : const Icon(Icons.person, size: 24, color: Colors.white), + ), + ), + ).onPress(() { + _scaffoldKey.currentState!.isDrawerOpen ? _scaffoldKey.currentState!.closeDrawer() : _scaffoldKey.currentState!.openDrawer(); + }); + }), + ], + ).paddingOnly(start: 16, end: 16), + ), + body: Stack( + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + context.translation.welcome, + style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20), + ), + Text( + _userProvider.user?.username ?? "", + style: AppTextStyles.heading2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50, fontWeight: FontWeight.w600), + ), + ], + ).paddingOnly(start: 16, end: 16, top: 8, bottom: 4), + SwipeHistoryView().expanded, + ], + ), + Positioned( + right: 20.toScreenWidth, + bottom: 60.toScreenHeight, + child: GestureDetector( + onTap: () async { + bool isNfcSupported = await NfcManager.instance.isAvailable(); + SwipeGeneralUtils.instance.showSwipeTypeBottomSheetSheet(isNfcSupported: isNfcSupported); + }, + child: CircularAnimatedContainer( + child: Container( + width: 100.toScreenWidth, + height: 100.toScreenHeight, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: AppColor.white10, + border: Border.all(color: AppColor.primary80.withOpacity(0.5), width: 2), + ), + child: Consumer(builder: (context, userProvider, child) { + return Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + 'swipe'.toSvgAsset(width: 32, height: 32), + 8.height, + Text( + ("${context.translation.checkIn}\n${userProvider.swipeTransactionModel != null && userProvider.swipeTransactionModel.swipeTime != null ? SwipeGeneralUtils.instance.formatTimeOnly(userProvider.swipeTransactionModel.swipeTime!) : '--:--'}"), + style: AppTextStyles.bodyText2.copyWith(color: AppColor.neutral80, fontWeight: FontWeight.w500, fontFamily: "Poppins"), + ), + ], + ); + }), + ), + ), + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/views/pages/splash_screen.dart b/lib/views/pages/splash_screen.dart deleted file mode 100644 index 046e4ebd..00000000 --- a/lib/views/pages/splash_screen.dart +++ /dev/null @@ -1,77 +0,0 @@ -///todo deleted -// import 'package:firebase_core/firebase_core.dart'; -// import 'package:flare_flutter/flare_actor.dart'; -// import 'package:flutter/material.dart'; -// import 'package:provider/provider.dart'; -// import 'package:test_sa/controllers/notification/notification_manger.dart'; -// import 'package:test_sa/controllers/providers/api/user_provider.dart'; -// import 'package:test_sa/controllers/providers/settings/setting_provider.dart'; -// import 'package:test_sa/models/user.dart'; -// import 'package:test_sa/new_views/pages/land_page/land_page.dart'; -// -// import 'login.dart'; -// -// class SplashScreen extends StatefulWidget { -// static const String id = '/splash'; -// -// const SplashScreen({Key? key}) : super(key: key); -// -// @override -// State createState() => _SplashScreenState(); -// } -// -// class _SplashScreenState extends State { -// SettingProvider _settingProvider; -// UserProvider _userProvider; -// -// _goToUserScreen(User user) { -// if (user.tokenlife != null && (DateTime.tryParse(user.tokenlife)?.isAfter(DateTime.now()) ?? false)) { -// _userProvider.user = user; -// // Navigator.of(context).pushNamed(Login.id); -// Navigator.of(context).pushNamed(LandPage.routeName); -// } -// } -// -// @override -// void initState() { -// Firebase.initializeApp(); -// -// NotificationManger.initialisation((notificationDetails) { -// // todo @sikander, check notifications payload, because notification model is different to need to check from backend -// // SystemNotificationModel notification = SystemNotificationModel.fromJson(json.decode(notificationDetails.payload)); -// // if (notification.path == null || notification.path.isEmpty) return; -// // Navigator.pushNamed(context, notification.path, arguments: notification.requestId); -// }, (id, title, body, payload) async {}); -// super.initState(); -// } -// -// @override -// Widget build(BuildContext context) { -// _settingProvider = Provider.of(context, listen: false); -// _userProvider = Provider.of(context, listen: false); -// return Scaffold( -// backgroundColor: Colors.white, -// body: Center( -// child: SizedBox( -// width: MediaQuery.of(context).size.width / 1.1, -// child: FlareActor( -// "assets/rives/atoms_splash.flr", -// fit: BoxFit.contain, -// animation: "splash", -// callback: (animation) async { -// Navigator.of(context).pushNamed(Login.id); -// if (_settingProvider.isLoaded && _settingProvider.user != null) { -// _goToUserScreen(_settingProvider.user); -// } -// }, -// ), -// //const Center(child: CircularProgressIndicator()) -// -// // Image.asset("assets/images/logo.png", -// // fit: BoxFit.contain, -// // ), -// ), -// ), -// ); -// } -// } diff --git a/lib/views/update_available_screen.dart b/lib/views/update_available_screen.dart new file mode 100644 index 00000000..558a0233 --- /dev/null +++ b/lib/views/update_available_screen.dart @@ -0,0 +1,54 @@ +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; +import 'package:url_launcher/url_launcher.dart'; + +class UpdateAvailableScreen extends StatelessWidget { + static const String routeName = "/UpdateAvailableScreen"; + + UpdateAvailableScreen({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Hero(tag: "logo", child: "logo".toSvgAsset(height: 64)), + 48.height, + Text( + "Update Available", + style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50), + ), + 24.height, + Text( + "A new update is available on store.\nUpdate now to enjoy the latest features, improvements, and bug fixes for a smoother experience! ", + textAlign: TextAlign.center, + style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20), + ), + 24.height, + AppFilledButton( + label: context.translation.update, + maxWidth: true, + onPressed: () { + if (Platform.isAndroid || Platform.isIOS) { + final appId = Platform.isAndroid ? 'com.hmg.atoms' : '6446684161'; + final url = Uri.parse(Platform.isAndroid ? "market://details?id=$appId" : "https://apps.apple.com/app/id$appId"); + launchUrl( + url, + mode: LaunchMode.externalApplication, + ); + } + }), + ], + ).paddingAll(24), + ); + } +} diff --git a/pubspec.lock b/pubspec.lock index 9ff16b2f..7e051fcd 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1325,6 +1325,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.28.0" + safe_device: + dependency: "direct main" + description: + name: safe_device + sha256: "953aeac3486180df9118a1a3f5fb842d84015e8aa6f2607edeb5fb881b67a669" + url: "https://pub.dev" + source: hosted + version: "1.2.0" share_plus: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 88bda3c5..9d81d41e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.3.1+14 +version: 1.2.6+14 environment: sdk: ">=3.5.0 <4.0.0" @@ -92,6 +92,7 @@ dependencies: nfc_manager: ^3.2.0 wifi_iot: ^0.3.19+1 just_audio: ^0.9.30 + safe_device: ^1.1.9 local_auth_darwin: any dev_dependencies: