|
|
|
|
@ -5,7 +5,6 @@ import 'package:hmg_patient_app_new/core/app_export.dart';
|
|
|
|
|
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
|
|
|
|
|
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
|
|
|
|
|
import 'package:hmg_patient_app_new/features/qr_parking/models/qr_parking_response_model.dart';
|
|
|
|
|
|
|
|
|
|
import '../../features/qr_parking/qr_parking_view_model.dart';
|
|
|
|
|
import '../../theme/colors.dart';
|
|
|
|
|
import '../../widgets/appbar/app_bar_widget.dart';
|
|
|
|
|
@ -13,7 +12,7 @@ import '../../widgets/buttons/custom_button.dart';
|
|
|
|
|
import '../../widgets/chip/app_custom_chip_widget.dart';
|
|
|
|
|
import 'package:maps_launcher/maps_launcher.dart';
|
|
|
|
|
import 'package:provider/provider.dart';
|
|
|
|
|
|
|
|
|
|
import '../../widgets/routes/custom_page_route.dart';
|
|
|
|
|
|
|
|
|
|
class ParkingSlot extends StatefulWidget {
|
|
|
|
|
final QrParkingResponseModel model;
|
|
|
|
|
@ -28,7 +27,6 @@ class ParkingSlot extends StatefulWidget {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class _ParkingSlotState extends State<ParkingSlot> {
|
|
|
|
|
|
|
|
|
|
void _openDirection() {
|
|
|
|
|
final lat = widget.model.latitude;
|
|
|
|
|
final lng = widget.model.longitude;
|
|
|
|
|
@ -36,8 +34,10 @@ class _ParkingSlotState extends State<ParkingSlot> {
|
|
|
|
|
final valid = lat != null &&
|
|
|
|
|
lng != null &&
|
|
|
|
|
!(lat == 0.0 && lng == 0.0) &&
|
|
|
|
|
lat >= -90 && lat <= 90 &&
|
|
|
|
|
lng >= -180 && lng <= 180;
|
|
|
|
|
lat >= -90 &&
|
|
|
|
|
lat <= 90 &&
|
|
|
|
|
lng >= -180 &&
|
|
|
|
|
lng <= 180;
|
|
|
|
|
|
|
|
|
|
if (!valid) {
|
|
|
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
|
|
|
@ -49,12 +49,33 @@ class _ParkingSlotState extends State<ParkingSlot> {
|
|
|
|
|
MapsLauncher.launchCoordinates(lat, lng);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Future<void> _resetDirection() async {
|
|
|
|
|
final vm = context.read<QrParkingViewModel>();
|
|
|
|
|
await vm.clearParking();
|
|
|
|
|
Navigator.of(context).popUntil((route) => route.isFirst);
|
|
|
|
|
final model = await vm.scanAndGetParking();
|
|
|
|
|
if (model == null) {
|
|
|
|
|
if (!mounted) return;
|
|
|
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
|
|
|
SnackBar(content: Text(vm.error ?? "Scan cancelled")),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
Navigator.of(context).pop();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!mounted) return;
|
|
|
|
|
Navigator.of(context).pushReplacement(
|
|
|
|
|
CustomPageRoute(
|
|
|
|
|
page: ChangeNotifierProvider.value(
|
|
|
|
|
value: vm,
|
|
|
|
|
child: ParkingSlot(model: model),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DateTime? _parseDotNetDate(String? value) {
|
|
|
|
|
if (value == null || value.isEmpty) return null;
|
|
|
|
|
|
|
|
|
|
@ -65,11 +86,9 @@ class _ParkingSlotState extends State<ParkingSlot> {
|
|
|
|
|
final milliseconds = int.tryParse(match.group(1)!);
|
|
|
|
|
if (milliseconds == null) return null;
|
|
|
|
|
|
|
|
|
|
return DateTime.fromMillisecondsSinceEpoch(milliseconds, isUtc: true)
|
|
|
|
|
.toLocal();
|
|
|
|
|
return DateTime.fromMillisecondsSinceEpoch(milliseconds, isUtc: true).toLocal();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
String _formatPrettyDate(String? value) {
|
|
|
|
|
final date = _parseDotNetDate(value);
|
|
|
|
|
if (date == null) return '-';
|
|
|
|
|
@ -79,14 +98,13 @@ class _ParkingSlotState extends State<ParkingSlot> {
|
|
|
|
|
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
final day = date.day;
|
|
|
|
|
final day = date.day.toString().padLeft(2, '0');
|
|
|
|
|
final month = months[date.month - 1];
|
|
|
|
|
final year = date.year;
|
|
|
|
|
|
|
|
|
|
return "$day $month $year";
|
|
|
|
|
return "$day $month $year"; // ✅ 15 Dec 2025
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
String _formatPrettyTime(String? value) {
|
|
|
|
|
final date = _parseDotNetDate(value);
|
|
|
|
|
if (date == null) return '-';
|
|
|
|
|
@ -100,7 +118,7 @@ class _ParkingSlotState extends State<ParkingSlot> {
|
|
|
|
|
hour = hour % 12;
|
|
|
|
|
if (hour == 0) hour = 12;
|
|
|
|
|
|
|
|
|
|
return "${hour.toString().padLeft(2, '0')}:$minute $period";
|
|
|
|
|
return "${hour.toString().padLeft(2, '0')}:$minute $period"; // ✅ 03:05 PM
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
@ -126,11 +144,9 @@ class _ParkingSlotState extends State<ParkingSlot> {
|
|
|
|
|
child: Column(
|
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
|
|
|
children: [
|
|
|
|
|
|
|
|
|
|
Container(
|
|
|
|
|
width: double.infinity,
|
|
|
|
|
decoration: RoundedRectangleBorder()
|
|
|
|
|
.toSmoothCornerDecoration(
|
|
|
|
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
|
|
|
|
color: AppColors.whiteColor,
|
|
|
|
|
borderRadius: 24.r,
|
|
|
|
|
hasShadow: true,
|
|
|
|
|
@ -154,24 +170,16 @@ class _ParkingSlotState extends State<ParkingSlot> {
|
|
|
|
|
runSpacing: 4,
|
|
|
|
|
children: [
|
|
|
|
|
AppCustomChipWidget(
|
|
|
|
|
labelText:
|
|
|
|
|
"Slot: ${widget.model.qRParkingCode ?? '-'}"
|
|
|
|
|
.needTranslation,
|
|
|
|
|
labelText: "Slot: ${widget.model.qRParkingCode ?? '-'}".needTranslation,
|
|
|
|
|
),
|
|
|
|
|
AppCustomChipWidget(
|
|
|
|
|
labelText:
|
|
|
|
|
"Basement: ${widget.model.floorDescription ?? '-'}"
|
|
|
|
|
.needTranslation,
|
|
|
|
|
labelText: "Basement: ${widget.model.floorDescription ?? '-'}".needTranslation,
|
|
|
|
|
),
|
|
|
|
|
AppCustomChipWidget(
|
|
|
|
|
labelText:
|
|
|
|
|
"Date: ${_formatPrettyDate(widget.model.createdOn)}"
|
|
|
|
|
.needTranslation,
|
|
|
|
|
labelText: "Date: ${_formatPrettyDate(widget.model.createdOn)}".needTranslation,
|
|
|
|
|
),
|
|
|
|
|
AppCustomChipWidget(
|
|
|
|
|
labelText:
|
|
|
|
|
"Parked Since: ${_formatPrettyTime(widget.model.createdOn)}"
|
|
|
|
|
.needTranslation,
|
|
|
|
|
labelText: "Parked Since: ${_formatPrettyTime(widget.model.createdOn)}".needTranslation,
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
@ -179,13 +187,12 @@ class _ParkingSlotState extends State<ParkingSlot> {
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
|
|
|
|
|
SizedBox(height: 24.h),
|
|
|
|
|
|
|
|
|
|
SizedBox(
|
|
|
|
|
width: double.infinity,
|
|
|
|
|
height: 48.h,
|
|
|
|
|
child:CustomButton(
|
|
|
|
|
child: CustomButton(
|
|
|
|
|
text: "Get Direction".needTranslation,
|
|
|
|
|
onPressed: _openDirection,
|
|
|
|
|
backgroundColor: AppColors.primaryRedColor,
|
|
|
|
|
@ -194,49 +201,25 @@ class _ParkingSlotState extends State<ParkingSlot> {
|
|
|
|
|
fontSize: 18,
|
|
|
|
|
fontWeight: FontWeight.bold,
|
|
|
|
|
borderRadius: 10,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// ElevatedButton(
|
|
|
|
|
// style: ElevatedButton.styleFrom(
|
|
|
|
|
// backgroundColor: AppColors.primaryRedColor,
|
|
|
|
|
// shape: RoundedRectangleBorder(
|
|
|
|
|
// borderRadius: BorderRadius.circular(10),
|
|
|
|
|
// ),
|
|
|
|
|
// ),
|
|
|
|
|
// onPressed: _openDirection,
|
|
|
|
|
// child: Text(
|
|
|
|
|
// "Get Direction".needTranslation,
|
|
|
|
|
// style: TextStyle(
|
|
|
|
|
// fontSize: 18,
|
|
|
|
|
// fontWeight: FontWeight.bold,
|
|
|
|
|
// color: AppColors.whiteColor,
|
|
|
|
|
// ),
|
|
|
|
|
// ),
|
|
|
|
|
// ),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
|
|
|
|
|
// const Spacer(),
|
|
|
|
|
// SizedBox(
|
|
|
|
|
// width: double.infinity,
|
|
|
|
|
// height: 48.h,
|
|
|
|
|
// child: OutlinedButton(
|
|
|
|
|
// style: OutlinedButton.styleFrom(
|
|
|
|
|
// side: BorderSide(color: AppColors.primaryRedColor),
|
|
|
|
|
// shape: RoundedRectangleBorder(
|
|
|
|
|
// borderRadius: BorderRadius.circular(10),
|
|
|
|
|
// ),
|
|
|
|
|
// ),
|
|
|
|
|
// onPressed: _resetDirection,
|
|
|
|
|
// child: Text(
|
|
|
|
|
// "Reset Direction".needTranslation,
|
|
|
|
|
// style: TextStyle(
|
|
|
|
|
// fontSize: 16,
|
|
|
|
|
// fontWeight: FontWeight.w600,
|
|
|
|
|
// color: AppColors.primaryRedColor,
|
|
|
|
|
// ),
|
|
|
|
|
// ),
|
|
|
|
|
// ),
|
|
|
|
|
// ),
|
|
|
|
|
const Spacer(),
|
|
|
|
|
|
|
|
|
|
SizedBox(
|
|
|
|
|
width: double.infinity,
|
|
|
|
|
height: 48.h,
|
|
|
|
|
child: CustomButton(
|
|
|
|
|
text: "Reset Direction".needTranslation,
|
|
|
|
|
onPressed: _resetDirection,
|
|
|
|
|
backgroundColor: AppColors.primaryRedColor,
|
|
|
|
|
borderColor: AppColors.primaryRedColor,
|
|
|
|
|
textColor: AppColors.whiteColor,
|
|
|
|
|
fontSize: 18,
|
|
|
|
|
fontWeight: FontWeight.bold,
|
|
|
|
|
borderRadius: 10,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
@ -249,3 +232,5 @@ class _ParkingSlotState extends State<ParkingSlot> {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|