Line data Source code
1 : /* MIT License
2 : *
3 : * Copyright (C) 2019, 2020, 2021 Famedly GmbH
4 : *
5 : * Permission is hereby granted, free of charge, to any person obtaining a copy
6 : * of this software and associated documentation files (the "Software"), to deal
7 : * in the Software without restriction, including without limitation the rights
8 : * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 : * copies of the Software, and to permit persons to whom the Software is
10 : * furnished to do so, subject to the following conditions:
11 : *
12 : * The above copyright notice and this permission notice shall be included in all
13 : * copies or substantial portions of the Software.
14 : *
15 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 : * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 : * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 : * SOFTWARE.
22 : */
23 :
24 : import 'package:matrix/matrix_api_lite/model/basic_event.dart';
25 : import 'package:matrix/matrix_api_lite/utils/filter_map_extension.dart';
26 : import 'package:matrix/matrix_api_lite/utils/try_get_map_extension.dart';
27 :
28 : extension ImagePackContentBasicEventExtension on BasicEvent {
29 2 : ImagePackContent get parsedImagePackContent =>
30 4 : ImagePackContent.fromJson(content);
31 : }
32 :
33 : enum ImagePackUsage {
34 : sticker,
35 : emoticon,
36 : }
37 :
38 2 : List<ImagePackUsage>? imagePackUsageFromJson(List<String>? json) => json
39 2 : ?.map(
40 4 : (v) => {
41 : 'sticker': ImagePackUsage.sticker,
42 : 'emoticon': ImagePackUsage.emoticon,
43 2 : }[v],
44 : )
45 2 : .whereType<ImagePackUsage>()
46 2 : .toList();
47 :
48 0 : List<String> imagePackUsageToJson(
49 : List<ImagePackUsage>? usage,
50 : List<String>? prevUsage,
51 : ) {
52 0 : final knownUsages = <String>{'sticker', 'emoticon'};
53 : final usagesStr = usage
54 0 : ?.map(
55 0 : (v) => {
56 : ImagePackUsage.sticker: 'sticker',
57 : ImagePackUsage.emoticon: 'emoticon',
58 0 : }[v],
59 : )
60 0 : .whereType<String>()
61 0 : .toList() ??
62 0 : [];
63 : // first we add all the unknown usages and the previous known usages which are new again
64 : final newUsages = prevUsage
65 0 : ?.where((v) => !knownUsages.contains(v) || usagesStr.contains(v))
66 0 : .toList() ??
67 0 : [];
68 : // now we need to add the new usages that we didn't add yet
69 0 : newUsages.addAll(usagesStr.where((v) => !newUsages.contains(v)));
70 : return newUsages;
71 : }
72 :
73 : class ImagePackContent {
74 : // we want to preserve potential custom keys in this object
75 : final Map<String, Object?> _json;
76 :
77 : Map<String, ImagePackImageContent> images;
78 : ImagePackPackContent pack;
79 :
80 0 : ImagePackContent({required this.images, required this.pack}) : _json = {};
81 :
82 2 : ImagePackContent.fromJson(Map<String, Object?> json)
83 2 : : _json = Map.fromEntries(
84 4 : json.entries.where(
85 8 : (e) => !['images', 'pack', 'emoticons', 'short'].contains(e.key),
86 : ),
87 : ),
88 2 : pack = ImagePackPackContent.fromJson(
89 4 : json.tryGetMap<String, Object?>('pack') ?? {},
90 : ),
91 4 : images = json.tryGetMap<String, Object?>('images')?.catchMap(
92 4 : (k, v) => MapEntry(
93 : k,
94 2 : ImagePackImageContent.fromJson(
95 : v as Map<String, Object?>,
96 : ),
97 : ),
98 : ) ??
99 : // the "emoticons" key needs a small migration on the key, ":string:" --> "string"
100 2 : json.tryGetMap<String, Object?>('emoticons')?.catchMap(
101 0 : (k, v) => MapEntry(
102 0 : k.startsWith(':') && k.endsWith(':')
103 0 : ? k.substring(1, k.length - 1)
104 : : k,
105 0 : ImagePackImageContent.fromJson(
106 : v as Map<String, Object?>,
107 : ),
108 : ),
109 : ) ??
110 : // the "short" key was still just a map from shortcode to mxc uri
111 2 : json.tryGetMap<String, String>('short')?.catchMap(
112 0 : (k, v) => MapEntry(
113 0 : k.startsWith(':') && k.endsWith(':')
114 0 : ? k.substring(1, k.length - 1)
115 : : k,
116 0 : ImagePackImageContent(url: Uri.parse(v)),
117 : ),
118 : ) ??
119 2 : {};
120 :
121 0 : Map<String, Object?> toJson() => {
122 0 : ..._json,
123 0 : 'images': images.map((k, v) => MapEntry(k, v.toJson())),
124 0 : 'pack': pack.toJson(),
125 : };
126 : }
127 :
128 : class ImagePackImageContent {
129 : // we want to preserve potential custom keys in this object
130 : final Map<String, Object?> _json;
131 :
132 : Uri url;
133 : String? body;
134 : Map<String, Object?>? info;
135 : List<ImagePackUsage>? usage;
136 :
137 0 : ImagePackImageContent({required this.url, this.body, this.info, this.usage})
138 0 : : _json = {};
139 :
140 2 : ImagePackImageContent.fromJson(Map<String, Object?> json)
141 2 : : _json = Map.fromEntries(
142 12 : json.entries.where((e) => !['url', 'body', 'info'].contains(e.key)),
143 : ),
144 4 : url = Uri.parse(json['url'] as String),
145 2 : body = json.tryGet('body'),
146 2 : info = json.tryGetMap<String, Object?>('info'),
147 4 : usage = imagePackUsageFromJson(json.tryGetList<String>('usage'));
148 :
149 0 : Map<String, Object?> toJson() {
150 0 : return {
151 0 : ...Map.from(_json)..remove('usage'),
152 0 : 'url': url.toString(),
153 0 : if (body != null) 'body': body,
154 0 : if (info != null) 'info': info,
155 0 : if (usage != null)
156 0 : 'usage': imagePackUsageToJson(usage, _json.tryGetList<String>('usage')),
157 : };
158 : }
159 : }
160 :
161 : class ImagePackPackContent {
162 : // we want to preserve potential custom keys in this object
163 : final Map<String, Object?> _json;
164 :
165 : String? displayName;
166 : Uri? avatarUrl;
167 : List<ImagePackUsage>? usage;
168 : String? attribution;
169 :
170 0 : ImagePackPackContent({
171 : this.displayName,
172 : this.avatarUrl,
173 : this.usage,
174 : this.attribution,
175 0 : }) : _json = {};
176 :
177 2 : ImagePackPackContent.fromJson(Map<String, Object?> json)
178 2 : : _json = Map.fromEntries(
179 4 : json.entries.where(
180 2 : (e) =>
181 6 : !['display_name', 'avatar_url', 'attribution'].contains(e.key),
182 : ),
183 : ),
184 2 : displayName = json.tryGet('display_name'),
185 : // we default to an invalid uri
186 4 : avatarUrl = Uri.tryParse(json.tryGet('avatar_url') ?? '.::'),
187 4 : usage = imagePackUsageFromJson(json.tryGetList<String>('usage')),
188 2 : attribution = json.tryGet('attribution');
189 :
190 0 : Map<String, Object?> toJson() {
191 0 : return {
192 0 : ...Map.from(_json)..remove('usage'),
193 0 : if (displayName != null) 'display_name': displayName,
194 0 : if (avatarUrl != null) 'avatar_url': avatarUrl.toString(),
195 0 : if (usage != null)
196 0 : 'usage': imagePackUsageToJson(usage, _json.tryGetList<String>('usage')),
197 0 : if (attribution != null) 'attribution': attribution,
198 : };
199 : }
200 : }
|