Merge branch 'dev_aamir' of http://34.17.52.180/Haroon6138/HMG_Patient_App_New into dev_sultan

# Conflicts:
#	lib/features/medical_file/medical_file_view_model.dart
pull/76/head
Sultan khan 1 month ago
commit 3642523fdf

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -0,0 +1 @@
{"nm":"Splash Launch 1","ddd":0,"h":927,"w":430,"meta":{"g":"LottieFiles Figma v92"},"layers":[{"ty":4,"nm":"Ellipse 54","sr":1,"st":0,"op":121.06,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.82,"y":-0.01},"i":{"x":0.58,"y":1},"s":[19.5,19.5],"t":0},{"o":{"x":0.82,"y":-0.01},"i":{"x":0.58,"y":1},"s":[19.5,19.5],"t":60},{"s":[628.5,628.5],"t":120}]},"s":{"a":0,"k":[100,100]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.82,"y":-0.01},"i":{"x":0.58,"y":1},"s":[216,464],"t":0},{"o":{"x":0.82,"y":-0.01},"i":{"x":0.58,"y":1},"s":[216.5,464.5],"t":60},{"s":[225.5,473.5],"t":120}]},"r":{"a":0,"k":0},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.82,"y":-0.01},"i":{"x":0.58,"y":1},"s":[0],"t":0},{"o":{"x":0.82,"y":-0.01},"i":{"x":0.58,"y":1},"s":[0],"t":60},{"s":[100],"t":120}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.82,"y":-0.01},"i":{"x":0.58,"y":1},"s":[{"c":true,"i":[[0,0],[10.493846153846153,0],[0,10.493846153846153],[-10.493846153846153,0],[0,-10.493846153846153]],"o":[[0,10.493846153846153],[-10.493846153846153,0],[0,-10.493846153846153],[10.493846153846153,0],[0,0]],"v":[[38,19],[19,38],[0,19],[19,0],[38,19]]}],"t":0},{"o":{"x":0.82,"y":-0.01},"i":{"x":0.58,"y":1},"s":[{"c":true,"i":[[0,0],[10.493846153846153,0],[0,10.493846153846153],[-10.493846153846153,0],[0,-10.493846153846153]],"o":[[0,10.493846153846153],[-10.493846153846153,0],[0,-10.493846153846153],[10.493846153846153,0],[0,0]],"v":[[38,19],[19,38],[0,19],[19,0],[38,19]]}],"t":60},{"s":[{"c":true,"i":[[0,0],[341.5871678599841,0],[0,341.5871678599841],[-341.5871678599841,0],[0,-341.5871678599841]],"o":[[0,341.5871678599841],[-341.5871678599841,0],[0,-341.5871678599841],[341.5871678599841,0],[0,0]],"v":[[1237,618.5],[618.5,1237],[0,618.5],[618.5,0],[1237,618.5]]}],"t":120}]}},{"ty":"st","bm":0,"hd":false,"nm":"","lc":1,"lj":1,"ml":4,"o":{"a":1,"k":[{"o":{"x":0.82,"y":-0.01},"i":{"x":0.58,"y":1},"s":[20],"t":0},{"o":{"x":0.82,"y":-0.01},"i":{"x":0.58,"y":1},"s":[20],"t":60},{"s":[100],"t":120}]},"w":{"a":1,"k":[{"o":{"x":0.82,"y":-0.01},"i":{"x":0.58,"y":1},"s":[1],"t":0},{"o":{"x":0.82,"y":-0.01},"i":{"x":0.58,"y":1},"s":[1],"t":60},{"s":[20],"t":120}]},"c":{"a":0,"k":[0.9295,0.1098,0.1687]}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":0,"k":[1,1,1]},"r":1,"o":{"a":0,"k":100}}],"ind":1},{"ty":4,"nm":"Group 8232","sr":1,"st":0,"op":121.06,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"sk":{"a":0,"k":0},"p":{"a":0,"k":[155,404]},"r":{"a":0,"k":0},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":0},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":60.06},{"s":[100],"t":120}]}},"shapes":[],"ind":2},{"ty":4,"nm":"Rectangle 17364","sr":1,"st":0,"op":121.06,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[200,326.5]},"s":{"a":0,"k":[100,100]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.82,"y":-0.01},"i":{"x":0.58,"y":1},"s":[-207.54,1178.76],"t":0},{"o":{"x":0.82,"y":-0.01},"i":{"x":0.58,"y":1},"s":[565.46,-310.24],"t":60},{"s":[565.46,-310.24],"t":120.12}]},"r":{"a":0,"k":30},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.82,"y":-0.01},"i":{"x":0.58,"y":1},"s":[100],"t":0},{"o":{"x":0.82,"y":-0.01},"i":{"x":0.58,"y":1},"s":[100],"t":60},{"s":[0],"t":120.12}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,-110.38],[0,0],[110.38,0],[0,0],[0,110.38],[0,0],[-110.38,0],[0,0]],"o":[[0,0],[0,110.38],[0,0],[-110.38,0],[0,0],[0,-110.38],[0,0],[110.38,0]],"v":[[400,200],[400,453],[200,653],[200,653],[0,453],[0,200],[200,0],[200,0]]}}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":0,"k":[0.9295,0.1098,0.1687]},"r":1,"o":{"a":0,"k":100}}],"ind":3},{"ty":4,"nm":"Symptoms Checker Bg","sr":1,"st":0,"op":121.06,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[215,463.5]},"s":{"a":0,"k":[100,100]},"sk":{"a":0,"k":0},"p":{"a":0,"k":[215,463.5]},"r":{"a":0,"k":0},"sa":{"a":0,"k":0},"o":{"a":0,"k":100}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[430,0],[430,927],[0,927],[0,0]]}}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.82,"y":-0.01},"i":{"x":0.58,"y":1},"s":[1,1,1],"t":0},{"o":{"x":0.82,"y":-0.01},"i":{"x":0.58,"y":1},"s":[1,1,1],"t":60},{"s":[0.9295,0.1098,0.1687],"t":120}]},"r":1,"o":{"a":0,"k":100}}],"ind":4}],"v":"5.7.0","fr":60,"op":120.06,"ip":0,"assets":[]}

@ -849,6 +849,7 @@
"pleaseEnterEmail": "يرجى إدخال البريد الإلكتروني",
"pleaseEnterAValidEmailFormat": "يرجى إدخال تنسيق بريد إلكتروني صالح",
"selectCountry": "اختر الدولة",
"forLoginVerification": "للتحقق من تسجيل الدخول"
"forLoginVerification": "للتحقق من تسجيل الدخول",
"searchHospital": "بحث في المستشفى"
}

@ -845,5 +845,6 @@
"pleaseEnterAValidEmailFormat": "Please enter a valid email format",
"selectCountry": "Select Country",
"forLoginVerification": "for login verification",
"lastLoginBy": "Last login by"
"lastLoginBy": "Last login by",
"searchHospital": "Search Hospital"
}

@ -166,6 +166,9 @@ class AppAnimations {
static const String register = '$lottieBasePath/register.json';
static const String checkmark = '$lottieBasePath/checkmark.json';
static const String loadingAnimation = '$lottieBasePath/Loader.json';
static const String onboarding_1 = '$lottieBasePath/onboarding_1.json';
static const String onboarding_2 = '$lottieBasePath/onboarding_2.json';
static const String errorAnimation = '$lottieBasePath/ErrorAnimation.json';
static const String warningAnimation = '$lottieBasePath/warningAnimation.json';
static const String splashLaunching = '$lottieBasePath/splash_launching.json';
}

@ -37,6 +37,8 @@ class AppState {
AuthenticatedUser? _authenticatedRootUser;
AuthenticatedUser? _authenticatedChildUser;
int? _superUserID;
void setAuthenticatedUser(AuthenticatedUser authenticatedUser, {bool isFamily = false}) {
if (isFamily) {
_authenticatedChildUser = authenticatedUser;
@ -55,6 +57,10 @@ class AppState {
}
}
int? get superUserID => _superUserID;
set setSuperUserID(int? value) => _superUserID = value;
String _userBloodGroup = "";
String get getUserBloodGroup => _userBloodGroup;

@ -22,7 +22,7 @@ extension WidgetExtensions on Widget {
Widget paddingSymmetrical(double horizontal, double vertical) => Padding(padding: EdgeInsets.symmetric(horizontal: horizontal, vertical: vertical), child: this);
Widget paddingOnly({double left = 0.0, double right = 0.0, double top = 0.0, double bottom = 0.0}) =>
Padding(padding: EdgeInsets.only(left: left, right: right, top: top, bottom: bottom), child: this);
Padding(padding: EdgeInsetsDirectional.only(start: left, end: right, top: top, bottom: bottom), child: this);
Widget toExpanded({int flex = 1}) => Expanded(flex: flex, child: this);

@ -3,6 +3,7 @@ import 'dart:async';
import 'package:dartz/dartz.dart';
import 'package:hmg_patient_app_new/core/api/api_client.dart';
import 'package:hmg_patient_app_new/core/api_consts.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/common_models/generic_api_model.dart';
import 'package:hmg_patient_app_new/core/common_models/privilege/PrivilegeModel.dart';
import 'package:hmg_patient_app_new/core/exceptions/api_failure.dart';
@ -19,7 +20,15 @@ abstract class AuthenticationRepo {
Future<Either<Failure, GenericApiModel<dynamic>>> sendActivationCodeRepo({required dynamic sendActivationCodeReq, String? languageID, bool isRegister = false, bool isFormFamilyFile = false});
Future<Either<Failure, GenericApiModel<dynamic>>> checkActivationCodeRepo({required dynamic newRequest, required String? activationCode, required bool isRegister, bool isExcludedUser = false});
Future<Either<Failure, GenericApiModel<dynamic>>> checkActivationCodeRepo(
{required dynamic newRequest,
required String? activationCode,
required bool isRegister,
bool isFormFamilyFile = false,
int? patientShareRequestID,
int? responseID,
bool isSwitchUser = false,
int? patientID});
Future<Either<Failure, GenericApiModel<dynamic>>> checkIfUserAgreed({required dynamic commonAuthanticatedRequest});
@ -178,7 +187,11 @@ class AuthenticationRepoImp implements AuthenticationRepo {
required dynamic newRequest, // could be CheckActivationCodeReq or CheckActivationCodeRegisterReq
required String? activationCode,
required bool isRegister,
bool isExcludedUser = false,
bool isFormFamilyFile = false,
int? patientShareRequestID,
int? responseID,
bool isSwitchUser = false,
int? patientID,
}) async {
if (isRegister) {
newRequest["activationCode"] = activationCode ?? "0000";
@ -191,8 +204,26 @@ class AuthenticationRepoImp implements AuthenticationRepo {
newRequest.forRegisteration = newRequest.isRegister ?? false;
newRequest.isRegister = false;
}
final endpoint = isExcludedUser
Map<String, dynamic> familyRequest = {};
if (isFormFamilyFile) {
familyRequest = newRequest.toJson();
familyRequest['PatientShareRequestID'] = patientShareRequestID;
familyRequest['ResponseID'] = responseID;
familyRequest['Status'] = 3;
familyRequest["PatientID"] = newRequest["PatientID"];
}
Map<String, dynamic> switchRequest = {};
if (isSwitchUser) {
switchRequest = newRequest.toJson();
switchRequest['SuperUser'] = patientID;
switchRequest['PatientID'] = responseID;
switchRequest['IsSilentLogin'] = true;
switchRequest['LogInTokenID'] = null;
switchRequest['DeviceToken'] = null;
switchRequest['SearchType'] = 2;
}
final endpoint = isFormFamilyFile
? ApiConsts.checkActivationCodeForFamily
: isRegister
? ApiConsts.checkActivationCodeRegister
@ -204,7 +235,13 @@ class AuthenticationRepoImp implements AuthenticationRepo {
await apiClient.post(
endpoint,
body: isRegister ? newRequest : newRequest.toJson(),
body: isFormFamilyFile
? familyRequest
: isRegister
? newRequest
: isSwitchUser
? switchRequest
: newRequest.toJson(),
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},

@ -382,12 +382,16 @@ class AuthenticationViewModel extends ChangeNotifier {
_appState.setUserRegistrationPayload = RegistrationDataModelPayload.fromJson(payload);
}
final resultEither =
await _authenticationRepo.sendActivationCodeRepo(sendActivationCodeReq: request, isRegister: checkIsUserComingForRegister(request: payload), languageID: 'er', isFormFamilyFile: isFormFamilyFile);
final resultEither = await _authenticationRepo.sendActivationCodeRepo(
sendActivationCodeReq: request, isRegister: checkIsUserComingForRegister(request: payload), languageID: 'er', isFormFamilyFile: isFormFamilyFile);
resultEither.fold(
(failure) async => await _errorHandlerService.handleError(failure: failure),
(apiResponse) async {
int? patientShareRequestID = 0;
if (isFormFamilyFile) {
patientShareRequestID = apiResponse.data['PatientShareRequestID'];
}
if (apiResponse.messageStatus == 2) {
LoaderBottomSheet.hideLoader();
await _dialogService.showCommonBottomSheetWithoutH(
@ -400,7 +404,15 @@ class AuthenticationViewModel extends ChangeNotifier {
LoaderBottomSheet.hideLoader();
if (!isComingFromResendOTP) {
navigateToOTPScreen(
otpTypeEnum: otpTypeEnum, phoneNumber: phoneNumber, isComingFromRegister: checkIsUserComingForRegister(request: payload), payload: payload, isExcludedUser: isExcludedUser);
otpTypeEnum: otpTypeEnum,
phoneNumber: phoneNumber,
isComingFromRegister: checkIsUserComingForRegister(request: payload),
payload: payload,
isFormFamilyFile: isFormFamilyFile,
isExcludedUser: isExcludedUser,
responseID: responseID,
patientShareRequestID: patientShareRequestID,
);
}
} else {
// TODO: Handle isSMSSent false
@ -424,9 +436,12 @@ class AuthenticationViewModel extends ChangeNotifier {
required OTPTypeEnum otpTypeEnum,
required Function(String? message) onWrongActivationCode,
Function()? onResendActivation,
bool isExcludedUser = false,
dynamic requestID,
dynamic responseID}) async {
bool isFormFamilyFile = false,
dynamic patientShareRequestID,
dynamic responseID,
bool isSwitchUser =false,
int? patientID
}) async {
bool isForRegister = (_appState.getUserRegistrationPayload.healthId != null || _appState.getUserRegistrationPayload.patientOutSa == true || _appState.getUserRegistrationPayload.patientOutSa == 1);
final request = RequestUtils.getCommonRequestWelcome(
@ -453,12 +468,6 @@ class AuthenticationViewModel extends ChangeNotifier {
loginType: loginTypeEnum.toInt)
.toJson();
if (isExcludedUser) {
request['PatientShareRequestID'] = requestID;
request['ResponseID'] = responseID;
request['Status'] = 3;
}
LoaderBottomSheet.showLoader();
if (isForRegister) {
if (_appState.getUserRegistrationPayload.patientOutSa == 0) request['DOB'] = _appState.getUserRegistrationPayload.dob;
@ -468,7 +477,11 @@ class AuthenticationViewModel extends ChangeNotifier {
request["ForRegisteration"] = _appState.getUserRegistrationPayload.isRegister;
request["isRegister"] = false;
final resultEither = await _authenticationRepo.checkActivationCodeRepo(newRequest: request, activationCode: activationCode.toString(), isRegister: true);
final resultEither = await _authenticationRepo.checkActivationCodeRepo(
newRequest: request,
activationCode: activationCode.toString(),
isRegister: true,
);
LoaderBottomSheet.hideLoader();
@ -495,7 +508,15 @@ class AuthenticationViewModel extends ChangeNotifier {
});
} else {
final resultEither = await _authenticationRepo.checkActivationCodeRepo(
newRequest: CheckActivationCodeRegisterReq.fromJson(request), activationCode: activationCode, isRegister: false, isExcludedUser: isExcludedUser);
newRequest: CheckActivationCodeRegisterReq.fromJson(request),
activationCode: activationCode,
isRegister: false,
isFormFamilyFile: isFormFamilyFile,
patientShareRequestID: patientShareRequestID,
responseID: responseID,
isSwitchUser: isSwitchUser,
patientID: patientID
);
resultEither.fold(
(failure) async => await _errorHandlerService.handleError(
@ -509,6 +530,8 @@ class AuthenticationViewModel extends ChangeNotifier {
LoaderBottomSheet.hideLoader();
await _dialogService.showCommonBottomSheetWithoutH(message: failure.message, label: LocaleKeys.notice.tr(), onOkPressed: () {});
}), (apiResponse) async {
print("API Response Data: ${apiResponse.data}");
final activation = CheckActivationCode.fromJson(apiResponse.data as Map<String, dynamic>);
if (activation.errorCode == '699') {
@ -527,6 +550,9 @@ class AuthenticationViewModel extends ChangeNotifier {
return;
} else {
if (activation.list != null && activation.list!.isNotEmpty) {
if(isSwitchUser){
_appState.setSuperUserID = _appState.getAuthenticatedUser()?.patientId;
}
_appState.setAuthenticatedUser(activation.list!.first);
_appState.setPrivilegeModelList(activation.list!.first.listPrivilege!);
}
@ -605,14 +631,25 @@ class AuthenticationViewModel extends ChangeNotifier {
_navigationService.pushAndReplace(AppRoutes.landingScreen);
}
Future<void> navigateToOTPScreen({required OTPTypeEnum otpTypeEnum, required String phoneNumber, required bool isComingFromRegister, dynamic payload, bool isExcludedUser = false}) async {
Future<void> navigateToOTPScreen(
{required OTPTypeEnum otpTypeEnum,
required String phoneNumber,
required bool isComingFromRegister,
dynamic payload,
bool isFormFamilyFile = false,
bool isExcludedUser = false,
int? responseID,
int? patientShareRequestID}) async {
_navigationService.pushToOtpScreen(
phoneNumber: phoneNumber,
isFormFamilyFile: isFormFamilyFile,
checkActivationCode: (int activationCode) async {
await checkActivationCode(
activationCode: activationCode.toString(),
isExcludedUser: isExcludedUser,
isFormFamilyFile: isFormFamilyFile,
otpTypeEnum: otpTypeEnum,
responseID: responseID,
patientShareRequestID: patientShareRequestID,
onWrongActivationCode: (String? value) {
onWrongActivationCode(message: value);
},
@ -625,7 +662,11 @@ class AuthenticationViewModel extends ChangeNotifier {
nationalIdOrFileNumber: nationalIdController.text,
isForRegister: isComingFromRegister,
isComingFromResendOTP: true,
payload: payload);
payload: payload,
isFormFamilyFile: isFormFamilyFile,
isExcludedUser: isExcludedUser,
responseID: responseID,
);
},
);
}

@ -69,7 +69,7 @@ class AuthenticatedUser {
dynamic authenticatedUserPatientPayType;
dynamic authenticatedUserPatientType;
dynamic authenticatedUserStatus;
int? superUser;
AuthenticatedUser({
this.setupId,
this.patientType,
@ -139,6 +139,7 @@ class AuthenticatedUser {
this.authenticatedUserPatientPayType,
this.authenticatedUserPatientType,
this.authenticatedUserStatus,
this.superUser
});
factory AuthenticatedUser.fromRawJson(String str) => AuthenticatedUser.fromJson(json.decode(str));
@ -214,6 +215,7 @@ class AuthenticatedUser {
authenticatedUserPatientPayType: json["patientPayType"],
authenticatedUserPatientType: json["patientType"],
authenticatedUserStatus: json["status"],
superUser: json["superUser"],
);
Map<String, dynamic> toJson() => {
@ -285,6 +287,7 @@ class AuthenticatedUser {
"patientPayType": authenticatedUserPatientPayType,
"patientType": authenticatedUserPatientType,
"status": authenticatedUserStatus,
"superUser": superUser,
};
}

@ -428,13 +428,9 @@ class OTPVerificationScreen extends StatefulWidget {
final String phoneNumber;
final Function(int code) checkActivationCode;
final Function(String phoneNumber) onResendOTPPressed;
final bool isFormFamilyFile;
const OTPVerificationScreen({
super.key,
required this.phoneNumber,
required this.checkActivationCode,
required this.onResendOTPPressed,
});
const OTPVerificationScreen({super.key, required this.phoneNumber, required this.checkActivationCode, required this.onResendOTPPressed, required this.isFormFamilyFile});
@override
State<OTPVerificationScreen> createState() => _OTPVerificationScreenState();
@ -559,7 +555,7 @@ class _OTPVerificationScreenState extends State<OTPVerificationScreen> {
LocaleKeys.weHaveSendOTP.tr().toText15(color: AppColors.inputLabelTextColor, letterSpacing: -0.4),
_getMaskedPhoneNumber().toText15(color: AppColors.inputLabelTextColor, isBold: true),
LocaleKeys.via.tr().toText15(color: AppColors.inputLabelTextColor, letterSpacing: -0.4),
authVM.loginTypeEnum.displayName.toText15(color: AppColors.inputLabelTextColor, isBold: true, letterSpacing: -0.4),
(widget.isFormFamilyFile ? LoginTypeEnum.sms.displayName : authVM.loginTypeEnum.displayName).toText15(color: AppColors.inputLabelTextColor, isBold: true, letterSpacing: -0.4),
appState.getUserRegistrationPayload.isRegister != null && appState.getUserRegistrationPayload.isRegister == true
? LocaleKeys.forRegistrationVerification.tr().toText15(color: AppColors.inputLabelTextColor, letterSpacing: -0.4)
: LocaleKeys.forLoginVerification.tr().toText15(color: AppColors.inputLabelTextColor, letterSpacing: -0.4),

@ -414,11 +414,6 @@ class BookAppointmentsViewModel extends ChangeNotifier {
}
Future<void> getRegionMappedProjectList() async {
//todo handle the case in the location is switch on
// if(hospitalList != null && hospitalList!.registeredDoctorMap != null && hospitalList!.registeredDoctorMap!.isNotEmpty){
// filteredHospitalList = hospitalList;
// return;
// }
isRegionListLoading = true;
notifyListeners();
final result = await bookAppointmentsRepo.getProjectList();
@ -432,7 +427,7 @@ class BookAppointmentsViewModel extends ChangeNotifier {
} else if (apiResponse.messageStatus == 1) {
var projectList = apiResponse.data!;
hospitalList = await DoctorMapper.getMappedHospitals(projectList,
isArabic: false,
isArabic: _appState.isArabic(),
lat: _appState.userLat,
lng: _appState.userLong,
);

@ -24,7 +24,7 @@ abstract class MedicalFileRepo {
Future<Either<Failure, GenericApiModel<dynamic>>> getPatientMedicalReportPDF(PatientMedicalReportResponseModel patientMedicalReportResponseModel, AuthenticatedUser authenticatedUser);
Future<Either<Failure, GenericApiModel<List<FamilyFileResponseModelLists>>>> getPatientFamilyFiles();
Future<Either<Failure, GenericApiModel<List<FamilyFileResponseModelLists>>>> getPatientFamilyFiles(int status, int patientId);
Future<Either<Failure, GenericApiModel<dynamic>>> addFamilyFile({required dynamic request});
}
@ -274,13 +274,13 @@ class MedicalFileRepoImp implements MedicalFileRepo {
}
@override
Future<Either<Failure, GenericApiModel<List<FamilyFileResponseModelLists>>>> getPatientFamilyFiles() async {
Future<Either<Failure, GenericApiModel<List<FamilyFileResponseModelLists>>>> getPatientFamilyFiles(int status, int patientID) async {
try {
GenericApiModel<List<FamilyFileResponseModelLists>>? apiResponse;
Failure? failure;
await apiClient.post(
FAMILY_FILES,
body: {"Status": 3},
body: {"Status": status, "PatientID":patientID},
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},

@ -17,6 +17,7 @@ import 'package:hmg_patient_app_new/features/medical_file/models/patient_vaccine
import 'package:hmg_patient_app_new/services/dialog_service.dart';
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart';
class MedicalFileViewModel extends ChangeNotifier {
int selectedTabIndex = 0;
@ -235,7 +236,7 @@ class MedicalFileViewModel extends ChangeNotifier {
}
Future<void> getFamilyFiles({Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await medicalFileRepo.getPatientFamilyFiles();
final result = await medicalFileRepo.getPatientFamilyFiles(3,_appState.superUserID !=null ? _appState.superUserID! : _appState.getAuthenticatedUser()!.patientId!);
result.fold(
(failure) async => await errorHandlerService.handleError(
@ -256,6 +257,8 @@ class MedicalFileViewModel extends ChangeNotifier {
patientName: '${_appState.getAuthenticatedUser()!.firstName!} ${_appState.getAuthenticatedUser()!.lastName!}',
isActive: true,
gender: _appState.getAuthenticatedUser()!.gender!,
age: _appState.getAuthenticatedUser()!.age,
mobileNumber: _appState.getAuthenticatedUser()!.mobileNumber,
responseId: _appState.getAuthenticatedUser()!.patientId),
);
notifyListeners();
@ -268,14 +271,18 @@ class MedicalFileViewModel extends ChangeNotifier {
}
Future<void> switchFamilyFiles( {Function(dynamic)? onSuccess,int? responseID,int? patientID, String? phoneNumber, Function(String)? onError}) async {
authVM.phoneNumberController.text = phoneNumber!;
authVM.phoneNumberController.text =phoneNumber!.startsWith("0")
? phoneNumber.replaceFirst("0", "")
: phoneNumber;
await authVM.checkActivationCode(activationCode: '0000', otpTypeEnum: OTPTypeEnum.sms, onWrongActivationCode: (String? str) {}, responseID: responseID, requestID: patientID, isExcludedUser: true);
await authVM.checkActivationCode(activationCode: '0000', otpTypeEnum: OTPTypeEnum.sms, onWrongActivationCode: (String? str) {}, responseID: responseID, isFormFamilyFile:false, isSwitchUser: true, patientID: patientID);
}
Future<void> addFamilyFile({required OTPTypeEnum otpTypeEnum, required bool isExcludedUser}) async {
LoaderBottomSheet.showLoader();
AuthenticationViewModel authVM = getIt.get<AuthenticationViewModel>();
NavigationService navigationService = getIt.get<NavigationService>();
FamilyFileRequest request =
await RequestUtils.getAddFamilyRequest(nationalIDorFile: authVM.nationalIdController.text, mobileNo: authVM.phoneNumberController.text, countryCode: authVM.selectedCountrySignup.countryCode);
@ -285,9 +292,11 @@ class MedicalFileViewModel extends ChangeNotifier {
if (apiResponse != null && apiResponse.data != null) {
request.isPatientExcluded = apiResponse.data["IsPatientExcluded"];
request.responseID = apiResponse.data["ReponseID"];
LoaderBottomSheet.hideLoader();
_dialogService.showExceptionBottomSheet(
message: apiResponse.data['Message'],
onOkPressed: () {
LoaderBottomSheet.showLoader();
print("=================== On Press Ok ==================");
authVM.sendActivationCode(
otpTypeEnum: otpTypeEnum,
@ -298,7 +307,6 @@ class MedicalFileViewModel extends ChangeNotifier {
responseID: apiResponse.data["ReponseID"],
isFormFamilyFile: true);
// insertFamilyData(payload: apiResponse.data![0]['ShareFamilyFileObj'], isExcludedPatient: apiResponse.data![0]['ShareFamilyFileObj']['IsPatientExcluded']);
},
onCancelPressed: () {
navigationService.pop();

@ -1,4 +1,5 @@
import 'package:flutter/foundation.dart' show ChangeNotifier;
import 'package:hmg_patient_app_new/core/app_state.dart' show AppState;
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/doctor_list_api_response.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/select_clinic_page.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
@ -20,8 +21,9 @@ class AppointmentViaRegionViewmodel extends ChangeNotifier {
final NavigationService navigationService;
AppointmentViaRegionState bottomSheetState =
AppointmentViaRegionState.REGION_SELECTION;
final AppState appState;
AppointmentViaRegionViewmodel({required this.navigationService});
AppointmentViaRegionViewmodel({required this.navigationService,required this.appState});
void setSelectedRegionId(String? regionId) {
selectedRegionId = regionId;
@ -69,4 +71,6 @@ class AppointmentViaRegionViewmodel extends ChangeNotifier {
void setHospitalModel(PatientDoctorAppointmentList? hospital) {
selectedHospital = hospital;
}
bool get isArabic => appState.isArabic();
}

@ -848,5 +848,6 @@ abstract class LocaleKeys {
static const pleaseEnterAValidEmailFormat = 'pleaseEnterAValidEmailFormat';
static const selectCountry = 'selectCountry';
static const forLoginVerification = 'forLoginVerification';
static const searchHospital = 'searchHospital';
}

@ -147,8 +147,8 @@ void main() async {
),
),
ChangeNotifierProvider<AppointmentViaRegionViewmodel>(
create: (_) =>
AppointmentViaRegionViewmodel(navigationService: getIt()))
create: (_) => AppointmentViaRegionViewmodel(
navigationService: getIt(), appState: getIt()))
], child: MyApp()),
),
);

@ -38,7 +38,7 @@ class FacilityTypeSelectionWidget extends StatelessWidget {
),
),
Text(
LocaleKeys.selectFacilitiesSubTitle,
LocaleKeys.selectFacilitiesSubTitle.tr(),
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
@ -55,9 +55,11 @@ class FacilityTypeSelectionWidget extends StatelessWidget {
}),
).onPress(
() {
if(bookAppointmentViewModel.hospitalList?.registeredDoctorMap?[selectedRegion]?.hmgSize != 0) {
regionalViewModel.setFacility(FacilitySelection.HMG.name);
regionalViewModel.setBottomSheetState(
AppointmentViaRegionState.HOSPITAL_SELECTION);
}
},
),
SizedBox(height: 16.h),
@ -69,9 +71,11 @@ class FacilityTypeSelectionWidget extends StatelessWidget {
"${bookAppointmentViewModel.hospitalList?.registeredDoctorMap?[selectedRegion]?.hmcSize ?? 0}"
})).onPress(
() {
if(bookAppointmentViewModel.hospitalList?.registeredDoctorMap?[selectedRegion]?.hmcSize!= 0 ) {
regionalViewModel.setFacility(FacilitySelection.HMC.name);
regionalViewModel.setBottomSheetState(
AppointmentViaRegionState.HOSPITAL_SELECTION);
}
},
),
],

@ -50,7 +50,7 @@ class HospitalBottomSheetBody extends StatelessWidget {
SizedBox(height: 16.h),
TextInputWidget(
labelText: LocaleKeys.search.tr(),
hintText: "Search Hospital".tr(),
hintText: LocaleKeys.searchHospital.tr(),
controller: searchText,
onChange: (value) {
appointmentsViewModel.filterHospitalListByString(value, regionalViewModel.selectedRegionId , regionalViewModel.selectedFacilityType ==

@ -77,7 +77,7 @@ class RegionListItem extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Align(
alignment: Alignment.centerLeft,
alignment: AlignmentDirectional.centerStart,
child: Text(
title,
style: TextStyle(

@ -200,7 +200,11 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
void openRegionListBottomSheet(BuildContext context) {
regionalViewModel.flush();
// AppointmentViaRegionViewmodel? viewmodel = null;
showCommonBottomSheetWithoutHeight(context, title: "", titleWidget: Consumer<AppointmentViaRegionViewmodel>(builder: (_, data, __) => getTitle(data)), isDismissible: false,
showCommonBottomSheetWithoutHeight(context,
title: "",
titleWidget: Consumer<AppointmentViaRegionViewmodel>(
builder: (_, data, __) => getTitle(data)),
isDismissible: false,
child: Consumer<AppointmentViaRegionViewmodel>(builder: (_, data, __) {
return getRegionalSelectionWidget(data);
}), callBackFunc: () {});
@ -234,9 +238,19 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
if (data.selectedRegionId == null) {
return LocaleKeys.selectRegion.tr().toText20(weight: FontWeight.w600);
} else {
return Utils.buildSvgWithAssets(icon: AppAssets.arrow_back, iconColor: Color(0xff2B353E)).onPress(() {
return
Transform.flip(
flipX: data.isArabic ? true : false,
child: Utils.buildSvgWithAssets(
icon: AppAssets.arrow_back,
iconColor: Color(0xff2B353E),
fit: BoxFit.contain,
),
).onPress(() {
data.handleBackPress();
});
}
}
}

@ -16,9 +16,9 @@ import 'package:hmg_patient_app_new/presentation/lab/lab_result_item_view.dart';
import 'package:hmg_patient_app_new/presentation/lab/search_lab_report.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/chip/custom_chip_widget.dart';
import 'package:hmg_patient_app_new/widgets/custom_tab_bar.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:provider/provider.dart';
import 'package:hmg_patient_app_new/widgets/custom_tab_bar.dart';
import 'collapsing_list_view.dart';
class LabOrdersPage extends StatefulWidget {
@ -54,7 +54,13 @@ class _LabOrdersPageState extends State<LabOrdersPage> {
if (lavVM.isLabOrdersLoading) {
return;
} else {
String? value = await Navigator.of(context).push(CupertinoPageRoute(fullscreenDialog: true, builder: (context) => SearchLabResultsContent(labSuggestionsList: lavVM.labSuggestions)));
String? value = await Navigator.of(context).push(
CustomPageRoute(
page: SearchLabResultsContent(labSuggestionsList: lavVM.labSuggestions),
fullScreenDialog: true,
direction: AxisDirection.down,
),
);
if (value != null) {
selectedFilterText = value;
lavVM.filterLabReports(value);

@ -776,4 +776,9 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
return Container();
}
}
getMember() {
// AuthanticationViewModel authanticationViewModel = getIt.get<AuthanticationViewModel>();
// RequestUtils.getAddFamilyRequest(nationalIDorFile: nationalIDorFile, mobileNo: mobileNo, countryCode: countryCode, loginType: loginType);
}
}

@ -0,0 +1,173 @@
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/extensions/int_extensions.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/presentation/home/navigation_screen.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart';
import 'package:lottie/lottie.dart';
class OnboardingScreen extends StatefulWidget {
OnboardingScreen({Key? key}) : super(key: key);
@override
_OnboardingScreenState createState() {
return _OnboardingScreenState();
}
}
class _OnboardingScreenState extends State<OnboardingScreen> {
int selectedIndex = 0;
late PageController pageController;
void goToHomePage() => Navigator.of(context).pushReplacement(FadePage(page: LandingNavigation()));
@override
void initState() {
super.initState();
pageController = PageController();
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColors.whiteColor,
body: SafeArea(
top: false,
left: false,
right: false,
child: Column(
spacing: 24,
children: [
PageView(
controller: pageController,
children: [
onboardingView(
AppAnimations.onboarding_1,
"Booking appointment has never been easy".needTranslation,
"In few clicks find yourself having consultation with the doctor of your choice.".needTranslation,
),
onboardingView(
AppAnimations.onboarding_2,
"Access the medical history on finger tips".needTranslation,
"Keep track on your medical history including labs, prescription, insurance, etc".needTranslation,
),
],
onPageChanged: (int index) {
selectedIndex = index;
setState(() {});
},
).expanded,
Row(
spacing: 4.h,
children: [
AnimatedContainer(
duration: const Duration(milliseconds: 250),
height: 6.h,
width: selectedIndex == 0 ? 18.h : 6.h,
decoration: BoxDecoration(color: selectedIndex == 0 ? AppColors.textColor : AppColors.inputLabelTextColor, borderRadius: BorderRadius.circular(30)),
),
AnimatedContainer(
duration: const Duration(milliseconds: 250),
height: 6.h,
width: selectedIndex == 1 ? 18.h : 6.h,
decoration: BoxDecoration(color: selectedIndex == 1 ? AppColors.textColor : AppColors.inputLabelTextColor, borderRadius: BorderRadius.circular(30)),
),
],
).paddingOnly(left: 24, right: 24),
Row(
children: [
AnimatedSwitcher(
duration: const Duration(milliseconds: 250),
transitionBuilder: (child, anim) => FadeTransition(opacity: anim, child: child),
child: selectedIndex == 0
? CustomButton(
text: "Skip".needTranslation,
onPressed: () => goToHomePage(),
width: 86.h,
height: 56.h,
borderRadius: 12.h,
backgroundColor: Color(0xffFEE9EA),
textColor: AppColors.primaryRedColor,
borderWidth: 0,
borderColor: Colors.transparent,
).paddingOnly(left: 24)
: const SizedBox.shrink(),
),
const Spacer(),
AnimatedContainer(
duration: const Duration(milliseconds: 400),
curve: Curves.easeInOut,
width: selectedIndex == 0 ? 86 : MediaQuery.of(context).size.width - 48,
margin: EdgeInsets.only(left: 24, right: 24),
decoration: BoxDecoration(
color: AppColors.primaryRedColor,
borderRadius: BorderRadius.circular(12),
),
child: AnimatedSwitcher(
duration: const Duration(milliseconds: 250),
transitionBuilder: (child, anim) => FadeTransition(opacity: anim, child: child),
child: selectedIndex == 0
? CustomButton(
icon: AppAssets.arrow_forward,
iconSize: 32.h,
width: 86.h,
height: 56.h,
borderRadius: 12.h,
text: "".needTranslation,
backgroundColor: Colors.transparent,
onPressed: () {
pageController.animateToPage(1, duration: Duration(milliseconds: 400), curve: Curves.easeInOut);
})
: CustomButton(
text: "Get Started".needTranslation,
fontWeight: FontWeight.w500,
fontSize: 16.h,
height: 56.h,
borderRadius: 16.h,
textOverflow: TextOverflow.ellipsis,
backgroundColor: Colors.transparent,
onPressed: () => goToHomePage(),
),
),
),
],
),
],
),
),
);
}
Widget onboardingView(String icon, String heading, String body) {
return Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 12,
children: [
Align(
alignment: Alignment.bottomCenter,
child: Lottie.asset(icon, repeat: true, reverse: false, frameRate: FrameRate(60), width: MediaQuery.sizeOf(context).width - 50, height: MediaQuery.sizeOf(context).width - 50))
.expanded,
// 12.height,
Text(
heading,
style: TextStyle(fontSize: 36.h, fontWeight: FontWeight.w600, color: AppColors.textColor, letterSpacing: -0.4, height: 1),
),
Text(
body,
style: TextStyle(fontSize: 16.h, fontWeight: FontWeight.w500, color: AppColors.greyTextColor, letterSpacing: 0, height: 26 / 16),
),
],
).paddingOnly(left: 24, right: 24);
}
}

@ -0,0 +1,383 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/app_export.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/presentation/authentication/login.dart';
import 'package:hmg_patient_app_new/presentation/home/navigation_screen.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart';
import 'package:lottie/lottie.dart';
class SplashAnimationScreen extends StatefulWidget {
final Widget? routeWidget;
SplashAnimationScreen({super.key, this.routeWidget});
@override
_SplashAnimationScreenState createState() {
return _SplashAnimationScreenState();
}
}
class _SplashAnimationScreenState extends State<SplashAnimationScreen> with SingleTickerProviderStateMixin {
late final AnimationController _controller;
@override
void initState() {
super.initState();
_controller = AnimationController(vsync: this);
_controller.addListener(() {
if (_controller.status == AnimationStatus.completed) {
Navigator.of(context).pushReplacement(FadePage(page: widget.routeWidget ?? LandingNavigation()));
}
});
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColors.whiteColor,
body: Stack(
children: [
Lottie.asset(AppAnimations.splashLaunching, controller: _controller, width: double.infinity, height: double.infinity, onLoaded: (composition) {
_controller
..duration = composition.duration
..forward(); // Start the animation
}, repeat: false, reverse: false, frameRate: FrameRate(60), fit: BoxFit.fill)
.center,
],
),
);
}
}
// todo: do-not remove this code,as animation need to test on multiple screen sizes
class AnimatedScreen extends StatefulWidget {
const AnimatedScreen({super.key});
@override
State<AnimatedScreen> createState() => _AnimatedScreenState();
}
class _AnimatedScreenState extends State<AnimatedScreen> with TickerProviderStateMixin {
late AnimationController _moveController;
late Animation<Offset> _positionAnimation;
late AnimationController _expandController;
late Animation<double> _expandAnimation;
bool isRipple = false;
late final AnimationController _controller;
@override
void initState() {
super.initState();
_controller = AnimationController(vsync: this);
_controller.addListener(() {
if (_controller.status == AnimationStatus.completed) {
// Navigator.of(context).pushReplacement(
// FadePage(
// page: LoginScreen(),
// ),
// );
}
});
// Step 1: Move circle from bottom-left to top-right
_moveController = AnimationController(vsync: this, duration: const Duration(seconds: 1));
_positionAnimation = Tween<Offset>(
begin: const Offset(-1, 1),
end: const Offset(1, -1),
).animate(
CurvedAnimation(parent: _moveController, curve: const Cubic(0.82, -0.01, 0.58, 1)),
);
// Step 2: Expand white circle from center
_expandController = AnimationController(vsync: this, duration: const Duration(milliseconds: 1000));
_expandAnimation = Tween<double>(
begin: 0.0,
end: 4.0,
).animate(CurvedAnimation(parent: _expandController, curve: Curves.easeOut));
// Trigger the animations in sequence
_moveController.forward().whenComplete(() {
setState(() {
isRipple = true;
});
_expandController.forward().whenComplete(() {
setState(() {
isRipple = false;
});
});
});
}
@override
void dispose() {
_controller.dispose();
_moveController.dispose();
_expandController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final screenSize = MediaQuery.of(context).size;
return Scaffold(
backgroundColor: AppColors.whiteColor,
body: Stack(
children: [
// Moving rotated ellipse
Lottie.asset(AppAnimations.splashLaunching, controller: _controller, onLoaded: (composition) {
_controller
..duration = composition.duration
..forward(); // Start the animation
}, repeat: false, reverse: false, frameRate: FrameRate(60), fit: BoxFit.fill)
.center,
Lottie.asset(AppAnimations.loadingAnimation, repeat: true, reverse: false, frameRate: FrameRate(60), width: 80.h, height: 80.h, fit: BoxFit.fill).center,
AnimatedContainer(
duration: Duration(milliseconds: 500),
width: screenSize.width,
height: screenSize.height,
color: isRipple ? AppColors.primaryRedColor : AppColors.whiteColor,
),
AnimatedBuilder(
animation: _moveController,
builder: (context, child) {
final pos = _positionAnimation.value;
return Positioned(
left: ((screenSize.width * .75) * (pos.dx)).h,
top: ((screenSize.height * 0.75) * (pos.dy)).h,
child: Transform.rotate(
angle: -120 * 3.1415927 / 150, // convert degrees to radians
child: Container(
width: 400.h,
height: 653.h,
decoration: BoxDecoration(
color: Color(0xffED1C2B),
borderRadius: BorderRadius.circular(330.h),
),
),
),
);
},
),
// Expanding white circle
AnimatedBuilder(
animation: _expandController,
builder: (context, child) {
return Center(
child: Transform.scale(
scale: _expandAnimation.value,
child: Opacity(
opacity: 1.0, //- _expandAnimation.value.clamp(0.0, 1.0),
child: Container(
decoration: const BoxDecoration(
color: Colors.white,
shape: BoxShape.circle,
// border: Border.fromBorderSide(BorderSide(
// width: 0,
// color: Color(0xffED1C2B),
// )
)),
),
// ),
),
);
},
),
// AnimatedBuilder(
// animation: _expandController,
// builder: (context, child) {
// final screenSize = MediaQuery.of(context).size;
// final maxDiameter =
// (screenSize.width > screenSize.height ? screenSize.width : screenSize.height) * 2;
//
// return Center(
// child: Transform.scale(
// scale: _expandAnimation.value * maxDiameter / 100, // scale up to fill screen
// child: Opacity(
// opacity: (1.0 - _expandAnimation.value).clamp(0.0, 1.0),
// child: Container(
// decoration: const BoxDecoration(
// color: Colors.white,
// shape: BoxShape.circle,
// ),
// ),
// ),
// ),
// );
// },
// ),
],
),
);
}
}
class MoveObjectDemo extends StatefulWidget {
const MoveObjectDemo({super.key});
@override
State<MoveObjectDemo> createState() => _MoveObjectDemoState();
}
class _MoveObjectDemoState extends State<MoveObjectDemo> with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<Alignment> _alignmentAnimation;
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: const Duration(seconds: 1),
);
_alignmentAnimation = AlignmentTween(
begin: Alignment(-2.0, 2.5),
end: Alignment(2.5, -2),
).animate(CurvedAnimation(parent: _controller, curve: Curves.easeInOut));
_controller.forward(); // start animation
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: AnimatedBuilder(
animation: _alignmentAnimation,
builder: (context, child) {
return Align(
alignment: _alignmentAnimation.value,
child: Transform.rotate(
angle: -120 * 3.1415927 / 180,
child: Container(
width: 200,
height: 375,
decoration: BoxDecoration(
color: const Color(0xffED1C2B),
borderRadius: BorderRadius.circular(330),
),
),
),
// Transform.rotate(
// angle: -120 * 3.1415927 / 180, // convert to radians
// child: Container(
// width: 400,
// height: 653,
// decoration: BoxDecoration(
// color: const Color(0xffED1C2B),
// borderRadius: BorderRadius.circular(330),
// ),
// ),
// ),
);
},
),
);
}
}
class MoveOnClickDemo extends StatefulWidget {
const MoveOnClickDemo({super.key});
@override
State<MoveOnClickDemo> createState() => _MoveOnClickDemoState();
}
class _MoveOnClickDemoState extends State<MoveOnClickDemo> with TickerProviderStateMixin {
late AnimationController _controller;
late Animation<Alignment> _alignmentAnimation;
@override
void initState() {
super.initState();
init();
}
init() {
_controller = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 1000), // Figma duration
);
_alignmentAnimation = AlignmentTween(
// begin: Alignment(-10.0, 5),
// end: Alignment(5, -2),
begin: Alignment.bottomLeft,
end: Alignment.topRight,
).animate(CurvedAnimation(
parent: _controller,
curve: const Cubic(0.82, -0.01, 0.58, 1), // Figma cubic-bezier
));
_animate();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
void _animate() {
if (_controller.isCompleted) {
_controller.reverse();
} else {
_controller.forward();
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: GestureDetector(
onTap: _animate, // trigger on click
onDoubleTap: () {
_controller.dispose();
init();
},
child: AnimatedBuilder(
animation: _alignmentAnimation,
builder: (context, child) {
print(_alignmentAnimation.value);
return Align(
alignment: _alignmentAnimation.value,
child: Transform.rotate(
angle: -120 * 3.1415927 / 145, // -120 deg
child: Container(
width: 100,
height: 150,
decoration: BoxDecoration(
color: const Color(0xffED1C2B),
borderRadius: BorderRadius.circular(330),
),
),
),
);
},
),
),
);
}
}

@ -22,9 +22,9 @@ class NavigationService {
navigatorKey.currentState?.pushReplacementNamed(routeName);
}
Future<T?> pushToOtpScreen<T>({required String phoneNumber, required Function(int code) checkActivationCode, required Function(String phoneNumber) onResendOTPPressed}) {
Future<T?> pushToOtpScreen<T>({required String phoneNumber, required Function(int code) checkActivationCode, required Function(String phoneNumber) onResendOTPPressed, bool isFormFamilyFile = false}) {
return navigatorKey.currentState!.push(
MaterialPageRoute(builder: (_) => OTPVerificationScreen(phoneNumber: phoneNumber, checkActivationCode: checkActivationCode, onResendOTPPressed: onResendOTPPressed)),
MaterialPageRoute(builder: (_) => OTPVerificationScreen(phoneNumber: phoneNumber, checkActivationCode: checkActivationCode, onResendOTPPressed: onResendOTPPressed, isFormFamilyFile : isFormFamilyFile)),
);
}

@ -6,9 +6,13 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:flutter_zoom_videosdk/native/zoom_videosdk.dart';
import 'package:hmg_patient_app_new/presentation/onboarding/onboarding_screen.dart';
import 'package:hmg_patient_app_new/presentation/onboarding/splash_animation_screen.dart';
import 'package:hmg_patient_app_new/core/api_consts.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/app_export.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart';
// import 'package:hmg_patient_app_new/presentation/authantication/login.dart';
@ -16,6 +20,7 @@ import 'package:hmg_patient_app_new/presentation/home/landing_page.dart';
import 'package:hmg_patient_app_new/presentation/home/navigation_screen.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart';
import 'package:lottie/lottie.dart';
import 'package:provider/provider.dart';
import 'core/cache_consts.dart';
@ -31,6 +36,8 @@ class SplashPage extends StatefulWidget {
class _SplashScreenState extends State<SplashPage> {
late AuthenticationViewModel authVm;
bool isNewDesign = true;
Future<void> initializeStuff() async {
Timer(
Duration(milliseconds: 500),
@ -42,12 +49,17 @@ class _SplashScreenState extends State<SplashPage> {
await authVm.getServicePrivilege();
Timer(Duration(seconds: 2, milliseconds: 500), () async {
LocalNotification.init(onNotificationClick: (payload) {});
if (isNewDesign) {
Navigator.of(context).pushReplacement(FadePage(page: SplashAnimationScreen(routeWidget: OnboardingScreen())));
} else {
Navigator.of(context).pushReplacement(
CustomPageRoute(
page: LandingNavigation(),
// page: LoginScreen(),
),
);
}
});
var zoom = ZoomVideoSdk();
InitConfig initConfig = InitConfig(
@ -86,7 +98,9 @@ class _SplashScreenState extends State<SplashPage> {
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColors.whiteColor,
body: Stack(
body: isNewDesign
? Lottie.asset(AppAnimations.loadingAnimation, repeat: true, reverse: false, frameRate: FrameRate(60), width: 80.h, height: 80.h, fit: BoxFit.fill).center
: Stack(
alignment: Alignment.center,
children: [
Padding(

@ -20,7 +20,9 @@ class CustomButton extends StatelessWidget {
final bool isDisabled;
final Color? iconColor;
final double height;
final double? width;
final double iconSize;
final TextOverflow? textOverflow;
CustomButton({
Key? key,
@ -39,7 +41,9 @@ class CustomButton extends StatelessWidget {
this.icon,
this.iconColor = Colors.white,
this.height = 56,
this.width,
this.iconSize = 24,
this.textOverflow,
}) : super(key: key);
@override
@ -48,6 +52,7 @@ class CustomButton extends StatelessWidget {
onTap: isDisabled ? null : onPressed,
child: Container(
height: height,
width: width,
padding: padding,
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: isDisabled ? Colors.transparent : backgroundColor,
@ -69,6 +74,7 @@ class CustomButton extends StatelessWidget {
padding: EdgeInsets.only(top: 2.5),
child: Text(
text,
overflow: textOverflow,
style: context.dynamicTextStyle(
fontSize: fontSize.fSize,
color: isDisabled ? textColor.withOpacity(0.5) : textColor,

@ -2,14 +2,16 @@ import 'package:flutter/material.dart';
import 'package:flutter/physics.dart';
/// Reusable spring route
class CustomPageRoute extends PageRouteBuilder {
class CustomPageRoute<T> extends PageRouteBuilder<T> {
final Widget page;
final AxisDirection direction;
final bool fullScreenDialog;
CustomPageRoute({required this.page, this.direction = AxisDirection.right})
CustomPageRoute({required this.page, this.direction = AxisDirection.right, this.fullScreenDialog = false})
: super(
transitionDuration: const Duration(milliseconds: 1500),
reverseTransitionDuration: const Duration(milliseconds: 500),
fullscreenDialog: fullScreenDialog,
pageBuilder: (_, __, ___) => page,
transitionsBuilder: (context, animation, secondaryAnimation, child) {
final spring = SpringDescription(mass: 1, stiffness: 100, damping: 15);

Loading…
Cancel
Save