adding missing const

This commit is contained in:
2025-10-20 17:08:10 +02:00
parent 71c7325370
commit 0070e57aec
36 changed files with 298 additions and 210 deletions

View File

@@ -37,8 +37,8 @@ jobs:
- uses: https://github.com/actions/setup-java@v4
with:
java-version: '17'
distribution: 'zulu'
java-version: '21'
distribution: 'oracle'
- name: Setup Android SDK
uses: https://github.com/android-actions/setup-android@v3

5
.vscode/launch.json vendored
View File

@@ -33,8 +33,11 @@
"request": "launch",
"program": "lib/main.dart",
"cwd": "${workspaceFolder}/frontend",
"args": [
"--dart-define-from-file=secrets.json"
],
"env": {
"GOOGLE_MAPS_API_KEY": "testing"
"ANDROID_GOOGLE_MAPS_API_KEY": "AIzaSyD6RK_pzKFc8T-t1t0jiC3PNRZwNXECFG4"
}
},
{

View File

@@ -1,17 +1,19 @@
{ pkgs ? import <nixpkgs> { config.android_sdk.accept_license = true; config.allowUnfree = true; } }:
pkgs.mkShell {
buildInputs = [
pkgs.flutter
#pkgs.android-tools # for adb
#pkgs.openjdk # required for Android builds
buildInputs = with pkgs; [
flutter
android-tools # for adb
openjdk # required for Android builds
# pkgs.androidenv.androidPkgs.androidsdk # The customized SDK that we've made above
# androidenv.androidPkgs.ndk-bundle
];
# Set up Android SDK paths if needed
ANDROID_HOME = "/scratch/remy/android";
shellHook = ''
export ANDROID_SDK_ROOT=${pkgs.androidsdk}/libexec/android-sdk
export PATH=$PATH:${pkgs.androidsdk}/libexec/android-sdk/platform-tools
echo "Flutter dev environment ready. 'adb' and 'flutter' are available."
'';
}

View File

@@ -19,7 +19,7 @@ pluginManagement {
plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version "8.1.0" apply false
id "com.android.application" version "8.7.0" apply false
id "org.jetbrains.kotlin.android" version "2.0.20" apply false
}

View File

@@ -26,13 +26,13 @@ ThemeData APP_THEME = ThemeData(
cardColor: Colors.white,
useMaterial3: true,
colorScheme: ColorScheme.light(
colorScheme: const ColorScheme.light(
primary: PRIMARY_COLOR,
secondary: GRADIENT_END,
surface: Colors.white,
error: Colors.red,
onPrimary: Colors.white,
onSecondary: const Color.fromARGB(255, 30, 22, 22),
onSecondary: Color.fromARGB(255, 30, 22, 22),
onSurface: Colors.black,
onError: Colors.white,
brightness: Brightness.light,
@@ -64,12 +64,6 @@ ThemeData APP_THEME = ThemeData(
),
cardTheme: const CardTheme(
shadowColor: Colors.grey,
elevation: 2,
margin: EdgeInsets.all(10),
),
sliderTheme: const SliderThemeData(
trackHeight: 15,
inactiveTrackColor: Colors.grey,

View File

@@ -20,7 +20,7 @@ class _CurrentTripErrorMessageState extends State<CurrentTripErrorMessage> {
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
const Text(
"😢",
style: TextStyle(
fontSize: 40,

View File

@@ -8,7 +8,7 @@ import 'package:anyway/structs/trip.dart';
class CurrentTripGreeter extends StatefulWidget {
final Trip trip;
CurrentTripGreeter({
const CurrentTripGreeter({
super.key,
required this.trip,
});

View File

@@ -33,7 +33,7 @@ List<Widget> landmarksList(Trip trip, {required bool Function(Landmark) selector
}
if (nextLandmark != null) {
children.add(
StepBetweenLandmarks(current: landmark, next: nextLandmark!)
StepBetweenLandmarks(current: landmark, next: nextLandmark)
);
}
}

View File

@@ -49,7 +49,7 @@ class _CurrentTripLoadingIndicatorState extends State<CurrentTripLoadingIndicato
// automatically cycle through the greeter texts
class StatusText extends StatefulWidget {
const StatusText({Key? key}) : super(key: key);
const StatusText({super.key});
@override
_StatusTextState createState() => _StatusTextState();
@@ -110,10 +110,10 @@ class AnimatedDotsText extends StatefulWidget {
final TextStyle style;
const AnimatedDotsText({
Key? key,
super.key,
required this.baseText,
required this.style,
}) : super(key: key);
});
@override
_AnimatedDotsTextState createState() => _AnimatedDotsTextState();

View File

@@ -0,0 +1,53 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:auto_size_text/auto_size_text.dart';
import 'package:anyway/structs/trip.dart';
List<Map<String, dynamic>> locationActions = [
{'name': 'Toilet', 'action': () {}},
{'name': 'Food', 'action': () {}},
{'name': 'Surrounding landmarks', 'action': () {}},
];
class CurrentTripLocations extends StatefulWidget {
final Trip? trip;
const CurrentTripLocations({super.key, this.trip});
@override
State<CurrentTripLocations> createState() => _CurrentTripLocationsState();
}
class _CurrentTripLocationsState extends State<CurrentTripLocations> {
@override
Widget build(BuildContext context) {
// A horizontally scrolling list of buttons with predefined actions
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
padding: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 10.0),
child: Row(
children: [
if (widget.trip != null)
for (Map action in locationActions)
Padding(
padding: const EdgeInsets.symmetric(horizontal: 3.0),
child: ElevatedButton(
onPressed: action['action'],
child: AutoSizeText(
action['name'],
maxLines: 1,
minFontSize: 8,
maxFontSize: 16,
overflow: TextOverflow.ellipsis,
),
),
),
],
),
);
}
}

View File

@@ -13,7 +13,7 @@ import 'package:anyway/modules/landmark_map_marker.dart';
class CurrentTripMap extends StatefulWidget {
final Trip? trip;
CurrentTripMap({this.trip});
const CurrentTripMap({super.key, this.trip});
@override
State<CurrentTripMap> createState() => _CurrentTripMapState();
@@ -22,7 +22,7 @@ class CurrentTripMap extends StatefulWidget {
class _CurrentTripMapState extends State<CurrentTripMap> {
late GoogleMapController mapController;
CameraPosition _cameraPosition = CameraPosition(
final CameraPosition _cameraPosition = const CameraPosition(
target: LatLng(48.8566, 2.3522),
zoom: 11.0,
);

View File

@@ -0,0 +1,31 @@
import 'package:anyway/structs/trip.dart';
import 'package:flutter/material.dart';
import 'package:anyway/modules/current_trip_map.dart';
import 'package:anyway/modules/current_trip_locations.dart';
class CurrentTripOverview extends StatefulWidget {
final Trip? trip;
const CurrentTripOverview({super.key, this.trip});
@override
State<CurrentTripOverview> createState() => _CurrentTripOverviewState();
}
class _CurrentTripOverviewState extends State<CurrentTripOverview> {
@override
Widget build(BuildContext context) {
// The background map has a horizontally scrolling list of rounded buttons overlaid
return Stack(
alignment: Alignment.topLeft,
children: [
CurrentTripMap(trip: widget.trip),
CurrentTripLocations(trip: widget.trip),
],
);
}
}

View File

@@ -81,7 +81,7 @@ class _CurrentTripPanelState extends State<CurrentTripPanel> {
),
Padding(
padding: EdgeInsets.all(10),
padding: const EdgeInsets.all(10),
child: Container(
decoration: BoxDecoration(
color: Colors.grey[100],
@@ -94,9 +94,6 @@ class _CurrentTripPanelState extends State<CurrentTripPanel> {
ExpansionTile(
leading: const Icon(Icons.location_on),
title: const Text('Visited Landmarks (tap to expand)'),
children: [
...landmarksList(widget.trip, selector: (Landmark landmark) => landmark.visited),
],
visualDensity: VisualDensity.compact,
collapsedShape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
@@ -104,6 +101,9 @@ class _CurrentTripPanelState extends State<CurrentTripPanel> {
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
children: [
...landmarksList(widget.trip, selector: (Landmark landmark) => landmark.visited),
],
),
],
),

View File

@@ -20,14 +20,14 @@ class _saveButtonState extends State<saveButton> {
onPressed: () async {
savedTrips.addTrip(widget.trip);
rootScaffoldMessengerKey.currentState!.showSnackBar(
SnackBar(
const SnackBar(
content: Text('Trip saved'),
duration: Duration(seconds: 2),
dismissDirection: DismissDirection.horizontal
)
);
},
child: SizedBox(
child: const SizedBox(
width: 100,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,

View File

@@ -14,7 +14,7 @@ class LandmarkCard extends StatefulWidget {
final Landmark landmark;
final Trip parentTrip;
LandmarkCard(
const LandmarkCard(
this.landmark,
this.parentTrip,
);
@@ -66,11 +66,11 @@ class _LandmarkCardState extends State<LandmarkCard> {
color: PRIMARY_COLOR,
child: Center(
child: Padding(
padding: EdgeInsets.all(5),
padding: const EdgeInsets.all(5),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.timer_outlined, size: 16),
const Icon(Icons.timer_outlined, size: 16),
Text("${widget.landmark.duration?.inMinutes} minutes"),
],
)
@@ -114,7 +114,7 @@ class _LandmarkCardState extends State<LandmarkCard> {
SingleChildScrollView(
scrollDirection: Axis.horizontal,
padding: EdgeInsets.only(left: 5, right: 5, bottom: 10),
padding: const EdgeInsets.only(left: 5, right: 5, bottom: 10),
// the scroll view should be flush once the buttons are scrolled to the left
// but initially there should be some padding
child: Wrap(
@@ -181,7 +181,7 @@ class _LandmarkCardState extends State<LandmarkCard> {
title: const Text('Favorite'),
onTap: () async {
rootScaffoldMessengerKey.currentState!.showSnackBar(
SnackBar(content: Text("Not implemented yet"))
const SnackBar(content: Text("Not implemented yet"))
);
},
),

View File

@@ -7,7 +7,7 @@ class ThemedMarker extends StatelessWidget {
final Landmark landmark;
final int position;
ThemedMarker({
const ThemedMarker({
super.key,
required this.landmark,
required this.position
@@ -24,12 +24,12 @@ class ThemedMarker extends StatelessWidget {
top: 0,
right: 0,
child: Container(
padding: EdgeInsets.all(5),
padding: const EdgeInsets.all(5),
decoration: BoxDecoration(
color: Colors.grey[100],
shape: BoxShape.circle,
),
child: Text('$position', style: TextStyle(color: Colors.black, fontSize: 25)),
child: Text('$position', style: const TextStyle(color: Colors.black, fontSize: 25)),
),
);
}
@@ -40,7 +40,7 @@ class ThemedMarker extends StatelessWidget {
children: [
Container(
decoration: BoxDecoration(
gradient: landmark.visited ? LinearGradient(colors: [Colors.grey, Colors.white]) : APP_GRADIENT,
gradient: landmark.visited ? const LinearGradient(colors: [Colors.grey, Colors.white]) : APP_GRADIENT,
shape: BoxShape.circle,
border: Border.all(color: Colors.black, width: 5),
),

View File

@@ -11,7 +11,7 @@ class NewTripButton extends StatefulWidget {
final Trip trip;
final UserPreferences preferences;
const NewTripButton({
const NewTripButton({super.key,
required this.trip,
required this.preferences,
});
@@ -35,7 +35,7 @@ class _NewTripButtonState extends State<NewTripButton> {
return FloatingActionButton.extended(
onPressed: onPressed,
icon: const Icon(Icons.directions),
label: AutoSizeText('Start planning!'),
label: const AutoSizeText('Start planning!'),
);
}
);

View File

@@ -71,13 +71,13 @@ class _NewTripLocationSearchState extends State<NewTripLocationSearch> {
hintText: 'Enter a city name or long press on the map.',
onSubmitted: setTripLocation,
controller: _controller,
leading: Icon(Icons.search),
leading: const Icon(Icons.search),
trailing: [
ElevatedButton(
onPressed: () {
setTripLocation(_controller.text);
},
child: Text('Search'),
child: const Text('Search'),
)
]
);
@@ -97,7 +97,7 @@ class _NewTripLocationSearchState extends State<NewTripLocationSearch> {
)
);
},
child: Text('Use current location'),
child: const Text('Use current location'),
);
@override

View File

@@ -7,7 +7,7 @@ import 'package:flutter/material.dart';
class NewTripOptionsButton extends StatefulWidget {
final Trip trip;
const NewTripOptionsButton({required this.trip});
const NewTripOptionsButton({super.key, required this.trip});
@override
State<NewTripOptionsButton> createState() => _NewTripOptionsButtonState();

View File

@@ -13,7 +13,7 @@ class OnboardingAgreementCard extends StatefulWidget {
final ValueChanged<bool> onAgreementChanged;
OnboardingAgreementCard({
const OnboardingAgreementCard({
super.key,
required this.title,
required this.description,
@@ -30,12 +30,12 @@ class _OnboardingAgreementCardState extends State<OnboardingAgreementCard> {
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.all(20),
padding: const EdgeInsets.all(20),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
OnboardingCard(title: widget.title, description: widget.description, imagePath: widget.imagePath),
Padding(padding: EdgeInsets.only(top: 20)),
const Padding(padding: EdgeInsets.only(top: 20)),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
@@ -91,7 +91,7 @@ class _OnboardingAgreementCardState extends State<OnboardingAgreementCard> {
data: snapshot.data.toString(),
);
} else {
return CircularProgressIndicator();
return const CircularProgressIndicator();
}
},

View File

@@ -6,7 +6,7 @@ class OnboardingCard extends StatelessWidget {
final String description;
final String imagePath;
const OnboardingCard({
const OnboardingCard({super.key,
required this.title,
required this.description,
required this.imagePath,
@@ -16,7 +16,7 @@ class OnboardingCard extends StatelessWidget {
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.all(20),
padding: const EdgeInsets.all(20),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
@@ -26,12 +26,12 @@ class OnboardingCard extends StatelessWidget {
color: Colors.white,
),
),
Padding(padding: EdgeInsets.only(top: 20)),
const Padding(padding: EdgeInsets.only(top: 20)),
SvgPicture.asset(
imagePath,
height: 200,
),
Padding(padding: EdgeInsets.only(top: 20)),
const Padding(padding: EdgeInsets.only(top: 20)),
Text(
description,
style: Theme.of(context).textTheme.bodyMedium!.copyWith(

View File

@@ -17,48 +17,78 @@ class TripsOverview extends StatefulWidget {
}
class _TripsOverviewState extends State<TripsOverview> {
Widget listBuild (BuildContext context, SavedTrips trips) {
List<Widget> children;
List<Trip> items = trips.trips;
children = List<Widget>.generate(items.length, (index) {
Trip trip = items[index];
return ListTile(
title: FutureBuilder(
future: trip.cityName,
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
if (snapshot.hasData) {
return Text("Trip to ${snapshot.data}");
} else if (snapshot.hasError) {
return Text("Error: ${snapshot.error}");
} else {
return const Text("Trip to ...");
}
},
),
leading: Icon(Icons.pin_drop),
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => TripPage(trip: trip)
)
);
Widget tripListItemBuilder(BuildContext context, int index) {
Trip trip = widget.trips.trips[index];
return ListTile(
title: FutureBuilder(
future: trip.cityName,
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
if (snapshot.hasData) {
return Text("Trip to ${snapshot.data}");
} else if (snapshot.hasError) {
return Text("Error: ${snapshot.error}");
} else {
return const Text("Trip to ...");
}
},
);
});
),
// emoji of the country flag of the trip's country
leading: const Icon(Icons.pin_drop),
return ListView(
children: children,
padding: const EdgeInsets.only(top: 0),
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => TripPage(trip: trip)
)
);
},
);
}
// Widget listBuild (BuildContext context, SavedTrips trips) {
// List<Widget> children;
// List<Trip> items = trips.trips;
// children = List<Widget>.generate(items.length, (index) {
// Trip trip = items[index];
// return ListTile(
// title: FutureBuilder(
// future: trip.cityName,
// builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
// if (snapshot.hasData) {
// return Text("Trip to ${snapshot.data}");
// } else if (snapshot.hasError) {
// return Text("Error: ${snapshot.error}");
// } else {
// return const Text("Trip to ...");
// }
// },
// ),
// leading: const Icon(Icons.pin_drop),
// onTap: () {
// Navigator.of(context).push(
// MaterialPageRoute(
// builder: (context) => TripPage(trip: trip)
// )
// );
// },
// );
// });
// return ListView(
// padding: const EdgeInsets.only(top: 0),
// children: children,
// );
// }
@override
Widget build(BuildContext context) {
return ListenableBuilder(
listenable: widget.trips,
builder: (BuildContext context, Widget? child) {
return listBuild(context, widget.trips);
}
builder: (BuildContext context, Widget? child) => ListView.builder(
itemCount: widget.trips.trips.length,
itemBuilder: tripListItemBuilder,
)
);
}
}

View File

@@ -4,10 +4,10 @@ import 'package:flutter/material.dart';
import 'package:sliding_up_panel/sliding_up_panel.dart';
import 'package:anyway/structs/trip.dart';
import 'package:anyway/modules/current_trip_map.dart';
import 'package:anyway/modules/current_trip_overview.dart';
import 'package:anyway/modules/current_trip_panel.dart';
final Shader textGradient = APP_GRADIENT.createShader(Rect.fromLTWH(0.0, 0.0, 200.0, 70.0));
final Shader textGradient = APP_GRADIENT.createShader(const Rect.fromLTWH(0.0, 0.0, 200.0, 70.0));
TextStyle greeterStyle = TextStyle(
foreground: Paint()..shader = textGradient,
fontWeight: FontWeight.bold,
@@ -18,7 +18,7 @@ TextStyle greeterStyle = TextStyle(
class TripPage extends StatefulWidget {
final Trip trip;
TripPage({
const TripPage({super.key,
required this.trip,
});
@@ -39,7 +39,7 @@ class _TripPageState extends State<TripPage> with ScaffoldLayout{
panelBuilder: (scrollcontroller) => CurrentTripPanel(controller: scrollcontroller, trip: widget.trip),
// using collapsed and panelBuilder seems to show both at the same time, so we include the greeter in the panelBuilder
// collapsed: Greeter(trip: widget.trip),
body: CurrentTripMap(trip: widget.trip),
body: CurrentTripOverview(trip: widget.trip),
minHeight: MediaQuery.of(context).size.height * TRIP_PANEL_MIN_HEIGHT,
maxHeight: MediaQuery.of(context).size.height * TRIP_PANEL_MAX_HEIGHT,
// padding in this context is annoying: it offsets the notion of vertical alignment.

View File

@@ -8,7 +8,7 @@ import 'package:anyway/modules/new_trip_map.dart';
class NewTripPage extends StatefulWidget {
const NewTripPage({Key? key}) : super(key: key);
const NewTripPage({super.key});
@override
_NewTripPageState createState() => _NewTripPageState();
@@ -30,14 +30,14 @@ class _NewTripPageState extends State<NewTripPage> with ScaffoldLayout {
children: [
NewTripMap(trip),
Padding(
padding: EdgeInsets.all(15),
padding: const EdgeInsets.all(15),
child: NewTripLocationSearch(trip),
),
],
),
floatingActionButton: NewTripOptionsButton(trip: trip),
),
title: Text("New Trip"),
title: const Text("New Trip"),
helpTexts: [
"Setting the start location",
"To set the starting point, type a city name in the search bar. You can also navigate the map like you're used to and long press anywhere to set a starting point."

View File

@@ -10,7 +10,7 @@ import 'package:flutter/material.dart';
class NewTripPreferencesPage extends StatefulWidget {
final Trip trip;
const NewTripPreferencesPage({required this.trip});
const NewTripPreferencesPage({super.key, required this.trip});
@override
_NewTripPreferencesPageState createState() => _NewTripPreferencesPageState();
@@ -34,14 +34,14 @@ class _NewTripPreferencesPageState extends State<NewTripPreferencesPage> with Sc
child: Scaffold(
body: ListView(
children: [
Center(
const Center(
child: Padding(
padding: EdgeInsets.only(left: 10, right: 10, top: 20, bottom: 0),
child: Text('Tell us about your ideal trip.', style: TextStyle(fontSize: 18))
),
),
Divider(indent: 25, endIndent: 25, height: 50),
const Divider(indent: 25, endIndent: 25, height: 50),
durationPicker(preferences.maxTime),
@@ -78,7 +78,7 @@ class _NewTripPreferencesPageState extends State<NewTripPreferencesPage> with Sc
title: Text(preferences.maxTime.description),
subtitle: CupertinoTimerPicker(
mode: CupertinoTimerPickerMode.hm,
initialTimerDuration: Duration(minutes: 90),
initialTimerDuration: const Duration(minutes: 90),
minuteInterval: 15,
onTimerDurationChanged: (Duration newDuration) {
setState(() {

View File

@@ -23,7 +23,7 @@ class _NoTripsPageState extends State<NoTripsPage> with ScaffoldLayout {
style: Theme.of(context).textTheme.headlineMedium,
textAlign: TextAlign.center,
),
Padding(padding: EdgeInsets.only(bottom: 10)),
const Padding(padding: EdgeInsets.only(bottom: 10)),
Text(
"You can start a new trip by clicking the button below",
style: Theme.of(context).textTheme.bodyMedium,

View File

@@ -116,9 +116,9 @@ class _OnboardingPageState extends State<OnboardingPage> {
if ((_controller.hasClients ? (_controller.page ?? _controller.initialPage) : 0) != fullCards.length - 1) {
return FloatingActionButton.extended(
onPressed: () {
controller.nextPage(duration: Duration(milliseconds: 500), curve: Curves.ease);
controller.nextPage(duration: const Duration(milliseconds: 500), curve: Curves.ease);
},
label: Icon(Icons.arrow_forward)
label: const Icon(Icons.arrow_forward)
);
} else {
// only allow the user to proceed if they have agreed to the terms and conditions

View File

@@ -11,6 +11,8 @@ import 'package:anyway/layouts/scaffold.dart';
bool debugMode = false;
class SettingsPage extends StatefulWidget {
const SettingsPage({super.key});
@override
_SettingsPageState createState() => _SettingsPageState();
}
@@ -20,31 +22,31 @@ class _SettingsPageState extends State<SettingsPage> with ScaffoldLayout {
Widget build (BuildContext context) => mainScaffold(
context,
child: ListView(
padding: EdgeInsets.all(15),
padding: const EdgeInsets.all(15),
children: [
// First a round, centered image
Center(
const Center(
child: CircleAvatar(
radius: 75,
child: Icon(Icons.settings, size: 100),
)
),
Center(
const Center(
child: Text('Global settings', style: TextStyle(fontSize: 24))
),
Divider(indent: 25, endIndent: 25, height: 50),
const Divider(indent: 25, endIndent: 25, height: 50),
darkMode(),
setLocationUsage(),
setDebugMode(),
Divider(indent: 25, endIndent: 25, height: 50),
const Divider(indent: 25, endIndent: 25, height: 50),
privacyInfo(),
]
),
title: Text('Settings'),
title: const Text('Settings'),
helpTexts: [
'Settings',
'Preferences set in this page are global and will affect the entire application.'
@@ -54,9 +56,9 @@ class _SettingsPageState extends State<SettingsPage> with ScaffoldLayout {
Widget setDebugMode() {
return Row(
children: [
Text('Debugging: use a custom API URL'),
const Text('Debugging: use a custom API URL'),
// white space
Spacer(),
const Spacer(),
Switch(
value: debugMode,
onChanged: (bool? newValue) {
@@ -67,7 +69,7 @@ class _SettingsPageState extends State<SettingsPage> with ScaffoldLayout {
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('Debug mode - use a custom API endpoint'),
title: const Text('Debug mode - use a custom API endpoint'),
content: TextField(
controller: TextEditingController(text: API_URL_DEBUG),
onChanged: (value) {
@@ -78,7 +80,7 @@ class _SettingsPageState extends State<SettingsPage> with ScaffoldLayout {
),
actions: [
TextButton(
child: Text('OK'),
child: const Text('OK'),
onPressed: () {
Navigator.of(context).pop();
},
@@ -98,14 +100,14 @@ class _SettingsPageState extends State<SettingsPage> with ScaffoldLayout {
Widget darkMode() {
return Row(
children: [
Text('Dark mode'),
Spacer(),
const Text('Dark mode'),
const Spacer(),
Switch(
value: Theme.of(context).brightness == Brightness.dark,
onChanged: (bool? newValue) {
setState(() {
rootScaffoldMessengerKey.currentState!.showSnackBar(
SnackBar(content: Text('Dark mode is not implemented yet'))
const SnackBar(content: Text('Dark mode is not implemented yet'))
);
// if (newValue!) {
// // Dark mode
@@ -125,9 +127,9 @@ class _SettingsPageState extends State<SettingsPage> with ScaffoldLayout {
Future<SharedPreferences> preferences = SharedPreferences.getInstance();
return Row(
children: [
Text('Use location services'),
const Text('Use location services'),
// white space
Spacer(),
const Spacer(),
FutureBuilder(
future: preferences,
builder: (context, snapshot) {
@@ -138,7 +140,7 @@ class _SettingsPageState extends State<SettingsPage> with ScaffoldLayout {
onChanged: setUseLocation,
);
} else {
return CircularProgressIndicator();
return const CircularProgressIndicator();
}
}
)
@@ -150,12 +152,12 @@ class _SettingsPageState extends State<SettingsPage> with ScaffoldLayout {
await Permission.locationWhenInUse
.onDeniedCallback(() {
rootScaffoldMessengerKey.currentState!.showSnackBar(
SnackBar(content: Text('Location services are required for this feature'))
const SnackBar(content: Text('Location services are required for this feature'))
);
})
.onGrantedCallback(() {
rootScaffoldMessengerKey.currentState!.showSnackBar(
SnackBar(content: Text('Location services are now enabled'))
const SnackBar(content: Text('Location services are now enabled'))
);
SharedPreferences.getInstance().then(
(SharedPreferences prefs) {
@@ -167,7 +169,7 @@ class _SettingsPageState extends State<SettingsPage> with ScaffoldLayout {
})
.onPermanentlyDeniedCallback(() {
rootScaffoldMessengerKey.currentState!.showSnackBar(
SnackBar(content: Text('Location services are required for this feature'))
const SnackBar(content: Text('Location services are required for this feature'))
);
})
.request();
@@ -177,12 +179,12 @@ class _SettingsPageState extends State<SettingsPage> with ScaffoldLayout {
return Center(
child: Column(
children: [
Text('AnyWay does not collect or store any of the data that is submitted via the app. The location of your trip is not stored. The location feature is only used to show your current location on the map.', textAlign: TextAlign.center),
Padding(padding: EdgeInsets.only(top: 3)),
Text('Our full privacy policy is available under:', textAlign: TextAlign.center),
const Text('AnyWay does not collect or store any of the data that is submitted via the app. The location of your trip is not stored. The location feature is only used to show your current location on the map.', textAlign: TextAlign.center),
const Padding(padding: EdgeInsets.only(top: 3)),
const Text('Our full privacy policy is available under:', textAlign: TextAlign.center),
TextButton.icon(
icon: Icon(Icons.info),
icon: const Icon(Icons.info),
label: Text(PRIVACY_URL),
onPressed: () async{
await launchUrl(Uri.parse(PRIVACY_URL));

View File

@@ -53,7 +53,7 @@ class UserPreferences {
value: 30,
minVal: 30,
maxVal: 720,
icon: Icon(Icons.timer),
icon: const Icon(Icons.timer),
);

View File

@@ -82,11 +82,11 @@ class Trip with ChangeNotifier {
// removing the landmark means we need to recompute the time between the two adjoined landmarks
if (previous != null && next != null) {
// previous.next = next happens automatically since we are using a LinkedList
this.totalTime -= previous.tripTime ?? Duration.zero;
totalTime -= previous.tripTime ?? Duration.zero;
previous.tripTime = null;
// TODO
}
this.totalTime -= landmark.tripTime ?? Duration.zero;
totalTime -= landmark.tripTime ?? Duration.zero;
notifyListeners();
}

View File

@@ -32,7 +32,7 @@ fetchTrip(
) async {
Map<String, dynamic> data = {
"preferences": preferences.toJson(),
"start": trip.landmarks!.first.location,
"start": trip.landmarks.first.location,
};
String dataString = jsonEncode(data);
log(dataString);

View File

@@ -23,27 +23,27 @@ Widget getFirstPage() {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.hasData) {
List<Trip> trips = snapshot.data!;
if (trips.length > 0) {
if (trips.isNotEmpty) {
return TripPage(trip: trips[0]);
} else {
return NoTripsPage();
return const NoTripsPage();
}
} else {
return Center(child: CircularProgressIndicator());
return const Center(child: CircularProgressIndicator());
}
} else {
return Center(child: CircularProgressIndicator());
return const Center(child: CircularProgressIndicator());
}
},
);
} else {
return OnboardingPage();
return const OnboardingPage();
}
} else {
return OnboardingPage();
return const OnboardingPage();
}
} else {
return OnboardingPage();
return const OnboardingPage();
}
},
);

View File

@@ -21,10 +21,10 @@ packages:
dependency: transitive
description:
name: async
sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63
sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb"
url: "https://pub.dev"
source: hosted
version: "2.12.0"
version: "2.13.0"
auto_size_text:
dependency: "direct main"
description:
@@ -149,10 +149,10 @@ packages:
dependency: transitive
description:
name: fake_async
sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc"
sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44"
url: "https://pub.dev"
source: hosted
version: "1.3.2"
version: "1.3.3"
ffi:
dependency: transitive
description:
@@ -420,10 +420,10 @@ packages:
dependency: transitive
description:
name: leak_tracker
sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec
sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0"
url: "https://pub.dev"
source: hosted
version: "10.0.8"
version: "10.0.9"
leak_tracker_flutter_testing:
dependency: transitive
description:
@@ -969,10 +969,10 @@ packages:
dependency: transitive
description:
name: vm_service
sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14"
sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02
url: "https://pub.dev"
source: hosted
version: "14.3.1"
version: "15.0.0"
web:
dependency: transitive
description:

3
frontend/secrets.json Normal file
View File

@@ -0,0 +1,3 @@
{
"ANDROID_GOOGLE_MAPS_API_KEY": "lfhasölkjfslöfjöksjf"
}

View File

@@ -1,30 +0,0 @@
// This is a basic Flutter widget test.
//
// To perform an interaction with a widget in your test, use the WidgetTester
// utility in the flutter_test package. For example, you can send tap and scroll
// gestures. You can also use WidgetTester to find child widgets in the widget
// tree, read text, and verify that the values of widget properties are correct.
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:anyway/main.dart';
void main() {
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
// Build our app and trigger a frame.
await tester.pumpWidget(const MyApp());
// Verify that our counter starts at 0.
expect(find.text('0'), findsOneWidget);
expect(find.text('1'), findsNothing);
// Tap the '+' icon and trigger a frame.
await tester.tap(find.byIcon(Icons.add));
await tester.pump();
// Verify that our counter has incremented.
expect(find.text('0'), findsNothing);
expect(find.text('1'), findsOneWidget);
});
}