mirror of
https://github.com/Myzel394/quid_faciam_hodie.git
synced 2025-06-19 07:35:26 +02:00
improvements & bugfixes; added cache manager
This commit is contained in:
parent
4630c6d983
commit
d92451d808
@ -1 +1 @@
|
|||||||
const STARTUP_PAGE_KEY = 'startup_page';
|
const CACHE_KEY = '_cache';
|
||||||
|
@ -7,3 +7,4 @@ const PHOTO_SHOW_AFTER_CREATION_DURATION = Duration(milliseconds: 500);
|
|||||||
final UnmodifiableSetView<double> DEFAULT_ZOOM_LEVELS =
|
final UnmodifiableSetView<double> DEFAULT_ZOOM_LEVELS =
|
||||||
UnmodifiableSetView({0.6, 1, 2, 5, 10, 20, 50, 100});
|
UnmodifiableSetView({0.6, 1, 2, 5, 10, 20, 50, 100});
|
||||||
const CALENDAR_DATE_IN_MAX_DELAY = Duration(milliseconds: 500);
|
const CALENDAR_DATE_IN_MAX_DELAY = Duration(milliseconds: 500);
|
||||||
|
const CACHE_INVALIDATION_DURATION = Duration(days: 7);
|
||||||
|
@ -13,6 +13,7 @@ import 'package:quid_faciam_hodie/screens/server_loading_screen.dart';
|
|||||||
import 'package:quid_faciam_hodie/screens/settings_screen.dart';
|
import 'package:quid_faciam_hodie/screens/settings_screen.dart';
|
||||||
import 'package:quid_faciam_hodie/screens/timeline_screen.dart';
|
import 'package:quid_faciam_hodie/screens/timeline_screen.dart';
|
||||||
import 'package:quid_faciam_hodie/screens/welcome_screen.dart';
|
import 'package:quid_faciam_hodie/screens/welcome_screen.dart';
|
||||||
|
import 'package:supabase_flutter/supabase_flutter.dart';
|
||||||
|
|
||||||
import 'managers/global_values_manager.dart';
|
import 'managers/global_values_manager.dart';
|
||||||
import 'models/memories.dart';
|
import 'models/memories.dart';
|
||||||
@ -43,6 +44,27 @@ class MyApp extends StatefulWidget {
|
|||||||
class _MyAppState extends State<MyApp> {
|
class _MyAppState extends State<MyApp> {
|
||||||
final memories = Memories();
|
final memories = Memories();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
|
||||||
|
watchAuthenticationStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> watchAuthenticationStatus() async {
|
||||||
|
await GlobalValuesManager.waitForServerInitialization();
|
||||||
|
|
||||||
|
Supabase.instance.client.auth.onAuthStateChange((event, session) {
|
||||||
|
switch (event) {
|
||||||
|
case AuthChangeEvent.signedIn:
|
||||||
|
memories.refresh();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ChangeNotifierProvider.value(
|
return ChangeNotifierProvider.value(
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:quid_faciam_hodie/extensions/snackbar.dart';
|
import 'package:quid_faciam_hodie/extensions/snackbar.dart';
|
||||||
import 'package:quid_faciam_hodie/screens/login_screen.dart';
|
|
||||||
import 'package:quid_faciam_hodie/screens/main_screen.dart';
|
import 'package:quid_faciam_hodie/screens/main_screen.dart';
|
||||||
|
import 'package:quid_faciam_hodie/screens/welcome_screen.dart';
|
||||||
import 'package:supabase/supabase.dart';
|
import 'package:supabase/supabase.dart';
|
||||||
import 'package:supabase_flutter/supabase_flutter.dart';
|
import 'package:supabase_flutter/supabase_flutter.dart';
|
||||||
|
|
||||||
@ -10,7 +10,7 @@ class AuthState<T extends StatefulWidget> extends SupabaseAuthState<T> {
|
|||||||
void onUnauthenticated() {
|
void onUnauthenticated() {
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
Navigator.of(context)
|
Navigator.of(context)
|
||||||
.pushNamedAndRemoveUntil(LoginScreen.ID, (route) => false);
|
.pushNamedAndRemoveUntil(WelcomeScreen.ID, (route) => false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
55
lib/managers/cache_manager.dart
Normal file
55
lib/managers/cache_manager.dart
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||||
|
import 'package:quid_faciam_hodie/constants/storage_keys.dart';
|
||||||
|
import 'package:quid_faciam_hodie/constants/values.dart';
|
||||||
|
|
||||||
|
const storage = FlutterSecureStorage();
|
||||||
|
|
||||||
|
class CacheManager {
|
||||||
|
static _createKey(final String key) => '$CACHE_KEY/$key';
|
||||||
|
|
||||||
|
static Future<bool> isCacheValid(final String key) async {
|
||||||
|
final cacheKey = _createKey(key);
|
||||||
|
final existingEntry = await storage.read(key: cacheKey);
|
||||||
|
|
||||||
|
if (existingEntry != null) {
|
||||||
|
final entry = jsonDecode(existingEntry);
|
||||||
|
final DateTime creationDate = DateTime.parse(entry['creationDate']);
|
||||||
|
|
||||||
|
// Check if the entry is still valid using CACHE_INVALIDATION_DURATION as the validity duration.
|
||||||
|
return DateTime.now().difference(creationDate) <
|
||||||
|
CACHE_INVALIDATION_DURATION;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<void> set(final String key, final String data) async {
|
||||||
|
final cacheKey = _createKey(key);
|
||||||
|
final cacheEntry = {
|
||||||
|
'creationDate': DateTime.now().toIso8601String(),
|
||||||
|
'data': data,
|
||||||
|
};
|
||||||
|
|
||||||
|
return storage.write(
|
||||||
|
key: cacheKey,
|
||||||
|
value: json.encode({
|
||||||
|
key: cacheEntry,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<String?> get(final String key) async {
|
||||||
|
final cacheKey = _createKey(key);
|
||||||
|
final existingEntry = await storage.read(key: cacheKey);
|
||||||
|
|
||||||
|
if (existingEntry == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
final entry = jsonDecode(existingEntry);
|
||||||
|
|
||||||
|
return entry['data'];
|
||||||
|
}
|
||||||
|
}
|
@ -1,20 +1,20 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
import 'package:quid_faciam_hodie/enums.dart';
|
|
||||||
import 'package:quid_faciam_hodie/foreign_types/memory.dart';
|
import 'package:quid_faciam_hodie/foreign_types/memory.dart';
|
||||||
|
import 'package:quid_faciam_hodie/managers/cache_manager.dart';
|
||||||
import 'package:quid_faciam_hodie/managers/global_values_manager.dart';
|
import 'package:quid_faciam_hodie/managers/global_values_manager.dart';
|
||||||
import 'package:supabase_flutter/supabase_flutter.dart';
|
import 'package:supabase_flutter/supabase_flutter.dart';
|
||||||
import 'package:uuid/uuid.dart';
|
import 'package:uuid/uuid.dart';
|
||||||
|
|
||||||
const uuid = Uuid();
|
const uuid = Uuid();
|
||||||
|
const storage = FlutterSecureStorage();
|
||||||
|
|
||||||
final supabase = Supabase.instance.client;
|
final supabase = Supabase.instance.client;
|
||||||
|
|
||||||
class FileManager {
|
class FileManager {
|
||||||
static Map<String, Uint8List> fileCache = {};
|
|
||||||
|
|
||||||
static Future<Memory> getMemoryMetadata(final String id) async {
|
static Future<Memory> getMemoryMetadata(final String id) async {
|
||||||
await GlobalValuesManager.waitForServerInitialization();
|
await GlobalValuesManager.waitForServerInitialization();
|
||||||
|
|
||||||
@ -56,51 +56,31 @@ class FileManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<List?> getLastFile(final User user) async {
|
static Future<Uint8List> _downloadFileData(
|
||||||
final response = await supabase
|
final String table, final String path) async {
|
||||||
.from('memories')
|
|
||||||
.select()
|
|
||||||
.eq('user_id', user.id)
|
|
||||||
.order('created_at', ascending: false)
|
|
||||||
.limit(1)
|
|
||||||
.single()
|
|
||||||
.execute();
|
|
||||||
|
|
||||||
if (response.data == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
final memory = response.data;
|
|
||||||
final location = memory['location'];
|
|
||||||
final memoryType =
|
|
||||||
location.split('.').last == 'jpg' ? MemoryType.photo : MemoryType.video;
|
|
||||||
|
|
||||||
try {
|
|
||||||
final file = await _getFileData('memories', location);
|
|
||||||
|
|
||||||
return [file, memoryType];
|
|
||||||
} catch (error) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static Future<Uint8List> _getFileData(final String table, final String path,
|
|
||||||
{final bool disableCache = false}) async {
|
|
||||||
final key = '$table:$path';
|
|
||||||
|
|
||||||
if (!disableCache && fileCache.containsKey(key)) {
|
|
||||||
return fileCache[key]!;
|
|
||||||
}
|
|
||||||
|
|
||||||
final response = await supabase.storage.from(table).download(path);
|
final response = await supabase.storage.from(table).download(path);
|
||||||
|
|
||||||
if (response.error != null) {
|
if (response.error != null) {
|
||||||
throw Exception('Error downloading file: ${response.error!.message}');
|
throw Exception('Error downloading file: ${response.error!.message}');
|
||||||
}
|
}
|
||||||
|
|
||||||
final data = response.data!;
|
return response.data!;
|
||||||
|
}
|
||||||
|
|
||||||
fileCache[key] = data;
|
static Future<Uint8List> _getFileData(final String table, final String path,
|
||||||
|
{final bool disableCache = false}) async {
|
||||||
|
final key = '$table:$path';
|
||||||
|
|
||||||
|
// Check cache
|
||||||
|
if (!disableCache && await CacheManager.isCacheValid(key)) {
|
||||||
|
final data = (await CacheManager.get(key))!;
|
||||||
|
return Uint8List.fromList(data.codeUnits);
|
||||||
|
}
|
||||||
|
|
||||||
|
final data = await _downloadFileData(table, path);
|
||||||
|
|
||||||
|
final cacheData = String.fromCharCodes(data);
|
||||||
|
await CacheManager.set(key, cacheData);
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
@ -68,6 +68,13 @@ class Memories extends PropertyChangeNotifier<String> {
|
|||||||
.subscribe();
|
.subscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> refresh() async {
|
||||||
|
memories.clear();
|
||||||
|
_serverSubscription?.unsubscribe();
|
||||||
|
|
||||||
|
setIsInitialized(false);
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> _onServerUpdate(
|
Future<void> _onServerUpdate(
|
||||||
final SupabaseRealtimePayload response,
|
final SupabaseRealtimePayload response,
|
||||||
) async {
|
) async {
|
||||||
|
@ -73,7 +73,6 @@ class _LoginScreenState extends AuthState<LoginScreen> with Loadable {
|
|||||||
message: localizations.loginScreenLoginFailed,
|
message: localizations.loginScreenLoginFailed,
|
||||||
);
|
);
|
||||||
|
|
||||||
emailController.clear();
|
|
||||||
passwordController.clear();
|
passwordController.clear();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -2,6 +2,7 @@ import 'package:flutter/cupertino.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
|
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:intl/intl.dart';
|
||||||
import 'package:quid_faciam_hodie/constants/spacing.dart';
|
import 'package:quid_faciam_hodie/constants/spacing.dart';
|
||||||
import 'package:quid_faciam_hodie/extensions/snackbar.dart';
|
import 'package:quid_faciam_hodie/extensions/snackbar.dart';
|
||||||
@ -14,6 +15,8 @@ import 'package:supabase_flutter/supabase_flutter.dart';
|
|||||||
|
|
||||||
final supabase = Supabase.instance.client;
|
final supabase = Supabase.instance.client;
|
||||||
|
|
||||||
|
const storage = FlutterSecureStorage();
|
||||||
|
|
||||||
class SettingsScreen extends StatefulWidget {
|
class SettingsScreen extends StatefulWidget {
|
||||||
static const ID = '/settings';
|
static const ID = '/settings';
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user