|
|
|
|
@ -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)
|
|
|
|
|
// ]
|
|
|
|
|
// ],
|
|
|
|
|
// );
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|