Gomuks SDK Rewrite #2
11 changed files with 228 additions and 19 deletions
wip
commit
4862bf47c7
|
|
@ -1,3 +1,5 @@
|
||||||
|
import "dart:convert";
|
||||||
|
import "dart:developer";
|
||||||
import "dart:ffi";
|
import "dart:ffi";
|
||||||
import "dart:isolate";
|
import "dart:isolate";
|
||||||
import "package:ffi/ffi.dart";
|
import "package:ffi/ffi.dart";
|
||||||
|
|
@ -7,6 +9,7 @@ import "package:nexus/controllers/sync_status_controller.dart";
|
||||||
import "package:nexus/helpers/extensions/gomuks_buffer.dart";
|
import "package:nexus/helpers/extensions/gomuks_buffer.dart";
|
||||||
import "package:nexus/models/client_state.dart";
|
import "package:nexus/models/client_state.dart";
|
||||||
import "package:nexus/models/login.dart";
|
import "package:nexus/models/login.dart";
|
||||||
|
import "package:nexus/models/sync_complete.dart";
|
||||||
import "package:nexus/models/sync_status.dart";
|
import "package:nexus/models/sync_status.dart";
|
||||||
import "package:nexus/src/third_party/gomuks.g.dart";
|
import "package:nexus/src/third_party/gomuks.g.dart";
|
||||||
import "package:flutter_riverpod/flutter_riverpod.dart";
|
import "package:flutter_riverpod/flutter_riverpod.dart";
|
||||||
|
|
@ -42,10 +45,16 @@ class ClientController extends AsyncNotifier<int> {
|
||||||
.set(SyncStatus.fromJson(decodedMuksEvent));
|
.set(SyncStatus.fromJson(decodedMuksEvent));
|
||||||
break;
|
break;
|
||||||
case "sync_complete":
|
case "sync_complete":
|
||||||
|
debugger(message: jsonEncode(decodedMuksEvent));
|
||||||
|
final thing = SyncComplete.fromJson(decodedMuksEvent);
|
||||||
|
debugger(message: jsonEncode(thing.toJson()));
|
||||||
// ref
|
// ref
|
||||||
// .watch(SyncStatusController.provider.notifier)
|
// .watch(SyncStatusController.provider.notifier)
|
||||||
// .set(SyncStatus.fromJson(decodedMuksEvent));
|
// .set(SyncStatus.fromJson(decodedMuksEvent));
|
||||||
break;
|
break;
|
||||||
|
case "typing":
|
||||||
|
//TODO: IMPL
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
debugPrint("Unhandled event: $muksEventType");
|
debugPrint("Unhandled event: $muksEventType");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
import "package:flutter_riverpod/flutter_riverpod.dart";
|
|
||||||
import "package:path/path.dart";
|
|
||||||
import "package:path_provider/path_provider.dart";
|
|
||||||
import "package:sqflite_common_ffi/sqflite_ffi.dart";
|
|
||||||
|
|
||||||
class DatabaseController extends AsyncNotifier<Database> {
|
|
||||||
@override
|
|
||||||
Future<Database> build() async {
|
|
||||||
databaseFactory = databaseFactoryFfi;
|
|
||||||
return databaseFactoryFfi.openDatabase(
|
|
||||||
join((await getApplicationSupportDirectory()).path, "database.db"),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static final provider = AsyncNotifierProvider<DatabaseController, Database>(
|
|
||||||
DatabaseController.new,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
14
lib/models/content_uri.dart
Normal file
14
lib/models/content_uri.dart
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
import "package:freezed_annotation/freezed_annotation.dart";
|
||||||
|
part "content_uri.freezed.dart";
|
||||||
|
part "content_uri.g.dart";
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
abstract class ContentUri with _$ContentUri {
|
||||||
|
const factory ContentUri({
|
||||||
|
required String homeserver,
|
||||||
|
required String fileID,
|
||||||
|
}) = _ContentUri;
|
||||||
|
|
||||||
|
factory ContentUri.fromJson(Map<String, Object?> json) =>
|
||||||
|
_$ContentUriFromJson(json);
|
||||||
|
}
|
||||||
11
lib/models/epoch_date_time_converter.dart
Normal file
11
lib/models/epoch_date_time_converter.dart
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
import "package:freezed_annotation/freezed_annotation.dart";
|
||||||
|
|
||||||
|
class EpochDateTimeConverter implements JsonConverter<DateTime, int> {
|
||||||
|
const EpochDateTimeConverter();
|
||||||
|
|
||||||
|
@override
|
||||||
|
DateTime fromJson(int json) => DateTime.fromMillisecondsSinceEpoch(json);
|
||||||
|
|
||||||
|
@override
|
||||||
|
int toJson(DateTime object) => object.millisecondsSinceEpoch;
|
||||||
|
}
|
||||||
79
lib/models/event.dart
Normal file
79
lib/models/event.dart
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
import "package:freezed_annotation/freezed_annotation.dart";
|
||||||
|
import "package:nexus/models/epoch_date_time_converter.dart";
|
||||||
|
part "event.freezed.dart";
|
||||||
|
part "event.g.dart";
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
abstract class Event with _$Event {
|
||||||
|
const factory Event({
|
||||||
|
@JsonKey(name: "rowid") required int rowId,
|
||||||
|
@JsonKey(name: "timeline_rowid") required int timelineRowId,
|
||||||
|
required String roomId,
|
||||||
|
required int eventId,
|
||||||
|
@JsonKey(name: "sender") required int authorId,
|
||||||
|
required String type,
|
||||||
|
required String stateKey,
|
||||||
|
@EpochDateTimeConverter() required DateTime timestamp,
|
||||||
|
required Map<String, dynamic> content,
|
||||||
|
required Map<String, dynamic> decrypted,
|
||||||
|
required Map<String, dynamic> decryptedType,
|
||||||
|
required Map<String, dynamic> unsigned,
|
||||||
|
required LocalContent localContent,
|
||||||
|
required String transactionId,
|
||||||
|
required String redactedBy,
|
||||||
|
required String relatesTo,
|
||||||
|
required String relatesType,
|
||||||
|
required String decryptionError,
|
||||||
|
required String sendError,
|
||||||
|
required Map<String, int> reactions,
|
||||||
|
required int lastEditRowId,
|
||||||
|
@UnreadTypeConverter() UnreadType? unreadType,
|
||||||
|
}) = _Event;
|
||||||
|
|
||||||
|
factory Event.fromJson(Map<String, Object?> json) => _$EventFromJson(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
abstract class LocalContent with _$LocalContent {
|
||||||
|
const factory LocalContent({
|
||||||
|
required String sanitizedHtml,
|
||||||
|
required String htmlVersion,
|
||||||
|
required bool wasPlaintext,
|
||||||
|
required bool bigEmoji,
|
||||||
|
required bool hasMath,
|
||||||
|
required String editSource,
|
||||||
|
required String replyFallbackRemoved,
|
||||||
|
}) = _LocalContent;
|
||||||
|
|
||||||
|
factory LocalContent.fromJson(Map<String, Object?> json) =>
|
||||||
|
_$LocalContentFromJson(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
class UnreadTypeConverter implements JsonConverter<UnreadType?, int?> {
|
||||||
|
const UnreadTypeConverter();
|
||||||
|
|
||||||
|
@override
|
||||||
|
UnreadType? fromJson(int? json) => json == null ? null : UnreadType(json);
|
||||||
|
|
||||||
|
@override
|
||||||
|
int? toJson(UnreadType? object) => object?.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@immutable
|
||||||
|
class UnreadType {
|
||||||
|
final int value;
|
||||||
|
|
||||||
|
const UnreadType(this.value);
|
||||||
|
|
||||||
|
static const none = UnreadType(0);
|
||||||
|
static const normal = UnreadType(1);
|
||||||
|
static const notify = UnreadType(2);
|
||||||
|
static const highlight = UnreadType(4);
|
||||||
|
static const sound = UnreadType(8);
|
||||||
|
|
||||||
|
bool get isNone => value == 0;
|
||||||
|
bool get isNormal => (value & 1) != 0;
|
||||||
|
bool get shouldNotify => (value & 2) != 0;
|
||||||
|
bool get isHighlighted => (value & 4) != 0;
|
||||||
|
bool get playsSound => (value & 8) != 0;
|
||||||
|
}
|
||||||
15
lib/models/lazy_load_summary.dart
Normal file
15
lib/models/lazy_load_summary.dart
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
import "package:freezed_annotation/freezed_annotation.dart";
|
||||||
|
part "lazy_load_summary.freezed.dart";
|
||||||
|
part "lazy_load_summary.g.dart";
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
abstract class LazyLoadSummary with _$LazyLoadSummary {
|
||||||
|
const factory LazyLoadSummary({
|
||||||
|
required List<String> heroes,
|
||||||
|
required int? joinedMemberCount,
|
||||||
|
required int? invitedMemberCount,
|
||||||
|
}) = _LazyLoadSummary;
|
||||||
|
|
||||||
|
factory LazyLoadSummary.fromJson(Map<String, Object?> json) =>
|
||||||
|
_$LazyLoadSummaryFromJson(json);
|
||||||
|
}
|
||||||
18
lib/models/read_receipt.dart
Normal file
18
lib/models/read_receipt.dart
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
import "package:freezed_annotation/freezed_annotation.dart";
|
||||||
|
import "package:nexus/models/epoch_date_time_converter.dart";
|
||||||
|
part "read_receipt.freezed.dart";
|
||||||
|
part "read_receipt.g.dart";
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
abstract class ReadReceipt with _$ReadReceipt {
|
||||||
|
const factory ReadReceipt({
|
||||||
|
String? roomId,
|
||||||
|
required String userId,
|
||||||
|
String? threadId,
|
||||||
|
required String eventId,
|
||||||
|
@EpochDateTimeConverter() required DateTime timestamp,
|
||||||
|
}) = _ReadReceipt;
|
||||||
|
|
||||||
|
factory ReadReceipt.fromJson(Map<String, Object?> json) =>
|
||||||
|
_$ReadReceiptFromJson(json);
|
||||||
|
}
|
||||||
34
lib/models/room.dart
Normal file
34
lib/models/room.dart
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
import "package:freezed_annotation/freezed_annotation.dart";
|
||||||
|
import "package:nexus/models/event.dart";
|
||||||
|
import "package:nexus/models/read_receipt.dart";
|
||||||
|
import "package:nexus/models/room_metadata.dart";
|
||||||
|
part "room.freezed.dart";
|
||||||
|
part "room.g.dart";
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
abstract class Room with _$Room {
|
||||||
|
const factory Room({
|
||||||
|
@JsonKey(name: "meta") RoomMetadata? metadata,
|
||||||
|
required List<TimelineRowTuple> timeline,
|
||||||
|
required bool reset,
|
||||||
|
required Map<String, Map> state,
|
||||||
|
// required Map<String, AccountData> accountData,
|
||||||
|
required List<Event> events,
|
||||||
|
required Map<String, List<ReadReceipt>> receipts,
|
||||||
|
required bool dismissNotifications,
|
||||||
|
// required List<Notification> notifications,
|
||||||
|
}) = _Room;
|
||||||
|
|
||||||
|
factory Room.fromJson(Map<String, Object?> json) => _$RoomFromJson(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
abstract class TimelineRowTuple with _$TimelineRowTuple {
|
||||||
|
const factory TimelineRowTuple({
|
||||||
|
@JsonKey(name: "timeline_rowid") required int timelineRowId,
|
||||||
|
@JsonKey(name: "timeline_eventid") required int eventRowId,
|
||||||
|
}) = _TimelineRowTuple;
|
||||||
|
|
||||||
|
factory TimelineRowTuple.fromJson(Map<String, Object?> json) =>
|
||||||
|
_$TimelineRowTupleFromJson(json);
|
||||||
|
}
|
||||||
27
lib/models/room_metadata.dart
Normal file
27
lib/models/room_metadata.dart
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
import "package:freezed_annotation/freezed_annotation.dart";
|
||||||
|
import "package:nexus/models/content_uri.dart";
|
||||||
|
import "package:nexus/models/epoch_date_time_converter.dart";
|
||||||
|
import "package:nexus/models/lazy_load_summary.dart";
|
||||||
|
part "room_metadata.freezed.dart";
|
||||||
|
part "room_metadata.g.dart";
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
abstract class RoomMetadata with _$RoomMetadata {
|
||||||
|
const factory RoomMetadata({
|
||||||
|
@JsonKey(name: "room_id") required String id,
|
||||||
|
// required CreateEventContent creationContent,
|
||||||
|
// required TombstoneEventContent tombstoneEventContent,
|
||||||
|
String? name,
|
||||||
|
ContentUri? avatar,
|
||||||
|
String? topic,
|
||||||
|
String? canonicalAlias,
|
||||||
|
LazyLoadSummary? lazyLoadSummary,
|
||||||
|
required bool hasMemberList,
|
||||||
|
@JsonKey(name: "preview_event_rowid") required String previewEventRowID,
|
||||||
|
@EpochDateTimeConverter() required DateTime sortingTimestamp,
|
||||||
|
@Default(false) bool markedUnread,
|
||||||
|
}) = _RoomMetadata;
|
||||||
|
|
||||||
|
factory RoomMetadata.fromJson(Map<String, Object?> json) =>
|
||||||
|
_$RoomMetadataFromJson(json);
|
||||||
|
}
|
||||||
20
lib/models/sync_complete.dart
Normal file
20
lib/models/sync_complete.dart
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
import "package:freezed_annotation/freezed_annotation.dart";
|
||||||
|
import "package:nexus/models/room.dart";
|
||||||
|
part "sync_complete.freezed.dart";
|
||||||
|
part "sync_complete.g.dart";
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
abstract class SyncComplete with _$SyncComplete {
|
||||||
|
const factory SyncComplete({
|
||||||
|
@Default(false) bool clearState,
|
||||||
|
// required Map<String, AccountData> accountData,
|
||||||
|
required Map<String, Room> rooms,
|
||||||
|
required List<String> leftRooms,
|
||||||
|
// required List<InvitedRoom> invitedRooms,
|
||||||
|
// required List<SpaceEdge> spaceEdges,
|
||||||
|
required List<String> topLevelSpaces,
|
||||||
|
}) = _SyncComplete;
|
||||||
|
|
||||||
|
factory SyncComplete.fromJson(Map<String, Object?> json) =>
|
||||||
|
_$SyncCompleteFromJson(json);
|
||||||
|
}
|
||||||
|
|
@ -6,8 +6,8 @@ part "sync_status.g.dart";
|
||||||
abstract class SyncStatus with _$SyncStatus {
|
abstract class SyncStatus with _$SyncStatus {
|
||||||
const factory SyncStatus({
|
const factory SyncStatus({
|
||||||
required SyncStatusType type,
|
required SyncStatusType type,
|
||||||
|
String? error,
|
||||||
required int errorCount,
|
required int errorCount,
|
||||||
required int lastSync,
|
|
||||||
}) = _SyncStatus;
|
}) = _SyncStatus;
|
||||||
|
|
||||||
factory SyncStatus.fromJson(Map<String, Object?> json) =>
|
factory SyncStatus.fromJson(Map<String, Object?> json) =>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue