Merge pull request 'feature/sos/SOS-#9Implement-SOS-API' (#10) from feature/sos/SOS-#9Implement-SOS-API into develop

Reviewed-on: http://git.agusandelnorte.gov.ph:3000/SoftwareDevelopmentSection/unit2-null-safety-repository/pulls/10
feature/passo/PASSO-#1-Sync-data-from-device-to-postgre-and-vice-versa
superadmin 2023-04-14 17:18:46 +08:00
commit c6ba708ab5
36 changed files with 2698 additions and 279 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

View File

@ -3,6 +3,8 @@ PODS:
- Flutter - Flutter
- MTBBarcodeScanner - MTBBarcodeScanner
- SwiftProtobuf - SwiftProtobuf
- device_info (0.0.1):
- Flutter
- easy_app_installer (0.0.1): - easy_app_installer (0.0.1):
- Flutter - Flutter
- Flutter (1.0.0) - Flutter (1.0.0)
@ -12,6 +14,8 @@ PODS:
- FMDB (2.7.5): - FMDB (2.7.5):
- FMDB/standard (= 2.7.5) - FMDB/standard (= 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): - modal_progress_hud_nsn (0.0.1):
- Flutter - Flutter
- MTBBarcodeScanner (5.0.11) - MTBBarcodeScanner (5.0.11)
@ -22,6 +26,8 @@ PODS:
- FlutterMacOS - FlutterMacOS
- permission_handler_apple (9.0.4): - permission_handler_apple (9.0.4):
- Flutter - Flutter
- platform_device_id (0.0.1):
- Flutter
- shared_preferences_foundation (0.0.1): - shared_preferences_foundation (0.0.1):
- Flutter - Flutter
- FlutterMacOS - FlutterMacOS
@ -33,13 +39,16 @@ PODS:
DEPENDENCIES: DEPENDENCIES:
- barcode_scan2 (from `.symlinks/plugins/barcode_scan2/ios`) - 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`) - easy_app_installer (from `.symlinks/plugins/easy_app_installer/ios`)
- Flutter (from `Flutter`) - Flutter (from `Flutter`)
- fluttertoast (from `.symlinks/plugins/fluttertoast/ios`) - fluttertoast (from `.symlinks/plugins/fluttertoast/ios`)
- location (from `.symlinks/plugins/location/ios`)
- modal_progress_hud_nsn (from `.symlinks/plugins/modal_progress_hud_nsn/ios`) - modal_progress_hud_nsn (from `.symlinks/plugins/modal_progress_hud_nsn/ios`)
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/ios`) - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/ios`)
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/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`) - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/ios`)
- sqflite (from `.symlinks/plugins/sqflite/ios`) - sqflite (from `.symlinks/plugins/sqflite/ios`)
@ -53,12 +62,16 @@ SPEC REPOS:
EXTERNAL SOURCES: EXTERNAL SOURCES:
barcode_scan2: barcode_scan2:
:path: ".symlinks/plugins/barcode_scan2/ios" :path: ".symlinks/plugins/barcode_scan2/ios"
device_info:
:path: ".symlinks/plugins/device_info/ios"
easy_app_installer: easy_app_installer:
:path: ".symlinks/plugins/easy_app_installer/ios" :path: ".symlinks/plugins/easy_app_installer/ios"
Flutter: Flutter:
:path: Flutter :path: Flutter
fluttertoast: fluttertoast:
:path: ".symlinks/plugins/fluttertoast/ios" :path: ".symlinks/plugins/fluttertoast/ios"
location:
:path: ".symlinks/plugins/location/ios"
modal_progress_hud_nsn: modal_progress_hud_nsn:
:path: ".symlinks/plugins/modal_progress_hud_nsn/ios" :path: ".symlinks/plugins/modal_progress_hud_nsn/ios"
package_info_plus: package_info_plus:
@ -67,6 +80,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/path_provider_foundation/ios" :path: ".symlinks/plugins/path_provider_foundation/ios"
permission_handler_apple: permission_handler_apple:
:path: ".symlinks/plugins/permission_handler_apple/ios" :path: ".symlinks/plugins/permission_handler_apple/ios"
platform_device_id:
:path: ".symlinks/plugins/platform_device_id/ios"
shared_preferences_foundation: shared_preferences_foundation:
:path: ".symlinks/plugins/shared_preferences_foundation/ios" :path: ".symlinks/plugins/shared_preferences_foundation/ios"
sqflite: sqflite:
@ -74,16 +89,19 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS: SPEC CHECKSUMS:
barcode_scan2: 0af2bb63c81b4565aab6cd78278e4c0fa136dbb0 barcode_scan2: 0af2bb63c81b4565aab6cd78278e4c0fa136dbb0
device_info: d7d233b645a32c40dfdc212de5cf646ca482f175
easy_app_installer: 29abe397da7d86721fee853281202f414373f45c easy_app_installer: 29abe397da7d86721fee853281202f414373f45c
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
fluttertoast: eb263d302cc92e04176c053d2385237e9f43fad0 fluttertoast: eb263d302cc92e04176c053d2385237e9f43fad0
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
location: 3a2eed4dd2fab25e7b7baf2a9efefe82b512d740
modal_progress_hud_nsn: f6fb744cd060653d66ed8f325360ef3650eb2fde modal_progress_hud_nsn: f6fb744cd060653d66ed8f325360ef3650eb2fde
MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb
package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e
path_provider_foundation: 37748e03f12783f9de2cb2c4eadfaa25fe6d4852 path_provider_foundation: c68054786f1b4f3343858c1e1d0caaded73f0be9
permission_handler_apple: 44366e37eaf29454a1e7b1b7d736c2cceaeb17ce permission_handler_apple: 44366e37eaf29454a1e7b1b7d736c2cceaeb17ce
shared_preferences_foundation: 297b3ebca31b34ec92be11acd7fb0ba932c822ca platform_device_id: 81b3e2993881f87d0c82ef151dc274df4869aef5
shared_preferences_foundation: 986fc17f3d3251412d18b0265f9c64113a8c2472
sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904 sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904
SwiftProtobuf: b02b5075dcf60c9f5f403000b3b0c202a11b6ae1 SwiftProtobuf: b02b5075dcf60c9f5f403000b3b0c202a11b6ae1
Toast: 91b396c56ee72a5790816f40d3a94dd357abc196 Toast: 91b396c56ee72a5790816f40d3a94dd357abc196

View File

@ -47,5 +47,14 @@
</array> </array>
<key>UIViewControllerBasedStatusBarAppearance</key> <key>UIViewControllerBasedStatusBarAppearance</key>
<false/> <false/>
<!-- Permission options for the `location` group -->
<key>NSLocationWhenInUseUsageDescription</key>
<string>Need location when in use</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Always and when in use!</string>
<key>NSLocationUsageDescription</key>
<string>Older devices need location.</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>Can I have location always?</string>
</dict> </dict>
</plist> </plist>

View File

@ -0,0 +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<SosEvent, SosState> {
SosBloc() : super(SosInitial()) {
LocationData? locationData;
String? mobile1;
String? mobile2;
String? sessionToken;
////get user location
on<LoadUserLocation>((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;
emit(UserLocationLoaded(locationData: locationData!));
} catch (e) {
emit(ErrorState(message: e.toString()));
}
}
});
////submit mobile
on<SubmitMobile>((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<SendSOS>((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<CheckAcknowledgement>((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<OnDoneRequest>((event, emit) async {
await SOS!.delete('session_token');
add(LoadUserLocation());
});
}
}

View File

@ -0,0 +1,43 @@
part of 'sos_bloc.dart';
abstract class SosEvent extends Equatable {
const SosEvent();
@override
List<Object> get props => [];
}
class LoadUserLocation extends SosEvent {
@override
List<Object> get props => [];
}
class SubmitMobile extends SosEvent {
final String mobile1;
final String? mobile2;
const
SubmitMobile({required this.mobile1,required this.mobile2});
@override
List<Object> get props => [];
}
class SendSOS extends SosEvent {
final String msg;
final String requestDate;
const SendSOS({required this.msg, required this.requestDate});
@override
List<Object> get props => [msg, requestDate];
}
class CheckAcknowledgement extends SosEvent {
final String sessionToken;
const CheckAcknowledgement({required this.sessionToken});
@override
List<Object> get props => [sessionToken];
}
class OnDoneRequest extends SosEvent {
@override
List<Object> get props => [];
}

View File

@ -0,0 +1,50 @@
part of 'sos_bloc.dart';
abstract class SosState extends Equatable {
const SosState();
@override
List<Object> get props => [];
}
class SosInitial extends SosState {}
class UserLocationLoaded extends SosState {
final LocationData locationData;
const UserLocationLoaded({required this.locationData});
@override
List<Object> get props => [locationData];
}
class ErrorState extends SosState{
final String message;
const ErrorState({required this.message});
@override
List<Object> 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<Object> 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<Object> get props => [sessionToken];
}
class SoSAcknowledgementConfirm extends SosState{
final SessionData sessionData;
const SoSAcknowledgementConfirm({required this.sessionData});
@override
List<Object> get props => [sessionData];
}

View File

@ -22,26 +22,31 @@ class UserBloc extends Bloc<UserEvent, UserState> {
String? _apkVersion; String? _apkVersion;
bool save = false; bool save = false;
UserBloc() : super(UserInitial()) { UserBloc() : super(UserInitial()) {
// this event is called when opening the app to check if //// this event is called when opening the app to check if
// there is new app version //// there is new app version
on<GetApkVersion>((event, emit) async { on<GetApkVersion>((event, emit) async {
try { try {
emit(SplashScreen()); emit(SplashScreen());
VersionInfo versionInfo = await AuthService.instance.getVersionInfo(); if (_versionInfo == null) {
_versionInfo = versionInfo; VersionInfo versionInfo = await AuthService.instance.getVersionInfo();
_versionInfo = versionInfo;
}
String apkVersion = await getAppVersion(); String apkVersion = await getAppVersion();
_apkVersion = apkVersion; _apkVersion = apkVersion;
final String? saved = CREDENTIALS?.get('saved'); final String? saved = CREDENTIALS?.get('saved');
final String? username = CREDENTIALS?.get('username'); final String? username = CREDENTIALS?.get('username');
final String? password = CREDENTIALS?.get('password'); final String? password = CREDENTIALS?.get('password');
debugPrint(username); debugPrint(username);
debugPrint(password); debugPrint(password);
if (saved != null) { if (saved != null) {
save = true; save = true;
add(UserLogin(username: username, password: password)); add(UserLogin(username: username, password: password));
} else { } else {
emit(VersionLoaded( emit(VersionLoaded(
versionInfo: _versionInfo, apkVersion: _apkVersion)); versionInfo: _versionInfo,
apkVersion: _apkVersion,
username: null,
password: null));
} }
} catch (e) { } catch (e) {
emit(UserError( emit(UserError(
@ -49,11 +54,15 @@ class UserBloc extends Bloc<UserEvent, UserState> {
)); ));
} }
}); });
//Loading the current version of the app ////Loading the current version of the app
on<LoadVersion>((event, emit) { on<LoadVersion>((event, emit) {
emit(VersionLoaded(versionInfo: _versionInfo, apkVersion: _apkVersion)); emit(VersionLoaded(
versionInfo: _versionInfo,
apkVersion: _apkVersion,
username: event.username,
password: event.password));
}); });
////userlogin
on<UserLogin>((event, emit) async { on<UserLogin>((event, emit) async {
try { try {
Map<dynamic, dynamic> response = await AuthService.instance Map<dynamic, dynamic> response = await AuthService.instance
@ -61,10 +70,16 @@ class UserBloc extends Bloc<UserEvent, UserState> {
if (response['status'] == true) { if (response['status'] == true) {
UserData userData = UserData.fromJson(response['data']); UserData userData = UserData.fromJson(response['data']);
emit(UserLoggedIn( emit(UserLoggedIn(
userData: userData, success: true, message: response['message'],savedCredentials: save)); userData: userData,
success: true,
message: response['message'],
savedCredentials: save));
} else { } else {
emit(UserLoggedIn( emit(UserLoggedIn(
userData: null, success: false, message: response['message'],savedCredentials: save)); userData: null,
success: false,
message: response['message'],
savedCredentials: save));
} }
} on TimeoutException catch (_) { } on TimeoutException catch (_) {
emit(InternetTimeout(message: timeoutError)); emit(InternetTimeout(message: timeoutError));
@ -77,7 +92,7 @@ class UserBloc extends Bloc<UserEvent, UserState> {
UserData? userData = await AuthService.instance UserData? userData = await AuthService.instance
.qrLogin(uuid: event.uuid, password: event.password); .qrLogin(uuid: event.uuid, password: event.password);
_userData = userData; _userData = userData;
emit(UserLoggedIn(userData: _userData,savedCredentials: save)); emit(UserLoggedIn(userData: _userData, savedCredentials: save));
} on TimeoutException catch (_) { } on TimeoutException catch (_) {
emit(InternetTimeout(message: timeoutError)); emit(InternetTimeout(message: timeoutError));
} on SocketException catch (_) { } on SocketException catch (_) {
@ -87,7 +102,7 @@ class UserBloc extends Bloc<UserEvent, UserState> {
} }
}); });
on<LoadLoggedInUser>((event, emit) { on<LoadLoggedInUser>((event, emit) {
emit(UserLoggedIn(userData: _userData,savedCredentials: save)); emit(UserLoggedIn(userData: _userData, savedCredentials: save));
}); });
on<GetUuid>((event, emit) async { on<GetUuid>((event, emit) async {
ScanResult result = await QRCodeBarCodeScanner.instance.scanner(); ScanResult result = await QRCodeBarCodeScanner.instance.scanner();

View File

@ -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 { class UuidLogin extends UserEvent {
final String? uuid; final String? uuid;

View File

@ -42,7 +42,9 @@ class UserLoggedIn extends UserState{
class VersionLoaded extends UserState { class VersionLoaded extends UserState {
final VersionInfo? versionInfo; final VersionInfo? versionInfo;
final String? apkVersion; final String? apkVersion;
VersionLoaded({this.versionInfo,this.apkVersion}); final String? username;
final String? password;
VersionLoaded({this.versionInfo,this.apkVersion, this.password,this.username});
@override @override
List<Object> get props => [versionInfo!]; List<Object> get props => [versionInfo!];
} }

View File

@ -20,7 +20,7 @@ Future main() async {
var appDirectory = await path_provider.getApplicationDocumentsDirectory(); var appDirectory = await path_provider.getApplicationDocumentsDirectory();
await Hive.initFlutter(appDirectory.path); await Hive.initFlutter(appDirectory.path);
CREDENTIALS = await Hive.openBox<dynamic>('credentials'); CREDENTIALS = await Hive.openBox<dynamic>('credentials');
SOSCONTACTS = await Hive.openBox<String>('soscontacts'); SOS = await Hive.openBox<dynamic>('soscontacts');
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]) SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp])
.then((_) { .then((_) {
runApp(MyApp()); runApp(MyApp());

View File

@ -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<String, dynamic> 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<String, dynamic> 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,
};
}

View File

@ -82,7 +82,7 @@ class AddMobile extends StatelessWidget {
validator: mobileNumberValidator, validator: mobileNumberValidator,
maxLength: 11, maxLength: 11,
decoration: decoration:
normalTextFieldStyle(mobile1, "+63")), normalTextFieldStyle(mobile1, "09000000000")),
const SizedBox( const SizedBox(
height: 12, height: 12,
), ),
@ -90,7 +90,7 @@ class AddMobile extends StatelessWidget {
name: 'mobile2', name: 'mobile2',
maxLength: 11, maxLength: 11,
decoration: decoration:
normalTextFieldStyle(mobile2, "+63")), normalTextFieldStyle(mobile2, "0900000000000")),
SizedBox( SizedBox(
height: isMobile() height: isMobile()

View File

@ -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!")),
),
)
],
),
],
),
);
}
}

View File

@ -0,0 +1,132 @@
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';
import '../../../theme-data.dart/btn-style.dart';
import '../../../theme-data.dart/colors.dart';
import '../../../theme-data.dart/form-style.dart';
import '../../../utils/global.dart';
import '../../../utils/text_container.dart';
import '../../../utils/validators.dart';
import '../../../widgets/wave.dart';
class AddMobile extends StatelessWidget {
AddMobile({super.key});
final _formKey = GlobalKey<FormBuilderState>();
@override
Widget build(BuildContext context) {
return BlocBuilder<SosBloc, SosState>(
builder: (context, state) {
if(state is UserLocationLoaded){
return SingleChildScrollView(
child: SizedBox(
height: screenHeight * .95,
child: Stack(
children: [
Positioned(
bottom: 0,
right: 0,
child: WaveReverse(height: blockSizeVertical * 8)),
Container(
height: screenHeight,
padding: isMobile()
? const EdgeInsets.symmetric(horizontal: 24)
: const EdgeInsets.symmetric(horizontal: 60),
width: double.infinity,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(
height: isMobile()
? screenHeight * .12
: screenHeight * .20),
SvgPicture.asset(
'assets/svgs/add_mobile.svg',
height: isMobile()
? blockSizeVertical * 22
: blockSizeVertical * 30,
allowDrawingOutsideViewBox: true,
),
const SizedBox(
height: 24,
),
Text(addMobile, style: titleTextStyle()),
const SizedBox(
height: 8,
),
Text(addMobileCaption,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.caption),
const SizedBox(
height: 24,
),
FormBuilder(
key: _formKey,
child: Column(
children: [
//// Mobile number 1
FormBuilderTextField(
autovalidateMode: AutovalidateMode.onUserInteraction,
name: 'mobile1',
validator: mobileNumberValidator,
maxLength: 11,
decoration:
normalTextFieldStyle(mobile1, "09")),
const SizedBox(
height: 12,
),
//// Mobile number 2
FormBuilderTextField(
autovalidateMode: AutovalidateMode.onUserInteraction,
name: 'mobile2',
decoration:
normalTextFieldStyle(mobile2, "09")),
SizedBox(
height: isMobile()
? blockSizeVertical * 3
: blockSizeHorizontal * 5),
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: () {
if (_formKey.currentState!
.saveAndValidate()) {
String mobile1 = _formKey.currentState!.value['mobile1'];
String? mobile2 = _formKey.currentState!.value['mobile2'];
context.read<SosBloc>().add(SubmitMobile(mobile1: mobile1, mobile2: mobile2));
}
// }
},
),
),
],
))
]),
),
],
),
),
);
}
return Container();
},
);
}
}

View File

@ -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<FormBuilderState>();
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")),
)
],
),
),
],
),
);
}
}

View File

@ -0,0 +1,168 @@
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});
@override
State<RequestSOS> createState() => _RequestSOSState();
}
class _RequestSOSState extends State<RequestSOS> {
final formKey = GlobalKey<FormBuilderState>();
DateFormat dteFormat = DateFormat("y-M-d H:m:s");
String? mobileNumber1;
String? mobileNumber2;
@override
Widget build(BuildContext context) {
return BlocBuilder<SosBloc, SosState>(
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,
),
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<SosBloc>(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<SosBloc>(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<SosBloc>(context).add(SendSOS(msg: message, requestDate: requestedDate));
}
},
),
),
],
),
)),
);
}
return Container();
},
);
}
}

View File

@ -0,0 +1,133 @@
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({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/pngs/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/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,
),
),
],
),
),
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: onpressed,
child: const Text(cancelRequest,
style: TextStyle(
color: Colors.white,
)),
),
),
)
],
),
],
),
);
}
}

View File

@ -0,0 +1,128 @@
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});
@override
State<SosScreen> createState() => _SosScreenState();
}
class _SosScreenState extends State<SosScreen> {
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,
body: ProgressHUD(
padding: const EdgeInsets.all(32),
backgroundColor: Colors.black87,
indicatorWidget: const SpinKitFadingCircle(color: Colors.white),
child: BlocConsumer<SosBloc, SosState>(
listener: (context, state) {
if (state is ErrorState) {
final progress = ProgressHUD.of(context);
progress!.dismiss();
}
////loading state
if (state is LoadingState) {
final progress = ProgressHUD.of(context);
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) {
//// error state
if (state is ErrorState) {
timer!.cancel();
return SomethingWentWrong(
message: state.message,
onpressed: () {
context.read<SosBloc>().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<SosBloc>().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))
]),
);
},
),
),
));
}
}

View File

@ -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<RequestSOS> createState() => _RequestSOSState();
}
class _RequestSOSState extends State<RequestSOS> {
@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<UserBloc>(context)
// .add(UserWebLogin(
// password: password,
// username: username));
// }
},
),
),
],
)),
),
),
);
}
}

View File

@ -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,
)),
),
),
)
],
),
],
),
);
}
}

View File

@ -5,6 +5,7 @@ import 'package:flutter_svg/svg.dart';
import 'package:fluttericon/font_awesome5_icons.dart'; import 'package:fluttericon/font_awesome5_icons.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:qr_flutter/qr_flutter.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/model/login_data/user_info/user_data.dart';
import 'package:unit2/theme-data.dart/btn-style.dart'; import 'package:unit2/theme-data.dart/btn-style.dart';
import 'package:unit2/utils/global.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 '../../../bloc/user/user_bloc.dart';
import '../../../theme-data.dart/colors.dart'; import '../../../theme-data.dart/colors.dart';
import '../../../widgets/splash_screen.dart'; import '../../../widgets/splash_screen.dart';
import '../signature/signature_pad.dart';
import './components/cover-image.dart'; import './components/cover-image.dart';
class BasicInfo extends StatelessWidget { class BasicInfo extends StatelessWidget {
@ -159,6 +161,9 @@ class BuildInformation extends StatelessWidget {
style: style:
mainBtnStyle(third, Colors.transparent, Colors.white54), mainBtnStyle(third, Colors.transparent, Colors.white54),
onPressed: () { onPressed: () {
Navigator.push(context, MaterialPageRoute(builder: (BuildContext context){
return SignaturePad();
}));
}, },
icon: const Icon( icon: const Icon(
FontAwesome5.signature, FontAwesome5.signature,

View File

@ -56,7 +56,7 @@ class _MenuScreenState extends State<MenuScreen> {
getTile(FontAwesome5.user_circle, "Profile", getTile(FontAwesome5.user_circle, "Profile",
'/profile', context, widget.userData!), '/profile', context, widget.userData!),
const Divider(), const Divider(),
getTile(FontAwesome5.life_ring, "Request SOS", '/request-sos', getTile(FontAwesome5.life_ring, "Request SOS", '/sos',
context, widget.userData!), context, widget.userData!),
const Divider(), const Divider(),
Expanded( Expanded(

View File

@ -30,6 +30,8 @@ Widget getTile(
Navigator.pushNamed(context, route,arguments: profileArguments); Navigator.pushNamed(context, route,arguments: profileArguments);
}if(title.toLowerCase() == 'basic info'){ }if(title.toLowerCase() == 'basic info'){
Navigator.pushNamed(context, '/basic-info'); Navigator.pushNamed(context, '/basic-info');
}if(title.toLowerCase() == 'request sos'){
Navigator.pushNamed(context, '/sos');
} }
}, },

View File

@ -78,7 +78,7 @@ class _UniT2LoginState extends State<UniT2Login> {
final progress = ProgressHUD.of(context); final progress = ProgressHUD.of(context);
progress!.dismiss(); progress!.dismiss();
errorAlert(context, "Error Login", state.message, () { errorAlert(context, "Error Login", state.message, () {
context.read<UserBloc>().add(LoadVersion()); context.read<UserBloc>().add(LoadVersion(username: username,password: password));
Navigator.of(context).pop(); Navigator.of(context).pop();
}); });
} }
@ -138,9 +138,10 @@ class _UniT2LoginState extends State<UniT2Login> {
SizedBox( SizedBox(
height: blockSizeVertical * 3, height: blockSizeVertical * 3,
), ),
// USERNAME //// USERNAME
FormBuilderTextField( FormBuilderTextField(
name: 'username', name: 'username',
initialValue: state.username,
validator: validator:
FormBuilderValidators.required( FormBuilderValidators.required(
errorText: usernameRequired), errorText: usernameRequired),
@ -153,9 +154,10 @@ class _UniT2LoginState extends State<UniT2Login> {
SizedBox( SizedBox(
height: blockSizeVertical * 1.5, height: blockSizeVertical * 1.5,
), ),
// PASSWORD //// PASSWORD
FormBuilderTextField( FormBuilderTextField(
name: 'password', name: 'password',
initialValue: state.password,
validator: FormBuilderValidators.required( validator: FormBuilderValidators.required(
errorText: passwordRequired), errorText: passwordRequired),
onChanged: (value) { onChanged: (value) {
@ -222,7 +224,7 @@ class _UniT2LoginState extends State<UniT2Login> {
), ),
SizedBox( SizedBox(
height: blockSizeVertical * 7, height: blockSizeVertical * 7,
// Login Button //// Login Button
child: SizedBox( child: SizedBox(
width: width:
MediaQuery.of(context).size.width, MediaQuery.of(context).size.width,
@ -296,12 +298,12 @@ class _UniT2LoginState extends State<UniT2Login> {
), ),
)), )),
SizedBox( SizedBox(
height: blockSizeVertical * 1, height: blockSizeVertical * 2,
), ),
const LoginViaQr( const LoginViaQr(
text: emergencyReponseLabel), text: emergencyReponseLabel),
SizedBox( SizedBox(
height: blockSizeVertical * 1, height: blockSizeVertical * 2,
), ),
// REQUEST SOS // REQUEST SOS
SizedBox( SizedBox(
@ -317,7 +319,7 @@ class _UniT2LoginState extends State<UniT2Login> {
Colors.transparent, Colors.transparent,
Colors.white38), Colors.white38),
onPressed: () { onPressed: () {
Navigator.pushNamed(context, '/sos');
}, },
label: const Text( label: const Text(
requestSOS, requestSOS,

View File

@ -0,0 +1,125 @@
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();
static SosService get instance => _instance;
DateFormat todayFormat = DateFormat("yMdHms");
Future<LocationData?> getUserLocation() async {
Location location = Location();
LocationData? locationData;
bool serviceEnabled = false;
PermissionStatus permissionGranted;
serviceEnabled = await location.serviceEnabled();
if (!serviceEnabled) {
serviceEnabled = await location.requestService();
if (!serviceEnabled) {
return null;
}
}
permissionGranted = await location.hasPermission();
if (permissionGranted == PermissionStatus.denied) {
permissionGranted = await location.requestPermission();
if (permissionGranted != PermissionStatus.granted) {
return null;
}
}
try{
LocationData newLocationData = await location.getLocation();
locationData = newLocationData;
return locationData;
}catch(e){
throw e.toString();
}
}
Future<String> initPlatformState() async {
String? deviceId;
try {
deviceId = await PlatformDeviceId.getDeviceId;
} on PlatformException {
deviceId = 'Failed to get deviceId.';
}
return deviceId!;
}
Future<SessionData> 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<String, String> 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<SessionData> 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!;
}
}

View File

@ -1,6 +1,8 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:unit2/bloc/profile/profile_bloc.dart'; import 'package:unit2/bloc/profile/profile_bloc.dart';
import 'package:unit2/bloc/sos/sos_bloc.dart';
import 'package:unit2/screens/sos/index.dart';
import 'package:unit2/screens/unit2/homepage.dart/components/menu.dart'; import 'package:unit2/screens/unit2/homepage.dart/components/menu.dart';
import 'package:unit2/screens/unit2/login/login.dart'; import 'package:unit2/screens/unit2/login/login.dart';
import 'package:unit2/utils/global_context.dart'; import 'package:unit2/utils/global_context.dart';
@ -34,13 +36,21 @@ class AppRouter {
return const QRLogin(); return const QRLogin();
}); });
case '/profile': case '/profile':
ProfileArguments arguments = routeSettings.arguments as ProfileArguments; ProfileArguments arguments =
BlocProvider.of<ProfileBloc>( routeSettings.arguments as ProfileArguments;
BlocProvider.of<ProfileBloc>(
NavigationService.navigatorKey.currentContext!) NavigationService.navigatorKey.currentContext!)
.add(LoadProfile(token:arguments.token ,userID:arguments.userID )); .add(LoadProfile(token: arguments.token, userID: arguments.userID));
return MaterialPageRoute(builder: (_) { return MaterialPageRoute(builder: (_) {
return const ProfileInfo(); return const ProfileInfo();
}); });
case '/sos':
return MaterialPageRoute(builder: (BuildContext context) {
return BlocProvider(
create: (_) => SosBloc()..add(LoadUserLocation()),
child: const SosScreen(),
);
});
default: default:
return MaterialPageRoute(builder: (context) { return MaterialPageRoute(builder: (context) {
return Container(); return Container();

View File

@ -12,4 +12,4 @@ double safeBlockVertical = 0;
//// hive boxes //// hive boxes
Box? CREDENTIALS; Box? CREDENTIALS;
Box? SOSCONTACTS; Box? SOS;

View File

@ -3,10 +3,10 @@ class Url {
static Url get instance => _instance; static Url get instance => _instance;
String host() { String host() {
// return '192.168.10.221:3003'; // return '192.168.10.183:3000';
return 'agusandelnorte.gov.ph'; // return 'agusandelnorte.gov.ph';
// return "192.168.10.219:3000"; // return "192.168.10.219:3000";
// return "devweb.agusandelnorte.gov.ph"; return "devweb.agusandelnorte.gov.ph";
// return 'devapi.agusandelnorte.gov.ph:3004'; // return 'devapi.agusandelnorte.gov.ph:3004';
} }
@ -22,6 +22,11 @@ class Url {
return "/api/system_app/apk_version/latest"; return "/api/system_app/apk_version/latest";
} }
////SOS paths
String sosRequest(){
return "/api/sos_app/sos_request/";
}
////ELIGIBILITIES PATHS ////ELIGIBILITIES PATHS
String eligibilities(){ String eligibilities(){
return "/api/jobnet_app/eligibilities/"; return "/api/jobnet_app/eligibilities/";

View File

@ -7,9 +7,13 @@
#include "generated_plugin_registrant.h" #include "generated_plugin_registrant.h"
#include <modal_progress_hud_nsn/modal_progress_hud_nsn_plugin.h> #include <modal_progress_hud_nsn/modal_progress_hud_nsn_plugin.h>
#include <platform_device_id_linux/platform_device_id_linux_plugin.h>
void fl_register_plugins(FlPluginRegistry* registry) { void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) modal_progress_hud_nsn_registrar = g_autoptr(FlPluginRegistrar) modal_progress_hud_nsn_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "ModalProgressHudNsnPlugin"); fl_plugin_registry_get_registrar_for_plugin(registry, "ModalProgressHudNsnPlugin");
modal_progress_hud_nsn_plugin_register_with_registrar(modal_progress_hud_nsn_registrar); 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);
} }

View File

@ -4,6 +4,7 @@
list(APPEND FLUTTER_PLUGIN_LIST list(APPEND FLUTTER_PLUGIN_LIST
modal_progress_hud_nsn modal_progress_hud_nsn
platform_device_id_linux
) )
list(APPEND FLUTTER_FFI_PLUGIN_LIST list(APPEND FLUTTER_FFI_PLUGIN_LIST

View File

@ -5,16 +5,22 @@
import FlutterMacOS import FlutterMacOS
import Foundation import Foundation
import location
import modal_progress_hud_nsn import modal_progress_hud_nsn
import package_info_plus import package_info_plus
import path_provider_foundation import path_provider_foundation
import platform_device_id
import platform_device_id_macos
import shared_preferences_foundation import shared_preferences_foundation
import sqflite import sqflite
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
LocationPlugin.register(with: registry.registrar(forPlugin: "LocationPlugin"))
ModalProgressHudNsnPlugin.register(with: registry.registrar(forPlugin: "ModalProgressHudNsnPlugin")) ModalProgressHudNsnPlugin.register(with: registry.registrar(forPlugin: "ModalProgressHudNsnPlugin"))
FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin")) FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) 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")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
} }

View File

@ -3,6 +3,8 @@ PODS:
- FMDB (2.7.5): - FMDB (2.7.5):
- FMDB/standard (= 2.7.5) - FMDB/standard (= 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): - modal_progress_hud_nsn (0.0.1):
- FlutterMacOS - FlutterMacOS
- package_info_plus (0.0.1): - package_info_plus (0.0.1):
@ -10,6 +12,10 @@ PODS:
- path_provider_foundation (0.0.1): - path_provider_foundation (0.0.1):
- Flutter - Flutter
- FlutterMacOS - FlutterMacOS
- platform_device_id (0.0.1):
- FlutterMacOS
- platform_device_id_macos (0.0.1):
- FlutterMacOS
- shared_preferences_foundation (0.0.1): - shared_preferences_foundation (0.0.1):
- Flutter - Flutter
- FlutterMacOS - FlutterMacOS
@ -19,9 +25,12 @@ PODS:
DEPENDENCIES: DEPENDENCIES:
- FlutterMacOS (from `Flutter/ephemeral`) - 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`) - 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`) - package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`)
- path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/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`) - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/macos`)
- sqflite (from `Flutter/ephemeral/.symlinks/plugins/sqflite/macos`) - sqflite (from `Flutter/ephemeral/.symlinks/plugins/sqflite/macos`)
@ -32,12 +41,18 @@ SPEC REPOS:
EXTERNAL SOURCES: EXTERNAL SOURCES:
FlutterMacOS: FlutterMacOS:
:path: Flutter/ephemeral :path: Flutter/ephemeral
location:
:path: Flutter/ephemeral/.symlinks/plugins/location/macos
modal_progress_hud_nsn: modal_progress_hud_nsn:
:path: Flutter/ephemeral/.symlinks/plugins/modal_progress_hud_nsn/macos :path: Flutter/ephemeral/.symlinks/plugins/modal_progress_hud_nsn/macos
package_info_plus: package_info_plus:
:path: Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos :path: Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos
path_provider_foundation: path_provider_foundation:
:path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/macos :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: shared_preferences_foundation:
:path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/macos :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/macos
sqflite: sqflite:
@ -46,10 +61,13 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS: SPEC CHECKSUMS:
FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
location: 7cdb0665bd6577d382b0a343acdadbcb7f964775
modal_progress_hud_nsn: 8099d46c2cf9de7af8fe0a3f8f5d2aa32cf956c3 modal_progress_hud_nsn: 8099d46c2cf9de7af8fe0a3f8f5d2aa32cf956c3
package_info_plus: 02d7a575e80f194102bef286361c6c326e4c29ce package_info_plus: 02d7a575e80f194102bef286361c6c326e4c29ce
path_provider_foundation: 37748e03f12783f9de2cb2c4eadfaa25fe6d4852 path_provider_foundation: c68054786f1b4f3343858c1e1d0caaded73f0be9
shared_preferences_foundation: 297b3ebca31b34ec92be11acd7fb0ba932c822ca platform_device_id: 3e414428f45df149bbbfb623e2c0ca27c545b763
platform_device_id_macos: f763bb55f088be804d61b96eb4710b8ab6598e94
shared_preferences_foundation: 986fc17f3d3251412d18b0265f9c64113a8c2472
sqflite: a5789cceda41d54d23f31d6de539d65bb14100ea sqflite: a5789cceda41d54d23f31d6de539d65bb14100ea
PODFILE CHECKSUM: 353c8bcc5d5b0994e508d035b5431cfe18c1dea7 PODFILE CHECKSUM: 353c8bcc5d5b0994e508d035b5431cfe18c1dea7

1391
pubspec.lock 100644

File diff suppressed because it is too large Load Diff

View File

@ -76,6 +76,8 @@ dependencies:
hive: ^2.0.5 hive: ^2.0.5
hive_flutter: ^1.1.0 hive_flutter: ^1.1.0
mask_text_input_formatter: ^2.4.0 mask_text_input_formatter: ^2.4.0
location: ^4.3.0
platform_device_id: ^1.0.1
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:

View File

@ -8,10 +8,13 @@
#include <modal_progress_hud_nsn/modal_progress_hud_nsn_plugin.h> #include <modal_progress_hud_nsn/modal_progress_hud_nsn_plugin.h>
#include <permission_handler_windows/permission_handler_windows_plugin.h> #include <permission_handler_windows/permission_handler_windows_plugin.h>
#include <platform_device_id_windows/platform_device_id_windows_plugin.h>
void RegisterPlugins(flutter::PluginRegistry* registry) { void RegisterPlugins(flutter::PluginRegistry* registry) {
ModalProgressHudNsnPluginRegisterWithRegistrar( ModalProgressHudNsnPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("ModalProgressHudNsnPlugin")); registry->GetRegistrarForPlugin("ModalProgressHudNsnPlugin"));
PermissionHandlerWindowsPluginRegisterWithRegistrar( PermissionHandlerWindowsPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin")); registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin"));
PlatformDeviceIdWindowsPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("PlatformDeviceIdWindowsPlugin"));
} }

View File

@ -5,6 +5,7 @@
list(APPEND FLUTTER_PLUGIN_LIST list(APPEND FLUTTER_PLUGIN_LIST
modal_progress_hud_nsn modal_progress_hud_nsn
permission_handler_windows permission_handler_windows
platform_device_id_windows
) )
list(APPEND FLUTTER_FFI_PLUGIN_LIST list(APPEND FLUTTER_FFI_PLUGIN_LIST