mirror of
https://gitlab.com/veilid/veilidchat.git
synced 2024-10-01 06:55:46 -04:00
more refactor
This commit is contained in:
parent
45ab494969
commit
9219e1307e
@ -1,4 +1,4 @@
|
||||
export 'cubit/cubit.dart';
|
||||
export 'cubits/cubits.dart';
|
||||
export 'models/models.dart';
|
||||
export 'repository/repository.dart';
|
||||
export 'views/views.dart';
|
||||
|
@ -1,3 +0,0 @@
|
||||
part of 'active_user_login_cubit.dart';
|
||||
|
||||
typedef ActiveUserLoginState = TypedKey?;
|
@ -1,4 +0,0 @@
|
||||
export 'account_record_cubit.dart';
|
||||
export 'active_user_login_cubit/active_user_login_cubit.dart';
|
||||
export 'local_accounts_cubit/local_accounts_cubit.dart';
|
||||
export 'user_logins_cubit/user_logins_cubit.dart';
|
@ -1,14 +0,0 @@
|
||||
part of 'local_accounts_cubit.dart';
|
||||
|
||||
typedef LocalAccountsState = IList<LocalAccount>;
|
||||
|
||||
extension LocalAccountsStateExt on LocalAccountsState {
|
||||
LocalAccount? fetchLocalAccount({required TypedKey accountMasterRecordKey}) {
|
||||
final idx = indexWhere(
|
||||
(e) => e.identityMaster.masterRecordKey == accountMasterRecordKey);
|
||||
if (idx == -1) {
|
||||
return null;
|
||||
}
|
||||
return this[idx];
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
part of 'user_logins_cubit.dart';
|
||||
|
||||
typedef UserLoginsState = IList<UserLogin>;
|
||||
|
||||
extension UserLoginsStateExt on UserLoginsState {
|
||||
UserLogin? fetchUserLogin({required TypedKey accountMasterRecordKey}) {
|
||||
final idx =
|
||||
indexWhere((e) => e.accountMasterRecordKey == accountMasterRecordKey);
|
||||
if (idx == -1) {
|
||||
return null;
|
||||
}
|
||||
return this[idx];
|
||||
}
|
||||
}
|
@ -3,12 +3,10 @@ import 'dart:async';
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:veilid_support/veilid_support.dart';
|
||||
|
||||
import '../../repository/account_repository/account_repository.dart';
|
||||
import '../repository/account_repository/account_repository.dart';
|
||||
|
||||
part 'active_user_login_state.dart';
|
||||
|
||||
class ActiveUserLoginCubit extends Cubit<ActiveUserLoginState> {
|
||||
ActiveUserLoginCubit(AccountRepository accountRepository)
|
||||
class ActiveLocalAccountCubit extends Cubit<TypedKey?> {
|
||||
ActiveLocalAccountCubit(AccountRepository accountRepository)
|
||||
: _accountRepository = accountRepository,
|
||||
super(null) {
|
||||
// Subscribe to streams
|
||||
@ -18,8 +16,8 @@ class ActiveUserLoginCubit extends Cubit<ActiveUserLoginState> {
|
||||
void _initAccountRepositorySubscription() {
|
||||
_accountRepositorySubscription = _accountRepository.stream.listen((change) {
|
||||
switch (change) {
|
||||
case AccountRepositoryChange.activeUserLogin:
|
||||
emit(_accountRepository.getActiveUserLogin());
|
||||
case AccountRepositoryChange.activeLocalAccount:
|
||||
emit(_accountRepository.getActiveLocalAccount());
|
||||
break;
|
||||
// Ignore these
|
||||
case AccountRepositoryChange.localAccounts:
|
4
lib/account_manager/cubits/cubits.dart
Normal file
4
lib/account_manager/cubits/cubits.dart
Normal file
@ -0,0 +1,4 @@
|
||||
export 'account_record_cubit.dart';
|
||||
export 'active_local_account_cubit.dart';
|
||||
export 'local_accounts_cubit.dart';
|
||||
export 'user_logins_cubit.dart';
|
@ -2,17 +2,14 @@ import 'dart:async';
|
||||
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:fast_immutable_collections/fast_immutable_collections.dart';
|
||||
import 'package:veilid_support/veilid_support.dart';
|
||||
|
||||
import '../../models/models.dart';
|
||||
import '../../repository/account_repository/account_repository.dart';
|
||||
import '../models/models.dart';
|
||||
import '../repository/account_repository/account_repository.dart';
|
||||
|
||||
part 'local_accounts_state.dart';
|
||||
|
||||
class LocalAccountsCubit extends Cubit<LocalAccountsState> {
|
||||
class LocalAccountsCubit extends Cubit<IList<LocalAccount>> {
|
||||
LocalAccountsCubit(AccountRepository accountRepository)
|
||||
: _accountRepository = accountRepository,
|
||||
super(LocalAccountsState()) {
|
||||
super(IList<LocalAccount>()) {
|
||||
// Subscribe to streams
|
||||
_initAccountRepositorySubscription();
|
||||
}
|
||||
@ -25,7 +22,7 @@ class LocalAccountsCubit extends Cubit<LocalAccountsState> {
|
||||
break;
|
||||
// Ignore these
|
||||
case AccountRepositoryChange.userLogins:
|
||||
case AccountRepositoryChange.activeUserLogin:
|
||||
case AccountRepositoryChange.activeLocalAccount:
|
||||
break;
|
||||
}
|
||||
});
|
@ -2,17 +2,14 @@ import 'dart:async';
|
||||
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:fast_immutable_collections/fast_immutable_collections.dart';
|
||||
import 'package:veilid_support/veilid_support.dart';
|
||||
|
||||
import '../../models/models.dart';
|
||||
import '../../repository/account_repository/account_repository.dart';
|
||||
import '../models/models.dart';
|
||||
import '../repository/account_repository/account_repository.dart';
|
||||
|
||||
part 'user_logins_state.dart';
|
||||
|
||||
class UserLoginsCubit extends Cubit<UserLoginsState> {
|
||||
class UserLoginsCubit extends Cubit<IList<UserLogin>> {
|
||||
UserLoginsCubit(AccountRepository accountRepository)
|
||||
: _accountRepository = accountRepository,
|
||||
super(UserLoginsState()) {
|
||||
super(IList<UserLogin>()) {
|
||||
// Subscribe to streams
|
||||
_initAccountRepositorySubscription();
|
||||
}
|
||||
@ -25,7 +22,7 @@ class UserLoginsCubit extends Cubit<UserLoginsState> {
|
||||
break;
|
||||
// Ignore these
|
||||
case AccountRepositoryChange.localAccounts:
|
||||
case AccountRepositoryChange.activeUserLogin:
|
||||
case AccountRepositoryChange.activeLocalAccount:
|
||||
break;
|
||||
}
|
||||
});
|
@ -6,16 +6,16 @@ import 'package:veilid_support/veilid_support.dart';
|
||||
import '../../../../proto/proto.dart' as proto;
|
||||
import '../../../tools/tools.dart';
|
||||
import '../../models/models.dart';
|
||||
import 'active_logins.dart';
|
||||
|
||||
const String veilidChatAccountKey = 'com.veilid.veilidchat';
|
||||
|
||||
enum AccountRepositoryChange { localAccounts, userLogins, activeUserLogin }
|
||||
enum AccountRepositoryChange { localAccounts, userLogins, activeLocalAccount }
|
||||
|
||||
class AccountRepository {
|
||||
AccountRepository._()
|
||||
: _localAccounts = _initLocalAccounts(),
|
||||
_activeLogins = _initActiveLogins(),
|
||||
_userLogins = _initUserLogins(),
|
||||
_activeLocalAccount = _initActiveAccount(),
|
||||
_streamController =
|
||||
StreamController<AccountRepositoryChange>.broadcast();
|
||||
|
||||
@ -28,16 +28,23 @@ class AccountRepository {
|
||||
: IList<LocalAccount>(),
|
||||
valueToJson: (val) => val.toJson((la) => la.toJson()));
|
||||
|
||||
static TableDBValue<ActiveLogins> _initActiveLogins() => TableDBValue(
|
||||
static TableDBValue<IList<UserLogin>> _initUserLogins() => TableDBValue(
|
||||
tableName: 'local_account_manager',
|
||||
tableKeyName: 'active_logins',
|
||||
tableKeyName: 'user_logins',
|
||||
valueFromJson: (obj) => obj != null
|
||||
? ActiveLogins.fromJson(obj as Map<String, dynamic>)
|
||||
: ActiveLogins.empty(),
|
||||
valueToJson: (val) => val.toJson());
|
||||
? IList<UserLogin>.fromJson(obj, genericFromJson(UserLogin.fromJson))
|
||||
: IList<UserLogin>(),
|
||||
valueToJson: (val) => val.toJson((la) => la.toJson()));
|
||||
|
||||
static TableDBValue<TypedKey?> _initActiveAccount() => TableDBValue(
|
||||
tableName: 'local_account_manager',
|
||||
tableKeyName: 'active_local_account',
|
||||
valueFromJson: (obj) => obj == null ? null : TypedKey.fromJson(obj),
|
||||
valueToJson: (val) => val?.toJson());
|
||||
|
||||
final TableDBValue<IList<LocalAccount>> _localAccounts;
|
||||
final TableDBValue<ActiveLogins> _activeLogins;
|
||||
final TableDBValue<IList<UserLogin>> _userLogins;
|
||||
final TableDBValue<TypedKey?> _activeLocalAccount;
|
||||
final StreamController<AccountRepositoryChange> _streamController;
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
@ -47,7 +54,8 @@ class AccountRepository {
|
||||
|
||||
Future<void> init() async {
|
||||
await _localAccounts.load();
|
||||
await _activeLogins.load();
|
||||
await _userLogins.load();
|
||||
await _activeLocalAccount.load();
|
||||
await _openLoggedInDHTRecords();
|
||||
}
|
||||
|
||||
@ -59,10 +67,16 @@ class AccountRepository {
|
||||
//////////////////////////////////////////////////////////////
|
||||
/// Selectors
|
||||
IList<LocalAccount> getLocalAccounts() => _localAccounts.requireValue;
|
||||
IList<UserLogin> getUserLogins() => _activeLogins.requireValue.userLogins;
|
||||
TypedKey? getActiveUserLogin() => _activeLogins.requireValue.activeUserLogin;
|
||||
TypedKey? getActiveLocalAccount() => _activeLocalAccount.requireValue;
|
||||
IList<UserLogin> getUserLogins() => _userLogins.requireValue;
|
||||
UserLogin? getActiveUserLogin() {
|
||||
final activeLocalAccount = _activeLocalAccount.requireValue;
|
||||
return activeLocalAccount == null
|
||||
? null
|
||||
: fetchUserLogin(activeLocalAccount);
|
||||
}
|
||||
|
||||
LocalAccount? fetchLocalAccount({required TypedKey accountMasterRecordKey}) {
|
||||
LocalAccount? fetchLocalAccount(TypedKey accountMasterRecordKey) {
|
||||
final localAccounts = _localAccounts.requireValue;
|
||||
final idx = localAccounts.indexWhere(
|
||||
(e) => e.identityMaster.masterRecordKey == accountMasterRecordKey);
|
||||
@ -72,8 +86,8 @@ class AccountRepository {
|
||||
return localAccounts[idx];
|
||||
}
|
||||
|
||||
UserLogin? fetchUserLogin({required TypedKey accountMasterRecordKey}) {
|
||||
final userLogins = _activeLogins.requireValue.userLogins;
|
||||
UserLogin? fetchUserLogin(TypedKey accountMasterRecordKey) {
|
||||
final userLogins = _userLogins.requireValue;
|
||||
final idx = userLogins
|
||||
.indexWhere((e) => e.accountMasterRecordKey == accountMasterRecordKey);
|
||||
if (idx == -1) {
|
||||
@ -82,34 +96,33 @@ class AccountRepository {
|
||||
return userLogins[idx];
|
||||
}
|
||||
|
||||
AccountInfo? getAccountInfo({TypedKey? accountMasterRecordKey}) {
|
||||
// Get active user if we have one
|
||||
AccountInfo getAccountInfo(TypedKey? accountMasterRecordKey) {
|
||||
// Get active account if we have one
|
||||
final activeLocalAccount = getActiveLocalAccount();
|
||||
if (accountMasterRecordKey == null) {
|
||||
final activeUserLogin = getActiveUserLogin();
|
||||
if (activeUserLogin == null) {
|
||||
if (activeLocalAccount == null) {
|
||||
// No user logged in
|
||||
return null;
|
||||
return const AccountInfo(
|
||||
status: AccountInfoStatus.noAccount,
|
||||
active: false,
|
||||
activeAccountInfo: null);
|
||||
}
|
||||
accountMasterRecordKey = activeUserLogin;
|
||||
accountMasterRecordKey = activeLocalAccount;
|
||||
}
|
||||
final active = accountMasterRecordKey == activeLocalAccount;
|
||||
|
||||
// Get which local account we want to fetch the profile for
|
||||
final localAccount =
|
||||
fetchLocalAccount(accountMasterRecordKey: accountMasterRecordKey);
|
||||
final localAccount = fetchLocalAccount(accountMasterRecordKey);
|
||||
if (localAccount == null) {
|
||||
// Local account does not exist
|
||||
return const AccountInfo(
|
||||
// account does not exist
|
||||
return AccountInfo(
|
||||
status: AccountInfoStatus.noAccount,
|
||||
active: false,
|
||||
active: active,
|
||||
activeAccountInfo: null);
|
||||
}
|
||||
|
||||
// See if we've logged into this account or if it is locked
|
||||
final activeUserLogin = getActiveUserLogin();
|
||||
final active = activeUserLogin == accountMasterRecordKey;
|
||||
|
||||
final userLogin =
|
||||
fetchUserLogin(accountMasterRecordKey: accountMasterRecordKey);
|
||||
final userLogin = fetchUserLogin(accountMasterRecordKey);
|
||||
if (userLogin == null) {
|
||||
// Account was locked
|
||||
return AccountInfo(
|
||||
@ -268,22 +281,20 @@ class AccountRepository {
|
||||
/// Delete an account from all devices
|
||||
|
||||
Future<void> switchToAccount(TypedKey? accountMasterRecordKey) async {
|
||||
final activeLogins = await _activeLogins.get();
|
||||
final activeLocalAccount = await _activeLocalAccount.get();
|
||||
|
||||
if (activeLogins.activeUserLogin == accountMasterRecordKey) {
|
||||
if (activeLocalAccount == accountMasterRecordKey) {
|
||||
// Nothing to do
|
||||
return;
|
||||
}
|
||||
|
||||
if (accountMasterRecordKey != null) {
|
||||
// Assert the specified record key can be found, will throw if not
|
||||
final _ = activeLogins.userLogins.firstWhere(
|
||||
final _ = _userLogins.requireValue.firstWhere(
|
||||
(ul) => ul.accountMasterRecordKey == accountMasterRecordKey);
|
||||
}
|
||||
final newActiveLogins =
|
||||
activeLogins.copyWith(activeUserLogin: accountMasterRecordKey);
|
||||
await _activeLogins.set(newActiveLogins);
|
||||
_streamController.add(AccountRepositoryChange.activeUserLogin);
|
||||
await _activeLocalAccount.set(accountMasterRecordKey);
|
||||
_streamController.add(AccountRepositoryChange.activeLocalAccount);
|
||||
}
|
||||
|
||||
Future<bool> _decryptedLogin(
|
||||
@ -301,25 +312,25 @@ class AccountRepository {
|
||||
identitySecret: identitySecret, accountKey: veilidChatAccountKey);
|
||||
|
||||
// Add to user logins and select it
|
||||
final activeLogins = await _activeLogins.get();
|
||||
final userLogins = await _userLogins.get();
|
||||
final now = Veilid.instance.now();
|
||||
final newActiveLogins = activeLogins.copyWith(
|
||||
userLogins: activeLogins.userLogins.replaceFirstWhere(
|
||||
(ul) => ul.accountMasterRecordKey == identityMaster.masterRecordKey,
|
||||
(ul) => ul != null
|
||||
? ul.copyWith(lastActive: now)
|
||||
: UserLogin(
|
||||
accountMasterRecordKey: identityMaster.masterRecordKey,
|
||||
identitySecret:
|
||||
TypedSecret(kind: cs.kind(), value: identitySecret),
|
||||
accountRecordInfo: accountRecordInfo,
|
||||
lastActive: now),
|
||||
addIfNotFound: true),
|
||||
activeUserLogin: identityMaster.masterRecordKey);
|
||||
await _activeLogins.set(newActiveLogins);
|
||||
final newUserLogins = userLogins.replaceFirstWhere(
|
||||
(ul) => ul.accountMasterRecordKey == identityMaster.masterRecordKey,
|
||||
(ul) => ul != null
|
||||
? ul.copyWith(lastActive: now)
|
||||
: UserLogin(
|
||||
accountMasterRecordKey: identityMaster.masterRecordKey,
|
||||
identitySecret:
|
||||
TypedSecret(kind: cs.kind(), value: identitySecret),
|
||||
accountRecordInfo: accountRecordInfo,
|
||||
lastActive: now),
|
||||
addIfNotFound: true);
|
||||
|
||||
await _userLogins.set(newUserLogins);
|
||||
await _activeLocalAccount.set(identityMaster.masterRecordKey);
|
||||
_streamController
|
||||
..add(AccountRepositoryChange.activeUserLogin)
|
||||
..add(AccountRepositoryChange.userLogins);
|
||||
..add(AccountRepositoryChange.userLogins)
|
||||
..add(AccountRepositoryChange.activeLocalAccount);
|
||||
|
||||
// Ensure all logins are opened
|
||||
await _openLoggedInDHTRecords();
|
||||
@ -355,34 +366,31 @@ class AccountRepository {
|
||||
|
||||
Future<void> logout(TypedKey? accountMasterRecordKey) async {
|
||||
// Resolve which user to log out
|
||||
final activeLogins = await _activeLogins.get();
|
||||
final logoutUser = accountMasterRecordKey ?? activeLogins.activeUserLogin;
|
||||
//final userLogins = await _userLogins.get();
|
||||
final activeLocalAccount = await _activeLocalAccount.get();
|
||||
final logoutUser = accountMasterRecordKey ?? activeLocalAccount;
|
||||
if (logoutUser == null) {
|
||||
log.error('missing user in logout: $accountMasterRecordKey');
|
||||
return;
|
||||
}
|
||||
|
||||
final logoutUserLogin = fetchUserLogin(accountMasterRecordKey: logoutUser);
|
||||
if (logoutUserLogin != null) {
|
||||
// Close DHT records for this account
|
||||
final pool = DHTRecordPool.instance;
|
||||
final accountRecordKey =
|
||||
logoutUserLogin.accountRecordInfo.accountRecord.recordKey;
|
||||
final accountRecord = pool.getOpenedRecord(accountRecordKey);
|
||||
await accountRecord?.close();
|
||||
final logoutUserLogin = fetchUserLogin(logoutUser);
|
||||
if (logoutUserLogin == null) {
|
||||
// Already logged out
|
||||
return;
|
||||
}
|
||||
|
||||
// Close DHT records for this account
|
||||
final pool = DHTRecordPool.instance;
|
||||
final accountRecordKey =
|
||||
logoutUserLogin.accountRecordInfo.accountRecord.recordKey;
|
||||
final accountRecord = pool.getOpenedRecord(accountRecordKey);
|
||||
await accountRecord?.close();
|
||||
|
||||
// Remove user from active logins list
|
||||
final newActiveLogins = activeLogins.copyWith(
|
||||
activeUserLogin: activeLogins.activeUserLogin == logoutUser
|
||||
? null
|
||||
: activeLogins.activeUserLogin,
|
||||
userLogins: activeLogins.userLogins
|
||||
.removeWhere((ul) => ul.accountMasterRecordKey == logoutUser));
|
||||
await _activeLogins.set(newActiveLogins);
|
||||
if (activeLogins.activeUserLogin == logoutUser) {
|
||||
_streamController.add(AccountRepositoryChange.activeUserLogin);
|
||||
}
|
||||
final newUserLogins = (await _userLogins.get())
|
||||
.removeWhere((ul) => ul.accountMasterRecordKey == logoutUser);
|
||||
await _userLogins.set(newUserLogins);
|
||||
_streamController.add(AccountRepositoryChange.userLogins);
|
||||
}
|
||||
|
||||
@ -390,15 +398,15 @@ class AccountRepository {
|
||||
final pool = DHTRecordPool.instance;
|
||||
|
||||
// For all user logins if they arent open yet
|
||||
final activeLogins = await _activeLogins.get();
|
||||
for (final userLogin in activeLogins.userLogins) {
|
||||
final userLogins = await _userLogins.get();
|
||||
for (final userLogin in userLogins) {
|
||||
//// Account record key /////////////////////////////
|
||||
final accountRecordKey =
|
||||
userLogin.accountRecordInfo.accountRecord.recordKey;
|
||||
final existingAccountRecord = pool.getOpenedRecord(accountRecordKey);
|
||||
if (existingAccountRecord == null) {
|
||||
final localAccount = fetchLocalAccount(
|
||||
accountMasterRecordKey: userLogin.accountMasterRecordKey);
|
||||
final localAccount =
|
||||
fetchLocalAccount(userLogin.accountMasterRecordKey);
|
||||
|
||||
// Record not yet open, do it
|
||||
final record = await pool.openOwned(
|
||||
@ -413,8 +421,8 @@ class AccountRepository {
|
||||
Future<void> _closeLoggedInDHTRecords() async {
|
||||
final pool = DHTRecordPool.instance;
|
||||
|
||||
final activeLogins = await _activeLogins.get();
|
||||
for (final userLogin in activeLogins.userLogins) {
|
||||
final userLogins = await _userLogins.get();
|
||||
for (final userLogin in userLogins) {
|
||||
//// Account record key /////////////////////////////
|
||||
final accountRecordKey =
|
||||
userLogin.accountRecordInfo.accountRecord.recordKey;
|
||||
|
@ -1,25 +0,0 @@
|
||||
// Represents a set of user logins and the currently selected account
|
||||
import 'package:fast_immutable_collections/fast_immutable_collections.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:veilid_support/veilid_support.dart';
|
||||
|
||||
import '../../models/models.dart';
|
||||
|
||||
part 'active_logins.g.dart';
|
||||
part 'active_logins.freezed.dart';
|
||||
|
||||
@freezed
|
||||
class ActiveLogins with _$ActiveLogins {
|
||||
const factory ActiveLogins({
|
||||
// The list of current logged in accounts
|
||||
required IList<UserLogin> userLogins,
|
||||
// The current selected account indexed by master record key
|
||||
TypedKey? activeUserLogin,
|
||||
}) = _ActiveLogins;
|
||||
|
||||
factory ActiveLogins.empty() =>
|
||||
const ActiveLogins(userLogins: IListConst([]));
|
||||
|
||||
factory ActiveLogins.fromJson(dynamic json) =>
|
||||
_ActiveLogins.fromJson(json as Map<String, dynamic>);
|
||||
}
|
@ -1,181 +0,0 @@
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
part of 'active_logins.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
|
||||
|
||||
ActiveLogins _$ActiveLoginsFromJson(Map<String, dynamic> json) {
|
||||
return _ActiveLogins.fromJson(json);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$ActiveLogins {
|
||||
// The list of current logged in accounts
|
||||
IList<UserLogin> get userLogins =>
|
||||
throw _privateConstructorUsedError; // The current selected account indexed by master record key
|
||||
Typed<FixedEncodedString43>? get activeUserLogin =>
|
||||
throw _privateConstructorUsedError;
|
||||
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@JsonKey(ignore: true)
|
||||
$ActiveLoginsCopyWith<ActiveLogins> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $ActiveLoginsCopyWith<$Res> {
|
||||
factory $ActiveLoginsCopyWith(
|
||||
ActiveLogins value, $Res Function(ActiveLogins) then) =
|
||||
_$ActiveLoginsCopyWithImpl<$Res, ActiveLogins>;
|
||||
@useResult
|
||||
$Res call(
|
||||
{IList<UserLogin> userLogins,
|
||||
Typed<FixedEncodedString43>? activeUserLogin});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$ActiveLoginsCopyWithImpl<$Res, $Val extends ActiveLogins>
|
||||
implements $ActiveLoginsCopyWith<$Res> {
|
||||
_$ActiveLoginsCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? userLogins = null,
|
||||
Object? activeUserLogin = freezed,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
userLogins: null == userLogins
|
||||
? _value.userLogins
|
||||
: userLogins // ignore: cast_nullable_to_non_nullable
|
||||
as IList<UserLogin>,
|
||||
activeUserLogin: freezed == activeUserLogin
|
||||
? _value.activeUserLogin
|
||||
: activeUserLogin // ignore: cast_nullable_to_non_nullable
|
||||
as Typed<FixedEncodedString43>?,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$ActiveLoginsImplCopyWith<$Res>
|
||||
implements $ActiveLoginsCopyWith<$Res> {
|
||||
factory _$$ActiveLoginsImplCopyWith(
|
||||
_$ActiveLoginsImpl value, $Res Function(_$ActiveLoginsImpl) then) =
|
||||
__$$ActiveLoginsImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call(
|
||||
{IList<UserLogin> userLogins,
|
||||
Typed<FixedEncodedString43>? activeUserLogin});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$ActiveLoginsImplCopyWithImpl<$Res>
|
||||
extends _$ActiveLoginsCopyWithImpl<$Res, _$ActiveLoginsImpl>
|
||||
implements _$$ActiveLoginsImplCopyWith<$Res> {
|
||||
__$$ActiveLoginsImplCopyWithImpl(
|
||||
_$ActiveLoginsImpl _value, $Res Function(_$ActiveLoginsImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? userLogins = null,
|
||||
Object? activeUserLogin = freezed,
|
||||
}) {
|
||||
return _then(_$ActiveLoginsImpl(
|
||||
userLogins: null == userLogins
|
||||
? _value.userLogins
|
||||
: userLogins // ignore: cast_nullable_to_non_nullable
|
||||
as IList<UserLogin>,
|
||||
activeUserLogin: freezed == activeUserLogin
|
||||
? _value.activeUserLogin
|
||||
: activeUserLogin // ignore: cast_nullable_to_non_nullable
|
||||
as Typed<FixedEncodedString43>?,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _$ActiveLoginsImpl implements _ActiveLogins {
|
||||
const _$ActiveLoginsImpl({required this.userLogins, this.activeUserLogin});
|
||||
|
||||
factory _$ActiveLoginsImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$ActiveLoginsImplFromJson(json);
|
||||
|
||||
// The list of current logged in accounts
|
||||
@override
|
||||
final IList<UserLogin> userLogins;
|
||||
// The current selected account indexed by master record key
|
||||
@override
|
||||
final Typed<FixedEncodedString43>? activeUserLogin;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ActiveLogins(userLogins: $userLogins, activeUserLogin: $activeUserLogin)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$ActiveLoginsImpl &&
|
||||
const DeepCollectionEquality()
|
||||
.equals(other.userLogins, userLogins) &&
|
||||
(identical(other.activeUserLogin, activeUserLogin) ||
|
||||
other.activeUserLogin == activeUserLogin));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,
|
||||
const DeepCollectionEquality().hash(userLogins), activeUserLogin);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$ActiveLoginsImplCopyWith<_$ActiveLoginsImpl> get copyWith =>
|
||||
__$$ActiveLoginsImplCopyWithImpl<_$ActiveLoginsImpl>(this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$$ActiveLoginsImplToJson(
|
||||
this,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _ActiveLogins implements ActiveLogins {
|
||||
const factory _ActiveLogins(
|
||||
{required final IList<UserLogin> userLogins,
|
||||
final Typed<FixedEncodedString43>? activeUserLogin}) = _$ActiveLoginsImpl;
|
||||
|
||||
factory _ActiveLogins.fromJson(Map<String, dynamic> json) =
|
||||
_$ActiveLoginsImpl.fromJson;
|
||||
|
||||
@override // The list of current logged in accounts
|
||||
IList<UserLogin> get userLogins;
|
||||
@override // The current selected account indexed by master record key
|
||||
Typed<FixedEncodedString43>? get activeUserLogin;
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
_$$ActiveLoginsImplCopyWith<_$ActiveLoginsImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'active_logins.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_$ActiveLoginsImpl _$$ActiveLoginsImplFromJson(Map<String, dynamic> json) =>
|
||||
_$ActiveLoginsImpl(
|
||||
userLogins: IList<UserLogin>.fromJson(
|
||||
json['user_logins'], (value) => UserLogin.fromJson(value)),
|
||||
activeUserLogin: json['active_user_login'] == null
|
||||
? null
|
||||
: Typed<FixedEncodedString43>.fromJson(json['active_user_login']),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$ActiveLoginsImplToJson(_$ActiveLoginsImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'user_logins': instance.userLogins.toJson(
|
||||
(value) => value.toJson(),
|
||||
),
|
||||
'active_user_login': instance.activeUserLogin?.toJson(),
|
||||
};
|
@ -47,9 +47,9 @@ class VeilidChatApp extends StatelessWidget {
|
||||
create: (context) =>
|
||||
UserLoginsCubit(AccountRepository.instance),
|
||||
),
|
||||
BlocProvider<ActiveUserLoginCubit>(
|
||||
BlocProvider<ActiveLocalAccountCubit>(
|
||||
create: (context) =>
|
||||
ActiveUserLoginCubit(AccountRepository.instance),
|
||||
ActiveLocalAccountCubit(AccountRepository.instance),
|
||||
),
|
||||
BlocProvider<PreferencesCubit>(
|
||||
create: (context) =>
|
||||
|
@ -2,9 +2,12 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:veilid_support/veilid_support.dart';
|
||||
|
||||
class ActiveChatCubit extends Cubit<TypedKey?> {
|
||||
ActiveChatCubit(super.initialState);
|
||||
ActiveChatCubit(super.initialState, this.setHasActiveChat);
|
||||
|
||||
void setActiveChat(TypedKey? activeChatRemoteConversationRecordKey) {
|
||||
setHasActiveChat(activeChatRemoteConversationRecordKey != null);
|
||||
emit(activeChatRemoteConversationRecordKey);
|
||||
}
|
||||
|
||||
void Function(bool) setHasActiveChat;
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import '../../../chat/chat.dart';
|
||||
import '../../../chat_list/chat_list.dart';
|
||||
import '../../../contact_invitation/contact_invitation.dart';
|
||||
import '../../../contacts/contacts.dart';
|
||||
import '../../../router/router.dart';
|
||||
import '../../../tools/tools.dart';
|
||||
|
||||
class HomeAccountReadyShell extends StatefulWidget {
|
||||
@ -18,58 +19,28 @@ class HomeAccountReadyShell extends StatefulWidget {
|
||||
final Widget child;
|
||||
}
|
||||
|
||||
class HomeAccountReadyShellState extends State<HomeAccountReadyShell>
|
||||
with TickerProviderStateMixin {
|
||||
class HomeAccountReadyShellState extends State<HomeAccountReadyShell> {
|
||||
//
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
// xxx figure out how to do this switch
|
||||
|
||||
// Widget buildWithLogin(BuildContext context) {
|
||||
// final activeUserLogin = context.watch<ActiveUserLoginCubit>().state;
|
||||
|
||||
// if (activeUserLogin == null) {
|
||||
// // If no logged in user is active, show the loading panel
|
||||
// return const HomeNoActive();
|
||||
// }
|
||||
|
||||
// final accountInfo = AccountRepository.instance
|
||||
// .getAccountInfo(accountMasterRecordKey: activeUserLogin)!;
|
||||
|
||||
// switch (accountInfo.status) {
|
||||
// case AccountInfoStatus.noAccount:
|
||||
// return const HomeAccountMissing();
|
||||
// case AccountInfoStatus.accountInvalid:
|
||||
// return const HomeAccountInvalid();
|
||||
// case AccountInfoStatus.accountLocked:
|
||||
// return const HomeAccountLocked();
|
||||
// case AccountInfoStatus.accountReady:
|
||||
// return Provider<ActiveAccountInfo>.value(
|
||||
// value: accountInfo.activeAccountInfo!,
|
||||
// child: BlocProvider(
|
||||
// create: (context) => AccountRecordCubit(
|
||||
// record: accountInfo.activeAccountInfo!.accountRecord),
|
||||
// child: const HomeAccountReady()));
|
||||
// }
|
||||
// }
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// These must be valid already before making this widget,
|
||||
// per the ShellRoute above it
|
||||
final activeUserLogin = context.read<ActiveUserLoginCubit>().state!;
|
||||
final accountInfo = AccountRepository.instance
|
||||
.getAccountInfo(accountMasterRecordKey: activeUserLogin)!;
|
||||
final activeLocalAccount = context.read<ActiveLocalAccountCubit>().state!;
|
||||
final accountInfo =
|
||||
AccountRepository.instance.getAccountInfo(activeLocalAccount);
|
||||
final activeAccountInfo = accountInfo.activeAccountInfo!;
|
||||
final routerCubit = context.read<RouterCubit>();
|
||||
|
||||
return Provider<ActiveAccountInfo>.value(
|
||||
value: activeAccountInfo,
|
||||
child: BlocProvider(
|
||||
create: (context) => AccountRecordCubit(
|
||||
record: accountInfo.activeAccountInfo!.accountRecord),
|
||||
create: (context) =>
|
||||
AccountRecordCubit(record: activeAccountInfo.accountRecord),
|
||||
child: Builder(builder: (context) {
|
||||
final account =
|
||||
context.watch<AccountRecordCubit>().state.data?.value;
|
||||
@ -92,7 +63,9 @@ class HomeAccountReadyShellState extends State<HomeAccountReadyShell>
|
||||
BlocProvider(
|
||||
create: (context) => ActiveConversationsCubit(
|
||||
activeAccountInfo: activeAccountInfo)),
|
||||
BlocProvider(create: (context) => ActiveChatCubit(null))
|
||||
BlocProvider(
|
||||
create: (context) =>
|
||||
ActiveChatCubit(null, routerCubit.setHasActiveChat))
|
||||
], child: widget.child);
|
||||
})));
|
||||
}
|
||||
|
@ -1,6 +1,13 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import '../../account_manager/account_manager.dart';
|
||||
import '../../theme/theme.dart';
|
||||
import 'home_account_invalid.dart';
|
||||
import 'home_account_locked.dart';
|
||||
import 'home_account_missing.dart';
|
||||
import 'home_no_active.dart';
|
||||
|
||||
class HomeShell extends StatefulWidget {
|
||||
const HomeShell({required this.child, super.key});
|
||||
@ -25,6 +32,34 @@ class HomeShellState extends State<HomeShell> {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Widget buildWithLogin(BuildContext context, Widget child) {
|
||||
final activeLocalAccount = context.watch<ActiveLocalAccountCubit>().state;
|
||||
|
||||
if (activeLocalAccount == null) {
|
||||
// If no logged in user is active, show the loading panel
|
||||
return const HomeNoActive();
|
||||
}
|
||||
|
||||
final accountInfo =
|
||||
AccountRepository.instance.getAccountInfo(activeLocalAccount);
|
||||
|
||||
switch (accountInfo.status) {
|
||||
case AccountInfoStatus.noAccount:
|
||||
return const HomeAccountMissing();
|
||||
case AccountInfoStatus.accountInvalid:
|
||||
return const HomeAccountInvalid();
|
||||
case AccountInfoStatus.accountLocked:
|
||||
return const HomeAccountLocked();
|
||||
case AccountInfoStatus.accountReady:
|
||||
return Provider<ActiveAccountInfo>.value(
|
||||
value: accountInfo.activeAccountInfo!,
|
||||
child: BlocProvider(
|
||||
create: (context) => AccountRecordCubit(
|
||||
record: accountInfo.activeAccountInfo!.accountRecord),
|
||||
child: child));
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
@ -37,6 +72,6 @@ class HomeShellState extends State<HomeShell> {
|
||||
child: DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
color: scale.primaryScale.activeElementBackground),
|
||||
child: widget.child)));
|
||||
child: buildWithLogin(context, widget.child))));
|
||||
}
|
||||
}
|
||||
|
@ -20,8 +20,6 @@ part 'router_state.dart';
|
||||
|
||||
final _rootNavKey = GlobalKey<NavigatorState>(debugLabel: 'rootNavKey');
|
||||
final _homeNavKey = GlobalKey<NavigatorState>(debugLabel: 'homeNavKey');
|
||||
final _readyAccountNavKey =
|
||||
GlobalKey<NavigatorState>(debugLabel: 'readyAccountNavKey');
|
||||
|
||||
class RouterCubit extends Cubit<RouterState> {
|
||||
RouterCubit(AccountRepository accountRepository)
|
||||
@ -44,12 +42,16 @@ class RouterCubit extends Cubit<RouterState> {
|
||||
hasAnyAccount: accountRepository.getLocalAccounts().isNotEmpty));
|
||||
break;
|
||||
case AccountRepositoryChange.userLogins:
|
||||
case AccountRepositoryChange.activeUserLogin:
|
||||
case AccountRepositoryChange.activeLocalAccount:
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void setHasActiveChat(bool active) {
|
||||
emit(state.copyWith(hasActiveChat: active));
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() async {
|
||||
await _accountRepositorySubscription.cancel();
|
||||
@ -63,37 +65,20 @@ class RouterCubit extends Cubit<RouterState> {
|
||||
builder: (context, state) => const IndexPage(),
|
||||
),
|
||||
ShellRoute(
|
||||
navigatorKey: _homeNavKey,
|
||||
builder: (context, state, child) => HomeShell(child: child),
|
||||
routes: [
|
||||
GoRoute(
|
||||
path: '/home/no_active',
|
||||
builder: (context, state) => const HomeNoActive(),
|
||||
),
|
||||
GoRoute(
|
||||
path: '/home/account_missing',
|
||||
builder: (context, state) => const HomeAccountMissing(),
|
||||
),
|
||||
GoRoute(
|
||||
path: '/home/account_locked',
|
||||
builder: (context, state) => const HomeAccountLocked(),
|
||||
),
|
||||
ShellRoute(
|
||||
navigatorKey: _readyAccountNavKey,
|
||||
builder: (context, state, child) =>
|
||||
HomeAccountReadyShell(child: child),
|
||||
routes: [
|
||||
GoRoute(
|
||||
path: '/home',
|
||||
builder: (context, state) => const HomeAccountReadyMain(),
|
||||
),
|
||||
GoRoute(
|
||||
path: '/home/chat',
|
||||
builder: (context, state) => const HomeAccountReadyChat(),
|
||||
),
|
||||
],
|
||||
),
|
||||
]),
|
||||
navigatorKey: _homeNavKey,
|
||||
builder: (context, state, child) =>
|
||||
HomeShell(child: HomeAccountReadyShell(child: child)),
|
||||
routes: [
|
||||
GoRoute(
|
||||
path: '/home',
|
||||
builder: (context, state) => const HomeAccountReadyMain(),
|
||||
),
|
||||
GoRoute(
|
||||
path: '/home/chat',
|
||||
builder: (context, state) => const HomeAccountReadyChat(),
|
||||
),
|
||||
],
|
||||
),
|
||||
GoRoute(
|
||||
path: '/new_account',
|
||||
builder: (context, state) => const NewAccountPage(),
|
||||
@ -127,9 +112,6 @@ class RouterCubit extends Cubit<RouterState> {
|
||||
if (!state.hasAnyAccount) {
|
||||
return '/new_account';
|
||||
}
|
||||
if (!state.hasActiveChat) { xxx stop using hasActiveChat here... we need a pager for the accounts and a way to get the current account state maybe a 'activeAccountCubit' or something, we may have this alraeady but it needs to work even if logged out.``
|
||||
return '/home/no_active';
|
||||
}
|
||||
if (responsiveVisibility(
|
||||
context: context,
|
||||
tablet: false,
|
||||
@ -144,9 +126,6 @@ class RouterCubit extends Cubit<RouterState> {
|
||||
if (!state.hasAnyAccount) {
|
||||
return '/new_account';
|
||||
}
|
||||
if (!state.hasActiveChat) {
|
||||
return '/home/no_active';
|
||||
}
|
||||
if (responsiveVisibility(
|
||||
context: context,
|
||||
tablet: false,
|
||||
@ -159,21 +138,6 @@ class RouterCubit extends Cubit<RouterState> {
|
||||
return '/home';
|
||||
}
|
||||
return null;
|
||||
case '/home/no_active':
|
||||
if (state.hasActiveChat) {
|
||||
return '/home';
|
||||
}
|
||||
return null;
|
||||
case '/home/account_missing':
|
||||
if (!state.hasActiveChat) {
|
||||
return '/home/no_active';
|
||||
}
|
||||
return null;
|
||||
case '/home/account_locked':
|
||||
if (!state.hasActiveChat) {
|
||||
return '/home/no_active';
|
||||
}
|
||||
return null;
|
||||
case '/settings':
|
||||
return null;
|
||||
case '/developer':
|
||||
|
Loading…
Reference in New Issue
Block a user