dev merge

This commit is contained in:
2026-03-19 15:25:37 +05:30
parent e671827dc4
commit 230942e776
12 changed files with 156 additions and 24 deletions

View File

@@ -45,6 +45,11 @@ public final class GeneratedPluginRegistrant {
} catch (Exception e) { } catch (Exception e) {
Log.e(TAG, "Error registering plugin geolocator_android, com.baseflow.geolocator.GeolocatorPlugin", e); Log.e(TAG, "Error registering plugin geolocator_android, com.baseflow.geolocator.GeolocatorPlugin", e);
} }
try {
flutterEngine.getPlugins().add(new io.flutter.plugins.googlemaps.GoogleMapsPlugin());
} catch (Exception e) {
Log.e(TAG, "Error registering plugin google_maps_flutter_android, io.flutter.plugins.googlemaps.GoogleMapsPlugin", e);
}
try { try {
flutterEngine.getPlugins().add(new io.flutter.plugins.imagepicker.ImagePickerPlugin()); flutterEngine.getPlugins().add(new io.flutter.plugins.imagepicker.ImagePickerPlugin());
} catch (Exception e) { } catch (Exception e) {

View File

@@ -36,6 +36,12 @@
@import geolocator_apple; @import geolocator_apple;
#endif #endif
#if __has_include(<google_maps_flutter_ios/FGMGoogleMapsPlugin.h>)
#import <google_maps_flutter_ios/FGMGoogleMapsPlugin.h>
#else
@import google_maps_flutter_ios;
#endif
#if __has_include(<image_picker_ios/FLTImagePickerPlugin.h>) #if __has_include(<image_picker_ios/FLTImagePickerPlugin.h>)
#import <image_picker_ios/FLTImagePickerPlugin.h> #import <image_picker_ios/FLTImagePickerPlugin.h>
#else #else
@@ -86,6 +92,7 @@
[FLTFirebaseCorePlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTFirebaseCorePlugin"]]; [FLTFirebaseCorePlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTFirebaseCorePlugin"]];
[FlutterLocalNotificationsPlugin registerWithRegistrar:[registry registrarForPlugin:@"FlutterLocalNotificationsPlugin"]]; [FlutterLocalNotificationsPlugin registerWithRegistrar:[registry registrarForPlugin:@"FlutterLocalNotificationsPlugin"]];
[GeolocatorPlugin registerWithRegistrar:[registry registrarForPlugin:@"GeolocatorPlugin"]]; [GeolocatorPlugin registerWithRegistrar:[registry registrarForPlugin:@"GeolocatorPlugin"]];
[FGMGoogleMapsPlugin registerWithRegistrar:[registry registrarForPlugin:@"FGMGoogleMapsPlugin"]];
[FLTImagePickerPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTImagePickerPlugin"]]; [FLTImagePickerPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTImagePickerPlugin"]];
[FPPPackageInfoPlusPlugin registerWithRegistrar:[registry registrarForPlugin:@"FPPPackageInfoPlusPlugin"]]; [FPPPackageInfoPlusPlugin registerWithRegistrar:[registry registrarForPlugin:@"FPPPackageInfoPlusPlugin"]];
[RecordIosPlugin registerWithRegistrar:[registry registrarForPlugin:@"RecordIosPlugin"]]; [RecordIosPlugin registerWithRegistrar:[registry registrarForPlugin:@"RecordIosPlugin"]];

View File

@@ -132,6 +132,11 @@ abstract final class ClientEndpoints {
static const ApiEndpoint ordersOneTime = static const ApiEndpoint ordersOneTime =
ApiEndpoint('/client/orders/one-time'); ApiEndpoint('/client/orders/one-time');
/// Create rapid order.
static const ApiEndpoint ordersRapid =
ApiEndpoint('/client/orders/rapid');
/// Create recurring order. /// Create recurring order.
static const ApiEndpoint ordersRecurring = static const ApiEndpoint ordersRecurring =
ApiEndpoint('/client/orders/recurring'); ApiEndpoint('/client/orders/recurring');

View File

@@ -37,9 +37,11 @@ class ShiftDetail extends Equatable {
this.assignmentStatus, this.assignmentStatus,
this.applicationStatus, this.applicationStatus,
this.clockInMode, this.clockInMode,
required this.allowClockInOverride, this.allowClockInOverride = false,
this.geofenceRadiusMeters, this.geofenceRadiusMeters,
this.nfcTagId, this.nfcTagId,
this.breakDurationMinutes,
this.isBreakPaid = false,
}); });
/// Deserialises from the V2 API JSON response. /// Deserialises from the V2 API JSON response.
@@ -75,6 +77,8 @@ class ShiftDetail extends Equatable {
allowClockInOverride: json['allowClockInOverride'] as bool? ?? false, allowClockInOverride: json['allowClockInOverride'] as bool? ?? false,
geofenceRadiusMeters: json['geofenceRadiusMeters'] as int?, geofenceRadiusMeters: json['geofenceRadiusMeters'] as int?,
nfcTagId: json['nfcTagId'] as String?, nfcTagId: json['nfcTagId'] as String?,
breakDurationMinutes: json['breakDurationMinutes'] as int?,
isBreakPaid: json['isBreakPaid'] as bool? ?? false,
); );
} }
@@ -156,6 +160,12 @@ class ShiftDetail extends Equatable {
/// NFC tag identifier for NFC-based clock-in. /// NFC tag identifier for NFC-based clock-in.
final String? nfcTagId; final String? nfcTagId;
/// Optional break duration in minutes.
final int? breakDurationMinutes;
/// Whether the break is paid.
final bool isBreakPaid;
/// Duration of the shift in hours. /// Duration of the shift in hours.
double get durationHours { double get durationHours {
return endTime.difference(startTime).inMinutes / 60; return endTime.difference(startTime).inMinutes / 60;
@@ -193,6 +203,8 @@ class ShiftDetail extends Equatable {
'allowClockInOverride': allowClockInOverride, 'allowClockInOverride': allowClockInOverride,
'geofenceRadiusMeters': geofenceRadiusMeters, 'geofenceRadiusMeters': geofenceRadiusMeters,
'nfcTagId': nfcTagId, 'nfcTagId': nfcTagId,
'breakDurationMinutes': breakDurationMinutes,
'isBreakPaid': isBreakPaid,
}; };
} }
@@ -224,5 +236,7 @@ class ShiftDetail extends Equatable {
allowClockInOverride, allowClockInOverride,
geofenceRadiusMeters, geofenceRadiusMeters,
nfcTagId, nfcTagId,
breakDurationMinutes,
isBreakPaid,
]; ];
} }

View File

@@ -39,7 +39,10 @@ class ClientCreateOrderRepositoryImpl
@override @override
Future<void> createRapidOrder(String description) async { Future<void> createRapidOrder(String description) async {
throw UnimplementedError('Rapid order creation is not connected yet.'); await _api.post(
ClientEndpoints.ordersRapid,
data: <String, dynamic>{'description': description},
);
} }
@override @override

View File

@@ -2,7 +2,6 @@ import 'package:krow_core/core.dart';
/// Represents the arguments required for the [ClockInUseCase]. /// Represents the arguments required for the [ClockInUseCase].
class ClockInArguments extends UseCaseArgument { class ClockInArguments extends UseCaseArgument {
/// Creates a [ClockInArguments] instance. /// Creates a [ClockInArguments] instance.
const ClockInArguments({ const ClockInArguments({
required this.shiftId, required this.shiftId,
@@ -18,6 +17,7 @@ class ClockInArguments extends UseCaseArgument {
this.proofTimestamp, this.proofTimestamp,
this.attestationProvider, this.attestationProvider,
this.attestationToken, this.attestationToken,
this.sourceType = 'GEO',
}); });
/// The ID of the shift to clock in to. /// The ID of the shift to clock in to.
@@ -59,14 +59,16 @@ class ClockInArguments extends UseCaseArgument {
/// Signed attestation token from the device integrity API. /// Signed attestation token from the device integrity API.
final String? attestationToken; final String? attestationToken;
/// The source type of the clock-in (e.g. 'GEO', 'NFC', 'QR').
final String sourceType;
/// Serializes the arguments to a JSON map for the V2 API request body. /// Serializes the arguments to a JSON map for the V2 API request body.
/// ///
/// Only includes non-null fields. The `sourceType` is inferred from /// Only includes non-null fields.
/// whether [nfcTagId] is present.
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
return <String, dynamic>{ return <String, dynamic>{
'shiftId': shiftId, 'shiftId': shiftId,
'sourceType': nfcTagId != null ? 'NFC' : 'GEO', 'sourceType': sourceType,
if (notes != null && notes!.isNotEmpty) 'notes': notes, if (notes != null && notes!.isNotEmpty) 'notes': notes,
if (deviceId != null) 'deviceId': deviceId, if (deviceId != null) 'deviceId': deviceId,
if (latitude != null) 'latitude': latitude, if (latitude != null) 'latitude': latitude,
@@ -101,5 +103,6 @@ class ClockInArguments extends UseCaseArgument {
proofTimestamp, proofTimestamp,
attestationProvider, attestationProvider,
attestationToken, attestationToken,
sourceType,
]; ];
} }

View File

@@ -18,6 +18,7 @@ class ClockOutArguments extends UseCaseArgument {
this.proofTimestamp, this.proofTimestamp,
this.attestationProvider, this.attestationProvider,
this.attestationToken, this.attestationToken,
this.sourceType = 'GEO',
}); });
/// Optional notes provided by the user during clock-out. /// Optional notes provided by the user during clock-out.
@@ -62,14 +63,16 @@ class ClockOutArguments extends UseCaseArgument {
/// Signed attestation token from the device integrity API. /// Signed attestation token from the device integrity API.
final String? attestationToken; final String? attestationToken;
/// The source type of the clock-out (e.g. 'GEO', 'NFC', 'QR').
final String sourceType;
/// Serializes the arguments to a JSON map for the V2 API request body. /// Serializes the arguments to a JSON map for the V2 API request body.
/// ///
/// Only includes non-null fields. The `sourceType` is inferred from /// Only includes non-null fields.
/// whether [nfcTagId] is present.
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
return <String, dynamic>{ return <String, dynamic>{
if (shiftId != null) 'shiftId': shiftId, if (shiftId != null) 'shiftId': shiftId,
'sourceType': nfcTagId != null ? 'NFC' : 'GEO', 'sourceType': sourceType,
if (notes != null && notes!.isNotEmpty) 'notes': notes, if (notes != null && notes!.isNotEmpty) 'notes': notes,
if (breakTimeMinutes != null) 'breakMinutes': breakTimeMinutes, if (breakTimeMinutes != null) 'breakMinutes': breakTimeMinutes,
if (deviceId != null) 'deviceId': deviceId, if (deviceId != null) 'deviceId': deviceId,
@@ -106,5 +109,6 @@ class ClockOutArguments extends UseCaseArgument {
proofTimestamp, proofTimestamp,
attestationProvider, attestationProvider,
attestationToken, attestationToken,
sourceType,
]; ];
} }

View File

@@ -213,6 +213,7 @@ class ClockInBloc extends Bloc<ClockInEvent, ClockInState>
longitude: location?.longitude, longitude: location?.longitude,
accuracyMeters: location?.accuracy, accuracyMeters: location?.accuracy,
capturedAt: location?.timestamp, capturedAt: location?.timestamp,
sourceType: event.sourceType,
overrideReason: geofenceState.isGeofenceOverridden overrideReason: geofenceState.isGeofenceOverridden
? geofenceState.overrideNotes ? geofenceState.overrideNotes
: null, : null,
@@ -291,6 +292,7 @@ class ClockInBloc extends Bloc<ClockInEvent, ClockInState>
longitude: location?.longitude, longitude: location?.longitude,
accuracyMeters: location?.accuracy, accuracyMeters: location?.accuracy,
capturedAt: location?.timestamp, capturedAt: location?.timestamp,
sourceType: event.sourceType,
overrideReason: currentGeofence.isGeofenceOverridden overrideReason: currentGeofence.isGeofenceOverridden
? currentGeofence.overrideNotes ? currentGeofence.overrideNotes
: null, : null,

View File

@@ -47,6 +47,7 @@ class CheckInRequested extends ClockInEvent {
this.clockInGreetingBody = '', this.clockInGreetingBody = '',
this.leftGeofenceTitle = '', this.leftGeofenceTitle = '',
this.leftGeofenceBody = '', this.leftGeofenceBody = '',
this.sourceType = 'GEO',
}); });
/// The ID of the shift to clock into. /// The ID of the shift to clock into.
@@ -67,6 +68,9 @@ class CheckInRequested extends ClockInEvent {
/// Localized body for the left-geofence background notification. /// Localized body for the left-geofence background notification.
final String leftGeofenceBody; final String leftGeofenceBody;
/// The source type of the clock-in (e.g. 'GEO', 'NFC', 'QR').
final String sourceType;
@override @override
List<Object?> get props => <Object?>[ List<Object?> get props => <Object?>[
shiftId, shiftId,
@@ -75,6 +79,7 @@ class CheckInRequested extends ClockInEvent {
clockInGreetingBody, clockInGreetingBody,
leftGeofenceTitle, leftGeofenceTitle,
leftGeofenceBody, leftGeofenceBody,
sourceType,
]; ];
} }
@@ -85,6 +90,7 @@ class CheckOutRequested extends ClockInEvent {
this.breakTimeMinutes, this.breakTimeMinutes,
this.clockOutTitle = '', this.clockOutTitle = '',
this.clockOutBody = '', this.clockOutBody = '',
this.sourceType = 'GEO',
}); });
/// Optional notes provided by the user. /// Optional notes provided by the user.
@@ -99,12 +105,16 @@ class CheckOutRequested extends ClockInEvent {
/// Localized body for the clock-out notification. /// Localized body for the clock-out notification.
final String clockOutBody; final String clockOutBody;
/// The source type of the clock-out (e.g. 'GEO', 'NFC', 'QR').
final String sourceType;
@override @override
List<Object?> get props => <Object?>[ List<Object?> get props => <Object?>[
notes, notes,
breakTimeMinutes, breakTimeMinutes,
clockOutTitle, clockOutTitle,
clockOutBody, clockOutBody,
sourceType,
]; ];
} }

View File

@@ -2,6 +2,7 @@ import 'package:core_localization/core_localization.dart';
import 'package:design_system/design_system.dart'; import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_modular/flutter_modular.dart'; import 'package:flutter_modular/flutter_modular.dart';
import 'package:geolocator/geolocator.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:krow_core/core.dart'; import 'package:krow_core/core.dart';
import 'package:krow_domain/krow_domain.dart'; import 'package:krow_domain/krow_domain.dart';
@@ -147,8 +148,6 @@ class _FindShiftsTabState extends State<FindShiftsTab> {
return DateFormat('EEE, MMM d').format(date); return DateFormat('EEE, MMM d').format(date);
} }
}
Widget _buildFilterTab(String id, String label) { Widget _buildFilterTab(String id, String label) {
final bool isSelected = _jobType == id; final bool isSelected = _jobType == id;
return GestureDetector( return GestureDetector(
@@ -421,7 +420,6 @@ class _FindShiftsTabState extends State<FindShiftsTab> {
), ),
), ),
), ),
),
], ],
), ),
), ),

View File

@@ -29,6 +29,7 @@ dependencies:
url_launcher: ^6.3.1 url_launcher: ^6.3.1
bloc: ^8.1.4 bloc: ^8.1.4
meta: ^1.17.0 meta: ^1.17.0
google_maps_flutter: ^2.5.3
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:

View File

@@ -141,10 +141,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: characters name: characters
sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.4.1" version: "1.4.0"
charcode: charcode:
dependency: transitive dependency: transitive
description: description:
@@ -257,6 +257,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.7" version: "3.0.7"
csslib:
dependency: transitive
description:
name: csslib
sha256: "09bad715f418841f976c77db72d5398dc1253c21fb9c0c7f0b0b985860b2d58e"
url: "https://pub.dev"
source: hosted
version: "1.0.2"
csv: csv:
dependency: transitive dependency: transitive
description: description:
@@ -637,6 +645,54 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "7.0.2" version: "7.0.2"
google_maps:
dependency: transitive
description:
name: google_maps
sha256: "5d410c32112d7c6eb7858d359275b2aa04778eed3e36c745aeae905fb2fa6468"
url: "https://pub.dev"
source: hosted
version: "8.2.0"
google_maps_flutter:
dependency: transitive
description:
name: google_maps_flutter
sha256: "0114a31e177f650f0972347d93122c42661a75b869561ff6a374cc42ff3af886"
url: "https://pub.dev"
source: hosted
version: "2.16.0"
google_maps_flutter_android:
dependency: transitive
description:
name: google_maps_flutter_android
sha256: "68a3907c90dc37caffbcfc1093541ef2c18d6ebb53296fdb9f04822d16269353"
url: "https://pub.dev"
source: hosted
version: "2.19.3"
google_maps_flutter_ios:
dependency: transitive
description:
name: google_maps_flutter_ios
sha256: c855600dce17e77e8af96edcf85cb68501675bb77a72f85009d08c17a8805ace
url: "https://pub.dev"
source: hosted
version: "2.18.0"
google_maps_flutter_platform_interface:
dependency: transitive
description:
name: google_maps_flutter_platform_interface
sha256: ddbe34435dfb34e83fca295c6a8dcc53c3b51487e9eec3c737ce4ae605574347
url: "https://pub.dev"
source: hosted
version: "2.15.0"
google_maps_flutter_web:
dependency: transitive
description:
name: google_maps_flutter_web
sha256: "6cefe4ef4cc61dc0dfba4c413dec4bd105cb6b9461bfbe1465ddd09f80af377d"
url: "https://pub.dev"
source: hosted
version: "0.6.2"
google_places_flutter: google_places_flutter:
dependency: transitive dependency: transitive
description: description:
@@ -669,6 +725,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.20.5" version: "0.20.5"
html:
dependency: transitive
description:
name: html
sha256: "6d1264f2dffa1b1101c25a91dff0dc2daee4c18e87cd8538729773c073dbf602"
url: "https://pub.dev"
source: hosted
version: "0.15.6"
http: http:
dependency: transitive dependency: transitive
description: description:
@@ -781,6 +845,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.5" version: "1.0.5"
js:
dependency: transitive
description:
name: js
sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc"
url: "https://pub.dev"
source: hosted
version: "0.7.2"
json_annotation: json_annotation:
dependency: transitive dependency: transitive
description: description:
@@ -849,18 +921,18 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: matcher name: matcher
sha256: "12956d0ad8390bbcc63ca2e1469c0619946ccb52809807067a7020d57e647aa6" sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.12.18" version: "0.12.17"
material_color_utilities: material_color_utilities:
dependency: transitive dependency: transitive
description: description:
name: material_color_utilities name: material_color_utilities
sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b" sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.13.0" version: "0.11.1"
melos: melos:
dependency: "direct dev" dependency: "direct dev"
description: description:
@@ -1197,6 +1269,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.28.0" version: "0.28.0"
sanitize_html:
dependency: transitive
description:
name: sanitize_html
sha256: "12669c4a913688a26555323fb9cec373d8f9fbe091f2d01c40c723b33caa8989"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
shared_preferences: shared_preferences:
dependency: transitive dependency: transitive
description: description:
@@ -1412,26 +1492,26 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: test name: test
sha256: "54c516bbb7cee2754d327ad4fca637f78abfc3cbcc5ace83b3eda117e42cd71a" sha256: "75906bf273541b676716d1ca7627a17e4c4070a3a16272b7a3dc7da3b9f3f6b7"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.29.0" version: "1.26.3"
test_api: test_api:
dependency: transitive dependency: transitive
description: description:
name: test_api name: test_api
sha256: "93167629bfc610f71560ab9312acdda4959de4df6fac7492c89ff0d3886f6636" sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.7.9" version: "0.7.7"
test_core: test_core:
dependency: transitive dependency: transitive
description: description:
name: test_core name: test_core
sha256: "394f07d21f0f2255ec9e3989f21e54d3c7dc0e6e9dbce160e5a9c1a6be0e2943" sha256: "0cc24b5ff94b38d2ae73e1eb43cc302b77964fbf67abad1e296025b78deb53d0"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.6.15" version: "0.6.12"
timezone: timezone:
dependency: transitive dependency: transitive
description: description: