diff --git a/android/key.properties b/android/key.properties index 9cd1c57c..fae5f053 100644 --- a/android/key.properties +++ b/android/key.properties @@ -2,4 +2,4 @@ storePassword=Cloud@AtomsSA keyPassword=Cloud@AtomsSA keyAlias=playstore #storeFile=/Users/sikandersaleem/StudioProjects/cloudsolutions-atoms/android/AtomsSA-playStore.jks -storeFile=AtomsSA-playStore.jks +storeFile=../AtomsSA-playStore.jks diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index fd320f8f..f8226e55 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -1,16 +1,16 @@ class URLs { URLs._(); - static const String appReleaseBuildNumber = "22"; + static const String appReleaseBuildNumber = "24"; - // static const host1 = "https://atomsm.hmg.com"; // production url + static const host1 = "https://atomsm.hmg.com"; // production url // static const host1 = "https://atomsmdev.hmg.com"; // local DEV url - static const host1 = "https://atomsmuat.hmg.com"; // local UAT url + // static const host1 = "https://atomsmuat.hmg.com"; // local UAT url - static String _baseUrl = "$_host/mobile"; + // static String _baseUrl = "$_host/mobile"; // static final String _baseUrl = "$_host/v2/mobile"; // new V2 apis // static final String _baseUrl = "$_host/mobile"; // host local UAT - // static final String _baseUrl = "$_host/v3/mobile"; // v3 for new CM,PM,TM + static final String _baseUrl = "$_host/v3/mobile"; // v3 for production CM,PM,TM static String _host = host1; @@ -21,7 +21,14 @@ class URLs { // static String getFileUrl(String file) => (file == null || file.isEmpty) ? null :1 (file.contains("/") ? file : "$_host/attachment/$file"); // API Routes - static get login => "$_baseUrl/MobileAuth/Login"; // web login + static get login => "$_baseUrl/MobileAuth/Login"; + + static get getUserInfo => "$_baseUrl/MobileAuth/GetUserInfo"; + + static get logout => "$_baseUrl/MobileAuth/Logout"; + + static get enableFaceId => "$_baseUrl/MobileAuth/EnabledFaceId"; + static get checkLoginValidation => "$_baseUrl/Account/Authenticate"; // web login static get checkAppVersion => "$_baseUrl/Account/CheckAppVersion"; // web login //Reset Password Apis... diff --git a/lib/controllers/providers/api/user_provider.dart b/lib/controllers/providers/api/user_provider.dart index d013651a..afc67620 100644 --- a/lib/controllers/providers/api/user_provider.dart +++ b/lib/controllers/providers/api/user_provider.dart @@ -32,6 +32,10 @@ class UserProvider extends ChangeNotifier { User? get user => _user; + User? _refreshedUser; + + User? get refreshedUser => _refreshedUser; + File? profileImage; VerifyOtpModel _verifyOtpModel = VerifyOtpModel(); @@ -117,6 +121,40 @@ class UserProvider extends ChangeNotifier { } } + Future getUserInfo({String? fireBaseToken}) async { + Response response; + try { + response = await ApiManager.instance.post(URLs.getUserInfo, body: {'fireBaseToken': fireBaseToken}); + if (response.statusCode >= 200 && response.statusCode < 300) { + _refreshedUser = await User.fromJson(jsonDecode(response.body)); + _refreshedUser!.profilePhotoName = URLs.getFileUrl(_refreshedUser!.profilePhotoName); + if (response.statusCode == 200) { + return true; + } + } + return false; + } catch (error) { + return false; + } + } + + Future logout(BuildContext context) async { + Response response; + try { + showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); + response = await ApiManager.instance.post(URLs.logout, body: {}); + if (response.statusCode >= 200 && response.statusCode < 300) { + Navigator.pop(context); + return true; + } + Navigator.pop(context); + return false; + } catch (error) { + Navigator.pop(context); + return false; + } + } + /// sign up with User object; /// return -2 if request in progress /// return -1 if error happen when sending request diff --git a/lib/controllers/providers/settings/setting_provider.dart b/lib/controllers/providers/settings/setting_provider.dart index 59adf6a0..2482c5b9 100644 --- a/lib/controllers/providers/settings/setting_provider.dart +++ b/lib/controllers/providers/settings/setting_provider.dart @@ -77,6 +77,7 @@ class SettingProvider extends ChangeNotifier { } void selectAssetGroup(User user) { + if(user.assetGroups ==null) return; if (user.assetGroups!.length == 1) { _assetGroup = user.assetGroups!.first; } else { @@ -186,6 +187,23 @@ class SettingProvider extends ChangeNotifier { } } + + Future checkIsEnabledFaceId({required bool status}) async { + try { + final response = await ApiManager.instance.post( + URLs.enableFaceId, + showToast: false, + body: { + 'isEnabled':status, + }, + ); + return response.statusCode >= 200 && response.statusCode < 300; + } catch (error) { + return false; + } + } + + Future checkAppUpdate(String buildNumber, String osType) async { Response response; bool isValid = false; diff --git a/lib/dashboard_latest/dashboard_view.dart b/lib/dashboard_latest/dashboard_view.dart index 149a9e24..3e399e41 100644 --- a/lib/dashboard_latest/dashboard_view.dart +++ b/lib/dashboard_latest/dashboard_view.dart @@ -103,7 +103,7 @@ class _DashboardViewState extends State { @override Widget build(BuildContext context) { - bool isNurse = (Provider.of(context, listen: false).user!.type) == UsersTypes.normal_user; + bool isNurse = (Provider.of(context, listen: false).user?.type) == UsersTypes.normal_user; final user = Provider.of(context, listen: false).user; return Stack( children: [ diff --git a/lib/extensions/widget_extensions.dart b/lib/extensions/widget_extensions.dart index 0bb4ec12..8caa8ccf 100644 --- a/lib/extensions/widget_extensions.dart +++ b/lib/extensions/widget_extensions.dart @@ -79,10 +79,9 @@ extension WidgetExtensions on Widget { : this; } - Widget toShimmer({bool isShow = true, double radius = 20,required BuildContext context}) => isShow + Widget toShimmer({bool isShow = true, double radius = 20, required BuildContext context}) => isShow ? Shimmer.fromColors( - // baseColor: const Color(0xffe8eff0), - baseColor: Theme.of(context).scaffoldBackgroundColor, + baseColor: context.isDark ? AppColor.backgroundDark : const Color(0xffe8eff0), highlightColor: AppColor.background(context), child: ClipRRect( borderRadius: BorderRadius.circular(radius), @@ -98,17 +97,26 @@ extension WidgetExtensions on Widget { ? Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const SizedBox(width: 250, height: 24).toShimmer(isShow: isShow,context: context), + const SizedBox(width: 250, height: 24).toShimmer(isShow: isShow, context: context), 8.height, - const SizedBox(width: 160, height: 16).toShimmer(isShow: isShow,context: context), + const SizedBox(width: 160, height: 16).toShimmer(isShow: isShow, context: context), 8.height, - const SizedBox(width: 120, height: 18).toShimmer(isShow: isShow,context: context).toShimmer(isShow: isShow,context: context), + const SizedBox(width: 120, height: 18).toShimmer(isShow: isShow, context: context).toShimmer(isShow: isShow, context: context), ], ).toShadowContainer(context) : this; - Widget toShadowContainer(BuildContext context, - {bool showShadow = true, double borderRadius = 14, bool withShadow = true, Color? backgroundColor, Color borderColor = Colors.transparent, double padding = 16, EdgeInsets? paddingObject, EdgeInsets? margin,}) => + Widget toShadowContainer( + BuildContext context, { + bool showShadow = true, + double borderRadius = 14, + bool withShadow = true, + Color? backgroundColor, + Color borderColor = Colors.transparent, + double padding = 16, + EdgeInsets? paddingObject, + EdgeInsets? margin, + }) => withShadow ? Container( padding: paddingObject ?? EdgeInsets.all(padding), diff --git a/lib/main.dart b/lib/main.dart index 3bdce858..e60fb1e8 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -315,7 +315,7 @@ class MyApp extends StatelessWidget { //ReportIssuesPage.id: (_) => ReportIssuesPage(), RequestGasRefill.id: (_) => const RequestGasRefill(), UpdateGasRefillRequest.id: (_) => const UpdateGasRefillRequest(), - CreateServiceRequestPage.id: (_) => const CreateServiceRequestPage(), + // CreateServiceRequestPage.id: (_) => const CreateServiceRequestPage(), CreateNewRequest.id: (_) => const CreateNewRequest(), // SingleHospitalPicker.id: (_) => SingleHospitalPicker(), MyAssetsPage.id: (_) => const MyAssetsPage(), diff --git a/lib/models/user.dart b/lib/models/user.dart index 75045ac0..a1ed40b0 100644 --- a/lib/models/user.dart +++ b/lib/models/user.dart @@ -42,6 +42,7 @@ class User { bool? enableWifi; bool? enableNFC; bool? enableQR; + bool? isEnabledFaceId; bool? onlySwipe; User({ @@ -79,6 +80,7 @@ class User { this.enableNFC, this.enableQR, this.enableWifi, + this.isEnabledFaceId, this.onlySwipe, }); @@ -86,9 +88,12 @@ class User { Future> toLoginJson() async { String notificationType = (Platform.isAndroid && !(await FirebaseNotificationManger.isGoogleServicesAvailable())) ? "HMC" : "FCM"; + if(FirebaseNotificationManger.token==null){ + //calling this agin to check for token as sometimes token is null fresh install.. + await FirebaseNotificationManger.getToken(); + } return {"username": userName, "password": password, "fireBaseToken": FirebaseNotificationManger?.token ?? "", "notificationType": notificationType}; } - UsersTypes? get type { switch (userRoles?.first.value) { case "R-6": @@ -167,6 +172,7 @@ class User { map['enableNFC'] = enableNFC; map['enableQR'] = enableQR; map['onlySwipe'] = onlySwipe; + map['isEnabledFaceId'] = isEnabledFaceId; return map; } @@ -233,6 +239,7 @@ class User { enableNFC = json['enableNFC']; enableQR = json['enableQR']; onlySwipe = json['onlySwipe']; + isEnabledFaceId = json['isEnabledFaceId']; } } @@ -300,6 +307,14 @@ class AssetGroup { data['enabledEngineerTimer'] = enabledEngineerTimer; return data; } + + @override + bool operator ==(Object other) => + identical(this, other) || + other is AssetGroup && runtimeType == other.runtimeType && id == other.id; + + @override + int get hashCode => id.hashCode; } class UserContactInfoModel { diff --git a/lib/new_views/common_widgets/app_drawer.dart b/lib/new_views/common_widgets/app_drawer.dart index 3426a056..093b8de1 100644 --- a/lib/new_views/common_widgets/app_drawer.dart +++ b/lib/new_views/common_widgets/app_drawer.dart @@ -73,8 +73,8 @@ class AppDrawer extends StatelessWidget { // 18.height, drawerItem("setting", context.translation.settings, context).onPress(() => Navigator.of(context).pushNamed(SettingsPage.id)), 18.height, - if(userProvider.user!=null&&userProvider.user?.employeeIsHMG==false) - drawerItem("swipe", "Swipe History", context) .onPress(() => Navigator.of(context).pushNamed(SwipeHistoryView.routeName)), + if (userProvider.user != null && userProvider.user?.employeeIsHMG == false) + drawerItem("swipe", "Swipe History", context).onPress(() => Navigator.of(context).pushNamed(SwipeHistoryView.routeName)), // 18.height, // drawerItem("report", context.translation.reportBg, context) /*.onPress(() => Navigator.of(context).pushNamed(ReportBugPage.id))*/, // 18.height, @@ -87,11 +87,14 @@ class AppDrawer extends StatelessWidget { builder: (_) => AAlertDialog(title: context.translation.signOut, content: context.translation.logoutAlert), ); if (result) { - settingProvider.resetSettings(); - userProvider.reset(); - Navigator.of(context).pop(); - Navigator.of(context).pop(); - Navigator.of(context).pushNamedAndRemoveUntil(LoginPage.routeName, (routes) => true); + bool isSuccess = await userProvider.logout(context); + if (isSuccess) { + settingProvider.resetSettings(); + userProvider.reset(); + Navigator.of(context).pop(); + Navigator.of(context).pop(); + Navigator.of(context).pushNamedAndRemoveUntil(LoginPage.routeName, (routes) => true); + } } }), 18.height, diff --git a/lib/new_views/pages/land_page/land_page.dart b/lib/new_views/pages/land_page/land_page.dart index 9e06e918..a4ed3dd5 100644 --- a/lib/new_views/pages/land_page/land_page.dart +++ b/lib/new_views/pages/land_page/land_page.dart @@ -133,9 +133,12 @@ class _LandPageState extends State { builder: (_) => AAlertDialog(title: context.translation.signOut, content: context.translation.logoutAlert), ); if (result) { - Provider.of(context, listen: false).resetSettings(); - Provider.of(context, listen: false).reset(); - Navigator.of(context).pushNamedAndRemoveUntil(LoginPage.routeName, (routes) => true); + bool isSuccess = await Provider.of(context, listen: false).logout(context); + if (isSuccess) { + Provider.of(context, listen: false).resetSettings(); + Provider.of(context, listen: false).reset(); + Navigator.of(context).pushNamedAndRemoveUntil(LoginPage.routeName, (routes) => true); + } } return false; }, diff --git a/lib/new_views/pages/login_page.dart b/lib/new_views/pages/login_page.dart index 304daf92..35eb9134 100644 --- a/lib/new_views/pages/login_page.dart +++ b/lib/new_views/pages/login_page.dart @@ -110,8 +110,8 @@ class _LoginPageState extends State { backgroundColor: AppColor.fieldBgColor(context), validator: (value) => Validator.hasValue(value!) ? null : context.translation.requiredField, labelText: context.translation.username, - style: TextStyle(fontWeight: FontWeight.w500, fontSize: 12, color:context .isDark?Colors.white: const Color(0xff3B3D4A)), - labelStyle: TextStyle(fontWeight: FontWeight.w500, fontSize: 11, color:context .isDark?Colors.white:const Color(0xff767676)), + style: TextStyle(fontWeight: FontWeight.w500, fontSize: 12, color: context.isDark ? Colors.white : const Color(0xff3B3D4A)), + labelStyle: TextStyle(fontWeight: FontWeight.w500, fontSize: 11, color: context.isDark ? Colors.white : const Color(0xff767676)), textInputType: TextInputType.text, showWithoutDecoration: true, contentPadding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 12.toScreenHeight), @@ -125,8 +125,8 @@ class _LoginPageState extends State { showWithoutDecoration: true, labelText: context.translation.password, backgroundColor: AppColor.fieldBgColor(context), - style: TextStyle(fontWeight: FontWeight.w500, fontSize: 12, color: context .isDark?Colors.white: const Color(0xff3B3D4A)), - labelStyle: TextStyle(fontWeight: FontWeight.w500, fontSize: 11, color: context .isDark?Colors.white: const Color(0xff767676)), + style: TextStyle(fontWeight: FontWeight.w500, fontSize: 12, color: context.isDark ? Colors.white : const Color(0xff3B3D4A)), + labelStyle: TextStyle(fontWeight: FontWeight.w500, fontSize: 11, color: context.isDark ? Colors.white : const Color(0xff767676)), contentPadding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 12.toScreenHeight), obscureText: !_passwordVisible, suffixIcon: Icon( @@ -233,8 +233,15 @@ class _LoginPageState extends State { int status = await _userProvider.login(context: context, user: _user); if (status >= 200 && status < 300 && _userProvider.user!.isAuthenticated! ?? false) { await _settingProvider!.setUser(_userProvider.user!); - (await SharedPreferences.getInstance()).remove(ASettings.localAuth); + + // (await SharedPreferences.getInstance()).remove(ASettings.localAuth); await _settingProvider!.setRememberMe(_user.userName!, _user.password!, rememberMe); + //TODO need to verify this here... + if (_userProvider.user?.isEnabledFaceId == true) { + await _settingProvider!.setAuth(_userProvider.user!.isEnabledFaceId!); + } else { + (await SharedPreferences.getInstance()).remove(ASettings.localAuth); + } Navigator.pushReplacementNamed(context, LandPage.routeName); } else { Fluttertoast.showToast(msg: _userProvider.user?.message ?? context.translation.failedToCompleteRequest); diff --git a/lib/new_views/pages/settings_page.dart b/lib/new_views/pages/settings_page.dart index 18043733..ddb449c6 100644 --- a/lib/new_views/pages/settings_page.dart +++ b/lib/new_views/pages/settings_page.dart @@ -52,6 +52,7 @@ class _SettingsPageState extends State { if (authStatus) { localAuth = !localAuth; await _settingProvider!.setAuth(localAuth); + await _settingProvider!.checkIsEnabledFaceId(status: localAuth); // authController.value = _settingProvider.localAuth == buttonState.toString(); setState(() {}); } else { diff --git a/lib/new_views/pages/splash_page.dart b/lib/new_views/pages/splash_page.dart index ec2bfe10..f3954a99 100644 --- a/lib/new_views/pages/splash_page.dart +++ b/lib/new_views/pages/splash_page.dart @@ -1,17 +1,21 @@ +import 'dart:developer'; import 'dart:io'; import 'package:firebase_core/firebase_core.dart'; +import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flare_flutter/flare_actor.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:local_auth/local_auth.dart'; import 'package:provider/provider.dart'; import 'package:safe_device/safe_device.dart'; +import 'package:test_sa/controllers/api_routes/api_manager.dart'; import 'package:test_sa/controllers/api_routes/urls.dart'; import 'package:test_sa/controllers/notification/firebase_notification_manger.dart'; import 'package:test_sa/controllers/providers/api/user_provider.dart'; import 'package:test_sa/controllers/providers/settings/setting_provider.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; import 'package:test_sa/new_views/pages/land_page/land_page.dart'; import 'package:test_sa/new_views/pages/login_page.dart'; import 'package:test_sa/new_views/pages/unsafe_device_view.dart'; @@ -40,6 +44,7 @@ class _SplashPageState extends State { @override void initState() { Firebase.initializeApp(); + // NotificationManger.initialisation((notificationDetails) { // // todo @sikander, check notifications payload, because notification model is different to need to check from backend // // SystemNotificationModel notification = SystemNotificationModel.fromJson(json.decode(notificationDetails.payload)); @@ -85,6 +90,7 @@ class _SplashPageState extends State { setState(() { loading = false; }); + if (isValid == false) { showDialog( context: context, @@ -98,11 +104,28 @@ class _SplashPageState extends State { }), ); } else { - if (isValid && _settingProvider.isLocalAuthEnable) { - handleLocalAuth(); - return; - } - Navigator.of(context).pushNamedAndRemoveUntil(LoginPage.routeName, (routes) => true); + ApiManager.instance.user = _settingProvider.user!; + + if (FirebaseNotificationManger.token == null) await FirebaseNotificationManger.getToken(); + setState(() { + loading = true; + }); + await _userProvider.getUserInfo(fireBaseToken: FirebaseNotificationManger.token).then((status) async { + setState(() { + loading = false; + }); + if (status && _userProvider.refreshedUser != null) { + _userProvider.refreshedUser!.token = _settingProvider.user?.token; + await _settingProvider.setUser(_userProvider.refreshedUser!); + _userProvider.setUser(_userProvider.refreshedUser!); + await _settingProvider.setAuth(_settingProvider.user?.isEnabledFaceId ?? false); + } + if (_settingProvider.isLocalAuthEnable) { + handleLocalAuth(); + return; + } + Navigator.of(context).pushNamedAndRemoveUntil(LoginPage.routeName, (routes) => true); + }); } } } @@ -116,7 +139,16 @@ class _SplashPageState extends State { } if (isSuccess) { - _userProvider.setUser(_settingProvider.user!); + // _userProvider.setUser(_settingProvider.user!); + // if (FirebaseNotificationManger.token == null) await FirebaseNotificationManger.getToken(); + // await _userProvider.getUserInfo(fireBaseToken: FirebaseNotificationManger.token).then((status) async { + // if (status && _userProvider.refreshedUser != null) { + // _userProvider.refreshedUser!.token = _settingProvider.user?.token; + // await _settingProvider.setUser(_userProvider.refreshedUser!); + // _userProvider.setUser(_settingProvider.user!); + // await _settingProvider.setAuth(_settingProvider.user?.isEnabledFaceId ?? false); + // } + // }); if (_userProvider.user!.onlySwipe!) { Navigator.of(context).pushNamedAndRemoveUntil(SwipeView.routeName, (routes) => true); diff --git a/lib/new_views/swipe_module/swipe_view.dart b/lib/new_views/swipe_module/swipe_view.dart index 40eabe46..e6412ea4 100644 --- a/lib/new_views/swipe_module/swipe_view.dart +++ b/lib/new_views/swipe_module/swipe_view.dart @@ -55,9 +55,12 @@ class _SwipeViewState extends State { builder: (_) => AAlertDialog(title: context.translation.signOut, content: context.translation.logoutAlert), ); if (result) { - Provider.of(context, listen: false).resetSettings(); - Provider.of(context, listen: false).reset(); - Navigator.of(context).pushNamedAndRemoveUntil(LoginPage.routeName, (routes) => true); + bool isSuccess = await Provider.of(context, listen: false).logout(context); + if (isSuccess) { + Provider.of(context, listen: false).resetSettings(); + Provider.of(context, listen: false).reset(); + Navigator.of(context).pushNamedAndRemoveUntil(LoginPage.routeName, (routes) => true); + } } return false; }, diff --git a/lib/views/pages/user/requests/create_service_request_page.dart b/lib/views/pages/user/requests/create_service_request_page.dart index 9eb6c32b..9fc69f4b 100644 --- a/lib/views/pages/user/requests/create_service_request_page.dart +++ b/lib/views/pages/user/requests/create_service_request_page.dart @@ -1,407 +1,407 @@ -import 'dart:convert'; -import 'dart:io'; - -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; -import 'package:test_sa/controllers/providers/api/service_requests_provider.dart'; -import 'package:test_sa/controllers/providers/api/user_provider.dart'; -import 'package:test_sa/controllers/providers/settings/setting_provider.dart'; -import 'package:test_sa/extensions/context_extension.dart'; -import 'package:test_sa/extensions/int_extensions.dart'; -import 'package:test_sa/extensions/widget_extensions.dart'; -import 'package:test_sa/models/generic_attachment_model.dart'; -import 'package:test_sa/models/service_request/pending_service_request_model.dart'; -import 'package:test_sa/models/service_request/service_request.dart'; -import 'package:test_sa/modules/cm_module/utilities/service_request_utils.dart'; -import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; -import 'package:test_sa/providers/service_request_providers/equipment_status_provider.dart'; -import 'package:test_sa/providers/service_request_providers/requested_through_provider.dart'; -import 'package:test_sa/views/pages/user/requests/pending_requests_screen.dart'; -import 'package:test_sa/views/widgets/bottom_sheets/pending_request_bottom_sheet.dart'; -import 'package:test_sa/views/widgets/equipment/asset_picker.dart'; -import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; -import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; -import 'package:test_sa/views/widgets/sound/TextSpeechRecordWidget.dart'; - -import '../../../../new_views/app_style/app_color.dart'; -import '../../../../new_views/common_widgets/default_app_bar.dart'; -import '../../../../providers/service_request_providers/priority_provider.dart'; -import '../../../../providers/service_request_providers/type_of_request_provider.dart'; - -class CreateServiceRequestPage extends StatefulWidget { - static const String id = "/create-request"; - final ServiceRequest? serviceRequest; - - const CreateServiceRequestPage({this.serviceRequest, Key? key}) : super(key: key); - - @override - CreateServiceRequestPageState createState() => CreateServiceRequestPageState(); -} - -class CreateServiceRequestPageState extends State { - late TextEditingController _commentController; - - late double _height; - late UserProvider _userProvider; - late SettingProvider _settingProvider; - late ServiceRequestsProvider _serviceRequestsProvider; - late ServiceRequest _serviceRequest; - final List attachments = []; - final bool _isLoading = false; - bool _showDatePicker = false; - final GlobalKey _formKey = GlobalKey(); - final GlobalKey _scaffoldKey = GlobalKey(); - DateTime? _dateTime; - - bool isFirstActionSubmitted = false; - - @override - void initState() { - _commentController = TextEditingController(); - if (widget.serviceRequest != null) { - _serviceRequest = widget.serviceRequest!; - attachments.addAll(_serviceRequest.devicePhotos!.map((e) => GenericAttachmentModel(name: e)).toList()); - _showDatePicker = _serviceRequest.firstAction != null && _serviceRequest.firstAction?.name == "Need a visit"; - if (_showDatePicker && _serviceRequest.visitDate != null) { - _dateTime = DateTime.tryParse(_serviceRequest.visitDate!); - } - } else { - _serviceRequest = ServiceRequest(); - } - isFirstActionSubmitted = _serviceRequest.firstAction != null; - super.initState(); - } - - // - // getServiceRequestById(String id) async { - // try { - // ServiceRequest request = await _serviceRequestsProvider.getServiceRequestObjectById(requestId: id) ?? ""; - // _serviceRequest = request; - // _device = _serviceRequest.device; - // attachments.addAll(_serviceRequest.devicePhotos.map((e) { - // return File(e); - // }).toList()); - // _showDatePicker = _serviceRequest.firstAction != null && _serviceRequest.firstAction.name == "Need a visit"; - // if (_showDatePicker && _serviceRequest.visitDate != null) { - // _dateTime = DateTime.tryParse(_serviceRequest.visitDate); - // } - // _isLoading = false; - // } catch (ex) { - // _isLoading = false; - // } - // setState(() {}); - // } - - @override - void dispose() { - _commentController.dispose(); - super.dispose(); - } - - bool _isLocalUrl(String url) { - if (url.isEmpty != false) return false; - return url.startsWith("/") || url.startsWith("file://") || url.substring(1).startsWith(':\\'); - } - - // bool priority; - - void getData() { - Provider.of(context).getData(); - Provider.of(context).getData(); - Provider.of(context).getData(); - Provider.of(context).getData(); - } - - PendingAssetServiceRequest? pendingAssetServiceRequest; - - @override - Widget build(BuildContext context) { - _height = MediaQuery.of(context).size.height; - _userProvider = Provider.of(context); - - _serviceRequestsProvider = Provider.of(context); - - return Scaffold( - key: _scaffoldKey, - appBar: DefaultAppBar(title: context.translation.newServiceRequest), - body: SafeArea( - child: LoadingManager( - isLoading: _isLoading, - isFailedLoading: false, - stateCode: 200, - onRefresh: () async {}, - child: Form( - key: _formKey, - child: Column( - children: [ - SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - AssetPicker( - device: _serviceRequest.device, - showLoading: checkPendingRequest, - onPick: (asset) async { - pendingAssetServiceRequest = null; - _serviceRequest.device = asset; - await checkAssetForPendingServiceRequest(asset.id!.toInt()); - - if (pendingAssetServiceRequest != null && pendingAssetServiceRequest!.details!.isNotEmpty) { - showPendingRequestBottomSheet(); - } - }, - ), - if (pendingAssetServiceRequest != null && pendingAssetServiceRequest!.details!.isNotEmpty) ...[ - 8.height, - Row( - children: [ - const Icon(Icons.warning, color: Color(0xffEE404C), size: 14), - 8.width, - Text( - "This asset already have ${pendingAssetServiceRequest!.details!.length} request pending", - style: const TextStyle(fontSize: 12, fontWeight: FontWeight.w500, color: Color(0xff7D859A), decoration: TextDecoration.underline), - ).expanded, - ], - ).onPress(() { - showPendingRequests(); - }), - ], - 16.height, - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text(context.translation.priority, style: Theme.of(context).textTheme.bodyLarge), - Consumer(builder: (cxt, snapshot, _) { - _serviceRequest.priority ??= snapshot.items.firstWhere((element) => element.value == 0, orElse: null); - - return Transform.scale( - scale: 0.8, - child: CupertinoSwitch( - thumbColor: _serviceRequest.priority?.value != 0 ? const Color(0xffF63939) : Colors.blueGrey.withOpacity(.5), - activeColor: AppColor.blueStatus(context).withOpacity(.25), - value: _serviceRequest.priority?.value != 0, - onChanged: (state) { - if (state) { - _serviceRequest.priority = snapshot.items.firstWhere((element) => element.value == 1, orElse: null); - } else { - _serviceRequest.priority = snapshot.items.firstWhere((element) => element.value == 0, orElse: null); - } - setState(() {}); - }).toShimmer(isShow: snapshot.loading,context: context), - ); - }), - ], - ), - 16.height, - Consumer(builder: (cxt, snapshot, _) { - try { - _serviceRequest.defectType ??= snapshot.items.first; - } catch (ex) { - print("snapshot.items:${snapshot.items.length}"); - } - - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - Text(context.translation.equipmentStatus, style: Theme.of(context).textTheme.bodyLarge), - 8.height, - Wrap( - runSpacing: 8, - spacing: 8, - children: [ - for (var element in snapshot.items) - Row( - mainAxisSize: MainAxisSize.min, - children: [ - SizedBox( - width: 24, - height: 24, - child: Radio( - value: element, - activeColor: Colors.red, - fillColor: WidgetStateColor.resolveWith((states) { - if (states.contains(WidgetState.selected)) return const Color(0xff3DA5E5); - return const Color(0xffE0E0E0); - }), - groupValue: _serviceRequest.defectType, - onChanged: (state) { - setState(() { - _serviceRequest.defectType = element; - }); - }), - ), - 8.width, - Text(element.name!, style: Theme.of(context).textTheme.bodySmall), - ], - ) - ], - ).toShimmer(isShow: snapshot.loading,context: context), - ], - ); - }), - 16.height, - AttachmentPicker(label: context.translation.attachImage, attachment: attachments, showAsGrid: true), - ], - ).toShadowContainer(context), - - // SingleItemDropDownMenu( - // context: context, - // title: context.translation.priority, - // initialValue: _serviceRequest?.priority, - // onSelect: (value) { - // _serviceRequest.priority = value; - // }, - // ), - // 8.height, - // SingleItemDropDownMenu( - // context: context, - // title: context.translation.equipmentStatus, - // initialValue: _serviceRequest?.defectType, - // onSelect: (value) { - // _serviceRequest.defectType = value; - // }, - // ), - - // Consumer(builder: (context, snapshot, _) { - // return SingleItemDropDownMenu( - // context: context, - // enabled: false, - // title: context.translation.source, - // initialValue: snapshot.items?.firstWhere((element) => element.value == 3, orElse: null), - // ); - // }), - // 8.height, - // Consumer(builder: (context, snapshot, _) { - // return SingleItemDropDownMenu( - // context: context, - // title: context.translation.requestType, - // enabled: false, - // initialValue: snapshot.items?.firstWhere((element) => element.value == 1, orElse: null), - // // onSelect: (value) { - // // _serviceRequest.type = value; - // // }, - // ); - // }), - - // Align( - // alignment: AlignmentDirectional.centerStart, - // child: context.translation.callComments.heading5(context), - // ), - 8.height, - // SpeechToTextButton( - // controller: _commentController, - // ), - // 8.height, - // AppTextFormField( - // controller: _commentController, - // labelText: context.translation.problemDesc, - // suffixIcon: "warning".toSvgAsset(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20, width: 24).paddingOnly(end: 16), - // initialValue: _serviceRequest.callComments, - // onSaved: (text) { - // _serviceRequest.callComments = text; - // }, - // ), - // 8.height, - // RecordSound( - // onRecord: (audio) { - // _serviceRequest.audio = audio; - // }, - // enabled: widget.serviceRequest == null ? true : false, - // ), - 8.height, - TextSpeechRecordWidget( - initialMessage: _serviceRequest.callComments!, - onMessageChange: (message) { - _serviceRequest.callComments = message; - }, - onRecord: (audio) { - _serviceRequest.audio = audio; - }, - enabled: widget.serviceRequest == null ? true : false, - ), - 16.height, - ], - ), - ).expanded, - AppFilledButton( - onPressed: checkPendingRequest ? null : _submit, - loading: checkPendingRequest, - label: (pendingAssetServiceRequest != null && (pendingAssetServiceRequest!.details?.isNotEmpty ?? false)) ? "Submit Duplicate Request" : "Submit New Request", - ), - ], - ), - ).paddingOnly(start: 16, end: 16, bottom: 24, top: 16), - ), - ), - ); - } - - bool checkPendingRequest = false; - - void showPendingRequests() { - Navigator.of(context).push(MaterialPageRoute(builder: (_) => PendingServiceRequestScreen(pendingAssetServiceRequest!))); - } - - void showPendingRequestBottomSheet() async { - bool view = (await showModalBottomSheet( - context: context, - isDismissible: false, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.vertical( - top: Radius.circular(20), - ), - ), - clipBehavior: Clip.antiAliasWithSaveLayer, - builder: (BuildContext context) => PendingRequestBottomSheet(pendingAssetServiceRequest!, _serviceRequest.device!), - )) as bool; - if (view) { - showPendingRequests(); - } - } - - Future checkAssetForPendingServiceRequest(int assetId) async { - checkPendingRequest = true; - setState(() {}); - - pendingAssetServiceRequest = await _serviceRequestsProvider.checkAssetPendingRequest(assetId); - await Future.delayed(const Duration(milliseconds: 250)); - - checkPendingRequest = false; - setState(() {}); - } - - Future _submit() async { - _serviceRequest.requestedThrough = Provider.of(context, listen: false).items.firstWhere((element) => element.value == 3, orElse: null); - _serviceRequest.type = Provider.of(context, listen: false).items.firstWhere((element) => element.value == 1, orElse: null); - - if (_formKey.currentState!.validate() && await _serviceRequest.validateNewRequest(context)) { - _formKey.currentState!.save(); - - // bool canSubmitRequest = await checkAssetForPendingServiceRequest(_serviceRequest.device.id); - // if (!canSubmitRequest) { - // return; - // } - - - _serviceRequest.devicePhotos = attachments.map((item) => ServiceRequestUtils.isLocalUrl(item.name??'') ? "${item.name?.split("/").last}|${base64Encode(File(item.name??'').readAsBytesSync())}" : item.name??'').toList(); - if (_serviceRequest.audio != null) { - if (_isLocalUrl(_serviceRequest.audio!)) { - final File file = File(_serviceRequest.audio!); - _serviceRequest.audio = "${file.path.split("/").last}|${base64Encode(file.readAsBytesSync())}"; - } - } - await _serviceRequestsProvider.createRequest( - context: context, - user: _userProvider.user!, - host: _settingProvider.host!, - serviceRequest: _serviceRequest, - ); - } - } -} +// import 'dart:convert'; +// import 'dart:io'; +// +// import 'package:flutter/cupertino.dart'; +// import 'package:flutter/material.dart'; +// import 'package:provider/provider.dart'; +// import 'package:test_sa/controllers/providers/api/service_requests_provider.dart'; +// import 'package:test_sa/controllers/providers/api/user_provider.dart'; +// import 'package:test_sa/controllers/providers/settings/setting_provider.dart'; +// import 'package:test_sa/extensions/context_extension.dart'; +// import 'package:test_sa/extensions/int_extensions.dart'; +// import 'package:test_sa/extensions/widget_extensions.dart'; +// import 'package:test_sa/models/generic_attachment_model.dart'; +// import 'package:test_sa/models/service_request/pending_service_request_model.dart'; +// import 'package:test_sa/models/service_request/service_request.dart'; +// import 'package:test_sa/modules/cm_module/utilities/service_request_utils.dart'; +// import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; +// import 'package:test_sa/providers/service_request_providers/equipment_status_provider.dart'; +// import 'package:test_sa/providers/service_request_providers/requested_through_provider.dart'; +// import 'package:test_sa/views/pages/user/requests/pending_requests_screen.dart'; +// import 'package:test_sa/views/widgets/bottom_sheets/pending_request_bottom_sheet.dart'; +// import 'package:test_sa/views/widgets/equipment/asset_picker.dart'; +// import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; +// import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; +// import 'package:test_sa/views/widgets/sound/TextSpeechRecordWidget.dart'; +// +// import '../../../../new_views/app_style/app_color.dart'; +// import '../../../../new_views/common_widgets/default_app_bar.dart'; +// import '../../../../providers/service_request_providers/priority_provider.dart'; +// import '../../../../providers/service_request_providers/type_of_request_provider.dart'; +// +// class CreateServiceRequestPage extends StatefulWidget { +// static const String id = "/create-request"; +// final ServiceRequest? serviceRequest; +// +// const CreateServiceRequestPage({this.serviceRequest, Key? key}) : super(key: key); +// +// @override +// CreateServiceRequestPageState createState() => CreateServiceRequestPageState(); +// } +// +// class CreateServiceRequestPageState extends State { +// late TextEditingController _commentController; +// +// late double _height; +// late UserProvider _userProvider; +// late SettingProvider _settingProvider; +// late ServiceRequestsProvider _serviceRequestsProvider; +// late ServiceRequest _serviceRequest; +// final List attachments = []; +// final bool _isLoading = false; +// bool _showDatePicker = false; +// final GlobalKey _formKey = GlobalKey(); +// final GlobalKey _scaffoldKey = GlobalKey(); +// DateTime? _dateTime; +// +// bool isFirstActionSubmitted = false; +// +// @override +// void initState() { +// _commentController = TextEditingController(); +// if (widget.serviceRequest != null) { +// _serviceRequest = widget.serviceRequest!; +// attachments.addAll(_serviceRequest.devicePhotos!.map((e) => GenericAttachmentModel(name: e)).toList()); +// _showDatePicker = _serviceRequest.firstAction != null && _serviceRequest.firstAction?.name == "Need a visit"; +// if (_showDatePicker && _serviceRequest.visitDate != null) { +// _dateTime = DateTime.tryParse(_serviceRequest.visitDate!); +// } +// } else { +// _serviceRequest = ServiceRequest(); +// } +// isFirstActionSubmitted = _serviceRequest.firstAction != null; +// super.initState(); +// } +// +// // +// // getServiceRequestById(String id) async { +// // try { +// // ServiceRequest request = await _serviceRequestsProvider.getServiceRequestObjectById(requestId: id) ?? ""; +// // _serviceRequest = request; +// // _device = _serviceRequest.device; +// // attachments.addAll(_serviceRequest.devicePhotos.map((e) { +// // return File(e); +// // }).toList()); +// // _showDatePicker = _serviceRequest.firstAction != null && _serviceRequest.firstAction.name == "Need a visit"; +// // if (_showDatePicker && _serviceRequest.visitDate != null) { +// // _dateTime = DateTime.tryParse(_serviceRequest.visitDate); +// // } +// // _isLoading = false; +// // } catch (ex) { +// // _isLoading = false; +// // } +// // setState(() {}); +// // } +// +// @override +// void dispose() { +// _commentController.dispose(); +// super.dispose(); +// } +// +// bool _isLocalUrl(String url) { +// if (url.isEmpty != false) return false; +// return url.startsWith("/") || url.startsWith("file://") || url.substring(1).startsWith(':\\'); +// } +// +// // bool priority; +// +// void getData() { +// Provider.of(context).getDate(); +// Provider.of(context).getDate(); +// Provider.of(context).getDate(); +// Provider.of(context).getDate(); +// } +// +// PendingAssetServiceRequest? pendingAssetServiceRequest; +// +// @override +// Widget build(BuildContext context) { +// _height = MediaQuery.of(context).size.height; +// _userProvider = Provider.of(context); +// +// _serviceRequestsProvider = Provider.of(context); +// +// return Scaffold( +// key: _scaffoldKey, +// appBar: DefaultAppBar(title: context.translation.newServiceRequest), +// body: SafeArea( +// child: LoadingManager( +// isLoading: _isLoading, +// isFailedLoading: false, +// stateCode: 200, +// onRefresh: () async {}, +// child: Form( +// key: _formKey, +// child: Column( +// children: [ +// SingleChildScrollView( +// child: Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// mainAxisSize: MainAxisSize.min, +// children: [ +// AssetPicker( +// device: _serviceRequest.device, +// showLoading: checkPendingRequest, +// onPick: (asset) async { +// pendingAssetServiceRequest = null; +// _serviceRequest.device = asset; +// await checkAssetForPendingServiceRequest(asset.id!.toInt()); +// +// if (pendingAssetServiceRequest != null && pendingAssetServiceRequest!.details!.isNotEmpty) { +// showPendingRequestBottomSheet(); +// } +// }, +// ), +// if (pendingAssetServiceRequest != null && pendingAssetServiceRequest!.details!.isNotEmpty) ...[ +// 8.height, +// Row( +// children: [ +// const Icon(Icons.warning, color: Color(0xffEE404C), size: 14), +// 8.width, +// Text( +// "This asset already have ${pendingAssetServiceRequest!.details!.length} request pending", +// style: const TextStyle(fontSize: 12, fontWeight: FontWeight.w500, color: Color(0xff7D859A), decoration: TextDecoration.underline), +// ).expanded, +// ], +// ).onPress(() { +// showPendingRequests(); +// }), +// ], +// 16.height, +// Row( +// mainAxisAlignment: MainAxisAlignment.spaceBetween, +// children: [ +// Text(context.translation.priority, style: Theme.of(context).textTheme.bodyLarge), +// Consumer(builder: (cxt, snapshot, _) { +// _serviceRequest.priority ??= snapshot.items.firstWhere((element) => element.value == 0, orElse: null); +// +// return Transform.scale( +// scale: 0.8, +// child: CupertinoSwitch( +// thumbColor: _serviceRequest.priority?.value != 0 ? const Color(0xffF63939) : Colors.blueGrey.withOpacity(.5), +// activeColor: AppColor.blueStatus(context).withOpacity(.25), +// value: _serviceRequest.priority?.value != 0, +// onChanged: (state) { +// if (state) { +// _serviceRequest.priority = snapshot.items.firstWhere((element) => element.value == 1, orElse: null); +// } else { +// _serviceRequest.priority = snapshot.items.firstWhere((element) => element.value == 0, orElse: null); +// } +// setState(() {}); +// }).toShimmer(isShow: snapshot.loading,context: context), +// ); +// }), +// ], +// ), +// 16.height, +// Consumer(builder: (cxt, snapshot, _) { +// try { +// _serviceRequest.defectType ??= snapshot.items.first; +// } catch (ex) { +// print("snapshot.items:${snapshot.items.length}"); +// } +// +// return Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// mainAxisSize: MainAxisSize.min, +// children: [ +// Text(context.translation.equipmentStatus, style: Theme.of(context).textTheme.bodyLarge), +// 8.height, +// Wrap( +// runSpacing: 8, +// spacing: 8, +// children: [ +// for (var element in snapshot.items) +// Row( +// mainAxisSize: MainAxisSize.min, +// children: [ +// SizedBox( +// width: 24, +// height: 24, +// child: Radio( +// value: element, +// activeColor: Colors.red, +// fillColor: WidgetStateColor.resolveWith((states) { +// if (states.contains(WidgetState.selected)) return const Color(0xff3DA5E5); +// return const Color(0xffE0E0E0); +// }), +// groupValue: _serviceRequest.defectType, +// onChanged: (state) { +// setState(() { +// _serviceRequest.defectType = element; +// }); +// }), +// ), +// 8.width, +// Text(element.name!, style: Theme.of(context).textTheme.bodySmall), +// ], +// ) +// ], +// ).toShimmer(isShow: snapshot.loading,context: context), +// ], +// ); +// }), +// 16.height, +// AttachmentPicker(label: context.translation.attachImage, attachment: attachments, showAsGrid: true), +// ], +// ).toShadowContainer(context), +// +// // SingleItemDropDownMenu( +// // context: context, +// // title: context.translation.priority, +// // initialValue: _serviceRequest?.priority, +// // onSelect: (value) { +// // _serviceRequest.priority = value; +// // }, +// // ), +// // 8.height, +// // SingleItemDropDownMenu( +// // context: context, +// // title: context.translation.equipmentStatus, +// // initialValue: _serviceRequest?.defectType, +// // onSelect: (value) { +// // _serviceRequest.defectType = value; +// // }, +// // ), +// +// // Consumer(builder: (context, snapshot, _) { +// // return SingleItemDropDownMenu( +// // context: context, +// // enabled: false, +// // title: context.translation.source, +// // initialValue: snapshot.items?.firstWhere((element) => element.value == 3, orElse: null), +// // ); +// // }), +// // 8.height, +// // Consumer(builder: (context, snapshot, _) { +// // return SingleItemDropDownMenu( +// // context: context, +// // title: context.translation.requestType, +// // enabled: false, +// // initialValue: snapshot.items?.firstWhere((element) => element.value == 1, orElse: null), +// // // onSelect: (value) { +// // // _serviceRequest.type = value; +// // // }, +// // ); +// // }), +// +// // Align( +// // alignment: AlignmentDirectional.centerStart, +// // child: context.translation.callComments.heading5(context), +// // ), +// 8.height, +// // SpeechToTextButton( +// // controller: _commentController, +// // ), +// // 8.height, +// // AppTextFormField( +// // controller: _commentController, +// // labelText: context.translation.problemDesc, +// // suffixIcon: "warning".toSvgAsset(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20, width: 24).paddingOnly(end: 16), +// // initialValue: _serviceRequest.callComments, +// // onSaved: (text) { +// // _serviceRequest.callComments = text; +// // }, +// // ), +// // 8.height, +// // RecordSound( +// // onRecord: (audio) { +// // _serviceRequest.audio = audio; +// // }, +// // enabled: widget.serviceRequest == null ? true : false, +// // ), +// 8.height, +// TextSpeechRecordWidget( +// initialMessage: _serviceRequest.callComments!, +// onMessageChange: (message) { +// _serviceRequest.callComments = message; +// }, +// onRecord: (audio) { +// _serviceRequest.audio = audio; +// }, +// enabled: widget.serviceRequest == null ? true : false, +// ), +// 16.height, +// ], +// ), +// ).expanded, +// AppFilledButton( +// onPressed: checkPendingRequest ? null : _submit, +// loading: checkPendingRequest, +// label: (pendingAssetServiceRequest != null && (pendingAssetServiceRequest!.details?.isNotEmpty ?? false)) ? "Submit Duplicate Request" : "Submit New Request", +// ), +// ], +// ), +// ).paddingOnly(start: 16, end: 16, bottom: 24, top: 16), +// ), +// ), +// ); +// } +// +// bool checkPendingRequest = false; +// +// void showPendingRequests() { +// Navigator.of(context).push(MaterialPageRoute(builder: (_) => PendingServiceRequestScreen(pendingAssetServiceRequest!))); +// } +// +// void showPendingRequestBottomSheet() async { +// bool view = (await showModalBottomSheet( +// context: context, +// isDismissible: false, +// shape: const RoundedRectangleBorder( +// borderRadius: BorderRadius.vertical( +// top: Radius.circular(20), +// ), +// ), +// clipBehavior: Clip.antiAliasWithSaveLayer, +// builder: (BuildContext context) => PendingRequestBottomSheet(pendingAssetServiceRequest!, _serviceRequest.device!), +// )) as bool; +// if (view) { +// showPendingRequests(); +// } +// } +// +// Future checkAssetForPendingServiceRequest(int assetId) async { +// checkPendingRequest = true; +// setState(() {}); +// +// pendingAssetServiceRequest = await _serviceRequestsProvider.checkAssetPendingRequest(assetId); +// await Future.delayed(const Duration(milliseconds: 250)); +// +// checkPendingRequest = false; +// setState(() {}); +// } +// +// Future _submit() async { +// _serviceRequest.requestedThrough = Provider.of(context, listen: false).items.firstWhere((element) => element.value == 3, orElse: null); +// _serviceRequest.type = Provider.of(context, listen: false).items.firstWhere((element) => element.value == 1, orElse: null); +// +// if (_formKey.currentState!.validate() && await _serviceRequest.validateNewRequest(context)) { +// _formKey.currentState!.save(); +// +// // bool canSubmitRequest = await checkAssetForPendingServiceRequest(_serviceRequest.device.id); +// // if (!canSubmitRequest) { +// // return; +// // } +// +// +// _serviceRequest.devicePhotos = attachments.map((item) => ServiceRequestUtils.isLocalUrl(item.name??'') ? "${item.name?.split("/").last}|${base64Encode(File(item.name??'').readAsBytesSync())}" : item.name??'').toList(); +// if (_serviceRequest.audio != null) { +// if (_isLocalUrl(_serviceRequest.audio!)) { +// final File file = File(_serviceRequest.audio!); +// _serviceRequest.audio = "${file.path.split("/").last}|${base64Encode(file.readAsBytesSync())}"; +// } +// } +// await _serviceRequestsProvider.createRequest( +// context: context, +// user: _userProvider.user!, +// host: _settingProvider.host!, +// serviceRequest: _serviceRequest, +// ); +// } +// } +// } diff --git a/lib/views/widgets/images/multi_image_picker.dart b/lib/views/widgets/images/multi_image_picker.dart index 18dce2a5..e7fb963a 100644 --- a/lib/views/widgets/images/multi_image_picker.dart +++ b/lib/views/widgets/images/multi_image_picker.dart @@ -14,229 +14,279 @@ import 'package:test_sa/new_views/app_style/app_color.dart'; import '../../../new_views/common_widgets/app_dashed_button.dart'; import 'multi_image_picker_item.dart'; -class MultiFilesPicker extends StatefulWidget { - final String label; - final bool error; - final List files; - final List attachment; - - final bool enabled, onlyImages; - double? buttonHeight; - Widget? buttonIcon; - Color? buttonColor; - final VoidCallback? onChange; - final bool showAsGrid; - - MultiFilesPicker( - {Key? key, - this.files = const [], - this.attachment = const [], - required this.label, - this.error = false, - this.buttonHeight, - this.buttonIcon, - this.enabled = true, - this.onlyImages = false, - this.onChange, - this.showAsGrid = false, - this.buttonColor}) - : super(key: key); - - @override - State createState() => _MultiFilesPickerState(); -} - -class _MultiFilesPickerState extends State { - @override - Widget build(BuildContext context) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (widget.enabled) ...[ - AppDashedButton( - title: widget.label, - height: widget.buttonHeight, - buttonColor: widget.buttonColor, - icon: widget.buttonIcon, - onPressed: (widget.enabled == false) - ? () {} - : widget.showAsGrid - ? showFileSourceSheet - : onFilePicker), - 16.height, - ], - if (widget.files.isNotEmpty) - Wrap( - spacing: 8.toScreenWidth, - children: List.generate( - widget.files!.length, - (index) { - File image = widget.files![index]; - return MultiFilesPickerItem( - file: image, - enabled: widget.enabled, - onRemoveTap: (image) { - if (!widget.enabled) { - return; - } - widget.files.remove(image); - if (widget.onChange != null) { - widget.onChange!(); - } - setState(() {}); - }, - ); - }, - ), - ), - ], - ); - } - - fromFilePicker() async { - FilePickerResult? result = await FilePicker.platform.pickFiles( - type: FileType.custom, - allowMultiple: true, - allowedExtensions: widget.onlyImages ? ['jpg', 'jpeg', 'png'] : ['jpg', 'jpeg', 'png', 'pdf', 'doc', 'docx', 'xlsx', 'pptx'], - ); - if (result != null) { - for (var path in result.paths) { - widget.files.add(File(path!)); - if (widget.onChange != null) { - widget.onChange!(); - } - } - setState(() {}); - } - } - - void showFileSourceSheet() async { - if (widget.files.length >= 5) { - Fluttertoast.showToast(msg: context.translation.maxImagesNumberIs5); - return; - } - - ImageSource? source = (await showModalBottomSheet( - context: context, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.vertical( - top: Radius.circular(20), - ), - ), - clipBehavior: Clip.antiAliasWithSaveLayer, - builder: (BuildContext context) => Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - "Attach File".heading4(context), - 12.height, - GridView( - padding: const EdgeInsets.all(0), - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3, childAspectRatio: 1, crossAxisSpacing: 12, mainAxisSpacing: 12), - children: [ - gridItem(Icons.camera_enhance_rounded, context.translation.pickFromCamera).onPress(() => Navigator.of(context).pop(ImageSource.camera)), - gridItem(Icons.image_rounded, context.translation.pickFromGallery).onPress(() => Navigator.of(context).pop(ImageSource.gallery)), - gridItem(Icons.file_present_rounded, context.translation.pickFromFiles).onPress(() async { - await fromFilePicker(); - Navigator.pop(context); - }), - ], - ), - 12.height, - ], - ).paddingAll(21), - )) as ImageSource?; - if (source == null) return; - final pickedFile = await ImagePicker().pickImage(source: source, imageQuality: 70, maxWidth: 800, maxHeight: 800); - - if (pickedFile != null) { - File fileImage = File(pickedFile.path); - widget.files.add(fileImage); - if (widget.onChange != null) { - widget.onChange!(); - } - setState(() {}); - } - } - - Widget gridItem(IconData iconData, String title) { - return Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - border: Border.all(color: const Color(0xffF1F1F1), width: 1), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Icon(iconData, color: const Color(0xff7D859A), size: 36), - Text( - title, - style: const TextStyle(fontSize: 12, fontWeight: FontWeight.w500), - ), - ], - ), - ); - } - - Widget gridItemNew(String icon, String label) { - return Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - border: Border.all(color: const Color(0xffF1F1F1), width: 1), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - icon.toSvgAsset(), - Text(label, style: AppTextStyles.bodyText2).custom(color: AppColor.black20), - ], - ), - ); - } - - onFilePicker() async { - if (widget.files.length >= 5) { - Fluttertoast.showToast(msg: context.translation.maxImagesNumberIs5); - return; - } - - ImageSource? source = await context.showBottomSheet( - GridView( - padding: const EdgeInsets.all(0), - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3, childAspectRatio: 1, crossAxisSpacing: 12, mainAxisSpacing: 12), - children: [ - gridItemNew('camera_icon', context.translation.pickFromCamera).onPress(() => Navigator.of(context).pop(ImageSource.camera)), - gridItemNew('gallery_icon', context.translation.pickFromGallery).onPress(() => Navigator.of(context).pop(ImageSource.gallery)), - gridItemNew('file_icon', context.translation.pickFromFiles).onPress(() async { - await fromFilePicker(); - Navigator.pop(context); - }), - ], - ), - title: "Attach File"); - - if (source == null) return; - final pickedFile = await ImagePicker().pickImage(source: source, imageQuality: 70, maxWidth: 800, maxHeight: 800); - if (pickedFile != null) { - File fileImage = File(pickedFile.path); - widget.files.add(fileImage); - if (widget.onChange != null) { - widget.onChange!(); - } - setState(() {}); - } - } -} +// class MultiFilesPicker extends StatefulWidget { +// final String label; +// final bool error; +// final List files; +// final List attachment; +// +// final bool enabled, onlyImages; +// double? buttonHeight; +// Widget? buttonIcon; +// Color? buttonColor; +// final Function(List)? onChange; +// final bool showAsGrid; +// +// MultiFilesPicker( +// {Key? key, +// this.files = const [], +// this.attachment = const [], +// required this.label, +// this.error = false, +// this.buttonHeight, +// this.buttonIcon, +// this.enabled = true, +// this.onlyImages = false, +// this.onChange, +// this.showAsGrid = false, +// this.buttonColor}) +// : super(key: key); +// +// @override +// State createState() => _MultiFilesPickerState(); +// } +// +// class _MultiFilesPickerState extends State { +// @override +// Widget build(BuildContext context) { +// return Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// if (widget.enabled) ...[ +// AppDashedButton( +// title: widget.label, +// height: widget.buttonHeight, +// buttonColor: widget.buttonColor, +// icon: widget.buttonIcon, +// onPressed: (widget.enabled == false) +// ? () {} +// : widget.showAsGrid +// ? showFileSourceSheet +// : onFilePicker), +// 16.height, +// ], +// if (widget.files.isNotEmpty) +// Wrap( +// spacing: 8.toScreenWidth, +// children: List.generate( +// widget.files!.length, +// (index) { +// File image = widget.files![index]; +// return MultiFilesPickerItem( +// file: image, +// enabled: widget.enabled, +// onRemoveTap: (image) { +// if (!widget.enabled) { +// return; +// } +// widget.files.remove(image); +// if (widget.onChange != null) { +// widget.onChange!(widget.files); +// } +// setState(() {}); +// }, +// ); +// }, +// ), +// ), +// ], +// ); +// } +// +// fromFilePicker() async { +// FilePickerResult? result = await FilePicker.platform.pickFiles( +// type: FileType.custom, +// allowMultiple: true, +// allowedExtensions: widget.onlyImages ? ['jpg', 'jpeg', 'png'] : ['jpg', 'jpeg', 'png', 'pdf', 'doc', 'docx', 'xlsx', 'pptx'], +// ); +// if (result != null) { +// for (var path in result.paths) { +// widget.files.add(File(path!)); +// if (widget.onChange != null) { +// widget.onChange!(widget.files); +// } +// } +// setState(() {}); +// } +// } +// +// void showFileSourceSheet() async { +// if (widget.files.length >= 5) { +// Fluttertoast.showToast(msg: context.translation.maxImagesNumberIs5); +// return; +// } +// +// ImageSource? source = (await showModalBottomSheet( +// context: context, +// shape: const RoundedRectangleBorder( +// borderRadius: BorderRadius.vertical( +// top: Radius.circular(20), +// ), +// ), +// clipBehavior: Clip.antiAliasWithSaveLayer, +// builder: (BuildContext context) => Column( +// mainAxisSize: MainAxisSize.min, +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// "Attach File".heading4(context), +// 12.height, +// GridView( +// padding: const EdgeInsets.all(0), +// shrinkWrap: true, +// physics: const NeverScrollableScrollPhysics(), +// gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3, childAspectRatio: 1, crossAxisSpacing: 12, mainAxisSpacing: 12), +// children: [ +// gridItem(Icons.camera_enhance_rounded, context.translation.pickFromCamera).onPress(() => Navigator.of(context).pop(ImageSource.camera)), +// gridItem(Icons.image_rounded, context.translation.pickFromGallery).onPress(() => Navigator.of(context).pop(ImageSource.gallery)), +// gridItem(Icons.file_present_rounded, context.translation.pickFromFiles).onPress(() async { +// await fromFilePicker(); +// Navigator.pop(context); +// }), +// ], +// ), +// 12.height, +// ], +// ).paddingAll(21), +// )) as ImageSource?; +// if (source == null) return; +// final pickedFile = await ImagePicker().pickImage(source: source, imageQuality: 70, maxWidth: 800, maxHeight: 800); +// +// if (pickedFile != null) { +// File fileImage = File(pickedFile.path); +// widget.files.add(fileImage); +// if (widget.onChange != null) { +// widget.onChange!(widget.files); +// } +// setState(() {}); +// } +// } +// +// Widget gridItem(IconData iconData, String title) { +// return Container( +// padding: const EdgeInsets.all(12), +// decoration: BoxDecoration( +// color: Colors.white, +// borderRadius: BorderRadius.circular(12), +// border: Border.all(color: const Color(0xffF1F1F1), width: 1), +// ), +// child: Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// mainAxisAlignment: MainAxisAlignment.spaceBetween, +// children: [ +// Icon(iconData, color: const Color(0xff7D859A), size: 36), +// Text( +// title, +// style: const TextStyle(fontSize: 12, fontWeight: FontWeight.w500), +// ), +// ], +// ), +// ); +// } +// +// onFilePicker() async { +// if (widget.files.length >= 5) { +// Fluttertoast.showToast(msg: context.translation.maxImagesNumberIs5); +// return; +// } +// ImageSource? source = await showModalBottomSheet( +// context: context, +// builder: (BuildContext context) { +// Widget listCard({required String icon, required String label, required VoidCallback onTap}) { +// return GestureDetector( +// onTap: onTap, +// child: Container( +// constraints: BoxConstraints(minWidth: 111.toScreenWidth, minHeight: 111.toScreenHeight), +// padding: EdgeInsets.symmetric(horizontal: 12.toScreenWidth, vertical: 12.toScreenHeight), +// decoration: BoxDecoration(borderRadius: BorderRadius.circular(12), border: Border.all(width: 1, color: AppColor.white70)), +// child: Column( +// mainAxisSize: MainAxisSize.min, +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// icon.toSvgAsset(), +// 24.height, +// label.bodyText2(context).custom(color: AppColor.black20), +// ], +// ), +// ), +// ); +// } +// +// return Container( +// padding: const EdgeInsets.all(16.0), +// child: Row( +// mainAxisAlignment: MainAxisAlignment.spaceBetween, +// children: [ +// listCard( +// icon: 'camera_icon', +// label: '${context.translation.open}\n${context.translation.camera}', +// onTap: () { +// Navigator.of(context).pop(ImageSource.camera); +// }, +// ), +// listCard( +// icon: 'gallery_icon', +// label: '${context.translation.open}\n${context.translation.gallery}', +// onTap: () { +// Navigator.of(context).pop(ImageSource.gallery); +// }, +// ), +// listCard( +// icon: 'file_icon', +// label: '${context.translation.open}\n${context.translation.files}', +// onTap: () async { +// await fromFilePicker(); +// Navigator.pop(context); +// }, +// ), +// ], +// ), +// ); +// }, +// ); +// // ImageSource source = await showDialog( +// // context: context, +// // builder: (dialogContext) => CupertinoAlertDialog( +// // actions: [ +// // TextButton( +// // child: Text(context.translation.pickFromCamera), +// // onPressed: () { +// // Navigator.of(dialogContext).pop(ImageSource.camera); +// // }, +// // ), +// // TextButton( +// // child: Text(context.translation.pickFromGallery), +// // onPressed: () { +// // Navigator.of(dialogContext).pop(ImageSource.gallery); +// // }, +// // ), +// // TextButton( +// // child: Text(context.translation.pickFromFiles), +// // onPressed: () async { +// // await fromFilePicker(); +// // Navigator.pop(context); +// // }, +// // ), +// // ], +// // ), +// // ); +// if (source == null) return; +// +// final pickedFile = await ImagePicker().pickImage(source: source, imageQuality: 70, maxWidth: 800, maxHeight: 800); +// +// if (pickedFile != null) { +// File fileImage = File(pickedFile.path); +// if (fileImage != null) { +// widget.files.add(fileImage); +// if (widget.onChange != null) { +// widget.onChange!(widget.files); +// } +// setState(() {}); +// } +// } +// +// setState(() {}); +// } +// } class AttachmentModel { int id = 0; @@ -245,7 +295,10 @@ class AttachmentModel { AttachmentModel(this.id, this.file); factory AttachmentModel.fromJson(Map json) { - return AttachmentModel(json['id'] ?? 0, json['file'] != null ? File(json['file']) : null); + return AttachmentModel( + json['id'] ?? 0, + json['file'] != null ? File(json['file']) : null, + ); } Map toJson() { @@ -339,7 +392,7 @@ class _AttachmentPickerState extends State { ); if (result != null) { for (var path in result.paths) { - widget.attachment.add(GenericAttachmentModel(id: 0, name: File(path!).path)); + widget.attachment.add(GenericAttachmentModel(id: 0,name: File(path!).path)); } if (widget.onChange != null) { widget.onChange!(widget.attachment); @@ -349,10 +402,11 @@ class _AttachmentPickerState extends State { } void showFileSourceSheet() async { - if (widget.attachment.length >= 5) { - Fluttertoast.showToast(msg: context.translation.maxImagesNumberIs5); - return; - } + // if (widget.attachment.length >= 5) { + // Fluttertoast.showToast(msg: context.translation.maxImagesNumberIs5); + // return; + // } + ImageSource source = (await showModalBottomSheet( context: context, shape: const RoundedRectangleBorder( @@ -390,7 +444,7 @@ class _AttachmentPickerState extends State { if (pickedFile != null) { File fileImage = File(pickedFile.path); - widget.attachment.add(GenericAttachmentModel(id: 0, name: fileImage.path)); + widget.attachment.add(GenericAttachmentModel(id: 0,name: fileImage.path)); if (widget.onChange != null) { widget.onChange!(widget.attachment); } @@ -421,10 +475,11 @@ class _AttachmentPickerState extends State { } onFilePicker() async { - if (widget.attachment.length >= 5) { - Fluttertoast.showToast(msg: context.translation.maxImagesNumberIs5); - return; - } + //TODO removed on request by Backend as they don't have anyissue with large number of files + // if (widget.attachment.length >= 5) { + // Fluttertoast.showToast(msg: context.translation.maxImagesNumberIs5); + // return; + // } ImageSource? source = await showModalBottomSheet( context: context, builder: (BuildContext context) { @@ -480,7 +535,32 @@ class _AttachmentPickerState extends State { ); }, ); - + // ImageSource source = await showDialog( + // context: context, + // builder: (dialogContext) => CupertinoAlertDialog( + // actions: [ + // TextButton( + // child: Text(context.translation.pickFromCamera), + // onPressed: () { + // Navigator.of(dialogContext).pop(ImageSource.camera); + // }, + // ), + // TextButton( + // child: Text(context.translation.pickFromGallery), + // onPressed: () { + // Navigator.of(dialogContext).pop(ImageSource.gallery); + // }, + // ), + // TextButton( + // child: Text(context.translation.pickFromFiles), + // onPressed: () async { + // await fromFilePicker(); + // Navigator.pop(context); + // }, + // ), + // ], + // ), + // ); if (source == null) return; final pickedFile = await ImagePicker().pickImage(source: source, imageQuality: 70, maxWidth: 800, maxHeight: 800); diff --git a/pubspec.yaml b/pubspec.yaml index a562ad1d..b3a11d0c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.3.6+25 +version: 1.3.8+27 environment: sdk: ">=3.5.0 <4.0.0"