This commit is contained in:
Hamza-Ayed
2024-12-22 16:06:07 +03:00
parent 2910750483
commit 0f16dd9293
22 changed files with 2531 additions and 1282 deletions

View File

@@ -5,7 +5,9 @@ import 'package:sefer_driver/constant/style.dart';
import 'package:flutter/services.dart';
import 'package:vibration/vibration.dart';
import '../../constant/box_name.dart';
import '../../constant/colors.dart';
import '../../main.dart';
class MyElevatedButton extends StatelessWidget {
final String title;
@@ -22,17 +24,25 @@ class MyElevatedButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
bool vibrate = box.read(BoxName.isvibrate) ?? true;
return ElevatedButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(kolor),
backgroundColor: WidgetStateProperty.all(AppColor.blueColor),
shadowColor: WidgetStateProperty.all(Colors.transparent),
shape: WidgetStateProperty.all(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
),
onPressed: () async {
// Handle haptic feedback for both iOS and Android
if (Platform.isIOS) {
HapticFeedback.selectionClick();
} else {
Vibration.vibrate(duration: 100);
// Vibrate.vibrateWithPauses(pauses);
if (vibrate == true) {
if (Platform.isIOS) {
HapticFeedback.selectionClick();
} else if (Platform.isAndroid) {
await Vibration.vibrate(duration: vibrateDuration);
} else {}
}
// Ensure the onPressed callback is called after haptic feedback

View File

@@ -1,69 +1,123 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import '../../constant/colors.dart';
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.9),
backgroundColor: AppColor.redColor.withOpacity(0.95),
colorText: AppColor.secondaryColor,
icon: const Icon(Icons.error, color: AppColor.secondaryColor),
icon: const Icon(
Icons.error_outline_rounded,
color: AppColor.secondaryColor,
size: 28,
),
shouldIconPulse: true,
snackPosition: SnackPosition.TOP,
margin: const EdgeInsets.all(10),
borderRadius: 10,
animationDuration: const Duration(milliseconds: 500),
forwardAnimationCurve: Curves.easeOutBack,
reverseAnimationCurve: Curves.easeInBack,
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.bold,
fontWeight: FontWeight.w700,
color: Colors.white,
fontSize: 16,
letterSpacing: 0.2,
),
),
messageText: Text(
message,
style: TextStyle(
color: Colors.white.withOpacity(0.9),
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.9), // Assuming green color for success
backgroundColor: AppColor.greenColor.withOpacity(0.95),
colorText: AppColor.secondaryColor,
icon: const Icon(Icons.check_circle, color: AppColor.secondaryColor),
icon: const Icon(
Icons.check_circle_outline_rounded,
color: AppColor.secondaryColor,
size: 28,
),
shouldIconPulse: true,
snackPosition: SnackPosition.TOP,
margin: const EdgeInsets.all(10),
borderRadius: 10,
animationDuration: const Duration(milliseconds: 500),
forwardAnimationCurve: Curves.easeOutBack,
reverseAnimationCurve: Curves.easeInBack,
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.bold,
fontWeight: FontWeight.w700,
color: Colors.white,
fontSize: 16,
letterSpacing: 0.2,
),
),
messageText: Text(
message,
style: TextStyle(
color: Colors.white.withOpacity(0.9),
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,
);
}

View File

@@ -1,36 +1,131 @@
import 'package:flutter/material.dart';
class MyCircularProgressIndicator extends StatelessWidget {
class MyCircularProgressIndicator extends StatefulWidget {
final Color backgroundColor;
final double size;
final Color progressColor;
final double strokeWidth;
const MyCircularProgressIndicator({
super.key,
this.backgroundColor = Colors.transparent,
this.size = 110,
this.progressColor = Colors.blue,
this.strokeWidth = 3.0,
});
@override
State<MyCircularProgressIndicator> createState() =>
_MyCircularProgressIndicatorState();
}
class _MyCircularProgressIndicatorState
extends State<MyCircularProgressIndicator>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _scaleAnimation;
late Animation<double> _rotationAnimation;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(seconds: 2),
vsync: this,
)..repeat(reverse: true);
_scaleAnimation = Tween<double>(
begin: 0.95,
end: 1.05,
).animate(CurvedAnimation(
parent: _controller,
curve: Curves.easeInOut,
));
_rotationAnimation = Tween<double>(
begin: 0,
end: 2,
).animate(CurvedAnimation(
parent: _controller,
curve: Curves.linear,
));
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@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.gif'),
),
],
child: AnimatedBuilder(
animation: _controller,
builder: (context, child) {
return Transform.scale(
scale: _scaleAnimation.value,
child: Container(
width: widget.size,
height: widget.size,
decoration: BoxDecoration(
color: widget.backgroundColor,
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
color: widget.progressColor.withAlpha(30),
blurRadius: 12,
spreadRadius: 2,
),
],
),
child: Stack(
alignment: Alignment.center,
children: [
// Outer rotating progress indicator
Transform.rotate(
angle: _rotationAnimation.value * 3.14,
child: CircularProgressIndicator(
strokeWidth: widget.strokeWidth,
valueColor: AlwaysStoppedAnimation<Color>(
widget.progressColor,
),
),
),
// Inner static progress indicator
CircularProgressIndicator(
strokeWidth: widget.strokeWidth * 0.7,
valueColor: AlwaysStoppedAnimation<Color>(
widget.progressColor.withAlpha(150),
),
),
// Logo container with scale animation
ScaleTransition(
scale: Tween<double>(
begin: 0.9,
end: 1.0,
).animate(CurvedAnimation(
parent: _controller,
curve: Curves.easeInOut,
)),
child: Container(
width: widget.size * 0.7,
height: widget.size * 0.7,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: widget.backgroundColor,
),
child: Image.asset(
'assets/images/logo.gif',
fit: BoxFit.contain,
),
),
),
],
),
),
],
),
);
},
),
);
}

View File

@@ -1,58 +1,139 @@
import 'dart:ui';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:sefer_driver/constant/colors.dart';
import 'package:sefer_driver/constant/style.dart';
import 'package:sefer_driver/controller/functions/tts.dart';
class DialogConfig {
static const Duration animationDuration = Duration(milliseconds: 200);
static const double blurStrength = 8.0;
static const double cornerRadius = 14.0;
static final BoxDecoration decoration = BoxDecoration(
borderRadius: BorderRadius.circular(cornerRadius),
boxShadow: [
BoxShadow(
color: Colors.black.withAlpha(38), // 0.15 opacity
blurRadius: 16,
offset: const Offset(0, 8),
),
],
);
}
class MyDialog extends GetxController {
void getDialog(String title, String? midTitle, VoidCallback onPressed) {
final textToSpeechController = Get.put(TextToSpeechController());
HapticFeedback.mediumImpact();
Get.dialog(
BackdropFilter(
filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5),
child: CupertinoAlertDialog(
title: Text(
title,
style: AppStyle.title.copyWith(
fontSize: 20,
fontWeight: FontWeight.bold,
TweenAnimationBuilder<double>(
duration: DialogConfig.animationDuration,
tween: Tween(begin: 0.0, end: 1.0),
builder: (context, value, child) {
return Transform.scale(
scale: 0.95 + (0.05 * value),
child: Opacity(opacity: value, child: child),
);
},
child: BackdropFilter(
filter: ImageFilter.blur(
sigmaX: DialogConfig.blurStrength,
sigmaY: DialogConfig.blurStrength,
),
child: Theme(
data: ThemeData.light().copyWith(
dialogBackgroundColor: CupertinoColors.systemBackground,
),
child: CupertinoAlertDialog(
title: Column(
children: [
Text(
title,
style: AppStyle.title.copyWith(
fontSize: 20,
fontWeight: FontWeight.w700,
letterSpacing: -0.5,
color: AppColor.primaryColor,
),
),
const SizedBox(height: 8),
],
),
content: Column(
children: [
CupertinoButton(
padding: const EdgeInsets.all(8),
onPressed: () async {
HapticFeedback.selectionClick();
await textToSpeechController.speakText(title);
await textToSpeechController.speakText(midTitle!);
},
child: Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color:
AppColor.primaryColor.withAlpha(26), // 0.1 opacity
borderRadius: BorderRadius.circular(8),
),
child: Icon(
CupertinoIcons.speaker_2_fill,
color: AppColor.primaryColor,
size: 24,
),
),
),
const SizedBox(height: 8),
Text(
midTitle!,
style: AppStyle.title.copyWith(
fontSize: 16,
height: 1.3,
color: Colors.black87,
),
textAlign: TextAlign.center,
),
],
),
actions: [
CupertinoDialogAction(
onPressed: () {
HapticFeedback.lightImpact();
Get.back();
},
child: Text(
'Cancel',
style: TextStyle(
color: AppColor.redColor,
fontWeight: FontWeight.w600,
fontSize: 17,
),
),
),
CupertinoDialogAction(
onPressed: () {
HapticFeedback.mediumImpact();
onPressed();
},
child: Text(
'OK'.tr,
style: TextStyle(
color: AppColor.greenColor,
fontWeight: FontWeight.w600,
fontSize: 17,
),
),
),
],
),
),
content: Column(
children: [
CupertinoButton(
onPressed: () async {
await textToSpeechController.speakText(title);
await textToSpeechController.speakText(midTitle!);
},
child: const Icon(CupertinoIcons.speaker_2,
color: AppColor.primaryColor),
),
Text(
midTitle!,
style: AppStyle.title.copyWith(fontSize: 16),
),
],
),
actions: [
CupertinoDialogAction(
child: const Text('Cancel',
style: TextStyle(color: AppColor.redColor)),
onPressed: () {
Get.back();
},
),
CupertinoDialogAction(
onPressed: onPressed,
child: Text('OK'.tr,
style: const TextStyle(color: AppColor.greenColor)),
),
],
),
),
barrierDismissible: false,
barrierDismissible: true,
barrierColor: Colors.black.withAlpha(102), // 0.4 opacity
);
}
}
@@ -61,46 +142,104 @@ class MyDialogContent extends GetxController {
void getDialog(String title, Widget? content, VoidCallback onPressed) {
final textToSpeechController = Get.put(TextToSpeechController());
HapticFeedback.mediumImpact();
Get.dialog(
BackdropFilter(
filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5),
child: CupertinoAlertDialog(
title: Text(
title,
style: AppStyle.title.copyWith(
fontSize: 20,
fontWeight: FontWeight.bold,
),
TweenAnimationBuilder<double>(
duration: DialogConfig.animationDuration,
tween: Tween(begin: 0.0, end: 1.0),
builder: (context, value, child) {
return Transform.scale(
scale: 0.95 + (0.05 * value),
child: Opacity(opacity: value, child: child),
);
},
child: BackdropFilter(
filter: ImageFilter.blur(
sigmaX: DialogConfig.blurStrength,
sigmaY: DialogConfig.blurStrength,
),
content: Column(
children: [
CupertinoButton(
onPressed: () async {
await textToSpeechController.speakText(title);
},
child: const Icon(CupertinoIcons.headphones,
color: AppColor.primaryColor),
child: Theme(
data: ThemeData.light().copyWith(
dialogBackgroundColor: CupertinoColors.systemBackground,
),
child: CupertinoAlertDialog(
title: Column(
children: [
Text(
title,
style: AppStyle.title.copyWith(
fontSize: 20,
fontWeight: FontWeight.w700,
letterSpacing: -0.5,
color: AppColor.primaryColor,
),
),
const SizedBox(height: 8),
],
),
content!
],
content: Column(
children: [
CupertinoButton(
padding: const EdgeInsets.all(8),
onPressed: () async {
HapticFeedback.selectionClick();
await textToSpeechController.speakText(title);
},
child: Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color:
AppColor.primaryColor.withAlpha(26), // 0.1 opacity
borderRadius: BorderRadius.circular(8),
),
child: Icon(
CupertinoIcons.headphones,
color: AppColor.primaryColor,
size: 24,
),
),
),
const SizedBox(height: 12),
content!,
],
),
actions: [
CupertinoDialogAction(
onPressed: () {
HapticFeedback.lightImpact();
Get.back();
},
child: Text(
'Cancel',
style: TextStyle(
color: AppColor.redColor,
fontWeight: FontWeight.w600,
fontSize: 17,
),
),
),
CupertinoDialogAction(
onPressed: () {
HapticFeedback.mediumImpact();
onPressed();
},
child: Text(
'OK'.tr,
style: TextStyle(
color: AppColor.greenColor,
fontWeight: FontWeight.w600,
fontSize: 17,
),
),
),
],
),
),
actions: [
CupertinoDialogAction(
child: const Text('Cancel',
style: TextStyle(color: AppColor.redColor)),
onPressed: () {
Get.back();
},
),
CupertinoDialogAction(
onPressed: onPressed,
child: Text('OK'.tr,
style: const TextStyle(color: AppColor.greenColor)),
),
],
),
),
barrierDismissible: false,
barrierDismissible: true,
barrierColor: Colors.black.withAlpha(102), // 0.4 opacity
);
}
}