Fix item count in HomeCollections does not consider the runtime count from item controller

This commit is contained in:
Ming Ming 2024-02-07 01:08:28 +08:00
parent e77059225b
commit 0521e2b5c3
7 changed files with 89 additions and 16 deletions

View file

@ -51,6 +51,13 @@ class CollectionItemsController {
required this.collection, required this.collection,
required this.onCollectionUpdated, required this.onCollectionUpdated,
}) { }) {
_countStreamController = BehaviorSubject.seeded(collection.count);
_subscriptions.add(_dataStreamController.stream.listen((event) {
if (!event.hasNext) {
_countStreamController.add(event.items.length);
}
}));
_subscriptions.add(filesController.stream.listen(_onFilesEvent)); _subscriptions.add(filesController.stream.listen(_onFilesEvent));
} }
@ -82,6 +89,8 @@ class CollectionItemsController {
/// Peek the stream and return the current value /// Peek the stream and return the current value
CollectionItemStreamData peekStream() => _dataStreamController.stream.value; CollectionItemStreamData peekStream() => _dataStreamController.stream.value;
ValueStream<int?> get countStream => _countStreamController.stream;
/// Add list of [files] to [collection] /// Add list of [files] to [collection]
Future<void> addFiles(List<FileDescriptor> files) async { Future<void> addFiles(List<FileDescriptor> files) async {
final isInited = _isDataStreamInited; final isInited = _isDataStreamInited;
@ -346,6 +355,7 @@ class CollectionItemsController {
hasNext: true, hasNext: true,
), ),
); );
late final BehaviorSubject<int?> _countStreamController;
final _mutex = Mutex(); final _mutex = Mutex();
final _subscriptions = <StreamSubscription>[]; final _subscriptions = <StreamSubscription>[];

View file

@ -191,9 +191,14 @@ class _WrappedHomeCollectionsState extends State<_WrappedHomeCollections>
items: state.transformedItems, items: state.transformedItems,
itemBuilder: (_, __, metadata) { itemBuilder: (_, __, metadata) {
final item = metadata as _Item; final item = metadata as _Item;
return _ItemView( return _BlocSelector<int?>(
account: _bloc.account, selector: (state) =>
item: item, state.itemCounts[item.collection.id],
builder: (context, itemCount) => _ItemView(
account: _bloc.account,
item: item,
collectionItemCountOverride: itemCount,
),
); );
}, },
staggeredTileBuilder: (_, __) => staggeredTileBuilder: (_, __) =>
@ -267,7 +272,8 @@ class _WrappedHomeCollectionsState extends State<_WrappedHomeCollections>
typedef _BlocBuilder = BlocBuilder<_Bloc, _State>; typedef _BlocBuilder = BlocBuilder<_Bloc, _State>;
typedef _BlocListener = BlocListener<_Bloc, _State>; typedef _BlocListener = BlocListener<_Bloc, _State>;
// typedef _BlocSelector<T> = BlocSelector<_Bloc, _State, T>; // typedef _BlocListenerT<T> = BlocListenerT<_Bloc, _State, T>;
typedef _BlocSelector<T> = BlocSelector<_Bloc, _State, T>;
extension on BuildContext { extension on BuildContext {
_Bloc get bloc => read<_Bloc>(); _Bloc get bloc => read<_Bloc>();

View file

@ -19,6 +19,7 @@ abstract class $_StateCopyWithWorker {
bool? isLoading, bool? isLoading,
List<_Item>? transformedItems, List<_Item>? transformedItems,
Set<_Item>? selectedItems, Set<_Item>? selectedItems,
Map<String, int>? itemCounts,
ExceptionEvent? error, ExceptionEvent? error,
ExceptionEvent? removeError}); ExceptionEvent? removeError});
} }
@ -33,6 +34,7 @@ class _$_StateCopyWithWorkerImpl implements $_StateCopyWithWorker {
dynamic isLoading, dynamic isLoading,
dynamic transformedItems, dynamic transformedItems,
dynamic selectedItems, dynamic selectedItems,
dynamic itemCounts,
dynamic error = copyWithNull, dynamic error = copyWithNull,
dynamic removeError = copyWithNull}) { dynamic removeError = copyWithNull}) {
return _State( return _State(
@ -42,6 +44,7 @@ class _$_StateCopyWithWorkerImpl implements $_StateCopyWithWorker {
transformedItems: transformedItems:
transformedItems as List<_Item>? ?? that.transformedItems, transformedItems as List<_Item>? ?? that.transformedItems,
selectedItems: selectedItems as Set<_Item>? ?? that.selectedItems, selectedItems: selectedItems as Set<_Item>? ?? that.selectedItems,
itemCounts: itemCounts as Map<String, int>? ?? that.itemCounts,
error: error == copyWithNull ? that.error : error as ExceptionEvent?, error: error == copyWithNull ? that.error : error as ExceptionEvent?,
removeError: removeError == copyWithNull removeError: removeError == copyWithNull
? that.removeError ? that.removeError
@ -96,7 +99,7 @@ extension _$_ItemNpLog on _Item {
extension _$_StateToString on _State { extension _$_StateToString on _State {
String _$toString() { String _$toString() {
// ignore: unnecessary_string_interpolations // ignore: unnecessary_string_interpolations
return "_State {collections: [length: ${collections.length}], sort: ${sort.name}, isLoading: $isLoading, transformedItems: [length: ${transformedItems.length}], selectedItems: {length: ${selectedItems.length}}, error: $error, removeError: $removeError}"; return "_State {collections: [length: ${collections.length}], sort: ${sort.name}, isLoading: $isLoading, transformedItems: [length: ${transformedItems.length}], selectedItems: {length: ${selectedItems.length}}, itemCounts: $itemCounts, error: $error, removeError: $removeError}";
} }
} }
@ -149,6 +152,13 @@ extension _$_SetCollectionSortToString on _SetCollectionSort {
} }
} }
extension _$_SetItemCountToString on _SetItemCount {
String _$toString() {
// ignore: unnecessary_string_interpolations
return "_SetItemCount {collection: $collection, value: $value}";
}
}
extension _$_SetErrorToString on _SetError { extension _$_SetErrorToString on _SetError {
String _$toString() { String _$toString() {
// ignore: unnecessary_string_interpolations // ignore: unnecessary_string_interpolations

View file

@ -16,18 +16,36 @@ class _Bloc extends Bloc<_Event, _State> with BlocLogger {
on<_UpdateCollectionSort>(_onUpdateCollectionSort); on<_UpdateCollectionSort>(_onUpdateCollectionSort);
on<_SetCollectionSort>(_onSetCollectionSort); on<_SetCollectionSort>(_onSetCollectionSort);
on<_SetItemCount>(_onSetItemCount);
on<_SetError>(_onSetError); on<_SetError>(_onSetError);
_homeAlbumsSortSubscription = _subscriptions.add(prefController.homeAlbumsSort.distinct().listen((event) {
prefController.homeAlbumsSort.distinct().listen((event) {
add(_UpdateCollectionSort(collection_util.CollectionSort.values[event])); add(_UpdateCollectionSort(collection_util.CollectionSort.values[event]));
}); }));
_subscriptions.add(controller.stream.listen((event) {
for (final s in _itemSubscriptions) {
s.cancel();
}
_itemSubscriptions.clear();
for (final d in event.data) {
_itemSubscriptions.add(d.controller.countStream.listen((event) {
if (event != null) {
add(_SetItemCount(d.collection, event));
}
}));
}
}));
} }
@override @override
Future<void> close() { Future<void> close() {
_homeAlbumsSortSubscription?.cancel(); for (final s in _itemSubscriptions) {
s.cancel();
}
for (final s in _subscriptions) {
s.cancel();
}
return super.close(); return super.close();
} }
@ -105,6 +123,13 @@ class _Bloc extends Bloc<_Event, _State> with BlocLogger {
prefController.setHomeAlbumsSort(ev.sort.index); prefController.setHomeAlbumsSort(ev.sort.index);
} }
void _onSetItemCount(_SetItemCount ev, Emitter<_State> emit) {
_log.info(ev);
final next = Map.of(state.itemCounts);
next[ev.collection.id] = ev.value;
emit(state.copyWith(itemCounts: next));
}
void _onSetError(_SetError ev, Emitter<_State> emit) { void _onSetError(_SetError ev, Emitter<_State> emit) {
_log.info(ev); _log.info(ev);
emit(state.copyWith(error: ExceptionEvent(ev.error, ev.stackTrace))); emit(state.copyWith(error: ExceptionEvent(ev.error, ev.stackTrace)));
@ -122,6 +147,7 @@ class _Bloc extends Bloc<_Event, _State> with BlocLogger {
final CollectionsController controller; final CollectionsController controller;
final PrefController prefController; final PrefController prefController;
StreamSubscription<int>? _homeAlbumsSortSubscription; final _subscriptions = <StreamSubscription>[];
final _itemSubscriptions = <StreamSubscription>[];
var _isHandlingError = false; var _isHandlingError = false;
} }

View file

@ -9,6 +9,7 @@ class _State {
required this.isLoading, required this.isLoading,
required this.transformedItems, required this.transformedItems,
required this.selectedItems, required this.selectedItems,
required this.itemCounts,
this.error, this.error,
required this.removeError, required this.removeError,
}); });
@ -20,6 +21,7 @@ class _State {
isLoading: false, isLoading: false,
transformedItems: [], transformedItems: [],
selectedItems: {}, selectedItems: {},
itemCounts: {},
removeError: null, removeError: null,
); );
} }
@ -32,6 +34,7 @@ class _State {
final bool isLoading; final bool isLoading;
final List<_Item> transformedItems; final List<_Item> transformedItems;
final Set<_Item> selectedItems; final Set<_Item> selectedItems;
final Map<String, int> itemCounts;
final ExceptionEvent? error; final ExceptionEvent? error;
final ExceptionEvent? removeError; final ExceptionEvent? removeError;
@ -112,6 +115,17 @@ class _SetCollectionSort implements _Event {
final collection_util.CollectionSort sort; final collection_util.CollectionSort sort;
} }
@toString
class _SetItemCount implements _Event {
const _SetItemCount(this.collection, this.value);
@override
String toString() => _$toString();
final Collection collection;
final int value;
}
@toString @toString
class _SetError implements _Event { class _SetError implements _Event {
const _SetError(this.error, [this.stackTrace]); const _SetError(this.error, [this.stackTrace]);

View file

@ -11,9 +11,6 @@ enum _ItemType {
class _Item implements SelectableItemMetadata { class _Item implements SelectableItemMetadata {
_Item(this.collection) _Item(this.collection)
: isShared = collection.shares.isNotEmpty || !collection.isOwned { : isShared = collection.shares.isNotEmpty || !collection.isOwned {
if (collection.count != null) {
_subtitle = L10n.global().albumSize(collection.count!);
}
try { try {
_coverUrl = collection.getCoverUrl(k.coverSize, k.coverSize); _coverUrl = collection.getCoverUrl(k.coverSize, k.coverSize);
} catch (e, stackTrace) { } catch (e, stackTrace) {
@ -35,7 +32,15 @@ class _Item implements SelectableItemMetadata {
String get name => collection.name; String get name => collection.name;
String? get subtitle => _subtitle; String? getSubtitle({
int? itemCountOverride,
}) {
if (collection.count != null) {
return L10n.global().albumSize(itemCountOverride ?? collection.count!);
} else {
return null;
}
}
String? get coverUrl => _coverUrl; String? get coverUrl => _coverUrl;
@ -64,7 +69,6 @@ class _Item implements SelectableItemMetadata {
final Collection collection; final Collection collection;
final bool isShared; final bool isShared;
String? _subtitle;
String? _coverUrl; String? _coverUrl;
late _ItemType _itemType; late _ItemType _itemType;
} }

View file

@ -129,6 +129,7 @@ class _ItemView extends StatelessWidget {
const _ItemView({ const _ItemView({
required this.account, required this.account,
required this.item, required this.item,
this.collectionItemCountOverride,
}); });
@override @override
@ -152,7 +153,8 @@ class _ItemView extends StatelessWidget {
if (item.isShared) { if (item.isShared) {
subtitle = "${L10n.global().albumSharedLabel} | "; subtitle = "${L10n.global().albumSharedLabel} | ";
} }
subtitle += item.subtitle ?? ""; subtitle +=
item.getSubtitle(itemCountOverride: collectionItemCountOverride) ?? "";
return CollectionGridItem( return CollectionGridItem(
cover: _CollectionCover( cover: _CollectionCover(
account: account, account: account,
@ -166,6 +168,7 @@ class _ItemView extends StatelessWidget {
final Account account; final Account account;
final _Item item; final _Item item;
final int? collectionItemCountOverride;
} }
class _CollectionCover extends StatelessWidget { class _CollectionCover extends StatelessWidget {