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/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:image_picker/image_picker.dart'; import 'package:image_picker/image_picker.dart';

View File

@ -1,13 +1,14 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_animate/flutter_animate.dart'; import 'package:flutter_animate/flutter_animate.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
// ignore: depend_on_referenced_packages
import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:proxibuy/data/models/datasources/offer_data_source.dart'; import 'package:proxibuy/data/models/datasources/offer_data_source.dart';
import 'package:proxibuy/data/repositories/offer_repository.dart'; import 'package:proxibuy/data/repositories/offer_repository.dart';
import 'package:proxibuy/presentation/auth/bloc/auth_bloc.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_bloc.dart';
import 'package:proxibuy/presentation/notification_preferences/bloc/notification_preferences_event.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 'package:proxibuy/presentation/reservation/cubit/reservation_cubit.dart';
import 'core/config/app_colors.dart'; import 'core/config/app_colors.dart';
import 'presentation/pages/onboarding_page.dart'; import 'presentation/pages/onboarding_page.dart';
@ -98,6 +99,7 @@ class MyApp extends StatelessWidget {
), ),
), ),
labelStyle: const TextStyle(color: Colors.black), labelStyle: const TextStyle(color: Colors.black),
// ignore: deprecated_member_use
hintStyle: TextStyle(color: Colors.black.withOpacity(0.8)), hintStyle: TextStyle(color: Colors.black.withOpacity(0.8)),
), ),
outlinedButtonTheme: OutlinedButtonThemeData( outlinedButtonTheme: OutlinedButtonThemeData(

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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