first commit

This commit is contained in:
Hamza-Ayed
2026-06-09 08:40:31 +03:00
commit d8901e1a87
3161 changed files with 536187 additions and 0 deletions

View File

@@ -0,0 +1,172 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:siro_service/constant/colors.dart';
import 'package:siro_service/controller/auth/register_controller.dart';
import 'package:siro_service/views/widgets/my_textField.dart';
class RegisterPage extends StatelessWidget {
const RegisterPage({super.key});
@override
Widget build(BuildContext context) {
final RegisterController controller = Get.put(RegisterController());
return Scaffold(
backgroundColor: const Color(0xFFF8F9FD),
appBar: AppBar(
backgroundColor: Colors.transparent,
elevation: 0,
leading: IconButton(
icon: const Icon(Icons.arrow_back_ios_new, color: Colors.black87),
onPressed: () => Get.back(),
),
title: Text(
'إنشاء حساب موظف'.tr,
style: const TextStyle(color: Colors.black87, fontWeight: FontWeight.bold),
),
centerTitle: true,
),
body: SafeArea(
child: SingleChildScrollView(
padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 16.0),
child: Form(
key: controller.formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Center(
child: Icon(
Icons.person_add_rounded,
size: 80,
color: AppColor.blueColor,
),
),
const SizedBox(height: 32),
_buildFieldTitle('الاسم الأول'),
MyTextForm(
controller: controller.firstName,
label: 'الاسم الأول',
hint: 'أدخل الاسم الأول',
type: TextInputType.name,
),
const SizedBox(height: 16),
_buildFieldTitle('الاسم الأخير'),
MyTextForm(
controller: controller.lastName,
label: 'الاسم الأخير',
hint: 'أدخل الاسم الأخير',
type: TextInputType.name,
),
const SizedBox(height: 16),
_buildFieldTitle('البريد الإلكتروني'),
MyTextForm(
controller: controller.email,
label: 'البريد الإلكتروني',
hint: 'example@mail.com',
type: TextInputType.emailAddress,
),
const SizedBox(height: 16),
_buildFieldTitle('رقم الهاتف'),
MyTextForm(
controller: controller.phone,
label: 'رقم الهاتف',
hint: '09xxxxxxxx',
type: TextInputType.phone,
),
const SizedBox(height: 16),
_buildFieldTitle('كلمة المرور'),
MyTextForm(
controller: controller.password,
label: 'كلمة المرور',
hint: '********',
type: TextInputType.visiblePassword,
),
const SizedBox(height: 40),
Obx(() => controller.isLoading.value
? const Center(child: CircularProgressIndicator())
: Container(
height: 55,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16),
gradient: const LinearGradient(
colors: [AppColor.blueColor, Color(0xFF1A237E)],
begin: Alignment.centerLeft,
end: Alignment.centerRight,
),
boxShadow: [
BoxShadow(
color: AppColor.blueColor.withOpacity(0.3),
blurRadius: 12,
offset: const Offset(0, 6),
),
],
),
child: Material(
color: Colors.transparent,
child: InkWell(
borderRadius: BorderRadius.circular(16),
onTap: () => controller.register(),
child: const Center(
child: Text(
'تقديم طلب تسجيل',
style: TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
),
),
),
)),
const SizedBox(height: 24),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'لديك حساب بالفعل؟ '.tr,
style: const TextStyle(color: Colors.grey),
),
TextButton(
onPressed: () => Get.back(),
child: const Text(
'تسجيل الدخول',
style: TextStyle(
color: AppColor.blueColor,
fontWeight: FontWeight.bold,
),
),
),
],
),
const SizedBox(height: 20),
],
),
),
),
),
);
}
Widget _buildFieldTitle(String title) {
return Padding(
padding: const EdgeInsets.only(bottom: 8.0, right: 4.0),
child: Text(
title,
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
color: Colors.black54,
),
),
);
}
}

View File

@@ -0,0 +1,635 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:siro_service/constant/colors.dart';
import 'package:siro_service/constant/links.dart';
import 'package:siro_service/controller/functions/crud.dart';
import 'package:siro_service/controller/mainController/main_controller.dart';
import 'package:siro_service/controller/mainController/pages/best_driver_page.dart';
import 'package:siro_service/controller/mainController/pages/complaint.dart';
import 'package:siro_service/controller/mainController/pages/edit_car_plate.dart';
import 'package:siro_service/controller/mainController/pages/passengers_cant_regster.dart';
import 'package:siro_service/views/widgets/elevated_btn.dart';
import 'package:siro_service/views/widgets/my_dialog.dart';
import 'package:siro_service/views/widgets/my_textField.dart';
import '../../constant/style.dart';
import '../../controller/mainController/pages/add_car.dart';
import '../../controller/mainController/pages/drivers_cant_register.dart';
import '../../controller/mainController/pages/new_driver.dart';
import '../../controller/mainController/pages/welcome_call.dart';
import '../../main.dart';
import '../widgets/my_scafold.dart';
class Main extends StatelessWidget {
Main({super.key});
final MainController mainController = Get.put(MainController());
@override
Widget build(BuildContext context) {
return MyScaffold(title: 'Intaleq Service'.tr, isleading: false, body: [
Container(
color: AppColor.surfaceColor,
child: SingleChildScrollView(
physics: const BouncingScrollPhysics(),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// --- Header Section ---
_buildHeader(),
// --- Statistics Section ---
_buildStatsSection(),
// --- Actions Section ---
_buildCategoryTitle('🔍 Search & Inquiries'.tr),
_buildGridSection([
ServiceItem(
title: 'passenger details by phone'.tr,
icon: Icons.person_search_rounded,
color: Colors.blue,
onTap: () => _showSearchDialog(
title: 'insert passenger phone'.tr,
controller: mainController.passengerPhoneController,
onSearch: () => mainController.searchPassengerByPhone(),
),
),
ServiceItem(
title: 'Driver details by phone'.tr,
icon: Icons.contact_phone_rounded,
color: Colors.indigo,
onTap: () => _showSearchDialog(
title: 'insert Driver phone'.tr,
controller: mainController.driverPhoneController,
onSearch: () => mainController.searchDriverByPhone(),
),
),
ServiceItem(
title: 'Driver details by national number'.tr,
icon: Icons.badge_rounded,
color: Colors.teal,
onTap: () => _showSearchDialog(
title: 'insert Driver national'.tr,
controller: mainController.driverPhoneController,
type: TextInputType.number,
onSearch: () => mainController.searchDriverByNational(),
),
),
]),
_buildCategoryTitle('⏳ Approval Queue'.tr),
_buildGridSection([
ServiceItem(
title: 'Drivers waitting Register'.tr,
icon: Icons.pending_actions_rounded,
color: Colors.orange,
onTap: () async {
await mainController.getDriverWantCompleteRegistration();
Get.to(() => DriversCantRegister());
},
),
ServiceItem(
title: 'Drivers phones not register'.tr,
icon: Icons.phone_disabled_rounded,
color: Colors.blueGrey,
onTap: () async {
await mainController.getDriversPhoneNotComplete();
Get.to(() => DriversCantRegister());
},
),
ServiceItem(
title: 'Drivers Activity'.tr,
icon: Icons.assessment_rounded,
color: Colors.blueAccent,
onTap: () async {
await mainController.getDriversPhoneNotComplete();
Get.to(() => DriversCantRegister());
},
),
ServiceItem(
title: 'Drivers Cant Register'.tr,
icon: Icons.car_crash_rounded,
color: Colors.redAccent,
onTap: () async {
await mainController.getDriverNotCompleteRegistration();
Get.to(() => DriversCantRegister());
},
),
ServiceItem(
title: 'Passengers Cant Register'.tr,
icon: Icons.group_off_rounded,
color: Colors.deepOrange,
onTap: () async {
await mainController.getPassengerNotCompleteRegistration();
Get.to(() => PassengersCantRegister());
},
),
]),
_buildCategoryTitle('⚡ Quick Actions'.tr),
_buildGridSection([
ServiceItem(
title: 'Register new driver'.tr,
icon: Icons.person_add_rounded,
color: Colors.green,
onTap: () => Get.to(() => RegisterCaptain()),
),
ServiceItem(
title: 'Add Driver Who Wants to Work'.tr,
icon: Icons.handshake_rounded,
color: Colors.lightGreen,
onTap: () => _showAddDriverDialog(),
),
ServiceItem(
title: 'Add Car Who Wants to Work'.tr,
icon: Icons.add_road_rounded,
color: Colors.cyan,
onTap: () => _showAddCarDialog(),
),
]),
_buildCategoryTitle('🚗 Vehicle Management'.tr),
_buildGridSection([
ServiceItem(
title: 'Add car'.tr,
icon: Icons.add_circle_outline_rounded,
color: Colors.purple,
onTap: () async {
await mainController.getdriverWithoutCar();
if (mainController.driverWithoutCar.isNotEmpty) {
Get.to(() => const AddCar());
}
},
),
ServiceItem(
title: 'Edit car plate'.tr,
icon: Icons.edit_attributes_rounded,
color: Colors.amber,
onTap: () async {
await mainController.getCarPlateNotEdit();
if (mainController.carPlateNotEdit.isNotEmpty) {
Get.to(() => const EditCarPlate());
}
},
),
]),
_buildCategoryTitle('📊 Reporting & Quality'.tr),
_buildGridSection([
ServiceItem(
title: "View complaint".tr,
icon: Icons.report_problem_rounded,
color: Colors.deepOrange,
onTap: () => Get.to(() => const Complaint()),
),
ServiceItem(
title: "Welcome call".tr,
icon: Icons.ring_volume_rounded,
color: Colors.pink,
onTap: () async {
await mainController.getNewDriverRegister();
Get.to(() => const WelcomeCall());
},
),
ServiceItem(
title: "best driver".tr,
icon: Icons.emoji_events_rounded,
color: Colors.orangeAccent,
onTap: () async {
await mainController.getNewDriverRegister();
Get.to(() => DriverTheBest());
},
),
]),
const SizedBox(height: 32),
],
),
),
),
]);
}
Widget _buildHeader() {
return Container(
padding: const EdgeInsets.all(24),
decoration: const BoxDecoration(
color: AppColor.primaryColor,
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(32),
bottomRight: Radius.circular(32),
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Welcome back,'.tr,
style: AppStyle.title.copyWith(color: Colors.white70),
),
Text(
'Service Agent'.tr,
style: AppStyle.headTitle2.copyWith(color: Colors.white),
),
],
),
Row(
children: [
IconButton(
icon:
const Icon(Icons.refresh_rounded, color: Colors.white),
onPressed: () => mainController.refreshDashboardStats(),
),
const SizedBox(width: 8),
CircleAvatar(
radius: 24,
backgroundColor: Colors.white24,
child: IconButton(
icon: const Icon(Icons.logout, color: Colors.white),
onPressed: () {
box.erase();
Get.offAllNamed('/login');
},
),
),
],
),
],
),
const SizedBox(height: 24),
// --- Custom Search Bar ---
Container(
margin: const EdgeInsets.symmetric(horizontal: 16),
padding: const EdgeInsets.symmetric(horizontal: 16),
decoration: AppStyle.boxDecoration.copyWith(
color: Colors.white.withValues(alpha: 0.95),
borderRadius: BorderRadius.circular(16),
),
child: TextField(
decoration: InputDecoration(
hintText: 'Quick Search...'.tr,
border: InputBorder.none,
icon: const Icon(Icons.search, color: AppColor.primaryColor),
),
onSubmitted: (val) {
// Global search logic
},
),
),
],
),
);
}
Widget _buildStatsSection() {
return GetBuilder<MainController>(
builder: (controller) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 20.0, horizontal: 16.0),
child: Row(
children: [
_buildStatCard(
'Pending'.tr,
controller.isLoading
? '...'
: controller.driverWantCompleteRegistration.length
.toString(),
Icons.timer_rounded,
Colors.orange,
),
const SizedBox(width: 12),
_buildStatCard(
'New'.tr,
controller.isLoading
? '...'
: controller.newDriverRegister.length.toString(),
Icons.person_add_alt_1_rounded,
Colors.green,
),
const SizedBox(width: 12),
_buildStatCard(
'Issues'.tr,
controller.isLoading
? '...'
: controller.driverNotCompleteRegistration.length
.toString(),
Icons.warning_rounded,
Colors.red,
),
],
),
);
},
);
}
Widget _buildStatCard(
String title, String count, IconData icon, Color color) {
return Expanded(
child: Container(
padding: const EdgeInsets.all(16),
decoration: AppStyle.boxDecoration,
child: Column(
children: [
Icon(icon, color: color, size: 24),
const SizedBox(height: 8),
Text(count, style: AppStyle.headTitle2.copyWith(fontSize: 20)),
Text(title,
style: AppStyle.subtitle.copyWith(color: AppColor.accentColor)),
],
),
),
);
}
Widget _buildCategoryTitle(String title) {
return Padding(
padding: const EdgeInsets.fromLTRB(20, 24, 20, 12),
child: Text(
title,
style: AppStyle.headTitle2.copyWith(fontSize: 18),
),
);
}
Widget _buildGridSection(List<ServiceItem> items) {
return GridView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
padding: const EdgeInsets.symmetric(horizontal: 16),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 12,
mainAxisSpacing: 12,
childAspectRatio: 1.15,
),
itemCount: items.length,
itemBuilder: (context, index) {
final item = items[index];
return _buildServiceCard(item);
},
);
}
Widget _buildServiceCard(ServiceItem item) {
return InkWell(
onTap: item.onTap,
borderRadius: BorderRadius.circular(20),
child: Container(
decoration: AppStyle.boxDecoration1,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: item.color.withValues(alpha: 0.1),
shape: BoxShape.circle,
),
child: Icon(item.icon, color: item.color, size: 30),
),
const SizedBox(height: 12),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Text(
item.title,
textAlign: TextAlign.center,
style: AppStyle.title
.copyWith(fontSize: 13, fontWeight: FontWeight.w600),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
),
],
),
),
);
}
void _showSearchDialog({
required String title,
required TextEditingController controller,
required VoidCallback onSearch,
TextInputType type = TextInputType.phone,
}) {
MyDialog().getDialog(
title,
'Search Details'.tr,
Form(
key: mainController.formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
MyTextForm(
controller: controller,
label: title,
hint: title,
type: type,
validator: (val) {
if (val == null || val.isEmpty) {
return 'Please enter a value'.tr;
}
return null;
},
),
],
),
),
onSearch,
);
}
void _showAddDriverDialog() {
Get.defaultDialog(
barrierDismissible: false,
title: "Add Driver Who Wants to Work".tr,
titleStyle: AppStyle.headTitle2,
content: SizedBox(
width: Get.width * .8,
height: 350,
child: Form(
key: mainController.formKey,
child: ListView(
padding: const EdgeInsets.all(8),
children: [
MyTextForm(
controller: mainController.driverNameController,
label: 'Insert Name of Driver'.tr,
hint: 'Insert Name of Driver'.tr,
type: TextInputType.name),
MyTextForm(
controller: mainController.nationalIdController,
label: 'Insert national ID of Driver'.tr,
hint: 'Insert national ID of Driver'.tr,
type: TextInputType.number),
MyTextForm(
controller: mainController.phoneController,
label: 'Insert phone of Driver'.tr,
hint: 'Insert phone of Driver'.tr,
type: TextInputType.phone),
MyTextForm(
controller: mainController.licenseTypeController,
label: 'Insert license type of Driver'.tr,
hint: 'Insert license type of Driver'.tr,
type: TextInputType.name),
MyTextForm(
controller: mainController.siteDriverController,
label: 'Insert site of Driver'.tr,
hint: 'Insert site of Driver'.tr,
type: TextInputType.name),
MyTextForm(
controller: mainController.birthDateController,
label: 'Insert birth_date of Driver'.tr,
hint: 'YYYY-MM-DD'.tr,
type: TextInputType.datetime),
],
),
),
),
confirm: MyElevatedButton(
title: 'Add'.tr,
onPressed: () async {
var res =
await CRUD().post(link: AppLink.addDriverWantWork, payload: {
"driver_name": mainController.driverNameController.text,
"national_id": mainController.nationalIdController.text,
"birth_date": mainController.birthDateController.text,
"site": mainController.siteDriverController.text,
"license_type": mainController.licenseTypeController.text,
"phone": mainController.phoneController.text,
});
if (res != 'failure' && res['status'] == 'success') {
Get.back();
mainController.driverNameController.clear();
mainController.nationalIdController.clear();
mainController.birthDateController.clear();
mainController.licenseTypeController.clear();
mainController.siteDriverController.clear();
mainController.phoneController.clear();
Get.snackbar('Success'.tr, 'Added successfully'.tr,
backgroundColor: AppColor.greenColor, colorText: Colors.white);
}
},
kolor: AppColor.greenColor,
),
cancel: MyElevatedButton(
title: 'Cancel'.tr,
kolor: AppColor.redColor,
onPressed: () => Get.back()),
);
}
void _showAddCarDialog() {
Get.defaultDialog(
barrierDismissible: false,
title: "Add Car Who Wants to Work".tr,
titleStyle: AppStyle.headTitle2,
content: SizedBox(
width: Get.width * .8,
height: 350,
child: Form(
key: mainController.formKey,
child: ListView(
padding: const EdgeInsets.all(8),
children: [
MyTextForm(
controller: mainController.carOwnerWorkController,
label: 'Insert Name of Owner'.tr,
hint: 'Insert Name of Owner'.tr,
type: TextInputType.name),
MyTextForm(
controller: mainController.carNumberController,
label: 'Insert car_number of Driver'.tr,
hint: 'Insert car_number of Driver'.tr,
type: TextInputType.name),
MyTextForm(
controller: mainController.phoneCarController,
label: 'Insert phone of Owner'.tr,
hint: 'Insert phone of Owner'.tr,
type: TextInputType.phone),
MyTextForm(
controller: mainController.manufactureYearController,
label: 'Insert year of Car'.tr,
hint: 'Insert year of Car'.tr,
type: TextInputType.number),
MyTextForm(
controller: mainController.carModelController,
label: 'Insert car_model of Driver'.tr,
hint: 'Insert car_model of Driver'.tr,
type: TextInputType.name),
MyTextForm(
controller: mainController.siteCarController,
label: 'Insert site of Owner'.tr,
hint: 'Insert site of Owner'.tr,
type: TextInputType.name),
MyTextForm(
controller: mainController.carTypeController,
label: 'Insert car_type of Driver'.tr,
hint: 'Insert car_type of Driver'.tr,
type: TextInputType.name),
MyTextForm(
controller: mainController.registrationDateController,
label: 'Insert registration_date of Car'.tr,
hint: 'YYYY-MM-DD'.tr,
type: TextInputType.datetime),
],
),
),
),
confirm: MyElevatedButton(
title: 'Add'.tr,
onPressed: () async {
var res = await CRUD().post(link: AppLink.addCarWantWork, payload: {
"owner_name": mainController.carOwnerWorkController.text,
"car_number": mainController.carNumberController.text,
"manufacture_year": mainController.manufactureYearController.text,
"car_model": mainController.carModelController.text,
"car_type": mainController.carTypeController.text,
"site": mainController.siteCarController.text,
"registration_date": mainController.registrationDateController.text,
"phone": mainController.phoneCarController.text,
});
if (res != 'failure' && res['status'] == 'success') {
Get.back();
mainController.carOwnerWorkController.clear();
mainController.carNumberController.clear();
mainController.manufactureYearController.clear();
mainController.carModelController.clear();
mainController.siteCarController.clear();
mainController.carTypeController.clear();
mainController.registrationDateController.clear();
mainController.phoneCarController.clear();
Get.snackbar('Success'.tr, 'Added successfully'.tr,
backgroundColor: AppColor.greenColor, colorText: Colors.white);
}
},
kolor: AppColor.greenColor,
),
cancel: MyElevatedButton(
title: 'Cancel'.tr,
kolor: AppColor.redColor,
onPressed: () => Get.back()),
);
}
}
class ServiceItem {
final String title;
final IconData icon;
final Color color;
final VoidCallback onTap;
ServiceItem({
required this.title,
required this.icon,
required this.color,
required this.onTap,
});
}

View File

@@ -0,0 +1,63 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../../constant/colors.dart';
class MyCircleContainer extends StatelessWidget {
final Widget child;
final Color backgroundColor;
final Color borderColor;
MyCircleContainer({
Key? key,
required this.child,
this.backgroundColor = AppColor.secondaryColor,
this.borderColor = AppColor.accentColor,
}) : super(key: key);
final controller = Get.put(CircleController());
@override
Widget build(BuildContext context) {
return GetBuilder<CircleController>(
builder: ((controller) => GestureDetector(
onTap: () {
controller.changeColor();
},
child: AnimatedContainer(
onEnd: () {
controller.onEnd();
},
duration: const Duration(milliseconds: 300),
width: controller.size,
height: controller.size,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: controller.backgroundColor,
border: Border.all(
color: borderColor,
width: 1,
),
),
child: Center(child: child),
),
)));
}
}
class CircleController extends GetxController {
Color backgroundColor = AppColor.secondaryColor;
double size = 40;
void changeColor() {
backgroundColor = backgroundColor == AppColor.secondaryColor
? AppColor.accentColor
: AppColor.secondaryColor;
size = 60;
update();
}
void onEnd() {
size = 40;
update();
}
}

View File

@@ -0,0 +1,69 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:vibration/vibration.dart';
import '../../constant/box_name.dart';
import '../../constant/colors.dart';
import '../../constant/style.dart';
import '../../main.dart';
class MyElevatedButton extends StatelessWidget {
final String title;
final VoidCallback onPressed;
final Color kolor;
final int vibrateDuration;
final bool loading;
final Widget? child;
const MyElevatedButton({
Key? key,
required this.title,
required this.onPressed,
this.kolor = AppColor.primaryColor,
this.vibrateDuration = 100,
this.loading = false,
this.child,
}) : super(key: key);
@override
Widget build(BuildContext context) {
bool vibrate = box.read(BoxName.isvibrate) ?? true;
return ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: kolor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12.0),
),
),
onPressed: loading
? null
: () async {
if (vibrate == true) {
if (Platform.isIOS) {
HapticFeedback.selectionClick();
} else if (Platform.isAndroid) {
await Vibration.vibrate(duration: vibrateDuration);
} else {}
}
onPressed();
},
child: loading
? const SizedBox(
height: 20,
width: 20,
child: CircularProgressIndicator(
color: Colors.white,
strokeWidth: 2,
),
)
: child ??
Text(
title,
textAlign: TextAlign.center,
style: AppStyle.title.copyWith(color: AppColor.secondaryColor),
),
);
}
}

View File

@@ -0,0 +1,66 @@
import 'package:flutter/material.dart';
import '../../constant/colors.dart';
import '../../constant/style.dart';
class IconWidgetMenu extends StatelessWidget {
const IconWidgetMenu({
Key? key,
required this.onpressed,
required this.icon,
required this.title,
}) : super(key: key);
final VoidCallback onpressed;
final IconData icon;
final String title;
@override
Widget build(BuildContext context) {
return InkWell(
onTap: onpressed,
child: Padding(
padding: const EdgeInsets.only(top: 1),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: 50,
decoration: const BoxDecoration(
color: AppColor.secondaryColor,
shape: BoxShape.circle,
// boxShadow: [
// BoxShadow(
// color: AppColor.secondaryColor,
// offset: Offset(-2, -2),
// blurRadius: 0,
// spreadRadius: 0,
// blurStyle: BlurStyle.outer,
// ),
// BoxShadow(
// color: AppColor.accentColor,
// offset: Offset(3, 3),
// blurRadius: 0,
// spreadRadius: 0,
// blurStyle: BlurStyle.outer,
// ),
// ],
),
child: Center(
child: Icon(
icon,
size: 30,
color: AppColor.primaryColor,
),
),
),
Text(
title,
style: AppStyle.subtitle.copyWith(color: AppColor.secondaryColor),
)
],
),
),
);
}
}

View File

@@ -0,0 +1,40 @@
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../../constant/colors.dart';
import '../../constant/style.dart';
import 'elevated_btn.dart';
class MyDialog extends GetxController {
void getDialog(
String title, String? midTitle, Widget widget, VoidCallback onPressed) {
// final textToSpeechController = Get.put(TextToSpeechController());
Get.defaultDialog(
title: title,
titleStyle: AppStyle.title,
middleTextStyle: AppStyle.title,
content: Column(
children: [
// IconButton(
// onPressed: () async {
// // await textToSpeechController.speakText(title ?? midTitle!);
// },
// icon: const Icon(Icons.headphones)),
widget
],
),
confirm: MyElevatedButton(
title: 'Ok'.tr,
onPressed: onPressed,
kolor: AppColor.greenColor,
),
cancel: MyElevatedButton(
title: 'Cancel',
kolor: AppColor.redColor,
onPressed: () {
Get.back();
}));
}
}

View File

@@ -0,0 +1,51 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../../constant/colors.dart';
import '../../constant/style.dart';
class MyScaffold extends StatelessWidget {
const MyScaffold({
super.key,
required this.title,
this.action = const Icon(
Icons.clear,
color: AppColor.secondaryColor,
),
required this.isleading,
required this.body,
});
final String title;
final List<Widget> body;
final Widget action;
final bool isleading;
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColor.secondaryColor,
appBar: AppBar(
backgroundColor: AppColor.secondaryColor,
elevation: 0,
leading: isleading
? IconButton(
onPressed: () {
Get.back();
},
icon: const Icon(
Icons.arrow_back_ios_new,
color: AppColor.primaryColor,
),
)
: const SizedBox(),
actions: [action],
title: Text(
title,
style: AppStyle.title
.copyWith(fontSize: 20, fontWeight: FontWeight.bold),
),
),
body: SafeArea(child: Stack(children: body)));
}
}

View File

@@ -0,0 +1,69 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../../constant/colors.dart';
import '../../constant/style.dart';
class MyTextForm extends StatelessWidget {
const MyTextForm({
super.key,
required this.controller,
required this.label,
required this.hint,
required this.type,
this.validator,
});
final TextEditingController controller;
final String label, hint;
final TextInputType type;
final String? Function(String?)? validator;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(bottom: 10),
child: SizedBox(
width: Get.width * .8,
child: TextFormField(
keyboardType: type,
cursorColor: AppColor.accentColor,
controller: controller,
decoration: InputDecoration(
focusedBorder: OutlineInputBorder(
borderSide: const BorderSide(
color: AppColor.primaryColor,
width: 2.0,
),
borderRadius: BorderRadius.circular(10),
),
focusColor: AppColor.accentColor,
fillColor: AppColor.accentColor,
border: const OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(12))),
labelText: label.tr,
hintText: hint.tr,
hintStyle: AppStyle.title,
labelStyle: AppStyle.title,
),
validator: validator ?? (value) {
if (value == null || value.isEmpty) {
return '${'Please enter'.tr} $label.'.tr;
}
if (type == TextInputType.emailAddress) {
if (!value.contains('@')) {
return 'Please enter a valid email.'.tr;
}
} else if (type == TextInputType.phone) {
if (value.length > 14) {
return 'Please enter a valid phone number.'.tr;
}
}
return null;
},
),
),
);
}
}

View File

@@ -0,0 +1,160 @@
import 'package:flutter/material.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import '../../constant/colors.dart';
class MyCircularProgressIndicator extends StatelessWidget {
final Color backgroundColor;
const MyCircularProgressIndicator({
super.key,
this.backgroundColor = Colors.transparent,
});
@override
Widget build(BuildContext context) {
return Center(
child: Container(
width: 110,
height: 110,
decoration: BoxDecoration(
color: backgroundColor,
shape: BoxShape.circle,
),
child: Stack(
children: [
const Center(child: CircularProgressIndicator()),
Column(
children: [
Align(
alignment: Alignment.center,
child: Image.asset('assets/images/logo.png'),
),
],
),
],
),
),
);
}
}
class SnackbarConfig {
static const duration = Duration(seconds: 3);
static const animationDuration = Duration(milliseconds: 300);
static const margin = EdgeInsets.symmetric(horizontal: 16, vertical: 10);
static const borderRadius = 12.0;
static const elevation = 6.0;
static final BoxShadow shadow = BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 10,
offset: const Offset(0, 2),
);
}
SnackbarController mySnackeBarError(String message) {
// Trigger error haptic feedback
HapticFeedback.mediumImpact();
return Get.snackbar(
'Error'.tr,
message,
backgroundColor: AppColor.redColor.withOpacity(0.95),
colorText: AppColor.secondaryColor,
icon: const Icon(
Icons.error_outline_rounded,
color: AppColor.secondaryColor,
size: 28,
),
shouldIconPulse: true,
snackPosition: SnackPosition.TOP,
margin: SnackbarConfig.margin,
borderRadius: SnackbarConfig.borderRadius,
duration: SnackbarConfig.duration,
animationDuration: SnackbarConfig.animationDuration,
forwardAnimationCurve: Curves.easeOutCirc,
reverseAnimationCurve: Curves.easeInCirc,
boxShadows: [SnackbarConfig.shadow],
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
titleText: Text(
'Error'.tr,
style: const TextStyle(
fontWeight: FontWeight.w700,
color: Colors.white,
fontSize: 16,
letterSpacing: 0.2,
),
),
messageText: Text(
message,
style: TextStyle(
color: Colors.white.withOpacity(0.95),
fontSize: 14,
height: 1.3,
),
),
onTap: (_) {
HapticFeedback.lightImpact();
Get.closeCurrentSnackbar();
},
isDismissible: true,
dismissDirection: DismissDirection.horizontal,
overlayBlur: 0.8,
overlayColor: Colors.black12,
);
}
SnackbarController mySnackbarSuccess(String message) {
// Trigger success haptic feedback
HapticFeedback.lightImpact();
return Get.snackbar(
'Success'.tr,
message,
backgroundColor: AppColor.greenColor.withOpacity(0.95),
colorText: AppColor.secondaryColor,
icon: const Icon(
Icons.check_circle_outline_rounded,
color: AppColor.secondaryColor,
size: 28,
),
shouldIconPulse: true,
snackPosition: SnackPosition.TOP,
margin: SnackbarConfig.margin,
borderRadius: SnackbarConfig.borderRadius,
duration: SnackbarConfig.duration,
animationDuration: SnackbarConfig.animationDuration,
forwardAnimationCurve: Curves.easeOutCirc,
reverseAnimationCurve: Curves.easeInCirc,
boxShadows: [SnackbarConfig.shadow],
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
titleText: Text(
'Success'.tr,
style: const TextStyle(
fontWeight: FontWeight.w700,
color: Colors.white,
fontSize: 16,
letterSpacing: 0.2,
),
),
messageText: Text(
message,
style: TextStyle(
color: Colors.white.withOpacity(0.95),
fontSize: 14,
height: 1.3,
),
),
onTap: (_) {
HapticFeedback.lightImpact();
Get.closeCurrentSnackbar();
},
isDismissible: true,
dismissDirection: DismissDirection.horizontal,
overlayBlur: 0.8,
overlayColor: Colors.black12,
);
}