added adjustable settings

This commit is contained in:
Myzel394 2022-08-18 23:53:48 +02:00
parent 359ed768c5
commit affac14aba
13 changed files with 208 additions and 23 deletions

View File

@ -1 +1,2 @@
const CACHE_KEY = '_cache';
const SETTINGS_KEY = 'settings';

View File

@ -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),
),
),
);

View 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,
};
}

View File

@ -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"
}

View File

@ -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"
}

View File

@ -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) {

View File

@ -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();

View File

@ -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 =>

View File

@ -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
View 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();
}
}

View File

@ -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) {

View File

@ -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();

View File

@ -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>[