import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:hive_flutter/hive_flutter.dart'; import '../models/sake_item.dart'; import 'filter_providers.dart'; // 1. Raw List Stream final rawSakeListItemsProvider = StreamProvider>((ref) { final box = Hive.box('sake_items'); // Use startWith to emit current value immediately return box.watch().map((event) => box.values.toList()).startWith(box.values.toList()); }); // 2. Sort Order Stream final sakeSortOrderProvider = StreamProvider>((ref) { final box = Hive.box('settings'); return box.watch(key: 'sake_sort_order').map((event) { final List? stored = box.get('sake_sort_order'); return stored?.cast() ?? []; }).startWith(box.get('sake_sort_order')?.cast() ?? []); }); // Sort Mode Enum enum SortMode { newest, oldest, name, custom } class SakeSortModeNotifier extends Notifier { @override SortMode build() => SortMode.newest; void set(SortMode mode) => state = mode; } final sakeSortModeProvider = NotifierProvider(SakeSortModeNotifier.new); // 3. Combined Sorted List final sakeListProvider = Provider>>((ref) { final rawListAsync = ref.watch(rawSakeListItemsProvider); final sortOrderAsync = ref.watch(sakeSortOrderProvider); final sortMode = ref.watch(sakeSortModeProvider); // Watch Filters final searchQuery = ref.watch(sakeSearchQueryProvider).toLowerCase(); final showFavoritesOnly = ref.watch(sakeFilterFavoriteProvider); final filterTag = ref.watch(sakeFilterTagProvider); final filterPrefecture = ref.watch(sakeFilterPrefectureProvider); return rawListAsync.when( data: (rawList) { if (rawList.isEmpty) return const AsyncValue.data([]); // 1. First, apply filters to raw list var filtered = rawList.where((item) { // Search Filter if (searchQuery.isNotEmpty) { final matches = item.displayData.name.toLowerCase().contains(searchQuery) || item.displayData.brewery.toLowerCase().contains(searchQuery) || item.displayData.prefecture.toLowerCase().contains(searchQuery); if (!matches) return false; } // Favorite Filter if (showFavoritesOnly) { if (!item.userData.isFavorite) return false; } // Prefecture Filter if (filterPrefecture != null) { if (item.displayData.prefecture != filterPrefecture) return false; } // Tag Filter if (filterTag != null && filterTag != 'All') { // Special case for 'Set' which effectively filters by itemType if we had it, or implicit tag if (filterTag == 'Set') { // Assuming 'Set' tag is manually added or we check itemType if implemented // For now, check flavorTags for 'Set' or 'セット' final isSet = item.hiddenSpecs.flavorTags.contains('セット') || item.hiddenSpecs.flavorTags.contains('Set') || item.displayData.name.contains('セット'); if (!isSet) return false; } else { final matchesTag = item.hiddenSpecs.flavorTags.contains(filterTag); if (!matchesTag) return false; } } return true; }).toList(); // 2. Then apply sort based on SortMode switch (sortMode) { case SortMode.newest: filtered.sort((a, b) => b.metadata.createdAt.compareTo(a.metadata.createdAt)); break; case SortMode.oldest: filtered.sort((a, b) => a.metadata.createdAt.compareTo(b.metadata.createdAt)); break; case SortMode.name: filtered.sort((a, b) => a.displayData.name.compareTo(b.displayData.name)); break; case SortMode.custom: default: // Use Manual Sort Order return sortOrderAsync.when( data: (sortOrder) { if (sortOrder.isEmpty) { // Default fallback if no custom order filtered.sort((a, b) => b.metadata.createdAt.compareTo(a.metadata.createdAt)); return AsyncValue.data(filtered); } final orderMap = {for (var i = 0; i < sortOrder.length; i++) sortOrder[i]: i}; filtered.sort((a, b) { final idxA = orderMap[a.id]; final idxB = orderMap[b.id]; if (idxA != null && idxB != null) { return idxA.compareTo(idxB); } else if (idxA != null) { return -1; } else if (idxB != null) { return 1; } else { return b.metadata.createdAt.compareTo(a.metadata.createdAt); } }); return AsyncValue.data(filtered); }, loading: () => AsyncValue.data(filtered), error: (e, s) => AsyncValue.error(e, s), ); } return AsyncValue.data(filtered); }, loading: () => const AsyncValue.loading(), error: (e, s) => AsyncValue.error(e, s), ); }); // 4. Controller for Updating Order class SakeOrderController extends Notifier { @override void build() {} void updateOrder(List newOrder) { final box = Hive.box('settings'); final ids = newOrder.map((e) => e.id).toList(); box.put('sake_sort_order', ids); } } final sakeOrderControllerProvider = NotifierProvider(SakeOrderController.new); extension StreamStartWith on Stream { Stream startWith(T initial) async* { yield initial; yield* this; } }