✨ Better channel list
This commit is contained in:
parent
30b05e440c
commit
2716690c41
@ -33,6 +33,8 @@ class ChannelChatScreen extends StatefulWidget {
|
|||||||
|
|
||||||
class _ChannelChatScreenState extends State<ChannelChatScreen> {
|
class _ChannelChatScreenState extends State<ChannelChatScreen> {
|
||||||
bool _isBusy = false;
|
bool _isBusy = false;
|
||||||
|
int? _accountId;
|
||||||
|
|
||||||
String? _overrideAlias;
|
String? _overrideAlias;
|
||||||
|
|
||||||
Channel? _channel;
|
Channel? _channel;
|
||||||
@ -41,6 +43,12 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
|
|||||||
final PagingController<int, Message> _pagingController =
|
final PagingController<int, Message> _pagingController =
|
||||||
PagingController(firstPageKey: 0);
|
PagingController(firstPageKey: 0);
|
||||||
|
|
||||||
|
getProfile() async {
|
||||||
|
final AuthProvider auth = Get.find();
|
||||||
|
final prof = await auth.getProfile();
|
||||||
|
_accountId = prof.body['id'];
|
||||||
|
}
|
||||||
|
|
||||||
getChannel({String? overrideAlias}) async {
|
getChannel({String? overrideAlias}) async {
|
||||||
final ChannelProvider provider = Get.find();
|
final ChannelProvider provider = Get.find();
|
||||||
|
|
||||||
@ -167,6 +175,7 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
|
|||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
|
getProfile();
|
||||||
getChannel().then((_) {
|
getChannel().then((_) {
|
||||||
listenMessages();
|
listenMessages();
|
||||||
_pagingController.addPageRequestListener(getMessages);
|
_pagingController.addPageRequestListener(getMessages);
|
||||||
@ -181,9 +190,22 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String title = _channel?.name ?? 'loading'.tr;
|
||||||
|
String? placeholder;
|
||||||
|
|
||||||
|
if (_channel?.type == 1) {
|
||||||
|
final otherside = _channel!.members!
|
||||||
|
.where((e) => e.account.externalId != _accountId)
|
||||||
|
.first;
|
||||||
|
title = otherside.account.nick;
|
||||||
|
placeholder = 'messageInputPlaceholder'.trParams(
|
||||||
|
{'channel': '@${otherside.account.name}'},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(_channel?.name ?? 'loading'.tr),
|
title: Text(title),
|
||||||
centerTitle: false,
|
centerTitle: false,
|
||||||
actions: [
|
actions: [
|
||||||
IconButton(
|
IconButton(
|
||||||
@ -233,6 +255,7 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
|
|||||||
right: 16,
|
right: 16,
|
||||||
child: ChatMessageInput(
|
child: ChatMessageInput(
|
||||||
realm: widget.realm,
|
realm: widget.realm,
|
||||||
|
placeholder: placeholder,
|
||||||
channel: _channel!,
|
channel: _channel!,
|
||||||
onSent: (Message item) {
|
onSent: (Message item) {
|
||||||
setState(() {
|
setState(() {
|
||||||
|
@ -276,6 +276,7 @@ class RealmChannelListWidget extends StatelessWidget {
|
|||||||
ChannelListWidget(
|
ChannelListWidget(
|
||||||
channels: channels,
|
channels: channels,
|
||||||
selfId: snapshot.data?.body['id'] ?? 0,
|
selfId: snapshot.data?.body['id'] ?? 0,
|
||||||
|
noCategory: true,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -144,6 +144,8 @@ class SolianMessages extends Translations {
|
|||||||
'channelDeletionConfirm': 'Confirm channel deletion',
|
'channelDeletionConfirm': 'Confirm channel deletion',
|
||||||
'channelDeletionConfirmCaption':
|
'channelDeletionConfirmCaption':
|
||||||
'Are you sure to delete channel @channel? This action cannot be undone!',
|
'Are you sure to delete channel @channel? This action cannot be undone!',
|
||||||
|
'channelCategoryDirect': 'DM',
|
||||||
|
'channelCategoryDirectHint': 'Your direct messages',
|
||||||
'messageDecoding': 'Decoding...',
|
'messageDecoding': 'Decoding...',
|
||||||
'messageDecodeFailed': 'Unable to decode: @message',
|
'messageDecodeFailed': 'Unable to decode: @message',
|
||||||
'messageInputPlaceholder': 'Message @channel',
|
'messageInputPlaceholder': 'Message @channel',
|
||||||
@ -280,6 +282,8 @@ class SolianMessages extends Translations {
|
|||||||
'channelSettings': '频道设置',
|
'channelSettings': '频道设置',
|
||||||
'channelDeletionConfirm': '确认删除频道',
|
'channelDeletionConfirm': '确认删除频道',
|
||||||
'channelDeletionConfirmCaption': '你确认要删除频道 @channel 吗?该操作不可撤销。',
|
'channelDeletionConfirmCaption': '你确认要删除频道 @channel 吗?该操作不可撤销。',
|
||||||
|
'channelCategoryDirect': '私聊频道',
|
||||||
|
'channelCategoryDirectHint': '你的所有私聊频道',
|
||||||
'messageDecoding': '解码信息中…',
|
'messageDecoding': '解码信息中…',
|
||||||
'messageDecodeFailed': '解码信息失败:@message',
|
'messageDecodeFailed': '解码信息失败:@message',
|
||||||
'messageInputPlaceholder': '在 @channel 发信息',
|
'messageInputPlaceholder': '在 @channel 发信息',
|
||||||
|
@ -5,23 +5,61 @@ import 'package:solian/models/channel.dart';
|
|||||||
import 'package:solian/router.dart';
|
import 'package:solian/router.dart';
|
||||||
import 'package:solian/widgets/account/account_avatar.dart';
|
import 'package:solian/widgets/account/account_avatar.dart';
|
||||||
|
|
||||||
class ChannelListWidget extends StatelessWidget {
|
class ChannelListWidget extends StatefulWidget {
|
||||||
final List<Channel> channels;
|
final List<Channel> channels;
|
||||||
final int selfId;
|
final int selfId;
|
||||||
|
final bool noCategory;
|
||||||
|
|
||||||
const ChannelListWidget(
|
const ChannelListWidget({
|
||||||
{super.key, required this.channels, required this.selfId});
|
super.key,
|
||||||
|
required this.channels,
|
||||||
|
required this.selfId,
|
||||||
|
this.noCategory = false,
|
||||||
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
State<ChannelListWidget> createState() => _ChannelListWidgetState();
|
||||||
return SliverList.builder(
|
}
|
||||||
itemCount: channels.length,
|
|
||||||
itemBuilder: (context, index) {
|
|
||||||
final element = channels[index];
|
|
||||||
|
|
||||||
|
class _ChannelListWidgetState extends State<ChannelListWidget> {
|
||||||
|
final List<Channel> _globalChannels = List.empty(growable: true);
|
||||||
|
final List<Channel> _directMessages = List.empty(growable: true);
|
||||||
|
final Map<String, List<Channel>> _inRealms = {};
|
||||||
|
|
||||||
|
void mapChannels() {
|
||||||
|
_inRealms.clear();
|
||||||
|
_globalChannels.clear();
|
||||||
|
_directMessages.clear();
|
||||||
|
|
||||||
|
if (widget.noCategory) {
|
||||||
|
_globalChannels.addAll(widget.channels);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (final channel in widget.channels) {
|
||||||
|
if (channel.realmId != null) {
|
||||||
|
if (_inRealms[channel.alias] == null) {
|
||||||
|
_inRealms[channel.alias] = List.empty(growable: true);
|
||||||
|
}
|
||||||
|
_inRealms[channel.alias]!.add(channel);
|
||||||
|
} else if (channel.type == 1) {
|
||||||
|
_directMessages.add(channel);
|
||||||
|
} else {
|
||||||
|
_globalChannels.add(channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didUpdateWidget(covariant ChannelListWidget oldWidget) {
|
||||||
|
setState(() => mapChannels());
|
||||||
|
super.didUpdateWidget(oldWidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget buildItem(Channel element) {
|
||||||
if (element.type == 1) {
|
if (element.type == 1) {
|
||||||
final otherside = element.members!
|
final otherside = element.members!
|
||||||
.where((e) => e.account.externalId != selfId)
|
.where((e) => e.account.externalId != widget.selfId)
|
||||||
.first;
|
.first;
|
||||||
|
|
||||||
return ListTile(
|
return ListTile(
|
||||||
@ -70,7 +108,43 @@ class ChannelListWidget extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
if (widget.noCategory) {
|
||||||
|
return SliverList.builder(
|
||||||
|
itemCount: _globalChannels.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final element = _globalChannels[index];
|
||||||
|
return buildItem(element);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return SliverList.list(
|
||||||
|
children: [
|
||||||
|
..._globalChannels.map((e) => buildItem(e)),
|
||||||
|
if (_directMessages.isNotEmpty)
|
||||||
|
ExpansionTile(
|
||||||
|
tilePadding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
|
title: Text('channelCategoryDirect'.tr),
|
||||||
|
subtitle: Text('channelCategoryDirectHint'.tr),
|
||||||
|
children: _directMessages.map((e) => buildItem(e)).toList(),
|
||||||
|
),
|
||||||
|
..._inRealms.entries.map((element) {
|
||||||
|
return ExpansionTile(
|
||||||
|
tilePadding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
|
title: Text(element.value.first.realm!.name),
|
||||||
|
subtitle: Text(
|
||||||
|
element.value.first.realm!.description,
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
children: element.value.map((e) => buildItem(e)).toList(),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ import 'package:uuid/uuid.dart';
|
|||||||
class ChatMessageInput extends StatefulWidget {
|
class ChatMessageInput extends StatefulWidget {
|
||||||
final Message? edit;
|
final Message? edit;
|
||||||
final Message? reply;
|
final Message? reply;
|
||||||
|
final String? placeholder;
|
||||||
final Channel channel;
|
final Channel channel;
|
||||||
final String realm;
|
final String realm;
|
||||||
final Function(Message) onSent;
|
final Function(Message) onSent;
|
||||||
@ -20,6 +21,7 @@ class ChatMessageInput extends StatefulWidget {
|
|||||||
super.key,
|
super.key,
|
||||||
this.edit,
|
this.edit,
|
||||||
this.reply,
|
this.reply,
|
||||||
|
this.placeholder,
|
||||||
required this.channel,
|
required this.channel,
|
||||||
required this.realm,
|
required this.realm,
|
||||||
required this.onSent,
|
required this.onSent,
|
||||||
@ -145,7 +147,8 @@ class _ChatMessageInputState extends State<ChatMessageInput> {
|
|||||||
autocorrect: true,
|
autocorrect: true,
|
||||||
keyboardType: TextInputType.text,
|
keyboardType: TextInputType.text,
|
||||||
decoration: InputDecoration.collapsed(
|
decoration: InputDecoration.collapsed(
|
||||||
hintText: 'messageInputPlaceholder'.trParams(
|
hintText: widget.placeholder ??
|
||||||
|
'messageInputPlaceholder'.trParams(
|
||||||
{'channel': '#${widget.channel.alias}'},
|
{'channel': '#${widget.channel.alias}'},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
Loading…
Reference in New Issue
Block a user