2026-04-15

This commit is contained in:
MAGESHWARAN 2026-04-15 12:32:30 +05:30
parent d01e5ba860
commit 96de59e9be
46 changed files with 1299 additions and 1191 deletions

Binary file not shown.

View File

@ -4,6 +4,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:get/get.dart';
import 'package:taxglide/consts/app_asstes.dart';
import 'package:taxglide/consts/app_colors.dart';
import 'package:taxglide/consts/app_style.dart';
import 'package:taxglide/consts/comman_button.dart';
import 'package:taxglide/consts/comman_container_auth.dart';
import 'package:taxglide/consts/comman_textformfileds.dart';
@ -100,7 +101,13 @@ class _EmployeeLoginScreenState extends ConsumerState<EmployeeLoginScreen> {
final spacingMD = r.spacing(mobile: 20, tablet: 20, desktop: 24);
final spacingLG = r.spacing(mobile: 20, tablet: 22, desktop: 28);
return Scaffold(
return PopScope(
canPop: false,
onPopInvokedWithResult: (didPop, result) {
if (didPop) return;
Get.offAllNamed(ConstRouters.login);
},
child: Scaffold(
resizeToAvoidBottomInset: true,
body: Container(
width: double.infinity,
@ -141,10 +148,8 @@ class _EmployeeLoginScreenState extends ConsumerState<EmployeeLoginScreen> {
Text(
"Login",
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
style: AppTextStyles.bold.copyWith(
fontSize: titleFontSize,
fontWeight: FontWeight.w600,
height: 1.3,
letterSpacing: 0.01 * titleFontSize,
color: AppColors.authheading,
@ -156,10 +161,8 @@ class _EmployeeLoginScreenState extends ConsumerState<EmployeeLoginScreen> {
Text(
"Enter your registered Mobile Number",
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
style: AppTextStyles.bold.copyWith(
fontSize: subtitleFontSize,
fontWeight: FontWeight.w600,
height: 1.4,
letterSpacing: 0.03 * subtitleFontSize,
color: AppColors.authleading,
@ -180,9 +183,7 @@ class _EmployeeLoginScreenState extends ConsumerState<EmployeeLoginScreen> {
Text.rich(
TextSpan(
text: "By signing up, you agree to the ",
style: TextStyle(
fontFamily: 'Gilroy-Medium',
fontWeight: FontWeight.w500,
style: AppTextStyles.medium.copyWith(
fontSize: termsFontSize,
height: 1.8,
letterSpacing: 0.01,
@ -191,9 +192,7 @@ class _EmployeeLoginScreenState extends ConsumerState<EmployeeLoginScreen> {
children: [
TextSpan(
text: "Terms of Service ",
style: TextStyle(
fontFamily: 'Gilroy-Bold',
fontWeight: FontWeight.w700,
style: AppTextStyles.bold.copyWith(
fontSize: termsFontSize,
height: 1.8,
letterSpacing: 0.01,
@ -202,20 +201,16 @@ class _EmployeeLoginScreenState extends ConsumerState<EmployeeLoginScreen> {
),
TextSpan(
text: "and ",
style: TextStyle(
fontFamily: 'Gilroy-Medium',
fontWeight: FontWeight.w500,
fontSize: termsFontSize,
height: 1.8,
letterSpacing: 0.01,
color: AppColors.authleading,
),
style: AppTextStyles.medium.copyWith(
fontSize: termsFontSize,
height: 1.8,
letterSpacing: 0.01,
color: AppColors.authleading,
),
),
TextSpan(
text: "Data Processing Agreement",
style: TextStyle(
fontFamily: 'Gilroy-Bold',
fontWeight: FontWeight.w700,
style: AppTextStyles.bold.copyWith(
fontSize: termsFontSize,
height: 1.8,
letterSpacing: 0.01,
@ -242,13 +237,11 @@ class _EmployeeLoginScreenState extends ConsumerState<EmployeeLoginScreen> {
Text(
"Other Login",
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: 'Inter',
fontWeight: FontWeight.w500,
style: AppTextStyles.semiBold.copyWith(
fontSize: otherLoginFontSize,
height: 1.8,
letterSpacing: 0.13,
color: const Color(0xFF6C7278),
color: AppColors.authleading,
),
),
@ -257,14 +250,16 @@ class _EmployeeLoginScreenState extends ConsumerState<EmployeeLoginScreen> {
Text.rich(
TextSpan(
text: "User Login? ",
style: TextStyle(fontSize: linkFontSize),
style: AppTextStyles.bold.copyWith(
fontSize: linkFontSize,
color: AppColors.black,
),
children: [
TextSpan(
text: "Click Here",
style: TextStyle(
style: AppTextStyles.bold.copyWith(
fontSize: linkFontSize,
color: AppColors.authsignup,
fontWeight: FontWeight.bold,
),
recognizer: TapGestureRecognizer()
..onTap = () {
@ -282,6 +277,7 @@ class _EmployeeLoginScreenState extends ConsumerState<EmployeeLoginScreen> {
),
),
),
),
);
}
}

View File

@ -247,7 +247,7 @@ class _EmployeeOtpScreenState extends ConsumerState<EmployeeOtpScreen> {
"Enter OTP",
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontFamily: "Gilroy",
fontSize: titleFontSize,
fontWeight: FontWeight.w600,
height: 1.3,
@ -262,7 +262,7 @@ class _EmployeeOtpScreenState extends ConsumerState<EmployeeOtpScreen> {
"OTP has been sent to your registered mobile number",
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontFamily: "Gilroy",
fontSize: subtitleFontSize,
fontWeight: FontWeight.w600,
height: 1.4,
@ -277,7 +277,7 @@ class _EmployeeOtpScreenState extends ConsumerState<EmployeeOtpScreen> {
TextSpan(
text: mobile,
style: TextStyle(
fontFamily: 'Gilroy-Medium',
fontFamily: "Gilroy",
fontWeight: FontWeight.w500,
fontSize: mobileFontSize,
height: 1.8,
@ -288,7 +288,7 @@ class _EmployeeOtpScreenState extends ConsumerState<EmployeeOtpScreen> {
TextSpan(
text: " ( Change Number )",
style: TextStyle(
fontFamily: 'Gilroy-ExtraBold',
fontFamily: "Gilroy",
fontWeight: FontWeight.w800,
fontSize: mobileFontSize,
height: 1.8,
@ -347,7 +347,7 @@ class _EmployeeOtpScreenState extends ConsumerState<EmployeeOtpScreen> {
maxLength: 1,
enabled: !isLoading,
style: TextStyle(
fontFamily: 'Gilroy-Medium',
fontFamily: "Gilroy",
fontWeight: FontWeight.w400,
fontSize: otpFontSize,
letterSpacing: 0.03 * otpFontSize,
@ -375,7 +375,7 @@ class _EmployeeOtpScreenState extends ConsumerState<EmployeeOtpScreen> {
"Resend",
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: 'Gilroy-Medium',
fontFamily: "Gilroy",
fontWeight: FontWeight.w500,
fontSize: resendFontSize,
height: 1.4,
@ -393,7 +393,7 @@ class _EmployeeOtpScreenState extends ConsumerState<EmployeeOtpScreen> {
Text(
_formatTime(_remainingSeconds),
style: TextStyle(
fontFamily: 'Gilroy-Medium',
fontFamily: "Gilroy",
fontWeight: FontWeight.w600,
fontSize: timerFontSize,
color: _remainingSeconds > 0

View File

@ -12,6 +12,7 @@ import 'package:taxglide/consts/responsive_helper.dart';
import 'package:taxglide/consts/validation_popup.dart';
import 'package:taxglide/controller/api_contoller.dart';
import 'package:taxglide/router/consts_routers.dart';
import 'package:taxglide/consts/app_style.dart';
class LoginScreen extends ConsumerStatefulWidget {
const LoginScreen({super.key});
@ -102,7 +103,12 @@ class _LoginScreenState extends ConsumerState<LoginScreen> {
final spacingMD = r.spacing(mobile: 20, tablet: 22, desktop: 26);
final spacingLG = r.spacing(mobile: 20, tablet: 22, desktop: 28);
return Scaffold(
return PopScope(
canPop: true,
onPopInvokedWithResult: (didPop, result) {
// Handle custom behavior here if needed in the future
},
child: Scaffold(
resizeToAvoidBottomInset: true,
body: Container(
width: double.infinity,
@ -141,10 +147,8 @@ class _LoginScreenState extends ConsumerState<LoginScreen> {
// Title
Text(
"Login",
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
style: AppTextStyles.semiBold.copyWith(
fontSize: titleFontSize,
fontWeight: FontWeight.w600,
color: AppColors.authheading,
),
),
@ -154,8 +158,7 @@ class _LoginScreenState extends ConsumerState<LoginScreen> {
Text(
"Enter your Mobile Number",
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
style: AppTextStyles.semiBold.copyWith(
fontSize: subtitleFontSize,
color: AppColors.authleading,
),
@ -175,15 +178,14 @@ class _LoginScreenState extends ConsumerState<LoginScreen> {
Text.rich(
TextSpan(
text: "By signing up, you agree to the ",
style: TextStyle(
style: AppTextStyles.medium.copyWith(
fontSize: termsFontSize,
color: AppColors.authleading,
),
children: [
TextSpan(
text: "Terms of Service ",
style: TextStyle(
fontWeight: FontWeight.w700,
style: AppTextStyles.bold.copyWith(
fontSize: termsFontSize,
color: AppColors.authtermsandcondition,
),
@ -259,21 +261,26 @@ class _LoginScreenState extends ConsumerState<LoginScreen> {
),
SizedBox(height: spacingSM),
const Text("Or"),
Text("Or",style: AppTextStyles.medium.copyWith(
fontSize: spacingSM,
color: AppColors.authleading,
),),
SizedBox(height: spacingSM),
// Sign up
Text.rich(
TextSpan(
text: "Didn't Have account? ",
style: TextStyle(fontSize: signupFontSize),
style: AppTextStyles.bold.copyWith(
fontSize: signupFontSize,
color: AppColors.black,
),
children: [
TextSpan(
text: "Sign Up",
style: TextStyle(
style: AppTextStyles.bold.copyWith(
fontSize: signupFontSize,
color: AppColors.authsignup,
fontWeight: FontWeight.bold,
),
recognizer: TapGestureRecognizer()
..onTap = () {
@ -298,13 +305,11 @@ class _LoginScreenState extends ConsumerState<LoginScreen> {
Text(
"Other Login",
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: 'Inter',
fontWeight: FontWeight.w500,
style: AppTextStyles.semiBold.copyWith(
fontSize: otherLoginFontSize,
height: 1.8,
letterSpacing: 0.13,
color: const Color(0xFF6C7278),
color: AppColors.authleading,
),
),
@ -313,14 +318,16 @@ class _LoginScreenState extends ConsumerState<LoginScreen> {
Text.rich(
TextSpan(
text: "Staff Login? ",
style: TextStyle(fontSize: signupFontSize),
style: AppTextStyles.bold.copyWith(
fontSize: signupFontSize,
color: AppColors.black,
),
children: [
TextSpan(
text: "Click Here",
style: TextStyle(
style: AppTextStyles.bold.copyWith(
fontSize: signupFontSize,
color: AppColors.authsignup,
fontWeight: FontWeight.bold,
),
recognizer: TapGestureRecognizer()
..onTap = () {
@ -338,6 +345,7 @@ class _LoginScreenState extends ConsumerState<LoginScreen> {
),
),
),
),
);
}
}

View File

@ -13,6 +13,7 @@ import 'package:taxglide/controller/api_contoller.dart';
import 'package:taxglide/router/consts_routers.dart';
import 'package:taxglide/view/Main_controller/main_controller.dart';
import 'package:taxglide/consts/app_style.dart';
class OtpScreen extends ConsumerStatefulWidget {
const OtpScreen({super.key});
@ -248,10 +249,8 @@ class _OtpScreenState extends ConsumerState<OtpScreen> {
Text(
"Enter OTP",
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
style: AppTextStyles.semiBold.copyWith(
fontSize: titleFontSize,
fontWeight: FontWeight.w600,
height: 1.3,
letterSpacing: 0.01 * titleFontSize,
color: AppColors.authheading,
@ -263,10 +262,8 @@ class _OtpScreenState extends ConsumerState<OtpScreen> {
Text(
"OTP has been sent to your registered mobile number",
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
style: AppTextStyles.semiBold.copyWith(
fontSize: subtitleFontSize,
fontWeight: FontWeight.w600,
height: 1.4,
letterSpacing: 0.03 * subtitleFontSize,
color: AppColors.authleading,
@ -278,9 +275,7 @@ class _OtpScreenState extends ConsumerState<OtpScreen> {
Text.rich(
TextSpan(
text: mobile,
style: TextStyle(
fontFamily: 'Gilroy-Medium',
fontWeight: FontWeight.w500,
style: AppTextStyles.medium.copyWith(
fontSize: mobileFontSize,
height: 1.8,
letterSpacing: 0.01,
@ -289,9 +284,7 @@ class _OtpScreenState extends ConsumerState<OtpScreen> {
children: [
TextSpan(
text: " ( Change Number )",
style: TextStyle(
fontFamily: 'Gilroy-ExtraBold',
fontWeight: FontWeight.w800,
style: AppTextStyles.extraBold.copyWith(
fontSize: mobileFontSize,
height: 1.8,
letterSpacing: 0.04,
@ -349,7 +342,7 @@ class _OtpScreenState extends ConsumerState<OtpScreen> {
maxLength: 1,
enabled: !isLoading,
style: TextStyle(
fontFamily: 'Gilroy-Medium',
fontFamily: "Gilroy",
fontWeight: FontWeight.w400,
fontSize: otpFontSize,
letterSpacing: 0.03 * otpFontSize,
@ -376,9 +369,7 @@ class _OtpScreenState extends ConsumerState<OtpScreen> {
child: Text(
"Resend",
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: 'Gilroy-Medium',
fontWeight: FontWeight.w500,
style: AppTextStyles.medium.copyWith(
fontSize: resendFontSize,
height: 1.4,
letterSpacing: 0.02 * resendFontSize,
@ -394,9 +385,7 @@ class _OtpScreenState extends ConsumerState<OtpScreen> {
// Timer
Text(
_formatTime(_remainingSeconds),
style: TextStyle(
fontFamily: 'Gilroy-Medium',
fontWeight: FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontSize: timerFontSize,
color: _remainingSeconds > 0
? AppColors.authheading

View File

@ -11,6 +11,7 @@ import 'package:taxglide/consts/validation_popup.dart';
import 'package:taxglide/controller/api_contoller.dart';
import 'package:taxglide/router/consts_routers.dart';
import 'package:taxglide/view/Main_controller/main_controller.dart';
import 'package:taxglide/consts/app_style.dart';
class RegisterOtpScreen extends ConsumerStatefulWidget {
const RegisterOtpScreen({super.key});
@ -247,10 +248,8 @@ class _RegisterOtpScreenState extends ConsumerState<RegisterOtpScreen> {
Text(
"Enter OTP",
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
style: AppTextStyles.semiBold.copyWith(
fontSize: 32,
fontWeight: FontWeight.w600,
height: 1.3,
letterSpacing: 0.01 * 32,
color: AppColors.authheading,
@ -260,10 +259,8 @@ class _RegisterOtpScreenState extends ConsumerState<RegisterOtpScreen> {
Text(
"OTP has been sent to your registered mobile number",
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
style: AppTextStyles.semiBold.copyWith(
fontSize: 14,
fontWeight: FontWeight.w600,
height: 1.4,
letterSpacing: 0.03 * 14,
color: AppColors.authleading,
@ -273,9 +270,7 @@ class _RegisterOtpScreenState extends ConsumerState<RegisterOtpScreen> {
Text.rich(
TextSpan(
text: mobile,
style: const TextStyle(
fontFamily: 'Gilroy-Medium',
fontWeight: FontWeight.w500,
style: AppTextStyles.medium.copyWith(
fontSize: 13,
height: 1.8,
letterSpacing: 0.01,
@ -284,9 +279,7 @@ class _RegisterOtpScreenState extends ConsumerState<RegisterOtpScreen> {
children: [
TextSpan(
text: " ( Change Number )",
style: const TextStyle(
fontFamily: 'Gilroy-ExtraBold',
fontWeight: FontWeight.w800,
style: AppTextStyles.extraBold.copyWith(
fontSize: 13,
height: 1.8,
letterSpacing: 0.04,
@ -346,7 +339,7 @@ class _RegisterOtpScreenState extends ConsumerState<RegisterOtpScreen> {
maxLength: 1,
enabled: !isLoading,
style: TextStyle(
fontFamily: 'Gilroy-Medium',
fontFamily: "Gilroy",
fontWeight: FontWeight.w400,
fontSize: 28,
letterSpacing: 0.03 * 28,
@ -373,9 +366,7 @@ class _RegisterOtpScreenState extends ConsumerState<RegisterOtpScreen> {
child: Text(
"Resend",
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: 'Gilroy-Medium',
fontWeight: FontWeight.w500,
style: AppTextStyles.medium.copyWith(
fontSize: 14,
height: 1.4,
letterSpacing: 0.02 * 14,
@ -391,9 +382,7 @@ class _RegisterOtpScreenState extends ConsumerState<RegisterOtpScreen> {
// Timer Display
Text(
_formatTime(_remainingSeconds),
style: TextStyle(
fontFamily: 'Gilroy-Medium',
fontWeight: FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontSize: 16,
color: _remainingSeconds > 0
? AppColors.authheading

View File

@ -9,6 +9,7 @@ import 'package:taxglide/consts/comman_textformfileds.dart';
import 'package:taxglide/consts/validation_popup.dart';
import 'package:taxglide/controller/api_contoller.dart';
import 'package:taxglide/router/consts_routers.dart';
import 'package:taxglide/consts/app_style.dart';
class SignupScreen extends ConsumerStatefulWidget {
const SignupScreen({super.key});
@ -89,7 +90,13 @@ class _SignupScreenState extends ConsumerState<SignupScreen> {
);
});
return Scaffold(
return PopScope(
canPop: false,
onPopInvokedWithResult: (didPop, result) {
if (didPop) return;
Get.offAllNamed(ConstRouters.login);
},
child: Scaffold(
body: Stack(
children: [
// 🌈 Background gradient
@ -131,10 +138,8 @@ class _SignupScreenState extends ConsumerState<SignupScreen> {
Text(
"Sign Up",
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
style: AppTextStyles.semiBold.copyWith(
fontSize: 32,
fontWeight: FontWeight.w600,
height: 1.3,
letterSpacing: 0.01 * 32,
color: AppColors.authheading,
@ -148,10 +153,9 @@ class _SignupScreenState extends ConsumerState<SignupScreen> {
alignment: Alignment.centerLeft,
child: Text(
"Name*",
style: TextStyle(
fontFamily: 'Gilroy-Medium',
style: AppTextStyles.semiBold.copyWith(
fontSize: 14,
color: AppColors.authleading,
color: AppColors.authheading,
),
),
),
@ -177,10 +181,9 @@ class _SignupScreenState extends ConsumerState<SignupScreen> {
alignment: Alignment.centerLeft,
child: Text(
"Contact Number *",
style: TextStyle(
fontFamily: 'Gilroy-Medium',
style: AppTextStyles.semiBold.copyWith(
fontSize: 14,
color: AppColors.authleading,
color: AppColors.authheading,
),
),
),
@ -206,10 +209,9 @@ class _SignupScreenState extends ConsumerState<SignupScreen> {
alignment: Alignment.centerLeft,
child: Text(
"Email *",
style: TextStyle(
fontFamily: 'Gilroy-Medium',
style: AppTextStyles.semiBold.copyWith(
fontSize: 14,
color: AppColors.authleading,
color: AppColors.authheading,
),
),
),
@ -247,6 +249,7 @@ class _SignupScreenState extends ConsumerState<SignupScreen> {
),
],
),
),
);
}

47
lib/consts/app_style.dart Normal file
View File

@ -0,0 +1,47 @@
import 'package:flutter/material.dart';
class AppTextStyles {
static const TextStyle thin = TextStyle(
fontFamily: 'Gilroy-Thin',
);
static const TextStyle ultraLight = TextStyle(
fontFamily: 'Gilroy-UltraLight',
);
static const TextStyle ultralight = ultraLight;
static const TextStyle light = TextStyle(
fontFamily: 'Gilroy-Light',
);
static const TextStyle regular = TextStyle(
fontFamily: 'Gilroy-Regular',
);
static const TextStyle medium = TextStyle(
fontFamily: 'Gilroy-Medium',
);
static const TextStyle semiBold = TextStyle(
fontFamily: 'Gilroy-SemiBold',
);
static const TextStyle semibold = semiBold;
static const TextStyle semi_bold = semiBold;
static const TextStyle bold = TextStyle(
fontFamily: 'Gilroy-Bold',
);
static const TextStyle extraBold = TextStyle(
fontFamily: 'Gilroy-ExtraBold',
);
static const TextStyle extrabold = extraBold;
static const TextStyle black = TextStyle(
fontFamily: 'Gilroy-Black',
);
static const TextStyle heavy = TextStyle(
fontFamily: 'Gilroy-Heavy',
);
}

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:taxglide/consts/app_colors.dart';
import 'package:taxglide/consts/app_style.dart';
class CommanButton extends StatelessWidget {
final String text;
@ -51,9 +52,7 @@ class CommanButton extends StatelessWidget {
],
Text(
text,
style: const TextStyle(
fontFamily: 'Gilroy-Medium',
fontWeight: FontWeight.w500,
style: AppTextStyles.semiBold.copyWith(
fontSize: 16,
height: 1.4,
letterSpacing: 0.03 * 16,

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:taxglide/consts/app_style.dart';
class CommonInfoPopup {
/// 🔹 Show a reusable popup dialog
@ -22,10 +23,8 @@ class CommonInfoPopup {
contentPadding: const EdgeInsets.fromLTRB(20, 0, 20, 10),
title: Text(
title,
style: const TextStyle(
fontFamily: 'Gilroy-Bold',
style: AppTextStyles.bold.copyWith(
fontSize: 18,
fontWeight: FontWeight.w700,
color: Colors.black87,
),
),
@ -48,8 +47,7 @@ class CommonInfoPopup {
child: Text(
content,
textAlign: TextAlign.justify,
style: const TextStyle(
fontFamily: 'Gilroy-Medium',
style: AppTextStyles.regular.copyWith(
fontSize: 14,
height: 1.6,
color: Colors.black54,
@ -63,15 +61,14 @@ class CommonInfoPopup {
actions: [
TextButton(
onPressed: () => Navigator.of(ctx).pop(),
child: const Text(
"Close",
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontSize: 14,
color: Color(0xFF6A4BFC),
),
child: Text(
"Close",
style: AppTextStyles.regular.copyWith(
fontSize: 14,
color: const Color(0xFF6A4BFC),
),
),
),
],
);
},

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:taxglide/consts/app_style.dart';
import 'package:get/get.dart';
import 'package:taxglide/consts/app_colors.dart';
import 'package:taxglide/model/serivce_list_model.dart';
@ -67,9 +68,7 @@ class CommonServiceItem extends StatelessWidget {
textAlign: TextAlign.center,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontSize: 13,
height: 1.3,
letterSpacing: 0.02,

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:taxglide/consts/app_colors.dart';
import 'package:taxglide/consts/app_style.dart';
import 'package:flutter/services.dart';
class CommanTextFormField extends StatelessWidget {
@ -69,15 +70,13 @@ class CommanTextFormField extends StatelessWidget {
prefixIcon: prefixIcon != null
? Icon(prefixIcon, color: AppColors.authleading)
: null,
hintStyle: TextStyle(
fontFamily: 'Gilroy-Medium',
fontWeight: FontWeight.w400,
hintStyle: AppTextStyles.medium.copyWith(
fontSize: 11.31,
height: 1.4,
letterSpacing: 0.03,
color: hasError
? Colors.red.withOpacity(0.6)
: Colors.grey.shade500,
: AppColors.authleading
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(6),
@ -85,7 +84,7 @@ class CommanTextFormField extends StatelessWidget {
color: hasError
? Colors.red
: readOnly
? Colors.grey.shade300
? AppColors.authleading
: const Color(0xFFDFDFDF),
width: 1,
),
@ -113,13 +112,11 @@ class CommanTextFormField extends StatelessWidget {
),
),
),
style: TextStyle(
fontFamily: 'Gilroy-Medium',
fontWeight: FontWeight.w500,
style: AppTextStyles.medium.copyWith(
fontSize: 11.31,
height: 1.4,
letterSpacing: 0.03,
color: readOnly ? Colors.grey.shade600 : AppColors.authleading,
color: readOnly ? AppColors.authleading : AppColors.authleading,
),
),
);

View File

@ -1,10 +1,13 @@
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:open_filex/open_filex.dart';
import 'package:gal/gal.dart';
import 'package:taxglide/services/notification_service.dart';
class DownloadHelper {
static const String API_BASE_URL = "https://www.taxglide.amrithaa.net/api/";
@ -254,6 +257,13 @@ class DownloadHelper {
}
print("✅ File downloaded to: $savePath");
// Show Download Notification
try {
Get.find<NotificationService>().showDownloadNotification(fileName, savePath);
} catch (e) {
debugPrint('⚠️ Could not show download notification: $e');
}
// Open the downloaded file
await openDownloadedFile(savePath);
@ -349,6 +359,28 @@ class DownloadHelper {
}
}
/// NEW: Open folder in system file manager
static Future<void> openFolder(String path) async {
print("📂 Opening folder: $path");
try {
final dir = Directory(path);
if (!await dir.exists()) {
print("❌ Folder not found at $path");
return;
}
// On Android, most file managers respond well to OpenFilex on a directory
final result = await OpenFilex.open(path);
if (result.type != ResultType.done) {
print("⚠️ Could not open folder: ${result.message}");
}
} catch (e) {
print("❌ Error opening folder: $e");
}
}
/// Get all files from Send folder
static Future<List<File>> getSentFiles() async {
try {

View File

@ -318,7 +318,7 @@ class LabeledTextField extends StatelessWidget {
Text(
label,
style: const TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontFamily: "Gilroy",
fontWeight: FontWeight.w600,
fontSize: 16,
height: 1.3,
@ -391,7 +391,7 @@ class SingleImageSectionField extends StatelessWidget {
Text(
title,
style: const TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontFamily: "Gilroy",
fontWeight: FontWeight.w600,
fontSize: 16,
height: 1.3,
@ -527,7 +527,7 @@ class FileUploadSectionField extends StatelessWidget {
Text(
title,
style: const TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontFamily: "Gilroy",
fontWeight: FontWeight.w600,
fontSize: 16,
height: 1.3,

View File

@ -1,3 +1,4 @@
import 'package:flutter/material.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
class LocalStore {
@ -10,7 +11,8 @@ class LocalStore {
Future<void> saveLoginData(Map<String, dynamic> data) async {
final token = data['access_token'] ?? '';
final role = data['role'] ?? '';
debugPrint('token: $token');
debugPrint('role: $role');
// Keep existing FCM token (do not overwrite)
String? existingFcmToken = await _storage.read(key: 'fcm_token');

View File

@ -55,6 +55,16 @@ class NotificationWebSocket {
_subscribeToChatChannel(chatId);
}
/// Manually trigger a refresh for all providers watching `notificationTriggerProvider`.
void triggerRefresh() {
try {
_container?.read(notificationTriggerProvider.notifier).update((state) => state + 1);
debugPrint('🔔 NotificationWS: manual refresh triggered');
} catch (e) {
debugPrint('⚠️ NotificationWS: triggerRefresh failed: $e');
}
}
/// Connect (or skip if already connected for the same user).
Future<void> connect({
required String userId,

View File

@ -185,10 +185,14 @@ class ServiceHistoryNotifier
fetchServiceHistory();
}
Future<void> fetchServiceHistory() async {
Future<void> fetchServiceHistory({bool isSilent = false}) async {
try {
if (!mounted) return;
state = const AsyncValue.loading();
// 🔄 Skip loading state for silent refresh
if (!isSilent) {
state = const AsyncValue.loading();
}
final repo = ref.read(apiRepositoryProvider);
@ -238,8 +242,6 @@ final notificationTriggerProvider = StateProvider<int>((ref) => 0);
// 🔥 fetch notification count API
final notificationCountProvider =
FutureProvider.autoDispose<NotificationCountModel>((ref) async {
ref.watch(notificationTriggerProvider); // listen for refresh trigger
final repo = ref.read(apiRepositoryProvider);
return await repo.fetchNotificationCount();
});
@ -409,34 +411,55 @@ class ChatMessagesNotifier
return dateA.compareTo(dateB);
});
// Check if we have any new messages
final lastMessageId = _messages.isNotEmpty ? _messages.last.id : -1;
final latestMessageId = result.last.id;
// Merge strategy:
// 1. Update existing messages (read/delivered status)
// 2. Add new messages
bool hasChanges = false;
if (latestMessageId != lastMessageId) {
// New messages found - merge them smoothly
print("✅ Found new messages, updating list");
for (var incomingMsg in result) {
final existingIndex = _messages.indexWhere((m) => m.id == incomingMsg.id);
if (existingIndex != -1) {
// Check if status changed
final existingMsg = _messages[existingIndex];
if (existingMsg.isRead != incomingMsg.isRead ||
existingMsg.isDelivered != incomingMsg.isDelivered) {
print("♻️ Updating status for message ID ${incomingMsg.id}");
_messages[existingIndex] = incomingMsg;
hasChanges = true;
}
} else {
// NEW: Check if this server message replaces an optimistic one
final optimisticIndex = _messages.indexWhere(
(m) => (m.id > 1000000000000 &&
m.message == incomingMsg.message &&
m.chatBy == incomingMsg.chatBy)
);
// Add only new messages that don't exist in current list
for (var newMsg in result) {
final exists = _messages.any((m) => m.id == newMsg.id);
if (!exists) {
_messages.add(newMsg);
if (optimisticIndex != -1) {
print("🔄 refresh: Replacing optimistic message with ID ${incomingMsg.id}");
_messages[optimisticIndex] = incomingMsg;
hasChanges = true;
} else {
// Truly new message (e.g. incoming from someone else)
print(" Adding new message ID ${incomingMsg.id}");
_messages.add(incomingMsg);
hasChanges = true;
}
}
}
// Sort the entire list
if (hasChanges) {
// Sort the entire list to be sure
_messages.sort((a, b) {
final dateA =
DateTime.tryParse(a.createdAt ?? '') ?? DateTime(1970);
final dateB =
DateTime.tryParse(b.createdAt ?? '') ?? DateTime(1970);
final dateA = DateTime.tryParse(a.createdAt ?? '') ?? DateTime(1970);
final dateB = DateTime.tryParse(b.createdAt ?? '') ?? DateTime(1970);
return dateA.compareTo(dateB);
});
if (mounted) state = AsyncData(List.from(_messages));
} else {
print("✅ No new messages");
print("✅ No new messages or status changes");
}
}
} catch (e) {
@ -472,10 +495,8 @@ class ChatMessagesNotifier
// 2. Check if this is a server confirmation of an optimistic message
// Optimistic messages have large positive IDs from DateTime.now().millisecondsSinceEpoch
// OR content match for very recent messages
final optimisticIndex = _messages.indexWhere(
(m) =>
// Match by content and sender if it's a very recent "local" message
(m.id > 1000000000000 &&
m.message == msg.message &&
m.chatBy == msg.chatBy),
@ -489,6 +510,13 @@ class ChatMessagesNotifier
_messages.add(msg);
}
// Sort to ensure order (important if multiple local messages are sent)
_messages.sort((a, b) {
final dateA = DateTime.tryParse(a.createdAt ?? '') ?? DateTime(1970);
final dateB = DateTime.tryParse(b.createdAt ?? '') ?? DateTime(1970);
return dateA.compareTo(dateB);
});
if (mounted) state = AsyncData(List.from(_messages));
}

View File

@ -458,7 +458,7 @@ class ApiRepository {
headers: await _authorizedHeaders(),
);
});
debugPrint("response: ${response.body}");
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
return DetailModel.fromJson(data);
@ -635,17 +635,17 @@ class ApiRepository {
File? panFile,
File? gstFile,
File? incorporationFile,
required int countryId,
required int stateId,
required int cityId,
required String companyPincode,
required String companyAddress,
required String panNumber,
required String gstNumber,
required String tanNumber,
required String cinNumber,
required String yearOfIncorporation,
required String address,
int? countryId,
int? stateId,
int? cityId,
String? companyPincode,
String? companyAddress,
String? panNumber,
String? gstNumber,
String? tanNumber,
String? cinNumber,
String? yearOfIncorporation,
String? address,
}) async {
try {
final token = await _localStore.getToken();
@ -658,17 +658,17 @@ class ApiRepository {
'Connection': 'keep-alive',
})
..fields.addAll({
'country_id': countryId.toString(),
'state_id': stateId.toString(),
'district_id': cityId.toString(),
'company_pincode': companyPincode,
'company_address': companyAddress,
'pan_number': panNumber,
'gst_number': gstNumber,
'tan_number': tanNumber,
'cin': cinNumber,
'year_of_incorporation': yearOfIncorporation,
'address': address,
if (countryId != null) 'country_id': countryId.toString(),
if (stateId != null) 'state_id': stateId.toString(),
if (cityId != null) 'district_id': cityId.toString(),
if (companyPincode != null) 'company_pincode': companyPincode,
if (companyAddress != null) 'company_address': companyAddress,
if (panNumber != null) 'pan_number': panNumber,
if (gstNumber != null) 'gst_number': gstNumber,
if (tanNumber != null) 'tan_number': tanNumber,
if (cinNumber != null) 'cin': cinNumber,
if (yearOfIncorporation != null) 'year_of_incorporation': yearOfIncorporation,
if (address != null) 'address': address,
});
await Future.wait([
@ -686,7 +686,8 @@ class ApiRepository {
);
final response = await http.Response.fromStream(streamedResponse);
debugPrint('📦 KYC Response Status: ${response.statusCode}');
debugPrint('📦 KYC Response Body: ${response.body}');
// Handle token expiry
if (response.statusCode == 401 || response.statusCode == 403) {
await _handleUnauthorized();

View File

@ -85,4 +85,4 @@ class DefaultFirebaseOptions {
storageBucket: 'taxglide-bd535.firebasestorage.app',
measurementId: 'G-14E4NG37P2',
);
}
}

View File

@ -6,6 +6,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:get/get.dart';
import 'package:file_picker/file_picker.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:taxglide/consts/notification_webscoket.dart';
import 'firebase_options.dart';
import 'package:taxglide/router/router.dart';
@ -138,6 +139,9 @@ void _setupFcmListeners() {
message,
tag: dedupTag,
);
// 🔄 Trigger live refresh for detail screens/badge counts
NotificationWebSocket().triggerRefresh();
}
});
@ -232,6 +236,7 @@ class _TaxglideAppState extends State<TaxglideApp> {
getPages: AppRoutes.routes,
theme: ThemeData(
useMaterial3: true,
fontFamily: 'Gilroy',
colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
),
);

View File

@ -50,12 +50,13 @@ class DetailData {
final String? proforma;
final int? proformaId;
final String? proformaNumber;
final String? proformastatus;
final String? proformaStatus;
final String? createdDate;
final String? createdTime;
final String? createdBy;
final String? message;
final String? subject;
final String? completedDate;
final String? paidBy;
@ -70,7 +71,7 @@ class DetailData {
this.firmId,
this.dueDate,
this.service,
this.proformastatus,
this.proformaStatus,
this.serviceStatus,
this.paymentStatus,
this.paidStatus,
@ -85,6 +86,7 @@ class DetailData {
this.createdTime,
this.createdBy,
this.message,
this.subject,
this.completedDate,
this.paidBy,
required this.userUploadedDocuments,
@ -102,7 +104,7 @@ class DetailData {
serviceStatus: json["service_status"],
paymentStatus: json["payment_status"],
proformastatus: json["proforma_status"],
proformaStatus: json["proforma_status"],
paidStatus: json["paid_status"],
paymentDate: json["payment_date"],
paymentAmount: json["payment_amount"]?.toString(),
@ -119,6 +121,7 @@ class DetailData {
createdBy: json["created_by"],
message: json["message"],
subject: json["subject"],
completedDate: json["completed_date"],
paidBy: json["paid_by"],
@ -153,7 +156,7 @@ class DetailData {
"payment_date": paymentDate,
"payment_amount": paymentAmount,
"invoice": invoice,
"proforma_status": proformastatus,
"proforma_status": proformaStatus,
"invoice_number": invoiceNumber,
"proforma": proforma,
"proforma_id": proformaId,
@ -162,6 +165,7 @@ class DetailData {
"created_time": createdTime,
"created_by": createdBy,
"message": message,
"subject": subject,
"completed_date": completedDate,
"paid_by": paidBy,
"user_uploaded_documents": userUploadedDocuments

View File

@ -42,23 +42,41 @@ class ServiceListHistoryModel {
class ServiceHistoryData {
final int? id;
final String? name;
final String? firmName;
final String? paymentStatus;
final String? paymentAmount;
final String? status;
final String? service;
final String? message;
final String? subject;
final String? assignee;
final String? createdDate;
final String? createdTime;
final String? createdAt;
final int? actions;
final int? chatId;
final int? isProformaGenerated;
final String? paymentId;
ServiceHistoryData({
this.id,
this.name,
this.firmName,
this.paymentStatus,
this.paymentAmount,
this.status,
this.service,
this.message,
this.subject,
this.assignee,
this.createdDate,
this.createdTime,
this.createdAt,
this.actions,
this.chatId,
this.isProformaGenerated,
this.paymentId,
});
factory ServiceHistoryData.fromJson(Map<String, dynamic> json) {
@ -66,26 +84,50 @@ class ServiceHistoryData {
id: json['id'] is int
? json['id']
: int.tryParse(json['id']?.toString() ?? ''),
name: json['name']?.toString(),
firmName: json['firm_name']?.toString(),
paymentStatus: json['payment_status']?.toString(),
paymentAmount: json['payment_amount']?.toString(),
status: json['status']?.toString(),
service: json['service']?.toString(),
message: json['message']?.toString(),
subject: json['subject']?.toString(),
assignee: json['assignee']?.toString(),
createdDate: json['created_date']?.toString(),
createdTime: json['created_time']?.toString(),
createdAt: json['created_at']?.toString(),
actions: json['actions'] is int
? json['actions']
: int.tryParse(json['actions']?.toString() ?? ''),
chatId: json['chat_id'] is int
? json['chat_id']
: int.tryParse(json['chat_id']?.toString() ?? ''),
isProformaGenerated: json['is_proforma_generated'] is int
? json['is_proforma_generated']
: int.tryParse(json['is_proforma_generated']?.toString() ?? ''),
paymentId: json['payment_id']?.toString(),
);
}
Map<String, dynamic> toJson() {
return {
'id': id,
'name': name,
'firm_name': firmName,
'payment_status': paymentStatus,
'payment_amount': paymentAmount,
'status': status,
'service': service,
'message': message,
'subject': subject,
'assignee': assignee,
'created_date': createdDate,
'created_time': createdTime,
'created_at': createdAt,
'actions': actions,
'chat_id': chatId,
'is_proforma_generated': isProformaGenerated,
'payment_id': paymentId,
};
}
}

View File

@ -2,6 +2,7 @@ import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:get/get.dart';
import 'package:taxglide/consts/download_helper.dart';
import 'package:taxglide/consts/local_store.dart';
import 'package:taxglide/view/Mahi_chat/live_chat_screen.dart';
import 'package:taxglide/view/Main_controller/main_controller.dart';
@ -26,6 +27,16 @@ const AndroidNotificationChannel _channel = AndroidNotificationChannel(
enableVibration: true,
);
/// Android notification channel for download updates.
const AndroidNotificationChannel _downloadChannel = AndroidNotificationChannel(
'taxglide_downloads',
'TaxGlide Downloads',
description: 'Notifications for file downloads',
importance: Importance.high,
playSound: true,
enableVibration: true,
);
/// Call once in main() after Firebase.initializeApp().
Future<void> initLocalNotifications() async {
const initSettings = InitializationSettings(
@ -37,19 +48,34 @@ Future<void> initLocalNotifications() async {
initSettings,
onDidReceiveNotificationResponse: (NotificationResponse response) {
// Notification tapped while app is open handled inside NotificationService.
debugPrint('🔔 Local notification tapped: payload=${response.payload}');
debugPrint('🔔 Local notification action: ${response.actionId} payload=${response.payload}');
if (response.actionId == 'location') {
final payload = response.payload;
if (payload != null && payload.startsWith('download:')) {
final filePath = payload.replaceFirst('download:', '');
final String dirPath = filePath.substring(0, filePath.lastIndexOf('/'));
debugPrint('📂 Opening folder from notification: $dirPath');
// Open the system file manager at this location
DownloadHelper.openFolder(dirPath);
return;
}
}
Get.find<NotificationService>().handleNavigationFromPayload(
response.payload,
);
},
);
// Create the Android channel (no-op on iOS).
await flutterLocalNotificationsPlugin
// Create the channels
final androidPlugin = flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin
>()
?.createNotificationChannel(_channel);
>();
await androidPlugin?.createNotificationChannel(_channel);
await androidPlugin?.createNotificationChannel(_downloadChannel);
debugPrint('✅ LocalNotifications initialized');
}
@ -123,6 +149,55 @@ class NotificationService extends GetxController {
);
}
/// Shows a notification when a file is successfully downloaded.
/// [filename] is the base name of the file.
/// [filePath] is the absolute path to the local file.
void showDownloadNotification(String filename, String filePath) {
debugPrint('📩 NotificationService: showing download success: $filename');
flutterLocalNotificationsPlugin.show(
filename.hashCode.abs() % 100000,
'Download Complete',
'File saved: $filename',
NotificationDetails(
android: AndroidNotificationDetails(
_downloadChannel.id,
_downloadChannel.name,
channelDescription: _downloadChannel.description,
importance: Importance.high,
priority: Priority.high,
icon: '@mipmap/launcher_icon',
playSound: true,
styleInformation: BigTextStyleInformation(
'The file **$filename** has been saved to your downloads folder:\n\n$filePath',
contentTitle: 'Download Complete',
summaryText: 'TaxGlide Download',
htmlFormatContent: true,
htmlFormatTitle: true,
),
actions: <AndroidNotificationAction>[
const AndroidNotificationAction(
'view',
'View File',
showsUserInterface: true,
),
const AndroidNotificationAction(
'location',
'Show in Folder',
showsUserInterface: true,
),
],
),
iOS: const DarwinNotificationDetails(
presentAlert: true,
presentBadge: true,
presentSound: true,
),
),
payload: 'download:$filePath',
);
}
// Navigation helpers
/// Called when a local notification is tapped (payload = "type:id").
@ -131,6 +206,15 @@ class NotificationService extends GetxController {
_safeNavigate(() => Get.offAll(() => MainController()));
return;
}
// Handle file download notifications
if (payload.startsWith('download:')) {
final filePath = payload.replaceFirst('download:', '');
debugPrint('📂 Opening downloaded file from notification: $filePath');
DownloadHelper.openDownloadedFile(filePath);
return;
}
final parts = payload.split(':');
final type = parts.isNotEmpty ? parts[0] : null;
final idStr = parts.length > 1 ? parts[1] : null;

View File

@ -39,7 +39,7 @@ class ChatProfileScreen extends ConsumerWidget {
title: const Text(
"Profile",
style: TextStyle(
fontFamily: "Gilroy-SemiBold",
fontFamily: "Gilroy",
fontWeight: FontWeight.w400,
fontSize: 20,
height: 1.4,
@ -113,7 +113,7 @@ class ChatProfileScreen extends ConsumerWidget {
const Text(
"Shared By Taxglide",
style: TextStyle(
fontFamily: "Gilroy-SemiBold",
fontFamily: "Gilroy",
fontWeight: FontWeight.w600,
fontSize: 20,
height: 1.4,
@ -213,7 +213,7 @@ class ChatProfileScreen extends ConsumerWidget {
const Text(
"Shared By Client",
style: TextStyle(
fontFamily: "Gilroy-SemiBold",
fontFamily: "Gilroy",
fontWeight: FontWeight.w600,
fontSize: 20,
height: 1.4,

View File

@ -7,6 +7,7 @@ import 'package:permission_handler/permission_handler.dart';
import 'package:taxglide/consts/download_helper.dart';
import 'package:taxglide/controller/api_contoller.dart';
import 'package:taxglide/controller/api_repository.dart';
import 'package:taxglide/model/chat_model.dart';
import 'package:taxglide/view/Mahi_chat/live_chat_screen.dart';
// CHAT INPUT BOX WITH FILE TAG SUPPORT
@ -246,49 +247,61 @@ class _ChatInputBoxState extends ConsumerState<ChatInputBox> {
setState(() => _isSending = true);
// Show loading dialog
showDialog(
context: context,
barrierDismissible: false,
builder: (context) => WillPopScope(
onWillPop: () async => false,
child: const Center(
child: Card(
child: Padding(
padding: EdgeInsets.all(20),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
CircularProgressIndicator(),
SizedBox(height: 16),
Text("Sending message..."),
],
),
),
),
),
),
// OPTIMISTIC UI: Create a temporary message and add it immediately
final tempId = DateTime.now().millisecondsSinceEpoch;
final tempMsg = MessageModel(
id: tempId,
chatBy: "user", // User
message: text,
type: selectedFiles.isNotEmpty ? "file" : "text",
isDelivered: 0,
isRead: 0,
createdAt: DateTime.now().toIso8601String(),
userId: 0,
tagId: tagId > 0 ? tagId : null,
parentTag: taggedMessage != null ? ParentTagModel(
id: taggedMessage.id,
message: taggedMessage.message,
type: taggedMessage.type,
fileName: taggedMessage.fileName,
) : null,
uploadedDocuments: selectedFiles.map((file) => DocumentModel(
filePath: file.path,
fileName: file.path.split('/').last,
fileType: "image",
)).toList(),
documents: [],
);
// Add to UI immediately
final notifier = ref.read(chatMessagesProvider(widget.chatId).notifier);
notifier.addNewMessage(tempMsg);
// Clear input immediately for snappy feel
final savedSelectedFiles = List<File>.from(selectedFiles);
messageCtrl.clear();
selectedFiles.clear();
ref.read(taggedMessageProvider.notifier).state = null;
// Notify parent to scroll to bottom instantly
if (widget.onMessageSent != null) {
widget.onMessageSent!();
}
try {
List<File> filesToUpload = [];
// Save files to Send folder
if (selectedFiles.isNotEmpty) {
print("📤 Saving ${selectedFiles.length} files to Send folder...");
for (File file in selectedFiles) {
if (savedSelectedFiles.isNotEmpty) {
for (File file in savedSelectedFiles) {
try {
// Try to save to Send folder, fallback to original if fails
final savedPath = await DownloadHelper.saveToSendFolder(file);
filesToUpload.add(File(savedPath));
} catch (e) {
print("⚠️ Could not save file, using original: $e");
filesToUpload.add(file);
}
}
print("✅ Files prepared for upload: ${filesToUpload.length}");
}
// Send message with files
@ -299,37 +312,22 @@ class _ChatInputBoxState extends ConsumerState<ChatInputBox> {
files: filesToUpload,
);
// Refresh chat messages
await ref.read(chatMessagesProvider(widget.chatId).notifier).refresh();
// Refresh chat messages (this will replace the temp message with the real one)
await notifier.refresh();
ref.invalidate(chatDocumentProvider);
print("✅ Message sent successfully with tagId: $tagId");
// Close loading dialog
if (mounted) Navigator.pop(context);
// Clear input
if (mounted) {
setState(() {
messageCtrl.clear();
selectedFiles.clear();
_isSending = false;
});
}
// Clear the tagged message
ref.read(taggedMessageProvider.notifier).state = null;
// Notify parent to scroll to bottom
if (widget.onMessageSent != null) {
widget.onMessageSent!();
setState(() => _isSending = false);
}
} catch (e) {
print("❌ Error sending message: $e");
if (mounted) {
setState(() => _isSending = false);
}
// Close loading dialog
if (mounted) Navigator.pop(context);
setState(() => _isSending = false);
// If it failed, delete the temporary message
notifier.deleteMessage(tempId);
// Show error message
if (mounted) {
@ -361,6 +359,7 @@ class _ChatInputBoxState extends ConsumerState<ChatInputBox> {
}
}
@override
Widget build(BuildContext context) {
final taggedMessage = ref.watch(taggedMessageProvider);

View File

@ -270,7 +270,7 @@ class _DownloadsScreenState extends State<DownloadsScreen>
title: const Text(
"Downloads",
style: TextStyle(
fontFamily: "Gilroy-SemiBold",
fontFamily: "Gilroy",
fontWeight: FontWeight.w600,
),
),

View File

@ -9,7 +9,7 @@ class SwipeableMessageBubble extends StatefulWidget {
final MessageModel message;
final DateTime msgDate;
final String Function(DateTime) formatTime;
final Widget Function(int, int) buildTick;
final Widget Function(MessageModel) buildTick;
final VoidCallback onSwipe;
final Function(int?)? onParentTagTap;
final Function(List<String> imageUrls, int initialIndex)?
@ -669,10 +669,7 @@ class SwipeableMessageBubbleState extends State<SwipeableMessageBubble>
),
),
const SizedBox(width: 4),
widget.buildTick(
widget.message.isDelivered,
widget.message.isRead,
),
widget.buildTick(widget.message),
],
),
],

View File

@ -160,8 +160,11 @@ class _LiveChatScreenState extends ConsumerState<LiveChatScreen>
try {
final event = message['event'] as String?;
if (event == 'message.sent' || event == 'message.received') {
debugPrint("🔔 New message detected!");
if (event == 'message.sent' ||
event == 'message.received' ||
event == 'message.read' ||
event == 'message.delivered') {
debugPrint("🔔 Message status/new message event: $event");
if (WidgetsBinding.instance.lifecycleState ==
AppLifecycleState.resumed) {
@ -409,7 +412,16 @@ class _LiveChatScreenState extends ConsumerState<LiveChatScreen>
return "$hour:$minute $period";
}
Widget buildTick(int isDelivered, int isRead) {
Widget buildTick(MessageModel message) {
// Status 0/1/pending
final isRead = message.isRead;
final isDelivered = message.isDelivered;
// Check if it's an optimistic pending message (huge ID)
if (message.id > 1000000000000) {
return const Icon(Icons.schedule, size: 14, color: Colors.grey);
}
if (isRead == 1) {
return const Icon(Icons.done_all, size: 16, color: Colors.blue);
} else if (isDelivered == 1) {
@ -445,7 +457,7 @@ class _LiveChatScreenState extends ConsumerState<LiveChatScreen>
? 'File ID : ${widget.fileid.toString()}'
: "Live Chat",
style: const TextStyle(
fontFamily: "Gilroy-SemiBold",
fontFamily: "Gilroy",
fontWeight: FontWeight.w600,
),
),

View File

@ -1,12 +1,14 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:taxglide/consts/app_asstes.dart';
import 'package:taxglide/consts/app_style.dart';
import 'package:taxglide/consts/comman_webscoket.dart';
import 'package:taxglide/consts/local_store.dart';
import 'package:taxglide/consts/notification_webscoket.dart';
import 'package:taxglide/controller/api_contoller.dart';
import 'package:taxglide/view/Mahi_chat/live_chat_screen.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:taxglide/consts/responsive_helper.dart';
class CommanChatBox extends ConsumerStatefulWidget {
final String? chatId;
@ -86,11 +88,12 @@ class _CommanChatBoxState extends ConsumerState<CommanChatBox> {
}
final id = snapshot.data ?? "0";
final r = ResponsiveUtils(context);
final countAsync = ref.watch(countProvider(id));
return Positioned(
right: 20,
bottom: 120,
bottom: r.spacing(mobile: 35, tablet: 45, desktop: 55),
child: Stack(
clipBehavior: Clip.none,
children: [
@ -154,10 +157,9 @@ class _CommanChatBoxState extends ConsumerState<CommanChatBox> {
),
child: Text(
data.count.toString(),
style: const TextStyle(
style: AppTextStyles.bold.copyWith(
color: Colors.white,
fontSize: 11,
fontWeight: FontWeight.bold,
fontSize: 10,
),
),
);

View File

@ -13,6 +13,9 @@ import 'package:taxglide/view/screens/home_screen.dart';
import 'package:taxglide/view/screens/list_service_screen.dart';
import 'package:taxglide/view/screens/profile/employee_profile/employee_profile_screen.dart';
import 'package:taxglide/view/screens/profile/profile_screen.dart';
import 'package:curved_labeled_navigation_bar/curved_navigation_bar.dart';
import 'package:curved_labeled_navigation_bar/curved_navigation_bar_item.dart';
import 'package:taxglide/consts/app_style.dart';
class MainController extends ConsumerStatefulWidget {
final Widget? child; // Optional child (like ServiceRequestScreen)
@ -39,7 +42,7 @@ class _MainControllerState extends ConsumerState<MainController> {
final List<String> _labels = [
'Home',
'Services',
'Service Details',
'Task Status',
'Profile',
];
@ -177,65 +180,6 @@ class _MainControllerState extends ConsumerState<MainController> {
body: Stack(
children: [
mainContent,
/// Bottom Navigation Bar
Positioned(
bottom: 0,
left: 0,
child: SafeArea(
top: false,
child: Container(
width: size.width,
height: 80,
child: Stack(
clipBehavior: Clip.none,
children: [
CustomPaint(
size: Size(size.width, 80),
painter: BNBCustomPainter(),
),
Center(
heightFactor: 0.6,
child: GestureDetector(
onTap: () {},
child: CustomPaint(
painter: PentagonPainter(
color: const Color(0xFF61277A),
),
child: Container(
width: 70,
height: 70,
alignment: Alignment.center,
child: Image.asset(
AppAssets.maincontroller,
color: Colors.white,
fit: BoxFit.contain,
height: 40,
width: 40,
),
),
),
),
),
SizedBox(
width: size.width,
height: 80,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
_buildNavItem(Icons.home, 0, _labels[0]),
_buildNavItem(Icons.list_alt_sharp, 1, _labels[1]),
SizedBox(width: size.width * 0.20),
_buildNavItem(Icons.history_edu, 2, _labels[2]),
_buildNavItem(Icons.person_2, 3, _labels[3]),
],
),
),
],
),
),
),
),
dashboardAsync.when(
data: (dashboard) {
final int? chatIdInt = dashboard.generalChatId;
@ -253,199 +197,89 @@ class _MainControllerState extends ConsumerState<MainController> {
),
],
),
),
);
}
/// Navigation Logic with Refresh
Widget _buildNavItem(IconData icon, int index, String label) {
bool isSelected = currentIndex == index;
return GestureDetector(
onTap: () {
// 🔹 If inside ServiceRequestScreen
if (widget.child != null) {
if (widget.initialIndex == index) return;
if (widget.sourceTabIndex == 0 && index == 1) {
Get.offAll(() => const MainController(initialIndex: 1));
return;
}
if (widget.sourceTabIndex == 1 && index == 1) return;
Get.offAll(() => MainController(initialIndex: index));
return;
}
// 🔹 If same tab tapped again refresh
if (currentIndex == index) {
_refreshTab(index);
return;
}
// 🔹 Switch to a different tab
setBottomBarIndex(index);
},
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
AnimatedContainer(
duration: const Duration(milliseconds: 200),
padding: const EdgeInsets.all(6),
decoration: BoxDecoration(
shape: BoxShape.circle,
border: isSelected
? Border.all(color: const Color(0xFF61277A), width: 2)
: null,
),
child: Icon(
icon,
color: isSelected
? const Color(0xFF61277A)
: const Color(0xFF6C7278),
size: isSelected ? 19.5 : 20.8,
),
),
if (isSelected)
Padding(
padding: const EdgeInsets.only(top: 4),
child: Text(
label,
style: const TextStyle(
color: Color(0xFF61277A),
bottomNavigationBar: SafeArea(
top: false,
child: CurvedNavigationBar(
backgroundColor: Color(0xFF61277A),
buttonBackgroundColor: Colors.white,
color: Colors.white,
animationDuration: const Duration(milliseconds: 300),
index: currentIndex,
items: [
CurvedNavigationBarItem(
child: Icon(
Icons.home,
color: currentIndex == 0 ? Colors.black : const Color(0xFF6C7278),
),
label: _labels[0],
labelStyle: (currentIndex == 0 ? AppTextStyles.bold : AppTextStyles.bold).copyWith(
color: currentIndex == 0 ? const Color(0xFF61277A) : const Color(0xFF6C7278),
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
),
],
CurvedNavigationBarItem(
child: Icon(
Icons.list_alt_sharp,
color: currentIndex == 1 ? Colors.black : const Color(0xFF6C7278),
),
label: _labels[1],
labelStyle: (currentIndex == 0 ? AppTextStyles.bold : AppTextStyles.bold).copyWith(
color: currentIndex == 1 ? const Color(0xFF61277A) : const Color(0xFF6C7278),
fontSize: 12,
),
),
CurvedNavigationBarItem(
child: Icon(
Icons.history_edu,
color: currentIndex == 2 ? Colors.black : const Color(0xFF6C7278),
),
label: _labels[2],
labelStyle: (currentIndex == 0 ? AppTextStyles.bold : AppTextStyles.bold).copyWith(
color: currentIndex == 2 ? const Color(0xFF61277A) : const Color(0xFF6C7278),
fontSize: 12,
),
),
CurvedNavigationBarItem(
child: Icon(
Icons.person_2,
color: currentIndex == 3 ? Colors.black : const Color(0xFF6C7278),
),
label: _labels[3],
labelStyle: (currentIndex == 0 ? AppTextStyles.bold : AppTextStyles.bold).copyWith(
color: currentIndex == 3 ? const Color(0xFF61277A) : const Color(0xFF6C7278),
fontSize: 12,
),
),
],
onTap: (index) {
// 🔹 If inside ServiceRequestScreen
if (widget.child != null) {
if (widget.initialIndex == index) return;
if (widget.sourceTabIndex == 0 && index == 1) {
Get.offAll(() => const MainController(initialIndex: 1));
return;
}
if (widget.sourceTabIndex == 1 && index == 1) return;
Get.offAll(() => MainController(initialIndex: index));
return;
}
// 🔹 If same tab tapped again refresh
if (currentIndex == index) {
_refreshTab(index);
return;
}
// 🔹 Switch to a different tab
setBottomBarIndex(index);
},
),
),
),
);
}
}
/// Custom Curved Bottom Navigation Painter
class BNBCustomPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
Paint paint = Paint()
..color = Colors.white
..style = PaintingStyle.fill;
Path path = Path();
path.moveTo(0, 20);
path.quadraticBezierTo(size.width * 0.20, 0, size.width * 0.35, 0);
path.quadraticBezierTo(size.width * 0.40, 0, size.width * 0.40, 20);
path.arcToPoint(
Offset(size.width * 0.60, 20),
radius: const Radius.circular(20.0),
clockwise: false,
);
path.quadraticBezierTo(size.width * 0.60, 0, size.width * 0.65, 0);
path.quadraticBezierTo(size.width * 0.80, 0, size.width, 20);
path.lineTo(size.width, size.height);
path.lineTo(0, size.height);
path.close();
canvas.drawShadow(path, Colors.black.withOpacity(0.2), 5, true);
canvas.drawPath(path, paint);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) => false;
}
/// Pentagon Button Painter
/// Pentagon Button Painter
class PentagonPainter extends CustomPainter {
final Color color;
final double cornerRadius;
PentagonPainter({
required this.color,
this.cornerRadius = 8.0, // Adjust this value for more/less rounding
});
@override
void paint(Canvas canvas, Size size) {
final paint = Paint()
..color = color
..style = PaintingStyle.fill;
final double w = size.width;
final double cx = w / 2;
final double cy = size.height / 2;
final double r = w / 2;
// Calculate pentagon vertices
List<Offset> vertices = [];
for (int i = 0; i < 5; i++) {
double angle = (72 * i - 90) * math.pi / 180;
double x = cx + r * 0.95 * math.cos(angle);
double y = cy + r * 0.95 * math.sin(angle);
vertices.add(Offset(x, y));
}
// Create path with rounded corners
final path = Path();
for (int i = 0; i < vertices.length; i++) {
final current = vertices[i];
final next = vertices[(i + 1) % vertices.length];
final prev = vertices[(i - 1 + vertices.length) % vertices.length];
// Calculate direction vectors
final toCurrent = Offset(current.dx - prev.dx, current.dy - prev.dy);
final toNext = Offset(next.dx - current.dx, next.dy - current.dy);
// Normalize and scale by corner radius
final lengthToCurrent = math.sqrt(
toCurrent.dx * toCurrent.dx + toCurrent.dy * toCurrent.dy,
);
final lengthToNext = math.sqrt(
toNext.dx * toNext.dx + toNext.dy * toNext.dy,
);
final normalizedToCurrent = Offset(
toCurrent.dx / lengthToCurrent,
toCurrent.dy / lengthToCurrent,
);
final normalizedToNext = Offset(
toNext.dx / lengthToNext,
toNext.dy / lengthToNext,
);
// Points before and after the corner
final beforeCorner = Offset(
current.dx - normalizedToCurrent.dx * cornerRadius,
current.dy - normalizedToCurrent.dy * cornerRadius,
);
final afterCorner = Offset(
current.dx + normalizedToNext.dx * cornerRadius,
current.dy + normalizedToNext.dy * cornerRadius,
);
if (i == 0) {
path.moveTo(beforeCorner.dx, beforeCorner.dy);
} else {
path.lineTo(beforeCorner.dx, beforeCorner.dy);
}
// Draw rounded corner using quadratic bezier
path.quadraticBezierTo(
current.dx,
current.dy,
afterCorner.dx,
afterCorner.dy,
);
}
path.close();
canvas.drawShadow(path, Colors.black.withOpacity(0.3), 4, true);
canvas.drawPath(path, paint);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) => false;
}

View File

@ -4,6 +4,7 @@ import 'package:flutter_riverpod/legacy.dart';
import 'package:get/get.dart';
import 'package:get/get_core/src/get_main.dart';
import 'package:taxglide/consts/app_asstes.dart';
import 'package:taxglide/consts/app_style.dart';
import 'package:taxglide/controller/api_contoller.dart';
import 'package:taxglide/model/chat_model.dart';
import 'package:taxglide/view/Mahi_chat/chat_profile_screen.dart';
@ -193,8 +194,11 @@ class _CompletedLiveChatScreenState
try {
final event = message['event'] as String?;
if (event == 'message.sent' || event == 'message.received') {
debugPrint("🔔 New message detected!");
if (event == 'message.sent' ||
event == 'message.received' ||
event == 'message.read' ||
event == 'message.delivered') {
debugPrint("🔔 Message status/new message event: $event");
if (WidgetsBinding.instance.lifecycleState ==
AppLifecycleState.resumed) {
@ -332,7 +336,11 @@ class _CompletedLiveChatScreenState
return "$hour:$minute $period";
}
Widget buildTick(int isDelivered, int isRead) {
Widget buildTick(MessageModel message) {
// Status 0/1
final isRead = message.isRead;
final isDelivered = message.isDelivered;
if (isRead == 1) {
return const Icon(Icons.done_all, size: 16, color: Colors.blue);
} else if (isDelivered == 1) {
@ -357,9 +365,9 @@ class _CompletedLiveChatScreenState
widget.fileid.toString() != "0")
? 'File ID : ${widget.fileid.toString()}'
: "Live Chat",
style: const TextStyle(
fontFamily: "Gilroy-SemiBold",
fontWeight: FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontSize: 16,
color: Colors.black,
),
),
backgroundColor: Colors.white,

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:taxglide/consts/app_style.dart';
import 'package:get/get.dart';
import 'package:taxglide/consts/app_asstes.dart';
import 'package:taxglide/consts/comman_button.dart';
@ -183,9 +184,7 @@ class _DetailScreenState extends ConsumerState<DetailScreen> {
label: Text(
"Invoice Not Available",
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w400,
style: AppTextStyles.regular.copyWith(
fontSize: width * 0.045,
height: 1.3,
letterSpacing: 0.04 * 17.64,
@ -239,9 +238,7 @@ class _DetailScreenState extends ConsumerState<DetailScreen> {
? "View Invoice"
: "Download Invoice",
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w400,
style: AppTextStyles.regular.copyWith(
fontSize: width * 0.045,
height: 1.3,
letterSpacing: 0.04 * 17.64,
@ -312,9 +309,7 @@ class _DetailScreenState extends ConsumerState<DetailScreen> {
: isDownloaded
? "View Proforma"
: "Download Proforma",
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontSize: 12,
height: 1.3,
letterSpacing: 0.04 * 14.47,
@ -337,6 +332,22 @@ class _DetailScreenState extends ConsumerState<DetailScreen> {
final detailAsync = ref.watch(serviceDetailProvider(widget.id));
// 🔄 Silent refresh when notification trigger changes
ref.listen(notificationTriggerProvider, (previous, next) {
if (previous != null && next != previous) {
debugPrint("🔔 Silent refresh triggered for DetailScreen");
ref.refresh(serviceDetailProvider(widget.id));
// Also refresh unread count if available
detailAsync.whenData((model) {
final chatId = model.data?.chatId;
if (chatId != null && chatId.isNotEmpty) {
ref.refresh(countProvider(chatId));
}
});
}
});
return Scaffold(
body: Container(
height: height,
@ -349,16 +360,16 @@ class _DetailScreenState extends ConsumerState<DetailScreen> {
),
child: SafeArea(
child: detailAsync.when(
skipLoadingOnRefresh: true,
loading: () => const Center(
child: CircularProgressIndicator(color: Colors.deepPurple),
),
error: (e, _) => Center(
child: Text(
"Error: $e",
style: const TextStyle(
style: AppTextStyles.regular.copyWith(
color: Colors.red,
fontSize: 16,
fontFamily: 'Gilroy-Medium',
),
),
),
@ -391,9 +402,7 @@ class _DetailScreenState extends ConsumerState<DetailScreen> {
Text(
"Service Details",
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontSize: width * 0.055,
color: const Color(0xFF111827),
),
@ -474,9 +483,7 @@ class _DetailScreenState extends ConsumerState<DetailScreen> {
children: [
Text(
"Detailed Information",
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontSize: width * 0.047,
height: 1.4,
letterSpacing: 0.03 * 20,
@ -508,9 +515,7 @@ class _DetailScreenState extends ConsumerState<DetailScreen> {
child: Center(
child: Text(
data.serviceStatus.toString(),
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w400,
style: AppTextStyles.regular.copyWith(
fontSize: width * 0.029,
color: const Color(0xFFFF0F0F),
),
@ -541,9 +546,7 @@ class _DetailScreenState extends ConsumerState<DetailScreen> {
child: Center(
child: Text(
data.serviceStatus.toString(),
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w400,
style: AppTextStyles.regular.copyWith(
fontSize: width * 0.032,
letterSpacing: 0.03,
color: const Color(0xFF12800C),
@ -575,9 +578,7 @@ class _DetailScreenState extends ConsumerState<DetailScreen> {
child: Center(
child: Text(
data.serviceStatus.toString(),
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w400,
style: AppTextStyles.regular.copyWith(
fontSize: width * 0.029,
letterSpacing: 0.03,
color: const Color(0xFFFF630F),
@ -616,18 +617,16 @@ class _DetailScreenState extends ConsumerState<DetailScreen> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Task Final Report",
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
fontSize: width * 0.042,
height: 1.4,
letterSpacing: 0.03 * 16,
color: const Color(0xFF111827),
),
textAlign: TextAlign.start,
Text(
"This is your final task document",
style: AppTextStyles.semiBold.copyWith(
fontSize: width * 0.042,
height: 1.4,
letterSpacing: 0.03 * 16,
color: const Color(0xFF111827),
),
textAlign: TextAlign.start,
),
const SizedBox(height: 15),
Row(
mainAxisAlignment:
@ -640,9 +639,7 @@ class _DetailScreenState extends ConsumerState<DetailScreen> {
children: [
TextSpan(
text: 'Date: ',
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontSize: width * 0.035,
height: 1.3,
letterSpacing: 0.04 * 13.97,
@ -651,9 +648,7 @@ class _DetailScreenState extends ConsumerState<DetailScreen> {
),
TextSpan(
text: data.createdDate ?? "-",
style: TextStyle(
fontFamily: 'Gilroy-Medium',
fontWeight: FontWeight.w400,
style: AppTextStyles.regular.copyWith(
fontSize: width * 0.035,
height: 1.3,
letterSpacing: 0.04 * 13.97,
@ -673,9 +668,7 @@ class _DetailScreenState extends ConsumerState<DetailScreen> {
children: [
TextSpan(
text: 'Payment : ',
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontSize: width * 0.035,
height: 1.3,
letterSpacing: 0.04 * 13.97,
@ -684,9 +677,7 @@ class _DetailScreenState extends ConsumerState<DetailScreen> {
),
TextSpan(
text: data.paymentStatus ?? "-",
style: TextStyle(
fontFamily: 'Gilroy-Medium',
fontWeight: FontWeight.w400,
style: AppTextStyles.regular.copyWith(
fontSize: width * 0.035,
height: 1.3,
letterSpacing: 0.04 * 13.97,
@ -899,7 +890,10 @@ class _DetailScreenState extends ConsumerState<DetailScreen> {
],
Column(
children: [
if (data.paymentStatus == "Un Paid") ...[
if (data.paymentStatus == "Un Paid" &&
!(data.serviceStatus ?? "")
.toLowerCase()
.contains("cancelled")) ...[
Padding(
padding: const EdgeInsets.symmetric(
vertical: 31,
@ -932,9 +926,7 @@ class _DetailScreenState extends ConsumerState<DetailScreen> {
children: [
Text(
"Payment Advice",
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontSize: width * 0.042,
height: 1.4,
letterSpacing: 0.03 * 16,
@ -953,36 +945,22 @@ class _DetailScreenState extends ConsumerState<DetailScreen> {
children: [
TextSpan(
text: 'Date: ',
style: TextStyle(
fontFamily:
'Gilroy-SemiBold',
fontWeight:
FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontSize: width * 0.035,
height: 1.3,
letterSpacing:
0.04 * 13.97,
color: const Color(
0xFF111827,
),
letterSpacing: 0.04 * 13.97,
color: const Color(0xFF111827),
),
),
TextSpan(
text:
data.createdDate ??
"-",
style: TextStyle(
fontFamily:
'Gilroy-Medium',
fontWeight:
FontWeight.w400,
style: AppTextStyles.regular.copyWith(
fontSize: width * 0.035,
height: 1.3,
letterSpacing:
0.04 * 13.97,
color: const Color(
0xFF111827,
),
letterSpacing: 0.04 * 13.97,
color: const Color(0xFF111827),
),
),
],
@ -998,36 +976,22 @@ class _DetailScreenState extends ConsumerState<DetailScreen> {
children: [
TextSpan(
text: 'Payment : ',
style: TextStyle(
fontFamily:
'Gilroy-SemiBold',
fontWeight:
FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontSize: width * 0.035,
height: 1.3,
letterSpacing:
0.04 * 13.97,
color: const Color(
0xFF111827,
),
letterSpacing: 0.04 * 13.97,
color: const Color(0xFF111827),
),
),
TextSpan(
text:
data.paymentStatus ??
"-",
style: TextStyle(
fontFamily:
'Gilroy-Medium',
fontWeight:
FontWeight.w400,
style: AppTextStyles.regular.copyWith(
fontSize: width * 0.035,
height: 1.3,
letterSpacing:
0.04 * 13.97,
color: const Color(
0xFF111827,
),
letterSpacing: 0.04 * 13.97,
color: const Color(0xFF111827),
),
),
],
@ -1045,18 +1009,15 @@ class _DetailScreenState extends ConsumerState<DetailScreen> {
children: [
Text(
"Total Amount",
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontSize: width * 0.04,
color: const Color(0xFF111827),
),
),
Text(
"${data.paymentAmount ?? '0'}",
style: TextStyle(
style: AppTextStyles.semiBold.copyWith(
fontFamily: 'Roboto',
fontWeight: FontWeight.w600,
fontSize: width * 0.045,
color: const Color(0xFF111827),
),
@ -1105,9 +1066,7 @@ class _DetailScreenState extends ConsumerState<DetailScreen> {
children: [
Text(
"Payment Advice",
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontSize: width * 0.042,
height: 1.4,
letterSpacing: 0.03 * 16,
@ -1126,36 +1085,22 @@ class _DetailScreenState extends ConsumerState<DetailScreen> {
children: [
TextSpan(
text: 'Date: ',
style: TextStyle(
fontFamily:
'Gilroy-SemiBold',
fontWeight:
FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontSize: width * 0.035,
height: 1.3,
letterSpacing:
0.04 * 13.97,
color: const Color(
0xFF111827,
),
letterSpacing: 0.04 * 13.97,
color: const Color(0xFF111827),
),
),
TextSpan(
text:
data.createdDate ??
"-",
style: TextStyle(
fontFamily:
'Gilroy-Medium',
fontWeight:
FontWeight.w400,
style: AppTextStyles.regular.copyWith(
fontSize: width * 0.035,
height: 1.3,
letterSpacing:
0.04 * 13.97,
color: const Color(
0xFF111827,
),
letterSpacing: 0.04 * 13.97,
color: const Color(0xFF111827),
),
),
],
@ -1171,36 +1116,22 @@ class _DetailScreenState extends ConsumerState<DetailScreen> {
children: [
TextSpan(
text: 'Payment: ',
style: TextStyle(
fontFamily:
'Gilroy-SemiBold',
fontWeight:
FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontSize: width * 0.035,
height: 1.3,
letterSpacing:
0.04 * 13.97,
color: const Color(
0xFF111827,
),
letterSpacing: 0.04 * 13.97,
color: const Color(0xFF111827),
),
),
TextSpan(
text:
data.paymentStatus ??
"-",
style: TextStyle(
fontFamily:
'Gilroy-Medium',
fontWeight:
FontWeight.w400,
style: AppTextStyles.regular.copyWith(
fontSize: width * 0.035,
height: 1.3,
letterSpacing:
0.04 * 13.97,
color: const Color(
0xFF111827,
),
letterSpacing: 0.04 * 13.97,
color: const Color(0xFF111827),
),
),
],
@ -1218,18 +1149,15 @@ class _DetailScreenState extends ConsumerState<DetailScreen> {
children: [
Text(
"Total Amount",
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontSize: width * 0.04,
color: const Color(0xFF111827),
),
),
Text(
"${data.paymentAmount ?? '0'}",
style: TextStyle(
style: AppTextStyles.semiBold.copyWith(
fontFamily: 'Roboto',
fontWeight: FontWeight.w600,
fontSize: width * 0.045,
color: const Color(0xFF111827),
),
@ -1248,10 +1176,8 @@ class _DetailScreenState extends ConsumerState<DetailScreen> {
],
),
),
] else if (data.paymentStatus == "Waiting") ...[
const SizedBox.shrink(),
] else ...[
Text("Unknown Status: ${data.paymentStatus}"),
const SizedBox.shrink(),
],
if (data.proforma != null &&
@ -1285,10 +1211,8 @@ class _DetailScreenState extends ConsumerState<DetailScreen> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Payment Advice",
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
"Profoma Advice",
style: AppTextStyles.semiBold.copyWith(
fontSize: width * 0.042,
height: 1.4,
letterSpacing: 0.03 * 16,
@ -1308,10 +1232,7 @@ class _DetailScreenState extends ConsumerState<DetailScreen> {
children: [
TextSpan(
text: 'proforma Number : ',
style: TextStyle(
fontFamily:
'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontSize: width * 0.035,
height: 1.3,
letterSpacing: 0.04 * 13.97,
@ -1321,12 +1242,9 @@ class _DetailScreenState extends ConsumerState<DetailScreen> {
),
),
TextSpan(
text:
data.proformaNumber ??
text: data.proformaNumber ??
"-",
style: TextStyle(
fontFamily: 'Gilroy-Medium',
fontWeight: FontWeight.w400,
style: AppTextStyles.regular.copyWith(
fontSize: width * 0.035,
height: 1.3,
letterSpacing: 0.04 * 13.97,
@ -1349,9 +1267,7 @@ class _DetailScreenState extends ConsumerState<DetailScreen> {
children: [
TextSpan(
text: 'proforma Status : ',
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontSize: width * 0.035,
height: 1.3,
letterSpacing: 0.04 * 13.97,
@ -1359,10 +1275,35 @@ class _DetailScreenState extends ConsumerState<DetailScreen> {
),
),
TextSpan(
text: data.proformastatus ?? "-",
style: TextStyle(
fontFamily: 'Gilroy-Medium',
fontWeight: FontWeight.w400,
text: data.proformaStatus ?? "-",
style: AppTextStyles.regular.copyWith(
fontSize: width * 0.035,
height: 1.3,
letterSpacing: 0.04 * 13.97,
color: const Color(0xFF111827),
),
),
],
),
),
const SizedBox(height: 20),
RichText(
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.end,
text: TextSpan(
children: [
TextSpan(
text: 'Subject : ',
style: AppTextStyles.semiBold.copyWith(
fontSize: width * 0.035,
height: 1.3,
letterSpacing: 0.04 * 13.97,
color: const Color(0xFF111827),
),
),
TextSpan(
text: data.subject ?? "-",
style: AppTextStyles.regular.copyWith(
fontSize: width * 0.035,
height: 1.3,
letterSpacing: 0.04 * 13.97,
@ -1372,15 +1313,12 @@ class _DetailScreenState extends ConsumerState<DetailScreen> {
],
),
),
const SizedBox(height: 20),
if (data.proformastatus != "Accepted") ...[
if (data.proformaStatus != "Accepted") ...[
Text(
"Note : Once you accept this proforma only you can pay the amount for the service",
textAlign: TextAlign.start,
style: const TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontSize: 13,
height: 1.78, // 178% line-height
letterSpacing: 0.04 * 13, // 4%
@ -1404,7 +1342,7 @@ class _DetailScreenState extends ConsumerState<DetailScreen> {
const SizedBox(width: 8),
if (data.proformastatus != "Accepted")
if (data.proformaStatus != "Accepted")
/// Accept (Less width)
Expanded(
flex: 2,
@ -1525,9 +1463,7 @@ class _DetailScreenState extends ConsumerState<DetailScreen> {
/// 🔹 File List Section
Text(
"File Attachments:",
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontSize: width * 0.04,
color: const Color(0xFF111827),
),
@ -1714,18 +1650,19 @@ class _DetailScreenState extends ConsumerState<DetailScreen> {
),
)
else
const Text(
Text(
"No documents uploaded",
style: TextStyle(
fontFamily: 'Gilroy-Medium',
color: Color(0xFF6B7280),
style: AppTextStyles.regular.copyWith(
color: const Color(0xFF6B7280),
),
),
],
),
),
),
if (data.chatId != null && data.chatId!.isNotEmpty)
if (data.chatId != null &&
data.chatId!.isNotEmpty &&
!(data.serviceStatus ?? "").toLowerCase().contains("cancelled"))
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 20,
@ -1821,7 +1758,7 @@ class _DetailScreenState extends ConsumerState<DetailScreen> {
),
),
const SizedBox(height: 150),
SizedBox(height: 80.0 + MediaQuery.of(context).padding.bottom),
],
),
);
@ -1839,18 +1776,14 @@ class _DetailScreenState extends ConsumerState<DetailScreen> {
children: [
TextSpan(
text: '$label: ',
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontSize: width * 0.04,
color: const Color(0xFF111827),
),
),
TextSpan(
text: value.isEmpty ? '' : value,
style: TextStyle(
fontFamily: 'Gilroy-Medium',
fontWeight: FontWeight.w500,
style: AppTextStyles.medium.copyWith(
fontSize: width * 0.04,
height: 1.5,
color: const Color(0xFF374151),
@ -1879,10 +1812,9 @@ class _DetailScreenState extends ConsumerState<DetailScreen> {
),
child: Text(
count.toString(),
style: const TextStyle(
style: AppTextStyles.bold.copyWith(
color: Colors.white,
fontSize: 10,
fontWeight: FontWeight.bold,
),
),
),

View File

@ -145,7 +145,7 @@ class _FilterBottomSheetState extends State<_FilterBottomSheet>
child: const Text(
"Cancel",
style: TextStyle(
fontFamily: "Gilroy-SemiBold", // Font
fontFamily: "Gilroy", // Font
fontWeight: FontWeight.w400,
fontSize: 16,
height: 1.3, // line-height 130%

View File

@ -1,9 +1,12 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:taxglide/consts/app_style.dart';
import 'package:get/get.dart';
import 'package:taxglide/controller/api_contoller.dart';
import 'package:taxglide/view/Main_controller/main_controller.dart';
import 'package:taxglide/view/screens/history/detail_screen.dart';
import 'package:taxglide/view/Mahi_chat/live_chat_screen.dart';
import 'package:taxglide/view/screens/history/completed_live_chat_screen.dart';
class PendingScreen extends ConsumerWidget {
final String status;
@ -17,6 +20,17 @@ class PendingScreen extends ConsumerWidget {
final width = size.width;
final height = size.height;
// 🔄 Silent refresh when notification trigger changes
ref.listen(notificationTriggerProvider, (previous, next) {
if (previous != null && next != previous) {
debugPrint("🔔 Silent refresh triggered for PendingScreen ($status)");
ref
.read(serviceHistoryNotifierProvider(status).notifier)
.fetchServiceHistory(isSilent: true);
ref.invalidate(countProvider);
}
});
return pendingAsync.when(
data: (data) {
final list = data.data ?? [];
@ -31,7 +45,7 @@ class PendingScreen extends ConsumerWidget {
width * 0.04,
height * 0.01,
width * 0.04,
height * 0.2,
80.0 + MediaQuery.of(context).padding.bottom,
),
itemCount: list.length,
separatorBuilder: (_, __) => SizedBox(height: height * 0.01),
@ -58,137 +72,236 @@ class PendingScreen extends ConsumerWidget {
children: [
// 🔹 File ID Row
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
RichText(
text: TextSpan(
children: [
TextSpan(
text: 'File ID : ',
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
fontSize: width * 0.04,
color: const Color(0xFF111827),
),
),
TextSpan(
text: '${item.id}',
style: TextStyle(
fontFamily: 'Gilroy-Medium',
fontWeight: FontWeight.w500,
fontSize: width * 0.04,
color: const Color(0xFF111827),
),
),
],
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
/// 🔹 File ID
RichText(
text: TextSpan(
children: [
TextSpan(
text: 'File ID : ',
style: AppTextStyles.semiBold.copyWith(
fontSize: width * 0.04,
color: const Color(0xFF111827),
),
),
TextSpan(
text: '${item.id}',
style: AppTextStyles.medium.copyWith(
fontSize: width * 0.04,
color: const Color(0xFF111827),
),
),
],
),
),
/// 🔥 Status + Chat Icon
Row(
children: [
/// 🔴 Waiting / Pending / Cancelled
if (item.status == 'Waiting for Admin' ||
item.status == 'Payment Pending' ||
item.status == 'Cancelled By Admin')
Container(
width: width * 0.4,
height: height * 0.04,
decoration: BoxDecoration(
color: const Color(0xFFFFE8E8),
borderRadius: BorderRadius.circular(5.52),
border: Border.all(
color: const Color(0xFFFFD7D7),
width: 1.84,
),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.25),
blurRadius: 7.17,
offset: const Offset(0, 3.68),
),
],
),
child: Center(
child: Text(
item.status.toString(),
style: AppTextStyles.regular.copyWith(
fontSize: 11.03,
color: const Color(0xFFFF0F0F),
),
),
),
),
/// 🟢 In Progress
if (item.status == 'In Progress')
Container(
width: 98,
height: 34.9,
decoration: BoxDecoration(
color: const Color(0xFFEAFAE6),
borderRadius: BorderRadius.circular(6.21),
border: Border.all(
color: const Color(0xFFDDFFDD),
width: 2.07,
),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.25),
blurRadius: 8.08,
offset: const Offset(0, 4.14),
),
],
),
child: Center(
child: Text(
'In Progress',
style: AppTextStyles.regular.copyWith(
fontSize: 12.43,
color: const Color(0xFF12800C),
),
),
),
),
/// 🟡 Completed
if (item.status == 'Completed')
Container(
width: 87,
height: 31,
decoration: BoxDecoration(
color: const Color(0xFFFAF7E6),
borderRadius: BorderRadius.circular(5.52),
border: Border.all(
color: const Color(0xFFFFE9DD),
width: 1.84,
),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.25),
blurRadius: 7.17,
offset: const Offset(0, 3.68),
),
],
),
child: Center(
child: Text(
'Completed',
style: AppTextStyles.regular.copyWith(
fontSize: 11.03,
color: const Color(0xFFFF630F),
),
),
),
),
/// 🔥 Space between status & icon
const SizedBox(width: 8),
if ((item.status == 'Completed' ||
item.status == 'Cancelled By Admin' ||
item.status == 'In Progress') &&
item.chatId != null &&
item.chatId.toString().isNotEmpty &&
item.chatId.toString() != "0") ...[
/// 💬 Chat Icon with Badge
Builder(builder: (context) {
final chatIdStr = item.chatId.toString();
final countAsync = ref.watch(countProvider(chatIdStr));
return GestureDetector(
onTap: () {
final chatid = int.tryParse(chatIdStr) ?? 0;
if (chatid == 0) return;
if (item.status == 'In Progress') {
Get.to(() => LiveChatScreen(
fileid: item.id.toString(),
chatid: chatid,
))?.then((_) {
ref.read(notificationTriggerProvider.notifier).state++;
ref.invalidate(chatMessagesProvider(chatid));
ref.invalidate(countProvider(chatIdStr));
});
} else {
Get.to(() => CompletedLiveChatScreen(
fileid: item.id.toString(),
chatid: chatid,
))?.then((_) {
ref.read(notificationTriggerProvider.notifier).state++;
ref.invalidate(chatMessagesProvider(chatid));
ref.invalidate(countProvider(chatIdStr));
});
}
},
child: Stack(
clipBehavior: Clip.none,
children: [
/// 🔵 Chat Icon
Container(
width: 39,
height: 39,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: const Color(0xFF61277A),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.25),
blurRadius: 8.08,
offset: const Offset(0, 4.14),
),
],
),
child: const Center(
child: Icon(
Icons.message,
color: Colors.white,
size: 20,
),
),
),
/// 🔴 Badge
countAsync.when(
data: (countData) => countData.count > 0
? Positioned(
top: -4,
right: -4,
child: Container(
padding: const EdgeInsets.all(4),
decoration: const BoxDecoration(
color: Colors.red,
shape: BoxShape.circle,
),
constraints: const BoxConstraints(
minWidth: 16,
minHeight: 16,
),
child: Text(
'${countData.count}',
textAlign: TextAlign.center,
style: const TextStyle(
color: Colors.white,
fontSize: 10,
fontWeight: FontWeight.bold,
),
),
),
)
: const SizedBox.shrink(),
loading: () => const SizedBox.shrink(),
error: (_, __) => const SizedBox.shrink(),
),
],
),
);
}),
// 🔹 Status Badges
if (item.status == 'Waiting for Admin' ||
item.status == 'Payment Pending' ||
item.status == 'Cancelled By Admin')
Container(
width: width * 0.3,
height: height * 0.04,
decoration: BoxDecoration(
color: const Color(0xFFFFE8E8),
borderRadius: BorderRadius.circular(5.52),
border: Border.all(
color: const Color(0xFFFFD7D7),
width: 1.84,
),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.25),
blurRadius: 7.17,
offset: const Offset(0, 3.68),
),
],
),
child: Center(
child: Text(
item.status.toString(),
style: const TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w400,
fontSize: 11.03,
color: Color(0xFFFF0F0F),
),
),
),
),
// 🔹 In Progress Badge
if (item.status == 'In Progress')
Container(
width: 98,
height: 34.9,
decoration: BoxDecoration(
color: const Color(0xFFEAFAE6),
borderRadius: BorderRadius.circular(6.21),
border: Border.all(
color: const Color(0xFFDDFFDD),
width: 2.07,
),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.25),
blurRadius: 8.08,
offset: const Offset(0, 4.14),
),
],
),
child: const Center(
child: Text(
'In Progress',
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w400,
fontSize: 12.43,
letterSpacing: 0.03,
color: Color(0xFF12800C),
),
),
),
),
// 🔹 Completed Badge
if (item.status == 'Completed')
Container(
width: 87,
height: 31,
decoration: BoxDecoration(
color: const Color(0xFFFAF7E6),
borderRadius: BorderRadius.circular(5.52),
border: Border.all(
color: const Color(0xFFFFE9DD),
width: 1.84,
),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.25),
blurRadius: 7.17,
offset: const Offset(0, 3.68),
),
],
),
child: const Center(
child: Text(
'Completed',
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w400,
fontSize: 11.03,
letterSpacing: 0.03,
color: Color(0xFFFF630F),
),
),
),
),
],
),
],
]
),
],
),
SizedBox(height: height * 0.015),
@ -198,18 +311,14 @@ class PendingScreen extends ConsumerWidget {
children: [
TextSpan(
text: 'Request Type : ',
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
fontSize: width * 0.035,
color: const Color(0xFF111827),
),
style: AppTextStyles.semiBold.copyWith(
fontSize: width * 0.035,
color: const Color(0xFF111827),
),
),
TextSpan(
text: item.service,
style: TextStyle(
fontFamily: 'Gilroy-Medium',
fontWeight: FontWeight.w500,
style: AppTextStyles.medium.copyWith(
fontSize: width * 0.035,
color: const Color(0xFF111827),
),
@ -228,21 +337,17 @@ class PendingScreen extends ConsumerWidget {
children: [
TextSpan(
text: 'Date : ',
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
fontSize: width * 0.035,
color: const Color(0xFF111827),
),
style: AppTextStyles.semiBold.copyWith(
fontSize: width * 0.035,
color: const Color(0xFF111827),
),
),
TextSpan(
text: item.createdDate,
style: TextStyle(
fontFamily: 'Gilroy-Medium',
fontWeight: FontWeight.w500,
fontSize: width * 0.035,
color: const Color(0xFF111827),
),
style: AppTextStyles.medium.copyWith(
fontSize: width * 0.035,
color: const Color(0xFF111827),
),
),
],
),
@ -253,21 +358,17 @@ class PendingScreen extends ConsumerWidget {
children: [
TextSpan(
text: 'Time : ',
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
fontSize: width * 0.035,
color: const Color(0xFF111827),
),
style: AppTextStyles.semiBold.copyWith(
fontSize: width * 0.035,
color: const Color(0xFF111827),
),
),
TextSpan(
text: item.createdTime,
style: TextStyle(
fontFamily: 'Gilroy-Medium',
fontWeight: FontWeight.w500,
fontSize: width * 0.035,
color: const Color(0xFF111827),
),
style: AppTextStyles.medium.copyWith(
fontSize: width * 0.035,
color: const Color(0xFF111827),
),
),
],
),
@ -283,18 +384,14 @@ class PendingScreen extends ConsumerWidget {
children: [
TextSpan(
text: 'Message : ',
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
fontSize: width * 0.035,
color: const Color(0xFF111827),
),
style: AppTextStyles.semiBold.copyWith(
fontSize: width * 0.035,
color: const Color(0xFF111827),
),
),
TextSpan(
text: item.message,
style: TextStyle(
fontFamily: 'Gilroy-Medium',
fontWeight: FontWeight.w500,
style: AppTextStyles.medium.copyWith(
fontSize: width * 0.035,
color: const Color(0xFF111827),
),
@ -314,9 +411,7 @@ class PendingScreen extends ConsumerWidget {
children: [
Text(
"Total Amount",
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontSize: width * 0.038,
color: const Color(0xFF111827),
),
@ -357,14 +452,12 @@ class PendingScreen extends ConsumerWidget {
),
],
),
child: const Center(
child: Center(
child: Text(
"Pay Now",
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontSize: 16,
color: Color(0xFF61277A),
color: const Color(0xFF61277A),
),
),
),
@ -399,12 +492,10 @@ class PendingScreen extends ConsumerWidget {
),
],
),
child: const Center(
child: Center(
child: Text(
"View Details",
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontSize: 16,
color: Colors.white,
),
@ -434,12 +525,10 @@ class PendingScreen extends ConsumerWidget {
],
),
alignment: Alignment.center,
child: const Text(
child: Text(
"Payment Status: Paid",
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w400,
style: AppTextStyles.regular.copyWith(
fontSize: 12.08,
letterSpacing: 0.04,
height: 1.3,
@ -474,12 +563,10 @@ class PendingScreen extends ConsumerWidget {
),
],
),
child: const Center(
child: Center(
child: Text(
"View Details",
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontSize: 16,
color: Colors.white,
),
@ -519,12 +606,10 @@ class PendingScreen extends ConsumerWidget {
),
],
),
child: const Center(
child: Center(
child: Text(
"View Details",
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontSize: 16,
color: Colors.white,
),

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:taxglide/consts/app_style.dart';
import 'package:taxglide/view/screens/history/flitter_popup.dart';
import 'package:taxglide/view/screens/history/pending_screen.dart';
@ -57,15 +58,13 @@ class _ServicesStatusScreenState extends ConsumerState<ServicesStatusScreen>
children: [
const SizedBox(width: 40), // Left side space balance
// CENTER TITLE
const Text(
"Service Status",
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
fontSize: 24,
color: Color(0xFF111827),
),
),
Text(
"My Task Status",
style: AppTextStyles.bold.copyWith(
fontSize: 24,
color: Color(0xFF111827),
),
),
// RIGHT SIDE FILTER ICON
GestureDetector(
@ -126,21 +125,17 @@ class _ServicesStatusScreenState extends ConsumerState<ServicesStatusScreen>
),
labelColor: const Color(0xFF5F297B),
unselectedLabelColor: const Color(0xFF6C7278),
labelStyle: const TextStyle(
fontFamily: "Gilroy-SemiBold",
fontWeight: FontWeight.w600,
labelStyle: AppTextStyles.semiBold.copyWith(
fontSize: 16,
height: 1.4,
letterSpacing: 0.03,
color: Color(0xFF5F297B),
color: const Color(0xFF5F297B),
),
unselectedLabelStyle: const TextStyle(
fontFamily: "Gilroy-Regular",
fontWeight: FontWeight.w400,
unselectedLabelStyle: AppTextStyles.regular.copyWith(
fontSize: 16,
height: 1.4,
letterSpacing: 0.03,
color: Color(0xFF6C7278),
color: const Color(0xFF6C7278),
),
tabs: _tabs.map((tab) => Tab(text: tab)).toList(),
),

View File

@ -1,9 +1,12 @@
import 'dart:ui';
import 'package:carousel_slider/carousel_options.dart';
import 'package:carousel_slider/carousel_slider.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:get/get.dart';
import 'package:taxglide/consts/app_asstes.dart';
import 'package:taxglide/consts/app_style.dart';
import 'package:taxglide/consts/app_colors.dart';
import 'package:taxglide/consts/comman_serivce.dart';
import 'package:taxglide/consts/home_page_headers.dart';
@ -128,6 +131,29 @@ class _HomeScreenState extends ConsumerState<HomeScreen> {
final kycTitleSize = r.fontSize(mobile: 16, tablet: 18, desktop: 20);
final kycBodySize = r.fontSize(mobile: 10, tablet: 10, desktop: 11);
// My Task Status Button responsive values
final taskStatusGlowWidth = r.getValue<double>(
mobile: 200,
tablet: 220,
desktop: 240,
);
final taskStatusGlowHeight = r.getValue<double>(
mobile: 45,
tablet: 50,
desktop: 55,
);
final taskStatusButtonWidth = r.getValue<double>(
mobile: 197.45,
tablet: 215,
desktop: 235,
);
final taskStatusButtonHeight = r.getValue<double>(
mobile: 41.38,
tablet: 46,
desktop: 50,
);
final taskStatusFontSize = r.fontSize(mobile: 18, tablet: 20, desktop: 22);
return SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
@ -141,8 +167,8 @@ class _HomeScreenState extends ConsumerState<HomeScreen> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// KYC Banner
if (dashboard.isKycCompleted == false)
Container(
if (dashboard.isKycCompleted == true)...[
Container(
width: double.infinity,
padding: EdgeInsets.all(cardPadding),
decoration: const BoxDecoration(
@ -162,8 +188,7 @@ class _HomeScreenState extends ConsumerState<HomeScreen> {
children: [
Text(
"KYC Details",
style: TextStyle(
fontWeight: FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontSize: kycTitleSize,
color: Colors.white,
),
@ -171,7 +196,7 @@ class _HomeScreenState extends ConsumerState<HomeScreen> {
const SizedBox(height: 8),
Text(
"Your KYC verification couldn't be completed. Please complete your KYC details to continue exploring more features.",
style: TextStyle(
style: AppTextStyles.regular.copyWith(
fontSize: kycBodySize,
color: const Color(0xFFFFFFCC),
),
@ -213,15 +238,85 @@ class _HomeScreenState extends ConsumerState<HomeScreen> {
),
),
SizedBox(
SizedBox(
height: r.spacing(mobile: 26, tablet: 28, desktop: 32),
),],
Center(
child: Stack(
alignment: Alignment.center,
children: [
/// 🌈 Gradient + Blur Glow
ClipRRect(
borderRadius: BorderRadius.circular(40),
child: BackdropFilter(
filter: ImageFilter.blur(
sigmaX: 16.54,
sigmaY: 16.54,
),
child: Container(
width: taskStatusGlowWidth,
height: taskStatusGlowHeight,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(40),
gradient: const LinearGradient(
colors: [
Color(0xFF7BFAFA),
Color(0xFF8BF0FD),
Color(0xFF8EFFD5),
Color(0xFFC8F895),
Color(0xFFE7F392),
Color(0xFFFBE28D),
Color(0xFFFCDAB1),
Color(0xFFFEDCAA),
],
),
),
),
),
),
/// 🔲 Black Button
GestureDetector(
onTap: () {
Get.offAll(
() => const MainController(
initialIndex: 2,
sourceTabIndex: 0,
),
);
},
child: Container(
width: taskStatusButtonWidth,
height: taskStatusButtonHeight,
alignment: Alignment.center,
decoration: BoxDecoration(
color: const Color(0xFF000000),
borderRadius: BorderRadius.circular(39.02),
),
child: Text(
"My Task Status",
textAlign: TextAlign.center,
style: AppTextStyles.semiBold.copyWith(
fontSize: taskStatusFontSize,
height: 1.4,
letterSpacing: 0.03 * taskStatusFontSize,
color: Colors.white,
),
),
),
),
],
),
),
SizedBox(
height: r.spacing(mobile: 26, tablet: 28, desktop: 32),
),
Text(
"List of Services Offered",
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
style: AppTextStyles.bold.copyWith(
fontSize: sectionTitleSize,
height: 1.3,
letterSpacing: 0.72,
@ -295,9 +390,7 @@ class _HomeScreenState extends ConsumerState<HomeScreen> {
children: [
Text(
"Booking List",
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
style: AppTextStyles.bold.copyWith(
fontSize: bookingTitleSize,
height: 1.4,
letterSpacing: 0.6,
@ -314,9 +407,7 @@ class _HomeScreenState extends ConsumerState<HomeScreen> {
},
child: Text(
"See All",
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontSize: seeAllSize,
height: 1.4,
letterSpacing: 0.45,
@ -369,18 +460,14 @@ class _HomeScreenState extends ConsumerState<HomeScreen> {
children: [
TextSpan(
text: 'File ID : ',
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontSize: fileIdSize,
color: const Color(0xFF111827),
),
),
TextSpan(
text: '${item.id}',
style: TextStyle(
fontFamily: 'Gilroy-Medium',
fontWeight: FontWeight.w500,
style: AppTextStyles.medium.copyWith(
fontSize: fileIdSize,
color: const Color(0xFF111827),
),
@ -426,9 +513,7 @@ class _HomeScreenState extends ConsumerState<HomeScreen> {
child: Center(
child: Text(
item.status.toString(),
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w400,
style: AppTextStyles.regular.copyWith(
fontSize: r.fontSize(
mobile: 10,
tablet: 11,
@ -474,9 +559,7 @@ class _HomeScreenState extends ConsumerState<HomeScreen> {
child: Center(
child: Text(
'In Progress',
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w400,
style: AppTextStyles.regular.copyWith(
fontSize: r.fontSize(
mobile: 11,
tablet: 12.43,
@ -523,9 +606,7 @@ class _HomeScreenState extends ConsumerState<HomeScreen> {
child: Center(
child: Text(
'Completed',
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w400,
style: AppTextStyles.regular.copyWith(
fontSize: r.fontSize(
mobile: 10,
tablet: 11.03,
@ -548,18 +629,14 @@ class _HomeScreenState extends ConsumerState<HomeScreen> {
children: [
TextSpan(
text: 'Request Type : ',
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontSize: labelSize,
color: const Color(0xFF111827),
),
),
TextSpan(
text: item.service,
style: TextStyle(
fontFamily: 'Gilroy-Medium',
fontWeight: FontWeight.w500,
style: AppTextStyles.medium.copyWith(
fontSize: valueSize,
color: const Color(0xFF111827),
),
@ -578,18 +655,14 @@ class _HomeScreenState extends ConsumerState<HomeScreen> {
children: [
TextSpan(
text: 'Date : ',
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontSize: labelSize,
color: const Color(0xFF111827),
),
),
TextSpan(
text: item.createdDate,
style: TextStyle(
fontFamily: 'Gilroy-Medium',
fontWeight: FontWeight.w500,
style: AppTextStyles.medium.copyWith(
fontSize: valueSize,
color: const Color(0xFF111827),
),
@ -609,18 +682,14 @@ class _HomeScreenState extends ConsumerState<HomeScreen> {
children: [
TextSpan(
text: 'Time : ',
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontSize: labelSize,
color: const Color(0xFF111827),
),
),
TextSpan(
text: item.createdTime,
style: TextStyle(
fontFamily: 'Gilroy-Medium',
fontWeight: FontWeight.w500,
style: AppTextStyles.medium.copyWith(
fontSize: valueSize,
color: const Color(0xFF111827),
),
@ -639,18 +708,14 @@ class _HomeScreenState extends ConsumerState<HomeScreen> {
children: [
TextSpan(
text: 'Message : ',
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontSize: labelSize,
color: const Color(0xFF111827),
),
),
TextSpan(
text: item.message,
style: TextStyle(
fontFamily: 'Gilroy-Medium',
fontWeight: FontWeight.w500,
style: AppTextStyles.medium.copyWith(
fontSize: valueSize,
color: const Color(0xFF111827),
),
@ -671,18 +736,15 @@ class _HomeScreenState extends ConsumerState<HomeScreen> {
children: [
Text(
"Total Amount",
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontSize: labelSize,
color: const Color(0xFF111827),
),
),
Text(
'${item.paymentAmount.toString()}',
style: TextStyle(
style: AppTextStyles.semiBold.copyWith(
fontFamily: 'Roboto',
fontWeight: FontWeight.w600,
fontSize: amountSize,
color: const Color(0xFF111827),
),
@ -719,9 +781,7 @@ class _HomeScreenState extends ConsumerState<HomeScreen> {
child: Center(
child: Text(
"Pay Now",
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontSize: buttonTextSize,
color: const Color(0xFF61277A),
),
@ -773,9 +833,7 @@ class _HomeScreenState extends ConsumerState<HomeScreen> {
child: Center(
child: Text(
"View Details",
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontSize: buttonTextSize,
color: Colors.white,
),
@ -821,9 +879,7 @@ class _HomeScreenState extends ConsumerState<HomeScreen> {
child: Text(
"Payment Status: Paid",
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w400,
style: AppTextStyles.regular.copyWith(
fontSize: r.fontSize(
mobile: 11,
tablet: 12.08,
@ -872,9 +928,7 @@ class _HomeScreenState extends ConsumerState<HomeScreen> {
child: Center(
child: Text(
"View Details",
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontSize: buttonTextSize,
color: Colors.white,
),
@ -922,9 +976,7 @@ class _HomeScreenState extends ConsumerState<HomeScreen> {
child: Center(
child: Text(
"View Details",
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontSize: buttonTextSize,
color: Colors.white,
),
@ -1038,11 +1090,9 @@ class _HomeScreenState extends ConsumerState<HomeScreen> {
children: [
Text(
"What Our Customers Say",
style: TextStyle(
fontFamily: "Gilroy-SemiBold",
style: AppTextStyles.semiBold.copyWith(
fontSize: reviewTitleSize,
color: Colors.white,
fontWeight: FontWeight.w600,
),
),
],
@ -1084,7 +1134,7 @@ class _HomeScreenState extends ConsumerState<HomeScreen> {
],
),
const SizedBox(height: 200),
SizedBox(height: r.spacing(mobile: 120, tablet: 140, desktop: 160)),
],
),
);
@ -1129,15 +1179,14 @@ class _HomeScreenState extends ConsumerState<HomeScreen> {
children: [
Text(
name,
style: TextStyle(
style: AppTextStyles.bold.copyWith(
fontSize: r.fontSize(mobile: 13, tablet: 15, desktop: 16),
fontWeight: FontWeight.w700,
color: Colors.black87,
),
),
Text(
position,
style: TextStyle(
style: AppTextStyles.regular.copyWith(
fontSize: r.fontSize(mobile: 10, tablet: 11, desktop: 12),
color: Colors.grey,
),
@ -1164,7 +1213,7 @@ class _HomeScreenState extends ConsumerState<HomeScreen> {
maxLines: 4,
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.center,
style: TextStyle(
style: AppTextStyles.regular.copyWith(
fontSize: r.fontSize(mobile: 11, tablet: 12, desktop: 13),
height: 1.3,
color: Colors.black87,
@ -1180,13 +1229,12 @@ class _HomeScreenState extends ConsumerState<HomeScreen> {
width: 40,
height: 40,
decoration: BoxDecoration(color: iconColor, shape: BoxShape.circle),
child: const Center(
child: Center(
child: Text(
"",
style: TextStyle(
style: AppTextStyles.bold.copyWith(
color: Colors.white,
fontSize: 22,
fontWeight: FontWeight.bold,
),
),
),

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:taxglide/consts/app_style.dart';
import 'package:taxglide/consts/app_asstes.dart';
import 'package:taxglide/consts/comman_serivce.dart';
import 'package:taxglide/controller/api_contoller.dart';
@ -38,9 +39,7 @@ class _ListServiceScreenState extends ConsumerState<ListServiceScreen> {
children: [
Text(
"List of Services Offered",
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontStyle: FontStyle.normal,
fontSize: 18,
height: 1.3,
@ -54,14 +53,13 @@ class _ListServiceScreenState extends ConsumerState<ListServiceScreen> {
serviceAsync.when(
data: (services) {
if (services.isEmpty) {
return const Padding(
return Padding(
padding: EdgeInsets.only(top: 40),
child: Center(
child: Text(
"No Services Available",
style: TextStyle(
style: AppTextStyles.regular.copyWith(
fontSize: 16,
fontFamily: 'Gilroy-SemiBold',
color: Colors.black54,
),
),

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:taxglide/consts/app_style.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:get/get.dart';
import 'package:get/get_core/src/get_main.dart';
@ -55,11 +56,9 @@ class _NotificationScreenState extends ConsumerState<NotificationScreen> {
child: Stack(
alignment: Alignment.center,
children: [
const Text(
Text(
"Notification",
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontSize: 24,
color: Color(0xFF111827),
),
@ -126,9 +125,7 @@ class _NotificationScreenState extends ConsumerState<NotificationScreen> {
children: [
Text(
item.title,
style: const TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w700,
style: AppTextStyles.bold.copyWith(
fontSize: 16,
color: Colors.black,
),
@ -136,12 +133,12 @@ class _NotificationScreenState extends ConsumerState<NotificationScreen> {
const SizedBox(height: 4),
Text(
item.description,
style: const TextStyle(fontSize: 14, color: Colors.grey),
style: AppTextStyles.regular.copyWith(fontSize: 14, color: Colors.grey),
),
const SizedBox(height: 8),
Text(
item.createdAt,
style: const TextStyle(fontSize: 12, color: Colors.grey),
style: AppTextStyles.regular.copyWith(fontSize: 12, color: Colors.grey),
),
],
),

View File

@ -71,7 +71,7 @@ class _EmployeeProfileListState extends ConsumerState<EmployeeProfileList> {
"KYC Details",
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontFamily: "Gilroy",
fontWeight: FontWeight
.w600, // equivalent to 400 (Normal)
fontStyle: FontStyle.normal,
@ -117,7 +117,7 @@ class _EmployeeProfileListState extends ConsumerState<EmployeeProfileList> {
const Text(
"Personal Details",
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontFamily: "Gilroy",
fontSize: 20,
color: Color(0xFF111827),
),
@ -202,7 +202,7 @@ class _EmployeeProfileListState extends ConsumerState<EmployeeProfileList> {
Text(
title,
style: const TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontFamily: "Gilroy",
fontWeight: FontWeight.w600,
fontSize: 14,
height: 1.3,
@ -216,7 +216,7 @@ class _EmployeeProfileListState extends ConsumerState<EmployeeProfileList> {
softWrap: true,
overflow: TextOverflow.visible,
style: const TextStyle(
fontFamily: 'Gilroy-Regular',
fontFamily: "Gilroy",
fontWeight: FontWeight.w400,
fontSize: 14,
height: 1.3,

View File

@ -22,6 +22,12 @@ class _EmployeeProfileScreenState extends ConsumerState<EmployeeProfileScreen> {
String? selectedItem;
bool _isLoggingOut = false;
@override
void initState() {
super.initState();
selectedItem = 'profile'; // Default selection
}
@override
Widget build(BuildContext context) {
final profileAsync = ref.watch(employeeProfileProvider);
@ -110,7 +116,7 @@ class _EmployeeProfileScreenState extends ConsumerState<EmployeeProfileScreen> {
Text(
data?.name ?? 'No Company Name',
style: const TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontFamily: "Gilroy",
fontWeight: FontWeight.w600,
fontSize: 20,
color: Colors.black,
@ -244,7 +250,7 @@ class _EmployeeProfileScreenState extends ConsumerState<EmployeeProfileScreen> {
const Text(
"Note",
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontFamily: "Gilroy",
fontWeight: FontWeight.w600,
fontSize: 20,
color: Colors.black,
@ -254,7 +260,7 @@ class _EmployeeProfileScreenState extends ConsumerState<EmployeeProfileScreen> {
"Are you sure you want to log out?",
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontFamily: "Gilroy",
fontWeight: FontWeight.w500,
fontSize: 15,
color: Colors.black87,
@ -270,7 +276,7 @@ class _EmployeeProfileScreenState extends ConsumerState<EmployeeProfileScreen> {
style: TextStyle(
color: Color(0xFF535A5B),
fontSize: 16,
fontFamily: 'Gilroy-SemiBold',
fontFamily: "Gilroy",
fontWeight: FontWeight.w600,
),
),
@ -321,7 +327,7 @@ class _EmployeeProfileScreenState extends ConsumerState<EmployeeProfileScreen> {
style: TextStyle(
color: Color(0xFF5F297B),
fontSize: 16,
fontFamily: 'Gilroy-SemiBold',
fontFamily: "Gilroy",
fontWeight: FontWeight.w600,
),
),
@ -384,7 +390,7 @@ class _EmployeeProfileScreenState extends ConsumerState<EmployeeProfileScreen> {
child: Text(
title,
style: const TextStyle(
fontFamily: 'Gilroy-Medium',
fontFamily: "Gilroy",
fontSize: 16,
fontWeight: FontWeight.w500,
color: Colors.black87,

View File

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:get/get.dart';
import 'package:taxglide/consts/app_asstes.dart';
import 'package:taxglide/consts/app_style.dart';
import 'package:taxglide/consts/download_helper.dart';
import 'package:taxglide/controller/api_consts.dart';
import 'package:taxglide/controller/api_contoller.dart';
@ -65,7 +66,7 @@ class _KycDetailsListState extends ConsumerState<KycDetailsList> {
"KYC Details",
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontFamily: "Gilroy",
fontWeight: FontWeight
.w600, // equivalent to 400 (Normal)
fontStyle: FontStyle.normal,
@ -115,7 +116,7 @@ class _KycDetailsListState extends ConsumerState<KycDetailsList> {
"Personal Details",
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontFamily: "Gilroy",
fontWeight: FontWeight
.w400, // equivalent to 400 (Normal)
fontStyle: FontStyle.normal,
@ -181,7 +182,7 @@ class _KycDetailsListState extends ConsumerState<KycDetailsList> {
'Edit',
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontFamily: "Gilroy",
fontWeight: FontWeight.w600,
fontStyle: FontStyle.normal,
fontSize: 16,
@ -277,9 +278,8 @@ class _KycDetailsListState extends ConsumerState<KycDetailsList> {
children: [
Text(
title,
style: const TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontSize: 14,
height: 1.3,
letterSpacing: 0.64,
@ -291,9 +291,8 @@ class _KycDetailsListState extends ConsumerState<KycDetailsList> {
value,
softWrap: true,
overflow: TextOverflow.visible,
style: const TextStyle(
fontFamily: 'Gilroy-Regular',
fontWeight: FontWeight.w400,
style: AppTextStyles.regular.copyWith(
fontSize: 14,
height: 1.3,
letterSpacing: 0.64,
@ -342,9 +341,9 @@ class _KycDetailsListState extends ConsumerState<KycDetailsList> {
maxLines: 1,
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.center,
style: const TextStyle(
fontFamily: 'Roboto',
fontWeight: FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontSize: 13,
),
),

View File

@ -1,6 +1,7 @@
import 'dart:math' as math show sqrt;
import 'package:flutter/material.dart';
import 'package:taxglide/consts/app_style.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:get/get.dart';
import 'package:taxglide/consts/app_asstes.dart';
@ -28,6 +29,7 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
@override
void initState() {
super.initState();
selectedItem = 'profile'; // Set default selection
_loadRole(); // <-- load role on start
}
@ -104,10 +106,9 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
data!.companyName!.isNotEmpty)
? data.companyName![0].toUpperCase()
: "M",
style: const TextStyle(
style: AppTextStyles.bold.copyWith(
color: Colors.white,
fontSize: 40,
fontWeight: FontWeight.bold,
),
),
),
@ -120,9 +121,7 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
const SizedBox(height: 60),
Text(
data?.companyName ?? 'No Company Name',
style: const TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontSize: 20,
color: Colors.black,
),
@ -271,21 +270,17 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text(
Text(
"Note",
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontSize: 20,
color: Colors.black,
),
),
const Text(
Text(
"Are you sure you want to log out?",
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w500,
style: AppTextStyles.medium.copyWith(
fontSize: 15,
color: Colors.black87,
),
@ -295,13 +290,11 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
children: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text(
child: Text(
"Cancel",
style: TextStyle(
color: Color(0xFF535A5B),
style: AppTextStyles.semiBold.copyWith(
color: const Color(0xFF535A5B),
fontSize: 16,
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
),
),
),
@ -344,13 +337,11 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
color: Color(0xFF5F297B),
),
)
: const Text(
: Text(
"Log Out",
style: TextStyle(
color: Color(0xFF5F297B),
style: AppTextStyles.semiBold.copyWith(
color: const Color(0xFF5F297B),
fontSize: 16,
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
),
),
),
@ -411,10 +402,8 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
Expanded(
child: Text(
title,
style: const TextStyle(
fontFamily: 'Gilroy-Medium',
style: AppTextStyles.medium.copyWith(
fontSize: 16,
fontWeight: FontWeight.w500,
color: Colors.black87,
),
),
@ -445,7 +434,7 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
Expanded(
child: Text(
msg,
style: const TextStyle(color: Colors.white, fontSize: 12),
style: AppTextStyles.regular.copyWith(color: Colors.white, fontSize: 12),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),

View File

@ -16,7 +16,7 @@ class _StaffListScreenState extends ConsumerState<StaffListScreen> {
final staffAsync = ref.watch(staffListProvider);
const commonTextStyle = TextStyle(
fontFamily: "Gilroy-SemiBold",
fontFamily: "Gilroy",
fontWeight: FontWeight.w600,
fontSize: 14.7,
height: 1.30, // 130%
@ -24,7 +24,7 @@ class _StaffListScreenState extends ConsumerState<StaffListScreen> {
color: Color(0xFF111827),
);
const commonTextStylevalue = TextStyle(
fontFamily: "Gilroy-SemiBold",
fontFamily: "Gilroy",
fontWeight: FontWeight.w400,
fontSize: 14.7,
height: 1.30, // 130%

View File

@ -7,6 +7,7 @@ import 'package:permission_handler/permission_handler.dart';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:file_picker/file_picker.dart';
import 'package:path/path.dart' as path;
import 'package:taxglide/consts/app_style.dart';
import 'package:taxglide/consts/comman_button.dart';
import 'package:taxglide/consts/responsive_helper.dart';
import 'package:taxglide/controller/api_contoller.dart';
@ -71,7 +72,7 @@ class _ServiceRequestScreenState extends ConsumerState<ServiceRequestScreen> {
Expanded(
child: Text(
msg,
style: const TextStyle(color: Colors.white, fontSize: 12),
style: AppTextStyles.regular.copyWith(color: Colors.white, fontSize: 12),
overflow: TextOverflow.ellipsis,
maxLines: 2,
),
@ -89,11 +90,11 @@ class _ServiceRequestScreenState extends ConsumerState<ServiceRequestScreen> {
});
bool isValid = true;
if (_selectedFiles.isEmpty) {
setState(() => _isFileError = true);
_showSnackBar("Please upload at least one file", isError: true);
isValid = false;
}
// if (_selectedFiles.isEmpty) {
// setState(() => _isFileError = true);
// _showSnackBar("Please upload at least one file", isError: true);
// isValid = false;
// }
if (!_isTermsAccepted) {
setState(() => _isCheckboxError = true);
_showSnackBar("Please accept terms and conditions", isError: true);
@ -374,9 +375,7 @@ class _ServiceRequestScreenState extends ConsumerState<ServiceRequestScreen> {
children: [
Text(
"New Service Request",
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontSize: headerFontSize,
color: const Color(0xFF111827),
),
@ -424,9 +423,7 @@ class _ServiceRequestScreenState extends ConsumerState<ServiceRequestScreen> {
SizedBox(height: spacingMD),
Text(
widget.service,
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontSize: serviceNameFontSize,
color: const Color(0xFF3F3F3F),
),
@ -454,10 +451,8 @@ class _ServiceRequestScreenState extends ConsumerState<ServiceRequestScreen> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"File Upload *",
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
"File Upload",
style: AppTextStyles.semiBold.copyWith(
fontSize: labelFontSize,
color: const Color(0xFF111827),
),
@ -527,9 +522,7 @@ class _ServiceRequestScreenState extends ConsumerState<ServiceRequestScreen> {
Expanded(
child: Text(
"I accept the terms and conditions *",
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontStyle: FontStyle.normal,
fontSize: checkboxFontSize,
height: 25.56 / 12.78,
@ -556,7 +549,7 @@ class _ServiceRequestScreenState extends ConsumerState<ServiceRequestScreen> {
),
),
const SizedBox(height: 250),
SizedBox(height: r.spacing(mobile: 40, tablet: 60, desktop: 80)),
],
),
),
@ -568,9 +561,7 @@ class _ServiceRequestScreenState extends ConsumerState<ServiceRequestScreen> {
padding: EdgeInsets.symmetric(horizontal: hPadding),
child: Text(
title,
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontSize: fontSize,
color: const Color(0xFF111827),
),
@ -597,9 +588,7 @@ class _ServiceRequestScreenState extends ConsumerState<ServiceRequestScreen> {
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 21),
child: Text(
text,
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontSize: fontSize,
color: const Color(0xFF3F3F3F),
),
@ -619,8 +608,8 @@ class _ServiceRequestScreenState extends ConsumerState<ServiceRequestScreen> {
color: Colors.white,
borderRadius: BorderRadius.circular(6),
border: Border.all(
color: _isFileError ? Colors.red : const Color(0xFFDFDFDF),
width: _isFileError ? 2 : 1,
color: const Color(0xFFDFDFDF),
width: 1,
),
),
padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 21),
@ -628,34 +617,22 @@ class _ServiceRequestScreenState extends ConsumerState<ServiceRequestScreen> {
children: [
Text(
"Upload PDF, IMG, JPG, ZIP",
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontSize: fontSize,
height: 25.56 / 12.78,
letterSpacing: 0.8,
color: _isFileError ? Colors.red : const Color(0xFF4F4C4C),
color: const Color(0xFF4F4C4C),
),
),
Text(
"(40 MB only allowed File)",
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontSize: subFontSize,
height: 25.56 / 12.78,
letterSpacing: 0.8,
color: _isFileError ? Colors.red : const Color(0xFF4F4C4C),
color: const Color(0xFF4F4C4C),
),
),
if (_isFileError)
const Padding(
padding: EdgeInsets.only(top: 8),
child: Text(
"Please upload at least one file",
style: TextStyle(color: Colors.red, fontSize: 11),
),
),
],
),
),
@ -705,9 +682,7 @@ class _ServiceRequestScreenState extends ConsumerState<ServiceRequestScreen> {
const SizedBox(width: 8),
Text(
"Uploaded Files (${_selectedFiles.length})",
style: TextStyle(
fontFamily: 'Gilroy-SemiBold',
fontWeight: FontWeight.w600,
style: AppTextStyles.semiBold.copyWith(
fontSize: countFontSize,
color: const Color(0xFF111827),
),
@ -894,8 +869,7 @@ class _ServiceRequestScreenState extends ConsumerState<ServiceRequestScreen> {
controller: _messageController,
maxLines: null,
expands: true,
style: TextStyle(
fontFamily: 'Gilroy-Medium',
style: AppTextStyles.regular.copyWith(
fontSize: fontSize,
color: const Color(0xFF6C7278),
),

View File

@ -5,10 +5,10 @@ packages:
dependency: transitive
description:
name: _fe_analyzer_shared
sha256: "8d7ff3948166b8ec5da0fbb5962000926b8e02f2ed9b3e51d1738905fbd4c98d"
sha256: da0d9209ca76bde579f2da330aeb9df62b6319c834fa7baae052021b0462401f
url: "https://pub.dev"
source: hosted
version: "93.0.0"
version: "85.0.0"
_flutterfire_internals:
dependency: transitive
description:
@ -21,10 +21,10 @@ packages:
dependency: transitive
description:
name: analyzer
sha256: de7148ed2fcec579b19f122c1800933dfa028f6d9fd38a152b04b1516cec120b
sha256: "974859dc0ff5f37bc4313244b3218c791810d03ab3470a579580279ba971a48d"
url: "https://pub.dev"
source: hosted
version: "10.0.1"
version: "7.7.1"
animated_notch_bottom_bar:
dependency: "direct main"
description:
@ -101,10 +101,10 @@ packages:
dependency: transitive
description:
name: characters
sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b
sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803
url: "https://pub.dev"
source: hosted
version: "1.4.1"
version: "1.4.0"
checked_yaml:
dependency: transitive
description:
@ -185,6 +185,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.8"
curved_labeled_navigation_bar:
dependency: "direct main"
description:
name: curved_labeled_navigation_bar
sha256: "936d8a34128478498e330588dbed3fdd7a6cc55ebada6e67340c080387e1a37e"
url: "https://pub.dev"
source: hosted
version: "2.0.6"
dbus:
dependency: transitive
description:
@ -708,26 +716,26 @@ packages:
dependency: transitive
description:
name: matcher
sha256: "12956d0ad8390bbcc63ca2e1469c0619946ccb52809807067a7020d57e647aa6"
sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2
url: "https://pub.dev"
source: hosted
version: "0.12.18"
version: "0.12.17"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b"
sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
url: "https://pub.dev"
source: hosted
version: "0.13.0"
version: "0.11.1"
meta:
dependency: transitive
description:
name: meta
sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394"
sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c
url: "https://pub.dev"
source: hosted
version: "1.17.0"
version: "1.16.0"
mime:
dependency: transitive
description:
@ -1113,26 +1121,26 @@ packages:
dependency: transitive
description:
name: test
sha256: "54c516bbb7cee2754d327ad4fca637f78abfc3cbcc5ace83b3eda117e42cd71a"
sha256: "65e29d831719be0591f7b3b1a32a3cda258ec98c58c7b25f7b84241bc31215bb"
url: "https://pub.dev"
source: hosted
version: "1.29.0"
version: "1.26.2"
test_api:
dependency: transitive
description:
name: test_api
sha256: "93167629bfc610f71560ab9312acdda4959de4df6fac7492c89ff0d3886f6636"
sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00"
url: "https://pub.dev"
source: hosted
version: "0.7.9"
version: "0.7.6"
test_core:
dependency: transitive
description:
name: test_core
sha256: "394f07d21f0f2255ec9e3989f21e54d3c7dc0e6e9dbce160e5a9c1a6be0e2943"
sha256: "80bf5a02b60af04b09e14f6fe68b921aad119493e26e490deaca5993fef1b05a"
url: "https://pub.dev"
source: hosted
version: "0.6.15"
version: "0.6.11"
timezone:
dependency: transitive
description:
@ -1149,6 +1157,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.4.0"
universal_io:
dependency: transitive
description:
name: universal_io
sha256: f63cbc48103236abf48e345e07a03ce5757ea86285ed313a6a032596ed9301e2
url: "https://pub.dev"
source: hosted
version: "2.3.1"
url_launcher:
dependency: "direct main"
description:

View File

@ -39,6 +39,7 @@ dependencies:
gal: ^2.3.2
web_socket_channel: ^3.0.2
flutter_local_notifications: ^18.0.1
curved_labeled_navigation_bar: ^2.0.6
@ -69,55 +70,39 @@ flutter:
fonts:
# =========================
# Gilroy Font Family
# =========================
- family: Gilroy
fonts:
- asset: assets/fonts/Gilroy-Thin.ttf
weight: 100
- asset: assets/fonts/Gilroy-ThinItalic.ttf
weight: 100
style: italic
- asset: assets/fonts/Gilroy-UltraLight.ttf
weight: 200
- asset: assets/fonts/Gilroy-UltraLightItalic.ttf
weight: 200
style: italic
- asset: assets/fonts/Gilroy-Light.ttf
weight: 300
- asset: assets/fonts/Gilroy-LightItalic.ttf
weight: 300
style: italic
- asset: assets/fonts/Gilroy-Regular.ttf
weight: 400
- asset: assets/fonts/Gilroy-RegularItalic.ttf
weight: 400
style: italic
- family: Gilroy-Thin
fonts:
- asset: assets/fonts/Gilroy-Thin.ttf
- family: Gilroy-UltraLight
fonts:
- asset: assets/fonts/Gilroy-UltraLight.ttf
- family: Gilroy-Light
fonts:
- asset: assets/fonts/Gilroy-Light.ttf
- family: Gilroy-Regular
fonts:
- asset: assets/fonts/Gilroy-Regular.ttf
- family: Gilroy-Medium
fonts:
- asset: assets/fonts/Gilroy-Medium.ttf
weight: 500
- asset: assets/fonts/Gilroy-MediumItalic.ttf
weight: 500
style: italic
- family: Gilroy-SemiBold
fonts:
- asset: assets/fonts/Gilroy-SemiBold.ttf
weight: 600
- asset: assets/fonts/Gilroy-SemiBoldItalic.ttf
weight: 600
style: italic
- family: Gilroy-Bold
fonts:
- asset: assets/fonts/Gilroy-Bold.ttf
weight: 700
- asset: assets/fonts/Gilroy-BoldItalic.ttf
weight: 700
style: italic
- family: Gilroy-ExtraBold
fonts:
- asset: assets/fonts/Gilroy-ExtraBold.ttf
weight: 800
- asset: assets/fonts/Gilroy-ExtraBoldItalic.ttf
weight: 800
style: italic
- family: Gilroy-Black
fonts:
- asset: assets/fonts/Gilroy-Black.ttf
weight: 900
- asset: assets/fonts/Gilroy-BlackItalic.ttf
weight: 900
style: italic
- family: Gilroy-Heavy
fonts:
- asset: assets/fonts/Gilroy-Heavy.ttf
weight: 900
- asset: assets/fonts/Gilroy-HeavyItalic.ttf
weight: 900
style: italic