first commit
This commit is contained in:
72
lib/Screens/hrm/widgets/deleteing_alart_dialog.dart
Normal file
72
lib/Screens/hrm/widgets/deleteing_alart_dialog.dart
Normal file
@@ -0,0 +1,72 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:mobile_pos/generated/l10n.dart' as l;
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
|
||||
Future<bool> showDeleteConfirmationDialog({
|
||||
required BuildContext context,
|
||||
required String itemName, // Name of the item to delete
|
||||
}) async {
|
||||
final _theme = Theme.of(context);
|
||||
final _lang = l.S.of(context);
|
||||
return await showDialog(
|
||||
barrierDismissible: false,
|
||||
context: context,
|
||||
builder: (BuildContext dialogContext) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Center(
|
||||
child: Container(
|
||||
decoration: const BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(15),
|
||||
),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 30),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
'${_lang.doYouReallyWantToDeleteThis} $itemName?',
|
||||
style: _theme.textTheme.titleLarge?.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Colors.black,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
SizedBox(height: 26),
|
||||
Center(child: SvgPicture.asset('assets/hrm/delete.svg')),
|
||||
SizedBox(height: 26),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: OutlinedButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context, false);
|
||||
},
|
||||
child: Text(_lang.no),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: ElevatedButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context, true);
|
||||
},
|
||||
child: Text(_lang.yes),
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
102
lib/Screens/hrm/widgets/filter_dropdown.dart
Normal file
102
lib/Screens/hrm/widgets/filter_dropdown.dart
Normal file
@@ -0,0 +1,102 @@
|
||||
import 'package:dropdown_button2/dropdown_button2.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:mobile_pos/generated/l10n.dart' as l;
|
||||
import 'package:mobile_pos/constant.dart';
|
||||
|
||||
class FilterDropdownButton<T> extends StatefulWidget {
|
||||
const FilterDropdownButton({
|
||||
super.key,
|
||||
this.value,
|
||||
required this.items,
|
||||
this.onChanged,
|
||||
this.buttonDecoration,
|
||||
this.hint,
|
||||
this.buttonHeight = 40,
|
||||
this.buttonWidth,
|
||||
this.dropdownWidth,
|
||||
this.icon,
|
||||
this.iconSize = 24,
|
||||
this.dropdownDecoration,
|
||||
this.selectedItemBuilder,
|
||||
});
|
||||
|
||||
final T? value;
|
||||
final List<DropdownMenuItem<T>> items;
|
||||
final ValueChanged<T?>? onChanged;
|
||||
final BoxDecoration? buttonDecoration;
|
||||
final Widget? hint;
|
||||
final double buttonHeight;
|
||||
final double? buttonWidth;
|
||||
final double? dropdownWidth;
|
||||
final Widget? icon;
|
||||
final double iconSize;
|
||||
final BoxDecoration? dropdownDecoration;
|
||||
final DropdownButtonBuilder? selectedItemBuilder;
|
||||
|
||||
@override
|
||||
State<FilterDropdownButton<T>> createState() => _FilterDropdownButtonState<T>();
|
||||
}
|
||||
|
||||
class _FilterDropdownButtonState<T> extends State<FilterDropdownButton<T>> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
final isDarkMode = theme.brightness == Brightness.dark;
|
||||
|
||||
return DropdownButtonHideUnderline(
|
||||
child: DropdownButton2<T>(
|
||||
isExpanded: true,
|
||||
value: widget.value,
|
||||
items: widget.items,
|
||||
onChanged: widget.onChanged,
|
||||
selectedItemBuilder: widget.selectedItemBuilder,
|
||||
hint: widget.hint ?? Text(l.S.of(context).selectOne),
|
||||
buttonStyleData: ButtonStyleData(
|
||||
height: widget.buttonHeight,
|
||||
width: widget.buttonWidth,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 2),
|
||||
decoration: widget.buttonDecoration ??
|
||||
BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(5),
|
||||
border: Border.all(
|
||||
color: kBorderColor,
|
||||
),
|
||||
color: isDarkMode ? Colors.grey.shade900 : Colors.white,
|
||||
),
|
||||
elevation: 0,
|
||||
),
|
||||
iconStyleData: IconStyleData(
|
||||
icon: widget.icon ??
|
||||
const Icon(
|
||||
Icons.keyboard_arrow_down,
|
||||
color: kNeutral800,
|
||||
),
|
||||
iconSize: widget.iconSize,
|
||||
iconEnabledColor: theme.iconTheme.color,
|
||||
iconDisabledColor: Colors.grey,
|
||||
),
|
||||
dropdownStyleData: DropdownStyleData(
|
||||
maxHeight: 250,
|
||||
width: widget.dropdownWidth,
|
||||
padding: null,
|
||||
decoration: widget.dropdownDecoration ??
|
||||
BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
color: isDarkMode ? Colors.grey.shade900 : Colors.white,
|
||||
),
|
||||
elevation: 4,
|
||||
// offset: const Offset(0, 0),
|
||||
scrollbarTheme: ScrollbarThemeData(
|
||||
radius: const Radius.circular(40),
|
||||
thickness: WidgetStateProperty.all<double>(6),
|
||||
thumbVisibility: WidgetStateProperty.all<bool>(true),
|
||||
),
|
||||
),
|
||||
menuItemStyleData: const MenuItemStyleData(
|
||||
height: 40,
|
||||
padding: EdgeInsets.symmetric(horizontal: 12),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
80
lib/Screens/hrm/widgets/global_search_appbar.dart
Normal file
80
lib/Screens/hrm/widgets/global_search_appbar.dart
Normal file
@@ -0,0 +1,80 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_feather_icons/flutter_feather_icons.dart';
|
||||
import 'package:mobile_pos/generated/l10n.dart' as l;
|
||||
|
||||
import '../../../constant.dart';
|
||||
|
||||
class GlobalSearchAppBar extends StatelessWidget implements PreferredSizeWidget {
|
||||
final bool isSearch;
|
||||
final VoidCallback onSearchToggle;
|
||||
final String title;
|
||||
final TextEditingController? controller;
|
||||
final ValueChanged<String>? onChanged;
|
||||
final PopupMenuItemSelected<dynamic>? onManuSelect;
|
||||
final List<PopupMenuItem>? popupMenuButtons;
|
||||
|
||||
const GlobalSearchAppBar({
|
||||
super.key,
|
||||
required this.isSearch,
|
||||
required this.onSearchToggle,
|
||||
required this.title,
|
||||
this.controller,
|
||||
this.onChanged,
|
||||
this.popupMenuButtons,
|
||||
this.onManuSelect,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AppBar(
|
||||
title: isSearch
|
||||
? TextField(
|
||||
autofocus: true,
|
||||
controller: controller,
|
||||
onChanged: onChanged,
|
||||
decoration: InputDecoration(
|
||||
hintText: '${l.S.of(context).searchH}...',
|
||||
border: InputBorder.none,
|
||||
suffixIcon: Icon(
|
||||
FeatherIcons.search,
|
||||
// size: 18,
|
||||
color: kNeutral800,
|
||||
),
|
||||
),
|
||||
)
|
||||
: Text(title),
|
||||
centerTitle: true,
|
||||
automaticallyImplyLeading: !isSearch,
|
||||
actions: [
|
||||
IconButton(
|
||||
style: ButtonStyle(
|
||||
overlayColor: WidgetStatePropertyAll(Colors.transparent),
|
||||
),
|
||||
visualDensity: const VisualDensity(horizontal: -4),
|
||||
padding: EdgeInsets.only(right: 16),
|
||||
onPressed: onSearchToggle,
|
||||
icon: Icon(
|
||||
isSearch ? Icons.close : FeatherIcons.search,
|
||||
color: isSearch ? kMainColor : kNeutral800,
|
||||
size: isSearch ? null : 22,
|
||||
),
|
||||
),
|
||||
if (popupMenuButtons != null)
|
||||
PopupMenuButton(
|
||||
onSelected: onManuSelect,
|
||||
itemBuilder: (context) => popupMenuButtons!,
|
||||
icon: const Icon(Icons.more_vert),
|
||||
)
|
||||
],
|
||||
bottom: PreferredSize(
|
||||
preferredSize: Size.fromHeight(1),
|
||||
child: Divider(
|
||||
height: 2,
|
||||
color: kBackgroundColor,
|
||||
)),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Size get preferredSize => Size.fromHeight(isSearch ? 65 : kToolbarHeight);
|
||||
}
|
||||
16
lib/Screens/hrm/widgets/label_style.dart
Normal file
16
lib/Screens/hrm/widgets/label_style.dart
Normal file
@@ -0,0 +1,16 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
Widget labelSpan({required String title, required BuildContext context}) {
|
||||
final _theme = Theme.of(context);
|
||||
return Text.rich(
|
||||
TextSpan(text: title, children: [
|
||||
TextSpan(
|
||||
text: '*',
|
||||
style: TextStyle(color: Colors.red),
|
||||
)
|
||||
]),
|
||||
style: _theme.textTheme.titleSmall?.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
);
|
||||
}
|
||||
138
lib/Screens/hrm/widgets/model_bottom_sheet.dart
Normal file
138
lib/Screens/hrm/widgets/model_bottom_sheet.dart
Normal file
@@ -0,0 +1,138 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:mobile_pos/generated/l10n.dart' as l;
|
||||
import '../../../Const/api_config.dart';
|
||||
import '../../../constant.dart';
|
||||
|
||||
void viewModalSheet({
|
||||
required BuildContext context,
|
||||
required Map<String, String> item,
|
||||
String? description,
|
||||
bool? showImage,
|
||||
String? image,
|
||||
String? descriptionTitle,
|
||||
}) {
|
||||
final _theme = Theme.of(context);
|
||||
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
useSafeArea: true,
|
||||
isDismissible: false,
|
||||
builder: (BuildContext context) {
|
||||
return SingleChildScrollView(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.of(context).viewInsets.bottom,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsetsDirectional.only(start: 16),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
l.S.of(context).viewDetails,
|
||||
style: _theme.textTheme.titleMedium?.copyWith(
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 18,
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
icon: Icon(Icons.close, size: 18),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
Divider(color: kBorderColor, height: 1),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (showImage == true) ...[
|
||||
SizedBox(height: 15),
|
||||
image != null
|
||||
? Center(
|
||||
child: Container(
|
||||
height: 120,
|
||||
width: 120,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
image: DecorationImage(
|
||||
fit: BoxFit.cover,
|
||||
image: NetworkImage('${APIConfig.domain}$image'),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
: Center(
|
||||
child: Image.asset(
|
||||
height: 120,
|
||||
width: 120,
|
||||
fit: BoxFit.cover,
|
||||
'assets/hrm/image_icon.jpg',
|
||||
),
|
||||
),
|
||||
SizedBox(height: 21),
|
||||
],
|
||||
Column(
|
||||
children: item.entries.map((entry) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 4.0),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Flexible(
|
||||
fit: FlexFit.tight,
|
||||
flex: 2,
|
||||
child: Text(
|
||||
'${entry.key} ',
|
||||
style: _theme.textTheme.bodyLarge?.copyWith(
|
||||
color: kNeutral800,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 8),
|
||||
Flexible(
|
||||
fit: FlexFit.tight,
|
||||
flex: 4,
|
||||
child: Text(
|
||||
': ${entry.value}',
|
||||
style: _theme.textTheme.bodyLarge,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
if (description != null) ...[
|
||||
SizedBox(height: 16),
|
||||
Text.rich(
|
||||
TextSpan(
|
||||
text: "${descriptionTitle ?? l.S.of(context).description}\n",
|
||||
style: _theme.textTheme.titleMedium?.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
children: [
|
||||
TextSpan(
|
||||
text: description,
|
||||
style: _theme.textTheme.bodyLarge?.copyWith(
|
||||
color: kNeutral800,
|
||||
),
|
||||
)
|
||||
]),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
86
lib/Screens/hrm/widgets/set_time.dart
Normal file
86
lib/Screens/hrm/widgets/set_time.dart
Normal file
@@ -0,0 +1,86 @@
|
||||
// import 'package:flutter/material.dart';
|
||||
//
|
||||
// Future<void> setTime(TextEditingController controller, BuildContext context) async {
|
||||
// TimeOfDay initialTime = TimeOfDay.now();
|
||||
//
|
||||
// if (controller.text.isNotEmpty) {
|
||||
// final timeParts = controller.text.split(' ');
|
||||
// final time = timeParts[0].split(':');
|
||||
// final period = timeParts[1];
|
||||
//
|
||||
// int hour = int.parse(time[0]);
|
||||
// if (period == 'PM' && hour != 12) hour += 12;
|
||||
// if (period == 'AM' && hour == 12) hour = 0;
|
||||
//
|
||||
// initialTime = TimeOfDay(hour: hour, minute: int.parse(time[1]));
|
||||
// }
|
||||
//
|
||||
// final TimeOfDay? picked = await showTimePicker(
|
||||
// context: context,
|
||||
// initialTime: initialTime,
|
||||
// builder: (context, child) => MediaQuery(
|
||||
// data: MediaQuery.of(context).copyWith(alwaysUse24HourFormat: false),
|
||||
// child: child!,
|
||||
// ),
|
||||
// );
|
||||
//
|
||||
// if (picked != null) {
|
||||
// final hours = picked.hourOfPeriod;
|
||||
// final minutes = picked.minute.toString().padLeft(2, '0');
|
||||
// final period = picked.period == DayPeriod.am ? 'AM' : 'PM';
|
||||
// controller.text = '$hours:$minutes $period';
|
||||
// }
|
||||
// }
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
Future<void> setTime(TextEditingController controller, BuildContext context) async {
|
||||
TimeOfDay initialTime = TimeOfDay.now();
|
||||
|
||||
if (controller.text.isNotEmpty) {
|
||||
final timeParts = controller.text.split(' ');
|
||||
final time = timeParts[0].split(':');
|
||||
final period = timeParts.length > 1 ? timeParts[1] : '';
|
||||
|
||||
int hour = int.parse(time[0]);
|
||||
if (period == 'PM' && hour != 12) hour += 12;
|
||||
if (period == 'AM' && hour == 12) hour = 0;
|
||||
|
||||
initialTime = TimeOfDay(hour: hour, minute: int.parse(time[1]));
|
||||
}
|
||||
|
||||
final TimeOfDay? picked = await showTimePicker(
|
||||
context: context,
|
||||
initialTime: initialTime,
|
||||
builder: (context, child) {
|
||||
final theme = Theme.of(context);
|
||||
return Theme(
|
||||
data: theme.copyWith(
|
||||
colorScheme: theme.colorScheme.copyWith(
|
||||
primary: theme.colorScheme.primary, // active selection color
|
||||
onPrimary: Colors.white, // text color on primary (e.g., white text)
|
||||
surface: theme.colorScheme.surface, // dialog background
|
||||
onSurface: theme.colorScheme.onSurface, // default text color
|
||||
),
|
||||
timePickerTheme: TimePickerThemeData(
|
||||
backgroundColor: theme.dialogBackgroundColor,
|
||||
hourMinuteTextColor: theme.colorScheme.onSurface,
|
||||
dialBackgroundColor: theme.colorScheme.surfaceVariant,
|
||||
dialHandColor: theme.colorScheme.primary,
|
||||
),
|
||||
),
|
||||
child: MediaQuery(
|
||||
data: MediaQuery.of(context).copyWith(alwaysUse24HourFormat: false),
|
||||
child: child!,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
if (picked != null) {
|
||||
final hours = picked.hourOfPeriod == 0 ? 12 : picked.hourOfPeriod;
|
||||
final minutes = picked.minute.toString().padLeft(2, '0');
|
||||
final period = picked.period == DayPeriod.am ? 'AM' : 'PM';
|
||||
controller.text = '$hours:$minutes $period';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user