add sticker and emote support
This commit is contained in:
parent
3e82faeb86
commit
e7890cfe4f
6 changed files with 97 additions and 6 deletions
24
lib/controllers/thumbnail_controller.dart
Normal file
24
lib/controllers/thumbnail_controller.dart
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
import "package:flutter_riverpod/flutter_riverpod.dart";
|
||||
import "package:matrix/matrix.dart";
|
||||
import "package:nexus/controllers/client_controller.dart";
|
||||
import "package:nexus/models/image_data.dart";
|
||||
|
||||
class ThumbnailController extends AsyncNotifier<String?> {
|
||||
ThumbnailController(this.data);
|
||||
final ImageData data;
|
||||
|
||||
@override
|
||||
Future<String?> build({String? from}) async {
|
||||
final client = await ref.watch(ClientController.provider.future);
|
||||
final uri = await Uri.tryParse(data.uri)?.getDownloadUri(
|
||||
client,
|
||||
); // TODO: Should use thumb when c10y fixes animated thumbs
|
||||
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
static final provider = AsyncNotifierProvider.family
|
||||
.autoDispose<ThumbnailController, String?, ImageData>(
|
||||
ThumbnailController.new,
|
||||
);
|
||||
}
|
||||
|
|
@ -50,8 +50,8 @@ extension EventToMessage on Event {
|
|||
text: "Unable to decrypt message.",
|
||||
metadata: {"formatted": "Unable to decrypt message.", ...metadata},
|
||||
),
|
||||
EventTypes.Message => switch (messageType) {
|
||||
MessageTypes.Image => Message.image(
|
||||
(EventTypes.Sticker || EventTypes.Message) => switch (messageType) {
|
||||
(MessageTypes.Sticker || MessageTypes.Image) => Message.image(
|
||||
metadata: metadata,
|
||||
id: eventId,
|
||||
authorId: senderId,
|
||||
|
|
|
|||
11
lib/models/image_data.dart
Normal file
11
lib/models/image_data.dart
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import "package:freezed_annotation/freezed_annotation.dart";
|
||||
part "image_data.freezed.dart";
|
||||
|
||||
@freezed
|
||||
abstract class ImageData with _$ImageData {
|
||||
const factory ImageData({
|
||||
required String uri,
|
||||
required int? height,
|
||||
required int? width,
|
||||
}) = _ImageData;
|
||||
}
|
||||
|
|
@ -2,14 +2,20 @@ import "package:fast_immutable_collections/fast_immutable_collections.dart";
|
|||
import "package:flutter/material.dart";
|
||||
import "package:flutter_riverpod/flutter_riverpod.dart";
|
||||
import "package:flutter_widget_from_html_core/flutter_widget_from_html_core.dart";
|
||||
import "package:matrix/matrix.dart";
|
||||
import "package:nexus/controllers/thumbnail_controller.dart";
|
||||
import "package:nexus/helpers/extensions/get_headers.dart";
|
||||
import "package:nexus/helpers/launch_helper.dart";
|
||||
import "package:nexus/models/image_data.dart";
|
||||
import "package:nexus/widgets/chat_page/html/spoiler_text.dart";
|
||||
import "package:nexus/widgets/chat_page/html/code_block.dart";
|
||||
import "package:nexus/widgets/chat_page/quoted.dart";
|
||||
import "package:nexus/widgets/error_dialog.dart";
|
||||
|
||||
class Html extends ConsumerWidget {
|
||||
final String html;
|
||||
const Html(this.html, {super.key});
|
||||
final Client client;
|
||||
const Html(this.html, {required this.client, super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) => HtmlWidget(
|
||||
|
|
@ -18,13 +24,63 @@ class Html extends ConsumerWidget {
|
|||
if (element.attributes.keys.contains("data-mx-spoiler")) {
|
||||
return SpoilerText(text: element.text);
|
||||
}
|
||||
|
||||
final height = int.tryParse(element.attributes["height"] ?? "") ?? 300;
|
||||
final width = int.tryParse(element.attributes["width"] ?? "");
|
||||
|
||||
return switch (element.localName) {
|
||||
"code" => CodeBlock(
|
||||
element.text,
|
||||
lang: element.className.replaceAll("language-", ""),
|
||||
),
|
||||
|
||||
"blockquote" => Quoted(Html(element.innerHtml)),
|
||||
"blockquote" => Quoted(Html(element.innerHtml, client: client)),
|
||||
|
||||
"img" =>
|
||||
element.attributes["src"] == null
|
||||
? null
|
||||
: Consumer(
|
||||
builder: (_, ref, _) => ref
|
||||
.watch(
|
||||
ThumbnailController.provider(
|
||||
ImageData(
|
||||
uri: element.attributes["src"]!,
|
||||
height: height,
|
||||
width: width,
|
||||
),
|
||||
),
|
||||
)
|
||||
.when(
|
||||
data: (uri) {
|
||||
if (uri == null) return SizedBox.shrink();
|
||||
|
||||
return InlineCustomWidget(
|
||||
child: Image.network(
|
||||
uri,
|
||||
headers: client.headers,
|
||||
errorBuilder: (_, error, _) => Text(
|
||||
"Image Failed to Load",
|
||||
style: TextStyle(color: Colors.red),
|
||||
),
|
||||
height: height.toDouble(),
|
||||
width: width?.toDouble(),
|
||||
loadingBuilder: (_, child, loadingProgress) =>
|
||||
loadingProgress == null
|
||||
? child
|
||||
: CircularProgressIndicator(),
|
||||
),
|
||||
);
|
||||
},
|
||||
error: ErrorDialog.new,
|
||||
loading: () => InlineCustomWidget(
|
||||
child: SizedBox(
|
||||
width: width?.toDouble(),
|
||||
height: height.toDouble(),
|
||||
child: CircularProgressIndicator(),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
("del" ||
|
||||
"h1" ||
|
||||
|
|
@ -59,7 +115,6 @@ class Html extends ConsumerWidget {
|
|||
"caption" ||
|
||||
"pre" ||
|
||||
"span" ||
|
||||
"img" ||
|
||||
"details" ||
|
||||
"summary") =>
|
||||
null,
|
||||
|
|
|
|||
|
|
@ -200,6 +200,7 @@ class RoomChat extends HookConsumerWidget {
|
|||
((message.editedAt != null)
|
||||
? "<sub edited>(edited)</sub>"
|
||||
: ""),
|
||||
client: room.roomData.client,
|
||||
),
|
||||
topWidget: TopWidget(
|
||||
message,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue