From 3c86da7932b2460d511811cb34b0bd601f9a3dd5 Mon Sep 17 00:00:00 2001 From: krille-chan Date: Thu, 20 Nov 2025 19:50:27 +0100 Subject: [PATCH] refactor: Display all sticker packs in same editor with filterchips --- lib/config/routes.dart | 27 ++------ .../settings_emotes/settings_emotes.dart | 30 +++++++-- .../settings_emotes/settings_emotes_view.dart | 45 ++++++++++++- .../settings_multiple_emotes.dart | 19 ------ .../settings_multiple_emotes_view.dart | 64 ------------------- lib/widgets/chat_settings_popup_menu.dart | 15 +---- 6 files changed, 76 insertions(+), 124 deletions(-) delete mode 100644 lib/pages/settings_multiple_emotes/settings_multiple_emotes.dart delete mode 100644 lib/pages/settings_multiple_emotes/settings_multiple_emotes_view.dart diff --git a/lib/config/routes.dart b/lib/config/routes.dart index 8f92d4c6d..a598ffd70 100644 --- a/lib/config/routes.dart +++ b/lib/config/routes.dart @@ -27,7 +27,6 @@ import 'package:fluffychat/pages/settings_chat/settings_chat.dart'; import 'package:fluffychat/pages/settings_emotes/settings_emotes.dart'; import 'package:fluffychat/pages/settings_homeserver/settings_homeserver.dart'; import 'package:fluffychat/pages/settings_ignore_list/settings_ignore_list.dart'; -import 'package:fluffychat/pages/settings_multiple_emotes/settings_multiple_emotes.dart'; import 'package:fluffychat/pages/settings_notifications/settings_notifications.dart'; import 'package:fluffychat/pages/settings_password/settings_password.dart'; import 'package:fluffychat/pages/settings_security/settings_security.dart'; @@ -249,7 +248,9 @@ abstract class AppRoutes { pageBuilder: (context, state) => defaultPageBuilder( context, state, - const EmotesSettings(), + EmotesSettings( + roomId: state.pathParameters['roomid'], + ), ), ), ], @@ -441,30 +442,14 @@ abstract class AppRoutes { ), redirect: loggedOutRedirect, ), - GoRoute( - path: 'multiple_emotes', - pageBuilder: (context, state) => defaultPageBuilder( - context, - state, - const MultipleEmotesSettings(), - ), - redirect: loggedOutRedirect, - ), GoRoute( path: 'emotes', pageBuilder: (context, state) => defaultPageBuilder( context, state, - const EmotesSettings(), - ), - redirect: loggedOutRedirect, - ), - GoRoute( - path: 'emotes/:state_key', - pageBuilder: (context, state) => defaultPageBuilder( - context, - state, - const EmotesSettings(), + EmotesSettings( + roomId: state.pathParameters['roomid'], + ), ), redirect: loggedOutRedirect, ), diff --git a/lib/pages/settings_emotes/settings_emotes.dart b/lib/pages/settings_emotes/settings_emotes.dart index 56c24ca93..95ec753e9 100644 --- a/lib/pages/settings_emotes/settings_emotes.dart +++ b/lib/pages/settings_emotes/settings_emotes.dart @@ -3,7 +3,6 @@ import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; import 'package:http/http.dart' hide Client; import 'package:matrix/matrix.dart'; @@ -21,19 +20,38 @@ import 'package:archive/archive.dart' if (dart.library.io) 'package:archive/archive_io.dart'; class EmotesSettings extends StatefulWidget { - const EmotesSettings({super.key}); + final String? roomId; + const EmotesSettings({required this.roomId, super.key}); @override EmotesSettingsController createState() => EmotesSettingsController(); } class EmotesSettingsController extends State { - String? get roomId => GoRouterState.of(context).pathParameters['roomid']; + Room? get room => widget.roomId != null + ? Matrix.of(context).client.getRoomById(widget.roomId!) + : null; - Room? get room => - roomId != null ? Matrix.of(context).client.getRoomById(roomId!) : null; + String? stateKey; - String? get stateKey => GoRouterState.of(context).pathParameters['state_key']; + List? get packKeys { + final room = this.room; + if (room == null) return null; + final keys = room.states['im.ponies.room_emotes']?.keys.toList() ?? []; + keys.sort(); + return keys; + } + + @override + void initState() { + super.initState(); + stateKey = packKeys?.first; + } + + void setStateKey(String key) { + stateKey = key; + resetAction(); + } bool showSave = false; diff --git a/lib/pages/settings_emotes/settings_emotes_view.dart b/lib/pages/settings_emotes/settings_emotes_view.dart index 47a08aa60..cc2111b97 100644 --- a/lib/pages/settings_emotes/settings_emotes_view.dart +++ b/lib/pages/settings_emotes/settings_emotes_view.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:matrix/matrix_api_lite/model/events/image_pack_content.dart'; +import 'package:matrix/matrix.dart'; import 'package:fluffychat/l10n/l10n.dart'; import 'package:fluffychat/utils/platform_infos.dart'; @@ -24,6 +24,7 @@ class EmotesSettingsView extends StatelessWidget { final client = Matrix.of(context).client; final imageKeys = controller.pack!.images.keys.toList(); + final packKeys = controller.packKeys; return Scaffold( appBar: AppBar( automaticallyImplyLeading: !controller.showSave, @@ -70,6 +71,45 @@ class EmotesSettingsView extends StatelessWidget { ], ), ], + bottom: packKeys == null + ? null + : PreferredSize( + preferredSize: const Size.fromHeight(48), + child: Padding( + padding: const EdgeInsets.all(4.0), + child: SizedBox( + height: 40, + child: ListView.builder( + scrollDirection: Axis.horizontal, + itemCount: packKeys.length, + itemBuilder: (context, i) { + final key = packKeys[i]; + final event = controller.room + ?.getState('im.ponies.room_emotes', packKeys[i]); + + final eventPack = + event?.content.tryGetMap('pack'); + final packName = + eventPack?.tryGet('displayname') ?? + eventPack?.tryGet('name') ?? + (key.isNotEmpty ? key : 'Default'); + + return Padding( + padding: const EdgeInsets.symmetric( + horizontal: 4.0, + ), + child: FilterChip( + label: Text(packName), + selected: controller.stateKey == packKeys[i], + onSelected: (_) => + controller.setStateKey(packKeys[i]), + ), + ); + }, + ), + ), + ), + ), ), body: MaxWidthBody( child: Column( @@ -240,6 +280,7 @@ class _EmoteImage extends StatelessWidget { @override Widget build(BuildContext context) { const size = 44.0; + final key = 'sticker_preview_$mxc'; return InkWell( borderRadius: BorderRadius.circular(4), onTap: () => showDialog( @@ -247,6 +288,8 @@ class _EmoteImage extends StatelessWidget { builder: (_) => MxcImageViewer(mxc), ), child: MxcImage( + key: ValueKey(key), + cacheKey: key, uri: mxc, fit: BoxFit.contain, width: size, diff --git a/lib/pages/settings_multiple_emotes/settings_multiple_emotes.dart b/lib/pages/settings_multiple_emotes/settings_multiple_emotes.dart deleted file mode 100644 index 276bc08ad..000000000 --- a/lib/pages/settings_multiple_emotes/settings_multiple_emotes.dart +++ /dev/null @@ -1,19 +0,0 @@ -import 'package:flutter/material.dart'; - -import 'package:go_router/go_router.dart'; - -import 'settings_multiple_emotes_view.dart'; - -class MultipleEmotesSettings extends StatefulWidget { - const MultipleEmotesSettings({super.key}); - - @override - MultipleEmotesSettingsController createState() => - MultipleEmotesSettingsController(); -} - -class MultipleEmotesSettingsController extends State { - String? get roomId => GoRouterState.of(context).pathParameters['roomid']; - @override - Widget build(BuildContext context) => MultipleEmotesSettingsView(this); -} diff --git a/lib/pages/settings_multiple_emotes/settings_multiple_emotes_view.dart b/lib/pages/settings_multiple_emotes/settings_multiple_emotes_view.dart deleted file mode 100644 index 6559d0f15..000000000 --- a/lib/pages/settings_multiple_emotes/settings_multiple_emotes_view.dart +++ /dev/null @@ -1,64 +0,0 @@ -import 'package:flutter/material.dart'; - -import 'package:go_router/go_router.dart'; -import 'package:matrix/matrix.dart'; - -import 'package:fluffychat/l10n/l10n.dart'; -import 'package:fluffychat/pages/settings_multiple_emotes/settings_multiple_emotes.dart'; -import 'package:fluffychat/widgets/matrix.dart'; - -class MultipleEmotesSettingsView extends StatelessWidget { - final MultipleEmotesSettingsController controller; - - const MultipleEmotesSettingsView(this.controller, {super.key}); - - @override - Widget build(BuildContext context) { - final room = Matrix.of(context).client.getRoomById(controller.roomId!)!; - return Scaffold( - appBar: AppBar( - leading: const Center(child: BackButton()), - title: Text(L10n.of(context).emotePacks), - ), - body: StreamBuilder( - stream: room.client.onRoomState.stream - .where((update) => update.roomId == room.id), - builder: (context, snapshot) { - final packStateEvents = room.states['im.ponies.room_emotes']; - // we need to manually convert the map using Map.of, otherwise assigning null will throw a type error. - final packs = packStateEvents != null - ? Map.of(packStateEvents) - : {}; - if (!packs.containsKey('')) { - packs[''] = null; - } - final keys = packs.keys.toList(); - keys.sort(); - return ListView.separated( - separatorBuilder: (BuildContext context, int i) => - const SizedBox.shrink(), - itemCount: keys.length, - itemBuilder: (BuildContext context, int i) { - final event = packs[keys[i]]; - final eventPack = - event?.content.tryGetMap('pack'); - final packName = eventPack?.tryGet('displayname') ?? - eventPack?.tryGet('name') ?? - (keys[i].isNotEmpty ? keys[i] : 'Default Pack'); - - return ListTile( - title: Text(packName), - onTap: () async { - context.go( - ['', 'rooms', room.id, 'details', 'emotes', keys[i]] - .join('/'), - ); - }, - ); - }, - ); - }, - ), - ); - } -} diff --git a/lib/widgets/chat_settings_popup_menu.dart b/lib/widgets/chat_settings_popup_menu.dart index 6969fd901..81123f62f 100644 --- a/lib/widgets/chat_settings_popup_menu.dart +++ b/lib/widgets/chat_settings_popup_menu.dart @@ -31,19 +31,8 @@ class ChatSettingsPopupMenuState extends State { super.dispose(); } - void goToEmoteSettings() async { - final room = widget.room; - // okay, we need to test if there are any emote state events other than the default one - // if so, we need to be directed to a selection screen for which pack we want to look at - // otherwise, we just open the normal one. - if ((room.states['im.ponies.room_emotes'] ?? {}) - .keys - .any((String s) => s.isNotEmpty)) { - context.push('/rooms/${room.id}/details/multiple_emotes'); - } else { - context.push('/rooms/${room.id}/details/emotes'); - } - } + void goToEmoteSettings() => + context.push('/rooms/${widget.room.id}/details/emotes'); @override Widget build(BuildContext context) {