part of '../account_settings.dart'; @npLog class _Bloc extends Bloc<_Event, _State> with BlocLogger { _Bloc({ required DiContainer container, required Account account, required this.accountPrefController, this.highlight, }) : _c = container, super(_State.init( account: account, label: accountPrefController.accountLabel.value, shareFolder: accountPrefController.shareFolder.value, personProvider: accountPrefController.personProvider.value, )) { on<_SetLabel>(_onSetLabel); on<_OnUpdateLabel>(_onOnUpdateLabel); _subscriptions.add(accountPrefController.accountLabel.listen( (event) { add(_OnUpdateLabel(event)); }, onError: (e, stackTrace) { add(_SetError(_WritePrefError(e, stackTrace))); }, )); on<_SetAccount>(_onSetAccount); on<_OnUpdateAccount>(_onOnUpdateAccount); on<_SetShareFolder>(_onSetShareFolder); on<_OnUpdateShareFolder>(_onOnUpdateShareFolder); _subscriptions.add(accountPrefController.shareFolder.listen( (event) { add(_OnUpdateShareFolder(event)); }, onError: (e, stackTrace) { add(_SetError(_WritePrefError(e, stackTrace))); }, )); on<_SetPersonProvider>(_onSetPersonProvider); on<_OnUpdatePersonProvider>(_onOnUpdatePersonProvider); _subscriptions.add(accountPrefController.personProvider.listen( (event) { add(_OnUpdatePersonProvider(event)); }, onError: (e, stackTrace) { add(_SetError(_WritePrefError(e, stackTrace))); }, )); on<_SetError>(_onSetError); } @override String get tag => _log.fullName; @override Future close() { for (final s in _subscriptions) { unawaited(s.cancel()); } return super.close(); } @override void onError(Object error, StackTrace stackTrace) { // we need this to prevent onError being triggered recursively if (!isClosed && !_isHandlingError) { _isHandlingError = true; try { add(_SetError(error, stackTrace)); } catch (_) {} _isHandlingError = false; } super.onError(error, stackTrace); } void _onSetLabel(_SetLabel ev, Emitter<_State> emit) { _log.info(ev); accountPrefController.setAccountLabel(ev.label); } void _onOnUpdateLabel(_OnUpdateLabel ev, Emitter<_State> emit) { _log.info(ev); emit(state.copyWith(label: ev.label)); } Future _onSetAccount(_SetAccount ev, Emitter<_State> emit) async { _log.info(ev); emit(state.copyWith( account: ev.account, shouldReload: true, )); final revert = state.account; try { final accounts = _c.pref.getAccounts3()!; if (accounts.contains(ev.account)) { // conflict with another account. This normally won't happen because // the app passwords are unique to each entry, but just in case throw const _AccountConflictError(); } final index = accounts.indexWhere((a) => a.id == ev.account.id); if (index < 0) { _log.shout("[_onSetAccount] Account not found: ${ev.account}"); throw const _WritePrefError(); } accounts[index] = ev.account; if (!await _c.pref.setAccounts3(accounts)) { _log.severe("[_onSetAccount] Failed while setAccounts3: ${ev.account}"); throw const _WritePrefError(); } } catch (_) { emit(state.copyWith(account: revert)); rethrow; } } void _onOnUpdateAccount(_OnUpdateAccount ev, Emitter<_State> emit) { _log.info(ev); } void _onSetShareFolder(_SetShareFolder ev, Emitter<_State> emit) { _log.info(ev); accountPrefController.setShareFolder(ev.shareFolder); emit(state.copyWith(shouldReload: true)); } void _onOnUpdateShareFolder(_OnUpdateShareFolder ev, Emitter<_State> emit) { _log.info(ev); emit(state.copyWith(shareFolder: ev.shareFolder)); } void _onSetPersonProvider(_SetPersonProvider ev, Emitter<_State> emit) { _log.info(ev); accountPrefController.setPersonProvider(ev.personProvider); } void _onOnUpdatePersonProvider( _OnUpdatePersonProvider ev, Emitter<_State> emit) { _log.info(ev); emit(state.copyWith( personProvider: ev.personProvider, shouldResync: true, )); } void _onSetError(_SetError ev, Emitter<_State> emit) { _log.info(ev); emit(state.copyWith(error: ExceptionEvent(ev.error, ev.stackTrace))); } final DiContainer _c; final AccountPrefController accountPrefController; final AccountSettingsOption? highlight; final _subscriptions = []; var _isHandlingError = false; }