mirror of
https://gitlab.com/veilid/veilidchat.git
synced 2025-05-03 14:55:02 -04:00
refactor and cleanup in prep for profile changing
This commit is contained in:
parent
87bb1657c7
commit
56d65442f4
49 changed files with 967 additions and 655 deletions
|
@ -27,6 +27,22 @@
|
||||||
"name": "Name",
|
"name": "Name",
|
||||||
"pronouns": "Pronouns"
|
"pronouns": "Pronouns"
|
||||||
},
|
},
|
||||||
|
"edit_account_page": {
|
||||||
|
"titlebar": "Edit Account",
|
||||||
|
"header": "Account Profile",
|
||||||
|
"update": "Update",
|
||||||
|
"instructions": "This information will be shared with the people you invite to connect with you on VeilidChat.",
|
||||||
|
"error": "Account modification error",
|
||||||
|
"name": "Name",
|
||||||
|
"pronouns": "Pronouns",
|
||||||
|
"remove_account": "Remove Account",
|
||||||
|
"delete_identity": "Delete Identity",
|
||||||
|
"remove_account_confirm": "Confirm Account Removal?",
|
||||||
|
"remove_account_description": "Remove account from this device only",
|
||||||
|
"delete_identity_description": "Delete identity and all messages completely",
|
||||||
|
"delete_identity_confirm_message": "This action is PERMANENT, and your identity will no longer be recoverable with the recovery key. This will not remove your messages you have sent from other people's devices.",
|
||||||
|
"confirm_are_you_sure": "Are you sure you want to do this?"
|
||||||
|
},
|
||||||
"show_recovery_key_page": {
|
"show_recovery_key_page": {
|
||||||
"titlebar": "Save Recovery Key",
|
"titlebar": "Save Recovery Key",
|
||||||
"instructions": "You must save this recovery key somewhere safe. This key is the ONLY way to recover your VeilidChat account in the event of a forgotton password or a lost, stolen, or compromised device.",
|
"instructions": "You must save this recovery key somewhere safe. This key is the ONLY way to recover your VeilidChat account in the event of a forgotton password or a lost, stolen, or compromised device.",
|
||||||
|
|
|
@ -3,13 +3,33 @@ import 'dart:async';
|
||||||
import 'package:veilid_support/veilid_support.dart';
|
import 'package:veilid_support/veilid_support.dart';
|
||||||
|
|
||||||
import '../../proto/proto.dart' as proto;
|
import '../../proto/proto.dart' as proto;
|
||||||
|
import '../account_manager.dart';
|
||||||
|
|
||||||
typedef AccountRecordState = proto.Account;
|
typedef AccountRecordState = proto.Account;
|
||||||
|
|
||||||
class AccountRecordCubit extends DefaultDHTRecordCubit<AccountRecordState> {
|
class AccountRecordCubit extends DefaultDHTRecordCubit<AccountRecordState> {
|
||||||
AccountRecordCubit({
|
AccountRecordCubit(
|
||||||
required super.open,
|
{required AccountRepository accountRepository,
|
||||||
}) : super(decodeState: proto.Account.fromBuffer);
|
required TypedKey superIdentityRecordKey})
|
||||||
|
: super(
|
||||||
|
decodeState: proto.Account.fromBuffer,
|
||||||
|
open: () => _open(accountRepository, superIdentityRecordKey));
|
||||||
|
|
||||||
|
static Future<DHTRecord> _open(AccountRepository accountRepository,
|
||||||
|
TypedKey superIdentityRecordKey) async {
|
||||||
|
final localAccount =
|
||||||
|
accountRepository.fetchLocalAccount(superIdentityRecordKey)!;
|
||||||
|
final userLogin = accountRepository.fetchUserLogin(superIdentityRecordKey)!;
|
||||||
|
|
||||||
|
// Record not yet open, do it
|
||||||
|
final pool = DHTRecordPool.instance;
|
||||||
|
final record = await pool.openRecordOwned(
|
||||||
|
userLogin.accountRecordInfo.accountRecord,
|
||||||
|
debugName: 'AccountRecordCubit::_open::AccountRecord',
|
||||||
|
parent: localAccount.superIdentity.currentInstance.recordKey);
|
||||||
|
|
||||||
|
return record;
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> close() async {
|
Future<void> close() async {
|
||||||
|
|
|
@ -15,11 +15,13 @@ class AccountRecordsBlocMapCubit extends BlocMapCubit<TypedKey,
|
||||||
: _accountRepository = accountRepository;
|
: _accountRepository = accountRepository;
|
||||||
|
|
||||||
// Add account record cubit
|
// Add account record cubit
|
||||||
Future<void> _addAccountRecordCubit({required UserLogin userLogin}) async =>
|
Future<void> _addAccountRecordCubit(
|
||||||
|
{required TypedKey superIdentityRecordKey}) async =>
|
||||||
add(() => MapEntry(
|
add(() => MapEntry(
|
||||||
userLogin.superIdentityRecordKey,
|
superIdentityRecordKey,
|
||||||
AccountRecordCubit(
|
AccountRecordCubit(
|
||||||
open: () => _accountRepository.openAccountRecord(userLogin))));
|
accountRepository: _accountRepository,
|
||||||
|
superIdentityRecordKey: superIdentityRecordKey)));
|
||||||
|
|
||||||
/// StateFollower /////////////////////////
|
/// StateFollower /////////////////////////
|
||||||
|
|
||||||
|
@ -28,7 +30,8 @@ class AccountRecordsBlocMapCubit extends BlocMapCubit<TypedKey,
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> updateState(TypedKey key, UserLogin value) async {
|
Future<void> updateState(TypedKey key, UserLogin value) async {
|
||||||
await _addAccountRecordCubit(userLogin: value);
|
await _addAccountRecordCubit(
|
||||||
|
superIdentityRecordKey: value.superIdentityRecordKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -1,23 +1,23 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:bloc/bloc.dart';
|
import 'package:bloc/bloc.dart';
|
||||||
import 'package:veilid_support/veilid_support.dart';
|
|
||||||
|
|
||||||
|
import '../models/models.dart';
|
||||||
import '../repository/account_repository.dart';
|
import '../repository/account_repository.dart';
|
||||||
|
|
||||||
class ActiveLocalAccountCubit extends Cubit<TypedKey?> {
|
class ActiveAccountInfoCubit extends Cubit<AccountInfo> {
|
||||||
ActiveLocalAccountCubit(AccountRepository accountRepository)
|
ActiveAccountInfoCubit(AccountRepository accountRepository)
|
||||||
: _accountRepository = accountRepository,
|
: _accountRepository = accountRepository,
|
||||||
super(accountRepository.getActiveLocalAccount()) {
|
super(accountRepository
|
||||||
|
.getAccountInfo(accountRepository.getActiveLocalAccount())) {
|
||||||
// Subscribe to streams
|
// Subscribe to streams
|
||||||
_accountRepositorySubscription = _accountRepository.stream.listen((change) {
|
_accountRepositorySubscription = _accountRepository.stream.listen((change) {
|
||||||
switch (change) {
|
switch (change) {
|
||||||
case AccountRepositoryChange.activeLocalAccount:
|
case AccountRepositoryChange.activeLocalAccount:
|
||||||
emit(_accountRepository.getActiveLocalAccount());
|
|
||||||
break;
|
|
||||||
// Ignore these
|
|
||||||
case AccountRepositoryChange.localAccounts:
|
case AccountRepositoryChange.localAccounts:
|
||||||
case AccountRepositoryChange.userLogins:
|
case AccountRepositoryChange.userLogins:
|
||||||
|
emit(accountRepository
|
||||||
|
.getAccountInfo(accountRepository.getActiveLocalAccount()));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
|
@ -1,5 +1,5 @@
|
||||||
export 'account_record_cubit.dart';
|
export 'account_record_cubit.dart';
|
||||||
export 'account_records_bloc_map_cubit.dart';
|
export 'account_records_bloc_map_cubit.dart';
|
||||||
export 'active_local_account_cubit.dart';
|
export 'active_account_info_cubit.dart';
|
||||||
export 'local_accounts_cubit.dart';
|
export 'local_accounts_cubit.dart';
|
||||||
export 'user_logins_cubit.dart';
|
export 'user_logins_cubit.dart';
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import 'package:meta/meta.dart';
|
import 'package:meta/meta.dart';
|
||||||
|
|
||||||
import 'active_account_info.dart';
|
import 'unlocked_account_info.dart';
|
||||||
|
|
||||||
enum AccountInfoStatus {
|
enum AccountInfoStatus {
|
||||||
noAccount,
|
noAccount,
|
||||||
|
@ -14,10 +14,10 @@ class AccountInfo {
|
||||||
const AccountInfo({
|
const AccountInfo({
|
||||||
required this.status,
|
required this.status,
|
||||||
required this.active,
|
required this.active,
|
||||||
required this.activeAccountInfo,
|
required this.unlockedAccountInfo,
|
||||||
});
|
});
|
||||||
|
|
||||||
final AccountInfoStatus status;
|
final AccountInfoStatus status;
|
||||||
final bool active;
|
final bool active;
|
||||||
final ActiveAccountInfo? activeAccountInfo;
|
final UnlockedAccountInfo? unlockedAccountInfo;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
export 'account_info.dart';
|
export 'account_info.dart';
|
||||||
export 'active_account_info.dart';
|
export 'unlocked_account_info.dart';
|
||||||
export 'encryption_key_type.dart';
|
export 'encryption_key_type.dart';
|
||||||
export 'local_account/local_account.dart';
|
export 'local_account/local_account.dart';
|
||||||
export 'new_profile_spec.dart';
|
export 'new_profile_spec.dart';
|
||||||
|
|
|
@ -7,8 +7,8 @@ import 'local_account/local_account.dart';
|
||||||
import 'user_login/user_login.dart';
|
import 'user_login/user_login.dart';
|
||||||
|
|
||||||
@immutable
|
@immutable
|
||||||
class ActiveAccountInfo {
|
class UnlockedAccountInfo {
|
||||||
const ActiveAccountInfo({
|
const UnlockedAccountInfo({
|
||||||
required this.localAccount,
|
required this.localAccount,
|
||||||
required this.userLogin,
|
required this.userLogin,
|
||||||
});
|
});
|
|
@ -45,19 +45,6 @@ class AccountRepository {
|
||||||
valueToJson: (val) => val?.toJson(),
|
valueToJson: (val) => val?.toJson(),
|
||||||
makeInitialValue: () => null);
|
makeInitialValue: () => null);
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////
|
|
||||||
/// Fields
|
|
||||||
|
|
||||||
final TableDBValue<IList<LocalAccount>> _localAccounts;
|
|
||||||
final TableDBValue<IList<UserLogin>> _userLogins;
|
|
||||||
final TableDBValue<TypedKey?> _activeLocalAccount;
|
|
||||||
final StreamController<AccountRepositoryChange> _streamController;
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////
|
|
||||||
/// Singleton initialization
|
|
||||||
|
|
||||||
static AccountRepository instance = AccountRepository._();
|
|
||||||
|
|
||||||
Future<void> init() async {
|
Future<void> init() async {
|
||||||
await _localAccounts.get();
|
await _localAccounts.get();
|
||||||
await _userLogins.get();
|
await _userLogins.get();
|
||||||
|
@ -71,12 +58,10 @@ class AccountRepository {
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////
|
||||||
/// Streams
|
/// Public Interface
|
||||||
|
///
|
||||||
Stream<AccountRepositoryChange> get stream => _streamController.stream;
|
Stream<AccountRepositoryChange> get stream => _streamController.stream;
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////
|
|
||||||
/// Selectors
|
|
||||||
IList<LocalAccount> getLocalAccounts() => _localAccounts.value;
|
IList<LocalAccount> getLocalAccounts() => _localAccounts.value;
|
||||||
TypedKey? getActiveLocalAccount() => _activeLocalAccount.value;
|
TypedKey? getActiveLocalAccount() => _activeLocalAccount.value;
|
||||||
IList<UserLogin> getUserLogins() => _userLogins.value;
|
IList<UserLogin> getUserLogins() => _userLogins.value;
|
||||||
|
@ -116,7 +101,7 @@ class AccountRepository {
|
||||||
return const AccountInfo(
|
return const AccountInfo(
|
||||||
status: AccountInfoStatus.noAccount,
|
status: AccountInfoStatus.noAccount,
|
||||||
active: false,
|
active: false,
|
||||||
activeAccountInfo: null);
|
unlockedAccountInfo: null);
|
||||||
}
|
}
|
||||||
superIdentityRecordKey = activeLocalAccount;
|
superIdentityRecordKey = activeLocalAccount;
|
||||||
}
|
}
|
||||||
|
@ -129,7 +114,7 @@ class AccountRepository {
|
||||||
return AccountInfo(
|
return AccountInfo(
|
||||||
status: AccountInfoStatus.noAccount,
|
status: AccountInfoStatus.noAccount,
|
||||||
active: active,
|
active: active,
|
||||||
activeAccountInfo: null);
|
unlockedAccountInfo: null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// See if we've logged into this account or if it is locked
|
// See if we've logged into this account or if it is locked
|
||||||
|
@ -139,21 +124,18 @@ class AccountRepository {
|
||||||
return AccountInfo(
|
return AccountInfo(
|
||||||
status: AccountInfoStatus.accountLocked,
|
status: AccountInfoStatus.accountLocked,
|
||||||
active: active,
|
active: active,
|
||||||
activeAccountInfo: null);
|
unlockedAccountInfo: null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Got account, decrypted and decoded
|
// Got account, decrypted and decoded
|
||||||
return AccountInfo(
|
return AccountInfo(
|
||||||
status: AccountInfoStatus.accountReady,
|
status: AccountInfoStatus.accountReady,
|
||||||
active: active,
|
active: active,
|
||||||
activeAccountInfo:
|
unlockedAccountInfo:
|
||||||
ActiveAccountInfo(localAccount: localAccount, userLogin: userLogin),
|
UnlockedAccountInfo(localAccount: localAccount, userLogin: userLogin),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////
|
|
||||||
/// Mutators
|
|
||||||
|
|
||||||
/// Reorder accounts
|
/// Reorder accounts
|
||||||
Future<void> reorderAccount(int oldIndex, int newIndex) async {
|
Future<void> reorderAccount(int oldIndex, int newIndex) async {
|
||||||
final localAccounts = await _localAccounts.get();
|
final localAccounts = await _localAccounts.get();
|
||||||
|
@ -168,15 +150,14 @@ class AccountRepository {
|
||||||
/// Creates a new super identity, an identity instance, an account associated
|
/// Creates a new super identity, an identity instance, an account associated
|
||||||
/// with the identity instance, stores the account in the identity key and
|
/// with the identity instance, stores the account in the identity key and
|
||||||
/// then logs into that account with no password set at this time
|
/// then logs into that account with no password set at this time
|
||||||
Future<SecretKey> createWithNewSuperIdentity(
|
Future<SecretKey> createWithNewSuperIdentity(proto.Profile newProfile) async {
|
||||||
NewProfileSpec newProfileSpec) async {
|
|
||||||
log.debug('Creating super identity');
|
log.debug('Creating super identity');
|
||||||
final wsi = await WritableSuperIdentity.create();
|
final wsi = await WritableSuperIdentity.create();
|
||||||
try {
|
try {
|
||||||
final localAccount = await _newLocalAccount(
|
final localAccount = await _newLocalAccount(
|
||||||
superIdentity: wsi.superIdentity,
|
superIdentity: wsi.superIdentity,
|
||||||
identitySecret: wsi.identitySecret,
|
identitySecret: wsi.identitySecret,
|
||||||
newProfileSpec: newProfileSpec);
|
newProfile: newProfile);
|
||||||
|
|
||||||
// Log in the new account by default with no pin
|
// Log in the new account by default with no pin
|
||||||
final ok = await login(
|
final ok = await login(
|
||||||
|
@ -190,85 +171,18 @@ class AccountRepository {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new Account associated with the current instance of the identity
|
Future<void> editAccountProfile(
|
||||||
/// Adds a logged-out LocalAccount to track its existence on this device
|
TypedKey superIdentityRecordKey, proto.Profile newProfile) async {
|
||||||
Future<LocalAccount> _newLocalAccount(
|
log.debug('Editing profile for $superIdentityRecordKey');
|
||||||
{required SuperIdentity superIdentity,
|
|
||||||
required SecretKey identitySecret,
|
|
||||||
required NewProfileSpec newProfileSpec,
|
|
||||||
EncryptionKeyType encryptionKeyType = EncryptionKeyType.none,
|
|
||||||
String encryptionKey = ''}) async {
|
|
||||||
log.debug('Creating new local account');
|
|
||||||
|
|
||||||
final localAccounts = await _localAccounts.get();
|
final localAccounts = await _localAccounts.get();
|
||||||
|
|
||||||
// Add account with profile to DHT
|
final newLocalAccounts = localAccounts.replaceFirstWhere(
|
||||||
await superIdentity.currentInstance.addAccount(
|
(x) => x.superIdentity.recordKey == superIdentityRecordKey,
|
||||||
superRecordKey: superIdentity.recordKey,
|
(localAccount) => localAccount!.copyWith(name: newProfile.name));
|
||||||
secretKey: identitySecret,
|
|
||||||
accountKey: veilidChatAccountKey,
|
|
||||||
createAccountCallback: (parent) async {
|
|
||||||
// Make empty contact list
|
|
||||||
log.debug('Creating contacts list');
|
|
||||||
final contactList = await (await DHTShortArray.create(
|
|
||||||
debugName: 'AccountRepository::_newLocalAccount::Contacts',
|
|
||||||
parent: parent))
|
|
||||||
.scope((r) async => r.recordPointer);
|
|
||||||
|
|
||||||
// Make empty contact invitation record list
|
|
||||||
log.debug('Creating contact invitation records list');
|
|
||||||
final contactInvitationRecords = await (await DHTShortArray.create(
|
|
||||||
debugName:
|
|
||||||
'AccountRepository::_newLocalAccount::ContactInvitations',
|
|
||||||
parent: parent))
|
|
||||||
.scope((r) async => r.recordPointer);
|
|
||||||
|
|
||||||
// Make empty chat record list
|
|
||||||
log.debug('Creating chat records list');
|
|
||||||
final chatRecords = await (await DHTShortArray.create(
|
|
||||||
debugName: 'AccountRepository::_newLocalAccount::Chats',
|
|
||||||
parent: parent))
|
|
||||||
.scope((r) async => r.recordPointer);
|
|
||||||
|
|
||||||
// Make account object
|
|
||||||
final account = proto.Account()
|
|
||||||
..profile = (proto.Profile()
|
|
||||||
..name = newProfileSpec.name
|
|
||||||
..pronouns = newProfileSpec.pronouns)
|
|
||||||
..contactList = contactList.toProto()
|
|
||||||
..contactInvitationRecords = contactInvitationRecords.toProto()
|
|
||||||
..chatList = chatRecords.toProto();
|
|
||||||
return account.writeToBuffer();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Encrypt identitySecret with key
|
|
||||||
final identitySecretBytes = await encryptionKeyType.encryptSecretToBytes(
|
|
||||||
secret: identitySecret,
|
|
||||||
cryptoKind: superIdentity.currentInstance.recordKey.kind,
|
|
||||||
encryptionKey: encryptionKey,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Create local account object
|
|
||||||
// Does not contain the account key or its secret
|
|
||||||
// as that is not to be persisted, and only pulled from the identity key
|
|
||||||
// and optionally decrypted with the unlock password
|
|
||||||
final localAccount = LocalAccount(
|
|
||||||
superIdentity: superIdentity,
|
|
||||||
identitySecretBytes: identitySecretBytes,
|
|
||||||
encryptionKeyType: encryptionKeyType,
|
|
||||||
biometricsEnabled: false,
|
|
||||||
hiddenAccount: false,
|
|
||||||
name: newProfileSpec.name,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Add local account object to internal store
|
|
||||||
final newLocalAccounts = localAccounts.add(localAccount);
|
|
||||||
|
|
||||||
await _localAccounts.set(newLocalAccounts);
|
await _localAccounts.set(newLocalAccounts);
|
||||||
_streamController.add(AccountRepositoryChange.localAccounts);
|
_streamController.add(AccountRepositoryChange.localAccounts);
|
||||||
|
|
||||||
// Return local account object
|
|
||||||
return localAccount;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Remove an account and wipe the messages for this account from this device
|
/// Remove an account and wipe the messages for this account from this device
|
||||||
|
@ -310,6 +224,88 @@ class AccountRepository {
|
||||||
_streamController.add(AccountRepositoryChange.activeLocalAccount);
|
_streamController.add(AccountRepositoryChange.activeLocalAccount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////
|
||||||
|
/// Internal Implementation
|
||||||
|
|
||||||
|
/// Creates a new Account associated with the current instance of the identity
|
||||||
|
/// Adds a logged-out LocalAccount to track its existence on this device
|
||||||
|
Future<LocalAccount> _newLocalAccount(
|
||||||
|
{required SuperIdentity superIdentity,
|
||||||
|
required SecretKey identitySecret,
|
||||||
|
required proto.Profile newProfile,
|
||||||
|
EncryptionKeyType encryptionKeyType = EncryptionKeyType.none,
|
||||||
|
String encryptionKey = ''}) async {
|
||||||
|
log.debug('Creating new local account');
|
||||||
|
|
||||||
|
final localAccounts = await _localAccounts.get();
|
||||||
|
|
||||||
|
// Add account with profile to DHT
|
||||||
|
await superIdentity.currentInstance.addAccount(
|
||||||
|
superRecordKey: superIdentity.recordKey,
|
||||||
|
secretKey: identitySecret,
|
||||||
|
accountKey: veilidChatAccountKey,
|
||||||
|
createAccountCallback: (parent) async {
|
||||||
|
// Make empty contact list
|
||||||
|
log.debug('Creating contacts list');
|
||||||
|
final contactList = await (await DHTShortArray.create(
|
||||||
|
debugName: 'AccountRepository::_newLocalAccount::Contacts',
|
||||||
|
parent: parent))
|
||||||
|
.scope((r) async => r.recordPointer);
|
||||||
|
|
||||||
|
// Make empty contact invitation record list
|
||||||
|
log.debug('Creating contact invitation records list');
|
||||||
|
final contactInvitationRecords = await (await DHTShortArray.create(
|
||||||
|
debugName:
|
||||||
|
'AccountRepository::_newLocalAccount::ContactInvitations',
|
||||||
|
parent: parent))
|
||||||
|
.scope((r) async => r.recordPointer);
|
||||||
|
|
||||||
|
// Make empty chat record list
|
||||||
|
log.debug('Creating chat records list');
|
||||||
|
final chatRecords = await (await DHTShortArray.create(
|
||||||
|
debugName: 'AccountRepository::_newLocalAccount::Chats',
|
||||||
|
parent: parent))
|
||||||
|
.scope((r) async => r.recordPointer);
|
||||||
|
|
||||||
|
// Make account object
|
||||||
|
final account = proto.Account()
|
||||||
|
..profile = newProfile
|
||||||
|
..contactList = contactList.toProto()
|
||||||
|
..contactInvitationRecords = contactInvitationRecords.toProto()
|
||||||
|
..chatList = chatRecords.toProto();
|
||||||
|
return account.writeToBuffer();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Encrypt identitySecret with key
|
||||||
|
final identitySecretBytes = await encryptionKeyType.encryptSecretToBytes(
|
||||||
|
secret: identitySecret,
|
||||||
|
cryptoKind: superIdentity.currentInstance.recordKey.kind,
|
||||||
|
encryptionKey: encryptionKey,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Create local account object
|
||||||
|
// Does not contain the account key or its secret
|
||||||
|
// as that is not to be persisted, and only pulled from the identity key
|
||||||
|
// and optionally decrypted with the unlock password
|
||||||
|
final localAccount = LocalAccount(
|
||||||
|
superIdentity: superIdentity,
|
||||||
|
identitySecretBytes: identitySecretBytes,
|
||||||
|
encryptionKeyType: encryptionKeyType,
|
||||||
|
biometricsEnabled: false,
|
||||||
|
hiddenAccount: false,
|
||||||
|
name: newProfile.name,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Add local account object to internal store
|
||||||
|
final newLocalAccounts = localAccounts.add(localAccount);
|
||||||
|
|
||||||
|
await _localAccounts.set(newLocalAccounts);
|
||||||
|
_streamController.add(AccountRepositoryChange.localAccounts);
|
||||||
|
|
||||||
|
// Return local account object
|
||||||
|
return localAccount;
|
||||||
|
}
|
||||||
|
|
||||||
Future<bool> _decryptedLogin(
|
Future<bool> _decryptedLogin(
|
||||||
SuperIdentity superIdentity, SecretKey identitySecret) async {
|
SuperIdentity superIdentity, SecretKey identitySecret) async {
|
||||||
// Verify identity secret works and return the valid cryptosystem
|
// Verify identity secret works and return the valid cryptosystem
|
||||||
|
@ -402,16 +398,13 @@ class AccountRepository {
|
||||||
_streamController.add(AccountRepositoryChange.userLogins);
|
_streamController.add(AccountRepositoryChange.userLogins);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<DHTRecord> openAccountRecord(UserLogin userLogin) async {
|
//////////////////////////////////////////////////////////////
|
||||||
final localAccount = fetchLocalAccount(userLogin.superIdentityRecordKey)!;
|
/// Fields
|
||||||
|
|
||||||
// Record not yet open, do it
|
static AccountRepository instance = AccountRepository._();
|
||||||
final pool = DHTRecordPool.instance;
|
|
||||||
final record = await pool.openRecordOwned(
|
|
||||||
userLogin.accountRecordInfo.accountRecord,
|
|
||||||
debugName: 'AccountRepository::openAccountRecord::AccountRecord',
|
|
||||||
parent: localAccount.superIdentity.currentInstance.recordKey);
|
|
||||||
|
|
||||||
return record;
|
final TableDBValue<IList<LocalAccount>> _localAccounts;
|
||||||
}
|
final TableDBValue<IList<UserLogin>> _userLogins;
|
||||||
|
final TableDBValue<TypedKey?> _activeLocalAccount;
|
||||||
|
final StreamController<AccountRepositoryChange> _streamController;
|
||||||
}
|
}
|
||||||
|
|
163
lib/account_manager/views/edit_account_page.dart
Normal file
163
lib/account_manager/views/edit_account_page.dart
Normal file
|
@ -0,0 +1,163 @@
|
||||||
|
import 'package:awesome_extensions/awesome_extensions.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:flutter_form_builder/flutter_form_builder.dart';
|
||||||
|
import 'package:flutter_translate/flutter_translate.dart';
|
||||||
|
import 'package:go_router/go_router.dart';
|
||||||
|
import 'package:protobuf/protobuf.dart';
|
||||||
|
import 'package:veilid_support/veilid_support.dart';
|
||||||
|
|
||||||
|
import '../../contacts/cubits/contact_list_cubit.dart';
|
||||||
|
import '../../conversation/conversation.dart';
|
||||||
|
import '../../layout/default_app_bar.dart';
|
||||||
|
import '../../proto/proto.dart' as proto;
|
||||||
|
import '../../theme/theme.dart';
|
||||||
|
import '../../tools/tools.dart';
|
||||||
|
import '../../veilid_processor/veilid_processor.dart';
|
||||||
|
import '../account_manager.dart';
|
||||||
|
import 'profile_edit_form.dart';
|
||||||
|
|
||||||
|
class EditAccountPage extends StatefulWidget {
|
||||||
|
const EditAccountPage(
|
||||||
|
{required this.superIdentityRecordKey,
|
||||||
|
required this.existingProfile,
|
||||||
|
super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State createState() => _EditAccountPageState();
|
||||||
|
|
||||||
|
final TypedKey superIdentityRecordKey;
|
||||||
|
final proto.Profile existingProfile;
|
||||||
|
@override
|
||||||
|
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||||
|
super.debugFillProperties(properties);
|
||||||
|
properties
|
||||||
|
..add(DiagnosticsProperty<TypedKey>(
|
||||||
|
'superIdentityRecordKey', superIdentityRecordKey))
|
||||||
|
..add(DiagnosticsProperty<proto.Profile>(
|
||||||
|
'existingProfile', existingProfile));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _EditAccountPageState extends State<EditAccountPage> {
|
||||||
|
final _formKey = GlobalKey<FormBuilderState>();
|
||||||
|
bool _isInAsyncCall = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||||
|
await changeWindowSetup(
|
||||||
|
TitleBarStyle.normal, OrientationCapability.portraitOnly);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _editAccountForm(BuildContext context,
|
||||||
|
{required Future<void> Function(GlobalKey<FormBuilderState>)
|
||||||
|
onSubmit}) =>
|
||||||
|
EditProfileForm(
|
||||||
|
header: translate('edit_account_page.header'),
|
||||||
|
instructions: translate('edit_account_page.instructions'),
|
||||||
|
submitText: translate('edit_account_page.update'),
|
||||||
|
submitDisabledText: translate('button.waiting_for_network'),
|
||||||
|
onSubmit: onSubmit);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final displayModalHUD = _isInAsyncCall;
|
||||||
|
final accountRecordCubit = context.read<AccountRecordCubit>();
|
||||||
|
final activeConversationsBlocMapCubit =
|
||||||
|
context.read<ActiveConversationsBlocMapCubit>();
|
||||||
|
final contactListCubit = context.read<ContactListCubit>();
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
// resizeToAvoidBottomInset: false,
|
||||||
|
appBar: DefaultAppBar(
|
||||||
|
title: Text(translate('edit_account_page.titlebar')),
|
||||||
|
actions: [
|
||||||
|
const SignalStrengthMeterWidget(),
|
||||||
|
IconButton(
|
||||||
|
icon: const Icon(Icons.settings),
|
||||||
|
tooltip: translate('menu.settings_tooltip'),
|
||||||
|
onPressed: () async {
|
||||||
|
await GoRouterHelper(context).push('/settings');
|
||||||
|
})
|
||||||
|
]),
|
||||||
|
body: _editAccountForm(
|
||||||
|
context,
|
||||||
|
onSubmit: (formKey) async {
|
||||||
|
// dismiss the keyboard by unfocusing the textfield
|
||||||
|
FocusScope.of(context).unfocus();
|
||||||
|
|
||||||
|
try {
|
||||||
|
final name = _formKey.currentState!
|
||||||
|
.fields[EditProfileForm.formFieldName]!.value as String;
|
||||||
|
final pronouns = _formKey
|
||||||
|
.currentState!
|
||||||
|
.fields[EditProfileForm.formFieldPronouns]!
|
||||||
|
.value as String? ??
|
||||||
|
'';
|
||||||
|
final newProfile = widget.existingProfile.deepCopy()
|
||||||
|
..name = name
|
||||||
|
..pronouns = pronouns;
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
_isInAsyncCall = true;
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
// Update account profile DHT record
|
||||||
|
final newValue = await accountRecordCubit.record
|
||||||
|
.tryWriteProtobuf(proto.Account.fromBuffer, newProfile);
|
||||||
|
if (newValue != null) {
|
||||||
|
if (context.mounted) {
|
||||||
|
await showErrorModal(
|
||||||
|
context,
|
||||||
|
translate('edit_account_page.error'),
|
||||||
|
'Failed to update profile online');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update local account profile
|
||||||
|
await AccountRepository.instance.editAccountProfile(
|
||||||
|
widget.superIdentityRecordKey, newProfile);
|
||||||
|
|
||||||
|
// Update all conversations with new profile
|
||||||
|
final updates = <Future<void>>[];
|
||||||
|
for (final key in activeConversationsBlocMapCubit.state.keys) {
|
||||||
|
await activeConversationsBlocMapCubit.operateAsync(key,
|
||||||
|
closure: (cubit) async {
|
||||||
|
final newLocalConversation =
|
||||||
|
cubit.state.asData?.value.localConversation.deepCopy();
|
||||||
|
if (newLocalConversation != null) {
|
||||||
|
newLocalConversation.profile = newProfile;
|
||||||
|
updates.add(cubit.input.writeLocalConversation(
|
||||||
|
conversation: newLocalConversation));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for updates
|
||||||
|
await updates.wait;
|
||||||
|
|
||||||
|
// XXX: how to do this for non-chat contacts?
|
||||||
|
} finally {
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
_isInAsyncCall = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} on Exception catch (e) {
|
||||||
|
if (context.mounted) {
|
||||||
|
await showErrorModal(context,
|
||||||
|
translate('edit_account_page.error'), 'Exception: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
).paddingSymmetric(horizontal: 24, vertical: 8),
|
||||||
|
).withModalHUD(context, displayModalHUD);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,30 +1,28 @@
|
||||||
import 'package:awesome_extensions/awesome_extensions.dart';
|
import 'package:awesome_extensions/awesome_extensions.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:flutter_form_builder/flutter_form_builder.dart';
|
import 'package:flutter_form_builder/flutter_form_builder.dart';
|
||||||
import 'package:flutter_translate/flutter_translate.dart';
|
import 'package:flutter_translate/flutter_translate.dart';
|
||||||
import 'package:form_builder_validators/form_builder_validators.dart';
|
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
|
|
||||||
import '../../layout/default_app_bar.dart';
|
import '../../layout/default_app_bar.dart';
|
||||||
|
import '../../proto/proto.dart' as proto;
|
||||||
import '../../theme/theme.dart';
|
import '../../theme/theme.dart';
|
||||||
import '../../tools/tools.dart';
|
import '../../tools/tools.dart';
|
||||||
import '../../veilid_processor/veilid_processor.dart';
|
import '../../veilid_processor/veilid_processor.dart';
|
||||||
import '../account_manager.dart';
|
import '../account_manager.dart';
|
||||||
|
import 'profile_edit_form.dart';
|
||||||
|
|
||||||
class NewAccountPage extends StatefulWidget {
|
class NewAccountPage extends StatefulWidget {
|
||||||
const NewAccountPage({super.key});
|
const NewAccountPage({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
NewAccountPageState createState() => NewAccountPageState();
|
State createState() => _NewAccountPageState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class NewAccountPageState extends State<NewAccountPage> {
|
class _NewAccountPageState extends State<NewAccountPage> {
|
||||||
final _formKey = GlobalKey<FormBuilderState>();
|
final _formKey = GlobalKey<FormBuilderState>();
|
||||||
late bool isInAsyncCall = false;
|
bool _isInAsyncCall = false;
|
||||||
static const String formFieldName = 'name';
|
|
||||||
static const String formFieldPronouns = 'pronouns';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
@ -47,70 +45,17 @@ class NewAccountPageState extends State<NewAccountPage> {
|
||||||
false;
|
false;
|
||||||
final canSubmit = networkReady;
|
final canSubmit = networkReady;
|
||||||
|
|
||||||
return FormBuilder(
|
return EditProfileForm(
|
||||||
key: _formKey,
|
header: translate('new_account_page.header'),
|
||||||
child: ListView(
|
instructions: translate('new_account_page.instructions'),
|
||||||
children: [
|
submitText: translate('new_account_page.create'),
|
||||||
Text(translate('new_account_page.header'))
|
submitDisabledText: translate('button.waiting_for_network'),
|
||||||
.textStyle(context.headlineSmall)
|
onSubmit: !canSubmit ? null : onSubmit);
|
||||||
.paddingSymmetric(vertical: 16),
|
|
||||||
FormBuilderTextField(
|
|
||||||
autofocus: true,
|
|
||||||
name: formFieldName,
|
|
||||||
decoration:
|
|
||||||
InputDecoration(labelText: translate('account.form_name')),
|
|
||||||
maxLength: 64,
|
|
||||||
// The validator receives the text that the user has entered.
|
|
||||||
validator: FormBuilderValidators.compose([
|
|
||||||
FormBuilderValidators.required(),
|
|
||||||
]),
|
|
||||||
textInputAction: TextInputAction.next,
|
|
||||||
),
|
|
||||||
FormBuilderTextField(
|
|
||||||
name: formFieldPronouns,
|
|
||||||
maxLength: 64,
|
|
||||||
decoration:
|
|
||||||
InputDecoration(labelText: translate('account.form_pronouns')),
|
|
||||||
textInputAction: TextInputAction.next,
|
|
||||||
),
|
|
||||||
Row(children: [
|
|
||||||
const Spacer(),
|
|
||||||
Text(translate('new_account_page.instructions'))
|
|
||||||
.toCenter()
|
|
||||||
.flexible(flex: 6),
|
|
||||||
const Spacer(),
|
|
||||||
]).paddingSymmetric(vertical: 4),
|
|
||||||
ElevatedButton(
|
|
||||||
onPressed: !canSubmit
|
|
||||||
? null
|
|
||||||
: () async {
|
|
||||||
if (_formKey.currentState?.saveAndValidate() ?? false) {
|
|
||||||
setState(() {
|
|
||||||
isInAsyncCall = true;
|
|
||||||
});
|
|
||||||
try {
|
|
||||||
await onSubmit(_formKey);
|
|
||||||
} finally {
|
|
||||||
if (mounted) {
|
|
||||||
setState(() {
|
|
||||||
isInAsyncCall = false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
child: Text(translate(!networkReady
|
|
||||||
? 'button.waiting_for_network'
|
|
||||||
: 'new_account_page.create')),
|
|
||||||
).paddingSymmetric(vertical: 4).alignAtCenterRight(),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final displayModalHUD = isInAsyncCall;
|
final displayModalHUD = _isInAsyncCall;
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
// resizeToAvoidBottomInset: false,
|
// resizeToAvoidBottomInset: false,
|
||||||
|
@ -120,7 +65,7 @@ class NewAccountPageState extends State<NewAccountPage> {
|
||||||
const SignalStrengthMeterWidget(),
|
const SignalStrengthMeterWidget(),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Icons.settings),
|
icon: const Icon(Icons.settings),
|
||||||
tooltip: translate('app_bar.settings_tooltip'),
|
tooltip: translate('menu.settings_tooltip'),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
await GoRouterHelper(context).push('/settings');
|
await GoRouterHelper(context).push('/settings');
|
||||||
})
|
})
|
||||||
|
@ -132,19 +77,33 @@ class NewAccountPageState extends State<NewAccountPage> {
|
||||||
FocusScope.of(context).unfocus();
|
FocusScope.of(context).unfocus();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final name =
|
final name = _formKey.currentState!
|
||||||
_formKey.currentState!.fields[formFieldName]!.value as String;
|
.fields[EditProfileForm.formFieldName]!.value as String;
|
||||||
final pronouns = _formKey.currentState!.fields[formFieldPronouns]!
|
final pronouns = _formKey
|
||||||
|
.currentState!
|
||||||
|
.fields[EditProfileForm.formFieldPronouns]!
|
||||||
.value as String? ??
|
.value as String? ??
|
||||||
'';
|
'';
|
||||||
final newProfileSpec =
|
final newProfile = proto.Profile()
|
||||||
NewProfileSpec(name: name, pronouns: pronouns);
|
..name = name
|
||||||
|
..pronouns = pronouns;
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
_isInAsyncCall = true;
|
||||||
|
});
|
||||||
|
try {
|
||||||
final superSecret = await AccountRepository.instance
|
final superSecret = await AccountRepository.instance
|
||||||
.createWithNewSuperIdentity(newProfileSpec);
|
.createWithNewSuperIdentity(newProfile);
|
||||||
|
GoRouterHelper(context).pushReplacement(
|
||||||
GoRouterHelper(context).pushReplacement('/new_account/recovery_key',
|
'/new_account/recovery_key',
|
||||||
extra: superSecret);
|
extra: superSecret);
|
||||||
|
} finally {
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
_isInAsyncCall = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
} on Exception catch (e) {
|
} on Exception catch (e) {
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
await showErrorModal(context, translate('new_account_page.error'),
|
await showErrorModal(context, translate('new_account_page.error'),
|
||||||
|
@ -155,10 +114,4 @@ class NewAccountPageState extends State<NewAccountPage> {
|
||||||
).paddingSymmetric(horizontal: 24, vertical: 8),
|
).paddingSymmetric(horizontal: 24, vertical: 8),
|
||||||
).withModalHUD(context, displayModalHUD);
|
).withModalHUD(context, displayModalHUD);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
|
||||||
super.debugFillProperties(properties);
|
|
||||||
properties.add(DiagnosticsProperty<bool>('isInAsyncCall', isInAsyncCall));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
106
lib/account_manager/views/profile_edit_form.dart
Normal file
106
lib/account_manager/views/profile_edit_form.dart
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
import 'package:awesome_extensions/awesome_extensions.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_form_builder/flutter_form_builder.dart';
|
||||||
|
import 'package:flutter_translate/flutter_translate.dart';
|
||||||
|
import 'package:form_builder_validators/form_builder_validators.dart';
|
||||||
|
|
||||||
|
class EditProfileForm extends StatefulWidget {
|
||||||
|
const EditProfileForm({
|
||||||
|
required this.header,
|
||||||
|
required this.instructions,
|
||||||
|
required this.submitText,
|
||||||
|
required this.submitDisabledText,
|
||||||
|
super.key,
|
||||||
|
this.onSubmit,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State createState() => _EditProfileFormState();
|
||||||
|
|
||||||
|
final String header;
|
||||||
|
final String instructions;
|
||||||
|
final Future<void> Function(GlobalKey<FormBuilderState>)? onSubmit;
|
||||||
|
final String submitText;
|
||||||
|
final String submitDisabledText;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||||
|
super.debugFillProperties(properties);
|
||||||
|
properties
|
||||||
|
..add(StringProperty('header', header))
|
||||||
|
..add(StringProperty('instructions', instructions))
|
||||||
|
..add(ObjectFlagProperty<
|
||||||
|
Future<void> Function(
|
||||||
|
GlobalKey<FormBuilderState> p1)?>.has('onSubmit', onSubmit))
|
||||||
|
..add(StringProperty('submitText', submitText))
|
||||||
|
..add(StringProperty('submitDisabledText', submitDisabledText));
|
||||||
|
}
|
||||||
|
|
||||||
|
static const String formFieldName = 'name';
|
||||||
|
static const String formFieldPronouns = 'pronouns';
|
||||||
|
}
|
||||||
|
|
||||||
|
class _EditProfileFormState extends State<EditProfileForm> {
|
||||||
|
final _formKey = GlobalKey<FormBuilderState>();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _editProfileForm(
|
||||||
|
BuildContext context,
|
||||||
|
) =>
|
||||||
|
FormBuilder(
|
||||||
|
key: _formKey,
|
||||||
|
child: ListView(
|
||||||
|
children: [
|
||||||
|
Text(widget.header)
|
||||||
|
.textStyle(context.headlineSmall)
|
||||||
|
.paddingSymmetric(vertical: 16),
|
||||||
|
FormBuilderTextField(
|
||||||
|
autofocus: true,
|
||||||
|
name: EditProfileForm.formFieldName,
|
||||||
|
decoration:
|
||||||
|
InputDecoration(labelText: translate('account.form_name')),
|
||||||
|
maxLength: 64,
|
||||||
|
// The validator receives the text that the user has entered.
|
||||||
|
validator: FormBuilderValidators.compose([
|
||||||
|
FormBuilderValidators.required(),
|
||||||
|
]),
|
||||||
|
textInputAction: TextInputAction.next,
|
||||||
|
),
|
||||||
|
FormBuilderTextField(
|
||||||
|
name: EditProfileForm.formFieldPronouns,
|
||||||
|
maxLength: 64,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: translate('account.form_pronouns')),
|
||||||
|
textInputAction: TextInputAction.next,
|
||||||
|
),
|
||||||
|
Row(children: [
|
||||||
|
const Spacer(),
|
||||||
|
Text(widget.instructions).toCenter().flexible(flex: 6),
|
||||||
|
const Spacer(),
|
||||||
|
]).paddingSymmetric(vertical: 4),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: widget.onSubmit == null
|
||||||
|
? null
|
||||||
|
: () async {
|
||||||
|
if (_formKey.currentState?.saveAndValidate() ?? false) {
|
||||||
|
await widget.onSubmit!(_formKey);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: Text((widget.onSubmit == null)
|
||||||
|
? widget.submitDisabledText
|
||||||
|
: widget.submitText),
|
||||||
|
).paddingSymmetric(vertical: 4).alignAtCenterRight(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => _editProfileForm(
|
||||||
|
context,
|
||||||
|
);
|
||||||
|
}
|
|
@ -48,7 +48,7 @@ class ShowRecoveryKeyPageState extends State<ShowRecoveryKeyPage> {
|
||||||
const SignalStrengthMeterWidget(),
|
const SignalStrengthMeterWidget(),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Icons.settings),
|
icon: const Icon(Icons.settings),
|
||||||
tooltip: translate('app_bar.settings_tooltip'),
|
tooltip: translate('menu.settings_tooltip'),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
await GoRouterHelper(context).push('/settings');
|
await GoRouterHelper(context).push('/settings');
|
||||||
})
|
})
|
||||||
|
|
|
@ -122,9 +122,9 @@ class VeilidChatApp extends StatelessWidget {
|
||||||
create: (context) =>
|
create: (context) =>
|
||||||
UserLoginsCubit(AccountRepository.instance),
|
UserLoginsCubit(AccountRepository.instance),
|
||||||
),
|
),
|
||||||
BlocProvider<ActiveLocalAccountCubit>(
|
BlocProvider<ActiveAccountInfoCubit>(
|
||||||
create: (context) =>
|
create: (context) =>
|
||||||
ActiveLocalAccountCubit(AccountRepository.instance),
|
ActiveAccountInfoCubit(AccountRepository.instance),
|
||||||
),
|
),
|
||||||
BlocProvider<PreferencesCubit>(
|
BlocProvider<PreferencesCubit>(
|
||||||
create: (context) =>
|
create: (context) =>
|
||||||
|
|
|
@ -1,13 +1,19 @@
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:veilid_support/veilid_support.dart';
|
import 'package:veilid_support/veilid_support.dart';
|
||||||
|
|
||||||
|
import '../../router/router.dart';
|
||||||
|
|
||||||
// XXX: if we ever want to have more than one chat 'open', we should put the
|
// XXX: if we ever want to have more than one chat 'open', we should put the
|
||||||
// operations and state for that here.
|
// operations and state for that here.
|
||||||
|
|
||||||
class ActiveChatCubit extends Cubit<TypedKey?> {
|
class ActiveChatCubit extends Cubit<TypedKey?> {
|
||||||
ActiveChatCubit(super.initialState);
|
ActiveChatCubit(super.initialState, {required RouterCubit routerCubit})
|
||||||
|
: _routerCubit = routerCubit;
|
||||||
|
|
||||||
void setActiveChat(TypedKey? activeChatLocalConversationRecordKey) {
|
void setActiveChat(TypedKey? activeChatLocalConversationRecordKey) {
|
||||||
emit(activeChatLocalConversationRecordKey);
|
emit(activeChatLocalConversationRecordKey);
|
||||||
|
_routerCubit.setHasActiveChat(activeChatLocalConversationRecordKey != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final RouterCubit _routerCubit;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ import 'package:scroll_to_index/scroll_to_index.dart';
|
||||||
import 'package:veilid_support/veilid_support.dart';
|
import 'package:veilid_support/veilid_support.dart';
|
||||||
|
|
||||||
import '../../account_manager/account_manager.dart';
|
import '../../account_manager/account_manager.dart';
|
||||||
import '../../chat_list/chat_list.dart';
|
import '../../conversation/conversation.dart';
|
||||||
import '../../proto/proto.dart' as proto;
|
import '../../proto/proto.dart' as proto;
|
||||||
import '../models/chat_component_state.dart';
|
import '../models/chat_component_state.dart';
|
||||||
import '../models/message_state.dart';
|
import '../models/message_state.dart';
|
||||||
|
@ -44,7 +44,7 @@ class ChatComponentCubit extends Cubit<ChatComponentState> {
|
||||||
|
|
||||||
// ignore: prefer_constructors_over_static_methods
|
// ignore: prefer_constructors_over_static_methods
|
||||||
static ChatComponentCubit singleContact(
|
static ChatComponentCubit singleContact(
|
||||||
{required ActiveAccountInfo activeAccountInfo,
|
{required UnlockedAccountInfo activeAccountInfo,
|
||||||
required proto.Account accountRecordInfo,
|
required proto.Account accountRecordInfo,
|
||||||
required ActiveConversationState activeConversationState,
|
required ActiveConversationState activeConversationState,
|
||||||
required SingleContactMessagesCubit messagesCubit}) {
|
required SingleContactMessagesCubit messagesCubit}) {
|
||||||
|
|
|
@ -50,7 +50,7 @@ typedef SingleContactMessagesState = AsyncValue<WindowState<MessageState>>;
|
||||||
// Builds the reconciled chat record from the local and remote conversation keys
|
// Builds the reconciled chat record from the local and remote conversation keys
|
||||||
class SingleContactMessagesCubit extends Cubit<SingleContactMessagesState> {
|
class SingleContactMessagesCubit extends Cubit<SingleContactMessagesState> {
|
||||||
SingleContactMessagesCubit({
|
SingleContactMessagesCubit({
|
||||||
required ActiveAccountInfo activeAccountInfo,
|
required UnlockedAccountInfo activeAccountInfo,
|
||||||
required TypedKey remoteIdentityPublicKey,
|
required TypedKey remoteIdentityPublicKey,
|
||||||
required TypedKey localConversationRecordKey,
|
required TypedKey localConversationRecordKey,
|
||||||
required TypedKey localMessagesRecordKey,
|
required TypedKey localMessagesRecordKey,
|
||||||
|
@ -402,7 +402,7 @@ class SingleContactMessagesCubit extends Cubit<SingleContactMessagesState> {
|
||||||
/////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
final WaitSet<void> _initWait = WaitSet();
|
final WaitSet<void> _initWait = WaitSet();
|
||||||
final ActiveAccountInfo _activeAccountInfo;
|
final UnlockedAccountInfo _activeAccountInfo;
|
||||||
final TypedKey _remoteIdentityPublicKey;
|
final TypedKey _remoteIdentityPublicKey;
|
||||||
final TypedKey _localConversationRecordKey;
|
final TypedKey _localConversationRecordKey;
|
||||||
final TypedKey _localMessagesRecordKey;
|
final TypedKey _localMessagesRecordKey;
|
||||||
|
|
|
@ -9,7 +9,7 @@ import 'package:flutter_chat_ui/flutter_chat_ui.dart';
|
||||||
import 'package:veilid_support/veilid_support.dart';
|
import 'package:veilid_support/veilid_support.dart';
|
||||||
|
|
||||||
import '../../account_manager/account_manager.dart';
|
import '../../account_manager/account_manager.dart';
|
||||||
import '../../chat_list/chat_list.dart';
|
import '../../conversation/conversation.dart';
|
||||||
import '../../theme/theme.dart';
|
import '../../theme/theme.dart';
|
||||||
import '../chat.dart';
|
import '../chat.dart';
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ class ChatComponentWidget extends StatelessWidget {
|
||||||
{required TypedKey localConversationRecordKey, Key? key}) =>
|
{required TypedKey localConversationRecordKey, Key? key}) =>
|
||||||
Builder(builder: (context) {
|
Builder(builder: (context) {
|
||||||
// Get all watched dependendies
|
// Get all watched dependendies
|
||||||
final activeAccountInfo = context.watch<ActiveAccountInfo>();
|
final activeAccountInfo = context.watch<UnlockedAccountInfo>();
|
||||||
final accountRecordInfo =
|
final accountRecordInfo =
|
||||||
context.watch<AccountRecordCubit>().state.asData?.value;
|
context.watch<AccountRecordCubit>().state.asData?.value;
|
||||||
if (accountRecordInfo == null) {
|
if (accountRecordInfo == null) {
|
||||||
|
|
|
@ -19,15 +19,15 @@ typedef ChatListCubitState = DHTShortArrayBusyState<proto.Chat>;
|
||||||
class ChatListCubit extends DHTShortArrayCubit<proto.Chat>
|
class ChatListCubit extends DHTShortArrayCubit<proto.Chat>
|
||||||
with StateMapFollowable<ChatListCubitState, TypedKey, proto.Chat> {
|
with StateMapFollowable<ChatListCubitState, TypedKey, proto.Chat> {
|
||||||
ChatListCubit({
|
ChatListCubit({
|
||||||
required ActiveAccountInfo activeAccountInfo,
|
required UnlockedAccountInfo unlockedAccountInfo,
|
||||||
required proto.Account account,
|
required proto.Account account,
|
||||||
required this.activeChatCubit,
|
required this.activeChatCubit,
|
||||||
}) : super(
|
}) : super(
|
||||||
open: () => _open(activeAccountInfo, account),
|
open: () => _open(unlockedAccountInfo, account),
|
||||||
decodeElement: proto.Chat.fromBuffer);
|
decodeElement: proto.Chat.fromBuffer);
|
||||||
|
|
||||||
static Future<DHTShortArray> _open(
|
static Future<DHTShortArray> _open(
|
||||||
ActiveAccountInfo activeAccountInfo, proto.Account account) async {
|
UnlockedAccountInfo activeAccountInfo, proto.Account account) async {
|
||||||
final accountRecordKey =
|
final accountRecordKey =
|
||||||
activeAccountInfo.userLogin.accountRecordInfo.accountRecord.recordKey;
|
activeAccountInfo.userLogin.accountRecordInfo.accountRecord.recordKey;
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1 @@
|
||||||
export 'active_single_contact_chat_bloc_map_cubit.dart';
|
|
||||||
export 'active_conversations_bloc_map_cubit.dart';
|
|
||||||
export 'chat_list_cubit.dart';
|
export 'chat_list_cubit.dart';
|
||||||
|
|
|
@ -36,16 +36,16 @@ class ContactInvitationListCubit
|
||||||
StateMapFollowable<ContactInvitiationListState, TypedKey,
|
StateMapFollowable<ContactInvitiationListState, TypedKey,
|
||||||
proto.ContactInvitationRecord> {
|
proto.ContactInvitationRecord> {
|
||||||
ContactInvitationListCubit({
|
ContactInvitationListCubit({
|
||||||
required ActiveAccountInfo activeAccountInfo,
|
required UnlockedAccountInfo unlockedAccountInfo,
|
||||||
required proto.Account account,
|
required proto.Account account,
|
||||||
}) : _activeAccountInfo = activeAccountInfo,
|
}) : _activeAccountInfo = unlockedAccountInfo,
|
||||||
_account = account,
|
_account = account,
|
||||||
super(
|
super(
|
||||||
open: () => _open(activeAccountInfo, account),
|
open: () => _open(unlockedAccountInfo, account),
|
||||||
decodeElement: proto.ContactInvitationRecord.fromBuffer);
|
decodeElement: proto.ContactInvitationRecord.fromBuffer);
|
||||||
|
|
||||||
static Future<DHTShortArray> _open(
|
static Future<DHTShortArray> _open(
|
||||||
ActiveAccountInfo activeAccountInfo, proto.Account account) async {
|
UnlockedAccountInfo activeAccountInfo, proto.Account account) async {
|
||||||
final accountRecordKey =
|
final accountRecordKey =
|
||||||
activeAccountInfo.userLogin.accountRecordInfo.accountRecord.recordKey;
|
activeAccountInfo.userLogin.accountRecordInfo.accountRecord.recordKey;
|
||||||
|
|
||||||
|
@ -318,6 +318,6 @@ class ContactInvitationListCubit
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
final ActiveAccountInfo _activeAccountInfo;
|
final UnlockedAccountInfo _activeAccountInfo;
|
||||||
final proto.Account _account;
|
final proto.Account _account;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ class ContactRequestInboxCubit
|
||||||
// : super.value(decodeState: proto.SignedContactResponse.fromBuffer);
|
// : super.value(decodeState: proto.SignedContactResponse.fromBuffer);
|
||||||
|
|
||||||
static Future<DHTRecord> _open(
|
static Future<DHTRecord> _open(
|
||||||
{required ActiveAccountInfo activeAccountInfo,
|
{required UnlockedAccountInfo activeAccountInfo,
|
||||||
required proto.ContactInvitationRecord contactInvitationRecord}) async {
|
required proto.ContactInvitationRecord contactInvitationRecord}) async {
|
||||||
final pool = DHTRecordPool.instance;
|
final pool = DHTRecordPool.instance;
|
||||||
final accountRecordKey =
|
final accountRecordKey =
|
||||||
|
@ -42,6 +42,6 @@ class ContactRequestInboxCubit
|
||||||
defaultSubkey: 1);
|
defaultSubkey: 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
final ActiveAccountInfo activeAccountInfo;
|
final UnlockedAccountInfo activeAccountInfo;
|
||||||
final proto.ContactInvitationRecord contactInvitationRecord;
|
final proto.ContactInvitationRecord contactInvitationRecord;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ import 'package:meta/meta.dart';
|
||||||
import 'package:veilid_support/veilid_support.dart';
|
import 'package:veilid_support/veilid_support.dart';
|
||||||
|
|
||||||
import '../../account_manager/account_manager.dart';
|
import '../../account_manager/account_manager.dart';
|
||||||
import '../../contacts/contacts.dart';
|
import '../../conversation/conversation.dart';
|
||||||
import '../../proto/proto.dart' as proto;
|
import '../../proto/proto.dart' as proto;
|
||||||
import '../../tools/tools.dart';
|
import '../../tools/tools.dart';
|
||||||
import '../models/accepted_contact.dart';
|
import '../models/accepted_contact.dart';
|
||||||
|
@ -25,7 +25,7 @@ class InvitationStatus extends Equatable {
|
||||||
class WaitingInvitationCubit extends AsyncTransformerCubit<InvitationStatus,
|
class WaitingInvitationCubit extends AsyncTransformerCubit<InvitationStatus,
|
||||||
proto.SignedContactResponse?> {
|
proto.SignedContactResponse?> {
|
||||||
WaitingInvitationCubit(ContactRequestInboxCubit super.input,
|
WaitingInvitationCubit(ContactRequestInboxCubit super.input,
|
||||||
{required ActiveAccountInfo activeAccountInfo,
|
{required UnlockedAccountInfo activeAccountInfo,
|
||||||
required proto.Account account,
|
required proto.Account account,
|
||||||
required proto.ContactInvitationRecord contactInvitationRecord})
|
required proto.ContactInvitationRecord contactInvitationRecord})
|
||||||
: super(
|
: super(
|
||||||
|
@ -37,7 +37,7 @@ class WaitingInvitationCubit extends AsyncTransformerCubit<InvitationStatus,
|
||||||
|
|
||||||
static Future<AsyncValue<InvitationStatus>> _transform(
|
static Future<AsyncValue<InvitationStatus>> _transform(
|
||||||
proto.SignedContactResponse? signedContactResponse,
|
proto.SignedContactResponse? signedContactResponse,
|
||||||
{required ActiveAccountInfo activeAccountInfo,
|
{required UnlockedAccountInfo activeAccountInfo,
|
||||||
required proto.Account account,
|
required proto.Account account,
|
||||||
required proto.ContactInvitationRecord contactInvitationRecord}) async {
|
required proto.ContactInvitationRecord contactInvitationRecord}) async {
|
||||||
if (signedContactResponse == null) {
|
if (signedContactResponse == null) {
|
||||||
|
|
|
@ -18,7 +18,7 @@ class WaitingInvitationsBlocMapCubit extends BlocMapCubit<TypedKey,
|
||||||
StateMapFollower<DHTShortArrayBusyState<proto.ContactInvitationRecord>,
|
StateMapFollower<DHTShortArrayBusyState<proto.ContactInvitationRecord>,
|
||||||
TypedKey, proto.ContactInvitationRecord> {
|
TypedKey, proto.ContactInvitationRecord> {
|
||||||
WaitingInvitationsBlocMapCubit(
|
WaitingInvitationsBlocMapCubit(
|
||||||
{required this.activeAccountInfo, required this.account});
|
{required this.unlockedAccountInfo, required this.account});
|
||||||
|
|
||||||
Future<void> _addWaitingInvitation(
|
Future<void> _addWaitingInvitation(
|
||||||
{required proto.ContactInvitationRecord
|
{required proto.ContactInvitationRecord
|
||||||
|
@ -27,9 +27,9 @@ class WaitingInvitationsBlocMapCubit extends BlocMapCubit<TypedKey,
|
||||||
contactInvitationRecord.contactRequestInbox.recordKey.toVeilid(),
|
contactInvitationRecord.contactRequestInbox.recordKey.toVeilid(),
|
||||||
WaitingInvitationCubit(
|
WaitingInvitationCubit(
|
||||||
ContactRequestInboxCubit(
|
ContactRequestInboxCubit(
|
||||||
activeAccountInfo: activeAccountInfo,
|
activeAccountInfo: unlockedAccountInfo,
|
||||||
contactInvitationRecord: contactInvitationRecord),
|
contactInvitationRecord: contactInvitationRecord),
|
||||||
activeAccountInfo: activeAccountInfo,
|
activeAccountInfo: unlockedAccountInfo,
|
||||||
account: account,
|
account: account,
|
||||||
contactInvitationRecord: contactInvitationRecord)));
|
contactInvitationRecord: contactInvitationRecord)));
|
||||||
|
|
||||||
|
@ -43,6 +43,6 @@ class WaitingInvitationsBlocMapCubit extends BlocMapCubit<TypedKey,
|
||||||
_addWaitingInvitation(contactInvitationRecord: value);
|
_addWaitingInvitation(contactInvitationRecord: value);
|
||||||
|
|
||||||
////
|
////
|
||||||
final ActiveAccountInfo activeAccountInfo;
|
final UnlockedAccountInfo unlockedAccountInfo;
|
||||||
final proto.Account account;
|
final proto.Account account;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ import 'package:meta/meta.dart';
|
||||||
import 'package:veilid_support/veilid_support.dart';
|
import 'package:veilid_support/veilid_support.dart';
|
||||||
|
|
||||||
import '../../account_manager/account_manager.dart';
|
import '../../account_manager/account_manager.dart';
|
||||||
import '../../contacts/contacts.dart';
|
import '../../conversation/conversation.dart';
|
||||||
import '../../proto/proto.dart' as proto;
|
import '../../proto/proto.dart' as proto;
|
||||||
import '../../tools/tools.dart';
|
import '../../tools/tools.dart';
|
||||||
import 'models.dart';
|
import 'models.dart';
|
||||||
|
@ -13,7 +13,7 @@ import 'models.dart';
|
||||||
class ValidContactInvitation {
|
class ValidContactInvitation {
|
||||||
@internal
|
@internal
|
||||||
ValidContactInvitation(
|
ValidContactInvitation(
|
||||||
{required ActiveAccountInfo activeAccountInfo,
|
{required UnlockedAccountInfo activeAccountInfo,
|
||||||
required proto.Account account,
|
required proto.Account account,
|
||||||
required TypedKey contactRequestInboxKey,
|
required TypedKey contactRequestInboxKey,
|
||||||
required proto.ContactRequestPrivate contactRequestPrivate,
|
required proto.ContactRequestPrivate contactRequestPrivate,
|
||||||
|
@ -129,7 +129,7 @@ class ValidContactInvitation {
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
final ActiveAccountInfo _activeAccountInfo;
|
final UnlockedAccountInfo _activeAccountInfo;
|
||||||
final proto.Account _account;
|
final proto.Account _account;
|
||||||
final TypedKey _contactRequestInboxKey;
|
final TypedKey _contactRequestInboxKey;
|
||||||
final SuperIdentity _contactSuperIdentity;
|
final SuperIdentity _contactSuperIdentity;
|
||||||
|
|
|
@ -74,7 +74,7 @@ class InvitationDialogState extends State<InvitationDialog> {
|
||||||
|
|
||||||
Future<void> _onAccept() async {
|
Future<void> _onAccept() async {
|
||||||
final navigator = Navigator.of(context);
|
final navigator = Navigator.of(context);
|
||||||
final activeAccountInfo = widget.modalContext.read<ActiveAccountInfo>();
|
final activeAccountInfo = widget.modalContext.read<UnlockedAccountInfo>();
|
||||||
final contactList = widget.modalContext.read<ContactListCubit>();
|
final contactList = widget.modalContext.read<ContactListCubit>();
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
|
|
|
@ -13,15 +13,15 @@ import 'conversation_cubit.dart';
|
||||||
|
|
||||||
class ContactListCubit extends DHTShortArrayCubit<proto.Contact> {
|
class ContactListCubit extends DHTShortArrayCubit<proto.Contact> {
|
||||||
ContactListCubit({
|
ContactListCubit({
|
||||||
required ActiveAccountInfo activeAccountInfo,
|
required UnlockedAccountInfo unlockedAccountInfo,
|
||||||
required proto.Account account,
|
required proto.Account account,
|
||||||
}) : _activeAccountInfo = activeAccountInfo,
|
}) : _activeAccountInfo = unlockedAccountInfo,
|
||||||
super(
|
super(
|
||||||
open: () => _open(activeAccountInfo, account),
|
open: () => _open(unlockedAccountInfo, account),
|
||||||
decodeElement: proto.Contact.fromBuffer);
|
decodeElement: proto.Contact.fromBuffer);
|
||||||
|
|
||||||
static Future<DHTShortArray> _open(
|
static Future<DHTShortArray> _open(
|
||||||
ActiveAccountInfo activeAccountInfo, proto.Account account) async {
|
UnlockedAccountInfo activeAccountInfo, proto.Account account) async {
|
||||||
final accountRecordKey =
|
final accountRecordKey =
|
||||||
activeAccountInfo.userLogin.accountRecordInfo.accountRecord.recordKey;
|
activeAccountInfo.userLogin.accountRecordInfo.accountRecord.recordKey;
|
||||||
|
|
||||||
|
@ -99,5 +99,5 @@ class ContactListCubit extends DHTShortArrayCubit<proto.Contact> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final ActiveAccountInfo _activeAccountInfo;
|
final UnlockedAccountInfo _activeAccountInfo;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,2 +1 @@
|
||||||
export 'contact_list_cubit.dart';
|
export 'contact_list_cubit.dart';
|
||||||
export 'conversation_cubit.dart';
|
|
||||||
|
|
1
lib/conversation/conversation.dart
Normal file
1
lib/conversation/conversation.dart
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export 'cubits/cubits.dart';
|
|
@ -6,6 +6,7 @@ import 'package:veilid_support/veilid_support.dart';
|
||||||
|
|
||||||
import '../../account_manager/account_manager.dart';
|
import '../../account_manager/account_manager.dart';
|
||||||
import '../../contacts/contacts.dart';
|
import '../../contacts/contacts.dart';
|
||||||
|
import '../../conversation/conversation.dart';
|
||||||
import '../../proto/proto.dart' as proto;
|
import '../../proto/proto.dart' as proto;
|
||||||
import 'cubits.dart';
|
import 'cubits.dart';
|
||||||
|
|
||||||
|
@ -26,7 +27,9 @@ class ActiveConversationState extends Equatable {
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef ActiveConversationCubit = TransformerCubit<
|
typedef ActiveConversationCubit = TransformerCubit<
|
||||||
AsyncValue<ActiveConversationState>, AsyncValue<ConversationState>>;
|
AsyncValue<ActiveConversationState>,
|
||||||
|
AsyncValue<ConversationState>,
|
||||||
|
ConversationCubit>;
|
||||||
|
|
||||||
typedef ActiveConversationsBlocMapState
|
typedef ActiveConversationsBlocMapState
|
||||||
= BlocMapState<TypedKey, AsyncValue<ActiveConversationState>>;
|
= BlocMapState<TypedKey, AsyncValue<ActiveConversationState>>;
|
||||||
|
@ -41,11 +44,17 @@ class ActiveConversationsBlocMapCubit extends BlocMapCubit<TypedKey,
|
||||||
AsyncValue<ActiveConversationState>, ActiveConversationCubit>
|
AsyncValue<ActiveConversationState>, ActiveConversationCubit>
|
||||||
with StateMapFollower<ChatListCubitState, TypedKey, proto.Chat> {
|
with StateMapFollower<ChatListCubitState, TypedKey, proto.Chat> {
|
||||||
ActiveConversationsBlocMapCubit(
|
ActiveConversationsBlocMapCubit(
|
||||||
{required ActiveAccountInfo activeAccountInfo,
|
{required UnlockedAccountInfo unlockedAccountInfo,
|
||||||
required ContactListCubit contactListCubit})
|
required ContactListCubit contactListCubit})
|
||||||
: _activeAccountInfo = activeAccountInfo,
|
: _activeAccountInfo = unlockedAccountInfo,
|
||||||
_contactListCubit = contactListCubit;
|
_contactListCubit = contactListCubit;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Public Interface
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Private Implementation
|
||||||
|
|
||||||
// Add an active conversation to be tracked for changes
|
// Add an active conversation to be tracked for changes
|
||||||
Future<void> _addConversation({required proto.Contact contact}) async =>
|
Future<void> _addConversation({required proto.Contact contact}) async =>
|
||||||
add(() => MapEntry(
|
add(() => MapEntry(
|
||||||
|
@ -97,6 +106,6 @@ class ActiveConversationsBlocMapCubit extends BlocMapCubit<TypedKey,
|
||||||
|
|
||||||
////
|
////
|
||||||
|
|
||||||
final ActiveAccountInfo _activeAccountInfo;
|
final UnlockedAccountInfo _activeAccountInfo;
|
||||||
final ContactListCubit _contactListCubit;
|
final ContactListCubit _contactListCubit;
|
||||||
}
|
}
|
|
@ -20,10 +20,10 @@ class ActiveSingleContactChatBlocMapCubit extends BlocMapCubit<TypedKey,
|
||||||
StateMapFollower<ActiveConversationsBlocMapState, TypedKey,
|
StateMapFollower<ActiveConversationsBlocMapState, TypedKey,
|
||||||
AsyncValue<ActiveConversationState>> {
|
AsyncValue<ActiveConversationState>> {
|
||||||
ActiveSingleContactChatBlocMapCubit(
|
ActiveSingleContactChatBlocMapCubit(
|
||||||
{required ActiveAccountInfo activeAccountInfo,
|
{required UnlockedAccountInfo unlockedAccountInfo,
|
||||||
required ContactListCubit contactListCubit,
|
required ContactListCubit contactListCubit,
|
||||||
required ChatListCubit chatListCubit})
|
required ChatListCubit chatListCubit})
|
||||||
: _activeAccountInfo = activeAccountInfo,
|
: _activeAccountInfo = unlockedAccountInfo,
|
||||||
_contactListCubit = contactListCubit,
|
_contactListCubit = contactListCubit,
|
||||||
_chatListCubit = chatListCubit;
|
_chatListCubit = chatListCubit;
|
||||||
|
|
||||||
|
@ -95,7 +95,7 @@ class ActiveSingleContactChatBlocMapCubit extends BlocMapCubit<TypedKey,
|
||||||
|
|
||||||
////
|
////
|
||||||
|
|
||||||
final ActiveAccountInfo _activeAccountInfo;
|
final UnlockedAccountInfo _activeAccountInfo;
|
||||||
final ContactListCubit _contactListCubit;
|
final ContactListCubit _contactListCubit;
|
||||||
final ChatListCubit _chatListCubit;
|
final ChatListCubit _chatListCubit;
|
||||||
}
|
}
|
|
@ -29,11 +29,11 @@ class ConversationState extends Equatable {
|
||||||
|
|
||||||
class ConversationCubit extends Cubit<AsyncValue<ConversationState>> {
|
class ConversationCubit extends Cubit<AsyncValue<ConversationState>> {
|
||||||
ConversationCubit(
|
ConversationCubit(
|
||||||
{required ActiveAccountInfo activeAccountInfo,
|
{required UnlockedAccountInfo activeAccountInfo,
|
||||||
required TypedKey remoteIdentityPublicKey,
|
required TypedKey remoteIdentityPublicKey,
|
||||||
TypedKey? localConversationRecordKey,
|
TypedKey? localConversationRecordKey,
|
||||||
TypedKey? remoteConversationRecordKey})
|
TypedKey? remoteConversationRecordKey})
|
||||||
: _activeAccountInfo = activeAccountInfo,
|
: _unlockedAccountInfo = activeAccountInfo,
|
||||||
_localConversationRecordKey = localConversationRecordKey,
|
_localConversationRecordKey = localConversationRecordKey,
|
||||||
_remoteIdentityPublicKey = remoteIdentityPublicKey,
|
_remoteIdentityPublicKey = remoteIdentityPublicKey,
|
||||||
_remoteConversationRecordKey = remoteConversationRecordKey,
|
_remoteConversationRecordKey = remoteConversationRecordKey,
|
||||||
|
@ -41,13 +41,13 @@ class ConversationCubit extends Cubit<AsyncValue<ConversationState>> {
|
||||||
if (_localConversationRecordKey != null) {
|
if (_localConversationRecordKey != null) {
|
||||||
_initWait.add(() async {
|
_initWait.add(() async {
|
||||||
await _setLocalConversation(() async {
|
await _setLocalConversation(() async {
|
||||||
final accountRecordKey = _activeAccountInfo
|
final accountRecordKey = _unlockedAccountInfo
|
||||||
.userLogin.accountRecordInfo.accountRecord.recordKey;
|
.userLogin.accountRecordInfo.accountRecord.recordKey;
|
||||||
|
|
||||||
// Open local record key if it is specified
|
// Open local record key if it is specified
|
||||||
final pool = DHTRecordPool.instance;
|
final pool = DHTRecordPool.instance;
|
||||||
final crypto = await _cachedConversationCrypto();
|
final crypto = await _cachedConversationCrypto();
|
||||||
final writer = _activeAccountInfo.identityWriter;
|
final writer = _unlockedAccountInfo.identityWriter;
|
||||||
final record = await pool.openRecordWrite(
|
final record = await pool.openRecordWrite(
|
||||||
_localConversationRecordKey!, writer,
|
_localConversationRecordKey!, writer,
|
||||||
debugName: 'ConversationCubit::LocalConversation',
|
debugName: 'ConversationCubit::LocalConversation',
|
||||||
|
@ -61,7 +61,7 @@ class ConversationCubit extends Cubit<AsyncValue<ConversationState>> {
|
||||||
if (_remoteConversationRecordKey != null) {
|
if (_remoteConversationRecordKey != null) {
|
||||||
_initWait.add(() async {
|
_initWait.add(() async {
|
||||||
await _setRemoteConversation(() async {
|
await _setRemoteConversation(() async {
|
||||||
final accountRecordKey = _activeAccountInfo
|
final accountRecordKey = _unlockedAccountInfo
|
||||||
.userLogin.accountRecordInfo.accountRecord.recordKey;
|
.userLogin.accountRecordInfo.accountRecord.recordKey;
|
||||||
|
|
||||||
// Open remote record key if it is specified
|
// Open remote record key if it is specified
|
||||||
|
@ -217,11 +217,11 @@ class ConversationCubit extends Cubit<AsyncValue<ConversationState>> {
|
||||||
'must not have a local conversation yet');
|
'must not have a local conversation yet');
|
||||||
|
|
||||||
final pool = DHTRecordPool.instance;
|
final pool = DHTRecordPool.instance;
|
||||||
final accountRecordKey =
|
final accountRecordKey = _unlockedAccountInfo
|
||||||
_activeAccountInfo.userLogin.accountRecordInfo.accountRecord.recordKey;
|
.userLogin.accountRecordInfo.accountRecord.recordKey;
|
||||||
|
|
||||||
final crypto = await _cachedConversationCrypto();
|
final crypto = await _cachedConversationCrypto();
|
||||||
final writer = _activeAccountInfo.identityWriter;
|
final writer = _unlockedAccountInfo.identityWriter;
|
||||||
|
|
||||||
// Open with SMPL scheme for identity writer
|
// Open with SMPL scheme for identity writer
|
||||||
late final DHTRecord localConversationRecord;
|
late final DHTRecord localConversationRecord;
|
||||||
|
@ -247,7 +247,7 @@ class ConversationCubit extends Cubit<AsyncValue<ConversationState>> {
|
||||||
.deleteScope((localConversation) async {
|
.deleteScope((localConversation) async {
|
||||||
// Make messages log
|
// Make messages log
|
||||||
return _initLocalMessages(
|
return _initLocalMessages(
|
||||||
activeAccountInfo: _activeAccountInfo,
|
activeAccountInfo: _unlockedAccountInfo,
|
||||||
remoteIdentityPublicKey: _remoteIdentityPublicKey,
|
remoteIdentityPublicKey: _remoteIdentityPublicKey,
|
||||||
localConversationKey: localConversation.key,
|
localConversationKey: localConversation.key,
|
||||||
callback: (messages) async {
|
callback: (messages) async {
|
||||||
|
@ -255,7 +255,7 @@ class ConversationCubit extends Cubit<AsyncValue<ConversationState>> {
|
||||||
final conversation = proto.Conversation()
|
final conversation = proto.Conversation()
|
||||||
..profile = profile
|
..profile = profile
|
||||||
..superIdentityJson = jsonEncode(
|
..superIdentityJson = jsonEncode(
|
||||||
_activeAccountInfo.localAccount.superIdentity.toJson())
|
_unlockedAccountInfo.localAccount.superIdentity.toJson())
|
||||||
..messages = messages.recordKey.toProto();
|
..messages = messages.recordKey.toProto();
|
||||||
|
|
||||||
// Write initial conversation to record
|
// Write initial conversation to record
|
||||||
|
@ -282,7 +282,7 @@ class ConversationCubit extends Cubit<AsyncValue<ConversationState>> {
|
||||||
|
|
||||||
// Initialize local messages
|
// Initialize local messages
|
||||||
Future<T> _initLocalMessages<T>({
|
Future<T> _initLocalMessages<T>({
|
||||||
required ActiveAccountInfo activeAccountInfo,
|
required UnlockedAccountInfo activeAccountInfo,
|
||||||
required TypedKey remoteIdentityPublicKey,
|
required TypedKey remoteIdentityPublicKey,
|
||||||
required TypedKey localConversationKey,
|
required TypedKey localConversationKey,
|
||||||
required FutureOr<T> Function(DHTLog) callback,
|
required FutureOr<T> Function(DHTLog) callback,
|
||||||
|
@ -332,14 +332,14 @@ class ConversationCubit extends Cubit<AsyncValue<ConversationState>> {
|
||||||
if (conversationCrypto != null) {
|
if (conversationCrypto != null) {
|
||||||
return conversationCrypto;
|
return conversationCrypto;
|
||||||
}
|
}
|
||||||
conversationCrypto = await _activeAccountInfo
|
conversationCrypto = await _unlockedAccountInfo
|
||||||
.makeConversationCrypto(_remoteIdentityPublicKey);
|
.makeConversationCrypto(_remoteIdentityPublicKey);
|
||||||
|
|
||||||
_conversationCrypto = conversationCrypto;
|
_conversationCrypto = conversationCrypto;
|
||||||
return conversationCrypto;
|
return conversationCrypto;
|
||||||
}
|
}
|
||||||
|
|
||||||
final ActiveAccountInfo _activeAccountInfo;
|
final UnlockedAccountInfo _unlockedAccountInfo;
|
||||||
final TypedKey _remoteIdentityPublicKey;
|
final TypedKey _remoteIdentityPublicKey;
|
||||||
TypedKey? _localConversationRecordKey;
|
TypedKey? _localConversationRecordKey;
|
||||||
final TypedKey? _remoteConversationRecordKey;
|
final TypedKey? _remoteConversationRecordKey;
|
3
lib/conversation/cubits/cubits.dart
Normal file
3
lib/conversation/cubits/cubits.dart
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
export 'active_conversations_bloc_map_cubit.dart';
|
||||||
|
export 'active_single_contact_chat_bloc_map_cubit.dart';
|
||||||
|
export 'conversation_cubit.dart';
|
|
@ -1,3 +1,4 @@
|
||||||
|
import 'package:async_tools/async_tools.dart';
|
||||||
import 'package:awesome_extensions/awesome_extensions.dart';
|
import 'package:awesome_extensions/awesome_extensions.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
@ -9,6 +10,7 @@ import 'package:veilid_support/veilid_support.dart';
|
||||||
import '../../../account_manager/account_manager.dart';
|
import '../../../account_manager/account_manager.dart';
|
||||||
import '../../../theme/theme.dart';
|
import '../../../theme/theme.dart';
|
||||||
import '../../../tools/tools.dart';
|
import '../../../tools/tools.dart';
|
||||||
|
import '../../../veilid_processor/veilid_processor.dart';
|
||||||
import 'menu_item_widget.dart';
|
import 'menu_item_widget.dart';
|
||||||
|
|
||||||
class DrawerMenu extends StatefulWidget {
|
class DrawerMenu extends StatefulWidget {
|
||||||
|
@ -29,8 +31,10 @@ class _DrawerMenuState extends State<DrawerMenu> {
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _doLoginClick(TypedKey superIdentityRecordKey) {
|
void _doSwitchClick(TypedKey superIdentityRecordKey) {
|
||||||
//
|
singleFuture(this, () async {
|
||||||
|
await AccountRepository.instance.switchToAccount(superIdentityRecordKey);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void _doEditClick(TypedKey superIdentityRecordKey) {
|
void _doEditClick(TypedKey superIdentityRecordKey) {
|
||||||
|
@ -47,10 +51,12 @@ class _DrawerMenuState extends State<DrawerMenu> {
|
||||||
|
|
||||||
Widget _makeAccountWidget(
|
Widget _makeAccountWidget(
|
||||||
{required String name,
|
{required String name,
|
||||||
|
required bool selected,
|
||||||
|
required ScaleColor scale,
|
||||||
required bool loggedIn,
|
required bool loggedIn,
|
||||||
required void Function() clickHandler}) {
|
required void Function()? callback,
|
||||||
|
required void Function()? footerCallback}) {
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
final scale = theme.extension<ScaleScheme>()!.tertiaryScale;
|
|
||||||
final abbrev = name.split(' ').map((s) => s.isEmpty ? '' : s[0]).join();
|
final abbrev = name.split(' ').map((s) => s.isEmpty ? '' : s[0]).join();
|
||||||
late final String shortname;
|
late final String shortname;
|
||||||
if (abbrev.length >= 3) {
|
if (abbrev.length >= 3) {
|
||||||
|
@ -65,30 +71,36 @@ class _DrawerMenuState extends State<DrawerMenu> {
|
||||||
foregroundColor: loggedIn ? scale.primaryText : scale.subtleText,
|
foregroundColor: loggedIn ? scale.primaryText : scale.subtleText,
|
||||||
child: Text(shortname, style: theme.textTheme.titleLarge));
|
child: Text(shortname, style: theme.textTheme.titleLarge));
|
||||||
|
|
||||||
return MenuItemWidget(
|
return AnimatedPadding(
|
||||||
|
padding: EdgeInsets.fromLTRB(selected ? 0 : 0, 0, selected ? 0 : 8, 0),
|
||||||
|
duration: const Duration(milliseconds: 50),
|
||||||
|
child: MenuItemWidget(
|
||||||
title: name,
|
title: name,
|
||||||
headerWidget: avatar,
|
headerWidget: avatar,
|
||||||
titleStyle: theme.textTheme.titleLarge!,
|
titleStyle: theme.textTheme.titleLarge!,
|
||||||
foregroundColor: scale.primary,
|
foregroundColor: scale.primary,
|
||||||
backgroundColor: scale.elementBackground,
|
backgroundColor: selected
|
||||||
|
? scale.activeElementBackground
|
||||||
|
: scale.elementBackground,
|
||||||
backgroundHoverColor: scale.hoverElementBackground,
|
backgroundHoverColor: scale.hoverElementBackground,
|
||||||
backgroundFocusColor: scale.activeElementBackground,
|
backgroundFocusColor: scale.activeElementBackground,
|
||||||
borderColor: scale.border,
|
borderColor: scale.border,
|
||||||
borderHoverColor: scale.hoverBorder,
|
borderHoverColor: scale.hoverBorder,
|
||||||
borderFocusColor: scale.primary,
|
borderFocusColor: scale.primary,
|
||||||
footerButtonIcon: loggedIn ? Icons.edit_outlined : Icons.login_outlined,
|
callback: callback,
|
||||||
footerCallback: clickHandler,
|
footerButtonIcon: loggedIn ? Icons.edit_outlined : null,
|
||||||
|
footerCallback: footerCallback,
|
||||||
footerButtonIconColor: scale.border,
|
footerButtonIconColor: scale.border,
|
||||||
footerButtonIconHoverColor: scale.hoverElementBackground,
|
footerButtonIconHoverColor: scale.hoverElementBackground,
|
||||||
footerButtonIconFocusColor: scale.activeElementBackground,
|
footerButtonIconFocusColor: scale.activeElementBackground,
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _getAccountList(
|
Widget _getAccountList(
|
||||||
{required TypedKey? activeLocalAccount,
|
{required TypedKey? activeLocalAccount,
|
||||||
required AccountRecordsBlocMapState accountRecords}) {
|
required AccountRecordsBlocMapState accountRecords}) {
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
final scale = theme.extension<ScaleScheme>()!;
|
final scaleScheme = theme.extension<ScaleScheme>()!;
|
||||||
|
|
||||||
final accountRepo = AccountRepository.instance;
|
final accountRepo = AccountRepository.instance;
|
||||||
final localAccounts = accountRepo.getLocalAccounts();
|
final localAccounts = accountRepo.getLocalAccounts();
|
||||||
|
@ -104,28 +116,38 @@ class _DrawerMenuState extends State<DrawerMenu> {
|
||||||
final acctRecord = accountRecords.get(superIdentityRecordKey);
|
final acctRecord = accountRecords.get(superIdentityRecordKey);
|
||||||
if (acctRecord != null) {
|
if (acctRecord != null) {
|
||||||
// Account is logged in
|
// Account is logged in
|
||||||
|
final scale = theme.extension<ScaleScheme>()!.tertiaryScale;
|
||||||
final loggedInAccount = acctRecord.when(
|
final loggedInAccount = acctRecord.when(
|
||||||
data: (value) => _makeAccountWidget(
|
data: (value) => _makeAccountWidget(
|
||||||
name: value.profile.name,
|
name: value.profile.name,
|
||||||
|
scale: scale,
|
||||||
|
selected: superIdentityRecordKey == activeLocalAccount,
|
||||||
loggedIn: true,
|
loggedIn: true,
|
||||||
clickHandler: () {
|
callback: () {
|
||||||
|
_doSwitchClick(superIdentityRecordKey);
|
||||||
|
},
|
||||||
|
footerCallback: () {
|
||||||
_doEditClick(superIdentityRecordKey);
|
_doEditClick(superIdentityRecordKey);
|
||||||
}),
|
}),
|
||||||
loading: () => _wrapInBox(
|
loading: () => _wrapInBox(
|
||||||
child: buildProgressIndicator(),
|
child: buildProgressIndicator(),
|
||||||
color: scale.grayScale.subtleBorder),
|
color: scaleScheme.grayScale.subtleBorder),
|
||||||
error: (err, st) => _wrapInBox(
|
error: (err, st) => _wrapInBox(
|
||||||
child: errorPage(err, st), color: scale.errorScale.subtleBorder),
|
child: errorPage(err, st),
|
||||||
|
color: scaleScheme.errorScale.subtleBorder),
|
||||||
);
|
);
|
||||||
loggedInAccounts.add(loggedInAccount);
|
loggedInAccounts.add(loggedInAccount.paddingLTRB(0, 0, 0, 8));
|
||||||
} else {
|
} else {
|
||||||
// Account is not logged in
|
// Account is not logged in
|
||||||
|
final scale = theme.extension<ScaleScheme>()!.grayScale;
|
||||||
final loggedOutAccount = _makeAccountWidget(
|
final loggedOutAccount = _makeAccountWidget(
|
||||||
name: la.name,
|
name: la.name,
|
||||||
|
scale: scale,
|
||||||
|
selected: superIdentityRecordKey == activeLocalAccount,
|
||||||
loggedIn: false,
|
loggedIn: false,
|
||||||
clickHandler: () {
|
callback: () => {_doSwitchClick(superIdentityRecordKey)},
|
||||||
_doLoginClick(superIdentityRecordKey);
|
footerCallback: null,
|
||||||
});
|
);
|
||||||
loggedOutAccounts.add(loggedOutAccount);
|
loggedOutAccounts.add(loggedOutAccount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -208,7 +230,7 @@ class _DrawerMenuState extends State<DrawerMenu> {
|
||||||
final scale = theme.extension<ScaleScheme>()!;
|
final scale = theme.extension<ScaleScheme>()!;
|
||||||
//final textTheme = theme.textTheme;
|
//final textTheme = theme.textTheme;
|
||||||
final accountRecords = context.watch<AccountRecordsBlocMapCubit>().state;
|
final accountRecords = context.watch<AccountRecordsBlocMapCubit>().state;
|
||||||
final activeLocalAccount = context.watch<ActiveLocalAccountCubit>().state;
|
final activeLocalAccount = context.watch<ActiveAccountInfoCubit>().state;
|
||||||
final gradient = LinearGradient(
|
final gradient = LinearGradient(
|
||||||
begin: Alignment.topLeft,
|
begin: Alignment.topLeft,
|
||||||
end: Alignment.bottomRight,
|
end: Alignment.bottomRight,
|
||||||
|
@ -249,13 +271,21 @@ class _DrawerMenuState extends State<DrawerMenu> {
|
||||||
])),
|
])),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
_getAccountList(
|
_getAccountList(
|
||||||
activeLocalAccount: activeLocalAccount,
|
activeLocalAccount:
|
||||||
|
activeLocalAccount.unlockedAccountInfo?.superIdentityRecordKey,
|
||||||
accountRecords: accountRecords),
|
accountRecords: accountRecords),
|
||||||
_getBottomButtons(),
|
_getBottomButtons(),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
|
Row(children: [
|
||||||
Text('Version $packageInfoVersion',
|
Text('Version $packageInfoVersion',
|
||||||
style: theme.textTheme.labelMedium!
|
style: theme.textTheme.labelMedium!
|
||||||
.copyWith(color: scale.tertiaryScale.hoverBorder))
|
.copyWith(color: scale.tertiaryScale.hoverBorder)),
|
||||||
|
const Spacer(),
|
||||||
|
SignalStrengthMeterWidget(
|
||||||
|
color: scale.tertiaryScale.hoverBorder,
|
||||||
|
inactiveColor: scale.tertiaryScale.border,
|
||||||
|
),
|
||||||
|
])
|
||||||
]).paddingAll(16),
|
]).paddingAll(16),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ class MenuItemWidget extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => TextButton(
|
Widget build(BuildContext context) => TextButton(
|
||||||
onPressed: () => callback,
|
onPressed: callback,
|
||||||
style: TextButton.styleFrom(foregroundColor: foregroundColor).copyWith(
|
style: TextButton.styleFrom(foregroundColor: foregroundColor).copyWith(
|
||||||
backgroundColor: WidgetStateProperty.resolveWith((states) {
|
backgroundColor: WidgetStateProperty.resolveWith((states) {
|
||||||
if (states.contains(WidgetState.hovered)) {
|
if (states.contains(WidgetState.hovered)) {
|
||||||
|
|
|
@ -44,7 +44,7 @@ class _HomeAccountReadyMainState extends State<HomeAccountReadyMain> {
|
||||||
WidgetStateProperty.all(scale.primaryScale.hoverBorder),
|
WidgetStateProperty.all(scale.primaryScale.hoverBorder),
|
||||||
shape: WidgetStateProperty.all(const RoundedRectangleBorder(
|
shape: WidgetStateProperty.all(const RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.all(Radius.circular(16))))),
|
borderRadius: BorderRadius.all(Radius.circular(16))))),
|
||||||
tooltip: translate('app_bar.settings_tooltip'),
|
tooltip: translate('menu.settings_tooltip'),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
final ctrl = context.read<ZoomDrawerController>();
|
final ctrl = context.read<ZoomDrawerController>();
|
||||||
await ctrl.toggle?.call();
|
await ctrl.toggle?.call();
|
||||||
|
|
|
@ -1,15 +1,14 @@
|
||||||
import 'package:async_tools/async_tools.dart';
|
import 'package:async_tools/async_tools.dart';
|
||||||
import 'package:bloc_advanced_tools/bloc_advanced_tools.dart';
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:veilid_support/veilid_support.dart';
|
|
||||||
|
|
||||||
import '../../../account_manager/account_manager.dart';
|
import '../../../account_manager/account_manager.dart';
|
||||||
import '../../../chat/chat.dart';
|
import '../../../chat/chat.dart';
|
||||||
import '../../../chat_list/chat_list.dart';
|
import '../../../chat_list/chat_list.dart';
|
||||||
import '../../../contact_invitation/contact_invitation.dart';
|
import '../../../contact_invitation/contact_invitation.dart';
|
||||||
import '../../../contacts/contacts.dart';
|
import '../../../contacts/contacts.dart';
|
||||||
|
import '../../../conversation/conversation.dart';
|
||||||
import '../../../router/router.dart';
|
import '../../../router/router.dart';
|
||||||
import '../../../theme/theme.dart';
|
import '../../../theme/theme.dart';
|
||||||
|
|
||||||
|
@ -18,20 +17,17 @@ class HomeAccountReadyShell extends StatefulWidget {
|
||||||
{required BuildContext context, required Widget child, Key? key}) {
|
{required BuildContext context, required Widget child, Key? key}) {
|
||||||
// These must exist in order for the account to
|
// These must exist in order for the account to
|
||||||
// be considered 'ready' for this widget subtree
|
// be considered 'ready' for this widget subtree
|
||||||
final activeLocalAccount = context.read<ActiveLocalAccountCubit>().state!;
|
final unlockedAccountInfo = context.watch<UnlockedAccountInfo>();
|
||||||
final activeAccountInfo = context.read<ActiveAccountInfo>();
|
|
||||||
final routerCubit = context.read<RouterCubit>();
|
final routerCubit = context.read<RouterCubit>();
|
||||||
|
|
||||||
return HomeAccountReadyShell._(
|
return HomeAccountReadyShell._(
|
||||||
activeLocalAccount: activeLocalAccount,
|
unlockedAccountInfo: unlockedAccountInfo,
|
||||||
activeAccountInfo: activeAccountInfo,
|
|
||||||
routerCubit: routerCubit,
|
routerCubit: routerCubit,
|
||||||
key: key,
|
key: key,
|
||||||
child: child);
|
child: child);
|
||||||
}
|
}
|
||||||
const HomeAccountReadyShell._(
|
const HomeAccountReadyShell._(
|
||||||
{required this.activeLocalAccount,
|
{required this.unlockedAccountInfo,
|
||||||
required this.activeAccountInfo,
|
|
||||||
required this.routerCubit,
|
required this.routerCubit,
|
||||||
required this.child,
|
required this.child,
|
||||||
super.key});
|
super.key});
|
||||||
|
@ -40,18 +36,15 @@ class HomeAccountReadyShell extends StatefulWidget {
|
||||||
HomeAccountReadyShellState createState() => HomeAccountReadyShellState();
|
HomeAccountReadyShellState createState() => HomeAccountReadyShellState();
|
||||||
|
|
||||||
final Widget child;
|
final Widget child;
|
||||||
final TypedKey activeLocalAccount;
|
final UnlockedAccountInfo unlockedAccountInfo;
|
||||||
final ActiveAccountInfo activeAccountInfo;
|
|
||||||
final RouterCubit routerCubit;
|
final RouterCubit routerCubit;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||||
super.debugFillProperties(properties);
|
super.debugFillProperties(properties);
|
||||||
properties
|
properties
|
||||||
..add(DiagnosticsProperty<TypedKey>(
|
..add(DiagnosticsProperty<UnlockedAccountInfo>(
|
||||||
'activeLocalAccount', activeLocalAccount))
|
'unlockedAccountInfo', unlockedAccountInfo))
|
||||||
..add(DiagnosticsProperty<ActiveAccountInfo>(
|
|
||||||
'activeAccountInfo', activeAccountInfo))
|
|
||||||
..add(DiagnosticsProperty<RouterCubit>('routerCubit', routerCubit));
|
..add(DiagnosticsProperty<RouterCubit>('routerCubit', routerCubit));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -115,39 +108,41 @@ class HomeAccountReadyShellState extends State<HomeAccountReadyShell> {
|
||||||
}
|
}
|
||||||
return MultiBlocProvider(
|
return MultiBlocProvider(
|
||||||
providers: [
|
providers: [
|
||||||
|
// Contact Cubits
|
||||||
BlocProvider(
|
BlocProvider(
|
||||||
create: (context) => ContactInvitationListCubit(
|
create: (context) => ContactInvitationListCubit(
|
||||||
activeAccountInfo: widget.activeAccountInfo,
|
unlockedAccountInfo: widget.unlockedAccountInfo,
|
||||||
account: account)),
|
account: account)),
|
||||||
BlocProvider(
|
BlocProvider(
|
||||||
create: (context) => ContactListCubit(
|
create: (context) => ContactListCubit(
|
||||||
activeAccountInfo: widget.activeAccountInfo,
|
unlockedAccountInfo: widget.unlockedAccountInfo,
|
||||||
account: account)),
|
account: account)),
|
||||||
BlocProvider(
|
|
||||||
create: (context) => ActiveChatCubit(null)
|
|
||||||
..withStateListen((event) {
|
|
||||||
widget.routerCubit.setHasActiveChat(event != null);
|
|
||||||
})),
|
|
||||||
BlocProvider(
|
|
||||||
create: (context) => ChatListCubit(
|
|
||||||
activeAccountInfo: widget.activeAccountInfo,
|
|
||||||
activeChatCubit: context.read<ActiveChatCubit>(),
|
|
||||||
account: account)),
|
|
||||||
BlocProvider(
|
|
||||||
create: (context) => ActiveConversationsBlocMapCubit(
|
|
||||||
activeAccountInfo: widget.activeAccountInfo,
|
|
||||||
contactListCubit: context.read<ContactListCubit>())
|
|
||||||
..follow(context.read<ChatListCubit>())),
|
|
||||||
BlocProvider(
|
|
||||||
create: (context) => ActiveSingleContactChatBlocMapCubit(
|
|
||||||
activeAccountInfo: widget.activeAccountInfo,
|
|
||||||
contactListCubit: context.read<ContactListCubit>(),
|
|
||||||
chatListCubit: context.read<ChatListCubit>())
|
|
||||||
..follow(context.read<ActiveConversationsBlocMapCubit>())),
|
|
||||||
BlocProvider(
|
BlocProvider(
|
||||||
create: (context) => WaitingInvitationsBlocMapCubit(
|
create: (context) => WaitingInvitationsBlocMapCubit(
|
||||||
activeAccountInfo: widget.activeAccountInfo, account: account)
|
unlockedAccountInfo: widget.unlockedAccountInfo,
|
||||||
..follow(context.read<ContactInvitationListCubit>()))
|
account: account)
|
||||||
|
..follow(context.watch<ContactInvitationListCubit>())),
|
||||||
|
// Chat Cubits
|
||||||
|
BlocProvider(
|
||||||
|
create: (context) => ActiveChatCubit(null,
|
||||||
|
routerCubit: context.watch<RouterCubit>())),
|
||||||
|
BlocProvider(
|
||||||
|
create: (context) => ChatListCubit(
|
||||||
|
unlockedAccountInfo: widget.unlockedAccountInfo,
|
||||||
|
activeChatCubit: context.watch<ActiveChatCubit>(),
|
||||||
|
account: account)),
|
||||||
|
// Conversation Cubits
|
||||||
|
BlocProvider(
|
||||||
|
create: (context) => ActiveConversationsBlocMapCubit(
|
||||||
|
unlockedAccountInfo: widget.unlockedAccountInfo,
|
||||||
|
contactListCubit: context.watch<ContactListCubit>())
|
||||||
|
..follow(context.watch<ChatListCubit>())),
|
||||||
|
BlocProvider(
|
||||||
|
create: (context) => ActiveSingleContactChatBlocMapCubit(
|
||||||
|
unlockedAccountInfo: widget.unlockedAccountInfo,
|
||||||
|
contactListCubit: context.watch<ContactListCubit>(),
|
||||||
|
chatListCubit: context.watch<ChatListCubit>())
|
||||||
|
..follow(context.watch<ActiveConversationsBlocMapCubit>())),
|
||||||
],
|
],
|
||||||
child: MultiBlocListener(listeners: [
|
child: MultiBlocListener(listeners: [
|
||||||
BlocListener<WaitingInvitationsBlocMapCubit,
|
BlocListener<WaitingInvitationsBlocMapCubit,
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:awesome_extensions/awesome_extensions.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:flutter_zoom_drawer/flutter_zoom_drawer.dart';
|
import 'package:flutter_zoom_drawer/flutter_zoom_drawer.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
@ -35,17 +33,19 @@ class HomeShellState extends State<HomeShell> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget buildWithLogin(BuildContext context) {
|
Widget buildWithLogin(BuildContext context) {
|
||||||
final activeLocalAccount = context.watch<ActiveLocalAccountCubit>().state;
|
final accountInfo = context.watch<ActiveAccountInfoCubit>().state;
|
||||||
final accountRecordsCubit = context.watch<AccountRecordsBlocMapCubit>();
|
final accountRecordsCubit = context.watch<AccountRecordsBlocMapCubit>();
|
||||||
if (activeLocalAccount == null) {
|
if (!accountInfo.active) {
|
||||||
// If no logged in user is active, show the loading panel
|
// If no logged in user is active, show the loading panel
|
||||||
return const HomeNoActive();
|
return const HomeNoActive();
|
||||||
}
|
}
|
||||||
|
|
||||||
final accountInfo =
|
final superIdentityRecordKey =
|
||||||
AccountRepository.instance.getAccountInfo(activeLocalAccount);
|
accountInfo.unlockedAccountInfo?.superIdentityRecordKey;
|
||||||
final activeCubit =
|
final activeCubit = superIdentityRecordKey == null
|
||||||
accountRecordsCubit.tryOperate(activeLocalAccount, closure: (c) => c);
|
? null
|
||||||
|
: accountRecordsCubit.tryOperate(superIdentityRecordKey,
|
||||||
|
closure: (c) => c);
|
||||||
if (activeCubit == null) {
|
if (activeCubit == null) {
|
||||||
return waitingPage();
|
return waitingPage();
|
||||||
}
|
}
|
||||||
|
@ -59,8 +59,8 @@ class HomeShellState extends State<HomeShell> {
|
||||||
return const HomeAccountLocked();
|
return const HomeAccountLocked();
|
||||||
case AccountInfoStatus.accountReady:
|
case AccountInfoStatus.accountReady:
|
||||||
return MultiProvider(providers: [
|
return MultiProvider(providers: [
|
||||||
Provider<ActiveAccountInfo>.value(
|
Provider<UnlockedAccountInfo>.value(
|
||||||
value: accountInfo.activeAccountInfo!,
|
value: accountInfo.unlockedAccountInfo!,
|
||||||
),
|
),
|
||||||
Provider<AccountRecordCubit>.value(value: activeCubit),
|
Provider<AccountRecordCubit>.value(value: activeCubit),
|
||||||
Provider<ZoomDrawerController>.value(value: _zoomDrawerController),
|
Provider<ZoomDrawerController>.value(value: _zoomDrawerController),
|
||||||
|
@ -101,6 +101,7 @@ class HomeShellState extends State<HomeShell> {
|
||||||
// duration: const Duration(milliseconds: 250),
|
// duration: const Duration(milliseconds: 250),
|
||||||
// reverseDuration: const Duration(milliseconds: 250),
|
// reverseDuration: const Duration(milliseconds: 250),
|
||||||
menuScreenTapClose: true,
|
menuScreenTapClose: true,
|
||||||
|
mainScreenTapClose: true,
|
||||||
mainScreenScale: .25,
|
mainScreenScale: .25,
|
||||||
slideWidth: min(360, MediaQuery.of(context).size.width * 0.9),
|
slideWidth: min(360, MediaQuery.of(context).size.width * 0.9),
|
||||||
)));
|
)));
|
||||||
|
|
|
@ -20,6 +20,177 @@ import 'veilidchat.pbenum.dart';
|
||||||
|
|
||||||
export 'veilidchat.pbenum.dart';
|
export 'veilidchat.pbenum.dart';
|
||||||
|
|
||||||
|
class DHTDataReference extends $pb.GeneratedMessage {
|
||||||
|
factory DHTDataReference() => create();
|
||||||
|
DHTDataReference._() : super();
|
||||||
|
factory DHTDataReference.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
|
||||||
|
factory DHTDataReference.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
|
||||||
|
|
||||||
|
static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'DHTDataReference', package: const $pb.PackageName(_omitMessageNames ? '' : 'veilidchat'), createEmptyInstance: create)
|
||||||
|
..aOM<$0.TypedKey>(1, _omitFieldNames ? '' : 'dhtData', subBuilder: $0.TypedKey.create)
|
||||||
|
..aOM<$0.TypedKey>(2, _omitFieldNames ? '' : 'hash', subBuilder: $0.TypedKey.create)
|
||||||
|
..hasRequiredFields = false
|
||||||
|
;
|
||||||
|
|
||||||
|
@$core.Deprecated(
|
||||||
|
'Using this can add significant overhead to your binary. '
|
||||||
|
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
|
||||||
|
'Will be removed in next major version')
|
||||||
|
DHTDataReference clone() => DHTDataReference()..mergeFromMessage(this);
|
||||||
|
@$core.Deprecated(
|
||||||
|
'Using this can add significant overhead to your binary. '
|
||||||
|
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
|
||||||
|
'Will be removed in next major version')
|
||||||
|
DHTDataReference copyWith(void Function(DHTDataReference) updates) => super.copyWith((message) => updates(message as DHTDataReference)) as DHTDataReference;
|
||||||
|
|
||||||
|
$pb.BuilderInfo get info_ => _i;
|
||||||
|
|
||||||
|
@$core.pragma('dart2js:noInline')
|
||||||
|
static DHTDataReference create() => DHTDataReference._();
|
||||||
|
DHTDataReference createEmptyInstance() => create();
|
||||||
|
static $pb.PbList<DHTDataReference> createRepeated() => $pb.PbList<DHTDataReference>();
|
||||||
|
@$core.pragma('dart2js:noInline')
|
||||||
|
static DHTDataReference getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<DHTDataReference>(create);
|
||||||
|
static DHTDataReference? _defaultInstance;
|
||||||
|
|
||||||
|
@$pb.TagNumber(1)
|
||||||
|
$0.TypedKey get dhtData => $_getN(0);
|
||||||
|
@$pb.TagNumber(1)
|
||||||
|
set dhtData($0.TypedKey v) { setField(1, v); }
|
||||||
|
@$pb.TagNumber(1)
|
||||||
|
$core.bool hasDhtData() => $_has(0);
|
||||||
|
@$pb.TagNumber(1)
|
||||||
|
void clearDhtData() => clearField(1);
|
||||||
|
@$pb.TagNumber(1)
|
||||||
|
$0.TypedKey ensureDhtData() => $_ensure(0);
|
||||||
|
|
||||||
|
@$pb.TagNumber(2)
|
||||||
|
$0.TypedKey get hash => $_getN(1);
|
||||||
|
@$pb.TagNumber(2)
|
||||||
|
set hash($0.TypedKey v) { setField(2, v); }
|
||||||
|
@$pb.TagNumber(2)
|
||||||
|
$core.bool hasHash() => $_has(1);
|
||||||
|
@$pb.TagNumber(2)
|
||||||
|
void clearHash() => clearField(2);
|
||||||
|
@$pb.TagNumber(2)
|
||||||
|
$0.TypedKey ensureHash() => $_ensure(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
class BlockStoreDataReference extends $pb.GeneratedMessage {
|
||||||
|
factory BlockStoreDataReference() => create();
|
||||||
|
BlockStoreDataReference._() : super();
|
||||||
|
factory BlockStoreDataReference.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
|
||||||
|
factory BlockStoreDataReference.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
|
||||||
|
|
||||||
|
static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'BlockStoreDataReference', package: const $pb.PackageName(_omitMessageNames ? '' : 'veilidchat'), createEmptyInstance: create)
|
||||||
|
..aOM<$0.TypedKey>(1, _omitFieldNames ? '' : 'block', subBuilder: $0.TypedKey.create)
|
||||||
|
..hasRequiredFields = false
|
||||||
|
;
|
||||||
|
|
||||||
|
@$core.Deprecated(
|
||||||
|
'Using this can add significant overhead to your binary. '
|
||||||
|
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
|
||||||
|
'Will be removed in next major version')
|
||||||
|
BlockStoreDataReference clone() => BlockStoreDataReference()..mergeFromMessage(this);
|
||||||
|
@$core.Deprecated(
|
||||||
|
'Using this can add significant overhead to your binary. '
|
||||||
|
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
|
||||||
|
'Will be removed in next major version')
|
||||||
|
BlockStoreDataReference copyWith(void Function(BlockStoreDataReference) updates) => super.copyWith((message) => updates(message as BlockStoreDataReference)) as BlockStoreDataReference;
|
||||||
|
|
||||||
|
$pb.BuilderInfo get info_ => _i;
|
||||||
|
|
||||||
|
@$core.pragma('dart2js:noInline')
|
||||||
|
static BlockStoreDataReference create() => BlockStoreDataReference._();
|
||||||
|
BlockStoreDataReference createEmptyInstance() => create();
|
||||||
|
static $pb.PbList<BlockStoreDataReference> createRepeated() => $pb.PbList<BlockStoreDataReference>();
|
||||||
|
@$core.pragma('dart2js:noInline')
|
||||||
|
static BlockStoreDataReference getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<BlockStoreDataReference>(create);
|
||||||
|
static BlockStoreDataReference? _defaultInstance;
|
||||||
|
|
||||||
|
@$pb.TagNumber(1)
|
||||||
|
$0.TypedKey get block => $_getN(0);
|
||||||
|
@$pb.TagNumber(1)
|
||||||
|
set block($0.TypedKey v) { setField(1, v); }
|
||||||
|
@$pb.TagNumber(1)
|
||||||
|
$core.bool hasBlock() => $_has(0);
|
||||||
|
@$pb.TagNumber(1)
|
||||||
|
void clearBlock() => clearField(1);
|
||||||
|
@$pb.TagNumber(1)
|
||||||
|
$0.TypedKey ensureBlock() => $_ensure(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum DataReference_Kind {
|
||||||
|
dhtData,
|
||||||
|
blockStoreData,
|
||||||
|
notSet
|
||||||
|
}
|
||||||
|
|
||||||
|
class DataReference extends $pb.GeneratedMessage {
|
||||||
|
factory DataReference() => create();
|
||||||
|
DataReference._() : super();
|
||||||
|
factory DataReference.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
|
||||||
|
factory DataReference.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
|
||||||
|
|
||||||
|
static const $core.Map<$core.int, DataReference_Kind> _DataReference_KindByTag = {
|
||||||
|
1 : DataReference_Kind.dhtData,
|
||||||
|
2 : DataReference_Kind.blockStoreData,
|
||||||
|
0 : DataReference_Kind.notSet
|
||||||
|
};
|
||||||
|
static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'DataReference', package: const $pb.PackageName(_omitMessageNames ? '' : 'veilidchat'), createEmptyInstance: create)
|
||||||
|
..oo(0, [1, 2])
|
||||||
|
..aOM<DHTDataReference>(1, _omitFieldNames ? '' : 'dhtData', subBuilder: DHTDataReference.create)
|
||||||
|
..aOM<BlockStoreDataReference>(2, _omitFieldNames ? '' : 'blockStoreData', subBuilder: BlockStoreDataReference.create)
|
||||||
|
..hasRequiredFields = false
|
||||||
|
;
|
||||||
|
|
||||||
|
@$core.Deprecated(
|
||||||
|
'Using this can add significant overhead to your binary. '
|
||||||
|
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
|
||||||
|
'Will be removed in next major version')
|
||||||
|
DataReference clone() => DataReference()..mergeFromMessage(this);
|
||||||
|
@$core.Deprecated(
|
||||||
|
'Using this can add significant overhead to your binary. '
|
||||||
|
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
|
||||||
|
'Will be removed in next major version')
|
||||||
|
DataReference copyWith(void Function(DataReference) updates) => super.copyWith((message) => updates(message as DataReference)) as DataReference;
|
||||||
|
|
||||||
|
$pb.BuilderInfo get info_ => _i;
|
||||||
|
|
||||||
|
@$core.pragma('dart2js:noInline')
|
||||||
|
static DataReference create() => DataReference._();
|
||||||
|
DataReference createEmptyInstance() => create();
|
||||||
|
static $pb.PbList<DataReference> createRepeated() => $pb.PbList<DataReference>();
|
||||||
|
@$core.pragma('dart2js:noInline')
|
||||||
|
static DataReference getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<DataReference>(create);
|
||||||
|
static DataReference? _defaultInstance;
|
||||||
|
|
||||||
|
DataReference_Kind whichKind() => _DataReference_KindByTag[$_whichOneof(0)]!;
|
||||||
|
void clearKind() => clearField($_whichOneof(0));
|
||||||
|
|
||||||
|
@$pb.TagNumber(1)
|
||||||
|
DHTDataReference get dhtData => $_getN(0);
|
||||||
|
@$pb.TagNumber(1)
|
||||||
|
set dhtData(DHTDataReference v) { setField(1, v); }
|
||||||
|
@$pb.TagNumber(1)
|
||||||
|
$core.bool hasDhtData() => $_has(0);
|
||||||
|
@$pb.TagNumber(1)
|
||||||
|
void clearDhtData() => clearField(1);
|
||||||
|
@$pb.TagNumber(1)
|
||||||
|
DHTDataReference ensureDhtData() => $_ensure(0);
|
||||||
|
|
||||||
|
@$pb.TagNumber(2)
|
||||||
|
BlockStoreDataReference get blockStoreData => $_getN(1);
|
||||||
|
@$pb.TagNumber(2)
|
||||||
|
set blockStoreData(BlockStoreDataReference v) { setField(2, v); }
|
||||||
|
@$pb.TagNumber(2)
|
||||||
|
$core.bool hasBlockStoreData() => $_has(1);
|
||||||
|
@$pb.TagNumber(2)
|
||||||
|
void clearBlockStoreData() => clearField(2);
|
||||||
|
@$pb.TagNumber(2)
|
||||||
|
BlockStoreDataReference ensureBlockStoreData() => $_ensure(1);
|
||||||
|
}
|
||||||
|
|
||||||
enum Attachment_Kind {
|
enum Attachment_Kind {
|
||||||
media,
|
media,
|
||||||
notSet
|
notSet
|
||||||
|
@ -98,7 +269,7 @@ class AttachmentMedia extends $pb.GeneratedMessage {
|
||||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'AttachmentMedia', package: const $pb.PackageName(_omitMessageNames ? '' : 'veilidchat'), createEmptyInstance: create)
|
static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'AttachmentMedia', package: const $pb.PackageName(_omitMessageNames ? '' : 'veilidchat'), createEmptyInstance: create)
|
||||||
..aOS(1, _omitFieldNames ? '' : 'mime')
|
..aOS(1, _omitFieldNames ? '' : 'mime')
|
||||||
..aOS(2, _omitFieldNames ? '' : 'name')
|
..aOS(2, _omitFieldNames ? '' : 'name')
|
||||||
..aOM<$1.DataReference>(3, _omitFieldNames ? '' : 'content', subBuilder: $1.DataReference.create)
|
..aOM<DataReference>(3, _omitFieldNames ? '' : 'content', subBuilder: DataReference.create)
|
||||||
..hasRequiredFields = false
|
..hasRequiredFields = false
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -142,15 +313,15 @@ class AttachmentMedia extends $pb.GeneratedMessage {
|
||||||
void clearName() => clearField(2);
|
void clearName() => clearField(2);
|
||||||
|
|
||||||
@$pb.TagNumber(3)
|
@$pb.TagNumber(3)
|
||||||
$1.DataReference get content => $_getN(2);
|
DataReference get content => $_getN(2);
|
||||||
@$pb.TagNumber(3)
|
@$pb.TagNumber(3)
|
||||||
set content($1.DataReference v) { setField(3, v); }
|
set content(DataReference v) { setField(3, v); }
|
||||||
@$pb.TagNumber(3)
|
@$pb.TagNumber(3)
|
||||||
$core.bool hasContent() => $_has(2);
|
$core.bool hasContent() => $_has(2);
|
||||||
@$pb.TagNumber(3)
|
@$pb.TagNumber(3)
|
||||||
void clearContent() => clearField(3);
|
void clearContent() => clearField(3);
|
||||||
@$pb.TagNumber(3)
|
@$pb.TagNumber(3)
|
||||||
$1.DataReference ensureContent() => $_ensure(2);
|
DataReference ensureContent() => $_ensure(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
class Permissions extends $pb.GeneratedMessage {
|
class Permissions extends $pb.GeneratedMessage {
|
||||||
|
@ -276,7 +447,7 @@ class ChatSettings extends $pb.GeneratedMessage {
|
||||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'ChatSettings', package: const $pb.PackageName(_omitMessageNames ? '' : 'veilidchat'), createEmptyInstance: create)
|
static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'ChatSettings', package: const $pb.PackageName(_omitMessageNames ? '' : 'veilidchat'), createEmptyInstance: create)
|
||||||
..aOS(1, _omitFieldNames ? '' : 'title')
|
..aOS(1, _omitFieldNames ? '' : 'title')
|
||||||
..aOS(2, _omitFieldNames ? '' : 'description')
|
..aOS(2, _omitFieldNames ? '' : 'description')
|
||||||
..aOM<$1.DataReference>(3, _omitFieldNames ? '' : 'icon', subBuilder: $1.DataReference.create)
|
..aOM<DataReference>(3, _omitFieldNames ? '' : 'icon', subBuilder: DataReference.create)
|
||||||
..a<$fixnum.Int64>(4, _omitFieldNames ? '' : 'defaultExpiration', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO)
|
..a<$fixnum.Int64>(4, _omitFieldNames ? '' : 'defaultExpiration', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO)
|
||||||
..hasRequiredFields = false
|
..hasRequiredFields = false
|
||||||
;
|
;
|
||||||
|
@ -321,15 +492,15 @@ class ChatSettings extends $pb.GeneratedMessage {
|
||||||
void clearDescription() => clearField(2);
|
void clearDescription() => clearField(2);
|
||||||
|
|
||||||
@$pb.TagNumber(3)
|
@$pb.TagNumber(3)
|
||||||
$1.DataReference get icon => $_getN(2);
|
DataReference get icon => $_getN(2);
|
||||||
@$pb.TagNumber(3)
|
@$pb.TagNumber(3)
|
||||||
set icon($1.DataReference v) { setField(3, v); }
|
set icon(DataReference v) { setField(3, v); }
|
||||||
@$pb.TagNumber(3)
|
@$pb.TagNumber(3)
|
||||||
$core.bool hasIcon() => $_has(2);
|
$core.bool hasIcon() => $_has(2);
|
||||||
@$pb.TagNumber(3)
|
@$pb.TagNumber(3)
|
||||||
void clearIcon() => clearField(3);
|
void clearIcon() => clearField(3);
|
||||||
@$pb.TagNumber(3)
|
@$pb.TagNumber(3)
|
||||||
$1.DataReference ensureIcon() => $_ensure(2);
|
DataReference ensureIcon() => $_ensure(2);
|
||||||
|
|
||||||
@$pb.TagNumber(4)
|
@$pb.TagNumber(4)
|
||||||
$fixnum.Int64 get defaultExpiration => $_getI64(3);
|
$fixnum.Int64 get defaultExpiration => $_getI64(3);
|
||||||
|
@ -1224,7 +1395,7 @@ class Profile extends $pb.GeneratedMessage {
|
||||||
..aOS(3, _omitFieldNames ? '' : 'about')
|
..aOS(3, _omitFieldNames ? '' : 'about')
|
||||||
..aOS(4, _omitFieldNames ? '' : 'status')
|
..aOS(4, _omitFieldNames ? '' : 'status')
|
||||||
..e<Availability>(5, _omitFieldNames ? '' : 'availability', $pb.PbFieldType.OE, defaultOrMaker: Availability.AVAILABILITY_UNSPECIFIED, valueOf: Availability.valueOf, enumValues: Availability.values)
|
..e<Availability>(5, _omitFieldNames ? '' : 'availability', $pb.PbFieldType.OE, defaultOrMaker: Availability.AVAILABILITY_UNSPECIFIED, valueOf: Availability.valueOf, enumValues: Availability.values)
|
||||||
..aOM<$0.TypedKey>(6, _omitFieldNames ? '' : 'avatar', subBuilder: $0.TypedKey.create)
|
..aOM<DataReference>(6, _omitFieldNames ? '' : 'avatar', subBuilder: DataReference.create)
|
||||||
..hasRequiredFields = false
|
..hasRequiredFields = false
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -1295,15 +1466,15 @@ class Profile extends $pb.GeneratedMessage {
|
||||||
void clearAvailability() => clearField(5);
|
void clearAvailability() => clearField(5);
|
||||||
|
|
||||||
@$pb.TagNumber(6)
|
@$pb.TagNumber(6)
|
||||||
$0.TypedKey get avatar => $_getN(5);
|
DataReference get avatar => $_getN(5);
|
||||||
@$pb.TagNumber(6)
|
@$pb.TagNumber(6)
|
||||||
set avatar($0.TypedKey v) { setField(6, v); }
|
set avatar(DataReference v) { setField(6, v); }
|
||||||
@$pb.TagNumber(6)
|
@$pb.TagNumber(6)
|
||||||
$core.bool hasAvatar() => $_has(5);
|
$core.bool hasAvatar() => $_has(5);
|
||||||
@$pb.TagNumber(6)
|
@$pb.TagNumber(6)
|
||||||
void clearAvatar() => clearField(6);
|
void clearAvatar() => clearField(6);
|
||||||
@$pb.TagNumber(6)
|
@$pb.TagNumber(6)
|
||||||
$0.TypedKey ensureAvatar() => $_ensure(5);
|
DataReference ensureAvatar() => $_ensure(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
class Account extends $pb.GeneratedMessage {
|
class Account extends $pb.GeneratedMessage {
|
||||||
|
|
|
@ -65,6 +65,51 @@ final $typed_data.Uint8List scopeDescriptor = $convert.base64Decode(
|
||||||
'CgVTY29wZRIMCghXQVRDSEVSUxAAEg0KCU1PREVSQVRFRBABEgsKB1RBTEtFUlMQAhIOCgpNT0'
|
'CgVTY29wZRIMCghXQVRDSEVSUxAAEg0KCU1PREVSQVRFRBABEgsKB1RBTEtFUlMQAhIOCgpNT0'
|
||||||
'RFUkFUT1JTEAMSCgoGQURNSU5TEAQ=');
|
'RFUkFUT1JTEAMSCgoGQURNSU5TEAQ=');
|
||||||
|
|
||||||
|
@$core.Deprecated('Use dHTDataReferenceDescriptor instead')
|
||||||
|
const DHTDataReference$json = {
|
||||||
|
'1': 'DHTDataReference',
|
||||||
|
'2': [
|
||||||
|
{'1': 'dht_data', '3': 1, '4': 1, '5': 11, '6': '.veilid.TypedKey', '10': 'dhtData'},
|
||||||
|
{'1': 'hash', '3': 2, '4': 1, '5': 11, '6': '.veilid.TypedKey', '10': 'hash'},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Descriptor for `DHTDataReference`. Decode as a `google.protobuf.DescriptorProto`.
|
||||||
|
final $typed_data.Uint8List dHTDataReferenceDescriptor = $convert.base64Decode(
|
||||||
|
'ChBESFREYXRhUmVmZXJlbmNlEisKCGRodF9kYXRhGAEgASgLMhAudmVpbGlkLlR5cGVkS2V5Ug'
|
||||||
|
'dkaHREYXRhEiQKBGhhc2gYAiABKAsyEC52ZWlsaWQuVHlwZWRLZXlSBGhhc2g=');
|
||||||
|
|
||||||
|
@$core.Deprecated('Use blockStoreDataReferenceDescriptor instead')
|
||||||
|
const BlockStoreDataReference$json = {
|
||||||
|
'1': 'BlockStoreDataReference',
|
||||||
|
'2': [
|
||||||
|
{'1': 'block', '3': 1, '4': 1, '5': 11, '6': '.veilid.TypedKey', '10': 'block'},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Descriptor for `BlockStoreDataReference`. Decode as a `google.protobuf.DescriptorProto`.
|
||||||
|
final $typed_data.Uint8List blockStoreDataReferenceDescriptor = $convert.base64Decode(
|
||||||
|
'ChdCbG9ja1N0b3JlRGF0YVJlZmVyZW5jZRImCgVibG9jaxgBIAEoCzIQLnZlaWxpZC5UeXBlZE'
|
||||||
|
'tleVIFYmxvY2s=');
|
||||||
|
|
||||||
|
@$core.Deprecated('Use dataReferenceDescriptor instead')
|
||||||
|
const DataReference$json = {
|
||||||
|
'1': 'DataReference',
|
||||||
|
'2': [
|
||||||
|
{'1': 'dht_data', '3': 1, '4': 1, '5': 11, '6': '.veilidchat.DHTDataReference', '9': 0, '10': 'dhtData'},
|
||||||
|
{'1': 'block_store_data', '3': 2, '4': 1, '5': 11, '6': '.veilidchat.BlockStoreDataReference', '9': 0, '10': 'blockStoreData'},
|
||||||
|
],
|
||||||
|
'8': [
|
||||||
|
{'1': 'kind'},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Descriptor for `DataReference`. Decode as a `google.protobuf.DescriptorProto`.
|
||||||
|
final $typed_data.Uint8List dataReferenceDescriptor = $convert.base64Decode(
|
||||||
|
'Cg1EYXRhUmVmZXJlbmNlEjkKCGRodF9kYXRhGAEgASgLMhwudmVpbGlkY2hhdC5ESFREYXRhUm'
|
||||||
|
'VmZXJlbmNlSABSB2RodERhdGESTwoQYmxvY2tfc3RvcmVfZGF0YRgCIAEoCzIjLnZlaWxpZGNo'
|
||||||
|
'YXQuQmxvY2tTdG9yZURhdGFSZWZlcmVuY2VIAFIOYmxvY2tTdG9yZURhdGFCBgoEa2luZA==');
|
||||||
|
|
||||||
@$core.Deprecated('Use attachmentDescriptor instead')
|
@$core.Deprecated('Use attachmentDescriptor instead')
|
||||||
const Attachment$json = {
|
const Attachment$json = {
|
||||||
'1': 'Attachment',
|
'1': 'Attachment',
|
||||||
|
@ -89,14 +134,14 @@ const AttachmentMedia$json = {
|
||||||
'2': [
|
'2': [
|
||||||
{'1': 'mime', '3': 1, '4': 1, '5': 9, '10': 'mime'},
|
{'1': 'mime', '3': 1, '4': 1, '5': 9, '10': 'mime'},
|
||||||
{'1': 'name', '3': 2, '4': 1, '5': 9, '10': 'name'},
|
{'1': 'name', '3': 2, '4': 1, '5': 9, '10': 'name'},
|
||||||
{'1': 'content', '3': 3, '4': 1, '5': 11, '6': '.dht.DataReference', '10': 'content'},
|
{'1': 'content', '3': 3, '4': 1, '5': 11, '6': '.veilidchat.DataReference', '10': 'content'},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Descriptor for `AttachmentMedia`. Decode as a `google.protobuf.DescriptorProto`.
|
/// Descriptor for `AttachmentMedia`. Decode as a `google.protobuf.DescriptorProto`.
|
||||||
final $typed_data.Uint8List attachmentMediaDescriptor = $convert.base64Decode(
|
final $typed_data.Uint8List attachmentMediaDescriptor = $convert.base64Decode(
|
||||||
'Cg9BdHRhY2htZW50TWVkaWESEgoEbWltZRgBIAEoCVIEbWltZRISCgRuYW1lGAIgASgJUgRuYW'
|
'Cg9BdHRhY2htZW50TWVkaWESEgoEbWltZRgBIAEoCVIEbWltZRISCgRuYW1lGAIgASgJUgRuYW'
|
||||||
'1lEiwKB2NvbnRlbnQYAyABKAsyEi5kaHQuRGF0YVJlZmVyZW5jZVIHY29udGVudA==');
|
'1lEjMKB2NvbnRlbnQYAyABKAsyGS52ZWlsaWRjaGF0LkRhdGFSZWZlcmVuY2VSB2NvbnRlbnQ=');
|
||||||
|
|
||||||
@$core.Deprecated('Use permissionsDescriptor instead')
|
@$core.Deprecated('Use permissionsDescriptor instead')
|
||||||
const Permissions$json = {
|
const Permissions$json = {
|
||||||
|
@ -140,7 +185,7 @@ const ChatSettings$json = {
|
||||||
'2': [
|
'2': [
|
||||||
{'1': 'title', '3': 1, '4': 1, '5': 9, '10': 'title'},
|
{'1': 'title', '3': 1, '4': 1, '5': 9, '10': 'title'},
|
||||||
{'1': 'description', '3': 2, '4': 1, '5': 9, '10': 'description'},
|
{'1': 'description', '3': 2, '4': 1, '5': 9, '10': 'description'},
|
||||||
{'1': 'icon', '3': 3, '4': 1, '5': 11, '6': '.dht.DataReference', '9': 0, '10': 'icon', '17': true},
|
{'1': 'icon', '3': 3, '4': 1, '5': 11, '6': '.veilidchat.DataReference', '9': 0, '10': 'icon', '17': true},
|
||||||
{'1': 'default_expiration', '3': 4, '4': 1, '5': 4, '10': 'defaultExpiration'},
|
{'1': 'default_expiration', '3': 4, '4': 1, '5': 4, '10': 'defaultExpiration'},
|
||||||
],
|
],
|
||||||
'8': [
|
'8': [
|
||||||
|
@ -151,9 +196,9 @@ const ChatSettings$json = {
|
||||||
/// Descriptor for `ChatSettings`. Decode as a `google.protobuf.DescriptorProto`.
|
/// Descriptor for `ChatSettings`. Decode as a `google.protobuf.DescriptorProto`.
|
||||||
final $typed_data.Uint8List chatSettingsDescriptor = $convert.base64Decode(
|
final $typed_data.Uint8List chatSettingsDescriptor = $convert.base64Decode(
|
||||||
'CgxDaGF0U2V0dGluZ3MSFAoFdGl0bGUYASABKAlSBXRpdGxlEiAKC2Rlc2NyaXB0aW9uGAIgAS'
|
'CgxDaGF0U2V0dGluZ3MSFAoFdGl0bGUYASABKAlSBXRpdGxlEiAKC2Rlc2NyaXB0aW9uGAIgAS'
|
||||||
'gJUgtkZXNjcmlwdGlvbhIrCgRpY29uGAMgASgLMhIuZGh0LkRhdGFSZWZlcmVuY2VIAFIEaWNv'
|
'gJUgtkZXNjcmlwdGlvbhIyCgRpY29uGAMgASgLMhkudmVpbGlkY2hhdC5EYXRhUmVmZXJlbmNl'
|
||||||
'bogBARItChJkZWZhdWx0X2V4cGlyYXRpb24YBCABKARSEWRlZmF1bHRFeHBpcmF0aW9uQgcKBV'
|
'SABSBGljb26IAQESLQoSZGVmYXVsdF9leHBpcmF0aW9uGAQgASgEUhFkZWZhdWx0RXhwaXJhdG'
|
||||||
'9pY29u');
|
'lvbkIHCgVfaWNvbg==');
|
||||||
|
|
||||||
@$core.Deprecated('Use messageDescriptor instead')
|
@$core.Deprecated('Use messageDescriptor instead')
|
||||||
const Message$json = {
|
const Message$json = {
|
||||||
|
@ -365,7 +410,7 @@ const Profile$json = {
|
||||||
{'1': 'about', '3': 3, '4': 1, '5': 9, '10': 'about'},
|
{'1': 'about', '3': 3, '4': 1, '5': 9, '10': 'about'},
|
||||||
{'1': 'status', '3': 4, '4': 1, '5': 9, '10': 'status'},
|
{'1': 'status', '3': 4, '4': 1, '5': 9, '10': 'status'},
|
||||||
{'1': 'availability', '3': 5, '4': 1, '5': 14, '6': '.veilidchat.Availability', '10': 'availability'},
|
{'1': 'availability', '3': 5, '4': 1, '5': 14, '6': '.veilidchat.Availability', '10': 'availability'},
|
||||||
{'1': 'avatar', '3': 6, '4': 1, '5': 11, '6': '.veilid.TypedKey', '9': 0, '10': 'avatar', '17': true},
|
{'1': 'avatar', '3': 6, '4': 1, '5': 11, '6': '.veilidchat.DataReference', '9': 0, '10': 'avatar', '17': true},
|
||||||
],
|
],
|
||||||
'8': [
|
'8': [
|
||||||
{'1': '_avatar'},
|
{'1': '_avatar'},
|
||||||
|
@ -376,9 +421,9 @@ const Profile$json = {
|
||||||
final $typed_data.Uint8List profileDescriptor = $convert.base64Decode(
|
final $typed_data.Uint8List profileDescriptor = $convert.base64Decode(
|
||||||
'CgdQcm9maWxlEhIKBG5hbWUYASABKAlSBG5hbWUSGgoIcHJvbm91bnMYAiABKAlSCHByb25vdW'
|
'CgdQcm9maWxlEhIKBG5hbWUYASABKAlSBG5hbWUSGgoIcHJvbm91bnMYAiABKAlSCHByb25vdW'
|
||||||
'5zEhQKBWFib3V0GAMgASgJUgVhYm91dBIWCgZzdGF0dXMYBCABKAlSBnN0YXR1cxI8CgxhdmFp'
|
'5zEhQKBWFib3V0GAMgASgJUgVhYm91dBIWCgZzdGF0dXMYBCABKAlSBnN0YXR1cxI8CgxhdmFp'
|
||||||
'bGFiaWxpdHkYBSABKA4yGC52ZWlsaWRjaGF0LkF2YWlsYWJpbGl0eVIMYXZhaWxhYmlsaXR5Ei'
|
'bGFiaWxpdHkYBSABKA4yGC52ZWlsaWRjaGF0LkF2YWlsYWJpbGl0eVIMYXZhaWxhYmlsaXR5Ej'
|
||||||
'0KBmF2YXRhchgGIAEoCzIQLnZlaWxpZC5UeXBlZEtleUgAUgZhdmF0YXKIAQFCCQoHX2F2YXRh'
|
'YKBmF2YXRhchgGIAEoCzIZLnZlaWxpZGNoYXQuRGF0YVJlZmVyZW5jZUgAUgZhdmF0YXKIAQFC'
|
||||||
'cg==');
|
'CQoHX2F2YXRhcg==');
|
||||||
|
|
||||||
@$core.Deprecated('Use accountDescriptor instead')
|
@$core.Deprecated('Use accountDescriptor instead')
|
||||||
const Account$json = {
|
const Account$json = {
|
||||||
|
|
|
@ -47,6 +47,31 @@ enum Scope {
|
||||||
ADMINS = 4;
|
ADMINS = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Data
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Reference to data on the DHT
|
||||||
|
message DHTDataReference {
|
||||||
|
veilid.TypedKey dht_data = 1;
|
||||||
|
veilid.TypedKey hash = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reference to data on the BlockStore
|
||||||
|
message BlockStoreDataReference {
|
||||||
|
veilid.TypedKey block = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// DataReference
|
||||||
|
// Pointer to data somewhere in Veilid
|
||||||
|
// Abstraction over DHTData and BlockStore
|
||||||
|
message DataReference {
|
||||||
|
oneof kind {
|
||||||
|
DHTDataReference dht_data = 1;
|
||||||
|
BlockStoreDataReference block_store_data = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Attachments
|
// Attachments
|
||||||
////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -67,10 +92,9 @@ message AttachmentMedia {
|
||||||
// Title or filename
|
// Title or filename
|
||||||
string name = 2;
|
string name = 2;
|
||||||
// Pointer to the data content
|
// Pointer to the data content
|
||||||
dht.DataReference content = 3;
|
DataReference content = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Chat room controls
|
// Chat room controls
|
||||||
////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -106,7 +130,7 @@ message ChatSettings {
|
||||||
// Description for the chat
|
// Description for the chat
|
||||||
string description = 2;
|
string description = 2;
|
||||||
// Icon for the chat
|
// Icon for the chat
|
||||||
optional dht.DataReference icon = 3;
|
optional DataReference icon = 3;
|
||||||
// Default message expiration duration (in us)
|
// Default message expiration duration (in us)
|
||||||
uint64 default_expiration = 4;
|
uint64 default_expiration = 4;
|
||||||
}
|
}
|
||||||
|
@ -285,8 +309,8 @@ message Profile {
|
||||||
string status = 4;
|
string status = 4;
|
||||||
// Availability
|
// Availability
|
||||||
Availability availability = 5;
|
Availability availability = 5;
|
||||||
// Avatar DHTData
|
// Avatar
|
||||||
optional veilid.TypedKey avatar = 6;
|
optional DataReference avatar = 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
// A record of an individual account
|
// A record of an individual account
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import 'package:async_tools/async_tools.dart';
|
import 'package:async_tools/async_tools.dart';
|
||||||
import 'package:awesome_extensions/awesome_extensions.dart';
|
import 'package:awesome_extensions/awesome_extensions.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
|
@ -11,7 +12,7 @@ import '../../theme/theme.dart';
|
||||||
import '../cubit/connection_state_cubit.dart';
|
import '../cubit/connection_state_cubit.dart';
|
||||||
|
|
||||||
class SignalStrengthMeterWidget extends StatelessWidget {
|
class SignalStrengthMeterWidget extends StatelessWidget {
|
||||||
const SignalStrengthMeterWidget({super.key});
|
const SignalStrengthMeterWidget({super.key, this.color, this.inactiveColor});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
// ignore: prefer_expression_function_bodies
|
// ignore: prefer_expression_function_bodies
|
||||||
|
@ -33,32 +34,35 @@ class SignalStrengthMeterWidget extends StatelessWidget {
|
||||||
switch (connectionState.attachment.state) {
|
switch (connectionState.attachment.state) {
|
||||||
case AttachmentState.detached:
|
case AttachmentState.detached:
|
||||||
iconWidget = Icon(Icons.signal_cellular_nodata,
|
iconWidget = Icon(Icons.signal_cellular_nodata,
|
||||||
size: iconSize, color: scale.primaryScale.primaryText);
|
size: iconSize,
|
||||||
|
color: this.color ?? scale.primaryScale.primaryText);
|
||||||
return;
|
return;
|
||||||
case AttachmentState.detaching:
|
case AttachmentState.detaching:
|
||||||
iconWidget = Icon(Icons.signal_cellular_off,
|
iconWidget = Icon(Icons.signal_cellular_off,
|
||||||
size: iconSize, color: scale.primaryScale.primaryText);
|
size: iconSize,
|
||||||
|
color: this.color ?? scale.primaryScale.primaryText);
|
||||||
return;
|
return;
|
||||||
case AttachmentState.attaching:
|
case AttachmentState.attaching:
|
||||||
value = 0;
|
value = 0;
|
||||||
color = scale.primaryScale.primaryText;
|
color = this.color ?? scale.primaryScale.primaryText;
|
||||||
case AttachmentState.attachedWeak:
|
case AttachmentState.attachedWeak:
|
||||||
value = 1;
|
value = 1;
|
||||||
color = scale.primaryScale.primaryText;
|
color = this.color ?? scale.primaryScale.primaryText;
|
||||||
case AttachmentState.attachedStrong:
|
case AttachmentState.attachedStrong:
|
||||||
value = 2;
|
value = 2;
|
||||||
color = scale.primaryScale.primaryText;
|
color = this.color ?? scale.primaryScale.primaryText;
|
||||||
case AttachmentState.attachedGood:
|
case AttachmentState.attachedGood:
|
||||||
value = 3;
|
value = 3;
|
||||||
color = scale.primaryScale.primaryText;
|
color = this.color ?? scale.primaryScale.primaryText;
|
||||||
case AttachmentState.fullyAttached:
|
case AttachmentState.fullyAttached:
|
||||||
value = 4;
|
value = 4;
|
||||||
color = scale.primaryScale.primaryText;
|
color = this.color ?? scale.primaryScale.primaryText;
|
||||||
case AttachmentState.overAttached:
|
case AttachmentState.overAttached:
|
||||||
value = 4;
|
value = 4;
|
||||||
color = scale.primaryScale.primaryText;
|
color = this.color ?? scale.primaryScale.primaryText;
|
||||||
}
|
}
|
||||||
inactiveColor = scale.primaryScale.primaryText;
|
inactiveColor =
|
||||||
|
this.inactiveColor ?? scale.primaryScale.primaryText;
|
||||||
|
|
||||||
iconWidget = SignalStrengthIndicator.bars(
|
iconWidget = SignalStrengthIndicator.bars(
|
||||||
value: value,
|
value: value,
|
||||||
|
@ -86,4 +90,16 @@ class SignalStrengthMeterWidget extends StatelessWidget {
|
||||||
child: iconWidget);
|
child: iconWidget);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
final Color? color;
|
||||||
|
final Color? inactiveColor;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||||
|
super.debugFillProperties(properties);
|
||||||
|
properties
|
||||||
|
..add(ColorProperty('color', color))
|
||||||
|
..add(ColorProperty('inactiveColor', inactiveColor));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,6 @@ message DHTData {
|
||||||
uint32 size = 4;
|
uint32 size = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// DHTLog - represents a ring buffer of many elements with append/truncate semantics
|
// DHTLog - represents a ring buffer of many elements with append/truncate semantics
|
||||||
// Header in subkey 0 of first key follows this structure
|
// Header in subkey 0 of first key follows this structure
|
||||||
message DHTLog {
|
message DHTLog {
|
||||||
|
@ -62,27 +61,6 @@ message DHTShortArray {
|
||||||
// calculated through iteration
|
// calculated through iteration
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reference to data on the DHT
|
|
||||||
message DHTDataReference {
|
|
||||||
veilid.TypedKey dht_data = 1;
|
|
||||||
veilid.TypedKey hash = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reference to data on the BlockStore
|
|
||||||
message BlockStoreDataReference {
|
|
||||||
veilid.TypedKey block = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// DataReference
|
|
||||||
// Pointer to data somewhere in Veilid
|
|
||||||
// Abstraction over DHTData and BlockStore
|
|
||||||
message DataReference {
|
|
||||||
oneof kind {
|
|
||||||
DHTDataReference dht_data = 1;
|
|
||||||
BlockStoreDataReference block_store_data = 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// A pointer to an child DHT record
|
// A pointer to an child DHT record
|
||||||
message OwnedDHTRecordPointer {
|
message OwnedDHTRecordPointer {
|
||||||
// DHT Record key
|
// DHT Record key
|
||||||
|
|
|
@ -195,177 +195,6 @@ class DHTShortArray extends $pb.GeneratedMessage {
|
||||||
$core.List<$core.int> get seqs => $_getList(2);
|
$core.List<$core.int> get seqs => $_getList(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
class DHTDataReference extends $pb.GeneratedMessage {
|
|
||||||
factory DHTDataReference() => create();
|
|
||||||
DHTDataReference._() : super();
|
|
||||||
factory DHTDataReference.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
|
|
||||||
factory DHTDataReference.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
|
|
||||||
|
|
||||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'DHTDataReference', package: const $pb.PackageName(_omitMessageNames ? '' : 'dht'), createEmptyInstance: create)
|
|
||||||
..aOM<$0.TypedKey>(1, _omitFieldNames ? '' : 'dhtData', subBuilder: $0.TypedKey.create)
|
|
||||||
..aOM<$0.TypedKey>(2, _omitFieldNames ? '' : 'hash', subBuilder: $0.TypedKey.create)
|
|
||||||
..hasRequiredFields = false
|
|
||||||
;
|
|
||||||
|
|
||||||
@$core.Deprecated(
|
|
||||||
'Using this can add significant overhead to your binary. '
|
|
||||||
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
|
|
||||||
'Will be removed in next major version')
|
|
||||||
DHTDataReference clone() => DHTDataReference()..mergeFromMessage(this);
|
|
||||||
@$core.Deprecated(
|
|
||||||
'Using this can add significant overhead to your binary. '
|
|
||||||
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
|
|
||||||
'Will be removed in next major version')
|
|
||||||
DHTDataReference copyWith(void Function(DHTDataReference) updates) => super.copyWith((message) => updates(message as DHTDataReference)) as DHTDataReference;
|
|
||||||
|
|
||||||
$pb.BuilderInfo get info_ => _i;
|
|
||||||
|
|
||||||
@$core.pragma('dart2js:noInline')
|
|
||||||
static DHTDataReference create() => DHTDataReference._();
|
|
||||||
DHTDataReference createEmptyInstance() => create();
|
|
||||||
static $pb.PbList<DHTDataReference> createRepeated() => $pb.PbList<DHTDataReference>();
|
|
||||||
@$core.pragma('dart2js:noInline')
|
|
||||||
static DHTDataReference getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<DHTDataReference>(create);
|
|
||||||
static DHTDataReference? _defaultInstance;
|
|
||||||
|
|
||||||
@$pb.TagNumber(1)
|
|
||||||
$0.TypedKey get dhtData => $_getN(0);
|
|
||||||
@$pb.TagNumber(1)
|
|
||||||
set dhtData($0.TypedKey v) { setField(1, v); }
|
|
||||||
@$pb.TagNumber(1)
|
|
||||||
$core.bool hasDhtData() => $_has(0);
|
|
||||||
@$pb.TagNumber(1)
|
|
||||||
void clearDhtData() => clearField(1);
|
|
||||||
@$pb.TagNumber(1)
|
|
||||||
$0.TypedKey ensureDhtData() => $_ensure(0);
|
|
||||||
|
|
||||||
@$pb.TagNumber(2)
|
|
||||||
$0.TypedKey get hash => $_getN(1);
|
|
||||||
@$pb.TagNumber(2)
|
|
||||||
set hash($0.TypedKey v) { setField(2, v); }
|
|
||||||
@$pb.TagNumber(2)
|
|
||||||
$core.bool hasHash() => $_has(1);
|
|
||||||
@$pb.TagNumber(2)
|
|
||||||
void clearHash() => clearField(2);
|
|
||||||
@$pb.TagNumber(2)
|
|
||||||
$0.TypedKey ensureHash() => $_ensure(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
class BlockStoreDataReference extends $pb.GeneratedMessage {
|
|
||||||
factory BlockStoreDataReference() => create();
|
|
||||||
BlockStoreDataReference._() : super();
|
|
||||||
factory BlockStoreDataReference.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
|
|
||||||
factory BlockStoreDataReference.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
|
|
||||||
|
|
||||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'BlockStoreDataReference', package: const $pb.PackageName(_omitMessageNames ? '' : 'dht'), createEmptyInstance: create)
|
|
||||||
..aOM<$0.TypedKey>(1, _omitFieldNames ? '' : 'block', subBuilder: $0.TypedKey.create)
|
|
||||||
..hasRequiredFields = false
|
|
||||||
;
|
|
||||||
|
|
||||||
@$core.Deprecated(
|
|
||||||
'Using this can add significant overhead to your binary. '
|
|
||||||
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
|
|
||||||
'Will be removed in next major version')
|
|
||||||
BlockStoreDataReference clone() => BlockStoreDataReference()..mergeFromMessage(this);
|
|
||||||
@$core.Deprecated(
|
|
||||||
'Using this can add significant overhead to your binary. '
|
|
||||||
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
|
|
||||||
'Will be removed in next major version')
|
|
||||||
BlockStoreDataReference copyWith(void Function(BlockStoreDataReference) updates) => super.copyWith((message) => updates(message as BlockStoreDataReference)) as BlockStoreDataReference;
|
|
||||||
|
|
||||||
$pb.BuilderInfo get info_ => _i;
|
|
||||||
|
|
||||||
@$core.pragma('dart2js:noInline')
|
|
||||||
static BlockStoreDataReference create() => BlockStoreDataReference._();
|
|
||||||
BlockStoreDataReference createEmptyInstance() => create();
|
|
||||||
static $pb.PbList<BlockStoreDataReference> createRepeated() => $pb.PbList<BlockStoreDataReference>();
|
|
||||||
@$core.pragma('dart2js:noInline')
|
|
||||||
static BlockStoreDataReference getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<BlockStoreDataReference>(create);
|
|
||||||
static BlockStoreDataReference? _defaultInstance;
|
|
||||||
|
|
||||||
@$pb.TagNumber(1)
|
|
||||||
$0.TypedKey get block => $_getN(0);
|
|
||||||
@$pb.TagNumber(1)
|
|
||||||
set block($0.TypedKey v) { setField(1, v); }
|
|
||||||
@$pb.TagNumber(1)
|
|
||||||
$core.bool hasBlock() => $_has(0);
|
|
||||||
@$pb.TagNumber(1)
|
|
||||||
void clearBlock() => clearField(1);
|
|
||||||
@$pb.TagNumber(1)
|
|
||||||
$0.TypedKey ensureBlock() => $_ensure(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
enum DataReference_Kind {
|
|
||||||
dhtData,
|
|
||||||
blockStoreData,
|
|
||||||
notSet
|
|
||||||
}
|
|
||||||
|
|
||||||
class DataReference extends $pb.GeneratedMessage {
|
|
||||||
factory DataReference() => create();
|
|
||||||
DataReference._() : super();
|
|
||||||
factory DataReference.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
|
|
||||||
factory DataReference.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
|
|
||||||
|
|
||||||
static const $core.Map<$core.int, DataReference_Kind> _DataReference_KindByTag = {
|
|
||||||
1 : DataReference_Kind.dhtData,
|
|
||||||
2 : DataReference_Kind.blockStoreData,
|
|
||||||
0 : DataReference_Kind.notSet
|
|
||||||
};
|
|
||||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'DataReference', package: const $pb.PackageName(_omitMessageNames ? '' : 'dht'), createEmptyInstance: create)
|
|
||||||
..oo(0, [1, 2])
|
|
||||||
..aOM<DHTDataReference>(1, _omitFieldNames ? '' : 'dhtData', subBuilder: DHTDataReference.create)
|
|
||||||
..aOM<BlockStoreDataReference>(2, _omitFieldNames ? '' : 'blockStoreData', subBuilder: BlockStoreDataReference.create)
|
|
||||||
..hasRequiredFields = false
|
|
||||||
;
|
|
||||||
|
|
||||||
@$core.Deprecated(
|
|
||||||
'Using this can add significant overhead to your binary. '
|
|
||||||
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
|
|
||||||
'Will be removed in next major version')
|
|
||||||
DataReference clone() => DataReference()..mergeFromMessage(this);
|
|
||||||
@$core.Deprecated(
|
|
||||||
'Using this can add significant overhead to your binary. '
|
|
||||||
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
|
|
||||||
'Will be removed in next major version')
|
|
||||||
DataReference copyWith(void Function(DataReference) updates) => super.copyWith((message) => updates(message as DataReference)) as DataReference;
|
|
||||||
|
|
||||||
$pb.BuilderInfo get info_ => _i;
|
|
||||||
|
|
||||||
@$core.pragma('dart2js:noInline')
|
|
||||||
static DataReference create() => DataReference._();
|
|
||||||
DataReference createEmptyInstance() => create();
|
|
||||||
static $pb.PbList<DataReference> createRepeated() => $pb.PbList<DataReference>();
|
|
||||||
@$core.pragma('dart2js:noInline')
|
|
||||||
static DataReference getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<DataReference>(create);
|
|
||||||
static DataReference? _defaultInstance;
|
|
||||||
|
|
||||||
DataReference_Kind whichKind() => _DataReference_KindByTag[$_whichOneof(0)]!;
|
|
||||||
void clearKind() => clearField($_whichOneof(0));
|
|
||||||
|
|
||||||
@$pb.TagNumber(1)
|
|
||||||
DHTDataReference get dhtData => $_getN(0);
|
|
||||||
@$pb.TagNumber(1)
|
|
||||||
set dhtData(DHTDataReference v) { setField(1, v); }
|
|
||||||
@$pb.TagNumber(1)
|
|
||||||
$core.bool hasDhtData() => $_has(0);
|
|
||||||
@$pb.TagNumber(1)
|
|
||||||
void clearDhtData() => clearField(1);
|
|
||||||
@$pb.TagNumber(1)
|
|
||||||
DHTDataReference ensureDhtData() => $_ensure(0);
|
|
||||||
|
|
||||||
@$pb.TagNumber(2)
|
|
||||||
BlockStoreDataReference get blockStoreData => $_getN(1);
|
|
||||||
@$pb.TagNumber(2)
|
|
||||||
set blockStoreData(BlockStoreDataReference v) { setField(2, v); }
|
|
||||||
@$pb.TagNumber(2)
|
|
||||||
$core.bool hasBlockStoreData() => $_has(1);
|
|
||||||
@$pb.TagNumber(2)
|
|
||||||
void clearBlockStoreData() => clearField(2);
|
|
||||||
@$pb.TagNumber(2)
|
|
||||||
BlockStoreDataReference ensureBlockStoreData() => $_ensure(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
class OwnedDHTRecordPointer extends $pb.GeneratedMessage {
|
class OwnedDHTRecordPointer extends $pb.GeneratedMessage {
|
||||||
factory OwnedDHTRecordPointer() => create();
|
factory OwnedDHTRecordPointer() => create();
|
||||||
OwnedDHTRecordPointer._() : super();
|
OwnedDHTRecordPointer._() : super();
|
||||||
|
|
|
@ -60,51 +60,6 @@ final $typed_data.Uint8List dHTShortArrayDescriptor = $convert.base64Decode(
|
||||||
'Cg1ESFRTaG9ydEFycmF5EiQKBGtleXMYASADKAsyEC52ZWlsaWQuVHlwZWRLZXlSBGtleXMSFA'
|
'Cg1ESFRTaG9ydEFycmF5EiQKBGtleXMYASADKAsyEC52ZWlsaWQuVHlwZWRLZXlSBGtleXMSFA'
|
||||||
'oFaW5kZXgYAiABKAxSBWluZGV4EhIKBHNlcXMYAyADKA1SBHNlcXM=');
|
'oFaW5kZXgYAiABKAxSBWluZGV4EhIKBHNlcXMYAyADKA1SBHNlcXM=');
|
||||||
|
|
||||||
@$core.Deprecated('Use dHTDataReferenceDescriptor instead')
|
|
||||||
const DHTDataReference$json = {
|
|
||||||
'1': 'DHTDataReference',
|
|
||||||
'2': [
|
|
||||||
{'1': 'dht_data', '3': 1, '4': 1, '5': 11, '6': '.veilid.TypedKey', '10': 'dhtData'},
|
|
||||||
{'1': 'hash', '3': 2, '4': 1, '5': 11, '6': '.veilid.TypedKey', '10': 'hash'},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Descriptor for `DHTDataReference`. Decode as a `google.protobuf.DescriptorProto`.
|
|
||||||
final $typed_data.Uint8List dHTDataReferenceDescriptor = $convert.base64Decode(
|
|
||||||
'ChBESFREYXRhUmVmZXJlbmNlEisKCGRodF9kYXRhGAEgASgLMhAudmVpbGlkLlR5cGVkS2V5Ug'
|
|
||||||
'dkaHREYXRhEiQKBGhhc2gYAiABKAsyEC52ZWlsaWQuVHlwZWRLZXlSBGhhc2g=');
|
|
||||||
|
|
||||||
@$core.Deprecated('Use blockStoreDataReferenceDescriptor instead')
|
|
||||||
const BlockStoreDataReference$json = {
|
|
||||||
'1': 'BlockStoreDataReference',
|
|
||||||
'2': [
|
|
||||||
{'1': 'block', '3': 1, '4': 1, '5': 11, '6': '.veilid.TypedKey', '10': 'block'},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Descriptor for `BlockStoreDataReference`. Decode as a `google.protobuf.DescriptorProto`.
|
|
||||||
final $typed_data.Uint8List blockStoreDataReferenceDescriptor = $convert.base64Decode(
|
|
||||||
'ChdCbG9ja1N0b3JlRGF0YVJlZmVyZW5jZRImCgVibG9jaxgBIAEoCzIQLnZlaWxpZC5UeXBlZE'
|
|
||||||
'tleVIFYmxvY2s=');
|
|
||||||
|
|
||||||
@$core.Deprecated('Use dataReferenceDescriptor instead')
|
|
||||||
const DataReference$json = {
|
|
||||||
'1': 'DataReference',
|
|
||||||
'2': [
|
|
||||||
{'1': 'dht_data', '3': 1, '4': 1, '5': 11, '6': '.dht.DHTDataReference', '9': 0, '10': 'dhtData'},
|
|
||||||
{'1': 'block_store_data', '3': 2, '4': 1, '5': 11, '6': '.dht.BlockStoreDataReference', '9': 0, '10': 'blockStoreData'},
|
|
||||||
],
|
|
||||||
'8': [
|
|
||||||
{'1': 'kind'},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Descriptor for `DataReference`. Decode as a `google.protobuf.DescriptorProto`.
|
|
||||||
final $typed_data.Uint8List dataReferenceDescriptor = $convert.base64Decode(
|
|
||||||
'Cg1EYXRhUmVmZXJlbmNlEjIKCGRodF9kYXRhGAEgASgLMhUuZGh0LkRIVERhdGFSZWZlcmVuY2'
|
|
||||||
'VIAFIHZGh0RGF0YRJIChBibG9ja19zdG9yZV9kYXRhGAIgASgLMhwuZGh0LkJsb2NrU3RvcmVE'
|
|
||||||
'YXRhUmVmZXJlbmNlSABSDmJsb2NrU3RvcmVEYXRhQgYKBGtpbmQ=');
|
|
||||||
|
|
||||||
@$core.Deprecated('Use ownedDHTRecordPointerDescriptor instead')
|
@$core.Deprecated('Use ownedDHTRecordPointerDescriptor instead')
|
||||||
const OwnedDHTRecordPointer$json = {
|
const OwnedDHTRecordPointer$json = {
|
||||||
'1': 'OwnedDHTRecordPointer',
|
'1': 'OwnedDHTRecordPointer',
|
||||||
|
|
|
@ -52,11 +52,10 @@ packages:
|
||||||
bloc_advanced_tools:
|
bloc_advanced_tools:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: bloc_advanced_tools
|
path: "../../../bloc_advanced_tools"
|
||||||
sha256: "0cf9b3a73a67addfe22ec3f97a1ac240f6ad53870d6b21a980260f390d7901cd"
|
relative: true
|
||||||
url: "https://pub.dev"
|
source: path
|
||||||
source: hosted
|
version: "0.1.3"
|
||||||
version: "0.1.2"
|
|
||||||
boolean_selector:
|
boolean_selector:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -9,7 +9,7 @@ environment:
|
||||||
dependencies:
|
dependencies:
|
||||||
async_tools: ^0.1.2
|
async_tools: ^0.1.2
|
||||||
bloc: ^8.1.4
|
bloc: ^8.1.4
|
||||||
bloc_advanced_tools: ^0.1.2
|
bloc_advanced_tools: ^0.1.3
|
||||||
charcode: ^1.3.1
|
charcode: ^1.3.1
|
||||||
collection: ^1.18.0
|
collection: ^1.18.0
|
||||||
equatable: ^2.0.5
|
equatable: ^2.0.5
|
||||||
|
@ -24,11 +24,11 @@ dependencies:
|
||||||
# veilid: ^0.0.1
|
# veilid: ^0.0.1
|
||||||
path: ../../../veilid/veilid-flutter
|
path: ../../../veilid/veilid-flutter
|
||||||
|
|
||||||
# dependency_overrides:
|
dependency_overrides:
|
||||||
# async_tools:
|
# async_tools:
|
||||||
# path: ../../../dart_async_tools
|
# path: ../../../dart_async_tools
|
||||||
# bloc_advanced_tools:
|
bloc_advanced_tools:
|
||||||
# path: ../../../bloc_advanced_tools
|
path: ../../../bloc_advanced_tools
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
build_runner: ^2.4.10
|
build_runner: ^2.4.10
|
||||||
|
|
|
@ -100,11 +100,10 @@ packages:
|
||||||
bloc_advanced_tools:
|
bloc_advanced_tools:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: bloc_advanced_tools
|
path: "../bloc_advanced_tools"
|
||||||
sha256: "0cf9b3a73a67addfe22ec3f97a1ac240f6ad53870d6b21a980260f390d7901cd"
|
relative: true
|
||||||
url: "https://pub.dev"
|
source: path
|
||||||
source: hosted
|
version: "0.1.3"
|
||||||
version: "0.1.2"
|
|
||||||
blurry_modal_progress_hud:
|
blurry_modal_progress_hud:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -16,7 +16,7 @@ dependencies:
|
||||||
badges: ^3.1.2
|
badges: ^3.1.2
|
||||||
basic_utils: ^5.7.0
|
basic_utils: ^5.7.0
|
||||||
bloc: ^8.1.4
|
bloc: ^8.1.4
|
||||||
bloc_advanced_tools: ^0.1.2
|
bloc_advanced_tools: ^0.1.3
|
||||||
blurry_modal_progress_hud: ^1.1.1
|
blurry_modal_progress_hud: ^1.1.1
|
||||||
change_case: ^2.1.0
|
change_case: ^2.1.0
|
||||||
charcode: ^1.3.1
|
charcode: ^1.3.1
|
||||||
|
@ -93,11 +93,11 @@ dependencies:
|
||||||
xterm: ^4.0.0
|
xterm: ^4.0.0
|
||||||
zxing2: ^0.2.3
|
zxing2: ^0.2.3
|
||||||
|
|
||||||
# dependency_overrides:
|
dependency_overrides:
|
||||||
# async_tools:
|
# async_tools:
|
||||||
# path: ../dart_async_tools
|
# path: ../dart_async_tools
|
||||||
# bloc_advanced_tools:
|
bloc_advanced_tools:
|
||||||
# path: ../bloc_advanced_tools
|
path: ../bloc_advanced_tools
|
||||||
# flutter_chat_ui:
|
# flutter_chat_ui:
|
||||||
# path: ../flutter_chat_ui
|
# path: ../flutter_chat_ui
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue