From a556dc573687dd7ee37f3d5157f3fc08e775f60f Mon Sep 17 00:00:00 2001 From: Polyanka Date: Sat, 29 Aug 2026 00:00:09 +0300 Subject: [PATCH] bug fixes --- lib/data/network/api_service.dart | 29 ++++ .../repositories/zone_repository_impl.dart | 88 +++++----- lib/di/service_locator.dart | 4 + lib/domain/entities/tariff.dart | 3 - lib/domain/entities/zone.dart | 99 +++++------- lib/domain/repositories/zone_repository.dart | 1 + lib/domain/usecase/get_all_zones_usecase.dart | 30 ++++ .../components/scooter_bottom_sheet.dart | 2 +- .../components/sheet/tariff_info_sheet.dart | 3 +- .../components/sheet/tariff_sheet.dart | 2 +- .../screens/onboarding_screen.dart | 2 +- lib/presentation/screens/profile_screen.dart | 150 +++++++++--------- .../screens/send_photo_screen.dart | 56 +++++-- lib/presentation/viewmodel/map_bloc.dart | 143 ++++++++--------- pubspec.lock | 20 +-- 15 files changed, 361 insertions(+), 271 deletions(-) create mode 100644 lib/domain/usecase/get_all_zones_usecase.dart diff --git a/lib/data/network/api_service.dart b/lib/data/network/api_service.dart index 7897d52..c41151e 100644 --- a/lib/data/network/api_service.dart +++ b/lib/data/network/api_service.dart @@ -498,6 +498,35 @@ class ApiService { } } + Future getAllZones({ + int page = 1, + int pageSize = 500, + }) async { + const path = "$baseUrl/zone/available2"; + + final queryParams = { + 'readAll': 'true', + 'page': page, + 'pageSize': pageSize, + }; + + try { + final response = await _dio.get( + path, + queryParameters: queryParams, + options: await _getAuthOptions(), + ); + + if (response.statusCode == 200) { + return ZonesResponse.fromJson(response.data); + } + return null; + } catch (e) { + print("ERROR: getZones failed: $e"); + return null; + } + } + Future getAvailableTariffs({required int scooterId}) async { final url = "$baseUrl/scooterplan/$scooterId/available"; diff --git a/lib/data/repositories/zone_repository_impl.dart b/lib/data/repositories/zone_repository_impl.dart index 009714a..243c2b4 100644 --- a/lib/data/repositories/zone_repository_impl.dart +++ b/lib/data/repositories/zone_repository_impl.dart @@ -10,60 +10,60 @@ class ZoneRepositoryImpl extends ZoneRepository { ZoneRepositoryImpl(this._apiService); @override - Future> getZones(List area, - int page, - int pageSize,) async { - + Future> getZones(List area, int page, int pageSize) async { final List list = []; final List list2 = []; - /*list.add(Point(55.182372,30.203347)); - list.add(Point(55.173746,30.200257)); - list.add(Point(55.172153,30.212531)); - list.add(Point(55.179946,30.215964)); - - list2.add(Point(55.178304,30.227380)); - list2.add(Point(55.178059,30.229654)); - list2.add(Point(55.191339,30.234718)); - list2.add(Point(55.194352,30.234890)); - list2.add(Point(55.194377,30.231972)); - list2.add(Point(55.192123,30.232744)); - - final zone = Zone(id: 123, - title: "Zone 01", - description: "description", - type: "Finish", - isActive: true, - shapeType: "polygon", - points: list, - speedLimit: "speedLimit"); - - final zone2 = Zone(id: 124, - title: "Zone 02", - description: "description", - type: "NotDrive", - isActive: true, - shapeType: "polygon", - points: list2, - speedLimit: "speedLimit"); -*/ - final responce = await _apiService.getZones( area: area, page: page, pageSize: pageSize, ); - final List? zones = responce?.zones; - // zones?.add(zone); - // zones?.add(zone2); - - print("Scooters: ${zones?.first.title}"); - - if (responce != null) { - return zones ?? List.empty(); + if (responce == null) { + throw Exception( + 'Failed to load zones for area: empty response from server', + ); } - return List.empty(); + final zones = responce.zones; + + print("Zones: ${zones.length}"); + + return zones; + } + + @override + Future> getAllZones(int page, int pageSize) async { + final List list = []; + final List list2 = []; + + final responce = await _apiService.getAllZones( + page: page, + pageSize: pageSize, + ); + + // apiService.getAllZones ловит свои ошибки (сеть/401/5xx) и в этом + // случае возвращает null. Раньше это тихо превращалось в "зон нет" — + // из-за чего сбой запроса выглядел как легитимный пустой ответ и + // (в связке с кешем на уровне MapBloc) навсегда "прятал" зоны на + // время сессии. Бросаем исключение, чтобы вызывающий код (usecase/bloc) + // мог отличить реальный сбой от честного "зон действительно нет" + // и, при необходимости, повторить запрос. + if (responce == null) { + throw Exception('Failed to load zones: empty response from server'); + } + + final zones = responce.zones; + + print(zones.map((z) => '${z.type}:${z.id}')); + + for (final z in zones) { + print("Zone ${z.type}:${z.id} geometry.length=${z.geometry.length}"); + } + + print("Zones: ${zones.length}"); + + return zones; } } diff --git a/lib/di/service_locator.dart b/lib/di/service_locator.dart index a6545c0..3eb8530 100644 --- a/lib/di/service_locator.dart +++ b/lib/di/service_locator.dart @@ -18,6 +18,7 @@ import 'package:be_happy/domain/repositories/zone_repository.dart'; import 'package:be_happy/domain/service/security_service.dart'; import 'package:be_happy/domain/usecase/add_payment_card_usecase.dart'; // ← новый import 'package:be_happy/domain/usecase/delete_profile_usecase.dart'; +import 'package:be_happy/domain/usecase/get_all_zones_usecase.dart'; import 'package:be_happy/domain/usecase/get_certificates_usecase.dart'; import 'package:be_happy/domain/usecase/get_scooter_order_route_history_usecase.dart'; import 'package:be_happy/domain/usecase/is_pin_set_usecase.dart'; @@ -239,6 +240,9 @@ Future setupDependencies() async { getIt.registerSingleton( GetAvailableZonesUsecase(getIt()), ); + getIt.registerSingleton( + GetAllZonesUsecase(getIt()), + ); getIt.registerSingleton( GetMapSettingsUsecase(getIt()), ); diff --git a/lib/domain/entities/tariff.dart b/lib/domain/entities/tariff.dart index ea07259..a999e32 100644 --- a/lib/domain/entities/tariff.dart +++ b/lib/domain/entities/tariff.dart @@ -2,7 +2,6 @@ class Tariff { final int id; final String title; final String description; - final String descriptionJson; final bool isActive; final String currency; final double holdPrice; // Старт / бронь @@ -16,7 +15,6 @@ class Tariff { required this.id, required this.title, required this.description, - required this.descriptionJson, required this.isActive, required this.currency, required this.holdPrice, @@ -35,7 +33,6 @@ class Tariff { id: json['id'] ?? 0, title: json['title'] ?? 'Unknown', description: json['description'] ?? '', - descriptionJson: json['descriptionJson'] ?? '', isActive: json['isActive'] ?? false, currency: currency['currency'] ?? 'BYN', holdPrice: (planPrice['hold'] as num?)?.toDouble() ?? 0.0, diff --git a/lib/domain/entities/zone.dart b/lib/domain/entities/zone.dart index 5e693b4..46a75bb 100644 --- a/lib/domain/entities/zone.dart +++ b/lib/domain/entities/zone.dart @@ -1,4 +1,6 @@ + import 'dart:convert'; + import 'package:be_happy/domain/entities/point.dart'; class Zone { @@ -8,9 +10,6 @@ class Zone { final String type; final bool isActive; final String shapeType; - // Трехмерная структура для поддержки MultiPolygon и дыр (holes): - // geometry[индекс_полигона][индекс_кольца][индекс_точки] - // индекс_кольца == 0 — внешняя граница, > 0 — внутренние вырезы (дыры) final List>> geometry; final String speedLimit; @@ -25,7 +24,6 @@ class Zone { required this.speedLimit, }); - // Геттер для обратной совместимости (возвращает внешнее кольцо первого полигона) List get points { if (geometry.isNotEmpty && geometry[0].isNotEmpty) { return geometry[0][0]; @@ -45,77 +43,64 @@ class Zone { if (decoded is List && decoded.isNotEmpty) { if (shapeType == 'Polygon') { - // Структура: [[[lon, lat], [lon, lat], ...], [hole1], ...] - List> polygonRings = []; - for (var ring in decoded) { - if (ring is List) { - List ringPoints = []; - for (var coord in ring) { - if (coord is List && coord.length >= 2) { - // В GeoJSON сначала идет Longitude, затем Latitude - ringPoints.add(Point( - (coord[1] as num).toDouble(), - (coord[0] as num).toDouble(), - )); - } - } - if (ringPoints.isNotEmpty) polygonRings.add(ringPoints); - } - } + final polygonRings = _parseRings(decoded); if (polygonRings.isNotEmpty) parsedGeometry.add(polygonRings); - } else if (shapeType == 'MultiPolygon') { - // Структура: [[[[lon, lat], ...]], [[[lon, lat], ...]]] for (var poly in decoded) { if (poly is List) { - List> polygonRings = []; - for (var ring in poly) { - if (ring is List) { - List ringPoints = []; - for (var coord in ring) { - if (coord is List && coord.length >= 2) { - ringPoints.add(Point( - (coord[1] as num).toDouble(), - (coord[0] as num).toDouble(), - )); - } - } - if (ringPoints.isNotEmpty) polygonRings.add(ringPoints); - } - } + final polygonRings = _parseRings(poly); if (polygonRings.isNotEmpty) parsedGeometry.add(polygonRings); } } } else { - // Fallback для LineString или плоских списков - List ringPoints = []; - for (var coord in decoded) { - if (coord is List && coord.length >= 2) { - ringPoints.add(Point( - (coord[1] as num).toDouble(), - (coord[0] as num).toDouble(), - )); - } - } - if (ringPoints.isNotEmpty) parsedGeometry.add([ringPoints]); + final singleRing = _parseCoordinateList(decoded); + if (singleRing.isNotEmpty) parsedGeometry.add([singleRing]); } } - } catch (e) { - print("PARSE ERROR for Zone ID ${json['id']}: $e"); + } catch (e, stackTrace) { + // Replace with your project logger (e.g., debugPrint or Logger) + assert(() { + print("PARSE ERROR for Zone ID ${json['id']}: $e\n$stackTrace"); + return true; + }()); } return Zone( - id: json['id'] ?? 0, - title: json['title'] ?? 'Unknown', - description: json['description'] ?? '', - type: json['type'] ?? '', - isActive: json['isActive'] ?? false, - speedLimit: json['speedLimit'] ?? '', + id: json['id'] as int? ?? 0, + title: json['title'] as String? ?? 'Unknown', + description: json['description'] as String? ?? '', + type: json['type'] as String? ?? '', + isActive: json['isActive'] as bool? ?? false, + speedLimit: json['speedLimit'] as String? ?? '', shapeType: shapeType, geometry: parsedGeometry, ); } + static List> _parseRings(List rawRings) { + List> polygonRings = []; + for (var ring in rawRings) { + if (ring is List) { + final ringPoints = _parseCoordinateList(ring); + if (ringPoints.isNotEmpty) polygonRings.add(ringPoints); + } + } + return polygonRings; + } + + static List _parseCoordinateList(List rawCoords) { + List ringPoints = []; + for (var coord in rawCoords) { + if (coord is List && coord.length >= 2) { + ringPoints.add(Point( + (coord[1] as num).toDouble(), + (coord[0] as num).toDouble(), + )); + } + } + return ringPoints; + } + @override String toString() { return 'Zone{id: $id, title: $title, type: $type, polygonsCount: ${geometry.length}}'; diff --git a/lib/domain/repositories/zone_repository.dart b/lib/domain/repositories/zone_repository.dart index 96e3b68..35c05ac 100644 --- a/lib/domain/repositories/zone_repository.dart +++ b/lib/domain/repositories/zone_repository.dart @@ -2,5 +2,6 @@ import '../entities/zone.dart'; abstract class ZoneRepository { Future> getZones(List area, int page, int pageSize); + Future> getAllZones(int page, int pageSize); } diff --git a/lib/domain/usecase/get_all_zones_usecase.dart b/lib/domain/usecase/get_all_zones_usecase.dart new file mode 100644 index 0000000..19b54f9 --- /dev/null +++ b/lib/domain/usecase/get_all_zones_usecase.dart @@ -0,0 +1,30 @@ +import '../entities/zone.dart'; +import '../repositories/zone_repository.dart'; + +class GetAllZonesUsecase { + final ZoneRepository repository; + + GetAllZonesUsecase(this.repository); + + static const int _pageSize = 100; + + Future> call() async { + final List allZones = []; + int page = 0; + + while (true) { + final zones = await repository.getAllZones(page, _pageSize); + + if (zones == null || zones.isEmpty) break; + + allZones.addAll(zones); + + // если пришло меньше, чем размер страницы — это последняя страница + if (zones.length < _pageSize) break; + + page++; + } + + return allZones; + } +} \ No newline at end of file diff --git a/lib/presentation/components/scooter_bottom_sheet.dart b/lib/presentation/components/scooter_bottom_sheet.dart index d31344c..7cfc089 100644 --- a/lib/presentation/components/scooter_bottom_sheet.dart +++ b/lib/presentation/components/scooter_bottom_sheet.dart @@ -240,7 +240,7 @@ class _ScooterCard extends StatelessWidget { showArrows: true, height: 32, width: double.infinity, - fontSize: 12, + fontSize: 11, onTap: () { context.go('/home/scooter/${scooter.id}', extra: [address, scooter.distance]); }, diff --git a/lib/presentation/components/sheet/tariff_info_sheet.dart b/lib/presentation/components/sheet/tariff_info_sheet.dart index c882a8b..12437cf 100644 --- a/lib/presentation/components/sheet/tariff_info_sheet.dart +++ b/lib/presentation/components/sheet/tariff_info_sheet.dart @@ -123,8 +123,7 @@ class _TariffInfoSheetState extends State { crossAxisAlignment: CrossAxisAlignment.stretch, mainAxisSize: MainAxisSize.min, children: ContentParser.parseContent( - textJson: widget.tariff.description, - text: widget.tariff.descriptionJson, + text: widget.tariff.description, ), ), const SizedBox(height: 30), diff --git a/lib/presentation/components/sheet/tariff_sheet.dart b/lib/presentation/components/sheet/tariff_sheet.dart index d8e8658..a57d3c4 100644 --- a/lib/presentation/components/sheet/tariff_sheet.dart +++ b/lib/presentation/components/sheet/tariff_sheet.dart @@ -265,7 +265,7 @@ class _TariffSheetState extends State { const SizedBox(height: 20), SizedBox( - height: 150, + height: 160, child: ListView.builder( scrollDirection: Axis.horizontal, padding: const EdgeInsets.only(left: 20), diff --git a/lib/presentation/screens/onboarding_screen.dart b/lib/presentation/screens/onboarding_screen.dart index a330bf5..a0f279c 100644 --- a/lib/presentation/screens/onboarding_screen.dart +++ b/lib/presentation/screens/onboarding_screen.dart @@ -19,7 +19,7 @@ class _OnboardingScreenState extends State { }, { 'image': 'assets/onboard_2.jpg', - 'title': 'Отсканируйте QR-код или введите номер который указан под козлом', + 'title': 'Отсканируйте QR-код или введите номер который указан под кодом', }, { 'image': 'assets/onboard_3.png', diff --git a/lib/presentation/screens/profile_screen.dart b/lib/presentation/screens/profile_screen.dart index 793cf91..a5102e9 100644 --- a/lib/presentation/screens/profile_screen.dart +++ b/lib/presentation/screens/profile_screen.dart @@ -37,7 +37,6 @@ class _ProfileScreenState extends State { context.read().add( ProfilePhotoUpdated(File(pickedImage.path)), ); - } catch (e) { print("Error picking or uploading image: $e"); } @@ -63,9 +62,7 @@ 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) { @@ -88,82 +85,91 @@ class _ProfileScreenState extends State { 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), + return Column( + children: [ + Expanded( + child: 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, - ), + 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, - ), + GestureDetector( + onTap: _pickImage, + child: Container( + child: Image.asset( + 'assets/icons/edit.png', + width: 24, + height: 24, + ), + ), + ), + ], ), - ), - ], - ), - const SizedBox(height: 32), + const SizedBox(height: 32), - _ProfileInfoBlock( - profile: profile, - onEditTap: () => context.go("/home/profile/edit"), - ), - - Padding( - padding: const EdgeInsets.all(20), - child: GradientButton( - text: 'Удалить учётную запись', - onTap: () => _confirmDeleteAccount(context), - showArrows: true, - height: 56, - width: double.infinity, - fontSize: 16, + _ProfileInfoBlock( + profile: profile, + onEditTap: () => + context.go("/home/profile/edit"), + ), + ], ), ), - ], + ), ), ), - ), + Padding( + padding: const EdgeInsets.all(20), + child: GradientButton( + text: 'Удалить учётную запись', + onTap: () => _confirmDeleteAccount(context), + showArrows: true, + height: 56, + width: double.infinity, + fontSize: 16, + ), + ), + ], ); }, ); @@ -388,4 +394,4 @@ class _SettingsBlock extends StatelessWidget { ), ); } -} \ No newline at end of file +} diff --git a/lib/presentation/screens/send_photo_screen.dart b/lib/presentation/screens/send_photo_screen.dart index e5020db..d91158b 100644 --- a/lib/presentation/screens/send_photo_screen.dart +++ b/lib/presentation/screens/send_photo_screen.dart @@ -116,13 +116,19 @@ class _SendPhotoViewState extends State { @override Widget build(BuildContext context) { + final isUploading = context.select( + (SendPhotoBloc bloc) => bloc.state.status == SendPhotoStatus.loading, + ); + return Scaffold( - body: Container( - width: double.infinity, - decoration: const BoxDecoration(gradient: AppColors.phoneScreenBg), - child: SafeArea( - child: Column( - children: [ + body: Stack( + children: [ + Container( + width: double.infinity, + decoration: const BoxDecoration(gradient: AppColors.phoneScreenBg), + child: SafeArea( + child: Column( + children: [ const SizedBox(height: 16), Padding( padding: const EdgeInsets.symmetric(horizontal: 20), @@ -190,7 +196,8 @@ class _SendPhotoViewState extends State { }, builder: (context, state) { final photoCount = state.selectedImages.length; - final isEnabled = photoCount >= 2; + final isEnabled = photoCount >= 2 && + state.status != SendPhotoStatus.loading; return GradientButton( text: 'Отправить', @@ -210,9 +217,40 @@ class _SendPhotoViewState extends State { ), ), ), - ], + ], + ), + ), ), - ), + // Оверлей загрузки: показывается, пока фото отправляются на сервер + if (isUploading) + Positioned.fill( + child: AbsorbPointer( + absorbing: true, + child: Container( + color: Colors.black.withOpacity(0.45), + child: const Center( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + CircularProgressIndicator( + color: Color(0xFF8BFFAA), + ), + SizedBox(height: 16), + Text( + 'Загружаем фото...', + style: TextStyle( + color: Colors.white, + fontSize: 16, + fontWeight: FontWeight.w600, + ), + ), + ], + ), + ), + ), + ), + ), + ], ), ); } diff --git a/lib/presentation/viewmodel/map_bloc.dart b/lib/presentation/viewmodel/map_bloc.dart index 057e8b5..5cbb60b 100644 --- a/lib/presentation/viewmodel/map_bloc.dart +++ b/lib/presentation/viewmodel/map_bloc.dart @@ -4,7 +4,7 @@ import 'package:be_happy/core/result.dart'; 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_all_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'; @@ -26,7 +26,7 @@ import 'package:maps_toolkit/maps_toolkit.dart' as mt; class MapBloc extends Bloc { final GetAvailableScootersUsecase getScootersUsecase; final GetClientOrdersUsecase getClientOrdersUsecase; - final GetAvailableZonesUsecase getAvailableZonesUsecase; + final GetAllZonesUsecase getAllZonesUsecase; final GetMapSettingsUsecase getMapSettingsUsecase; final GetNotificationsStreamUseCase getNotificationsStreamUseCase; final GetProfileUseCase getProfileUseCase; @@ -35,17 +35,19 @@ class MapBloc extends Bloc { final SplashBloc splashBloc; StreamSubscription? _notificationSubscription; + Future>? _zonesFuture; + MapBloc( - this.getAvailableZonesUsecase, - this.getScootersUsecase, - this.getClientOrdersUsecase, - this.getMapSettingsUsecase, - this.getNotificationsStreamUseCase, - this.getProfileUseCase, - this.checkUserUseCase, - this.logoutUseCase, - this.splashBloc, - ) : super(ScooterState(isGeomarksShowed: true)) { + this.getAllZonesUsecase, + this.getScootersUsecase, + this.getClientOrdersUsecase, + this.getMapSettingsUsecase, + this.getNotificationsStreamUseCase, + this.getProfileUseCase, + this.checkUserUseCase, + this.logoutUseCase, + this.splashBloc, + ) : super(ScooterState(isGeomarksShowed: true)) { on(_onFetchScooters); on(_onUpdateMap); on(_onUpdateUserLocation); @@ -58,11 +60,43 @@ class MapBloc extends Bloc { on(_onClearMapFocus); } + Future> _getZones() async { + _zonesFuture ??= getAllZonesUsecase(); + + try { + return await _zonesFuture!; + } catch (e) { + // Не кешируем неудачную попытку — иначе сбой первого запроса + // (сеть/авторизация) навсегда "выключает" зоны до перезапуска + // приложения. Следующий FetchScooters/UpdateMap попробует заново. + _zonesFuture = null; + rethrow; + } + } + + List _filterZones(List zones, MapSettings settings) { + List filteredZones = []; + + if (settings.all_zones) { + if (settings.parking_zones) { + filteredZones.addAll(zones.where((el) => el.type == "Finish")); + } + if (settings.restricted_parking_zones) { + filteredZones.addAll(zones.where((el) => el.type == "Drive")); + } + if (settings.restricted_driving_zones) { + filteredZones.addAll(zones.where((el) => el.type == "NotDrive")); + } + } + + return filteredZones; + } + void startNotificationStream() { _notificationSubscription?.cancel(); _notificationSubscription = getNotificationsStreamUseCase().listen( - (notification) { + (notification) { add(NotificationReceived(notification)); }, onError: (error) { @@ -94,15 +128,15 @@ class MapBloc extends Bloc { } Future _onFetchScooters( - FetchScooters event, - Emitter emit, - ) async { + FetchScooters event, + Emitter emit, + ) async { emit(state.copyWith(status: ScooterStatus.loading)); try { final results = await Future.wait([ getScootersUsecase(event.areaScooters, 0, 100), - getAvailableZonesUsecase(event.area, 0, 100), + _getZones(), getMapSettingsUsecase(), getClientOrdersUsecase(), ]); @@ -112,23 +146,7 @@ class MapBloc extends Bloc { final settings = results[2] as MapSettings; final orders = results[3]; - - - zones.forEach(print); - - List filteredZones = []; - - if (settings.all_zones) { - if (settings.parking_zones) { - filteredZones.addAll(zones.where((el) => el.type == "Finish")); - } - if (settings.restricted_parking_zones) { - filteredZones.addAll(zones.where((el) => el.type == "Drive")); - } - if (settings.restricted_driving_zones) { - filteredZones.addAll(zones.where((el) => el.type == "NotDrive")); - } - } + final filteredZones = _filterZones(zones, settings); print( " FETCH: filteredZones.length = ${filteredZones.length}, all_zones=${settings.all_zones}", @@ -162,7 +180,7 @@ class MapBloc extends Bloc { try { final results = await Future.wait([ getScootersUsecase(state.areaScooters, 0, 100), - getAvailableZonesUsecase(state.area, 0, 100), + _getZones(), getMapSettingsUsecase(), ]); @@ -170,33 +188,17 @@ class MapBloc extends Bloc { final zones = results[1] as List; final settings = results[2] as MapSettings; - List filteredZones = []; - - if (settings.all_zones) { - if (settings.parking_zones) { - filteredZones.addAll(zones.where((el) => el.type == "Finish")); - } - if (settings.restricted_parking_zones) { - filteredZones.addAll(zones.where((el) => el.type == "Drive")); - } - if (settings.restricted_driving_zones) { - filteredZones.addAll(zones.where((el) => el.type == "NotDrive")); - } - } + final filteredZones = _filterZones(zones, settings); print( " UPDATE MAP: filteredZones.length = ${filteredZones.length}, all_zones=${settings.all_zones}", ); - final zonesToEmit = filteredZones.isNotEmpty - ? filteredZones - : state.zones; - emit( state.copyWith( status: ScooterStatus.success, scooters: scooters, - zones: zonesToEmit, + zones: filteredZones, isGeomarksShowed: settings.all_placemarks, ), ); @@ -212,9 +214,9 @@ class MapBloc extends Bloc { } FutureOr _onUpdateUserLocation( - UpdateUserLocation event, - Emitter emit, - ) { + UpdateUserLocation event, + Emitter emit, + ) { print("USER LOCATION UPDATED EVENT start"); state.zones.forEach((z) { if (checkUserInZone(Point(event.latitude, event.longitude), z.points)) { @@ -224,9 +226,9 @@ class MapBloc extends Bloc { } FutureOr _onNotificationReceived( - NotificationReceived event, - Emitter emit, - ) { + NotificationReceived event, + Emitter emit, + ) { print("NOTIFICATION RECEIVED: ${event.notification.content}"); emit(state.copyWith(lastNotification: event.notification)); } @@ -242,9 +244,9 @@ class MapBloc extends Bloc { } FutureOr _onFetchProfileData( - FetchProfileData event, - Emitter emit, - ) async { + FetchProfileData event, + Emitter emit, + ) async { try { final profile = await getProfileUseCase(); @@ -262,18 +264,19 @@ class MapBloc extends Bloc { } FutureOr _onLogoutPressed( - LogoutPressed event, - Emitter emit, - ) async { + LogoutPressed event, + Emitter emit, + ) async { await logoutUseCase(); stopNotificationStream(); + _zonesFuture = null; splashBloc.add(AuthLogoutRequested()); } FutureOr _onCheckUser( - CheckUser event, - Emitter emit, - ) async { + CheckUser event, + Emitter emit, + ) async { try { final flags = await checkUserUseCase(); @@ -341,6 +344,4 @@ class MapBloc extends Bloc { selectedScooterForFocus: null, )); } -} - - +} \ No newline at end of file diff --git a/pubspec.lock b/pubspec.lock index dd176cc..abe5e46 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -77,10 +77,10 @@ packages: dependency: transitive description: name: characters - sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b + sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 url: "https://pub.dev" source: hosted - version: "1.4.1" + version: "1.4.0" checked_yaml: dependency: transitive description: @@ -633,26 +633,26 @@ packages: dependency: transitive description: name: matcher - sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861 + sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 url: "https://pub.dev" source: hosted - version: "0.12.19" + version: "0.12.17" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b" + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec url: "https://pub.dev" source: hosted - version: "0.13.0" + version: "0.11.1" meta: dependency: transitive description: name: meta - sha256: "1741988757a65eb6b36abe716829688cf01910bbf91c34354ff7ec1c3de2b349" + sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.17.0" mime: dependency: "direct main" description: @@ -910,10 +910,10 @@ packages: dependency: transitive description: name: test_api - sha256: "949a932224383300f01be9221c39180316445ecb8e7547f70a41a35bf421fb9e" + sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55 url: "https://pub.dev" source: hosted - version: "0.7.11" + version: "0.7.7" typed_data: dependency: transitive description: