diff --git a/lib/providers/sn_sticker.dart b/lib/providers/sn_sticker.dart index 4a4cc78..df015dd 100644 --- a/lib/providers/sn_sticker.dart +++ b/lib/providers/sn_sticker.dart @@ -1,11 +1,17 @@ +import 'dart:convert'; + +import 'package:drift/drift.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; +import 'package:surface/database/database.dart'; import 'package:surface/logger.dart'; +import 'package:surface/providers/database.dart'; import 'package:surface/providers/sn_network.dart'; import 'package:surface/types/attachment.dart'; class SnStickerProvider { late final SnNetworkProvider _sn; + late final DatabaseProvider _dt; final Map _cache = {}; final Map> stickersByPack = {}; @@ -15,6 +21,7 @@ class SnStickerProvider { SnStickerProvider(BuildContext context) { _sn = context.read(); + _dt = context.read(); } bool hasNotSticker(String alias) { @@ -31,22 +38,32 @@ class SnStickerProvider { } } - void putSticker(Iterable sticker) { - for (final ele in sticker) { + void putSticker(Iterable stickers) { + for (final ele in stickers) { _cacheSticker(ele); } + _saveStickerToLocal(stickers); + _saveStickerPackToLocal(stickers.map((ele) => ele.pack).toSet()); } Future lookupSticker(String alias) async { + // In-memory cache if (_cache.containsKey(alias)) { return _cache[alias]; } - + // On-disk cache + final localStickers = await (_dt.db.snLocalSticker.select() + ..where((e) => e.fullAlias.equals(alias))) + .getSingleOrNull(); + if (localStickers != null) { + _cache[alias] = localStickers.content; + return localStickers.content; + } + // Remote server try { final resp = await _sn.client.get('/cgi/uc/stickers/lookup/$alias'); final sticker = SnSticker.fromJson(resp.data); - _cacheSticker(sticker); - + putSticker([sticker]); return sticker; } catch (err) { _cache[alias] = null; @@ -57,6 +74,18 @@ class SnStickerProvider { } Future listSticker() async { + final localPacks = await _dt.db.snLocalStickerPack.select().get(); + final localStickers = await _dt.db.snLocalSticker.select().get(); + final local = localStickers.map((ele) { + return ele.content.copyWith( + pack: localPacks + .firstWhere((pk) => pk.content.id == ele.content.packId) + .content, + ); + }); + for (final sticker in local) { + _cacheSticker(sticker); + } try { final resp = await _sn.client.get('/cgi/uc/stickers'); final data = resp.data; @@ -69,4 +98,35 @@ class SnStickerProvider { rethrow; } } + + Future _saveStickerToLocal(Iterable stickers) async { + await _dt.db.snLocalSticker.insertAll( + stickers.map( + (ele) => SnLocalStickerCompanion.insert( + id: Value(ele.id), + alias: ele.alias, + fullAlias: '${ele.pack.prefix}${ele.alias}', + content: ele, + createdAt: Value(ele.createdAt), + ), + ), + onConflict: DoNothing(), + ); + } + + Future _saveStickerPackToLocal(Iterable packs) async { + final queries = packs + .map( + (ele) => _dt.db.snLocalStickerPack.insertOne( + SnLocalStickerPackCompanion.insert( + id: Value(ele.id), + content: ele, + createdAt: Value(ele.createdAt), + ), + onConflict: DoUpdate((_) => SnLocalStickerPackCompanion.custom( + content: Constant(jsonEncode(ele.toJson()))))), + ) + .toList(); + await Future.wait(queries); + } } diff --git a/lib/screens/stickers.dart b/lib/screens/stickers.dart index c0a3ae8..475d684 100644 --- a/lib/screens/stickers.dart +++ b/lib/screens/stickers.dart @@ -284,7 +284,10 @@ class _StickerPackAddPopupState extends State<_StickerPackAddPopup> { ); if (!mounted) return; context.showSnackbar('stickersAdded'.tr()); - if (_pack?.stickers != null) stickers.putSticker(_pack!.stickers!); + if (_pack?.stickers != null) { + stickers.putSticker( + _pack!.stickers!.map((ele) => ele.copyWith(pack: _pack!))); + } Navigator.pop(context, true); } catch (err) { if (!mounted) return;