mirror of
https://gitlab.com/veilid/veilidchat.git
synced 2024-10-01 06:55:46 -04:00
messages wip
This commit is contained in:
parent
17f6dfce46
commit
9c5feed732
@ -4,7 +4,7 @@ import 'package:veilid_support/veilid_support.dart';
|
||||
class ActiveChatCubit extends Cubit<TypedKey?> {
|
||||
ActiveChatCubit(super.initialState);
|
||||
|
||||
void setActiveChat(TypedKey? activeChatRemoteConversationRecordKey) {
|
||||
emit(activeChatRemoteConversationRecordKey);
|
||||
void setActiveChat(TypedKey? activeChatLocalConversationRecordKey) {
|
||||
emit(activeChatLocalConversationRecordKey);
|
||||
}
|
||||
}
|
||||
|
@ -53,14 +53,12 @@ class SingleContactMessagesCubit extends Cubit<SingleContactMessagesState> {
|
||||
required TypedKey localMessagesRecordKey,
|
||||
required TypedKey remoteConversationRecordKey,
|
||||
required TypedKey remoteMessagesRecordKey,
|
||||
required OwnedDHTRecordPointer reconciledChatRecord,
|
||||
}) : _activeAccountInfo = activeAccountInfo,
|
||||
_remoteIdentityPublicKey = remoteIdentityPublicKey,
|
||||
_localConversationRecordKey = localConversationRecordKey,
|
||||
_localMessagesRecordKey = localMessagesRecordKey,
|
||||
_remoteConversationRecordKey = remoteConversationRecordKey,
|
||||
_remoteMessagesRecordKey = remoteMessagesRecordKey,
|
||||
_reconciledChatRecord = reconciledChatRecord,
|
||||
super(const AsyncValue.loading()) {
|
||||
// Async Init
|
||||
_initWait.add(_init);
|
||||
@ -420,7 +418,14 @@ class SingleContactMessagesCubit extends Cubit<SingleContactMessagesState> {
|
||||
emit(AsyncValue.data(renderedState));
|
||||
}
|
||||
|
||||
void addMessage({required proto.Message message}) {
|
||||
void addTextMessage({required proto.Message_Text messageText}) {
|
||||
final message = proto.Message()
|
||||
..author = _activeAccountInfo.localAccount.identityMaster
|
||||
.identityPublicTypedKey()
|
||||
.toProto()
|
||||
..timestamp = Veilid.instance.now().toInt64()
|
||||
..text = messageText;
|
||||
|
||||
_unreconciledMessagesQueue.addSync(message);
|
||||
_sendingMessagesQueue.addSync(message);
|
||||
|
||||
@ -428,6 +433,21 @@ class SingleContactMessagesCubit extends Cubit<SingleContactMessagesState> {
|
||||
_renderState();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static Future<void> cleanupAndDeleteMessages(
|
||||
{required TypedKey localConversationRecordKey}) async {
|
||||
final recmsgdbname =
|
||||
_reconciledMessagesTableDBName(localConversationRecordKey);
|
||||
await Veilid.instance.deleteTableDB(recmsgdbname);
|
||||
}
|
||||
|
||||
static String _reconciledMessagesTableDBName(
|
||||
TypedKey localConversationRecordKey) =>
|
||||
'msg_$localConversationRecordKey';
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
final WaitSet<void> _initWait = WaitSet();
|
||||
final ActiveAccountInfo _activeAccountInfo;
|
||||
final TypedKey _remoteIdentityPublicKey;
|
||||
@ -435,7 +455,6 @@ class SingleContactMessagesCubit extends Cubit<SingleContactMessagesState> {
|
||||
final TypedKey _localMessagesRecordKey;
|
||||
final TypedKey _remoteConversationRecordKey;
|
||||
final TypedKey _remoteMessagesRecordKey;
|
||||
final OwnedDHTRecordPointer _reconciledChatRecord;
|
||||
|
||||
late final VeilidCrypto _messagesCrypto;
|
||||
|
||||
|
@ -30,10 +30,28 @@ class MessageState with _$MessageState {
|
||||
required proto.Message content,
|
||||
// Received or delivered timestamp
|
||||
required Timestamp timestamp,
|
||||
// The state of the mssage
|
||||
// The state of the message
|
||||
required MessageSendState? sendState,
|
||||
}) = _MessageState;
|
||||
|
||||
factory MessageState.fromJson(dynamic json) =>
|
||||
_$MessageStateFromJson(json as Map<String, dynamic>);
|
||||
}
|
||||
|
||||
extension MessageStateExt on MessageState {
|
||||
String get uniqueId {
|
||||
final author = content.author.toVeilid().toString();
|
||||
final id = base64UrlNoPadEncode(content.id);
|
||||
return '$author|$id';
|
||||
}
|
||||
|
||||
static (proto.TypedKey, Uint8List) splitUniqueId(String uniqueId) {
|
||||
final parts = uniqueId.split('|');
|
||||
if (parts.length != 2) {
|
||||
throw Exception('invalid unique id');
|
||||
}
|
||||
final author = TypedKey.fromString(parts[0]).toProto();
|
||||
final id = base64UrlNoPadDecode(parts[1]);
|
||||
return (author, id);
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ mixin _$MessageState {
|
||||
proto.Message get content =>
|
||||
throw _privateConstructorUsedError; // Received or delivered timestamp
|
||||
Timestamp get timestamp =>
|
||||
throw _privateConstructorUsedError; // The state of the mssage
|
||||
throw _privateConstructorUsedError; // The state of the message
|
||||
MessageSendState? get sendState => throw _privateConstructorUsedError;
|
||||
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@ -147,7 +147,7 @@ class _$MessageStateImpl with DiagnosticableTreeMixin implements _MessageState {
|
||||
// Received or delivered timestamp
|
||||
@override
|
||||
final Timestamp timestamp;
|
||||
// The state of the mssage
|
||||
// The state of the message
|
||||
@override
|
||||
final MessageSendState? sendState;
|
||||
|
||||
@ -211,7 +211,7 @@ abstract class _MessageState implements MessageState {
|
||||
proto.Message get content;
|
||||
@override // Received or delivered timestamp
|
||||
Timestamp get timestamp;
|
||||
@override // The state of the mssage
|
||||
@override // The state of the message
|
||||
MessageSendState? get sendState;
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
|
@ -1,5 +1,8 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:async_tools/async_tools.dart';
|
||||
import 'package:awesome_extensions/awesome_extensions.dart';
|
||||
import 'package:fixnum/fixnum.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_chat_types/flutter_chat_types.dart' as types;
|
||||
@ -13,6 +16,10 @@ import '../../proto/proto.dart' as proto;
|
||||
import '../../theme/theme.dart';
|
||||
import '../chat.dart';
|
||||
|
||||
const String metadataKeyExpirationDuration = 'expiration';
|
||||
const String metadataKeyViewLimit = 'view_limit';
|
||||
const String metadataKeyAttachments = 'attachments';
|
||||
|
||||
class ChatComponent extends StatelessWidget {
|
||||
const ChatComponent._(
|
||||
{required TypedKey localUserIdentityKey,
|
||||
@ -35,7 +42,7 @@ class ChatComponent extends StatelessWidget {
|
||||
|
||||
// Builder wrapper function that takes care of state management requirements
|
||||
static Widget builder(
|
||||
{required TypedKey remoteConversationRecordKey, Key? key}) =>
|
||||
{required TypedKey localConversationRecordKey, Key? key}) =>
|
||||
Builder(builder: (context) {
|
||||
// Get all watched dependendies
|
||||
final activeAccountInfo = context.watch<ActiveAccountInfo>();
|
||||
@ -51,7 +58,7 @@ class ChatComponent extends StatelessWidget {
|
||||
}
|
||||
final avconversation = context.select<ActiveConversationsBlocMapCubit,
|
||||
AsyncValue<ActiveConversationState>?>(
|
||||
(x) => x.state[remoteConversationRecordKey]);
|
||||
(x) => x.state[localConversationRecordKey]);
|
||||
if (avconversation == null) {
|
||||
return waitingPage();
|
||||
}
|
||||
@ -77,7 +84,7 @@ class ChatComponent extends StatelessWidget {
|
||||
// Get the messages cubit
|
||||
final messages = context.select<ActiveSingleContactChatBlocMapCubit,
|
||||
(SingleContactMessagesCubit, SingleContactMessagesState)?>(
|
||||
(x) => x.tryOperate(remoteConversationRecordKey,
|
||||
(x) => x.tryOperate(localConversationRecordKey,
|
||||
closure: (cubit) => (cubit, cubit.state)));
|
||||
|
||||
// Get the messages to display
|
||||
@ -97,8 +104,8 @@ class ChatComponent extends StatelessWidget {
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
types.Message messageToChatMessage(MessageState message) {
|
||||
final isLocal = message.author == _localUserIdentityKey;
|
||||
types.Message? messageToChatMessage(MessageState message) {
|
||||
final isLocal = message.content.author.toVeilid() == _localUserIdentityKey;
|
||||
|
||||
types.Status? status;
|
||||
if (message.sendState != null) {
|
||||
@ -113,31 +120,83 @@ class ChatComponent extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
switch (message.content.whichKind()) {
|
||||
case proto.Message_Kind.text:
|
||||
final contextText = message.content.text;
|
||||
final textMessage = types.TextMessage(
|
||||
author: isLocal ? _localUser : _remoteUser,
|
||||
createdAt: (message.timestamp.value ~/ BigInt.from(1000)).toInt(),
|
||||
id: message.timestamp.toString(),
|
||||
text: message.text,
|
||||
id: message.uniqueId,
|
||||
text: contextText.text,
|
||||
showStatus: status != null,
|
||||
status: status);
|
||||
return textMessage;
|
||||
case proto.Message_Kind.secret:
|
||||
case proto.Message_Kind.delete:
|
||||
case proto.Message_Kind.erase:
|
||||
case proto.Message_Kind.settings:
|
||||
case proto.Message_Kind.permissions:
|
||||
case proto.Message_Kind.membership:
|
||||
case proto.Message_Kind.moderation:
|
||||
case proto.Message_Kind.notSet:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
void _addMessage(proto.Message message) {
|
||||
if (message.text.isEmpty) {
|
||||
return;
|
||||
void _addTextMessage(
|
||||
{required String text,
|
||||
String? topic,
|
||||
Uint8List? replyId,
|
||||
Timestamp? expiration,
|
||||
int? viewLimit,
|
||||
List<proto.Attachment> attachments = const []}) {
|
||||
final protoMessageText = proto.Message_Text()..text = text;
|
||||
if (topic != null) {
|
||||
protoMessageText.topic = topic;
|
||||
}
|
||||
_messagesCubit.addMessage(message: message);
|
||||
if (replyId != null) {
|
||||
protoMessageText.replyId = replyId;
|
||||
}
|
||||
protoMessageText
|
||||
..expiration = expiration?.toInt64() ?? Int64.ZERO
|
||||
..viewLimit = viewLimit ?? 0;
|
||||
protoMessageText.attachments.addAll(attachments);
|
||||
|
||||
_messagesCubit.addTextMessage(messageText: protoMessageText);
|
||||
}
|
||||
|
||||
void _handleSendPressed(types.PartialText message) {
|
||||
final protoMessage = proto.Message()
|
||||
..author = _localUserIdentityKey.toProto()
|
||||
..timestamp = Veilid.instance.now().toInt64()
|
||||
..text = message.text;
|
||||
//..signature = signature;
|
||||
final text = message.text;
|
||||
final replyId = (message.repliedMessage != null)
|
||||
? MessageStateExt.splitUniqueId(message.repliedMessage!.id).$2
|
||||
: null;
|
||||
Timestamp? expiration;
|
||||
int? viewLimit;
|
||||
List<proto.Attachment>? attachments;
|
||||
final metadata = message.metadata;
|
||||
if (metadata != null) {
|
||||
final expirationValue =
|
||||
metadata[metadataKeyExpirationDuration] as TimestampDuration?;
|
||||
if (expirationValue != null) {
|
||||
expiration = Veilid.instance.now().offset(expirationValue);
|
||||
}
|
||||
final viewLimitValue = metadata[metadataKeyViewLimit] as int?;
|
||||
if (viewLimitValue != null) {
|
||||
viewLimit = viewLimitValue;
|
||||
}
|
||||
final attachmentsValue =
|
||||
metadata[metadataKeyAttachments] as List<proto.Attachment>?;
|
||||
if (attachmentsValue != null) {
|
||||
attachments = attachmentsValue;
|
||||
}
|
||||
}
|
||||
|
||||
_addMessage(protoMessage);
|
||||
_addTextMessage(
|
||||
text: text,
|
||||
replyId: replyId,
|
||||
expiration: expiration,
|
||||
viewLimit: viewLimit,
|
||||
attachments: attachments ?? []);
|
||||
}
|
||||
|
||||
// void _handleAttachmentPressed() async {
|
||||
@ -161,6 +220,9 @@ class ChatComponent extends StatelessWidget {
|
||||
final tsSet = <String>{};
|
||||
for (final message in messages) {
|
||||
final chatMessage = messageToChatMessage(message);
|
||||
if (chatMessage == null) {
|
||||
continue;
|
||||
}
|
||||
chatMessages.insert(0, chatMessage);
|
||||
if (!tsSet.add(chatMessage.id)) {
|
||||
// ignore: avoid_print
|
||||
|
@ -31,7 +31,7 @@ typedef ActiveConversationCubit = TransformerCubit<
|
||||
typedef ActiveConversationsBlocMapState
|
||||
= BlocMapState<TypedKey, AsyncValue<ActiveConversationState>>;
|
||||
|
||||
// Map of remoteConversationRecordKey to ActiveConversationCubit
|
||||
// Map of localConversationRecordKey to ActiveConversationCubit
|
||||
// Wraps a conversation cubit to only expose completely built conversations
|
||||
// Automatically follows the state of a ChatListCubit.
|
||||
// Even though 'conversations' are per-contact and not per-chat
|
||||
@ -49,7 +49,7 @@ class ActiveConversationsBlocMapCubit extends BlocMapCubit<TypedKey,
|
||||
// Add an active conversation to be tracked for changes
|
||||
Future<void> _addConversation({required proto.Contact contact}) async =>
|
||||
add(() => MapEntry(
|
||||
contact.remoteConversationRecordKey.toVeilid(),
|
||||
contact.localConversationRecordKey.toVeilid(),
|
||||
TransformerCubit(
|
||||
ConversationCubit(
|
||||
activeAccountInfo: _activeAccountInfo,
|
||||
@ -86,7 +86,7 @@ class ActiveConversationsBlocMapCubit extends BlocMapCubit<TypedKey,
|
||||
return;
|
||||
}
|
||||
final contactIndex = contactList.indexWhere(
|
||||
(c) => c.value.remoteConversationRecordKey.toVeilid() == key);
|
||||
(c) => c.value.localConversationRecordKey.toVeilid() == key);
|
||||
if (contactIndex == -1) {
|
||||
await addState(key, AsyncValue.error('Contact not found'));
|
||||
return;
|
||||
|
@ -11,7 +11,7 @@ import '../../proto/proto.dart' as proto;
|
||||
import 'active_conversations_bloc_map_cubit.dart';
|
||||
import 'chat_list_cubit.dart';
|
||||
|
||||
// Map of remoteConversationRecordKey to MessagesCubit
|
||||
// Map of localConversationRecordKey to MessagesCubit
|
||||
// Wraps a MessagesCubit to stream the latest messages to the state
|
||||
// Automatically follows the state of a ActiveConversationsBlocMapCubit.
|
||||
class ActiveSingleContactChatBlocMapCubit extends BlocMapCubit<TypedKey,
|
||||
@ -33,7 +33,7 @@ class ActiveSingleContactChatBlocMapCubit extends BlocMapCubit<TypedKey,
|
||||
required proto.Conversation localConversation,
|
||||
required proto.Conversation remoteConversation}) async =>
|
||||
add(() => MapEntry(
|
||||
contact.remoteConversationRecordKey.toVeilid(),
|
||||
contact.localConversationRecordKey.toVeilid(),
|
||||
SingleContactMessagesCubit(
|
||||
activeAccountInfo: _activeAccountInfo,
|
||||
remoteIdentityPublicKey: contact.identityPublicKey.toVeilid(),
|
||||
@ -43,7 +43,6 @@ class ActiveSingleContactChatBlocMapCubit extends BlocMapCubit<TypedKey,
|
||||
contact.remoteConversationRecordKey.toVeilid(),
|
||||
localMessagesRecordKey: localConversation.messages.toVeilid(),
|
||||
remoteMessagesRecordKey: remoteConversation.messages.toVeilid(),
|
||||
reconciledChatRecord: chat.reconciledChatRecord.toVeilid(),
|
||||
)));
|
||||
|
||||
/// StateFollower /////////////////////////
|
||||
@ -61,7 +60,7 @@ class ActiveSingleContactChatBlocMapCubit extends BlocMapCubit<TypedKey,
|
||||
return;
|
||||
}
|
||||
final contactIndex = contactList.indexWhere(
|
||||
(c) => c.value.remoteConversationRecordKey.toVeilid() == key);
|
||||
(c) => c.value.localConversationRecordKey.toVeilid() == key);
|
||||
if (contactIndex == -1) {
|
||||
await addState(
|
||||
key, AsyncValue.error('Contact not found for conversation'));
|
||||
@ -76,7 +75,7 @@ class ActiveSingleContactChatBlocMapCubit extends BlocMapCubit<TypedKey,
|
||||
return;
|
||||
}
|
||||
final chatIndex = chatList.indexWhere(
|
||||
(c) => c.value.remoteConversationRecordKey.toVeilid() == key);
|
||||
(c) => c.value.localConversationRecordKey.toVeilid() == key);
|
||||
if (contactIndex == -1) {
|
||||
await addState(key, AsyncValue.error('Chat not found for conversation'));
|
||||
return;
|
||||
|
@ -2,6 +2,7 @@ import 'dart:async';
|
||||
|
||||
import 'package:bloc_advanced_tools/bloc_advanced_tools.dart';
|
||||
import 'package:fast_immutable_collections/fast_immutable_collections.dart';
|
||||
import 'package:fixnum/fixnum.dart';
|
||||
import 'package:veilid_support/veilid_support.dart';
|
||||
|
||||
import '../../account_manager/account_manager.dart';
|
||||
@ -21,8 +22,7 @@ class ChatListCubit extends DHTShortArrayCubit<proto.Chat>
|
||||
required ActiveAccountInfo activeAccountInfo,
|
||||
required proto.Account account,
|
||||
required this.activeChatCubit,
|
||||
}) : _activeAccountInfo = activeAccountInfo,
|
||||
super(
|
||||
}) : super(
|
||||
open: () => _open(activeAccountInfo, account),
|
||||
decodeElement: proto.Chat.fromBuffer);
|
||||
|
||||
@ -39,16 +39,30 @@ class ChatListCubit extends DHTShortArrayCubit<proto.Chat>
|
||||
return dhtRecord;
|
||||
}
|
||||
|
||||
Future<proto.ChatSettings> getDefaultChatSettings(
|
||||
proto.Contact contact) async {
|
||||
final pronouns = contact.editedProfile.pronouns.isEmpty
|
||||
? ''
|
||||
: ' (${contact.editedProfile.pronouns})';
|
||||
return proto.ChatSettings()
|
||||
..title = '${contact.editedProfile.name}$pronouns'
|
||||
..description = ''
|
||||
..defaultExpiration = Int64.ZERO;
|
||||
}
|
||||
|
||||
/// Create a new chat (singleton for single contact chats)
|
||||
Future<void> getOrCreateChatSingleContact({
|
||||
required TypedKey remoteConversationRecordKey,
|
||||
required proto.Contact contact,
|
||||
}) async {
|
||||
// Make local copy so we don't share the buffer
|
||||
final localConversationRecordKey =
|
||||
contact.localConversationRecordKey.toVeilid();
|
||||
final remoteConversationRecordKey =
|
||||
contact.remoteConversationRecordKey.toVeilid();
|
||||
|
||||
// Add Chat to account's list
|
||||
// if this fails, don't keep retrying, user can try again later
|
||||
await operateWrite((writer) async {
|
||||
final remoteConversationRecordKeyProto =
|
||||
remoteConversationRecordKey.toProto();
|
||||
|
||||
// See if we have added this chat already
|
||||
for (var i = 0; i < writer.length; i++) {
|
||||
final cbuf = await writer.getItem(i);
|
||||
@ -56,26 +70,18 @@ class ChatListCubit extends DHTShortArrayCubit<proto.Chat>
|
||||
throw Exception('Failed to get chat');
|
||||
}
|
||||
final c = proto.Chat.fromBuffer(cbuf);
|
||||
if (c.remoteConversationRecordKey == remoteConversationRecordKeyProto) {
|
||||
if (c.localConversationRecordKey ==
|
||||
contact.localConversationRecordKey) {
|
||||
// Nothing to do here
|
||||
return;
|
||||
}
|
||||
}
|
||||
final accountRecordKey = _activeAccountInfo
|
||||
.userLogin.accountRecordInfo.accountRecord.recordKey;
|
||||
|
||||
// Make a record that can store the reconciled version of the chat
|
||||
final reconciledChatRecord = await (await DHTLog.create(
|
||||
debugName:
|
||||
'ChatListCubit::getOrCreateChatSingleContact::ReconciledChat',
|
||||
parent: accountRecordKey))
|
||||
.scope((r) async => r.recordPointer);
|
||||
|
||||
// Create conversation type Chat
|
||||
// Create 1:1 conversation type Chat
|
||||
final chat = proto.Chat()
|
||||
..type = proto.ChatType.SINGLE_CONTACT
|
||||
..remoteConversationRecordKey = remoteConversationRecordKeyProto
|
||||
..reconciledChatRecord = reconciledChatRecord.toProto();
|
||||
..settings = await getDefaultChatSettings(contact)
|
||||
..localConversationRecordKey = localConversationRecordKey.toProto()
|
||||
..remoteConversationRecordKey = remoteConversationRecordKey.toProto();
|
||||
|
||||
// Add chat
|
||||
final added = await writer.tryAddItem(chat.writeToBuffer());
|
||||
@ -87,15 +93,16 @@ class ChatListCubit extends DHTShortArrayCubit<proto.Chat>
|
||||
|
||||
/// Delete a chat
|
||||
Future<void> deleteChat(
|
||||
{required TypedKey remoteConversationRecordKey}) async {
|
||||
final remoteConversationKey = remoteConversationRecordKey.toProto();
|
||||
{required TypedKey localConversationRecordKey}) async {
|
||||
final localConversationRecordKeyProto =
|
||||
localConversationRecordKey.toProto();
|
||||
|
||||
// Remove Chat from account's list
|
||||
// if this fails, don't keep retrying, user can try again later
|
||||
final deletedItem =
|
||||
// Ensure followers get their changes before we return
|
||||
await syncFollowers(() => operateWrite((writer) async {
|
||||
if (activeChatCubit.state == remoteConversationRecordKey) {
|
||||
if (activeChatCubit.state == localConversationRecordKey) {
|
||||
activeChatCubit.setActiveChat(null);
|
||||
}
|
||||
for (var i = 0; i < writer.length; i++) {
|
||||
@ -104,7 +111,8 @@ class ChatListCubit extends DHTShortArrayCubit<proto.Chat>
|
||||
if (c == null) {
|
||||
throw Exception('Failed to get chat');
|
||||
}
|
||||
if (c.remoteConversationRecordKey == remoteConversationKey) {
|
||||
if (c.localConversationRecordKey ==
|
||||
localConversationRecordKeyProto) {
|
||||
// Found the right chat
|
||||
await writer.removeItem(i);
|
||||
return c;
|
||||
@ -116,10 +124,10 @@ class ChatListCubit extends DHTShortArrayCubit<proto.Chat>
|
||||
// chat record now
|
||||
if (deletedItem != null) {
|
||||
try {
|
||||
await DHTRecordPool.instance.deleteRecord(
|
||||
deletedItem.reconciledChatRecord.toVeilid().recordKey);
|
||||
await SingleContactMessagesCubit.cleanupAndDeleteMessages(
|
||||
localConversationRecordKey: localConversationRecordKey);
|
||||
} on Exception catch (e) {
|
||||
log.debug('error removing reconciled chat record: $e', e);
|
||||
log.debug('error removing reconciled chat table: $e', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -132,10 +140,9 @@ class ChatListCubit extends DHTShortArrayCubit<proto.Chat>
|
||||
return IMap();
|
||||
}
|
||||
return IMap.fromIterable(stateValue,
|
||||
keyMapper: (e) => e.value.remoteConversationRecordKey.toVeilid(),
|
||||
keyMapper: (e) => e.value.localConversationRecordKey.toVeilid(),
|
||||
valueMapper: (e) => e.value);
|
||||
}
|
||||
|
||||
final ActiveChatCubit activeChatCubit;
|
||||
final ActiveAccountInfo _activeAccountInfo;
|
||||
}
|
||||
|
@ -24,9 +24,9 @@ class ChatSingleContactItemWidget extends StatelessWidget {
|
||||
BuildContext context,
|
||||
) {
|
||||
final activeChatCubit = context.watch<ActiveChatCubit>();
|
||||
final remoteConversationRecordKey =
|
||||
_contact.remoteConversationRecordKey.toVeilid();
|
||||
final selected = activeChatCubit.state == remoteConversationRecordKey;
|
||||
final localConversationRecordKey =
|
||||
_contact.localConversationRecordKey.toVeilid();
|
||||
final selected = activeChatCubit.state == localConversationRecordKey;
|
||||
|
||||
return SliderTile(
|
||||
key: ObjectKey(_contact),
|
||||
@ -38,7 +38,7 @@ class ChatSingleContactItemWidget extends StatelessWidget {
|
||||
icon: Icons.chat,
|
||||
onTap: () {
|
||||
singleFuture(activeChatCubit, () async {
|
||||
activeChatCubit.setActiveChat(remoteConversationRecordKey);
|
||||
activeChatCubit.setActiveChat(localConversationRecordKey);
|
||||
});
|
||||
},
|
||||
endActions: [
|
||||
@ -49,7 +49,7 @@ class ChatSingleContactItemWidget extends StatelessWidget {
|
||||
onPressed: (context) async {
|
||||
final chatListCubit = context.read<ChatListCubit>();
|
||||
await chatListCubit.deleteChat(
|
||||
remoteConversationRecordKey: remoteConversationRecordKey);
|
||||
localConversationRecordKey: localConversationRecordKey);
|
||||
})
|
||||
],
|
||||
);
|
||||
|
@ -20,7 +20,7 @@ class ChatSingleContactListWidget extends StatelessWidget {
|
||||
|
||||
return contactListV.builder((context, contactList) {
|
||||
final contactMap = IMap.fromIterable(contactList,
|
||||
keyMapper: (c) => c.value.remoteConversationRecordKey,
|
||||
keyMapper: (c) => c.value.localConversationRecordKey,
|
||||
valueMapper: (c) => c.value);
|
||||
|
||||
final chatListV = context.watch<ChatListCubit>().state;
|
||||
@ -36,7 +36,7 @@ class ChatSingleContactListWidget extends StatelessWidget {
|
||||
initialList: chatList.map((x) => x.value).toList(),
|
||||
itemBuilder: (c) {
|
||||
final contact =
|
||||
contactMap[c.remoteConversationRecordKey];
|
||||
contactMap[c.localConversationRecordKey];
|
||||
if (contact == null) {
|
||||
return const Text('...');
|
||||
}
|
||||
@ -49,7 +49,7 @@ class ChatSingleContactListWidget extends StatelessWidget {
|
||||
final lowerValue = value.toLowerCase();
|
||||
return chatList.map((x) => x.value).where((c) {
|
||||
final contact =
|
||||
contactMap[c.remoteConversationRecordKey];
|
||||
contactMap[c.localConversationRecordKey];
|
||||
if (contact == null) {
|
||||
return false;
|
||||
}
|
||||
|
@ -27,12 +27,12 @@ class ContactInvitationItemWidget extends StatelessWidget {
|
||||
@override
|
||||
// ignore: prefer_expression_function_bodies
|
||||
Widget build(BuildContext context) {
|
||||
// final remoteConversationKey =
|
||||
// contact.remoteConversationRecordKey.toVeilid();
|
||||
// final localConversationKey =
|
||||
// contact.localConversationRecordKey.toVeilid();
|
||||
|
||||
const selected =
|
||||
false; // xxx: eventually when we have selectable invitations:
|
||||
// activeContactCubit.state == remoteConversationRecordKey;
|
||||
// activeContactCubit.state == localConversationRecordKey;
|
||||
|
||||
final tileDisabled =
|
||||
disabled || context.watch<ContactInvitationListCubit>().isBusy;
|
||||
|
@ -76,8 +76,8 @@ class ContactListCubit extends DHTShortArrayCubit<proto.Contact> {
|
||||
if (item == null) {
|
||||
throw Exception('Failed to get contact');
|
||||
}
|
||||
if (item.remoteConversationRecordKey ==
|
||||
contact.remoteConversationRecordKey) {
|
||||
if (item.localConversationRecordKey ==
|
||||
contact.localConversationRecordKey) {
|
||||
await writer.removeItem(i);
|
||||
return item;
|
||||
}
|
||||
|
@ -29,11 +29,11 @@ class ContactItemWidget extends StatelessWidget {
|
||||
Widget build(
|
||||
BuildContext context,
|
||||
) {
|
||||
final remoteConversationKey =
|
||||
contact.remoteConversationRecordKey.toVeilid();
|
||||
final localConversationRecordKey =
|
||||
contact.localConversationRecordKey.toVeilid();
|
||||
|
||||
const selected = false; // xxx: eventually when we have selectable contacts:
|
||||
// activeContactCubit.state == remoteConversationRecordKey;
|
||||
// activeContactCubit.state == localConversationRecordKey;
|
||||
|
||||
final tileDisabled = disabled || context.watch<ContactListCubit>().isBusy;
|
||||
|
||||
@ -49,8 +49,7 @@ class ContactItemWidget extends StatelessWidget {
|
||||
// Start a chat
|
||||
final chatListCubit = context.read<ChatListCubit>();
|
||||
|
||||
await chatListCubit.getOrCreateChatSingleContact(
|
||||
remoteConversationRecordKey: remoteConversationKey);
|
||||
await chatListCubit.getOrCreateChatSingleContact(contact: contact);
|
||||
// Click over to chats
|
||||
if (context.mounted) {
|
||||
await MainPager.of(context)
|
||||
@ -69,7 +68,7 @@ class ContactItemWidget extends StatelessWidget {
|
||||
|
||||
// Remove any chats for this contact
|
||||
await chatListCubit.deleteChat(
|
||||
remoteConversationRecordKey: remoteConversationKey);
|
||||
localConversationRecordKey: localConversationRecordKey);
|
||||
|
||||
// Delete the contact itself
|
||||
await contactListCubit.deleteContact(contact: contact);
|
||||
|
@ -34,7 +34,7 @@ class HomeAccountReadyChatState extends State<HomeAccountReadyChat> {
|
||||
return const EmptyChatWidget();
|
||||
}
|
||||
return ChatComponent.builder(
|
||||
remoteConversationRecordKey: activeChatRemoteConversationKey);
|
||||
localConversationRecordKey: activeChatRemoteConversationKey);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -66,13 +66,13 @@ class _HomeAccountReadyMainState extends State<HomeAccountReadyMain> {
|
||||
Material(color: Colors.transparent, child: buildUserPanel()));
|
||||
|
||||
Widget buildTabletRightPane(BuildContext context) {
|
||||
final activeChatRemoteConversationKey =
|
||||
final activeChatLocalConversationKey =
|
||||
context.watch<ActiveChatCubit>().state;
|
||||
if (activeChatRemoteConversationKey == null) {
|
||||
if (activeChatLocalConversationKey == null) {
|
||||
return const EmptyChatWidget();
|
||||
}
|
||||
return ChatComponent.builder(
|
||||
remoteConversationRecordKey: activeChatRemoteConversationKey);
|
||||
localConversationRecordKey: activeChatLocalConversationKey);
|
||||
}
|
||||
|
||||
// ignore: prefer_expression_function_bodies
|
||||
|
@ -350,9 +350,9 @@ class Message_Text extends $pb.GeneratedMessage {
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'Message.Text', package: const $pb.PackageName(_omitMessageNames ? '' : 'veilidchat'), createEmptyInstance: create)
|
||||
..aOS(1, _omitFieldNames ? '' : 'text')
|
||||
..aOS(2, _omitFieldNames ? '' : 'topic')
|
||||
..aOM<$0.TypedKey>(3, _omitFieldNames ? '' : 'replyId', subBuilder: $0.TypedKey.create)
|
||||
..a<$core.List<$core.int>>(3, _omitFieldNames ? '' : 'replyId', $pb.PbFieldType.OY)
|
||||
..a<$fixnum.Int64>(4, _omitFieldNames ? '' : 'expiration', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO)
|
||||
..a<$fixnum.Int64>(5, _omitFieldNames ? '' : 'viewLimit', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO)
|
||||
..a<$core.int>(5, _omitFieldNames ? '' : 'viewLimit', $pb.PbFieldType.OU3)
|
||||
..pc<Attachment>(6, _omitFieldNames ? '' : 'attachments', $pb.PbFieldType.PM, subBuilder: Attachment.create)
|
||||
..hasRequiredFields = false
|
||||
;
|
||||
@ -397,15 +397,13 @@ class Message_Text extends $pb.GeneratedMessage {
|
||||
void clearTopic() => clearField(2);
|
||||
|
||||
@$pb.TagNumber(3)
|
||||
$0.TypedKey get replyId => $_getN(2);
|
||||
$core.List<$core.int> get replyId => $_getN(2);
|
||||
@$pb.TagNumber(3)
|
||||
set replyId($0.TypedKey v) { setField(3, v); }
|
||||
set replyId($core.List<$core.int> v) { $_setBytes(2, v); }
|
||||
@$pb.TagNumber(3)
|
||||
$core.bool hasReplyId() => $_has(2);
|
||||
@$pb.TagNumber(3)
|
||||
void clearReplyId() => clearField(3);
|
||||
@$pb.TagNumber(3)
|
||||
$0.TypedKey ensureReplyId() => $_ensure(2);
|
||||
|
||||
@$pb.TagNumber(4)
|
||||
$fixnum.Int64 get expiration => $_getI64(3);
|
||||
@ -417,9 +415,9 @@ class Message_Text extends $pb.GeneratedMessage {
|
||||
void clearExpiration() => clearField(4);
|
||||
|
||||
@$pb.TagNumber(5)
|
||||
$fixnum.Int64 get viewLimit => $_getI64(4);
|
||||
$core.int get viewLimit => $_getIZ(4);
|
||||
@$pb.TagNumber(5)
|
||||
set viewLimit($fixnum.Int64 v) { $_setInt64(4, v); }
|
||||
set viewLimit($core.int v) { $_setUnsignedInt32(4, v); }
|
||||
@$pb.TagNumber(5)
|
||||
$core.bool hasViewLimit() => $_has(4);
|
||||
@$pb.TagNumber(5)
|
||||
@ -517,13 +515,13 @@ class Message_ControlDelete extends $pb.GeneratedMessage {
|
||||
$core.List<$0.TypedKey> get ids => $_getList(0);
|
||||
}
|
||||
|
||||
class Message_ControlClear extends $pb.GeneratedMessage {
|
||||
factory Message_ControlClear() => create();
|
||||
Message_ControlClear._() : super();
|
||||
factory Message_ControlClear.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
|
||||
factory Message_ControlClear.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
|
||||
class Message_ControlErase extends $pb.GeneratedMessage {
|
||||
factory Message_ControlErase() => create();
|
||||
Message_ControlErase._() : super();
|
||||
factory Message_ControlErase.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
|
||||
factory Message_ControlErase.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
|
||||
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'Message.ControlClear', package: const $pb.PackageName(_omitMessageNames ? '' : 'veilidchat'), createEmptyInstance: create)
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'Message.ControlErase', package: const $pb.PackageName(_omitMessageNames ? '' : 'veilidchat'), createEmptyInstance: create)
|
||||
..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'timestamp', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO)
|
||||
..hasRequiredFields = false
|
||||
;
|
||||
@ -532,22 +530,22 @@ class Message_ControlClear extends $pb.GeneratedMessage {
|
||||
'Using this can add significant overhead to your binary. '
|
||||
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
|
||||
'Will be removed in next major version')
|
||||
Message_ControlClear clone() => Message_ControlClear()..mergeFromMessage(this);
|
||||
Message_ControlErase clone() => Message_ControlErase()..mergeFromMessage(this);
|
||||
@$core.Deprecated(
|
||||
'Using this can add significant overhead to your binary. '
|
||||
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
|
||||
'Will be removed in next major version')
|
||||
Message_ControlClear copyWith(void Function(Message_ControlClear) updates) => super.copyWith((message) => updates(message as Message_ControlClear)) as Message_ControlClear;
|
||||
Message_ControlErase copyWith(void Function(Message_ControlErase) updates) => super.copyWith((message) => updates(message as Message_ControlErase)) as Message_ControlErase;
|
||||
|
||||
$pb.BuilderInfo get info_ => _i;
|
||||
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static Message_ControlClear create() => Message_ControlClear._();
|
||||
Message_ControlClear createEmptyInstance() => create();
|
||||
static $pb.PbList<Message_ControlClear> createRepeated() => $pb.PbList<Message_ControlClear>();
|
||||
static Message_ControlErase create() => Message_ControlErase._();
|
||||
Message_ControlErase createEmptyInstance() => create();
|
||||
static $pb.PbList<Message_ControlErase> createRepeated() => $pb.PbList<Message_ControlErase>();
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static Message_ControlClear getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<Message_ControlClear>(create);
|
||||
static Message_ControlClear? _defaultInstance;
|
||||
static Message_ControlErase getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<Message_ControlErase>(create);
|
||||
static Message_ControlErase? _defaultInstance;
|
||||
|
||||
@$pb.TagNumber(1)
|
||||
$fixnum.Int64 get timestamp => $_getI64(0);
|
||||
@ -735,7 +733,7 @@ enum Message_Kind {
|
||||
text,
|
||||
secret,
|
||||
delete,
|
||||
clear_7,
|
||||
erase,
|
||||
settings,
|
||||
permissions,
|
||||
membership,
|
||||
@ -753,7 +751,7 @@ class Message extends $pb.GeneratedMessage {
|
||||
4 : Message_Kind.text,
|
||||
5 : Message_Kind.secret,
|
||||
6 : Message_Kind.delete,
|
||||
7 : Message_Kind.clear_7,
|
||||
7 : Message_Kind.erase,
|
||||
8 : Message_Kind.settings,
|
||||
9 : Message_Kind.permissions,
|
||||
10 : Message_Kind.membership,
|
||||
@ -762,13 +760,13 @@ class Message extends $pb.GeneratedMessage {
|
||||
};
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'Message', package: const $pb.PackageName(_omitMessageNames ? '' : 'veilidchat'), createEmptyInstance: create)
|
||||
..oo(0, [4, 5, 6, 7, 8, 9, 10, 11])
|
||||
..aOM<$0.TypedKey>(1, _omitFieldNames ? '' : 'id', subBuilder: $0.TypedKey.create)
|
||||
..a<$core.List<$core.int>>(1, _omitFieldNames ? '' : 'id', $pb.PbFieldType.OY)
|
||||
..aOM<$0.TypedKey>(2, _omitFieldNames ? '' : 'author', subBuilder: $0.TypedKey.create)
|
||||
..a<$fixnum.Int64>(3, _omitFieldNames ? '' : 'timestamp', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO)
|
||||
..aOM<Message_Text>(4, _omitFieldNames ? '' : 'text', subBuilder: Message_Text.create)
|
||||
..aOM<Message_Secret>(5, _omitFieldNames ? '' : 'secret', subBuilder: Message_Secret.create)
|
||||
..aOM<Message_ControlDelete>(6, _omitFieldNames ? '' : 'delete', subBuilder: Message_ControlDelete.create)
|
||||
..aOM<Message_ControlClear>(7, _omitFieldNames ? '' : 'clear', subBuilder: Message_ControlClear.create)
|
||||
..aOM<Message_ControlErase>(7, _omitFieldNames ? '' : 'erase', subBuilder: Message_ControlErase.create)
|
||||
..aOM<Message_ControlSettings>(8, _omitFieldNames ? '' : 'settings', subBuilder: Message_ControlSettings.create)
|
||||
..aOM<Message_ControlPermissions>(9, _omitFieldNames ? '' : 'permissions', subBuilder: Message_ControlPermissions.create)
|
||||
..aOM<Message_ControlMembership>(10, _omitFieldNames ? '' : 'membership', subBuilder: Message_ControlMembership.create)
|
||||
@ -802,15 +800,13 @@ class Message extends $pb.GeneratedMessage {
|
||||
void clearKind() => clearField($_whichOneof(0));
|
||||
|
||||
@$pb.TagNumber(1)
|
||||
$0.TypedKey get id => $_getN(0);
|
||||
$core.List<$core.int> get id => $_getN(0);
|
||||
@$pb.TagNumber(1)
|
||||
set id($0.TypedKey v) { setField(1, v); }
|
||||
set id($core.List<$core.int> v) { $_setBytes(0, v); }
|
||||
@$pb.TagNumber(1)
|
||||
$core.bool hasId() => $_has(0);
|
||||
@$pb.TagNumber(1)
|
||||
void clearId() => clearField(1);
|
||||
@$pb.TagNumber(1)
|
||||
$0.TypedKey ensureId() => $_ensure(0);
|
||||
|
||||
@$pb.TagNumber(2)
|
||||
$0.TypedKey get author => $_getN(1);
|
||||
@ -866,15 +862,15 @@ class Message extends $pb.GeneratedMessage {
|
||||
Message_ControlDelete ensureDelete() => $_ensure(5);
|
||||
|
||||
@$pb.TagNumber(7)
|
||||
Message_ControlClear get clear_7 => $_getN(6);
|
||||
Message_ControlErase get erase => $_getN(6);
|
||||
@$pb.TagNumber(7)
|
||||
set clear_7(Message_ControlClear v) { setField(7, v); }
|
||||
set erase(Message_ControlErase v) { setField(7, v); }
|
||||
@$pb.TagNumber(7)
|
||||
$core.bool hasClear_7() => $_has(6);
|
||||
$core.bool hasErase() => $_has(6);
|
||||
@$pb.TagNumber(7)
|
||||
void clearClear_7() => clearField(7);
|
||||
void clearErase() => clearField(7);
|
||||
@$pb.TagNumber(7)
|
||||
Message_ControlClear ensureClear_7() => $_ensure(6);
|
||||
Message_ControlErase ensureErase() => $_ensure(6);
|
||||
|
||||
@$pb.TagNumber(8)
|
||||
Message_ControlSettings get settings => $_getN(7);
|
||||
|
@ -159,20 +159,20 @@ final $typed_data.Uint8List chatSettingsDescriptor = $convert.base64Decode(
|
||||
const Message$json = {
|
||||
'1': 'Message',
|
||||
'2': [
|
||||
{'1': 'id', '3': 1, '4': 1, '5': 11, '6': '.veilid.TypedKey', '10': 'id'},
|
||||
{'1': 'id', '3': 1, '4': 1, '5': 12, '10': 'id'},
|
||||
{'1': 'author', '3': 2, '4': 1, '5': 11, '6': '.veilid.TypedKey', '10': 'author'},
|
||||
{'1': 'timestamp', '3': 3, '4': 1, '5': 4, '10': 'timestamp'},
|
||||
{'1': 'text', '3': 4, '4': 1, '5': 11, '6': '.veilidchat.Message.Text', '9': 0, '10': 'text'},
|
||||
{'1': 'secret', '3': 5, '4': 1, '5': 11, '6': '.veilidchat.Message.Secret', '9': 0, '10': 'secret'},
|
||||
{'1': 'delete', '3': 6, '4': 1, '5': 11, '6': '.veilidchat.Message.ControlDelete', '9': 0, '10': 'delete'},
|
||||
{'1': 'clear', '3': 7, '4': 1, '5': 11, '6': '.veilidchat.Message.ControlClear', '9': 0, '10': 'clear'},
|
||||
{'1': 'erase', '3': 7, '4': 1, '5': 11, '6': '.veilidchat.Message.ControlErase', '9': 0, '10': 'erase'},
|
||||
{'1': 'settings', '3': 8, '4': 1, '5': 11, '6': '.veilidchat.Message.ControlSettings', '9': 0, '10': 'settings'},
|
||||
{'1': 'permissions', '3': 9, '4': 1, '5': 11, '6': '.veilidchat.Message.ControlPermissions', '9': 0, '10': 'permissions'},
|
||||
{'1': 'membership', '3': 10, '4': 1, '5': 11, '6': '.veilidchat.Message.ControlMembership', '9': 0, '10': 'membership'},
|
||||
{'1': 'moderation', '3': 11, '4': 1, '5': 11, '6': '.veilidchat.Message.ControlModeration', '9': 0, '10': 'moderation'},
|
||||
{'1': 'signature', '3': 12, '4': 1, '5': 11, '6': '.veilid.Signature', '10': 'signature'},
|
||||
],
|
||||
'3': [Message_Text$json, Message_Secret$json, Message_ControlDelete$json, Message_ControlClear$json, Message_ControlSettings$json, Message_ControlPermissions$json, Message_ControlMembership$json, Message_ControlModeration$json],
|
||||
'3': [Message_Text$json, Message_Secret$json, Message_ControlDelete$json, Message_ControlErase$json, Message_ControlSettings$json, Message_ControlPermissions$json, Message_ControlMembership$json, Message_ControlModeration$json],
|
||||
'8': [
|
||||
{'1': 'kind'},
|
||||
],
|
||||
@ -183,12 +183,16 @@ const Message_Text$json = {
|
||||
'1': 'Text',
|
||||
'2': [
|
||||
{'1': 'text', '3': 1, '4': 1, '5': 9, '10': 'text'},
|
||||
{'1': 'topic', '3': 2, '4': 1, '5': 9, '10': 'topic'},
|
||||
{'1': 'reply_id', '3': 3, '4': 1, '5': 11, '6': '.veilid.TypedKey', '10': 'replyId'},
|
||||
{'1': 'topic', '3': 2, '4': 1, '5': 9, '9': 0, '10': 'topic', '17': true},
|
||||
{'1': 'reply_id', '3': 3, '4': 1, '5': 12, '9': 1, '10': 'replyId', '17': true},
|
||||
{'1': 'expiration', '3': 4, '4': 1, '5': 4, '10': 'expiration'},
|
||||
{'1': 'view_limit', '3': 5, '4': 1, '5': 4, '10': 'viewLimit'},
|
||||
{'1': 'view_limit', '3': 5, '4': 1, '5': 13, '10': 'viewLimit'},
|
||||
{'1': 'attachments', '3': 6, '4': 3, '5': 11, '6': '.veilidchat.Attachment', '10': 'attachments'},
|
||||
],
|
||||
'8': [
|
||||
{'1': '_topic'},
|
||||
{'1': '_reply_id'},
|
||||
],
|
||||
};
|
||||
|
||||
@$core.Deprecated('Use messageDescriptor instead')
|
||||
@ -209,8 +213,8 @@ const Message_ControlDelete$json = {
|
||||
};
|
||||
|
||||
@$core.Deprecated('Use messageDescriptor instead')
|
||||
const Message_ControlClear$json = {
|
||||
'1': 'ControlClear',
|
||||
const Message_ControlErase$json = {
|
||||
'1': 'ControlErase',
|
||||
'2': [
|
||||
{'1': 'timestamp', '3': 1, '4': 1, '5': 4, '10': 'timestamp'},
|
||||
],
|
||||
@ -251,32 +255,32 @@ const Message_ControlModeration$json = {
|
||||
|
||||
/// Descriptor for `Message`. Decode as a `google.protobuf.DescriptorProto`.
|
||||
final $typed_data.Uint8List messageDescriptor = $convert.base64Decode(
|
||||
'CgdNZXNzYWdlEiAKAmlkGAEgASgLMhAudmVpbGlkLlR5cGVkS2V5UgJpZBIoCgZhdXRob3IYAi'
|
||||
'ABKAsyEC52ZWlsaWQuVHlwZWRLZXlSBmF1dGhvchIcCgl0aW1lc3RhbXAYAyABKARSCXRpbWVz'
|
||||
'dGFtcBIuCgR0ZXh0GAQgASgLMhgudmVpbGlkY2hhdC5NZXNzYWdlLlRleHRIAFIEdGV4dBI0Cg'
|
||||
'ZzZWNyZXQYBSABKAsyGi52ZWlsaWRjaGF0Lk1lc3NhZ2UuU2VjcmV0SABSBnNlY3JldBI7CgZk'
|
||||
'ZWxldGUYBiABKAsyIS52ZWlsaWRjaGF0Lk1lc3NhZ2UuQ29udHJvbERlbGV0ZUgAUgZkZWxldG'
|
||||
'USOAoFY2xlYXIYByABKAsyIC52ZWlsaWRjaGF0Lk1lc3NhZ2UuQ29udHJvbENsZWFySABSBWNs'
|
||||
'ZWFyEkEKCHNldHRpbmdzGAggASgLMiMudmVpbGlkY2hhdC5NZXNzYWdlLkNvbnRyb2xTZXR0aW'
|
||||
'5nc0gAUghzZXR0aW5ncxJKCgtwZXJtaXNzaW9ucxgJIAEoCzImLnZlaWxpZGNoYXQuTWVzc2Fn'
|
||||
'ZS5Db250cm9sUGVybWlzc2lvbnNIAFILcGVybWlzc2lvbnMSRwoKbWVtYmVyc2hpcBgKIAEoCz'
|
||||
'IlLnZlaWxpZGNoYXQuTWVzc2FnZS5Db250cm9sTWVtYmVyc2hpcEgAUgptZW1iZXJzaGlwEkcK'
|
||||
'Cm1vZGVyYXRpb24YCyABKAsyJS52ZWlsaWRjaGF0Lk1lc3NhZ2UuQ29udHJvbE1vZGVyYXRpb2'
|
||||
'5IAFIKbW9kZXJhdGlvbhIvCglzaWduYXR1cmUYDCABKAsyES52ZWlsaWQuU2lnbmF0dXJlUglz'
|
||||
'aWduYXR1cmUa1gEKBFRleHQSEgoEdGV4dBgBIAEoCVIEdGV4dBIUCgV0b3BpYxgCIAEoCVIFdG'
|
||||
'9waWMSKwoIcmVwbHlfaWQYAyABKAsyEC52ZWlsaWQuVHlwZWRLZXlSB3JlcGx5SWQSHgoKZXhw'
|
||||
'aXJhdGlvbhgEIAEoBFIKZXhwaXJhdGlvbhIdCgp2aWV3X2xpbWl0GAUgASgEUgl2aWV3TGltaX'
|
||||
'QSOAoLYXR0YWNobWVudHMYBiADKAsyFi52ZWlsaWRjaGF0LkF0dGFjaG1lbnRSC2F0dGFjaG1l'
|
||||
'bnRzGkgKBlNlY3JldBIeCgpjaXBoZXJ0ZXh0GAEgASgMUgpjaXBoZXJ0ZXh0Eh4KCmV4cGlyYX'
|
||||
'Rpb24YAiABKARSCmV4cGlyYXRpb24aMwoNQ29udHJvbERlbGV0ZRIiCgNpZHMYASADKAsyEC52'
|
||||
'ZWlsaWQuVHlwZWRLZXlSA2lkcxosCgxDb250cm9sQ2xlYXISHAoJdGltZXN0YW1wGAEgASgEUg'
|
||||
'l0aW1lc3RhbXAaRwoPQ29udHJvbFNldHRpbmdzEjQKCHNldHRpbmdzGAEgASgLMhgudmVpbGlk'
|
||||
'Y2hhdC5DaGF0U2V0dGluZ3NSCHNldHRpbmdzGk8KEkNvbnRyb2xQZXJtaXNzaW9ucxI5CgtwZX'
|
||||
'JtaXNzaW9ucxgBIAEoCzIXLnZlaWxpZGNoYXQuUGVybWlzc2lvbnNSC3Blcm1pc3Npb25zGksK'
|
||||
'EUNvbnRyb2xNZW1iZXJzaGlwEjYKCm1lbWJlcnNoaXAYASABKAsyFi52ZWlsaWRjaGF0Lk1lbW'
|
||||
'JlcnNoaXBSCm1lbWJlcnNoaXAafQoRQ29udHJvbE1vZGVyYXRpb24SMwoMYWNjZXB0ZWRfaWRz'
|
||||
'GAEgAygLMhAudmVpbGlkLlR5cGVkS2V5UgthY2NlcHRlZElkcxIzCgxyZWplY3RlZF9pZHMYAi'
|
||||
'ADKAsyEC52ZWlsaWQuVHlwZWRLZXlSC3JlamVjdGVkSWRzQgYKBGtpbmQ=');
|
||||
'CgdNZXNzYWdlEg4KAmlkGAEgASgMUgJpZBIoCgZhdXRob3IYAiABKAsyEC52ZWlsaWQuVHlwZW'
|
||||
'RLZXlSBmF1dGhvchIcCgl0aW1lc3RhbXAYAyABKARSCXRpbWVzdGFtcBIuCgR0ZXh0GAQgASgL'
|
||||
'MhgudmVpbGlkY2hhdC5NZXNzYWdlLlRleHRIAFIEdGV4dBI0CgZzZWNyZXQYBSABKAsyGi52ZW'
|
||||
'lsaWRjaGF0Lk1lc3NhZ2UuU2VjcmV0SABSBnNlY3JldBI7CgZkZWxldGUYBiABKAsyIS52ZWls'
|
||||
'aWRjaGF0Lk1lc3NhZ2UuQ29udHJvbERlbGV0ZUgAUgZkZWxldGUSOAoFZXJhc2UYByABKAsyIC'
|
||||
'52ZWlsaWRjaGF0Lk1lc3NhZ2UuQ29udHJvbEVyYXNlSABSBWVyYXNlEkEKCHNldHRpbmdzGAgg'
|
||||
'ASgLMiMudmVpbGlkY2hhdC5NZXNzYWdlLkNvbnRyb2xTZXR0aW5nc0gAUghzZXR0aW5ncxJKCg'
|
||||
'twZXJtaXNzaW9ucxgJIAEoCzImLnZlaWxpZGNoYXQuTWVzc2FnZS5Db250cm9sUGVybWlzc2lv'
|
||||
'bnNIAFILcGVybWlzc2lvbnMSRwoKbWVtYmVyc2hpcBgKIAEoCzIlLnZlaWxpZGNoYXQuTWVzc2'
|
||||
'FnZS5Db250cm9sTWVtYmVyc2hpcEgAUgptZW1iZXJzaGlwEkcKCm1vZGVyYXRpb24YCyABKAsy'
|
||||
'JS52ZWlsaWRjaGF0Lk1lc3NhZ2UuQ29udHJvbE1vZGVyYXRpb25IAFIKbW9kZXJhdGlvbhIvCg'
|
||||
'lzaWduYXR1cmUYDCABKAsyES52ZWlsaWQuU2lnbmF0dXJlUglzaWduYXR1cmUa5QEKBFRleHQS'
|
||||
'EgoEdGV4dBgBIAEoCVIEdGV4dBIZCgV0b3BpYxgCIAEoCUgAUgV0b3BpY4gBARIeCghyZXBseV'
|
||||
'9pZBgDIAEoDEgBUgdyZXBseUlkiAEBEh4KCmV4cGlyYXRpb24YBCABKARSCmV4cGlyYXRpb24S'
|
||||
'HQoKdmlld19saW1pdBgFIAEoDVIJdmlld0xpbWl0EjgKC2F0dGFjaG1lbnRzGAYgAygLMhYudm'
|
||||
'VpbGlkY2hhdC5BdHRhY2htZW50UgthdHRhY2htZW50c0IICgZfdG9waWNCCwoJX3JlcGx5X2lk'
|
||||
'GkgKBlNlY3JldBIeCgpjaXBoZXJ0ZXh0GAEgASgMUgpjaXBoZXJ0ZXh0Eh4KCmV4cGlyYXRpb2'
|
||||
'4YAiABKARSCmV4cGlyYXRpb24aMwoNQ29udHJvbERlbGV0ZRIiCgNpZHMYASADKAsyEC52ZWls'
|
||||
'aWQuVHlwZWRLZXlSA2lkcxosCgxDb250cm9sRXJhc2USHAoJdGltZXN0YW1wGAEgASgEUgl0aW'
|
||||
'1lc3RhbXAaRwoPQ29udHJvbFNldHRpbmdzEjQKCHNldHRpbmdzGAEgASgLMhgudmVpbGlkY2hh'
|
||||
'dC5DaGF0U2V0dGluZ3NSCHNldHRpbmdzGk8KEkNvbnRyb2xQZXJtaXNzaW9ucxI5CgtwZXJtaX'
|
||||
'NzaW9ucxgBIAEoCzIXLnZlaWxpZGNoYXQuUGVybWlzc2lvbnNSC3Blcm1pc3Npb25zGksKEUNv'
|
||||
'bnRyb2xNZW1iZXJzaGlwEjYKCm1lbWJlcnNoaXAYASABKAsyFi52ZWlsaWRjaGF0Lk1lbWJlcn'
|
||||
'NoaXBSCm1lbWJlcnNoaXAafQoRQ29udHJvbE1vZGVyYXRpb24SMwoMYWNjZXB0ZWRfaWRzGAEg'
|
||||
'AygLMhAudmVpbGlkLlR5cGVkS2V5UgthY2NlcHRlZElkcxIzCgxyZWplY3RlZF9pZHMYAiADKA'
|
||||
'syEC52ZWlsaWQuVHlwZWRLZXlSC3JlamVjdGVkSWRzQgYKBGtpbmQ=');
|
||||
|
||||
@$core.Deprecated('Use reconciledMessageDescriptor instead')
|
||||
const ReconciledMessage$json = {
|
||||
|
@ -123,13 +123,13 @@ message Message {
|
||||
// Text of the message
|
||||
string text = 1;
|
||||
// Topic of the message / Content warning
|
||||
string topic = 2;
|
||||
optional string topic = 2;
|
||||
// Message id replied to
|
||||
veilid.TypedKey reply_id = 3;
|
||||
optional bytes reply_id = 3;
|
||||
// Message expiration timestamp
|
||||
uint64 expiration = 4;
|
||||
// Message view limit before deletion
|
||||
uint64 view_limit = 5;
|
||||
uint32 view_limit = 5;
|
||||
// Attachments on the message
|
||||
repeated Attachment attachments = 6;
|
||||
}
|
||||
@ -148,9 +148,9 @@ message Message {
|
||||
message ControlDelete {
|
||||
repeated veilid.TypedKey ids = 1;
|
||||
}
|
||||
// A 'clear' control message
|
||||
// An 'erase' control message
|
||||
// Deletes a set of messages from before some timestamp
|
||||
message ControlClear {
|
||||
message ControlErase {
|
||||
// The latest timestamp to delete messages before
|
||||
// If this is zero then all messages are cleared
|
||||
uint64 timestamp = 1;
|
||||
@ -181,10 +181,9 @@ message Message {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Hash of previous message from the same author,
|
||||
// including its previous hash.
|
||||
// Also serves as a unique key for the message.
|
||||
veilid.TypedKey id = 1;
|
||||
// Unique id for this author stream
|
||||
// Calculated from the hash of the previous message from this author
|
||||
bytes id = 1;
|
||||
// Author of the message (identity public key)
|
||||
veilid.TypedKey author = 2;
|
||||
// Time the message was sent according to sender
|
||||
@ -195,7 +194,7 @@ message Message {
|
||||
Text text = 4;
|
||||
Secret secret = 5;
|
||||
ControlDelete delete = 6;
|
||||
ControlClear clear = 7;
|
||||
ControlErase erase = 7;
|
||||
ControlSettings settings = 8;
|
||||
ControlPermissions permissions = 9;
|
||||
ControlMembership membership = 10;
|
||||
|
Loading…
Reference in New Issue
Block a user