2023-07-29 02:17:26 +00:00
|
|
|
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
|
2023-10-12 22:09:37 +00:00
|
|
|
@HiveField(0, defaultValue: [])
|
|
|
|
@JsonKey(defaultValue: [])
|
|
|
|
List<String> libraryTracks = [];
|
2023-07-29 02:17:26 +00:00
|
|
|
|
|
|
|
//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;
|
|
|
|
|
2023-10-18 15:08:05 +00:00
|
|
|
@HiveField(8, defaultValue: false)
|
|
|
|
bool canStreamHQ = false;
|
|
|
|
@HiveField(9, defaultValue: false)
|
|
|
|
bool canStreamLossless = false;
|
|
|
|
|
2023-07-29 02:17:26 +00:00
|
|
|
@JsonKey(includeToJson: false, includeFromJson: false)
|
|
|
|
bool wakelock = false;
|
|
|
|
|
2023-10-12 22:09:37 +00:00
|
|
|
Cache();
|
2023-07-29 02:17:26 +00:00
|
|
|
|
|
|
|
//Wrapper to test if track is favorite against cache
|
|
|
|
bool checkTrackFavorite(Track t) {
|
|
|
|
if (t.favorite != null && t.favorite!) return true;
|
2023-10-12 22:09:37 +00:00
|
|
|
if (libraryTracks.isEmpty) return false;
|
|
|
|
return libraryTracks.contains(t.id);
|
2023-07-29 02:17:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//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);
|
|
|
|
}
|
|
|
|
|
2023-10-12 22:09:37 +00:00
|
|
|
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) {
|
2023-07-29 02:17:26 +00:00
|
|
|
searchHistory
|
2023-10-12 22:09:37 +00:00
|
|
|
.add(SearchHistoryItem(item, SearchHistoryItemType.playlist));
|
|
|
|
}
|
2023-07-29 02:17:26 +00:00
|
|
|
|
|
|
|
await save();
|
|
|
|
}
|
|
|
|
|
|
|
|
//Save, load
|
|
|
|
|
|
|
|
static Future wipe() async {
|
|
|
|
await (await _box).clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: improve
|
2023-09-26 00:06:59 +00:00
|
|
|
static Future<Cache> load([int tryN = 0]) async {
|
2023-07-29 02:17:26 +00:00
|
|
|
final box = await _box;
|
|
|
|
|
2023-09-26 00:06:59 +00:00
|
|
|
if (tryN > 2) {
|
|
|
|
// recursion error, something's wrong
|
2023-10-12 22:09:37 +00:00
|
|
|
throw Exception("can't load cache");
|
2023-09-26 00:06:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//Doesn't exist, create new
|
2023-07-29 02:17:26 +00:00
|
|
|
if (box.isEmpty) {
|
|
|
|
final c = Cache();
|
|
|
|
await c.save();
|
|
|
|
return c;
|
|
|
|
}
|
2023-09-26 00:06:59 +00:00
|
|
|
try {
|
|
|
|
return (await box.get(0))!;
|
|
|
|
} catch (e) {
|
|
|
|
// invalidate cache on error
|
|
|
|
await box.clear();
|
|
|
|
return await load(tryN + 1);
|
|
|
|
}
|
2023-07-29 02:17:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
2023-09-26 00:06:59 +00:00
|
|
|
// TODO: make this type-safe
|
2023-07-29 02:17:26 +00:00
|
|
|
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)
|
2023-10-12 22:09:37 +00:00
|
|
|
track,
|
2023-07-29 02:17:26 +00:00
|
|
|
@HiveField(1)
|
2023-10-12 22:09:37 +00:00
|
|
|
album,
|
2023-07-29 02:17:26 +00:00
|
|
|
@HiveField(2)
|
2023-10-12 22:09:37 +00:00
|
|
|
artist,
|
2023-07-29 02:17:26 +00:00
|
|
|
@HiveField(3)
|
2023-10-12 22:09:37 +00:00
|
|
|
playlist
|
2023-07-29 02:17:26 +00:00
|
|
|
}
|