import 'dart:async'; import 'package:copy_with/copy_with.dart'; import 'package:logging/logging.dart'; import 'package:nc_photos/account.dart'; import 'package:nc_photos/controller/account_pref_controller.dart'; import 'package:nc_photos/di_container.dart'; import 'package:nc_photos/entity/person.dart'; import 'package:nc_photos/use_case/person/list_person.dart'; import 'package:np_codegen/np_codegen.dart'; import 'package:rxdart/rxdart.dart'; part 'persons_controller.g.dart'; @genCopyWith class PersonStreamEvent { const PersonStreamEvent({ required this.data, required this.hasNext, }); final List data; /// If true, the results are intermediate values and may not represent the /// latest state final bool hasNext; } @npLog class PersonsController { PersonsController( this._c, { required this.account, required this.accountPrefController, }); void dispose() { _personStreamContorller.close(); } /// Return a stream of [Person]s associated with [account] /// /// There's no guarantee that the returned list is always sorted in some ways, /// callers must sort it by themselves if the ordering is important ValueStream get stream { if (!_isPersonStreamInited) { _isPersonStreamInited = true; unawaited(_load()); } return _personStreamContorller.stream; } Future reload() async { if (_isPersonStreamInited) { return _load(); } else { _log.warning("[reload] Not inited, ignore"); } } Future _load() async { var lastData = _personStreamContorller.value.copyWith(hasNext: true); _personStreamContorller.add(lastData); final completer = Completer(); ListPerson(_c.withLocalRepo())( account, accountPrefController.personProvider.value) .listen( (results) { lastData = PersonStreamEvent( data: results, hasNext: true, ); _personStreamContorller.add(lastData); }, onError: _personStreamContorller.addError, onDone: () => completer.complete(), ); await completer.future; _personStreamContorller.add(lastData.copyWith(hasNext: false)); } final DiContainer _c; final Account account; final AccountPrefController accountPrefController; var _isPersonStreamInited = false; final _personStreamContorller = BehaviorSubject.seeded( const PersonStreamEvent(data: [], hasNext: true), ); }