freezer/lib/api/cache.dart
Pato05 2862c9ec05
remove browser login for desktop
restore translations functionality
make scrollViews handle mouse pointers like touch, so that pull to refresh functionality is available
exit app if opening cache or settings fails (another instance running)
remove draggable_scrollbar and use builtin widget instead
fix email login
better way to manage lyrics (less updates and lookups in the lyrics List)
fix player_screen on mobile (too big -> just average :))
right click: use TapUp events instead
desktop: show context menu on triple dots button also
avoid showing connection error if the homepage is cached and available offline
i'm probably forgetting something idk
2023-10-25 00:32:28 +02:00

206 lines
5.4 KiB
Dart

import 'package:freezer/api/definitions.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:json_annotation/json_annotation.dart';
import 'dart:async';
part 'cache.g.dart';
late Cache cache;
//Cache for miscellaneous things
@HiveType(typeId: 22)
@JsonSerializable()
class Cache {
static Future<LazyBox<Cache>> get _box =>
Hive.openLazyBox<Cache>('metacache');
//ID's of tracks that are in library
@HiveField(0, defaultValue: [])
@JsonKey(defaultValue: [])
List<String> libraryTracks = [];
//Track ID of logged track, to prevent duplicates
@HiveField(1)
@JsonKey(includeToJson: false, includeFromJson: false)
String? loggedTrackId;
@HiveField(2)
@JsonKey(defaultValue: [])
List<Track> history = [];
//All sorting cached
@HiveField(3)
@JsonKey(defaultValue: [])
List<Sorting?> sorts = [];
//Sleep timer
@JsonKey(includeToJson: false, includeFromJson: false)
DateTime? sleepTimerTime;
@JsonKey(includeToJson: false, includeFromJson: false)
// ignore: cancel_subscriptions
StreamSubscription? sleepTimer;
//Search history
@HiveField(4)
@JsonKey(name: 'searchHistory2', defaultValue: [])
List<SearchHistoryItem> searchHistory = [];
//If download threads warning was shown
@HiveField(5)
@JsonKey(defaultValue: false)
bool threadsWarning = false;
//Last time update check
@HiveField(6)
DateTime? lastUpdateCheck;
@HiveField(7)
String? favoritesPlaylistId;
@HiveField(8, defaultValue: false)
bool canStreamHQ = false;
@HiveField(9, defaultValue: false)
bool canStreamLossless = false;
@JsonKey(includeToJson: false, includeFromJson: false)
bool wakelock = false;
Cache();
//Wrapper to test if track is favorite against cache
bool checkTrackFavorite(Track t) {
if (t.favorite != null && t.favorite!) return true;
if (libraryTracks.isEmpty) return false;
return libraryTracks.contains(t.id);
}
//Add to history
void addToSearchHistory(DeezerMediaItem item) async {
// Remove duplicate
int i = searchHistory.indexWhere((e) => e.data.id == item.id);
if (i != -1) {
searchHistory.removeAt(i);
}
if (item is Track) {
searchHistory.add(SearchHistoryItem(item, SearchHistoryItemType.track));
}
if (item is Album) {
searchHistory.add(SearchHistoryItem(item, SearchHistoryItemType.album));
}
if (item is Artist) {
searchHistory.add(SearchHistoryItem(item, SearchHistoryItemType.artist));
}
if (item is Playlist) {
searchHistory
.add(SearchHistoryItem(item, SearchHistoryItemType.playlist));
}
await save();
}
//Save, load
static Future wipe() async {
await (await _box).clear();
}
// TODO: improve
static Future<Cache> load([int tryN = 0]) async {
final box = await _box;
if (tryN > 1) {
// recursion error, something's wrong
throw Exception("can't load cache");
}
if (box.isNotEmpty) {
try {
return (await box.get(0))!;
} catch (e) {
// invalidate cache on error
await box.clear();
}
}
// create cache if non-existent or error occurred
final c = Cache();
await c.save();
return c;
}
Future<void> save() async {
final box = await _box;
await box.clear();
await box.put(0, this);
}
//JSON
factory Cache.fromJson(Map<String, dynamic> json) => _$CacheFromJson(json);
Map<String, dynamic> toJson() => _$CacheToJson(this);
//Search History JSON
// static List<SearchHistoryItem> _searchHistoryFromJson(List<dynamic>? json) {
// return (json ?? [])
// .map<SearchHistoryItem>((i) => _searchHistoryItemFromJson(i))
// .toList();
// }
// static SearchHistoryItem _searchHistoryItemFromJson(
// Map<String, dynamic> json) {
// SearchHistoryItemType type = SearchHistoryItemType.values[json['type']];
// dynamic data;
// switch (type) {
// case SearchHistoryItemType.TRACK:
// data = Track.fromJson(json['data']);
// break;
// case SearchHistoryItemType.ALBUM:
// data = Album.fromJson(json['data']);
// break;
// case SearchHistoryItemType.ARTIST:
// data = Artist.fromJson(json['data']);
// break;
// case SearchHistoryItemType.PLAYLIST:
// data = Playlist.fromJson(json['data']);
// break;
// }
// return SearchHistoryItem(data, type);
// }
}
@HiveType(typeId: 20)
@JsonSerializable()
class SearchHistoryItem {
@HiveField(0)
@JsonKey(
toJson: _searchHistoryItemTypeToJson,
fromJson: _searchHistoryItemTypeFromJson)
SearchHistoryItemType type;
@HiveField(1)
// TODO: make this type-safe
dynamic data;
SearchHistoryItem(this.data, this.type);
Map<String, dynamic> toJson() => _$SearchHistoryItemToJson(this);
factory SearchHistoryItem.fromJson(Map<String, dynamic> json) =>
_$SearchHistoryItemFromJson(json);
static int _searchHistoryItemTypeToJson(SearchHistoryItemType type) =>
type.index;
static SearchHistoryItemType _searchHistoryItemTypeFromJson(int index) =>
SearchHistoryItemType.values[index];
}
@HiveType(typeId: 21)
enum SearchHistoryItemType {
@HiveField(0)
track,
@HiveField(1)
album,
@HiveField(2)
artist,
@HiveField(3)
playlist
}