diff --git a/assets/pngs/emergency.png b/assets/pngs/emergency.png new file mode 100644 index 0000000..5a12015 Binary files /dev/null and b/assets/pngs/emergency.png differ diff --git a/ios/Podfile.lock b/ios/Podfile.lock index e6a0ac0..0f8d01a 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -3,6 +3,8 @@ PODS: - Flutter - MTBBarcodeScanner - SwiftProtobuf + - device_info (0.0.1): + - Flutter - easy_app_installer (0.0.1): - Flutter - Flutter (1.0.0) @@ -12,6 +14,8 @@ PODS: - FMDB (2.7.5): - FMDB/standard (= 2.7.5) - FMDB/standard (2.7.5) + - location (0.0.1): + - Flutter - modal_progress_hud_nsn (0.0.1): - Flutter - MTBBarcodeScanner (5.0.11) @@ -22,6 +26,8 @@ PODS: - FlutterMacOS - permission_handler_apple (9.0.4): - Flutter + - platform_device_id (0.0.1): + - Flutter - shared_preferences_foundation (0.0.1): - Flutter - FlutterMacOS @@ -33,13 +39,16 @@ PODS: DEPENDENCIES: - barcode_scan2 (from `.symlinks/plugins/barcode_scan2/ios`) + - device_info (from `.symlinks/plugins/device_info/ios`) - easy_app_installer (from `.symlinks/plugins/easy_app_installer/ios`) - Flutter (from `Flutter`) - fluttertoast (from `.symlinks/plugins/fluttertoast/ios`) + - location (from `.symlinks/plugins/location/ios`) - modal_progress_hud_nsn (from `.symlinks/plugins/modal_progress_hud_nsn/ios`) - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/ios`) - permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`) + - platform_device_id (from `.symlinks/plugins/platform_device_id/ios`) - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/ios`) - sqflite (from `.symlinks/plugins/sqflite/ios`) @@ -53,12 +62,16 @@ SPEC REPOS: EXTERNAL SOURCES: barcode_scan2: :path: ".symlinks/plugins/barcode_scan2/ios" + device_info: + :path: ".symlinks/plugins/device_info/ios" easy_app_installer: :path: ".symlinks/plugins/easy_app_installer/ios" Flutter: :path: Flutter fluttertoast: :path: ".symlinks/plugins/fluttertoast/ios" + location: + :path: ".symlinks/plugins/location/ios" modal_progress_hud_nsn: :path: ".symlinks/plugins/modal_progress_hud_nsn/ios" package_info_plus: @@ -67,6 +80,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/path_provider_foundation/ios" permission_handler_apple: :path: ".symlinks/plugins/permission_handler_apple/ios" + platform_device_id: + :path: ".symlinks/plugins/platform_device_id/ios" shared_preferences_foundation: :path: ".symlinks/plugins/shared_preferences_foundation/ios" sqflite: @@ -74,16 +89,19 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: barcode_scan2: 0af2bb63c81b4565aab6cd78278e4c0fa136dbb0 + device_info: d7d233b645a32c40dfdc212de5cf646ca482f175 easy_app_installer: 29abe397da7d86721fee853281202f414373f45c Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 fluttertoast: eb263d302cc92e04176c053d2385237e9f43fad0 FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a + location: 3a2eed4dd2fab25e7b7baf2a9efefe82b512d740 modal_progress_hud_nsn: f6fb744cd060653d66ed8f325360ef3650eb2fde MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e - path_provider_foundation: 37748e03f12783f9de2cb2c4eadfaa25fe6d4852 + path_provider_foundation: c68054786f1b4f3343858c1e1d0caaded73f0be9 permission_handler_apple: 44366e37eaf29454a1e7b1b7d736c2cceaeb17ce - shared_preferences_foundation: 297b3ebca31b34ec92be11acd7fb0ba932c822ca + platform_device_id: 81b3e2993881f87d0c82ef151dc274df4869aef5 + shared_preferences_foundation: 986fc17f3d3251412d18b0265f9c64113a8c2472 sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904 SwiftProtobuf: b02b5075dcf60c9f5f403000b3b0c202a11b6ae1 Toast: 91b396c56ee72a5790816f40d3a94dd357abc196 diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 097b297..3559a67 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -47,5 +47,14 @@ UIViewControllerBasedStatusBarAppearance + + NSLocationWhenInUseUsageDescription + Need location when in use + NSLocationAlwaysAndWhenInUseUsageDescription + Always and when in use! + NSLocationUsageDescription + Older devices need location. + NSLocationAlwaysUsageDescription + Can I have location always? diff --git a/lib/bloc/sos/sos_bloc.dart b/lib/bloc/sos/sos_bloc.dart index 03e5341..beb2c0f 100644 --- a/lib/bloc/sos/sos_bloc.dart +++ b/lib/bloc/sos/sos_bloc.dart @@ -1,22 +1,106 @@ import 'package:bloc/bloc.dart'; import 'package:equatable/equatable.dart'; +import 'package:flutter/foundation.dart'; import 'package:location/location.dart'; +import 'package:unit2/model/sos/session.dart'; import 'package:unit2/sevices/sos/sos_service.dart'; +import '../../utils/global.dart'; + part 'sos_event.dart'; part 'sos_state.dart'; class SosBloc extends Bloc { SosBloc() : super(SosInitial()) { LocationData? locationData; - on((event, emit)async { - emit(LoadingState()); + String? mobile1; + String? mobile2; + String? sessionToken; + ////get user location + on((event, emit) async { + emit(const LoadingState(message: "Getting Location")); + mobile1 = await SOS!.get('mobile1'); + mobile2 = await SOS!.get('mobile2'); + sessionToken = await SOS!.get('session_token'); + if (mobile1 != null) { + if (sessionToken != null) { + add(CheckAcknowledgement(sessionToken: sessionToken!)); + } else { + try { + LocationData? newLocationData = + await SosService.instance.getUserLocation(); + locationData = newLocationData; + emit(RequestSosState( + locationData: locationData!, + mobile1: mobile1!, + mobile2: mobile2)); + } catch (e) { + emit(ErrorState(message: e.toString())); + } + } + } else { + try { LocationData? newLocationData = - await SosService.instance.getUserLocation(); - locationData = newLocationData; - // User location Loaded and there is no mobile numbers in cache - emit(UserLocationLoaded(locationData: locationData!)); + await SosService.instance.getUserLocation(); + locationData = newLocationData; + + emit(UserLocationLoaded(locationData: locationData!)); + } catch (e) { + emit(ErrorState(message: e.toString())); + } + } + }); + ////submit mobile + on((event, emit) async { + emit(const LoadingState(message: "")); + mobile1 = event.mobile1; + mobile2 = event.mobile2; + await SOS!.put('mobile1', event.mobile1); + await SOS!.put('mobile2', event.mobile2); + emit(RequestSosState( + locationData: locationData!, + mobile1: event.mobile1, + mobile2: event.mobile2)); + }); + + //// send SOS + on((event, emit) async { + SessionData sessionData; + emit(const LoadingState(message: "Sending emergency response request")); + try { + sessionData = await SosService.instance.requestSos( + location: locationData!, + mobile1: mobile1!, + mobile2: mobile2, + msg: event.msg, + requestedDate: event.requestDate); + await SOS!.put('session_token', sessionData.sessionToken); + emit(SOSReceivedState(sessionToken: sessionData.sessionToken!)); + } catch (e) { + emit(ErrorState(message: e.toString())); + } + }); + //// check acknowledgement + on((event, emit) async { + SessionData sessionData; + try { + SessionData? newSessionData = + await SosService.instance.checkAcknowledgement(event.sessionToken); + if (newSessionData.acknowledgeDate == null) { + debugPrint(newSessionData.sessionToken); + emit(SOSReceivedState(sessionToken: newSessionData.sessionToken!)); + } else { + sessionData = newSessionData; + emit(SoSAcknowledgementConfirm(sessionData: sessionData)); + } + } catch (e) { + emit(ErrorState(message: e.toString())); + } + }); + on((event, emit) async { + await SOS!.delete('session_token'); + add(LoadUserLocation()); }); } } diff --git a/lib/bloc/sos/sos_event.dart b/lib/bloc/sos/sos_event.dart index 0880459..db341cd 100644 --- a/lib/bloc/sos/sos_event.dart +++ b/lib/bloc/sos/sos_event.dart @@ -11,3 +11,33 @@ class LoadUserLocation extends SosEvent { @override List get props => []; } + +class SubmitMobile extends SosEvent { + final String mobile1; + final String? mobile2; + const + SubmitMobile({required this.mobile1,required this.mobile2}); + @override + List get props => []; + +} + +class SendSOS extends SosEvent { + final String msg; + final String requestDate; + const SendSOS({required this.msg, required this.requestDate}); + @override + List get props => [msg, requestDate]; +} + +class CheckAcknowledgement extends SosEvent { + final String sessionToken; + const CheckAcknowledgement({required this.sessionToken}); + @override + List get props => [sessionToken]; +} + +class OnDoneRequest extends SosEvent { + @override + List get props => []; +} \ No newline at end of file diff --git a/lib/bloc/sos/sos_state.dart b/lib/bloc/sos/sos_state.dart index ee325b9..44ca7a8 100644 --- a/lib/bloc/sos/sos_state.dart +++ b/lib/bloc/sos/sos_state.dart @@ -21,7 +21,30 @@ class ErrorState extends SosState{ @override List get props => [message]; } +class RequestSosState extends SosState{ + final LocationData locationData; + final String mobile1; + final String? mobile2; + + const RequestSosState({required this.locationData, required this.mobile1, required this.mobile2}); + @override + List get props => [locationData,mobile1]; +} class LoadingState extends SosState{ - + final String message; + const LoadingState({required this.message}); +} +class SOSReceivedState extends SosState { + final String sessionToken; + const SOSReceivedState({required this.sessionToken}); + @override + List get props => [sessionToken]; +} + +class SoSAcknowledgementConfirm extends SosState{ + final SessionData sessionData; + const SoSAcknowledgementConfirm({required this.sessionData}); + @override + List get props => [sessionData]; } diff --git a/lib/bloc/user/user_bloc.dart b/lib/bloc/user/user_bloc.dart index 5c9c705..3bec84b 100644 --- a/lib/bloc/user/user_bloc.dart +++ b/lib/bloc/user/user_bloc.dart @@ -22,26 +22,31 @@ class UserBloc extends Bloc { String? _apkVersion; bool save = false; UserBloc() : super(UserInitial()) { - // this event is called when opening the app to check if - // there is new app version + //// this event is called when opening the app to check if + //// there is new app version on((event, emit) async { try { emit(SplashScreen()); - VersionInfo versionInfo = await AuthService.instance.getVersionInfo(); - _versionInfo = versionInfo; + if (_versionInfo == null) { + VersionInfo versionInfo = await AuthService.instance.getVersionInfo(); + _versionInfo = versionInfo; + } String apkVersion = await getAppVersion(); _apkVersion = apkVersion; final String? saved = CREDENTIALS?.get('saved'); final String? username = CREDENTIALS?.get('username'); final String? password = CREDENTIALS?.get('password'); debugPrint(username); - debugPrint(password); + debugPrint(password); if (saved != null) { save = true; add(UserLogin(username: username, password: password)); } else { emit(VersionLoaded( - versionInfo: _versionInfo, apkVersion: _apkVersion)); + versionInfo: _versionInfo, + apkVersion: _apkVersion, + username: null, + password: null)); } } catch (e) { emit(UserError( @@ -49,11 +54,15 @@ class UserBloc extends Bloc { )); } }); -//Loading the current version of the app +////Loading the current version of the app on((event, emit) { - emit(VersionLoaded(versionInfo: _versionInfo, apkVersion: _apkVersion)); + emit(VersionLoaded( + versionInfo: _versionInfo, + apkVersion: _apkVersion, + username: event.username, + password: event.password)); }); - +////userlogin on((event, emit) async { try { Map response = await AuthService.instance @@ -61,10 +70,16 @@ class UserBloc extends Bloc { if (response['status'] == true) { UserData userData = UserData.fromJson(response['data']); emit(UserLoggedIn( - userData: userData, success: true, message: response['message'],savedCredentials: save)); + userData: userData, + success: true, + message: response['message'], + savedCredentials: save)); } else { emit(UserLoggedIn( - userData: null, success: false, message: response['message'],savedCredentials: save)); + userData: null, + success: false, + message: response['message'], + savedCredentials: save)); } } on TimeoutException catch (_) { emit(InternetTimeout(message: timeoutError)); @@ -77,7 +92,7 @@ class UserBloc extends Bloc { UserData? userData = await AuthService.instance .qrLogin(uuid: event.uuid, password: event.password); _userData = userData; - emit(UserLoggedIn(userData: _userData,savedCredentials: save)); + emit(UserLoggedIn(userData: _userData, savedCredentials: save)); } on TimeoutException catch (_) { emit(InternetTimeout(message: timeoutError)); } on SocketException catch (_) { @@ -87,7 +102,7 @@ class UserBloc extends Bloc { } }); on((event, emit) { - emit(UserLoggedIn(userData: _userData,savedCredentials: save)); + emit(UserLoggedIn(userData: _userData, savedCredentials: save)); }); on((event, emit) async { ScanResult result = await QRCodeBarCodeScanner.instance.scanner(); diff --git a/lib/bloc/user/user_event.dart b/lib/bloc/user/user_event.dart index cf529fb..a0cbd10 100644 --- a/lib/bloc/user/user_event.dart +++ b/lib/bloc/user/user_event.dart @@ -28,7 +28,11 @@ class GetUuid extends UserEvent { } -class LoadVersion extends UserEvent {} +class LoadVersion extends UserEvent { + final String? username; + final String? password; + LoadVersion({this.password,this.username}); +} class UuidLogin extends UserEvent { final String? uuid; diff --git a/lib/bloc/user/user_state.dart b/lib/bloc/user/user_state.dart index de6688f..ab21f7f 100644 --- a/lib/bloc/user/user_state.dart +++ b/lib/bloc/user/user_state.dart @@ -42,7 +42,9 @@ class UserLoggedIn extends UserState{ class VersionLoaded extends UserState { final VersionInfo? versionInfo; final String? apkVersion; - VersionLoaded({this.versionInfo,this.apkVersion}); + final String? username; + final String? password; + VersionLoaded({this.versionInfo,this.apkVersion, this.password,this.username}); @override List get props => [versionInfo!]; } diff --git a/lib/main.dart b/lib/main.dart index da7df5a..20b079b 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -20,7 +20,7 @@ Future main() async { var appDirectory = await path_provider.getApplicationDocumentsDirectory(); await Hive.initFlutter(appDirectory.path); CREDENTIALS = await Hive.openBox('credentials'); - SOSCONTACTS = await Hive.openBox('soscontacts'); + SOS = await Hive.openBox('soscontacts'); SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]) .then((_) { runApp(MyApp()); diff --git a/lib/model/sos/session.dart b/lib/model/sos/session.dart new file mode 100644 index 0000000..2fa398a --- /dev/null +++ b/lib/model/sos/session.dart @@ -0,0 +1,69 @@ +// To parse this JSON data, do +// +// final sessionData = sessionDataFromJson(jsonString); + +import 'dart:convert'; + +SessionData sessionDataFromJson(String str) => SessionData.fromJson(json.decode(str)); + +String sessionDataToJson(SessionData data) => json.encode(data.toJson()); + +class SessionData { + SessionData({ + this.id, + this.receivedDate, + this.responseDate, + this.statusid, + this.acknowledgeDate, + this.acknowledgedBy, + this.remarks, + this.respondentid, + this.respondentMessage, + this.pushedbuttonDate, + this.sosLevel, + this.sessionToken, + }); + + final int? id; + final String? receivedDate; + final String? responseDate; + final int? statusid; + final String? acknowledgeDate; + final String? acknowledgedBy; + final String? remarks; + final int? respondentid; + final String? respondentMessage; + final String? pushedbuttonDate; + final String? sosLevel; + final String? sessionToken; + + factory SessionData.fromJson(Map json) => SessionData( + id: json["id"] = json["id"], + receivedDate: json["received_date"], + responseDate: json["response_date"], + statusid: json["statusid"], + acknowledgeDate: json["acknowledge_date"], + acknowledgedBy: json["acknowledged_by"], + remarks: json["remarks"], + respondentid: json["respondentid"], + respondentMessage: json["respondent_message"], + pushedbuttonDate: json["pushedbutton_date"], + sosLevel: json["sos_level"], + sessionToken: json["session_token"], + ); + + Map toJson() => { + "id": id, + "received_date": receivedDate, + "response_date": responseDate, + "statusid": statusid, + "acknowledge_date": acknowledgeDate, + "acknowledged_by": acknowledgedBy, + "remarks": remarks, + "respondentid": respondentid, + "respondent_message": respondentMessage, + "pushedbutton_date": pushedbuttonDate , + "sos_level": sosLevel, + "session_token": sessionToken, + }; +} diff --git a/lib/screens/sos/add_mobile.dart b/lib/screens/sos/add_mobile.dart index 8abe496..51aa7e9 100644 --- a/lib/screens/sos/add_mobile.dart +++ b/lib/screens/sos/add_mobile.dart @@ -82,7 +82,7 @@ class AddMobile extends StatelessWidget { validator: mobileNumberValidator, maxLength: 11, decoration: - normalTextFieldStyle(mobile1, "+63")), + normalTextFieldStyle(mobile1, "09000000000")), const SizedBox( height: 12, ), @@ -90,7 +90,7 @@ class AddMobile extends StatelessWidget { name: 'mobile2', maxLength: 11, decoration: - normalTextFieldStyle(mobile2, "+63")), + normalTextFieldStyle(mobile2, "0900000000000")), SizedBox( height: isMobile() diff --git a/lib/screens/sos/components/acknnowledge.dart b/lib/screens/sos/components/acknnowledge.dart new file mode 100644 index 0000000..8a771ba --- /dev/null +++ b/lib/screens/sos/components/acknnowledge.dart @@ -0,0 +1,123 @@ +import 'package:animate_do/animate_do.dart'; +import 'package:auto_size_text/auto_size_text.dart'; +import 'package:flutter/material.dart'; +import 'package:fluttericon/iconic_icons.dart'; +import 'package:unit2/theme-data.dart/btn-style.dart'; + +import '../../../model/sos/session.dart'; +import '../../../theme-data.dart/colors.dart'; +import '../../../utils/global.dart'; + +class SosAcknowledged extends StatelessWidget { + final Function() onpressed; + final SessionData sessionData; + const SosAcknowledged({super.key, required this.onpressed, required this.sessionData}); + + @override + Widget build(BuildContext context) { + + return Container( + padding: const EdgeInsets.symmetric(vertical: 40, horizontal: 35), + height: screenHeight, + child: Stack( + children: [ + Positioned( + bottom: 0, + child: SizedBox( + width: screenWidth, + height: screenHeight / 2, + child: Opacity( + opacity: .2, + child: Image.asset( + "assets/pngs/emergency.png", + fit: BoxFit.cover, + ), + ), + )), + Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const SizedBox( + height: 18, + ), + SlideInDown( + child: AutoSizeText( + "SOS Acknowledged!", + maxLines: 2, + textAlign: TextAlign.center, + style: Theme.of(context).textTheme.displayMedium!.copyWith( + fontSize: 40, + color: success2, + fontWeight: FontWeight.w600), + ), + ), + const SizedBox( + height: 5, + ), + SlideInDown( + child: const Icon( + Iconic.ok_circle, + color: success2, + size: 120, + ), + ), + const SizedBox( + height: 22, + ), + SlideInUp( + child: Container( + decoration: const BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(15))), + child: Column( + children: [ + + + ListTile( + title: AutoSizeText( + sessionData.acknowledgedBy!.toUpperCase(), + maxLines: 2, + style: Theme.of(context).textTheme.headline4!.copyWith( + fontSize: 22, + fontWeight: FontWeight.bold, + color: third), + ), + subtitle: Text( + "Acknowledge by", + style: Theme.of(context).textTheme.labelLarge, + ), + ), + Container( + padding: const EdgeInsets.all(15), + child: Text( + "NOTE: Please ensure that the mobile numbers you provided are still active, and look for an area with stable network. The response team will contact your mobile number.", + textAlign: TextAlign.justify, + style: Theme.of(context).textTheme.caption!.copyWith( + fontSize: 14, + color: Colors.black87, + ), + ), + ), + ], + ), + ), + ), + Expanded(child: Container()), + SlideInUp( + child: SizedBox( + height: 50, + width: double.infinity, + child: ElevatedButton( + style: + mainBtnStyle(second, Colors.transparent, Colors.white54), + onPressed: onpressed, + child: const Text("DONE!")), + ), + ) + ], + ), + ], + ), + ); + } +} \ No newline at end of file diff --git a/lib/screens/sos/components/add_mobile.dart b/lib/screens/sos/components/add_mobile.dart index 80b16b4..3025e92 100644 --- a/lib/screens/sos/components/add_mobile.dart +++ b/lib/screens/sos/components/add_mobile.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_form_builder/flutter_form_builder.dart'; import 'package:flutter_svg/svg.dart'; +import 'package:unit2/bloc/sos/sos_bloc.dart'; import 'package:unit2/screens/sos/components/request_sos.dart'; import 'package:unit2/theme-data.dart/text-styles.dart'; import 'package:unit2/utils/screen_info.dart'; @@ -17,25 +19,16 @@ class AddMobile extends StatelessWidget { final _formKey = GlobalKey(); @override Widget build(BuildContext context) { - return WillPopScope( - onWillPop: () async { - return true; - }, - child: SafeArea( - child: Scaffold( - appBar: AppBar( - title: const Text("Add contact info"), - centerTitle: true, - backgroundColor: primary, - elevation: 0, - ), - resizeToAvoidBottomInset: true, - body: SingleChildScrollView( + + return BlocBuilder( + builder: (context, state) { + if(state is UserLocationLoaded){ + return SingleChildScrollView( child: SizedBox( - height: screenHeight * .90, + height: screenHeight * .95, child: Stack( children: [ - Wave(height: blockSizeVertical * 8), + Positioned( bottom: 0, right: 0, @@ -77,22 +70,25 @@ class AddMobile extends StatelessWidget { key: _formKey, child: Column( children: [ - // Mobile number 1 + //// Mobile number 1 FormBuilderTextField( + autovalidateMode: AutovalidateMode.onUserInteraction, name: 'mobile1', validator: mobileNumberValidator, maxLength: 11, decoration: - normalTextFieldStyle(mobile1, "+63")), + normalTextFieldStyle(mobile1, "09")), const SizedBox( height: 12, ), + //// Mobile number 2 FormBuilderTextField( + autovalidateMode: AutovalidateMode.onUserInteraction, name: 'mobile2', - maxLength: 11, + decoration: - normalTextFieldStyle(mobile2, "+63")), - + normalTextFieldStyle(mobile2, "09")), + SizedBox( height: isMobile() ? blockSizeVertical * 3 @@ -101,22 +97,20 @@ class AddMobile extends StatelessWidget { width: double.infinity, height: screenHeight * .06, child: ElevatedButton( - style: secondaryBtnStyle(second, + style: secondaryBtnStyle(primary, Colors.transparent, Colors.white54), child: const Text( submit, style: TextStyle(color: Colors.white), - ), + ),//// on pressed onPressed: () { if (_formKey.currentState! .saveAndValidate()) { - - Navigator.push(context, MaterialPageRoute(builder: (BuildContext context){ - return RequestSOS(); - })); - + String mobile1 = _formKey.currentState!.value['mobile1']; + String? mobile2 = _formKey.currentState!.value['mobile2']; + context.read().add(SubmitMobile(mobile1: mobile1, mobile2: mobile2)); } - + // } }, ), @@ -128,9 +122,11 @@ class AddMobile extends StatelessWidget { ], ), ), - ), - ), - ), + ); + } + return Container(); + + }, ); } } diff --git a/lib/screens/sos/components/edit_mobile.dart b/lib/screens/sos/components/edit_mobile.dart new file mode 100644 index 0000000..8270841 --- /dev/null +++ b/lib/screens/sos/components/edit_mobile.dart @@ -0,0 +1,86 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_form_builder/flutter_form_builder.dart'; +import 'package:unit2/main.dart'; +import 'package:unit2/theme-data.dart/btn-style.dart'; +import 'package:unit2/utils/validators.dart'; + +import '../../../theme-data.dart/colors.dart'; +import '../../../theme-data.dart/form-style.dart'; + +class EditMobile extends StatelessWidget { + final String initialValue; + final String title; + final String label; + final Function() onpressed; + final Function(String?) onchanged; + const EditMobile( + {super.key, + required this.initialValue, + required this.label, + required this.title, + required this.onpressed, + required this.onchanged}); + + + @override + + Widget build(BuildContext context) { + final formKey = GlobalKey(); + return Container( + height: 300, + padding: const EdgeInsets.all(26), + child: Stack( + children: [ + Positioned( + top: -16, + right: -10, + child: IconButton( + onPressed: () { + Navigator.of(context, rootNavigator: true).pop(); + }, + icon: const Icon( + Icons.close, + size: 18, + )), + ), + FormBuilder( + key: formKey, + child: Column( + children: [ + Text(title), + const SizedBox( + height: 25, + ), + FormBuilderTextField( + autovalidateMode: AutovalidateMode.onUserInteraction, + name: "mobile", + onChanged: onchanged, + validator: mobileNumberValidator, + keyboardType: TextInputType.number, + initialValue: initialValue, + decoration: normalTextFieldStyle(label, label), + maxLength: 11, + ), + const SizedBox( + height: 25, + ), + SizedBox( + height: 50, + width: 200, + child: ElevatedButton( + onPressed: (){ + if(formKey.currentState!.saveAndValidate()){ + onpressed(); + } + }, + style: mainBtnStyle(success2, Colors.transparent, success), + child: const Text("Submit")), + ) + ], + ), + ), + ], + ), + ); + } +} diff --git a/lib/screens/sos/components/request_sos.dart b/lib/screens/sos/components/request_sos.dart index f6e6f6d..990de3e 100644 --- a/lib/screens/sos/components/request_sos.dart +++ b/lib/screens/sos/components/request_sos.dart @@ -1,18 +1,23 @@ import 'package:flutter/material.dart'; import 'package:flutter/src/widgets/container.dart'; import 'package:flutter/src/widgets/framework.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_form_builder/flutter_form_builder.dart'; import 'package:flutter_svg/svg.dart'; import 'package:fluttericon/font_awesome5_icons.dart'; import 'package:fluttericon/typicons_icons.dart'; import 'package:form_builder_validators/form_builder_validators.dart'; +import 'package:intl/intl.dart'; +import 'package:unit2/bloc/sos/sos_bloc.dart'; import 'package:unit2/screens/sos/components/mobile.dart'; import 'package:unit2/theme-data.dart/colors.dart'; import 'package:unit2/utils/text_container.dart'; +import '../../../sevices/sos/sos_service.dart'; import '../../../theme-data.dart/btn-style.dart'; import '../../../theme-data.dart/form-style.dart'; import '../../../utils/global.dart'; +import 'edit_mobile.dart'; class RequestSOS extends StatefulWidget { const RequestSOS({super.key}); @@ -22,88 +27,142 @@ class RequestSOS extends StatefulWidget { } class _RequestSOSState extends State { + final formKey = GlobalKey(); + DateFormat dteFormat = DateFormat("y-M-d H:m:s"); + + String? mobileNumber1; + String? mobileNumber2; @override Widget build(BuildContext context) { - return SafeArea( - child: Scaffold( - appBar: AppBar( - centerTitle: true, - title: const Text(sOSTitle), - backgroundColor: second, - ), - body: SingleChildScrollView( - child: Container( - height: screenHeight * .84, - padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 10), - child: Column( - children: [ - SizedBox( - height: blockSizeVertical * 2, - ), - SvgPicture.asset( - 'assets/svgs/request_sos.svg', - height: blockSizeVertical * 22, - allowDrawingOutsideViewBox: true, - ), - Mobile( - title: "09661548775", - subtitle: mobile1, - onPressed: () {}), - const Divider(), - Mobile( - title: "09661548775", - subtitle: mobile2, - onPressed: () {}), - const Divider(), - ListTile( - leading: const Icon( - Typicons.location, - color: second, - ), - title: Text("Latitude/Longitude"), - subtitle: Text( - currentLocation, - style: Theme.of(context).textTheme.caption, - ), - ), - FormBuilderTextField( - name: "message", - validator: FormBuilderValidators.compose([ - FormBuilderValidators.required( - errorText: messageRequired) - ]), - autovalidateMode: AutovalidateMode.onUserInteraction, - maxLines: 5, - decoration: normalTextFieldStyle("", sosMessage), - ), - const Expanded( - child: SizedBox(), - ), - SizedBox( - width: double.infinity, - height: screenHeight * .06, - child: ElevatedButton( - style: secondaryBtnStyle( - second, Colors.transparent, Colors.white54), - child: const Text( - submit, - style: TextStyle(color: Colors.white), + return BlocBuilder( + builder: (context, state) { + if(state is RequestSosState){ + return SingleChildScrollView( + child: Container( + height: screenHeight * .82, + padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 10), + child: FormBuilder( + key: formKey, + child: Column( + children: [ + SizedBox( + height: blockSizeVertical * 2, ), - onPressed: () { - // if (_formKey.currentState.validate()) { - // _formKey.currentState.save(); - // BlocProvider.of(context) - // .add(UserWebLogin( - // password: password, - // username: username)); - // } - }, - ), + SvgPicture.asset( + 'assets/svgs/request_sos.svg', + height: blockSizeVertical * 22, + allowDrawingOutsideViewBox: true, + ), + Mobile( + title: state.mobile1, + subtitle: mobile1, + //// edit modal + onPressed: () { + showBottomSheet( + context: context, + builder: (context) { + return EditMobile( + title: "Edit Mobile 1", + label: "Mobile number 1", + initialValue: state.mobile1, + onchanged: (value) { + mobileNumber1 = value; + }, + onpressed: () { + Navigator.of(context, + rootNavigator: true) + .pop(); + BlocProvider.of(context) + .add(SubmitMobile( + mobile1: mobileNumber1!, + mobile2: state.mobile2)); + }, + ); + }); + },), + const Divider(), + ////edit mobile 2 + Mobile( + title: state.mobile2??"N/A", + subtitle: mobile2, + onPressed: () { + showBottomSheet( + context: context, + builder: (context) { + return EditMobile( + title: "Edit Mobile 2", + label: "Mobile number 2", + initialValue: state.mobile2??'', + onchanged: (value) { + mobileNumber2 = value; + }, + onpressed: () { + Navigator.of(context, + rootNavigator: true) + .pop(); + BlocProvider.of(context) + .add(SubmitMobile( + mobile1: state.mobile1, + mobile2: mobileNumber2)); + }, + ); + }); + }), + const Divider(), + ListTile( + leading: const Icon( + Typicons.location, + color: second, + ), + title: Text("${state.locationData.latitude}/${state.locationData.longitude}"), + subtitle: Text( + currentLocation, + style: Theme.of(context).textTheme.bodySmall, + ), + ), + FormBuilderTextField( + name: "message", + validator: FormBuilderValidators.compose([ + FormBuilderValidators.required(errorText: messageRequired) + ]), + autovalidateMode: AutovalidateMode.onUserInteraction, + maxLines: 5, + decoration: normalTextFieldStyle("", sosMessage), + ), + const Expanded( + child: SizedBox(), + ), + SizedBox( + width: double.infinity, + height: screenHeight * .06, + child: ElevatedButton( + style: secondaryBtnStyle( + primary, Colors.transparent, Colors.white54), + child: const Text( + submit, + style: TextStyle(color: Colors.white), + ), + //// on pressed + onPressed: () async{ + if( formKey.currentState!.saveAndValidate()){ + String message = formKey.currentState!.value['message']; + DateTime today = DateTime.now(); + String requestedDate = + dteFormat.format(today); + BlocProvider.of(context).add(SendSOS(msg: message, requestDate: requestedDate)); + + } + + }, + ), + ), + ], ), - ], - )), - ), - ), + )), + ); + } + return Container(); + }, ); } } diff --git a/lib/screens/sos/components/sos_received.dart b/lib/screens/sos/components/sos_received.dart index 3d9192d..a8bad17 100644 --- a/lib/screens/sos/components/sos_received.dart +++ b/lib/screens/sos/components/sos_received.dart @@ -9,125 +9,125 @@ import '../../../theme-data.dart/colors.dart'; import '../../../utils/global.dart'; class SOSreceived extends StatelessWidget { - final Function onpressed; - const SOSreceived({required Key key, required this.onpressed}) - : super(key: key); + final Function() onpressed; + const SOSreceived({super.key, required this.onpressed}); @override Widget build(BuildContext context) { - return Container( - padding: const EdgeInsets.symmetric(vertical: 40, horizontal: 35), - height: screenHeight, - child: Stack( - children: [ - Positioned( - bottom: 0, - child: SizedBox( - width: screenWidth, - height: screenHeight / 2, - child: Opacity( - opacity: .2, - child: Image.asset( - "assets/emergency.png", - fit: BoxFit.cover, + + return Container( + padding: const EdgeInsets.symmetric(vertical: 40, horizontal: 35), + height: screenHeight, + child: Stack( + children: [ + Positioned( + bottom: 0, + child: SizedBox( + width: screenWidth, + height: screenHeight / 2, + child: Opacity( + opacity: .2, + child: Image.asset( + "assets/pngs/emergency.png", + fit: BoxFit.cover, + ), ), + )), + Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SizedBox( + height: blockSizeVertical * 6, ), - )), - Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SizedBox( - height: blockSizeVertical * 6, - ), - Bounce( - from: 20, - infinite: true, - delay: const Duration(milliseconds: 800), - child: Stack( - alignment: AlignmentDirectional.topCenter, - children: [ - Container( - margin: const EdgeInsets.only(top: 20), - child: CircleAvatar( - radius: blockSizeVertical * 8, - backgroundColor: second, - child: Container( - margin: const EdgeInsets.only(top: 25), - child: SvgPicture.asset( - 'assets/sos.svg', - height: blockSizeHorizontal * 17, - color: Colors.white, - allowDrawingOutsideViewBox: true, - alignment: Alignment.bottomCenter, + Bounce( + from: 20, + infinite: true, + delay: const Duration(milliseconds: 800), + child: Stack( + alignment: AlignmentDirectional.topCenter, + children: [ + Container( + margin: const EdgeInsets.only(top: 20), + child: CircleAvatar( + radius: blockSizeVertical * 8, + backgroundColor: second, + child: Container( + margin: const EdgeInsets.only(top: 25), + child: SvgPicture.asset( + 'assets/svgs/sos.svg', + height: blockSizeHorizontal * 17, + color: Colors.white, + allowDrawingOutsideViewBox: true, + alignment: Alignment.bottomCenter, + ), ), ), ), - ), - Positioned( - top: blockSizeVertical * 3, - child: const SpinKitPulse( - color: primary, - size: 120, + Positioned( + top: blockSizeVertical * 3, + child: const SpinKitPulse( + color: primary, + size: 120, + ), ), - ), - ], + ], + ), ), - ), - const SizedBox(height: 16), - SlideInUp( - from: 50, - child: AutoSizeText( - sosReceived, - textAlign: TextAlign.center, - style: Theme.of(context).textTheme.displayMedium!.copyWith( - fontSize: 40, - color: third, - fontWeight: FontWeight.w500, - ), - ), - ), - const SizedBox( - height: 8, - ), - SlideInUp( - from: 50, - child: Container( - padding: const EdgeInsets.all(15), - decoration: const BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.all(Radius.circular(15))), + const SizedBox(height: 16), + SlideInUp( + from: 50, child: AutoSizeText( - sOSReceivedMessage, + sosReceived, textAlign: TextAlign.center, - style: Theme.of(context).textTheme.caption!.copyWith( - fontSize: 16, - color: Colors.black87, + style: Theme.of(context).textTheme.displayMedium!.copyWith( + fontSize: 40, + color: third, + fontWeight: FontWeight.w500, ), ), ), - ), - const SizedBox( - height: 40, - ), - Expanded(child: Container()), - SlideInUp( - child: SizedBox( - height: 50, - width: 200, - child: TextButton( - style: mainBtnStyle(second, Colors.transparent, second), - onPressed: () {}, - child: const Text(cancelRequest, - style: TextStyle( - color: Colors.white, - )), + const SizedBox( + height: 8, + ), + SlideInUp( + from: 50, + child: Container( + padding: const EdgeInsets.all(15), + decoration: const BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(15))), + child: AutoSizeText( + sOSReceivedMessage, + textAlign: TextAlign.center, + style: Theme.of(context).textTheme.caption!.copyWith( + fontSize: 16, + color: Colors.black87, + ), + ), ), ), - ) - ], - ), - ], - ), + const SizedBox( + height: 40, + ), + Expanded(child: Container()), + SlideInUp( + child: SizedBox( + height: 50, + width: 200, + child: TextButton( + style: mainBtnStyle(second, Colors.transparent, second), + onPressed: onpressed, + child: const Text(cancelRequest, + style: TextStyle( + color: Colors.white, + )), + ), + ), + ) + ], + ), + ], + ), ); } } diff --git a/lib/screens/sos/index.dart b/lib/screens/sos/index.dart index 6fe5db8..f3bdb90 100644 --- a/lib/screens/sos/index.dart +++ b/lib/screens/sos/index.dart @@ -1,12 +1,25 @@ +import 'dart:async'; + +import 'package:animate_do/animate_do.dart'; import 'package:flutter/material.dart'; import 'package:flutter/src/widgets/framework.dart'; import 'package:flutter/src/widgets/placeholder.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_progress_hud/flutter_progress_hud.dart'; import 'package:flutter_spinkit/flutter_spinkit.dart'; +import 'package:flutter_svg/svg.dart'; import 'package:unit2/bloc/sos/sos_bloc.dart'; +import 'package:unit2/screens/sos/components/acknnowledge.dart'; import 'package:unit2/screens/sos/components/add_mobile.dart'; +import 'package:unit2/screens/sos/components/request_sos.dart'; import 'package:unit2/theme-data.dart/colors.dart'; +import 'package:unit2/utils/text_container.dart'; +import 'package:unit2/widgets/error_state.dart'; + +import '../../utils/global.dart'; +import '../../widgets/wave.dart'; +import 'components/request_sos.dart'; +import 'components/sos_received.dart'; class SosScreen extends StatefulWidget { const SosScreen({super.key}); @@ -16,38 +29,97 @@ class SosScreen extends StatefulWidget { } class _SosScreenState extends State { + Timer? timer; + + @override + void dispose() { + timer != null ? timer!.cancel() : timer = null; + super.dispose(); + } + + @override + void initState() { + timer = Timer(Duration.zero, () {}); + super.initState(); + } + @override Widget build(BuildContext context) { return SafeArea( child: Scaffold( + appBar: AppBar(backgroundColor: primary), resizeToAvoidBottomInset: true, - appBar: AppBar( - title: const Text("SOS"), - centerTitle: true, - backgroundColor: primary, - ), body: ProgressHUD( - padding: const EdgeInsets.all(24), + padding: const EdgeInsets.all(32), backgroundColor: Colors.black87, indicatorWidget: const SpinKitFadingCircle(color: Colors.white), - child: BlocConsumer( + child: BlocConsumer( listener: (context, state) { - //// user location loaded - if (state is UserLocationLoaded) { - Navigator.push(context, - MaterialPageRoute(builder: (BuildContext context) { - return AddMobile(); - })); + if (state is ErrorState) { + final progress = ProgressHUD.of(context); + progress!.dismiss(); } ////loading state if (state is LoadingState) { final progress = ProgressHUD.of(context); - progress!.showWithText("Please wait..."); + progress!.showWithText(state.message); + } + //// dismiss progress + if (state is ErrorState || state is SOSReceivedState || state is RequestSosState || state is UserLocationLoaded || state is SoSAcknowledgementConfirm) { + final progress = ProgressHUD.of(context); + progress!.dismiss(); } }, builder: (context, state) { - if (state is ErrorState) {} - return Container(); + //// error state + if (state is ErrorState) { + timer!.cancel(); + return SomethingWentWrong( + message: state.message, + onpressed: () { + context.read().add(LoadUserLocation()); + }); + } //// user location loaded + if (state is UserLocationLoaded) { + return AddMobile(); + + //// request sos state + } + if (state is RequestSosState) { + return const RequestSOS(); + } + //// received sos state + if (state is SOSReceivedState) { + timer = Timer.periodic(const Duration(seconds: 10), (timer) { + context.read().add( + CheckAcknowledgement(sessionToken: state.sessionToken)); + }); + return SOSreceived(onpressed: () async { + timer!.cancel(); + await SOS!.delete('session_token'); + Navigator.pop(context); + }); + } + ///// sos acknowledge and confirm + if (state is SoSAcknowledgementConfirm) { + return SosAcknowledged( + onpressed: () async { + timer!.cancel(); + await SOS!.delete('session_token'); + Navigator.pop(context); + }, + sessionData: state.sessionData); + } + return SizedBox( + height: screenHeight, + child: Stack(children: [ + + Positioned( + bottom: 0, + right: 0, + child: WaveReverse(height: blockSizeVertical * 8)) + ]), + ); }, ), ), diff --git a/lib/screens/sos/request_sos.dart b/lib/screens/sos/request_sos.dart deleted file mode 100644 index a98b654..0000000 --- a/lib/screens/sos/request_sos.dart +++ /dev/null @@ -1,109 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/src/widgets/container.dart'; -import 'package:flutter/src/widgets/framework.dart'; -import 'package:flutter_form_builder/flutter_form_builder.dart'; -import 'package:flutter_svg/svg.dart'; -import 'package:fluttericon/font_awesome5_icons.dart'; -import 'package:fluttericon/typicons_icons.dart'; -import 'package:form_builder_validators/form_builder_validators.dart'; -import 'package:unit2/screens/sos/components/mobile.dart'; -import 'package:unit2/theme-data.dart/colors.dart'; -import 'package:unit2/utils/text_container.dart'; - -import '../../theme-data.dart/btn-style.dart'; -import '../../theme-data.dart/form-style.dart'; -import '../../utils/global.dart'; - -class RequestSOS extends StatefulWidget { - const RequestSOS({super.key}); - - @override - State createState() => _RequestSOSState(); -} - -class _RequestSOSState extends State { - @override - Widget build(BuildContext context) { - return SafeArea( - child: Scaffold( - appBar: AppBar( - centerTitle: true, - title: const Text(sOSTitle), - backgroundColor: second, - ), - body: SingleChildScrollView( - child: Container( - height: screenHeight * .89, - padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 10), - child: Column( - children: [ - SizedBox( - height: blockSizeVertical * 2, - ), - SvgPicture.asset( - 'assets/svgs/request_sos.svg', - height: blockSizeVertical * 22, - allowDrawingOutsideViewBox: true, - ), - Mobile( - title: "09661548775", - subtitle: mobile1, - onPressed: () {}), - const Divider(), - Mobile( - title: "09661548775", - subtitle: mobile2, - onPressed: () {}), - const Divider(), - ListTile( - leading: const Icon( - Typicons.location, - color: second, - ), - title: Text("Latitude/Longitude"), - subtitle: Text( - currentLocation, - style: Theme.of(context).textTheme.caption, - ), - ), - FormBuilderTextField( - name: "message", - validator: FormBuilderValidators.compose([ - FormBuilderValidators.required( - errorText: messageRequired) - ]), - autovalidateMode: AutovalidateMode.onUserInteraction, - maxLines: 5, - decoration: normalTextFieldStyle("", sosMessage), - ), - const Expanded( - child: SizedBox(), - ), - SizedBox( - width: double.infinity, - height: screenHeight * .06, - child: ElevatedButton( - style: secondaryBtnStyle( - second, Colors.transparent, Colors.white54), - child: const Text( - submit, - style: TextStyle(color: Colors.white), - ), - onPressed: () { - // if (_formKey.currentState.validate()) { - // _formKey.currentState.save(); - // BlocProvider.of(context) - // .add(UserWebLogin( - // password: password, - // username: username)); - // } - }, - ), - ), - ], - )), - ), - ), - ); - } -} diff --git a/lib/screens/sos/sos_received.dart b/lib/screens/sos/sos_received.dart deleted file mode 100644 index c89b81c..0000000 --- a/lib/screens/sos/sos_received.dart +++ /dev/null @@ -1,133 +0,0 @@ -import 'package:animate_do/animate_do.dart'; -import 'package:auto_size_text/auto_size_text.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_spinkit/flutter_spinkit.dart'; -import 'package:flutter_svg/svg.dart'; -import 'package:unit2/theme-data.dart/btn-style.dart'; -import 'package:unit2/utils/text_container.dart'; -import '../../theme-data.dart/colors.dart'; -import '../../utils/global.dart'; - -class SOSreceived extends StatelessWidget { - final Function onpressed; - const SOSreceived({required Key key, required this.onpressed}) - : super(key: key); - - @override - Widget build(BuildContext context) { - return Container( - padding: const EdgeInsets.symmetric(vertical: 40, horizontal: 35), - height: screenHeight, - child: Stack( - children: [ - Positioned( - bottom: 0, - child: SizedBox( - width: screenWidth, - height: screenHeight / 2, - child: Opacity( - opacity: .2, - child: Image.asset( - "assets/emergency.png", - fit: BoxFit.cover, - ), - ), - )), - Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SizedBox( - height: blockSizeVertical * 6, - ), - Bounce( - from: 20, - infinite: true, - delay: const Duration(milliseconds: 800), - child: Stack( - alignment: AlignmentDirectional.topCenter, - children: [ - Container( - margin: const EdgeInsets.only(top: 20), - child: CircleAvatar( - radius: blockSizeVertical * 8, - backgroundColor: second, - child: Container( - margin: const EdgeInsets.only(top: 25), - child: SvgPicture.asset( - 'assets/sos.svg', - height: blockSizeHorizontal * 17, - color: Colors.white, - allowDrawingOutsideViewBox: true, - alignment: Alignment.bottomCenter, - ), - ), - ), - ), - Positioned( - top: blockSizeVertical * 3, - child: const SpinKitPulse( - color: primary, - size: 120, - ), - ), - ], - ), - ), - const SizedBox(height: 16), - SlideInUp( - from: 50, - child: AutoSizeText( - sosReceived, - textAlign: TextAlign.center, - style: Theme.of(context).textTheme.displayMedium!.copyWith( - fontSize: 40, - color: third, - fontWeight: FontWeight.w500, - ), - ), - ), - const SizedBox( - height: 8, - ), - SlideInUp( - from: 50, - child: Container( - padding: const EdgeInsets.all(15), - decoration: const BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.all(Radius.circular(15))), - child: AutoSizeText( - sOSReceivedMessage, - textAlign: TextAlign.center, - style: Theme.of(context).textTheme.caption!.copyWith( - fontSize: 16, - color: Colors.black87, - ), - ), - ), - ), - const SizedBox( - height: 40, - ), - Expanded(child: Container()), - SlideInUp( - child: SizedBox( - height: 50, - width: 200, - child: TextButton( - style: mainBtnStyle(second, Colors.transparent, second), - onPressed: () {}, - child: const Text(cancelRequest, - style: TextStyle( - color: Colors.white, - )), - ), - ), - ) - ], - ), - ], - ), - ); - } -} diff --git a/lib/screens/unit2/basic-info/basic-info.dart b/lib/screens/unit2/basic-info/basic-info.dart index 6459508..c16824a 100644 --- a/lib/screens/unit2/basic-info/basic-info.dart +++ b/lib/screens/unit2/basic-info/basic-info.dart @@ -5,6 +5,7 @@ import 'package:flutter_svg/svg.dart'; import 'package:fluttericon/font_awesome5_icons.dart'; import 'package:intl/intl.dart'; import 'package:qr_flutter/qr_flutter.dart'; +import 'package:signature/signature.dart'; import 'package:unit2/model/login_data/user_info/user_data.dart'; import 'package:unit2/theme-data.dart/btn-style.dart'; import 'package:unit2/utils/global.dart'; @@ -12,6 +13,7 @@ import 'package:unit2/utils/text_container.dart'; import '../../../bloc/user/user_bloc.dart'; import '../../../theme-data.dart/colors.dart'; import '../../../widgets/splash_screen.dart'; +import '../signature/signature_pad.dart'; import './components/cover-image.dart'; class BasicInfo extends StatelessWidget { @@ -159,6 +161,9 @@ class BuildInformation extends StatelessWidget { style: mainBtnStyle(third, Colors.transparent, Colors.white54), onPressed: () { + Navigator.push(context, MaterialPageRoute(builder: (BuildContext context){ + return SignaturePad(); + })); }, icon: const Icon( FontAwesome5.signature, diff --git a/lib/screens/unit2/homepage.dart/components/menu-screen.dart b/lib/screens/unit2/homepage.dart/components/menu-screen.dart index 312d2d0..65b3621 100644 --- a/lib/screens/unit2/homepage.dart/components/menu-screen.dart +++ b/lib/screens/unit2/homepage.dart/components/menu-screen.dart @@ -56,7 +56,7 @@ class _MenuScreenState extends State { getTile(FontAwesome5.user_circle, "Profile", '/profile', context, widget.userData!), const Divider(), - getTile(FontAwesome5.life_ring, "Request SOS", '/request-sos', + getTile(FontAwesome5.life_ring, "Request SOS", '/sos', context, widget.userData!), const Divider(), Expanded( diff --git a/lib/screens/unit2/homepage.dart/components/menu.dart b/lib/screens/unit2/homepage.dart/components/menu.dart index 5ddc5cf..10103f7 100644 --- a/lib/screens/unit2/homepage.dart/components/menu.dart +++ b/lib/screens/unit2/homepage.dart/components/menu.dart @@ -30,6 +30,8 @@ Widget getTile( Navigator.pushNamed(context, route,arguments: profileArguments); }if(title.toLowerCase() == 'basic info'){ Navigator.pushNamed(context, '/basic-info'); + }if(title.toLowerCase() == 'request sos'){ + Navigator.pushNamed(context, '/sos'); } }, diff --git a/lib/screens/unit2/login/login.dart b/lib/screens/unit2/login/login.dart index 4c4ef35..bba33c3 100644 --- a/lib/screens/unit2/login/login.dart +++ b/lib/screens/unit2/login/login.dart @@ -78,7 +78,7 @@ class _UniT2LoginState extends State { final progress = ProgressHUD.of(context); progress!.dismiss(); errorAlert(context, "Error Login", state.message, () { - context.read().add(LoadVersion()); + context.read().add(LoadVersion(username: username,password: password)); Navigator.of(context).pop(); }); } @@ -138,9 +138,10 @@ class _UniT2LoginState extends State { SizedBox( height: blockSizeVertical * 3, ), - // USERNAME + //// USERNAME FormBuilderTextField( name: 'username', + initialValue: state.username, validator: FormBuilderValidators.required( errorText: usernameRequired), @@ -153,9 +154,10 @@ class _UniT2LoginState extends State { SizedBox( height: blockSizeVertical * 1.5, ), - // PASSWORD + //// PASSWORD FormBuilderTextField( name: 'password', + initialValue: state.password, validator: FormBuilderValidators.required( errorText: passwordRequired), onChanged: (value) { @@ -222,7 +224,7 @@ class _UniT2LoginState extends State { ), SizedBox( height: blockSizeVertical * 7, - // Login Button + //// Login Button child: SizedBox( width: MediaQuery.of(context).size.width, @@ -296,12 +298,12 @@ class _UniT2LoginState extends State { ), )), SizedBox( - height: blockSizeVertical * 1, + height: blockSizeVertical * 2, ), const LoginViaQr( text: emergencyReponseLabel), SizedBox( - height: blockSizeVertical * 1, + height: blockSizeVertical * 2, ), // REQUEST SOS SizedBox( diff --git a/lib/sevices/sos/sos_service.dart b/lib/sevices/sos/sos_service.dart index 40eb9c8..0cb0697 100644 --- a/lib/sevices/sos/sos_service.dart +++ b/lib/sevices/sos/sos_service.dart @@ -1,5 +1,14 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:flutter/services.dart'; import 'package:intl/intl.dart'; import 'package:location/location.dart'; +import 'package:platform_device_id/platform_device_id.dart'; +import 'package:http/http.dart' as http; +import 'package:unit2/utils/request.dart'; +import '../../model/sos/session.dart'; +import '../../utils/urls.dart'; class SosService{ static final SosService _instance = SosService(); @@ -10,7 +19,8 @@ class SosService{ LocationData? locationData; bool serviceEnabled = false; PermissionStatus permissionGranted; - serviceEnabled = await location.serviceEnabled(); + + serviceEnabled = await location.serviceEnabled(); if (!serviceEnabled) { serviceEnabled = await location.requestService(); if (!serviceEnabled) { @@ -24,8 +34,92 @@ class SosService{ return null; } } + try{ LocationData newLocationData = await location.getLocation(); locationData = newLocationData; return locationData; + }catch(e){ + throw e.toString(); + } + } + Future initPlatformState() async { + String? deviceId; + try { + deviceId = await PlatformDeviceId.getDeviceId; + } on PlatformException { + deviceId = 'Failed to get deviceId.'; + } + return deviceId!; + } + + +Future requestSos({required LocationData location, required String mobile1, + String? mobile2, required String msg, required String requestedDate}) async { + var body; + String deviceId = await initPlatformState(); + String sessionToken = + deviceId.toString() + todayFormat.format(DateTime.now()); + String path = Url.instance.sosRequest(); + SessionData? sessionData; + + if(mobile2 != null){ + body = { + "mobile_id": deviceId.toString(), + "mobile_gps": + "${location.latitude.toString()},${location.longitude.toString()}", + "mobile1": mobile1, + "mobile2": mobile2, + "respondent_message": msg, + "session_token": sessionToken, + "pushedbutton_date": requestedDate + }; + }else{ + body = { + "mobile_id": deviceId.toString(), + "mobile_gps": + "${location.latitude.toString()},${location.longitude.toString()}", + "mobile1": mobile1, + "respondent_message": msg, + "session_token": sessionToken, + "pushedbutton_date": requestedDate + }; + } + + Map headers = { + 'Content-Type': 'application/json; charset=UTF-8', + }; + + try { + http.Response response = await Request.instance.postRequest(path: path,body: body,headers: headers); + if (response.statusCode == 201) { + var body = jsonDecode(response.body); + SessionData newSessionData = SessionData.fromJson(body['data']); + sessionData = newSessionData; + } + + }on Error catch (e) { + throw (e.toString()); + } + return sessionData!; + } + + + Future checkAcknowledgement(String sessionToken) async { + String path = Url.instance.sosRequest(); + SessionData? sessionData; + try { + http.Response response = await Request.instance.getRequest(path: path,param:{"session_token":sessionToken} ); + if (response.statusCode == 200) { + var body = jsonDecode(response.body); + SessionData newSessionData = SessionData.fromJson(body['data'][0]); + + sessionData = newSessionData; + + } + } on Error + catch (e) { + throw (e.toString()); + } + return sessionData!; } } \ No newline at end of file diff --git a/lib/utils/app_router.dart b/lib/utils/app_router.dart index 3bd227a..9db2326 100644 --- a/lib/utils/app_router.dart +++ b/lib/utils/app_router.dart @@ -47,7 +47,7 @@ class AppRouter { case '/sos': return MaterialPageRoute(builder: (BuildContext context) { return BlocProvider( - create: (context) => SosBloc()..add(LoadUserLocation()), + create: (_) => SosBloc()..add(LoadUserLocation()), child: const SosScreen(), ); }); diff --git a/lib/utils/global.dart b/lib/utils/global.dart index de816db..65b6eaf 100644 --- a/lib/utils/global.dart +++ b/lib/utils/global.dart @@ -12,4 +12,4 @@ double safeBlockVertical = 0; //// hive boxes Box? CREDENTIALS; -Box? SOSCONTACTS; \ No newline at end of file +Box? SOS; \ No newline at end of file diff --git a/lib/utils/urls.dart b/lib/utils/urls.dart index 8849535..0d165e9 100644 --- a/lib/utils/urls.dart +++ b/lib/utils/urls.dart @@ -3,10 +3,10 @@ class Url { static Url get instance => _instance; String host() { - // return '192.168.10.221:3003'; - return 'agusandelnorte.gov.ph'; + // return '192.168.10.183:3000'; + // return 'agusandelnorte.gov.ph'; // return "192.168.10.219:3000"; - // return "devweb.agusandelnorte.gov.ph"; + return "devweb.agusandelnorte.gov.ph"; // return 'devapi.agusandelnorte.gov.ph:3004'; } @@ -22,6 +22,11 @@ class Url { return "/api/system_app/apk_version/latest"; } + ////SOS paths + String sosRequest(){ + return "/api/sos_app/sos_request/"; + } + ////ELIGIBILITIES PATHS String eligibilities(){ return "/api/jobnet_app/eligibilities/"; diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index a124bbe..4b37fe9 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -7,9 +7,13 @@ #include "generated_plugin_registrant.h" #include +#include void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) modal_progress_hud_nsn_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "ModalProgressHudNsnPlugin"); modal_progress_hud_nsn_plugin_register_with_registrar(modal_progress_hud_nsn_registrar); + g_autoptr(FlPluginRegistrar) platform_device_id_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "PlatformDeviceIdLinuxPlugin"); + platform_device_id_linux_plugin_register_with_registrar(platform_device_id_linux_registrar); } diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index f6f1987..f64d1cc 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -4,6 +4,7 @@ list(APPEND FLUTTER_PLUGIN_LIST modal_progress_hud_nsn + platform_device_id_linux ) list(APPEND FLUTTER_FFI_PLUGIN_LIST diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 4567379..7a1cdf6 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,16 +5,22 @@ import FlutterMacOS import Foundation +import location import modal_progress_hud_nsn import package_info_plus import path_provider_foundation +import platform_device_id +import platform_device_id_macos import shared_preferences_foundation import sqflite func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + LocationPlugin.register(with: registry.registrar(forPlugin: "LocationPlugin")) ModalProgressHudNsnPlugin.register(with: registry.registrar(forPlugin: "ModalProgressHudNsnPlugin")) FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + PlatformDeviceIdMacosPlugin.register(with: registry.registrar(forPlugin: "PlatformDeviceIdMacosPlugin")) + PlatformDeviceIdMacosPlugin.register(with: registry.registrar(forPlugin: "PlatformDeviceIdMacosPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) } diff --git a/macos/Podfile.lock b/macos/Podfile.lock index 42d76d9..d473e2f 100644 --- a/macos/Podfile.lock +++ b/macos/Podfile.lock @@ -3,6 +3,8 @@ PODS: - FMDB (2.7.5): - FMDB/standard (= 2.7.5) - FMDB/standard (2.7.5) + - location (0.0.1): + - FlutterMacOS - modal_progress_hud_nsn (0.0.1): - FlutterMacOS - package_info_plus (0.0.1): @@ -10,6 +12,10 @@ PODS: - path_provider_foundation (0.0.1): - Flutter - FlutterMacOS + - platform_device_id (0.0.1): + - FlutterMacOS + - platform_device_id_macos (0.0.1): + - FlutterMacOS - shared_preferences_foundation (0.0.1): - Flutter - FlutterMacOS @@ -19,9 +25,12 @@ PODS: DEPENDENCIES: - FlutterMacOS (from `Flutter/ephemeral`) + - location (from `Flutter/ephemeral/.symlinks/plugins/location/macos`) - modal_progress_hud_nsn (from `Flutter/ephemeral/.symlinks/plugins/modal_progress_hud_nsn/macos`) - package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`) - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/macos`) + - platform_device_id (from `Flutter/ephemeral/.symlinks/plugins/platform_device_id/macos`) + - platform_device_id_macos (from `Flutter/ephemeral/.symlinks/plugins/platform_device_id_macos/macos`) - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/macos`) - sqflite (from `Flutter/ephemeral/.symlinks/plugins/sqflite/macos`) @@ -32,12 +41,18 @@ SPEC REPOS: EXTERNAL SOURCES: FlutterMacOS: :path: Flutter/ephemeral + location: + :path: Flutter/ephemeral/.symlinks/plugins/location/macos modal_progress_hud_nsn: :path: Flutter/ephemeral/.symlinks/plugins/modal_progress_hud_nsn/macos package_info_plus: :path: Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos path_provider_foundation: :path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/macos + platform_device_id: + :path: Flutter/ephemeral/.symlinks/plugins/platform_device_id/macos + platform_device_id_macos: + :path: Flutter/ephemeral/.symlinks/plugins/platform_device_id_macos/macos shared_preferences_foundation: :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/macos sqflite: @@ -46,10 +61,13 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a + location: 7cdb0665bd6577d382b0a343acdadbcb7f964775 modal_progress_hud_nsn: 8099d46c2cf9de7af8fe0a3f8f5d2aa32cf956c3 package_info_plus: 02d7a575e80f194102bef286361c6c326e4c29ce - path_provider_foundation: 37748e03f12783f9de2cb2c4eadfaa25fe6d4852 - shared_preferences_foundation: 297b3ebca31b34ec92be11acd7fb0ba932c822ca + path_provider_foundation: c68054786f1b4f3343858c1e1d0caaded73f0be9 + platform_device_id: 3e414428f45df149bbbfb623e2c0ca27c545b763 + platform_device_id_macos: f763bb55f088be804d61b96eb4710b8ab6598e94 + shared_preferences_foundation: 986fc17f3d3251412d18b0265f9c64113a8c2472 sqflite: a5789cceda41d54d23f31d6de539d65bb14100ea PODFILE CHECKSUM: 353c8bcc5d5b0994e508d035b5431cfe18c1dea7 diff --git a/pubspec.lock b/pubspec.lock index 3bb1c30..3e337c3 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -297,6 +297,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.0" + device_info: + dependency: transitive + description: + name: device_info + sha256: f4a8156cb7b7480d969cb734907d18b333c8f0bc0b1ad0b342cdcecf30d62c48 + url: "https://pub.dev" + source: hosted + version: "2.0.3" + device_info_platform_interface: + dependency: transitive + description: + name: device_info_platform_interface + sha256: b148e0bf9640145d09a4f8dea96614076f889e7f7f8b5ecab1c7e5c2dbc73c1b + url: "https://pub.dev" + source: hosted + version: "2.0.1" device_preview: dependency: "direct main" description: @@ -925,6 +941,54 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.0" + platform_device_id: + dependency: "direct main" + description: + name: platform_device_id + sha256: "7a12ec84de4a823bb10eba2f0e1ad29e2365abba17790489a0d78029904f562e" + url: "https://pub.dev" + source: hosted + version: "1.0.1" + platform_device_id_linux: + dependency: transitive + description: + name: platform_device_id_linux + sha256: "994b1608593e527a629af2d5aeb241c60d308d3434bc78b0f6fcb3c1a02dff43" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + platform_device_id_macos: + dependency: transitive + description: + name: platform_device_id_macos + sha256: "968db2a504c611294b12a031b3734432d6df10553a0d3ae3b33ed21abfdbaba0" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + platform_device_id_platform_interface: + dependency: transitive + description: + name: platform_device_id_platform_interface + sha256: c61607594252aaddacf3e4c4371ab08f2ef85ff427817fa6e48a169429610c46 + url: "https://pub.dev" + source: hosted + version: "1.0.0" + platform_device_id_web: + dependency: transitive + description: + name: platform_device_id_web + sha256: "58e124594e1165db7f108395a780b1d1e1cd403021978e5228cf4289fbe736d5" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + platform_device_id_windows: + dependency: transitive + description: + name: platform_device_id_windows + sha256: dbf8dcf03ad8555320ebae2403a3081b79f137f37661874e161fe2de0a84eeeb + url: "https://pub.dev" + source: hosted + version: "1.0.0" plugin_platform_interface: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 5cd2be5..ab0bffe 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -76,6 +76,8 @@ dependencies: hive: ^2.0.5 hive_flutter: ^1.1.0 mask_text_input_formatter: ^2.4.0 + location: ^4.3.0 + platform_device_id: ^1.0.1 dev_dependencies: flutter_test: diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index c1aa7e0..458cc68 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -8,10 +8,13 @@ #include #include +#include void RegisterPlugins(flutter::PluginRegistry* registry) { ModalProgressHudNsnPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("ModalProgressHudNsnPlugin")); PermissionHandlerWindowsPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin")); + PlatformDeviceIdWindowsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("PlatformDeviceIdWindowsPlugin")); } diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index 2446653..4c970ab 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -5,6 +5,7 @@ list(APPEND FLUTTER_PLUGIN_LIST modal_progress_hud_nsn permission_handler_windows + platform_device_id_windows ) list(APPEND FLUTTER_FFI_PLUGIN_LIST