diff --git a/lib/account_manager/account_manager.dart b/lib/account_manager/account_manager.dart index af728ac..ac518b3 100644 --- a/lib/account_manager/account_manager.dart +++ b/lib/account_manager/account_manager.dart @@ -1,4 +1,4 @@ -export 'cubit/cubit.dart'; +export 'cubits/cubits.dart'; export 'models/models.dart'; export 'repository/repository.dart'; export 'views/views.dart'; diff --git a/lib/account_manager/cubit/active_user_login_cubit/active_user_login_state.dart b/lib/account_manager/cubit/active_user_login_cubit/active_user_login_state.dart deleted file mode 100644 index 098e7a4..0000000 --- a/lib/account_manager/cubit/active_user_login_cubit/active_user_login_state.dart +++ /dev/null @@ -1,3 +0,0 @@ -part of 'active_user_login_cubit.dart'; - -typedef ActiveUserLoginState = TypedKey?; diff --git a/lib/account_manager/cubit/cubit.dart b/lib/account_manager/cubit/cubit.dart deleted file mode 100644 index d86274b..0000000 --- a/lib/account_manager/cubit/cubit.dart +++ /dev/null @@ -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'; diff --git a/lib/account_manager/cubit/local_accounts_cubit/local_accounts_state.dart b/lib/account_manager/cubit/local_accounts_cubit/local_accounts_state.dart deleted file mode 100644 index 3b8d695..0000000 --- a/lib/account_manager/cubit/local_accounts_cubit/local_accounts_state.dart +++ /dev/null @@ -1,14 +0,0 @@ -part of 'local_accounts_cubit.dart'; - -typedef LocalAccountsState = IList; - -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]; - } -} diff --git a/lib/account_manager/cubit/user_logins_cubit/user_logins_state.dart b/lib/account_manager/cubit/user_logins_cubit/user_logins_state.dart deleted file mode 100644 index 04c70d7..0000000 --- a/lib/account_manager/cubit/user_logins_cubit/user_logins_state.dart +++ /dev/null @@ -1,14 +0,0 @@ -part of 'user_logins_cubit.dart'; - -typedef UserLoginsState = IList; - -extension UserLoginsStateExt on UserLoginsState { - UserLogin? fetchUserLogin({required TypedKey accountMasterRecordKey}) { - final idx = - indexWhere((e) => e.accountMasterRecordKey == accountMasterRecordKey); - if (idx == -1) { - return null; - } - return this[idx]; - } -} diff --git a/lib/account_manager/cubit/account_record_cubit.dart b/lib/account_manager/cubits/account_record_cubit.dart similarity index 100% rename from lib/account_manager/cubit/account_record_cubit.dart rename to lib/account_manager/cubits/account_record_cubit.dart diff --git a/lib/account_manager/cubit/active_user_login_cubit/active_user_login_cubit.dart b/lib/account_manager/cubits/active_local_account_cubit.dart similarity index 71% rename from lib/account_manager/cubit/active_user_login_cubit/active_user_login_cubit.dart rename to lib/account_manager/cubits/active_local_account_cubit.dart index 70392f5..bc28a92 100644 --- a/lib/account_manager/cubit/active_user_login_cubit/active_user_login_cubit.dart +++ b/lib/account_manager/cubits/active_local_account_cubit.dart @@ -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 { - ActiveUserLoginCubit(AccountRepository accountRepository) +class ActiveLocalAccountCubit extends Cubit { + ActiveLocalAccountCubit(AccountRepository accountRepository) : _accountRepository = accountRepository, super(null) { // Subscribe to streams @@ -18,8 +16,8 @@ class ActiveUserLoginCubit extends Cubit { 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: diff --git a/lib/account_manager/cubits/cubits.dart b/lib/account_manager/cubits/cubits.dart new file mode 100644 index 0000000..6d2875d --- /dev/null +++ b/lib/account_manager/cubits/cubits.dart @@ -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'; diff --git a/lib/account_manager/cubit/local_accounts_cubit/local_accounts_cubit.dart b/lib/account_manager/cubits/local_accounts_cubit.dart similarity index 73% rename from lib/account_manager/cubit/local_accounts_cubit/local_accounts_cubit.dart rename to lib/account_manager/cubits/local_accounts_cubit.dart index ee9aa81..457b8ba 100644 --- a/lib/account_manager/cubit/local_accounts_cubit/local_accounts_cubit.dart +++ b/lib/account_manager/cubits/local_accounts_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 { +class LocalAccountsCubit extends Cubit> { LocalAccountsCubit(AccountRepository accountRepository) : _accountRepository = accountRepository, - super(LocalAccountsState()) { + super(IList()) { // Subscribe to streams _initAccountRepositorySubscription(); } @@ -25,7 +22,7 @@ class LocalAccountsCubit extends Cubit { break; // Ignore these case AccountRepositoryChange.userLogins: - case AccountRepositoryChange.activeUserLogin: + case AccountRepositoryChange.activeLocalAccount: break; } }); diff --git a/lib/account_manager/cubit/user_logins_cubit/user_logins_cubit.dart b/lib/account_manager/cubits/user_logins_cubit.dart similarity index 74% rename from lib/account_manager/cubit/user_logins_cubit/user_logins_cubit.dart rename to lib/account_manager/cubits/user_logins_cubit.dart index 9e7aee1..56dbab5 100644 --- a/lib/account_manager/cubit/user_logins_cubit/user_logins_cubit.dart +++ b/lib/account_manager/cubits/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 'user_logins_state.dart'; - -class UserLoginsCubit extends Cubit { +class UserLoginsCubit extends Cubit> { UserLoginsCubit(AccountRepository accountRepository) : _accountRepository = accountRepository, - super(UserLoginsState()) { + super(IList()) { // Subscribe to streams _initAccountRepositorySubscription(); } @@ -25,7 +22,7 @@ class UserLoginsCubit extends Cubit { break; // Ignore these case AccountRepositoryChange.localAccounts: - case AccountRepositoryChange.activeUserLogin: + case AccountRepositoryChange.activeLocalAccount: break; } }); diff --git a/lib/account_manager/repository/account_repository/account_repository.dart b/lib/account_manager/repository/account_repository/account_repository.dart index 60d493e..1042523 100644 --- a/lib/account_manager/repository/account_repository/account_repository.dart +++ b/lib/account_manager/repository/account_repository/account_repository.dart @@ -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.broadcast(); @@ -28,16 +28,23 @@ class AccountRepository { : IList(), valueToJson: (val) => val.toJson((la) => la.toJson())); - static TableDBValue _initActiveLogins() => TableDBValue( + static TableDBValue> _initUserLogins() => TableDBValue( tableName: 'local_account_manager', - tableKeyName: 'active_logins', + tableKeyName: 'user_logins', valueFromJson: (obj) => obj != null - ? ActiveLogins.fromJson(obj as Map) - : ActiveLogins.empty(), - valueToJson: (val) => val.toJson()); + ? IList.fromJson(obj, genericFromJson(UserLogin.fromJson)) + : IList(), + valueToJson: (val) => val.toJson((la) => la.toJson())); + + static TableDBValue _initActiveAccount() => TableDBValue( + tableName: 'local_account_manager', + tableKeyName: 'active_local_account', + valueFromJson: (obj) => obj == null ? null : TypedKey.fromJson(obj), + valueToJson: (val) => val?.toJson()); final TableDBValue> _localAccounts; - final TableDBValue _activeLogins; + final TableDBValue> _userLogins; + final TableDBValue _activeLocalAccount; final StreamController _streamController; ////////////////////////////////////////////////////////////// @@ -47,7 +54,8 @@ class AccountRepository { Future init() async { await _localAccounts.load(); - await _activeLogins.load(); + await _userLogins.load(); + await _activeLocalAccount.load(); await _openLoggedInDHTRecords(); } @@ -59,10 +67,16 @@ class AccountRepository { ////////////////////////////////////////////////////////////// /// Selectors IList getLocalAccounts() => _localAccounts.requireValue; - IList getUserLogins() => _activeLogins.requireValue.userLogins; - TypedKey? getActiveUserLogin() => _activeLogins.requireValue.activeUserLogin; + TypedKey? getActiveLocalAccount() => _activeLocalAccount.requireValue; + IList 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 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 _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 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 _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; diff --git a/lib/account_manager/repository/account_repository/active_logins.dart b/lib/account_manager/repository/account_repository/active_logins.dart deleted file mode 100644 index 9d4e713..0000000 --- a/lib/account_manager/repository/account_repository/active_logins.dart +++ /dev/null @@ -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 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); -} diff --git a/lib/account_manager/repository/account_repository/active_logins.freezed.dart b/lib/account_manager/repository/account_repository/active_logins.freezed.dart deleted file mode 100644 index cf9c434..0000000 --- a/lib/account_manager/repository/account_repository/active_logins.freezed.dart +++ /dev/null @@ -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 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 json) { - return _ActiveLogins.fromJson(json); -} - -/// @nodoc -mixin _$ActiveLogins { -// The list of current logged in accounts - IList get userLogins => - throw _privateConstructorUsedError; // The current selected account indexed by master record key - Typed? get activeUserLogin => - throw _privateConstructorUsedError; - - Map toJson() => throw _privateConstructorUsedError; - @JsonKey(ignore: true) - $ActiveLoginsCopyWith get copyWith => - throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class $ActiveLoginsCopyWith<$Res> { - factory $ActiveLoginsCopyWith( - ActiveLogins value, $Res Function(ActiveLogins) then) = - _$ActiveLoginsCopyWithImpl<$Res, ActiveLogins>; - @useResult - $Res call( - {IList userLogins, - Typed? 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, - activeUserLogin: freezed == activeUserLogin - ? _value.activeUserLogin - : activeUserLogin // ignore: cast_nullable_to_non_nullable - as Typed?, - ) 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 userLogins, - Typed? 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, - activeUserLogin: freezed == activeUserLogin - ? _value.activeUserLogin - : activeUserLogin // ignore: cast_nullable_to_non_nullable - as Typed?, - )); - } -} - -/// @nodoc -@JsonSerializable() -class _$ActiveLoginsImpl implements _ActiveLogins { - const _$ActiveLoginsImpl({required this.userLogins, this.activeUserLogin}); - - factory _$ActiveLoginsImpl.fromJson(Map json) => - _$$ActiveLoginsImplFromJson(json); - -// The list of current logged in accounts - @override - final IList userLogins; -// The current selected account indexed by master record key - @override - final Typed? 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 toJson() { - return _$$ActiveLoginsImplToJson( - this, - ); - } -} - -abstract class _ActiveLogins implements ActiveLogins { - const factory _ActiveLogins( - {required final IList userLogins, - final Typed? activeUserLogin}) = _$ActiveLoginsImpl; - - factory _ActiveLogins.fromJson(Map json) = - _$ActiveLoginsImpl.fromJson; - - @override // The list of current logged in accounts - IList get userLogins; - @override // The current selected account indexed by master record key - Typed? get activeUserLogin; - @override - @JsonKey(ignore: true) - _$$ActiveLoginsImplCopyWith<_$ActiveLoginsImpl> get copyWith => - throw _privateConstructorUsedError; -} diff --git a/lib/account_manager/repository/account_repository/active_logins.g.dart b/lib/account_manager/repository/account_repository/active_logins.g.dart deleted file mode 100644 index 95646a6..0000000 --- a/lib/account_manager/repository/account_repository/active_logins.g.dart +++ /dev/null @@ -1,24 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'active_logins.dart'; - -// ************************************************************************** -// JsonSerializableGenerator -// ************************************************************************** - -_$ActiveLoginsImpl _$$ActiveLoginsImplFromJson(Map json) => - _$ActiveLoginsImpl( - userLogins: IList.fromJson( - json['user_logins'], (value) => UserLogin.fromJson(value)), - activeUserLogin: json['active_user_login'] == null - ? null - : Typed.fromJson(json['active_user_login']), - ); - -Map _$$ActiveLoginsImplToJson(_$ActiveLoginsImpl instance) => - { - 'user_logins': instance.userLogins.toJson( - (value) => value.toJson(), - ), - 'active_user_login': instance.activeUserLogin?.toJson(), - }; diff --git a/lib/app.dart b/lib/app.dart index e7569c0..6624602 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -47,9 +47,9 @@ class VeilidChatApp extends StatelessWidget { create: (context) => UserLoginsCubit(AccountRepository.instance), ), - BlocProvider( + BlocProvider( create: (context) => - ActiveUserLoginCubit(AccountRepository.instance), + ActiveLocalAccountCubit(AccountRepository.instance), ), BlocProvider( create: (context) => diff --git a/lib/chat/cubits/active_chat_cubit.dart b/lib/chat/cubits/active_chat_cubit.dart index e47caec..6215098 100644 --- a/lib/chat/cubits/active_chat_cubit.dart +++ b/lib/chat/cubits/active_chat_cubit.dart @@ -2,9 +2,12 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:veilid_support/veilid_support.dart'; class ActiveChatCubit extends Cubit { - ActiveChatCubit(super.initialState); + ActiveChatCubit(super.initialState, this.setHasActiveChat); void setActiveChat(TypedKey? activeChatRemoteConversationRecordKey) { + setHasActiveChat(activeChatRemoteConversationRecordKey != null); emit(activeChatRemoteConversationRecordKey); } + + void Function(bool) setHasActiveChat; } diff --git a/lib/layout/home/home_account_ready/home_account_ready_shell.dart b/lib/layout/home/home_account_ready/home_account_ready_shell.dart index 22e1266..03fb82e 100644 --- a/lib/layout/home/home_account_ready/home_account_ready_shell.dart +++ b/lib/layout/home/home_account_ready/home_account_ready_shell.dart @@ -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 - with TickerProviderStateMixin { +class HomeAccountReadyShellState extends State { // @override void initState() { super.initState(); } - // xxx figure out how to do this switch - - // Widget buildWithLogin(BuildContext context) { - // final activeUserLogin = context.watch().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.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().state!; - final accountInfo = AccountRepository.instance - .getAccountInfo(accountMasterRecordKey: activeUserLogin)!; + final activeLocalAccount = context.read().state!; + final accountInfo = + AccountRepository.instance.getAccountInfo(activeLocalAccount); final activeAccountInfo = accountInfo.activeAccountInfo!; + final routerCubit = context.read(); return Provider.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().state.data?.value; @@ -92,7 +63,9 @@ class HomeAccountReadyShellState extends State BlocProvider( create: (context) => ActiveConversationsCubit( activeAccountInfo: activeAccountInfo)), - BlocProvider(create: (context) => ActiveChatCubit(null)) + BlocProvider( + create: (context) => + ActiveChatCubit(null, routerCubit.setHasActiveChat)) ], child: widget.child); }))); } diff --git a/lib/layout/home/home_shell.dart b/lib/layout/home/home_shell.dart index 1124def..86969fc 100644 --- a/lib/layout/home/home_shell.dart +++ b/lib/layout/home/home_shell.dart @@ -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 { super.dispose(); } + Widget buildWithLogin(BuildContext context, Widget child) { + final activeLocalAccount = context.watch().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.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 { child: DecoratedBox( decoration: BoxDecoration( color: scale.primaryScale.activeElementBackground), - child: widget.child))); + child: buildWithLogin(context, widget.child)))); } } diff --git a/lib/router/cubit/router_cubit.dart b/lib/router/cubit/router_cubit.dart index aedae69..f43df6b 100644 --- a/lib/router/cubit/router_cubit.dart +++ b/lib/router/cubit/router_cubit.dart @@ -20,8 +20,6 @@ part 'router_state.dart'; final _rootNavKey = GlobalKey(debugLabel: 'rootNavKey'); final _homeNavKey = GlobalKey(debugLabel: 'homeNavKey'); -final _readyAccountNavKey = - GlobalKey(debugLabel: 'readyAccountNavKey'); class RouterCubit extends Cubit { RouterCubit(AccountRepository accountRepository) @@ -44,12 +42,16 @@ class RouterCubit extends Cubit { 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 close() async { await _accountRepositorySubscription.cancel(); @@ -63,37 +65,20 @@ class RouterCubit extends Cubit { 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 { 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 { 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 { 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':