Record voice before selecting place
All checks were successful
Build and deploy Flutter Web / build (push) Successful in 1m46s

This commit is contained in:
Ruslan Bakiev
2026-05-09 16:56:15 +07:00
parent b93f7ec4ec
commit 35ccfe2368

View File

@@ -726,7 +726,7 @@ class _AddExperienceFlowState extends ConsumerState<AddExperienceFlow> {
final _recorder = AudioRecorder(); final _recorder = AudioRecorder();
final _waveSamples = List<double>.filled(64, 0.04); final _waveSamples = List<double>.filled(64, 0.04);
late final Future<List<PlaceRecommendation>> _nearbyPlacesFuture; Future<List<PlaceRecommendation>>? _nearbyPlacesFuture;
Timer? _timer; Timer? _timer;
StreamSubscription<Uint8List>? _audioStreamSub; StreamSubscription<Uint8List>? _audioStreamSub;
var _step = 0; var _step = 0;
@@ -734,12 +734,10 @@ class _AddExperienceFlowState extends ConsumerState<AddExperienceFlow> {
var _recording = false; var _recording = false;
var _submitting = false; var _submitting = false;
var _micAllowed = true; var _micAllowed = true;
PlaceRecommendation? _selectedPlace;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_nearbyPlacesFuture = _loadNearbyPlaces();
} }
@override @override
@@ -851,19 +849,8 @@ class _AddExperienceFlowState extends ConsumerState<AddExperienceFlow> {
final controller = ref.read(placeControllerProvider.notifier); final controller = ref.read(placeControllerProvider.notifier);
final content = switch (_step) { final content = switch (_step) {
0 => _IntroStep(onNext: () => setState(() => _step = 1)), 0 => _IntroStep(onNext: () => setState(() => _step = 1)),
1 => _PlaceStep( 1 => _VoiceStep(
placesFuture: _nearbyPlacesFuture, placeName: '',
radiusMeters: _nearbyPlaceRadiusMeters,
onSelect: (place) {
setState(() {
_selectedPlace = place;
_step = 2;
});
controller.setReviewPlace(place.name);
},
),
_ => _VoiceStep(
placeName: _selectedPlace?.name ?? '',
hasTelegramAuth: widget.hasTelegramAuth, hasTelegramAuth: widget.hasTelegramAuth,
seconds: _seconds, seconds: _seconds,
minimumSeconds: _minimumVoiceSeconds, minimumSeconds: _minimumVoiceSeconds,
@@ -875,16 +862,23 @@ class _AddExperienceFlowState extends ConsumerState<AddExperienceFlow> {
canContinue: widget.hasTelegramAuth && _seconds >= _minimumVoiceSeconds, canContinue: widget.hasTelegramAuth && _seconds >= _minimumVoiceSeconds,
onToggleRecording: _toggleRecording, onToggleRecording: _toggleRecording,
onNext: () async { onNext: () async {
final selectedPlace = _selectedPlace;
if (selectedPlace == null) {
return;
}
if (_recording) { if (_recording) {
await _stopRecording(); await _stopRecording();
} }
setState(() {
_nearbyPlacesFuture = _loadNearbyPlaces();
_step = 2;
});
},
),
_ => _PlaceStep(
placesFuture: _nearbyPlacesFuture,
radiusMeters: _nearbyPlaceRadiusMeters,
isSubmitting: _submitting,
onSelect: (place) async {
setState(() => _submitting = true); setState(() => _submitting = true);
controller.setReviewPlace(selectedPlace.name); controller.setReviewPlace(place.name);
await controller.publishReview(place: selectedPlace); await controller.publishReview(place: place);
if (!context.mounted) { if (!context.mounted) {
return; return;
} }
@@ -967,12 +961,14 @@ class _PlaceStep extends StatelessWidget {
const _PlaceStep({ const _PlaceStep({
required this.placesFuture, required this.placesFuture,
required this.radiusMeters, required this.radiusMeters,
required this.isSubmitting,
required this.onSelect, required this.onSelect,
}); });
final Future<List<PlaceRecommendation>> placesFuture; final Future<List<PlaceRecommendation>>? placesFuture;
final int radiusMeters; final int radiusMeters;
final ValueChanged<PlaceRecommendation> onSelect; final bool isSubmitting;
final Future<void> Function(PlaceRecommendation) onSelect;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -1021,7 +1017,7 @@ class _PlaceStep extends StatelessWidget {
itemBuilder: (context, index) { itemBuilder: (context, index) {
final place = places[index]; final place = places[index];
return ListTile( return ListTile(
onTap: () => onSelect(place), onTap: isSubmitting ? null : () => onSelect(place),
contentPadding: const EdgeInsets.symmetric( contentPadding: const EdgeInsets.symmetric(
horizontal: 14, horizontal: 14,
vertical: 8, vertical: 8,
@@ -1083,8 +1079,9 @@ class _VoiceStep extends StatelessWidget {
return Column( return Column(
children: [ children: [
if (placeName.trim().isNotEmpty) ...[
Text( Text(
placeName.trim().isEmpty ? 'Место' : placeName.trim(), placeName.trim(),
maxLines: 1, maxLines: 1,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
textAlign: TextAlign.center, textAlign: TextAlign.center,
@@ -1093,6 +1090,7 @@ class _VoiceStep extends StatelessWidget {
).textTheme.titleLarge?.copyWith(fontWeight: FontWeight.w900), ).textTheme.titleLarge?.copyWith(fontWeight: FontWeight.w900),
), ),
const SizedBox(height: 10), const SizedBox(height: 10),
],
Expanded( Expanded(
child: Center( child: Center(
child: _VoiceWave( child: _VoiceWave(