Merge remote-tracking branch 'origin/main_design2.0' into main_design2.0

# Conflicts:
#	pubspec.yaml
main_design2.0
nextwo 2 years ago
commit 2604d8b253

@ -0,0 +1,3 @@
<svg width="24" height="21" viewBox="0 0 24 21" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M22.5707 8.52108L3.20688 0.761111C2.39112 0.434161 1.46951 0.577989 0.801771 1.13628C0.134036 1.69465 -0.145246 2.55499 0.0730043 3.38151L1.79655 9.90929H10.2353C10.6236 9.90929 10.9385 10.2133 10.9385 10.5884C10.9385 10.9634 10.6236 11.2675 10.2353 11.2675H1.79655L0.0730043 17.7953C-0.145246 18.6218 0.133989 19.4822 0.801771 20.0405C1.47087 20.5999 2.39257 20.742 3.20693 20.4157L22.5707 12.6557C23.4524 12.3024 24 11.5103 24 10.5884C24 9.66654 23.4524 8.87434 22.5707 8.52108Z" fill="#163A51"/>
</svg>

After

Width:  |  Height:  |  Size: 615 B

@ -0,0 +1,8 @@
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="0.5" y="0.5" width="47" height="47" rx="23.5" fill="white" stroke="#EAF1F4"/>
<g opacity="0.5">
<path d="M26.5703 25.9869C26.3589 26.1982 26.0976 26.3596 25.8145 26.4541L23.0799 27.3655C22.8826 27.4314 22.6768 27.4648 22.4685 27.4648C21.952 27.4648 21.4664 27.2637 21.1012 26.8984C20.58 26.3771 20.4011 25.6189 20.6342 24.9197L21.5457 22.1852C21.64 21.902 21.8016 21.6406 22.0128 21.4294L27.919 15.5232H16.3633C15.0602 15.5232 14 16.5834 14 17.8865V31.6365C14 32.9396 15.0602 33.9997 16.3633 33.9997H30.1133C31.4164 33.9997 32.4766 32.9396 32.4766 31.6365V20.0807L26.5703 25.9869Z" fill="#163A51"/>
<path d="M22.9243 22.341C22.8535 22.4118 22.8002 22.498 22.7686 22.593L21.8571 25.3275C21.7799 25.5591 21.8401 25.8144 22.0128 25.987C22.1854 26.1597 22.4407 26.22 22.6723 26.1427L25.4069 25.2312C25.5018 25.1996 25.588 25.1463 25.6588 25.0755L33.7104 17.0239L30.9759 14.2894L22.9243 22.341Z" fill="#163A51"/>
<path d="M34.47 12.3144C34.0505 11.8949 33.3704 11.8949 32.9509 12.3144L31.8875 13.3778L34.622 16.1123L35.6854 15.0489C36.1049 14.6294 36.1049 13.9493 35.6854 13.5298L34.47 12.3144Z" fill="#163A51"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

@ -0,0 +1,4 @@
<svg width="16" height="24" viewBox="0 0 16 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6.32812 12.6562H2.86313C3.20484 15.0384 5.25891 16.875 7.73438 16.875C10.2098 16.875 12.2639 15.0384 12.6056 12.6562H9.14062V11.25H12.6562V9.14062H9.14062V7.73438H12.6562V5.625H9.14062V4.21875H12.6056C12.2639 1.83656 10.2098 0 7.73438 0C5.25891 0 3.20484 1.83656 2.86313 4.21875H6.32812V5.625H2.8125V7.73438H6.32812V9.14062H2.8125V11.25H6.32812V12.6562Z" fill="#767676"/>
<path d="M8.4375 19.6561C12.3741 19.2994 15.4688 15.9806 15.4688 11.9531C15.2906 11.9531 14.4632 11.9531 14.0625 11.9531C14.0625 15.446 11.2205 18.2812 7.73438 18.2812C4.245 18.2812 1.40625 15.4425 1.40625 11.9531H0C0 15.9806 3.09469 19.2994 7.03125 19.6561V22.5938H2.10938V24H13.3594V22.5938H8.4375V19.6561Z" fill="#767676"/>
</svg>

After

Width:  |  Height:  |  Size: 812 B

@ -0,0 +1,3 @@
<svg width="24" height="20" viewBox="0 0 24 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M23.3186 17.8143L12.9972 0.69713C12.7363 0.264525 12.268 0 11.7628 0C11.2576 0 10.7892 0.264479 10.5284 0.69713L0.207042 17.8143C-0.0613895 18.2595 -0.0693386 18.8148 0.186319 19.2674C0.441976 19.7201 0.921541 20 1.4414 20H22.0842C22.604 20 23.0836 19.72 23.3393 19.2674C23.5949 18.8147 23.587 18.2595 23.3186 17.8143ZM11.7705 5.92101C12.3633 5.92101 12.8648 6.25543 12.8648 6.84816C12.8648 8.65683 12.6521 11.256 12.6521 13.0646C12.6521 13.5358 12.1353 13.7334 11.7705 13.7334C11.2842 13.7334 10.8738 13.5358 10.8738 13.0646C10.8738 11.256 10.661 8.65683 10.661 6.84816C10.661 6.25543 11.1473 5.92101 11.7705 5.92101ZM11.7857 17.1228C11.117 17.1228 10.6153 16.5757 10.6153 15.9525C10.6153 15.3142 11.1169 14.7822 11.7857 14.7822C12.4088 14.7822 12.9408 15.3142 12.9408 15.9525C12.9408 16.5757 12.4088 17.1228 11.7857 17.1228Z" fill="#767676"/>
</svg>

After

Width:  |  Height:  |  Size: 957 B

File diff suppressed because one or more lines are too long

@ -0,0 +1,2 @@
assets:
- assets/images/

@ -102,7 +102,7 @@ class URLs {
// employee
static get getEmployees => "$_baseUrl/Lookups/GetLookup?lookupEnum=33"; // get
static get getEngineers => "$_baseUrl/Account/GetUserByRoleValue?value=R-6"; // get
static get getEngineers => "$_baseUrl/Account/GetUserByRoleValue?value=R-6"; // get /// TODO : we also need to send the asset id
// pentry
static get getPentry => "$_baseUrl/return/pentry/details"; // get

@ -8,6 +8,7 @@ import 'package:test_sa/controllers/api_routes/urls.dart';
import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/models/user.dart';
@Deprecated("Use the one inside lib/providers folder")
class ServiceRequestPriorityProvider extends ChangeNotifier {
//reset provider data
void reset() {

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:lottie/lottie.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart';
@ -46,7 +47,6 @@ abstract class AppTextStyles {
static final TextStyle heading1 = TextStyle(
fontSize: 54.toScreenWidth,
fontWeight: FontWeight.w500,
height: 0.89,
letterSpacing: -0.81,
fontStyle: FontStyle.normal,
decoration: TextDecoration.none,
@ -55,7 +55,6 @@ abstract class AppTextStyles {
static final TextStyle heading2 = TextStyle(
fontSize: 28.toScreenWidth,
fontWeight: FontWeight.w700,
height: 1.5,
letterSpacing: -0.56,
fontStyle: FontStyle.normal,
decoration: TextDecoration.none,
@ -64,7 +63,6 @@ abstract class AppTextStyles {
static final TextStyle heading3 = TextStyle(
fontSize: 24.toScreenWidth,
fontWeight: FontWeight.w700,
height: 1.5,
letterSpacing: -0.12,
fontStyle: FontStyle.normal,
decoration: TextDecoration.none,
@ -73,7 +71,6 @@ abstract class AppTextStyles {
static final TextStyle heading4 = TextStyle(
fontSize: 21.toScreenWidth,
fontWeight: FontWeight.w500,
height: 1.48,
fontStyle: FontStyle.normal,
decoration: TextDecoration.none,
);
@ -81,7 +78,6 @@ abstract class AppTextStyles {
static final TextStyle heading5 = TextStyle(
fontSize: 19.toScreenWidth,
fontWeight: FontWeight.w500,
//height: 1.47,
fontStyle: FontStyle.normal,
decoration: TextDecoration.none,
);
@ -89,7 +85,6 @@ abstract class AppTextStyles {
static final TextStyle heading6 = TextStyle(
fontSize: 16.toScreenWidth,
fontWeight: FontWeight.w500,
height: 1.5,
fontStyle: FontStyle.normal,
decoration: TextDecoration.none,
);
@ -97,7 +92,6 @@ abstract class AppTextStyles {
static final TextStyle bodyText = TextStyle(
fontSize: 14.toScreenWidth,
fontWeight: FontWeight.w500,
height: 1.5,
fontStyle: FontStyle.normal,
decoration: TextDecoration.none,
);
@ -105,7 +99,6 @@ abstract class AppTextStyles {
static final TextStyle bodyText2 = TextStyle(
fontSize: 12.toScreenWidth,
fontWeight: FontWeight.w500,
height: 1.5,
fontStyle: FontStyle.normal,
decoration: TextDecoration.none,
);
@ -113,7 +106,6 @@ abstract class AppTextStyles {
static final TextStyle tinyFont = TextStyle(
fontSize: 11.toScreenWidth,
fontWeight: FontWeight.w500,
height: 1.45,
fontStyle: FontStyle.normal,
decoration: TextDecoration.none,
);
@ -121,7 +113,6 @@ abstract class AppTextStyles {
static final TextStyle overline = TextStyle(
fontSize: 9.toScreenWidth,
fontWeight: FontWeight.w500,
height: 1.56,
letterSpacing: 0.05,
fontStyle: FontStyle.normal,
decoration: TextDecoration.none,
@ -154,4 +145,11 @@ extension FilesExtension on String {
BoxFit fit = BoxFit.contain,
}) =>
Image.asset("assets/images/$this.png", width: width?.toScreenWidth, height: height?.toScreenHeight, color: color, fit: fit);
LottieBuilder toLottieAsset({
int width,
int height,
BoxFit fit = BoxFit.contain,
bool repeat = true,
}) =>
Lottie.asset("assets/lottie/$this.json", width: width?.toScreenWidth, height: height?.toScreenHeight, fit: fit, repeat: repeat);
}

@ -1,6 +1,6 @@
{
"serverErrorMessage": "الخدمة غير متاحة حاليا",
"failedRequestMessage": "الفشل في إكمال الطلب",
"failedRequestMessage": "فشل إكمال الطلب",
"successfulRequestMessage": "تم إكمال الطلب بنجاح",
"requestLockMessage": "انتظر حتى إكمال الطلب",
"cancel": "إلغاء",
@ -251,5 +251,12 @@
"model" : "الطراز",
"serialNumber" : "الرقم التسلسلي",
"device" : "الجهاز",
"pickAsset" : "إختر جهاز"
"pickAsset" : "إختر جهاز",
"firstAction" : "First Action",
"priority" : "الأولوية",
"equipmentStatus" : "حالة المعدات",
"attachImage" : "إرفاق صورة",
"callComments" : "تعليقات الطلب",
"comments" : "تعليقات",
"recordVoice" : "تسجيل صوت"
}

@ -251,5 +251,17 @@
"model" : "Model",
"serialNumber" : "Serial Number",
"device" : "Device",
"pickAsset" : "Pick Asset"
"pickAsset" : "Pick Asset",
"firstAction" : "First Action",
"workOrder" : "Work Orders",
"viewWorkOrder" : "View All Work Order",
"createWorkOrder" : "Create Work Order",
"viewWorkOrder" : "View All Work Order",
"serviceDetails": "Service Details",
"priority" : "Priority",
"equipmentStatus" : "Equipment Status",
"attachImage" : "Attach Image",
"callComments" : "Call Comments",
"comments": "Comments",
"recordVoice" : "Record Voice"
}

@ -3,10 +3,9 @@ import 'dart:io';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:localization/localization.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/localization/localization.dart';
import 'package:test_sa/controllers/providers/api/asset_transfer_provider.dart';
import 'package:test_sa/controllers/providers/api/departments_provider.dart';
import 'package:test_sa/controllers/providers/api/devices_provider.dart';
@ -55,6 +54,8 @@ import 'package:test_sa/providers/gas_request_providers/cylinder_type_provider.d
import 'package:test_sa/providers/gas_request_providers/gas_types_provider.dart';
import 'package:test_sa/providers/gas_request_providers/site_provider.dart';
import 'package:test_sa/providers/loading_list_notifier.dart';
import 'package:test_sa/providers/service_request_providers/equipment_status_provider.dart';
import 'package:test_sa/providers/service_request_providers/priority_provider.dart';
import 'package:test_sa/views/pages/device_transfer/request_device_transfer.dart';
import 'package:test_sa/views/pages/device_transfer/track_device_transfer.dart';
import 'package:test_sa/views/pages/sub_workorder/create_sub_workorder_page.dart';
@ -67,6 +68,7 @@ import 'package:test_sa/views/pages/user/report_issues_page.dart';
import 'package:test_sa/views/pages/user/requests/create_request.dart';
import 'package:test_sa/views/pages/user/requests/future_request_service_details.dart';
import 'package:test_sa/views/pages/user/requests/requests_page.dart';
import 'package:test_sa/views/pages/user/requests/work_order/work_orders_list_page.dart';
import 'package:test_sa/views/pages/user/visits/preventive_maintenance_visits_page.dart';
import 'package:test_sa/views/pages/user/visits/regular_visits_page.dart';
import 'package:test_sa/views/widgets/departments/single_department_picker.dart';
@ -77,8 +79,6 @@ import 'controllers/providers/api/user_provider.dart';
import 'controllers/providers/settings/setting_provider.dart';
import 'new_views/pages/new_gas_refill_request_page.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
if (Platform.isIOS) {
@ -158,6 +158,8 @@ class MyApp extends StatelessWidget {
ChangeNotifierProvider(create: (_) => ServiceReportMaintenanceSituationProvider()),
ChangeNotifierProvider(create: (_) => ServiceReportUsersProvider()),
ChangeNotifierProvider(create: (_) => ServiceReportAssistantsEmployeeProvider()),
ChangeNotifierProvider(create: (_) => PriorityProvider()),
ChangeNotifierProvider(create: (_) => EquipmentStatusProvider()),
],
child: GestureDetector(
onTap: () {
@ -197,6 +199,7 @@ class MyApp extends StatelessWidget {
TrackDeviceTransferPage.id: (_) => const TrackDeviceTransferPage(),
SearchSubWorkOrderPage.id: (_) => const SearchSubWorkOrderPage(),
CreateSubWorkOrderPage.id: (_) => const CreateSubWorkOrderPage(),
WorkOrderListPage.id: (_) => WorkOrderListPage(),
},
),
),

@ -1,4 +1,7 @@
import 'package:flutter/src/widgets/framework.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:test_sa/controllers/api_routes/urls.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/models/device/device.dart';
import 'package:test_sa/models/fault_description.dart';
import 'package:test_sa/models/lookup.dart';
@ -138,4 +141,18 @@ class ServiceRequest {
priority: Lookup.fromJson(parsedJson['priority']),
);
}
Future<bool> validateNewRequest(BuildContext context) async {
if (device == null) {
await Fluttertoast.showToast(msg: "${context.translation.youHaveToSelect} ${context.translation.device}");
return false;
} else if (priority == null) {
await Fluttertoast.showToast(msg: "${context.translation.youHaveToSelect} ${context.translation.priority}");
return false;
} else if (defectType == null) {
await Fluttertoast.showToast(msg: "${context.translation.youHaveToSelect} ${context.translation.equipmentStatus}");
return false;
}
return true;
}
}

@ -68,7 +68,7 @@ class AppTextStyle {
decoration: TextDecoration.none,
);
static final TextStyle tiny = TextStyle(
height: 1.5,
//height: 1.5,
fontSize: 11.toScreenWidth,
letterSpacing: 0,
fontFamily: fontFamily,

@ -0,0 +1,33 @@
import 'package:dotted_border/dotted_border.dart';
import 'package:flutter/material.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import '../app_style/app_color.dart';
class AppDashedButton extends StatelessWidget {
final String title;
final VoidCallback onPressed;
const AppDashedButton({@required this.title, @required this.onPressed, Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
padding: EdgeInsets.symmetric(horizontal: 2.toScreenWidth),
decoration: BoxDecoration(color: Theme.of(context).cardColor, borderRadius: BorderRadius.circular(10)),
child: DottedBorder(
strokeWidth: 2,
padding: EdgeInsets.symmetric(vertical: 16.toScreenHeight, horizontal: 16.toScreenWidth),
color: context.isDark ? AppColor.primary40 : AppColor.primary60,
dashPattern: const [4, 3],
radius: const Radius.circular(10),
borderType: BorderType.RRect,
child: title.heading6(context).custom(color: context.isDark ? AppColor.primary40 : AppColor.primary60).center,
),
).onPress(onPressed);
}
}

@ -0,0 +1,36 @@
import 'dart:convert';
import 'package:http/http.dart';
import 'package:test_sa/providers/loading_list_notifier.dart';
import '../../controllers/api_routes/api_manager.dart';
import '../../controllers/api_routes/urls.dart';
import '../../models/lookup.dart';
class EquipmentStatusProvider extends LoadingListNotifier<Lookup> {
@override
Future getDate() async {
if (loading == true) return -2;
loading = true;
notifyListeners();
loading = true;
notifyListeners();
try {
Response response = await ApiManager.instance.get(URLs.equipmentStatus);
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received
List categoriesListJson = json.decode(response.body)["data"];
items = categoriesListJson.map((item) => Lookup.fromJson(item)).toList();
}
loading = false;
notifyListeners();
return response.statusCode;
} catch (error) {
loading = false;
stateCode = -1;
notifyListeners();
return -1;
}
}
}

@ -0,0 +1,36 @@
import 'dart:convert';
import 'package:http/http.dart';
import 'package:test_sa/providers/loading_list_notifier.dart';
import '../../controllers/api_routes/api_manager.dart';
import '../../controllers/api_routes/urls.dart';
import '../../models/lookup.dart';
class PriorityProvider extends LoadingListNotifier<Lookup> {
@override
Future getDate() async {
if (loading == true) return -2;
loading = true;
notifyListeners();
loading = true;
notifyListeners();
try {
Response response = await ApiManager.instance.get(URLs.getServiceReportPriority);
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received
List categoriesListJson = json.decode(response.body)["data"];
items = categoriesListJson.map((item) => Lookup.fromJson(item)).toList();
}
loading = false;
notifyListeners();
return response.statusCode;
} catch (error) {
loading = false;
stateCode = -1;
notifyListeners();
return -1;
}
}
}

@ -53,12 +53,14 @@ class AColors {
return AColors.statusBlue;
case 2:
return AColors.statusYellowLight;
case 3:
return AColors.statusGreenLight;
case 4:
return AColors.statusRedLight;
case 6:
return AColors.statusGreenLight;
case 5:
return AColors.orange;
return AColors.statusGreenLight;
case 8:
return AColors.statusGreenLight;
case 9:
@ -72,12 +74,14 @@ class AColors {
switch (id) {
case 2:
return AColors.statusYellow;
case 3:
return AColors.white;
case 4:
return AColors.deepRed;
case 6:
return AColors.green;
case 5:
return AColors.orange;
return AColors.white;
case 8:
return AColors.green;
case 9:

@ -1,43 +1,34 @@
import 'dart:convert';
import 'dart:io';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:image_picker/image_picker.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/api_routes/http_status_manger.dart';
import 'package:test_sa/controllers/localization/localization.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/controllers/validator/validator.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/service_request/service_request.dart';
import 'package:test_sa/models/subtitle.dart';
import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
import 'package:test_sa/views/widgets/app_text_form_field.dart';
import 'package:test_sa/views/widgets/date_and_time/time_picker.dart';
import 'package:test_sa/views/widgets/equipment/pick_asset.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/record_sound.dart';
import 'package:test_sa/views/widgets/sound/sound_player.dart';
import 'package:test_sa/views/widgets/speech_to_text/speech_to_text.dart';
import 'package:test_sa/views/widgets/status/service_request/service_request_defect_types_mune.dart';
import 'package:test_sa/views/widgets/status/service_request/service_request_priority_mune.dart';
import 'package:test_sa/views/widgets/status/service_request/service_request_through_mune.dart';
import 'package:test_sa/views/widgets/status/service_request/service_request_types_mune.dart';
import 'package:test_sa/views/widgets/titles/app_sub_title.dart';
import '../../../../controllers/providers/api/status_drop_down/service_reqest/service_request_through_provider.dart';
import '../../../../controllers/providers/api/status_drop_down/service_reqest/service_request_type_provider.dart';
import '../../../../models/device/device.dart';
import '../../../../models/enums/translation_keys.dart';
import '../../../../models/lookup.dart';
import '../../../../new_views/app_style/app_color.dart';
import '../../../../new_views/common_widgets/app_dashed_button.dart';
import '../../../../new_views/common_widgets/app_lazy_loading.dart';
import '../../../../new_views/common_widgets/app_text_form_field.dart';
import '../../../../new_views/common_widgets/default_app_bar.dart';
import '../../../widgets/status/service_request/service_request_first_action.dart';
import '../../../widgets/status/service_request/service_request_loan_availability.dart';
import '../../../../new_views/common_widgets/single_item_drop_down_menu.dart';
import '../../../../providers/service_request_providers/equipment_status_provider.dart';
import '../../../../providers/service_request_providers/priority_provider.dart';
class CreateRequestPage extends StatefulWidget {
static const String id = "/create-request";
@ -50,6 +41,8 @@ class CreateRequestPage extends StatefulWidget {
}
class CreateRequestPageState extends State<CreateRequestPage> {
TextEditingController _commentController;
double _height;
UserProvider _userProvider;
SettingProvider _settingProvider;
@ -58,21 +51,17 @@ class CreateRequestPageState extends State<CreateRequestPage> {
final List<File> _deviceImages = [];
bool _isLoading = false;
bool _showDatePicker = false;
Device _asset;
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
TextEditingController _maintenanceController, _commentController, _reviewCommentController;
DateTime _dateTime;
bool isFirstActionSubmitted = false;
@override
void initState() {
_maintenanceController = TextEditingController();
_commentController = TextEditingController();
if (widget.serviceRequest != null) {
_serviceRequest = widget.serviceRequest;
_asset = _serviceRequest.device;
_deviceImages.addAll(_serviceRequest.devicePhotos.map((e) => File(e)).toList());
_showDatePicker = _serviceRequest.firstAction != null && _serviceRequest.firstAction.name == "Need a visit";
if (_showDatePicker && _serviceRequest.visitDate != null) {
@ -107,7 +96,6 @@ class CreateRequestPageState extends State<CreateRequestPage> {
@override
void dispose() {
_maintenanceController.dispose();
_commentController.dispose();
super.dispose();
}
@ -127,7 +115,7 @@ class CreateRequestPageState extends State<CreateRequestPage> {
return Scaffold(
key: _scaffoldKey,
appBar: DefaultAppBar(title: context.translation.newServiceRequest),
appBar: DefaultAppBar(title: context.translation.newServiceRequest),
body: SafeArea(
child: LoadingManager(
isLoading: _isLoading,
@ -143,235 +131,58 @@ class CreateRequestPageState extends State<CreateRequestPage> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
PickAsset(
device: _asset,
device: _serviceRequest.device,
onPickAsset: (asset) {
_asset = asset;
_serviceRequest.device = asset;
setState(() {});
},
),
const SizedBox(
height: 8,
),
const ASubTitle("Priority"),
const SizedBox(
height: 4,
),
ServiceRequestPriorityMenu(
initialValue: widget.serviceRequest?.priority,
onSelect: (status) {
_serviceRequest.priority = status;
8.height,
SingleItemDropDownMenu<Lookup, PriorityProvider>(
context: context,
title: context.translation.priority,
initialValue: _serviceRequest?.priority,
onSelect: (value) {
_serviceRequest.priority = value;
},
enabled: widget.serviceRequest == null ? true : false,
),
const SizedBox(
height: 8,
),
const ASubTitle("Equipment Status"),
const SizedBox(
height: 4,
),
ServiceRequestDefectTypesMenu(
initialValue: _serviceRequest.defectType,
onSelect: (status) {
_serviceRequest.defectType = status;
8.height,
SingleItemDropDownMenu<Lookup, EquipmentStatusProvider>(
context: context,
title: context.translation.equipmentStatus,
initialValue: _serviceRequest?.defectType,
onSelect: (value) {
_serviceRequest.defectType = value;
},
enabled: widget.serviceRequest == null ? true : false,
),
12.height,
const SizedBox(
height: 8,
8.height,
AppDashedButton(title: _serviceRequest.devicePhotos?.first?.split("/")?.last ?? context.translation.attachImage, onPressed: _attachImage),
16.height,
Align(
alignment: AlignmentDirectional.centerStart,
child: context.translation.callComments.heading5(context),
),
const ASubTitle("Type of Request"),
const SizedBox(
height: 4,
8.height,
AppTextFormField(
controller: _commentController,
labelText: context.translation.comments,
suffixIcon: "warning".toSvgAsset(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20, width: 24).paddingOnly(end: 16),
),
ServiceRequestTypesMenu(
initialValue: _serviceRequest.type,
onSelect: (status) {
_serviceRequest.type = status;
8.height,
RecordSound(
onRecord: (audio) {
_serviceRequest.audio = audio;
},
enabled: false,
withDefaultItem: widget.serviceRequest == null,
),
const SizedBox(
height: 8,
),
const ASubTitle("Through"),
const SizedBox(
height: 4,
),
ServiceRequestedThroughMenu(
initialValue: _serviceRequest.requestedThrough,
enabled: false,
),
if (widget.serviceRequest != null) 12.height,
if (widget.serviceRequest != null) const ASubTitle("First Action"),
const SizedBox(
height: 4,
),
if (widget.serviceRequest != null)
ServiceRequestedFirstAction(
initialValue: _serviceRequest.firstAction,
enabled: !isFirstActionSubmitted,
onSelect: (status) {
_dateTime = null;
_serviceRequest.firstAction = status;
_showDatePicker = _serviceRequest.firstAction != null && _serviceRequest.firstAction.name == "Need a visit";
_serviceRequestsProvider.notifyListeners();
},
),
if (_showDatePicker) 12.height,
if (_showDatePicker)
ADateTimePicker(
date: _dateTime,
enable: !isFirstActionSubmitted,
from: DateTime.now(),
onDateTimePicker: (date) {
_dateTime = date;
setState(() {});
},
),
if (widget.serviceRequest != null) 12.height,
if (widget.serviceRequest != null) const ASubTitle("Loan Availability"),
const SizedBox(
height: 4,
),
if (widget.serviceRequest != null)
ServiceRequestedLoanAvailability(
initialValue: _serviceRequest.loanAvailability,
onSelect: (status) {
_serviceRequest.loanAvailability = status;
},
),
12.height,
if (widget.serviceRequest != null) const ASubTitle("Comments"),
const SizedBox(
height: 4,
),
if (widget.serviceRequest != null)
ATextFormField(
controller: _reviewCommentController,
initialValue: _serviceRequest.reviewComment,
hintText: context.translation.comment,
style: Theme.of(context).textTheme.titleMedium,
textInputType: TextInputType.multiline,
onSaved: (value) {
_serviceRequest.reviewComment = value;
},
enable: widget.serviceRequest != null ? false : true,
),
12.height,
MultiFilesPicker(
label: context.translation.deviceFiles,
files: _deviceImages,
enabled: widget.serviceRequest == null ? true : false,
),
12.height,
SpeechToTextButton(
controller: _maintenanceController,
enabled: widget.serviceRequest == null ? true : false,
),
12.height,
ATextFormField(
controller: _maintenanceController,
initialValue: _serviceRequest.callComments,
hintText: context.translation.maintenanceIssue,
prefixIconData: FontAwesomeIcons.triangleExclamation,
style: Theme.of(context).textTheme.titleLarge,
textInputType: TextInputType.multiline,
validator: (value) => widget.serviceRequest != null || Validator.hasValue(value) ? null : context.translation.maintenanceIssueRequired,
onSaved: (value) {
_serviceRequest.callComments = value;
},
enable: widget.serviceRequest == null ? true : false,
),
12.height,
if (_serviceRequest.audio?.isNotEmpty == true)
ASoundPlayer(
audio: _serviceRequest.audio,
)
else
RecordSound(
onRecord: (audio) {
_serviceRequest.audio = audio;
},
enabled: widget.serviceRequest == null ? true : false,
),
12.height,
if (widget.serviceRequest != null)
ATextFormField(
controller: _commentController,
initialValue: _serviceRequest.comments,
hintText: context.translation.comment,
style: Theme.of(context).textTheme.titleMedium,
textInputType: TextInputType.multiline,
onSaved: (value) {
_serviceRequest.comments = value;
},
),
16.height,
],
),
).expanded,
AppFilledButton(
onPressed: () async {
if (!_formKey.currentState.validate()) return;
if (_asset?.id == null) {
Fluttertoast.showToast(msg: context.translation.pickDevice);
return;
}
if (_serviceRequest.firstAction?.name == "Need a visit" && _dateTime == null) {
Fluttertoast.showToast(msg: "first action is required");
return;
}
if (widget.serviceRequest != null && (_serviceRequest?.engineerId == null || (_serviceRequest?.engineerId?.isEmpty ?? false))) {
await Fluttertoast.showToast(msg: "No Assigned Employee");
return;
}
_formKey.currentState.save();
_serviceRequest.deviceId = _asset?.id;
if (widget.serviceRequest == null) {
_serviceRequest.type = Provider.of<ServiceRequestTypeProvider>(context, listen: false).getDefaultItem();
}
_serviceRequest.requestedThrough = Provider.of<ServiceRequestedThroughProvider>(context, listen: false).getDefaultItem();
_isLoading = true;
setState(() {});
_serviceRequest.devicePhotos = _deviceImages.map((e) => _isLocalUrl(e.path) ? "${e.path.split("/").last}|${base64Encode(e.readAsBytesSync())}" : e.path).toList();
if (_serviceRequest.audio != null) {
if (_isLocalUrl(_serviceRequest.audio)) {
final File file = File(_serviceRequest.audio);
_serviceRequest.audio = "${file.path.split("/").last}|${base64Encode(file.readAsBytesSync())}";
}
}
int status = 0;
if (widget.serviceRequest == null) {
status = await _serviceRequestsProvider.createRequest(
user: _userProvider.user,
host: _settingProvider.host,
serviceRequest: _serviceRequest,
);
} else {
status = await _serviceRequestsProvider.updateDate(
user: _userProvider.user,
host: _settingProvider.host,
request: _serviceRequest,
date: _dateTime,
);
}
_isLoading = false;
setState(() {});
if (status >= 200 && status < 300) {
Fluttertoast.showToast(
msg: context.translation.successfulRequestMessage,
);
Navigator.of(context).pop();
} else {
String errorMessage = HttpStatusManger.getStatusMessage(status: status, subtitle: context.translation);
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(errorMessage),
));
}
},
label: context.translation.submitRequest),
onPressed: _submit,
label: context.translation.submitRequest,
),
],
),
).paddingOnly(start: 16, end: 16, bottom: 24, top: 16),
@ -379,4 +190,81 @@ class CreateRequestPageState extends State<CreateRequestPage> {
),
);
}
_attachImage() async {
ImageSource source = await showDialog(
context: context,
builder: (dialogContext) => CupertinoAlertDialog(
actions: <Widget>[
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) {
_serviceRequest.devicePhotos ??= [];
_serviceRequest.devicePhotos?.clear();
_serviceRequest.devicePhotos?.add(pickedFile.path);
setState(() {});
}
}
_fromFilePicker() async {
FilePickerResult result = await FilePicker.platform.pickFiles(
type: FileType.custom,
allowedExtensions: ['jpg', 'jpeg', 'png', 'pdf', 'doc', 'docx', 'xlsx', 'pptx'],
);
if (result?.files?.first != null) {
_serviceRequest.devicePhotos ??= [];
_serviceRequest.devicePhotos?.clear();
_serviceRequest.devicePhotos?.add(result?.files?.first?.path);
setState(() {});
}
}
Future<void> _submit() async {
if (_formKey.currentState.validate() && await _serviceRequest.validateNewRequest(context)) {
_formKey.currentState.save();
_serviceRequest.devicePhotos = _deviceImages.map((e) => _isLocalUrl(e.path) ? "${e.path.split("/").last}|${base64Encode(e.readAsBytesSync())}" : e.path).toList();
if (_serviceRequest.audio != null) {
if (_isLocalUrl(_serviceRequest.audio)) {
final File file = File(_serviceRequest.audio);
_serviceRequest.audio = "${file.path.split("/").last}|${base64Encode(file.readAsBytesSync())}";
}
}
showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
int status = await _serviceRequestsProvider.createRequest(
user: _userProvider.user,
host: _settingProvider.host,
serviceRequest: _serviceRequest,
);
Navigator.of(context);
if (status >= 200 && status < 300) {
Fluttertoast.showToast(msg: context.translation.successfulRequestMessage);
Navigator.pop(context);
} else {
Fluttertoast.showToast(msg: context.translation.failedRequestMessage);
}
}
}
}

@ -7,7 +7,7 @@ import 'package:test_sa/controllers/providers/settings/setting_provider.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/models/service_request/service_request.dart';
import 'package:test_sa/models/subtitle.dart';
import 'package:test_sa/views/pages/user/requests/request_details.dart';
import 'package:test_sa/views/pages/user/requests/service_request_details.dart';
import 'package:test_sa/views/widgets/loaders/app_loading.dart';
import 'package:test_sa/views/widgets/loaders/failed_loading.dart';
@ -40,7 +40,7 @@ class _FutureRequestServiceDetailsState extends State<FutureRequestServiceDetail
},
);
if (snapshot.hasData) {
return RequestDetailsPage(
return ServiceRequestDetailsPage(
serviceRequest: snapshot.data,
);
}

@ -1,548 +0,0 @@
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/localization/localization.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/string_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/enums/translation_keys.dart';
import 'package:test_sa/models/enums/user_types.dart';
import 'package:test_sa/models/service_request/service_request.dart';
import 'package:test_sa/models/subtitle.dart';
import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
import 'package:test_sa/views/app_style/colors.dart';
import 'package:test_sa/views/app_style/sizing.dart';
import 'package:test_sa/views/pages/user/requests/create_request.dart';
import 'package:test_sa/views/pages/user/requests/report/create_service_report.dart';
import 'package:test_sa/views/widgets/buttons/app_back_button.dart';
import 'package:test_sa/views/widgets/buttons/app_button.dart';
import 'package:test_sa/views/widgets/buttons/app_icon_button.dart';
import 'package:test_sa/views/widgets/images/files_list.dart';
import 'package:test_sa/views/widgets/loaders/app_loading.dart';
import 'package:test_sa/views/widgets/requests/info_row.dart';
import 'package:test_sa/views/widgets/requests/request_status.dart';
import 'package:test_sa/views/widgets/sound/sound_player.dart';
import 'package:test_sa/views/widgets/titles/app_sub_title.dart';
import '../../../../models/service_request/search_work_order.dart';
import 'report/future_service_report.dart';
class RequestDetailsPage extends StatelessWidget {
static const String id = "/call-details";
ServiceRequest serviceRequest;
RequestDetailsPage({Key key, this.serviceRequest}) : super(key: key);
@override
Widget build(BuildContext context) {
UserProvider _userProvider = Provider.of<UserProvider>(context);
SettingProvider _settingProvider = Provider.of<SettingProvider>(context);
List<SearchWorkOrder> workOrders = [];
ServiceRequestsProvider _serviceRequestsProvider = Provider.of<ServiceRequestsProvider>(context);
_serviceRequestsProvider.getServiceRequestObjectById(requestId: serviceRequest.id);
Widget informationCard() {
return Container(
decoration: ShapeDecoration(
color: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
shadows: const [BoxShadow(color: Color(0x07000000), blurRadius: 14, offset: Offset(0, 0), spreadRadius: 0)],
),
child: Column(
children: [
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
StatusLabel(
label: serviceRequest.priority.name,
id: serviceRequest.priority.id,
textColor: AColors.getPriorityStatusTextColor(serviceRequest.priority.id),
backgroundColor: AColors.getPriorityStatusColor(serviceRequest.priority.id)),
8.width,
StatusLabel(
label: serviceRequest.statusLabel,
textColor: AColors.getRequestStatusTextColor(serviceRequest.statusValue),
backgroundColor: AColors.getRequestStatusColor(serviceRequest.statusValue)),
1.width.expanded,
Text(serviceRequest.date.toServiceRequestCardFormat, textAlign: TextAlign.end, style: AppTextStyles.tinyFont.copyWith(color: const Color(0xFF3B3D4A))),
],
),
8.height,
Text(serviceRequest.deviceEnName, style: AppTextStyles.heading5.copyWith(color: const Color(0xFF3B3D4A))),
Text(
'${context.translation.assetNumber}: ${serviceRequest.device.assetNumber}',
style: AppTextStyles.bodyText.copyWith(color: Color(0xFF757575)),
),
Text(
'Request Type: ${serviceRequest.type.name}',
style: AppTextStyles.bodyText.copyWith(color: Color(0xFF757575)),
),
Text(
'Request No: ${serviceRequest.requestCode}',
style: AppTextStyles.bodyText.copyWith(color: Color(0xFF757575)),
),
8.height,
const Divider(color: Color(0xFFEAF1F4), height: 1, thickness: 1),
8.height,
Text(
'Manufacture: ${serviceRequest.device.modelDefinition.manufacturerName}',
style: AppTextStyles.bodyText.copyWith(color: Color(0xFF757575)),
),
Text(
'Model: ${serviceRequest.device.modelDefinition.modelName}',
style: AppTextStyles.bodyText.copyWith(color: Color(0xFF757575)),
),
8.height,
const Divider(color: Color(0xFFEAF1F4), height: 1, thickness: 1),
8.height,
if ((serviceRequest.callComments ?? "").isNotEmpty) ...[
Text(
serviceRequest.callComments,
style: AppTextStyles.bodyText.copyWith(color: Color(0xFF757575)),
),
8.height,
const Divider(color: Color(0xFFEAF1F4), height: 1, thickness: 1),
],
if (serviceRequest.devicePhotos.isNotEmpty) ...[
FilesList(images: serviceRequest.devicePhotos),
const Divider(color: Color(0xFFEAF1F4), height: 1, thickness: 1),
],
if (serviceRequest.audio?.isNotEmpty == true) ...[
16.height,
ASoundPlayer(
audio: serviceRequest.audio,
),
16.height,
const Divider(color: Color(0xFFEAF1F4), height: 1, thickness: 1),
],
Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
'View Comments',
style: AppTextStyles.bodyText.copyWith(color: const Color(0xFF4A8DB7)),
),
4.width,
const Icon(
Icons.arrow_forward,
color: Color(0xFF4A8DB7),
size: 14,
)
],
),
],
).paddingAll(16),
],
),
);
}
return DefaultTabController(
length: 2,
child: Scaffold(
appBar: DefaultAppBar(title: context.translation.serviceRequest),
backgroundColor: const Color(0xfff8f9fb),
body: SafeArea(
child: FutureBuilder(
future: _serviceRequestsProvider.getServiceRequestObjectById(requestId: serviceRequest.id),
builder: (context, snap) {
if (snap.connectionState == ConnectionState.waiting) {
return const ALoading();
} else if (snap.hasData) {
serviceRequest = snap.data;
return Column(
children: [
Container(
color: AColors.primaryColor,
padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 4),
child: Row(
children: [
ABackButton(),
Expanded(
child: Center(
child: Text(
context.translation.details,
style: Theme.of(context).textTheme.headline6.copyWith(color: AColors.white, fontStyle: FontStyle.italic),
),
),
),
_userProvider.user.type == UsersTypes.normal_user
?
// AIconButton(
// iconData: Icons.warning_amber_rounded,
// color: AColors.white,
// buttonSize: 42,
// backgroundColor: AColors.deepOrange,
// onPressed: (){
// Navigator.of(context).push(
// MaterialPageRoute(
// builder: (_) => ReportIssuesPage(serviceRequest: serviceRequest,)
// )
// );
// },
// )
const SizedBox(
width: 48,
)
: AIconButton(
iconData: Icons.edit,
color: AColors.white,
buttonSize: 42,
backgroundColor: AColors.green,
onPressed: (serviceRequest.statusValue == 5 || serviceRequest.statusValue == 3)
? null
: () async {
Navigator.of(context).push(
MaterialPageRoute(builder: (_) => CreateRequestPage(serviceRequest: serviceRequest)),
);
// showModalBottomSheet(
// context: context,
// builder: (context) {
// return ServiceRequestsUpdateDialog(
// request: serviceRequest,
// );
// });
// DateTime picked = await showDatePicker(
// context: context,
// initialDate: DateTime.now(),
// firstDate: DateTime.now(),
// lastDate: DateTime.now().add(Duration(days: 182))
// );
// if(picked == null){return;}
// showDialog<void>(
// context: context,
// barrierDismissible: false,
// builder: (BuildContext context) {
// return CupertinoAlertDialog(
// title: Text(context.translation.updatingDots),
// content: Center(child: CircularProgressIndicator()),
// );
// },
// );
// int status = await _serviceRequestsProvider.updateDate(
// user: _userProvider.user,
// host: _settingProvider.host,
// request: serviceRequest,
// newDate: picked.toString().split(" ").first
// );
// Navigator.of(context).pop();
// Fluttertoast.showToast(
// msg: HttpStatusManger.getStatusMessage(status: status, subtitle: context.translation),
// );
},
),
SizedBox(
width: 16,
)
],
),
),
serviceRequest.devicePhotos.isEmpty
? const SizedBox.shrink()
: SizedBox(
height: 60 * AppStyle.getScaleFactor(context),
child: FilesList(
images: serviceRequest.devicePhotos,
),
).paddingOnly(top: 4, bottom: 4),
TabBar(labelColor: AColors.primaryColor, tabs: [
Tab(
text: context.translation.general,
),
Tab(
text: context.translation.serviceRequestInformation,
),
]),
SizedBox(
height: 8,
),
Expanded(
child: TabBarView(
children: [
Column(
children: [
ListView(
padding: const EdgeInsets.all(16),
children: [
informationCard(),
RequestInfoRow(
title: context.translation.callId,
info: serviceRequest.requestCode,
),
RequestInfoRow(
title: "Asset Number",
info: serviceRequest.deviceNumber,
),
RequestInfoRow(
title: context.translation.assetName,
info: serviceRequest.deviceEnName,
),
RequestInfoRow(
title: context.translation.deviceModel,
info: serviceRequest.deviceModel,
),
RequestInfoRow(
title: context.translation.engineerName,
info: serviceRequest.engineerName,
),
RequestInfoRow(
title: context.translation.engineerPhone,
info: serviceRequest.engineerMobile,
),
RequestInfoRow(
title: context.translation.date,
info: serviceRequest.date,
),
serviceRequest.nextVisitDate == null
? SizedBox.shrink()
: RequestInfoRow(
title: context.translation.next,
info: DateFormat('EE dd/MM/yyyy').format(serviceRequest.nextVisitDate),
),
Row(
children: [
Expanded(
child: Text(
"${context.translation.status} : ",
style: Theme.of(context).textTheme.subtitle1,
textScaleFactor: AppStyle.getScaleFactor(context),
),
),
StatusLabel(label: serviceRequest.statusLabel, backgroundColor: AColors.getRequestStatusColor(serviceRequest.statusValue)),
],
),
Divider(
color: Theme.of(context).primaryColor,
),
RequestInfoRow(
title: context.translation.hospital,
info: serviceRequest.hospitalName,
),
RequestInfoRow(
title: context.translation.unite,
info: serviceRequest.departmentName,
),
// RequestInfoRow(
// title: context.translation.deviceArName,
// content: serviceRequest.deviceArName,
// ),
// RequestInfoRow(
// title: context.translation.deviceName,
// content: serviceRequest.deviceEnName,
// ),
RequestInfoRow(
title: context.translation.maintenanceIssue,
content: serviceRequest.callComments,
),
if (serviceRequest.audio?.isNotEmpty == true)
ASoundPlayer(
audio: serviceRequest.audio,
),
//
// Center(
// child: Padding(
// padding: EdgeInsets.all(32),
// child: AButton(
// text: context.translation.duplicateRequest,
// onPressed: () async {
// bool result = await showDialog(
// context: context,
// builder: (_) => AAlertDialog(
// title: context.translation.duplicateAlert,
// content: context.translation.duplicateAlertMessage,
// )
// );
// if(result == true){
// showDialog(
// context: context,
// builder: (context){
// return Center(child: CircularProgressIndicator());
// }
// );
// int status = await _serviceRequestsProvider.createDuplicatedReport(
// host: _settingProvider.host,
// user: _userProvider.user,
// request: serviceRequest
// );
// Navigator.of(context).pop();
// ScaffoldMessenger.of(context).showSnackBar(
// SnackBar(
// content: Text(
// HttpStatusManger.getStatusMessage(status: status, subtitle: context.translation)
// )
// )
// );
// }
// },
// ),
// ),
// )
],
).expanded,
AppFilledButton(label: context.translation.login, maxWidth: true, onPressed: () {}).paddingOnly(start: 16, end: 16, bottom: 24),
],
),
// workOrders.isEmpty ?
FutureBuilder(
future: _serviceRequestsProvider.searchWorkOrders(callId: serviceRequest.requestCode),
builder: (context, snap) {
workOrders = snap.data as List<SearchWorkOrder>;
if (snap.connectionState == ConnectionState.waiting) return Center(child: CircularProgressIndicator());
if (snap.connectionState == ConnectionState.done && (snap.data?.length ?? 0) != 0) {
return SingleChildScrollView(
child: Column(
children: [
ListView.separated(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
padding: EdgeInsets.all(21),
itemCount: workOrders.length,
separatorBuilder: (czt, index) => 21.height,
itemBuilder: (context, index) {
Color itemColor = index % 2 == 0 ? Theme.of(context).colorScheme.primary : Theme.of(context).colorScheme.onPrimary;
Color onItemColor = index % 2 != 0 ? Theme.of(context).colorScheme.primary : Theme.of(context).colorScheme.onPrimary;
return ElevatedButton(
style: ElevatedButton.styleFrom(
padding: EdgeInsets.symmetric(vertical: 8, horizontal: 8),
primary: itemColor.withOpacity(.7),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppStyle.getBorderRadius(context)),
),
),
//padding: EdgeInsets.symmetric(vertical: 8,horizontal: 8),
onPressed: () {
// onPressed(request);
},
child: Column(
children: [
RequestInfoRow(
title: context.translation.callId,
content: serviceRequest.requestCode,
),
RequestInfoRow(
title: context.translation.orderWorkNumber,
info: workOrders[index].workOrderNo.toString(),
),
RequestInfoRow(
title: context.translation.visitDate,
info: workOrders[index].visitDate,
),
RequestInfoRow(title: context.translation.assignedEmployee, info: workOrders[index].assignedEmployee?.name ?? ""),
RequestInfoRow(
title: context.translation.assetSN,
info: workOrders[index].callRequest.asset.assetSerialNo,
),
RequestInfoRow(
title: context.translation.assetName,
info: workOrders[index].callRequest.asset.modelDefinition.assetName,
),
RequestInfoRow(
title: context.translation.assetNumber,
info: workOrders[index].callRequest.asset.assetNumber,
),
RequestInfoRow(
title: context.translation.model,
info: workOrders[index].callRequest.asset.modelDefinition.modelName,
),
RequestInfoRow(
title: context.translation.site,
info: workOrders[index].callRequest.asset.site.custName,
),
RequestInfoRow(
title: "Call last Situation",
info: workOrders[index].currentSituation.name ?? '',
),
_userProvider.user.type == UsersTypes.engineer && workOrders[index].workOrderNo != null
? Padding(
padding: EdgeInsets.all(32),
child: AButton(
text: context.translation.editServiceReport,
onPressed: serviceRequest.statusValue == 5 || serviceRequest.statusValue == 3
? null
: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => FutureServiceReport(
request: serviceRequest,
workOrder: workOrders[index],
)),
);
},
),
)
: SizedBox.shrink(),
],
),
);
},
),
if (_userProvider.user.type == UsersTypes.engineer)
Center(
child: Padding(
padding: const EdgeInsets.all(32),
child: AButton(
text: "Create Work Order",
onPressed: serviceRequest.statusValue == 5 || serviceRequest.statusValue == 3
? null
: () {
Navigator.of(context).push(MaterialPageRoute(builder: (_) => CreateServiceReport(request: serviceRequest)));
},
),
),
),
],
),
);
} else {
return Column(
children: [
Expanded(
child: Center(
child: ASubTitle(context.translation.dataNotFound),
),
),
if (_userProvider.user.type == UsersTypes.engineer)
Center(
child: Padding(
padding: const EdgeInsets.all(32),
child: AButton(
text: "Create Work Order",
onPressed: serviceRequest.statusValue == 5 || serviceRequest.statusValue == 3
? null
: () {
Navigator.of(context).push(MaterialPageRoute(builder: (_) => CreateServiceReport(request: serviceRequest)));
},
),
),
),
],
);
}
},
),
],
),
),
],
);
}
return const SizedBox();
}),
),
),
);
}
}

@ -0,0 +1,228 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/localization/localization.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/string_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/enums/translation_keys.dart';
import 'package:test_sa/models/enums/user_types.dart';
import 'package:test_sa/models/service_request/service_request.dart';
import 'package:test_sa/models/subtitle.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
import 'package:test_sa/views/app_style/colors.dart';
import 'package:test_sa/views/app_style/sizing.dart';
import 'package:test_sa/views/pages/user/requests/create_request.dart';
import 'package:test_sa/views/pages/user/requests/work_order/create_service_report.dart';
import 'package:test_sa/views/pages/user/requests/work_order/future_service_report.dart';
import 'package:test_sa/views/pages/user/requests/work_order/work_orders_list_page.dart';
import 'package:test_sa/views/widgets/buttons/app_back_button.dart';
import 'package:test_sa/views/widgets/buttons/app_button.dart';
import 'package:test_sa/views/widgets/buttons/app_icon_button.dart';
import 'package:test_sa/views/widgets/images/files_list.dart';
import 'package:test_sa/views/widgets/loaders/app_loading.dart';
import 'package:test_sa/views/widgets/requests/info_row.dart';
import 'package:test_sa/views/widgets/requests/request_status.dart';
import 'package:test_sa/views/widgets/sound/sound_player.dart';
import 'package:test_sa/views/widgets/titles/app_sub_title.dart';
import '../../../../models/service_request/search_work_order.dart';
class ServiceRequestDetailsPage extends StatelessWidget {
static const String id = "/call-details";
ServiceRequest serviceRequest;
ServiceRequestDetailsPage({Key key, this.serviceRequest}) : super(key: key);
@override
Widget build(BuildContext context) {
UserProvider _userProvider = Provider.of<UserProvider>(context);
ServiceRequestsProvider _serviceRequestsProvider = Provider.of<ServiceRequestsProvider>(context);
// _serviceRequestsProvider.getServiceRequestObjectById(requestId: serviceRequest.id);
Widget informationCard() {
return Container(
decoration: ShapeDecoration(
color: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
shadows: const [BoxShadow(color: Color(0x07000000), blurRadius: 14, offset: Offset(0, 0), spreadRadius: 0)],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
StatusLabel(
label: serviceRequest.priority.name,
id: serviceRequest.priority.id,
textColor: AColors.getPriorityStatusTextColor(serviceRequest.priority.id),
backgroundColor: AColors.getPriorityStatusColor(serviceRequest.priority.id)),
8.width,
StatusLabel(
label: serviceRequest.statusLabel,
textColor: AColors.getRequestStatusTextColor(serviceRequest.statusValue),
backgroundColor: AColors.getRequestStatusColor(serviceRequest.statusValue)),
1.width.expanded,
Text(serviceRequest.date.toServiceRequestCardFormat, textAlign: TextAlign.end, style: AppTextStyles.tinyFont.copyWith(color: const Color(0xFF3B3D4A))),
],
),
8.height,
Text(serviceRequest.deviceEnName, style: AppTextStyles.heading5.copyWith(color: const Color(0xFF3B3D4A))),
Text(
'${context.translation.assetNumber}: ${serviceRequest.device.assetNumber}',
style: AppTextStyles.bodyText.copyWith(color: Color(0xFF757575)),
),
Text(
'Request Type: ${serviceRequest.type.name}',
style: AppTextStyles.bodyText.copyWith(color: Color(0xFF757575)),
),
Text(
'Request No: ${serviceRequest.requestCode}',
style: AppTextStyles.bodyText.copyWith(color: Color(0xFF757575)),
),
8.height,
const Divider(color: Color(0xFFEAF1F4), height: 1, thickness: 1),
8.height,
Text(
'Manufacture: ${serviceRequest.device.modelDefinition.manufacturerName}',
style: AppTextStyles.bodyText.copyWith(color: Color(0xFF757575)),
),
Text(
'Model: ${serviceRequest.device.modelDefinition.modelName}',
style: AppTextStyles.bodyText.copyWith(color: Color(0xFF757575)),
),
8.height,
if ((serviceRequest.callComments ?? "").isNotEmpty) ...[
const Divider(color: Color(0xFFEAF1F4), height: 1, thickness: 1),
8.height,
Text(
serviceRequest.callComments,
style: AppTextStyles.bodyText.copyWith(color: Color(0xFF757575)),
),
],
if (serviceRequest.devicePhotos.isNotEmpty) ...[
8.height,
const Divider(color: Color(0xFFEAF1F4), height: 1, thickness: 1),
FilesList(images: serviceRequest.devicePhotos),
],
if (serviceRequest.audio?.isNotEmpty ?? false) ...[
const Divider(color: Color(0xFFEAF1F4), height: 1, thickness: 1),
16.height,
ASoundPlayer(audio: serviceRequest.audio),
],
],
).paddingAll(16),
(_userProvider.user.type == UsersTypes.normal_user
? Container(
height: 50,
padding: const EdgeInsets.only(left: 16, right: 16),
alignment: Alignment.center,
width: double.infinity,
decoration: const ShapeDecoration(
color: Color(0xFFEAF1F4),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(20),
bottomRight: Radius.circular(20),
),
),
),
child: Row(
children: [
Text(
'Comment here...',
style: AppTextStyles.heading6.copyWith(
color: AppColor.neutral50.withOpacity(.6),
),
).expanded,
SvgPicture.asset("assets/images/comment_send.svg", width: 24 * AppStyle.getScaleFactor(context), height: 24 * AppStyle.getScaleFactor(context), color: AppColor.primary70),
],
),
)
: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Divider(color: Color(0xFFEAF1F4), height: 1, thickness: 1),
16.height,
Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
'View Comments',
style: AppTextStyles.bodyText.copyWith(color: const Color(0xFF4A8DB7)),
),
4.width,
const Icon(
Icons.arrow_forward,
color: Color(0xFF4A8DB7),
size: 14,
)
],
),
],
).paddingOnly(bottom: 16, start: 16, end: 16))
.onPress(() {
// todo 'sikander' add comment bottom sheet
}),
],
),
);
}
return Scaffold(
appBar: DefaultAppBar(title: context.translation.serviceDetails),
backgroundColor: const Color(0xfff8f9fb),
body: SafeArea(
child: FutureBuilder(
future: _serviceRequestsProvider.getServiceRequestObjectById(requestId: serviceRequest.id),
builder: (context, snap) {
if (snap.connectionState == ConnectionState.waiting) {
return const ALoading();
} else if (snap.hasData) {
serviceRequest = snap.data;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: informationCard(),
).expanded,
if (_userProvider.user.type != UsersTypes.engineer || (serviceRequest.statusValue == 5 || serviceRequest.statusValue == 3))
(serviceRequest.firstAction == null
? AppFilledButton(
label: context.translation.firstAction,
maxWidth: true,
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (_) => CreateRequestPage(serviceRequest: serviceRequest)),
);
})
: AppFilledButton(
label: context.translation.viewWorkOrder,
maxWidth: true,
onPressed: () {
Navigator.of(context).pushNamed(WorkOrderListPage.id, arguments: serviceRequest);
}))
.paddingOnly(start: 16, end: 16, bottom: 24),
],
);
}
return const SizedBox();
})));
}
}

@ -0,0 +1,175 @@
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/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/string_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/enums/user_types.dart';
import 'package:test_sa/models/service_request/search_work_order.dart';
import 'package:test_sa/models/service_request/service_request.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
import 'package:test_sa/views/app_style/sizing.dart';
import 'package:test_sa/views/pages/user/requests/work_order/create_service_report.dart';
import 'package:test_sa/views/pages/user/requests/work_order/future_service_report.dart';
import 'package:test_sa/views/widgets/buttons/app_button.dart';
import 'package:test_sa/views/widgets/requests/info_row.dart';
import 'package:test_sa/views/widgets/requests/request_status.dart';
import 'package:test_sa/views/widgets/titles/app_sub_title.dart';
class WorkOrderListPage extends StatelessWidget {
static const String id = "/work-order-list";
ServiceRequest serviceRequest;
WorkOrderListPage({Key key, this.serviceRequest}) : super(key: key);
@override
Widget build(BuildContext context) {
// UserProvider _userProvider = Provider.of<UserProvider>(context);
// SettingProvider _settingProvider = Provider.of<SettingProvider>(context);
List<SearchWorkOrder> workOrders = [];
ServiceRequestsProvider serviceRequestsProvider;
UserProvider _userProvider = Provider.of<UserProvider>(context);
if (serviceRequestsProvider == null) {
serviceRequestsProvider = Provider.of<ServiceRequestsProvider>(context);
serviceRequest = ModalRoute.of(context).settings.arguments;
}
print("serviceRequest.statusValue:${serviceRequest.statusValue}");
return Scaffold(
appBar: DefaultAppBar(title: context.translation.workOrder),
backgroundColor: const Color(0xfff8f9fb),
body: SafeArea(
child: FutureBuilder(
future: serviceRequestsProvider.searchWorkOrders(callId: serviceRequest.requestCode),
builder: (context, snap) {
workOrders = snap.data as List<SearchWorkOrder>;
if (snap.connectionState == ConnectionState.waiting) return Center(child: CircularProgressIndicator());
return Column(
children: [
ListView.separated(
padding: const EdgeInsets.all(16),
itemCount: workOrders?.length ?? 0,
separatorBuilder: (czt, index) => 8.height,
itemBuilder: (context, index) {
Color itemColor = index % 2 == 0 ? Theme.of(context).colorScheme.primary : Theme.of(context).colorScheme.onPrimary;
Color onItemColor = index % 2 != 0 ? Theme.of(context).colorScheme.primary : Theme.of(context).colorScheme.onPrimary;
return Container(
decoration: ShapeDecoration(
color: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
shadows: const [BoxShadow(color: Color(0x07000000), blurRadius: 14, offset: Offset(0, 0), spreadRadius: 0)],
),
child: Column(
children: [
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
StatusLabel(label: workOrders[index].currentSituation.name, textColor: AppColor.orange60, backgroundColor: AppColor.orange40),
8.height,
Text(serviceRequest.requestCode, style: AppTextStyles.heading5.copyWith(color: const Color(0xFF3B3D4A))),
],
).expanded,
if (serviceRequest.statusValue != 5 && serviceRequest.statusValue != 3)
"edit".toSvgAsset(height: 48, width: 48).onPress(() {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => FutureServiceReport(
request: serviceRequest,
workOrder: workOrders[index],
)),
);
})
],
),
8.height,
Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'${context.translation.assetName}: ${workOrders[index].callRequest.asset.modelDefinition.assetName}',
style: AppTextStyles.bodyText.copyWith(color: Color(0xFF757575)),
),
Text(
'${context.translation.status}: ${workOrders[index].currentSituation.name}',
style: AppTextStyles.bodyText.copyWith(color: Color(0xFF757575)),
),
],
).expanded,
Text(workOrders[index].visitDate.toServiceRequestCardFormat, textAlign: TextAlign.end, style: AppTextStyles.tinyFont.copyWith(color: const Color(0xFF3B3D4A))),
],
),
Text(
'${context.translation.orderWorkNumber}: ${workOrders[index].workOrderNo}',
style: AppTextStyles.bodyText.copyWith(color: Color(0xFF757575)),
),
Text(
'${context.translation.assignedEmployee}: ${workOrders[index].assignedEmployee?.name ?? ""}',
style: AppTextStyles.bodyText.copyWith(color: Color(0xFF757575)),
),
Text('${context.translation.assetSN}: ${workOrders[index].callRequest.asset.assetSerialNo ?? ""}', style: AppTextStyles.bodyText.copyWith(color: Color(0xFF757575))),
Text('${context.translation.assetName}: ${workOrders[index].callRequest.asset.modelDefinition.assetName ?? ""}',
style: AppTextStyles.bodyText.copyWith(color: Color(0xFF757575))),
Text('${context.translation.assetNumber}: ${workOrders[index].callRequest.asset.assetNumber ?? ""}', style: AppTextStyles.bodyText.copyWith(color: Color(0xFF757575))),
Text('${context.translation.model}: ${workOrders[index].callRequest.asset.modelDefinition.modelName ?? ""}',
style: AppTextStyles.bodyText.copyWith(color: Color(0xFF757575))),
Text('${context.translation.site}: ${workOrders[index].callRequest.asset.site.custName ?? ""}', style: AppTextStyles.bodyText.copyWith(color: Color(0xFF757575))),
Text('${"Call last Situation"}: ${workOrders[index].calllastSituation.name ?? '' ?? ""}', style: AppTextStyles.bodyText.copyWith(color: Color(0xFF757575))),
16.height,
Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
'View Details',
style: AppTextStyles.bodyText.copyWith(color: const Color(0xFF4A8DB7)),
),
4.width,
const Icon(
Icons.arrow_forward,
color: Color(0xFF4A8DB7),
size: 14,
)
],
),
],
).paddingAll(16).onPress(() {
// onPressed(request);
}),
],
),
);
},
).expanded,
if (_userProvider.user.type != UsersTypes.engineer && (serviceRequest.statusValue != 5 && serviceRequest.statusValue != 3))
AppFilledButton(
label: context.translation.createWorkOrder,
maxWidth: true,
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(builder: (_) => CreateServiceReport(request: serviceRequest)));
}).paddingOnly(start: 16, end: 16, bottom: 16)
],
);
},
)));
}
}

@ -3,11 +3,10 @@ import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/enums/translation_keys.dart';
import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart';
import 'package:test_sa/views/widgets/equipment/single_device_picker.dart';
import '../../../models/device/device.dart';
import '../../../new_views/app_style/app_color.dart';
class PickAsset extends StatelessWidget {
final Function(Device) onPickAsset;
@ -19,22 +18,36 @@ class PickAsset extends StatelessWidget {
Widget build(BuildContext context) {
return Column(
children: [
AppTextFormField(
enable: false,
labelText: context.translation.device,
initialValue: context.translation.site,
suffixIcon: "qr".toSvgAsset(height: 24, fit: BoxFit.fitHeight).paddingOnly(end: 16),
).onPress(() async {
Device device = await Navigator.of(context).pushNamed(SingleDevicePicker.id) as Device;
onPickAsset(device);
}),
if (device != null) 8.height,
Container(
decoration: BoxDecoration(
color: Theme.of(context).cardColor,
borderRadius: BorderRadius.circular(10),
boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.03), blurRadius: 14)],
),
child: Row(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
context.translation.device.tinyFont(context).custom(color: context.isDark ? AppColor.neutral40 : AppColor.neutral50),
context.translation.pickAsset.bodyText(context).custom(color: context.isDark ? AppColor.neutral40 : AppColor.neutral50),
],
).onPress(() async {
Device device = await Navigator.of(context).pushNamed(SingleDevicePicker.id) as Device;
onPickAsset(device);
}).expanded,
"qr".toSvgAsset(height: 24, fit: BoxFit.fitHeight).onPress(() {
/// TODO [Zaid] : open qr reader
}),
],
).paddingOnly(start: 16, end: 16, top: 8, bottom: 8),
),
if (device != null)
Card(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
context.translation.myAssets.heading5(context),
device.modelDefinition?.assetName?.heading5(context),
8.height,
"${context.translation.assetNo}: ${device.assetNumber}".bodyText(context),
"${context.translation.manufacture}: ${device.modelDefinition?.manufacturerName}".bodyText(context),
@ -45,7 +58,7 @@ class PickAsset extends StatelessWidget {
"${context.translation.site}: ${device.site?.custName}".bodyText(context),
],
).paddingAll(16),
),
).paddingOnly(top: 8),
],
);
}

@ -4,7 +4,7 @@ import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/models/service_request/service_request.dart';
import 'package:test_sa/models/subtitle.dart';
import 'package:test_sa/views/pages/user/requests/request_details.dart';
import 'package:test_sa/views/pages/user/requests/service_request_details.dart';
import 'package:test_sa/views/widgets/loaders/lazy_loading.dart';
import 'package:test_sa/views/widgets/loaders/no_item_found.dart';
import 'package:test_sa/views/widgets/requests/service_request_item.dart';
@ -37,7 +37,7 @@ class ServiceRequestsList extends StatelessWidget {
request: requests[itemIndex],
onPressed: (request) {
Navigator.of(context).push(MaterialPageRoute(
builder: (_) => RequestDetailsPage(
builder: (_) => ServiceRequestDetailsPage(
serviceRequest: request,
)));
},

@ -1,23 +1,28 @@
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_sound/flutter_sound.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:record_mp3/record_mp3.dart';
import 'package:rive/rive.dart';
import 'package:test_sa/views/widgets/buttons/app_icon_button2.dart';
import 'package:test_sa/views/widgets/buttons/app_small_button.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/views/widgets/sound/sound_player.dart';
import 'package:record_mp3/record_mp3.dart';
import '../../app_style/sizing.dart';
import '../../../new_views/app_style/app_color.dart';
import '../../../new_views/common_widgets/app_text_form_field.dart';
class RecordSound extends StatefulWidget {
final Function(String) onRecord;
final Function(String) onStop;
final bool enabled;
const RecordSound({Key key, @required this.onRecord, this.enabled = true}) : super(key: key);
const RecordSound({Key key, @required this.onRecord, this.onStop, this.enabled = true}) : super(key: key);
@override
State<RecordSound> createState() => _RecordSoundState();
@ -28,8 +33,11 @@ class _RecordSoundState extends State<RecordSound> {
bool _recorderIsOpened = false;
bool _recording = false;
bool _played = false;
String _record;
Artboard _rive;
Timer _timer;
TextEditingController _timeController;
@override
void setState(VoidCallback fn) {
@ -39,7 +47,7 @@ class _RecordSoundState extends State<RecordSound> {
@override
void initState() {
super.initState();
_timeController = TextEditingController();
_recorderIsOpened = true;
// RecordMp3.instance.start(recordFilePath, (type) {
// // record fail callback
@ -70,6 +78,7 @@ class _RecordSoundState extends State<RecordSound> {
@override
void dispose() {
_timeController?.dispose();
// Be careful : you must `close` the audio session when you have finished with it.
RecordMp3.instance.stop();
//_myRecorder.closeRecorder();
@ -80,7 +89,6 @@ class _RecordSoundState extends State<RecordSound> {
String recordingFileDirectory;
_startRecording() async {
// await Permission.camera
PermissionStatus status = await Permission.microphone.request();
if (!status.isGranted) {
PermissionStatus status = await Permission.microphone.request();
@ -89,6 +97,15 @@ class _RecordSoundState extends State<RecordSound> {
return;
}
}
_timer = Timer.periodic(const Duration(seconds: 1), (timer) {
setState(() {
String recordTime = ((timer?.tick ?? 0) / 60)?.toStringAsFixed(2)?.replaceFirst(".", ":");
if (recordTime.length == 4 || recordTime.length == 7) {
recordTime = "0$recordTime";
}
_timeController.text = recordTime;
});
});
_rive.addController(SimpleAnimation('recording'));
if (!_recorderIsOpened) {
// await _myRecorder.openRecorder();
@ -111,7 +128,9 @@ class _RecordSoundState extends State<RecordSound> {
setState(() {});
return;
}
if (_timer?.isActive ?? false) {
_timer.cancel();
}
RecordMp3.instance.stop();
//String path = (await _myRecorder.stopRecorder()).toString();
@ -137,94 +156,37 @@ class _RecordSoundState extends State<RecordSound> {
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.only(left: 12, right: 0),
decoration: BoxDecoration(
color: const Color(0xfff5f5f5),
border: Border.all(
color: const Color(0xffefefef),
return Column(
children: [
Stack(
alignment: AlignmentDirectional.centerEnd,
children: [
AppTextFormField(
enable: false,
controller: _timeController,
labelText: context.translation.recordVoice,
initialValue: (_timeController?.text?.isEmpty ?? true) ? "00:00" : _timeController?.text,
suffixIcon:
(_recording ? "record".toLottieAsset(height: 24) : (_record != null ? "trash" : "mic").toSvgAsset(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20, height: 24))
.paddingOnly(end: 16),
),
SizedBox(height: 50.toScreenHeight, width: 50.toScreenWidth).onPress(() {
if (_recording) {
_stopRecording();
} else if (_record != null) {
_timeController?.text = "00:00";
widget.onRecord(null);
_record = null;
setState(() {});
} else {
_startRecording();
}
}),
],
),
borderRadius: BorderRadius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context)),
),
child: Column(
children: [
Row(
children: [
Expanded(
child: _recording
? Row(
children: [
ASmallButton(
text: "done",
onPressed: () {
_stopRecording();
},
),
Expanded(
child: Stack(
children: [
SizedBox(
height: 24 * AppStyle.getScaleFactor(context),
child: Rive(
artboard: _rive,
)),
InkWell(
child: SizedBox(
height: 32 * AppStyle.getScaleFactor(context),
width: MediaQuery.of(context).size.width,
),
onTap: () {
_cancelRecording();
},
),
],
),
),
],
)
: _record != null
? Row(
children: [
Expanded(child: ASoundPlayer(audio: _record)),
AIconButton2(
iconData: Icons.delete,
onPressed: () {
widget.onRecord(null);
_record = null;
setState(() {});
},
)
],
)
: const Text("Record Voice"),
),
Material(
color: Colors.transparent,
child: GestureDetector(
//key: ValueKey("voice"),
onTapDown: widget.enabled
? (TapDownDetails details) async {
_startRecording();
}
: null,
onTapUp: widget.enabled
? (TapUpDetails details) async {
_stopRecording();
}
: null,
onTapCancel: widget.enabled
? () async {
_cancelRecording();
}
: null,
//key: ValueKey("voice"),
child: const Padding(padding: EdgeInsets.all(12.0), child: Icon(Icons.mic)),
),
),
],
),
],
),
if (_record != null) 8.height,
if (_record != null) ASoundPlayer(audio: _record),
],
);
}
}

@ -1,5 +1,8 @@
import 'package:audioplayers/audioplayers.dart';
import 'package:flutter/material.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/new_views/app_style/app_text_style.dart';
import 'package:test_sa/views/app_style/sizing.dart';
import '../../app_style/colors.dart';
@ -23,64 +26,73 @@ class _ASoundPlayerState extends State<ASoundPlayer> {
bool _failedToLoad = false;
AudioPlayer _audioPlayer;
Widget audioPlayerButton(IconData icon, VoidCallback onpress) {
return Container(
width: 48,
height: 48,
decoration: ShapeDecoration(
color: Colors.white,
shape: RoundedRectangleBorder(
side: const BorderSide(width: 1, color: Color(0xFFEAF1F4)),
borderRadius: BorderRadius.circular(32),
),
),
child: Icon(
icon,
color: const Color(0xff163A51).withOpacity(0.5),
),
).onPress(onpress);
}
Widget _getAudioButton() {
switch (_audioPlayer.state) {
case PlayerState.playing:
return IconButton(
icon: const Icon(Icons.pause_rounded),
onPressed: () async {
_failedToLoad = false;
await _audioPlayer.pause();
rebuild();
});
return audioPlayerButton(Icons.pause_rounded, () async {
_failedToLoad = false;
await _audioPlayer.pause();
rebuild();
});
case PlayerState.paused:
return IconButton(
icon: const Icon(Icons.play_arrow_rounded),
onPressed: () async {
_failedToLoad = false;
await _audioPlayer.resume();
rebuild();
});
return audioPlayerButton(Icons.play_arrow_rounded, () async {
_failedToLoad = false;
await _audioPlayer.resume();
rebuild();
});
case PlayerState.completed:
return IconButton(
icon: const Icon(Icons.replay_rounded),
onPressed: () async {
_failedToLoad = false;
await _audioPlayer.stop();
await _audioPlayer.resume();
rebuild();
});
return audioPlayerButton(Icons.replay_rounded, () async {
_failedToLoad = false;
await _audioPlayer.stop();
await _audioPlayer.resume();
rebuild();
});
case PlayerState.stopped:
return IconButton(
icon: Icon(_isLocalFile ? Icons.play_circle_fill_outlined : Icons.download_rounded),
onPressed: () async {
_failedToLoad = false;
try {
await _audioPlayer.play(
_isLocalFile ? DeviceFileSource(_audio) : UrlSource(_audio),
);
rebuild();
} on Exception catch (e) {
_failedToLoad = true;
}
});
return audioPlayerButton(_isLocalFile ? Icons.play_circle_fill_outlined : Icons.download_rounded, () async {
_failedToLoad = false;
try {
await _audioPlayer.play(
_isLocalFile ? DeviceFileSource(_audio) : UrlSource(_audio),
);
rebuild();
} on Exception catch (e) {
_failedToLoad = true;
}
});
default:
return IconButton(
icon: const Icon(Icons.replay_rounded),
onPressed: () async {
_failedToLoad = false;
return audioPlayerButton(Icons.replay_rounded, () async {
_failedToLoad = false;
try {
_audioPlayer.seek(const Duration(milliseconds: 0));
_audioPlayer.stop();
await _audioPlayer.play(
_isLocalFile ? DeviceFileSource(_audio) : UrlSource(_audio),
);
rebuild();
} on Exception catch (e) {
_failedToLoad = true;
}
});
try {
_audioPlayer.seek(const Duration(milliseconds: 0));
_audioPlayer.stop();
await _audioPlayer.play(
_isLocalFile ? DeviceFileSource(_audio) : UrlSource(_audio),
);
rebuild();
} on Exception catch (e) {
_failedToLoad = true;
}
});
}
}
@ -163,12 +175,15 @@ class _ASoundPlayerState extends State<ASoundPlayer> {
children: [
Row(
children: [
Material(color: Colors.transparent, child: _getAudioButton()),
Expanded(
_getAudioButton(),
SliderTheme(
data: SliderTheme.of(context).copyWith(trackHeight: 2.0, thumbShape: const RoundSliderThumbShape(enabledThumbRadius: 6.0), overlayShape: SliderComponentShape.noOverlay),
child: Slider(
value: _audioPosition?.inMilliseconds?.toDouble() ?? 0.0,
min: 0,
max: _audioTime?.inMilliseconds?.toDouble() ?? 60.0,
activeColor: AppColor.primary70,
inactiveColor: AppColor.neutral30,
onChangeStart: (value) {
_sliderMoving = true;
},
@ -181,35 +196,12 @@ class _ASoundPlayerState extends State<ASoundPlayer> {
_audioPlayer.seek(Duration(milliseconds: value.round()));
rebuild();
}),
),
).paddingOnly(start: 8, end: 8).expanded,
_failedToLoad
? Text("Failed to load", style: AppTextStyle.tiny.copyWith(color: AppColor.red60))
: Text("${format(_audioPosition)}/${format(_audioTime)}", style: AppTextStyle.tiny.copyWith(color: AppColor.neutral50)),
],
),
Row(
children: [
Expanded(
child: Visibility(
visible: _failedToLoad,
child: Row(
children: [
Text(
"Failed to load",
style: Theme.of(context).textTheme.overline.copyWith(color: AColors.red),
textScaleFactor: AppStyle.getScaleFactor(context),
),
],
),
),
),
Visibility(
visible: _audioPlayer.state != PlayerState.stopped,
child: Text(
"${format(_audioPosition)}/${format(_audioTime)}",
style: Theme.of(context).textTheme.overline,
textScaleFactor: AppStyle.getScaleFactor(context),
),
),
],
)
],
);
}

@ -217,6 +217,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.7.8"
dotted_border:
dependency: "direct main"
description:
name: dotted_border
sha256: "108837e11848ca776c53b30bc870086f84b62ed6e01c503ed976e8f8c7df9c04"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
fake_async:
dependency: transitive
description:
@ -669,6 +677,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.4.0"
lottie:
dependency: "direct main"
description:
name: lottie
sha256: "23522951540d20a57a60202ed7022e6376bed206a4eee1c347a91f58bd57eb9f"
url: "https://pub.dev"
source: hosted
version: "2.3.2"
matcher:
dependency: transitive
description:

@ -68,7 +68,8 @@ dependencies:
path_provider: ^2.1.0
open_file: ^3.3.2
localization: ^2.1.0
buttons_tabbar: ^1.3.7+1
dotted_border: ^2.1.0
lottie: ^2.3.0
dev_dependencies:
flutter_test:
@ -98,6 +99,7 @@ flutter:
assets:
- assets/
- assets/images/
- assets/lottie/
- assets/subtitles/
- assets/rives/
- assets/translations/

Loading…
Cancel
Save