Files
anyway/frontend/lib/pages/settings.dart
2025-10-20 17:08:10 +02:00

199 lines
5.8 KiB
Dart

import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:anyway/main.dart';
import 'package:anyway/constants.dart';
import 'package:anyway/layouts/scaffold.dart';
bool debugMode = false;
class SettingsPage extends StatefulWidget {
const SettingsPage({super.key});
@override
_SettingsPageState createState() => _SettingsPageState();
}
class _SettingsPageState extends State<SettingsPage> with ScaffoldLayout {
@override
Widget build (BuildContext context) => mainScaffold(
context,
child: ListView(
padding: const EdgeInsets.all(15),
children: [
// First a round, centered image
const Center(
child: CircleAvatar(
radius: 75,
child: Icon(Icons.settings, size: 100),
)
),
const Center(
child: Text('Global settings', style: TextStyle(fontSize: 24))
),
const Divider(indent: 25, endIndent: 25, height: 50),
darkMode(),
setLocationUsage(),
setDebugMode(),
const Divider(indent: 25, endIndent: 25, height: 50),
privacyInfo(),
]
),
title: const Text('Settings'),
helpTexts: [
'Settings',
'Preferences set in this page are global and will affect the entire application.'
],
);
Widget setDebugMode() {
return Row(
children: [
const Text('Debugging: use a custom API URL'),
// white space
const Spacer(),
Switch(
value: debugMode,
onChanged: (bool? newValue) {
setState(() {
debugMode = newValue!;
if (debugMode) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Debug mode - use a custom API endpoint'),
content: TextField(
controller: TextEditingController(text: API_URL_DEBUG),
onChanged: (value) {
setState(() {
API_URL_BASE = value;
});
},
),
actions: [
TextButton(
child: const Text('OK'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
}
);
}
});
}
)
],
);
}
Widget darkMode() {
return Row(
children: [
const Text('Dark mode'),
const Spacer(),
Switch(
value: Theme.of(context).brightness == Brightness.dark,
onChanged: (bool? newValue) {
setState(() {
rootScaffoldMessengerKey.currentState!.showSnackBar(
const SnackBar(content: Text('Dark mode is not implemented yet'))
);
// if (newValue!) {
// // Dark mode
// Theme.of(context).brightness = Brightness.dark;
// } else {
// // Light mode
// Theme.of(context).brightness = Brightness.light;
// }
});
}
)
],
);
}
Widget setLocationUsage() {
Future<SharedPreferences> preferences = SharedPreferences.getInstance();
return Row(
children: [
const Text('Use location services'),
// white space
const Spacer(),
FutureBuilder(
future: preferences,
builder: (context, snapshot) {
if (snapshot.hasData) {
bool useLocation = snapshot.data!.getBool('useLocation') ?? false;
return Switch(
value: useLocation,
onChanged: setUseLocation,
);
} else {
return const CircularProgressIndicator();
}
}
)
],
);
}
void setUseLocation(bool newValue) async {
await Permission.locationWhenInUse
.onDeniedCallback(() {
rootScaffoldMessengerKey.currentState!.showSnackBar(
const SnackBar(content: Text('Location services are required for this feature'))
);
})
.onGrantedCallback(() {
rootScaffoldMessengerKey.currentState!.showSnackBar(
const SnackBar(content: Text('Location services are now enabled'))
);
SharedPreferences.getInstance().then(
(SharedPreferences prefs) {
setState(() {
prefs.setBool('useLocation', newValue);
});
}
);
})
.onPermanentlyDeniedCallback(() {
rootScaffoldMessengerKey.currentState!.showSnackBar(
const SnackBar(content: Text('Location services are required for this feature'))
);
})
.request();
}
Widget privacyInfo() {
return Center(
child: Column(
children: [
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: const Icon(Icons.info),
label: Text(PRIVACY_URL),
onPressed: () async{
await launchUrl(Uri.parse(PRIVACY_URL));
}
)
],
)
);
}
}