Fix review place loading state
Build and deploy Flutter Web / build (push) Successful in 4m28s

This commit is contained in:
Ruslan Bakiev
2026-06-24 14:07:47 +07:00
parent 98d6ec3f45
commit 739bc5391e
@@ -73,6 +73,7 @@ class _MapContentState extends State<_MapContent> {
final selected = state.selectedPlace; final selected = state.selectedPlace;
final userCoordinate = state.userCoordinate; final userCoordinate = state.userCoordinate;
final targetCenter = _focusCenter(state); final targetCenter = _focusCenter(state);
final reviewCoordinate = userCoordinate ?? selected?.coordinate;
final placeCubit = context.read<PlaceCubit>(); final placeCubit = context.read<PlaceCubit>();
final traitCounts = _countPlaceTraits(state.places); final traitCounts = _countPlaceTraits(state.places);
final availableTraits = [ final availableTraits = [
@@ -98,7 +99,6 @@ class _MapContentState extends State<_MapContent> {
userCoordinate: userCoordinate, userCoordinate: userCoordinate,
onPlaceTap: (place) => _selectAndShowPlace(context, place), onPlaceTap: (place) => _selectAndShowPlace(context, place),
), ),
if (targetCenter == null) const _MapTargetLoadingOverlay(),
SafeArea( SafeArea(
child: Align( child: Align(
alignment: Alignment.topLeft, alignment: Alignment.topLeft,
@@ -118,10 +118,9 @@ class _MapContentState extends State<_MapContent> {
child: Align( child: Align(
alignment: Alignment.topRight, alignment: Alignment.topRight,
child: _AddReviewAction( child: _AddReviewAction(
onPressed: () => _openAddFlow( onPressed: reviewCoordinate == null
context, ? null
userCoordinate ?? selected?.coordinate, : () => _openAddFlow(context, reviewCoordinate),
),
), ),
), ),
), ),
@@ -614,7 +613,7 @@ class _UserAvatar extends StatelessWidget {
class _AddReviewAction extends StatelessWidget { class _AddReviewAction extends StatelessWidget {
const _AddReviewAction({required this.onPressed}); const _AddReviewAction({required this.onPressed});
final VoidCallback onPressed; final VoidCallback? onPressed;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -1515,49 +1514,6 @@ class _MapLoading extends StatelessWidget {
} }
} }
class _MapTargetLoadingOverlay extends StatelessWidget {
const _MapTargetLoadingOverlay();
@override
Widget build(BuildContext context) {
final tokens = context.mapflowTokens;
return IgnorePointer(
child: SafeArea(
child: Align(
alignment: Alignment.topCenter,
child: Padding(
padding: const EdgeInsets.only(top: 18),
child: DecoratedBox(
decoration: BoxDecoration(
color: tokens.mapPanel.withValues(alpha: 0.84),
borderRadius: BorderRadius.circular(999),
boxShadow: [
BoxShadow(
color: Colors.black.withValues(alpha: 0.24),
blurRadius: 22,
offset: const Offset(0, 10),
),
],
),
child: Padding(
padding: const EdgeInsets.all(10),
child: SizedBox.square(
dimension: 28,
child: CircularProgressIndicator(
strokeWidth: 2.5,
color: tokens.voiceAccent,
backgroundColor: tokens.onDark.withValues(alpha: 0.12),
),
),
),
),
),
),
),
);
}
}
class _MapError extends StatelessWidget { class _MapError extends StatelessWidget {
const _MapError({required this.message}); const _MapError({required this.message});
@@ -2385,6 +2341,7 @@ class AddExperienceFlow extends StatefulWidget {
class _AddExperienceFlowState extends State<AddExperienceFlow> { class _AddExperienceFlowState extends State<AddExperienceFlow> {
static const _minimumInformationUnits = 16.0; static const _minimumInformationUnits = 16.0;
static const _nearbyPlaceRadiusMeters = 50; static const _nearbyPlaceRadiusMeters = 50;
static const _nearbyPlacesTimeout = Duration(seconds: 12);
static const _voicePromptHints = [ static const _voicePromptHints = [
'атмосфера', 'атмосфера',
'еда', 'еда',
@@ -2445,10 +2402,13 @@ class _AddExperienceFlowState extends State<AddExperienceFlow> {
return const []; return const [];
} }
return context.read<PlacesRepository>().fetchNearbyPlaces( return context
.read<PlacesRepository>()
.fetchNearbyPlaces(
coordinate: coordinate, coordinate: coordinate,
radiusMeters: _nearbyPlaceRadiusMeters, radiusMeters: _nearbyPlaceRadiusMeters,
); )
.timeout(_nearbyPlacesTimeout);
} }
Future<void> _startRecording() async { Future<void> _startRecording() async {
@@ -2559,8 +2519,14 @@ class _AddExperienceFlowState extends State<AddExperienceFlow> {
), ),
1 => _PlaceStep( 1 => _PlaceStep(
placesFuture: _nearbyPlacesFuture, placesFuture: _nearbyPlacesFuture,
hasCoordinate: widget.coordinate != null,
radiusMeters: _nearbyPlaceRadiusMeters, radiusMeters: _nearbyPlaceRadiusMeters,
isSubmitting: _submitting, isSubmitting: _submitting,
onRetry: () {
setState(() {
_nearbyPlacesFuture = _loadNearbyPlaces();
});
},
onSelect: (place) async { onSelect: (place) async {
controller.setReviewPlace(place.name); controller.setReviewPlace(place.name);
setState(() { setState(() {
@@ -2659,14 +2625,18 @@ class _AddExperienceFlowState extends State<AddExperienceFlow> {
class _PlaceStep extends StatelessWidget { class _PlaceStep extends StatelessWidget {
const _PlaceStep({ const _PlaceStep({
required this.placesFuture, required this.placesFuture,
required this.hasCoordinate,
required this.radiusMeters, required this.radiusMeters,
required this.isSubmitting, required this.isSubmitting,
required this.onRetry,
required this.onSelect, required this.onSelect,
}); });
final Future<List<PlaceRecommendation>>? placesFuture; final Future<List<PlaceRecommendation>>? placesFuture;
final bool hasCoordinate;
final int radiusMeters; final int radiusMeters;
final bool isSubmitting; final bool isSubmitting;
final VoidCallback onRetry;
final Future<void> Function(PlaceRecommendation) onSelect; final Future<void> Function(PlaceRecommendation) onSelect;
@override @override
@@ -2687,42 +2657,43 @@ class _PlaceStep extends StatelessWidget {
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
Expanded( Expanded(
child: FutureBuilder<List<PlaceRecommendation>>( child: placesFuture == null
? _PlaceUnavailable(
icon: Icons.location_off_outlined,
message: 'Нет геопозиции',
tokens: tokens,
)
: FutureBuilder<List<PlaceRecommendation>>(
future: placesFuture, future: placesFuture,
builder: (context, snapshot) { builder: (context, snapshot) {
if (snapshot.connectionState != ConnectionState.done) { if (snapshot.connectionState != ConnectionState.done) {
return Center( return Center(
child: CircularProgressIndicator(color: tokens.voiceAccent), child: CircularProgressIndicator(
color: tokens.voiceAccent,
),
); );
} }
if (snapshot.hasError) { if (snapshot.hasError) {
return Center( return _PlaceUnavailable(
child: Icon( icon: Icons.error_outline,
Icons.error_outline, message: 'Места не загрузились',
color: tokens.onDark, tokens: tokens,
size: 42, action: TextButton(
onPressed: onRetry,
child: const Text('Повторить'),
), ),
); );
} }
final places = snapshot.data ?? const <PlaceRecommendation>[]; final places =
snapshot.data ?? const <PlaceRecommendation>[];
if (places.isEmpty) { if (places.isEmpty) {
return Center( return _PlaceUnavailable(
child: Column( icon: Icons.location_off_outlined,
mainAxisSize: MainAxisSize.min, message: hasCoordinate
children: [ ? 'Нет мест в $radiusMetersм'
Icon( : 'Нет геопозиции',
Icons.location_off_outlined, tokens: tokens,
color: tokens.onDark,
size: 42,
),
const SizedBox(height: 10),
Text(
'Нет мест в $radiusMetersм',
style: TextStyle(color: tokens.onDark),
),
],
),
); );
} }
@@ -2747,6 +2718,35 @@ class _PlaceStep extends StatelessWidget {
} }
} }
class _PlaceUnavailable extends StatelessWidget {
const _PlaceUnavailable({
required this.icon,
required this.message,
required this.tokens,
this.action,
});
final IconData icon;
final String message;
final MapflowThemeTokens tokens;
final Widget? action;
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(icon, color: tokens.onDark, size: 42),
const SizedBox(height: 10),
Text(message, style: TextStyle(color: tokens.onDark)),
if (action != null) ...[const SizedBox(height: 8), action!],
],
),
);
}
}
class _FavoriteStep extends StatelessWidget { class _FavoriteStep extends StatelessWidget {
const _FavoriteStep({ const _FavoriteStep({
required this.place, required this.place,