Remove flutter chat #26
3 changed files with 194 additions and 162 deletions
various fixes
commit
c9b5b3dda8
|
|
@ -21,8 +21,8 @@ class UserController extends AsyncNotifier<MembershipContent> {
|
|||
),
|
||||
);
|
||||
|
||||
if (member?.content is MembershipContent) {
|
||||
return member!.content as MembershipContent;
|
||||
if (member?.content case final MembershipContent content) {
|
||||
return content;
|
||||
}
|
||||
|
||||
final profile = await ref.watch(ProfileController.provider(userId).future);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import "package:fast_immutable_collections/fast_immutable_collections.dart";
|
|||
import "package:flutter/material.dart";
|
||||
import "package:flutter_riverpod/flutter_riverpod.dart";
|
||||
import "package:nexus/controllers/client_state_controller.dart";
|
||||
import "package:nexus/helpers/extensions/show_context_menu.dart";
|
||||
import "package:nexus/helpers/launch_helper.dart";
|
||||
import "package:nexus/models/content/avatar.dart";
|
||||
import "package:nexus/models/content/content.dart";
|
||||
|
|
@ -35,6 +36,7 @@ class EventText extends ConsumerWidget {
|
|||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final theme = Theme.of(context);
|
||||
final colorScheme = theme.colorScheme;
|
||||
final errorStyle = TextStyle(color: colorScheme.error);
|
||||
|
||||
final timestamp = Tooltip(
|
||||
message: event.timestamp.toString(),
|
||||
|
|
@ -43,140 +45,165 @@ class EventText extends ConsumerWidget {
|
|||
style: theme.textTheme.labelSmall?.copyWith(color: Colors.grey),
|
||||
),
|
||||
);
|
||||
final contextMenuCallback = getEventOptions == null
|
||||
? null
|
||||
: (details) => context.showContextMenu(
|
||||
globalPosition: details.globalPosition,
|
||||
children: getEventOptions!(event).toList(),
|
||||
);
|
||||
|
||||
return switch (event.content) {
|
||||
MessageContent() => Row(
|
||||
spacing: 8,
|
||||
children: [
|
||||
isGrouped ? SizedBox(width: 40) : MessageAvatar(event, height: 40),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (!isGrouped)
|
||||
Row(
|
||||
spacing: 4,
|
||||
children: [
|
||||
MessageDisplayname(
|
||||
event,
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
Flexible(child: timestamp),
|
||||
],
|
||||
),
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.all(Radius.circular(8)),
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(vertical: 8, horizontal: 12),
|
||||
decoration: BoxDecoration(
|
||||
color:
|
||||
ref.watch(
|
||||
ClientStateController.provider.select(
|
||||
(value) => value?.userId,
|
||||
),
|
||||
) ==
|
||||
event.sender
|
||||
? (event.eventId.startsWith("~")
|
||||
? colorScheme.onPrimary
|
||||
: colorScheme.primaryContainer)
|
||||
: colorScheme.surfaceContainer,
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
return GestureDetector(
|
||||
onSecondaryTapUp: contextMenuCallback,
|
||||
onLongPressStart: contextMenuCallback,
|
||||
child: switch (event.content) {
|
||||
MessageContent() => Row(
|
||||
spacing: 8,
|
||||
children: [
|
||||
isGrouped ? SizedBox(width: 40) : MessageAvatar(event, height: 40),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (!isGrouped)
|
||||
Row(
|
||||
spacing: 4,
|
||||
children: [
|
||||
// Quoted( // TODO: Show replies
|
||||
// EventText(replyEvent textOnly: true, maxLines: 1,)
|
||||
// ),
|
||||
switch (event.content) {
|
||||
Content(:final parseError?) => SelectableText(
|
||||
"An error occurred while parsing this message:\n$parseError",
|
||||
style: TextStyle(color: colorScheme.error),
|
||||
),
|
||||
TextMessageContent(
|
||||
:final body,
|
||||
:final formattedBody,
|
||||
:final format,
|
||||
) =>
|
||||
Column(
|
||||
children: [
|
||||
format == "org.matrix.custom.html"
|
||||
? Html(
|
||||
textStyle:
|
||||
event.localContent?.bigEmoji == true
|
||||
? TextStyle(fontSize: 32)
|
||||
: null,
|
||||
formattedBody!.replaceAllMapped(
|
||||
RegExp(
|
||||
"(<a\\b[^>]*>.*?<\\/a>)|(\\bhttps?:\\/\\/[^\\s<]+)",
|
||||
caseSensitive: false,
|
||||
dotAll: true,
|
||||
),
|
||||
(m) {
|
||||
// If it's already an <a> tag, leave it unchanged
|
||||
if (m.group(1) != null) {
|
||||
return m.group(1)!;
|
||||
}
|
||||
|
||||
// Otherwise, wrap the bare URL
|
||||
final url = m.group(2)!;
|
||||
return "<a href=\"$url\">$url</a>";
|
||||
},
|
||||
),
|
||||
)
|
||||
: Linkify(
|
||||
text: body,
|
||||
options: LinkifyOptions(
|
||||
humanize: false,
|
||||
),
|
||||
onOpen: (link) => ref
|
||||
.watch(LaunchHelper.provider)
|
||||
.launchUrl(Uri.parse(link.url)),
|
||||
linkStyle: TextStyle(
|
||||
color: Theme.of(
|
||||
context,
|
||||
).colorScheme.primary,
|
||||
),
|
||||
),
|
||||
if (event.lastEditRowId != null)
|
||||
Text(
|
||||
"(edited)",
|
||||
style: theme.textTheme.labelSmall,
|
||||
),
|
||||
if (RegExp(
|
||||
r'''https?://[^\s"'<>]+''',
|
||||
).allMatches(body).firstOrNull?.group(0)
|
||||
case final link?)
|
||||
LinkPreview(link),
|
||||
],
|
||||
),
|
||||
_ => SizedBox.shrink(),
|
||||
},
|
||||
MessageDisplayname(
|
||||
event,
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
Flexible(child: timestamp),
|
||||
],
|
||||
),
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.all(Radius.circular(8)),
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(
|
||||
vertical: 8,
|
||||
horizontal: 12,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color:
|
||||
ref.watch(
|
||||
ClientStateController.provider.select(
|
||||
(value) => value?.userId,
|
||||
),
|
||||
) ==
|
||||
event.sender
|
||||
? (event.eventId.startsWith("~")
|
||||
? colorScheme.onPrimary
|
||||
: colorScheme.primaryContainer)
|
||||
: colorScheme.surfaceContainer,
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Quoted( // TODO: Show replies
|
||||
// EventText(replyEvent textOnly: true, maxLines: 1,)
|
||||
// ),
|
||||
switch (event.content) {
|
||||
Content(:final parseError?) => SelectableText(
|
||||
"An error occurred while parsing this message:\n$parseError",
|
||||
style: errorStyle,
|
||||
),
|
||||
TextMessageContent(
|
||||
:final body,
|
||||
:final formattedBody,
|
||||
:final format,
|
||||
) =>
|
||||
Column(
|
||||
children: [
|
||||
format == "org.matrix.custom.html" &&
|
||||
!textOnly
|
||||
? Html(
|
||||
textStyle:
|
||||
event.localContent?.bigEmoji ==
|
||||
true
|
||||
? TextStyle(fontSize: 32)
|
||||
: null,
|
||||
formattedBody!.replaceAllMapped(
|
||||
RegExp(
|
||||
"(<a\\b[^>]*>.*?<\\/a>)|(\\bhttps?:\\/\\/[^\\s<]+)",
|
||||
caseSensitive: false,
|
||||
dotAll: true,
|
||||
),
|
||||
(m) {
|
||||
// If it's already an <a> tag, leave it unchanged
|
||||
if (m.group(1) != null) {
|
||||
return m.group(1)!;
|
||||
}
|
||||
|
||||
// Otherwise, wrap the bare URL
|
||||
final url = m.group(2)!;
|
||||
return "<a href=\"$url\">$url</a>";
|
||||
},
|
||||
),
|
||||
)
|
||||
: Linkify(
|
||||
text: body,
|
||||
maxLines: maxLines,
|
||||
options: LinkifyOptions(
|
||||
humanize: false,
|
||||
),
|
||||
onOpen: (link) => ref
|
||||
.watch(LaunchHelper.provider)
|
||||
.launchUrl(Uri.parse(link.url)),
|
||||
linkStyle: TextStyle(
|
||||
color: Theme.of(
|
||||
context,
|
||||
).colorScheme.primary,
|
||||
),
|
||||
),
|
||||
if (event.lastEditRowId != null)
|
||||
Text(
|
||||
"(edited)",
|
||||
style: theme.textTheme.labelSmall,
|
||||
),
|
||||
if (RegExp(
|
||||
r'''https?://[^\s"'<>]+''',
|
||||
).allMatches(body).firstOrNull?.group(0)
|
||||
case final link?)
|
||||
LinkPreview(link),
|
||||
],
|
||||
),
|
||||
_ =>
|
||||
textOnly
|
||||
? Text(
|
||||
"Unknown message type",
|
||||
style: errorStyle,
|
||||
)
|
||||
: SizedBox.shrink(),
|
||||
},
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
AvatarContent() => Row(
|
||||
spacing: 4,
|
||||
children: [
|
||||
SizedBox(width: 4),
|
||||
Icon(Icons.numbers),
|
||||
MessageDisplayname(
|
||||
event,
|
||||
style: TextStyle(
|
||||
color: theme.colorScheme.primary,
|
||||
fontWeight: FontWeight.bold,
|
||||
],
|
||||
),
|
||||
AvatarContent() => Row(
|
||||
spacing: 4,
|
||||
children: [
|
||||
SizedBox(width: 4),
|
||||
Icon(Icons.numbers),
|
||||
MessageDisplayname(
|
||||
event,
|
||||
style: TextStyle(
|
||||
color: theme.colorScheme.primary,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
Text("changed the room avatar"),
|
||||
],
|
||||
),
|
||||
_ => Text("AAAAA"),
|
||||
};
|
||||
Text("changed the room avatar"),
|
||||
],
|
||||
),
|
||||
_ =>
|
||||
textOnly
|
||||
? Text("Unknown event type", style: errorStyle)
|
||||
: SizedBox.shrink(),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -99,42 +99,47 @@ class RoomChat extends HookConsumerWidget {
|
|||
),
|
||||
))
|
||||
PopupMenuItem(
|
||||
child: Row(
|
||||
children: [
|
||||
...{
|
||||
...ref.watch(
|
||||
AccountDataController.provider.select(
|
||||
(value) => IList(
|
||||
value["m.recent_emoji"]?.content["recent_emoji"] ??
|
||||
[],
|
||||
).map((entry) => entry["emoji"]),
|
||||
enabled: false,
|
||||
child: IconTheme(
|
||||
data: theme.iconTheme,
|
||||
child: Row(
|
||||
children: [
|
||||
...{
|
||||
...ref.watch(
|
||||
AccountDataController.provider.select(
|
||||
(value) => IList(
|
||||
value["m.recent_emoji"]
|
||||
?.content["recent_emoji"] ??
|
||||
[],
|
||||
).map((entry) => entry["emoji"]),
|
||||
),
|
||||
),
|
||||
"👍",
|
||||
"🤣",
|
||||
"😭",
|
||||
"🤔",
|
||||
}
|
||||
.toIList()
|
||||
.sublist(0, 4)
|
||||
.map(
|
||||
(emoji) => IconButton(
|
||||
onPressed: () async {
|
||||
Navigator.of(context).pop();
|
||||
await notifier
|
||||
.sendReaction(emoji, event)
|
||||
.onError(showError);
|
||||
},
|
||||
icon: Text(emoji),
|
||||
),
|
||||
),
|
||||
"👍",
|
||||
"🤣",
|
||||
"😭",
|
||||
"🤔",
|
||||
}
|
||||
.toIList()
|
||||
.sublist(0, 4)
|
||||
.map(
|
||||
(emoji) => IconButton(
|
||||
onPressed: () async {
|
||||
Navigator.of(context).pop();
|
||||
await notifier
|
||||
.sendReaction(emoji, event)
|
||||
.onError(showError);
|
||||
},
|
||||
icon: Text(emoji),
|
||||
),
|
||||
),
|
||||
EmojiPickerButton(
|
||||
context: context,
|
||||
onPressed: Navigator.of(context).pop,
|
||||
onSelection: (emoji) =>
|
||||
notifier.sendReaction(emoji, event).onError(showError),
|
||||
),
|
||||
],
|
||||
EmojiPickerButton(
|
||||
context: context,
|
||||
onPressed: Navigator.of(context).pop,
|
||||
onSelection: (emoji) =>
|
||||
notifier.sendReaction(emoji, event).onError(showError),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
if (ref.watch(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue