unsafe device added, swipe only added, force update added,

design_3.0_latest
Sikander Saleem 9 months ago
parent fc1fb41bb9
commit 0a8b3314ce

@ -4,6 +4,15 @@
<dict>
<key>aps-environment</key>
<string>development</string>
<key>com.apple.developer.networking.HotspotConfiguration</key>
<true/>
<key>com.apple.developer.networking.wifi-info</key>
<true/>
<key>com.apple.developer.nfc.readersession.formats</key>
<array>
<string>NDEF</string>
<string>TAG</string>
</array>
<key>inter-app-audio</key>
<true/>
</dict>

@ -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.

@ -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);

@ -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<bool> checkAppUpdate(String buildNumber, String osType) async {
Response response;
bool isValid = false;
try {
Map<String, dynamic> 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;
}
}
}

@ -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(),

@ -9,6 +9,7 @@ class User {
List<int>? departmentId;
List<String>? 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'];
}
}

@ -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<SplashPage> {
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<SplashPage> {
)),
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<bool> 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;
}
}
}

@ -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<UnsafeDeviceScreen> createState() => _UnsafeDeviceScreenState();
}
class _UnsafeDeviceScreenState extends State<UnsafeDeviceScreen> {
@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)
],
);
}
}

@ -119,7 +119,6 @@ class _SwipeHistoryViewState extends State<SwipeHistoryView> {
],
),
12.height,
AppFilledButton(label: context.translation.search, maxWidth: false, onPressed: getSwipeHistory),
8.height,
const Divider(thickness: 2,color:AppColor.white60 ,),

@ -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<SwipeView> createState() => _SwipeViewState();
}
class _SwipeViewState extends State<SwipeView> {
late UserProvider _userProvider;
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
@override
void initState() {
super.initState();
_userProvider = Provider.of<UserProvider>(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<SettingProvider>(context, listen: false).resetSettings();
Provider.of<UserProvider>(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<UserProvider>(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<UserProvider>(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"),
),
],
);
}),
),
),
),
),
],
),
),
);
}
}

@ -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<SplashScreen> createState() => _SplashScreenState();
// }
//
// class _SplashScreenState extends State<SplashScreen> {
// 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<SettingProvider>(context, listen: false);
// _userProvider = Provider.of<UserProvider>(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,
// // ),
// ),
// ),
// );
// }
// }

@ -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),
);
}
}

@ -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:

@ -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:

Loading…
Cancel
Save