mirror of
https://gitlab.com/famedly/fluffychat.git
synced 2024-11-19 10:39:26 +01:00
chore: Update image pack file format to match that of the emote msc
This commit is contained in:
parent
aa0033c0a6
commit
b05189230f
@ -24,8 +24,6 @@ class EmoteEntry {
|
|||||||
String emote;
|
String emote;
|
||||||
String mxc;
|
String mxc;
|
||||||
EmoteEntry({this.emote, this.mxc});
|
EmoteEntry({this.emote, this.mxc});
|
||||||
|
|
||||||
String get emoteClean => emote.substring(1, emote.length - 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class EmotesSettingsController extends State<EmotesSettings> {
|
class EmotesSettingsController extends State<EmotesSettings> {
|
||||||
@ -39,54 +37,57 @@ class EmotesSettingsController extends State<EmotesSettings> {
|
|||||||
TextEditingController newEmoteController = TextEditingController();
|
TextEditingController newEmoteController = TextEditingController();
|
||||||
TextEditingController newMxcController = TextEditingController();
|
TextEditingController newMxcController = TextEditingController();
|
||||||
|
|
||||||
|
ImagePackContent _getPack(BuildContext context) {
|
||||||
|
final client = Matrix.of(context).client;
|
||||||
|
final event = (room != null
|
||||||
|
? room.getState('im.ponies.room_emotes', stateKey ?? '')
|
||||||
|
: client.accountData['im.ponies.user_emotes']) ??
|
||||||
|
BasicEvent.fromJson(<String, dynamic>{
|
||||||
|
'type': 'm.dummy',
|
||||||
|
'content': <String, dynamic>{},
|
||||||
|
});
|
||||||
|
// make sure we work on a *copy* of the event
|
||||||
|
return BasicEvent.fromJson(event.toJson()).parsedImagePackContent;
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> _save(BuildContext context) async {
|
Future<void> _save(BuildContext context) async {
|
||||||
if (readonly) {
|
if (readonly) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final client = Matrix.of(context).client;
|
final client = Matrix.of(context).client;
|
||||||
// be sure to preserve any data not in "short"
|
final pack = _getPack(context);
|
||||||
Map<String, dynamic> content;
|
|
||||||
if (room != null) {
|
|
||||||
content =
|
|
||||||
room.getState('im.ponies.room_emotes', stateKey ?? '')?.content ??
|
|
||||||
<String, dynamic>{};
|
|
||||||
} else {
|
|
||||||
content = client.accountData['im.ponies.user_emotes']?.content ??
|
|
||||||
<String, dynamic>{};
|
|
||||||
}
|
|
||||||
if (!(content['emoticons'] is Map)) {
|
|
||||||
content['emoticons'] = <String, dynamic>{};
|
|
||||||
}
|
|
||||||
// add / update changed emotes
|
// add / update changed emotes
|
||||||
final allowedShortcodes = <String>{};
|
final allowedShortcodes = <String>{};
|
||||||
for (final emote in emotes) {
|
for (final emote in emotes) {
|
||||||
allowedShortcodes.add(emote.emote);
|
allowedShortcodes.add(emote.emote);
|
||||||
if (!(content['emoticons'][emote.emote] is Map)) {
|
if (pack.images.containsKey(emote.emote)) {
|
||||||
content['emoticons'][emote.emote] = <String, dynamic>{};
|
pack.images[emote.emote].url = Uri.parse(emote.mxc);
|
||||||
|
} else {
|
||||||
|
pack.images[emote.emote] =
|
||||||
|
ImagePackImageContent.fromJson(<String, dynamic>{
|
||||||
|
'url': emote.mxc,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
content['emoticons'][emote.emote]['url'] = emote.mxc;
|
|
||||||
}
|
}
|
||||||
// remove emotes no more needed
|
// remove emotes no more needed
|
||||||
// we make the iterator .toList() here so that we don't get into trouble modifying the very
|
// we make the iterator .toList() here so that we don't get into trouble modifying the very
|
||||||
// thing we are iterating over
|
// thing we are iterating over
|
||||||
for (final shortcode in content['emoticons'].keys.toList()) {
|
for (final shortcode in pack.images.keys.toList()) {
|
||||||
if (!allowedShortcodes.contains(shortcode)) {
|
if (!allowedShortcodes.contains(shortcode)) {
|
||||||
content['emoticons'].remove(shortcode);
|
pack.images.remove(shortcode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// remove the old "short" key
|
|
||||||
content.remove('short');
|
|
||||||
if (room != null) {
|
if (room != null) {
|
||||||
await showFutureLoadingDialog(
|
await showFutureLoadingDialog(
|
||||||
context: context,
|
context: context,
|
||||||
future: () => client.setRoomStateWithKey(
|
future: () => client.setRoomStateWithKey(
|
||||||
room.id, 'im.ponies.room_emotes', content, stateKey ?? ''),
|
room.id, 'im.ponies.room_emotes', pack.toJson(), stateKey ?? ''),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
await showFutureLoadingDialog(
|
await showFutureLoadingDialog(
|
||||||
context: context,
|
context: context,
|
||||||
future: () => client.setAccountData(
|
future: () => client.setAccountData(
|
||||||
client.userID, 'im.ponies.user_emotes', content),
|
client.userID, 'im.ponies.user_emotes', pack.toJson()),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -126,14 +127,13 @@ class EmotesSettingsController extends State<EmotesSettings> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
void submitEmoteAction(
|
void submitEmoteAction(
|
||||||
String s,
|
String emoteCode,
|
||||||
EmoteEntry emote,
|
EmoteEntry emote,
|
||||||
TextEditingController controller,
|
TextEditingController controller,
|
||||||
) {
|
) {
|
||||||
final emoteCode = ':$s:';
|
|
||||||
if (emotes.indexWhere((e) => e.emote == emoteCode && e.mxc != emote.mxc) !=
|
if (emotes.indexWhere((e) => e.emote == emoteCode && e.mxc != emote.mxc) !=
|
||||||
-1) {
|
-1) {
|
||||||
controller.text = emote.emoteClean;
|
controller.text = emote.emote;
|
||||||
showOkAlertDialog(
|
showOkAlertDialog(
|
||||||
useRootNavigator: false,
|
useRootNavigator: false,
|
||||||
context: context,
|
context: context,
|
||||||
@ -142,8 +142,8 @@ class EmotesSettingsController extends State<EmotesSettings> {
|
|||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!RegExp(r'^:[-\w]+:$').hasMatch(emoteCode)) {
|
if (!RegExp(r'^[-\w]+$').hasMatch(emoteCode)) {
|
||||||
controller.text = emote.emoteClean;
|
controller.text = emote.emote;
|
||||||
showOkAlertDialog(
|
showOkAlertDialog(
|
||||||
useRootNavigator: false,
|
useRootNavigator: false,
|
||||||
context: context,
|
context: context,
|
||||||
@ -190,7 +190,7 @@ class EmotesSettingsController extends State<EmotesSettings> {
|
|||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final emoteCode = ':${newEmoteController.text}:';
|
final emoteCode = '${newEmoteController.text}';
|
||||||
final mxc = newMxcController.text;
|
final mxc = newMxcController.text;
|
||||||
if (emotes.indexWhere((e) => e.emote == emoteCode && e.mxc != mxc) != -1) {
|
if (emotes.indexWhere((e) => e.emote == emoteCode && e.mxc != mxc) != -1) {
|
||||||
await showOkAlertDialog(
|
await showOkAlertDialog(
|
||||||
@ -201,7 +201,7 @@ class EmotesSettingsController extends State<EmotesSettings> {
|
|||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!RegExp(r'^:[-\w]+:$').hasMatch(emoteCode)) {
|
if (!RegExp(r'^[-\w]+$').hasMatch(emoteCode)) {
|
||||||
await showOkAlertDialog(
|
await showOkAlertDialog(
|
||||||
useRootNavigator: false,
|
useRootNavigator: false,
|
||||||
context: context,
|
context: context,
|
||||||
@ -262,35 +262,10 @@ class EmotesSettingsController extends State<EmotesSettings> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
if (emotes == null) {
|
if (emotes == null) {
|
||||||
emotes = <EmoteEntry>[];
|
emotes = <EmoteEntry>[];
|
||||||
Map<String, dynamic> emoteSource;
|
final pack = _getPack(context);
|
||||||
if (room != null) {
|
for (final entry in pack.images.entries) {
|
||||||
emoteSource =
|
emotes
|
||||||
room.getState('im.ponies.room_emotes', stateKey ?? '')?.content;
|
.add(EmoteEntry(emote: entry.key, mxc: entry.value.url.toString()));
|
||||||
} else {
|
|
||||||
emoteSource = Matrix.of(context)
|
|
||||||
.client
|
|
||||||
.accountData['im.ponies.user_emotes']
|
|
||||||
?.content;
|
|
||||||
}
|
|
||||||
if (emoteSource != null) {
|
|
||||||
if (emoteSource['emoticons'] is Map) {
|
|
||||||
emoteSource['emoticons'].forEach((key, value) {
|
|
||||||
if (key is String &&
|
|
||||||
value is Map &&
|
|
||||||
value['url'] is String &&
|
|
||||||
value['url'].startsWith('mxc://')) {
|
|
||||||
emotes.add(EmoteEntry(emote: key, mxc: value['url']));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else if (emoteSource['short'] is Map) {
|
|
||||||
emoteSource['short'].forEach((key, value) {
|
|
||||||
if (key is String &&
|
|
||||||
value is String &&
|
|
||||||
value.startsWith('mxc://')) {
|
|
||||||
emotes.add(EmoteEntry(emote: key, mxc: value));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return EmotesSettingsView(this);
|
return EmotesSettingsView(this);
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
|
import 'package:fluffychat/utils/platform_infos.dart';
|
||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:matrix/matrix.dart';
|
import 'package:matrix/matrix.dart';
|
||||||
import 'package:fluffychat/widgets/layouts/max_width_body.dart';
|
import 'package:fluffychat/widgets/layouts/max_width_body.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||||
import '../../widgets/matrix.dart';
|
import '../../widgets/matrix.dart';
|
||||||
import '../settings_emotes.dart';
|
import '../settings_emotes.dart';
|
||||||
@ -117,7 +119,9 @@ class EmotesSettingsView extends StatelessWidget {
|
|||||||
final emote = controller.emotes[i];
|
final emote = controller.emotes[i];
|
||||||
final textEditingController =
|
final textEditingController =
|
||||||
TextEditingController();
|
TextEditingController();
|
||||||
textEditingController.text = emote.emoteClean;
|
textEditingController.text = emote.emote;
|
||||||
|
final useShortCuts = (PlatformInfos.isWeb ||
|
||||||
|
PlatformInfos.isDesktop);
|
||||||
return ListTile(
|
return ListTile(
|
||||||
leading: Container(
|
leading: Container(
|
||||||
width: 180.0,
|
width: 180.0,
|
||||||
@ -129,6 +133,28 @@ class EmotesSettingsView extends StatelessWidget {
|
|||||||
color:
|
color:
|
||||||
Theme.of(context).secondaryHeaderColor,
|
Theme.of(context).secondaryHeaderColor,
|
||||||
),
|
),
|
||||||
|
child: Shortcuts(
|
||||||
|
shortcuts: !useShortCuts
|
||||||
|
? {}
|
||||||
|
: {
|
||||||
|
LogicalKeySet(
|
||||||
|
LogicalKeyboardKey.enter):
|
||||||
|
SubmitLineIntent(),
|
||||||
|
},
|
||||||
|
child: Actions(
|
||||||
|
actions: !useShortCuts
|
||||||
|
? {}
|
||||||
|
: {
|
||||||
|
SubmitLineIntent:
|
||||||
|
CallbackAction(onInvoke: (i) {
|
||||||
|
controller.submitEmoteAction(
|
||||||
|
textEditingController.text,
|
||||||
|
emote,
|
||||||
|
textEditingController,
|
||||||
|
);
|
||||||
|
return null;
|
||||||
|
}),
|
||||||
|
},
|
||||||
child: TextField(
|
child: TextField(
|
||||||
readOnly: controller.readonly,
|
readOnly: controller.readonly,
|
||||||
controller: textEditingController,
|
controller: textEditingController,
|
||||||
@ -136,7 +162,8 @@ class EmotesSettingsView extends StatelessWidget {
|
|||||||
minLines: 1,
|
minLines: 1,
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText: L10n.of(context).emoteShortcode,
|
hintText:
|
||||||
|
L10n.of(context).emoteShortcode,
|
||||||
prefixText: ': ',
|
prefixText: ': ',
|
||||||
suffixText: ':',
|
suffixText: ':',
|
||||||
prefixStyle: TextStyle(
|
prefixStyle: TextStyle(
|
||||||
@ -161,6 +188,8 @@ class EmotesSettingsView extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
title: _EmoteImage(emote.mxc),
|
title: _EmoteImage(emote.mxc),
|
||||||
trailing: controller.readonly
|
trailing: controller.readonly
|
||||||
? null
|
? null
|
||||||
@ -232,3 +261,5 @@ class _EmoteImagePickerState extends State<_EmoteImagePicker> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SubmitLineIntent extends Intent {}
|
||||||
|
@ -63,16 +63,18 @@ class InputBar extends StatelessWidget {
|
|||||||
if (emojiMatch != null) {
|
if (emojiMatch != null) {
|
||||||
final packSearch = emojiMatch[1];
|
final packSearch = emojiMatch[1];
|
||||||
final emoteSearch = emojiMatch[2].toLowerCase();
|
final emoteSearch = emojiMatch[2].toLowerCase();
|
||||||
final emotePacks = room.emotePacks;
|
final emotePacks = room.getImagePacks(ImagePackUsage.emoticon);
|
||||||
if (packSearch == null || packSearch.isEmpty) {
|
if (packSearch == null || packSearch.isEmpty) {
|
||||||
for (final pack in emotePacks.entries) {
|
for (final pack in emotePacks.entries) {
|
||||||
for (final emote in pack.value.entries) {
|
for (final emote in pack.value.images.entries) {
|
||||||
if (emote.key.toLowerCase().contains(emoteSearch)) {
|
if (emote.key.toLowerCase().contains(emoteSearch)) {
|
||||||
ret.add({
|
ret.add({
|
||||||
'type': 'emote',
|
'type': 'emote',
|
||||||
'name': emote.key,
|
'name': emote.key,
|
||||||
'pack': pack.key,
|
'pack': pack.key,
|
||||||
'mxc': emote.value,
|
'pack_avatar_url': pack.value.pack.avatarUrl?.toString(),
|
||||||
|
'pack_display_name': pack.value.pack.displayName ?? pack.key,
|
||||||
|
'mxc': emote.value.url.toString(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (ret.length > maxResults) {
|
if (ret.length > maxResults) {
|
||||||
@ -84,13 +86,17 @@ class InputBar extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (emotePacks[packSearch] != null) {
|
} else if (emotePacks[packSearch] != null) {
|
||||||
for (final emote in emotePacks[packSearch].entries) {
|
for (final emote in emotePacks[packSearch].images.entries) {
|
||||||
if (emote.key.toLowerCase().contains(emoteSearch)) {
|
if (emote.key.toLowerCase().contains(emoteSearch)) {
|
||||||
ret.add({
|
ret.add({
|
||||||
'type': 'emote',
|
'type': 'emote',
|
||||||
'name': emote.key,
|
'name': emote.key,
|
||||||
'pack': packSearch,
|
'pack': packSearch,
|
||||||
'mxc': emote.value,
|
'pack_avatar_url':
|
||||||
|
emotePacks[packSearch].pack.avatarUrl?.toString(),
|
||||||
|
'pack_display_name':
|
||||||
|
emotePacks[packSearch].pack.displayName ?? packSearch,
|
||||||
|
'mxc': emote.value.url.toString(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (ret.length > maxResults) {
|
if (ret.length > maxResults) {
|
||||||
@ -239,8 +245,15 @@ class InputBar extends StatelessWidget {
|
|||||||
child: Align(
|
child: Align(
|
||||||
alignment: Alignment.centerRight,
|
alignment: Alignment.centerRight,
|
||||||
child: Opacity(
|
child: Opacity(
|
||||||
opacity: 0.5,
|
opacity: suggestion['pack_avatar_url'] != null ? 0.8 : 0.5,
|
||||||
child: Text(suggestion['pack']),
|
child: suggestion['pack_avatar_url'] != null
|
||||||
|
? Avatar(
|
||||||
|
Uri.parse(suggestion['pack_avatar_url']),
|
||||||
|
suggestion['pack_display_name'],
|
||||||
|
size: size * 0.9,
|
||||||
|
client: client,
|
||||||
|
)
|
||||||
|
: Text(suggestion['pack_display_name']),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -289,12 +302,12 @@ class InputBar extends StatelessWidget {
|
|||||||
var isUnique = true;
|
var isUnique = true;
|
||||||
final insertEmote = suggestion['name'];
|
final insertEmote = suggestion['name'];
|
||||||
final insertPack = suggestion['pack'];
|
final insertPack = suggestion['pack'];
|
||||||
final emotePacks = room.emotePacks;
|
final emotePacks = room.getImagePacks(ImagePackUsage.emoticon);
|
||||||
for (final pack in emotePacks.entries) {
|
for (final pack in emotePacks.entries) {
|
||||||
if (pack.key == insertPack) {
|
if (pack.key == insertPack) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (final emote in pack.value.entries) {
|
for (final emote in pack.value.images.entries) {
|
||||||
if (emote.key == insertEmote) {
|
if (emote.key == insertEmote) {
|
||||||
isUnique = false;
|
isUnique = false;
|
||||||
break;
|
break;
|
||||||
@ -304,10 +317,7 @@ class InputBar extends StatelessWidget {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
insertText = (isUnique
|
insertText = ':${isUnique ? '' : insertPack + '~'}$insertEmote: ';
|
||||||
? insertEmote
|
|
||||||
: ':$insertPack~${insertEmote.substring(1)}') +
|
|
||||||
' ';
|
|
||||||
startText = replaceText.replaceAllMapped(
|
startText = replaceText.replaceAllMapped(
|
||||||
RegExp(r'(\s|^)(:(?:[-\w]+~)?[-\w]+)$'),
|
RegExp(r'(\s|^)(:(?:[-\w]+~)?[-\w]+)$'),
|
||||||
(Match m) => '${m[1]}$insertText',
|
(Match m) => '${m[1]}$insertText',
|
||||||
|
11
pubspec.lock
11
pubspec.lock
@ -647,14 +647,14 @@ packages:
|
|||||||
name: matrix
|
name: matrix
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.1.7"
|
version: "0.1.8"
|
||||||
matrix_api_lite:
|
matrix_api_lite:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: matrix_api_lite
|
name: matrix_api_lite
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.3.3"
|
version: "0.3.5"
|
||||||
matrix_link_text:
|
matrix_link_text:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1110,6 +1110,13 @@ packages:
|
|||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.99"
|
version: "0.0.99"
|
||||||
|
slugify:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: slugify
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.0"
|
||||||
source_map_stack_trace:
|
source_map_stack_trace:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -48,7 +48,7 @@ dependencies:
|
|||||||
intl: any
|
intl: any
|
||||||
localstorage: ^4.0.0+1
|
localstorage: ^4.0.0+1
|
||||||
lottie: ^1.1.0
|
lottie: ^1.1.0
|
||||||
matrix: ^0.1.7
|
matrix: ^0.1.8
|
||||||
native_imaging:
|
native_imaging:
|
||||||
git:
|
git:
|
||||||
url: https://gitlab.com/famedly/libraries/native_imaging.git
|
url: https://gitlab.com/famedly/libraries/native_imaging.git
|
||||||
|
Loading…
Reference in New Issue
Block a user