improvements & bugfixes; added cache manager

This commit is contained in:
Myzel394 2022-08-18 13:52:11 +02:00
parent 4630c6d983
commit d92451d808
9 changed files with 112 additions and 45 deletions

View File

@ -1 +1 @@
const STARTUP_PAGE_KEY = 'startup_page';
const CACHE_KEY = '_cache';

View File

@ -7,3 +7,4 @@ const PHOTO_SHOW_AFTER_CREATION_DURATION = Duration(milliseconds: 500);
final UnmodifiableSetView<double> DEFAULT_ZOOM_LEVELS =
UnmodifiableSetView({0.6, 1, 2, 5, 10, 20, 50, 100});
const CALENDAR_DATE_IN_MAX_DELAY = Duration(milliseconds: 500);
const CACHE_INVALIDATION_DURATION = Duration(days: 7);

View File

@ -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/timeline_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 'models/memories.dart';
@ -43,6 +44,27 @@ class MyApp extends StatefulWidget {
class _MyAppState extends State<MyApp> {
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
Widget build(BuildContext context) {
return ChangeNotifierProvider.value(

View File

@ -1,7 +1,7 @@
import 'package:flutter/material.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/welcome_screen.dart';
import 'package:supabase/supabase.dart';
import 'package:supabase_flutter/supabase_flutter.dart';
@ -10,7 +10,7 @@ class AuthState<T extends StatefulWidget> extends SupabaseAuthState<T> {
void onUnauthenticated() {
if (mounted) {
Navigator.of(context)
.pushNamedAndRemoveUntil(LoginScreen.ID, (route) => false);
.pushNamedAndRemoveUntil(WelcomeScreen.ID, (route) => false);
}
}

View 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'];
}
}

View File

@ -1,20 +1,20 @@
import 'dart:io';
import 'dart:typed_data';
import 'package:flutter_secure_storage/flutter_secure_storage.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/managers/cache_manager.dart';
import 'package:quid_faciam_hodie/managers/global_values_manager.dart';
import 'package:supabase_flutter/supabase_flutter.dart';
import 'package:uuid/uuid.dart';
const uuid = Uuid();
const storage = FlutterSecureStorage();
final supabase = Supabase.instance.client;
class FileManager {
static Map<String, Uint8List> fileCache = {};
static Future<Memory> getMemoryMetadata(final String id) async {
await GlobalValuesManager.waitForServerInitialization();
@ -56,51 +56,31 @@ class FileManager {
}
}
static Future<List?> getLastFile(final User user) async {
final response = await supabase
.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]!;
}
static Future<Uint8List> _downloadFileData(
final String table, final String path) async {
final response = await supabase.storage.from(table).download(path);
if (response.error != null) {
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;
}

View File

@ -68,6 +68,13 @@ class Memories extends PropertyChangeNotifier<String> {
.subscribe();
}
Future<void> refresh() async {
memories.clear();
_serverSubscription?.unsubscribe();
setIsInitialized(false);
}
Future<void> _onServerUpdate(
final SupabaseRealtimePayload response,
) async {

View File

@ -73,7 +73,6 @@ class _LoginScreenState extends AuthState<LoginScreen> with Loadable {
message: localizations.loginScreenLoginFailed,
);
emailController.clear();
passwordController.clear();
}
return;

View File

@ -2,6 +2,7 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.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:quid_faciam_hodie/constants/spacing.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;
const storage = FlutterSecureStorage();
class SettingsScreen extends StatefulWidget {
static const ID = '/settings';