94 lines
2.5 KiB
Dart
94 lines
2.5 KiB
Dart
/// [ChangeNotifier] that loads, filters, and mutates the in-memory item list.
|
|
library;
|
|
|
|
import 'package:flutter/foundation.dart';
|
|
|
|
import '../models/item.dart';
|
|
import '../services/item_repository.dart';
|
|
import '../services/storage_service.dart';
|
|
|
|
/// App-wide catalog state. Screens call [loadItems], [addItem], and [search].
|
|
class ItemController extends ChangeNotifier {
|
|
ItemController({
|
|
required this._repository,
|
|
required this._storage,
|
|
}) {
|
|
_repository.useRemoteData = _storage.useRemoteData;
|
|
}
|
|
|
|
final ItemRepository _repository;
|
|
final StorageService _storage;
|
|
|
|
List<Item> _items = const [];
|
|
bool _isLoading = false;
|
|
String? _error;
|
|
|
|
List<Item> get items => List.unmodifiable(_items);
|
|
bool get isLoading => _isLoading;
|
|
String? get error => _error;
|
|
bool get useRemoteData => _repository.useRemoteData;
|
|
int get count => _items.length;
|
|
|
|
Future<void> loadItems() async {
|
|
_isLoading = true;
|
|
_error = null;
|
|
notifyListeners();
|
|
|
|
try {
|
|
// Small delay so the loading indicator is visible with local data.
|
|
await Future<void>.delayed(const Duration(milliseconds: 250));
|
|
_items = await _repository.fetchItems();
|
|
} catch (error, stackTrace) {
|
|
_error = 'Could not load items.';
|
|
debugPrint('ItemController.loadItems failed: $error\n$stackTrace');
|
|
} finally {
|
|
_isLoading = false;
|
|
notifyListeners();
|
|
}
|
|
}
|
|
|
|
Future<void> setUseRemoteData(bool value) async {
|
|
if (value == _repository.useRemoteData) return;
|
|
_repository.useRemoteData = value;
|
|
await _storage.setUseRemoteData(value);
|
|
notifyListeners();
|
|
await loadItems();
|
|
}
|
|
|
|
/// Case-insensitive match against title, subtitle, and category.
|
|
List<Item> search(String query) {
|
|
final needle = query.trim().toLowerCase();
|
|
if (needle.isEmpty) return items;
|
|
|
|
return _items.where((item) {
|
|
return item.title.toLowerCase().contains(needle) ||
|
|
item.subtitle.toLowerCase().contains(needle) ||
|
|
item.category.label.toLowerCase().contains(needle);
|
|
}).toList(growable: false);
|
|
}
|
|
|
|
Item addItem({
|
|
required String title,
|
|
required String subtitle,
|
|
required String description,
|
|
required ItemCategory category,
|
|
}) {
|
|
final created = _repository.createLocal(
|
|
title: title,
|
|
subtitle: subtitle,
|
|
description: description,
|
|
category: category,
|
|
);
|
|
_items = [created, ..._items];
|
|
notifyListeners();
|
|
return created;
|
|
}
|
|
|
|
Item? findById(String id) {
|
|
for (final item in _items) {
|
|
if (item.id == id) return item;
|
|
}
|
|
return null;
|
|
}
|
|
}
|