parent
2041b81141
commit
4b329b4c6f
3 changed files with 1115 additions and 119 deletions
|
|
@ -29,6 +29,9 @@ class const AccountData({
|
|||
static const imagePackRoomsKey = "m.image_pack.rooms";
|
||||
static const legacyImagePackRoomsKey = "im.ponies.emote_rooms";
|
||||
|
||||
ImagePackRooms get enabledImagePacks =>
|
||||
imagePackRooms ?? legacyImagePackRooms ?? const .new();
|
||||
|
||||
Map<String, Object?> toJson() => _$AccountDataToJson(this);
|
||||
|
||||
factory AccountData.fromJson(Map<String, Object?> json) =>
|
||||
|
|
@ -53,6 +56,29 @@ class const ImagePackRooms({
|
|||
/// empty) object
|
||||
final IMap<String, IMap<String, Map<String, dynamic>>> rooms = const .empty(),
|
||||
}) with _$ImagePackRooms {
|
||||
bool contains(String roomId, String stateKey) =>
|
||||
rooms[roomId]?.containsKey(stateKey) ?? false;
|
||||
|
||||
ImagePackRooms withPack(
|
||||
String roomId,
|
||||
String stateKey, {
|
||||
required bool enabled,
|
||||
}) {
|
||||
final packs =
|
||||
rooms[roomId] ?? const IMap<String, Map<String, dynamic>>.empty();
|
||||
final updated = switch ((enabled, packs.containsKey(stateKey))) {
|
||||
(true, false) => packs.add(stateKey, const {}),
|
||||
(false, true) => packs.remove(stateKey),
|
||||
_ => packs,
|
||||
};
|
||||
|
||||
return copyWith(
|
||||
rooms: updated.isEmpty
|
||||
? rooms.remove(roomId)
|
||||
: rooms.add(roomId, updated),
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, Object?> toJson() => _$ImagePackRoomsToJson(this);
|
||||
|
||||
factory ImagePackRooms.fromJson(Map<String, Object?> json) =>
|
||||
|
|
|
|||
|
|
@ -7,11 +7,14 @@ part "image_pack.g.dart";
|
|||
|
||||
/// An image pack (MSC2545), from a room's state.
|
||||
@Freezed(toJson: false, fromJson: false)
|
||||
@JsonSerializable()
|
||||
@JsonSerializable(includeIfNull: false)
|
||||
class const ImagePackContent({
|
||||
final IMap<String, PackImage> images = const .empty(),
|
||||
final PackInfo? pack,
|
||||
}) extends Content with _$ImagePackContent {
|
||||
/// Whether the pack has images or a name, as deleted packs are left empty.
|
||||
bool get hasContent => images.isNotEmpty || pack?.displayName != null;
|
||||
|
||||
IMap<String, PackImage> imagesFor(ImageUsage usage) => images.where(
|
||||
(_, image) => switch ((image.usage, pack?.usage ?? const .empty())) {
|
||||
(final usages, _) when usages.isNotEmpty => usages.contains(usage),
|
||||
|
|
@ -30,12 +33,12 @@ class const ImagePackContent({
|
|||
}
|
||||
|
||||
@Freezed(toJson: false, fromJson: false)
|
||||
@JsonSerializable()
|
||||
@JsonSerializable(includeIfNull: false)
|
||||
class const PackImage({
|
||||
required final Uri url,
|
||||
final String? body,
|
||||
final ImageInfo? info,
|
||||
@JsonKey(fromJson: ImageUsage.setFromJson)
|
||||
@JsonKey(fromJson: ImageUsage.setFromJson, toJson: ImageUsage.setToJson)
|
||||
final ISet<ImageUsage> usage = const .empty(),
|
||||
}) with _$PackImage {
|
||||
Map<String, Object?> toJson() => _$PackImageToJson(this);
|
||||
|
|
@ -45,12 +48,12 @@ class const PackImage({
|
|||
}
|
||||
|
||||
@Freezed(toJson: false, fromJson: false)
|
||||
@JsonSerializable()
|
||||
@JsonSerializable(includeIfNull: false)
|
||||
class const PackInfo({
|
||||
final String? displayName,
|
||||
final Uri? avatarUrl,
|
||||
final String? attribution,
|
||||
@JsonKey(fromJson: ImageUsage.setFromJson)
|
||||
@JsonKey(fromJson: ImageUsage.setFromJson, toJson: ImageUsage.setToJson)
|
||||
final ISet<ImageUsage> usage = const .empty(),
|
||||
}) with _$PackInfo {
|
||||
Map<String, Object?> toJson() => _$PackInfoToJson(this);
|
||||
|
|
@ -66,4 +69,8 @@ enum ImageUsage {
|
|||
/// Ignores usages we don't know about.
|
||||
static ISet<ImageUsage> setFromJson(List<dynamic>? json) =>
|
||||
ISet(values.where((value) => json?.contains(value.name) ?? false));
|
||||
|
||||
/// Omits an empty set, which means every usage.
|
||||
static List<String>? setToJson(ISet<ImageUsage> usages) =>
|
||||
usages.isEmpty ? null : usages.map((usage) => usage.name).toList();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,21 +13,42 @@ class const ImagePack({
|
|||
/// Map of shortcode to images
|
||||
required final IMap<String, PackImage> emoticons,
|
||||
required final IMap<String, PackImage> stickers,
|
||||
|
||||
/// The state event the pack is from, for editing it.
|
||||
required final ImagePackContent content,
|
||||
}) with _$ImagePack {
|
||||
static String emojiMarkdown(String shortcode, String url) {
|
||||
final title = ":$shortcode:".replaceAll(r"\", r"\\").replaceAll('"', r'\"');
|
||||
return '';
|
||||
}
|
||||
/// The pack's avatar, or its first image if it has none.
|
||||
Uri? get icon => avatar ?? content.images.values.firstOrNull?.url;
|
||||
|
||||
String get imageCountLabel => content.images.length == 1
|
||||
? "1 image"
|
||||
: "${content.images.length} images";
|
||||
|
||||
/// The name of a pack without one, from its room's name and state key.
|
||||
static String fallbackName(String roomName, String stateKey) =>
|
||||
stateKey.isEmpty ? roomName : "$roomName - $stateKey";
|
||||
|
||||
static String emojiMarkdown(
|
||||
String shortcode,
|
||||
String url, {
|
||||
String? description,
|
||||
}) =>
|
||||
' {
|
||||
final description? when description.isNotEmpty => description,
|
||||
_ => ":$shortcode:",
|
||||
}.replaceAll(r"\", r"\\").replaceAll('"', r'\"')}")';
|
||||
|
||||
factory ImagePack.fromContent(
|
||||
ImagePackContent content, {
|
||||
required String id,
|
||||
required String fallbackName,
|
||||
required String roomId,
|
||||
required String roomName,
|
||||
required String stateKey,
|
||||
}) => .new(
|
||||
id: id,
|
||||
name: content.pack?.displayName ?? fallbackName,
|
||||
id: "$roomId/$stateKey",
|
||||
name: content.pack?.displayName ?? fallbackName(roomName, stateKey),
|
||||
avatar: content.pack?.avatarUrl,
|
||||
emoticons: content.imagesFor(.emoticon),
|
||||
stickers: content.imagesFor(.sticker),
|
||||
content: content,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue