initial commit

main
Haroon Amjad 2 months ago
commit b6766654e0

45
.gitignore vendored

@ -0,0 +1,45 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.build/
.buildlog/
.history
.svn/
.swiftpm/
migrate_working_dir/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/
# Flutter/Dart/Pub related
**/doc/api/
**/ios/Flutter/.last_build_id
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
.pub-cache/
.pub/
/build/
# Symbolication related
app.*.symbols
# Obfuscation related
app.*.map.json
# Android Studio will place build artifacts here
/android/app/debug
/android/app/profile
/android/app/release

@ -0,0 +1,33 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
version:
revision: "d7b523b356d15fb81e7d340bbe52b47f93937323"
channel: "stable"
project_type: app
# Tracks metadata for the flutter migrate command
migration:
platforms:
- platform: root
create_revision: d7b523b356d15fb81e7d340bbe52b47f93937323
base_revision: d7b523b356d15fb81e7d340bbe52b47f93937323
- platform: android
create_revision: d7b523b356d15fb81e7d340bbe52b47f93937323
base_revision: d7b523b356d15fb81e7d340bbe52b47f93937323
- platform: ios
create_revision: d7b523b356d15fb81e7d340bbe52b47f93937323
base_revision: d7b523b356d15fb81e7d340bbe52b47f93937323
# User provided section
# List of Local paths (relative to this file) that should be
# ignored by the migrate tool.
#
# Files that are not part of the templates will be ignored by default.
unmanaged_files:
- 'lib/main.dart'
- 'ios/Runner.xcodeproj/project.pbxproj'

@ -0,0 +1,16 @@
# hmg_patient_app_new
New HMG Patient App
## Getting Started
This project is a starting point for a Flutter application.
A few resources to get you started if this is your first Flutter project:
- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
For help getting started with Flutter development, view the
[online documentation](https://docs.flutter.dev/), which offers tutorials,
samples, guidance on mobile development, and a full API reference.

@ -0,0 +1,28 @@
# This file configures the analyzer, which statically analyzes Dart code to
# check for errors, warnings, and lints.
#
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
# invoked from the command line by running `flutter analyze`.
# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml
linter:
# The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
# included above or to enable additional rules. A list of all available lints
# and their documentation is published at https://dart.dev/lints.
#
# Instead of disabling a lint rule for the entire project in the
# section below, it can also be suppressed for a single line of code
# or a specific dart file by using the `// ignore: name_of_lint` and
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint.
rules:
# avoid_print: false # Uncomment to disable the `avoid_print` rule
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options

@ -0,0 +1,9 @@
{
"english": "English",
"arabic": "عربي",
"login": "تسجيل الدخول",
"noDataAvailable": "لا تتوافر بيانات",
"ok": "موافق",
"confirm": "تأكيد",
"loadingText": "جاري التحميل، الرجاء الانتظار..."
}

@ -0,0 +1,9 @@
{
"english": "English",
"arabic": "عربي",
"login": "Login",
"noDataAvailable": "No Data Available",
"confirm": "Confirm",
"ok": "OK",
"loadingText": "Loading, please wait..."
}

BIN
key

Binary file not shown.

@ -0,0 +1,4 @@
storePassword=HmGsa123
keyPassword=HmGsa123
keyAlias=hmg
storeFile=key

@ -0,0 +1,2 @@
export '../routes/app_routes.dart';
export 'utils/size_utils.dart';

@ -0,0 +1,38 @@
import 'dart:io';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:hmg_patient_app_new/main.dart';
import 'consts.dart';
class AppState {
static final AppState _instance = AppState._internal();
AppState._internal();
factory AppState() => _instance;
//Tokens
bool isAuthenticated = false;
set setIsAuthenticated(v) => isAuthenticated = v;
set setAppAuthToken(v) => appAuthToken = v;
String appAuthToken = "";
set setUserLat(v) => userLat = v;
set setUserLong(v) => userLong = v;
double userLat = 0.0;
double userLong = 0.0;
bool isArabic() => EasyLocalization.of(navigatorKey.currentContext!)?.locale.languageCode == "ar";
int getLanguageID(context) => EasyLocalization.of(context)?.locale.languageCode == "ar" ? 1 : 2;
// bool isUserLoggedIn() =>
}

@ -0,0 +1,163 @@
class ApiConsts {
static const maxSmallScreen = 660;
static bool isDevelopment = true;
// static String baseUrlBackend = 'http://ec2-13-51-36-142.eu-north-1.compute.amazonaws.com:8082/api/'; // Backend API URL UAT
// static String baseUrlBackend = 'http://207.127.99.20:82/api/'; // Backend API URL PROD
static String baseUrlBackend = 'https://api-mob.meena-health.com/api/'; // Backend API URL PROD
static String checkIfUserExists = 'UserRegistrationHIS/phone';
static String checkIfUserExistsMultiple = 'UserRegistrationHIS/phone/multiple';
static String checkIfUserExistsByMRN = 'UserRegistrationHIS/mrn/phone';
static String checkIfUserLastLoggedIn = 'UserRegistrationHIS/device-token';
static String updateUserLastLogIn = 'UserRegistrationHIS/save-device-token';
static String getStories = 'Stories';
static String saveAppointmentDetailsInBackend = 'UserAppointment';
static String getPatientAppointmentHistory = 'UserAppointment/my-appointments';
static String updateAppointmentDetailsInBackend = 'UserAppointment/update/';
static String submitDoctorReview = 'DoctorReview/submit-review';
static String getUserDataFromYakeenByIqama = 'Yakeen/by-iqama';
static String getUserDataFromYakeenByNin = 'Yakeen/by-nin';
static String sendVerificationCode = 'UserLogin/otp-request';
static String checkVerificationCode = 'UserLogin/otp-verify';
static String registerNewPatient = 'UserRegistrationHIS/save/patient';
static String getPatientVitalSignsHistory = 'Vitals/my-vitals';
static String getPatientLabReports = 'LabsOrder/my-orders';
static String getPatientRadReports = 'RadiologyOrder/my-orders';
static String getPatientPrescriptionsReports = 'Prescription/my-prescriptions';
static String updatePatientStoryViewedAPI = 'Stories/view';
static String getClinicsList = 'Clinics';
static String getDoctorsList = 'Doctors';
static String checkAppVersion = 'AppVersion/check-version';
static String getPatientLabOrdersAndResults = 'LabsOrder/my-order-result';
static String updatePatientProfile = 'Users/profile-update';
static String getPatientVitalSignsFromHIS = 'getpatientvital';
static String getDoctorReviewsByDoctorID = 'DoctorReview/';
// static String baseUrl = 'http://158.101.230.106:5016/phi/'; // HIS API URL UAT
static String baseUrl = 'http://158.101.232.32:5016/phi/'; // HIS API URL PROD
//Doctor Search
static String doctorSearch = 'doctor/search';
//Get Patient Data
static String getPatientData = 'patientdata/getpatientsdata';
//Get Free Slots
static String getFreeSlots = 'doctor/timeslot';
//Create Appointment
static String createAppointment = 'patient/appointment/create';
//Cancel Appointment
static String cancelAppointment = 'patient/appointment/create';
//Create Deposit
static String createDeposit = 'patient/PatientDeposits';
//Update Patient Photo
static String updatePatientPhoto = 'patientphoto';
// get Patient Insurance Details
static String getPatientInsuranceDetails = "http://158.101.232.32:5021/getpolicydetails";
// get Patient Insurance Details
static String getDoctorSessionsByAppointments = "http://158.101.232.32:5016/phi/doctor/getdoctorsessionbyappointment"; // Prod
// static String getDoctorSessionsByAppointments = "http://158.101.230.106:5016/phi/doctor/getdoctorsessionbyappointment"; // UAT
//get Organization List
static String getOrganizationsList = 'organisationsearch';
//get Departments List
static String getDepartmentsList = 'getdepartmentsearch';
static String VERSION_ID = "1.6";
// Nabed APIs
static String nabedBaseUrl = "https://portal.nabed.net/api/"; // Live
static String nabedAuthenticationURL = "auth/jwt-token";
static String nabedGetPatientData = "educate/external/content/icd?page=";
// SANED URLs
static String sanedLoginPassword = "Aa123456@";
static String sanedSource = "Meena Mobile App";
static String baseUrlSaned = 'https://staging.sanedhealth.com/'; // SANED API URL STAGING
// static String baseUrlSaned = 'https://hc.sanedhealth.com/'; // SANED API URL PRODUCTION
static String sanedAPIVersion = 'mn_hc/';
// static String sanedWebSocketURL = 'wss://locationapi.sanedhealth.com/ws?apikey=st_zuhDm9xSyI'; // UAT SANED WEBSOCKET URL
static String sanedWebSocketURL = 'wss://locationapiprod.sanedhealth.com/ws?apikey=st_A1xVs5qA7z'; // PRODUCTION WEBSOCKET URL
static String getSanedAuthToken = 'api/external/login';
static String getSanedProductCategories = 'get_product_categories';
static String getProductPackages = 'get/product/packages';
static String getPackageDetails = 'get/package/details';
static String checkPatientByNationalitySaned = 'check_patient_by_nationality';
static String signupPatient = 'api/signup';
static String getPatientCartDetails = 'shop/cart';
static String addPackageToCart = 'shop/cart/update';
static String updateCartItems = 'shop/cart/update_json';
static String getPatientLocationList = 'get_patient_location_list';
static String updatePatientLocationList = 'update_patient_location';
static String getAvailableSlots = 'get/category/slot';
static String createHHCAppointment = 'api/create/appointment';
static String cancelHHCAppointment = 'cancel_appointment';
static String getBlackOutDates = 'get/blackout/dates';
// static String createConfirmHHCAppointment = 'api/create/appointment';
static String getPatientHHCAppointmentHistory = 'get_patient_medical_history/appointment';
static setBackendURLs() {
if (isDevelopment) {
baseUrlSaned = 'https://staging.sanedhealth.com/';
sanedWebSocketURL = "wss://locationapi.sanedhealth.com/ws?apikey=st_zuhDm9xSyI";
baseUrlBackend = "http://ec2-13-51-36-142.eu-north-1.compute.amazonaws.com:8082/api/";
baseUrl = "http://158.101.230.106:5016/phi/";
getDoctorSessionsByAppointments = "http://158.101.230.106:5016/phi/doctor/getdoctorsessionbyappointment";
} else {
baseUrlSaned = 'https://hc.sanedhealth.com/';
sanedWebSocketURL = "wss://locationapiprod.sanedhealth.com/ws?apikey=st_A1xVs5qA7z";
baseUrlBackend = "https://api-mob.meena-health.com/api/";
baseUrl = "http://158.101.232.32:5016/phi/";
getDoctorSessionsByAppointments = "http://158.101.232.32:5016/phi/doctor/getdoctorsessionbyappointment";
}
}
// Login
// static String baseUrlLogin = 'https://keycloak.dev.evxtest.monster/realms/';
// static String getLoginToken = 'my_city_uat/protocol/openid-connect/token';
}
class SharedPrefsConsts {
static String isRememberMe = "remember_me";
static String username = "doctorId";
static String password = "password";
static String logInTokenID = "logInTokenID";
static String vidaAuthTokenID = "vidaAuthTokenID";
static String vidaRefreshTokenID = "vidaRefreshTokenID";
static String authenticationTokenID = "authenticationTokenID";
static String projectID = "projectID";
static String clinicId = "clinicId";
static String lastLoginDate = "lastLoginDate";
static String lastLoginTime = "lastLoginTime";
static String memberModel = "memberModel";
static String isShowOnboarding = "is_show_onboarding";
static String appAuthToken = "app_auth_token";
static String appUserID = "app_user_id";
static String loggedInUserObj = "logged_in_user_obj";
static String PUSH_TOKEN = "push_token";
static String APNS_TOKEN = "apns_token";
static String VOIP_TOKEN = "voip_token";
static String PATIENT_MRN = "patient_mrn";
static String loggedInUserID = "logged_in_user_id";
static String loggedInUserPassword = "logged_in_user_password";
static String user_lat = 'user-lat';
static String user_long = 'user-long';
}

@ -0,0 +1,9 @@
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:injector/injector.dart';
class AppDependencies {
static void addDependencies() {
Injector injector = Injector.appInstance;
injector.registerSingleton<AppState>(() => AppState());
}
}

@ -0,0 +1,29 @@
// enum APPSTATUS {
// loading,
// unAuthenticated,
// authenticated,
// unverified,
// }
enum AuthMethodTypes {
sms,
whatsApp,
fingerPrint,
faceID,
moreOptions,
}
enum ViewState {
hide,
idle,
busy,
error,
busyLocal,
errorLocal,
}
enum LoginType {
FROM_LOGIN,
SILENT_LOGIN,
SILENT_WITH_OTP,
}

@ -0,0 +1,174 @@
import 'dart:io';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/consts.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:flutter/cupertino.dart';
import 'package:geolocator/geolocator.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
// import 'package:huawei_location/huawei_location.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:provider/provider.dart';
class LocationUtils {
bool isShowConfirmDialog;
bool isShowLocationTimeoutDialog;
BuildContext context;
bool isHuawei;
final GeolocatorPlatform _geolocatorPlatform = GeolocatorPlatform.instance;
LocationUtils({required this.isShowConfirmDialog, required this.context, this.isHuawei = false, this.isShowLocationTimeoutDialog = true});
void getCurrentLocation({Function(LatLng)? callBack}) async {
Geolocator.isLocationServiceEnabled().then((value) async {
if (value) {
await Geolocator.checkPermission().then((permission) async {
if (permission == LocationPermission.always || permission == LocationPermission.whileInUse) {
// Geolocator.getCurrentPosition(locationSettings: LocationSettings(accuracy: LocationAccuracy.medium, timeLimit: Duration(seconds: 5))).then((value) {
Geolocator.getLastKnownPosition().then((value) {
setLocation(value);
if (callBack != null) callBack(LatLng(value?.latitude ?? 24.7101433, value?.longitude ?? 46.6757709));
}).catchError((err) {
print(err);
if (isShowConfirmDialog && isShowLocationTimeoutDialog) {
// showLocationTimeOutDialog(failureCallBack: () {
// Geolocator.openAppSettings();
// });
}
});
}
if (permission == LocationPermission.denied || permission == LocationPermission.deniedForever) {
if (Platform.isAndroid) {
// Utils.showPermissionConsentDialog(context, TranslationBase.of(context).locationPermissionDialog, () async {
final hasPermission = await _handlePermission();
if (hasPermission) {
// Geolocator.getCurrentPosition(locationSettings: LocationSettings(accuracy: LocationAccuracy.medium, timeLimit: Duration(seconds: 5))).then((value) {
Geolocator.getLastKnownPosition().then((value) {
setLocation(value);
if (callBack != null) callBack(LatLng(value?.latitude ?? 24.7101433, value?.longitude ?? 46.6757709));
});
} else {
// if (isShowConfirmDialog) showErrorLocationDialog(false, failureCallBack: () {});
}
// });
} else {
if (await Permission.location.request().isGranted) {
getCurrentLocation(callBack: callBack);
} else {
setZeroLocation();
if (isShowConfirmDialog) showErrorLocationDialog(false, failureCallBack: () {});
}
}
}
}).catchError((err) {
print(err);
});
} else {
if (isShowConfirmDialog) showErrorLocationDialog(false, failureCallBack: () {});
}
}).catchError((err) {
print(err);
});
}
Future<bool> checkIfGPSIsEnabled() async {
return await Geolocator.isLocationServiceEnabled();
}
Future<bool> _handlePermission() async {
bool serviceEnabled;
LocationPermission permission;
serviceEnabled = await _geolocatorPlatform.isLocationServiceEnabled();
if (!serviceEnabled) {
return false;
}
permission = await _geolocatorPlatform.checkPermission();
if (permission == LocationPermission.denied) {
permission = await _geolocatorPlatform.requestPermission();
if (permission == LocationPermission.denied) {
return false;
}
}
if (permission == LocationPermission.deniedForever) {
return false;
}
return true;
}
// showLocationTimeOutDialog({Function()? failureCallBack}) {
// ConfirmDialog dialog = new ConfirmDialog(
// context: context,
// confirmMessage: TranslationBase.of(context).locationTimeoutError,
// okText: TranslationBase.of(context).ok,
// cancelText: TranslationBase.of(context).cancel_nocaps,
// okFunction: () {
// ConfirmDialog.closeAlertDialog(context);
// Navigator.of(context).canPop();
// if (failureCallBack != null) {
// failureCallBack();
// }
// },
// cancelFunction: () {
// if (failureCallBack != null) {
// failureCallBack();
// }
// });
// return dialog.showAlertDialog(context);
// }
showErrorLocationDialog(bool isPermissionError, {Function()? failureCallBack}) {
setLocation(null);
// ConfirmDialog dialog = new ConfirmDialog(
// context: context,
// confirmMessage: TranslationBase.of(context).locationDialogMessage,
// okText: TranslationBase.of(context).confirm,
// cancelText: TranslationBase.of(context).cancel_nocaps,
// okFunction: () {
// ConfirmDialog.closeAlertDialog(context);
// if (isPermissionError)
// Geolocator.openAppSettings();
// else
// Geolocator.openLocationSettings();
// Navigator.of(context).canPop();
// if (failureCallBack != null) {
// failureCallBack();
// }
// },
// cancelFunction: () {
// if (failureCallBack != null) {
// failureCallBack();
// }
// });
// return dialog.showAlertDialog(context);
}
void setLocation(Position? position) {
Utils.saveNumFromPrefs(SharedPrefsConsts.user_lat, position?.latitude ?? 0.0);
Utils.saveNumFromPrefs(SharedPrefsConsts.user_lat, position?.longitude ?? 0.0);
AppState().setUserLat = position?.latitude ?? 0.0;
AppState().setUserLong = position?.longitude ?? 0.0;
// projectViewModel.setLatitudeLongitude(position?.latitude ?? 0.0, position?.longitude ?? 0.0);
}
void setZeroLocation() {
Utils.saveNumFromPrefs(SharedPrefsConsts.user_lat, 0.0);
Utils.saveNumFromPrefs(SharedPrefsConsts.user_lat, 0.0);
AppState().setUserLat = 0.0;
AppState().setUserLong = 0.0;
}
Future<bool> requestPermissions() async {
var result = await [
Permission.location,
].request();
return (result[Permission.location]!.isGranted || result[Permission.locationAlways]!.isGranted);
}
}

@ -0,0 +1,178 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:ui';
import 'package:device_calendar/device_calendar.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:manage_calendar_events/manage_calendar_events.dart' as ios;
import 'package:timezone/data/latest.dart' as tzl;
final DeviceCalendarPlugin deviceCalendarPlugin = DeviceCalendarPlugin();
final ios.CalendarPlugin _myPlugin = ios.CalendarPlugin();
class CalendarUtils {
static Completer<CalendarUtils>? _completer;
dynamic get writableCalendars => calendars.firstWhere((c) => !c.isReadOnly!);
dynamic calendars;
CalendarUtils._(this.calendars);
// static Future<CalendarUtils> getInstance() async {
// if (_completer == null) {
// _completer = Completer<CalendarUtils>();
// print(_completer!.isCompleted);
// try {
// final dynamic calendarsResult;
// if (Platform.isIOS) {
// calendarsResult = await _myPlugin.getCalendars();
// if (!_completer!.isCompleted) {
// _completer?.complete(CalendarUtils._(await calendarsResult!));
// }
// } else {
// calendarsResult = await deviceCalendarPlugin.retrieveCalendars();
// if (!_completer!.isCompleted) {
// _completer?.complete(CalendarUtils._(await calendarsResult.data!));
// }
// }
// } on Exception catch (e) {
// if (!_completer!.isCompleted) {
// _completer!.completeError(e);
// }
// }
// }
// return _completer!.future;
// }
static Future<CalendarUtils> getInstance() async {
tzl.initializeTimeZones();
if (_completer != null) {
return _completer!.future;
}
_completer = Completer<CalendarUtils>();
try {
final dynamic calendarsResult;
if (Platform.isIOS) {
calendarsResult = await _myPlugin.getCalendars();
_completer!.complete(CalendarUtils._(calendarsResult));
} else {
calendarsResult = await deviceCalendarPlugin.retrieveCalendars();
_completer!.complete(CalendarUtils._(calendarsResult.data));
}
} catch (e) {
_completer!.completeError(e);
}
return _completer!.future;
}
Future createOrUpdateEvents({List<DateTime>? scheduleList, String? title, String? description, List<DateTime>? scheduleDateTime, List<DayOfWeek>? daysOfWeek}) async {
tzl.initializeTimeZones();
List<Event> events = [];
Location _currentLocation;
if (DateTime.now().timeZoneName == "+04")
_currentLocation = getLocation('Asia/Dubai');
else
_currentLocation = getLocation('Asia/Riyadh');
scheduleDateTime!.forEach((element) {
RecurrenceRule recurrenceRule = RecurrenceRule(
// RecurrenceFrequency.Daily,
// daysOfWeek: daysOfWeek,
// endDate: element,
until: element, frequency: Frequency.daily,
);
//added byAamir Tz Time
Event event = Event(writableCalendars!.id,
recurrenceRule: recurrenceRule,
start: TZDateTime.from(element, _currentLocation),
end: TZDateTime.from(element.add(Duration(minutes: 30)), _currentLocation),
title: title,
description: description);
events.add(event);
});
events.forEach((element) {
deviceCalendarPlugin.createOrUpdateEvent(element);
});
}
Future createOrUpdateEvent({required String title, required String description, required String location, DateTime? scheduleDateTime, String? eventId}) async {
RecurrenceRule recurrenceRule = RecurrenceRule(
// RecurrenceFrequency.Daily,
// daysOfWeek: daysOfWeek,
// endDate: scheduleDateTime,
until: scheduleDateTime, frequency: Frequency.daily,
);
Location _currentLocation;
// if (DateTime.now().timeZoneName == "+04")
// _currentLocation = getLocation('Asia/Dubai');
// else
_currentLocation = getLocation('Asia/Riyadh');
TZDateTime scheduleDateTimeUTZ = TZDateTime.from(scheduleDateTime!, _currentLocation);
print("writableCalendars-name: " + writableCalendars.name);
print("writableCalendars-Id: " + writableCalendars.id);
print("writableCalendarsToString: " + writableCalendars.toString());
print("writableCalendarsToString: " + writableCalendars!.id!);
Event event = Event(
writableCalendars!.id,
start: scheduleDateTimeUTZ,
end: scheduleDateTimeUTZ.add(Duration(minutes: 30)),
title: title,
description: description,
);
ios.CalendarEvent iosCalEvent =
ios.CalendarEvent(location: location, startDate: scheduleDateTimeUTZ, endDate: scheduleDateTimeUTZ.add(Duration(minutes: 30)), title: title, description: description, isAllDay: false);
if (Platform.isAndroid) {
Result<bool> result = await deviceCalendarPlugin.hasPermissions();
print(result);
await deviceCalendarPlugin.createOrUpdateEvent(event).catchError((e) {
print("catchError " + e.toString());
}).whenComplete(() {
print("whenComplete Calender ID " + eventId!);
// Utils.showToast(LocaleKeys.appoReminderSuccess.tr());
});
} else {
await _myPlugin.createEvent(calendarId: writableCalendars.id!, event: iosCalEvent).catchError((e) {
print("catchError " + e.toString());
}).whenComplete(() {
print("whenComplete Calender ID iOS " + eventId!);
// Utils.showToast(LocaleKeys.appoReminderSuccess.tr());
});
}
}
deleteEvent(String _calendarId, String _eventId) async {
if (Platform.isIOS) {
await _myPlugin.deleteEvent(calendarId: _calendarId, eventId: _eventId);
} else {
await deviceCalendarPlugin.deleteEvent(_calendarId, _eventId);
}
}
Future retrieveEvents(
String calendarId,
RetrieveEventsParams retrieveEventsParams,
) async {
if (Platform.isIOS) {
return await _myPlugin.getEvents(calendarId: calendarId);
} else {
return await deviceCalendarPlugin.retrieveEvents(calendarId, retrieveEventsParams);
}
}
Future createCalendar(
String calendarName, {
Color? calendarColor,
String? localAccountName,
}) async {
return await deviceCalendarPlugin.createCalendar(calendarName, calendarColor: calendarColor, localAccountName: localAccountName);
}
}

@ -0,0 +1,191 @@
import 'dart:math';
import 'dart:typed_data';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
class LocalNotification {
Function(String payload)? _onNotificationClick;
static LocalNotification? _instance;
static LocalNotification? getInstance() {
return _instance;
}
static init({required Function(String payload) onNotificationClick}) {
if (_instance == null) {
_instance = LocalNotification();
_instance?._onNotificationClick = onNotificationClick;
_instance?._initialize();
} else {
// assert(false,(){
// //TODO fix it
// "LocalNotification Already Initialized";
// });
}
}
_initialize() async {
try {
var initializationSettingsAndroid = new AndroidInitializationSettings('app_icon');
var initializationSettingsIOS = DarwinInitializationSettings();
var initializationSettings = InitializationSettings(android: initializationSettingsAndroid, iOS: initializationSettingsIOS);
await flutterLocalNotificationsPlugin.initialize(
initializationSettings,
onDidReceiveNotificationResponse: (NotificationResponse notificationResponse) {
switch (notificationResponse.notificationResponseType) {
case NotificationResponseType.selectedNotification:
// selectNotificationStream.add(notificationResponse.payload);
break;
case NotificationResponseType.selectedNotificationAction:
// if (notificationResponse.actionId == navigationActionId) {
// selectNotificationStream.add(notificationResponse.payload);
// }
break;
}
},
// onDidReceiveBackgroundNotificationResponse: notificationTapBackground,
);
} catch (ex) {
print(ex.toString());
}
// flutterLocalNotificationsPlugin.initialize(initializationSettings, onDidReceiveNotificationResponse: (NotificationResponse notificationResponse)
// {
// switch (notificationResponse.notificationResponseType) {
// case NotificationResponseType.selectedNotification:
// // selectNotificationStream.add(notificationResponse.payload);
// break;
// case NotificationResponseType.selectedNotificationAction:
// // if (notificationResponse.actionId == navigationActionId) {
// // selectNotificationStream.add(notificationResponse.payload);
// }
// // break;
// },}
//
// ,
//
// );
}
// void notificationTapBackground(NotificationResponse notificationResponse) {
// // ignore: avoid_print
// print('notification(${notificationResponse.id}) action tapped: '
// '${notificationResponse.actionId} with'
// ' payload: ${notificationResponse.payload}');
// if (notificationResponse.input?.isNotEmpty ?? false) {
// // ignore: avoid_print
// print('notification action tapped with input: ${notificationResponse.input}');
// }
// }
var _random = new Random();
_randomNumber({int from = 100000}) {
return _random.nextInt(from);
}
_vibrationPattern() {
var vibrationPattern = Int64List(4);
vibrationPattern[0] = 0;
vibrationPattern[1] = 1000;
vibrationPattern[2] = 5000;
vibrationPattern[3] = 2000;
return vibrationPattern;
}
Future? showNow({required String title, required String subtitle, required String payload}) {
Future.delayed(Duration(seconds: 1)).then((result) async {
var androidPlatformChannelSpecifics = AndroidNotificationDetails(
'com.hmg.local_notification',
'HMG',
channelDescription: 'HMG',
importance: Importance.max,
priority: Priority.high,
ticker: 'ticker',
vibrationPattern: _vibrationPattern(),
ongoing: true,
autoCancel: false,
usesChronometer: true,
when: DateTime.now().millisecondsSinceEpoch - 120 * 1000,
);
var iOSPlatformChannelSpecifics = DarwinNotificationDetails();
var platformChannelSpecifics = NotificationDetails(android: androidPlatformChannelSpecifics, iOS: iOSPlatformChannelSpecifics);
await flutterLocalNotificationsPlugin.show(25613, title, subtitle, platformChannelSpecifics, payload: payload).catchError((err) {
print(err);
});
});
}
Future scheduleNotification({required DateTime scheduledNotificationDateTime, required String title, required String description}) async {
///vibrationPattern
var vibrationPattern = Int64List(4);
vibrationPattern[0] = 0;
vibrationPattern[1] = 1000;
vibrationPattern[2] = 5000;
vibrationPattern[3] = 2000;
// var androidPlatformChannelSpecifics = AndroidNotificationDetails('active-prescriptions', 'ActivePrescriptions',
// channelDescription: 'ActivePrescriptionsDescription',
// // icon: 'secondary_icon',
// sound: RawResourceAndroidNotificationSound('slow_spring_board'),
//
// ///change it to be as ionic
// // largeIcon: DrawableResourceAndroidBitmap('sample_large_icon'),///change it to be as ionic
// vibrationPattern: vibrationPattern,
// enableLights: true,
// color: const Color.fromARGB(255, 255, 0, 0),
// ledColor: const Color.fromARGB(255, 255, 0, 0),
// ledOnMs: 1000,
// ledOffMs: 500);
// var iOSPlatformChannelSpecifics = DarwinNotificationDetails(sound: 'slow_spring_board.aiff');
// /change it to be as ionic
// var platformChannelSpecifics = NotificationDetails(android: androidPlatformChannelSpecifics, iOS: iOSPlatformChannelSpecifics);
// await flutterLocalNotificationsPlugin.schedule(0, title, description, scheduledNotificationDateTime, platformChannelSpecifics);
}
///Repeat notification every day at approximately 10:00:00 am
Future showDailyAtTime() async {
// var time = Time(10, 0, 0);
// var androidPlatformChannelSpecifics = AndroidNotificationDetails('repeatDailyAtTime channel id', 'repeatDailyAtTime channel name', channelDescription: 'repeatDailyAtTime description');
// var iOSPlatformChannelSpecifics = DarwinNotificationDetails();
// var platformChannelSpecifics = NotificationDetails(
// androidPlatformChannelSpecifics, iOSPlatformChannelSpecifics);
// await flutterLocalNotificationsPlugin.showDailyAtTime(
// 0,
// 'show daily title',
// 'Daily notification shown at approximately ${_toTwoDigitString(time.hour)}:${_toTwoDigitString(time.minute)}:${_toTwoDigitString(time.second)}',
// time,
// platformChannelSpecifics);
}
///Repeat notification weekly on Monday at approximately 10:00:00 am
Future showWeeklyAtDayAndTime() async {
// var time = Time(10, 0, 0);
// var androidPlatformChannelSpecifics = AndroidNotificationDetails('show weekly channel id', 'show weekly channel name', channelDescription: 'show weekly description');
// var iOSPlatformChannelSpecifics = DarwinNotificationDetails();
// var platformChannelSpecifics = NotificationDetails(
// androidPlatformChannelSpecifics, iOSPlatformChannelSpecifics);
// await flutterLocalNotificationsPlugin.showWeeklyAtDayAndTime(
// 0,
// 'show weekly title',
// 'Weekly notification shown on Monday at approximately ${_toTwoDigitString(time.hour)}:${_toTwoDigitString(time.minute)}:${_toTwoDigitString(time.second)}',
// Day.Monday,
// time,
// platformChannelSpecifics);
}
String _toTwoDigitString(int value) {
return value.toString().padLeft(2, '0');
}
Future cancelNotification() async {
await flutterLocalNotificationsPlugin.cancel(0);
}
Future cancelAllNotifications() async {
await flutterLocalNotificationsPlugin.cancelAll();
}
}

@ -0,0 +1,383 @@
import 'dart:async';
import 'dart:developer';
import 'dart:io';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:firebase_messaging/firebase_messaging.dart' as fir;
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_callkit_incoming/flutter_callkit_incoming.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:hmg_patient_app_new/core/utils/LocalNotification.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:uuid/uuid.dart';
import '../consts.dart';
// |--> Push Notification Background
@pragma('vm:entry-point')
Future<dynamic> backgroundMessageHandler(dynamic message) async {
print("Firebase backgroundMessageHandler!!!");
await Firebase.initializeApp();
fir.RemoteMessage message_;
if (message.data != null && (message.data['is_call'] == 'true' || message.data['is_call'] == true)) {
// showCallkitIncoming(message);
_incomingCall(message.data);
return;
} else {}
}
callPage(String sessionID, String token) async {}
_incomingCall(Map<String, dynamic> data) async {
// LandingPage.incomingCallData = IncomingCallData.fromJson(data);
// var dataItem = await AppSharedPreferences().getObject('call_data');
// if(dataItem != null ) return; // to stop repeated attempt to invoke the call
// if (LandingPage.isOpenCallPage == false) {
// LandingPage.isOpenCallPage = true;
WidgetsFlutterBinding.ensureInitialized();
// var _currentUuid = Uuid().v4();
// await FlutterCallkitIncoming.showCallkitIncoming(callKitParams);
// }
// LandingPage.isOpenCallPage = false;
await Future.delayed(Duration(milliseconds: 500));
}
Future<void> openCallPage(BuildContext context) async {
try {
// if (incomingCallData!.background == "0") {
// Zoom Call Page
// Navigator.of(context).pop();
Navigator.pushReplacementNamed(
context,
"zoom_call_page",
// arguments: CallArguments(incomingCallData!.sessionId!, "123", "Patient", "40", "0", false, int.parse(incomingCallData!.appointmentNo!)),
);
// } else {
// // OpenTok Call Page
// await Navigator.of(context).pushReplacement(
// MaterialPageRoute(
// // fullscreenDialog: true,
// builder: (BuildContext context) {
// // final caller = widget.incomingCallData.callerID;
// // final receiver = widget.incomingCallData.receiverID;
// // final host = widget.incomingCallData.server;
// // if(widget.incomingCallData.isWebRTC == "true"){
// // return StartVideoCall(caller: caller, receiver: receiver, iAmCaller: false, host: host);
// // }else{
// return OpenTokConnectCallPage(apiKey: OPENTOK_API_KEY, sessionId: incomingCallData!.sessionId!, token: incomingCallData!.token!);
// },
// ),
// );
// }
} catch (err) {
print(err);
// await PlatformExceptionAlertDialog(
// exception: Exception(err),
// ).show(context);
}
}
// Future<void> showCallkitIncoming(Map message) async {
// // if (message['type'] == 'ReservationCallStart') {
// var params = CallKitParams(
// id: DateTime.now().millisecondsSinceEpoch.toString(),
// nameCaller: 'Dr Sulaiman Al Habib',
// appName: 'Dr Sulaiman Al Habib',
// avatar: 'https://play-lh.googleusercontent.com/FBNNpxb7m6eM6wtW7MV1Ffp6OXOGLI38q47zcvP29OCYA1yhYH5mZzl5itZi0TgOyZpG',
// handle: 'LiveCare Call',
// type: 1,
// duration: 60000,
// textAccept: 'Accept',
// textDecline: 'Decline',
// textMissedCall: 'Missed call',
// textCallback: 'Call back',
// extra: <String, dynamic>{
// // 'reservationID': message['id'],
// 'userId': '1a2b3c4d'
// },
// headers: <String, dynamic>{'apiKey': 'Abc@123!', 'platform': 'flutter'},
// android: AndroidParams(
// isCustomNotification: true,
// isShowLogo: false,
// isShowCallback: false,
// ringtonePath: 'system_ringtone_default',
// backgroundColor: '#424242FF',
// // 'backgroundUrl': 'https://i.pravatar.cc/500',
// actionColor: '#4CAF50',
// incomingCallNotificationChannelName: "Incoming Call",
// missedCallNotificationChannelName: "Missed Call",
// ),
// ios: IOSParams(
// iconName: 'CallKitLogo',
// handleType: '',
// supportsVideo: true,
// maximumCallGroups: 2,
// maximumCallsPerCallGroup: 1,
// audioSessionMode: 'default',
// audioSessionActive: true,
// audioSessionPreferredSampleRate: 44100.0,
// audioSessionPreferredIOBufferDuration: 0.005,
// supportsDTMF: true,
// supportsHolding: true,
// supportsGrouping: false,
// supportsUngrouping: false,
// ringtonePath: 'system_ringtone_default'));
// await FlutterCallkitIncoming.showCallkitIncoming(params);
// // } else if (message['type'] == 'ReservationCallFinished') {
// // await FlutterCallkitIncoming.endAllCalls();
// // }
// }
class PushNotificationHandler {
late BuildContext context;
static final PushNotificationHandler _instance = PushNotificationHandler._internal();
// late HmsApiAvailability hmsApiAvailability;
// final voIPKit = FlutterIOSVoIPKit.instance;
late Timer timeOutTimer;
bool isTalking = false;
var data = {
"AppointmentNo": "2016059247",
"ProjectID": "15",
"NotificationType": "10",
"background": "0",
"doctorname": "Call from postman",
"clinicname": "LIVECARE FAMILY MEDICINE AND GP",
"speciality": "General Practioner",
"appointmentdate": "2022-01-19",
"appointmenttime": "12:10",
"PatientName": "Testing",
"session_id": "1_MX40NjIwOTk2Mn5-MTY1NDE2NDQxMjc2Mn5xc3NCZkNIejJOdzgzTkg2TmlXblhQdnl-fg",
"token":
"T1==cGFydG5lcl9pZD00NjIwOTk2MiZzaWc9MTliNTA3NDAxYmU0MjI5OGY5NTcxZTdhNzQyMTcyZjRjMjBhNjljZTpzZXNzaW9uX2lkPTFfTVg0ME5qSXdPVGsyTW41LU1UWTFOREUyTkRReE1qYzJNbjV4YzNOQ1prTkllakpPZHpnelRrZzJUbWxYYmxoUWRubC1mZyZjcmVhdGVfdGltZT0xNjU0MTY0NDEzJm5vbmNlPTAuNjM3ODkzNDk4NDQ2NTIxOSZyb2xlPW1vZGVyYXRvciZleHBpcmVfdGltZT0xNjU0MjUwODEzJmluaXRpYWxfbGF5b3V0X2NsYXNzX2xpc3Q9",
"DoctorImageURL": "https://image.shutterstock.com/image-vector/sample-stamp-square-grunge-sign-260nw-1474408826.jpg",
"callerID": "9920",
"PatientID": "1231755",
"is_call": "true"
};
PushNotificationHandler._internal();
factory PushNotificationHandler() => _instance;
static PushNotificationHandler getInstance() => _instance;
// void _timeOut({
// int seconds = 30,
// }) async {
// timeOutTimer = Timer(Duration(seconds: seconds), () async {
// print('🎈 example: timeOut');
// final incomingCallerName = await voIPKit.getIncomingCallerName();
// voIPKit.unansweredIncomingCall(
// skipLocalNotification: false,
// missedCallTitle: '📞 Missed call',
// missedCallBody: 'There was a call from $incomingCallerName',
// );
// });
// }
init(BuildContext context) async {
this.context = context;
if (Platform.isIOS) {
// voIPKit.getVoIPToken().then((value) {
// print("APNS VOIP KIT TOKEN: $value");
// AppSharedPreferences().setString(APNS_TOKEN, value!);
// });
//
// voIPKit.onDidUpdatePushToken = (String token) {
// print('🎈 example: onDidUpdatePushToken: $token');
// };
//
// voIPKit.onDidReceiveIncomingPush = (
// Map<String, dynamic> payload,
// ) async {
// print('🎈 example: onDidReceiveIncomingPush $payload');
// _timeOut();
// };
//
// voIPKit.onDidRejectIncomingCall = (
// String uuid,
// String callerId,
// ) async {
// try {
// print('🎈 example: onDidRejectIncomingCall $uuid - $callerId');
// timeOutTimer.cancel();
// } catch (err) {}
// };
//
// voIPKit.onDidAcceptIncomingCall = (
// String uuid,
// String callerId,
// ) async {
// print('🎈 example: onDidAcceptIncomingCall $uuid - $callerId');
// await voIPKit.acceptIncomingCall(callerState: CallStateType.calling);
// await voIPKit.callConnected();
// await Future.delayed(Duration(seconds: 1));
//
// Navigator.pushNamed(
// locator<NavigationService>().navigatorKey.currentContext!,
// "zoom_call_page",
// arguments: CallArguments("hoover-dam", "123", "Patient", "40", "1", false),
// );
//
// await voIPKit.endCall();
//
// // Navigator.pushNamed(navigatorKey.currentContext!, VIDEO_CALL_SCREEN,
// // arguments: VideoArgus(
// // reservationId: int.parse(callerId), token: null, isVideo: true));
//
// timeOutTimer.cancel();
// };
}
if (Platform.isAndroid) {
try {
final fcmToken = await FirebaseMessaging.instance.getToken().catchError((err) {
print(err);
});
if (fcmToken != null) onToken(fcmToken);
// }
} catch (ex) {
print("Notification Exception: " + ex.toString());
}
FirebaseMessaging.onBackgroundMessage(backgroundMessageHandler);
}
if (Platform.isIOS) {
await FirebaseMessaging.instance.getAPNSToken().then((value) async {
log("APNS token: " + value.toString());
await Utils.saveStringFromPrefs(SharedPrefsConsts.APNS_TOKEN, value.toString());
});
await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions(
alert: true, // Required to display a heads up notification
badge: true,
sound: true,
);
final permission = await FirebaseMessaging.instance.requestPermission();
if (permission.authorizationStatus == AuthorizationStatus.denied) return;
} else {}
try {
FirebaseMessaging.instance.getInitialMessage().then((RemoteMessage? message) async {
if (message != null) {
if (Platform.isIOS)
await Future.delayed(Duration(milliseconds: 3000)).then((value) {
if (message != null) newMessage(message);
});
else if (message != null) newMessage(message);
}
});
} catch (ex) {}
FirebaseMessaging.onMessage.listen((RemoteMessage message) async {
print("Firebase onMessage!!!");
// showCallkitIncoming();
if (Platform.isIOS)
await Future.delayed(Duration(milliseconds: 3000)).then((value) {
newMessage(message);
});
else
newMessage(message);
});
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) async {
print("Firebase onMessageOpenedApp!!!");
if (Platform.isIOS)
await Future.delayed(Duration(milliseconds: 3000)).then((value) {
newMessage(message);
});
else
newMessage(message);
});
FirebaseMessaging.instance.getToken().then((String? token) {
print("Push Notification getToken: " + token!);
onToken(token!);
}).catchError((err) {
print(err);
});
FirebaseMessaging.instance.onTokenRefresh.listen((fcm_token) {
print("Push Notification onTokenRefresh: " + fcm_token);
onToken(fcm_token);
});
if (Platform.isAndroid) {
final deviceInfo = DeviceInfoPlugin();
final androidInfo = await deviceInfo.androidInfo;
int sdkInt = androidInfo.version.sdkInt ?? 0;
if (sdkInt >= 33) {
await FlutterCallkitIncoming.requestFullIntentPermission();
}
}
}
newMessage(RemoteMessage remoteMessage) async {
print("Remote Message: " + remoteMessage.data.toString());
if (remoteMessage.data.isEmpty) {
return;
}
debugPrint('the value of the remote message is ${remoteMessage.data}');
if (remoteMessage.data['is_call'] == 'true' || remoteMessage.data['is_call'] == true) {
_incomingCall(remoteMessage.data);
// showCallkitIncoming();
} else {
// GetNotificationsResponseModel notification = new GetNotificationsResponseModel();
//
// notification.createdOn = DateUtil.convertDateToString(DateTime.now());
// notification.messageTypeData = remoteMessage.data['picture'];
// notification.message = remoteMessage.data['message'];
// notification.notificationType = remoteMessage.data["NotificationType"].toString();
// if (remoteMessage.data["NotificationType"] == "2") {
// notification.videoURL = remoteMessage.data["VideoUrl"];
// }
//
// await NavigationService.navigateToPage(NotificationsDetailsPage(
// notification: notification,
// ));
}
}
onToken(String token) async {
print("Push Notification Token: " + token);
await Utils.saveStringFromPrefs(SharedPrefsConsts.PUSH_TOKEN, token);
}
onResume() async {
// var call_data = await AppSharedPreferences().getObject('call_data');
// if (call_data != null) {
// _incomingCall(call_data);
// }
}
Future<void> requestPermissions() async {
try {
if (Platform.isIOS) {
await flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation<IOSFlutterLocalNotificationsPlugin>()?.requestPermissions(alert: true, badge: true, sound: true);
} else if (Platform.isAndroid) {
Map<Permission, PermissionStatus> statuses = await [
Permission.notification,
// Permission.camera,
// Permission.audio,
// Permission.microphone,
].request();
print("=-=-=-=-=-=-=-=-=-=-");
print(statuses[Permission.notification]);
}
} catch (_) {
debugPrint(_.toString());
}
}
}

@ -0,0 +1,103 @@
import 'package:flutter/cupertino.dart';
import 'package:hmg_patient_app_new/core/consts.dart';
class SizeConfig {
static double _blockWidth = 0;
static double _blockHeight = 0;
static double? realScreenWidth;
static double? realScreenHeight;
static double? screenWidth;
static double? screenHeight;
static double? textMultiplier;
static double? imageSizeMultiplier;
static double? heightMultiplier;
static bool isPortrait = true;
static double? widthMultiplier;
static bool isMobilePortrait = false;
static bool isMobile = false;
static bool isHeightShort = false;
static bool isHeightVeryShort = false;
static bool isHeightMiddle = false;
static bool isHeightLarge = false;
static bool isWidthLarge = false;
void init(BoxConstraints constraints, Orientation orientation) {
realScreenHeight = constraints.maxHeight;
realScreenWidth = constraints.maxWidth;
if (constraints.maxWidth <= ApiConsts.maxSmallScreen) {
isMobile = true;
}
if (constraints.maxHeight < 600) {
isHeightVeryShort = true;
} else if (constraints.maxHeight < 800) {
isHeightShort = true;
} else if (constraints.maxHeight < 1000) {
isHeightMiddle = true;
} else {
isHeightLarge = true;
}
if (constraints.maxWidth > 600) {
isWidthLarge = true;
}
if (orientation == Orientation.portrait) {
isPortrait = true;
if (realScreenWidth! < 450) {
isMobilePortrait = true;
}
// textMultiplier = _blockHeight;
// imageSizeMultiplier = _blockWidth;
screenHeight = realScreenHeight;
screenWidth = realScreenWidth;
} else {
isPortrait = false;
isMobilePortrait = false;
// textMultiplier = _blockWidth;
// imageSizeMultiplier = _blockHeight;
screenHeight = realScreenWidth;
screenWidth = realScreenHeight;
}
_blockWidth = screenWidth! / 100;
_blockHeight = screenHeight! / 100;
textMultiplier = _blockHeight;
imageSizeMultiplier = _blockWidth;
heightMultiplier = _blockHeight;
widthMultiplier = _blockWidth;
print('realScreenWidth $realScreenWidth');
print('realScreenHeight $realScreenHeight');
print('textMultiplier $textMultiplier');
print('imageSizeMultiplier $imageSizeMultiplier');
print('heightMultiplier$heightMultiplier');
print('widthMultiplier $widthMultiplier');
print('isPortrait $isPortrait');
print('isMobilePortrait $isMobilePortrait');
}
static getTextMultiplierBasedOnWidth({double? width}) {
// TODO handel LandScape case
if (width != null) {
return width / 100;
}
return widthMultiplier;
}
static getWidthMultiplier({double? width}) {
// TODO handel LandScape case
if (width != null) {
return width / 100;
}
return widthMultiplier;
}
static getHeightMultiplier({double? height}) {
// TODO handel LandScape case
if (height != null) {
return height / 100;
}
return heightMultiplier;
}
}

@ -0,0 +1,93 @@
import 'package:flutter/material.dart'; // These are the Viewport values of your Figma Design.
// These are used in the code as a reference to create your UI Responsively.
const num FIGMA_DESIGN_WIDTH = 375;
const num FIGMA_DESIGN_HEIGHT = 667;
const num FIGMA_DESIGN_STATUS_BAR = 0;
extension ResponsiveExtension on num {
double get _width => SizeUtils.width;
double get h => ((this * _width) / FIGMA_DESIGN_WIDTH);
double get fSize => ((this * _width) / FIGMA_DESIGN_WIDTH);
}
extension FormatExtension on double {
double toDoubleValue({int fractionDigits = 2}) {
return double.parse(this.toStringAsFixed(fractionDigits));
}
double isNonZero({num defaultValue = 0.0}) {
return this > 0 ? this : defaultValue.toDouble();
}
}
enum DeviceType { mobile, tablet, desktop }
typedef ResponsiveBuild = Widget Function(
BuildContext context,
Orientation orientation,
DeviceType deviceType,
);
class Sizer extends StatelessWidget {
const Sizer({Key? key, required this.builder}) : super(key: key);
/// Builds the widget whenever the orientation changes.
final ResponsiveBuild builder;
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
return OrientationBuilder(
builder: (context, orientation) {
SizeUtils.setScreenSize(constraints, orientation);
return builder(context, orientation, SizeUtils.deviceType);
},
);
},
);
}
}
// ignore_for_file: must_be_immutable
class SizeUtils {
/// Device's BoxConstraints
static late BoxConstraints boxConstraints;
/// Device's Orientation
static late Orientation orientation;
/// Type of Device
///
/// This can either be mobile or tablet
static late DeviceType deviceType;
/// Device's Height
static late double height;
/// Device's Width
static late double width;
static void setScreenSize(
BoxConstraints constraints,
Orientation currentOrientation,
) {
boxConstraints = constraints;
orientation = currentOrientation;
if (orientation == Orientation.portrait) {
width = boxConstraints.maxWidth.isNonZero(
defaultValue: FIGMA_DESIGN_WIDTH,
);
height = boxConstraints.maxHeight.isNonZero();
} else {
width = boxConstraints.maxHeight.isNonZero(
defaultValue: FIGMA_DESIGN_WIDTH,
);
height = boxConstraints.maxWidth.isNonZero();
}
deviceType = DeviceType.mobile;
}
}

@ -0,0 +1,341 @@
import 'package:hmg_patient_app_new/core/app_state.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/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/main.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/dialogs/confirm_dialog.dart';
import 'package:hmg_patient_app_new/widgets/loading_dialog.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:shared_preferences/shared_preferences.dart';
class Utils {
static bool _isLoadingVisible = false;
static bool get isLoading => _isLoadingVisible;
static void showToast(String message, {bool longDuration = true}) {
Fluttertoast.showToast(
msg: message,
toastLength: longDuration ? Toast.LENGTH_LONG : Toast.LENGTH_SHORT,
gravity: ToastGravity.BOTTOM,
timeInSecForIosWeb: 1,
backgroundColor: blackColor,
textColor: whiteColor,
fontSize: 16.0);
}
static bool isArabicText(String inputText) {
bool isArabicText = false;
final arabic = RegExp(r'^[\u0621-\u064A]+');
if (arabic.hasMatch(inputText)) {
isArabicText = true;
} else {
isArabicText = false;
}
return isArabicText;
}
static String getFreeSlotsTimeText(String startTime, {bool isAddHours = false}) {
// return DateFormat('hh:mm a', AppState().isArabic() ? "ar_SA" : "en_US").format(DateTime.tryParse(startTime)!.add(
// Duration(
// hours: isAddHours ? 3 : 0,
// ),
// ));
return !isAddHours
? DateFormat('hh:mm a', AppState().isArabic() ? "ar_SA" : "en_US").format(DateTime.tryParse(startTime.contains("T") ? startTime : convertStringToDateTime(startTime))!.toLocal())
: DateFormat('hh:mm a', AppState().isArabic() ? "ar_SA" : "en_US").format(DateTime.tryParse(startTime.contains("T") ? startTime : convertStringToDateTime(startTime))!.add(
Duration(
hours: isAddHours ? 3 : 0,
),
));
;
}
static String convertStringToDateTime(String dateTimeString) {
String timeString = dateTimeString;
// Parse the time string using DateFormat
DateFormat format = DateFormat.Hms(); // 'Hms' = 'HH:mm:ss'
DateTime time = format.parse(timeString);
DateTime now = DateTime.now();
DateTime dateTimeWithToday = DateTime(
now.year,
now.month,
now.day,
time.hour,
time.minute,
time.second,
);
return dateTimeWithToday.toIso8601String();
}
static String getMonthDayYearDateFormatted(DateTime dateTime) {
if (dateTime != null)
return AppState().isArabic()
? getMonthArabic(dateTime.month) + " " + dateTime.day.toString() + ", " + dateTime.year.toString()
: getMonth(dateTime.month) + " " + dateTime.day.toString() + ", " + dateTime.year.toString();
else
return "";
}
/// get month by
/// [month] convert month number in to month name
static getMonth(int month) {
switch (month) {
case 1:
return "January";
case 2:
return "February";
case 3:
return "March";
case 4:
return "April";
case 5:
return "May";
case 6:
return "June";
case 7:
return "July";
case 8:
return "August";
case 9:
return "September";
case 10:
return "October";
case 11:
return "November";
case 12:
return "December";
}
}
/// get month by
/// [month] convert month number in to month name in Arabic
static getMonthArabic(int month) {
switch (month) {
case 1:
return "يناير";
case 2:
return " فبراير";
case 3:
return "مارس";
case 4:
return "أبريل";
case 5:
return "مايو";
case 6:
return "يونيو";
case 7:
return "يوليو";
case 8:
return "أغسطس";
case 9:
return "سبتمبر";
case 10:
return " اكتوبر";
case 11:
return " نوفمبر";
case 12:
return "ديسمبر";
}
}
static Future<String> getStringFromPrefs(String key) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
return prefs.getString(key) ?? "";
}
static Future<bool> saveStringFromPrefs(String key, String value) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
return await prefs.setString(key, value);
}
static Future<int> getIntFromPrefs(String key) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
return prefs.getInt(key) ?? 0;
}
static Future<bool> saveIntFromPrefs(String key, int value) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
return await prefs.setInt(key, value);
}
static Future<num> getNumFromPrefs(String key) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
return num.parse(prefs.getString(key) ?? "0");
}
static Future<bool> saveNumFromPrefs(String key, num value) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
return await prefs.setString(key, value.toString());
}
static Future<bool> removeFromPrefs(String key) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
return await prefs.remove(key);
}
static void showLoading({bool isNeedBinding = true}) {
if (isNeedBinding) {
WidgetsBinding.instance.addPostFrameCallback((_) {
showLoadingDialog();
});
} else {
showLoadingDialog();
}
}
static void showLoadingDialog() {
_isLoadingVisible = true;
showDialog(
context: navigatorKey.currentContext!,
barrierColor: Colors.black.withOpacity(0.5),
builder: (BuildContext context) => LoadingDialog(),
)
.then((value) {
_isLoadingVisible = false;
})
.catchError((e) {})
.onError(
(error, stackTrace) {},
);
}
static void hideLoading() {
try {
if (_isLoadingVisible) {
_isLoadingVisible = false;
Navigator.of(navigatorKey.currentContext!).pop();
}
_isLoadingVisible = false;
} catch (e) {}
}
static List<T> uniqueBy<T, K>(List<T> list, K Function(T) keySelector) {
final seenKeys = <K>{};
return list.where((item) => seenKeys.add(keySelector(item))).toList();
}
static void showAppDialog(BuildContext context, String? title, String? message, VoidCallback? onTap) {
showDialog(
barrierDismissible: false,
context: context,
builder: (cxt) => ConfirmDialog(
title: title!,
message: message!,
onTap: onTap,
),
);
}
static bool isSAUDIIDValid(String id, type) {
if (type == 1) {
if (id == null) {
return false;
}
try {
id = id.toString();
id = id.trim();
var returnValue = int.parse(id);
var sum = 0;
if (returnValue > 0) {
var type = int.parse(id[0]);
if (id.length != 10) {
return false;
}
if (type != 2 && type != 1) {
return false;
}
for (var i = 0; i < 10; i++) {
if (i % 2 == 0) {
var a = id[i];
var x = int.parse(a) * 2;
var b = x.toString();
if (b.length == 1) {
b = "0" + b;
}
sum += int.parse(b[0]) + int.parse(b[1]);
} else {
sum += int.parse(id[i]);
}
}
return sum % 10 == 0;
}
} catch (err) {}
return false;
} else {
return true;
}
}
static Widget getNoDataWidget(BuildContext context, {String? errorText}) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SvgPicture.asset('assets/images/NoDataAvailableIcon.svg', width: 150.0, height: 150.0),
(errorText ?? LocaleKeys.noDataAvailable.tr()).toText16(isCenter: true).paddingOnly(top: 15),
],
).center;
}
static getPhoneNumberWithoutZero(String number) {
String newNumber = "";
if (number.startsWith('0')) {
newNumber = number.substring(1);
} else {
newNumber = number;
}
return newNumber;
}
static String removeHtmlTags(String htmlString) {
if (htmlString == null || htmlString.isEmpty) {
return '';
}
// Replace HTML line breaks with newlines
var withLineBreaks =
htmlString.replaceAll(RegExp(r'<br\s*\/?>', multiLine: true), '\n').replaceAll(RegExp(r'<\/p>', multiLine: true), '\n').replaceAll(RegExp(r'<divider>', multiLine: true), '\n');
// Remove all other HTML tags
var withoutTags = withLineBreaks.replaceAll(RegExp(r'<[^>]*>'), '');
// Decode HTML entities
var decodedString = withoutTags
.replaceAll('&nbsp;', ' ')
.replaceAll('&amp;', '&')
.replaceAll('&lt;', '<')
.replaceAll('&gt;', '>')
.replaceAll('&quot;', '"')
.replaceAll('&#39;', "'")
.replaceAll('&rsquo;', "'")
.replaceAll('&lsquo;', "'")
.replaceAll('&rdquo;', '"')
.replaceAll('&ldquo;', '"');
// Remove extra whitespace and normalize line breaks
var normalizedString = decodedString
.replaceAll(RegExp(r'\n\s*\n'), '\n\n') // Replace multiple blank lines with double line break
.replaceAll(RegExp(r' +'), ' ') // Replace multiple spaces with single space
.trim(); // Remove leading/trailing whitespace
return normalizedString;
}
Widget mDivider(Color color) {
return Divider(
// width: double.infinity,
height: 1,
color: color,
);
}
}

@ -0,0 +1,16 @@
import 'package:flutter/material.dart';
extension ContextUtils on BuildContext {
double get screenHeight => MediaQuery.of(this).size.height;
double get screenWidth => MediaQuery.of(this).size.width;
ThemeData get theme => Theme.of(this);
TextTheme get textTheme => theme.textTheme;
// TextStyle get headline1 => textTheme.headline1!;
// TextStyle get headline2 => textTheme.headline2!;
// TextStyle get headline3 => textTheme.headline3!;
// TextStyle get headline4 => textTheme.headline4!;
// TextStyle get headline5 => textTheme.headline5!;
// TextStyle get headline6 => textTheme.headline6!;
// TextStyle get bodyText1 => textTheme.bodyText1!;
// TextStyle get bodyText2 => textTheme.bodyText2!;
}

@ -0,0 +1,14 @@
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
extension IntExtensions on int {
Widget get height => SizedBox(height: toDouble());
Widget get width => SizedBox(width: toDouble());
Widget get divider => Divider(height: toDouble(), thickness: toDouble(), color: buttonColor);
Widget get makeItSquare => SizedBox(width: toDouble(), height: toDouble());
}

@ -0,0 +1,311 @@
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:auto_size_text/auto_size_text.dart';
import 'package:flutter/cupertino.dart';
import 'package:intl/intl.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:sizer/sizer.dart';
extension CapExtension on String {
String get toCamelCase => "${this[0].toUpperCase()}${this.substring(1)}";
String get inCaps => '${this[0].toUpperCase()}${this.substring(1)}';
String get allInCaps => this.toUpperCase();
String get capitalizeFirstofEach => this.trim().length > 0 ? this.trim().toLowerCase().split(" ").map((str) => str.inCaps).join(" ") : "";
}
extension EmailValidator on String {
Widget get toWidget => Text(this);
Widget toText8({Color? color, bool isBold = false, int? maxlines, FontStyle? fontStyle, TextOverflow? textOverflow}) => Text(
this,
maxLines: maxlines,
overflow: textOverflow,
style: TextStyle(
fontSize: 8.fSize,
fontStyle: fontStyle ?? FontStyle.normal,
fontWeight: isBold ? FontWeight.bold : FontWeight.normal,
color: color ?? blackColor,
letterSpacing: 0.64,
),
);
Widget toText10({Color? color, bool isBold = false, bool isUnderLine = false, int? maxlines, FontStyle? fontStyle, TextOverflow? textOverflow}) => Text(
this,
maxLines: maxlines,
overflow: textOverflow,
style: TextStyle(
fontSize: 10.fSize,
fontStyle: fontStyle ?? FontStyle.normal,
fontWeight: isBold ? FontWeight.bold : FontWeight.normal,
color: color ?? blackColor,
letterSpacing: 0.64,
decoration: isUnderLine ? TextDecoration.underline : null,
decorationColor: color ?? blackColor),
);
Widget toText11({Color? color, FontWeight? weight, bool isUnderLine = false, bool isCenter = false, bool isBold = false, int maxLine = 0, double letterSpacing = 0.64}) => Text(
this,
textAlign: isCenter ? TextAlign.center : null,
maxLines: (maxLine > 0) ? maxLine : null,
softWrap: true,
style: TextStyle(
fontSize: 11.fSize,
fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal),
color: color ?? blackColor,
letterSpacing: letterSpacing,
decoration: isUnderLine ? TextDecoration.underline : null,
),
);
Widget toText12({Color? color, bool isUnderLine = false, bool isBold = false, bool isCenter = false, int maxLine = 0}) => Text(
this,
textAlign: isCenter ? TextAlign.center : null,
maxLines: (maxLine > 0) ? maxLine : null,
style: TextStyle(
fontSize: 12.fSize,
fontWeight: isBold ? FontWeight.bold : FontWeight.normal,
color: color ?? blackColor,
letterSpacing: 0.64,
decorationColor: isUnderLine ? blackColor : null,
decoration: isUnderLine ? TextDecoration.underline : null,
),
);
Widget toText12Auto({Color? color, bool isUnderLine = false, bool isBold = false, bool isCenter = false, int maxLine = 0}) => AutoSizeText(
this,
textAlign: isCenter ? TextAlign.center : null,
maxLines: (maxLine > 0) ? maxLine : null,
minFontSize: 8,
style: TextStyle(
fontSize: 12.fSize,
fontWeight: isBold ? FontWeight.bold : FontWeight.normal,
color: color ?? blackColor,
letterSpacing: 0.64,
decoration: isUnderLine ? TextDecoration.underline : null,
),
);
Widget toTextAuto({
Color? color,
bool isUnderLine = false,
bool isBold = false,
bool isCenter = false,
int maxLine = 0,
double fontSize = 12,
double letterSpacing = 0.64,
double height = 1,
TextOverflow? textOverflow,
FontWeight? fontWeight,
}) =>
AutoSizeText(
this,
textAlign: isCenter ? TextAlign.center : null,
maxLines: (maxLine > 0) ? maxLine : null,
minFontSize: 5,
overflow: textOverflow,
softWrap: true,
style: TextStyle(
fontSize: fontSize,
fontWeight: fontWeight ?? (isBold ? FontWeight.bold : FontWeight.normal),
color: color ?? blackColor,
letterSpacing: letterSpacing,
decoration: isUnderLine ? TextDecoration.underline : null,
),
);
Widget toText13({
Color? color,
bool isUnderLine = false,
bool isBold = false,
bool isCenter = false,
int maxLine = 0,
}) =>
Text(
this,
textAlign: isCenter ? TextAlign.center : null,
maxLines: (maxLine > 0) ? maxLine : null,
style: TextStyle(
fontSize: 13.fSize, fontWeight: isBold ? FontWeight.bold : FontWeight.normal, color: color ?? blackColor, letterSpacing: 0.64, decoration: isUnderLine ? TextDecoration.underline : null),
);
Widget toText14({Color? color, bool isUnderLine = false, bool isBold = false, bool isCenter = false, FontWeight? weight, int? maxlines}) => Text(
this,
textAlign: isCenter ? TextAlign.center : null,
maxLines: maxlines,
style: TextStyle(
color: color ?? blackColor,
fontSize: 14.fSize,
letterSpacing: 0.64,
fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal),
decoration: isUnderLine ? TextDecoration.underline : null),
);
Widget toText15({Color? color, bool isUnderLine = false, bool isBold = false, bool isCenter = false, FontWeight? weight, int? maxlines}) => Text(
this,
textAlign: isCenter ? TextAlign.center : null,
maxLines: maxlines,
style: TextStyle(
color: color ?? blackColor,
fontSize: 15.fSize,
letterSpacing: 0.64,
fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal),
decoration: isUnderLine ? TextDecoration.underline : null),
);
Widget toText16({
Color? color,
bool isUnderLine = false,
bool isBold = false,
bool isCenter = false,
int? maxlines,
TextAlign? textAlign,
}) =>
Text(
this,
maxLines: maxlines,
textAlign: isCenter ? TextAlign.center : null,
style: TextStyle(
color: color ?? blackColor,
fontSize: 16.fSize,
letterSpacing: 0.64,
fontWeight: isBold ? FontWeight.bold : FontWeight.normal,
decoration: isUnderLine ? TextDecoration.underline : null,
),
);
Widget toText17({Color? color, bool isBold = false, bool isCenter = false}) => Text(
this,
textAlign: isCenter ? TextAlign.center : null,
style: TextStyle(color: color ?? blackColor, fontSize: 17.fSize, letterSpacing: 0.64, fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
);
Widget toText18({Color? color, bool isBold = false, bool isCenter = false, int? maxlines}) => Text(
maxLines: maxlines,
textAlign: isCenter ? TextAlign.center : null,
this,
style: TextStyle(fontSize: 18.fSize, fontWeight: isBold ? FontWeight.bold : FontWeight.normal, color: color ?? blackColor, letterSpacing: 0.64),
);
Widget toText19({Color? color, bool isBold = false}) => Text(
this,
style: TextStyle(fontSize: 19.fSize, fontWeight: isBold ? FontWeight.bold : FontWeight.normal, color: color ?? blackColor, letterSpacing: 0.64),
);
Widget toText20({Color? color, bool isBold = false}) => Text(
this,
style: TextStyle(fontSize: 20.fSize, fontWeight: isBold ? FontWeight.bold : FontWeight.normal, color: color ?? blackColor, letterSpacing: 0.64),
);
Widget toText21({Color? color, bool isBold = false, FontWeight? weight, int? maxlines}) => Text(
this,
maxLines: maxlines,
style: TextStyle(color: color ?? blackColor, fontSize: 21.fSize, letterSpacing: 0.64, fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal)),
);
Widget toText22({Color? color, bool isBold = false, bool isCenter = false}) => Text(
this,
textAlign: isCenter ? TextAlign.center : null,
style: TextStyle(height: 1, color: color ?? blackColor, fontSize: 22.fSize, letterSpacing: 0.64, fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
);
Widget toText24({Color? color, bool isBold = false, bool isCenter = false}) => Text(
this,
textAlign: isCenter ? TextAlign.center : null,
style: TextStyle(height: 23 / 24, color: color ?? blackColor, fontSize: 24.fSize, letterSpacing: 0.64, fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
);
Widget toText32({Color? color, bool isBold = false, bool isCenter = false}) => Text(
this,
textAlign: isCenter ? TextAlign.center : null,
style: TextStyle(height: 32 / 32, color: color ?? blackColor, fontSize: 32.fSize, letterSpacing: 0.64, fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
);
Widget toText44({Color? color, bool isBold = false}) => Text(
this,
style: TextStyle(height: 32 / 32, color: color ?? blackColor, fontSize: 44.fSize, letterSpacing: 0.64, fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
);
Widget toSectionHeading({String upperHeading = "", String lowerHeading = ""}) {
String upper = "";
String lower = "";
String heading = this;
if (heading.isNotEmpty) {
List<String> data = heading.split(" ");
if (data.length > 1) {
upper = data[0];
data.removeAt(0);
lower = data.join(" ");
} else {
lower = data[0];
}
}
if (upperHeading.isNotEmpty) {
upper = upperHeading;
}
if (lowerHeading.isNotEmpty) {
lower = lowerHeading;
}
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
if (upper.isNotEmpty) upper.toText12(),
lower.toText24(isBold: true),
],
);
}
bool isValidEmail() {
return RegExp(r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$').hasMatch(this);
}
String toFormattedDate() {
String date = this.split("T")[0];
String time = this.split("T")[1];
var dates = date.split("-");
return "${dates[2]} ${getMonth(int.parse(dates[1]))} ${dates[0]} ${DateFormat('hh:mm a').format(DateFormat('hh:mm:ss').parse(time))}";
}
String getMonth(int month) {
switch (month) {
case 1:
return "January";
case 2:
return "February";
case 3:
return "March";
case 4:
return "April";
case 5:
return "May";
case 6:
return "June";
case 7:
return "July";
case 8:
return "August";
case 9:
return "September";
case 10:
return "October";
case 11:
return "November";
case 12:
return "December";
default:
return "";
}
}
String truncate(int max, {String suffix = ''}) {
try {
return length <= max ? this : '${substring(0, max - suffix.length)}$suffix';
} catch (e) {
return this;
}
}
}

@ -0,0 +1,33 @@
// import 'package:Dleelna/classes/enums.dart';
//
// extension SelectedAuthMethodTypesService on AuthMethodTypes {
// int getTypeIdService() {
// switch (this) {
// case AuthMethodTypes.sms:
// return 1;
// case AuthMethodTypes.whatsApp:
// return 2;
// case AuthMethodTypes.fingerPrint:
// return 3;
// case AuthMethodTypes.faceID:
// return 4;
// case AuthMethodTypes.moreOptions:
// return 5;
// }
// }
//
// static getMethodsTypeService(int typeId) {
// switch (typeId) {
// case 1:
// return AuthMethodTypes.sms;
// case 2:
// return AuthMethodTypes.whatsApp;
// case 3:
// return AuthMethodTypes.fingerPrint;
// case 4:
// return AuthMethodTypes.faceID;
// case 5:
// return AuthMethodTypes.moreOptions;
// }
// }
// }

@ -0,0 +1,151 @@
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:hmg_patient_app_new/extensions/int_extensions.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:shimmer/shimmer.dart';
import 'package:sizer/sizer.dart';
extension WidgetExtensions on Widget {
Widget onPress(VoidCallback onTap) => InkWell(onTap: onTap, child: this);
Widget get expanded => Expanded(child: this);
Widget get center => Center(child: this);
Widget circle(double _value) => ClipRRect(borderRadius: BorderRadius.circular(_value), child: this);
Widget paddingAll(double _value) => Padding(padding: EdgeInsets.all(_value), child: this);
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);
Widget toExpanded({int flex = 1}) => Expanded(flex: flex, child: this);
Widget toShimmer({bool isShow = true, bool isTransparent = false}) => isShow
? Shimmer.fromColors(
baseColor: Color(0xffb9bebe),
highlightColor: Colors.white,
child: Container(
color: isTransparent ? Colors.transparent : Colors.white.withOpacity(0.3),
child: this,
),
)
: Container(
child: this,
);
Widget animatedSwither() => AnimatedSwitcher(
duration: const Duration(milliseconds: 500),
// transitionBuilder: (Widget child, Animation<double> animation) {
// return ScaleTransition(scale: animation, child: child);
// },
switchInCurve: Curves.linearToEaseOut,
switchOutCurve: Curves.linearToEaseOut,
child: this,
);
Widget objectContainerView({String title = "", String note = "", bool disablePadding = false, double radius = 15}) {
return Container(
padding: disablePadding ? EdgeInsets.zero : const EdgeInsets.only(top: 15, bottom: 15, left: 14, right: 14),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(radius),
boxShadow: [
BoxShadow(
color: const Color(0xff000000).withOpacity(.15),
blurRadius: 26,
offset: const Offset(0, -3),
),
],
),
alignment: Alignment.center,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
if (title.isNotEmpty) title.toText16(),
if (title.isNotEmpty) 12.height,
this,
if (note.isNotEmpty) note.toText11(),
],
),
);
}
Widget objectContainerBorderView(
{String title = "", String note = "", bool disablePadding = false, double radius = 20, Color? color, Color borderColor = buttonColor, bool disableWidth = false, bool isAlignment = false}) {
return Container(
padding: disablePadding ? EdgeInsets.zero : const EdgeInsets.only(top: 15, bottom: 15, left: 14, right: 14),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(
Radius.circular(radius),
),
color: color,
border: Border.all(
color: borderColor,
width: disableWidth ? 2 : 1,
),
),
alignment: isAlignment ? Alignment.center : null,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
if (title.isNotEmpty) title.toText16(),
if (title.isNotEmpty) 12.height,
this,
if (note.isNotEmpty) note.toText11(),
],
),
);
}
}
//Height Spacers in percentages
Widget heightSpacer02per() => SizedBox(height: 0.2.h);
Widget heightSpacer04per() => SizedBox(height: 0.4.h);
Widget heightSpacer06per() => SizedBox(height: 0.6.h);
Widget heightSpacer08per() => SizedBox(height: 0.8.h);
Widget heightSpacer1per() => SizedBox(height: 1.h);
Widget heightSpacer2per() => SizedBox(height: 2.h);
Widget heightSpacer3per() => SizedBox(height: 3.h);
Widget heightSpacer4per() => SizedBox(height: 4.h);
Widget heightSpacer5per() => SizedBox(height: 5.h);
Widget heightSpacer8per() => SizedBox(height: 8.h);
Widget heightSpacer10per() => SizedBox(height: 10.h);
Widget heightSpacer15per() => SizedBox(height: 15.h);
Widget heightSpacer20per() => SizedBox(height: 20.h);
//Width Spacers in percentages
Widget widthSpacer02perc() => SizedBox(height: 0.2.w);
Widget widthSpacer04perc() => SizedBox(height: 0.4.w);
Widget widthSpacer06perc() => SizedBox(height: 0.6.w);
Widget widthSpacer08per() => SizedBox(height: 0.8.w);
Widget widthSpacer1per() => SizedBox(height: 1.w);
Widget widthSpacer2per() => SizedBox(height: 2.w);
Widget widthSpacer3per() => SizedBox(height: 3.w);
Widget widthSpacer4per() => SizedBox(height: 4.w);
Widget widthSpacer5per() => SizedBox(height: 5.w);

@ -0,0 +1,65 @@
// Copyright 2022, the Chromium project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// File generated by FlutterFire CLI.
// ignore_for_file: lines_longer_than_80_chars, avoid_classes_with_only_static_members
import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;
import 'package:flutter/foundation.dart'
show defaultTargetPlatform, kIsWeb, TargetPlatform;
/// Default [FirebaseOptions] for use with your Firebase apps.
///
/// Example:
/// ```dart
/// import 'firebase_options.dart';
/// // ...
/// await Firebase.initializeApp(
/// options: DefaultFirebaseOptions.currentPlatform,
/// );
/// ```
class DefaultFirebaseOptions {
static FirebaseOptions get currentPlatform {
// if (kIsWeb) {
// return web;
// }
switch (defaultTargetPlatform) {
case TargetPlatform.android:
return android;
case TargetPlatform.iOS:
return ios;
// case TargetPlatform.macOS:
// return macos;
// TODO(Lyokone): Remove when FlutterFire CLI updated
case TargetPlatform.windows:
return android;
default:
throw UnsupportedError(
'DefaultFirebaseOptions are not supported for this platform.',
);
}
}
static const FirebaseOptions android = FirebaseOptions(
apiKey: 'AIzaSyDZDeWcBlRE3YfJWYt_DCiToVnANfaj8qg',
appId: '1:815750722565:android:62281cd3e5df4063',
messagingSenderId: '815750722565',
projectId: 'api-project-815750722565',
// databaseURL:
// 'https://flutterfire-e2e-tests-default-rtdb.europe-west1.firebasedatabase.app',
storageBucket: 'api-project-815750722565.appspot.com',
);
static const FirebaseOptions ios = FirebaseOptions(
apiKey: 'AIzaSyDiXnCO00li4V7Ioa2YZ_M4ECxRsu_P9tA',
appId: '1:815750722565:ios:328ec247a81a2ca23c186c',
messagingSenderId: '815750722565',
projectId: 'api-project-815750722565',
storageBucket: 'api-project-815750722565.appspot.com',
androidClientId:
'815750722565-m14h8mkosm7cnq6uh6rhqr54dn02d705.apps.googleusercontent.com',
iosClientId:
'815750722565-da8p56le8bd6apsbm9eft0jjl1rtpgkt.apps.googleusercontent.com',
iosBundleId: 'com.HMG.HMG-Smartphone',
);
}

@ -0,0 +1,14 @@
// DO NOT EDIT. This is code generated via package:easy_localization/generate.dart
// ignore_for_file: constant_identifier_names
abstract class LocaleKeys {
static const english = 'english';
static const arabic = 'arabic';
static const login = 'login';
static const noDataAvailable = 'noDataAvailable';
static const ok = 'ok';
static const confirm = 'confirm';
static const loadingText = 'loadingText';
}

@ -0,0 +1,79 @@
import 'dart:io';
import 'package:easy_localization/easy_localization.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/routes/app_routes.dart';
import 'package:hmg_patient_app_new/theme/app_theme.dart';
import 'package:logger/logger.dart';
import 'firebase_options.dart';
var globalMessengerKey = GlobalKey<ScaffoldMessengerState>();
final navigatorKey = GlobalKey<NavigatorState>();
Logger logger = Logger(
printer: PrettyPrinter(
lineLength: 0,
),
);
late AppState appState;
@pragma('vm:entry-point')
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
print("Firebase backgroundMessageHandler Main!!!");
// debugPrint('backgroundMessage: message => ${message.notification!.title.toString()}');
// messagesOpended = message.notification!.title.toString();
var payload = message.data;
// showCallkitIncoming(payload);
// await backgroundCallHandler(payload);
}
class MyHttpOverrides extends HttpOverrides {
@override
HttpClient createHttpClient(SecurityContext? context) {
return super.createHttpClient(context)..badCertificateCallback = (X509Certificate cert, String host, int port) => true;
}
}
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return SafeArea(
top: false, // Set to true if you want to avoid the notch area as well
bottom: Platform.isIOS ? false : true,
child: MaterialApp(
title: 'Dr. AlHabib',
builder: (context, mchild) {
return MediaQuery(
data: MediaQuery.of(context).copyWith(
textScaler: TextScaler.linear(1.0),
), //set desired text scale factor here
child: mchild!);
},
showSemanticsDebugger: false,
debugShowCheckedModeBanner: false,
localizationsDelegates: context.localizationDelegates,
supportedLocales: context.supportedLocales,
locale: context.locale,
initialRoute: AppRoutes.initialRoute,
routes: AppRoutes.routes,
theme: AppTheme.getTheme(
EasyLocalization.of(context)?.locale.languageCode == "ar",
),
navigatorKey: navigatorKey,
),
);
}
}

@ -0,0 +1,15 @@
import 'package:flutter/material.dart';
class LandingPage extends StatefulWidget {
const LandingPage({super.key});
@override
State<LandingPage> createState() => _LandingPageState();
}
class _LandingPageState extends State<LandingPage> {
@override
Widget build(BuildContext context) {
return const Placeholder();
}
}

@ -0,0 +1,8 @@
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/splashPage.dart';
class AppRoutes {
static const String initialRoute = '/initialRoute';
static Map<String, WidgetBuilder> get routes => {initialRoute: (context) => SplashPage()};
}

@ -0,0 +1,300 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:hmg_patient_app_new/services/api_exception.dart';
import 'package:http/http.dart';
import 'package:http/io_client.dart';
import '../core/app_state.dart';
import '../core/consts.dart';
import '../core/utils/utils.dart';
import '../main.dart';
// ignore_for_file: avoid_annotating_with_dynamic
typedef FactoryConstructor<U> = U Function(dynamic);
class APIError {
int? errorCode;
String? errorMessage;
APIError(this.errorCode, this.errorMessage);
Map<String, dynamic> toJson() => {'errorCode': errorCode, 'errorMessage': errorMessage};
@override
String toString() {
return jsonEncode(this);
}
}
APIException _throwAPIException(Response response, Function retryCallBack) {
switch (response.statusCode) {
case 200:
APIError? apiError;
if (response.body != null && response.body.isNotEmpty) {
var jsonError = jsonDecode(response.body);
print(jsonError);
apiError = APIError(jsonError['ErrorCode'], jsonError['ErrorMessage']);
}
return APIException(APIException.BAD_REQUEST, error: apiError);
case 400:
APIError? apiError;
if (response.body != null && response.body.isNotEmpty) {
var jsonError = jsonDecode(response.body);
apiError = APIError(jsonError['ErrorCode'], jsonError['ErrorMessage']);
}
return APIException(APIException.BAD_REQUEST, error: apiError);
case 401:
return APIException(APIException.UNAUTHORIZED);
case 403:
return APIException(APIException.FORBIDDEN);
case 404:
return APIException(APIException.NOT_FOUND);
case 500:
return APIException(APIException.INTERNAL_SERVER_ERROR);
case 444:
var downloadUrl = response.headers["location"];
return APIException(APIException.UPGRADE_REQUIRED, arguments: downloadUrl);
default:
return APIException(APIException.OTHER);
}
}
abstract class IApiClient {
Future<U> postJsonForObject<T, U>(FactoryConstructor<U> factoryConstructor, String url, T jsonObject,
{String? token, Map<String, dynamic>? queryParameters, Map<String, String>? headers, int retryTimes = 0, bool isFormData = false});
Future<Response> postJsonForResponse<T>(String url, T jsonObject, {String? token, Map<String, dynamic>? queryParameters, Map<String, String>? headers, int retryTimes = 0, bool isFormData = false});
Future<Response> getJsonForResponse<T>(String url, {String? token, Map<String, dynamic>? queryParameters, Map<String, String>? headers, int retryTimes = 0});
void setHomeUrl(String url);
}
class ApiClient implements IApiClient {
// static final ApiClient _instance = ApiClient._internal();
// ApiClient._internal();
// factory ApiClient() => _instance;
@override
Future<U> postJsonForObject<T, U>(FactoryConstructor<U> factoryConstructor, String url, T jsonObject,
{String? token, Map<String, dynamic>? queryParameters, Map<String, String>? headers, int retryTimes = 0, bool isFormData = false}) async {
var _headers = {'Accept': 'application/json'};
if (headers != null && headers.isNotEmpty) {
_headers.addAll(headers);
}
if (!kReleaseMode) {
print("Url:$url");
var bodyJson = json.encode(jsonObject);
print("body:$bodyJson");
}
var response = await postJsonForResponse(url, jsonObject, token: token, queryParameters: queryParameters, headers: _headers, retryTimes: retryTimes, isFormData: isFormData);
// try {
if (!kReleaseMode) {
logger.i("res: " + response.body);
}
var jsonData = jsonDecode(response.body);
if (jsonData["IsAuthenticated"] != null) {
AppState().setIsAuthenticated = jsonData["IsAuthenticated"];
}
if (jsonData["ErrorMessage"] == null) {
return factoryConstructor(jsonData);
} else {
APIError? apiError;
apiError = APIError(jsonData['ErrorCode'], jsonData['ErrorEndUserMessage']);
throw APIException(APIException.BAD_REQUEST, error: apiError);
}
// } catch (ex) {
// if (ex is APIException) {
// rethrow;
// } else {
// throw APIException(APIException.BAD_RESPONSE_FORMAT, arguments: ex);
// }
// }
}
@override
Future<Response> postJsonForResponse<T>(String url, T jsonObject,
{String? token,
Map<String, dynamic>? queryParameters,
Map<String, String>? headers,
int retryTimes = 0,
bool isFormData = false,
bool isAuthAPI = false,
bool isHISAPI = false,
bool isSanedAPI = false,
bool isPutRequest = false}) async {
String? requestBody;
late Map<String, String> stringObj;
if (jsonObject != null) {
requestBody = jsonEncode(jsonObject);
if (headers == null) {
headers = {'Content-Type': 'application/json'};
} else {
headers['Content-Type'] = 'application/json';
}
}
return await _postForResponse(url, requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes);
}
Future<Response> _postForResponse(String url, requestBody, {String? token, Map<String, dynamic>? queryParameters, Map<String, String>? headers, int retryTimes = 0}) async {
try {
var _headers = <String, String>{};
// if (token != null) {
// _headers['Authorization'] = 'Bearer $token';
// }
if (headers != null && headers.isNotEmpty) {
_headers.addAll(headers);
}
if (queryParameters != null) {
// var queryString = new Uri(queryParameters: queryParameters).query;
var queryString = Uri(queryParameters: queryParameters.map((key, value) => MapEntry(key, value == null ? null : value.toString()))).query;
url = url + '?' + queryString;
}
// if (!kReleaseMode && url.contains("saned")) {
if (!kReleaseMode) {
print("Url: $url");
print("Headers: $_headers");
// var bodyJson = json.encode(requestBody);
print("body: $requestBody");
}
var response = await _post(Uri.parse(url), body: requestBody, headers: _headers).timeout(Duration(seconds: 120));
if (response.statusCode >= 200 && response.statusCode < 300) {
return response;
} else {
throw _throwAPIException(response, () {
// _postForResponse(url, requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes, isAuthAPI: isAuthAPI);
postJsonForResponse(url, requestBody);
});
}
} on SocketException catch (e) {
if (retryTimes > 0) {
print('will retry after 3 seconds...');
await Future.delayed(Duration(seconds: 3));
return await _postForResponse(url, requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1);
} else {
throw APIException(APIException.OTHER, arguments: e);
}
} on HttpException catch (e) {
if (retryTimes > 0) {
print('will retry after 3 seconds...');
await Future.delayed(Duration(seconds: 3));
return await _postForResponse(url, requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1);
} else {
throw APIException(APIException.OTHER, arguments: e);
}
} on TimeoutException catch (e) {
throw APIException(APIException.TIMEOUT, arguments: e);
} on ClientException catch (e) {
if (retryTimes > 0) {
print('will retry after 3 seconds...');
await Future.delayed(Duration(seconds: 3));
return await _postForResponse(url, requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1);
} else {
throw APIException(APIException.OTHER, arguments: e);
}
}
}
@override
Future<Response> getJsonForResponse<T>(String url, {String? token, Map<String, dynamic>? queryParameters, Map<String, String>? headers, int retryTimes = 0, bool isAuthAPI = false}) async {
logger.i("Url:$url");
if (headers == null) {
headers = {'Content-Type': 'application/json'};
} else {
headers['Content-Type'] = 'application/json';
}
return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes, isAuthAPI: isAuthAPI);
}
Future<Response> _getForResponse(String url, {String? token, Map<String, dynamic>? queryParameters, Map<String, String>? headers, int retryTimes = 0, bool isAuthAPI = false}) async {
try {
var _headers = <String, String>{};
if (token != null) {
_headers['Authorization'] = 'Bearer $token';
}
if (headers != null && headers.isNotEmpty) {
_headers.addAll(headers);
}
if (isAuthAPI) {
String token = await Utils.getStringFromPrefs(SharedPrefsConsts.appAuthToken);
_headers['Authorization'] = "Bearer $token";
}
if (queryParameters != null) {
var queryString = new Uri(queryParameters: queryParameters).query;
url = url + '?' + queryString;
}
var response = await _get(Uri.parse(url), headers: _headers).timeout(Duration(seconds: 60));
if (response.statusCode >= 200 && response.statusCode < 300) {
return response;
} else {
throw _throwAPIException(response, () {
_getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes);
});
}
} on SocketException catch (e) {
if (retryTimes > 0) {
print('will retry after 3 seconds...');
await Future.delayed(Duration(seconds: 3));
return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1);
} else {
throw APIException(APIException.OTHER, arguments: e);
}
} on HttpException catch (e) {
if (retryTimes > 0) {
print('will retry after 3 seconds...');
await Future.delayed(Duration(seconds: 3));
return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1);
} else {
throw APIException(APIException.OTHER, arguments: e);
}
} on TimeoutException catch (e) {
throw APIException(APIException.TIMEOUT, arguments: e);
} on ClientException catch (e) {
if (retryTimes > 0) {
print('will retry after 3 seconds...');
await Future.delayed(Duration(seconds: 3));
return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1);
} else {
throw APIException(APIException.OTHER, arguments: e);
}
}
}
Future<Response> _get(url, {Map<String, String>? headers}) => _withClient((client) => client.get(url, headers: headers));
bool _certificateCheck(X509Certificate cert, String host, int port) => true;
Future<T> _withClient<T>(Future<T> Function(Client) fn) async {
var httpClient = HttpClient()..badCertificateCallback = _certificateCheck;
var client = IOClient(httpClient);
try {
return await fn(client);
} finally {
client.close();
}
}
Future<Response> _post(url, {Map<String, String>? headers, body, Encoding? encoding}) => _withClient((client) => client.post(url, headers: headers, body: body, encoding: encoding));
Future<Response> _put(url, {Map<String, String>? headers, body, Encoding? encoding}) => _withClient((client) => client.put(url, headers: headers, body: body, encoding: encoding));
@override
void setHomeUrl(String url) {
// TODO: implement setHomeUrl
}
}

@ -0,0 +1,29 @@
import 'dart:convert';
import 'package:hmg_patient_app_new/services/api_client.dart';
class APIException implements Exception {
static const String BAD_REQUEST = 'api_common_bad_request';
static const String UNAUTHORIZED = 'api_common_unauthorized';
static const String FORBIDDEN = 'api_common_forbidden';
static const String NOT_FOUND = 'api_common_not_found';
static const String INTERNAL_SERVER_ERROR = 'api_common_internal_server_error';
static const String UPGRADE_REQUIRED = 'api_common_upgrade_required';
static const String BAD_RESPONSE_FORMAT = 'api_common_bad_response_format';
static const String OTHER = 'api_common_http_error';
static const String TIMEOUT = 'api_common_http_timeout';
static const String UNKNOWN = 'unexpected_error';
final String message;
final APIError? error;
final arguments;
const APIException(this.message, {this.arguments, this.error});
Map<String, dynamic> toJson() => {'message': message, 'error': error, 'arguments': '$arguments'};
@override
String toString() {
return jsonEncode(this);
}
}

@ -0,0 +1,117 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
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/home/landing_page.dart';
import 'package:provider/provider.dart';
import 'core/utils/LocalNotification.dart';
import 'core/utils/push-notification-handler.dart';
class SplashPage extends StatefulWidget {
@override
_SplashScreenState createState() => _SplashScreenState();
}
class _SplashScreenState extends State<SplashPage> {
@override
void initState() {
super.initState();
print("Splash init called.............");
Timer(Duration(seconds: 1, milliseconds: 500), () async {
LocalNotification.init(onNotificationClick: (payload) {});
Navigator.of(context).pushReplacement(
MaterialPageRoute(
builder: (BuildContext context) => LandingPage(),
),
);
// } else {}
});
// },
// );
var zoom = ZoomVideoSdk();
InitConfig initConfig = InitConfig(
domain: "zoom.us",
enableLog: true,
);
zoom.initSdk(initConfig);
// AppSharedPreferences().getAll().then((value) {
// debugPrint("ALL SHARED PREFERENCES!!!!!");
// debugPrint(jsonEncode(value));
// });
}
/// load the Privilege from service
Future loadPrivilege() async {
// ProjectViewModel projectProvider = Provider.of<ProjectViewModel>(context, listen: false);
// projectProvider.setPrivilegeModelList(privilege: _privilegeService.privilegeModelList);
// projectProvider.setVidaPlusProjectList(_privilegeService.vidaPlusProjectListModel);
// projectProvider.setHMCProjectList(_privilegeService.hMCProjectListModel);
// projectProvider.setProjectsDetailList(_privilegeService.projectDetailListModel);
// double lat = await AppSharedPreferences().getDouble(USER_LAT) ?? 0.0;
// double long = await AppSharedPreferences().getDouble(USER_LONG) ?? 0.0;
// AppSharedPreferences().clear(); // Clearing Shared Preferences On App Launch
// await AppSharedPreferences().setDouble(USER_LAT, lat);
// await AppSharedPreferences().setDouble(USER_LONG, long);
// AppSharedPreferences().setString(APP_LANGUAGE, projectProvider.isArabic ? "ar" : "en");
// var themeNotifier = Provider.of<ThemeNotifier>(context, listen: false);
// themeNotifier.setTheme(defaultTheme(fontName: projectProvider.isArabic ? 'Cairo' : 'Poppins'));
PushNotificationHandler().init(context); // Asyncronously
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xffF8F8F8),
body: Stack(
alignment: Alignment.center,
children: [
Padding(
padding: EdgeInsets.symmetric(horizontal: 53),
child: Image.asset(
'assets/images/new/hmg_logo.png',
fit: BoxFit.fitWidth,
width: MediaQuery.of(context).size.width,
),
),
Align(
alignment: Alignment.bottomCenter,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
"Powered by",
style: TextStyle(fontSize: 14, fontWeight: FontWeight.w400, color: Color(0xff333C45), letterSpacing: -0.56, height: 16 / 14),
),
SizedBox(
height: 5,
),
SvgPicture.asset(
'assets/images/new/cloud_logo.svg',
width: 40,
height: 40,
),
SizedBox(
height: 7,
),
// Text(
// "Version 1.1.0",
// style: TextStyle(fontSize: 10, fontWeight: FontWeight.w400, color: Color(0xff3989898), letterSpacing: 0, height: 12 / 10),
// ),
SizedBox(
height: 18,
)
],
),
)
],
),
);
}
}

@ -0,0 +1,58 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class AppTheme {
static ThemeData getTheme(isArabic) => ThemeData(
fontFamily: isArabic ? 'NotoSansArabic' : 'Jost',
primarySwatch: Colors.red,
visualDensity: VisualDensity.adaptivePlatformDensity,
brightness: Brightness.light,
pageTransitionsTheme: const PageTransitionsTheme(
builders: {
TargetPlatform.android: ZoomPageTransitionsBuilder(),
TargetPlatform.iOS: CupertinoPageTransitionsBuilder(),
},
),
hintColor: Colors.grey[400],
// colorScheme: ColorScheme.fromSwatch(accentColor: MyColors.backgroundColor),
disabledColor: Colors.grey[300],
// errorColor: const Colors,
// scaffoldBackgroundColor: MyColors.backgroundColor,
textSelectionTheme: const TextSelectionThemeData(cursorColor: Colors.grey, selectionColor: Color.fromRGBO(80, 100, 253, 0.5), selectionHandleColor: Colors.grey),
canvasColor: Colors.white,
// backgroundColor: const Color.fromRGBO(255, 255, 255, 1),
highlightColor: Colors.grey[100]!.withOpacity(0.4),
splashColor: Colors.transparent,
// primaryColor: primaryColor,
// primaryColorDark: primaryColor,
// toggleableActiveColor: secondaryColor,
// indicatorColor: secondaryColor,
bottomSheetTheme: const BottomSheetThemeData(
backgroundColor: Color(0xFFE0E0E0),
),
// primaryTextTheme: const TextTheme(
// bodyText2: TextStyle(color: Colors.white),
// ),
// iconTheme: const IconThemeData(color: MyColors.darkTextColor),
// textTheme: const TextTheme(
// bodyText1: TextStyle(color: Colors.black, letterSpacing: 0.6),
// headline1: TextStyle(color: Colors.white, letterSpacing: 0.6),
// headline2: TextStyle(color: Colors.white, letterSpacing: 0.6),
// ),
floatingActionButtonTheme: const FloatingActionButtonThemeData(highlightElevation: 2, disabledElevation: 0, elevation: 2),
appBarTheme: AppBarTheme(
color: const Color(0xff515A5D),
elevation: 0.0,
actionsIconTheme: IconThemeData(
color: Colors.grey[800],
),
systemOverlayStyle: SystemUiOverlayStyle.light,
),
);
}
extension ExtendedRevoCheckTheme on TextTheme {
//add custom styles and colors here
//taken from https://medium.com/@crizantlai/flutter-how-to-extend-themedata-b5b987a95bb5
TextStyle get price => const TextStyle(color: Colors.redAccent);
}

@ -0,0 +1,18 @@
import 'package:flutter/material.dart';
const mainPurple = Color(0xFF7954F7);
const purpleBg = Color(0xFFAEA4FC);
const deepPurple = Color(0xFF7C65E7);
const logoColor = Color(0xFF7C65E7);
const buttonColor = Color(0xFF6A46F5);
const splashBgColor = Color(0xFF3C355D);
const whiteColor = Color(0xFFffffff);
const blackColor = Color(0xFF000000);
const lightGray = Color(0xFFF4F5F7);
const lightPurple = Color(0xFFB7A3E6);
const scaffoldBgColor = Color(0xFFF8F8F8);
const lightGreyEFColor = Color(0xffeaeaff);
const greyF7Color = Color(0xffF7F7F7);
const lightGrayColor = Color(0xff808080);
const buttonGrayColor = Color(0xffF1F1F1);
const lightPurpleAlpha = Color(0x5AB7A3E6);

@ -0,0 +1,32 @@
import 'package:hmg_patient_app_new/widgets/arrow_back.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
AppBar AppBarWidget(
BuildContext context, {
required String title,
String? image,
bool isNeedLeading = true,
List<Widget>? actions,
Function? onTap,
Color? backgroundColor,
Color? foregroundColor,
bool? isCenter,
}) {
return AppBar(
// leadingWidth: 0,
titleSpacing: -8,
leading: isNeedLeading
? ArrowBack(
onTap: onTap,
color: foregroundColor ?? whiteColor,
)
: Container(),
title: title.toText16(color: foregroundColor ?? whiteColor, isBold: true),
centerTitle: isCenter ?? true,
elevation: 0,
backgroundColor: backgroundColor ?? mainPurple,
actions: actions,
);
}

@ -0,0 +1,24 @@
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:flutter/material.dart';
class ArrowBack extends StatelessWidget {
final Function? onTap;
final Color color;
ArrowBack({Key? key, this.onTap, this.color = whiteColor}) : super(key: key);
@override
Widget build(BuildContext context) {
// ProjectViewModel projectViewModel = Provider.of(context);
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: Feedback.wrapForTap(() {
onTap != null ? onTap!() : Navigator.maybePop(context);
}, context),
child: Icon(
Icons.arrow_back_ios,
color: color,
),
);
}
}

@ -0,0 +1,58 @@
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/theme/colors.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
class AttachmentOptions extends StatelessWidget {
VoidCallback onCameraTap;
VoidCallback onGalleryTap;
VoidCallback onFilesTap;
bool showFilesOption;
AttachmentOptions({Key? key, required this.onCameraTap, required this.onGalleryTap, required this.onFilesTap, this.showFilesOption = true}) : super(key: key);
@override
Widget build(BuildContext context) {
return SizedBox(
width: double.infinity,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Upload Attachment".toSectionHeading(),
"Select from gallery or open camera".toText11(weight: FontWeight.w500),
GridView(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3, childAspectRatio: 105 / 105, crossAxisSpacing: 9, mainAxisSpacing: 9),
physics: const NeverScrollableScrollPhysics(),
padding: const EdgeInsets.only(top: 21, bottom: 14),
shrinkWrap: true,
children: [
itemView("open_camera.svg", "Open\nCamera", onCameraTap),
itemView("gallery.svg", "Upload from\nGallery", onGalleryTap),
if (showFilesOption) itemView("files.svg", "Upload from\nFiles", onFilesTap),
],
)
],
).paddingOnly(left: 21, right: 21, bottom: 21),
);
}
Widget itemView(String icon, String title, VoidCallback onTap) {
return InkWell(
onTap: onTap,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SvgPicture.asset("assets/images/$icon", color: mainPurple,),
title.toText11(isBold: true),
],
).paddingOnly(left: 13, right: 13, top: 16, bottom: 12).expanded.objectContainerBorderView(
disablePadding: true,
radius: 10,
color: greyF7Color.withOpacity(.48),
borderColor: lightGreyEFColor.withOpacity(.48),
),
);
}
}

@ -0,0 +1,89 @@
import 'package:hmg_patient_app_new/extensions/int_extensions.dart';
import 'package:flutter/material.dart';
void showMyBottomSheet(BuildContext context, {required Widget child, required VoidCallback callBackFunc, String? type}) {
showModalBottomSheet<String>(
context: context,
isScrollControlled: true,
backgroundColor: Colors.transparent,
builder: (BuildContext context) {
return Container(
constraints: BoxConstraints(
maxHeight: type =='CONTINUE_ACTION' ? MediaQuery.of(context).size.height *.75 : double.infinity,),
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topRight: Radius.circular(25),
topLeft: Radius.circular(25),
),
),
padding: MediaQuery.of(context).viewInsets,
clipBehavior: Clip.antiAlias,
child:SingleChildScrollView(child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
13.height,
Container(
height: 6,
width: 60,
decoration: const BoxDecoration(
color: Color(0xff9A9A9A),
borderRadius: BorderRadius.all(
Radius.circular(20),
),
),
),
8.height,
child,
],
)),
);
},
).then((value) {
// print("BACK FROM DELEGATE!!!!");
// print("value: $value");
if (value == "delegate_reload") {
callBackFunc();
}
});
}
class BottomSheetItem extends StatelessWidget {
final Function onTap;
final IconData icon;
final String title;
final Color color;
const BottomSheetItem({Key? key, required this.onTap, required this.title, required this.icon, this.color = Colors.black}) : super(key: key);
@override
Widget build(BuildContext context) {
return InkWell(
onTap: () {
if (onTap != null) {
Navigator.pop(context);
onTap();
}
},
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 18.0, vertical: 18.0),
child: Row(
children: <Widget>[
if (icon != null)
Icon(
icon,
color: color,
size: 18.0,
),
if (icon != null) SizedBox(width: 24.0),
Text(
title ?? "",
style: TextStyle(color: color),
),
],
),
),
);
}
}

@ -0,0 +1,34 @@
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:flutter/material.dart';
import '../theme/colors.dart';
class CategoryButtons extends StatelessWidget {
CategoryButtons({super.key, required this.label, required this.selected, required this.onTap});
late String label;
late bool selected;
late Function onTap;
@override
Widget build(BuildContext context) {
return Expanded(
child: InkWell(
onTap: () {
onTap();
},
child: Container(
height: 64.h,
decoration: BoxDecoration(
color: selected ? mainPurple : Colors.grey.shade200,
borderRadius: BorderRadius.circular(16),
),
child: Center(
child: label.toText13(color: selected ? Colors.white : Colors.black, isBold: true),
),
),
),
);
}
}

@ -0,0 +1,73 @@
// Dropdown Field
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:flutter/material.dart';
import '../theme/colors.dart';
class DropdownField<T> extends StatelessWidget {
late String hint;
late T? value;
late IconData? icon;
late List<T>? items;
late ValueChanged<T?>? onChanged;
late bool isEnabled;
final String keyName = "dropdown_field";
DropdownField({
required this.hint,
this.value,
this.icon,
this.items,
this.onChanged,
this.isEnabled = true,
});
@override
Widget build(BuildContext context) {
return Container(
height: 54.h,
margin: const EdgeInsets.symmetric(vertical: 8),
padding: const EdgeInsets.symmetric(horizontal: 16),
decoration: BoxDecoration(
color: const Color(0xFFF4F5F7),
borderRadius: BorderRadius.circular(13),
),
child: Row(
children: [
if (icon != null) Icon(icon, color: mainPurple),
if (icon != null) SizedBox(width: 8.h),
Expanded(
child: items != null
? DropdownButton<T>(
value: value,
isExpanded: true,
icon: const Icon(Icons.keyboard_arrow_down_rounded, color: mainPurple),
underline: const SizedBox(),
items: items!
.map(
(item) => DropdownMenuItem(
value: item,
child: item.toString().toText15(isBold: true),
),
)
.toList(),
hint: hint.toText15(color: Colors.black45),
onChanged: onChanged,
)
: Text(
value?.toString() ?? hint,
style: TextStyle(
color: value != null ? Colors.black : Colors.black45,
fontWeight: value != null ? FontWeight.bold : FontWeight.normal,
fontSize: 15,
),
),
),
],
),
);
}
}

@ -0,0 +1,133 @@
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
extension WithContainer on Widget {
Widget get insideContainer => Container(
color: Colors.white,
padding: const EdgeInsets.only(top: 16, bottom: 16, right: 21, left: 21),
child: this,
);
}
class DefaultButton extends StatelessWidget {
final String text;
final VoidCallback? onPress;
final Color textColor;
final Color? color;
final Color? disabledColor;
final IconData? iconData;
final String? svgIcon;
final double? fontSize;
final bool isTextExpanded;
final int count;
final List<Color>? colors;
final double height;
final double borderRadius;
const DefaultButton(this.text, this.onPress,
{Key? key,
this.color,
this.isTextExpanded = true,
this.svgIcon,
this.disabledColor,
this.count = 0,
this.textColor = Colors.white,
this.iconData,
this.fontSize,
this.colors,
this.height = 50,
this.borderRadius = 100})
: super(key: key);
@override
Widget build(BuildContext context) {
return InkWell(
onTap: onPress,
child: Container(
height: height,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(borderRadius),
gradient: onPress == null
? LinearGradient(
colors: <Color>[
disabledColor ?? const Color(0xffEAEAEA),
disabledColor ?? const Color(0xffEAEAEA),
],
)
: LinearGradient(
transform: const GradientRotation(.83),
begin: Alignment.topRight,
end: Alignment.bottomLeft,
colors: colors ??
<Color>[
buttonColor,
buttonColor,
],
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
if (iconData != null) Icon(iconData, color: textColor),
if (svgIcon != null) SvgPicture.asset(svgIcon ?? "", color: textColor),
if (!isTextExpanded)
Padding(
padding: EdgeInsets.only(
left: (iconData ?? svgIcon) != null ? 6 : 0,
),
child: Text(
text,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: fontSize ?? 18.fSize,
fontWeight: FontWeight.w600,
color: textColor,
letterSpacing: -0.48,
),
),
),
if (isTextExpanded)
Expanded(
child: Text(
text,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: fontSize ?? 18.fSize,
fontWeight: FontWeight.w600,
color: textColor,
letterSpacing: -0.48,
),
),
),
if (count > 0)
Align(
alignment: Alignment.topCenter,
child: Container(
margin: const EdgeInsets.only(top: 6, bottom: 6),
padding: const EdgeInsets.only(left: 5, right: 5),
alignment: Alignment.center,
height: 16,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.0),
color: Colors.white,
),
child: Text(
"$count",
textAlign: TextAlign.center,
style: const TextStyle(
fontSize: 12,
fontWeight: FontWeight.w700,
color: Color(0xffD02127),
letterSpacing: -0.6,
),
),
),
)
],
),
),
);
}
}

@ -0,0 +1,65 @@
import 'package:easy_localization/easy_localization.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/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/widgets/default_button.dart';
import 'package:flutter/material.dart';
import '../../theme/colors.dart';
class ConfirmDialog extends StatelessWidget {
final String? title;
final String message;
final String? okTitle;
final VoidCallback? onTap;
final VoidCallback? onCloseTap;
const ConfirmDialog({Key? key, this.title, required this.message, this.okTitle, this.onTap, this.onCloseTap}) : super(key: key);
@override
Widget build(BuildContext context) {
return Dialog(
backgroundColor: Colors.white,
shape: const RoundedRectangleBorder(),
insetPadding: const EdgeInsets.only(left: 21, right: 21),
child: Padding(
padding: const EdgeInsets.only(left: 20, right: 20, top: 18, bottom: 28),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Text(
title ?? LocaleKeys.confirm.tr(),
style: const TextStyle(fontSize: 24, fontWeight: FontWeight.w600, color: blackColor, height: 35 / 24, letterSpacing: -0.96),
).paddingOnly(top: 16),
),
IconButton(
padding: EdgeInsets.zero,
icon: const Icon(Icons.close),
color: blackColor,
constraints: const BoxConstraints(),
onPressed: () => onCloseTap ?? Navigator.pop(context),
// onPressed: () => Navigator.pop(context),
)
],
),
14.height,
message.toText16(color: lightGrayColor),
28.height,
DefaultButton(
okTitle ?? LocaleKeys.ok.tr(),
onTap ?? () => Navigator.pop(context),
textColor: Colors.white,
//color: Ap.green,
),
],
),
),
);
}
}

@ -0,0 +1,214 @@
import 'dart:convert';
import 'dart:io';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/attachment_options.dart';
import 'package:hmg_patient_app_new/widgets/bottom_sheet.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
final ImagePicker picker = ImagePicker();
class ImageOptions {
static void showImageOptionsNew(BuildContext context, bool showFilesOption, Function(String, File) image) {
showMyBottomSheet(
context,
callBackFunc: () {},
child: AttachmentOptions(
showFilesOption: showFilesOption,
onCameraTap: () async {
if (Platform.isAndroid) {
cameraImageAndroid(image);
} else {
File _image = File((await ImagePicker.platform.pickImage(source: ImageSource.camera, imageQuality: 20))?.path ?? "");
// XFile? media = await picker.pickMedia();
String? fileName = _image.path;
var bytes = File(fileName!).readAsBytesSync();
String base64Encode = base64.encode(bytes);
if (base64Encode != null) {
image(base64Encode, _image);
}
}
},
onGalleryTap: () async {
if (Platform.isAndroid) {
galleryImageAndroid(image);
} else {
File _image = File((await picker.pickMedia())?.path ?? "");
String fileName = _image.path;
var bytes = File(fileName).readAsBytesSync();
String base64Encode = base64.encode(bytes);
if (base64Encode != null) {
image(base64Encode, _image);
}
}
},
onFilesTap: () async {
FilePickerResult? result = await FilePicker.platform.pickFiles(
type: FileType.custom,
allowedExtensions: [
'jpg',
'jpeg ',
'pdf',
'txt',
'docx',
'doc',
'pptx',
'xlsx',
'png',
'rar',
'zip',
],
);
List<File> files = result!.paths.map((path) => File(path!)).toList();
image(result.files.first.path.toString(), files.first);
},
),
);
}
// static void showImageOptions(BuildContext context, Function(String, File) image) {
// showModalBottomSheet(
// backgroundColor: Colors.transparent,
// context: context,
// builder: (BuildContext bc) {
// return _BottomSheet(
// children: <Widget>[
// _BottomSheetItem(
// title: "Select File Source",
// onTap: () {},
// icon: Icons.file_present,
// color: MyColors.black,
// ),
// _BottomSheetItem(
// title: "Gallery",
// icon: Icons.image,
// onTap: () async {
// if (Platform.isAndroid) {
// galleryImageAndroid(image);
// } else {
// File _image = File((await ImagePicker.platform.pickImage(source: ImageSource.gallery, imageQuality: 10))?.path ?? "");
// String fileName = _image.path;
// var bytes = File(fileName).readAsBytesSync();
// String base64Encode = base64.encode(bytes);
// if (base64Encode != null) {
// image(base64Encode, _image);
// }
// }
// },
// ),
// _BottomSheetItem(
// title: "Camera",
// icon: Icons.camera_alt,
// onTap: () async {
// if (Platform.isAndroid) {
// cameraImageAndroid(image);
// } else {
// File _image = File((await ImagePicker.platform.pickImage(source: ImageSource.camera, imageQuality: 10))?.path ?? "");
// String fileName = _image.path;
// var bytes = File(fileName).readAsBytesSync();
// String base64Encode = base64.encode(bytes);
// if (base64Encode != null) {
// image(base64Encode, _image);
// }
// }
// },
// ),
// _BottomSheetItem(
// title: "Cancel",
// onTap: () {},
// icon: Icons.cancel,
// color: MyColors.redColor,
// )
// ],
// );
// });
// }
}
void galleryImageAndroid(Function(String, File) image) async {
File _image = File((await picker.pickMedia())?.path ?? "");
String fileName = _image.path;
var bytes = File(fileName).readAsBytesSync();
String base64Encode = base64.encode(bytes);
if (base64Encode != null) {
image(base64Encode, _image);
}
}
void cameraImageAndroid(Function(String, File) image) async {
File _image = File((await picker.pickMedia())?.path ?? "");
String fileName = _image.path;
var bytes = File(fileName).readAsBytesSync();
String base64Encode = base64.encode(bytes);
if (base64Encode != null) {
image(base64Encode, _image);
}
}
class _BottomSheet extends StatelessWidget {
final List<Widget> children;
const _BottomSheet({Key? key, required this.children}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.symmetric(vertical: 12.0),
decoration: BoxDecoration(color: Theme.of(context).scaffoldBackgroundColor, borderRadius: const BorderRadius.only(topLeft: Radius.circular(16.0), topRight: Radius.circular(16.0))),
child: SafeArea(
top: false,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
decoration: BoxDecoration(color: Theme.of(context).dividerColor, borderRadius: BorderRadius.circular(3.0)),
width: 40.0,
height: 6.0,
),
...children
],
),
),
);
}
}
class _BottomSheetItem extends StatelessWidget {
final Function onTap;
final IconData icon;
final String title;
final Color color;
_BottomSheetItem({Key? key, required this.onTap, required this.title, required this.icon, this.color = mainPurple}) : super(key: key);
@override
Widget build(BuildContext context) {
return InkWell(
onTap: () {
if (onTap != null) {
Navigator.pop(context);
onTap();
}
},
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 18.0, vertical: 18.0),
child: Row(
children: <Widget>[
if (icon != null)
Icon(
icon,
color: color,
size: 18.0,
),
if (icon != null) const SizedBox(width: 24.0),
title.toText17(),
],
),
),
);
}
}

@ -0,0 +1,164 @@
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/extensions/int_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
// import 'package:sizer/sizer.dart';
class CustomTextField extends StatefulWidget {
final String labelText;
final String? hintText;
final TextEditingController controller;
final VoidCallback? suffixTap;
final IconData? suffixIcon;
final bool isEnable;
final bool hasSelection;
final int? lines;
final bool isInputTypeNum;
final bool isTextIsPassword;
final bool isBackgroundEnable;
final bool isEnableBorder;
final double verticalPadding;
final double horizontalPadding;
final Function(String)? onChange;
final Function()? onEditComplete;
final Function(String)? onSubmit;
final Function? onClick;
final FocusNode? focusNode;
List<TextInputFormatter>? inputFormatters;
CustomTextField(
this.labelText,
this.controller, {
Key? key,
this.isTextIsPassword = false,
this.suffixTap,
this.suffixIcon,
this.hintText,
this.isEnable = true,
this.hasSelection = false,
this.isEnableBorder = true,
this.lines = 1,
this.onChange,
this.onEditComplete,
this.onSubmit,
this.onClick,
this.isInputTypeNum = false,
this.isBackgroundEnable = false,
this.focusNode,
this.verticalPadding = 15,
this.horizontalPadding = 16,
this.inputFormatters,
}) : super(key: key);
@override
CustomTextFieldState createState() => CustomTextFieldState();
}
class CustomTextFieldState extends State<CustomTextField> {
late bool isObscureText;
late FocusNode focusNode;
@override
void initState() {
super.initState();
focusNode = FocusNode();
isObscureText = widget.isTextIsPassword;
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
return InkWell(
onTap: () {
focusNode.requestFocus();
if (widget.hasSelection) widget.onClick!();
},
child: Container(
padding: EdgeInsets.only(left: widget.horizontalPadding, right: widget.horizontalPadding, bottom: widget.verticalPadding, top: widget.verticalPadding),
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
color: widget.isBackgroundEnable ? const Color(0xffF7F7F7) : Colors.white,
border: Border.all(color: widget.isEnableBorder ? Colors.grey.shade300 : Colors.transparent, width: 1),
),
child: Row(
children: [
Expanded(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
widget.labelText,
style: TextStyle(
fontSize: 12.h,
fontWeight: FontWeight.w600,
color: const Color(0xff2B353E),
letterSpacing: -0.44,
),
),
TextField(
focusNode: focusNode,
autofocus: false,
enabled: widget.isEnable,
scrollPadding: EdgeInsets.zero,
keyboardType: widget.isInputTypeNum ? TextInputType.number : TextInputType.text,
controller: widget.controller,
maxLines: widget.lines,
obscuringCharacter: "*",
obscureText: isObscureText,
onChanged: widget.onChange,
onEditingComplete: widget.onEditComplete,
onSubmitted: widget.onSubmit,
inputFormatters: widget.inputFormatters,
style: const TextStyle(
fontSize: 16,
height: 21 / 14,
fontWeight: FontWeight.w400,
color: Color(0xff2B353E),
letterSpacing: -0.44,
),
decoration: InputDecoration(
isDense: true,
hintText: widget.hintText,
hintStyle: const TextStyle(
fontSize: 14,
height: 21 / 14,
fontWeight: FontWeight.w400,
color: Color(0xff575757),
letterSpacing: -0.56,
),
suffixIconConstraints: const BoxConstraints(minWidth: 50),
suffixIcon: widget.suffixTap == null ? null : IconButton(icon: Icon(Icons.mic, color: blackColor), onPressed: widget.suffixTap),
contentPadding: EdgeInsets.zero,
border: InputBorder.none,
focusedBorder: InputBorder.none,
enabledBorder: InputBorder.none,
),
),
],
),
),
if (widget.isTextIsPassword) ...[
16.width,
Icon(isObscureText ? Icons.visibility_rounded : Icons.visibility_off_rounded).onPress(() {
setState(() {
isObscureText = !isObscureText;
});
})
],
if (widget.hasSelection) const Icon(Icons.keyboard_arrow_down_outlined),
if (widget.suffixIcon != null && widget.suffixTap == null) Icon(widget.suffixIcon!),
],
),
),
);
}
}

@ -0,0 +1,66 @@
import 'package:easy_localization/easy_localization.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/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:lottie/lottie.dart';
class LoadingDialog extends StatefulWidget {
LoadingDialog({Key? key}) : super(key: key);
@override
_LoadingDialogState createState() {
return _LoadingDialogState();
}
}
class _LoadingDialogState extends State<LoadingDialog> {
@override
void initState() {
super.initState();
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
return Dialog(
insetPadding: const EdgeInsets.symmetric(horizontal: 60.0, vertical: 24.0),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
elevation: 0,
backgroundColor: whiteColor,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
Center(
child: Padding(
padding: const EdgeInsets.all(24.0),
child: Column(
children: [
Lottie.asset('assets/json/loading_animation.json', repeat: true, reverse: false, frameRate: FrameRate(60)),
24.height,
LocaleKeys.loadingText.tr(context: context).toText16(color: blackColor)
],
),
),
// Image.asset(
// "assets/images/loading.gif",
// height: 96.0,
// width: 96.0,
// ),
),
],
),
);
}
}

@ -0,0 +1,377 @@
import 'dart:async';
import 'package:flutter/animation.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
typedef OnDone = void Function(String text);
class ProvidedPinBoxTextAnimation {
static AnimatedSwitcherTransitionBuilder scalingTransition = (child, animation) {
return ScaleTransition(
child: child,
scale: animation,
);
};
static AnimatedSwitcherTransitionBuilder defaultNoTransition = (Widget child, Animation<double> animation) {
return child;
};
}
class OTPWidget extends StatefulWidget {
final int maxLength;
late TextEditingController? controller;
final Color defaultBorderColor;
final Color pinBoxColor;
final double pinBoxBorderWidth;
final double pinBoxRadius;
final bool hideDefaultKeyboard;
final TextStyle? pinTextStyle;
final double pinBoxHeight;
final double pinBoxWidth;
final OnDone? onDone;
final bool hasError;
final Color errorBorderColor;
final Color textBorderColor;
final Function(String)? onTextChanged;
final bool autoFocus;
final FocusNode? focusNode;
final AnimatedSwitcherTransitionBuilder? pinTextAnimatedSwitcherTransition;
final Duration pinTextAnimatedSwitcherDuration;
final TextDirection textDirection;
final TextInputType keyboardType;
final EdgeInsets pinBoxOuterPadding;
OTPWidget({
Key? key,
this.maxLength = 4,
this.controller,
this.pinBoxWidth = 70.0,
this.pinBoxHeight = 70.0,
this.pinTextStyle,
this.onDone,
this.defaultBorderColor = Colors.black,
this.textBorderColor = Colors.black,
this.pinTextAnimatedSwitcherTransition,
this.pinTextAnimatedSwitcherDuration = const Duration(),
this.hasError = false,
this.errorBorderColor = Colors.red,
this.onTextChanged,
this.autoFocus = false,
this.focusNode,
this.textDirection = TextDirection.ltr,
this.keyboardType = TextInputType.number,
this.pinBoxOuterPadding = const EdgeInsets.symmetric(horizontal: 4.0),
this.pinBoxColor = Colors.white,
this.pinBoxBorderWidth = 2.0,
this.pinBoxRadius = 0,
this.hideDefaultKeyboard = false,
}) : super(key: key);
@override
State<StatefulWidget> createState() {
return OTPWidgetState();
}
}
class OTPWidgetState extends State<OTPWidget> with SingleTickerProviderStateMixin {
late AnimationController _highlightAnimationController;
late FocusNode focusNode;
String text = "";
int currentIndex = 0;
List<String> strList = [];
bool hasFocus = false;
@override
void didUpdateWidget(OTPWidget oldWidget) {
super.didUpdateWidget(oldWidget);
focusNode = widget.focusNode ?? focusNode;
if (oldWidget.maxLength < widget.maxLength) {
setState(() {
currentIndex = text.length;
});
widget.controller?.text = text;
widget.controller?.selection = TextSelection.collapsed(offset: text.length);
} else if (oldWidget.maxLength > widget.maxLength && widget.maxLength > 0 && text.length > 0 && text.length > widget.maxLength) {
setState(() {
text = text.substring(0, widget.maxLength);
currentIndex = text.length;
});
widget.controller?.text = text;
widget.controller?.selection = TextSelection.collapsed(offset: text.length);
}
}
_calculateStrList() {
if (strList.length > widget.maxLength) {
strList.length = widget.maxLength;
}
while (strList.length < widget.maxLength) {
strList.add("");
}
}
@override
void initState() {
super.initState();
focusNode = widget.focusNode ?? FocusNode();
_highlightAnimationController = AnimationController(vsync: this);
_initTextController();
_calculateStrList();
widget.controller!.addListener(_controllerListener);
focusNode.addListener(_focusListener);
}
void _controllerListener() {
if (mounted == true) {
setState(() {
_initTextController();
});
var onTextChanged = widget.onTextChanged;
if (onTextChanged != null) {
onTextChanged(widget.controller?.text ?? "");
}
}
}
void _focusListener() {
if (mounted == true) {
setState(() {
hasFocus = focusNode?.hasFocus ?? false;
});
}
}
void _initTextController() {
if (widget.controller == null) {
return;
}
strList.clear();
var text = widget.controller?.text ?? "";
if (text.isNotEmpty) {
if (text.length > widget.maxLength) {
throw Exception("TextEditingController length exceeded maxLength!");
}
}
for (var i = 0; i < text.length; i++) {
strList.add(text[i]);
}
}
double get _width {
var width = 0.0;
for (var i = 0; i < widget.maxLength; i++) {
width += widget.pinBoxWidth;
if (i == 0) {
width += widget.pinBoxOuterPadding.left;
} else if (i + 1 == widget.maxLength) {
width += widget.pinBoxOuterPadding.right;
} else {
width += widget.pinBoxOuterPadding.left;
}
}
return width;
}
@override
void dispose() {
if (widget.focusNode == null) {
focusNode.dispose();
} else {
focusNode.removeListener(_focusListener);
}
_highlightAnimationController.dispose();
widget.controller?.removeListener(_controllerListener);
super.dispose();
}
@override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
_otpTextInput(),
_touchPinBoxRow(),
],
);
}
Widget _touchPinBoxRow() {
return widget.hideDefaultKeyboard
? _pinBoxRow(context)
: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
if (hasFocus) {
FocusScope.of(context).requestFocus(FocusNode());
Future.delayed(Duration(milliseconds: 100), () {
FocusScope.of(context).requestFocus(focusNode);
});
} else {
FocusScope.of(context).requestFocus(focusNode);
}
},
child: _pinBoxRow(context),
);
}
Widget _otpTextInput() {
var transparentBorder = OutlineInputBorder(
borderSide: BorderSide(
color: Colors.transparent,
width: 0.0,
),
);
return Container(
width: _width,
height: widget.pinBoxHeight,
child: TextField(
autofocus: !kIsWeb ? widget.autoFocus : false,
enableInteractiveSelection: false,
focusNode: focusNode,
controller: widget.controller,
keyboardType: widget.keyboardType,
inputFormatters: widget.keyboardType == TextInputType.number ? <TextInputFormatter>[FilteringTextInputFormatter.digitsOnly] : null,
style: TextStyle(
height: 0.1,
color: Colors.transparent,
),
decoration: InputDecoration(
contentPadding: EdgeInsets.all(0),
focusedErrorBorder: transparentBorder,
errorBorder: transparentBorder,
disabledBorder: transparentBorder,
enabledBorder: transparentBorder,
focusedBorder: transparentBorder,
counterText: null,
counterStyle: null,
helperStyle: TextStyle(
height: 0.0,
color: Colors.transparent,
),
labelStyle: TextStyle(height: 0.1),
fillColor: Colors.transparent,
border: InputBorder.none,
),
cursorColor: Colors.transparent,
showCursor: false,
maxLength: widget.maxLength,
onChanged: _onTextChanged,
),
);
}
void _onTextChanged(text) {
var onTextChanged = widget.onTextChanged;
if (onTextChanged != null) {
onTextChanged(text);
}
setState(() {
this.text = text;
if (text.length >= currentIndex) {
for (int i = currentIndex; i < text.length; i++) {
strList[i] = text[i];
}
}
currentIndex = text.length;
});
if (text.length == widget.maxLength) {
FocusScope.of(context).requestFocus(FocusNode());
var onDone = widget.onDone;
if (onDone != null) {
onDone(text);
}
}
}
Widget _pinBoxRow(BuildContext context) {
_calculateStrList();
List<Widget> pinCodes = List.generate(widget.maxLength, (int i) {
return _buildPinCode(i, context);
});
return Row(
children: pinCodes,
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
);
}
Widget _buildPinCode(int i, BuildContext context) {
Color borderColor;
Color pinBoxColor = widget.pinBoxColor;
if (widget.hasError) {
borderColor = widget.errorBorderColor;
} else if (i < text.length) {
borderColor = widget.textBorderColor;
} else {
borderColor = widget.defaultBorderColor;
pinBoxColor = widget.pinBoxColor;
}
EdgeInsets insets;
if (i == 0) {
insets = EdgeInsets.only(
left: 0,
top: widget.pinBoxOuterPadding.top,
right: widget.pinBoxOuterPadding.right,
bottom: widget.pinBoxOuterPadding.bottom,
);
} else if (i == strList.length - 1) {
insets = EdgeInsets.only(
left: widget.pinBoxOuterPadding.left,
top: widget.pinBoxOuterPadding.top,
right: 0,
bottom: widget.pinBoxOuterPadding.bottom,
);
} else {
insets = widget.pinBoxOuterPadding;
}
return Container(
key: ValueKey<String>("container$i"),
alignment: Alignment.center,
padding: EdgeInsets.symmetric(vertical: 4.0, horizontal: 1.0),
margin: insets,
child: _animatedTextBox(strList[i], i),
decoration: BoxDecoration(
border: Border.all(
color: borderColor,
width: widget.pinBoxBorderWidth,
),
color: pinBoxColor,
borderRadius: BorderRadius.circular(widget.pinBoxRadius),
),
width: widget.pinBoxWidth,
height: widget.pinBoxHeight,
);
}
Widget _animatedTextBox(String text, int i) {
if (widget.pinTextAnimatedSwitcherTransition != null) {
return AnimatedSwitcher(
duration: widget.pinTextAnimatedSwitcherDuration,
transitionBuilder: widget.pinTextAnimatedSwitcherTransition ??
(Widget child, Animation<double> animation) {
return child;
},
child: Text(
text,
key: ValueKey<String>("$text$i"),
style: widget.pinTextStyle,
),
);
} else {
return Text(
text,
key: ValueKey<String>("${strList[i]}$i"),
style: widget.pinTextStyle,
);
}
}
}

@ -0,0 +1,115 @@
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class PhoneNumberInput extends StatefulWidget {
final void Function(String fullNumber)? onChanged;
final TextEditingController textController;
const PhoneNumberInput({Key? key, this.onChanged, required this.textController}) : super(key: key);
@override
State<PhoneNumberInput> createState() => _PhoneNumberInputState();
}
class _PhoneNumberInputState extends State<PhoneNumberInput> {
String _selectedCountryCode = '+966';
final List<String> _countryCodes = ['+966', '+971', '+1', '+44', '+91'];
void _onCountryCodeChanged(String? code) {
if (code != null) {
setState(() {
_selectedCountryCode = code;
});
_notifyChanged();
}
}
void _onPhoneChanged(String value) {
_notifyChanged();
}
void _notifyChanged() {
if (widget.onChanged != null) {
widget.onChanged!(
'$_selectedCountryCode${widget.textController.text}',
);
}
}
@override
void dispose() {
widget.textController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 10),
decoration: BoxDecoration(
color: const Color(0xFFF4F5F7),
borderRadius: BorderRadius.circular(16),
),
child: Row(
children: [
// Country Code Dropdown
DropdownButtonHideUnderline(
child: DropdownButton<String>(
value: _selectedCountryCode,
items: _countryCodes
.map(
(code) => DropdownMenuItem(
value: code,
child: code.toText16(color: mainPurple, isBold: true),
),
)
.toList(),
onChanged: _onCountryCodeChanged,
icon: const Icon(
Icons.keyboard_arrow_down_rounded,
color: mainPurple,
),
),
),
const SizedBox(width: 8),
// Phone number input
Expanded(
child: TextField(
onTapOutside: (event) {
FocusScope.of(context).unfocus();
},
controller: widget.textController,
keyboardType: TextInputType.number,
textInputAction: TextInputAction.done,
maxLength: 10,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.allow(RegExp(r'^\d*\.?\d*$')),
],
decoration: const InputDecoration(
counterStyle: TextStyle(
height: double.minPositive,
),
counterText: "",
hintText: '5xxxxxxxx',
border: InputBorder.none,
hintStyle: TextStyle(
color: Colors.black38,
letterSpacing: 2,
),
),
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
letterSpacing: 2,
color: Colors.black,
),
onChanged: _onPhoneChanged,
),
),
],
),
);
}
}

@ -0,0 +1,256 @@
// import 'package:easy_localization/src/public_ext.dart';
// import 'package:flutter/material.dart';
// import 'package:flutter_svg/svg.dart';
// import 'package:MyCity/extensions/int_extensions.dart';
// import 'package:MyCity/extensions/string_extensions.dart';
// import 'package:MyCity/extensions/widget_extensions.dart';
//
// import 'package:shimmer/shimmer.dart';
//
// class GetAttendanceTrackingShimmer extends StatelessWidget {
// @override
// Widget build(BuildContext context) {
// return Container(
// width: double.infinity,
// height: double.infinity,
// clipBehavior: Clip.antiAlias,
// decoration: BoxDecoration(
// color: Colors.white,
// borderRadius: BorderRadius.circular(15),
// boxShadow: [
// BoxShadow(
// color: const Color(0xff000000).withOpacity(.05),
// blurRadius: 26,
// offset: const Offset(0, -3),
// ),
// ],
// ),
// child: Stack(
// alignment: Alignment.center,
// children: [
// // SvgPicture.asset("assets/images/"),
// Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Expanded(
// child: Column(
// mainAxisSize: MainAxisSize.min,
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// LocaleKeys.markAttendance.tr().toText14(color: Colors.white, isBold: true).toShimmer(),
// 16.height,
// "07:55:12".toText10(color: Colors.white, isBold: true).toShimmer(),
// 3.height,
// LocaleKeys.timeLeftToday.tr().toText10(color: Colors.white).toShimmer(),
// 9.height,
// const ClipRRect(
// borderRadius: BorderRadius.all(
// Radius.circular(20),
// ),
// child: LinearProgressIndicator(
// value: 0.7,
// minHeight: 8,
// valueColor: const AlwaysStoppedAnimation<Color>(Colors.white),
// backgroundColor: const Color(0xff196D73),
// ),
// ).toShimmer(),
// ],
// ).paddingOnly(top: 12, right: 15, left: 12),
// ),
// Row(
// children: [
// Expanded(
// child: Column(
// mainAxisSize: MainAxisSize.min,
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// LocaleKeys.checkIn.tr().toText12(color: Colors.white).toShimmer(),
// ],
// ).paddingOnly(left: 12),
// ),
// Container(
// width: 45,
// height: 45,
// // color: Colors.blue,
// padding: const EdgeInsets.only(left: 14, right: 14),
// ).toShimmer(),
// ],
// ),
// ],
// ),
// ],
// ),
// );
// }
// }
//
// class MenuShimmer extends StatelessWidget {
// @override
// Widget build(BuildContext context) {
// return Container(
// clipBehavior: Clip.antiAlias,
// decoration: BoxDecoration(
// color: Colors.white,
// borderRadius: BorderRadius.circular(15),
// boxShadow: [
// BoxShadow(
// color: const Color(0xff000000).withOpacity(.05),
// blurRadius: 26,
// offset: const Offset(0, -3),
// ),
// ],
// ),
// child: Column(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// LocaleKeys.workList.tr().toText12(color: Colors.white).toShimmer(),
// Row(
// children: [
// Expanded(
// flex: 3,
// child: 123.toString().toText10(color: Colors.white, isBold: true).toShimmer(),
// ),
// 12.width,
// SvgPicture.asset("assets/images/arrow_next.svg", color: Colors.white).toShimmer()
// ],
// )
// ],
// ).paddingOnly(left: 10, right: 10, bottom: 6, top: 6),
// );
// }
// }
//
// class ServicesHeaderShimmer extends StatelessWidget {
// @override
// Widget build(BuildContext context) {
// return Row(
// crossAxisAlignment: CrossAxisAlignment.center,
// children: [
// Expanded(
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// mainAxisSize: MainAxisSize.min,
// children: [
// "Other".tr().toText10().toShimmer(),
// 6.height,
// LocaleKeys.services.tr().toText12(isBold: true).toShimmer(),
// ],
// ),
// ),
// LocaleKeys.viewAllServices.tr().toText12(isUnderLine: true).toShimmer(),
// ],
// );
// }
// }
//
// class ServicesMenuShimmer extends StatelessWidget {
// @override
// Widget build(BuildContext context) {
// return Container(
// decoration: BoxDecoration(
// color: Colors.white,
// borderRadius: BorderRadius.circular(15),
// boxShadow: [
// BoxShadow(
// color: const Color(0xff000000).withOpacity(.05),
// blurRadius: 26,
// offset: const Offset(0, -3),
// ),
// ],
// ),
// child: Column(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// SvgPicture.asset("assets/images/monthly_attendance.svg").toShimmer(),
// Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// mainAxisAlignment: MainAxisAlignment.start,
// children: [
// "Attendan".toText11(isBold: false).toShimmer(),
// 5.height,
// Row(
// crossAxisAlignment: CrossAxisAlignment.end,
// children: [
// Expanded(
// child: LocaleKeys.attendance.tr().toText11(isBold: false).toShimmer(),
// ),
// 6.width,
// SvgPicture.asset("assets/images/arrow_next.svg").paddingOnly(bottom: 4).toShimmer()
// ],
// ),
// ],
// )
// ],
// ).paddingOnly(left: 10, right: 10, bottom: 10, top: 12),
// );
// }
// }
//
// class ChatHomeShimmer extends StatelessWidget {
// @override
// Widget build(BuildContext context) {
// return Container(
// width: double.infinity,
// padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 16.0),
// child: Column(
// mainAxisSize: MainAxisSize.max,
// children: <Widget>[
// Expanded(
// child: Shimmer.fromColors(
// baseColor: Colors.white,
// highlightColor: Colors.grey.shade100,
// child: ListView.builder(
// itemBuilder: (_, __) => Padding(
// padding: const EdgeInsets.only(bottom: 8.0),
// child: Row(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: <Widget>[
// Container(
// width: 48.0,
// height: 48.0,
// decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(40))),
// ),
// const Padding(
// padding: EdgeInsets.symmetric(horizontal: 8.0),
// ),
// Expanded(
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: <Widget>[
// Container(
// width: double.infinity,
// height: 8.0,
// color: Colors.white,
// ),
// const Padding(
// padding: EdgeInsets.symmetric(vertical: 2.0),
// ),
// Container(
// width: double.infinity,
// height: 8.0,
// color: Colors.white,
// ),
// const Padding(
// padding: EdgeInsets.symmetric(vertical: 2.0),
// ),
// Container(
// width: 40.0,
// height: 8.0,
// color: Colors.white,
// ),
// ],
// ),
// )
// ],
// ),
// ),
// itemCount: 6,
// ),
// ),
// ),
// ],
// ));
// }
// }

@ -0,0 +1,43 @@
import 'package:hmg_patient_app_new/extensions/int_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:flutter/material.dart';
class MoviesShimmerWidget extends StatelessWidget {
const MoviesShimmerWidget({super.key});
@override
Widget build(BuildContext context) {
return SizedBox(
child: Container(
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(
Radius.circular(10),
),
border: Border.all(color: lightGreyEFColor, width: 1),
boxShadow: [
BoxShadow(
color: const Color(0xff000000).withOpacity(.05),
blurRadius: 26,
offset: const Offset(0, -3),
),
],
),
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
children: [
Container(height: 100).toShimmer(),
16.height,
Container(height: 24).toShimmer(),
16.height,
Container(height: 48).toShimmer(),
16.height,
Container(height: 24).toShimmer(),
8.height
],
),
)),
);
}
}

@ -0,0 +1,30 @@
import 'package:flutter/material.dart';
/// FadePage animation
/// [page]
class FadePage extends PageRouteBuilder {
final Widget? page;
FadePage({this.page})
: super(
opaque: false,
fullscreenDialog: true,
barrierDismissible: true,
barrierColor: Colors.black.withOpacity(0.8),
pageBuilder: (
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
) =>
page!,
transitionDuration: const Duration(milliseconds: 600),
transitionsBuilder: (
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child,
) {
return FadeTransition(opacity: animation, child: child);
},
);
}

@ -0,0 +1,146 @@
// import 'package:diplomaticquarterapp/core/model/vital_sign/vital_sign_res_model.dart';
// import 'package:diplomaticquarterapp/core/viewModels/project_view_model.dart';
// import 'package:diplomaticquarterapp/uitl/date_uitl.dart';
// import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart';
// import 'package:diplomaticquarterapp/uitl/utils.dart';
// import 'package:diplomaticquarterapp/uitl/utils_new.dart';
// import 'package:diplomaticquarterapp/widgets/charts/app_time_series_chart.dart';
// import 'package:diplomaticquarterapp/widgets/charts/show_chart.dart';
// import 'package:diplomaticquarterapp/widgets/charts/sync_fu_chart.dart';
// import 'package:flutter/material.dart';
// import 'package:provider/provider.dart';
//
// import 'LineChartCurved.dart';
//
// class VitalSingChartAndDetials extends StatefulWidget {
// VitalSingChartAndDetials({
// Key? key,
// required this.vitalList,
// required this.name,
// required this.viewKey,
// required this.title1,
// required this.title2,
// }) : super(key: key);
//
// final List<VitalSignResModel> vitalList;
// final String name;
// final String viewKey;
// final String title1;
// final String title2;
//
// @override
// _VitalSingChartAndDetialsState createState() => _VitalSingChartAndDetialsState();
// }
//
// class _VitalSingChartAndDetialsState extends State<VitalSingChartAndDetials> {
// List<TimeSeriesSales2> timeSeriesData = [];
// bool isExpended = true;
// late ProjectViewModel projectViewModel;
//
// @override
// void initState() {
// // TODO: implement initState
// super.initState();
// generateData();
// }
//
// @override
// Widget build(BuildContext context) {
// projectViewModel = Provider.of(context);
// return SingleChildScrollView(
// child: Column(
// children: <Widget>[
// Container(
// height: 400,
// child: Container(
// decoration: cardRadius(12),
// margin: EdgeInsets.only(left: 16, top: 16, right: 16, bottom: 8),
// child: ShowChart(
// title: widget.name,
// timeSeries: timeSeriesData,
// indexes: timeSeriesData.length ~/ 5.5,
// horizontalInterval: 8,
// ),
// // child: SyncFuChart(),
// ),
// ),
// Container(
// decoration: cardRadius(12),
// margin: EdgeInsets.only(left: 16, top: 8, right: 16, bottom: 16),
// child: Padding(
// padding: const EdgeInsets.all(12.0),
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Text(
// TranslationBase.of(context).graphDetails,
// style: TextStyle(
// fontSize: 16,
// letterSpacing: -0.64,
// fontWeight: FontWeight.w600,
// ),
// ),
// Table(
// columnWidths: {
// 0: FlexColumnWidth(2),
// 1: FlexColumnWidth(1),
// // 2: FlexColumnWidth(1),
// },
// children: fullData(widget.vitalList, context),
// ),
// ],
// ),
// ),
// )
// ],
// ),
// );
// }
//
// List<TableRow> fullData(List<VitalSignResModel> labResultList, context) {
// List<TableRow> tableRow = [];
// tableRow.add(
// TableRow(
// children: [
// Utils.tableColumnTitle(widget.title1),
// Utils.tableColumnTitle(widget.title2),
// // Utils.tableColumnTitle(TranslationBase.of(context).range),
// ],
// ),
// );
//
// for (int i = 0; i < labResultList.length; i++) {
// var data = labResultList[i].toJson()[widget.viewKey];
// if (data != 0)
// tableRow.add(
// TableRow(
// children: [
// Utils.tableColumnValue(
// "${projectViewModel.isArabic ? DateUtil.getWeekDayArabic(labResultList[i].vitalSignDate!.weekday) : DateUtil.getWeekDay(labResultList[i].vitalSignDate!.weekday)}, ${labResultList[i].vitalSignDate!.day} ${projectViewModel.isArabic ? DateUtil.getMonthArabic(labResultList[i].vitalSignDate!.month) : DateUtil.getMonth(labResultList[i].vitalSignDate!.month)}, ${labResultList[i].vitalSignDate!.year}",
// isLast: i == (labResultList.length - 1), mProjectViewModel: projectViewModel),
// Utils.tableColumnValue('${labResultList[i].toJson()[widget.viewKey]}', isLast: i == (labResultList.length - 1), mProjectViewModel: projectViewModel),
// ],
// ),
// );
// }
//
// return tableRow;
// }
//
// generateData() {
// if (widget.vitalList.length > 0) {
// widget.vitalList.reversed.toList().forEach(
// (element) {
// if (element.toJson()[widget.viewKey] != null && element.toJson()[widget.viewKey]?.toInt() != 0)
// timeSeriesData.add(
// TimeSeriesSales2(
// DateTime(element.vitalSignDate!.year, element.vitalSignDate!.month, element.vitalSignDate!.day),
// element.toJson()[widget.viewKey].toDouble(),
// ),
// );
// },
// );
// }
// return timeSeriesData.reversed.toList();
// }
// }

@ -0,0 +1,149 @@
// import 'package:diplomaticquarterapp/core/model/vital_sign/vital_sign_res_model.dart';
// import 'package:diplomaticquarterapp/core/viewModels/project_view_model.dart';
// import 'package:diplomaticquarterapp/uitl/date_uitl.dart';
// import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart';
// import 'package:diplomaticquarterapp/uitl/utils.dart';
// import 'package:diplomaticquarterapp/uitl/utils_new.dart';
// import 'package:diplomaticquarterapp/widgets/charts/app_time_series_chart.dart';
// import 'package:flutter/material.dart';
// import 'package:provider/provider.dart';
//
// import 'LineChartCurvedBloodPressure.dart';
//
// class VitalSingChartBloodPressure extends StatelessWidget {
// VitalSingChartBloodPressure({
// Key? key,
// required this.vitalList,
// required this.name,
// required this.viewKey1,
// required this.viewKey2,
// required this.title1,
// required this.title2,
// required this.title3,
// }) : super(key: key);
//
// final List<VitalSignResModel> vitalList;
// final String name;
// final String viewKey1;
// final String viewKey2;
// final String title1;
// final String title2;
// final String title3;
// List<TimeSeriesSales2> timeSeriesData1 = [];
// List<TimeSeriesSales2> timeSeriesData2 = [];
// late ProjectViewModel projectViewModel;
//
// @override
// Widget build(BuildContext context) {
// projectViewModel = Provider.of(context);
// generateData();
// return SingleChildScrollView(
// child: Column(
// children: <Widget>[
// Container(
// decoration: cardRadius(12),
// margin: EdgeInsets.only(left: 16, top: 16, right: 16, bottom: 8),
// child: LineChartCurvedBloodPressure(
// title: name,
// timeSeries1: timeSeriesData1,
// timeSeries2: timeSeriesData2,
// indexes: timeSeriesData1.length ~/ 5.5,
// ),
// ),
//
// // VitalSignBloodPressureWidget(
// // vitalList: vitalList,
// // title1: title1,
// // title2: title2,
// // title3: title3,
// // viewKey1: viewKey1,
// // viewKey2: viewKey2,
// // ),
// Container(
// decoration: cardRadius(12),
// margin: EdgeInsets.only(left: 16, top: 8, right: 16, bottom: 16),
// child: Padding(
// padding: const EdgeInsets.all(12.0),
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Text(
// TranslationBase.of(context).graphDetails,
// style: TextStyle(
// fontSize: 16,
// letterSpacing: -0.64,
// fontWeight: FontWeight.w600,
// ),
// ),
// Table(
// columnWidths: {
// 0: FlexColumnWidth(2),
// 1: FlexColumnWidth(1),
// // 2: FlexColumnWidth(1),
// },
// children: fullData(vitalList, context),
// ),
// ],
// ),
// ),
// )
// ],
// ),
// );
// }
//
// List<TableRow> fullData(List<VitalSignResModel> labResultList, context) {
// List<TableRow> tableRow = [];
// tableRow.add(
// TableRow(
// children: [
// Utils.tableColumnTitle(title1),
// Utils.tableColumnTitle(title2),
// Utils.tableColumnTitle(title3),
// // Utils.tableColumnTitle(TranslationBase.of(context).range),
// ],
// ),
// );
//
// for (int i = 0; i < labResultList.length; i++) {
// var data = labResultList[i].toJson()[viewKey1];
// if (data != 0)
// tableRow.add(
// TableRow(
// children: [
// Utils.tableColumnValue(
// "${projectViewModel.isArabic ? DateUtil.getWeekDayArabic(labResultList[i].vitalSignDate!.weekday) : DateUtil.getWeekDay(labResultList[i].vitalSignDate!.weekday)}, ${labResultList[i].vitalSignDate!.day} ${projectViewModel.isArabic ? DateUtil.getMonthArabic(labResultList[i].vitalSignDate!.month) : DateUtil.getMonth(labResultList[i].vitalSignDate!.month)}, ${labResultList[i].vitalSignDate!.year}",
// isLast: i == (labResultList.length - 1), mProjectViewModel: projectViewModel),
// Utils.tableColumnValue('${labResultList[i].toJson()[viewKey1]}', isLast: i == (labResultList.length - 1), mProjectViewModel: projectViewModel),
// Utils.tableColumnValue('${labResultList[i].toJson()[viewKey2]}', isLast: i == (labResultList.length - 1), mProjectViewModel: projectViewModel),
// ],
// ),
// );
// }
//
// return tableRow;
// }
//
// generateData() {
// if (vitalList.length > 0) {
// vitalList.reversed.toList().forEach(
// (element) {
// if (element.toJson()[viewKey1]?.toInt() != 0)
// timeSeriesData1.add(
// TimeSeriesSales2(
// new DateTime(element.vitalSignDate!.year, element.vitalSignDate!.month, element.vitalSignDate!.day),
// element.toJson()[viewKey1].toDouble(),
// ),
// );
// if (element.toJson()[viewKey2]?.toInt() != 0)
// timeSeriesData2.add(
// TimeSeriesSales2(
// new DateTime(element.vitalSignDate!.year, element.vitalSignDate!.month, element.vitalSignDate!.day),
// element.toJson()[viewKey2].toDouble(),
// ),
// );
// },
// );
// }
// }
// }

File diff suppressed because it is too large Load Diff

@ -0,0 +1,76 @@
name: hmg_patient_app_new
description: "New HMG Patient App"
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
version: 1.0.0+1
environment:
sdk: ">=3.6.0 <4.0.0"
dependencies:
flutter:
sdk: flutter
flutter_localizations:
sdk: flutter
cupertino_icons: ^1.0.8
cached_network_image: ^3.4.1
http: ^1.5.0
flutter_svg: ^2.2.0
shared_preferences: ^2.5.3
connectivity_plus: ^6.1.5
auto_size_text: ^3.0.0
shimmer: ^3.0.0
sizer: ^3.1.3
easy_localization: ^3.0.8
fluttertoast: ^8.2.12
flutter_rating_bar: ^4.0.1
firebase_messaging: ^15.2.10
# firebase_messaging: any
firebase_core: any
# firebase_core: ^3.13.1
permission_handler: ^12.0.1
flutter_local_notifications: ^19.4.1
injector: ^4.0.0
provider: ^6.1.5+1
just_audio: ^0.10.4
flutter_callkit_incoming:
git:
url: https://github.com/hiennguyen92/flutter_callkit_incoming.git
ref: dev
url_launcher: ^6.3.2
logger: ^2.6.1
lottie: ^3.3.1
flutter_ios_voip_kit_karmm: ^0.8.0
image_picker: ^1.2.0
file_picker: ^10.3.2
local_auth: ^2.3.0
share_plus: ^11.1.0
device_calendar:
git: https://github.com/bardram/device_calendar
manage_calendar_events: ^2.0.3
flutter_inappwebview: ^6.1.5
# webview_flutter: ^4.13.0
syncfusion_flutter_calendar: ^30.2.7
device_info_plus: ^11.5.0
uuid: ^4.5.1
health: ^13.1.3
# health: 12.0.1
fl_chart: ^1.0.0
geolocator: ^14.0.2
dropdown_search: ^6.0.2
google_maps_flutter: ^2.12.3
flutter_zoom_videosdk: ^2.1.10
web: any
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^5.0.0
flutter:
uses-material-design: true
assets:
- assets/
- assets/langs/

@ -0,0 +1,30 @@
// This is a basic Flutter widget test.
//
// To perform an interaction with a widget in your test, use the WidgetTester
// utility in the flutter_test package. For example, you can send tap and scroll
// gestures. You can also use WidgetTester to find child widgets in the widget
// tree, read text, and verify that the values of widget properties are correct.
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:hmg_patient_app_new/main.dart';
void main() {
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
// Build our app and trigger a frame.
await tester.pumpWidget(const MyApp());
// Verify that our counter starts at 0.
expect(find.text('0'), findsOneWidget);
expect(find.text('1'), findsNothing);
// Tap the '+' icon and trigger a frame.
await tester.tap(find.byIcon(Icons.add));
await tester.pump();
// Verify that our counter has incremented.
expect(find.text('0'), findsNothing);
expect(find.text('1'), findsOneWidget);
});
}
Loading…
Cancel
Save