From 134ffdde60cbbe630b915e5660185ba0acb94222 Mon Sep 17 00:00:00 2001 From: Polyanka1 Date: Fri, 29 May 2026 11:40:55 +0300 Subject: [PATCH] fix functional bugs --- assets/fonts/DigitalNumbers-Regular.ttf | Bin 0 -> 20984 bytes assets/icons/qr_icon_order.png | Bin 0 -> 336 bytes .../icons/scooter_reserved_placemark_fill.png | Bin 0 -> 25601 bytes assets/icons/timer.png | Bin 0 -> 2039 bytes assets/splash_logo.png | Bin 0 -> 16070 bytes assets/splash_map.png | Bin 0 -> 68239 bytes lib/data/network/api_service.dart | 76 +-- .../repositories/payment_repository_impl.dart | 5 +- .../repositories/scooter_repository_impl.dart | 28 +- lib/di/service_locator.dart | 3 +- lib/domain/entities/client_subscription.dart | 24 + lib/domain/entities/scooter.dart | 3 +- lib/domain/entities/scooter_order.dart | 6 +- lib/domain/entities/subscription.dart | 3 + .../repositories/scooter_repository.dart | 7 +- .../get_client_subscriptions_usecase.dart | 3 +- lib/domain/usecase/pay_ride_usecase.dart | 2 +- ...pay_scooter_order_with_photos_usecase.dart | 2 +- lib/main.dart | 16 +- .../components/map_settings_sheet.dart | 141 ----- .../components/sheet/active_ride_sheet.dart | 41 +- .../components/sheet/current_rides_sheet.dart | 73 ++- .../components/sheet/map_settings_sheet.dart | 13 +- .../sheet/payment_method_sheet.dart | 35 +- .../components/sheet/reserved_ride_sheet.dart | 492 +++++++++--------- .../components/subscription_card.dart | 50 +- lib/presentation/event/map_event.dart | 10 + lib/presentation/navigation/app_router.dart | 3 +- lib/presentation/screens/add_card_screen.dart | 16 +- .../screens/documents_screen.dart | 7 +- lib/presentation/screens/map_screen.dart | 68 ++- .../screens/payment_confirm_screen.dart | 3 + .../screens/payment_methods_screen.dart | 98 ++-- lib/presentation/screens/profile_screen.dart | 122 +++-- lib/presentation/screens/splash_screen.dart | 208 +++++--- .../screens/subscription_details_screen.dart | 71 ++- .../screens/subscription_list_screen.dart | 16 +- lib/presentation/screens/top_up_screen.dart | 2 +- lib/presentation/state/active_ride_state.dart | 8 + lib/presentation/state/map_state.dart | 8 + .../state/subscription_list_state.dart | 4 +- .../state/susbcription_details_state.dart | 8 + .../viewmodel/active_ride_bloc.dart | 4 + lib/presentation/viewmodel/map_bloc.dart | 64 ++- .../viewmodel/order_history_bloc.dart | 2 - .../viewmodel/payment_confirm_bloc.dart | 3 +- .../viewmodel/payment_methods_bloc.dart | 7 +- .../viewmodel/subscription_list_bloc.dart | 23 +- .../viewmodel/susbcription_details_bloc.dart | 74 ++- pubspec.yaml | 5 + 50 files changed, 1086 insertions(+), 771 deletions(-) create mode 100644 assets/fonts/DigitalNumbers-Regular.ttf create mode 100644 assets/icons/qr_icon_order.png create mode 100644 assets/icons/scooter_reserved_placemark_fill.png create mode 100644 assets/icons/timer.png create mode 100644 assets/splash_logo.png create mode 100644 assets/splash_map.png create mode 100644 lib/domain/entities/client_subscription.dart delete mode 100644 lib/presentation/components/map_settings_sheet.dart diff --git a/assets/fonts/DigitalNumbers-Regular.ttf b/assets/fonts/DigitalNumbers-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..d6017caef77c8df2a3e05473c7e4f1bade486f06 GIT binary patch literal 20984 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 L12sZeu}%8l)>VYD literal 0 HcmV?d00001 diff --git a/assets/icons/qr_icon_order.png b/assets/icons/qr_icon_order.png new file mode 100644 index 0000000000000000000000000000000000000000..00e4334742b8e86d0d29b501b1d153bd2242e56d GIT binary patch literal 336 zcmeAS@N?(olHy`uVBq!ia0vp^JRr=$1|-8uW1a&k&H|6fVg?3oVGw3ym^DWND9BhG zt0{RPejUMnUahPe%b5{!n7NiBX1IR`jWn=Wxmsd1FQXj=2F zG3wV8`T1{;t?M?N=cw&vZgB79_2ARp_k2y*o<%hCh3mY3!d(1;LDr(;y?IH>f=L~X zx;q+GcQi0fxpjFJ&&1x9x0ZHs6_xqt=IQ<9%ziun)E$k3W}P_>29Y;8_`e-9=UQ;} z0c&5B|EfQ$C-7Fq@A|l1|59Vr`FoEHwYQqi_`ZSBcrJHF*_FEXhiX#oXDsiSeyiWl cCVX9fwNHurJ?0N?KyNX4y85}Sb4q9e0K*l1xBvhE literal 0 HcmV?d00001 diff --git a/assets/icons/scooter_reserved_placemark_fill.png b/assets/icons/scooter_reserved_placemark_fill.png new file mode 100644 index 0000000000000000000000000000000000000000..92c6074bb2240895c8f341a8dae8ce2c56587ecb GIT binary patch literal 25601 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
  • UoqbS{cSKw@_Rhfy~at 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 VuP&uQ_T&Hn002ovPDHLkV1g!a$9Vt% literal 0 HcmV?d00001 diff --git a/assets/splash_logo.png b/assets/splash_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..61ed566682274c9ffdb0b8d1a082f06618bcf1f6 GIT binary patch literal 16070 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 M07*qoM6N<$g3l%2h5!Hn literal 0 HcmV?d00001 diff --git a/assets/splash_map.png b/assets/splash_map.png new file mode 100644 index 0000000000000000000000000000000000000000..77840e2554bad12c6a66ed447beffa796ede2a4f GIT binary patch literal 68239 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�P$ymxDI4-jR`> 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 getClientSubscriptions() async { + Future> getClientSubscriptions() async { const url = "$baseUrl/scootersubscription/client"; try { @@ -474,14 +473,7 @@ class ApiService { final List items = responseData['data'] ?? []; return items.map((item) { - final Map subscriptionMap = - Map.from(item['subscription'] ?? {}); - - if (item['expiredAt'] != null) { - subscriptionMap['activeTo'] = item['expiredAt']; - } - - return Subscription.fromJson(subscriptionMap); + return ClientSubscription.fromJson(item); }).toList(); } return []; @@ -547,7 +539,7 @@ class ApiService { } } - Future addPaymentCard({ + Future addPaymentCard({ required String cardNumber, required String cardHolder, required int expirationMonth, @@ -571,8 +563,9 @@ class ApiService { ); if (response.statusCode == 200 || response.statusCode == 201) { - return response.data['id'] as int; + return; } + throw AuthException('Непредвиденный статус: ${response.statusCode}', 0); } on DioException catch (e) { final data = e.response?.data; @@ -674,7 +667,9 @@ class ApiService { final firstError = data['message'][0]['message'].toString(); if (firstError.contains("Wrong start zone")) { - throw WrongZoneException(message: "Некорректная зона для начала поездки."); + throw WrongZoneException( + message: "Некорректная зона для начала поездки.", + ); } } @@ -705,7 +700,9 @@ class ApiService { final firstError = data['message'][0]['message'].toString(); if (firstError.contains("Wrong start zone")) { - throw WrongZoneException(message: "Некорректная зона для начала поездки."); + throw WrongZoneException( + message: "Некорректная зона для начала поездки.", + ); } } @@ -791,7 +788,9 @@ class ApiService { final firstError = data['message'][0]['message'].toString(); if (firstError.contains("Wrong start zone")) { - throw WrongZoneException(message: "Некорректная зона для завершения поездки."); + throw WrongZoneException( + message: "Некорректная зона для завершения поездки.", + ); } } @@ -803,7 +802,7 @@ class ApiService { } } - Future payRide(int orderId) async { + Future payRide(int orderId) async { try { final response = await _dio.put( "$baseUrl/scooterorder/$orderId/pay", @@ -811,12 +810,12 @@ class ApiService { ); if (response.statusCode == 200 || response.statusCode == 201) { - return ScooterOrder.fromJson(response.data); + // return ScooterOrder.fromJson(response.data); + return; } - return null; } on DioException catch (e) { _handleDioError(e); - return null; + return; } } @@ -878,7 +877,7 @@ class ApiService { } } - Future payScooterOrderWithPhotos({ + Future payScooterOrderWithPhotos({ required int orderId, required int? cardId, required bool isBalance, @@ -891,12 +890,10 @@ class ApiService { ); if (response.statusCode == 200 || response.statusCode == 201) { - return ScooterOrder.fromJson(response.data); + return; } - return null; } on DioException catch (e) { _handleDioError(e); - return null; } } @@ -918,7 +915,6 @@ class ApiService { } } - Future> getScooterOrderRouteHistory({required int id}) async { try { final response = await _dio.get( @@ -930,13 +926,19 @@ class ApiService { final String routeString = response.data['route'] ?? '[]'; final List routeList = json.decode(routeString); - return routeList.map((item) => Point( - (item[1] as num).toDouble(), - (item[0] as num).toDouble(), - )).toList(); + return routeList + .map( + (item) => Point( + (item[1] as num).toDouble(), + (item[0] as num).toDouble(), + ), + ) + .toList(); } - throw RouteHistoryNotFoundException(message: "История маршрута не найдена"); + throw RouteHistoryNotFoundException( + message: "История маршрута не найдена", + ); } on DioException catch (e) { if (e.response?.statusCode == 401) throw UnauthorizedException(); if (e.response?.statusCode == 403) throw AuthBlockException(); @@ -1073,7 +1075,9 @@ class ApiService { if (list is List) { return list.cast>(); } else { - throw Exception('Expected a List under "data" but got ${list.runtimeType}'); + throw Exception( + 'Expected a List under "data" but got ${list.runtimeType}', + ); } } else { throw Exception('Expected a List or Map but got ${data.runtimeType}'); diff --git a/lib/data/repositories/payment_repository_impl.dart b/lib/data/repositories/payment_repository_impl.dart index cd53cf0..9b2ac5c 100644 --- a/lib/data/repositories/payment_repository_impl.dart +++ b/lib/data/repositories/payment_repository_impl.dart @@ -40,7 +40,7 @@ class PaymentRepositoryImpl implements PaymentRepository { required String cvv, }) async { try { - final cardId = await apiService.addPaymentCard( + await apiService.addPaymentCard( cardNumber: cardNumber, cardHolder: cardHolder, expirationMonth: int.parse(expiryMonth), @@ -48,8 +48,7 @@ class PaymentRepositoryImpl implements PaymentRepository { cvv: cvv, ); - // Сохраняем полный номер карты локально - await securityService.saveCardFullNumber(cardId, cardNumber); + // await securityService.saveCardFullNumber(cardId, cardNumber); return Success(null); } on AuthException catch (e) { diff --git a/lib/data/repositories/scooter_repository_impl.dart b/lib/data/repositories/scooter_repository_impl.dart index 2ba98e3..e39e751 100644 --- a/lib/data/repositories/scooter_repository_impl.dart +++ b/lib/data/repositories/scooter_repository_impl.dart @@ -10,6 +10,7 @@ import 'package:be_happy/domain/repositories/scooter_repository.dart'; import '../../core/failures.dart'; import '../../core/result.dart'; import '../../domain/entities/active_scooter_order.dart'; +import '../../domain/entities/client_subscription.dart'; import '../../domain/entities/scooter.dart'; import '../../domain/entities/tariff.dart'; import '../../domain/entities/subscription.dart'; @@ -127,8 +128,8 @@ class ScooterRepositoryImpl extends ScooterRepository { } @override - Future>> getClientSubscriptions() async { - late final Result> result; + Future>> getClientSubscriptions() async { + late final Result> result; try { final subscriptions = await _apiService.getClientSubscriptions(); result = Success(subscriptions); @@ -268,15 +269,12 @@ class ScooterRepositoryImpl extends ScooterRepository { } @override - Future> payRide(int orderId) async { - late final Result result; + Future> payRide(int orderId) async { + late final Result result; try { - final order = await _apiService.payRide(orderId); - if (order != null) { - result = Success(order); - } else { - result = Failure(UnknownFailure("Неизвестная ошибка")); - } + await _apiService.payRide(orderId); + result = Success(null); + } on AuthException catch (e) { result = Failure(AuthFailure(e.attemptsLeft)); } catch (e) { @@ -335,23 +333,19 @@ class ScooterRepositoryImpl extends ScooterRepository { } @override - Future> payScooterOrderWithPhotos({ + Future> payScooterOrderWithPhotos({ required int orderId, required int? cardId, required bool isBalance, }) async { - late final Result result; + late final Result result; try { final order = await _apiService.payScooterOrderWithPhotos( orderId: orderId, cardId: cardId, isBalance: isBalance, ); - if (order != null) { - result = Success(order); - } else { - result = Failure(UnknownFailure("Неизвестная ошибка")); - } + result = Success(null); } on AuthException catch (e) { result = Failure(AuthFailure(e.attemptsLeft)); } catch (e) { diff --git a/lib/di/service_locator.dart b/lib/di/service_locator.dart index 77a9d8e..48c9864 100644 --- a/lib/di/service_locator.dart +++ b/lib/di/service_locator.dart @@ -112,7 +112,7 @@ final getIt = GetIt.instance; Future setupDependencies() async { final sharedPreferences = await SharedPreferences.getInstance(); final dio = Dio(); - dio.interceptors.add(LogInterceptor(responseBody: true, requestBody: true)); + dio.interceptors.add(LogInterceptor(/*requestHeader: false, responseHeader:false, */responseBody: true, requestBody: true)); dio.interceptors.add(AuthInterceptor()); // HTTP getIt.registerSingleton(http.Client()); @@ -319,6 +319,7 @@ Future setupDependencies() async { getIt(), getIt(), getIt(), + getIt(), ), ); diff --git a/lib/domain/entities/client_subscription.dart b/lib/domain/entities/client_subscription.dart new file mode 100644 index 0000000..f68a51c --- /dev/null +++ b/lib/domain/entities/client_subscription.dart @@ -0,0 +1,24 @@ +import 'package:be_happy/domain/entities/subscription.dart'; + +class ClientSubscription { + final int id; + final int subscriptionId; + final Subscription subscription; + final DateTime? expiredAt; + + ClientSubscription({ + required this.id, + required this.subscriptionId, + required this.subscription, + this.expiredAt, + }); + + factory ClientSubscription.fromJson(Map json) { + return ClientSubscription( + id: json['id'] ?? 0, + subscriptionId: json['subscriptionId'] ?? 0, + subscription: Subscription.fromJson(json['subscription'] as Map), + expiredAt: json['expiredAt'] != null ? DateTime.parse(json['expiredAt']) : null, + ); + } +} \ No newline at end of file diff --git a/lib/domain/entities/scooter.dart b/lib/domain/entities/scooter.dart index 3422e00..4168e57 100644 --- a/lib/domain/entities/scooter.dart +++ b/lib/domain/entities/scooter.dart @@ -43,8 +43,9 @@ class Scooter { ); } + @override String toString() { - return 'Scooter{id: $id, title: $title}'; + return 'Scooter{id: $id, title: $title, status: $status, latitude: $latitude, longitude: $longitude, batteryLevel: $batteryLevel, isOnline: $isOnline}'; } } diff --git a/lib/domain/entities/scooter_order.dart b/lib/domain/entities/scooter_order.dart index 85b62c0..9d815ca 100644 --- a/lib/domain/entities/scooter_order.dart +++ b/lib/domain/entities/scooter_order.dart @@ -3,7 +3,7 @@ import 'scooter.dart'; class ScooterOrder { final int id; final int scooterId; - final Scooter? scooter; + final Scooter scooter; final int? planId; final ScooterPlan? plan; final int clientId; @@ -33,7 +33,7 @@ class ScooterOrder { ScooterOrder({ required this.id, required this.scooterId, - this.scooter, + required this.scooter, this.planId, this.plan, required this.clientId, @@ -65,7 +65,7 @@ class ScooterOrder { return ScooterOrder( id: json['id'] ?? 0, scooterId: json['scooterId'] ?? 0, - scooter: json['scooter'] != null ? Scooter.fromJson(json['scooter']) : null, + scooter: Scooter.fromJson(json['scooter']), planId: json['planId'], plan: json['plan'] != null ? ScooterPlan.fromJson(json['plan']) : null, clientId: json['clientId'] ?? 0, diff --git a/lib/domain/entities/subscription.dart b/lib/domain/entities/subscription.dart index 4f6ddba..51f1d69 100644 --- a/lib/domain/entities/subscription.dart +++ b/lib/domain/entities/subscription.dart @@ -8,6 +8,7 @@ class Subscription { final String fullDescription; final int planId; final bool isActive; + final bool isCurrent; final String currency; final DateTime? activeFrom; final DateTime? activeTo; @@ -28,6 +29,7 @@ class Subscription { this.activeTo, required this.createdAt, required this.updatedAt, + required this.isCurrent, required this.options, }); @@ -48,6 +50,7 @@ class Subscription { activeTo: json['activeTo'] != null ? DateTime.parse(json['activeTo']) : null, createdAt: json['createdAt'] != null ? DateTime.parse(json['createdAt']) : DateTime.now(), updatedAt: json['updatedAt'] != null ? DateTime.parse(json['updatedAt']) : DateTime.now(), + isCurrent: json['isCurrent'] ?? false, options: optionsData.map((e) => SubscriptionPeriod.fromJson(e as Map)).toList(), ); } diff --git a/lib/domain/repositories/scooter_repository.dart b/lib/domain/repositories/scooter_repository.dart index 239a008..1e2be47 100644 --- a/lib/domain/repositories/scooter_repository.dart +++ b/lib/domain/repositories/scooter_repository.dart @@ -4,6 +4,7 @@ import 'dart:io'; import 'package:be_happy/domain/entities/active_scooter_order.dart'; import '../../core/result.dart'; +import '../entities/client_subscription.dart'; import '../entities/point.dart'; import '../entities/scooter.dart'; import '../entities/subscription.dart'; @@ -16,7 +17,7 @@ abstract class ScooterRepository { Future>> getAvailableTariffs(int scooterId); Future>> getAvailableSubscriptions(); Future> getSubscriptionById(int id); - Future>> getClientSubscriptions(); + Future>> getClientSubscriptions(); Future> bookScooter({ required int scooterId, required int planId, @@ -30,13 +31,13 @@ abstract class ScooterRepository { Future> pauseRide(int orderId); Future> resumeRide(int orderId); Future> finishRide(int orderId, List files); - Future> payRide(int orderId); + Future> payRide(int orderId); Future>> getClientOrders(); Future>> uploadScooterPhotos(List images); Future> updateScooterOrderData({ required int orderId, }); - Future> payScooterOrderWithPhotos({ + Future> payScooterOrderWithPhotos({ required int orderId, required int? cardId, required bool isBalance, diff --git a/lib/domain/usecase/get_client_subscriptions_usecase.dart b/lib/domain/usecase/get_client_subscriptions_usecase.dart index 0155332..d1b0be3 100644 --- a/lib/domain/usecase/get_client_subscriptions_usecase.dart +++ b/lib/domain/usecase/get_client_subscriptions_usecase.dart @@ -1,6 +1,7 @@ import 'package:be_happy/core/result.dart'; import 'package:be_happy/domain/entities/scooter_order.dart'; +import '../entities/client_subscription.dart'; import '../repositories/scooter_repository.dart'; @@ -14,7 +15,7 @@ class GetClientSubscriptionsUsecase { GetClientSubscriptionsUsecase(this.repository); - Future>> call() { + Future>> call() { return repository.getClientSubscriptions(); } } diff --git a/lib/domain/usecase/pay_ride_usecase.dart b/lib/domain/usecase/pay_ride_usecase.dart index a75b5b3..034cefe 100644 --- a/lib/domain/usecase/pay_ride_usecase.dart +++ b/lib/domain/usecase/pay_ride_usecase.dart @@ -7,7 +7,7 @@ class PayRideUsecase { PayRideUsecase(this.repository); - Future> call(int orderId, int? cardId, + Future> call(int orderId, int? cardId, bool isBalance) { return repository.payScooterOrderWithPhotos(orderId: orderId, cardId: cardId, isBalance: isBalance); } diff --git a/lib/domain/usecase/pay_scooter_order_with_photos_usecase.dart b/lib/domain/usecase/pay_scooter_order_with_photos_usecase.dart index 8d51b42..a35c40b 100644 --- a/lib/domain/usecase/pay_scooter_order_with_photos_usecase.dart +++ b/lib/domain/usecase/pay_scooter_order_with_photos_usecase.dart @@ -7,7 +7,7 @@ class PayScooterOrderWithPhotosUsecase { PayScooterOrderWithPhotosUsecase(this.repository); - Future> call({ + Future> call({ required int orderId, required int cardId, required bool isBalance, diff --git a/lib/main.dart b/lib/main.dart index 7795097..5dc56a8 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -23,9 +23,21 @@ import 'di/service_locator.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); - SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky); + SystemChrome.setEnabledSystemUIMode( + SystemUiMode.manual, + overlays: [SystemUiOverlay.top], + ); + + SystemChrome.setSystemUIOverlayStyle( + const SystemUiOverlayStyle( + statusBarColor: Colors.transparent, + statusBarIconBrightness: Brightness.light, + statusBarBrightness: Brightness.dark, + ), + ); await setupDependencies(); + runApp(const MyApp()); } @@ -62,4 +74,4 @@ class MyApp extends StatelessWidget { ), ); } -} \ No newline at end of file +} diff --git a/lib/presentation/components/map_settings_sheet.dart b/lib/presentation/components/map_settings_sheet.dart deleted file mode 100644 index c04c4dc..0000000 --- a/lib/presentation/components/map_settings_sheet.dart +++ /dev/null @@ -1,141 +0,0 @@ -import 'dart:ui'; -import 'package:be_happy/presentation/event/map_event.dart'; -import 'package:be_happy/presentation/event/map_settings_modal_event.dart'; -import 'package:be_happy/presentation/state/map_settings_modal_state.dart'; -import 'package:be_happy/presentation/viewmodel/map_settings_modal_bloc.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:go_router/go_router.dart'; - -import '../viewmodel/map_bloc.dart'; - -class MapSettingsSheet extends StatelessWidget { - final VoidCallback? onClose; - - const MapSettingsSheet({super.key, this.onClose}); - - @override - Widget build(BuildContext context) { - return BlocBuilder( - builder: (context, state) { - final List<_SettingItemData> items = [ - _SettingItemData( - label: 'Геоточки', - icon: Icons.location_on_outlined, - color: const Color(0xFF66E3C4), - isActive: state.isAllGeomarksActive, - onChanged: (val) => context.read().add(AllGeomarksToggled(val)), - ), - _SettingItemData( - label: 'Геозоны', - icon: Icons.gps_fixed_outlined, - color: const Color(0xFF86EFAC), - isActive: state.isAllGeozonesActive, - onChanged: (val) => context.read().add(AllGeozonesToggled(val)), - ), - _SettingItemData( - label: 'Парковка', - icon: Icons.home_outlined, - color: const Color(0xFFA78BFA), - isActive: state.isParkingZoneActive, - onChanged: (val) => context.read().add(ParkingZonesToggled(val)), - ), - _SettingItemData( - label: 'Парковка запрещена', - icon: Icons.block_outlined, - color: const Color(0xFFF59E0B), - isActive: state.isRestrictedParkingZoneActive, - onChanged: (val) => context.read().add(RestrictedParkingZonesToggled(val)), - ), - _SettingItemData( - label: 'Запрещено кататься', - icon: Icons.warning_amber_outlined, - color: const Color(0xFFEF4444), - isActive: state.isRestrictedDrivingZoneActive, - onChanged: (val) => context.read().add(RestrictedDrivingZonesToggled(val)), - ), - ]; - - return Align( - alignment: Alignment.bottomCenter, - child: ClipRRect( - borderRadius: const BorderRadius.vertical(top: Radius.circular(30)), - child: BackdropFilter( - filter: ImageFilter.blur(sigmaX: 20, sigmaY: 20), - child: Container( - height: 365, - decoration: BoxDecoration( - color: const Color(0xFF000032).withOpacity(0.88), - borderRadius: const BorderRadius.vertical(top: Radius.circular(30)), - ), - child: Column( - children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 16), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text( - 'Параметры карты', - style: TextStyle(color: Colors.white, fontSize: 16, fontWeight: FontWeight.w600), - ), - TextButton( - onPressed: () { - context.read().add(ApllyButtonClick()); - context.read().add(UpdateMap()); - Navigator.of(context).pop(); - }, - child: const Text( - 'Готово', - style: TextStyle(color: Color(0xFF66E3C4), fontSize: 16, fontWeight: FontWeight.w600), - ), - ), - ], - ), - ), - Expanded( - child: ListView.builder( - padding: const EdgeInsets.symmetric(horizontal: 10), - itemCount: items.length, - itemBuilder: (context, index) { - final item = items[index]; - return ListTile( - leading: Icon(item.icon, color: item.color), - title: Text(item.label, style: const TextStyle(color: Colors.white)), - trailing: Switch.adaptive( - value: item.isActive, - onChanged: item.onChanged, - activeTrackColor: const Color(0xFF66E3C4), - inactiveThumbColor: Colors.white, - ), - ); - }, - ), - ), - ], - ), - ), - ), - ), - ); - }, - ); - } -} - -// Вспомогательный класс для описания строк -class _SettingItemData { - final String label; - final IconData icon; - final Color color; - final bool isActive; - final ValueChanged onChanged; - - _SettingItemData({ - required this.label, - required this.icon, - required this.color, - required this.isActive, - required this.onChanged, - }); -} diff --git a/lib/presentation/components/sheet/active_ride_sheet.dart b/lib/presentation/components/sheet/active_ride_sheet.dart index a564221..2be73e1 100644 --- a/lib/presentation/components/sheet/active_ride_sheet.dart +++ b/lib/presentation/components/sheet/active_ride_sheet.dart @@ -1,13 +1,16 @@ import 'dart:async'; import 'dart:ui'; +import 'package:be_happy/domain/entities/scooter.dart'; import 'package:bot_toast/bot_toast.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:go_router/go_router.dart'; import '../../../di/service_locator.dart'; import '../../event/active_ride_event.dart'; +import '../../event/map_event.dart'; import '../../state/active_ride_state.dart'; import '../../viewmodel/active_ride_bloc.dart'; +import '../../viewmodel/map_bloc.dart'; import '../dialog/finish_ride_confirmation_dialog.dart'; import '../notification_toast.dart'; @@ -56,7 +59,7 @@ class _ActiveRideSheetState extends State { return BlocProvider.value( value: _bloc, child: BlocConsumer( - listenWhen: (previous, current) => previous.inZone != current.inZone, + listenWhen: (previous, current) => previous.inZone != current.inZone || previous.status != current.status, listener: (context, state) { if (!state.inZone) { BotToast.showCustomNotification( @@ -71,6 +74,15 @@ class _ActiveRideSheetState extends State { }, ); } + + if (state.status == ActiveRideStatus.success && state.order != null) { + final scooter = state.order!.scooter; + context.read().add(FocusOnScooter(Scooter(id: scooter.id, + title: scooter.title, status: scooter.status, + latitude: state.longitude, longitude: state.latitude, + batteryLevel: scooter.batteryLevel, isOnline: scooter.isOnline, + maxSpeed: scooter.maxSpeed, number: scooter.number))); + } }, builder: (context, state) { // Логика отображения загрузки и ошибок остается прежней @@ -203,8 +215,8 @@ class _ActiveRideSheetState extends State { color: Colors.white, fontSize: 32, fontWeight: FontWeight.bold, - fontFeatures: [FontFeature.tabularFigures()], - fontFamily: 'Digital Numbers', + fontFeatures: const [FontFeature.tabularFigures()], + fontFamily: 'DigitalNumbers', ), ), const SizedBox(height: 4), @@ -306,10 +318,27 @@ class _ActiveRideSheetState extends State { } // 🔹 Если отменил — ничего не делаем, диалог уже закрылся }, + borderRadius: BorderRadius.circular(16), + child: Column( // ✅ Вернули Column с иконкой и текстом + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon( + Icons.stop, + color: Colors.white, + size: 24, + ), + const SizedBox(height: 4), + const Text( + 'ЗАВЕРШИТЬ', + style: TextStyle( + color: Colors.white, + fontSize: 12, + fontWeight: FontWeight.w600, + ), + ), + ], + ), ), - - - ), ), ), diff --git a/lib/presentation/components/sheet/current_rides_sheet.dart b/lib/presentation/components/sheet/current_rides_sheet.dart index d0bd767..5305cea 100644 --- a/lib/presentation/components/sheet/current_rides_sheet.dart +++ b/lib/presentation/components/sheet/current_rides_sheet.dart @@ -219,11 +219,11 @@ class _RideCardState extends State<_RideCard> { displayTime = _elapsedTime; } final timeString = _formatDuration(displayTime); - final statusText = _getStatusText(widget.order.status); - final statusColor = _getStatusColor(widget.order.status); + final statusText = widget.order.status == 'Booking' ? 'Забронирован' : "Активный"; + final statusColor = widget.order.status == 'Booking' ? Color(0xFFFFCC00) : Color(0xFF8bffaa); final scooterNumber = - widget.order.scooter?.number ?? widget.order.scooterId.toString(); + widget.order.scooter.number ?? widget.order.scooterId.toString(); return Container( padding: const EdgeInsets.all(16), @@ -261,7 +261,7 @@ class _RideCardState extends State<_RideCard> { Text( statusText, style: TextStyle( - color: Colors.white, + color: statusColor, fontSize: 14, fontWeight: FontWeight.w600, ), @@ -269,22 +269,51 @@ class _RideCardState extends State<_RideCard> { ], ), const SizedBox(height: 4), - Text( - scooterNumber, - style: const TextStyle( - color: Colors.white, - fontSize: 16, - fontWeight: FontWeight.w600, - ), - ), - const SizedBox(height: 4), - Text( - _getLocationText(), - style: TextStyle( - color: Colors.white.withOpacity(0.6), - fontSize: 13, - ), + Row( + children: [ + Image.asset("assets/icons/qr_icon_order.png"), + const SizedBox(width: 6), + Text( + scooterNumber, + style: const TextStyle( + color: Colors.white, + fontSize: 16, + fontWeight: FontWeight.w600, + ), + ), + ], ), + + if (isReserved) + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 8), + Text( + "Тариф", + style: TextStyle( + color: Color(0xFF8bffaa), + fontSize: 11, + ), + ), + const SizedBox(height: 4), + Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Image.asset("assets/icons/timer.png", width: 14,), + const SizedBox(width: 4), + Text( + widget.order.plan?.title ?? "Название тарифа", + style: TextStyle( + color: Color(0xFF8bffaa), + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ], + ) + ], + ) ], ), ), @@ -301,10 +330,10 @@ class _RideCardState extends State<_RideCard> { timeString, style: TextStyle( color: statusColor, - fontSize: 26, + fontSize: 20, fontWeight: FontWeight.bold, fontFeatures: const [FontFeature.tabularFigures()], - fontFamily: 'Digital Numbers', + fontFamily: 'DigitalNumbers', ), ), ], @@ -360,7 +389,7 @@ class _RideCardState extends State<_RideCard> { switch (status.toLowerCase()) { case 'reserved': case 'holding': - return 'Забронировано'; + return 'Забронирован'; case 'active': case 'in_progress': return 'Активно'; diff --git a/lib/presentation/components/sheet/map_settings_sheet.dart b/lib/presentation/components/sheet/map_settings_sheet.dart index 07b8a2e..27b2f5c 100644 --- a/lib/presentation/components/sheet/map_settings_sheet.dart +++ b/lib/presentation/components/sheet/map_settings_sheet.dart @@ -5,8 +5,6 @@ import 'package:be_happy/presentation/state/map_settings_modal_state.dart'; import 'package:be_happy/presentation/viewmodel/map_settings_modal_bloc.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:go_router/go_router.dart'; - import '../../viewmodel/map_bloc.dart'; class MapSettingsSheet extends StatelessWidget { @@ -19,13 +17,6 @@ class MapSettingsSheet extends StatelessWidget { return BlocBuilder( builder: (context, state) { final List<_SettingItemData> items = [ - _SettingItemData( - label: 'Геоточки', - icon: Icons.location_on_outlined, - color: const Color(0xFF66E3C4), - isActive: state.isAllGeomarksActive, - onChanged: (val) => context.read().add(AllGeomarksToggled(val)), - ), _SettingItemData( label: 'Геозоны', icon: Icons.gps_fixed_outlined, @@ -41,9 +32,9 @@ class MapSettingsSheet extends StatelessWidget { onChanged: (val) => context.read().add(ParkingZonesToggled(val)), ), _SettingItemData( - label: 'Разрешено кататься', + label: 'Парковка запрещена', icon: Icons.block_outlined, - color: const Color(0xFF5ECD4C), + color: const Color(0xFFF59E0B), isActive: state.isRestrictedParkingZoneActive, onChanged: (val) => context.read().add(RestrictedParkingZonesToggled(val)), ), diff --git a/lib/presentation/components/sheet/payment_method_sheet.dart b/lib/presentation/components/sheet/payment_method_sheet.dart index 4eb5648..f30365d 100644 --- a/lib/presentation/components/sheet/payment_method_sheet.dart +++ b/lib/presentation/components/sheet/payment_method_sheet.dart @@ -12,11 +12,13 @@ import '../../state/payment_method_sheet_state.dart'; import '../../viewmodel/payment_method_sheet_bloc.dart'; class PaymentMethodSheet extends StatefulWidget { - final PaymentCard? initialSelectedCard; // Добавляем это поле + final PaymentCard? initialSelectedCard; + final bool showBalance; const PaymentMethodSheet({ super.key, - this.initialSelectedCard, // Инициализируем в конструкторе + this.initialSelectedCard, + this.showBalance = true, }); @override @@ -92,7 +94,7 @@ class _PaymentMethodSheetState extends State { _selectedPaymentMethod = initialIndex != -1 ? initialIndex : -1; } else { final mainCardIndex = state.cards.indexWhere((card) => card.isMain); - _selectedPaymentMethod = mainCardIndex != -1 ? mainCardIndex : -1; + _selectedPaymentMethod = mainCardIndex != -1 ? mainCardIndex : (widget.showBalance ? -1 : 0); } } @@ -169,19 +171,20 @@ class _PaymentMethodSheetState extends State { padding: const EdgeInsets.symmetric(horizontal: 20), child: Column( children: [ - PaymentOption( - title: 'Баланс', - subtitle: '${state.balance.toStringAsFixed(2)} BYN', - isSelected: _selectedPaymentMethod == -1, - onTap: () { - setState(() { - _selectedPaymentMethod = -1; - }); - Navigator.pop(context, 'balance'); - }, - ), - - const SizedBox(height: 12), + if (widget.showBalance) ...[ + PaymentOption( + title: 'Баланс', + subtitle: '${state.balance.toStringAsFixed(2)} BYN', + isSelected: _selectedPaymentMethod == -1, + onTap: () { + setState(() { + _selectedPaymentMethod = -1; + }); + Navigator.pop(context, 'balance'); + }, + ), + const SizedBox(height: 12), + ], ...state.cards.asMap().entries.map((entry) { final index = entry.key; diff --git a/lib/presentation/components/sheet/reserved_ride_sheet.dart b/lib/presentation/components/sheet/reserved_ride_sheet.dart index d122c0b..06c9d2f 100644 --- a/lib/presentation/components/sheet/reserved_ride_sheet.dart +++ b/lib/presentation/components/sheet/reserved_ride_sheet.dart @@ -14,7 +14,7 @@ class ReservedRideSheet extends StatefulWidget { final String scooterNumber; final int orderId; final Duration initialReservationTime; - + const ReservedRideSheet({ super.key, required this.scooterNumber, @@ -60,264 +60,286 @@ class _ReservedRideSheetState extends State { Widget build(BuildContext context) { return BlocProvider.value( value: _bloc, - child: Align( - alignment: Alignment.bottomCenter, - child: ClipRRect( - borderRadius: const BorderRadius.vertical(top: Radius.circular(30)), - child: BackdropFilter( - filter: ImageFilter.blur(sigmaX: 20, sigmaY: 20), - child: Container( - padding: const EdgeInsets.only(top: 20, bottom: 10), - decoration: BoxDecoration( - color: const Color(0xFF000032).withOpacity(0.5), - borderRadius: const BorderRadius.vertical(top: Radius.circular(30)), - ), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - // HEADER - Padding( - padding: const EdgeInsets.symmetric(horizontal: 20), - child: Row( - children: [ - GestureDetector( - onTap: () => Navigator.pop(context), - child: Row( - children: [ - Icon( - Icons.arrow_back_ios_sharp, - color: const Color(0x99FFFFFF), - size: 20, - ), - Icon( - Icons.arrow_back_ios_sharp, - color: const Color(0x66FFFFFF), - size: 20, - ), - Icon( - Icons.arrow_back_ios_sharp, - color: const Color(0x22FFFFFF), - size: 20, - ), - ], - ), - ), - const SizedBox(width: 12), - Expanded( - child: Text( - 'Бесплатное бронирование', - style: const TextStyle( - color: Colors.white, - fontSize: 16, - fontWeight: FontWeight.w600, - ), - overflow: TextOverflow.ellipsis, - ), - ), - ], - ), + child: Scaffold( + backgroundColor: Colors.transparent, + resizeToAvoidBottomInset: false, + body: Align( + alignment: Alignment.bottomCenter, + child: ClipRRect( + borderRadius: const BorderRadius.vertical(top: Radius.circular(30)), + child: BackdropFilter( + filter: ImageFilter.blur(sigmaX: 20, sigmaY: 20), + child: Container( + padding: const EdgeInsets.only(top: 20, bottom: 10), + decoration: BoxDecoration( + color: const Color(0xFF000032).withOpacity(0.5), + borderRadius: const BorderRadius.vertical( + top: Radius.circular(30), ), - - const SizedBox(height: 20), - - // ТАЙМЕР + ИНФО О САМОКАТЕ (КОМПАКТНЫЙ) - Padding( - padding: const EdgeInsets.symmetric(horizontal: 20), - child: Row( - children: [ - // Таймер - Expanded( - flex: 2, - child: Text( - _formatDuration(_reservationTime), - style: const TextStyle( - color: Colors.white, - fontSize: 32, - fontWeight: FontWeight.bold, - fontFeatures: [FontFeature.tabularFigures()], - fontFamily: 'Digital Numbers', - ), - ), - ), - // Иконка и информация (ВЫСОКИЙ БЛОК) - Expanded( - flex: 3, - child: Container( - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 16), - decoration: BoxDecoration( - color: Colors.white.withOpacity(0.1), - borderRadius: BorderRadius.circular(12), - ), + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + // HEADER + Padding( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: Row( + children: [ + GestureDetector( + onTap: () => Navigator.pop(context), child: Row( children: [ - // Иконка самоката (ВЫШЕ) - SizedBox( - width: 44, - height: 56, - child: Image.asset( - 'assets/icons/e6a5dcb6a3e2ec2362c25ea49509ab10d2312b19-reverse.png', - fit: BoxFit.contain, - ), + Icon( + Icons.arrow_back_ios_sharp, + color: const Color(0x99FFFFFF), + size: 20, ), - const SizedBox(width: 12), - // Инфо - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - Row( - mainAxisSize: MainAxisSize.min, - children: [ - Container( - width: 8, - height: 8, - decoration: const BoxDecoration( - color: Color(0xFFFFB800), - shape: BoxShape.circle, - ), - ), - const SizedBox(width: 6), - const Text( - 'Забронирован', - style: TextStyle( - color: Colors.white, - fontSize: 12, - fontWeight: FontWeight.w600, - ), - overflow: TextOverflow.ellipsis, - ), - ], - ), - const SizedBox(height: 8), - Text( - '№${widget.scooterNumber}', - style: const TextStyle( - color: Colors.white, - fontSize: 15, - fontWeight: FontWeight.w600, - ), - ), - ], - ), + Icon( + Icons.arrow_back_ios_sharp, + color: const Color(0x66FFFFFF), + size: 20, + ), + Icon( + Icons.arrow_back_ios_sharp, + color: const Color(0x22FFFFFF), + size: 20, ), ], ), ), - ), - ], - ), - ), - - const SizedBox(height: 16), - - // КНОПКА "НАЧАТЬ ПОЕЗДКУ" - Padding( - padding: const EdgeInsets.symmetric(horizontal: 20), - child: BlocListener( - listener: (context, state) { - if (state.rideStarted) { - Navigator.pop(context); - showModalBottomSheet( - context: context, - isScrollControlled: true, - backgroundColor: Colors.transparent, - builder: (context) => ActiveRideSheet( - scooterNumber: widget.scooterNumber, - initialElapsedTime: Duration.zero, - orderId: widget.orderId, + const SizedBox(width: 12), + Expanded( + child: Text( + 'Бесплатное бронирование', + style: const TextStyle( + color: Colors.white, + fontSize: 16, + fontWeight: FontWeight.w600, + ), + overflow: TextOverflow.ellipsis, ), - ); - } else if (state.status == ReservedRideStatus.failure) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text(state.errorMessage ?? 'Ошибка')), - ); - } - }, - child: GradientButton( - text: 'Начать поездку', - showArrows: true, - height: 48, - width: double.infinity, - fontSize: 15, - onTap: () { - _bloc.add(StartRide(widget.orderId)); - }, + ), + ], ), ), - ), - const SizedBox(height: 12), + const SizedBox(height: 20), - // КНОПКА "ОТМЕНИТЬ БРОНИРОВАНИЕ" - Padding( - padding: const EdgeInsets.symmetric(horizontal: 20), - child: BlocListener( - listener: (context, state) { - if (state.rideCancelled) { - Navigator.pop(context); - } else if (state.status == ReservedRideStatus.failure) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text(state.errorMessage ?? 'Ошибка')), - ); - } - }, - child: Container( - height: 48, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(24), - border: Border.all( - color: Colors.white.withOpacity(0.4), - width: 1, + // ТАЙМЕР + ИНФО О САМОКАТЕ (КОМПАКТНЫЙ) + Padding( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: Row( + children: [ + // Таймер + Expanded( + flex: 2, + child: Text( + _formatDuration(_reservationTime), + style: const TextStyle( + color: Colors.white, + fontSize: 32, + fontWeight: FontWeight.bold, + fontFeatures: [FontFeature.tabularFigures()], + fontFamily: 'Digital Numbers', + ), + ), ), - ), - child: Material( - color: Colors.transparent, - child: InkWell( - onTap: () async { - final result = await showDialog( - context: context, - builder: (context) => const CancelBookingDialog(), - ); - if (result != null && result) { - _bloc.add(CancelRide(widget.orderId)); - } - }, - borderRadius: BorderRadius.circular(24), - child: BlocBuilder( - builder: (context, state) { - if (state.status == ReservedRideStatus.loading) { - return const Center( - child: SizedBox( - width: 20, - height: 20, - child: CircularProgressIndicator( - color: Colors.white, - strokeWidth: 2, - ), - ), - ); - } - return const Center( - child: Text( - 'Отменить бронирование', - style: TextStyle( - color: Colors.white, - fontSize: 15, - fontWeight: FontWeight.w600, + // Иконка и информация (ВЫСОКИЙ БЛОК) + Expanded( + flex: 3, + child: Container( + padding: const EdgeInsets.symmetric( + horizontal: 12, + vertical: 16, + ), + decoration: BoxDecoration( + color: Colors.white.withOpacity(0.1), + borderRadius: BorderRadius.circular(12), + ), + child: Row( + children: [ + // Иконка самоката (ВЫШЕ) + SizedBox( + width: 44, + height: 56, + child: Image.asset( + 'assets/icons/e6a5dcb6a3e2ec2362c25ea49509ab10d2312b19-reverse.png', + fit: BoxFit.contain, ), ), + const SizedBox(width: 12), + // Инфо + Expanded( + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + width: 8, + height: 8, + decoration: const BoxDecoration( + color: Color(0xFFFFB800), + shape: BoxShape.circle, + ), + ), + const SizedBox(width: 6), + const Text( + 'Забронирован', + style: TextStyle( + color: Colors.white, + fontSize: 12, + fontWeight: FontWeight.w600, + ), + overflow: TextOverflow.ellipsis, + ), + ], + ), + const SizedBox(height: 8), + Text( + '№${widget.scooterNumber}', + style: const TextStyle( + color: Colors.white, + fontSize: 15, + fontWeight: FontWeight.w600, + ), + ), + ], + ), + ), + ], + ), + ), + ), + ], + ), + ), + + const SizedBox(height: 16), + + // КНОПКА "НАЧАТЬ ПОЕЗДКУ" + Padding( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: BlocListener( + listener: (context, state) { + if (state.rideStarted) { + Navigator.pop(context); + showModalBottomSheet( + context: context, + isScrollControlled: true, + backgroundColor: Colors.transparent, + builder: (context) => ActiveRideSheet( + scooterNumber: widget.scooterNumber, + initialElapsedTime: Duration.zero, + orderId: widget.orderId, + ), + ); + } else if (state.status == + ReservedRideStatus.failure) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(state.errorMessage ?? 'Ошибка'), + ), + ); + } + }, + child: GradientButton( + text: 'Начать поездку', + showArrows: true, + height: 48, + width: double.infinity, + fontSize: 15, + onTap: () { + _bloc.add(StartRide(widget.orderId)); + }, + ), + ), + ), + + const SizedBox(height: 12), + + // КНОПКА "ОТМЕНИТЬ БРОНИРОВАНИЕ" + Padding( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: BlocListener( + listener: (context, state) { + if (state.rideCancelled) { + Navigator.pop(context); + } else if (state.status == + ReservedRideStatus.failure) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(state.errorMessage ?? 'Ошибка'), + ), + ); + } + }, + child: Container( + height: 48, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(24), + border: Border.all( + color: Colors.white.withOpacity(0.4), + width: 1, + ), + ), + child: Material( + color: Colors.transparent, + child: InkWell( + onTap: () async { + final result = await showDialog( + context: context, + builder: (context) => + const CancelBookingDialog(), ); + if (result != null && result) { + _bloc.add(CancelRide(widget.orderId)); + } }, + borderRadius: BorderRadius.circular(24), + child: + BlocBuilder< + ReservedRideBloc, + ReservedRideState + >( + builder: (context, state) { + if (state.status == + ReservedRideStatus.loading) { + return const Center( + child: SizedBox( + width: 20, + height: 20, + child: CircularProgressIndicator( + color: Colors.white, + strokeWidth: 2, + ), + ), + ); + } + return const Center( + child: Text( + 'Отменить бронирование', + style: TextStyle( + color: Colors.white, + fontSize: 15, + fontWeight: FontWeight.w600, + ), + ), + ); + }, + ), ), ), ), ), ), - ), - const SizedBox(height: 20), - ], + const SizedBox(height: 20), + ], + ), ), ), ), diff --git a/lib/presentation/components/subscription_card.dart b/lib/presentation/components/subscription_card.dart index 1c086ed..3d55322 100644 --- a/lib/presentation/components/subscription_card.dart +++ b/lib/presentation/components/subscription_card.dart @@ -1,13 +1,18 @@ +import 'package:be_happy/presentation/components/gradient_button.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:go_router/go_router.dart'; import '../../domain/entities/subscription.dart'; +import '../event/subscription_list_event.dart'; class SubscriptionCard extends StatelessWidget { final Subscription subscription; final bool isActive; + final DateTime? expiredAt; + final VoidCallback? onRefresh; - const SubscriptionCard({super.key, required this.subscription, required this.isActive}); + const SubscriptionCard({super.key, required this.subscription, required this.isActive, this.expiredAt, this.onRefresh}); @override Widget build(BuildContext context) { @@ -15,9 +20,9 @@ class SubscriptionCard extends StatelessWidget { ? subscription.options.reduce((a, b) => a.price < b.price ? a : b) : null; - final maxDaysOption = subscription.options.isNotEmpty + /*final maxDaysOption = subscription.options.isNotEmpty ? subscription.options.reduce((a, b) => a.days > b.days ? a : b) - : null; + : null;*/ return Container( margin: const EdgeInsets.symmetric(vertical: 8, horizontal: 16), @@ -43,7 +48,7 @@ class SubscriptionCard extends StatelessWidget { padding: EdgeInsets.all(4), decoration: BoxDecoration( color: Colors.white.withOpacity(0.3), - borderRadius: BorderRadius.circular(12), // Опционально: скругление углов + borderRadius: BorderRadius.circular(12), ), child: Text( "АКТИВНА", @@ -64,12 +69,19 @@ class SubscriptionCard extends StatelessWidget { subscription.shortDescription, style: TextStyle(color: Colors.white.withOpacity(0.7), fontSize: 14), ), - const SizedBox(height: 16), - if (maxDaysOption != null) ...[ + if (isActive && expiredAt != null) ...[ const SizedBox(height: 16), - Text( - "Период действия: до ${maxDaysOption.days} дней", - style: const TextStyle(color: Colors.white, fontSize: 14), + Builder( + builder: (context) { + final day = expiredAt!.day.toString().padLeft(2, '0'); + final month = expiredAt!.month.toString().padLeft(2, '0'); + final year = expiredAt!.year; + + return Text( + "Период действия: до $day.$month.$year", + style: const TextStyle(color: Colors.white, fontSize: 14), + ); + }, ), ], const SizedBox(height: 20), @@ -83,15 +95,17 @@ class SubscriptionCard extends StatelessWidget { ) else const SizedBox.shrink(), - ElevatedButton( - onPressed: () => context.push("/home/subscriptions/${subscription.id}"), - style: ElevatedButton.styleFrom( - backgroundColor: const Color(0xFF80FFD1), - foregroundColor: Colors.black, - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)), - padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12), - ), - child: const Text("Подробнее", style: TextStyle(fontWeight: FontWeight.bold)), + GradientButton( + onTap: () async { + final isSubscribed = await context.push("/home/subscriptions/${subscription.id}"); + if (isSubscribed == true && onRefresh != null) { + onRefresh!(); + } + }, + text: "Подробнее", + enabled: true, + width: 120, + height: 40, ), ], ), diff --git a/lib/presentation/event/map_event.dart b/lib/presentation/event/map_event.dart index 1d4c21e..16886ef 100644 --- a/lib/presentation/event/map_event.dart +++ b/lib/presentation/event/map_event.dart @@ -30,4 +30,14 @@ class NotificationReceived extends ScooterEvent { NotificationReceived(this.notification); } +class FocusOnScooter extends ScooterEvent { + final Scooter scooter; + FocusOnScooter(this.scooter); +} + +class ClearMapPlacemarks extends ScooterEvent {} +class ClearMapFocus extends ScooterEvent {} + + + diff --git a/lib/presentation/navigation/app_router.dart b/lib/presentation/navigation/app_router.dart index 95799f7..7b994bc 100644 --- a/lib/presentation/navigation/app_router.dart +++ b/lib/presentation/navigation/app_router.dart @@ -58,9 +58,9 @@ import '../../domain/usecase/remove_payment_card_usecase.dart'; import '../../domain/usecase/save_map_settings_usecase.dart'; import '../../domain/usecase/set_main_payment_card_usecase.dart'; import '../../domain/usecase/verify_pin_usecase.dart'; -import '../components/map_settings_sheet.dart'; import '../components/scooter_bottom_sheet.dart'; import '../components/sheet/current_rides_sheet.dart'; +import '../components/sheet/map_settings_sheet.dart'; import '../components/sheet/payment_method_sheet.dart'; import '../components/sheet/reserved_ride_sheet.dart'; import '../components/sheet/tariff_sheet.dart'; @@ -372,6 +372,7 @@ class AppRouter { SubscriptionDetailsBloc( getIt(), getIt(), + getIt(), ) ..add( LoadDetailsEvent( diff --git a/lib/presentation/screens/add_card_screen.dart b/lib/presentation/screens/add_card_screen.dart index 27381db..d3cd555 100644 --- a/lib/presentation/screens/add_card_screen.dart +++ b/lib/presentation/screens/add_card_screen.dart @@ -19,11 +19,14 @@ class AddCardScreen extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( body: BlocListener( - listenWhen: (previous, current) => - previous.status != current.status && - current.status == AddCardStatus.success, + listenWhen: (previous, current) { + print( + 'Смена статуса: ${previous.status} -> ${current.status} ${current.errorMessage}'); + return previous.status != current.status && + current.status == AddCardStatus.success; + }, listener: (context, state) { - context.pop(); + context.pop(true); }, child: Container( decoration: const BoxDecoration(gradient: AppColors.phoneScreenBg), @@ -149,10 +152,7 @@ class AddCardScreen extends StatelessWidget { child: InkWell( onTap: state.isFormValid ? () => { - context.read().add( - AddCardSubmitted()), - context.read()..add(PaymentMethodsStarted()), - context.pop() + context.read().add(AddCardSubmitted()), } : null, borderRadius: BorderRadius.circular( diff --git a/lib/presentation/screens/documents_screen.dart b/lib/presentation/screens/documents_screen.dart index 49f5e8a..9e71c22 100644 --- a/lib/presentation/screens/documents_screen.dart +++ b/lib/presentation/screens/documents_screen.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; import 'package:url_launcher/url_launcher.dart'; import '../../core/app_colors.dart'; import '../components/custom_app_bar.dart'; @@ -17,12 +18,10 @@ class DocumentsScreen extends StatelessWidget { padding: const EdgeInsets.symmetric(horizontal: 20), child: Column( children: [ - // ✅ Используем общий AppBar const SizedBox(height: 16), CustomAppBar(title: 'Документы'), const SizedBox(height: 32), - // Список ссылок LinkRow( icon: 'assets/icons/doc.png', title: 'Договор аренды', @@ -33,14 +32,14 @@ class DocumentsScreen extends StatelessWidget { LinkRow( icon: 'assets/icons/doc.png', title: 'Политика конфиденциальности', - onTap: () => openLink('https://...'), + onTap: () => context.push('/privacy-policy') ), const Divider(height: 1, color: Colors.white24), const SizedBox(height: 12), LinkRow( icon: 'assets/icons/doc.png', title: 'Правила вождения', - onTap: () => openLink('https://...'), + onTap: () => openLink('https://behappybel.by/#rule'), ), const Divider(height: 1, color: Colors.white24), const SizedBox(height: 12), diff --git a/lib/presentation/screens/map_screen.dart b/lib/presentation/screens/map_screen.dart index 01a99d4..a6956ac 100644 --- a/lib/presentation/screens/map_screen.dart +++ b/lib/presentation/screens/map_screen.dart @@ -93,7 +93,9 @@ class _MapScreenState extends State { listenWhen: (previous, current) { return current.lastNotification != previous.lastNotification || - current.flags != previous.flags; + current.flags != previous.flags || + previous.selectedScooterForFocus?.id + != current.selectedScooterForFocus?.id; }, listener: (context, state) { @@ -164,14 +166,39 @@ class _MapScreenState extends State { ); } } + + if (state.selectedScooterForFocus != null) { + final targetScooter = state.selectedScooterForFocus!; + + print("RESERVED SCOOTER: $targetScooter"); + + _moveCameraToPoint( + targetScooter.longitude, + targetScooter.latitude, + zoom: 17, + ); + + context.read().add(ClearMapFocus()); + } }, - buildWhen: (previous, current) => - previous.scooters != current.scooters || - previous.zones != current.zones, + buildWhen: (previous, current) { + return previous.scooters != current.scooters || + previous.reservedScooters != current.reservedScooters || + previous.zones != current.zones || + previous.status != current.status; + }, + builder: (context, state) { - final scooters = _buildScooterPlacemarks( - state.scooters, - state.address ?? "Unknown address", + final freeScooters = _buildScooterPlacemarks( + scooters: state.scooters, + iconAsset: 'assets/icons/scooter_placemark_fill.png', + isClickable: true, + ); + + final reservedScooters = _buildScooterPlacemarks( + scooters: state.reservedScooters ?? [], + iconAsset: 'assets/icons/scooter_reserved_placemark_fill.png', + isClickable: false, ); final zonePolygons = _buildZonePolygons(state.zones); @@ -193,9 +220,10 @@ class _MapScreenState extends State { }, mapObjects: [ ...zonePolygons, + ...reservedScooters, ClusterizedPlacemarkCollection( mapId: const MapObjectId('scooters_cluster'), - placemarks: scooters, + placemarks: freeScooters, radius: 30, minZoom: 15, consumeTapEvents: true, @@ -232,7 +260,6 @@ class _MapScreenState extends State { }, ), - // Индикатор загрузки (отдельный строитель для статуса) BlocBuilder( buildWhen: (previous, current) => previous.status != current.status, @@ -378,6 +405,7 @@ class _MapScreenState extends State { } void _onMarkerTap(List scooters) async { + context.read().add(CheckUser()); final flags = context.read().state.flags; if (!flags.hasCard) { @@ -553,26 +581,26 @@ class _MapScreenState extends State { await ClusterIconPainter.initImage('assets/icons/scooter_placemark.png'); } - List _buildScooterPlacemarks( - List scooters, - String address, - ) { + List _buildScooterPlacemarks({ + required List scooters, + required String iconAsset, + required bool isClickable, + }) { return scooters.map((scooter) { return PlacemarkMapObject( - mapId: MapObjectId('${scooter.id}'), + mapId: MapObjectId('${isClickable ? "" : "reserved_"}${scooter.id}'), // уникальный ID для карты point: Point(latitude: scooter.longitude, longitude: scooter.latitude), icon: PlacemarkIcon.single( PlacemarkIconStyle( - image: BitmapDescriptor.fromAssetImage( - 'assets/icons/scooter_placemark_fill.png', - ), + image: BitmapDescriptor.fromAssetImage(iconAsset), scale: 0.2, ), ), opacity: 1.0, - onTap: (object, point) async => { - _onMarkerTap([scooter]), - }, + consumeTapEvents: isClickable, + onTap: isClickable + ? (object, point) async => _onMarkerTap([scooter]) + : null, ); }).toList(); } diff --git a/lib/presentation/screens/payment_confirm_screen.dart b/lib/presentation/screens/payment_confirm_screen.dart index 4eb8dbb..b8aafa1 100644 --- a/lib/presentation/screens/payment_confirm_screen.dart +++ b/lib/presentation/screens/payment_confirm_screen.dart @@ -9,9 +9,11 @@ import '../components/custom_app_bar.dart'; import '../components/gradient_button.dart'; import '../components/payment_option.dart'; import '../components/sheet/payment_method_sheet.dart'; +import '../event/map_event.dart'; import '../event/payment_confirm_event.dart'; import '../event/payment_method_sheet_event.dart'; import '../state/payment_confirm_state.dart'; +import '../viewmodel/map_bloc.dart'; import '../viewmodel/payment_confirm_bloc.dart'; import '../viewmodel/payment_method_sheet_bloc.dart'; @@ -78,6 +80,7 @@ class _PaymentConfirmScreenContent extends StatelessWidget { listener: (context, state) { if (state.status == PaymentConfirmStatus.success && state.paymentCompleted) { + context.read().add(ClearMapPlacemarks()); context.go('/home'); } else if (state.status == PaymentConfirmStatus.failure) { ScaffoldMessenger.of(context).hideCurrentSnackBar(); diff --git a/lib/presentation/screens/payment_methods_screen.dart b/lib/presentation/screens/payment_methods_screen.dart index e231908..f206781 100644 --- a/lib/presentation/screens/payment_methods_screen.dart +++ b/lib/presentation/screens/payment_methods_screen.dart @@ -17,43 +17,63 @@ class PaymentMethodsScreen extends StatelessWidget { body: Container( decoration: const BoxDecoration(gradient: AppColors.phoneScreenBg), child: SafeArea( - child: Column( - children: [ - const SizedBox(height: 16), - const Padding( - padding: EdgeInsets.symmetric(horizontal: 20), - child: CustomAppBar(title: 'Способы оплаты'), - ), - const SizedBox(height: 24), - Expanded( - child: BlocConsumer( - listener: (context, state) { - if (state.status == PaymentMethodsStatus.failure) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text(state.errorMessage ?? 'Ошибка')), - ); - } - }, - builder: (context, state) { - if (state.status == PaymentMethodsStatus.loading && state.cards.isEmpty) { - return const Center(child: CircularProgressIndicator(color: Color(0xFF00D4AA))); - } + child: BlocConsumer( + listener: (context, state) { + if (state.status == PaymentMethodsStatus.failure) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text(state.errorMessage ?? 'Ошибка')), + ); + } + }, + builder: (context, state) { + final isNetworkProcessing = state.status == PaymentMethodsStatus.loading || + (state.isDeleting ?? false) || + (state.isSettingMain ?? false); - return SingleChildScrollView( - padding: const EdgeInsets.symmetric(horizontal: 20), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - _buildBalanceCard(context, state.balance), - const SizedBox(height: 20), - _buildCardsList(context, state), - ], + return Stack( + children: [ + Column( + children: [ + const SizedBox(height: 16), + const Padding( + padding: EdgeInsets.symmetric(horizontal: 20), + child: CustomAppBar(title: 'Способы оплаты'), ), - ); - }, - ), - ), - ], + const SizedBox(height: 24), + Expanded( + child: state.cards.isEmpty && state.status == PaymentMethodsStatus.loading + ? const Center( + child: CircularProgressIndicator(color: Color(0xFF00D4AA)), + ) + : SingleChildScrollView( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildBalanceCard(context, state.balance), + const SizedBox(height: 20), + _buildCardsList(context, state), + ], + ), + ), + ), + ], + ), + + if (isNetworkProcessing && state.cards.isNotEmpty) + Positioned.fill( + child: Container( + color: Colors.black.withOpacity(0.4), + child: const Center( + child: CircularProgressIndicator( + color: Color(0xFF00D4AA), + ), + ), + ), + ), + ], + ); + }, ), ), ), @@ -163,7 +183,13 @@ class PaymentMethodsScreen extends StatelessWidget { child: Material( color: Colors.transparent, child: InkWell( - onTap: () => context.go('/home/payment-methods/add-card'), + onTap: () async { + final isCardAdded = await context.push('/home/payment-methods/add-card'); + + if (isCardAdded == true && context.mounted) { + context.read().add(PaymentMethodsStarted()); + } + }, borderRadius: BorderRadius.circular(24), child: const Padding( padding: EdgeInsets.symmetric(horizontal: 16), diff --git a/lib/presentation/screens/profile_screen.dart b/lib/presentation/screens/profile_screen.dart index c1ce386..916b3fd 100644 --- a/lib/presentation/screens/profile_screen.dart +++ b/lib/presentation/screens/profile_screen.dart @@ -50,7 +50,9 @@ class _ProfileScreenState extends State { Widget build(BuildContext context) { return Scaffold( body: Container( - decoration: const BoxDecoration(gradient: AppColors.phoneScreenBg), + decoration: const BoxDecoration( + gradient: AppColors.phoneScreenBg, + ), child: SafeArea( child: BlocBuilder( builder: (context, state) { @@ -70,56 +72,82 @@ class _ProfileScreenState extends State { } final profile = state.profile!; - return SingleChildScrollView( - padding: const EdgeInsets.symmetric(horizontal: 20), - child: Column( - children: [ - const SizedBox(height: 16), - CustomAppBar(title: 'Профиль'), - const SizedBox(height: 32), - Stack( - alignment: Alignment.topRight, - children: [ - CircleAvatar( - radius: 60, - backgroundColor: AppColors.checkboxFill, - backgroundImage: (profile.avatarUrl != null && profile.avatarUrl!.isNotEmpty) - ? NetworkImage("${profile.avatarUrl!}?v=${DateTime.now().minute}") - : null, - child: (profile.avatarUrl == null || profile.avatarUrl!.isEmpty) - ? Text( - profile.name.isNotEmpty ? profile.name[0].toUpperCase() : '', - style: const TextStyle(fontSize: 50, color: AppColors.darkBlue), - ) - : null, - ), GestureDetector( - onTap: _pickImage, - child: Container( - margin: const EdgeInsets.only(top: 0, right: 0), - child: Image.asset( - 'assets/icons/edit.png', - width: 24, - height: 24, + return LayoutBuilder( + builder: (context, constraints) { + return SingleChildScrollView( + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: constraints.maxHeight, + ), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: Column( + children: [ + const SizedBox(height: 16), + CustomAppBar(title: 'Профиль'), + const SizedBox(height: 32), + + Stack( + alignment: Alignment.topRight, + children: [ + CircleAvatar( + radius: 60, + backgroundColor: AppColors.checkboxFill, + backgroundImage: + (profile.avatarUrl != null && + profile.avatarUrl!.isNotEmpty) + ? NetworkImage( + "${profile.avatarUrl!}?v=${DateTime.now().minute}", + ) + : null, + child: + (profile.avatarUrl == null || + profile.avatarUrl!.isEmpty) + ? Text( + profile.name.isNotEmpty + ? profile.name[0].toUpperCase() + : '', + style: const TextStyle( + fontSize: 50, + color: AppColors.darkBlue, + ), + ) + : null, + ), + + GestureDetector( + onTap: _pickImage, + child: Container( + child: Image.asset( + 'assets/icons/edit.png', + width: 24, + height: 24, + ), + ), + ), + ], ), - ), + + const SizedBox(height: 32), + + _ProfileInfoBlock( + profile: profile, + onEditTap: () => context.go("/home/profile/edit"), + ), + + // const SizedBox(height: 24), + // _SettingsBlock( + // notificationsEnabled: notificationsEnabled, + // onNotificationsChanged: (v) => + // setState(() => notificationsEnabled = v), + // ), + ], ), - ], + ), ), - const SizedBox(height: 32), - _ProfileInfoBlock( - profile: profile, - onEditTap: () => context.go("/home/profile/edit"), - ), - const SizedBox(height: 24), - _SettingsBlock( - notificationsEnabled: notificationsEnabled, - onNotificationsChanged: (v) => - setState(() => notificationsEnabled = v), - ), - const SizedBox(height: 24), - ], - ), + ); + }, ); }, ), diff --git a/lib/presentation/screens/splash_screen.dart b/lib/presentation/screens/splash_screen.dart index b4805b4..695b783 100644 --- a/lib/presentation/screens/splash_screen.dart +++ b/lib/presentation/screens/splash_screen.dart @@ -1,13 +1,8 @@ - +import 'dart:math' as math; import 'package:be_happy/presentation/event/spalsh_event.dart'; import 'package:be_happy/presentation/viewmodel/splash_bloc.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:shared_preferences/shared_preferences.dart'; - -// Подключи сюда свои реальные экраны: -import 'phone_screen.dart'; -import 'pin_login_screen.dart'; class SplashScreen extends StatefulWidget { const SplashScreen({super.key}); @@ -19,35 +14,61 @@ class SplashScreen extends StatefulWidget { class _SplashScreenState extends State with SingleTickerProviderStateMixin { late final AnimationController _controller; - late final Animation _revealAnimation; - static const double logoSize = 300; + // Фаза 1: Заполнение цветом слева направо (0.0 -> 0.5) + late final Animation _fillProgress; + + // Фаза 2: Укатывание вправо (0.6 -> 1.0) + late final Animation _rollTranslation; + late final Animation _rollRotation; + + // Уменьшенный размер логотипа по вашему запросу + static const double logoSize = 130; @override void initState() { super.initState(); - // контроллер анимации _controller = AnimationController( vsync: this, - duration: const Duration(milliseconds: 2500), + duration: const Duration(milliseconds: 3000), ); - // анимация движения "затемняющего" прямоугольника - _revealAnimation = Tween(begin: 0.0, end: 1.0).animate( - CurvedAnimation(parent: _controller, curve: Curves.easeInOut), + _fillProgress = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation( + parent: _controller, + curve: const Interval(0.0, 0.5, curve: Curves.easeInOut), + ), ); - // запускаем анимацию - _controller.forward().then((_) async { - // небольшая пауза после анимации - await Future.delayed(const Duration(milliseconds: 800)); - if (!mounted) { - return; - } - context.read().add(AuthCheckRequested()); + _rollTranslation = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation( + parent: _controller, + curve: const Interval(0.6, 1.0, curve: Curves.easeInCubic), + ), + ); + + _rollRotation = Tween(begin: 0.0, end: 2 * math.pi).animate( + CurvedAnimation( + parent: _controller, + curve: const Interval(0.6, 1.0, curve: Curves.easeIn), + ), + ); + + // Добавляем задержку перед стартом, чтобы пользователь успел увидеть экран + WidgetsBinding.instance.addPostFrameCallback((_) async { + if (!mounted) return; + + // Ждем 500мс после того, как первый кадр отрисовался + await Future.delayed(const Duration(milliseconds: 500)); + + if (!mounted) return; + // Запускаем анимацию + _controller.forward().then((_) { + if (!mounted) return; + context.read().add(AuthCheckRequested()); + }); }); - } @override @@ -56,69 +77,102 @@ class _SplashScreenState extends State super.dispose(); } - @override @override Widget build(BuildContext context) { + final double screenWidth = MediaQuery.of(context).size.width; + final double endTranslation = screenWidth / 2 + logoSize; + return Scaffold( - backgroundColor: const Color(0xFF3A3A3A), - body: Center( - child: AnimatedBuilder( - animation: _controller, - builder: (context, _) { - final double offset = _revealAnimation.value * (logoSize * 1.2); - - return Stack( - alignment: Alignment.center, - children: [ - // Цветной логотип (на заднем плане) - Image.asset( - 'assets/logo_color.png', - width: logoSize, - height: logoSize, - fit: BoxFit.contain, + body: Stack( + children: [ + Positioned.fill( + child: Container( + decoration: const BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + Color(0xFF293A69), + Color(0xFF202741), + ], ), + ), + ), + ), - // Прямоугольник, который "уезжает" вправо, открывая логотип - ClipRect( - child: Align( - alignment: Alignment.centerLeft, - child: FractionallySizedBox( - widthFactor: 1, - child: Container( - width: logoSize, - height: logoSize, - color: const Color(0xFF3A3A3A), - transform: Matrix4.translationValues(offset, 0, 0), - ), + // 2. Волна + Positioned( + top: 0, + left: 0, + right: 0, + child: Image.asset( + 'assets/wave.png', + fit: BoxFit.contain, + ), + ), + + Positioned( + bottom: 0, + left: 0, + right: 0, + child: Image.asset( + 'assets/splash_map.png', + fit: BoxFit.contain, + ), + ), + + Center( + child: AnimatedBuilder( + animation: _controller, + builder: (context, child) { + final double translationX = _rollTranslation.value * endTranslation; + + return Transform( + transform: Matrix4.translationValues(translationX, 0, 0) + ..rotateZ(_rollRotation.value), + alignment: Alignment.center, + // Используем ShaderMask для эффекта заполнения/проявления + child: ShaderMask( + shaderCallback: (bounds) { + return LinearGradient( + begin: Alignment.centerLeft, + end: Alignment.centerRight, + // Используем _fillProgress для сдвига жесткой границы градиента + colors: const [Colors.white, Colors.transparent], + stops: [_fillProgress.value, _fillProgress.value], + ).createShader(bounds); + }, + blendMode: BlendMode.dstIn, // Оставляет только ту часть логотипа, где градиент белый + child: Image.asset( + 'assets/splash_logo.png', + width: logoSize, + height: logoSize, + fit: BoxFit.contain, ), ), - ), - - // Обводка логотипа (поверх) - Image.asset( - 'assets/logo_outline.png', - width: logoSize * 1.01, - height: logoSize * 1.01, - fit: BoxFit.contain, - ), - ], - ); - }, - ), - ), - - bottomNavigationBar: Padding( - padding: const EdgeInsets.only(bottom: 24), - child: Text( - 'Версия приложения 1.0', - textAlign: TextAlign.center, - style: TextStyle( - color: Colors.white.withOpacity(0.8), - fontSize: 12, + ); + }, + ), ), - ), + + // 5. Версия приложения + Positioned( + left: 0, + right: 0, + bottom: 24, + child: Text( + 'Версия приложения 1.0', + textAlign: TextAlign.center, + style: TextStyle( + color: Colors.white.withOpacity(0.6), + fontSize: 12, + fontWeight: FontWeight.w300, + letterSpacing: 0.5, + ), + ), + ), + ], ), ); } - -} +} \ No newline at end of file diff --git a/lib/presentation/screens/subscription_details_screen.dart b/lib/presentation/screens/subscription_details_screen.dart index ffde1ce..91f4694 100644 --- a/lib/presentation/screens/subscription_details_screen.dart +++ b/lib/presentation/screens/subscription_details_screen.dart @@ -27,15 +27,26 @@ class SubscriptionDetailsScreen extends StatelessWidget { const SizedBox(height: 16), Padding( padding: const EdgeInsets.symmetric(horizontal: 20), - child: BlocBuilder( - builder: (context, state) { - String title = "Загрузка..."; - if (state is DetailsContentState) { - title = state.subscription.title; - } - return CustomAppBar(title: title); - }, - ), + child: + BlocConsumer< + SubscriptionDetailsBloc, + SubscriptionDetailsState + >( + listenWhen: (previous, current) => + current is DetailsContentState && current.isSuccess, + listener: (context, state) { + if (state is DetailsContentState && state.isSuccess) { + context.pop(true); + } + }, + builder: (context, state) { + String title = "Загрузка..."; + if (state is DetailsContentState) { + title = state.subscription.title; + } + return CustomAppBar(title: title); + }, + ), ), const SizedBox(height: 20), @@ -53,11 +64,16 @@ class SubscriptionDetailsScreen extends StatelessWidget { child: Image.asset('assets/wave.png'), ), ), - BlocBuilder( + BlocBuilder< + SubscriptionDetailsBloc, + SubscriptionDetailsState + >( builder: (context, state) { if (state is DetailsLoading) { return const Center( - child: CircularProgressIndicator(color: Color(0xFF80FFD1)), + child: CircularProgressIndicator( + color: Color(0xFF80FFD1), + ), ); } if (state is DetailsError) { @@ -85,6 +101,7 @@ class SubscriptionDetailsScreen extends StatelessWidget { } Widget _buildContent(BuildContext context, DetailsContentState state) { + final bool isAvailableForPurchase = state.subscription.isActive; return SingleChildScrollView( padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 20), child: Column( @@ -98,22 +115,28 @@ class SubscriptionDetailsScreen extends StatelessWidget { height: 1.5, ), ), - const SizedBox(height: 30), - _ActionCard(state: state), + if (isAvailableForPurchase) ...[ + const SizedBox(height: 30), - const SizedBox(height: 30), + _ActionCard(state: state), - GradientButton( - text: 'Активировать', - onTap: () => context.read().add( - ActivateSubscriptionPressed(), + const SizedBox(height: 30), + + GradientButton( + text: state.isAlreadyPurchased ? 'Продлить' : 'Активировать', + onTap: () { + context.read().add( + ActivateSubscriptionPressed(), + ); + }, + enabled: state.isAgreed, + width: double.infinity, + height: 56, + fontSize: 16, + showArrows: true, ), - width: double.infinity, - height: 56, - fontSize: 16, - showArrows: true, - ), + ], const SizedBox(height: 20), ], ), @@ -232,4 +255,4 @@ class _PriceRow extends StatelessWidget { ), ); } -} \ No newline at end of file +} diff --git a/lib/presentation/screens/subscription_list_screen.dart b/lib/presentation/screens/subscription_list_screen.dart index d5094c6..c6b1b89 100644 --- a/lib/presentation/screens/subscription_list_screen.dart +++ b/lib/presentation/screens/subscription_list_screen.dart @@ -1,3 +1,4 @@ +import 'package:be_happy/presentation/event/subscription_list_event.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:go_router/go_router.dart'; @@ -44,17 +45,26 @@ class SubscriptionsListScreen extends StatelessWidget { if (state is SubscriptionsLoading) { return const Center(child: CircularProgressIndicator()); } else if (state is SubscriptionsLoaded) { - final activeIds = state.activeSubscriptions.map((e) => e.id).toSet(); + final clientSubsMap = { + for (var sub in state.activeSubscriptions) sub.subscriptionId: sub + }; + return ListView.builder( padding: const EdgeInsets.only(top: 20), itemCount: state.subscriptions.length, itemBuilder: (context, index) { final subscription = state.subscriptions[index]; - final bool isActive = activeIds.contains(subscription.id); + + final bool isPurchased = subscription.isCurrent; + + final clientSub = clientSubsMap[subscription.id]; + final DateTime? expirationDate = isPurchased ? clientSub?.expiredAt : null; return SubscriptionCard( subscription: subscription, - isActive: isActive, + isActive: isPurchased, + expiredAt: expirationDate, + onRefresh: () { context.read().add(LoadSubscriptionsEvent());}, ); }, ); diff --git a/lib/presentation/screens/top_up_screen.dart b/lib/presentation/screens/top_up_screen.dart index ba83f86..6e772c6 100644 --- a/lib/presentation/screens/top_up_screen.dart +++ b/lib/presentation/screens/top_up_screen.dart @@ -170,7 +170,7 @@ class TopUpScreen extends StatelessWidget { create: (context) => PaymentMethodSheetBloc(getIt()) ..add(PaymentMethodSheetStarted()), - child: const PaymentMethodSheet(), + child: const PaymentMethodSheet(showBalance: false,), ), ); diff --git a/lib/presentation/state/active_ride_state.dart b/lib/presentation/state/active_ride_state.dart index b04c81a..3f87931 100644 --- a/lib/presentation/state/active_ride_state.dart +++ b/lib/presentation/state/active_ride_state.dart @@ -12,6 +12,8 @@ class ActiveRideState { final double cost; final bool isPaused; final bool inZone; + final double latitude; + final double longitude; const ActiveRideState({ this.status = ActiveRideStatus.initial, @@ -20,6 +22,8 @@ class ActiveRideState { this.elapsedTime = Duration.zero, this.speed = 0.0, this.distance = 0.0, + this.latitude = 0.0, + this.longitude = 0.0, this.cost = 0.0, this.isPaused = false, this.inZone = true, @@ -33,6 +37,8 @@ class ActiveRideState { double? speed, double? distance, double? cost, + double? longitude, + double? latitude, bool? isPaused, bool? inZone, }) { @@ -44,6 +50,8 @@ class ActiveRideState { speed: speed ?? this.speed, distance: distance ?? this.distance, cost: cost ?? this.cost, + latitude: latitude ?? this.latitude, + longitude: longitude ?? this.longitude, isPaused: isPaused ?? this.isPaused, inZone: inZone ?? this.inZone, ); diff --git a/lib/presentation/state/map_state.dart b/lib/presentation/state/map_state.dart index 3c411a4..1c2a72e 100644 --- a/lib/presentation/state/map_state.dart +++ b/lib/presentation/state/map_state.dart @@ -9,6 +9,8 @@ enum ScooterStatus { initial, loading, success, failure } class ScooterState { final List scooters; + final List reservedScooters; + final Scooter? selectedScooterForFocus; final List zones; final List area; final List areaScooters; @@ -23,6 +25,8 @@ class ScooterState { ScooterState({ this.scooters = const [], + this.reservedScooters = const [], + this.selectedScooterForFocus, this.zones = const [], this.area = const [], this.areaScooters = const [], @@ -38,6 +42,8 @@ class ScooterState { ScooterState copyWith({ List? scooters, + List? reservedScooters, + Scooter? selectedScooterForFocus, List? zones, List? area, List? areaScooters, @@ -52,6 +58,8 @@ class ScooterState { }) { return ScooterState( scooters: scooters ?? this.scooters, + reservedScooters: reservedScooters ?? this.reservedScooters, + selectedScooterForFocus: selectedScooterForFocus ?? this.selectedScooterForFocus, zones: zones ?? this.zones, area: area ?? this.area, areaScooters: areaScooters ?? this.areaScooters, diff --git a/lib/presentation/state/subscription_list_state.dart b/lib/presentation/state/subscription_list_state.dart index 24596a1..1db5045 100644 --- a/lib/presentation/state/subscription_list_state.dart +++ b/lib/presentation/state/subscription_list_state.dart @@ -1,3 +1,5 @@ +import 'package:be_happy/domain/entities/client_subscription.dart'; + import '../../domain/entities/subscription.dart'; abstract class SubscriptionState {} @@ -6,7 +8,7 @@ class SubscriptionsLoading extends SubscriptionState {} class SubscriptionsLoaded extends SubscriptionState { final List subscriptions; - final List activeSubscriptions; + final List activeSubscriptions; SubscriptionsLoaded({ required this.subscriptions, diff --git a/lib/presentation/state/susbcription_details_state.dart b/lib/presentation/state/susbcription_details_state.dart index 1bc7d58..7ce8636 100644 --- a/lib/presentation/state/susbcription_details_state.dart +++ b/lib/presentation/state/susbcription_details_state.dart @@ -15,21 +15,29 @@ class DetailsContentState extends SubscriptionDetailsState { final Subscription subscription; final SubscriptionPeriod selectedPeriod; final bool isAgreed; + final bool isAlreadyPurchased; // ✅ Куплена ли эта подписка сейчас + final bool isSuccess; // ✅ Сигнал для навигатора назад DetailsContentState({ required this.subscription, required this.selectedPeriod, this.isAgreed = false, + this.isAlreadyPurchased = false, + this.isSuccess = false, }); DetailsContentState copyWith({ SubscriptionPeriod? selectedPeriod, bool? isAgreed, + bool? isAlreadyPurchased, + bool? isSuccess, }) { return DetailsContentState( subscription: this.subscription, selectedPeriod: selectedPeriod ?? this.selectedPeriod, isAgreed: isAgreed ?? this.isAgreed, + isAlreadyPurchased: isAlreadyPurchased ?? this.isAlreadyPurchased, + isSuccess: isSuccess ?? this.isSuccess, ); } } \ No newline at end of file diff --git a/lib/presentation/viewmodel/active_ride_bloc.dart b/lib/presentation/viewmodel/active_ride_bloc.dart index 661e95d..b525bc0 100644 --- a/lib/presentation/viewmodel/active_ride_bloc.dart +++ b/lib/presentation/viewmodel/active_ride_bloc.dart @@ -76,6 +76,8 @@ class ActiveRideBloc extends Bloc { cost: orderData?.price ?? 0.0, isPaused: isPaused, inZone: orderData?.zone, + latitude: orderData?.latitude, + longitude: orderData?.longitude, )); _syncTimer?.cancel(); @@ -196,6 +198,8 @@ class ActiveRideBloc extends Bloc { cost: orderData?.price ?? state.cost, isPaused: isPaused, inZone: orderData?.zone, + latitude: orderData?.latitude, + longitude: orderData?.longitude, )); } print("CURRENT STATE $state"); diff --git a/lib/presentation/viewmodel/map_bloc.dart b/lib/presentation/viewmodel/map_bloc.dart index d06169a..72268d0 100644 --- a/lib/presentation/viewmodel/map_bloc.dart +++ b/lib/presentation/viewmodel/map_bloc.dart @@ -5,6 +5,7 @@ import 'package:be_happy/domain/entities/client_notification.dart'; import 'package:be_happy/domain/entities/map_settings.dart'; import 'package:be_happy/domain/usecase/check_user_usecase.dart'; import 'package:be_happy/domain/usecase/get_available_zones_usecase.dart'; +import 'package:be_happy/domain/usecase/get_client_orders_usecase.dart'; import 'package:be_happy/domain/usecase/get_map_settings_usecase.dart'; import 'package:be_happy/domain/usecase/get_notifications_stream_usecase.dart'; import 'package:be_happy/domain/usecase/logout_usecase.dart'; @@ -13,6 +14,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import '../../domain/entities/point.dart'; import '../../domain/entities/scooter.dart'; +import '../../domain/entities/scooter_order.dart'; import '../../domain/entities/zone.dart'; import '../../domain/usecase/get_available_scooters_usecase.dart'; import '../../domain/usecase/get_profile_usecase.dart'; @@ -23,6 +25,7 @@ import 'package:maps_toolkit/maps_toolkit.dart' as mt; class MapBloc extends Bloc { final GetAvailableScootersUsecase getScootersUsecase; + final GetClientOrdersUsecase getClientOrdersUsecase; final GetAvailableZonesUsecase getAvailableZonesUsecase; final GetMapSettingsUsecase getMapSettingsUsecase; final GetNotificationsStreamUseCase getNotificationsStreamUseCase; @@ -35,6 +38,7 @@ class MapBloc extends Bloc { MapBloc( this.getAvailableZonesUsecase, this.getScootersUsecase, + this.getClientOrdersUsecase, this.getMapSettingsUsecase, this.getNotificationsStreamUseCase, this.getProfileUseCase, @@ -49,6 +53,9 @@ class MapBloc extends Bloc { on(_onFetchProfileData); on(_onCheckUser); on(_onLogoutPressed); + on(_onFocusOnScooter); + on(_onClearMapPlacemarks); + on(_onClearMapFocus); } void startNotificationStream() { @@ -97,11 +104,15 @@ class MapBloc extends Bloc { getScootersUsecase(event.areaScooters, 0, 100), getAvailableZonesUsecase(event.area, 0, 100), getMapSettingsUsecase(), + getClientOrdersUsecase(), ]); final scooters = results[0] as List; final zones = results[1] as List; final settings = results[2] as MapSettings; + final orders = results[3]; + + zones.forEach(print); @@ -127,6 +138,7 @@ class MapBloc extends Bloc { state.copyWith( status: ScooterStatus.success, scooters: scooters, + // reservedScooters: reservedScooters, zones: filteredZones, area: event.area, areaScooters: event.areaScooters, @@ -236,7 +248,9 @@ class MapBloc extends Bloc { try { final profile = await getProfileUseCase(); - emit(state.copyWith(phoneNumber: profile.phone, balance: profile.balance)); + emit( + state.copyWith(phoneNumber: profile.phone, balance: profile.balance), + ); } catch (e) { emit( state.copyWith( @@ -280,4 +294,52 @@ class MapBloc extends Bloc { ); } } + + FutureOr _onFocusOnScooter(FocusOnScooter event, Emitter emit) { + final updatedReserved = List.from(state.reservedScooters ?? []); + if (!updatedReserved.any((s) => s.id == event.scooter.id)) { + updatedReserved.add(event.scooter); + } + + emit(state.copyWith( + selectedScooterForFocus: event.scooter, + reservedScooters: updatedReserved, + )); + } + + + + FutureOr _onClearMapPlacemarks(ClearMapPlacemarks event, Emitter emit) async { + try{ + final orders = await getClientOrdersUsecase(); + + List updatedReservedScooters = []; + + if (orders is Success>) { + print("FETCH: orders.data.length = ${orders.data?.length}"); + + updatedReservedScooters = orders.data?.map((order) { + return order.scooter; + }).toList() ?? []; + } + + emit(state.copyWith( + reservedScooters: updatedReservedScooters, + )); + } catch (e) { + print("Error in _onClearMapPlacemarks: $e"); + emit(state.copyWith( + status: ScooterStatus.failure, + errorMessage: e.toString(), + )); + } + } + + FutureOr _onClearMapFocus(ClearMapFocus event, Emitter emit) { + emit(state.copyWith( + selectedScooterForFocus: null, + )); + } } + + diff --git a/lib/presentation/viewmodel/order_history_bloc.dart b/lib/presentation/viewmodel/order_history_bloc.dart index ff690f4..fb7e752 100644 --- a/lib/presentation/viewmodel/order_history_bloc.dart +++ b/lib/presentation/viewmodel/order_history_bloc.dart @@ -3,7 +3,6 @@ import 'package:be_happy/domain/entities/scooter_order.dart'; import 'package:be_happy/domain/usecase/get_scooter_order_history_usecase.dart'; import 'package:be_happy/core/result.dart'; -// 🔹 EVENTS abstract class OrderHistoryEvent {} class OrderHistoryFetchRequested extends OrderHistoryEvent { @@ -13,7 +12,6 @@ class OrderHistoryFetchRequested extends OrderHistoryEvent { class OrderHistoryRefreshRequested extends OrderHistoryEvent {} -// 🔹 STATES enum OrderHistoryStatus { initial, loading, success, failure, empty } class OrderHistoryState { diff --git a/lib/presentation/viewmodel/payment_confirm_bloc.dart b/lib/presentation/viewmodel/payment_confirm_bloc.dart index 826de8e..4ce9f0f 100644 --- a/lib/presentation/viewmodel/payment_confirm_bloc.dart +++ b/lib/presentation/viewmodel/payment_confirm_bloc.dart @@ -89,12 +89,11 @@ class PaymentConfirmBloc event.isBalance, ); - if (result is Success) { + if (result is Success) { emit( state.copyWith( status: PaymentConfirmStatus.success, paymentCompleted: true, - ), ); } else if (result is Failure) { diff --git a/lib/presentation/viewmodel/payment_methods_bloc.dart b/lib/presentation/viewmodel/payment_methods_bloc.dart index 48bca02..7ac3819 100644 --- a/lib/presentation/viewmodel/payment_methods_bloc.dart +++ b/lib/presentation/viewmodel/payment_methods_bloc.dart @@ -70,13 +70,16 @@ class PaymentMethodsBloc extends Bloc PaymentMethodsDeleteCard event, Emitter emit, ) async { - emit(state.copyWith(isDeleting: true)); + emit(state.copyWith( + status: PaymentMethodsStatus.loading, + isDeleting: true, + )); try { final result = await _removePaymentCardUsecase(event.cardId); if (result is Success) { - emit(state.copyWith(isDeleting: false)); + emit(state.copyWith(isDeleting: false, status: PaymentMethodsStatus.success)); add(PaymentMethodsStarted()); } else if (result is Failure) { String errorMessage = 'Не удалось удалить карту'; diff --git a/lib/presentation/viewmodel/subscription_list_bloc.dart b/lib/presentation/viewmodel/subscription_list_bloc.dart index eee7195..78a0086 100644 --- a/lib/presentation/viewmodel/subscription_list_bloc.dart +++ b/lib/presentation/viewmodel/subscription_list_bloc.dart @@ -1,4 +1,5 @@ import 'package:be_happy/core/result.dart'; +import 'package:be_happy/domain/entities/client_subscription.dart'; import 'package:be_happy/domain/entities/subscription.dart'; import 'package:be_happy/domain/usecase/get_available_subscriptions_usecase.dart'; import 'package:be_happy/domain/usecase/get_client_subscriptions_usecase.dart'; @@ -11,6 +12,7 @@ class SubscriptionListBloc extends Bloc { final GetAvailableSubscriptionsUsecase getAvailableSubscriptionsUsecase; final GetClientSubscriptionsUsecase getClientSubscriptionsUsecase; + SubscriptionListBloc({ required this.getAvailableSubscriptionsUsecase, required this.getClientSubscriptionsUsecase, @@ -26,10 +28,25 @@ class SubscriptionListBloc extends Bloc { final allResult = results[0]; final activeResult = results[1] ; - if (allResult is Success> && activeResult is Success>) { + if (allResult is Success> && activeResult is Success>) { + final availableSubs = allResult.data ?? []; + final clientSubs = activeResult.data ?? []; + + final Map combinedSubsMap = {}; + + for (var clientSub in clientSubs) { + if (clientSub.subscription != null) { + combinedSubsMap[clientSub.subscriptionId] = clientSub.subscription; + } + } + + for (var sub in availableSubs) { + combinedSubsMap[sub.id] = sub; + } + emit(SubscriptionsLoaded( - subscriptions: allResult.data ?? [], - activeSubscriptions: activeResult.data ?? [], + subscriptions: combinedSubsMap.values.toList(), + activeSubscriptions: clientSubs, )); } else { emit(SubscriptionsError("Не удалось загрузить данные из API")); diff --git a/lib/presentation/viewmodel/susbcription_details_bloc.dart b/lib/presentation/viewmodel/susbcription_details_bloc.dart index 68f2265..24d4208 100644 --- a/lib/presentation/viewmodel/susbcription_details_bloc.dart +++ b/lib/presentation/viewmodel/susbcription_details_bloc.dart @@ -4,38 +4,59 @@ import 'package:be_happy/domain/usecase/activate_subscription_usecase.dart'; import 'package:be_happy/domain/usecase/get_subscription_by_id_usecase.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import '../../domain/entities/client_subscription.dart'; +import '../../domain/usecase/get_client_subscriptions_usecase.dart'; import '../event/subscription_details_event.dart'; import '../state/susbcription_details_state.dart'; -class SubscriptionDetailsBloc extends Bloc { +class SubscriptionDetailsBloc + extends Bloc { final GetSubscriptionByIdUsecase getSubscriptionByIdUsecase; final ActivateSubscriptionUsecase activateSubscriptionUsecase; + final GetClientSubscriptionsUsecase getClientSubscriptionsUsecase; - SubscriptionDetailsBloc(this.getSubscriptionByIdUsecase, - this.activateSubscriptionUsecase) : super(DetailsLoading()) { + SubscriptionDetailsBloc( + this.getSubscriptionByIdUsecase, + this.activateSubscriptionUsecase, + this.getClientSubscriptionsUsecase, + ) : super(DetailsLoading()) { on((event, emit) async { emit(DetailsLoading()); try { - final result = await getSubscriptionByIdUsecase(event.subscriptionId); - switch (result) { + final clientSubsResult = await getClientSubscriptionsUsecase(); + bool isPurchased = false; - case Success(): - final sub = result.data; - - if (sub == null) return; - - emit(DetailsContentState( - subscription: sub, - selectedPeriod: sub.options.first, - )); - case Failure(): - emit(DetailsError("Ошибка при запросе данных")); + switch (clientSubsResult) { + case Success>(): + isPurchased = clientSubsResult.data?.any( + (element) => element.subscriptionId == event.subscriptionId, + ) ?? false; + break; + case Failure>(): + isPurchased = false; + break; } + switch (result) { + case Success(): + final sub = result.data; + if (sub == null) return; + emit( + DetailsContentState( + subscription: sub, + selectedPeriod: sub.options.first, + isAlreadyPurchased: isPurchased, + ), + ); + break; + case Failure(): + emit(DetailsError("Ошибка при запросе данных")); + break; + } } catch (e) { emit(DetailsError("Не удалось загрузить данные")); } @@ -43,7 +64,9 @@ class SubscriptionDetailsBloc extends Bloc((event, emit) { if (state is DetailsContentState) { - emit((state as DetailsContentState).copyWith(selectedPeriod: event.period)); + emit( + (state as DetailsContentState).copyWith(selectedPeriod: event.period), + ); } }); @@ -53,14 +76,23 @@ class SubscriptionDetailsBloc extends Bloc((event, emit) { - switch(state) { + on((event, emit) async { + switch (state) { case DetailsContentState contentState: - activateSubscriptionUsecase(contentState.selectedPeriod.id); + if (!contentState.isAgreed) { + return; + } + + final result = await activateSubscriptionUsecase(contentState.selectedPeriod.id); + + if (result is Success) { + emit(contentState.copyWith(isSuccess: true)); + } else { + } break; default: break; } }); } -} \ No newline at end of file +} diff --git a/pubspec.yaml b/pubspec.yaml index 4ab4aac..b687ce5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -54,6 +54,11 @@ flutter: - assets/ - assets/icons/ + fonts: + - family: "DigitalNumbers" + fonts: + - asset: assets/fonts/DigitalNumbers-Regular.ttf + # fonts: # - family: Schyler