Tentatively enable communication between front + backend #15
| @@ -9,6 +9,9 @@ class ProfilePage extends StatefulWidget { | |||||||
| } | } | ||||||
|  |  | ||||||
| class _ProfilePageState extends State<ProfilePage> { | class _ProfilePageState extends State<ProfilePage> { | ||||||
|  |   Future<UserPreferences> _prefs = loadUserPreferences(); | ||||||
|  |  | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context) { |   Widget build(BuildContext context) { | ||||||
|     return ListView( |     return ListView( | ||||||
| @@ -24,66 +27,82 @@ class _ProfilePageState extends State<ProfilePage> { | |||||||
|           child: Text('Curious traveler', style: TextStyle(fontSize: 24)) |           child: Text('Curious traveler', style: TextStyle(fontSize: 24)) | ||||||
|         ), |         ), | ||||||
|  |  | ||||||
|         Padding(padding: EdgeInsets.all(10)), |         Divider(indent: 25, endIndent: 25, height: 50), | ||||||
|         Divider(indent: 25, endIndent: 25), |  | ||||||
|         Padding(padding: EdgeInsets.all(10)), |  | ||||||
|  |  | ||||||
|         Padding( |         Center( | ||||||
|           padding: EdgeInsets.only(left: 10, right: 10, top: 0, bottom: 10), |           child: Padding( | ||||||
|           child: Text('Please rate your personal preferences so that we can taylor your experience.', style: TextStyle(fontSize: 18)) |            padding: EdgeInsets.only(left: 10, right: 10, top: 0, bottom: 10), | ||||||
|  |             child: Text('For a tailored experience, please rate your discovery preferences.', style: TextStyle(fontSize: 18)) | ||||||
|  |           ), | ||||||
|         ), |         ), | ||||||
|  |  | ||||||
|         // Now the sliders |         FutureBuilder(future: _prefs, builder: futureSliders) | ||||||
|         ImportanceSliders() |  | ||||||
|       ] |       ] | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   Widget futureSliders(BuildContext context, AsyncSnapshot<UserPreferences> snapshot) { | ||||||
|  |     if (snapshot.connectionState == ConnectionState.done) { | ||||||
|  |       UserPreferences prefs = snapshot.data!; | ||||||
|  |  | ||||||
|  |       return Column( | ||||||
|  |         children: [ | ||||||
|  |           PreferenceSliders(prefs: [prefs.maxTime, prefs.maxDetour]), | ||||||
|  |           Divider(indent: 25, endIndent: 25, height: 50), | ||||||
|  |           PreferenceSliders(prefs: [prefs.sightseeing, prefs.shopping, prefs.nature]) | ||||||
|  |         ] | ||||||
|  |       ); | ||||||
|  |     } else { | ||||||
|  |       return CircularProgressIndicator(); | ||||||
|  |     } | ||||||
|  |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class ImportanceSliders extends StatefulWidget { | class PreferenceSliders extends StatefulWidget { | ||||||
|  |   final List<SinglePreference> prefs; | ||||||
|  |  | ||||||
|  |   PreferenceSliders({required this.prefs}); | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   State<ImportanceSliders> createState() => _ImportanceSlidersState(); |   State<PreferenceSliders> createState() => _PreferenceSlidersState(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| class _ImportanceSlidersState extends State<ImportanceSliders> { | class _PreferenceSlidersState extends State<PreferenceSliders> { | ||||||
|  |  | ||||||
|   UserPreferences _prefs = UserPreferences(); |  | ||||||
|  |  | ||||||
|   List<Card> _createSliders() { |  | ||||||
|     List<Card> sliders = []; |  | ||||||
|     for (SinglePreference pref in _prefs.preferences) { |  | ||||||
|       sliders.add(Card( |  | ||||||
|         child: ListTile( |  | ||||||
|           leading: pref.icon, |  | ||||||
|           title: Text(pref.name), |  | ||||||
|           subtitle: Slider( |  | ||||||
|             value: pref.value.toDouble(), |  | ||||||
|             min: 0, |  | ||||||
|             max: 10, |  | ||||||
|             divisions: 10, |  | ||||||
|             label: pref.value.toString(), |  | ||||||
|             onChanged: (double newValue) { |  | ||||||
|               setState(() { |  | ||||||
|                 pref.value = newValue.toInt(); |  | ||||||
|                 _prefs.save(); |  | ||||||
|               }); |  | ||||||
|             }, |  | ||||||
|           ) |  | ||||||
|         ), |  | ||||||
|         margin: const EdgeInsets.only(left: 10, right: 10, top: 10, bottom: 0), |  | ||||||
|         shadowColor: Colors.grey, |  | ||||||
|       )); |  | ||||||
|     } |  | ||||||
|     return sliders; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context) { |   Widget build(BuildContext context) { | ||||||
|  |     List<Card> sliders = []; | ||||||
|  |       for (SinglePreference pref in widget.prefs) { | ||||||
|  |       sliders.add( | ||||||
|  |         Card( | ||||||
|  |           child: ListTile( | ||||||
|  |             leading: pref.icon, | ||||||
|  |             title: Text(pref.name), | ||||||
|  |             subtitle: Slider( | ||||||
|  |               value: pref.value.toDouble(), | ||||||
|  |               min: pref.minVal.toDouble(), | ||||||
|  |               max: pref.maxVal.toDouble(), | ||||||
|  |               divisions: pref.maxVal - pref.minVal, | ||||||
|  |               label: pref.value.toString(), | ||||||
|  |               onChanged: (double newValue) { | ||||||
|  |                 setState(() { | ||||||
|  |                   pref.value = newValue.toInt(); | ||||||
|  |                   pref.save(); | ||||||
|  |                 }); | ||||||
|  |               }, | ||||||
|  |             ) | ||||||
|  |           ), | ||||||
|  |           margin: const EdgeInsets.only(left: 10, right: 10, top: 10, bottom: 0), | ||||||
|  |           shadowColor: Colors.grey, | ||||||
|  |         ) | ||||||
|  |       ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     return Column(children: _createSliders()); |     return Column( | ||||||
|  |       children: sliders); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -3,80 +3,102 @@ import 'package:shared_preferences/shared_preferences.dart'; | |||||||
|  |  | ||||||
|  |  | ||||||
| class SinglePreference { | class SinglePreference { | ||||||
|  |   String slug; | ||||||
|   String name; |   String name; | ||||||
|   String description; |   String description; | ||||||
|   int value; |   int value; | ||||||
|  |   int minVal; | ||||||
|  |   int maxVal; | ||||||
|   Icon icon; |   Icon icon; | ||||||
|   String key; |  | ||||||
|  |  | ||||||
|   SinglePreference({ |   SinglePreference({ | ||||||
|  |     required this.slug, | ||||||
|     required this.name, |     required this.name, | ||||||
|     required this.description, |     required this.description, | ||||||
|     required this.value, |     required this.value, | ||||||
|     required this.icon, |     required this.icon, | ||||||
|     required this.key, |     this.minVal = 0, | ||||||
|  |     this.maxVal = 5, | ||||||
|   }); |   }); | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class UserPreferences { |  | ||||||
|   List<SinglePreference> preferences = [ |  | ||||||
|     SinglePreference( |  | ||||||
|       name: "Sightseeing", |  | ||||||
|       description: "How much do you like sightseeing?", |  | ||||||
|       value: 0, |  | ||||||
|       icon: Icon(Icons.church), |  | ||||||
|       key: "sightseeing", |  | ||||||
|     ), |  | ||||||
|     SinglePreference( |  | ||||||
|       name: "Shopping", |  | ||||||
|       description: "How much do you like shopping?", |  | ||||||
|       value: 0, |  | ||||||
|       icon: Icon(Icons.shopping_bag), |  | ||||||
|       key: "shopping", |  | ||||||
|     ), |  | ||||||
|     SinglePreference( |  | ||||||
|       name: "Foods & Drinks", |  | ||||||
|       description: "How much do you like eating?", |  | ||||||
|       value: 0, |  | ||||||
|       icon: Icon(Icons.restaurant), |  | ||||||
|       key: "eating", |  | ||||||
|     ), |  | ||||||
|     SinglePreference( |  | ||||||
|       name: "Nightlife", |  | ||||||
|       description: "How much do you like nightlife?", |  | ||||||
|       value: 0, |  | ||||||
|       icon: Icon(Icons.wine_bar), |  | ||||||
|       key: "nightlife", |  | ||||||
|     ), |  | ||||||
|     SinglePreference( |  | ||||||
|       name: "Nature", |  | ||||||
|       description: "How much do you like nature?", |  | ||||||
|       value: 0, |  | ||||||
|       icon: Icon(Icons.landscape), |  | ||||||
|       key: "nature", |  | ||||||
|     ), |  | ||||||
|     SinglePreference( |  | ||||||
|       name: "Culture", |  | ||||||
|       description: "How much do you like culture?", |  | ||||||
|       value: 0, |  | ||||||
|       icon: Icon(Icons.palette), |  | ||||||
|       key: "culture", |  | ||||||
|     ), |  | ||||||
|   ]; |  | ||||||
|  |  | ||||||
|  |  | ||||||
|   void save() async { |   void save() async { | ||||||
|     SharedPreferences sharedPrefs = await SharedPreferences.getInstance(); |     SharedPreferences sharedPrefs = await SharedPreferences.getInstance(); | ||||||
|     for (SinglePreference pref in preferences) { |       sharedPrefs.setInt('pref_$slug', value); | ||||||
|       sharedPrefs.setInt(pref.key, pref.value); |  | ||||||
|     } |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   void load() async { |   void load() async { | ||||||
|     SharedPreferences sharedPrefs = await SharedPreferences.getInstance(); |     SharedPreferences sharedPrefs = await SharedPreferences.getInstance(); | ||||||
|     for (SinglePreference pref in preferences) { |       value = sharedPrefs.getInt('pref_$slug') ?? minVal; | ||||||
|       pref.value = sharedPrefs.getInt(pref.key) ?? 0; |  | ||||||
|     } |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class UserPreferences { | ||||||
|  |   SinglePreference sightseeing = SinglePreference( | ||||||
|  |     name: "Sightseeing", | ||||||
|  |     slug: "sightseeing", | ||||||
|  |     description: "How much do you like sightseeing?", | ||||||
|  |     value: 0, | ||||||
|  |     icon: Icon(Icons.church), | ||||||
|  |   ); | ||||||
|  |   SinglePreference shopping = SinglePreference( | ||||||
|  |     name: "Shopping", | ||||||
|  |     slug: "shopping", | ||||||
|  |     description: "How much do you like shopping?", | ||||||
|  |     value: 0, | ||||||
|  |     icon: Icon(Icons.shopping_bag), | ||||||
|  |   ); | ||||||
|  |   SinglePreference nature = SinglePreference( | ||||||
|  |     name: "Nature", | ||||||
|  |     slug: "nature", | ||||||
|  |     description: "How much do you like nature?", | ||||||
|  |     value: 0, | ||||||
|  |     icon: Icon(Icons.landscape), | ||||||
|  |   ); | ||||||
|  |  | ||||||
|  |   SinglePreference maxTime = SinglePreference( | ||||||
|  |     name: "Trip duration", | ||||||
|  |     slug: "duration", | ||||||
|  |     description: "How long do you want your trip to be?", | ||||||
|  |     value: 30, | ||||||
|  |     minVal: 30, | ||||||
|  |     maxVal: 720, | ||||||
|  |     icon: Icon(Icons.timer), | ||||||
|  |   ); | ||||||
|  |   SinglePreference maxDetour = SinglePreference( | ||||||
|  |     name: "Trip detours", | ||||||
|  |     slug: "detours", | ||||||
|  |     description: "Are you okay with roaming even if makes the trip longer?", | ||||||
|  |     value: 0, | ||||||
|  |     maxVal: 30, | ||||||
|  |     icon: Icon(Icons.loupe_sharp), | ||||||
|  |   ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   Future<void> load() async { | ||||||
|  |     for (SinglePreference pref in [sightseeing, shopping, nature, maxTime, maxDetour]) { | ||||||
|  |       pref.load(); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   String toJson() { | ||||||
|  |     // This is "opinionated" JSON, corresponding to the backend's expectations | ||||||
|  |     return ''' | ||||||
|  |     { | ||||||
|  |       "sightseeing": {"type": "sightseeing", "score": ${sightseeing.value}}, | ||||||
|  |       "shopping": {"type": "shopping", "score": ${shopping.value}}, | ||||||
|  |       "nature": {"type": "nature", "score": ${nature.value}}, | ||||||
|  |       "max_time_minutes": ${maxTime.value}, | ||||||
|  |       "detour_tolerance_minute": ${maxDetour.value} | ||||||
|  |     } | ||||||
|  |     '''; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | Future<UserPreferences> loadUserPreferences() async { | ||||||
|  |   UserPreferences prefs = UserPreferences(); | ||||||
|  |   await prefs.load(); | ||||||
|  |   return prefs; | ||||||
|  | } | ||||||
| @@ -28,8 +28,8 @@ Future<Trip> fetchTrip( | |||||||
|   final response = await dio.post( |   final response = await dio.post( | ||||||
|     "/trip/new", |     "/trip/new", | ||||||
|     data: { |     data: { | ||||||
|       // 'preferences': preferences.toJson(), |       'preferences': preferences.toJson(), | ||||||
|       'start': [48,2.3] |       'start': startPoint | ||||||
|     } |     } | ||||||
|   ); |   ); | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user