Remove flutter chat #26

Manually merged
Henry-Hiles merged 108 commits from remove-flutter-chat into main 2026-05-22 15:26:28 -04:00
7 changed files with 55 additions and 27 deletions
Showing only changes of commit df491b2ed3 - Show all commits

fix decryption

Henry Hiles 2026-05-19 10:40:16 -04:00
Signed by: Henry-Hiles
SSH key fingerprint: SHA256:VKQUdS31Q90KvX7EkKMHMBpUspcmItAh86a+v7PGiIs

View file

@ -1,3 +1,4 @@
import "package:collection/collection.dart";
import "package:nexus/models/content/avatar.dart"; import "package:nexus/models/content/avatar.dart";
import "package:nexus/models/content/canonical_alias.dart"; import "package:nexus/models/content/canonical_alias.dart";
import "package:nexus/models/content/create.dart"; import "package:nexus/models/content/create.dart";
@ -9,30 +10,36 @@ import "package:nexus/models/content/name.dart";
import "package:nexus/models/content/pinned_events.dart"; import "package:nexus/models/content/pinned_events.dart";
import "package:nexus/models/content/power_levels.dart"; import "package:nexus/models/content/power_levels.dart";
import "package:nexus/models/content/reaction.dart"; import "package:nexus/models/content/reaction.dart";
import "package:nexus/models/content/encrypted.dart";
import "package:nexus/models/content/redaction.dart"; import "package:nexus/models/content/redaction.dart";
import "package:nexus/models/content/server_acl.dart"; import "package:nexus/models/content/server_acl.dart";
import "package:nexus/models/content/topic.dart"; import "package:nexus/models/content/topic.dart";
class Content { class Content {
final String? parseError; final Error? parseError;
Content({this.parseError}); Content({this.parseError});
factory Content.fromJson(Map<String, dynamic> json) => Content(); factory Content.fromJson(Map<String, dynamic> json) => Content();
Map<String, dynamic> toJson() => {}; Map<String, dynamic> toJson() => {};
static Content fromEventJson(Map<String, dynamic> eventJson, String type) { static Map<String, dynamic> readValue(Map<dynamic, dynamic> json, _) =>
json["decrypted"] ?? json["content"];
static Content fromEventJson(Map<String, dynamic> json, String type) {
try { try {
return EventType.values return (EventType.values
.firstWhere((eventType) => eventType.type == type) .firstWhereOrNull((eventType) => eventType.type == type)
.contentFromJson(eventJson); ?.contentFromJson ??
Content.fromJson)(json);
} catch (error) { } catch (error) {
return Content(parseError: error.toString()); if (error is Error) return Content(parseError: error);
rethrow;
} }
} }
} }
enum EventType { enum EventType {
encrypted("m.room.encrypted", Content.fromJson), encrypted("m.room.encrypted", EncryptedContent.fromJson),
redaction("m.room.redaction", RedactionContent.fromJson), redaction("m.room.redaction", RedactionContent.fromJson),
encryption("m.room.encryption", EncryptionContent.fromJson), encryption("m.room.encryption", EncryptionContent.fromJson),
membership("m.room.member", MembershipContent.fromJson), membership("m.room.member", MembershipContent.fromJson),

View file

@ -0,0 +1,13 @@
import "package:freezed_annotation/freezed_annotation.dart";
import "package:nexus/models/content/content.dart";
part "encrypted.freezed.dart";
part "encrypted.g.dart";
@freezed
abstract class EncryptedContent extends Content with _$EncryptedContent {
EncryptedContent._();
factory EncryptedContent() = _EncryptedContent;
factory EncryptedContent.fromJson(Map<String, Object?> json) =>
_$EncryptedContentFromJson(json);
}

View file

@ -3,13 +3,14 @@ import "package:nexus/models/content/content.dart";
part "reaction.freezed.dart"; part "reaction.freezed.dart";
part "reaction.g.dart"; part "reaction.g.dart";
String? keyFromJson(Map<String, dynamic> json) => json["m.relates_to"]?["key"]; String? keyFromJson(Map<String, dynamic> json) => json["key"];
@freezed @freezed
abstract class ReactionContent extends Content with _$ReactionContent { abstract class ReactionContent extends Content with _$ReactionContent {
ReactionContent._(); ReactionContent._();
factory ReactionContent({@JsonKey(fromJson: keyFromJson) String? key}) = factory ReactionContent({
_ReactionContent; @JsonKey(fromJson: keyFromJson, name: "m.relates_to") String? key,
}) = _ReactionContent;
factory ReactionContent.fromJson(Map<String, Object?> json) => factory ReactionContent.fromJson(Map<String, Object?> json) =>
_$ReactionContentFromJson(json); _$ReactionContentFromJson(json);

View file

@ -6,24 +6,25 @@ import "package:nexus/models/profile.dart";
part "event.freezed.dart"; part "event.freezed.dart";
part "event.g.dart"; part "event.g.dart";
Profile? pmpFromJson(Map<String, dynamic>? json) {
final pmp = json?["content"]?["com.beeper.per_message_profile"];
return pmp == null ? null : Profile.fromJsonWithCatch(pmp);
}
@freezed @freezed
abstract class Event with _$Event { abstract class Event with _$Event {
static Profile? pmpFromJson(Map<String, dynamic>? json) {
final pmp = json?["content"]?["com.beeper.per_message_profile"];
return pmp == null ? null : Profile.fromJsonWithCatch(pmp);
}
static String typeJsonFromJson(Map<dynamic, dynamic> json, _) =>
json["decrypted_type"] ?? json["type"];
const factory Event({ const factory Event({
@JsonKey(name: "rowid") required int rowId, @JsonKey(name: "rowid") required int rowId,
@JsonKey(name: "timeline_rowid") required int timelineRowId, @JsonKey(name: "timeline_rowid") required int timelineRowId,
required String roomId, required String roomId,
required String eventId, required String eventId,
required String sender, required String sender,
required String type, @JsonKey(readValue: Event.typeJsonFromJson) required String type,
String? stateKey, String? stateKey,
@EpochDateTimeConverter() required DateTime timestamp, @EpochDateTimeConverter() required DateTime timestamp,
IMap<String, dynamic>? decrypted,
String? decryptedType,
@Default(IMap.empty()) IMap<String, dynamic> unsigned, @Default(IMap.empty()) IMap<String, dynamic> unsigned,
LocalContent? localContent, LocalContent? localContent,
String? transactionId, String? transactionId,
@ -35,13 +36,16 @@ abstract class Event with _$Event {
@Default(IMap.empty()) IMap<String, int> reactions, @Default(IMap.empty()) IMap<String, int> reactions,
@JsonKey(name: "last_edit_rowid") int? lastEditRowId, @JsonKey(name: "last_edit_rowid") int? lastEditRowId,
@UnreadTypeConverter() UnreadType? unreadType, @UnreadTypeConverter() UnreadType? unreadType,
@JsonKey(fromJson: pmpFromJson) Profile? pmp, @JsonKey(fromJson: Event.pmpFromJson) Profile? pmp,
@JsonKey(fromJson: Content.fromJson) required Content content, @JsonKey(fromJson: Content.fromJson) required Content content,
}) = _Event; }) = _Event;
factory Event.fromJson(Map<String, dynamic> json) => factory Event.fromJson(Map<String, dynamic> json) =>
_$EventFromJson(json).copyWith( _$EventFromJson(json).copyWith(
content: Content.fromEventJson(json["content"], json["type"] as String), content: Content.fromEventJson(
json["decrypted"] ?? json["content"],
json["decrypted_type"] ?? json["type"],
),
); );
} }

View file

@ -13,6 +13,7 @@ import "package:nexus/helpers/extensions/show_context_menu.dart";
import "package:nexus/helpers/launch_helper.dart"; import "package:nexus/helpers/launch_helper.dart";
import "package:nexus/models/content/avatar.dart"; import "package:nexus/models/content/avatar.dart";
import "package:nexus/models/content/content.dart"; import "package:nexus/models/content/content.dart";
import "package:nexus/models/content/encrypted.dart";
import "package:nexus/models/content/message.dart"; import "package:nexus/models/content/message.dart";
import "package:nexus/models/event.dart"; import "package:nexus/models/event.dart";
import "package:nexus/widgets/chat_page/expandable_image.dart"; import "package:nexus/widgets/chat_page/expandable_image.dart";
@ -62,6 +63,11 @@ class RenderEvent extends ConsumerWidget {
); );
final child = switch (event.content) { final child = switch (event.content) {
Content(:final parseError?) => SelectableText(
"An error occurred while parsing this event:\n$parseError",
style: errorStyle,
),
EncryptedContent() => Text("Unable to decrypt event"),
MessageContent() => Row( MessageContent() => Row(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
spacing: 8, spacing: 8,
@ -119,10 +125,6 @@ class RenderEvent extends ConsumerWidget {
// EventText(replyEvent textOnly: true, maxLines: 1,) // EventText(replyEvent textOnly: true, maxLines: 1,)
// ), // ),
switch (event.content) { switch (event.content) {
Content(:final parseError?) => SelectableText(
"An error occurred while parsing this message:\n$parseError",
style: errorStyle,
),
TextMessageContent( TextMessageContent(
:final body, :final body,
:final formattedBody, :final formattedBody,

View file

@ -720,7 +720,7 @@ packages:
source: hosted source: hosted
version: "3.0.2" version: "3.0.2"
linkify: linkify:
dependency: "direct overridden" dependency: "direct main"
description: description:
path: "." path: "."
ref: "fix/consecutive-periods-loose-url" ref: "fix/consecutive-periods-loose-url"

View file

@ -54,11 +54,12 @@ dependencies:
timeago: 3.7.1 timeago: 3.7.1
http: 1.6.0 http: 1.6.0
flutter_linkify: 6.0.0 flutter_linkify: 6.0.0
linkify: 5.0.0
emoji_text_field: emoji_text_field:
git: git:
url: https://github.com/Henry-Hiles/emoji_text_field url: https://github.com/Henry-Hiles/emoji_text_field
flutter_blurhash: ^0.9.1 flutter_blurhash: 0.9.1
super_sliver_list: ^0.4.1 super_sliver_list: 0.4.1
dev_dependencies: dev_dependencies:
build_runner: 2.15.0 build_runner: 2.15.0