Leave & delete channel

This commit is contained in:
2024-04-26 23:25:56 +08:00
parent a02831644c
commit a761b80499
8 changed files with 222 additions and 65 deletions

View File

@ -32,17 +32,19 @@ class _ChatScreenState extends State<ChatScreen> {
final http.Client _client = http.Client();
Future<void> fetchMetadata() async {
Future<Channel> fetchMetadata() async {
var uri = getRequestUri('messaging', '/api/channels/${widget.alias}');
var res = await _client.get(uri);
if (res.statusCode == 200) {
final result = jsonDecode(utf8.decode(res.bodyBytes));
setState(() => _channelMeta = Channel.fromJson(result));
return _channelMeta!;
} else {
var message = utf8.decode(res.bodyBytes);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Something went wrong... $message")),
);
throw Exception(message);
}
}
@ -137,57 +139,67 @@ class _ChatScreenState extends State<ChatScreen> {
appBarActions: [
_channelMeta != null ? ChannelAction(channel: _channelMeta!, onUpdate: () => fetchMetadata()) : Container(),
],
child: ChatMaintainer(
child: Column(
children: [
Expanded(
child: PagedListView<int, Message>(
reverse: true,
pagingController: _pagingController,
builderDelegate: PagedChildBuilderDelegate<Message>(
noItemsFoundIndicatorBuilder: (_) => Container(),
itemBuilder: (context, item, index) {
bool isMerged = false, hasMerged = false;
if (index > 0) {
hasMerged = getMessageMergeable(_pagingController.itemList?[index - 1], item);
}
if (index + 1 < (_pagingController.itemList?.length ?? 0)) {
isMerged = getMessageMergeable(item, _pagingController.itemList?[index + 1]);
}
return InkWell(
child: Container(
padding: EdgeInsets.only(
top: !isMerged ? 8 : 0,
bottom: !hasMerged ? 8 : 0,
left: 12,
right: 12,
),
child: ChatMessage(
key: Key('m${item.id}'),
item: item,
underMerged: isMerged,
),
),
onLongPress: () => viewActions(item),
);
},
child: FutureBuilder(
future: fetchMetadata(),
builder: (context, snapshot) {
if (!snapshot.hasData || snapshot.data == null) {
return const Center(child: CircularProgressIndicator());
}
return ChatMaintainer(
channel: snapshot.data!,
child: Column(
children: [
Expanded(
child: PagedListView<int, Message>(
reverse: true,
pagingController: _pagingController,
builderDelegate: PagedChildBuilderDelegate<Message>(
noItemsFoundIndicatorBuilder: (_) => Container(),
itemBuilder: (context, item, index) {
bool isMerged = false, hasMerged = false;
if (index > 0) {
hasMerged = getMessageMergeable(_pagingController.itemList?[index - 1], item);
}
if (index + 1 < (_pagingController.itemList?.length ?? 0)) {
isMerged = getMessageMergeable(item, _pagingController.itemList?[index + 1]);
}
return InkWell(
child: Container(
padding: EdgeInsets.only(
top: !isMerged ? 8 : 0,
bottom: !hasMerged ? 8 : 0,
left: 12,
right: 12,
),
child: ChatMessage(
key: Key('m${item.id}'),
item: item,
underMerged: isMerged,
),
),
onLongPress: () => viewActions(item),
);
},
),
),
),
),
ChatMessageEditor(
channel: widget.alias,
editing: _editingItem,
replying: _replyingItem,
onReset: () => setState(() {
_editingItem = null;
_replyingItem = null;
}),
),
],
),
ChatMessageEditor(
channel: widget.alias,
editing: _editingItem,
replying: _replyingItem,
onReset: () => setState(() {
_editingItem = null;
_replyingItem = null;
}),
),
],
),
onInsertMessage: (message) => addMessage(message),
onUpdateMessage: (message) => updateMessage(message),
onDeleteMessage: (message) => deleteMessage(message),
onInsertMessage: (message) => addMessage(message),
onUpdateMessage: (message) => updateMessage(message),
onDeleteMessage: (message) => deleteMessage(message),
);
},
),
);
}

View File

@ -99,13 +99,17 @@ class _ChatIndexScreenState extends State<ChatIndexScreen> {
),
title: Text(element.name),
subtitle: Text(element.description),
onTap: () {
router.pushNamed(
onTap: () async {
final result = await router.pushNamed(
'chat.channel',
pathParameters: {
'channel': element.alias,
},
);
switch(result) {
case 'refresh':
fetchChannels();
}
},
);
},

View File

@ -1,8 +1,10 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:solian/models/channel.dart';
import 'package:solian/providers/auth.dart';
import 'package:solian/router.dart';
import 'package:solian/widgets/chat/channel_deletion.dart';
import 'package:solian/widgets/indent_wrapper.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
@ -16,7 +18,20 @@ class ChatManageScreen extends StatefulWidget {
}
class _ChatManageScreenState extends State<ChatManageScreen> {
bool isOwned = false;
bool _isOwned = false;
void promptLeaveChannel() async {
final did = await showDialog(
context: context,
builder: (context) => ChannelDeletion(
channel: widget.channel,
isOwned: _isOwned,
),
);
if (did == true && router.canPop()) {
router.pop('disposed');
}
}
@override
void initState() {
@ -27,7 +42,7 @@ class _ChatManageScreenState extends State<ChatManageScreen> {
final prof = await auth.getProfiles();
setState(() {
isOwned = prof['id'] == widget.channel.account.externalId;
_isOwned = prof['id'] == widget.channel.account.externalId;
});
});
}
@ -41,7 +56,7 @@ class _ChatManageScreenState extends State<ChatManageScreen> {
onTap: () async {
router.pushNamed('chat.channel.editor', extra: widget.channel).then((did) {
if (did == true) {
if (router.canPop()) router.pop(true);
if (router.canPop()) router.pop('refresh');
}
});
},
@ -64,10 +79,12 @@ class _ChatManageScreenState extends State<ChatManageScreen> {
child: Icon(Icons.tag, color: Colors.white),
),
const SizedBox(width: 16),
Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Text(widget.channel.name, style: Theme.of(context).textTheme.bodyLarge),
Text(widget.channel.description, style: Theme.of(context).textTheme.bodySmall),
])
Expanded(
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Text(widget.channel.name, style: Theme.of(context).textTheme.bodyLarge),
Text(widget.channel.description, style: Theme.of(context).textTheme.bodySmall),
]),
)
],
),
),
@ -91,7 +108,13 @@ class _ChatManageScreenState extends State<ChatManageScreen> {
);
},
),
...(isOwned ? authorizedItems : List.empty()),
...(_isOwned ? authorizedItems : List.empty()),
const Divider(thickness: 0.3),
ListTile(
leading: _isOwned ? const Icon(Icons.delete) : const Icon(Icons.exit_to_app),
title: Text(_isOwned ? AppLocalizations.of(context)!.delete : AppLocalizations.of(context)!.exit),
onTap: () => promptLeaveChannel(),
),
],
),
),