fixed edit
This commit is contained in:
parent
6f6e34e391
commit
ae5b280ffa
|
|
@ -6,5 +6,5 @@ class ApiConfig {
|
|||
static const String updateCategories = "/user/favoriteCategory";
|
||||
static const String getFavoriteCategories = "/user/getfavoriteCategory";
|
||||
static const String addReservation = "/reservation/add";
|
||||
static const String getReservations = "/reservation/get"; // <-- این خط اضافه شد
|
||||
static const String getReservations = "/reservation/get";
|
||||
}
|
||||
|
|
@ -1,5 +1,3 @@
|
|||
// lib/core/config/http_overrides.dart
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
class MyHttpOverrides extends HttpOverrides {
|
||||
|
|
|
|||
|
|
@ -110,17 +110,15 @@ class OfferModel extends Equatable {
|
|||
final originalPriceValue = (json['Price'] as num?)?.toDouble() ?? 0.0;
|
||||
final finalPriceValue = (json['NPrice'] as num?)?.toDouble() ?? 0.0;
|
||||
|
||||
// ******** شروع تغییر ۱ ********
|
||||
// مدیریت هوشمند فاصله و عکسها از منابع مختلف
|
||||
final distanceFromServer = (json['distance'] as num?)?.round() ?? (json['Distance'] as num?)?.round() ?? 0;
|
||||
|
||||
List<String> images = [];
|
||||
if (json['imageData'] is List) { // برای سازگاری با پاسخ MQTT
|
||||
if (json['imageData'] is List) {
|
||||
images = (json['imageData'] as List<dynamic>)
|
||||
.map((imageData) => imageData['Url']?.toString() ?? '')
|
||||
.where((url) => url.isNotEmpty)
|
||||
.toList();
|
||||
} else if (json['Images'] is List) { // برای پاسخ جدید API رزرو
|
||||
} else if (json['Images'] is List) {
|
||||
images = (json['Images'] as List<dynamic>)
|
||||
.map((imageData) => (imageData is Map) ? imageData['Url']?.toString() ?? '' : '')
|
||||
.where((url) => url.isNotEmpty)
|
||||
|
|
@ -129,13 +127,12 @@ class OfferModel extends Equatable {
|
|||
|
||||
final typeData = json['typeData'] ?? json['Type'];
|
||||
final discountTypeName = (typeData is Map) ? typeData['Name']?.toString() : typeData?.toString();
|
||||
// ******** پایان تغییر ۱ ********
|
||||
|
||||
return OfferModel(
|
||||
id: json['ID'] ?? '',
|
||||
title: json['Name'] ?? 'بدون عنوان',
|
||||
discount: json['Description'] ?? '',
|
||||
imageUrls: images, // <-- استفاده از لیست جدید
|
||||
imageUrls: images,
|
||||
category: json['categoryData']?['Name']?.toString() ?? '',
|
||||
expiryTime: DateTime.tryParse(json['EndDate'] ?? '') ?? DateTime.now().add(const Duration(days: 1)),
|
||||
discountType: discountTypeName ?? '',
|
||||
|
|
@ -146,7 +143,7 @@ class OfferModel extends Equatable {
|
|||
latitude: shopData.latitude,
|
||||
longitude: shopData.longitude,
|
||||
features: shopData.properties,
|
||||
distanceInMeters: distanceFromServer, // <-- استفاده از متغیر جدید
|
||||
distanceInMeters: distanceFromServer,
|
||||
isOpen: checkIsOpen,
|
||||
workingHours: [],
|
||||
rating: 0.0,
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ 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/core/config/http_overrides.dart'; // این خط را اضافه کنید
|
||||
import 'package:proxibuy/core/config/http_overrides.dart';
|
||||
import 'package:proxibuy/firebase_options.dart';
|
||||
import 'package:proxibuy/presentation/auth/bloc/auth_bloc.dart';
|
||||
import 'package:proxibuy/presentation/notification_preferences/bloc/notification_preferences_bloc.dart';
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
|||
},
|
||||
);
|
||||
|
||||
if (isClosed) return; // FIX: Add check here
|
||||
if (isClosed) return;
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final accessToken = response.data['data']['accessToken'];
|
||||
|
|
@ -91,26 +91,23 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
|||
emit(AuthFailure(response.data['message'] ?? 'کد صحیح نیست'));
|
||||
}
|
||||
} on DioException catch (e) {
|
||||
if (isClosed) return; // FIX: Add check here
|
||||
if (isClosed) return;
|
||||
emit(AuthFailure(e.response?.data['message'] ?? 'خطایی در سرور رخ داد'));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onUpdateUserInfo(
|
||||
UpdateUserInfoEvent event, Emitter<AuthState> emit) async {
|
||||
// ******** لاگ ۱: شروع پردازش ********
|
||||
debugPrint("AuthBloc: 🔵 ایونت UpdateUserInfoEvent دریافت شد با نام: ${event.name}");
|
||||
emit(AuthLoading());
|
||||
try {
|
||||
final token = await _storage.read(key: 'accessToken');
|
||||
if (token == null) {
|
||||
// ******** لاگ خطا: توکن وجود ندارد ********
|
||||
debugPrint("AuthBloc: 🔴 خطا: توکن کاربر یافت نشد.");
|
||||
emit(const AuthFailure("شما وارد نشدهاید."));
|
||||
return;
|
||||
}
|
||||
|
||||
// ******** لاگ ۲: ارسال درخواست به سرور ********
|
||||
debugPrint("AuthBloc: 🟡 در حال ارسال درخواست آپدیت به سرور...");
|
||||
final response = await _dio.post(
|
||||
ApiConfig.baseUrl + ApiConfig.updateUser,
|
||||
|
|
@ -118,7 +115,6 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
|||
options: Options(headers: {'Authorization': 'Bearer $token'}),
|
||||
);
|
||||
|
||||
// ******** لاگ ۳: پاسخ سرور ********
|
||||
debugPrint("AuthBloc: 🟠 پاسخ سرور دریافت شد. StatusCode: ${response.statusCode}");
|
||||
|
||||
if (isClosed) {
|
||||
|
|
@ -127,16 +123,13 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
|||
}
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
// ******** لاگ ۴: موفقیتآمیز بودن عملیات ********
|
||||
debugPrint("AuthBloc: ✅ درخواست موفق بود. در حال emit کردن AuthSuccess...");
|
||||
emit(AuthSuccess());
|
||||
} else {
|
||||
// ******** لاگ خطا: پاسخ ناموفق از سرور ********
|
||||
debugPrint("AuthBloc: 🔴 سرور پاسخ ناموفق داد: ${response.data['message']}");
|
||||
emit(AuthFailure(response.data['message'] ?? 'خطا در ثبت اطلاعات'));
|
||||
}
|
||||
} on DioException catch (e) {
|
||||
// ******** لاگ خطا: خطای Dio ********
|
||||
debugPrint("AuthBloc: 🔴 خطای DioException رخ داد: ${e.response?.data['message']}");
|
||||
if (isClosed) return;
|
||||
emit(AuthFailure(e.response?.data['message'] ?? 'خطا در ارتباط با سرور'));
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ class NotificationPreferencesBloc
|
|||
on<ToggleCategorySelection>(_onToggleCategorySelection);
|
||||
on<SubmitPreferences>(_onSubmitPreferences);
|
||||
on<LoadFavoriteCategories>(_onLoadFavoriteCategories);
|
||||
on<ResetSubmissionStatus>(_onResetSubmissionStatus);
|
||||
|
||||
add(LoadCategories());
|
||||
}
|
||||
|
|
@ -55,7 +56,7 @@ class NotificationPreferencesBloc
|
|||
try {
|
||||
final token = await _storage.read(key: 'accessToken');
|
||||
if (token == null) {
|
||||
if (isClosed) return; // بررسی قبل از emit
|
||||
if (isClosed) return;
|
||||
emit(state.copyWith(isLoading: false, errorMessage: "شما وارد نشدهاید."));
|
||||
return;
|
||||
}
|
||||
|
|
@ -66,7 +67,7 @@ class NotificationPreferencesBloc
|
|||
options: Options(headers: {'Authorization': 'Bearer $token'}),
|
||||
);
|
||||
|
||||
if (isClosed) return; // بررسی قبل از emit
|
||||
if (isClosed) return;
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
emit(state.copyWith(isLoading: false, submissionSuccess: true));
|
||||
|
|
@ -76,7 +77,7 @@ class NotificationPreferencesBloc
|
|||
errorMessage: response.data['message'] ?? 'خطا در ثبت اطلاعات'));
|
||||
}
|
||||
} on DioException catch (e) {
|
||||
if (isClosed) return; // بررسی قبل از emit
|
||||
if (isClosed) return;
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
errorMessage: e.response?.data['message'] ?? 'خطا در ارتباط با سرور'));
|
||||
|
|
@ -89,7 +90,7 @@ class NotificationPreferencesBloc
|
|||
try {
|
||||
final token = await _storage.read(key: 'accessToken');
|
||||
if (token == null) {
|
||||
if (isClosed) return; // بررسی قبل از emit
|
||||
if (isClosed) return;
|
||||
emit(state.copyWith(isLoading: false, errorMessage: "شما وارد نشدهاید."));
|
||||
return;
|
||||
}
|
||||
|
|
@ -99,7 +100,7 @@ class NotificationPreferencesBloc
|
|||
options: Options(headers: {'Authorization': 'Bearer $token'}),
|
||||
);
|
||||
|
||||
if (isClosed) return; // بررسی قبل از emit
|
||||
if (isClosed) return;
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final List<dynamic> fCategory = response.data['data']['FCategory'];
|
||||
|
|
@ -115,10 +116,16 @@ class NotificationPreferencesBloc
|
|||
errorMessage: response.data['message'] ?? 'خطا در دریافت اطلاعات'));
|
||||
}
|
||||
} on DioException catch (e) {
|
||||
if (isClosed) return; // بررسی قبل از emit
|
||||
if (isClosed) return;
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
errorMessage: e.response?.data['message'] ?? 'خطا در ارتباط با سرور'));
|
||||
}
|
||||
}
|
||||
void _onResetSubmissionStatus(
|
||||
ResetSubmissionStatus event, Emitter<NotificationPreferencesState> emit) {
|
||||
emit(state.copyWith(submissionSuccess: false));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ abstract class NotificationPreferencesEvent extends Equatable {
|
|||
|
||||
class LoadCategories extends NotificationPreferencesEvent {}
|
||||
|
||||
class LoadFavoriteCategories extends NotificationPreferencesEvent {} // این کلاس اضافه شد
|
||||
class LoadFavoriteCategories extends NotificationPreferencesEvent {}
|
||||
|
||||
class ToggleCategorySelection extends NotificationPreferencesEvent {
|
||||
final String categoryId;
|
||||
|
|
@ -21,3 +21,5 @@ class ToggleCategorySelection extends NotificationPreferencesEvent {
|
|||
}
|
||||
|
||||
class SubmitPreferences extends NotificationPreferencesEvent {}
|
||||
|
||||
class ResetSubmissionStatus extends NotificationPreferencesEvent {}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
// ignore: depend_on_referenced_packages
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:proxibuy/presentation/offer/bloc/offer_event.dart';
|
||||
import 'package:proxibuy/presentation/offer/bloc/offer_state.dart';
|
||||
|
|
@ -12,13 +13,8 @@ class OffersBloc extends Bloc<OffersEvent, OffersState> {
|
|||
OffersReceivedFromMqtt event,
|
||||
Emitter<OffersState> emit,
|
||||
) {
|
||||
// همیشه حالت موفقیت را با لیست دریافتی منتشر کن (حتی اگر خالی باشد).
|
||||
// این کار تضمین میکند که صفحه از حالت لودینگ خارج میشود و رابط کاربری
|
||||
// آخرین وضعیت (وجود یا عدم وجود تخفیف) را نمایش میدهد.
|
||||
emit(OffersLoadSuccess(event.offers));
|
||||
}
|
||||
|
||||
// برای زمانی که مثلا کاربر GPS را خاموش میکند
|
||||
void _onClearOffers(ClearOffers event, Emitter<OffersState> emit) {
|
||||
emit(OffersInitial());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@ class _OfferCardState extends State<OfferCard> {
|
|||
padding: const EdgeInsets.only(bottom: 10),
|
||||
child: Column(
|
||||
children: [
|
||||
// Hero ویجت به اینجا اضافه شد
|
||||
Hero(
|
||||
tag: 'offer_image_${widget.offer.id}',
|
||||
child: _buildOfferImage(),
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
// lib/presentation/pages/login_page.dart
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
|
@ -114,8 +113,6 @@ class _LoginPageState extends State<LoginPage> {
|
|||
);
|
||||
}
|
||||
if (state is AuthCodeSentSuccess) {
|
||||
// ******** شروع تغییر ۱ ********
|
||||
// BlocProvider.value حذف شد
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
|
|
@ -127,7 +124,6 @@ class _LoginPageState extends State<LoginPage> {
|
|||
),
|
||||
),
|
||||
);
|
||||
// ******** پایان تغییر ۱ ********
|
||||
}
|
||||
},
|
||||
builder: (context, state) {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ import 'package:proxibuy/core/config/api_config.dart';
|
|||
import 'package:proxibuy/core/config/app_colors.dart';
|
||||
import 'package:proxibuy/core/gen/assets.gen.dart';
|
||||
import 'package:proxibuy/data/models/offer_model.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';
|
||||
import 'package:proxibuy/presentation/offer/bloc/offer_event.dart';
|
||||
import 'package:proxibuy/presentation/offer/bloc/offer_state.dart';
|
||||
|
|
@ -47,16 +49,14 @@ class _OffersPageState extends State<OffersPage> {
|
|||
super.initState();
|
||||
_initializePage();
|
||||
_initConnectivityListener();
|
||||
_fetchInitialReservations(); // <-- فراخوانی متد جدید
|
||||
_fetchInitialReservations();
|
||||
}
|
||||
|
||||
// ******** شروع متد جدید ********
|
||||
// این متد تعداد اولیه رزروها را برای نمایش روی آیکون دریافت میکند
|
||||
Future<void> _fetchInitialReservations() async {
|
||||
try {
|
||||
const storage = FlutterSecureStorage();
|
||||
final token = await storage.read(key: 'accessToken');
|
||||
if (token == null) return; // کاربر لاگین نکرده است
|
||||
if (token == null) return;
|
||||
|
||||
final dio = Dio();
|
||||
final response = await dio.get(
|
||||
|
|
@ -75,15 +75,12 @@ class _OffersPageState extends State<OffersPage> {
|
|||
.where((id) => id.isNotEmpty)
|
||||
.toList();
|
||||
|
||||
// بهروزرسانی Cubit با لیست شناسهها
|
||||
context.read<ReservationCubit>().setReservedIds(reservedIds);
|
||||
}
|
||||
} catch (e) {
|
||||
// اگر خطایی رخ دهد، مشکلی نیست. فقط عدد نمایش داده نمیشود
|
||||
debugPrint("Error fetching initial reservations: $e");
|
||||
}
|
||||
}
|
||||
// ******** پایان متد جدید ********
|
||||
|
||||
Future<void> _initializePage() async {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||
|
|
@ -296,18 +293,21 @@ class _OffersPageState extends State<OffersPage> {
|
|||
),
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
final result = await Navigator.of(context).push<bool>(
|
||||
await Navigator.of(context).push<bool>(
|
||||
MaterialPageRoute(
|
||||
builder:
|
||||
(context) => const NotificationPreferencesPage(
|
||||
builder: (context) => const NotificationPreferencesPage(
|
||||
loadFavoritesOnStart: true,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
if (result == true && mounted) {
|
||||
if (!mounted) return;
|
||||
|
||||
context
|
||||
.read<NotificationPreferencesBloc>()
|
||||
.add(ResetSubmissionStatus());
|
||||
|
||||
_loadPreferences();
|
||||
}
|
||||
},
|
||||
child: Row(
|
||||
children: [
|
||||
|
|
|
|||
|
|
@ -74,7 +74,6 @@ class _OnboardingPageState extends State<OnboardingPage> {
|
|||
MaterialPageRoute(
|
||||
builder:
|
||||
(context) => BlocProvider(
|
||||
// This creates a NEW AuthBloc
|
||||
create: (context) => AuthBloc(),
|
||||
child: const LoginPage(),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -148,13 +148,10 @@ class _OtpPageState extends State<OtpPage> {
|
|||
});
|
||||
}
|
||||
if (state is AuthNeedsInfo) {
|
||||
// ******** شروع تغییر ۲ ********
|
||||
// BlocProvider.value حذف شد
|
||||
Navigator.of(context).pushAndRemoveUntil(
|
||||
MaterialPageRoute(builder: (_) => const UserInfoPage()),
|
||||
(route) => false,
|
||||
);
|
||||
// ******** پایان تغییر ۲ ********
|
||||
}
|
||||
},
|
||||
builder: (context, state) {
|
||||
|
|
|
|||
|
|
@ -191,7 +191,6 @@ class ProductDetailPage extends StatelessWidget {
|
|||
}
|
||||
}
|
||||
|
||||
// ... بقیه کدهای این فایل بدون تغییر باقی میماند ...
|
||||
class ProductDetailView extends StatefulWidget {
|
||||
final OfferModel offer;
|
||||
|
||||
|
|
@ -589,7 +588,7 @@ class _ProductDetailViewState extends State<ProductDetailView> {
|
|||
children: [
|
||||
Container(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 20, vertical: 11),
|
||||
const EdgeInsets.symmetric(horizontal: 8, vertical: 8),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.singleOfferType,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
|
|
|
|||
|
|
@ -36,7 +36,6 @@ class _ReservationConfirmationPageState
|
|||
super.initState();
|
||||
|
||||
_playSound();
|
||||
// ******** پایان تغییر اصلی ********
|
||||
|
||||
_calculateRemainingTime();
|
||||
_timer = Timer.periodic(const Duration(seconds: 1), (timer) {
|
||||
|
|
@ -44,10 +43,8 @@ class _ReservationConfirmationPageState
|
|||
});
|
||||
}
|
||||
|
||||
// متد جدید برای پخش صدا
|
||||
void _playSound() async {
|
||||
try {
|
||||
// فایل صدایی که در پوشه assets قرار دادهاید
|
||||
await _audioPlayer.play(AssetSource('sounds/positive-notification-alert-351299.mp3'));
|
||||
} catch (e) {
|
||||
debugPrint("Error playing sound: $e");
|
||||
|
|
@ -130,7 +127,7 @@ class _ReservationConfirmationPageState
|
|||
curve: Curves.easeOutBack,
|
||||
),
|
||||
const SizedBox(height: 18),
|
||||
_buildQrCodeCard() // نمایش QR Code با استفاده از توکن
|
||||
_buildQrCodeCard()
|
||||
.animate()
|
||||
.fadeIn(delay: 1000.ms, duration: 500.ms)
|
||||
.flipV(begin: -0.5, end: 0, curve: Curves.easeOut),
|
||||
|
|
@ -359,7 +356,7 @@ class _ReservationConfirmationPageState
|
|||
Text(
|
||||
value,
|
||||
style: const TextStyle(
|
||||
fontSize: 20, // فونت کمی کوچکتر شد
|
||||
fontSize: 20,
|
||||
fontFamily: 'Dana',
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.black,
|
||||
|
|
|
|||
|
|
@ -41,22 +41,18 @@ class _ReservedListPageState extends State<ReservedListPage> {
|
|||
if (response.statusCode == 200) {
|
||||
final List<dynamic> reserves = response.data['reserves'];
|
||||
|
||||
// ******** شروع تغییر ۲ ********
|
||||
// تبدیل ساختار جدید JSON به فرمت مورد انتظار OfferModel
|
||||
return reserves.map((reserveData) {
|
||||
final discountData = reserveData['Discount'] as Map<String, dynamic>;
|
||||
final shopData = reserveData['Shop'] as Map<String, dynamic>;
|
||||
|
||||
// ترکیب اطلاعات برای سازگاری با مدل
|
||||
final fullOfferData = {
|
||||
...discountData,
|
||||
'shopData': shopData,
|
||||
'Distance': reserveData['Distance'], // پاس دادن فاصله به مدل
|
||||
'Distance': reserveData['Distance'],
|
||||
};
|
||||
|
||||
return OfferModel.fromJson(fullOfferData);
|
||||
}).toList();
|
||||
// ******** پایان تغییر ۲ ********
|
||||
} else {
|
||||
throw Exception('خطا در دریافت اطلاعات از سرور');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
// lib/presentation/pages/user_info_page.dart
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
|
@ -24,9 +23,6 @@ class _UserInfoPageState extends State<UserInfoPage> {
|
|||
super.dispose();
|
||||
}
|
||||
|
||||
// ******** شروع تغییر ۱ ********
|
||||
// متد ناوبری را ساده میکنیم.
|
||||
// این متد دیگر Provider جدیدی نمیسازد و از Provider های سراسری استفاده میکند.
|
||||
void _navigateToNextPage() {
|
||||
Navigator.of(context).pushReplacement(
|
||||
MaterialPageRoute(
|
||||
|
|
@ -34,7 +30,6 @@ class _UserInfoPageState extends State<UserInfoPage> {
|
|||
),
|
||||
);
|
||||
}
|
||||
// ******** پایان تغییر ۱ ********
|
||||
|
||||
Widget _buildGenderRadio(String title, String value) {
|
||||
return InkWell(
|
||||
|
|
@ -146,7 +141,6 @@ class _UserInfoPageState extends State<UserInfoPage> {
|
|||
const SizedBox(height: 55),
|
||||
BlocConsumer<AuthBloc, AuthState>(
|
||||
listener: (context, state) {
|
||||
// ******** لاگ: state جدید دریافت شد ********
|
||||
debugPrint(
|
||||
"UserInfoPage: 🟠 Listener یک State جدید دریافت کرد: ${state.runtimeType}",
|
||||
);
|
||||
|
|
@ -160,7 +154,6 @@ class _UserInfoPageState extends State<UserInfoPage> {
|
|||
);
|
||||
}
|
||||
if (state is AuthSuccess) {
|
||||
// ******** لاگ: state موفقیت آمیز بود ********
|
||||
debugPrint(
|
||||
"UserInfoPage: ✅ State از نوع AuthSuccess است. فراخوانی _navigateToNextPage...",
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
// lib/presentation/reservation/cubit/reservation_cubit.dart
|
||||
|
||||
// ignore: depend_on_referenced_packages
|
||||
import 'package:bloc/bloc.dart';
|
||||
|
|
@ -15,7 +14,6 @@ class ReservationCubit extends Cubit<ReservationState> {
|
|||
emit(state.copyWith(reservedProductIds: updatedList));
|
||||
}
|
||||
|
||||
// متد جدید برای تنظیم کردن همه شناسههای رزرو شده
|
||||
void setReservedIds(List<String> productIds) {
|
||||
emit(state.copyWith(reservedProductIds: productIds));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import 'dart:async';
|
||||
import 'dart:async';
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:dart_jsonwebtoken/dart_jsonwebtoken.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
|
@ -58,7 +58,6 @@ class _ReservedListItemCardState extends State<ReservedListItemCard> {
|
|||
void _toggleExpansion() {
|
||||
setState(() {
|
||||
_isExpanded = !_isExpanded;
|
||||
// توکن فقط زمانی ساخته میشود که کاربر پنل را باز میکند
|
||||
if (_isExpanded && _qrTokenFuture == null) {
|
||||
_qrTokenFuture = _generateQrToken();
|
||||
}
|
||||
|
|
@ -90,7 +89,9 @@ class _ReservedListItemCardState extends State<ReservedListItemCard> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
final isExpired = _remaining <= Duration.zero;
|
||||
|
||||
final cardContent = Column(
|
||||
children: [
|
||||
Card(
|
||||
color: Colors.white,
|
||||
|
|
@ -107,6 +108,20 @@ class _ReservedListItemCardState extends State<ReservedListItemCard> {
|
|||
_buildExpansionPanel(),
|
||||
],
|
||||
);
|
||||
|
||||
if (isExpired) {
|
||||
return ColorFiltered(
|
||||
colorFilter: const ColorFilter.matrix(<double>[
|
||||
0.2126, 0.7152, 0.0722, 0, 0,
|
||||
0.2126, 0.7152, 0.0722, 0, 0,
|
||||
0.2126, 0.7152, 0.0722, 0, 0,
|
||||
0, 0, 0, 1, 0,
|
||||
]),
|
||||
child: cardContent,
|
||||
);
|
||||
}
|
||||
|
||||
return cardContent;
|
||||
}
|
||||
|
||||
Widget _buildOfferPrimaryDetails() {
|
||||
|
|
@ -214,6 +229,15 @@ class _ReservedListItemCardState extends State<ReservedListItemCard> {
|
|||
const SizedBox(height: 4),
|
||||
_buildTimerLabels(_remaining),
|
||||
],
|
||||
)
|
||||
else
|
||||
const Text(
|
||||
'منقضی شده',
|
||||
style: TextStyle(
|
||||
color: Colors.red,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
TextButton(
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
// lib/services/mqtt_service.dart
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
|
@ -10,7 +8,7 @@ import 'package:mqtt_client/mqtt_server_client.dart';
|
|||
|
||||
class MqttService {
|
||||
late MqttServerClient client;
|
||||
final String server = '5.75.200.241';
|
||||
final String server = '5.75.197.180';
|
||||
final int port = 1883;
|
||||
final StreamController<Map<String, dynamic>> _messageStreamController =
|
||||
StreamController.broadcast();
|
||||
|
|
@ -28,7 +26,7 @@ class MqttService {
|
|||
client = MqttServerClient.withPort(server, clientId, port);
|
||||
client.logging(on: true);
|
||||
client.keepAlivePeriod = 60;
|
||||
client.autoReconnect = true; // ✅ فعالسازی اتصال مجدد خودکار
|
||||
client.autoReconnect = true;
|
||||
client.setProtocolV311();
|
||||
|
||||
debugPrint('--- [MQTT] Attempting to connect...');
|
||||
|
|
@ -64,17 +62,14 @@ class MqttService {
|
|||
});
|
||||
};
|
||||
|
||||
// این callback زمانی فراخوانی میشود که اتصال قطع شود
|
||||
client.onDisconnected = () {
|
||||
debugPrint('❌ [MQTT] Disconnected.');
|
||||
};
|
||||
|
||||
// این callback زمانی فراخوانی میشود که کلاینت در حال تلاش برای اتصال مجدد خودکار است
|
||||
client.onAutoReconnect = () {
|
||||
debugPrint('↪️ [MQTT] Auto-reconnecting...');
|
||||
};
|
||||
|
||||
// این callback زمانی فراخوانی میشود که اتصال مجدد خودکار موفقیتآمیز باشد
|
||||
client.onAutoReconnected = () {
|
||||
debugPrint('✅ [MQTT] Auto-reconnected successfully.');
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue