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

# Conflicts:
#	lib/views/widgets/pentry/pentry_ppm_check_list_form.dart
main_design2.0
Sikander Saleem 2 years ago
commit 258fb2c333

@ -1,16 +1,20 @@
import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:http/http.dart';
import 'package:logger/logger.dart';
import 'package:test_sa/controllers/api_routes/api_manager.dart';
import 'package:test_sa/controllers/api_routes/urls.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/models/pantry/pentry.dart';
import 'package:test_sa/models/user.dart';
import 'package:test_sa/models/visits/visit.dart';
import 'package:test_sa/models/visits/visits_group.dart';
import 'package:test_sa/models/visits/visits_search.dart';
import '../../../new_views/common_widgets/app_lazy_loading.dart';
class RegularVisitsProvider extends ChangeNotifier {
// number of items call in each request
final pageItemNumber = 12;
@ -134,10 +138,9 @@ class RegularVisitsProvider extends ChangeNotifier {
}
}
Future<Pentry> getPently({String host, User user, int id}) async {
Future<Pentry> getPentry({String host, User user, int id}) async {
Response response;
response = await get(Uri.parse("$host${URLs.getPentry}/$id"), headers: {"Content-Type": "application/json; charset=utf-8"});
response = await ApiManager.instance.get("${URLs.getPentry}/$id");
Pentry pantry;
if (response.statusCode >= 200 && response.statusCode < 300) {
pantry = Pentry.fromMap(json.decode(utf8.decode(response.bodyBytes)));
@ -145,13 +148,14 @@ class RegularVisitsProvider extends ChangeNotifier {
return pantry;
}
Future<int> updatePentry({
@required String host,
Future<int> updatePentry(
BuildContext context, {
@required User user,
@required Pentry pentry,
@required Visit visit,
}) async {
try {
showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
Response response;
Map<String, dynamic> body = pentry.toMap(visit.id);
body["id"] = visit.id;
@ -170,7 +174,12 @@ class RegularVisitsProvider extends ChangeNotifier {
if (response.statusCode >= 200 && response.statusCode < 300) {
reset(); //visit.status = pentry.ppmVisitStatus;
notifyListeners();
Fluttertoast.showToast(msg: context.translation.successfulRequestMessage);
Navigator.of(context).pop();
} else {
Fluttertoast.showToast(msg: "${context.translation.failedToCompleteRequest} ${jsonDecode(response.body)["message"]}");
}
Navigator.of(context).pop();
return response.statusCode;
} catch (error) {
return -1;

@ -7,7 +7,11 @@ extension StringExtensions on String {
}
String get toServiceRequestDetailsFormat {
DateTime dateTime = DateTime.tryParse(this);
return "${DateFormat('dd MMM, yyyy').format(dateTime)} ${DateFormat('hh:mm a').format(dateTime)}";
try {
DateTime dateTime = DateTime.tryParse(this);
return "${DateFormat('dd MMM, yyyy').format(dateTime)} ${DateFormat('hh:mm a').format(dateTime)}";
} catch (e) {
return "null";
}
}
}

@ -304,5 +304,7 @@
"partNo" : "الجزء رقم",
"engSign" : "توقيع المهندس",
"requesterName" : "اسم الطالب",
"updateWorkOrder" : "تعديل طلب العمل"
"updateWorkOrder" : "تعديل طلب العمل",
"createPreventiveMaintenanceRequest" : "إنشاء طلب صيانة وقائية",
"createNewRequest" : "إنشاء طلب جديد"
}

@ -308,6 +308,7 @@
"partNo" : "Part No.",
"engSign" : "Engineer Signature",
"requesterName" : "Requester Name",
"updateWorkOrder" : "Update Work Order"
"updateWorkOrder" : "Update Work Order",
"createPreventiveMaintenanceRequest" : "Create Preventive Maintenance Request",
"createNewRequest" : "Create New Request"
}

@ -53,6 +53,8 @@ import 'package:test_sa/providers/gas_request_providers/gas_status_provider.dart
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/ppm_device_status_provider.dart';
import 'package:test_sa/providers/ppm_visit_status_provider.dart';
import 'package:test_sa/providers/service_request_providers/equipment_status_provider.dart';
import 'package:test_sa/providers/service_request_providers/first_action_provider.dart';
import 'package:test_sa/providers/service_request_providers/loan_availability_provider.dart';
@ -176,6 +178,9 @@ class MyApp extends StatelessWidget {
ChangeNotifierProvider(create: (_) => LoanAvailabilityProvider()),
ChangeNotifierProvider(create: (_) => ReasonProvider()),
ChangeNotifierProvider(create: (_) => ServiceTypeProvider()),
ChangeNotifierProvider(create: (_) => PPMVisitStatusProvider()),
ChangeNotifierProvider(create: (_) => PentryTaskStatusProvider()),
ChangeNotifierProvider(create: (_) => PPMDeviceStatusProvider()),
],
child: GestureDetector(
onTap: () {

@ -48,12 +48,16 @@ class Pentry {
this.localEngineerSignature});
Future<bool> validate() async {
if (ppmVisitStatus == null) {
await Fluttertoast.showToast(msg: "PPM Visit Status is Required");
return false;
}
if (actualVisitDate == null) {
await Fluttertoast.showToast(msg: "Actual visit date is Required");
return false;
}
if (expectedVisitDate == null) {
await Fluttertoast.showToast(msg: "expected visit date is Required");
await Fluttertoast.showToast(msg: "Expected visit date is Required");
return false;
}
if (timer?.startAt == null) {
@ -64,7 +68,6 @@ class Pentry {
await Fluttertoast.showToast(msg: "Please Stop The Timer");
return false;
}
if (ppmVisitStatus == null) return false;
if (status?.id == null) {
await Fluttertoast.showToast(msg: "Device Status is Required");
return false;
@ -75,8 +78,8 @@ class Pentry {
Map<String, dynamic> toMap(int visitId) {
Map<String, dynamic> map = {};
map["visitStatusId"] = ppmVisitStatus?.id?.toString();
if (status != null) map["deviceStatusId"] = status?.id?.toString();
map["visitStatusId"] = ppmVisitStatus?.id;
if (status != null) map["deviceStatusId"] = status?.id;
if (travelingHours != null) map["travelingHours"] = travelingHours;
//if(imageFile != null) map["file_attachement"] = base64Encode(imageFile.readAsBytesSync());
map["actualDate"] = actualVisitDate.toIso8601String();

@ -16,12 +16,12 @@ class PMKit {
return {
"id": id ?? 0,
"visitId": visitId,
if (itemCode != null) 'partCatalogItemId': (itemCode?.id).toString(),
// if(itemName != null) 'itemName': itemName,
if (itemCode != null) 'partCatalogItemId': (itemCode?.id),
if (itemName != null) 'itemName': itemName,
// if(preparationTimeFrame != null) 'preparationTimeFrame': preparationTimeFrame,
// if(kitFrequencyDemand != null) 'kitFrequencyDemand': kitFrequencyDemand,
// if(availability != null) 'availability': availability,
// if(quantityNeeded != null) 'quantityNeeded': quantityNeeded,
if (quantityNeeded != null) 'quantityNeeded': quantityNeeded,
// if(quantityReserved != null) 'quantityReserved': quantityReserved,
};
}

@ -28,31 +28,31 @@ class AppTextFormField extends StatefulWidget {
final Color backgroundColor;
final bool alignLabelWithHint;
const AppTextFormField({
Key key,
this.onSaved,
this.validator,
this.node,
this.onChange,
this.obscureText,
this.showPassword,
this.hintText,
this.labelText,
this.textInputType = TextInputType.text,
this.initialValue,
this.enable = true,
this.style,
this.textAlign,
this.suffixIcon,
this.prefixIcon,
this.prefixIconData,
this.prefixIconSize,
this.controller,
this.textInputAction,
this.onAction,
this.backgroundColor,
this.alignLabelWithHint
}) : super(key: key);
const AppTextFormField(
{Key key,
this.onSaved,
this.validator,
this.node,
this.onChange,
this.obscureText,
this.showPassword,
this.hintText,
this.labelText,
this.textInputType = TextInputType.text,
this.initialValue,
this.enable = true,
this.style,
this.textAlign,
this.suffixIcon,
this.prefixIcon,
this.prefixIconData,
this.prefixIconSize,
this.controller,
this.textInputAction,
this.onAction,
this.backgroundColor,
this.alignLabelWithHint})
: super(key: key);
@override
State<AppTextFormField> createState() => _AppTextFormFieldState();

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

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

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

@ -112,6 +112,7 @@ class AColors {
return AColors.statusDefault;
}
}
static Color getPriorityStatusColor(int id) {
switch (id) {
case 81:

@ -25,6 +25,7 @@ import 'package:test_sa/views/widgets/dialogs/dialog.dart';
import 'package:test_sa/views/widgets/drawer/drawer_item.dart';
import 'package:url_launcher/url_launcher.dart';
import '../../../models/enums/user_types.dart';
import '../../widgets/land_page/land_page_item.dart';
import '../device_transfer/request_device_transfer.dart';
import 'requests/requests_page.dart';
@ -147,16 +148,15 @@ class _LandPageState extends State<LandPage> {
mainAxisSpacing: 12,
childAspectRatio: 1,
children: [
/// todo [zaid] : enable this condition when the nurse account works
// if (_userProvider.user != null && _userProvider.user.type == UsersTypes.normal_user)
LandPageItem(
// text: _subtitle.newServiceRequest,
text: "New Service Request",
icon: FontAwesomeIcons.screwdriverWrench,
onPressed: () {
Navigator.of(context).pushNamed(CreateServiceRequestPage.id);
},
),
if (_userProvider.user != null && _userProvider.user.type == UsersTypes.normal_user)
LandPageItem(
// text: _subtitle.newServiceRequest,
text: "New Service Request",
icon: FontAwesomeIcons.screwdriverWrench,
onPressed: () {
Navigator.of(context).pushNamed(CreateServiceRequestPage.id);
},
),
LandPageItem(
// text: _subtitle.trackServiceRequest,
text: "Track Service Request",
@ -182,16 +182,15 @@ class _LandPageState extends State<LandPage> {
// Navigator.of(context).pushNamed(PreventiveMaintenanceVisitsPage.id);
// },
// ),
/// todo [zaid] : enable this condition when the nurse account works
// if (_userProvider?.user != null && _userProvider?.user?.type != UsersTypes.engineer)
LandPageItem(
text: "Request Gas Refill",
icon: FontAwesomeIcons.truckFast,
onPressed: () {
// Navigator.of(context).pushNamed(RequestGasRefill.id);
Navigator.of(context).pushNamed(NewGasRefillRequestPage.routeName);
},
),
if (_userProvider?.user != null && _userProvider?.user?.type != UsersTypes.engineer)
LandPageItem(
text: "Request Gas Refill",
icon: FontAwesomeIcons.truckFast,
onPressed: () {
// Navigator.of(context).pushNamed(RequestGasRefill.id);
Navigator.of(context).pushNamed(NewGasRefillRequestPage.routeName);
},
),
LandPageItem(
text: "Track Gas Refill",
icon: Icons.content_paste_search,
@ -213,16 +212,14 @@ class _LandPageState extends State<LandPage> {
Navigator.of(context).pushNamed(TrackDeviceTransferPage.id);
},
),
/// todo [zaid] : enable this condition when the nurse account works
// if (_userProvider?.user != null && _userProvider?.user?.type != UsersTypes.normal_user)
LandPageItem(
text: "Create Sub Work Order",
svgPath: "assets/images/sub_workorder_icon.svg",
onPressed: () {
Navigator.of(context).pushNamed(SearchSubWorkOrderPage.id);
},
),
if (_userProvider?.user != null && _userProvider?.user?.type != UsersTypes.normal_user)
LandPageItem(
text: "Create Sub Work Order",
svgPath: "assets/images/sub_workorder_icon.svg",
onPressed: () {
Navigator.of(context).pushNamed(SearchSubWorkOrderPage.id);
},
),
],
),
],

@ -14,7 +14,6 @@ import '../../../../../controllers/providers/api/user_provider.dart';
import '../../../../../models/enums/user_types.dart';
import '../../../../../models/service_request/search_work_order.dart';
import '../../../../widgets/requests/request_status.dart';
import 'update_service_report.dart';
class WorkOrderDetailsPage extends StatelessWidget {
static const String id = "/work_order_details_page";
@ -70,17 +69,13 @@ class WorkOrderDetailsPage extends StatelessWidget {
Text('${context.translation.site}: ${workOrder.callRequest.asset.site.custName ?? ""}', style: AppTextStyles.bodyText.copyWith(color: const Color(0xFF757575))),
Text('${"Call last Situation"}: ${workOrder.calllastSituation.name ?? '' ?? ""}', style: AppTextStyles.bodyText.copyWith(color: const Color(0xFF757575))),
],
).paddingAll(16).onPress(() {
// onPressed(request);
}),
).paddingAll(16),
),
).expanded,
if (userProvider.user.type == UsersTypes.engineer && serviceRequest.statusValue != 5 && serviceRequest.statusValue != 3)
AppFilledButton(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (_) => UpdateServiceReport(request: serviceRequest, workOrder: workOrder)),
);
Navigator.of(context).push(MaterialPageRoute(builder: (_) => Container()));
},
label: context.translation.updateRequest,
).paddingAll(16),

@ -1,24 +1,25 @@
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/localization/localization.dart';
import 'package:test_sa/controllers/providers/api/regular_visits_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/pantry/calibration_tools.dart';
import 'package:test_sa/models/pantry/pentry.dart';
import 'package:test_sa/models/pantry/pm_kit.dart';
import 'package:test_sa/models/pantry/ppm_check_list.dart';
import 'package:test_sa/models/subtitle.dart';
import 'package:test_sa/models/visits/visit.dart';
import 'package:test_sa/views/widgets/buttons/app_small_button.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/widgets/loaders/loading_manager.dart';
import 'package:test_sa/views/widgets/pentry/pentry_calibration_tool_form.dart';
import 'package:test_sa/views/widgets/pentry/pentry_pm_kit_form.dart';
import 'package:test_sa/views/widgets/pentry/pentry_ppm_check_list_form.dart';
import '../../../../widgets/pentry/pentry_info_form.dart';
import '../../../../widgets/pentry/pentry_tbs_form.dart';
class EditPentry extends StatefulWidget {
final Pentry pentry;
@ -48,25 +49,9 @@ class _EditPentryState extends State<EditPentry> with SingleTickerProviderStateM
setState(() {});
return;
}
_isLoading = true;
setState(() {});
_pentry.clearEmptyObjects();
int status = await _regularVisitsProvider.updatePentry(user: _userProvider.user, host: _settingProvider.host, pentry: _pentry, visit: widget.visit);
_isLoading = false;
setState(() {});
if (status >= 200 && status < 300) {
Fluttertoast.showToast(
msg: context.translation.successfulRequestMessage,
);
Navigator.of(context).pop();
Navigator.of(context).pop();
} else {
// String errorMessage = HttpStatusManger.getStatusMessage(
// status: status, subtitle: context.translation);
// Fluttertoast.showToast(
// msg: errorMessage,
// );
}
await _regularVisitsProvider.updatePentry(context, user: _userProvider.user, pentry: _pentry, visit: widget.visit);
}
@override
@ -91,109 +76,61 @@ class _EditPentryState extends State<EditPentry> with SingleTickerProviderStateM
_settingProvider = Provider.of<SettingProvider>(context);
_regularVisitsProvider = Provider.of<RegularVisitsProvider>(context);
return Scaffold(
appBar: DefaultAppBar(title: context.translation.preventiveMaintenance),
key: _scaffoldKey,
body: SafeArea(
child: LoadingManager(
isLoading: _isLoading,
isFailedLoading: false,
stateCode: 200,
onRefresh: () async {},
child: Column(
children: [
Material(
color: Theme.of(context).colorScheme.primary,
child: Padding(
padding: const EdgeInsets.all(2.0),
child: TabBar(
controller: _tabController,
isScrollable: true,
onTap: (index) {
setState(() {});
},
tabs: const [
Tab(
text: "PPM Check List",
),
Tab(
text: "Calibration Tools",
),
Tab(
text: "PM Kits",
),
Tab(
text: "PM Entry",
),
],
),
),
),
Expanded(
child: Stack(
children: [
TabBarView(
physics: const NeverScrollableScrollPhysics(),
controller: _tabController,
children: [
PentryPPMCheckListForm(
models: _pentry.ppmCheckLists,
enableValidate: _validate,
),
PentryCalibrationToolForm(
models: _pentry.calibrationTools,
enableValidate: _validate,
),
PentryPMKitForm(
models: _pentry.pmKits,
enableValidate: _validate,
assetId: widget.visit?.deviceId,
),
PentryInfoForm(
model: _pentry,
enableValidate: _validate,
),
],
),
Align(
alignment: Alignment.bottomCenter,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: [
if (_tabController.index != 0)
ASmallButton(
text: context.translation.back,
onPressed: () {
_tabController.animateTo(
_tabController.index - 1,
);
setState(() {});
},
),
const Spacer(),
if (_tabController.index != _tabController.length - 1)
ASmallButton(
text: context.translation.next,
onPressed: () {
_tabController.animateTo(
_tabController.index + 1,
);
setState(() {});
},
),
if (_tabController.index == _tabController.length - 1)
ASmallButton(
text: context.translation.update,
onPressed: _onSubmit,
),
],
),
),
)
],
),
isLoading: _isLoading,
isFailedLoading: false,
stateCode: 200,
onRefresh: () async {},
child: Column(
children: [
Container(
decoration: BoxDecoration(color: AppColor.neutral30, borderRadius: BorderRadius.circular(16)),
child: TabBar(
controller: _tabController,
isScrollable: true,
padding: EdgeInsets.zero,
labelColor: AppColor.neutral60,
unselectedLabelColor: AppColor.neutral20,
indicatorPadding: const EdgeInsets.all(4),
indicator: BoxDecoration(color: Theme.of(context).cardColor, borderRadius: BorderRadius.circular(13)),
onTap: (index) {
setState(() {});
},
tabs: [
Tab(text: "TBS", height: 57.toScreenHeight),
Tab(text: "Calibration Tool", height: 57.toScreenHeight),
Tab(text: "PM Kit", height: 57.toScreenHeight),
Tab(text: "PPM Checklist", height: 57.toScreenHeight),
],
),
],
)),
),
TabBarView(
physics: const NeverScrollableScrollPhysics(),
controller: _tabController,
children: [
PentryTBSForm(model: _pentry, enableValidate: _validate),
PentryCalibrationToolForm(models: _pentry.calibrationTools, enableValidate: _validate),
PentryPMKitForm(models: _pentry.pmKits, enableValidate: _validate, assetId: widget.visit?.deviceId),
PentryPMChecklistForm(models: _pentry.ppmCheckLists, enableValidate: _validate),
],
).expanded,
AppFilledButton(
onPressed: () {
if (_tabController.index == 3) {
_onSubmit();
} else {
_tabController.animateTo(_tabController.index + 1);
setState(() {});
}
},
label: _tabController.index == 3 ? context.translation.submit : context.translation.next,
).paddingOnly(top: 16),
],
).paddingAll(16),
),
),
);
}

@ -1,12 +1,10 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/localization/localization.dart';
import 'package:test_sa/controllers/providers/api/regular_visits_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/models/pantry/pentry.dart';
import 'package:test_sa/models/subtitle.dart';
import 'package:test_sa/models/visits/visit.dart';
import 'package:test_sa/views/pages/user/visits/pantry/edit_pentry.dart';
import 'package:test_sa/views/widgets/loaders/app_loading.dart';
@ -32,7 +30,7 @@ class _FutureEditPentryState extends State<FutureEditPentry> {
return Scaffold(
body: FutureBuilder<Pentry>(
future: RegularVisitsProvider().getPently(user: _userProvider.user, host: _settingProvider.host, id: widget.visit.id),
future: RegularVisitsProvider().getPentry(user: _userProvider.user, host: _settingProvider.host, id: widget.visit.id),
builder: (BuildContext context, AsyncSnapshot<Pentry> snapshot) {
if (snapshot.hasError) {
return FailedLoading(

@ -3,21 +3,14 @@ import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.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/regular_visits_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/models/subtitle.dart';
import 'package:test_sa/models/visits/visits_group.dart';
import 'package:test_sa/models/visits/visits_search.dart';
import 'package:test_sa/views/app_style/colors.dart';
import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
import 'package:test_sa/views/pages/user/visits/update_visits_group_sheet.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/loaders/loading_manager.dart';
import 'package:test_sa/views/widgets/search/visits_search_bar.dart';
import 'package:test_sa/views/widgets/visits/visits_list.dart';
class RegularVisitsPage extends StatefulWidget {
@ -40,6 +33,7 @@ class _RegularVisitsPageState extends State<RegularVisitsPage> with TickerProvid
_userProvider = Provider.of<UserProvider>(context);
return Scaffold(
appBar: DefaultAppBar(title: context.translation.preventiveMaintenance),
body: SafeArea(
child: LoadingManager(
isLoading: _visitsProvider.isLoading,
@ -53,128 +47,177 @@ class _RegularVisitsPageState extends State<RegularVisitsPage> with TickerProvid
host: _settingProvider.host,
);
},
child: Stack(
children: [
Column(
children: [
Container(
color: AColors.primaryColor,
padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 4),
child: Column(
children: [
Row(
children: [
ABackButton(),
Expanded(
child: Center(
child: Text(
context.translation.preventiveMaintenance,
style: Theme.of(context).textTheme.headline6.copyWith(color: AColors.white, fontStyle: FontStyle.italic),
),
),
),
AnimatedSwitcher(
duration: Duration(milliseconds: 400),
child: AIconButton(
key: ValueKey(_expandedSearch),
iconData: _expandedSearch ? Icons.keyboard_arrow_up : Icons.search,
color: AColors.secondaryColor,
buttonSize: 42,
backgroundColor: AColors.white,
onPressed: () async {
VisitsSearch _temp = await showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (context) {
return VisitsSearchDialog(
initialSearchValue: _visitsProvider.visitsSearch,
);
});
if (_temp != null) {
_visitsProvider.visitsSearch.fromSearch(_temp);
_visitsProvider.reset();
setState(() {});
}
},
),
),
SizedBox(
width: 16,
)
],
),
],
),
),
Visibility(
visible: (_visitsProvider.visitsSearch.toMap()..remove("mostRecent")).isNotEmpty,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: AButton(
text: context.translation.clearSearch,
onPressed: () {
_visitsProvider.visitsSearch = VisitsSearch();
_visitsProvider.reset();
setState(() {});
},
),
),
),
Expanded(
child: VisitsList(
nextPage: _visitsProvider.nextPage,
onLazyLoad: () async {
await _visitsProvider.getVisits(
user: _userProvider.user,
host: _settingProvider.host,
);
},
onEditGroup: (visits) async {
VisitsGroup _group = await showModalBottomSheet(
isScrollControlled: true,
context: context,
builder: (context) {
return UpdateVisitsGroupSheet(
visits: visits,
title: context.translation.updateRegularVisits,
);
},
) as VisitsGroup;
if (_group != null) {
showDialog<void>(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return CupertinoAlertDialog(
title: Text(context.translation.updatingDots),
content: Center(child: CircularProgressIndicator()),
);
},
);
int status = await _visitsProvider.updateGroupOfVisits(user: _userProvider.user, host: _settingProvider.host, group: _group);
Navigator.of(context).pop();
if (status >= 200 && status < 300) {
Fluttertoast.showToast(
msg: context.translation.preventiveMaintenanceUpdatedSuccessfully,
toastLength: Toast.LENGTH_LONG,
gravity: ToastGravity.BOTTOM,
);
} else {
Fluttertoast.showToast(
msg: HttpStatusManger.getStatusMessage(status: status, subtitle: context.translation),
toastLength: Toast.LENGTH_LONG,
gravity: ToastGravity.BOTTOM,
);
}
}
},
visits: _visitsProvider.visits,
),
),
],
),
],
child: VisitsList(
nextPage: _visitsProvider.nextPage,
onLazyLoad: () async {
await _visitsProvider.getVisits(
user: _userProvider.user,
host: _settingProvider.host,
);
},
onEditGroup: (visits) async {
VisitsGroup group = await showModalBottomSheet(
isScrollControlled: true,
context: context,
builder: (context) {
return UpdateVisitsGroupSheet(
visits: visits,
title: context.translation.updateRegularVisits,
);
},
) as VisitsGroup;
if (group != null) {
showDialog<void>(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return CupertinoAlertDialog(
title: Text(context.translation.updatingDots),
content: Center(child: CircularProgressIndicator()),
);
},
);
int status = await _visitsProvider.updateGroupOfVisits(user: _userProvider.user, host: _settingProvider.host, group: group);
Navigator.of(context).pop();
if (status >= 200 && status < 300) {
Fluttertoast.showToast(
msg: context.translation.preventiveMaintenanceUpdatedSuccessfully,
toastLength: Toast.LENGTH_LONG,
gravity: ToastGravity.BOTTOM,
);
} else {
Fluttertoast.showToast(
msg: HttpStatusManger.getStatusMessage(status: status, subtitle: context.translation),
toastLength: Toast.LENGTH_LONG,
gravity: ToastGravity.BOTTOM,
);
}
}
},
visits: _visitsProvider.visits,
),
// child: Stack(
// children: [
// Column(
// children: [
// Container(
// color: AColors.primaryColor,
// padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 4),
// child: Column(
// children: [
// Row(
// children: [
// ABackButton(),
// Expanded(
// child: Center(
// child: Text(
// context.translation.preventiveMaintenance,
// style: Theme.of(context).textTheme.headline6.copyWith(color: AColors.white, fontStyle: FontStyle.italic),
// ),
// ),
// ),
// AnimatedSwitcher(
// duration: Duration(milliseconds: 400),
// child: AIconButton(
// key: ValueKey(_expandedSearch),
// iconData: _expandedSearch ? Icons.keyboard_arrow_up : Icons.search,
// color: AColors.secondaryColor,
// buttonSize: 42,
// backgroundColor: AColors.white,
// onPressed: () async {
// VisitsSearch _temp = await showModalBottomSheet(
// context: context,
// isScrollControlled: true,
// builder: (context) {
// return VisitsSearchDialog(
// initialSearchValue: _visitsProvider.visitsSearch,
// );
// });
// if (_temp != null) {
// _visitsProvider.visitsSearch.fromSearch(_temp);
// _visitsProvider.reset();
// setState(() {});
// }
// },
// ),
// ),
// SizedBox(
// width: 16,
// )
// ],
// ),
// ],
// ),
// ),
// Visibility(
// visible: (_visitsProvider.visitsSearch.toMap()..remove("mostRecent")).isNotEmpty,
// child: Padding(
// padding: const EdgeInsets.all(8.0),
// child: AButton(
// text: context.translation.clearSearch,
// onPressed: () {
// _visitsProvider.visitsSearch = VisitsSearch();
// _visitsProvider.reset();
// setState(() {});
// },
// ),
// ),
// ),
// Expanded(
// child: VisitsList(
// nextPage: _visitsProvider.nextPage,
// onLazyLoad: () async {
// await _visitsProvider.getVisits(
// user: _userProvider.user,
// host: _settingProvider.host,
// );
// },
// onEditGroup: (visits) async {
// VisitsGroup _group = await showModalBottomSheet(
// isScrollControlled: true,
// context: context,
// builder: (context) {
// return UpdateVisitsGroupSheet(
// visits: visits,
// title: context.translation.updateRegularVisits,
// );
// },
// ) as VisitsGroup;
// if (_group != null) {
// showDialog<void>(
// context: context,
// barrierDismissible: false,
// builder: (BuildContext context) {
// return CupertinoAlertDialog(
// title: Text(context.translation.updatingDots),
// content: Center(child: CircularProgressIndicator()),
// );
// },
// );
// int status = await _visitsProvider.updateGroupOfVisits(user: _userProvider.user, host: _settingProvider.host, group: _group);
// Navigator.of(context).pop();
// if (status >= 200 && status < 300) {
// Fluttertoast.showToast(
// msg: context.translation.preventiveMaintenanceUpdatedSuccessfully,
// toastLength: Toast.LENGTH_LONG,
// gravity: ToastGravity.BOTTOM,
// );
// } else {
// Fluttertoast.showToast(
// msg: HttpStatusManger.getStatusMessage(status: status, subtitle: context.translation),
// toastLength: Toast.LENGTH_LONG,
// gravity: ToastGravity.BOTTOM,
// );
// }
// }
// },
// visits: _visitsProvider.visits,
// ),
// ),
// ],
// ),
// ],
// ),
),
),
);

@ -1,22 +1,19 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/localization/localization.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/visits/visit.dart';
import 'package:test_sa/views/app_style/colors.dart';
import 'package:test_sa/views/app_style/sizing.dart';
import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
import 'package:test_sa/views/pages/user/visits/pantry/edit_pentry.dart';
import 'package:test_sa/views/widgets/buttons/app_back_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/images/images_list.dart';
import 'package:test_sa/views/widgets/requests/info_row.dart';
import 'package:test_sa/views/widgets/visits/visit_status.dart';
import '../../../../controllers/providers/api/user_provider.dart';
import '../../../../models/enums/user_types.dart';
import '../../../widgets/loaders/image_loader.dart';
import '../../../../new_views/common_widgets/app_filled_button.dart';
import '../../../app_style/colors.dart';
import '../../../widgets/requests/request_status.dart';
class VisitDetailsPage extends StatelessWidget {
static const String id = "/visit-details";
@ -29,149 +26,64 @@ class VisitDetailsPage extends StatelessWidget {
UserProvider userProvider = Provider.of<UserProvider>(context);
return Scaffold(
appBar: DefaultAppBar(title: context.translation.preventiveMaintenance),
body: SafeArea(
child: Column(
children: [
Container(
color: AColors.primaryColor,
padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 4),
child: Row(
children: [
const ABackButton(),
Expanded(
child: Center(
child: Text(
context.translation.visitInformation,
style: Theme.of(context).textTheme.titleLarge.copyWith(color: AColors.white, fontStyle: FontStyle.italic),
),
),
),
if (userProvider?.user?.type == UsersTypes.engineer)
AIconButton(
iconData: Icons.edit,
color: AColors.white,
buttonSize: 42,
backgroundColor: AColors.green,
onPressed: visit?.status?.name == "Closed" || visit?.status?.name == "Complete"
? null
: () async {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => EditPentry(
visit: visit,
pentry: visit.pentry,
),
),
);
},
),
const SizedBox(width: 42)
],
),
),
Expanded(
child: ListView(
padding: const EdgeInsets.symmetric(horizontal: 16),
children: [
const SizedBox(height: 8),
// MaterialButton(
// padding: EdgeInsets.zero,
// onPressed: () {
// if ((visit.images?.isNotEmpty ?? false) && (visit.images?.first?.isNotEmpty ?? false)) {
// Navigator.of(context).push(
// MaterialPageRoute(
// builder: (_) => Scaffold(
// body: InteractiveViewer(
// child: Center(
// child: ImageLoader(
// url: visit.images.first,
// boxFit: BoxFit.contain,
// ),
// ),
// ),
// ),
// ),
// );
// }
// },
// child: SizedBox(
// height: 140 * AppStyle.getScaleFactor(context),
// width: MediaQuery.of(context).size.width,
// child: ImageLoader(
// url: visit.images.isEmpty ? " " : visit.images.first,
// boxFit: BoxFit.cover,
// ),
// ),
// ),
// const SizedBox(
// height: 8,
// ),
if (visit?.images?.isNotEmpty ?? false)
SizedBox(
height: 60 * AppStyle.getScaleFactor(context),
child: FilesList(
images: visit.images,
),
).paddingOnly(top: 4, bottom: 4),
const SizedBox(
height: 8,
),
RequestInfoRow(
title: context.translation.code,
info: visit.serialNumber,
),
RequestInfoRow(
title: "Asset Number",
info: visit.deviceNumber,
),
RequestInfoRow(
title: context.translation.deviceName,
content: visit.deviceEnglishName,
),
RequestInfoRow(
title: context.translation.deviceSN,
info: visit.deviceSerialNumber,
),
RequestInfoRow(
title: context.translation.expectDate,
info: visit.expectDate,
),
RequestInfoRow(
title: context.translation.actualDate,
info: visit.actualDate,
),
Row(
children: [
Expanded(
child: Text(
"${context.translation.status} : ",
style: Theme.of(context).textTheme.titleMedium.copyWith(fontWeight: FontWeight.bold),
textScaleFactor: AppStyle.getScaleFactor(context),
SingleChildScrollView(
child: Container(
margin: const EdgeInsets.all(16),
width: double.infinity,
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(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
// StatusLabel(
// label: visit.priority.name,
// id: visit.priority.id,
// textColor: AColors.getPriorityStatusTextColor(visit.priority.id),
// backgroundColor: AColors.getPriorityStatusColor(visit.priority.id)),
// 8.width,
StatusLabel(
label: visit.status.name,
id: visit.status.id,
textColor: AColors.getRequestStatusTextColor(visit.status.value),
backgroundColor: AColors.getRequestStatusColor(visit.status.value),
),
),
VisitStatusLabel(
visit: visit,
),
],
),
Divider(
color: Theme.of(context).primaryColor,
),
RequestInfoRow(
title: context.translation.contactStatus,
info: visit.assignTo,
),
RequestInfoRow(
title: context.translation.engineerName,
info: visit.employName,
),
RequestInfoRow(
title: context.translation.hospital,
content: visit.hospitalName,
),
],
1.width.expanded,
],
),
8.height,
Text(visit.deviceEnglishName, style: AppTextStyles.heading5.copyWith(color: const Color(0xFF3B3D4A))),
8.height,
Text('${context.translation.assetNumber}: ${visit.deviceNumber}', style: AppTextStyles.bodyText.copyWith(color: const Color(0xFF757575))),
Text('Asset Serial No.: ${visit.deviceSerialNumber}', style: AppTextStyles.bodyText.copyWith(color: const Color(0xFF757575))),
Text('Code: ${visit.serialNumber}', style: AppTextStyles.bodyText.copyWith(color: const Color(0xFF757575))),
const Divider().defaultStyle(context),
Text('Expected Date: ${visit.expectDate?.toServiceRequestDetailsFormat}', style: AppTextStyles.bodyText.copyWith(color: const Color(0xFF757575))),
Text('Actual Date: ${visit.actualDate?.toServiceRequestDetailsFormat}', style: AppTextStyles.bodyText.copyWith(color: const Color(0xFF757575))),
const Divider().defaultStyle(context),
Text('Assigned to: ${visit.assignTo}', style: AppTextStyles.bodyText.copyWith(color: const Color(0xFF757575))),
Text('Engineer Name: ${visit.employName}', style: AppTextStyles.bodyText.copyWith(color: const Color(0xFF757575))),
Text('Site: ${visit.hospitalName}', style: AppTextStyles.bodyText.copyWith(color: const Color(0xFF757575))),
],
).paddingAll(16),
),
),
).expanded,
if (userProvider.user.type == UsersTypes.engineer && visit.status.value != 5 && visit.status.value != 3)
AppFilledButton(
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(builder: (_) => EditPentry(visit: visit, pentry: visit.pentry)));
},
label: context.translation.updateRequest,
).paddingAll(16),
],
),
),

@ -1,11 +1,13 @@
import 'package:flutter/material.dart';
import 'package:flutter_typeahead/flutter_typeahead.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/parts_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/views/app_style/colors.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/views/app_style/sizing.dart';
import '../../../extensions/text_extensions.dart';
import '../../../models/service_request/spare_parts.dart';
class AutoCompletePartsField extends StatefulWidget {
@ -32,6 +34,14 @@ class _AutoCompletePartsFieldState extends State<AutoCompletePartsField> {
super.initState();
}
@override
void didUpdateWidget(covariant AutoCompletePartsField oldWidget) {
if (widget.initialValue != oldWidget.initialValue) {
_controller = TextEditingController(text: widget.initialValue);
}
super.didUpdateWidget(oldWidget);
}
@override
void dispose() {
_controller.dispose();
@ -47,17 +57,17 @@ class _AutoCompletePartsFieldState extends State<AutoCompletePartsField> {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 16),
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(color: AColors.black),
borderRadius: BorderRadius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context)),
boxShadow: const [AppStyle.boxShadow]),
child:
Container() /*TypeAheadField<SparePartsWorkOrders>(
color: Colors.white,
borderRadius: BorderRadius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context)),
boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)],
),
child: TypeAheadField<SparePartsWorkOrders>(
textFieldConfiguration: TextFieldConfiguration(
style: Theme.of(context).textTheme.subtitle1,
style: AppTextStyles.bodyText,
controller: _controller,
textAlign: TextAlign.center,
decoration: const InputDecoration(
textAlign: TextAlign.start,
decoration: InputDecoration(
label: context.translation.partNumberName.tinyFont(context),
border: InputBorder.none,
disabledBorder: InputBorder.none,
focusedBorder: InputBorder.none,
@ -66,14 +76,14 @@ class _AutoCompletePartsFieldState extends State<AutoCompletePartsField> {
textInputAction: TextInputAction.search,
),
suggestionsCallback: (vale) async {
return await _partsProvider.getPartsList(title: vale, assetId: widget.assetId);
return (await _partsProvider.getPartsList(title: vale, assetId: widget.assetId)).map((e) => SparePartsWorkOrders(sparePart: e)).toList();
},
itemBuilder: (context, part) {
return ListTile(
title: Text(part?.sparePart?.partNo ?? ""),
subtitle: Text(
part?.sparePart?.partName ?? "",
style: Theme.of(context).textTheme.caption,
style: Theme.of(context).textTheme.bodySmall,
),
);
},
@ -85,8 +95,7 @@ class _AutoCompletePartsFieldState extends State<AutoCompletePartsField> {
}
widget.onPick(part);
},
)*/
,
),
);
}
}

@ -4,8 +4,10 @@ import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/devices_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/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/views/app_style/colors.dart';
import 'package:test_sa/views/app_style/sizing.dart';
import '../../../../models/device/asset.dart';
@ -33,6 +35,14 @@ class _AutoCompleteDeviceNumberFieldState extends State<AutoCompleteDeviceNumber
super.initState();
}
@override
void didUpdateWidget(covariant AutoCompleteDeviceNumberField oldWidget) {
if (widget.initialValue != oldWidget.initialValue) {
_controller = TextEditingController(text: widget.initialValue?.name);
}
super.didUpdateWidget(oldWidget);
}
@override
void dispose() {
_controller.dispose();
@ -48,16 +58,17 @@ class _AutoCompleteDeviceNumberFieldState extends State<AutoCompleteDeviceNumber
return Container(
padding: const EdgeInsets.symmetric(horizontal: 16),
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(color: AColors.black),
borderRadius: BorderRadius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context)),
boxShadow: const [AppStyle.boxShadow]),
color: Colors.white,
borderRadius: BorderRadius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context)),
boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)],
),
child: TypeAheadField<Asset>(
textFieldConfiguration: TextFieldConfiguration(
style: Theme.of(context).textTheme.headline6,
style: AppTextStyles.bodyText,
controller: _controller,
textAlign: TextAlign.center,
decoration: const InputDecoration(
textAlign: TextAlign.start,
decoration: InputDecoration(
label: context.translation.assetNumber.tinyFont(context),
border: InputBorder.none,
disabledBorder: InputBorder.none,
focusedBorder: InputBorder.none,
@ -74,10 +85,7 @@ class _AutoCompleteDeviceNumberFieldState extends State<AutoCompleteDeviceNumber
);
},
itemBuilder: (context, device) {
return ListTile(
title: Text(device.assetNumber),
subtitle: Text("${device.modelDefinition.modelName}/${device.modelDefinition.manufacturerName}"),
);
return device.assetNumber.bodyText(context).paddingOnly(bottom: 16, start: 16);
},
onSuggestionSelected: (device) {
_controller.text = device.assetNumber;

@ -1,24 +1,21 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/localization/localization.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/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/pantry/calibration_tools.dart';
import 'package:test_sa/views/app_style/sizing.dart';
import 'package:test_sa/views/widgets/buttons/app_button.dart';
import 'package:test_sa/views/widgets/buttons/app_small_button.dart';
import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
import 'package:test_sa/views/widgets/date_and_time/date_picker.dart';
import 'package:test_sa/views/widgets/pentry/auto_complete_fields/auto_complete_devices_field.dart';
import 'package:test_sa/views/widgets/titles/app_sub_title.dart';
import '../../../new_views/app_style/app_color.dart';
class PentryCalibrationToolForm extends StatefulWidget {
final List<CalibrationTool> models;
final bool enableValidate;
const PentryCalibrationToolForm({
Key key,
this.models,
this.enableValidate,
}) : super(key: key);
const PentryCalibrationToolForm({Key key, this.models, this.enableValidate}) : super(key: key);
@override
State<PentryCalibrationToolForm> createState() => _PentryCalibrationToolFormState();
@ -27,48 +24,46 @@ class PentryCalibrationToolForm extends StatefulWidget {
class _PentryCalibrationToolFormState extends State<PentryCalibrationToolForm> {
@override
Widget build(BuildContext context) {
final userProvider = Provider.of<UserProvider>(context);
return ListView.builder(
padding: EdgeInsets.only(
top: 12 * AppStyle.getScaleFactor(context), left: 12 * AppStyle.getScaleFactor(context), right: 12 * AppStyle.getScaleFactor(context), bottom: 80 * AppStyle.getScaleFactor(context)),
itemCount: widget.models.length + 1,
itemBuilder: (context, index) {
if (index == widget.models.length) {
return AButton(
text: context.translation.add,
onPressed: () {
widget.models.add(CalibrationTool());
setState(() {});
},
);
}
final model = widget.models[index];
return Column(
itemCount: widget.models.length + 1,
padding: EdgeInsets.only(top: 16.toScreenHeight),
itemBuilder: (context, index) {
if (index == widget.models.length) {
return AppFilledButton(
label: "Add Asset",
maxWidth: true,
textColor: Colors.white,
buttonColor: context.isDark ? AppColor.neutral60 : AppColor.neutral50,
onPressed: () {
widget.models.add(CalibrationTool());
setState(() {});
},
);
}
final model = widget.models[index];
return Container(
padding: const EdgeInsets.all(16),
margin: EdgeInsets.only(bottom: 16.toScreenHeight),
decoration: BoxDecoration(
color: Theme.of(context).cardColor,
borderRadius: BorderRadius.circular(20),
boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.03), blurRadius: 14)],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ASubTitle("#${index + 1}"),
if (index != 0)
ASmallButton(
color: Theme.of(context).colorScheme.error,
text: context.translation.delete,
onPressed: () {
widget.models.remove(model);
setState(() {});
},
),
"Asset ${index + 1}".heading5(context),
"trash".toSvgAsset(height: 20, width: 15).onPress(() {
widget.models.remove(model);
setState(() {});
}),
],
),
const SizedBox(
height: 8,
),
const ASubTitle("Asset Number"),
const SizedBox(
height: 4,
),
16.height,
AutoCompleteDeviceNumberField(
initialValue: model.assetsNumber,
hospitalId: userProvider.user.clientId,
@ -76,28 +71,19 @@ class _PentryCalibrationToolFormState extends State<PentryCalibrationToolForm> {
model.assetsNumber = number;
},
),
const SizedBox(
height: 8,
),
const ASubTitle("Date of Testing"),
const SizedBox(
height: 4,
),
8.height,
ADatePicker(
label: "Calibration Date",
date: model.dataOfTesting,
onDatePicker: (date) {
model.dataOfTesting = date;
setState(() {});
},
),
const SizedBox(
height: 8,
),
Divider(
color: Theme.of(context).textTheme.titleMedium.color,
),
],
);
});
),
);
},
);
}
}

@ -1,209 +0,0 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/user_provider.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/models/pantry/pentry.dart';
import 'package:test_sa/views/app_style/sizing.dart';
import 'package:test_sa/views/widgets/app_text_form_field.dart';
import 'package:test_sa/views/widgets/date_and_time/date_picker.dart';
import 'package:test_sa/views/widgets/e_signature/e_signature.dart';
import 'package:test_sa/views/widgets/status/pentry/pentry_visit_status_mune.dart';
import 'package:test_sa/views/widgets/timer/app_timer.dart';
import 'package:test_sa/views/widgets/titles/app_sub_title.dart';
import '../images/multi_image_picker.dart';
import '../status/pentry/pentry_status_mune.dart';
class PentryInfoForm extends StatefulWidget {
final Pentry model;
final bool enableValidate;
const PentryInfoForm({
Key key,
this.model,
this.enableValidate,
}) : super(key: key);
@override
State<PentryInfoForm> createState() => _PentryInfoFormState();
}
class _PentryInfoFormState extends State<PentryInfoForm> {
@override
Widget build(BuildContext context) {
widget.model?.files ??= [];
final userProvider = Provider.of<UserProvider>(context);
return Padding(
padding: EdgeInsets.only(
top: 12 * AppStyle.getScaleFactor(context), left: 12 * AppStyle.getScaleFactor(context), right: 12 * AppStyle.getScaleFactor(context), bottom: 80 * AppStyle.getScaleFactor(context)),
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const SizedBox(
height: 8,
),
const ASubTitle("PPM Visit Status"),
if (widget.enableValidate && widget.model.ppmVisitStatus == null)
ASubTitle(
context.translation.requiredWord,
color: Colors.red,
),
const SizedBox(
height: 4,
),
PentryVisitsStatusMenu(
initialValue: widget.model.ppmVisitStatus,
onSelect: (status) {
if (status != null) {
widget.model.ppmVisitStatus = status;
}
},
),
const SizedBox(
height: 8,
),
const ASubTitle("Timer"),
if (widget.enableValidate && widget.model?.timer?.endAt == null)
ASubTitle(
context.translation.requiredWord,
color: Colors.red,
),
const SizedBox(
height: 4,
),
AppTimer(
timer: widget.model.timer,
enabled: widget.model.timer.endAt == null,
onChange: (timer) async {
widget.model.timer = timer;
return true;
},
),
const SizedBox(
height: 8,
),
const ASubTitle("Status"),
if (widget.enableValidate && widget.model.status == null)
ASubTitle(
context.translation.requiredWord,
color: Colors.red,
),
const SizedBox(
height: 4,
),
PentryStatusMenu(
initialValue: widget.model.status,
onSelect: (status) {
widget.model.status = status;
},
),
const SizedBox(
height: 8,
),
const ASubTitle("Actual Visit Date"),
if (widget.enableValidate && widget.model.actualVisitDate == null)
ASubTitle(
context.translation.requiredWord,
color: Colors.red,
),
const SizedBox(
height: 4,
),
ADatePicker(
date: widget.model.actualVisitDate,
from: DateTime.now().subtract(const Duration(days: 30)),
onDatePicker: (date) {
if (date == null) return;
widget.model.actualVisitDate = date;
setState(() {});
},
),
const SizedBox(
height: 8,
),
const ASubTitle("Expected Visit Date"),
if (widget.enableValidate && widget.model.expectedVisitDate == null)
ASubTitle(
context.translation.requiredWord,
color: Colors.red,
),
const SizedBox(
height: 4,
),
ADatePicker(
date: widget.model.expectedVisitDate,
from: DateTime.now().subtract(const Duration(days: 30)),
onDatePicker: (date) {
if (date == null) return;
widget.model.expectedVisitDate = date;
setState(() {});
},
),
const SizedBox(
height: 8,
),
const ASubTitle("Traveling Hours"),
const SizedBox(
height: 4,
),
ATextFormField(
initialValue: (widget.model.travelingHours ?? "").toString(),
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.titleMedium,
textInputType: TextInputType.number,
onChange: (value) {
widget.model.travelingHours = value;
},
),
const SizedBox(height: 12),
MultiFilesPicker(label: "PPM Attachments", files: widget.model.files),
// AMiniOneFilePicker(
// //error: _validate && _serviceReport.image == null,
// file: widget.model.file,
// onPick: (file) {
// widget.model.file = file;
// },
// ),
const SizedBox(
height: 8,
),
const ASubTitle("Nurse Signature"),
ESignature(
oldSignature: widget.model.signatureNurse,
newSignature: widget.model.localNurseSignature,
onChange: (signature) {
if (signature == null || signature.isEmpty) {
return;
}
widget.model.localNurseSignature = signature;
widget.model.signatureNurse = "${DateTime.now().toIso8601String()}.png|${base64Encode(signature)}";
},
),
const SizedBox(
height: 8,
),
const ASubTitle("Engineer Signature"),
ESignature(
oldSignature: widget.model.signatureEngineer,
newSignature: widget.model.localEngineerSignature,
onChange: (signature) {
if (signature == null || signature.isEmpty) {
return;
}
widget.model.localEngineerSignature = signature;
widget.model.signatureEngineer = "${DateTime.now().toIso8601String()}.png|${base64Encode(signature)}";
},
),
const SizedBox(
height: 8,
),
],
),
),
);
}
}

@ -1,12 +1,15 @@
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 'package:test_sa/models/lookup.dart';
import 'package:test_sa/models/pantry/pm_kit.dart';
import 'package:test_sa/views/app_style/sizing.dart';
import 'package:test_sa/views/widgets/buttons/app_button.dart';
import 'package:test_sa/views/widgets/buttons/app_small_button.dart';
import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart';
import 'package:test_sa/views/widgets/parts/auto_complete_parts_field.dart';
import 'package:test_sa/views/widgets/titles/app_sub_title.dart';
import '../../../new_views/app_style/app_color.dart';
import '../../../new_views/common_widgets/app_filled_button.dart';
class PentryPMKitForm extends StatefulWidget {
final List<PMKit> models;
@ -27,18 +30,16 @@ class _PentryPMKitFormState extends State<PentryPMKitForm> {
@override
Widget build(BuildContext context) {
return ListView.builder(
padding: EdgeInsets.only(
top: 12 * AppStyle.getScaleFactor(context),
left: 12 * AppStyle.getScaleFactor(context),
right: 12 * AppStyle.getScaleFactor(context),
bottom: 100 * AppStyle.getScaleFactor(context) + MediaQuery.of(context).padding.bottom,
),
itemCount: widget.models.length + 1,
shrinkWrap: true,
padding: EdgeInsets.only(top: 16.toScreenHeight),
itemBuilder: (context, index) {
if (index == widget.models.length) {
return AButton(
text: context.translation.add,
return AppFilledButton(
label: "Add Item",
maxWidth: true,
textColor: Colors.white,
buttonColor: context.isDark ? AppColor.neutral60 : AppColor.neutral50,
onPressed: () {
widget.models.add(PMKit());
setState(() {});
@ -46,46 +47,49 @@ class _PentryPMKitFormState extends State<PentryPMKitForm> {
);
}
final model = widget.models[index];
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ASubTitle("#${index + 1}"),
if (index != 0)
ASmallButton(
color: Theme.of(context).colorScheme.error,
text: context.translation.delete,
onPressed: () {
widget.models.remove(model);
setState(() {});
},
),
],
),
const SizedBox(
height: 8,
),
const ASubTitle("Item Code"),
const SizedBox(
height: 4,
),
AutoCompletePartsField(
assetId: widget.assetId,
clearAfterPick: false,
initialValue: (model.itemCode?.name ?? "").toString(),
onPick: (part) {
model.itemCode = Lookup(id: part.id, name: part?.sparePart?.partNo);
},
),
const SizedBox(
height: 8,
),
Divider(
color: Theme.of(context).textTheme.titleMedium.color,
),
],
final TextEditingController controller = TextEditingController(text: model.quantityNeeded);
return Container(
padding: const EdgeInsets.all(16),
margin: EdgeInsets.only(bottom: 16.toScreenHeight),
decoration: BoxDecoration(
color: Theme.of(context).cardColor,
borderRadius: BorderRadius.circular(20),
boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.03), blurRadius: 14)],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"Item ${index + 1}".heading5(context),
"trash".toSvgAsset(width: 15, height: 20).onPress(() {
widget.models.remove(model);
setState(() {});
}),
],
),
16.height,
AutoCompletePartsField(
assetId: widget.assetId,
clearAfterPick: false,
initialValue: (model.itemCode?.name ?? "").toString(),
onPick: (part) {
model.itemCode = Lookup(id: part.id, name: part?.sparePart?.partNo);
model.itemName = part?.sparePart?.partName;
},
),
8.height,
AppTextFormField(
controller: controller,
labelText: context.translation.quantity,
textInputType: TextInputType.number,
onChange: (text) {
model.quantityNeeded = num.tryParse(text ?? "")?.toString();
},
),
],
),
);
},
);

@ -1,135 +1,49 @@
import 'package:flutter/material.dart';
import 'package:test_sa/controllers/localization/localization.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/models/pantry/ppm_check_list.dart';
import 'package:test_sa/views/app_style/sizing.dart';
import 'package:test_sa/views/widgets/app_text_form_field.dart';
import 'package:test_sa/views/widgets/buttons/app_button.dart';
import 'package:test_sa/views/widgets/buttons/app_small_button.dart';
import 'package:test_sa/views/widgets/status/pentry/pentry_task_status_mune.dart';
import 'package:test_sa/views/widgets/titles/app_sub_title.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart';
class PentryPPMCheckListForm extends StatefulWidget {
class PentryPMChecklistForm extends StatefulWidget {
final List<PPMCheckList> models;
final bool enableValidate;
const PentryPPMCheckListForm({
Key key,
this.models,
this.enableValidate,
}) : super(key: key);
const PentryPMChecklistForm({Key key, this.models, this.enableValidate}) : super(key: key);
@override
State<PentryPPMCheckListForm> createState() => _PentryPPMCheckListFormState();
State<PentryPMChecklistForm> createState() => _PentryPMChecklistFormState();
}
class _PentryPPMCheckListFormState extends State<PentryPPMCheckListForm> {
class _PentryPMChecklistFormState extends State<PentryPMChecklistForm> {
PPMCheckList item = PPMCheckList();
@override
Widget build(BuildContext context) {
return ListView.builder(
padding: EdgeInsets.only(
top: 12 * AppStyle.getScaleFactor(context), left: 12 * AppStyle.getScaleFactor(context), right: 12 * AppStyle.getScaleFactor(context), bottom: 80 * AppStyle.getScaleFactor(context)),
itemCount: widget.models.length + 1,
itemBuilder: (context, index) {
if (index == widget.models.length) {
return AButton(
text: context.translation.add,
onPressed: () {
widget.models.add(PPMCheckList());
setState(() {});
},
);
}
final model = widget.models[index];
return ListView(
shrinkWrap: true,
physics: const ClampingScrollPhysics(),
padding: EdgeInsets.only(top: 16.toScreenHeight),
itemCount: widget.models.length,
shrinkWrap: true,
itemBuilder: (context, index) {
final model = widget.models[index];
return Card(
child: ExpansionTile(
shape: const Border(),
title: (model.title ?? "").heading5(context),
subtitle: "Status ${model.status?.name}".bodyText(context),
initiallyExpanded: index == 0,
iconColor: AppColor.neutral50,
collapsedIconColor: AppColor.neutral50,
childrenPadding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 8.toScreenHeight),
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ASubTitle("#${index + 1}"),
if (index != 0)
ASmallButton(
color: Theme.of(context).colorScheme.error,
text: context.translation.delete,
onPressed: () {
widget.models.remove(model);
setState(() {});
},
),
],
),
const SizedBox(
height: 8,
),
const ASubTitle("Task"),
const SizedBox(
height: 4,
),
ATextFormField(
initialValue: (model.title?.trim() ?? "").toString(),
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.subtitle1,
textInputType: TextInputType.text,
onChange: (value) {
model.title = value;
},
),
const SizedBox(
height: 8,
),
ASubTitle(context.translation.status),
const SizedBox(
height: 4,
),
PentryTaskStatusMenu(
initialValue: model.status,
onSelect: (status) {
model.status = status;
},
),
const SizedBox(
height: 8,
),
const ASubTitle("Comment"),
const SizedBox(
height: 4,
),
ATextFormField(
initialValue: (model.comment ?? "").toString(),
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.subtitle1,
textInputType: TextInputType.text,
onChange: (value) {
model.comment = value;
},
),
const SizedBox(
height: 8,
),
const ASubTitle("Measured Value"),
const SizedBox(
height: 4,
),
ATextFormField(
initialValue: (model.measuredValue ?? "").toString(),
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.subtitle1,
textInputType: TextInputType.text,
onChange: (value) {
model.measuredValue = value;
},
),
const SizedBox(
height: 8,
),
Divider(
color: Theme.of(context).textTheme.titleMedium.color,
),
AppTextFormField(labelText: "Measured Value", initialValue: model.measuredValue, enable: false),
8.height,
AppTextFormField(labelText: context.translation.comment, initialValue: model.comment, enable: false),
8.height,
],
);
});
),
);
},
);
}
}

@ -0,0 +1,147 @@
import 'dart:convert';
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/models/lookup.dart';
import 'package:test_sa/models/pantry/pentry.dart';
import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart';
import 'package:test_sa/providers/ppm_device_status_provider.dart';
import 'package:test_sa/providers/ppm_visit_status_provider.dart';
import 'package:test_sa/views/widgets/e_signature/e_signature.dart';
import 'package:test_sa/views/widgets/timer/app_timer.dart';
import '../date_and_time/date_picker.dart';
import '../images/multi_image_picker.dart';
class PentryTBSForm extends StatefulWidget {
final Pentry model;
final bool enableValidate;
const PentryTBSForm({
Key key,
this.model,
this.enableValidate,
}) : super(key: key);
@override
State<PentryTBSForm> createState() => _PentryTBSFormState();
}
class _PentryTBSFormState extends State<PentryTBSForm> {
@override
Widget build(BuildContext context) {
widget.model?.files ??= [];
return SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
8.height,
SingleItemDropDownMenu<Lookup, PPMVisitStatusProvider>(
context: context,
initialValue: widget.model.ppmVisitStatus,
title: "PPM Visit Status",
onSelect: (value) {
if (value != null) {
widget.model.ppmVisitStatus = value;
}
},
),
8.height,
AppTimer(
timer: widget.model.timer,
enabled: widget.model.timer.endAt == null,
onChange: (timer) async {
widget.model.timer = timer;
return true;
},
),
8.height,
SingleItemDropDownMenu<Lookup, PPMDeviceStatusProvider>(
context: context,
initialValue: widget.model.status,
title: "Device Status",
onSelect: (value) {
if (value != null) {
widget.model.status = value;
}
},
),
8.height,
ADatePicker(
label: "Actual Visit Date",
date: widget.model.actualVisitDate,
from: DateTime.now().subtract(const Duration(days: 30)),
onDatePicker: (date) {
if (date == null) return;
widget.model.actualVisitDate = date;
setState(() {});
},
),
8.height,
ADatePicker(
label: "Expected Visit Date",
date: widget.model.expectedVisitDate,
from: DateTime.now().subtract(const Duration(days: 30)),
onDatePicker: (date) {
if (date == null) return;
widget.model.expectedVisitDate = date;
setState(() {});
},
),
8.height,
// const ASubTitle("Traveling Hours"),
// const SizedBox(
// height: 4,
// ),
// ATextFormField(
// initialValue: (widget.model.travelingHours ?? "").toString(),
// textAlign: TextAlign.center,
// style: Theme.of(context).textTheme.titleMedium,
// textInputType: TextInputType.number,
// onChange: (value) {
// widget.model.travelingHours = value;
// },
// ),
8.height,
MultiFilesPicker(label: "Attach Image", files: widget.model.files),
// AMiniOneFilePicker(
// //error: _validate && _serviceReport.image == null,
// file: widget.model.file,
// onPick: (file) {
// widget.model.file = file;
// },
// ),
8.height,
ESignature(
title: "Nurse Signature",
oldSignature: widget.model.signatureNurse,
newSignature: widget.model.localNurseSignature,
onChange: (signature) {
// if (signature == null || signature.isEmpty) {
// return;
// }
widget.model.localNurseSignature = signature;
widget.model.signatureNurse = "${DateTime.now().toIso8601String()}.png|${base64Encode(signature)}";
},
),
8.height,
ESignature(
title: context.translation.engSign,
oldSignature: widget.model.signatureEngineer,
newSignature: widget.model.localEngineerSignature,
onChange: (signature) {
// if (signature == null || signature.isEmpty) {
// return;
// }
widget.model.localEngineerSignature = signature;
widget.model.signatureEngineer = "${DateTime.now().toIso8601String()}.png|${base64Encode(signature)}";
},
),
8.height,
],
),
);
}
}

@ -1,10 +1,14 @@
import 'dart:async';
import 'package:flutter/material.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/timer_model.dart';
import 'package:test_sa/views/app_style/colors.dart';
import 'package:test_sa/views/app_style/sizing.dart';
import '../../../new_views/app_style/app_color.dart';
class AppTimer extends StatefulWidget {
final TimerModel timer;
final Future<bool> Function(TimerModel) onChange;
@ -96,37 +100,37 @@ class _AppTimerState extends State<AppTimer> {
@override
Widget build(BuildContext context) {
return SizedBox(
return Container(
width: 100 * AppStyle.getScaleFactor(context),
height: 28 * AppStyle.getScaleFactor(context),
child: ElevatedButton(
style: ElevatedButton.styleFrom(
minimumSize: const Size(1, 1), padding: EdgeInsets.all(4 * AppStyle.getScaleFactor(context)), backgroundColor: _running ? AColors.green[300] : AColors.grey, foregroundColor: Colors.black),
onPressed: _loading || widget.enabled == false ? null : _onPressed,
child: _loading
? const SizedBox.square(
dimension: 18,
child: CircularProgressIndicator(
color: Colors.white,
))
: Row(
children: [
if (widget.enabled) Icon(_running ? Icons.pause : Icons.play_arrow),
Expanded(
child: Center(
child: ValueListenableBuilder<String>(
valueListenable: _period,
builder: (context, value, _) {
return Text(
value,
style: widget.enabled ? widget.style : widget.style?.copyWith(color: Colors.black54),
);
}),
),
),
],
),
height: 56.toScreenHeight,
padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth),
decoration: BoxDecoration(
color: Theme.of(context).cardColor,
borderRadius: BorderRadius.circular(10),
boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)],
),
);
child: _loading
? const SizedBox.square(dimension: 18, child: CircularProgressIndicator(color: Colors.white))
: Row(
children: [
Expanded(
child: ValueListenableBuilder<String>(
valueListenable: _period,
builder: (context, value, _) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
"Timer".tinyFont(context),
value.bodyText(context).custom(color: AppColor.neutral50),
],
);
},
),
),
if (widget.enabled) Icon(_running ? Icons.pause : Icons.play_arrow),
],
),
).onPress(_loading || widget.enabled == false ? () {} : _onPressed);
}
}

@ -1,171 +1,100 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/localization/localization.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/widget_extensions.dart';
import 'package:test_sa/models/enums/user_types.dart';
import 'package:test_sa/models/subtitle.dart';
import 'package:test_sa/models/visits/visit.dart';
import 'package:test_sa/views/app_style/sizing.dart';
import 'package:test_sa/views/widgets/visits/visit_status.dart';
import 'package:test_sa/views/pages/user/visits/visit_details.dart';
import '../../../controllers/providers/api/user_provider.dart';
import '../../../extensions/text_extensions.dart';
import '../../app_style/colors.dart';
import '../../pages/user/visits/pantry/edit_pentry.dart';
import '../requests/request_status.dart';
class VisitItem extends StatelessWidget {
final Visit visit;
final int index;
final bool isSelected;
final bool activeSelectMod;
final Function(Visit) onPressed;
final Function(Visit) onLongPress;
final Function(Visit) onSelect;
const VisitItem({Key key, this.visit, this.onPressed, this.isSelected = false, this.activeSelectMod = false, this.onLongPress, this.onSelect, this.index}) : super(key: key);
const VisitItem({Key key, this.visit}) : super(key: key);
@override
Widget build(BuildContext context) {
UserProvider userProvider = Provider.of<UserProvider>(context);
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 Padding(
padding: const EdgeInsets.symmetric(vertical: 4),
child: ElevatedButton(
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 8),
backgroundColor: itemColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppStyle.getBorderRadius(context)),
),
),
onPressed: () {
if (activeSelectMod && userProvider.user.type == UsersTypes.engineer) {
onSelect(visit);
} else {
onPressed(visit);
}
},
onLongPress: userProvider.user.type == UsersTypes.engineer
? () {
onLongPress(visit);
}
: null,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(
child: Text(
"S.N: ${visit.deviceSerialNumber}" ?? "No serial number",
style: Theme.of(context).textTheme.titleLarge.copyWith(color: onItemColor, fontSize: 16, fontWeight: FontWeight.bold),
),
),
AnimatedSwitcher(
duration: const Duration(milliseconds: 400),
child: Visibility(
key: ValueKey(activeSelectMod),
visible: activeSelectMod,
child: SizedBox(
height: 18,
child: Checkbox(
activeColor: Colors.black38,
value: isSelected,
onChanged: (value) {
onSelect(visit);
}),
),
),
),
VisitStatusLabel(
visit: visit,
)
],
),
Divider(
color: onItemColor,
),
Text(
visit.deviceNumber ?? "",
style: Theme.of(context).textTheme.titleMedium.copyWith(color: onItemColor, fontSize: 14),
),
Divider(
color: onItemColor,
),
Row(
children: [
Expanded(
child: Text(
visit.hospitalName ?? "No client found",
style: Theme.of(context).textTheme.titleMedium.copyWith(
color: onItemColor,
fontSize: 14,
),
),
),
],
),
Text(
visit.modelAndBrand ?? "",
style: Theme.of(context).textTheme.titleMedium.copyWith(
color: onItemColor,
fontSize: 14,
),
),
if (visit.employName != null && visit.employName.isNotEmpty) Divider(color: onItemColor),
if (visit.employName != null && visit.employName.isNotEmpty)
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)],
),
padding: const EdgeInsets.all(16),
margin: EdgeInsets.only(bottom: 8.toScreenHeight),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(
child: Text(
visit.employName ?? "No employ found",
style: Theme.of(context).textTheme.titleLarge.copyWith(color: onItemColor, fontSize: 14, fontWeight: FontWeight.bold),
),
// StatusLabel(
// label: visit.priority.name,
// id: visit.priority.id,
// textColor: AColors.getPriorityStatusTextColor(visit.priority.id),
// backgroundColor: AColors.getPriorityStatusColor(visit.priority.id)),
// 8.width,
StatusLabel(
label: visit.status.name,
id: visit.status.id,
textColor: AColors.getRequestStatusTextColor(visit.status.value),
backgroundColor: AColors.getRequestStatusColor(visit.status.value),
),
// Text(
// visit.contactStatus ?? "",
// style: Theme.of(context).textTheme.subtitle1.copyWith(
// color: onItemColor,
// fontSize: 14,
// ),
// ),
1.width.expanded,
],
),
Divider(
color: onItemColor,
),
Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
context.translation.expectDate,
style: Theme.of(context).textTheme.titleLarge.copyWith(color: onItemColor, fontSize: 14),
),
Text(
visit.expectDate ?? context.translation.noDateFound,
style: Theme.of(context).textTheme.titleLarge.copyWith(color: onItemColor, fontSize: 14),
),
],
8.height,
Text(visit.deviceEnglishName, style: AppTextStyles.heading5.copyWith(color: const Color(0xFF3B3D4A))),
8.height,
Text(
'${context.translation.assetNumber}: ${visit.deviceNumber}',
style: AppTextStyles.bodyText.copyWith(color: const Color(0xFF757575)),
),
Text(
'Asset Serial No.: ${visit.deviceSerialNumber}',
style: AppTextStyles.bodyText.copyWith(color: const Color(0xFF757575)),
),
Text(
'Code: ${visit.serialNumber}',
style: AppTextStyles.bodyText.copyWith(color: const Color(0xFF757575)),
),
16.height,
Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
'View Details',
style: AppTextStyles.bodyText.copyWith(color: const Color(0xFF4A8DB7)),
),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
context.translation.actualDate,
style: Theme.of(context).textTheme.titleLarge.copyWith(color: onItemColor, fontSize: 14),
),
Text(
visit.actualDate ?? context.translation.noDateFound,
style: Theme.of(context).textTheme.titleLarge.copyWith(color: onItemColor, fontSize: 14),
),
],
),
],
),
],
),
4.width,
const Icon(Icons.arrow_forward, color: Color(0xFF4A8DB7), size: 14)
],
).onPress(() {
Navigator.of(context).push(MaterialPageRoute(builder: (_) => VisitDetailsPage(visit: visit)));
}),
],
).expanded,
8.width,
Column(
children: [
if (userProvider.user.type == UsersTypes.engineer && visit.status.value != 5 && visit.status.value != 3)
"edit".toSvgAsset(height: 48, width: 48).onPress(() {
Navigator.of(context).push(MaterialPageRoute(builder: (_) => EditPentry(visit: visit, pentry: visit.pentry)));
}),
Text(visit.createdOn != null ? visit.createdOn.toServiceRequestCardFormat : "", textAlign: TextAlign.end, style: AppTextStyles.tinyFont.copyWith(color: const Color(0xFF3B3D4A))),
],
)
],
),
);
}

@ -1,14 +1,13 @@
import 'package:flutter/material.dart';
import 'package:test_sa/controllers/localization/localization.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/models/subtitle.dart';
import 'package:test_sa/models/visits/visit.dart';
import 'package:test_sa/views/app_style/sizing.dart';
import 'package:test_sa/views/pages/user/visits/visit_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/visits/visit_item.dart';
import '../../../controllers/providers/api/user_provider.dart';
class VisitsList extends StatefulWidget {
final List<Visit> visits;
final bool nextPage;
@ -32,10 +31,9 @@ class _VisitsListState extends State<VisitsList> {
@override
Widget build(BuildContext context) {
UserProvider userProvider = Provider.of<UserProvider>(context);
if (widget.visits.isEmpty) {
return NoItemFound(
message: context.translation.noVisitsFound,
);
return NoItemFound(message: context.translation.noVisitsFound);
}
return Stack(
children: [
@ -43,81 +41,54 @@ class _VisitsListState extends State<VisitsList> {
nextPage: widget.nextPage,
onLazyLoad: widget.onLazyLoad,
child: ListView.builder(
//physics: BouncingScrollPhysics(),
itemCount: widget.visits.length,
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
itemBuilder: (context, itemIndex) {
Visit visit = widget.visits[itemIndex];
bool isSelected = _selectedVisits.contains(visit);
return VisitItem(
visit: visit,
isSelected: isSelected,
index: itemIndex,
activeSelectMod: _selectedVisits.isNotEmpty,
onPressed: (visit) {
Navigator.of(context).push(MaterialPageRoute(
builder: (_) => VisitDetailsPage(
visit: visit,
)));
},
onSelect: (visit) {
if (isSelected) {
_selectedVisits.remove(visit);
} else {
_selectedVisits.add(visit);
}
setState(() {});
},
onLongPress: (visit) {
if (isSelected) {
_selectedVisits.remove(visit);
} else {
_selectedVisits.add(visit);
}
setState(() {});
},
);
}),
),
Align(
alignment: Alignment.bottomLeft,
child: Padding(
padding: EdgeInsets.all(8.0 * AppStyle.getScaleFactor(context)),
child: AnimatedSwitcher(
duration: const Duration(milliseconds: 400),
child: Visibility(
key: ValueKey(_selectedVisits.isNotEmpty),
visible: _selectedVisits.isNotEmpty,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
FloatingActionButton(
heroTag: "cancel",
child: const Icon(Icons.cancel),
onPressed: () {
_selectedVisits.clear();
setState(() {});
},
),
FloatingActionButton(
heroTag: "edit",
child: const Icon(Icons.edit),
onPressed: () {
if (!widget.visits.contains(_selectedVisits.first)) {
_selectedVisits.clear();
setState(() {});
return;
}
widget.onEditGroup(_selectedVisits);
//_selectedVisits.clear();
},
),
],
),
),
),
itemCount: widget.visits.length,
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
itemBuilder: (context, itemIndex) {
Visit visit = widget.visits[itemIndex];
// bool isSelected = _selectedVisits.contains(visit);
return VisitItem(visit: visit);
},
),
)
),
// Align(
// alignment: Alignment.bottomLeft,
// child: Padding(
// padding: EdgeInsets.all(8.0 * AppStyle.getScaleFactor(context)),
// child: AnimatedSwitcher(
// duration: const Duration(milliseconds: 400),
// child: Visibility(
// key: ValueKey(_selectedVisits.isNotEmpty),
// visible: _selectedVisits.isNotEmpty,
// child: Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// FloatingActionButton(
// heroTag: "cancel",
// child: const Icon(Icons.cancel),
// onPressed: () {
// _selectedVisits.clear();
// setState(() {});
// },
// ),
// FloatingActionButton(
// heroTag: "edit",
// child: const Icon(Icons.edit),
// onPressed: () {
// if (!widget.visits.contains(_selectedVisits.first)) {
// _selectedVisits.clear();
// setState(() {});
// return;
// }
// widget.onEditGroup(_selectedVisits);
// //_selectedVisits.clear();
// },
// ),
// ],
// ),
// ),
// ),
// ),
// )
],
);
}

Loading…
Cancel
Save