some preference improvements
Some checks failed
Build and release APK / Build APK (pull_request) Successful in 7m27s
Test code / Test code (push) Has been cancelled
Build web / Build Web (pull_request) Has been cancelled
Test code / Test code (pull_request) Has been cancelled

This commit is contained in:
Remy Moll 2024-05-25 18:55:58 +02:00
parent 07830de1b2
commit 3029fb8537
13 changed files with 365 additions and 56 deletions

View File

@ -48,4 +48,7 @@
<data android:mimeType="text/plain"/>
</intent>
</queries>
<!-- Required to fetch data from the internet. -->
<uses-permission android:name="android.permission.INTERNET" />
</manifest>

View File

@ -4,9 +4,10 @@ import 'package:fast_network_navigation/modules/overview.dart';
import 'package:fast_network_navigation/modules/profile.dart';
// BasePage is the scaffold that holds all other pages
// A side drawer is used to switch between pages
class BasePage extends StatefulWidget {
const BasePage({super.key, required this.title});
final String title;
@override
@ -22,7 +23,7 @@ class _BasePageState extends State<BasePage> {
});
}
Widget currentView = MainPage();
Widget currentView = NavigationOverview();
@override
Widget build(BuildContext context) {
final ThemeData theme = Theme.of(context);
@ -51,7 +52,7 @@ class _BasePageState extends State<BasePage> {
// Update the state of the app
_onItemTapped(0);
// Then close the drawer
currentView = MainPage();
currentView = NavigationOverview();
Navigator.pop(context);
},
),
@ -87,3 +88,4 @@ class _BasePageState extends State<BasePage> {
);
}
}

View File

@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:fast_network_navigation/modules/scaffold.dart';
import 'package:fast_network_navigation/layout.dart';
void main() => runApp(const App());

View File

@ -9,9 +9,9 @@ import 'package:fast_network_navigation/modules/map.dart';
class MainPage extends StatefulWidget {
class NavigationOverview extends StatefulWidget {
@override
State<MainPage> createState() => _MainPageState();
State<NavigationOverview> createState() => _NavigationOverviewState();
}
@ -35,7 +35,7 @@ class Debounce {
}
class _MainPageState extends State<MainPage> {
class _NavigationOverviewState extends State<NavigationOverview> {
@override
Widget build(BuildContext context) {

View File

@ -1,3 +1,4 @@
import 'package:fast_network_navigation/structs/preferences.dart';
import 'package:flutter/material.dart';
@ -8,48 +9,83 @@ class ProfilePage extends StatefulWidget {
}
class _ProfilePageState extends State<ProfilePage> {
double value = 0.0;
void onChanged(double newValue) {
setState(() {
value = newValue;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Profile'),
),
body: Padding(
padding: EdgeInsets.all(8.0),
child: Column(
children: <Widget>[
Card(
child: ListTile(
leading: Icon(Icons.notifications_sharp),
title: Text('Notification 1'),
subtitle: Text('This is a first notification'),
),
),
Card(
child: ListTile(
leading: Icon(Icons.notifications_sharp),
title: Text('Notification 2'),
subtitle: Text('This is a notification'),
),
),
Card(
child: ListTile(
leading: Icon(Icons.outdoor_grill),
title: Text("Eating preference"),
subtitle: Slider.adaptive(value: value, onChanged: onChanged, min: 0, max: 5, divisions: 5, label: value.toInt().toString(),)
)
)
],
return ListView(
children: [
// First a round, centered image
Center(
child: CircleAvatar(
radius: 100,
child: Icon(Icons.person, size: 100),
)
),
)
Center(
child: Text('Curious traveler', style: TextStyle(fontSize: 24))
),
Padding(
padding: EdgeInsets.all(10),
),
Text('Please rate your preferences for the following activities:'),
// Now the sliders
ImportanceSliders()
]
);
}
}
class ImportanceSliders extends StatefulWidget {
@override
State<ImportanceSliders> createState() => _ImportanceSlidersState();
}
class _ImportanceSlidersState extends State<ImportanceSliders> {
UserPreferences _prefs = UserPreferences();
@override
void initState() {
super.initState();
_prefs.load();
}
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: EdgeInsets.only(left: 10, right: 10, top: 10, bottom: 0),
shadowColor: Colors.grey,
));
}
return sliders;
}
@override
Widget build(BuildContext context) {
return Column(children: _createSliders());
}
}

View File

@ -1,31 +1,62 @@
import "package:flutter/material.dart";
class Destination {
final double latitude;
final double longitude;
final String name;
final String description;
final DestinationType type;
// final DestinationType type;
final Duration duration;
final bool visited;
Destination({
const Destination({
required this.latitude,
required this.longitude,
required this.name,
required this.description,
required this.type,
// required this.type,
required this.duration,
required this.visited,
});
factory Destination.fromJson(Map<String, dynamic> json) {
return switch (json) {
{
'lat': double latitude,
'lon': double longitude,
'name': String name,
'description': String description,
// 'type': String type,
'duration': int duration,
'visited': bool visited
} =>
Destination(
latitude: latitude,
longitude: longitude,
name: name,
description: description,
// type: "DestinationType.values.firstWhere((element) => element.name == type)",
duration: Duration(minutes: duration),
visited: visited
),
_ => throw const FormatException('Failed to load destination.'),
};
}
}
class DestinationType {
final String name;
final String description;
final Icon icon;
DestinationType({
const DestinationType({
required this.name,
required this.description,
required this.icon,
});
}

View File

@ -0,0 +1,82 @@
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
class SinglePreference {
String name;
String description;
int value;
Icon icon;
String key;
SinglePreference({
required this.name,
required this.description,
required this.value,
required this.icon,
required this.key,
});
}
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 {
SharedPreferences prefs = await SharedPreferences.getInstance();
for (SinglePreference pref in preferences) {
prefs.setInt(pref.key, pref.value);
}
}
void load() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
for (SinglePreference pref in preferences) {
pref.value = prefs.getInt(pref.key) ?? 0;
}
}
}

View File

@ -0,0 +1,14 @@
import "package:fast_network_navigation/structs/destination.dart";
class Route {
final String name;
final Duration duration;
final List<Destination> destinations;
Route({
required this.name,
required this.duration,
required this.destinations
});
}

View File

@ -0,0 +1,18 @@
import "package:fast_network_navigation/structs/destination.dart";
import 'package:http/http.dart' as http;
import 'dart:convert';
Future<Destination> fetchDestination() async {
final response = await http
.get(Uri.parse('https://nav.kluster.moll.re/v1/destination/1'));
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
return Destination.fromJson(jsonDecode(response.body) as Map<String, dynamic>);
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load destination');
}
}

View File

@ -5,6 +5,8 @@
import FlutterMacOS
import Foundation
import shared_preferences_foundation
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
}

View File

@ -65,6 +65,22 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.3.1"
ffi:
dependency: transitive
description:
name: ffi
sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
file:
dependency: transitive
description:
name: file
sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c"
url: "https://pub.dev"
source: hosted
version: "7.0.0"
flutter:
dependency: "direct main"
description: flutter
@ -193,7 +209,7 @@ packages:
source: hosted
version: "0.15.4"
http:
dependency: transitive
dependency: "direct main"
description:
name: http
sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938"
@ -288,6 +304,38 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.9.0"
path_provider_linux:
dependency: transitive
description:
name: path_provider_linux
sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
url: "https://pub.dev"
source: hosted
version: "2.2.1"
path_provider_platform_interface:
dependency: transitive
description:
name: path_provider_platform_interface
sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
path_provider_windows:
dependency: transitive
description:
name: path_provider_windows
sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170"
url: "https://pub.dev"
source: hosted
version: "2.2.1"
platform:
dependency: transitive
description:
name: platform
sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec"
url: "https://pub.dev"
source: hosted
version: "3.1.4"
plugin_platform_interface:
dependency: transitive
description:
@ -304,6 +352,62 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.0"
shared_preferences:
dependency: "direct main"
description:
name: shared_preferences
sha256: d3bbe5553a986e83980916ded2f0b435ef2e1893dfaa29d5a7a790d0eca12180
url: "https://pub.dev"
source: hosted
version: "2.2.3"
shared_preferences_android:
dependency: transitive
description:
name: shared_preferences_android
sha256: "1ee8bf911094a1b592de7ab29add6f826a7331fb854273d55918693d5364a1f2"
url: "https://pub.dev"
source: hosted
version: "2.2.2"
shared_preferences_foundation:
dependency: transitive
description:
name: shared_preferences_foundation
sha256: "0a8a893bf4fd1152f93fec03a415d11c27c74454d96e2318a7ac38dd18683ab7"
url: "https://pub.dev"
source: hosted
version: "2.4.0"
shared_preferences_linux:
dependency: transitive
description:
name: shared_preferences_linux
sha256: "9f2cbcf46d4270ea8be39fa156d86379077c8a5228d9dfdb1164ae0bb93f1faa"
url: "https://pub.dev"
source: hosted
version: "2.3.2"
shared_preferences_platform_interface:
dependency: transitive
description:
name: shared_preferences_platform_interface
sha256: "22e2ecac9419b4246d7c22bfbbda589e3acf5c0351137d87dd2939d984d37c3b"
url: "https://pub.dev"
source: hosted
version: "2.3.2"
shared_preferences_web:
dependency: transitive
description:
name: shared_preferences_web
sha256: "9aee1089b36bd2aafe06582b7d7817fd317ef05fc30e6ba14bff247d0933042a"
url: "https://pub.dev"
source: hosted
version: "2.3.0"
shared_preferences_windows:
dependency: transitive
description:
name: shared_preferences_windows
sha256: "841ad54f3c8381c480d0c9b508b89a34036f512482c407e6df7a9c4aa2ef8f59"
url: "https://pub.dev"
source: hosted
version: "2.3.2"
sky_engine:
dependency: transitive
description: flutter
@ -405,6 +509,22 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.5.1"
win32:
dependency: transitive
description:
name: win32
sha256: a79dbe579cb51ecd6d30b17e0cae4e0ea15e2c0e66f69ad4198f22a6789e94f4
url: "https://pub.dev"
source: hosted
version: "5.5.1"
xdg_directories:
dependency: transitive
description:
name: xdg_directories
sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d
url: "https://pub.dev"
source: hosted
version: "1.0.4"
sdks:
dart: ">=3.3.4 <4.0.0"
dart: ">=3.4.0 <4.0.0"
flutter: ">=3.19.0"

View File

@ -39,6 +39,8 @@ dependencies:
geocoding: ^3.0.0
geocode: ^1.0.3
google_maps_flutter: ^2.6.1
http: ^1.2.1
shared_preferences: ^2.2.3
dev_dependencies:
flutter_test:

View File

@ -9,16 +9,15 @@ import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
// import 'package:fast_network_navigation/main.dart';
import 'package:fast_network_navigation/modules/scaffold.dart';
import 'package:fast_network_navigation/layout.dart';
void main() {
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
// Build our app and trigger a frame.
await tester.pumpWidget(BasePage(title: "City Nav"));
// Verify that our counter starts at 0.
expect(find.text('0'), findsOneWidget);
expect(find.text('1'), findsNothing);
// Verfiy that the title is displayed
expect(find.text('City Nav'), findsOneWidget);
// Tap the '+' icon and trigger a frame.
await tester.tap(find.byIcon(Icons.add));