diff --git a/lib/client/base_app_client.dart b/lib/client/base_app_client.dart old mode 100644 new mode 100755 index 4147cfed..1ca9735e --- a/lib/client/base_app_client.dart +++ b/lib/client/base_app_client.dart @@ -122,6 +122,9 @@ class BaseAppClient { // } body['DeviceTypeID'] = Platform.isAndroid ? '1' : '2'; + if( body['SetupID'] != null) { + body['SetupID'] = body['SetupID'].trim(); + } // body['ClinicID'] = 501; // body['ProjectID'] = 12; diff --git a/lib/config/config.dart b/lib/config/config.dart old mode 100644 new mode 100755 index 72585642..38fa13b3 --- a/lib/config/config.dart +++ b/lib/config/config.dart @@ -9,16 +9,16 @@ const BASE_URL_LIVE_CARE = 'https://livecare.hmg.com/'; const DOCTOR_ROTATION = 'https://doctorrota.hmg.com/'; -const BASE_URL = 'https://hmgwebservices.com/'; +// const BASE_URL = 'https://hmgwebservices.com/'; // const BASE_URL = 'http://10.20.200.111:1010/'; // const BASE_URL = 'https://uat.hmgwebservices.com/'; -// const BASE_URL = 'https://hmgwebservices.com/'; +const BASE_URL = 'https://hmgwebservices.com/'; // const BASE_URL = 'https://uat.hmgwebservices.com/'; // const BASE_URL = 'https://webservices.hmg.com/'; - +// // const BASE_URL = 'https://vidauat.cloudsolutions.com.sa/'; //Vida Plus URL // const BASE_URL = 'https://vidamergeuat.cloudsolutions.com.sa/'; //Vida Plus URL diff --git a/lib/core/model/auth/insert_imei_model.dart b/lib/core/model/auth/insert_imei_model.dart old mode 100644 new mode 100755 index 61128c8d..9b7efe5f --- a/lib/core/model/auth/insert_imei_model.dart +++ b/lib/core/model/auth/insert_imei_model.dart @@ -33,7 +33,7 @@ class InsertIMEIDetailsModel { String? vidaRefreshTokenID; dynamic? password; int? loginDoctorID; - + String? zipCode; InsertIMEIDetailsModel( {this.iMEI, this.logInTypeID, @@ -68,7 +68,9 @@ class InsertIMEIDetailsModel { this.vidaAuthTokenID, this.vidaRefreshTokenID, this.password, - this.loginDoctorID}); + this.loginDoctorID, + this.zipCode + }); InsertIMEIDetailsModel.fromJson(Map json) { iMEI = json['IMEI']; @@ -105,6 +107,7 @@ class InsertIMEIDetailsModel { vidaRefreshTokenID = json['VidaRefreshTokenID']; password = json['Password']; loginDoctorID = json['LoginDoctorID']; + zipCode = json['ZipCode']; } Map toJson() { @@ -143,7 +146,7 @@ class InsertIMEIDetailsModel { data['VidaRefreshTokenID'] = this.vidaRefreshTokenID; data['Password'] = this.password; data['LoginDoctorID'] = this.loginDoctorID; - + data['ZipCode'] = this.zipCode; return data; } } diff --git a/lib/core/viewModel/authentication_view_model.dart b/lib/core/viewModel/authentication_view_model.dart old mode 100644 new mode 100755 index cdb2bbf7..1b68ce97 --- a/lib/core/viewModel/authentication_view_model.dart +++ b/lib/core/viewModel/authentication_view_model.dart @@ -61,7 +61,7 @@ class AuthenticationViewModel extends BaseViewModel { UserModel userInfo = UserModel(); final LocalAuthentication auth = LocalAuthentication(); List? _availableBiometrics; - final FirebaseMessaging _firebaseMessaging = FirebaseMessaging.instance; + late FirebaseMessaging _firebaseMessaging; bool isLogin = false; bool unverified = false; @@ -71,8 +71,30 @@ class AuthenticationViewModel extends BaseViewModel { bool isHuawei = false; AuthenticationViewModel({bool checkDeviceInfo = false}) { - getDeviceInfoFromFirebase(); - getDoctorProfile(); + FirebaseMessaging _firebaseMessaging = FirebaseMessaging.instance; + // getDeviceInfoFromFirebase(); + // getDoctorProfile(); + } + + Future initializeApp({String? token}) async { + setState(ViewState.Busy); + try { + localToken = token; + await getDeviceInfoFromFirebase(); + if (imeiDetails.isNotEmpty) { + user = imeiDetails.first; + sharedPref.setObj(LAST_LOGIN_USER, user!); + unverified = true; + appStatus = APP_STATUS.UNVERIFIED; + } else { + appStatus = APP_STATUS.UNAUTHENTICATED; + } + setState(ViewState.Idle); + } catch (e) { + error = e.toString(); + appStatus = APP_STATUS.UNAUTHENTICATED; + setState(ViewState.ErrorLocal); + } } /// Insert Device IMEI @@ -97,12 +119,12 @@ class AuthenticationViewModel extends BaseViewModel { insertIMEIDetailsModel.titleDescriptionN = profileInfo['Title_DescriptionN']; insertIMEIDetailsModel.projectID = await sharedPref.getInt(PROJECT_ID); insertIMEIDetailsModel.doctorID = loggedIn != null ? loggedIn['List_MemberInformation'][0]['MemberID'] : user!.doctorID; - insertIMEIDetailsModel.outSA = loggedIn != null ? loggedIn['PatientOutSA'] : user!.outSA; + insertIMEIDetailsModel.outSA = loggedIn != null ? loggedIn['ZipCode'].toString() =='966' ? false: true : user!.outSA; insertIMEIDetailsModel.vidaAuthTokenID = await sharedPref.getString(VIDA_AUTH_TOKEN_ID); insertIMEIDetailsModel.vidaRefreshTokenID = await sharedPref.getString(VIDA_REFRESH_TOKEN_ID); insertIMEIDetailsModel.password = userInfo.password; insertIMEIDetailsModel.loginDoctorID = loggedUser != null ? loggedUser!.listMemberInformation![0].employeeID : user!.editedBy; - + insertIMEIDetailsModel.zipCode = loggedIn != null ? loggedIn['ZipCode'] : user!.zipCode; await _authService.insertDeviceImei(insertIMEIDetailsModel); if (_authService.hasError) { error = _authService.error; @@ -332,48 +354,60 @@ class AuthenticationViewModel extends BaseViewModel { // } /// call firebase service to check if the user already login in before or not - getDeviceInfoFromFirebase() async { - // await checkIsHuawei(); - var token; - var APNSToken; - _firebaseMessaging.setAutoInitEnabled(true); - if (Platform.isIOS) { - _firebaseMessaging.requestPermission(); - } - setState(ViewState.Busy); + // getDeviceInfoFromFirebase() async { + // // await checkIsHuawei(); + // var token; + // var APNSToken; + // _firebaseMessaging.setAutoInitEnabled(true); + // if (Platform.isIOS) { + // _firebaseMessaging.requestPermission(); + // } + // setState(ViewState.Busy); + // try { + // if (Platform.isIOS) { + // APNSToken = await _firebaseMessaging.getAPNSToken(); + // print("APNS TOKEN: $APNSToken"); + // } + // token = await _firebaseMessaging.getToken(); + // print("Device TOKEN: $token"); + // } catch (ex) { + // print(ex); + // } + // if (localToken == "") { + // localToken = token; + // await _authService.selectDeviceImei(localToken); + // if (_authService.hasError) { + // error = _authService.error; + // setState(ViewState.ErrorLocal); + // } else { + // if (_authService.dashboardItemsList.length > 0) { + // user = _authService.dashboardItemsList[0]; + // sharedPref.setObj(LAST_LOGIN_USER, _authService.dashboardItemsList[0]); + // // await sharedPref.setString(VIDA_REFRESH_TOKEN_ID, user!.vidaRefreshTokenID!); + // // await sharedPref.setString(VIDA_AUTH_TOKEN_ID, user!.vidaAuthTokenID!); + // this.unverified = true; + // } + // setState(ViewState.Idle); + // } + // } else { + // setState(ViewState.Idle); + // } + // } + Future getDeviceInfoFromFirebase() async { try { - if (Platform.isIOS) { - APNSToken = await _firebaseMessaging.getAPNSToken(); - print("APNS TOKEN: $APNSToken"); - } - token = await _firebaseMessaging.getToken(); - print("Device TOKEN: $token"); - } catch (ex) { - print(ex); - } + // Only call API if we have a token + if (localToken != null && localToken!.isNotEmpty) { + await _authService.selectDeviceImei(localToken!); - if (localToken == "") { - localToken = token; - - await _authService.selectDeviceImei(localToken); - if (_authService.hasError) { - error = _authService.error; - setState(ViewState.ErrorLocal); - } else { - if (_authService.dashboardItemsList.length > 0) { - user = _authService.dashboardItemsList[0]; - sharedPref.setObj(LAST_LOGIN_USER, _authService.dashboardItemsList[0]); - // await sharedPref.setString(VIDA_REFRESH_TOKEN_ID, user!.vidaRefreshTokenID!); - // await sharedPref.setString(VIDA_AUTH_TOKEN_ID, user!.vidaAuthTokenID!); - this.unverified = true; + if (_authService.hasError) { + throw Exception(_authService.error); } - setState(ViewState.Idle); } - } else { - setState(ViewState.Idle); + } catch (e) { + // debugPrint("Error getting device info: $e"); + rethrow; } } - /// determine the status of the app APP_STATUS get status { if (state == ViewState.Busy) { @@ -417,8 +451,11 @@ class AuthenticationViewModel extends BaseViewModel { setState(ViewState.Idle); } - deleteUser() { - user = GetIMEIDetailsModel(); + deleteUser() async{ + await Utils.clearSharedPref(); + user = null; + doctorProfile = null; + appStatus = APP_STATUS.UNAUTHENTICATED; unverified = false; isLogin = false; } diff --git a/lib/routes.dart b/lib/routes.dart old mode 100644 new mode 100755 index 25dcf2a2..4c2cbe0e --- a/lib/routes.dart +++ b/lib/routes.dart @@ -32,6 +32,7 @@ import 'package:doctor_app_flutter/screens/patients/profile/vte_assessment/vte_a import 'package:doctor_app_flutter/screens/prescription/new_prescriptions_page.dart'; import 'package:doctor_app_flutter/screens/prescription/old_prescriptions_page.dart'; import 'package:doctor_app_flutter/screens/procedures/procedure_screen.dart'; +import 'package:doctor_app_flutter/screens/splash/splash_screen.dart'; import 'package:doctor_app_flutter/screens/video_call_zoom/zoom_video_call.dart'; import './screens/auth/login_screen.dart'; import './screens/patients/profile/vital_sign/vital_sign_details_screen.dart'; @@ -95,7 +96,8 @@ const String ZOOM_CALL_PAGE ='zoom-call'; //todo: change the routing way. var routes = { - ROOT: (_) => RootPage(), + // ROOT: (_) => RootPage(), + ROOT: (_) => SplashScreen(), HOME: (_) => LandingPage(), LOGIN: (_) => LoginScreen(), VERIFICATION_METHODS: (_) => VerificationMethodsScreen(), diff --git a/lib/screens/auth/login_screen.dart b/lib/screens/auth/login_screen.dart old mode 100644 new mode 100755 index 42628f04..374bea90 --- a/lib/screens/auth/login_screen.dart +++ b/lib/screens/auth/login_screen.dart @@ -4,6 +4,7 @@ import 'package:doctor_app_flutter/core/enum/view_state.dart'; import 'package:doctor_app_flutter/core/model/hospitals/get_hospitals_response_model.dart'; import 'package:doctor_app_flutter/core/viewModel/authentication_view_model.dart'; import 'package:doctor_app_flutter/core/viewModel/project_view_model.dart'; +import 'package:doctor_app_flutter/screens/auth/verification_methods_screen.dart'; import 'package:doctor_app_flutter/utils/translations_delegate_base_utils.dart'; import 'package:doctor_app_flutter/utils/utils.dart'; import 'package:doctor_app_flutter/widgets/shared/buttons/app_buttons_widget.dart'; @@ -201,16 +202,17 @@ class _LoginScreenState extends State { Utils.showErrorToast(authenticationViewModel.error); } else { GifLoaderDialogUtils.hideDialog(context); - authenticationViewModel.setUnverified(true, isFromLogin: true); - // Navigator.of(context).pushReplacement( - // MaterialPageRoute( - // builder: (BuildContext context) => - // VerificationMethodsScreen( - // password: authenticationViewModel.userInfo.password, - // isFromLogin: true, - // ), - // ), - // ); + // authenticationViewModel.setUnverified(true, isFromLogin: true); + Navigator.of(context).pushReplacement( + MaterialPageRoute( + builder: (BuildContext context) => + VerificationMethodsScreen( + password: authenticationViewModel.userInfo.password, + isMoreOption: true, + // isFromLogin: true, + ), + ), + ); } } } @@ -235,8 +237,10 @@ class _LoginScreenState extends State { projectsList = authenticationViewModel.hospitals; setState(() { projectViewModel.setVidaPlusProjectList(authenticationViewModel.vidaPlusProjectList); - authenticationViewModel.userInfo.projectID = projectsList[0].facilityId; - projectIdController.text = projectsList[0].facilityName!; + if(projectsList.isNotEmpty) { + authenticationViewModel.userInfo.projectID = projectsList.first.facilityId; + projectIdController.text = projectsList.first.facilityName!; + } }); } } diff --git a/lib/screens/auth/verification_methods_screen.dart b/lib/screens/auth/verification_methods_screen.dart old mode 100644 new mode 100755 index d9bf516c..e562c742 --- a/lib/screens/auth/verification_methods_screen.dart +++ b/lib/screens/auth/verification_methods_screen.dart @@ -7,6 +7,7 @@ import 'package:doctor_app_flutter/core/enum/view_state.dart'; import 'package:doctor_app_flutter/core/service/authentication_service.dart'; import 'package:doctor_app_flutter/core/viewModel/authentication_view_model.dart'; import 'package:doctor_app_flutter/core/viewModel/project_view_model.dart'; +import 'package:doctor_app_flutter/landing_page.dart'; import 'package:doctor_app_flutter/utils/date-utils.dart'; import 'package:doctor_app_flutter/utils/translations_delegate_base_utils.dart'; import 'package:doctor_app_flutter/widgets/auth/sms-popup.dart'; @@ -23,6 +24,7 @@ import '../../config/size_config.dart'; import '../../utils/dr_app_shared_pref.dart'; import '../../utils/utils.dart'; import '../../widgets/auth/verification_methods_list.dart'; +import 'login_screen.dart'; DrAppSharedPreferances sharedPref = new DrAppSharedPreferances(); Utils helpers = Utils(); @@ -30,9 +32,10 @@ Utils helpers = Utils(); ///TODO Elham* check if this still in user or not class VerificationMethodsScreen extends StatefulWidget { final password; - + final isMoreOption; VerificationMethodsScreen({ this.password, + this.isMoreOption = false, }); @override @@ -47,6 +50,12 @@ class _VerificationMethodsScreenState extends State { AuthMethodTypes? selectedOption; late AuthenticationViewModel authenticationViewModel; + @override + void initState() { + this.isMoreOption = widget.isMoreOption; + super.initState(); + } + @override Widget build(BuildContext context) { projectsProvider = Provider.of(context); @@ -339,7 +348,11 @@ class _VerificationMethodsScreenState extends State { //fontWeight: FontWeight.w700, onPressed: () { authenticationViewModel.deleteUser(); - authenticationViewModel.setAppStatus(APP_STATUS.UNAUTHENTICATED); + // authenticationViewModel.setAppStatus(APP_STATUS.UNAUTHENTICATED); + Navigator.pushReplacement( + context, + MaterialPageRoute(builder: (_) => LoginScreen()), + ); }, ), SizedBox( @@ -486,7 +499,17 @@ class _VerificationMethodsScreenState extends State { if (authenticationViewModel.state == ViewState.ErrorLocal) { Utils.showErrorToast(authenticationViewModel.error); } else { - authenticationViewModel.setAppStatus(APP_STATUS.AUTHENTICATED); + Navigator.of(context).pushReplacement( + MaterialPageRoute( + builder: (BuildContext context) => + LandingPage( + // password: authenticationViewModel.userInfo.password, + // isMoreOption: true, + // isFromLogin: true, + ), + ), + ); + // authenticationViewModel.setAppStatus(APP_STATUS.AUTHENTICATED); } } } diff --git a/lib/screens/splash/splash_screen.dart b/lib/screens/splash/splash_screen.dart new file mode 100644 index 00000000..32c364d0 --- /dev/null +++ b/lib/screens/splash/splash_screen.dart @@ -0,0 +1,121 @@ +import 'dart:async'; +import 'dart:io'; +import 'package:doctor_app_flutter/config/config.dart'; +import 'package:doctor_app_flutter/core/service/authentication_service.dart'; +import 'package:doctor_app_flutter/core/viewModel/authentication_view_model.dart'; +import 'package:doctor_app_flutter/locator.dart'; +import 'package:doctor_app_flutter/screens/auth/login_screen.dart'; +import 'package:doctor_app_flutter/screens/auth/verification_methods_screen.dart'; +import 'package:firebase_core/firebase_core.dart'; +import 'package:firebase_messaging/firebase_messaging.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +class SplashScreen extends StatefulWidget { + @override + _SplashScreenState createState() => _SplashScreenState(); +} + +class _SplashScreenState extends State { + final FirebaseMessaging _firebaseMessaging = FirebaseMessaging.instance; + late AuthenticationViewModel _authViewModel; + + @override + void initState() { + super.initState(); + AppGlobal.CONTEX = context; + + + _initializeApp(); + + + + } + + Future _initializeApp() async { + try { + final String? token = await _getFirebaseToken(); + + _authViewModel = Provider.of(context, listen: false); + await _authViewModel.initializeApp(token: token); + + _navigateBasedOnAuthState(); + } catch (e) { + // Handle error and fallback to login + _navigateToLogin(); + } + } + + Future _getFirebaseToken() async { + try { + await Firebase.initializeApp(); + Future.delayed(Duration(seconds: 1), () { + }); + if (Platform.isIOS) { + // Request permissions first + final settings = await _firebaseMessaging.requestPermission( + alert: true, + announcement: false, + badge: true, + carPlay: false, + criticalAlert: false, + provisional: false, + sound: true, + ); + + debugPrint('Notification permissions: ${settings.authorizationStatus}'); + + // Get both FCM and APNS tokens + final fcmToken = await _firebaseMessaging.getToken(); + debugPrint("FCM Token: $fcmToken"); + + // APNS token might not be immediately available + String? apnsToken; + int retries = 0; + while (apnsToken == null && retries < 3) { + apnsToken = await _firebaseMessaging.getAPNSToken(); + if (apnsToken == null) { + await Future.delayed(Duration(milliseconds: 500)); + retries++; + } + } + + debugPrint("APNS Token: $apnsToken"); + return apnsToken ?? fcmToken; // Fallback to FCM token if APNS is null + } else { + return await _firebaseMessaging.getToken(); + } + } catch (e) { + debugPrint("Failed to get FCM token: $e"); + return null; + } + } + void _navigateBasedOnAuthState() { + if (_authViewModel.status == APP_STATUS.UNVERIFIED) { + Navigator.pushReplacement( + context, + MaterialPageRoute(builder: (_) => VerificationMethodsScreen()), + ); + } else if (_authViewModel.status == APP_STATUS.UNAUTHENTICATED) { + _navigateToLogin(); + } else { + _navigateToLogin(); + } + } + + void _navigateToLogin() { + Navigator.pushReplacement( + context, + MaterialPageRoute(builder: (_) => LoginScreen()), + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Color(0xffF8F8F8), + body: Center( + child: Image.asset('assets/images/dr_app_logo.png'), + ), + ); + } +} \ No newline at end of file diff --git a/lib/widgets/shared/app_drawer_widget.dart b/lib/widgets/shared/app_drawer_widget.dart old mode 100644 new mode 100755 index a1598897..4b057bff --- a/lib/widgets/shared/app_drawer_widget.dart +++ b/lib/widgets/shared/app_drawer_widget.dart @@ -1,6 +1,9 @@ +import 'package:doctor_app_flutter/core/service/NavigationService.dart'; import 'package:doctor_app_flutter/core/viewModel/authentication_view_model.dart'; import 'package:doctor_app_flutter/core/viewModel/project_view_model.dart'; import 'package:doctor_app_flutter/icons_app/doctor_app_icons.dart'; +import 'package:doctor_app_flutter/locator.dart'; +import 'package:doctor_app_flutter/routes.dart'; import 'package:doctor_app_flutter/screens/doctor_schedule/doctor_schedule.dart'; import 'package:doctor_app_flutter/screens/reschedule_leaves/add_reschedule_leave.dart'; import 'package:doctor_app_flutter/utils/translations_delegate_base_utils.dart'; @@ -189,6 +192,7 @@ class _AppDrawerState extends State { onTap: () async { Navigator.pop(context); await authenticationViewModel.logout(isFromLogin: false); + locator().pushNamedAndRemoveUntil(ROOT); }, ), ],