feat: legacy mobile apps created

This commit is contained in:
Achintha Isuru
2025-12-02 23:51:04 -05:00
parent 850441ca64
commit 8e7753b324
1519 changed files with 0 additions and 16 deletions

View File

@@ -0,0 +1,104 @@
import 'package:auto_route/auto_route.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:krow/core/presentation/styles/kw_text_styles.dart';
import 'package:krow/core/presentation/styles/theme.dart';
import 'package:krow/core/presentation/widgets/ui_kit/kw_button.dart';
import 'package:krow/core/presentation/widgets/ui_kit/kw_input.dart';
import 'package:krow/features/shifts/presentation/dialogs/cancel_dialog/cancel_reason_dropdown.dart';
class CancelDialogView extends StatefulWidget {
const CancelDialogView({super.key});
@override
State<CancelDialogView> createState() => _CancelDialogViewState();
}
class _CancelDialogViewState extends State<CancelDialogView> {
String selectedReason = '';
final _textEditingController = TextEditingController();
@override
Widget build(BuildContext context) {
return Center(
child: AnimatedSize(
duration: const Duration(milliseconds: 300),
child: Container(
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 16),
decoration: BoxDecoration(
color: AppColors.grayWhite,
borderRadius: BorderRadius.circular(24),
),
child: SingleChildScrollView(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 56),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
Text(
'cancel_shift'.tr(),
style: AppTextStyles.headingH1.copyWith(height: 1),
textAlign: TextAlign.center,
),
const Gap(8),
Text(
'please_select_reason'.tr(),
style: AppTextStyles.bodyMediumReg
.copyWith(color: AppColors.blackGray),
textAlign: TextAlign.center,
),
const Gap(8),
CancelReasonDropdown(
selectedReason: selectedReason,
onReasonSelected: (String reason) {
setState(() {
selectedReason = reason;
});
},
),
const Gap(8),
KwTextInput(
controller: _textEditingController,
minHeight: 144,
maxLength: 300,
showCounter: true,
radius: 12,
title: 'additional_reasons'.tr(),
hintText: 'enter_main_text'.tr(),
),
const Gap(24),
_buttonGroup(context),
],
),
),
),
),
);
}
Widget _buttonGroup(
BuildContext context,
) {
return Column(
children: [
KwButton.primary(
disabled: selectedReason.isEmpty,
label: 'submit_reason'.tr(),
onPressed: () {
context.maybePop({
'reason': selectedReason,
'additionalReason': _textEditingController.text,
});
},
),
const Gap(8),
KwButton.outlinedPrimary(
label: 'cancel'.tr(),
onPressed: () {
context.maybePop();
}),
],
);
}
}

View File

@@ -0,0 +1,114 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:krow/core/presentation/gen/assets.gen.dart';
import 'package:krow/core/presentation/styles/kw_text_styles.dart';
import 'package:krow/core/presentation/styles/theme.dart';
import 'package:krow/core/presentation/widgets/ui_kit/kw_popup_menu.dart';
const reasons = {
'sick_leave': 'sick_leave',
'vacation ': 'vacation',
'other': 'other_specify',
};
class CancelReasonDropdown extends StatelessWidget {
final String? selectedReason;
final Function(String reason) onReasonSelected;
const CancelReasonDropdown(
{super.key,
required this.selectedReason,
required this.onReasonSelected});
@override
Widget build(BuildContext context) {
return Column(
children: buildReasonInput(context, selectedReason),
);
}
List<Widget> buildReasonInput(BuildContext context, String? selectedReason) {
return [
const Gap(24),
Row(
children: [
const Gap(16),
Text(
'reason'.tr(),
style:
AppTextStyles.bodyTinyReg.copyWith(color: AppColors.blackGray),
),
],
),
const Gap(4),
KwPopupMenu(
horizontalPadding: 40,
fit: KwPopupMenuFit.expand,
customButtonBuilder: (context, isOpened) {
return _buildMenuButton(isOpened, selectedReason);
},
menuItems: [
...reasons.entries
.map((e) => _buildMenuItem(context, e, selectedReason ?? ''))
])
];
}
Container _buildMenuButton(bool isOpened, String? selectedReason) {
return Container(
height: 48,
padding: const EdgeInsets.symmetric(horizontal: 16),
decoration: BoxDecoration(
color: AppColors.grayWhite,
borderRadius: BorderRadius.circular(24),
border: Border.all(
color: isOpened ? AppColors.bgColorDark : AppColors.grayTintStroke,
width: 1),
),
child: Row(
children: [
Expanded(
child: Text(
reasons[selectedReason]?.tr() ?? 'select_reason_from_list'.tr(),
style: AppTextStyles.bodyMediumReg.copyWith(
color: selectedReason == null
? AppColors.blackGray
: AppColors.blackBlack),
)),
],
),
);
}
KwPopupMenuItem _buildMenuItem(BuildContext context,
MapEntry<String, String> entry, String selectedReason) {
return KwPopupMenuItem(
title: entry.value.tr(),
onTap: () {
onReasonSelected(entry.key);
},
icon: Container(
height: 16,
width: 16,
decoration: BoxDecoration(
color: selectedReason != entry.key ? null : AppColors.bgColorDark,
shape: BoxShape.circle,
border: selectedReason == entry.key
? null
: Border.all(color: AppColors.grayTintStroke, width: 1),
),
child: selectedReason == entry.key
? Center(
child: Assets.images.icons.check.svg(
height: 10,
width: 10,
colorFilter: const ColorFilter.mode(
AppColors.grayWhite, BlendMode.srcIn),
))
: null,
),
textStyle: AppTextStyles.bodySmallMed,
);
}
}

View File

@@ -0,0 +1,19 @@
import 'package:flutter/material.dart';
import 'package:krow/features/shifts/presentation/dialogs/cancel_dialog/cancel_dialog_view.dart';
class ShiftCancelDialog extends StatelessWidget {
const ShiftCancelDialog({super.key});
static Future<Map<String, dynamic>?> showCustomDialog(
BuildContext context) async {
return await showDialog<Map<String, dynamic>>(
context: context,
builder: (context) => const CancelDialogView(),
);
}
@override
Widget build(BuildContext context) {
return const CancelDialogView();
}
}

View File

@@ -0,0 +1,60 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:krow/features/shifts/domain/blocs/complete_dialog/shift_complete_dialog_bloc.dart';
import 'package:krow/features/shifts/domain/blocs/complete_dialog/shift_complete_dialog_event.dart';
import 'package:krow/features/shifts/presentation/dialogs/complete_dialog/widgets/complete_dialog_view.dart';
//TODO(Artem: create widgets instead helper methods. Add initial break time values.Move reasons to state. Create Time slots validator.)
class ShiftCompleteDialog {
static Future<Map<String, dynamic>?> showCustomDialog(BuildContext context,
bool canSkip, String eventName, DateTime minLimit, int breakDurationInMinutes) async {
return showDialog<Map<String, dynamic>>(
barrierDismissible: canSkip,
context: context,
builder: (context) => BlocProvider(
create: (_) => CompleteDialogBloc()
..add(
InitializeCompleteDialog(
minLimit: minLimit,
breakDurationInMinutes:breakDurationInMinutes , // Default break duration
),
),
child: CompleteDialogView(
canSkip: canSkip,
eventName: eventName,
),
),
);
}
}
class ClockOutDetails {
final String? breakStartTime;
final String? breakEndTime;
final String? reason;
final String? additionalReason;
ClockOutDetails._(
{this.breakStartTime,
this.breakEndTime,
this.reason,
this.additionalReason});
factory ClockOutDetails.positive(String breakStartTime, String breakEndTime) {
return ClockOutDetails._(
breakStartTime: breakStartTime,
breakEndTime: breakEndTime,
);
}
factory ClockOutDetails.negative(String reason, String additionalReason) {
return ClockOutDetails._(
reason: reason,
additionalReason: additionalReason,
);
}
factory ClockOutDetails.empty() {
return ClockOutDetails._();
}
}

View File

@@ -0,0 +1,57 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:gap/gap.dart';
import 'package:intl/intl.dart';
import 'package:krow/core/application/common/date_time_extension.dart';
import 'package:krow/core/presentation/styles/kw_text_styles.dart';
import 'package:krow/core/presentation/styles/theme.dart';
import 'package:krow/core/presentation/widgets/kw_time_slot.dart';
import 'package:krow/features/shifts/domain/blocs/complete_dialog/shift_complete_dialog_bloc.dart';
import 'package:krow/features/shifts/domain/blocs/complete_dialog/shift_complete_dialog_event.dart';
import 'package:krow/features/shifts/domain/blocs/complete_dialog/shift_complete_dialog_state.dart';
class BreakTimePicker extends StatelessWidget {
final CompleteDialogState state;
const BreakTimePicker({super.key, required this.state});
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(
child: KwTimeSlotInput(
label: 'Break Start Time',
initialValue: DateFormat('H:mm').parse(state.startTime),
onChange: (v) => context.read<CompleteDialogBloc>().add(
ChangeStartTime(v),
),
),
),
const Gap(12),
Expanded(
child: KwTimeSlotInput(
editable: false,
label: 'Break End Time',
initialValue: DateFormat('H:mm').parse(state.endTime),
onChange: (v) {},
),
),
],
),
if (state.breakTimeInputError != null)
Padding(
padding: const EdgeInsets.only(top: 8, left: 16),
child: Text(
state.breakTimeInputError!,
style: AppTextStyles.bodyTinyReg
.copyWith(color: AppColors.statusError),
),
),
],
);
}
}

View File

@@ -0,0 +1,154 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:gap/gap.dart';
import 'package:krow/core/presentation/styles/kw_text_styles.dart';
import 'package:krow/core/presentation/styles/theme.dart';
import 'package:krow/core/presentation/widgets/ui_kit/kw_button.dart';
import 'package:krow/core/presentation/widgets/ui_kit/kw_input.dart';
import 'package:krow/features/shifts/domain/blocs/complete_dialog/shift_complete_dialog_bloc.dart';
import 'package:krow/features/shifts/domain/blocs/complete_dialog/shift_complete_dialog_event.dart';
import 'package:krow/features/shifts/domain/blocs/complete_dialog/shift_complete_dialog_state.dart';
import 'package:krow/features/shifts/presentation/dialogs/complete_dialog/shift_complete_dialog.dart';
import 'package:krow/features/shifts/presentation/dialogs/complete_dialog/widgets/break_time_picker.dart';
import 'package:krow/features/shifts/presentation/dialogs/complete_dialog/widgets/complete_reason_input.dart';
class CompleteDialogView extends StatelessWidget {
CompleteDialogView({super.key, this.canSkip = true, required this.eventName});
final _textEditingController = TextEditingController();
final bool canSkip;
final String eventName;
String _title(BreakStatus state) => state == BreakStatus.negative
? 'help_us_understand'.tr()
: 'did_you_take_a_break'.tr();
String _message(BreakStatus state) => state == BreakStatus.negative
? 'taking_breaks_essential'.tr()
: 'taking_regular_breaks'.tr(namedArgs: {'eventName': eventName});
@override
Widget build(BuildContext context) {
return BlocBuilder<CompleteDialogBloc, CompleteDialogState>(
builder: (context, state) {
return Center(
child: AnimatedSize(
duration: const Duration(milliseconds: 300),
child: Container(
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 16),
decoration: BoxDecoration(
color: AppColors.grayWhite,
borderRadius: BorderRadius.circular(24),
),
child: SingleChildScrollView(
padding:
const EdgeInsets.symmetric(horizontal: 24, vertical: 56),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
Text(
_title(state.status),
style: AppTextStyles.headingH1.copyWith(height: 1),
textAlign: TextAlign.center,
),
const Gap(8),
Text(
_message(state.status),
style: AppTextStyles.bodyMediumReg
.copyWith(color: AppColors.blackGray),
textAlign: TextAlign.center,
),
const Gap(8),
if (state.status == BreakStatus.positive)
BreakTimePicker(state: state),
if (state.status == BreakStatus.negative)
CompleteReasonInput(selectedReason: state.selectedReason),
if (state.status == BreakStatus.negative) ...[
const Gap(8),
KwTextInput(
controller: _textEditingController,
minHeight: 144,
maxLength: 300,
showCounter: true,
radius: 12,
title: 'additional_reasons'.tr(),
hintText: 'enter_main_text'.tr(),
),
],
const Gap(24),
_buttonGroup(context, state),
],
),
),
),
),
);
},
);
}
Widget _buttonGroup(BuildContext context, CompleteDialogState state) {
var cancelButton = canSkip
? Padding(
padding: const EdgeInsets.only(top: 8.0),
child: KwButton.outlinedPrimary(
label: 'cancel'.tr(),
onPressed: () {
Navigator.pop(context);
},
),
)
: const SizedBox.shrink();
return Column(
children: [
if (state.status == BreakStatus.neutral) ...[
KwButton.primary(
label: 'yes_i_took_a_break'.tr(),
onPressed: () => context
.read<CompleteDialogBloc>()
.add(SelectBreakStatus(BreakStatus.positive)),
),
const Gap(8),
KwButton.outlinedPrimary(
label: 'no_i_didnt_take_a_break'.tr(),
onPressed: () => context
.read<CompleteDialogBloc>()
.add(SelectBreakStatus(BreakStatus.negative)),
),
],
if (state.status == BreakStatus.positive) ...[
KwButton.primary(
disabled: state.breakTimeInputError != null,
label: 'submit_break_time'.tr(),
onPressed: () {
Navigator.pop(context, <String, dynamic>{
'result': true,
'details': ClockOutDetails.positive(
state.startTime,
state.endTime,
)
});
},
),
cancelButton,
],
if (state.status == BreakStatus.negative) ...[
KwButton.primary(
disabled: state.selectedReason == null,
label: 'submit_reason'.tr(),
onPressed: () {
Navigator.pop(context, {
'result': false,
'details': ClockOutDetails.negative(
state.selectedReason!, _textEditingController.text)
});
},
),
cancelButton,
]
],
);
}
}

View File

@@ -0,0 +1,115 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:gap/gap.dart';
import 'package:krow/core/presentation/gen/assets.gen.dart';
import 'package:krow/core/presentation/styles/kw_text_styles.dart';
import 'package:krow/core/presentation/styles/theme.dart';
import 'package:krow/core/presentation/widgets/ui_kit/kw_popup_menu.dart';
import 'package:krow/features/shifts/domain/blocs/complete_dialog/shift_complete_dialog_bloc.dart';
import 'package:krow/features/shifts/domain/blocs/complete_dialog/shift_complete_dialog_event.dart';
const reasons = {
'unpredictable_workflows': 'unpredictable_workflows',
'poor_time_management': 'poor_time_management',
'lack_of_coverage_or_short_staff': 'lack_of_coverage_or_short_staff',
'no_break_area': 'no_break_area',
'other': 'other',
};
class CompleteReasonInput extends StatelessWidget {
final String? selectedReason;
const CompleteReasonInput({super.key, required this.selectedReason});
@override
Widget build(BuildContext context) {
return Column(
children: buildReasonInput(context, selectedReason),
);
}
List<Widget> buildReasonInput(BuildContext context, String? selectedReason) {
return [
const Gap(24),
Row(
children: [
const Gap(16),
Text(
'reason'.tr(),
style:
AppTextStyles.bodyTinyReg.copyWith(color: AppColors.blackGray),
),
],
),
const Gap(4),
KwPopupMenu(
horizontalPadding: 40,
fit: KwPopupMenuFit.expand,
customButtonBuilder: (context, isOpened) {
return _buildMenuButton(isOpened, selectedReason);
},
menuItems: [
...reasons.entries
.map((e) => _buildMenuItem(context, e, selectedReason ?? ''))
])
];
}
Container _buildMenuButton(bool isOpened, String? selectedReason) {
return Container(
height: 48,
padding: const EdgeInsets.symmetric(horizontal: 16),
decoration: BoxDecoration(
color: AppColors.grayWhite,
borderRadius: BorderRadius.circular(24),
border: Border.all(
color: isOpened ? AppColors.bgColorDark : AppColors.grayTintStroke,
width: 1),
),
child: Row(
children: [
Expanded(
child: Text(
reasons[selectedReason]?.tr() ?? 'select_reason_from_list'.tr(),
style: AppTextStyles.bodyMediumReg.copyWith(
color: selectedReason == null
? AppColors.blackGray
: AppColors.blackBlack),
)),
],
),
);
}
KwPopupMenuItem _buildMenuItem(BuildContext context,
MapEntry<String, String> entry, String selectedReason) {
return KwPopupMenuItem(
title: entry.value.tr(),
onTap: () {
context.read<CompleteDialogBloc>().add(SelectReason(entry.key));
},
icon: Container(
height: 16,
width: 16,
decoration: BoxDecoration(
color: selectedReason != entry.key ? null : AppColors.bgColorDark,
shape: BoxShape.circle,
border: selectedReason == entry.key
? null
: Border.all(color: AppColors.grayTintStroke, width: 1),
),
child: selectedReason == entry.key
? Center(
child: Assets.images.icons.check.svg(
height: 10,
width: 10,
colorFilter: const ColorFilter.mode(
AppColors.grayWhite, BlendMode.srcIn),
))
: null,
),
textStyle: AppTextStyles.bodySmallMed,
);
}
}

View File

@@ -0,0 +1,105 @@
import 'package:auto_route/auto_route.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:krow/core/presentation/styles/kw_text_styles.dart';
import 'package:krow/core/presentation/styles/theme.dart';
import 'package:krow/core/presentation/widgets/ui_kit/kw_button.dart';
import 'package:krow/core/presentation/widgets/ui_kit/kw_input.dart';
import 'package:krow/features/shifts/presentation/dialogs/decline_dialog/decline_reason_dropdown.dart';
class DeclineDialogView extends StatefulWidget {
const DeclineDialogView({super.key});
@override
State<DeclineDialogView> createState() => _DeclineDialogViewState();
}
class _DeclineDialogViewState extends State<DeclineDialogView> {
String selectedReason = '';
final _textEditingController = TextEditingController();
@override
Widget build(BuildContext context) {
return Center(
child: AnimatedSize(
duration: const Duration(milliseconds: 300),
child: Container(
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 16),
decoration: BoxDecoration(
color: AppColors.grayWhite,
borderRadius: BorderRadius.circular(24),
),
child: SingleChildScrollView(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 56),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
Text(
'decline_alert'.tr(),
style: AppTextStyles.headingH1.copyWith(height: 1),
textAlign: TextAlign.center,
),
const Gap(8),
Text(
'mention_reason_declining'.tr(),
style: AppTextStyles.bodyMediumReg
.copyWith(color: AppColors.blackGray),
textAlign: TextAlign.center,
),
const Gap(8),
DeclineReasonDropdown(
selectedReason: selectedReason,
onReasonSelected: (String reason) {
setState(() {
selectedReason = reason;
});
},
),
const Gap(8),
KwTextInput(
controller: _textEditingController,
minHeight: 144,
maxLength: 300,
showCounter: true,
radius: 12,
title: 'additional_reasons'.tr(),
hintText: 'enter_main_text'.tr(),
),
const Gap(24),
_buttonGroup(context),
],
),
),
),
),
);
}
Widget _buttonGroup(
BuildContext context,
) {
return Column(
children: [
KwButton.primary(
disabled: selectedReason.isEmpty,
label: 'agree_and_close',
onPressed: () {
context.maybePop({
'reason': selectedReason,
'additionalReason': _textEditingController.text,
});
},
),
const Gap(8),
KwButton.outlinedPrimary(
label: 'contact_admin',
onPressed: () {
//todo contact admin
},
),
],
);
}
}

View File

@@ -0,0 +1,116 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:krow/core/presentation/gen/assets.gen.dart';
import 'package:krow/core/presentation/styles/kw_text_styles.dart';
import 'package:krow/core/presentation/styles/theme.dart';
import 'package:krow/core/presentation/widgets/ui_kit/kw_popup_menu.dart';
const reasons = {
'health': 'health',
'transportation': 'transportation',
'personal': 'personal',
'schedule_conflict': 'schedule_conflict',
'other': 'other_specify',
};
class DeclineReasonDropdown extends StatelessWidget {
final String? selectedReason;
final Function(String reason) onReasonSelected;
const DeclineReasonDropdown(
{super.key,
required this.selectedReason,
required this.onReasonSelected});
@override
Widget build(BuildContext context) {
return Column(
children: buildReasonInput(context, selectedReason),
);
}
List<Widget> buildReasonInput(BuildContext context, String? selectedReason) {
return [
const Gap(24),
Row(
children: [
const Gap(16),
Text(
'valid_reasons'.tr(),
style:
AppTextStyles.bodyTinyReg.copyWith(color: AppColors.blackGray),
),
],
),
const Gap(4),
KwPopupMenu(
horizontalPadding: 40,
fit: KwPopupMenuFit.expand,
customButtonBuilder: (context, isOpened) {
return _buildMenuButton(isOpened, selectedReason);
},
menuItems: [
...reasons.entries
.map((e) => _buildMenuItem(context, e, selectedReason ?? ''))
])
];
}
Container _buildMenuButton(bool isOpened, String? selectedReason) {
return Container(
height: 48,
padding: const EdgeInsets.symmetric(horizontal: 16),
decoration: BoxDecoration(
color: AppColors.grayWhite,
borderRadius: BorderRadius.circular(24),
border: Border.all(
color: isOpened ? AppColors.bgColorDark : AppColors.grayTintStroke,
width: 1),
),
child: Row(
children: [
Expanded(
child: Text(
reasons[selectedReason]?.tr() ?? 'select_reason_from_list'.tr(),
style: AppTextStyles.bodyMediumReg.copyWith(
color: selectedReason == null
? AppColors.blackGray
: AppColors.blackBlack),
)),
],
),
);
}
KwPopupMenuItem _buildMenuItem(BuildContext context,
MapEntry<String, String> entry, String selectedReason) {
return KwPopupMenuItem(
title: entry.value.tr(),
onTap: () {
onReasonSelected(entry.key);
},
icon: Container(
height: 16,
width: 16,
decoration: BoxDecoration(
color: selectedReason != entry.key ? null : AppColors.bgColorDark,
shape: BoxShape.circle,
border: selectedReason == entry.key
? null
: Border.all(color: AppColors.grayTintStroke, width: 1),
),
child: selectedReason == entry.key
? Center(
child: Assets.images.icons.check.svg(
height: 10,
width: 10,
colorFilter: const ColorFilter.mode(
AppColors.grayWhite, BlendMode.srcIn),
))
: null,
),
textStyle: AppTextStyles.bodySmallMed,
);
}
}

View File

@@ -0,0 +1,19 @@
import 'package:flutter/material.dart';
import 'package:krow/features/shifts/presentation/dialogs/decline_dialog/decline_dialog_view.dart';
class ShiftDeclineDialog extends StatelessWidget {
const ShiftDeclineDialog({super.key});
static Future<Map<String, dynamic>?> showCustomDialog(
BuildContext context) async {
return await showDialog<Map<String, dynamic>>(
context: context,
builder: (context) => const ShiftDeclineDialog(),
);
}
@override
Widget build(BuildContext context) {
return const DeclineDialogView();
}
}

View File

@@ -0,0 +1,107 @@
import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
import 'package:krow/core/presentation/gen/assets.gen.dart';
import 'package:krow/core/presentation/widgets/ui_kit/dialogs/kw_dialog.dart';
import 'package:krow/features/shifts/domain/blocs/shift_deteils_bloc/shift_details_bloc.dart';
class GeocodingDialogs {
static bool dialogAlreadyOpen = false;
static void showGeocodingErrorDialog(
ShiftDetailsState state, BuildContext context) async{
if (dialogAlreadyOpen) {
return;
}
dialogAlreadyOpen = true;
var future;
switch (state.proximityState) {
case GeofencingProximityState.tooFar:
future = KwDialog.show(
context: context,
icon: Assets.images.icons.alertTriangle,
state: KwDialogState.warning,
title: "You're too far",
message: 'Please move closer to the designated location.',
primaryButtonLabel: 'OK',
onPrimaryButtonPressed: (dialogContext) {
dialogContext.router.maybePop();
dialogAlreadyOpen = false;
},
);
break;
case GeofencingProximityState.locationDisabled:
future = KwDialog.show(
context: context,
icon: Assets.images.icons.alertTriangle,
state: KwDialogState.negative,
title: 'Location Disabled',
message: 'Please enable location services to continue.',
primaryButtonLabel: 'Go to Settings',
onPrimaryButtonPressed: (dialogContext) async {
dialogContext.router.maybePop();
dialogAlreadyOpen = false;
await Geolocator.openLocationSettings();
},
);
break;
case GeofencingProximityState.goToSettings:
future = KwDialog.show(
context: context,
icon: Assets.images.icons.alertTriangle,
state: KwDialogState.info,
title: 'Permission Required',
message: 'You need to allow location access in settings.',
primaryButtonLabel: 'Open Settings',
onPrimaryButtonPressed: (dialogContext) async {
dialogContext.maybePop();
dialogAlreadyOpen = false;
await Geolocator.openLocationSettings();
},
);
break;
case GeofencingProximityState.onlyInUse:
future = KwDialog.show(
context: context,
icon: Assets.images.icons.alertTriangle,
state: KwDialogState.info,
title: 'Track "All the time" required',
message:
'To ensure accurate time tracking, we need access to your location. Time tracking will automatically stop if you move more than 500 meters away from your assigned work location. '
'Please grant “Allow all the time” access to your location. '
'Go to Settings → Permissions → Location and select “Allow all the time”.',
primaryButtonLabel: 'Open Settings',
onPrimaryButtonPressed: (dialogContext) async {
dialogContext.maybePop();
dialogAlreadyOpen = false;
await Geolocator.openLocationSettings();
},
);
break;
case GeofencingProximityState.permissionDenied:
future = KwDialog.show(
context: context,
icon: Assets.images.icons.alertTriangle,
state: KwDialogState.negative,
title: 'Permission Denied',
message:
'You have denied location access. Please allow it manually.',
primaryButtonLabel: 'OK',
onPrimaryButtonPressed: (dialogContext) async {
dialogContext.maybePop();
dialogAlreadyOpen = false;
await Geolocator.openAppSettings();
});
break;
default:
dialogAlreadyOpen = false;
break;
}
await future;
dialogAlreadyOpen = false;
}
}