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
13 changed files with 48 additions and 27 deletions
Showing only changes of commit cb22ed9822 - Show all commits

fix up bugs related to new architecture

Henry Hiles 2026-05-17 22:24:41 -04:00
Signed by: Henry-Hiles
SSH key fingerprint: SHA256:VKQUdS31Q90KvX7EkKMHMBpUspcmItAh86a+v7PGiIs

View file

@ -80,7 +80,7 @@ class ClientController extends AsyncNotifier<int> {
case "send_complete": case "send_complete":
final event = Event.fromJson(decodedMuksEvent["event"]); final event = Event.fromJson(decodedMuksEvent["event"]);
if (event.type == EventType.message) { if (event.type == EventType.message.type) {
// ref.watch(provider.notifier).addEvent(event); TODO // ref.watch(provider.notifier).addEvent(event); TODO
} }
break; break;

View file

@ -28,7 +28,9 @@ class MembersController extends AsyncNotifier<IList<Event>> {
), ),
); );
return state.where((state) => state.type == EventType.membership).toIList(); return state
.where((state) => state.type == EventType.membership.type)
.toIList();
} }
static final provider = static final provider =

View file

@ -57,7 +57,7 @@ class RoomChatController extends AsyncNotifier<IList<Event>> {
if (room == null) return const IList.empty(); if (room == null) return const IList.empty();
// While there are under 30 messages, try up to load more messages until there's no more or we have 20 messages. // While there are under 30 messages, try up to load more messages until there's no more or we have 20 messages.
if (room.hasMore && room.events.length < 30) { if (room.hasMore && room.timeline.length < 30) {
loadOlder(); loadOlder();
} }

View file

@ -1,3 +1,3 @@
extension GetLocalpart on String { extension GetLocalpart on String {
String get localpart => substring(1).split(":").first; String get localpart => length > 1 ? substring(1).split(":").first : "?";
} }

View file

@ -20,9 +20,9 @@ class Content {
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) => static Content fromEventJson(Map<String, dynamic> eventJson, String type) =>
(EventType.values (EventType.values
.firstWhereOrNull((eventType) => eventType.type == eventJson["type"]) .firstWhereOrNull((eventType) => eventType.type == type)
?.contentFromJson ?? ?.contentFromJson ??
Content.fromJson)(eventJson); Content.fromJson)(eventJson);
} }

View file

@ -19,7 +19,7 @@ abstract class CreateContent extends Content with _$CreateContent {
@JsonKey(name: "m.federate") @Default(true) bool federated, @JsonKey(name: "m.federate") @Default(true) bool federated,
@Default("1") String roomVersion, @Default("1") String roomVersion,
required String type, String? type,
}) = _CreateContent; }) = _CreateContent;
factory CreateContent.fromJson(Map<String, Object?> json) => factory CreateContent.fromJson(Map<String, Object?> json) =>
@ -28,7 +28,7 @@ abstract class CreateContent extends Content with _$CreateContent {
@freezed @freezed
abstract class PreviousRoom with _$PreviousRoom { abstract class PreviousRoom with _$PreviousRoom {
const factory PreviousRoom({required int roomId}) = _PreviousRoom; const factory PreviousRoom({required String roomId}) = _PreviousRoom;
factory PreviousRoom.fromJson(Map<String, Object?> json) => factory PreviousRoom.fromJson(Map<String, Object?> json) =>
_$PreviousRoomFromJson(json); _$PreviousRoomFromJson(json);

View file

@ -8,7 +8,7 @@ part "membership.g.dart";
abstract class MembershipContent extends Content with _$MembershipContent { abstract class MembershipContent extends Content with _$MembershipContent {
MembershipContent._(); MembershipContent._();
factory MembershipContent({ factory MembershipContent({
@JsonKey(name: "displayname") required String displayName, @JsonKey(name: "displayname") required String? displayName,
@JsonKey(name: "membership") required MembershipStatus status, @JsonKey(name: "membership") required MembershipStatus status,
Uri? avatarUrl, Uri? avatarUrl,
String? reason, String? reason,

View file

@ -9,13 +9,22 @@ part "message.g.dart";
@Freezed(unionKey: "msgtype", fallbackUnion: "default") @Freezed(unionKey: "msgtype", fallbackUnion: "default")
abstract class MessageContent extends Content with _$MessageContent { abstract class MessageContent extends Content with _$MessageContent {
MessageContent._(); MessageContent._();
factory MessageContent({ factory MessageContent({required String body}) = UnknownMessageContent;
required String msgtype,
@FreezedUnionValue("m.text")
factory MessageContent.text({
required String body, required String body,
String? format, String? format,
String? formattedBody, String? formattedBody,
}) = TextMessageContent; }) = TextMessageContent;
@FreezedUnionValue("m.notice")
factory MessageContent.notice({
required String body,
String? format,
String? formattedBody,
}) = NoticeMessageContent;
@FreezedUnionValue("m.image") @FreezedUnionValue("m.image")
factory MessageContent.image({ factory MessageContent.image({
required String body, required String body,

View file

@ -36,10 +36,13 @@ abstract class Event with _$Event {
@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: pmpFromJson) Profile? pmp,
@JsonKey(fromJson: Content.fromEventJson) required Content content, @JsonKey(fromJson: Content.fromJson) required Content content,
}) = _Event; }) = _Event;
factory Event.fromJson(Map<String, Object?> json) => _$EventFromJson(json); factory Event.fromJson(Map<String, dynamic> json) =>
_$EventFromJson(json).copyWith(
content: Content.fromEventJson(json["content"], json["type"] as String),
);
} }
@freezed @freezed

View file

@ -4,6 +4,7 @@ import "package:nexus/controllers/members_by_type_controller.dart";
import "package:nexus/controllers/rooms_controller.dart"; import "package:nexus/controllers/rooms_controller.dart";
import "package:nexus/controllers/via_controller.dart"; import "package:nexus/controllers/via_controller.dart";
import "package:nexus/helpers/extensions/better_when.dart"; import "package:nexus/helpers/extensions/better_when.dart";
import "package:nexus/helpers/extensions/get_localpart.dart";
import "package:nexus/models/content/membership.dart"; import "package:nexus/models/content/membership.dart";
import "package:nexus/models/membership_status.dart"; import "package:nexus/models/membership_status.dart";
import "package:nexus/widgets/avatar_or_hash.dart"; import "package:nexus/widgets/avatar_or_hash.dart";
@ -55,7 +56,7 @@ class MentionOverlay extends ConsumerWidget {
:final displayName, :final displayName,
) => ) =>
displayName displayName
.toLowerCase() ?.toLowerCase()
.contains( .contains(
query.toLowerCase(), query.toLowerCase(),
) == ) ==
@ -72,16 +73,17 @@ class MentionOverlay extends ConsumerWidget {
ListTile( ListTile(
leading: AvatarOrHash( leading: AvatarOrHash(
avatarUrl, avatarUrl,
displayName, displayName ??
member.stateKey!.localpart,
),
title: Text(
displayName ??
member.stateKey!.localpart,
), ),
title: Text(displayName),
subtitle: Text(member.stateKey!), subtitle: Text(member.stateKey!),
onTap: () => addTag( onTap: () => addTag(
id: "[@$displayName](matrix:u/${member.stateKey!.substring(1)})", id: "[@$displayName](matrix:u/${member.stateKey!.substring(1)})",
name: member.stateKey! name: member.stateKey!.localpart,
.substring(1)
.split(":")
.first,
), ),
), ),
_ => SizedBox.shrink(), _ => SizedBox.shrink(),

View file

@ -2,8 +2,8 @@ import "package:flutter/material.dart";
import "package:flutter_riverpod/flutter_riverpod.dart"; import "package:flutter_riverpod/flutter_riverpod.dart";
import "package:nexus/controllers/author_controller.dart"; import "package:nexus/controllers/author_controller.dart";
import "package:nexus/helpers/extensions/better_when.dart"; import "package:nexus/helpers/extensions/better_when.dart";
import "package:nexus/helpers/extensions/get_localpart.dart";
import "package:nexus/helpers/extensions/show_user_popover.dart"; import "package:nexus/helpers/extensions/show_user_popover.dart";
import "package:nexus/models/content/membership.dart";
import "package:nexus/models/event.dart"; import "package:nexus/models/event.dart";
import "package:nexus/widgets/avatar_or_hash.dart"; import "package:nexus/widgets/avatar_or_hash.dart";
@ -26,11 +26,11 @@ class MessageAvatar extends ConsumerWidget {
}, },
child: AvatarOrHash( child: AvatarOrHash(
membership.avatarUrl, membership.avatarUrl,
membership.displayName, membership.displayName ?? event.sender.localpart,
height: height, height: height,
), ),
), ),
loading: () => loading: () =>
AvatarOrHash(null, event.sender.substring(1), height: height), AvatarOrHash(null, event.sender.localpart, height: height),
); );
} }

View file

@ -3,6 +3,7 @@ import "package:flutter_hooks/flutter_hooks.dart";
import "package:hooks_riverpod/hooks_riverpod.dart"; import "package:hooks_riverpod/hooks_riverpod.dart";
import "package:nexus/controllers/members_by_type_controller.dart"; import "package:nexus/controllers/members_by_type_controller.dart";
import "package:nexus/helpers/extensions/better_when.dart"; import "package:nexus/helpers/extensions/better_when.dart";
import "package:nexus/helpers/extensions/get_localpart.dart";
import "package:nexus/helpers/extensions/show_user_popover.dart"; import "package:nexus/helpers/extensions/show_user_popover.dart";
import "package:nexus/models/content/membership.dart"; import "package:nexus/models/content/membership.dart";
import "package:nexus/models/membership_status.dart"; import "package:nexus/models/membership_status.dart";
@ -75,9 +76,12 @@ class MemberList extends HookConsumerWidget {
globalPosition: details.globalPosition, globalPosition: details.globalPosition,
), ),
child: ListTile( child: ListTile(
leading: AvatarOrHash(avatarUrl, displayName), leading: AvatarOrHash(
avatarUrl,
displayName ?? member.sender.localpart,
),
title: Text( title: Text(
displayName, displayName ?? member.stateKey!.localpart,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
), ),
subtitle: Text( subtitle: Text(

View file

@ -8,6 +8,7 @@ import "package:nexus/controllers/power_level_controller.dart";
import "package:nexus/controllers/profile_controller.dart"; import "package:nexus/controllers/profile_controller.dart";
import "package:nexus/controllers/selected_room_controller.dart"; import "package:nexus/controllers/selected_room_controller.dart";
import "package:nexus/helpers/extensions/better_when.dart"; import "package:nexus/helpers/extensions/better_when.dart";
import "package:nexus/helpers/extensions/get_localpart.dart";
import "package:nexus/models/configs/power_level_config.dart"; import "package:nexus/models/configs/power_level_config.dart";
import "package:nexus/models/content/membership.dart"; import "package:nexus/models/content/membership.dart";
import "package:nexus/models/membership_status.dart"; import "package:nexus/models/membership_status.dart";
@ -93,7 +94,7 @@ class UserPopover extends ConsumerWidget {
member.avatarUrl?.toString(), member.avatarUrl?.toString(),
child: AvatarOrHash( child: AvatarOrHash(
member.avatarUrl, member.avatarUrl,
member.displayName, member.displayName ?? userId.localpart,
height: 80, height: 80,
), ),
), ),
@ -101,7 +102,7 @@ class UserPopover extends ConsumerWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
SelectableText( SelectableText(
member.displayName, member.displayName ?? userId.localpart,
style: textTheme.headlineSmall, style: textTheme.headlineSmall,
), ),
SelectableText(userId, style: textTheme.titleSmall), SelectableText(userId, style: textTheme.titleSmall),