Merge branch 'master' into haroon_dev

# Conflicts:
#	lib/routes/app_routes.dart
pull/159/head
haroon amjad 22 hours ago
commit 3e6ee8c10c

@ -299,13 +299,13 @@ class AppDependencies {
activePrescriptionsRepo: getIt() activePrescriptionsRepo: getIt()
), ),
); );
getIt.registerFactory<QrParkingViewModel>( // getIt.registerFactory<QrParkingViewModel>(
() => QrParkingViewModel( // () => QrParkingViewModel(
qrParkingRepo: getIt<QrParkingRepo>(), // qrParkingRepo: getIt<QrParkingRepo>(),
errorHandlerService: getIt<ErrorHandlerService>(), // errorHandlerService: getIt<ErrorHandlerService>(),
cacheService: getIt<CacheService>(), // cacheService: getIt<CacheService>(),
), // ),
); // );
} }
} }

@ -14,6 +14,7 @@ import '../../widgets/buttons/custom_button.dart';
import '../../widgets/routes/custom_page_route.dart'; import '../../widgets/routes/custom_page_route.dart';
class ParkingPage extends StatefulWidget { class ParkingPage extends StatefulWidget {
const ParkingPage({super.key}); const ParkingPage({super.key});
@ -22,11 +23,11 @@ class ParkingPage extends StatefulWidget {
} }
class _ParkingPageState extends State<ParkingPage> { class _ParkingPageState extends State<ParkingPage> {
Future<void> _readQR(BuildContext context) async { Future<void> _readQR(BuildContext context) async {
final vm = context.read<QrParkingViewModel>(); final vm = context.read<QrParkingViewModel>();
final model = await vm.scanAndGetParking(); final model = await vm.scanAndGetParking();
if (model == null) { if (model == null) {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(vm.error ?? "Invalid Qr Code")), SnackBar(content: Text(vm.error ?? "Invalid Qr Code")),
@ -36,15 +37,38 @@ class _ParkingPageState extends State<ParkingPage> {
Navigator.of(context).push( Navigator.of(context).push(
CustomPageRoute( CustomPageRoute(
page: ParkingSlot(model: model), page: ChangeNotifierProvider.value(
value: vm,
child: ParkingSlot(model: model),
),
), ),
); );
} }
@override @override
Widget build(BuildContext context) { void initState() {
final vm = context.watch<QrParkingViewModel>(); // عشان loading super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) async {
final vm = context.read<QrParkingViewModel>();
await vm.getIsSaveParking();
if (!mounted) return;
if (vm.isSavePark && vm.qrParkingModel != null) {
Navigator.of(context).push(
CustomPageRoute(
page: ChangeNotifierProvider.value(
value: vm,
child: ParkingSlot(model: vm.qrParkingModel!),
),
),
);
}
});
}
@override
Widget build(BuildContext context) {
final vm = context.watch<QrParkingViewModel>();
return Scaffold( return Scaffold(
backgroundColor: AppColors.scaffoldBgColor, backgroundColor: AppColors.scaffoldBgColor,
appBar: CustomAppBar( appBar: CustomAppBar(
@ -98,7 +122,6 @@ class _ParkingPageState extends State<ParkingPage> {
), ),
), ),
/// Bottom button
Container( Container(
decoration: RoundedRectangleBorder() decoration: RoundedRectangleBorder()
.toSmoothCornerDecoration( .toSmoothCornerDecoration(
@ -113,40 +136,13 @@ class _ParkingPageState extends State<ParkingPage> {
height: 56, height: 56,
child: CustomButton( child: CustomButton(
text: "Read Barcodes".needTranslation, text: "Read Barcodes".needTranslation,
onPressed: () => _readQR(context), // ALWAYS non-null onPressed: () => _readQR(context), // always non-null
isDisabled: vm.isLoading, // control disabled state here isDisabled: vm.isLoading,
backgroundColor: AppColors.primaryRedColor, backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.primaryRedColor, borderColor: AppColors.primaryRedColor,
fontSize: 18, fontSize: 18,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
) ),
// ElevatedButton(
// style: ElevatedButton.styleFrom(
// backgroundColor: AppColors.primaryRedColor,
// shape: RoundedRectangleBorder(
// borderRadius: BorderRadius.circular(10),
// ),
// ),
// onPressed: vm.isLoading ? null : () => _readQR(context),
// child: vm.isLoading
// ? const SizedBox(
// width: 22,
// height: 22,
// child: CircularProgressIndicator(
// strokeWidth: 2,
// color: Colors.white,
// ),
// )
// : const Text(
// "Read Barcodes",
// style: TextStyle(
// fontSize: 18,
// fontWeight: FontWeight.bold,
// color: Colors.white,
// ),
// ),
// ),
), ),
), ),
), ),
@ -156,3 +152,4 @@ class _ParkingPageState extends State<ParkingPage> {
} }
} }

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

Loading…
Cancel
Save