timer picker added and improvements

design_3.0_task_module_new
Sikander Saleem 5 months ago
parent 7f594fbb41
commit 64a2d39cb1

@ -50,7 +50,7 @@ class ApiManager {
return response;
}
Future<http.Response> post(String url, {Map<String, String>? headers, required Map<String, dynamic> body, bool ?showToast = true}) async {
Future<http.Response> post(String url, {Map<String, String>? headers, required Map<String, dynamic> body, bool showToast = true}) async {
headers ??= {};
headers.addAll(_headers);
@ -74,7 +74,7 @@ class ApiManager {
} else {
if (jsonDecode(response.body) is Map<String, dynamic>) {
final message = jsonDecode(response.body)["message"];
if (message != null && message.toString().isNotEmpty&&showToast!) {
if (message != null && message.toString().isNotEmpty && showToast) {
Fluttertoast.showToast(msg: message ?? "", toastLength: Toast.LENGTH_LONG);
}
}
@ -83,6 +83,7 @@ class ApiManager {
return response;
}
Future<http.Response> delete(String url, {Map<String, String>? headers, required Map<String, dynamic> body}) async {
headers ??= {};

@ -3,14 +3,14 @@ class URLs {
static const String appReleaseBuildNumber = "16";
static const host1 = "https://atomsm.hmg.com"; // production url
// static const host1 = "https://atomsm.hmg.com"; // production url
// static const host1 = "https://atomsmdev.hmg.com"; // local DEV url
// static const host1 = "https://atomsmuat.hmg.com"; // local UAT url
static const host1 = "https://atomsmuat.hmg.com"; // local UAT url
// static String _baseUrl = "$_host/mobile";
static String _baseUrl = "$_host/mobile";
// static final String _baseUrl = "$_host/v2/mobile"; // new V2 apis
// static final String _baseUrl = "$_host/mobile"; // host local UAT
static final String _baseUrl = "$_host/v3/mobile"; // v3 for new CM,PM,TM
// static final String _baseUrl = "$_host/v3/mobile"; // v3 for new CM,PM,TM
static String _host = host1;

@ -52,7 +52,7 @@ class RequestCategoryFragment extends StatelessWidget {
getTabs(
requestsProvider: dashboardProvider,
context: context,
userType: Provider.of<UserProvider>(context, listen: false).user?.type!,
userType: Provider.of<UserProvider>(context, listen: false).user?.type,
),
dashboardProvider.isDetailLoading
? Column(

@ -38,6 +38,14 @@ extension StringExtensions on String {
return "";
}
}
String get toYMDHMSA {
try {
DateTime dateTime = DateTime.parse(this);
return "${DateFormat('yyyy-MM-dd').format(dateTime)} ${DateFormat('hh:mm a').format(dateTime)}";
} catch (e) {
return "";
}
}
String get toMonthYearFormat {
try {
DateTime dateTime = DateTime.parse(this);

@ -77,7 +77,6 @@ import 'package:test_sa/views/pages/device_transfer/device_search_screen.dart';
import 'package:test_sa/views/pages/user/gas_refill/request_gas_refill.dart';
import 'package:test_sa/views/pages/user/gas_refill/update_gas_refill_request.dart';
import 'package:test_sa/views/pages/user/notifications/notifications_page.dart';
import 'package:test_sa/views/pages/user/profile_page.dart';
import 'package:test_sa/views/pages/user/requests/create_service_request_page.dart';
import 'package:test_sa/views/update_available_screen.dart';
@ -92,7 +91,6 @@ import 'controllers/providers/api/gas_refill_comments.dart';
import 'controllers/providers/api/user_provider.dart';
import 'controllers/providers/settings/setting_provider.dart';
import 'dashboard_latest/dashboard_provider.dart';
import 'new_views/pages/gas_refill_request_form.dart';
import 'providers/service_request_providers/loan_availability_provider.dart';
import 'providers/service_request_providers/reject_reason_provider.dart';
@ -122,7 +120,7 @@ void main() async {
} else {
await Firebase.initializeApp();
}
SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(statusBarColor: Colors.transparent));
SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(statusBarColor: Colors.transparent, systemNavigationBarColor: Colors.white));
/// only portrait mode
SystemChrome.setPreferredOrientations([

@ -34,6 +34,7 @@ class ActivityMaintenanceHelperModel {
List<AssistantEmployees>? assistantEmployees;
List<ActivityMaintenanceTimers>? activityMaintenanceTimers = [];
TimerModel? activityMaintenanceTimerModel = TimerModel();
TimerModel? activityTimePicker;
List<TimerModel>? timerModelList = [];
ActivityMaintenanceHelperModel(
@ -47,6 +48,7 @@ class ActivityMaintenanceHelperModel {
this.endTime,
this.workingHour,
this.activityMaintenanceTimerModel,
this.activityTimePicker,
this.travelHours,
this.repairLocation,
this.assignedEmployeeId,

@ -84,6 +84,28 @@ class ServiceRequestUtils {
return formattedDuration.trim();
}
static String formatTimerDurationCM(int seconds) {
int hours = seconds ~/ 3600;
int minutes = (seconds % 3600) ~/ 60;
int remainingSeconds = seconds % 60;
String formattedDuration = '';
if (hours > 0) {
formattedDuration += '$hours hour${hours > 1 ? 's' : ''} ';
}
if (minutes > 0) {
formattedDuration += '$minutes minute${minutes > 1 ? 's' : ''} ';
}
if (remainingSeconds > 0) {
formattedDuration += '$remainingSeconds second${remainingSeconds > 1 ? 's' : ''} ';
}
if (formattedDuration.isEmpty) {
formattedDuration = 'Less than a minute';
}
return formattedDuration.trim();
}
static void getQrCode({required BuildContext context}) async {
showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
ServiceRequestDetailProvider requestDetailProvider = Provider.of<ServiceRequestDetailProvider>(context, listen: false);

@ -62,6 +62,7 @@ class _ExternalMaintenanceRequestState extends State<ExternalMaintenanceRequest>
backgroundColor: AppColor.neutral100,
initialValue: requestDetailProvider.activityMaintenanceHelperModel?.supplier,
showAsBottomSheet: true,
showShadow: false,
onSelect: (supplier) {
if (supplier != null) {
requestDetailProvider.activityMaintenanceHelperModel?.supplier = supplier;

@ -1,8 +1,5 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_report_repair_location_provider.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart';
@ -19,7 +16,6 @@ import 'package:test_sa/views/widgets/timer/app_timer.dart';
import 'assistant_employee_card.dart';
class InternalMaintenanceRequest extends StatefulWidget {
static const String id = "/add-internal-activity";
@ -36,7 +32,6 @@ class _InternalMaintenanceRequestState extends State<InternalMaintenanceRequest>
final TextEditingController _travellingHoursController = TextEditingController();
Lookup statusLookup = Lookup.fromJson({"id": 5619, "name": "New", "value": 1});
@override
void initState() {
_requestDetailProvider = Provider.of<ServiceRequestDetailProvider>(context, listen: false);
@ -105,10 +100,25 @@ class _InternalMaintenanceRequestState extends State<InternalMaintenanceRequest>
},
),
8.height,
// AppTimerPicker(
// label: context.translation.timer,
// timer: requestDetailProvider.activityMaintenanceHelperModel?.activityTimePicker,
// enabled: enableTimer,
// // timerList: requestDetailProvider.activityMaintenanceHelperModel?.timerModelList ?? [],
// onPick: (time) {
// requestDetailProvider.activityMaintenanceHelperModel?.activityTimePicker = time;
// },
// ),
// 8.height,
AppTimer(
label: context.translation.timer,
timer: requestDetailProvider.activityMaintenanceHelperModel?.activityMaintenanceTimerModel,
enabled: enableTimer,
pickerTimer: requestDetailProvider.activityMaintenanceHelperModel?.activityTimePicker,
canPickTime: true,
onPick: (time) {
requestDetailProvider.activityMaintenanceHelperModel?.activityTimePicker = time;
},
timerProgress: (isRunning) {
print("timerProgress:$isRunning");
},

@ -14,6 +14,7 @@ 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/app_lazy_loading.dart';
import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
import 'components/external_request.dart';
import 'components/internal_request.dart';
@ -38,7 +39,6 @@ class _MaintenanceRequestFormState extends State<MaintenanceRequestForm> with Si
Future<void> getInitialData() async {
Provider.of<ServiceReportRepairLocationProvider>(context, listen: false).getTypes();
ServiceRequestDetailProvider requestDetailProvider = Provider.of<ServiceRequestDetailProvider>(context, listen: false);
requestDetailProvider.activityMaintenanceHelperModel?.modelAssistantEmployees =
requestDetailProvider.activityMaintenanceHelperModel?.modelAssistantEmployees ?? ActivityMaintenanceAssistantEmployees();
}
@ -47,7 +47,7 @@ class _MaintenanceRequestFormState extends State<MaintenanceRequestForm> with Si
Widget build(BuildContext context) {
return Consumer<ServiceRequestDetailProvider>(builder: (context, ServiceRequestDetailProvider requestDetailProvider, child) {
bool isUpdate = requestDetailProvider.activityMaintenanceHelperModel?.id != 0;
return Scaffold(
return Scaffold(
backgroundColor: AppColor.neutral110,
appBar: DefaultAppBar(
title: "CM Activity",
@ -111,15 +111,30 @@ class _MaintenanceRequestFormState extends State<MaintenanceRequestForm> with Si
),
],
),
).handlePopScope(cxt: context, showPopUp: !requestDetailProvider.isReadOnlyRequest, onSave: () {
save(requestDetailProvider);
});
).handlePopScope(
cxt: context,
showPopUp: !requestDetailProvider.isReadOnlyRequest,
onSave: () {
save(requestDetailProvider);
});
});
}
void save(ServiceRequestDetailProvider requestDetailProvider) async {
if (validate(model: requestDetailProvider.activityMaintenanceHelperModel!)) {
requestDetailProvider.activityMaintenanceHelperModel?.activityMaintenanceTimers = requestDetailProvider.activityMaintenanceHelperModel?.activityMaintenanceTimers ?? [];
if (requestDetailProvider.activityMaintenanceHelperModel?.activityTimePicker != null) {
int durationInSecond =
requestDetailProvider.activityMaintenanceHelperModel!.activityTimePicker!.endAt!.difference(requestDetailProvider.activityMaintenanceHelperModel!.activityTimePicker!.startAt!).inSeconds;
requestDetailProvider.activityMaintenanceHelperModel?.activityMaintenanceTimers?.add(
ActivityMaintenanceTimers(
id: 0,
startTime: requestDetailProvider.activityMaintenanceHelperModel?.activityTimePicker!.startAt!.toIso8601String(), // Handle potential null
endTime: requestDetailProvider.activityMaintenanceHelperModel?.activityTimePicker!.endAt?.toIso8601String(), // Handle potential null
workingHours: ((durationInSecond) / 60 / 60),
),
);
}
requestDetailProvider.activityMaintenanceHelperModel?.timerModelList?.forEach((timer) {
int durationInSecond = timer.endAt!.difference(timer.startAt!).inSeconds;
requestDetailProvider.activityMaintenanceHelperModel?.activityMaintenanceTimers?.add(

@ -75,9 +75,9 @@ class _SingleItemDropDownMenuState<T extends Base, X extends LoadingListNotifier
@override
void didUpdateWidget(covariant SingleItemDropDownMenu<T, X> oldWidget) {
if (widget.initialValue != null) {
print("$provider:start3:${DateTime.now()}");
// print("$provider:start3:${DateTime.now()}");
final result = (X == NullableLoadingProvider ? widget.staticData : provider?.items)?.where((element) => element.identifier == widget.initialValue?.identifier);
print("$provider:start4:${DateTime.now()}");
// print("$provider:start4:${DateTime.now()}");
if (result?.isNotEmpty ?? false) {
_selectedItem = result?.first as T?;
} else {

@ -70,7 +70,7 @@ class ADatePicker extends StatelessWidget {
.custom(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
],
).expanded,
enable ? 16.width : const Spacer(),
// enable ? 16.width : const Spacer(),
withIcon ? "calender".toSvgAsset(width: 20, color: context.isDark ? AppColor.neutral10 : null) : const SizedBox(),
],
),

@ -3,21 +3,26 @@ import 'dart:async';
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/string_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/sizing.dart';
import 'package:test_sa/modules/cm_module/utilities/service_request_utils.dart';
import 'package:test_sa/views/widgets/date_and_time/date_picker.dart';
import '../../../new_views/app_style/app_color.dart';
class AppTimer extends StatefulWidget {
final TimerModel? timer;
final Future<bool> Function(TimerModel)? onChange;
final TimerModel? pickerTimer;
final Function(TimerModel?)? onPick;
final TextStyle? style;
final BoxDecoration? decoration;
final bool enabled;
final String? label;
final double? width;
final bool canPickTime;
final Function(bool)? timerProgress;
@ -29,8 +34,11 @@ class AppTimer extends StatefulWidget {
this.style,
this.decoration,
this.width,
this.pickerTimer,
this.onPick,
this.timerProgress,
this.enabled = true,
this.canPickTime = false,
}) : super(key: key);
@override
@ -46,6 +54,28 @@ class _AppTimerState extends State<AppTimer> {
bool _loading = false;
final ValueNotifier<String> _period = ValueNotifier("0:00:00");
DateTime? _pickerStartAt;
DateTime? _pickerEndAt;
TimerModel? _tempPickerTimer;
void setPickerTime() async {
int difference = _pickerStartAt == null ? 0 : (_pickerEndAt ?? DateTime.now()).difference(_pickerStartAt!).inSeconds;
_tempPickerTimer = TimerModel(startAt: _pickerStartAt, endAt: _pickerEndAt, durationInSecond: difference);
_pickerStartAt = null;
_pickerEndAt = null;
setState(() {});
widget.onPick!(_tempPickerTimer);
}
void deletePickerTime() {
_tempPickerTimer = null;
_pickerStartAt = null;
_pickerEndAt = null;
widget.onPick!(_tempPickerTimer);
setState(() {});
}
Future<void> _startTimer() async {
if (!_running && widget.onChange != null) {
final time = DateTime.now();
@ -103,7 +133,9 @@ class _AppTimerState extends State<AppTimer> {
difference = difference + _delay;
}
_period.value = Duration(seconds: _running ? difference : (difference != 0 ? difference : _delay)).toString().split(".").first;
if (widget.pickerTimer != null) {
_tempPickerTimer = widget.pickerTimer;
}
super.initState();
if (_running) {
_startTimer();
@ -118,48 +150,250 @@ class _AppTimerState extends State<AppTimer> {
@override
Widget build(BuildContext context) {
return Container(
width: widget.width ?? 100 * AppStyle.getScaleFactor(context),
height: 56.toScreenHeight,
padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth),
decoration: widget.decoration ??
BoxDecoration(
color: context.isDark && !widget.enabled
? AppColor.neutral60
: !widget.enabled
? AppColor.neutral40
: AppColor.background(context),
borderRadius: BorderRadius.circular(10),
boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)],
return Column(
children: [
if (widget.canPickTime) ...[
Row(
mainAxisSize: MainAxisSize.min,
children: [
ADatePicker(
label: context.translation.startTime,
hideShadow: true,
backgroundColor: AppColor.neutral100,
date: _pickerStartAt,
enable: _tempPickerTimer == null,
formatDateWithTime: true,
onDatePicker: (selectedDate) {
showTimePicker(
context: context,
initialTime: TimeOfDay.now(),
).then((selectedTime) {
if (selectedTime != null) {
_pickerStartAt = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute);
setState(() {});
}
});
},
).expanded,
8.width,
ADatePicker(
label: context.translation.endTime,
hideShadow: true,
backgroundColor: AppColor.neutral100,
enable: _pickerStartAt != null,
date: _pickerEndAt,
formatDateWithTime: true,
onDatePicker: (selectedDate) {
showTimePicker(
context: context,
initialTime: TimeOfDay.now(),
).then((selectedTime) {
if (selectedTime != null) {
DateTime selectedDateTime = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute);
if (_pickerStartAt != null && selectedDateTime.isBefore(_pickerStartAt!)) {
"End Date time must be greater then start date".showToast;
return;
}
_pickerEndAt = selectedDateTime;
setPickerTime();
}
});
},
).expanded,
],
),
child: _loading
? const SizedBox.square(dimension: 18, child: CircularProgressIndicator(color: Colors.white))
: Row(
if (_tempPickerTimer != null) ...[
8.height,
Row(
children: [
Expanded(
child: ValueListenableBuilder<String>(
valueListenable: _period,
builder: (context, value, _) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
(widget.label ?? "Timer").tinyFont(context),
value.bodyText(context).custom(
color: widget.enabled
? context.isDark
? AppColor.neutral30
: AppColor.neutral50
: AppColor.neutral20,
),
],
);
},
),
),
if (widget.enabled) Icon(_running ? Icons.pause : Icons.play_arrow),
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ServiceRequestUtils.formatTimerDurationCM(_tempPickerTimer!.durationInSecond!.round()).bodyText(context).custom(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
"Start at: ${_tempPickerTimer!.startAt!.toIso8601String().toFirstActionFormat}\nEnd at: ${_tempPickerTimer!.endAt!.toIso8601String().toFirstActionFormat}".tinyFont(context),
],
).expanded,
8.width,
const Icon(Icons.delete_rounded, size: 20, color: Color(0xffF63939)).onPress(() {
deletePickerTime();
})
],
),
).onPress(_loading || !widget.enabled ? null : _onPressed);
).toShadowContainer(context, padding: 8)
],
8.height,
],
Container(
// width: widget.width ?? 100 * AppStyle.getScaleFactor(context),
height: 56.toScreenHeight,
padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth),
decoration: widget.decoration ??
BoxDecoration(
color: context.isDark && !widget.enabled
? AppColor.neutral60
: !widget.enabled
? AppColor.neutral40
: AppColor.background(context),
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: [
(widget.label ?? "Timer").tinyFont(context),
value.bodyText(context).custom(
color: widget.enabled
? context.isDark
? AppColor.neutral30
: AppColor.neutral50
: AppColor.neutral20,
),
],
);
},
),
),
if (widget.enabled) Icon(_running ? Icons.pause : Icons.play_arrow),
],
),
).onPress(_loading || !widget.enabled ? null : _onPressed),
],
);
}
}
// class AppTimerPicker extends StatefulWidget {
// final TimerModel? timer;
// final Function(TimerModel?) onPick;
//
// AppTimerPicker({Key? key, this.timer, required this.onPick}) : super(key: key);
//
// @override
// _AppTimerPickerState createState() {
// return _AppTimerPickerState();
// }
// }
//
// class _AppTimerPickerState extends State<AppTimerPicker> {
// DateTime? _pickerStartAt;
// DateTime? _pickerEndAt;
//
// TimerModel? _tempPickerTimer;
//
// @override
// void initState() {
// if (widget.timer != null) {
// _tempPickerTimer = widget.timer;
// }
// super.initState();
// }
//
// void setTime() async {
// int difference = _pickerStartAt == null ? 0 : (_pickerEndAt ?? DateTime.now()).difference(_pickerStartAt!).inSeconds;
// _tempPickerTimer = TimerModel(startAt: _pickerStartAt, endAt: _pickerEndAt, durationInSecond: difference);
// // timerList.add(_tempModel);
// // await widget.onChange!(_tempModel);
// _pickerStartAt = null;
// _pickerEndAt = null;
// setState(() {});
// widget.onPick(_tempPickerTimer);
// }
//
// void deleteTime() {
// _tempPickerTimer = null;
// _pickerStartAt = null;
// _pickerEndAt = null;
// widget.onPick(_tempPickerTimer);
// setState(() {});
// }
//
// @override
// void dispose() {
// super.dispose();
// }
//
// @override
// Widget build(BuildContext context) {
// return Column(
// children: [
// Row(
// mainAxisSize: MainAxisSize.min,
// children: [
// ADatePicker(
// label: context.translation.startTime,
// hideShadow: true,
// backgroundColor: AppColor.neutral100,
// date: _pickerStartAt,
// enable: _tempPickerTimer == null,
// formatDateWithTime: true,
// onDatePicker: (selectedDate) {
// showTimePicker(
// context: context,
// initialTime: TimeOfDay.now(),
// ).then((selectedTime) {
// if (selectedTime != null) {
// _pickerStartAt = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute);
// setState(() {});
// }
// });
// },
// ).expanded,
// 8.width,
// ADatePicker(
// label: context.translation.endTime,
// hideShadow: true,
// backgroundColor: AppColor.neutral100,
// enable: _pickerStartAt != null,
// date: _pickerEndAt,
// formatDateWithTime: true,
// onDatePicker: (selectedDate) {
// showTimePicker(
// context: context,
// initialTime: TimeOfDay.now(),
// ).then((selectedTime) {
// if (selectedTime != null) {
// DateTime selectedDateTime = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute);
// if (_pickerStartAt != null && selectedDateTime.isBefore(_pickerStartAt!)) {
// "End Date time must be greater then start date".showToast;
// return;
// }
// _pickerEndAt = selectedDateTime;
// setTime();
// }
// });
// },
// ).expanded,
// ],
// ),
// if (_tempPickerTimer != null) ...[
// 8.height,
// Row(
// children: [
// Column(
// mainAxisSize: MainAxisSize.min,
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// ServiceRequestUtils.formatTimerDurationCM(_tempPickerTimer!.durationInSecond!.round()).bodyText(context).custom(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
// "Start at: ${_tempPickerTimer!.startAt!.toIso8601String().toFirstActionFormat}\nEnd at: ${_tempPickerTimer!.endAt!.toIso8601String().toFirstActionFormat}".tinyFont(context),
// ],
// ).expanded,
// 8.width,
// const Icon(Icons.delete_rounded, size: 20, color: Color(0xffF63939)).onPress(() {
// deleteTime();
// })
// ],
// ).toShadowContainer(context, padding: 8)
// ]
// ],
// );
// }
// }

Loading…
Cancel
Save