feat(service): Implement automatic sticker pack downloading

This commit is contained in:
PapaTutuWawa 2022-12-19 14:09:21 +01:00
parent f04729261b
commit e373f5cffe
6 changed files with 143 additions and 29 deletions

View File

@ -250,6 +250,14 @@ files:
implements:
- JsonImplementation
attributes:
- name: StickerPackAddedEvent
extends: BackgroundEvent
implements:
- JsonImplementation
attributes:
stickerPack:
type: StickerPack
deserialise: true
generate_builder: true
builder_name: "Event"
builder_baseclass: "BackgroundEvent"

View File

@ -10,7 +10,9 @@ import 'package:moxxmpp/moxxmpp.dart' as moxxmpp;
import 'package:moxxyv2/service/database/database.dart';
import 'package:moxxyv2/service/helpers.dart';
import 'package:moxxyv2/service/httpfiletransfer/helpers.dart';
import 'package:moxxyv2/service/service.dart';
import 'package:moxxyv2/service/xmpp.dart';
import 'package:moxxyv2/shared/events.dart';
import 'package:moxxyv2/shared/helpers.dart';
import 'package:moxxyv2/shared/models/sticker.dart';
import 'package:moxxyv2/shared/models/sticker_pack.dart';
@ -107,6 +109,40 @@ class StickersService {
return stickerDirPath;
}
Future<void> importFromPubSubWithEvent(moxxmpp.JID jid, String stickerPackId) async {
final stickerPack = await importFromPubSub(jid, stickerPackId);
if (stickerPack == null) return;
sendEvent(
StickerPackAddedEvent(
stickerPack: stickerPack,
),
);
}
/// Takes the jid of the host [jid] and the id [stickerPackId] of the sticker pack
/// and tries to fetch and install it, including publishing on our own PubSub node.
///
/// On success, returns the installed StickerPack. On failure, returns null.
Future<StickerPack?> importFromPubSub(moxxmpp.JID jid, String stickerPackId) async {
final result = await GetIt.I.get<moxxmpp.XmppConnection>()
.getManagerById<moxxmpp.StickersManager>(moxxmpp.stickersManager)!
.fetchStickerPack(jid.toBare(), stickerPackId);
if (result.isType<moxxmpp.PubSubError>()) {
_log.warning('Failed to fetch sticker pack $jid:$stickerPackId');
return null;
}
final stickerPackRaw = StickerPack.fromMoxxmpp(
result.get<moxxmpp.StickerPack>(),
false,
);
// Install the sticker pack
return installFromPubSub(stickerPackRaw);
}
Future<StickerPack?> installFromPubSub(StickerPack remotePack) async {
assert(!remotePack.local, 'Sticker pack must be remote');
@ -175,33 +211,7 @@ class StickersService {
// Publish but don't block
unawaited(
_publishStickerPack(
moxxmpp.StickerPack(
remotePack.id,
remotePack.name,
remotePack.description,
moxxmpp.hashFunctionFromName(remotePack.hashAlgorithm),
remotePack.hashValue,
remotePack.stickers
.map((sticker) => moxxmpp.Sticker(
moxxmpp.FileMetadataData(
mediaType: sticker.mediaType,
desc: sticker.desc,
size: sticker.size,
width: sticker.width,
height: sticker.height,
thumbnails: [],
hashes: sticker.hashes,
),
sticker.urlSources
// ignore: unnecessary_lambdas
.map((src) => moxxmpp.StatelessFileSharingUrlSource(src))
.toList(),
sticker.suggests,
),).toList(),
remotePack.restricted,
),
),
_publishStickerPack(remotePack.toMoxxmpp()),
);
return remotePack.copyWith(

View File

@ -28,6 +28,7 @@ import 'package:moxxyv2/service/preferences.dart';
import 'package:moxxyv2/service/roster.dart';
import 'package:moxxyv2/service/service.dart';
import 'package:moxxyv2/service/state.dart';
import 'package:moxxyv2/service/stickers.dart';
import 'package:moxxyv2/shared/error_types.dart';
import 'package:moxxyv2/shared/eventhandler.dart';
import 'package:moxxyv2/shared/events.dart';
@ -1170,6 +1171,29 @@ class XmppService {
final stickerHashKey = event.stickerPackId != null ?
getStickerHashKey(event.sfs!.metadata.hashes) :
null;
// The potential sticker pack
final stickerPack = event.stickerPackId != null ?
await GetIt.I.get<StickersService>().getStickerPackById(
event.stickerPackId!,
) :
null;
// Automatically download the sticker pack, if
// - a sticker was received,
// - the sender is in the roster,
// - we don't have the sticker pack locally,
// - and it is enabled in the settings
if (event.stickerPackId != null &&
stickerPack == null &&
prefs.autoDownloadStickersFromContacts &&
isInRoster) {
unawaited(
GetIt.I.get<StickersService>().importFromPubSubWithEvent(
event.fromJid,
event.stickerPackId!,
),
);
}
// Create the message in the database
final ms = GetIt.I.get<MessageService>();

View File

@ -1,5 +1,7 @@
import 'dart:convert';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:moxxmpp/moxxmpp.dart' as moxxmpp;
import 'package:moxxyv2/service/helpers.dart';
part 'sticker.freezed.dart';
part 'sticker.g.dart';
@ -23,6 +25,24 @@ class Sticker with _$Sticker {
const Sticker._();
/// Moxxmpp
factory Sticker.fromMoxxmpp(moxxmpp.Sticker sticker, String stickerPackId) => Sticker(
getStickerHashKey(sticker.metadata.hashes),
sticker.metadata.mediaType!,
sticker.metadata.desc!,
sticker.metadata.size!,
sticker.metadata.width,
sticker.metadata.height,
sticker.metadata.hashes,
sticker.sources
.whereType<moxxmpp.StatelessFileSharingUrlSource>()
.map((src) => src.url)
.toList(),
'',
stickerPackId,
sticker.suggests,
);
/// JSON
factory Sticker.fromJson(Map<String, dynamic> json) => _$StickerFromJson(json);
@ -48,4 +68,21 @@ class Sticker with _$Sticker {
'suggests': jsonEncode(suggests),
};
}
moxxmpp.Sticker toMoxxmpp() => moxxmpp.Sticker(
moxxmpp.FileMetadataData(
mediaType: mediaType,
desc: desc,
size: size,
width: width,
height: height,
thumbnails: [],
hashes: hashes,
),
urlSources
// ignore: unnecessary_lambdas
.map((src) => moxxmpp.StatelessFileSharingUrlSource(src))
.toList(),
suggests,
);
}

View File

@ -1,4 +1,5 @@
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:moxxmpp/moxxmpp.dart' as moxxmpp;
import 'package:moxxyv2/service/database/helpers.dart';
import 'package:moxxyv2/shared/models/sticker.dart';
@ -20,6 +21,20 @@ class StickerPack with _$StickerPack {
const StickerPack._();
/// Moxxmpp
factory StickerPack.fromMoxxmpp(moxxmpp.StickerPack pack, bool local) => StickerPack(
pack.id,
pack.name,
pack.summary,
pack.stickers
.map((sticker) => Sticker.fromMoxxmpp(sticker, pack.id))
.toList(),
pack.hashAlgorithm.toName(),
pack.hashValue,
pack.restricted,
local,
);
/// JSON
factory StickerPack.fromJson(Map<String, dynamic> json) => _$StickerPackFromJson(json);
@ -44,4 +59,16 @@ class StickerPack with _$StickerPack {
'restricted': boolToInt(restricted),
};
}
moxxmpp.StickerPack toMoxxmpp() => moxxmpp.StickerPack(
id,
name,
description,
moxxmpp.hashFunctionFromName(hashAlgorithm),
hashValue,
stickers
.map((sticker) => sticker.toMoxxmpp())
.toList(),
restricted,
);
}

View File

@ -15,6 +15,7 @@ import 'package:moxxyv2/ui/bloc/conversations_bloc.dart' as conversations;
import 'package:moxxyv2/ui/bloc/newconversation_bloc.dart' as new_conversation;
import 'package:moxxyv2/ui/bloc/profile_bloc.dart' as profile;
import 'package:moxxyv2/ui/bloc/sharedmedia_bloc.dart' as sharedmedia;
import 'package:moxxyv2/ui/bloc/stickers_bloc.dart' as stickers;
import 'package:moxxyv2/ui/prestart.dart';
import 'package:moxxyv2/ui/service/progress.dart';
@ -32,6 +33,7 @@ void setupEventHandler() {
EventTypeMatcher<PreStartDoneEvent>(preStartDone),
EventTypeMatcher<ServiceReadyEvent>(onServiceReady),
EventTypeMatcher<MessageNotificationTappedEvent>(onNotificationTappend),
EventTypeMatcher<StickerPackAddedEvent>(onStickerPackAdded),
]);
GetIt.I.registerSingleton<EventHandler>(handler);
@ -159,3 +161,9 @@ Future<void> onNotificationTappend(MessageNotificationTappedEvent event, { dynam
),
);
}
Future<void> onStickerPackAdded(StickerPackAddedEvent event, { dynamic extra }) async {
GetIt.I.get<stickers.StickersBloc>().add(
stickers.StickerPackAddedEvent(event.stickerPack),
);
}