diff --git a/assets/images/undraw_connected_world_wuay.png b/assets/images/undraw_connected_world_wuay.png new file mode 100644 index 0000000..6e8eb47 Binary files /dev/null and b/assets/images/undraw_connected_world_wuay.png differ diff --git a/ios/Flutter/AppFrameworkInfo.plist b/ios/Flutter/AppFrameworkInfo.plist index 8d4492f..9625e10 100644 --- a/ios/Flutter/AppFrameworkInfo.plist +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 9.0 + 11.0 diff --git a/ios/Podfile b/ios/Podfile index 1e8c3c9..88359b2 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -# platform :ios, '9.0' +# platform :ios, '11.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 0cb89ab..305bc17 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1,29 +1,47 @@ PODS: + - audio_session (0.0.1): + - Flutter - connectivity (0.0.1): - Flutter - Reachability - Flutter (1.0.0) + - just_audio (0.0.1): + - Flutter + - path_provider_ios (0.0.1): + - Flutter - Reachability (3.2) DEPENDENCIES: + - audio_session (from `.symlinks/plugins/audio_session/ios`) - connectivity (from `.symlinks/plugins/connectivity/ios`) - Flutter (from `Flutter`) + - just_audio (from `.symlinks/plugins/just_audio/ios`) + - path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`) SPEC REPOS: trunk: - Reachability EXTERNAL SOURCES: + audio_session: + :path: ".symlinks/plugins/audio_session/ios" connectivity: :path: ".symlinks/plugins/connectivity/ios" Flutter: :path: Flutter + just_audio: + :path: ".symlinks/plugins/just_audio/ios" + path_provider_ios: + :path: ".symlinks/plugins/path_provider_ios/ios" SPEC CHECKSUMS: + audio_session: 4f3e461722055d21515cf3261b64c973c062f345 connectivity: c4130b2985d4ef6fd26f9702e886bd5260681467 - Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a + Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 + just_audio: baa7252489dbcf47a4c7cc9ca663e9661c99aafa + path_provider_ios: 14f3d2fd28c4fdb42f44e0f751d12861c43cee02 Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96 -PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c +PODFILE CHECKSUM: ef19549a9bc3046e7bb7d2fab4d021637c0c58a3 -COCOAPODS: 1.11.2 +COCOAPODS: 1.11.3 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 7046dae..6364bea 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -340,7 +340,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -418,7 +418,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -467,7 +467,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 81eb537..256543f 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -43,5 +43,7 @@ UIViewControllerBasedStatusBarAppearance + CADisableMinimumFrameDurationOnPhone + diff --git a/lib/core/api.dart b/lib/core/api.dart index 8f747ae..4f9c756 100644 --- a/lib/core/api.dart +++ b/lib/core/api.dart @@ -1,47 +1,57 @@ - import 'package:flutter/cupertino.dart'; import 'package:queuing_system/core/base/base_app_client.dart'; import 'package:queuing_system/core/response_model/patient_call.dart'; const _getCallRequestInfoByClinicInfo = "/GetCallRequestInfoByClinincInfo"; -const _call_UpdateNotIsQueueRecordByIDAsync = "/Call_UpdateNotIsQueueRecordByIDAsync"; - -class API{ - - static GetCallRequestInfoByClinincInfo(String deviceIp, {@required Function(List, List) onSuccess, @required Function(dynamic) onFailure}) async{ - final body = { "IPAdress" : deviceIp }; - BaseAppClient.post(_getCallRequestInfoByClinicInfo, body: body, onSuccess: (response, status){ - if(status == 200){ - final calledByNurse = (response["CalledByNurse"] as List).map((j) => Tickets.fromJson(j)).toList(); - final clinicCurrentPatient = (response["ClinicCurrentPatient"] as List).map((j) => Tickets.fromJson(j)).toList(); - onSuccess(calledByNurse, clinicCurrentPatient); - }else{ - onFailure(response); - } - }, onFailure: (error, status) => onFailure(error)); +const _call_UpdateNotIsQueueRecordByIDAsync = "/Call_UpdateNotIsQueueRecordByID"; + +class API { + static GetCallRequestInfoByClinincInfo(String deviceIp, {@required Function(List) onSuccess, @required Function(dynamic) onFailure}) async { + final body = {"IPAdress": deviceIp}; + BaseAppClient.post(_getCallRequestInfoByClinicInfo, + body: body, + onSuccess: (response, status) { + if (status == 200) { + var calledByNurse = (response["CalledByNurse"] as List).map((j) => Tickets.fromJson(j)).toList(); + final patients = (response["ClinicCurrentPatient"] as List).map((j) => Tickets.fromJson(j)).toList(); + calledByNurse.addAll(patients); + + calledByNurse.sort((a, b) => a.callNo.compareTo(b.callNo)); + + // final clinicCurrentPatient = (response["ClinicCurrentPatient"] as List).map((j) => Tickets.fromJson(j)).toList(); + onSuccess(calledByNurse); + } else { + onFailure(response); + } + }, + onFailure: (error, status) => onFailure(error)); } - // static Call_UpdateNotIsQueueRecordByIDAsync(String deviceIp, {@required List tickets, @required Function(List) onSuccess, @required Function(dynamic) onFailure}) async{ - // if(tickets.isEmpty) { - // return; - // } - // - // List _ticketsUpdated = []; - // - // for (var ticket in tickets) { - // final body = { "CallID" : ticket.callNo}; - // await BaseAppClient.post(_call_UpdateNotIsQueueRecordByIDAsync, body: body, onSuccess: (response, status){ - // if(status == 200){ - // ticket.call_updated = true; - // _ticketsUpdated.add(ticket); - // } - // }, onFailure: (error, status) => onFailure(error)); - // } - // - // if(_ticketsUpdated.isNotEmpty) { - // onSuccess(_ticketsUpdated); - // }else{ - // onFailure(false); - // } - // } + static Call_UpdateNotIsQueueRecordByIDAsync(String deviceIp, {@required List tickets, @required Function(List) onSuccess, @required Function(dynamic) onFailure}) async { + if (tickets.isEmpty) { + return; + } + + List _ticketsUpdated = []; + + for (var ticket in tickets) { + final body = {"CallID": ticket.callNo}; + await BaseAppClient.post(_call_UpdateNotIsQueueRecordByIDAsync, + body: body, + onSuccess: (response, status) { + print("response: $response"); + if (status == 200) { + ticket.call_updated = true; + _ticketsUpdated.add(ticket); + } + }, + onFailure: (error, status) => onFailure(error)); + } + + if (_ticketsUpdated.isNotEmpty) { + onSuccess(_ticketsUpdated); + } else { + onFailure(false); + } + } } diff --git a/lib/home/home_screen.dart b/lib/home/home_screen.dart index db9ea26..2ccf9f6 100644 --- a/lib/home/home_screen.dart +++ b/lib/home/home_screen.dart @@ -4,6 +4,7 @@ import 'package:connectivity/connectivity.dart'; import 'package:flutter/material.dart'; import 'package:queuing_system/core/api.dart'; import 'package:queuing_system/core/base/app_scaffold_widget.dart'; +import 'package:queuing_system/core/config/config.dart'; import 'package:queuing_system/core/config/size_config.dart'; import 'package:queuing_system/core/response_model/patient_call.dart'; import 'package:queuing_system/header/app_header.dart'; @@ -14,7 +15,10 @@ import 'package:queuing_system/utils/signalR_utils.dart'; import 'package:queuing_system/utils/utils.dart'; import 'package:queuing_system/widget/data_display/app_texts_widget.dart'; -var DEVICE_IP = "10.10.14.11"; // Testing IP +var DEVICE_IP = "10.10.14.11"; // Testing IP +// var DEVICE_IP = "10.10.14.11"; // Testing IP +// var DEVICE_IP = "10.10.15.11"; + // var DEVICE_IP = "10.70.249.21"; // (Make sure by Haroon before use it) Production IP class MyHomePage extends StatefulWidget { @@ -30,31 +34,25 @@ class _MyHomePageState extends State { List waitings = []; List currents = []; + bool isLoading = false; + @override void dispose() { super.dispose(); } - @override void initState() { listenNetworkConnectivity(); - if (!signalRHelper.getConnectionState()) { - signalRHelper.startSignalRConnection( - DEVICE_IP, - onUpdateAvailable: onUpdateAvailable, - onConnect: onConnect, - onConnecting: onConnecting, - onDisconnect: onDisconnect - ); + signalRHelper.startSignalRConnection(DEVICE_IP, onUpdateAvailable: onUpdateAvailable, onConnect: onConnect, onConnecting: onConnecting, onDisconnect: onDisconnect); } - - super.initState(); } + TextEditingController controller = TextEditingController(); + @override Widget build(BuildContext context) { return AppScaffold( @@ -66,48 +64,91 @@ class _MyHomePageState extends State { width: double.infinity, child: Row( crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - const SizedBox(width: 20), - AppText( - "Powered By", - fontSize: SizeConfig.getWidthMultiplier() * 2.6, - fontFamily: 'Poppins-Medium.ttf', + Row( + children: [ + const SizedBox(width: 20), + AppText( + "Powered By", + fontSize: SizeConfig.getWidthMultiplier() * 2.6, + fontFamily: 'Poppins-Medium.ttf', + ), + const SizedBox(width: 20), + Image.asset( + "assets/images/cloud_logo.png", + height: SizeConfig.getHeightMultiplier() * 4, + ), + ], ), - const SizedBox(width: 20), - Image.asset( - "assets/images/cloud_logo.png", - height: SizeConfig.getHeightMultiplier() * 4, + Row( + children: [ + const SizedBox(width: 60), + SizedBox( + width: 200, + child: TextField( + controller: controller, + )), + const SizedBox(width: 30), + isLoading + ? const CircularProgressIndicator() + : ElevatedButton( + onPressed: onUpdateIPPressed, + child: const Text( + "Update IP", + style: TextStyle(color: Colors.white), + ), + style: ElevatedButton.styleFrom(backgroundColor: AppGlobal.appRedColor), + ), + const SizedBox(width: 30), + Text("IP: $DEVICE_IP", style: const TextStyle(fontWeight: FontWeight.w600)), + const SizedBox(width: 20), + ], ), - const SizedBox(width: 20), ], ), ), ); } - Widget content(){ + onUpdateIPPressed() async { + if (controller.text.isNotEmpty) { + isLoading = true; + setState(() {}); + DEVICE_IP = controller.text; + + await signalRHelper.connection.stop(); + if (!signalRHelper.getConnectionState()) { + await signalRHelper.startSignalRConnection(DEVICE_IP, onUpdateAvailable: onUpdateAvailable, onConnect: onConnect, onConnecting: onConnecting, onDisconnect: onDisconnect); + } + + controller.clear(); + waitings.clear(); + isLoading = false; + setState(() {}); + } + } + + Widget content() { // waitings = waitings.sublist(0,3); voiceCall(); - if(waitings.isEmpty) { + if (waitings.isEmpty) { // No Patient in Queue return noPatientInQueue(); - - }else if(waitings.length > 4){ + } else if (waitings.length > 4) { // Return Content With Side List return priorityTicketsWithSideList(waitings); - - }else{ + } else { // Return Content In Center Aligned return priorityTickets(waitings); - } } - CallByVoice voiceCaller; - voiceCall() async{ - if(waitings.isNotEmpty && voiceCaller == null){ + + voiceCall() async { + if (waitings.isNotEmpty && voiceCaller == null) { final postVoice = waitings.first.getCallType().audio('en'); voiceCaller = CallByVoice(waitings.first.callNo.toString(), preVoice: 'ticket_number.mp3', postVoice: postVoice, lang: 'en'); await voiceCaller.start(); @@ -115,54 +156,47 @@ class _MyHomePageState extends State { } } - onUpdateAvailable(data) async{ - API.GetCallRequestInfoByClinincInfo( - DEVICE_IP, - onSuccess: (waitingCalls, currentInClinic){ - - setState(() { - waitings = waitingCalls; - currents = currentInClinic; - }); - - log("\n\n"); - log("--------------------"); - log("Current: $currentInClinic"); - log("Waiting: $waitingCalls"); - log("--------------------"); - log("\n\n"); - - updateTickets(); - - }, onFailure: (error){ - - }); + onUpdateAvailable(data) async { + API.GetCallRequestInfoByClinincInfo(DEVICE_IP, onSuccess: (waitingCalls) { + setState(() { + waitings = waitingCalls; + // currents = currentInClinic; + }); + + log("\n\n"); + log("--------------------"); + // log("Current: $currentInClinic"); + log("Waiting: $waitingCalls"); + log("--------------------"); + log("\n\n"); + + updateTickets(); + }, onFailure: (error) {}); } - - updateTickets(){ - // List _ticketsToUpdate = waitings.where((t) => t.call_updated == false); - // API.Call_UpdateNotIsQueueRecordByIDAsync(DEVICE_IP, tickets: _ticketsToUpdate, onSuccess: (tickets_updated){ - // print("[${tickets_updated.length}] Tickets Updated: $tickets_updated"); - // }, onFailure: (e){ - // - // }); + updateTickets() { + List _ticketsToUpdate = waitings.where((t) => t.call_updated == false).toList(); + API.Call_UpdateNotIsQueueRecordByIDAsync(DEVICE_IP, tickets: _ticketsToUpdate, onSuccess: (tickets_updated) { + print("[${tickets_updated.length}] Tickets Updated: $tickets_updated"); + }, onFailure: (e) { + print("API UPDate Tickets Failed with : ${e.toString()}"); + }); } - - onConnect(){ + onConnect() { log("SignalR: onConnect"); } - onDisconnect(exception){ + onDisconnect(exception) { log("SignalR: onDisconnect"); + signalRHelper.startSignalRConnection(DEVICE_IP, onUpdateAvailable: onUpdateAvailable, onConnect: onConnect, onConnecting: onConnecting, onDisconnect: onDisconnect); } - onConnecting(){ + onConnecting() { log("SignalR: onConnecting"); } - listenNetworkConnectivity() async{ + listenNetworkConnectivity() async { Connectivity().onConnectivityChanged.listen((event) { switch (event) { case ConnectivityResult.wifi: diff --git a/lib/utils/call_by_voice.dart b/lib/utils/call_by_voice.dart index 044c1c7..d58ec61 100644 --- a/lib/utils/call_by_voice.dart +++ b/lib/utils/call_by_voice.dart @@ -1,9 +1,7 @@ import 'package:flutter/cupertino.dart'; import 'package:just_audio/just_audio.dart'; -import 'package:queuing_system/utils/call_type.dart'; - -class CallByVoice{ +class CallByVoice { final String lang; final String preVoice; final String ticketNo; @@ -12,19 +10,19 @@ class CallByVoice{ CallByVoice(this.ticketNo, {this.lang = 'en', @required this.preVoice, @required this.postVoice}); final _player = AudioPlayer(); - start() async{ + start() async { // Create Pre Voice Players - if(preVoice != null && preVoice.isNotEmpty) { + if (preVoice != null && preVoice.isNotEmpty) { await _player.setAsset('assets/voice_$lang/$preVoice'); await _player.play(); } // Create Ticket Number Voice Players final characters = ticketNo.characters.toList(); - for(int i = 0; i< characters.length; i++){ + for (int i = 0; i < characters.length; i++) { final no = characters[i]; - if(no.isNotEmpty){ + if (no.isNotEmpty) { await Future.delayed(const Duration(milliseconds: 200)); await _player.stop(); @@ -33,9 +31,8 @@ class CallByVoice{ } } - // Create Post Voice Players - if(postVoice != null && postVoice.isNotEmpty) { + if (postVoice != null && postVoice.isNotEmpty) { await Future.delayed(const Duration(milliseconds: 1000)); await _player.stop(); @@ -45,4 +42,9 @@ class CallByVoice{ _player.dispose(); } -} \ No newline at end of file + + stop() async { + await _player.stop(); + } + +} diff --git a/lib/utils/signalR_utils.dart b/lib/utils/signalR_utils.dart index eb7ebcc..505feb1 100644 --- a/lib/utils/signalR_utils.dart +++ b/lib/utils/signalR_utils.dart @@ -25,7 +25,8 @@ class SignalRHelper{ startSignalRConnection(String deviceIp, {@required Function(dynamic) onUpdateAvailable, @required VoidCallback onConnect, @required Function(dynamic) onDisconnect, @required VoidCallback onConnecting}) async { // Hardcoded IP For Testing - deviceIp = "10.10.14.11"; + // deviceIp = "10.10.14.11"; + print("Connecting Signal R with: $deviceIp"); final url = hubBaseURL+"?IPAddress=$deviceIp"; connection = HubConnectionBuilder()