refactor: Display all sticker packs in same editor with filterchips
This commit is contained in:
parent
b625249ff8
commit
3c86da7932
6 changed files with 76 additions and 124 deletions
|
|
@ -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_emotes/settings_emotes.dart';
|
||||||
import 'package:fluffychat/pages/settings_homeserver/settings_homeserver.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_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_notifications/settings_notifications.dart';
|
||||||
import 'package:fluffychat/pages/settings_password/settings_password.dart';
|
import 'package:fluffychat/pages/settings_password/settings_password.dart';
|
||||||
import 'package:fluffychat/pages/settings_security/settings_security.dart';
|
import 'package:fluffychat/pages/settings_security/settings_security.dart';
|
||||||
|
|
@ -249,7 +248,9 @@ abstract class AppRoutes {
|
||||||
pageBuilder: (context, state) => defaultPageBuilder(
|
pageBuilder: (context, state) => defaultPageBuilder(
|
||||||
context,
|
context,
|
||||||
state,
|
state,
|
||||||
const EmotesSettings(),
|
EmotesSettings(
|
||||||
|
roomId: state.pathParameters['roomid'],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
@ -441,30 +442,14 @@ abstract class AppRoutes {
|
||||||
),
|
),
|
||||||
redirect: loggedOutRedirect,
|
redirect: loggedOutRedirect,
|
||||||
),
|
),
|
||||||
GoRoute(
|
|
||||||
path: 'multiple_emotes',
|
|
||||||
pageBuilder: (context, state) => defaultPageBuilder(
|
|
||||||
context,
|
|
||||||
state,
|
|
||||||
const MultipleEmotesSettings(),
|
|
||||||
),
|
|
||||||
redirect: loggedOutRedirect,
|
|
||||||
),
|
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: 'emotes',
|
path: 'emotes',
|
||||||
pageBuilder: (context, state) => defaultPageBuilder(
|
pageBuilder: (context, state) => defaultPageBuilder(
|
||||||
context,
|
context,
|
||||||
state,
|
state,
|
||||||
const EmotesSettings(),
|
EmotesSettings(
|
||||||
),
|
roomId: state.pathParameters['roomid'],
|
||||||
redirect: loggedOutRedirect,
|
),
|
||||||
),
|
|
||||||
GoRoute(
|
|
||||||
path: 'emotes/:state_key',
|
|
||||||
pageBuilder: (context, state) => defaultPageBuilder(
|
|
||||||
context,
|
|
||||||
state,
|
|
||||||
const EmotesSettings(),
|
|
||||||
),
|
),
|
||||||
redirect: loggedOutRedirect,
|
redirect: loggedOutRedirect,
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ import 'dart:async';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:go_router/go_router.dart';
|
|
||||||
import 'package:http/http.dart' hide Client;
|
import 'package:http/http.dart' hide Client;
|
||||||
import 'package:matrix/matrix.dart';
|
import 'package:matrix/matrix.dart';
|
||||||
|
|
||||||
|
|
@ -21,19 +20,38 @@ import 'package:archive/archive.dart'
|
||||||
if (dart.library.io) 'package:archive/archive_io.dart';
|
if (dart.library.io) 'package:archive/archive_io.dart';
|
||||||
|
|
||||||
class EmotesSettings extends StatefulWidget {
|
class EmotesSettings extends StatefulWidget {
|
||||||
const EmotesSettings({super.key});
|
final String? roomId;
|
||||||
|
const EmotesSettings({required this.roomId, super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
EmotesSettingsController createState() => EmotesSettingsController();
|
EmotesSettingsController createState() => EmotesSettingsController();
|
||||||
}
|
}
|
||||||
|
|
||||||
class EmotesSettingsController extends State<EmotesSettings> {
|
class EmotesSettingsController extends State<EmotesSettings> {
|
||||||
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 =>
|
String? stateKey;
|
||||||
roomId != null ? Matrix.of(context).client.getRoomById(roomId!) : null;
|
|
||||||
|
|
||||||
String? get stateKey => GoRouterState.of(context).pathParameters['state_key'];
|
List<String>? 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;
|
bool showSave = false;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.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/l10n/l10n.dart';
|
||||||
import 'package:fluffychat/utils/platform_infos.dart';
|
import 'package:fluffychat/utils/platform_infos.dart';
|
||||||
|
|
@ -24,6 +24,7 @@ class EmotesSettingsView extends StatelessWidget {
|
||||||
|
|
||||||
final client = Matrix.of(context).client;
|
final client = Matrix.of(context).client;
|
||||||
final imageKeys = controller.pack!.images.keys.toList();
|
final imageKeys = controller.pack!.images.keys.toList();
|
||||||
|
final packKeys = controller.packKeys;
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
automaticallyImplyLeading: !controller.showSave,
|
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<String, Object?>('pack');
|
||||||
|
final packName =
|
||||||
|
eventPack?.tryGet<String>('displayname') ??
|
||||||
|
eventPack?.tryGet<String>('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(
|
body: MaxWidthBody(
|
||||||
child: Column(
|
child: Column(
|
||||||
|
|
@ -240,6 +280,7 @@ class _EmoteImage extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
const size = 44.0;
|
const size = 44.0;
|
||||||
|
final key = 'sticker_preview_$mxc';
|
||||||
return InkWell(
|
return InkWell(
|
||||||
borderRadius: BorderRadius.circular(4),
|
borderRadius: BorderRadius.circular(4),
|
||||||
onTap: () => showDialog(
|
onTap: () => showDialog(
|
||||||
|
|
@ -247,6 +288,8 @@ class _EmoteImage extends StatelessWidget {
|
||||||
builder: (_) => MxcImageViewer(mxc),
|
builder: (_) => MxcImageViewer(mxc),
|
||||||
),
|
),
|
||||||
child: MxcImage(
|
child: MxcImage(
|
||||||
|
key: ValueKey(key),
|
||||||
|
cacheKey: key,
|
||||||
uri: mxc,
|
uri: mxc,
|
||||||
fit: BoxFit.contain,
|
fit: BoxFit.contain,
|
||||||
width: size,
|
width: size,
|
||||||
|
|
|
||||||
|
|
@ -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<MultipleEmotesSettings> {
|
|
||||||
String? get roomId => GoRouterState.of(context).pathParameters['roomid'];
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) => MultipleEmotesSettingsView(this);
|
|
||||||
}
|
|
||||||
|
|
@ -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<String, StrippedStateEvent?>.of(packStateEvents)
|
|
||||||
: <String, StrippedStateEvent?>{};
|
|
||||||
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<String, Object?>('pack');
|
|
||||||
final packName = eventPack?.tryGet<String>('displayname') ??
|
|
||||||
eventPack?.tryGet<String>('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('/'),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -31,19 +31,8 @@ class ChatSettingsPopupMenuState extends State<ChatSettingsPopupMenu> {
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
void goToEmoteSettings() async {
|
void goToEmoteSettings() =>
|
||||||
final room = widget.room;
|
context.push('/rooms/${widget.room.id}/details/emotes');
|
||||||
// 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'] ?? <String, Event>{})
|
|
||||||
.keys
|
|
||||||
.any((String s) => s.isNotEmpty)) {
|
|
||||||
context.push('/rooms/${room.id}/details/multiple_emotes');
|
|
||||||
} else {
|
|
||||||
context.push('/rooms/${room.id}/details/emotes');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue