finished ui/ux

This commit is contained in:
mohamadmahdi jebeli 2025-07-02 16:58:01 +03:30
parent 15782a7d34
commit 61611fef04
22 changed files with 283 additions and 171 deletions

View File

@ -1,4 +1,3 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:image_picker/image_picker.dart';

View File

@ -1,13 +1,14 @@
import 'package:flutter/material.dart';
import 'package:flutter_animate/flutter_animate.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
// ignore: depend_on_referenced_packages
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:proxibuy/data/models/datasources/offer_data_source.dart';
import 'package:proxibuy/data/repositories/offer_repository.dart';
import 'package:proxibuy/presentation/auth/bloc/auth_bloc.dart';
import 'package:proxibuy/presentation/notification_preferences/bloc/notification_preferences_bloc.dart';
import 'package:proxibuy/presentation/notification_preferences/bloc/notification_preferences_event.dart';
import 'package:proxibuy/presentation/offer/bloc/offer_bloc.dart'; // مسیر BLoC آفر
import 'package:proxibuy/presentation/offer/bloc/offer_bloc.dart';
import 'package:proxibuy/presentation/reservation/cubit/reservation_cubit.dart';
import 'core/config/app_colors.dart';
import 'presentation/pages/onboarding_page.dart';
@ -98,6 +99,7 @@ class MyApp extends StatelessWidget {
),
),
labelStyle: const TextStyle(color: Colors.black),
// ignore: deprecated_member_use
hintStyle: TextStyle(color: Colors.black.withOpacity(0.8)),
),
outlinedButtonTheme: OutlinedButtonThemeData(

View File

@ -1,4 +1,6 @@
// ignore: depend_on_referenced_packages
import 'package:bloc/bloc.dart';
// ignore: depend_on_referenced_packages
import 'package:meta/meta.dart';
import 'dart:async';
@ -30,9 +32,7 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
on<SaveUserInfoEvent>((event, emit) async {
emit(AuthLoading());
await Future.delayed(const Duration(milliseconds: 500));
print('User info to save: Name: ${event.name}, Gender: ${event.gender}');
if (event.name.trim().isEmpty) {
emit(AuthFailure('لطفاً نام خود را وارد کنید.'));
} else {

View File

@ -1,3 +1,4 @@
// ignore: depend_on_referenced_packages
import 'package:bloc/bloc.dart';
import 'package:proxibuy/data/repositories/offer_repository.dart';
import 'package:proxibuy/presentation/offer/bloc/offer_event.dart';

View File

@ -80,6 +80,7 @@ class _OfferCardState extends State<OfferCard> {
),
boxShadow: [
BoxShadow(
// ignore: deprecated_member_use
color: Colors.grey.withOpacity(0.2),
spreadRadius: 2,
blurRadius: 5,

View File

@ -188,6 +188,7 @@ class AddPhotoScreen extends StatelessWidget {
),
boxShadow: [
BoxShadow(
// ignore: deprecated_member_use
color: Colors.black.withOpacity(0.08),
blurRadius: 10,
offset: const Offset(0, 4),
@ -321,6 +322,7 @@ class AddPhotoScreen extends StatelessWidget {
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
// ignore: deprecated_member_use
color: Colors.black.withOpacity(0.3),
blurRadius: 8,
offset: const Offset(0, 4),

View File

@ -8,6 +8,8 @@ import 'package:proxibuy/presentation/notification_preferences/bloc/notification
import 'package:proxibuy/presentation/offer/bloc/offer_bloc.dart';
import 'package:proxibuy/presentation/offer/bloc/offer_event.dart';
import 'package:proxibuy/presentation/pages/offers_page.dart';
import 'package:proxibuy/presentation/pages/reserved_list_page.dart';
import 'package:proxibuy/presentation/reservation/cubit/reservation_cubit.dart';
import 'package:proxibuy/presentation/widgets/category_selection_card.dart';
import 'package:shared_preferences/shared_preferences.dart';
@ -31,17 +33,65 @@ class NotificationPreferencesPage extends StatelessWidget {
child: Assets.icons.logoWithName.svg(height: 40, width: 200),
),
actions: [
IconButton(
onPressed: () {
// TODO: Navigate to notifications page
IconButton(onPressed: () {}, icon: Assets.icons.notification.svg()),
BlocBuilder<ReservationCubit, ReservationState>(
builder: (context, state) {
final reservedCount = state.reservedProductIds.length;
return Stack(
alignment: Alignment.center,
children: [
IconButton(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => const ReservedListPage(),
),
);
},
icon: Assets.icons.scanBarcode.svg(),
),
if (reservedCount > 0)
Positioned(
top: 0,
right: 2,
child: GestureDetector(
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => const ReservedListPage(),
),
);
},
child: Container(
padding: const EdgeInsets.all(4),
decoration: BoxDecoration(
color: Colors.green,
shape: BoxShape.circle,
border: Border.all(color: Colors.white, width: 1.5),
),
constraints: const BoxConstraints(
minWidth: 18,
minHeight: 18,
),
child: Padding(
padding: const EdgeInsets.fromLTRB(2, 4, 2, 2),
child: Text(
'$reservedCount',
style: const TextStyle(
color: Colors.white,
fontSize: 11,
fontWeight: FontWeight.bold,
),
textAlign: TextAlign.center,
),
),
),
),
),
],
);
},
icon: Assets.icons.notification.svg(),
),
IconButton(
onPressed: () {
// TODO: Navigate to QR codes page
},
icon: Assets.icons.scanBarcode.svg(),
),
const SizedBox(width: 8),
],
@ -73,7 +123,7 @@ class NotificationPreferencesPage extends StatelessWidget {
TextSpan(
text:
'ترجیح می‌دی از کدام دسته‌بندی‌ها اعلان تخفیف دریافت کنی؟ ',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 14),
),
TextSpan(text: '(حداقل یک مورد رو انتخاب کن).'),
],
@ -105,33 +155,39 @@ class NotificationPreferencesPage extends StatelessWidget {
final itemHeight = itemWidth / childAspectRatio;
return SingleChildScrollView(
child: Wrap(
alignment: WrapAlignment.center,
spacing: crossAxisSpacing,
runSpacing: mainAxisSpacing,
children:
state.categories.map((category) {
final isSelected = state.selectedCategoryIds
.contains(category.id);
return SizedBox(
width: itemWidth,
height: itemHeight,
child: CategorySelectionCard(
name: category.name,
icon: category.icon,
isSelected: isSelected,
showSelectableIndicator:
state.selectedCategoryIds.isNotEmpty,
onTap: () {
context
.read<NotificationPreferencesBloc>()
.add(
ToggleCategorySelection(category.id),
);
},
),
);
}).toList(),
child: Center(
child: Wrap(
alignment: WrapAlignment.center,
spacing: crossAxisSpacing,
runSpacing: mainAxisSpacing,
children:
state.categories.map((category) {
final isSelected = state.selectedCategoryIds
.contains(category.id);
return SizedBox(
width: 100,
height: itemHeight,
child: Center(
child: CategorySelectionCard(
name: category.name,
icon: category.icon,
isSelected: isSelected,
showSelectableIndicator:
state.selectedCategoryIds.isNotEmpty,
onTap: () {
context
.read<NotificationPreferencesBloc>()
.add(
ToggleCategorySelection(
category.id,
),
);
},
),
),
);
}).toList(),
),
),
);
},
@ -212,7 +268,7 @@ class NotificationPreferencesPage extends StatelessWidget {
);
},
),
const SizedBox(height: 40),
const SizedBox(height: 20),
],
),
),

View File

@ -158,58 +158,71 @@ class _OffersPageState extends State<OffersPage> {
child: Assets.icons.logoWithName.svg(height: 40, width: 200),
),
actions: [
IconButton(onPressed: () {}, icon: Assets.icons.notification.svg()),
BlocBuilder<ReservationCubit, ReservationState>(
builder: (context, state) {
final reservedCount = state.reservedProductIds.length;
IconButton(onPressed: () {}, icon: Assets.icons.notification.svg()),
BlocBuilder<ReservationCubit, ReservationState>(
builder: (context, state) {
final reservedCount = state.reservedProductIds.length;
return Stack(
alignment: Alignment.center,
children: [
IconButton(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => const ReservedListPage()),
);
},
icon: Assets.icons.scanBarcode.svg(),
),
if (reservedCount > 0)
Positioned(
top: 0,
right: 2,
child: Container(
padding: const EdgeInsets.all(4),
decoration: BoxDecoration(
color: Colors.green,
shape: BoxShape.circle,
border: Border.all(color: Colors.white, width: 1.5),
),
constraints: const BoxConstraints(
minWidth: 18,
minHeight: 18,
),
child: Padding(
padding: const EdgeInsets.fromLTRB(2, 4, 2, 2),
child: Text(
'$reservedCount',
style: const TextStyle(
color: Colors.white,
fontSize: 11,
fontWeight: FontWeight.bold,
return Stack(
alignment: Alignment.center,
children: [
IconButton(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => const ReservedListPage(),
),
);
},
icon: Assets.icons.scanBarcode.svg(),
),
if (reservedCount > 0)
Positioned(
top: 0,
right: 2,
child: GestureDetector(
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => const ReservedListPage(),
),
);
},
child: Container(
padding: const EdgeInsets.all(4),
decoration: BoxDecoration(
color: Colors.green,
shape: BoxShape.circle,
border: Border.all(
color: Colors.white,
width: 1.5,
),
),
constraints: const BoxConstraints(
minWidth: 18,
minHeight: 18,
),
child: Padding(
padding: const EdgeInsets.fromLTRB(2, 4, 2, 2),
child: Text(
'$reservedCount',
style: const TextStyle(
color: Colors.white,
fontSize: 11,
fontWeight: FontWeight.bold,
),
textAlign: TextAlign.center,
),
),
textAlign: TextAlign.center,
),
),
),
),
],
);
},
),
const SizedBox(width: 8),
],
],
);
},
),
const SizedBox(width: 8),
],
),
body: SingleChildScrollView(
child: Column(

View File

@ -157,12 +157,11 @@ class _OnboardingPageState extends State<OnboardingPage> {
),
),),
Positioned(
bottom: 85,
bottom: 90,
left: 24,
right: 24,
child: Column(
children: [
const SizedBox(height: 40),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -173,7 +172,7 @@ class _OnboardingPageState extends State<OnboardingPage> {
context,
).textTheme.headlineSmall?.copyWith(
fontWeight: FontWeight.bold,
fontSize: 20,
fontSize: 18,
color:
Colors.white
),
@ -183,7 +182,9 @@ class _OnboardingPageState extends State<OnboardingPage> {
onboardingPages[_currentPage].description,
textAlign: TextAlign.right,
style: Theme.of(context).textTheme.bodyLarge?.copyWith(
// ignore: deprecated_member_use
color: Colors.white.withOpacity(0.8),
fontSize: 16,
height: 1.5,
),
),

View File

@ -1,4 +1,3 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/svg.dart';
@ -18,8 +17,10 @@ class OtpPage extends StatefulWidget {
class _OtpPageState extends State<OtpPage> {
final List<FocusNode> _focusNodes = List.generate(5, (_) => FocusNode());
final List<TextEditingController> _controllers =
List.generate(5, (_) => TextEditingController());
final List<TextEditingController> _controllers = List.generate(
5,
(_) => TextEditingController(),
);
late final OtpTimerHelper _otpTimer;
bool _hasError = false;
@ -54,7 +55,6 @@ class _OtpPageState extends State<OtpPage> {
return Directionality(
textDirection: TextDirection.rtl,
child: Scaffold(
appBar: AppBar(backgroundColor: Colors.transparent, elevation: 0),
body: SafeArea(
child: SingleChildScrollView(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
@ -70,14 +70,28 @@ class _OtpPageState extends State<OtpPage> {
),
),
const SizedBox(height: 12),
Text(
"کد تایید به شماره ${widget.phoneNumber} ارسال شد.",
style: textTheme.titleMedium?.copyWith(
color: Colors.grey,
height: 1.5,
Text.rich(
TextSpan(
style: textTheme.titleMedium?.copyWith(
color: Colors.grey,
height: 1.5,
),
children: <TextSpan>[
const TextSpan(text: 'کد تایید به شماره ',style: TextStyle(fontSize: 15)),
TextSpan(
text: widget.phoneNumber,
style: const TextStyle(
fontWeight:
FontWeight.bold,
fontSize: 15
),
),
const TextSpan(text: ' ارسال شد.',style: TextStyle(fontSize: 15)),
],
),
textDirection: TextDirection.rtl, // جهت متن برای RichText
),
SizedBox(height: 15,),
SizedBox(height: 15),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
@ -85,7 +99,10 @@ class _OtpPageState extends State<OtpPage> {
const SizedBox(width: 4),
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: const Text("ویرایش شماره همراه",style: TextStyle(color: AppColors.active),),
child: const Text(
"ویرایش شماره همراه",
style: TextStyle(color: AppColors.active),
),
),
],
),
@ -118,9 +135,7 @@ class _OtpPageState extends State<OtpPage> {
}
if (state is AuthVerified) {
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(
builder: (_) => const UserInfoPage(),
),
MaterialPageRoute(builder: (_) => const UserInfoPage()),
(route) => false,
);
}
@ -155,16 +170,20 @@ class _OtpPageState extends State<OtpPage> {
builder: (context, canResend, child) {
return canResend
? TextButton(
onPressed: _resendOtp,
child: const Text("ارسال مجدد کد",style: TextStyle(color: AppColors.active),),
)
onPressed: _resendOtp,
child: const Text(
"ارسال مجدد کد",
style: TextStyle(color: AppColors.active),
),
)
: ValueListenableBuilder<int>(
valueListenable: _otpTimer.remainingSeconds,
builder: (context, seconds, child) => Text(
"${_otpTimer.formatTime()} تا دریافت مجدد",
style: const TextStyle(color: Colors.grey),
),
);
valueListenable: _otpTimer.remainingSeconds,
builder:
(context, seconds, child) => Text(
"${_otpTimer.formatTime()} تا دریافت مجدد",
style: const TextStyle(color: Colors.grey),
),
);
},
),
],
@ -202,14 +221,15 @@ class _OtpPageState extends State<OtpPage> {
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(
color: _hasError
? Colors.red
: (Theme.of(context)
.inputDecorationTheme
.enabledBorder
?.borderSide
.color ??
Colors.grey),
color:
_hasError
? Colors.red
: (Theme.of(context)
.inputDecorationTheme
.enabledBorder
?.borderSide
.color ??
Colors.grey),
),
),
focusedBorder: OutlineInputBorder(
@ -264,4 +284,4 @@ class _OtpPageState extends State<OtpPage> {
context.read<AuthBloc>().add(SendOTPEvent(phoneNumber: widget.phoneNumber));
_otpTimer.resetTimer();
}
}
}

View File

@ -263,6 +263,7 @@ class _ProductDetailViewState extends State<ProductDetailView> {
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
// ignore: deprecated_member_use
color: Colors.black.withOpacity(0.15),
blurRadius: 7,
spreadRadius: 0,

View File

@ -63,44 +63,46 @@ class _ReservationConfirmationPageState extends State<ReservationConfirmationPag
child: Scaffold(
backgroundColor: Colors.grey[50],
appBar: _buildCustomAppBar(context),
body: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 32.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'تخفیف ${widget.offer.discountType} رزرو شد!',
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.black87,
),
).animate().fadeIn(delay: 300.ms, duration: 500.ms).slideY(begin: -0.2, end: 0),
const SizedBox(height: 8),
const Divider(thickness: 1.5)
.animate()
.fadeIn(delay: 400.ms)
.scaleX(begin: 0, duration: 600.ms, curve: Curves.easeInOut),
const SizedBox(height: 18),
_buildOfferDetailsCard()
.animate()
.fadeIn(delay: 600.ms, duration: 500.ms)
.slideX(begin: 0.5, end: 0, curve: Curves.easeOutCubic),
const SizedBox(height: 18),
_buildTimerCard()
.animate()
.fadeIn(delay: 800.ms, duration: 500.ms)
.scale(begin: const Offset(0.8, 0.8), curve: Curves.easeOutBack),
const SizedBox(height: 18),
_buildQrCodeCard()
.animate()
.fadeIn(delay: 1000.ms, duration: 500.ms)
.flipV(begin: -0.5, end: 0, curve: Curves.easeOut),
],
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 32.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'تخفیف ${widget.offer.discountType} رزرو شد!',
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.black87,
),
).animate().fadeIn(delay: 300.ms, duration: 500.ms).slideY(begin: -0.2, end: 0),
const SizedBox(height: 8),
const Divider(thickness: 1.5)
.animate()
.fadeIn(delay: 400.ms)
.scaleX(begin: 0, duration: 600.ms, curve: Curves.easeInOut),
const SizedBox(height: 18),
_buildOfferDetailsCard()
.animate()
.fadeIn(delay: 600.ms, duration: 500.ms)
.slideX(begin: 0.5, end: 0, curve: Curves.easeOutCubic),
const SizedBox(height: 18),
_buildTimerCard()
.animate()
.fadeIn(delay: 800.ms, duration: 500.ms)
.scale(begin: const Offset(0.8, 0.8), curve: Curves.easeOutBack),
const SizedBox(height: 18),
_buildQrCodeCard()
.animate()
.fadeIn(delay: 1000.ms, duration: 500.ms)
.flipV(begin: -0.5, end: 0, curve: Curves.easeOut),
],
),
),
),
),
@ -118,6 +120,7 @@ class _ReservationConfirmationPageState extends State<ReservationConfirmationPag
),
boxShadow: [
BoxShadow(
// ignore: deprecated_member_use
color: Colors.black.withOpacity(0.08),
blurRadius: 10,
offset: const Offset(0, 4),
@ -216,6 +219,7 @@ class _ReservationConfirmationPageState extends State<ReservationConfirmationPag
const SizedBox(height: 10),
Row(
children: [
// ignore: deprecated_member_use
SvgPicture.asset(Assets.icons.cardPos.path,height: 22,color: Color.fromARGB(255, 157, 157, 155),),
SizedBox(width: 6,),
Text(

View File

@ -119,6 +119,7 @@ class _ReservedListPageState extends State<ReservedListPage> {
),
boxShadow: [
BoxShadow(
// ignore: deprecated_member_use
color: Colors.black.withOpacity(0.08),
blurRadius: 10,
offset: const Offset(0, 4),

View File

@ -76,6 +76,7 @@ class _UserInfoPageState extends State<UserInfoPage> {
width: 50,
height: 5,
decoration: BoxDecoration(
// ignore: deprecated_member_use
color:Colors.grey.withOpacity(0.5),
borderRadius: BorderRadius.circular(12),
),
@ -113,7 +114,7 @@ class _UserInfoPageState extends State<UserInfoPage> {
_buildGenderRadio('تمایلی به پاسخ ندارم', 'نامشخص'),
],
),
const SizedBox(height: 70),
const SizedBox(height: 55),
BlocConsumer<AuthBloc, AuthState>(
listener: (context, state) {
@ -154,7 +155,7 @@ class _UserInfoPageState extends State<UserInfoPage> {
Center(
child: TextButton(
onPressed: () {
Navigator.of(context).push(NotificationPreferencesPage.route());
Navigator.of(context).pushReplacement(NotificationPreferencesPage.route());
},
child: const Text(
"رد شدن",

View File

@ -1,3 +1,4 @@
// ignore: depend_on_referenced_packages
import 'package:bloc/bloc.dart';
import 'package:proxibuy/data/repositories/offer_repository.dart';
import 'package:proxibuy/presentation/product_detail/bloc/product_detail_event.dart';

View File

@ -1,3 +1,4 @@
// ignore: depend_on_referenced_packages
import 'package:bloc/bloc.dart';
part 'reservation_state.dart';
@ -10,10 +11,8 @@ class ReservationCubit extends Cubit<ReservationState> {
final updatedList = List<String>.from(state.reservedProductIds)..add(productId);
emit(state.copyWith(reservedProductIds: updatedList));
// در اینجا میتوانید لاگیک مربوط به ارسال درخواست به API را نیز اضافه کنید
}
// متد برای بررسی اینکه آیا یک محصول خاص رزرو شده است یا نه
bool isProductReserved(String productId) {
return state.reservedProductIds.contains(productId);
}

View File

@ -11,13 +11,13 @@ class CategorySelectionCard extends StatelessWidget {
final VoidCallback onTap;
const CategorySelectionCard({
Key? key,
super.key,
required this.name,
required this.icon,
required this.isSelected,
required this.showSelectableIndicator,
required this.onTap,
}) : super(key: key);
});
@override
Widget build(BuildContext context) {
@ -44,6 +44,7 @@ class CategorySelectionCard extends StatelessWidget {
boxShadow: isSelected
? [
BoxShadow(
// ignore: deprecated_member_use
color: AppColors.confirm.withOpacity(0.25),
blurRadius: 8,
spreadRadius: 2,

View File

@ -35,8 +35,9 @@ class PhotoGalleryView extends StatelessWidget {
child: Stack(
fit: StackFit.expand,
children: [
_buildSmartImage(imageUrl), // از ویجت هوشمند استفاده میکنیم
_buildSmartImage(imageUrl),
Container(
// ignore: deprecated_member_use
color: Colors.white.withOpacity(0.7),
child: Center(
child: Text(

View File

@ -8,6 +8,7 @@ Future<void> showGPSDialog(BuildContext context) async {
bool isLocationEnabled = await Geolocator.isLocationServiceEnabled();
if (!isLocationEnabled) {
await showDialog(
// ignore: use_build_context_synchronously
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
@ -67,6 +68,7 @@ Future<void> showGPSDialog(BuildContext context) async {
),
onPressed: () async {
await Geolocator.openLocationSettings();
// ignore: use_build_context_synchronously
Navigator.of(context).pop();
},
child: const Text(
@ -86,6 +88,7 @@ Future<void> showGPSDialog(BuildContext context) async {
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
// ignore: deprecated_member_use
color: Colors.black.withOpacity(0.3),
blurRadius: 8,
offset: const Offset(0, 4),

View File

@ -11,6 +11,7 @@ Future<void> showNotificationPermissionDialog(BuildContext context) async {
}
await showDialog(
// ignore: use_build_context_synchronously
context: context,
barrierDismissible: false,
builder: (BuildContext dialogContext) {
@ -77,6 +78,7 @@ Future<void> showNotificationPermissionDialog(BuildContext context) async {
final result =
await Permission.notification.request();
if (result.isGranted) {
// ignore: use_build_context_synchronously
Navigator.of(dialogContext).pop();
} else {
openAppSettings();
@ -99,6 +101,7 @@ Future<void> showNotificationPermissionDialog(BuildContext context) async {
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
// ignore: deprecated_member_use
color: Colors.black.withOpacity(0.3),
blurRadius: 8,
offset: const Offset(0, 4),

View File

@ -55,6 +55,7 @@ class _ReservedListItemCardState extends State<ReservedListItemCard> {
super.dispose();
}
// ignore: unused_element
String _formatDuration(Duration duration) {
if (duration.inSeconds <= 0) return "پایان یافته";
final hours = duration.inHours.toString().padLeft(2, '0');

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
// ignore: depend_on_referenced_packages
import 'package:intl/intl.dart' as intl;
import 'package:proxibuy/core/config/app_colors.dart';
import 'package:proxibuy/core/gen/assets.gen.dart';