mirror of
https://github.com/Myzel394/quid_faciam_hodie.git
synced 2025-06-19 23:55:26 +02:00
added adjustable settings
This commit is contained in:
parent
359ed768c5
commit
affac14aba
@ -1 +1,2 @@
|
||||
const CACHE_KEY = '_cache';
|
||||
const SETTINGS_KEY = 'settings';
|
||||
|
@ -1,5 +1,6 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:quid_faciam_hodie/constants/spacing.dart';
|
||||
|
||||
final LIGHT_THEME_MATERIAL = ThemeData(
|
||||
textTheme: ThemeData().textTheme.copyWith(
|
||||
@ -13,7 +14,7 @@ final LIGHT_THEME_MATERIAL = ThemeData(
|
||||
helperMaxLines: 10,
|
||||
errorMaxLines: 10,
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
borderRadius: BorderRadius.circular(MEDIUM_SPACE),
|
||||
),
|
||||
),
|
||||
);
|
||||
@ -30,7 +31,7 @@ final DARK_THEME_MATERIAL = ThemeData.dark().copyWith(
|
||||
helperMaxLines: 10,
|
||||
errorMaxLines: 10,
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
borderRadius: BorderRadius.circular(MEDIUM_SPACE),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
19
lib/enum_mapping/resolution_preset/texts.dart
Normal file
19
lib/enum_mapping/resolution_preset/texts.dart
Normal file
@ -0,0 +1,19 @@
|
||||
import 'package:camera/camera.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
Map<ResolutionPreset, String> getResolutionTextMapping(
|
||||
final BuildContext context) {
|
||||
final localizations = AppLocalizations.of(context)!;
|
||||
|
||||
return {
|
||||
ResolutionPreset.low: localizations.enumMapping_ResolutionPreset_low,
|
||||
ResolutionPreset.medium: localizations.enumMapping_ResolutionPreset_medium,
|
||||
ResolutionPreset.high: localizations.enumMapping_ResolutionPreset_high,
|
||||
ResolutionPreset.veryHigh:
|
||||
localizations.enumMapping_ResolutionPreset_veryHigh,
|
||||
ResolutionPreset.ultraHigh:
|
||||
localizations.enumMapping_ResolutionPreset_ultraHigh,
|
||||
ResolutionPreset.max: localizations.enumMapping_ResolutionPreset_max,
|
||||
};
|
||||
}
|
@ -79,5 +79,15 @@
|
||||
"settingsScreenDangerSectionTitle": "Gefahrbereich",
|
||||
"settingsScreenDangerSectionDeleteAccountLabel": "Account löschen",
|
||||
"settingsScreenDeleteAccountDescription": "Bist du dir sicher, dass du deinen Account löschen möchtest? Diese Aktion kann nicht rückgangig gemacht werden! Deine Erfahrungen werden ebenfalls gelöscht.",
|
||||
"settingsScreenDeleteAccountConfirmLabel": "Account jetzt löschen"
|
||||
"settingsScreenDeleteAccountConfirmLabel": "Account jetzt löschen",
|
||||
"settingsScreenGeneralSectionTitle": "General",
|
||||
"settingsScreenGeneralSectionQualityLabel": "Quality",
|
||||
|
||||
|
||||
"enumMapping_ResolutionPreset_low": "Niedrig",
|
||||
"enumMapping_ResolutionPreset_medium": "Medium",
|
||||
"enumMapping_ResolutionPreset_high": "Hoch",
|
||||
"enumMapping_ResolutionPreset_veryHigh": "Sehr Hoch",
|
||||
"enumMapping_ResolutionPreset_ultraHigh": "Ultra Hoch",
|
||||
"enumMapping_ResolutionPreset_max": "Max"
|
||||
}
|
@ -108,5 +108,15 @@
|
||||
"settingsScreenDangerSectionTitle": "Danger Zone",
|
||||
"settingsScreenDangerSectionDeleteAccountLabel": "Delete Account",
|
||||
"settingsScreenDeleteAccountDescription": "Are you sure you want to delete your account? This action cannot be undone! All your memories will be deleted as well.",
|
||||
"settingsScreenDeleteAccountConfirmLabel": "Delete Account now"
|
||||
"settingsScreenDeleteAccountConfirmLabel": "Delete Account now",
|
||||
"settingsScreenGeneralSectionTitle": "General",
|
||||
"settingsScreenGeneralSectionQualityLabel": "Quality",
|
||||
|
||||
|
||||
"enumMapping_ResolutionPreset_low": "Low",
|
||||
"enumMapping_ResolutionPreset_medium": "Medium",
|
||||
"enumMapping_ResolutionPreset_high": "High",
|
||||
"enumMapping_ResolutionPreset_veryHigh": "Very High",
|
||||
"enumMapping_ResolutionPreset_ultraHigh": "Ultra High",
|
||||
"enumMapping_ResolutionPreset_max": "Max"
|
||||
}
|
@ -27,7 +27,7 @@ void main() async {
|
||||
DeviceOrientation.portraitDown,
|
||||
]);
|
||||
|
||||
GlobalValuesManager.initializeServer();
|
||||
GlobalValuesManager.initialize();
|
||||
|
||||
runApp(const MyApp());
|
||||
}
|
||||
@ -52,7 +52,7 @@ class _MyAppState extends State<MyApp> {
|
||||
}
|
||||
|
||||
Future<void> watchAuthenticationStatus() async {
|
||||
await GlobalValuesManager.waitForServerInitialization();
|
||||
await GlobalValuesManager.watchForInitialization();
|
||||
|
||||
Supabase.instance.client.auth.onAuthStateChange((event, session) {
|
||||
switch (event) {
|
||||
|
@ -17,7 +17,7 @@ final supabase = Supabase.instance.client;
|
||||
|
||||
class FileManager {
|
||||
static Future<Memory> getMemoryMetadata(final String id) async {
|
||||
await GlobalValuesManager.waitForServerInitialization();
|
||||
await GlobalValuesManager.watchForInitialization();
|
||||
|
||||
final response = await supabase
|
||||
.from('memories')
|
||||
@ -38,7 +38,7 @@ class FileManager {
|
||||
final File file, {
|
||||
LocationData? locationData,
|
||||
}) async {
|
||||
await GlobalValuesManager.waitForServerInitialization();
|
||||
await GlobalValuesManager.watchForInitialization();
|
||||
|
||||
final basename = uuid.v4();
|
||||
final extension = file.path.split('.').last;
|
||||
@ -108,7 +108,7 @@ class FileManager {
|
||||
final bool disableDownloadCache = false,
|
||||
final bool disableFileCache = false,
|
||||
}) async {
|
||||
await GlobalValuesManager.waitForServerInitialization();
|
||||
await GlobalValuesManager.watchForInitialization();
|
||||
|
||||
final tempDirectory = await getTemporaryDirectory();
|
||||
final filename = '${tempDirectory.path}/$path';
|
||||
@ -129,7 +129,7 @@ class FileManager {
|
||||
}
|
||||
|
||||
static Future<void> deleteFile(final String path) async {
|
||||
await GlobalValuesManager.waitForServerInitialization();
|
||||
await GlobalValuesManager.watchForInitialization();
|
||||
|
||||
final response =
|
||||
await supabase.from('memories').delete().eq('location', path).execute();
|
||||
|
@ -2,15 +2,19 @@ import 'package:camera/camera.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
import 'package:quid_faciam_hodie/constants/apis.dart';
|
||||
import 'package:quid_faciam_hodie/models/settings.dart';
|
||||
import 'package:supabase_flutter/supabase_flutter.dart';
|
||||
|
||||
class GlobalValuesManager {
|
||||
static Future? _serverInitializationFuture;
|
||||
static Future? _settingsInitializationFuture;
|
||||
static bool _isServerInitialized = false;
|
||||
static List<CameraDescription> _cameras = [];
|
||||
static Settings? _settings;
|
||||
|
||||
static List<CameraDescription> get cameras => [..._cameras];
|
||||
static bool get isServerInitialized => _isServerInitialized;
|
||||
static Settings? get settings => _settings;
|
||||
|
||||
static void setCameras(List<CameraDescription> cameras) {
|
||||
if (_cameras.isNotEmpty) {
|
||||
@ -20,7 +24,7 @@ class GlobalValuesManager {
|
||||
_cameras = cameras;
|
||||
}
|
||||
|
||||
static void initializeServer() {
|
||||
static void _initializeServer() {
|
||||
if (_isServerInitialized || _serverInitializationFuture != null) {
|
||||
return;
|
||||
}
|
||||
@ -35,16 +39,41 @@ class GlobalValuesManager {
|
||||
});
|
||||
}
|
||||
|
||||
static Future<void> waitForServerInitialization() async {
|
||||
static void _initializeSettings() {
|
||||
_settingsInitializationFuture = Settings.restore()
|
||||
..then((settings) {
|
||||
_settings = settings;
|
||||
_settingsInitializationFuture = null;
|
||||
});
|
||||
}
|
||||
|
||||
static void initialize() {
|
||||
_initializeServer();
|
||||
_initializeSettings();
|
||||
}
|
||||
|
||||
static Future<void> watchForInitialization() async {
|
||||
// Server initialization
|
||||
if (_serverInitializationFuture == null) {
|
||||
if (_isServerInitialized) {
|
||||
return;
|
||||
} else {
|
||||
throw Exception('Server has not been initialized yet');
|
||||
}
|
||||
} else {
|
||||
await _serverInitializationFuture;
|
||||
}
|
||||
|
||||
await _serverInitializationFuture;
|
||||
// Settings initialization
|
||||
if (_settingsInitializationFuture == null) {
|
||||
if (_settings == null) {
|
||||
throw Exception('Settings have not been initialized yet');
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
await _settingsInitializationFuture;
|
||||
}
|
||||
}
|
||||
|
||||
static Future<bool> hasGrantedPermissions() async =>
|
||||
|
@ -109,7 +109,7 @@ class Memories extends PropertyChangeNotifier<String> {
|
||||
}
|
||||
|
||||
Future<void> _loadInitialData() async {
|
||||
await GlobalValuesManager.waitForServerInitialization();
|
||||
await GlobalValuesManager.watchForInitialization();
|
||||
|
||||
final response = await supabase
|
||||
.from('memories')
|
||||
|
52
lib/models/settings.dart
Normal file
52
lib/models/settings.dart
Normal file
@ -0,0 +1,52 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:camera/camera.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:quid_faciam_hodie/constants/storage_keys.dart';
|
||||
|
||||
const secure = FlutterSecureStorage();
|
||||
|
||||
class Settings extends ChangeNotifier {
|
||||
ResolutionPreset _resolution = ResolutionPreset.high;
|
||||
|
||||
Settings({final ResolutionPreset resolution = ResolutionPreset.high})
|
||||
: _resolution = resolution;
|
||||
|
||||
ResolutionPreset get resolution => _resolution;
|
||||
|
||||
Map<String, dynamic> toJSONData() => {
|
||||
'resolution': _resolution.toString(),
|
||||
};
|
||||
|
||||
Future<void> save() async {
|
||||
final data = toJSONData();
|
||||
|
||||
await secure.write(
|
||||
key: SETTINGS_KEY,
|
||||
value: jsonEncode(data),
|
||||
);
|
||||
}
|
||||
|
||||
static Future<Settings> restore() async {
|
||||
final rawData = await secure.read(key: SETTINGS_KEY);
|
||||
|
||||
if (rawData == null) {
|
||||
return Settings();
|
||||
}
|
||||
|
||||
final data = jsonDecode(rawData);
|
||||
final resolution = ResolutionPreset.values.firstWhere(
|
||||
(preset) => preset.toString() == data['resolution'],
|
||||
);
|
||||
return Settings(
|
||||
resolution: resolution,
|
||||
);
|
||||
}
|
||||
|
||||
void setResolution(final ResolutionPreset value) {
|
||||
_resolution = value;
|
||||
notifyListeners();
|
||||
save();
|
||||
}
|
||||
}
|
@ -71,6 +71,7 @@ class _MainScreenState extends AuthRequiredState<MainScreen> with Loadable {
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
loadSettings();
|
||||
loadCameras();
|
||||
}
|
||||
|
||||
@ -85,6 +86,18 @@ class _MainScreenState extends AuthRequiredState<MainScreen> with Loadable {
|
||||
_updateCamera(state);
|
||||
}
|
||||
|
||||
Future<void> loadSettings() async {
|
||||
final settings = GlobalValuesManager.settings!;
|
||||
|
||||
settings.addListener(() {
|
||||
if (!mounted || controller == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
onNewCameraSelected(controller!.description);
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> loadCameras() async {
|
||||
GlobalValuesManager.setCameras(await availableCameras());
|
||||
|
||||
@ -116,11 +129,13 @@ class _MainScreenState extends AuthRequiredState<MainScreen> with Loadable {
|
||||
}
|
||||
|
||||
void onNewCameraSelected(final CameraDescription cameraDescription) async {
|
||||
final settings = GlobalValuesManager.settings!;
|
||||
final previousCameraController = controller;
|
||||
|
||||
// Instantiating the camera controller
|
||||
final CameraController cameraController = CameraController(
|
||||
cameraDescription,
|
||||
ResolutionPreset.high,
|
||||
settings.resolution,
|
||||
imageFormatGroup: ImageFormatGroup.jpeg,
|
||||
);
|
||||
cameraController.setFlashMode(FlashMode.off);
|
||||
@ -192,13 +207,6 @@ class _MainScreenState extends AuthRequiredState<MainScreen> with Loadable {
|
||||
}
|
||||
|
||||
final file = File((await controller!.takePicture()).path);
|
||||
LocationData? locationData;
|
||||
|
||||
if (Platform.isAndroid && (await Permission.location.isGranted)) {
|
||||
locationData = await Location().getLocation();
|
||||
|
||||
await tagLocationToImage(file, locationData);
|
||||
}
|
||||
|
||||
setState(() {
|
||||
uploadingPhotoAnimation = file.readAsBytesSync();
|
||||
@ -209,6 +217,14 @@ class _MainScreenState extends AuthRequiredState<MainScreen> with Loadable {
|
||||
message: localizations.mainScreenTakePhotoActionUploadingPhoto,
|
||||
);
|
||||
|
||||
LocationData? locationData;
|
||||
|
||||
if (Platform.isAndroid && (await Permission.location.isGranted)) {
|
||||
locationData = await Location().getLocation();
|
||||
|
||||
await tagLocationToImage(file, locationData);
|
||||
}
|
||||
|
||||
try {
|
||||
await FileManager.uploadFile(_user, file, locationData: locationData);
|
||||
} catch (error) {
|
||||
|
@ -43,7 +43,7 @@ class _ServerLoadingScreenState extends State<ServerLoadingScreen> {
|
||||
);
|
||||
}
|
||||
|
||||
await GlobalValuesManager.waitForServerInitialization();
|
||||
await GlobalValuesManager.watchForInitialization();
|
||||
|
||||
final memories = context.read<Memories>();
|
||||
final session = Supabase.instance.client.auth.session();
|
||||
|
@ -1,3 +1,4 @@
|
||||
import 'package:camera/camera.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
@ -5,7 +6,9 @@ import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:quid_faciam_hodie/constants/spacing.dart';
|
||||
import 'package:quid_faciam_hodie/enum_mapping/resolution_preset/texts.dart';
|
||||
import 'package:quid_faciam_hodie/extensions/snackbar.dart';
|
||||
import 'package:quid_faciam_hodie/managers/global_values_manager.dart';
|
||||
import 'package:quid_faciam_hodie/screens/welcome_screen.dart';
|
||||
import 'package:quid_faciam_hodie/utils/auth_required.dart';
|
||||
import 'package:quid_faciam_hodie/utils/loadable.dart';
|
||||
@ -30,6 +33,18 @@ class _SettingsScreenState extends AuthRequiredState<SettingsScreen>
|
||||
with Loadable {
|
||||
User? user;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
final settings = GlobalValuesManager.settings!;
|
||||
|
||||
// Update UI when settings change
|
||||
settings.addListener(() {
|
||||
setState(() {});
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void onAuthenticated(Session session) {
|
||||
if (session.user != null) {
|
||||
@ -68,7 +83,9 @@ class _SettingsScreenState extends AuthRequiredState<SettingsScreen>
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final settings = GlobalValuesManager.settings!;
|
||||
final localizations = AppLocalizations.of(context)!;
|
||||
final resolutionTextMapping = getResolutionTextMapping(context);
|
||||
|
||||
return PlatformScaffold(
|
||||
appBar: PlatformAppBar(
|
||||
@ -141,6 +158,36 @@ class _SettingsScreenState extends AuthRequiredState<SettingsScreen>
|
||||
)
|
||||
],
|
||||
),
|
||||
SettingsSection(
|
||||
title: Text(
|
||||
localizations.settingsScreenGeneralSectionTitle,
|
||||
),
|
||||
tiles: <SettingsTile>[
|
||||
SettingsTile(
|
||||
leading: Text(
|
||||
localizations
|
||||
.settingsScreenGeneralSectionQualityLabel,
|
||||
),
|
||||
title: DropdownButtonFormField<ResolutionPreset>(
|
||||
value: settings.resolution,
|
||||
onChanged: (value) async {
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
settings.setResolution(value);
|
||||
},
|
||||
items: ResolutionPreset.values
|
||||
.map((value) =>
|
||||
DropdownMenuItem<ResolutionPreset>(
|
||||
value: value,
|
||||
child: Text(resolutionTextMapping[value]!),
|
||||
))
|
||||
.toList(),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
SettingsSection(
|
||||
title: Text(localizations.settingsScreenDangerSectionTitle),
|
||||
tiles: <SettingsTile>[
|
||||
|
Loading…
x
Reference in New Issue
Block a user