finished ui/ux
This commit is contained in:
parent
15782a7d34
commit
61611fef04
|
|
@ -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';
|
||||||
|
|
|
||||||
|
|
@ -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(
|
||||||
|
|
|
||||||
|
|
@ -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';
|
||||||
|
|
||||||
|
|
@ -31,8 +33,6 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||||
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 {
|
||||||
|
|
|
||||||
|
|
@ -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';
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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),
|
||||||
|
|
|
||||||
|
|
@ -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,18 +33,66 @@ 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(onPressed: () {}, icon: Assets.icons.notification.svg()),
|
||||||
|
BlocBuilder<ReservationCubit, ReservationState>(
|
||||||
|
builder: (context, state) {
|
||||||
|
final reservedCount = state.reservedProductIds.length;
|
||||||
|
|
||||||
|
return Stack(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
children: [
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
// TODO: Navigate to notifications page
|
Navigator.of(context).push(
|
||||||
},
|
MaterialPageRoute(
|
||||||
icon: Assets.icons.notification.svg(),
|
builder: (_) => const ReservedListPage(),
|
||||||
),
|
),
|
||||||
IconButton(
|
);
|
||||||
onPressed: () {
|
|
||||||
// TODO: Navigate to QR codes page
|
|
||||||
},
|
},
|
||||||
icon: Assets.icons.scanBarcode.svg(),
|
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,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
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,6 +155,7 @@ class NotificationPreferencesPage extends StatelessWidget {
|
||||||
final itemHeight = itemWidth / childAspectRatio;
|
final itemHeight = itemWidth / childAspectRatio;
|
||||||
|
|
||||||
return SingleChildScrollView(
|
return SingleChildScrollView(
|
||||||
|
child: Center(
|
||||||
child: Wrap(
|
child: Wrap(
|
||||||
alignment: WrapAlignment.center,
|
alignment: WrapAlignment.center,
|
||||||
spacing: crossAxisSpacing,
|
spacing: crossAxisSpacing,
|
||||||
|
|
@ -114,8 +165,9 @@ class NotificationPreferencesPage extends StatelessWidget {
|
||||||
final isSelected = state.selectedCategoryIds
|
final isSelected = state.selectedCategoryIds
|
||||||
.contains(category.id);
|
.contains(category.id);
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
width: itemWidth,
|
width: 100,
|
||||||
height: itemHeight,
|
height: itemHeight,
|
||||||
|
child: Center(
|
||||||
child: CategorySelectionCard(
|
child: CategorySelectionCard(
|
||||||
name: category.name,
|
name: category.name,
|
||||||
icon: category.icon,
|
icon: category.icon,
|
||||||
|
|
@ -126,13 +178,17 @@ class NotificationPreferencesPage extends StatelessWidget {
|
||||||
context
|
context
|
||||||
.read<NotificationPreferencesBloc>()
|
.read<NotificationPreferencesBloc>()
|
||||||
.add(
|
.add(
|
||||||
ToggleCategorySelection(category.id),
|
ToggleCategorySelection(
|
||||||
|
category.id,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}).toList(),
|
}).toList(),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
@ -212,7 +268,7 @@ class NotificationPreferencesPage extends StatelessWidget {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
const SizedBox(height: 40),
|
const SizedBox(height: 20),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -170,7 +170,8 @@ class _OffersPageState extends State<OffersPage> {
|
||||||
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(),
|
||||||
|
|
@ -179,12 +180,23 @@ class _OffersPageState extends State<OffersPage> {
|
||||||
Positioned(
|
Positioned(
|
||||||
top: 0,
|
top: 0,
|
||||||
right: 2,
|
right: 2,
|
||||||
|
child: GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
Navigator.of(context).push(
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (_) => const ReservedListPage(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: const EdgeInsets.all(4),
|
padding: const EdgeInsets.all(4),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.green,
|
color: Colors.green,
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
border: Border.all(color: Colors.white, width: 1.5),
|
border: Border.all(
|
||||||
|
color: Colors.white,
|
||||||
|
width: 1.5,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
constraints: const BoxConstraints(
|
constraints: const BoxConstraints(
|
||||||
minWidth: 18,
|
minWidth: 18,
|
||||||
|
|
@ -204,6 +216,7 @@ class _OffersPageState extends State<OffersPage> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
),
|
),
|
||||||
SizedBox(height: 15,),
|
),
|
||||||
|
const TextSpan(text: ' ارسال شد.',style: TextStyle(fontSize: 15)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
textDirection: TextDirection.rtl, // جهت متن برای RichText
|
||||||
|
),
|
||||||
|
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,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -156,11 +171,15 @@ class _OtpPageState extends State<OtpPage> {
|
||||||
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:
|
||||||
|
(context, seconds, child) => Text(
|
||||||
"${_otpTimer.formatTime()} تا دریافت مجدد",
|
"${_otpTimer.formatTime()} تا دریافت مجدد",
|
||||||
style: const TextStyle(color: Colors.grey),
|
style: const TextStyle(color: Colors.grey),
|
||||||
),
|
),
|
||||||
|
|
@ -202,7 +221,8 @@ class _OtpPageState extends State<OtpPage> {
|
||||||
enabledBorder: OutlineInputBorder(
|
enabledBorder: OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
borderSide: BorderSide(
|
borderSide: BorderSide(
|
||||||
color: _hasError
|
color:
|
||||||
|
_hasError
|
||||||
? Colors.red
|
? Colors.red
|
||||||
: (Theme.of(context)
|
: (Theme.of(context)
|
||||||
.inputDecorationTheme
|
.inputDecorationTheme
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,8 @@ 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(
|
||||||
|
child: Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 32.0),
|
padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 32.0),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
|
@ -104,6 +105,7 @@ class _ReservationConfirmationPageState extends State<ReservationConfirmationPag
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -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(
|
||||||
|
|
|
||||||
|
|
@ -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),
|
||||||
|
|
|
||||||
|
|
@ -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(
|
||||||
"رد شدن",
|
"رد شدن",
|
||||||
|
|
|
||||||
|
|
@ -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';
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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(
|
||||||
|
|
|
||||||
|
|
@ -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),
|
||||||
|
|
|
||||||
|
|
@ -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),
|
||||||
|
|
|
||||||
|
|
@ -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');
|
||||||
|
|
|
||||||
|
|
@ -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';
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue