feat(wip): implement trip persistence through a local repository. Include loaded trips in the start page UI
This commit is contained in:
161
frontend/lib/presentation/pages/new_trip_preferences.dart
Normal file
161
frontend/lib/presentation/pages/new_trip_preferences.dart
Normal file
@@ -0,0 +1,161 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
import 'package:anyway/domain/entities/preferences.dart';
|
||||
import 'package:anyway/presentation/pages/trip_details_page.dart';
|
||||
import 'package:anyway/presentation/providers/trip_provider.dart';
|
||||
|
||||
class NewTripPreferencesPage extends ConsumerStatefulWidget {
|
||||
const NewTripPreferencesPage({super.key, required this.startLocation});
|
||||
|
||||
final List<double> startLocation;
|
||||
|
||||
@override
|
||||
ConsumerState<NewTripPreferencesPage> createState() =>
|
||||
_NewTripPreferencesPageState();
|
||||
}
|
||||
|
||||
class _NewTripPreferencesPageState
|
||||
extends ConsumerState<NewTripPreferencesPage> {
|
||||
int _sightseeing = 3;
|
||||
int _shopping = 1;
|
||||
int _nature = 2;
|
||||
int _maxTimeMinutes = 90;
|
||||
bool _isCreating = false;
|
||||
|
||||
Widget _preferenceSlider(
|
||||
String name,
|
||||
int value,
|
||||
ValueChanged<int> onChanged,
|
||||
Icon icon,
|
||||
) {
|
||||
return Card(
|
||||
margin: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
|
||||
child: ListTile(
|
||||
leading: icon,
|
||||
title: Text(name),
|
||||
subtitle: Slider(
|
||||
value: value.toDouble(),
|
||||
min: 0,
|
||||
max: 5,
|
||||
divisions: 5,
|
||||
label: value.toString(),
|
||||
onChanged: (v) => onChanged(v.toInt()),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _durationPicker() {
|
||||
return Card(
|
||||
margin: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
|
||||
child: ListTile(
|
||||
leading: const Icon(Icons.access_time),
|
||||
title: const Text('Maximum trip duration'),
|
||||
subtitle: CupertinoTimerPicker(
|
||||
mode: CupertinoTimerPickerMode.hm,
|
||||
initialTimerDuration: Duration(minutes: _maxTimeMinutes),
|
||||
minuteInterval: 15,
|
||||
onTimerDurationChanged: (Duration newDuration) {
|
||||
setState(() {
|
||||
_maxTimeMinutes = newDuration.inMinutes;
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _onCreatePressed() async {
|
||||
if (_isCreating) return;
|
||||
setState(() => _isCreating = true);
|
||||
final createTrip = ref.read(createTripProvider);
|
||||
|
||||
final prefs = Preferences(
|
||||
scores: {
|
||||
'sightseeing': _sightseeing,
|
||||
'shopping': _shopping,
|
||||
'nature': _nature,
|
||||
},
|
||||
maxTimeMinutes: _maxTimeMinutes,
|
||||
startLocation: widget.startLocation,
|
||||
);
|
||||
|
||||
try {
|
||||
final trip = await createTrip(prefs);
|
||||
if (!mounted) return;
|
||||
ScaffoldMessenger.of(
|
||||
context,
|
||||
).showSnackBar(SnackBar(content: Text('Trip created: ${trip.uuid}')));
|
||||
Navigator.of(context).pushAndRemoveUntil(
|
||||
MaterialPageRoute(builder: (_) => TripDetailsPage(trip: trip)),
|
||||
(route) => route.isFirst,
|
||||
);
|
||||
} catch (e) {
|
||||
if (!mounted) return;
|
||||
ScaffoldMessenger.of(
|
||||
context,
|
||||
).showSnackBar(SnackBar(content: Text('Failed to create trip: $e')));
|
||||
} finally {
|
||||
if (mounted) setState(() => _isCreating = false);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text('Trip Preferences')),
|
||||
body: ListView(
|
||||
children: [
|
||||
const Padding(
|
||||
padding: EdgeInsets.all(16.0),
|
||||
child: Text(
|
||||
'Tell us about your ideal trip.',
|
||||
style: TextStyle(fontSize: 18),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(Icons.place),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
'Start: ${widget.startLocation[0].toStringAsFixed(4)}, ${widget.startLocation[1].toStringAsFixed(4)}',
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
_durationPicker(),
|
||||
_preferenceSlider(
|
||||
'Sightseeing',
|
||||
_sightseeing,
|
||||
(v) => setState(() => _sightseeing = v),
|
||||
const Icon(Icons.camera_alt),
|
||||
),
|
||||
_preferenceSlider(
|
||||
'Shopping',
|
||||
_shopping,
|
||||
(v) => setState(() => _shopping = v),
|
||||
const Icon(Icons.shopping_bag),
|
||||
),
|
||||
_preferenceSlider(
|
||||
'Nature',
|
||||
_nature,
|
||||
(v) => setState(() => _nature = v),
|
||||
const Icon(Icons.park),
|
||||
),
|
||||
const SizedBox(height: 120), // padding for floating button
|
||||
],
|
||||
),
|
||||
floatingActionButton: FloatingActionButton.extended(
|
||||
onPressed: _isCreating ? null : _onCreatePressed,
|
||||
label: _isCreating
|
||||
? const Text('Creating...')
|
||||
: const Text('Create Trip'),
|
||||
icon: const Icon(Icons.playlist_add),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user