bug fixes

This commit is contained in:
2026-09-04 13:41:57 +03:00
parent cf5b56e365
commit 5f57af2ad2
14 changed files with 201 additions and 89 deletions

View File

@@ -10,6 +10,6 @@ class AppSettingsService {
} }
bool getMapSettingsFlag(String key) { bool getMapSettingsFlag(String key) {
return sharedPreferences.getBool(key) ?? false; return sharedPreferences.getBool(key) ?? true;
} }
} }

View File

@@ -6,10 +6,10 @@ class MapSettings {
final bool restricted_driving_zones; final bool restricted_driving_zones;
MapSettings({ MapSettings({
required this.all_placemarks, this.all_placemarks = true,
required this.all_zones, this.all_zones = true,
required this.parking_zones, this.parking_zones = true,
required this.restricted_parking_zones, this.restricted_parking_zones = true,
required this.restricted_driving_zones, this.restricted_driving_zones = true,
}); });
} }

View File

@@ -73,7 +73,6 @@ class MapSettingsSheet extends StatelessWidget {
TextButton( TextButton(
onPressed: () { onPressed: () {
context.read<MapSettingsModalBloc>().add(ApllyButtonClick()); context.read<MapSettingsModalBloc>().add(ApllyButtonClick());
context.read<MapBloc>().add(UpdateMap());
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },
child: const Text( child: const Text(

View File

@@ -3,8 +3,10 @@ import 'dart:ui';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import '../../../di/service_locator.dart'; import '../../../di/service_locator.dart';
import '../../event/map_event.dart';
import '../../event/reserved_ride_event.dart'; import '../../event/reserved_ride_event.dart';
import '../../state/reserved_ride_state.dart'; import '../../state/reserved_ride_state.dart';
import '../../viewmodel/map_bloc.dart';
import '../../viewmodel/reserved_ride_bloc.dart'; import '../../viewmodel/reserved_ride_bloc.dart';
import '../dialog/cancel_booking_dialog.dart'; import '../dialog/cancel_booking_dialog.dart';
import '../gradient_button.dart'; import '../gradient_button.dart';
@@ -125,7 +127,6 @@ class _ReservedRideSheetState extends State<ReservedRideSheet> {
const SizedBox(height: 20), const SizedBox(height: 20),
// ТАЙМЕР + ИНФО О САМОКАТЕ (КОМПАКТНЫЙ)
Padding( Padding(
padding: const EdgeInsets.symmetric(horizontal: 20), padding: const EdgeInsets.symmetric(horizontal: 20),
child: Row( child: Row(
@@ -227,6 +228,7 @@ class _ReservedRideSheetState extends State<ReservedRideSheet> {
listener: (context, state) { listener: (context, state) {
if (state.rideStarted) { if (state.rideStarted) {
Navigator.pop(context); Navigator.pop(context);
context.read<MapBloc>().add(FetchActiveOrders());
showModalBottomSheet( showModalBottomSheet(
context: context, context: context,
isScrollControlled: true, isScrollControlled: true,

View File

@@ -15,9 +15,11 @@ import '../../../domain/usecase/add_payment_card_usecase.dart';
import '../../../domain/usecase/get_payment_cards_usecase.dart'; import '../../../domain/usecase/get_payment_cards_usecase.dart';
import '../../../domain/usecase/get_profile_usecase.dart'; import '../../../domain/usecase/get_profile_usecase.dart';
import '../../../domain/usecase/set_main_payment_card_usecase.dart'; import '../../../domain/usecase/set_main_payment_card_usecase.dart';
import '../../event/map_event.dart';
import '../../event/payment_method_sheet_event.dart'; import '../../event/payment_method_sheet_event.dart';
import '../../event/tariff_sheet_event.dart'; import '../../event/tariff_sheet_event.dart';
import '../../state/tariff_sheet_state.dart'; import '../../state/tariff_sheet_state.dart';
import '../../viewmodel/map_bloc.dart';
import '../../viewmodel/tariff_sheet_bloc.dart'; import '../../viewmodel/tariff_sheet_bloc.dart';
import '../gradient_button.dart'; import '../gradient_button.dart';
import '../scooter/mini_battery_indicator.dart'; import '../scooter/mini_battery_indicator.dart';
@@ -62,6 +64,14 @@ class _TariffSheetState extends State<TariffSheet> {
} }
return BlocConsumer<TariffSheetBloc, TariffSheetState>( return BlocConsumer<TariffSheetBloc, TariffSheetState>(
listener: (context, state) { listener: (context, state) {
if (state.status == TariffSheetStatus.success &&
state.tariffs.isNotEmpty &&
_selectedTariffIndex == null) {
setState(() {
_selectedTariffIndex = 0;
});
}
if (state.status == TariffSheetStatus.failure && state.errorMessage != null) { if (state.status == TariffSheetStatus.failure && state.errorMessage != null) {
ScaffoldMessenger.of(context).hideCurrentSnackBar(); ScaffoldMessenger.of(context).hideCurrentSnackBar();
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
@@ -82,6 +92,8 @@ class _TariffSheetState extends State<TariffSheet> {
} }
}, },
builder: (context, state) { builder: (context, state) {
final selectedIndex = _selectedTariffIndex ?? (state.tariffs.isNotEmpty ? 0 : null);
if (state.status == TariffSheetStatus.loading) { if (state.status == TariffSheetStatus.loading) {
return Align( return Align(
alignment: Alignment.bottomCenter, alignment: Alignment.bottomCenter,
@@ -283,7 +295,7 @@ class _TariffSheetState extends State<TariffSheet> {
'Далее ${tariff.drivePrice.toStringAsFixed(2)} ${tariff.currency}/мин.', 'Далее ${tariff.drivePrice.toStringAsFixed(2)} ${tariff.currency}/мин.',
'Минута на паузе ${tariff.pausePrice.toStringAsFixed(2)} ${tariff.currency}', 'Минута на паузе ${tariff.pausePrice.toStringAsFixed(2)} ${tariff.currency}',
], ],
isSelected: _selectedTariffIndex == index, isSelected: selectedIndex == index,
isInsurance: state.isInsurance, isInsurance: state.isInsurance,
tariff: tariff, tariff: tariff,
onTap: () { onTap: () {
@@ -412,19 +424,20 @@ class _TariffSheetState extends State<TariffSheet> {
height: 56, height: 56,
width: double.infinity, width: double.infinity,
fontSize: 16, fontSize: 16,
enabled: _selectedTariffIndex != null && (state.selectedCard != null || state.useBalance), enabled: selectedIndex != null && (state.selectedCard != null || state.useBalance),
onTap: (_selectedTariffIndex != null && (state.selectedCard != null || state.useBalance)) onTap: (selectedIndex != null && (state.selectedCard != null || state.useBalance))
? () { ? () {
context.read<TariffSheetBloc>().add( context.read<TariffSheetBloc>().add(
BookScooterPressed( BookScooterPressed(
widget.scooter.id, widget.scooter.id,
state.tariffs[_selectedTariffIndex!].id, state.tariffs[selectedIndex].id,
state.tariffs[_selectedTariffIndex!].subscriptionId, state.tariffs[selectedIndex].subscriptionId,
state.useBalance ? null : state.selectedCard?.id, state.useBalance ? null : state.selectedCard?.id,
state.useBalance, state.useBalance,
state.isInsurance state.isInsurance
) )
); );
context.read<MapBloc>().add(FetchActiveOrders());
context.pushReplacement('/home/current-rides-sheet'); context.pushReplacement('/home/current-rides-sheet');
} }
: null, : null,

View File

@@ -38,6 +38,8 @@ class FocusOnScooter extends ScooterEvent {
class ClearMapPlacemarks extends ScooterEvent {} class ClearMapPlacemarks extends ScooterEvent {}
class ClearMapFocus extends ScooterEvent {} class ClearMapFocus extends ScooterEvent {}
class FetchActiveOrders extends ScooterEvent {}

View File

@@ -71,10 +71,10 @@ class _MapScreenState extends State<MapScreen> {
BlocConsumer<MapBloc, ScooterState>( BlocConsumer<MapBloc, ScooterState>(
listenWhen: (previous, current) { listenWhen: (previous, current) {
return current.lastNotification != return current.lastNotification !=
previous.lastNotification || previous.lastNotification ||
current.flags != previous.flags || current.flags != previous.flags ||
previous.selectedScooterForFocus?.id previous.selectedScooterForFocus?.id !=
!= current.selectedScooterForFocus?.id; current.selectedScooterForFocus?.id;
}, },
listener: (context, state) { listener: (context, state) {
@@ -176,7 +176,8 @@ class _MapScreenState extends State<MapScreen> {
final reservedScooters = _buildScooterPlacemarks( final reservedScooters = _buildScooterPlacemarks(
scooters: state.reservedScooters ?? [], scooters: state.reservedScooters ?? [],
iconAsset: 'assets/icons/scooter_reserved_placemark_fill.png', iconAsset:
'assets/icons/scooter_reserved_placemark_fill.png',
isClickable: false, isClickable: false,
); );
@@ -193,10 +194,10 @@ class _MapScreenState extends State<MapScreen> {
}, },
onCameraPositionChanged: onCameraPositionChanged:
(cameraPosition, reason, finished) { (cameraPosition, reason, finished) {
if (finished) { if (finished) {
_fetchScooters(); _fetchScooters();
} }
}, },
mapObjects: [ mapObjects: [
...zonePolygons, ...zonePolygons,
...reservedScooters, ...reservedScooters,
@@ -210,7 +211,7 @@ class _MapScreenState extends State<MapScreen> {
final clusteredPlacemarks = cluster.placemarks; final clusteredPlacemarks = cluster.placemarks;
final filtered = state.scooters.where((scooter) { final filtered = state.scooters.where((scooter) {
return clusteredPlacemarks.any( return clusteredPlacemarks.any(
(pm) => pm.mapId.value == scooter.id.toString(), (pm) => pm.mapId.value == scooter.id.toString(),
); );
}).toList(); }).toList();
_onMarkerTap(filtered); _onMarkerTap(filtered);
@@ -241,7 +242,7 @@ class _MapScreenState extends State<MapScreen> {
BlocBuilder<MapBloc, ScooterState>( BlocBuilder<MapBloc, ScooterState>(
buildWhen: (previous, current) => buildWhen: (previous, current) =>
previous.status != current.status, previous.status != current.status,
builder: (context, state) { builder: (context, state) {
if (state.status == ScooterStatus.loading) { if (state.status == ScooterStatus.loading) {
return const Positioned( return const Positioned(
@@ -368,6 +369,7 @@ class _MapScreenState extends State<MapScreen> {
} }
}); });
} }
Future<void> _moveCameraToPoint( Future<void> _moveCameraToPoint(
double lat, double lat,
double lon, { double lon, {
@@ -401,17 +403,13 @@ class _MapScreenState extends State<MapScreen> {
} }
if (flags.hasUnpaidOrder) { if (flags.hasUnpaidOrder) {
_showExistingNotification( _showExistingNotification(
child: UnpaidOrderNotificationCard( child: UnpaidOrderNotificationCard(onClose: () => BotToast.cleanAll()),
onClose: () => BotToast.cleanAll(),
),
); );
return; return;
} }
if (flags.hasFine) { if (flags.hasFine) {
_showExistingNotification( _showExistingNotification(
child: FineNotificationCard( child: FineNotificationCard(onClose: () => BotToast.cleanAll()),
onClose: () => BotToast.cleanAll(),
),
); );
return; return;
} }
@@ -567,7 +565,8 @@ class _MapScreenState extends State<MapScreen> {
}) { }) {
return scooters.map((scooter) { return scooters.map((scooter) {
return PlacemarkMapObject( return PlacemarkMapObject(
mapId: MapObjectId('${isClickable ? "" : "reserved_"}${scooter.id}'), // уникальный ID для карты mapId: MapObjectId('${isClickable ? "" : "reserved_"}${scooter.id}'),
// уникальный ID для карты
point: Point(latitude: scooter.longitude, longitude: scooter.latitude), point: Point(latitude: scooter.longitude, longitude: scooter.latitude),
icon: PlacemarkIcon.single( icon: PlacemarkIcon.single(
PlacemarkIconStyle( PlacemarkIconStyle(
@@ -595,7 +594,9 @@ class _MapScreenState extends State<MapScreen> {
for (var polygonData in zone.geometry) { for (var polygonData in zone.geometry) {
if (polygonData.isEmpty) continue; if (polygonData.isEmpty) continue;
var outerPoints = polygonData[0].map((p) => Point(latitude: p.latitude, longitude: p.longitude)).toList(); var outerPoints = polygonData[0]
.map((p) => Point(latitude: p.latitude, longitude: p.longitude))
.toList();
var cleanPoints = <Point>[]; var cleanPoints = <Point>[];
for (var p in outerPoints) { for (var p in outerPoints) {
@@ -619,12 +620,14 @@ class _MapScreenState extends State<MapScreen> {
PolygonMapObject( PolygonMapObject(
mapId: const MapObjectId('global_inverse_mask'), mapId: const MapObjectId('global_inverse_mask'),
polygon: Polygon( polygon: Polygon(
outerRing: const LinearRing(points: [ outerRing: const LinearRing(
Point(latitude: 85, longitude: -179.9), points: [
Point(latitude: 85, longitude: 179.9), Point(latitude: 85, longitude: -179.9),
Point(latitude: -85, longitude: 179.9), Point(latitude: 85, longitude: 179.9),
Point(latitude: -85, longitude: -179.9), Point(latitude: -85, longitude: 179.9),
]), Point(latitude: -85, longitude: -179.9),
],
),
innerRings: driveOuterRings, // Вырезаем только зоны Drive innerRings: driveOuterRings, // Вырезаем только зоны Drive
), ),
strokeWidth: 0, strokeWidth: 0,
@@ -641,13 +644,17 @@ class _MapScreenState extends State<MapScreen> {
// Стилизация в зависимости от типа зоны // Стилизация в зависимости от типа зоны
if (zone.type == "Drive") { if (zone.type == "Drive") {
borderColor = const Color(0xFF5ECD4C); // Зеленый бордюр borderColor = const Color(0xFF5ECD4C); // Зеленый бордюр
fillColor = Colors.transparent; // Прозрачная внутри маски fillColor = Colors.transparent; // Прозрачная внутри маски
} else if (zone.type == "NotDrive") { } else if (zone.type == "NotDrive") {
borderColor = const Color(0xFFEF4444); // Красный бордюр borderColor = const Color(0xFFEF4444); // Красный бордюр
fillColor = const Color(0xFFEF4444).withOpacity(0.3); // Красная полупрозрачная заливка для наглядности внутри Drive fillColor = const Color(0xFFEF4444).withOpacity(
0.3,
); // Красная полупрозрачная заливка для наглядности внутри Drive
} else { } else {
borderColor = const Color(0xFFA78BFA); // Фиолетовый бордюр (Парковка) borderColor = const Color(0xFFA78BFA); // Фиолетовый бордюр (Парковка)
fillColor = const Color(0xFFA78BFA).withOpacity(0.25); // Фиолетовая заливка fillColor = const Color(
0xFFA78BFA,
).withOpacity(0.25); // Фиолетовая заливка
} }
int polyIndex = 0; int polyIndex = 0;
@@ -655,7 +662,9 @@ class _MapScreenState extends State<MapScreen> {
if (polygonData.isEmpty) continue; if (polygonData.isEmpty) continue;
// Строим внешнее кольцо текущего полигона // Строим внешнее кольцо текущего полигона
var outerPoints = polygonData[0].map((p) => Point(latitude: p.latitude, longitude: p.longitude)).toList(); var outerPoints = polygonData[0]
.map((p) => Point(latitude: p.latitude, longitude: p.longitude))
.toList();
if (outerPoints.first != outerPoints.last) { if (outerPoints.first != outerPoints.last) {
outerPoints.add(outerPoints.first); outerPoints.add(outerPoints.first);
} }
@@ -664,7 +673,9 @@ class _MapScreenState extends State<MapScreen> {
// Строим внутренние кольца (дыры), если они есть у этого полигона // Строим внутренние кольца (дыры), если они есть у этого полигона
List<LinearRing> innerRings = []; List<LinearRing> innerRings = [];
for (int i = 1; i < polygonData.length; i++) { for (int i = 1; i < polygonData.length; i++) {
var innerPoints = polygonData[i].map((p) => Point(latitude: p.latitude, longitude: p.longitude)).toList(); var innerPoints = polygonData[i]
.map((p) => Point(latitude: p.latitude, longitude: p.longitude))
.toList();
if (innerPoints.isNotEmpty) { if (innerPoints.isNotEmpty) {
if (innerPoints.first != innerPoints.last) { if (innerPoints.first != innerPoints.last) {
innerPoints.add(innerPoints.first); innerPoints.add(innerPoints.first);
@@ -677,10 +688,7 @@ class _MapScreenState extends State<MapScreen> {
objects.add( objects.add(
PolygonMapObject( PolygonMapObject(
mapId: MapObjectId('zone_poly_${zone.type}_${zone.id}_$polyIndex'), mapId: MapObjectId('zone_poly_${zone.type}_${zone.id}_$polyIndex'),
polygon: Polygon( polygon: Polygon(outerRing: outerRing, innerRings: innerRings),
outerRing: outerRing,
innerRings: innerRings,
),
strokeColor: borderColor, strokeColor: borderColor,
strokeWidth: 2.0, strokeWidth: 2.0,
fillColor: fillColor, fillColor: fillColor,
@@ -707,7 +715,7 @@ class _MapScreenState extends State<MapScreen> {
onPressed: () { onPressed: () {
context.read<MapBloc>().add(FetchProfileData()); context.read<MapBloc>().add(FetchProfileData());
Scaffold.of(innerContext).openDrawer(); Scaffold.of(innerContext).openDrawer();
}, },
), ),
), ),
), ),
@@ -721,10 +729,21 @@ class _MapScreenState extends State<MapScreen> {
onPressed: () => context.push("/home/notifications"), onPressed: () => context.push("/home/notifications"),
), ),
const SizedBox(height: 12), const SizedBox(height: 12),
_RoundButton( BlocBuilder<MapBloc, ScooterState>(
imagePath: 'assets/icons/scooter_placemark.png', buildWhen: (previous, current) =>
onPressed: () => context.push("/home/current-rides-sheet"), previous.activeRidesCount != current.activeRidesCount,
) builder: (context, state) {
return _RoundButton(
imagePath: 'assets/icons/scooter_placemark.png',
count: state.activeRidesCount ?? 0,
onPressed: () {
context.push("/home/current-rides-sheet").then((_) {
context.read<MapBloc>().add(FetchActiveOrders());
});
},
);
},
),
], ],
), ),
), ),
@@ -765,9 +784,7 @@ class _MapScreenState extends State<MapScreen> {
} }
if (flags.hasFine) { if (flags.hasFine) {
_showExistingNotification( _showExistingNotification(
child: FineNotificationCard( child: FineNotificationCard(onClose: () => BotToast.cleanAll()),
onClose: () => BotToast.cleanAll(),
),
); );
return; return;
} }
@@ -870,32 +887,63 @@ class _RoundIconButton extends StatelessWidget {
class _RoundButton extends StatelessWidget { class _RoundButton extends StatelessWidget {
final String imagePath; final String imagePath;
final VoidCallback onPressed; final VoidCallback onPressed;
final int count;
const _RoundButton({ const _RoundButton({
required this.imagePath, required this.imagePath,
required this.onPressed, required this.onPressed,
this.count = 0,
}); });
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return GestureDetector(
width: 40, onTap: onPressed,
height: 40, child: Stack(
decoration: BoxDecoration( clipBehavior: Clip.none,
color: AppColors.darkBlue, children: [
borderRadius: BorderRadius.circular(12), Container(
), width: 40,
child: GestureDetector( height: 40,
onTap: onPressed, decoration: BoxDecoration(
child: Center( color: AppColors.darkBlue,
child: Image.asset( borderRadius: BorderRadius.circular(12),
imagePath, ),
width: 20, child: Center(
height: 20, child: Image.asset(
fit: BoxFit.contain, imagePath,
color: Colors.white, width: 20,
height: 20,
fit: BoxFit.contain,
color: Colors.white,
),
),
), ),
), if (count > 0)
Positioned(
top: -4,
right: -4,
child: Container(
padding: const EdgeInsets.all(4),
decoration: const BoxDecoration(
color: Colors.redAccent,
shape: BoxShape.circle,
),
constraints: const BoxConstraints(minWidth: 18, minHeight: 18),
child: Center(
child: Text(
'$count',
style: const TextStyle(
color: Colors.white,
fontSize: 10,
fontWeight: FontWeight.bold,
),
textAlign: TextAlign.center,
),
),
),
),
],
), ),
); );
} }
@@ -929,10 +977,12 @@ void _showExistingNotification({required Widget child}) {
duration: null, // не исчезает, пока пользователь не закроет duration: null, // не исчезает, пока пользователь не закроет
toastBuilder: (_) { toastBuilder: (_) {
return Container( return Container(
margin: const EdgeInsets.only(top: 120), // тот же отступ, что в listener margin: const EdgeInsets.only(top: 120),
// тот же отступ, что в listener
child: Material( child: Material(
color: Colors.transparent, color: Colors.transparent,
child: child, // PaymentNotificationCard / UnpaidOrderNotificationCard / FineNotificationCard child:
child, // PaymentNotificationCard / UnpaidOrderNotificationCard / FineNotificationCard
), ),
); );
}, },

View File

@@ -30,13 +30,13 @@ class SupportScreen extends StatelessWidget {
), ),
const Divider(height: 1, color: Colors.white24), const Divider(height: 1, color: Colors.white24),
const SizedBox(height: 12), const SizedBox(height: 12),
LinkRow( /*LinkRow(
icon: 'assets/icons/whatsapp.png', icon: 'assets/icons/whatsapp.png',
title: 'WhatsApp', title: 'WhatsApp',
onTap: () => openLink('https://wa.me/375257110909'), onTap: () => openLink('https://wa.me/375257110909'),
), ),
const Divider(height: 1, color: Colors.white24), const Divider(height: 1, color: Colors.white24),
const SizedBox(height: 12), const SizedBox(height: 12),*/
LinkRow( LinkRow(
icon: 'assets/icons/viber.png', icon: 'assets/icons/viber.png',
title: 'Viber', title: 'Viber',

View File

@@ -6,11 +6,11 @@ class MapSettingsModalState {
final bool isRestrictedParkingZoneActive; final bool isRestrictedParkingZoneActive;
MapSettingsModalState({ MapSettingsModalState({
required this.isAllGeomarksActive, this.isAllGeomarksActive = true,
required this.isAllGeozonesActive, this.isAllGeozonesActive = true,
required this.isRestrictedDrivingZoneActive, this.isRestrictedDrivingZoneActive = true,
required this.isParkingZoneActive, this.isParkingZoneActive = true,
required this.isRestrictedParkingZoneActive, this.isRestrictedParkingZoneActive = true,
}); });
MapSettingsModalState copyWith({ MapSettingsModalState copyWith({

View File

@@ -22,6 +22,7 @@ class ScooterState {
final double balance; final double balance;
final UserCheckFlags flags; final UserCheckFlags flags;
final ClientNotification? lastNotification; final ClientNotification? lastNotification;
final int activeRidesCount;
ScooterState({ ScooterState({
this.scooters = const [], this.scooters = const [],
@@ -38,6 +39,7 @@ class ScooterState {
this.balance = 999, this.balance = 999,
this.flags = const UserCheckFlags(hasFine: false, hasUnpaidOrder: false, hasCard: false), this.flags = const UserCheckFlags(hasFine: false, hasUnpaidOrder: false, hasCard: false),
this.lastNotification, this.lastNotification,
this.activeRidesCount = 0,
}); });
ScooterState copyWith({ ScooterState copyWith({
@@ -55,6 +57,7 @@ class ScooterState {
double? balance, double? balance,
UserCheckFlags? flags, UserCheckFlags? flags,
ClientNotification? lastNotification, ClientNotification? lastNotification,
int? activeRidesCount,
}) { }) {
return ScooterState( return ScooterState(
scooters: scooters ?? this.scooters, scooters: scooters ?? this.scooters,
@@ -71,6 +74,7 @@ class ScooterState {
balance: balance ?? this.balance, balance: balance ?? this.balance,
flags: flags ?? this.flags, flags: flags ?? this.flags,
lastNotification: lastNotification ?? this.lastNotification, lastNotification: lastNotification ?? this.lastNotification,
activeRidesCount: activeRidesCount ?? this.activeRidesCount,
); );
} }
} }

View File

@@ -17,7 +17,7 @@ class TariffSheetState {
this.status = TariffSheetStatus.initial, this.status = TariffSheetStatus.initial,
this.tariffs = const [], this.tariffs = const [],
this.selectedCard, this.selectedCard,
this.isInsurance = false, this.isInsurance = true,
this.errorMessage, this.errorMessage,
this.userBalance = 0, this.userBalance = 0,
this.useBalance = false, this.useBalance = false,

View File

@@ -34,6 +34,7 @@ class MapBloc extends Bloc<ScooterEvent, ScooterState> {
final LogoutUseCase logoutUseCase; final LogoutUseCase logoutUseCase;
final SplashBloc splashBloc; final SplashBloc splashBloc;
StreamSubscription<ClientNotification>? _notificationSubscription; StreamSubscription<ClientNotification>? _notificationSubscription;
Timer? _ordersTimer;
Future<List<Zone>>? _zonesFuture; Future<List<Zone>>? _zonesFuture;
@@ -58,6 +59,7 @@ class MapBloc extends Bloc<ScooterEvent, ScooterState> {
on<FocusOnScooter>(_onFocusOnScooter); on<FocusOnScooter>(_onFocusOnScooter);
on<ClearMapPlacemarks>(_onClearMapPlacemarks); on<ClearMapPlacemarks>(_onClearMapPlacemarks);
on<ClearMapFocus>(_onClearMapFocus); on<ClearMapFocus>(_onClearMapFocus);
on<FetchActiveOrders>(_onFetchActiveOrders);
} }
Future<List<Zone>> _getZones() async { Future<List<Zone>> _getZones() async {
@@ -344,4 +346,50 @@ class MapBloc extends Bloc<ScooterEvent, ScooterState> {
selectedScooterForFocus: null, selectedScooterForFocus: null,
)); ));
} }
void _startOrdersTimer() {
_ordersTimer?.cancel();
// Опрашиваем раз в 15 секунд, если есть активные поездки
_ordersTimer = Timer.periodic(const Duration(seconds: 15), (_) {
add(FetchActiveOrders());
});
}
void _stopOrdersTimer() {
_ordersTimer?.cancel();
_ordersTimer = null;
}
Future<void> _onFetchActiveOrders(
FetchActiveOrders event,
Emitter<ScooterState> emit,
) async {
try {
final result = await getClientOrdersUsecase();
if (result is Success<List<ScooterOrder>>) {
final activeOrders = result.data ?? [];
final count = activeOrders.length;
// Управляем таймером в зависимости от наличия активных поездок
if (count > 0 && (_ordersTimer == null || !_ordersTimer!.isActive)) {
_startOrdersTimer();
} else if (count == 0) {
_stopOrdersTimer();
}
emit(state.copyWith(
activeRidesCount: count,
reservedScooters: activeOrders.map((e) => e.scooter).toList(),
));
}
} catch (e) {
print("Error fetching active orders: $e");
}
}
@override
Future<void> close() {
_stopOrdersTimer();
return super.close();
}
} }

View File

@@ -15,13 +15,7 @@ class MapSettingsModalBloc extends Bloc<MapSettingsModalEvent, MapSettingsModalS
final SaveMapSettingsUsecase saveMapSettingsUsecase; final SaveMapSettingsUsecase saveMapSettingsUsecase;
MapSettingsModalBloc(this.getMapSettingsUsecase, this.saveMapSettingsUsecase) MapSettingsModalBloc(this.getMapSettingsUsecase, this.saveMapSettingsUsecase)
: super(MapSettingsModalState( : super(MapSettingsModalState()) {
isAllGeomarksActive: true,
isAllGeozonesActive: true,
isParkingZoneActive: true,
isRestrictedParkingZoneActive: true,
isRestrictedDrivingZoneActive: true,
)) {
on<AllGeozonesToggled>(_onAllGeozonesToggled); on<AllGeozonesToggled>(_onAllGeozonesToggled);
on<AllGeomarksToggled>(_onAllGeomarksToggled); on<AllGeomarksToggled>(_onAllGeomarksToggled);
on<ParkingZonesToggled>(_onParkingZonesToggled); on<ParkingZonesToggled>(_onParkingZonesToggled);

View File

@@ -2,7 +2,7 @@ name: be_happy
description: "" description: ""
publish_to: 'none' publish_to: 'none'
version: 1.0.3+1 version: 1.0.4+1
environment: environment:
sdk: ^3.8.1 sdk: ^3.8.1