mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-01-15 10:38:41 +00:00
331 lines
8.7 KiB
Dart
331 lines
8.7 KiB
Dart
// ignore_for_file: strict_raw_type, prefer_constructors_over_static_methods
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:twonly/src/database/tables/messages_table.dart';
|
|
import 'package:twonly/src/utils/misc.dart';
|
|
|
|
Color getMessageColorFromType(MessageContent content, BuildContext context) {
|
|
Color color;
|
|
|
|
if (content is TextMessageContent) {
|
|
color = Colors.blueAccent;
|
|
} else {
|
|
if (content is MediaMessageContent) {
|
|
if (content.isRealTwonly) {
|
|
color = context.color.primary;
|
|
} else {
|
|
if (content.isVideo) {
|
|
color = const Color.fromARGB(255, 243, 33, 208);
|
|
} else {
|
|
color = Colors.redAccent;
|
|
}
|
|
}
|
|
} else {
|
|
return (isDarkMode(context)) ? Colors.white : Colors.black;
|
|
}
|
|
}
|
|
return color;
|
|
}
|
|
|
|
extension MessageKindExtension on MessageKind {
|
|
String get name => toString().split('.').last;
|
|
|
|
static MessageKind fromString(String name) {
|
|
return MessageKind.values.firstWhere((e) => e.name == name);
|
|
}
|
|
}
|
|
|
|
class MessageJson {
|
|
MessageJson({
|
|
required this.kind,
|
|
required this.content,
|
|
required this.timestamp,
|
|
this.messageReceiverId,
|
|
this.messageSenderId,
|
|
this.retransId,
|
|
});
|
|
final MessageKind kind;
|
|
final MessageContent? content;
|
|
final int? messageReceiverId;
|
|
final int? messageSenderId;
|
|
int? retransId;
|
|
DateTime timestamp;
|
|
|
|
@override
|
|
String toString() {
|
|
return 'Message(kind: $kind, content: $content, timestamp: $timestamp)';
|
|
}
|
|
|
|
static MessageJson fromJson(Map<String, dynamic> json) {
|
|
final kind = MessageKindExtension.fromString(json['kind'] as String);
|
|
|
|
return MessageJson(
|
|
kind: kind,
|
|
messageReceiverId: (json['messageReceiverId'] as num?)?.toInt(),
|
|
messageSenderId: (json['messageSenderId'] as num?)?.toInt(),
|
|
retransId: (json['retransId'] as num?)?.toInt(),
|
|
content: MessageContent.fromJson(
|
|
kind,
|
|
json['content'] as Map<String, dynamic>,
|
|
),
|
|
timestamp: DateTime.fromMillisecondsSinceEpoch(json['timestamp'] as int),
|
|
);
|
|
}
|
|
|
|
Map<String, dynamic> toJson() => <String, dynamic>{
|
|
'kind': kind.name,
|
|
'content': content?.toJson(),
|
|
'messageReceiverId': messageReceiverId,
|
|
'messageSenderId': messageSenderId,
|
|
'retransId': retransId,
|
|
'timestamp': timestamp.toUtc().millisecondsSinceEpoch,
|
|
};
|
|
}
|
|
|
|
class MessageContent {
|
|
MessageContent();
|
|
|
|
static MessageContent? fromJson(MessageKind kind, Map json) {
|
|
switch (kind) {
|
|
case MessageKind.media:
|
|
return MediaMessageContent.fromJson(json);
|
|
case MessageKind.textMessage:
|
|
return TextMessageContent.fromJson(json);
|
|
case MessageKind.profileChange:
|
|
return ProfileContent.fromJson(json);
|
|
case MessageKind.pushKey:
|
|
return PushKeyContent.fromJson(json);
|
|
case MessageKind.reopenedMedia:
|
|
return ReopenedMediaFileContent.fromJson(json);
|
|
case MessageKind.flameSync:
|
|
return FlameSyncContent.fromJson(json);
|
|
case MessageKind.ack:
|
|
return AckContent.fromJson(json);
|
|
case MessageKind.signalDecryptError:
|
|
return SignalDecryptErrorContent.fromJson(json);
|
|
case MessageKind.storedMediaFile:
|
|
case MessageKind.contactRequest:
|
|
case MessageKind.rejectRequest:
|
|
case MessageKind.acceptRequest:
|
|
case MessageKind.opened:
|
|
case MessageKind.requestPushKey:
|
|
case MessageKind.receiveMediaError:
|
|
}
|
|
return null;
|
|
}
|
|
|
|
Map toJson() {
|
|
return {};
|
|
}
|
|
}
|
|
|
|
class MediaMessageContent extends MessageContent {
|
|
MediaMessageContent({
|
|
required this.maxShowTime,
|
|
required this.isRealTwonly,
|
|
required this.isVideo,
|
|
required this.mirrorVideo,
|
|
this.downloadToken,
|
|
this.encryptionKey,
|
|
this.encryptionMac,
|
|
this.encryptionNonce,
|
|
});
|
|
final int maxShowTime;
|
|
final bool isRealTwonly;
|
|
final bool isVideo;
|
|
final bool mirrorVideo;
|
|
final List<int>? downloadToken;
|
|
final List<int>? encryptionKey;
|
|
final List<int>? encryptionMac;
|
|
final List<int>? encryptionNonce;
|
|
|
|
static MediaMessageContent fromJson(Map json) {
|
|
return MediaMessageContent(
|
|
downloadToken: json['downloadToken'] == null
|
|
? null
|
|
: List<int>.from(json['downloadToken'] as List),
|
|
encryptionKey: json['encryptionKey'] == null
|
|
? null
|
|
: List<int>.from(json['encryptionKey'] as List),
|
|
encryptionMac: json['encryptionMac'] == null
|
|
? null
|
|
: List<int>.from(json['encryptionMac'] as List),
|
|
encryptionNonce: json['encryptionNonce'] == null
|
|
? null
|
|
: List<int>.from(json['encryptionNonce'] as List),
|
|
maxShowTime: json['maxShowTime'] as int,
|
|
isRealTwonly: json['isRealTwonly'] as bool,
|
|
isVideo: json['isVideo'] as bool? ?? false,
|
|
mirrorVideo: json['mirrorVideo'] as bool? ?? false,
|
|
);
|
|
}
|
|
|
|
@override
|
|
Map toJson() {
|
|
return {
|
|
'downloadToken': downloadToken,
|
|
'encryptionKey': encryptionKey,
|
|
'encryptionMac': encryptionMac,
|
|
'encryptionNonce': encryptionNonce,
|
|
'isRealTwonly': isRealTwonly,
|
|
'maxShowTime': maxShowTime,
|
|
'isVideo': isVideo,
|
|
'mirrorVideo': mirrorVideo,
|
|
};
|
|
}
|
|
}
|
|
|
|
class TextMessageContent extends MessageContent {
|
|
TextMessageContent({
|
|
required this.text,
|
|
this.responseToMessageId,
|
|
this.responseToOtherMessageId,
|
|
});
|
|
String text;
|
|
int? responseToMessageId;
|
|
int? responseToOtherMessageId;
|
|
|
|
static TextMessageContent fromJson(Map json) {
|
|
return TextMessageContent(
|
|
text: json['text'] as String,
|
|
responseToOtherMessageId: json.containsKey('responseToOtherMessageId')
|
|
? json['responseToOtherMessageId'] as int?
|
|
: null,
|
|
responseToMessageId: json.containsKey('responseToMessageId')
|
|
? json['responseToMessageId'] as int?
|
|
: null,
|
|
);
|
|
}
|
|
|
|
@override
|
|
Map toJson() {
|
|
return {
|
|
'text': text,
|
|
'responseToMessageId': responseToMessageId,
|
|
'responseToOtherMessageId': responseToOtherMessageId,
|
|
};
|
|
}
|
|
}
|
|
|
|
class ReopenedMediaFileContent extends MessageContent {
|
|
ReopenedMediaFileContent({required this.messageId});
|
|
int messageId;
|
|
|
|
static ReopenedMediaFileContent fromJson(Map json) {
|
|
return ReopenedMediaFileContent(messageId: json['messageId'] as int);
|
|
}
|
|
|
|
@override
|
|
Map toJson() {
|
|
return {'messageId': messageId};
|
|
}
|
|
}
|
|
|
|
class SignalDecryptErrorContent extends MessageContent {
|
|
SignalDecryptErrorContent({required this.encryptedHash});
|
|
List<int> encryptedHash;
|
|
|
|
static SignalDecryptErrorContent fromJson(Map json) {
|
|
return SignalDecryptErrorContent(
|
|
encryptedHash: List<int>.from(json['encryptedHash'] as List),
|
|
);
|
|
}
|
|
|
|
@override
|
|
Map toJson() {
|
|
return {
|
|
'encryptedHash': encryptedHash,
|
|
};
|
|
}
|
|
}
|
|
|
|
class AckContent extends MessageContent {
|
|
AckContent({required this.messageIdToAck, required this.retransIdToAck});
|
|
int? messageIdToAck;
|
|
int retransIdToAck;
|
|
|
|
static AckContent fromJson(Map json) {
|
|
return AckContent(
|
|
messageIdToAck: json['messageIdToAck'] as int?,
|
|
retransIdToAck: json['retransIdToAck'] as int,
|
|
);
|
|
}
|
|
|
|
@override
|
|
Map toJson() {
|
|
return {
|
|
'messageIdToAck': messageIdToAck,
|
|
'retransIdToAck': retransIdToAck,
|
|
};
|
|
}
|
|
}
|
|
|
|
class ProfileContent extends MessageContent {
|
|
ProfileContent({required this.avatarSvg, required this.displayName});
|
|
String avatarSvg;
|
|
String displayName;
|
|
|
|
static ProfileContent fromJson(Map json) {
|
|
return ProfileContent(
|
|
avatarSvg: json['avatarSvg'] as String,
|
|
displayName: json['displayName'] as String,
|
|
);
|
|
}
|
|
|
|
@override
|
|
Map toJson() {
|
|
return {'avatarSvg': avatarSvg, 'displayName': displayName};
|
|
}
|
|
}
|
|
|
|
class PushKeyContent extends MessageContent {
|
|
PushKeyContent({required this.keyId, required this.key});
|
|
int keyId;
|
|
List<int> key;
|
|
|
|
static PushKeyContent fromJson(Map json) {
|
|
return PushKeyContent(
|
|
keyId: json['keyId'] as int,
|
|
key: List<int>.from(json['key'] as List),
|
|
);
|
|
}
|
|
|
|
@override
|
|
Map toJson() {
|
|
return {
|
|
'keyId': keyId,
|
|
'key': key,
|
|
};
|
|
}
|
|
}
|
|
|
|
class FlameSyncContent extends MessageContent {
|
|
FlameSyncContent({
|
|
required this.flameCounter,
|
|
required this.bestFriend,
|
|
required this.lastFlameCounterChange,
|
|
});
|
|
int flameCounter;
|
|
DateTime lastFlameCounterChange;
|
|
bool bestFriend;
|
|
|
|
static FlameSyncContent fromJson(Map json) {
|
|
return FlameSyncContent(
|
|
flameCounter: json['flameCounter'] as int,
|
|
bestFriend: json['bestFriend'] as bool,
|
|
lastFlameCounterChange: DateTime.fromMillisecondsSinceEpoch(
|
|
json['lastFlameCounterChange'] as int,
|
|
),
|
|
);
|
|
}
|
|
|
|
@override
|
|
Map toJson() {
|
|
return {
|
|
'flameCounter': flameCounter,
|
|
'bestFriend': bestFriend,
|
|
'lastFlameCounterChange':
|
|
lastFlameCounterChange.toUtc().millisecondsSinceEpoch,
|
|
};
|
|
}
|
|
}
|