Compare commits

...

2 Commits

@ -115,6 +115,9 @@ class BaseAppClient {
// }
body['DeviceTypeID'] = Platform.isAndroid ? '1' : '2';
if( body['SetupID'] != null) {
body['SetupID'] = body['SetupID'].trim();
}
// body['ClinicID'] = 501;
// body['ProjectID'] = 12;

@ -18,7 +18,7 @@ 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

@ -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<String, dynamic> json) {
iMEI = json['IMEI'];
@ -105,6 +107,7 @@ class InsertIMEIDetailsModel {
vidaRefreshTokenID = json['VidaRefreshTokenID'];
password = json['Password'];
loginDoctorID = json['LoginDoctorID'];
zipCode = json['ZipCode'];
}
Map<String, dynamic> 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;
}
}

@ -61,7 +61,7 @@ class AuthenticationViewModel extends BaseViewModel {
UserModel userInfo = UserModel();
final LocalAuthentication auth = LocalAuthentication();
List<BiometricType>? _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<void> 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<void> 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);
}
if (localToken == "") {
localToken = token;
// Only call API if we have a token
if (localToken != null && localToken!.isNotEmpty) {
await _authService.selectDeviceImei(localToken!);
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) {
@ -418,8 +452,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;
}

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

@ -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<LoginScreen> {
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<LoginScreen> {
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!;
}
});
}
}

@ -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<VerificationMethodsScreen> {
AuthMethodTypes? selectedOption;
late AuthenticationViewModel authenticationViewModel;
@override
void initState() {
this.isMoreOption = widget.isMoreOption;
super.initState();
}
@override
Widget build(BuildContext context) {
projectsProvider = Provider.of<ProjectViewModel>(context);
@ -339,7 +348,11 @@ class _VerificationMethodsScreenState extends State<VerificationMethodsScreen> {
//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<VerificationMethodsScreen> {
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);
}
}
}

@ -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<SplashScreen> {
final FirebaseMessaging _firebaseMessaging = FirebaseMessaging.instance;
late AuthenticationViewModel _authViewModel;
@override
void initState() {
super.initState();
AppGlobal.CONTEX = context;
_initializeApp();
}
Future<void> _initializeApp() async {
try {
final String? token = await _getFirebaseToken();
_authViewModel = Provider.of<AuthenticationViewModel>(context, listen: false);
await _authViewModel.initializeApp(token: token);
_navigateBasedOnAuthState();
} catch (e) {
// Handle error and fallback to login
_navigateToLogin();
}
}
Future<String?> _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'),
),
);
}
}

@ -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<AppDrawer> {
onTap: () async {
Navigator.pop(context);
await authenticationViewModel.logout(isFromLogin: false);
locator<NavigationService>().pushNamedAndRemoveUntil(ROOT);
},
),
],

Loading…
Cancel
Save