Files
yanting/lib/data/state/app_state_controllers.dart
2026-06-07 11:38:08 +08:00

169 lines
4.3 KiB
Dart

import 'package:hooks_riverpod/hooks_riverpod.dart';
import '../models/models.dart';
import '../repositories/user_state_repository.dart';
import 'app_interaction_state.dart';
import 'report_query.dart';
class RecommendTopicController extends StateNotifier<String> {
RecommendTopicController() : super('全部');
void select(String topic) {
state = topic;
}
}
class ReportFilterController extends StateNotifier<ReportQuery> {
ReportFilterController() : super(const ReportQuery());
void setSearch(String value) {
state = state.copyWith(search: value);
}
void setTopic(String? topic) {
state = state.copyWith(topic: topic);
}
void setInstitution(String? institutionId) {
state = state.copyWith(institutionId: institutionId);
}
void toggleAudio() {
state = state.copyWith(hasAudio: !state.hasAudio);
}
void setSort(ReportSort sort) {
state = state.copyWith(sort: sort);
}
void reset() {
state = const ReportQuery();
}
}
class AuthController extends StateNotifier<AuthState> {
AuthController(this._repository) : super(const AuthState()) {
_load();
}
final UserStateRepository _repository;
Future<void> _load() async {
state = state.copyWith(
loggedIn: await _repository.isLoggedIn(),
phone: await _repository.getPhone(),
loginMethod: await _repository.getLoginMethod(),
);
}
void requireLogin(PendingLoginAction action) {
if (state.loggedIn) return;
state = state.copyWith(pendingAction: action);
}
Future<PendingLoginAction?> login(LoginMethod method, {String? phone}) async {
final pending = state.pendingAction;
await _repository.login(method, phone: phone);
state = AuthState(
loggedIn: true,
phone: phone ?? await _repository.getPhone(),
loginMethod: method,
);
return pending;
}
Future<void> logout() async {
await _repository.logout();
state = const AuthState();
}
void clearPending() {
state = state.copyWith(pendingAction: null);
}
}
class ProfileController extends StateNotifier<ProfileState> {
ProfileController(this._repository) : super(const ProfileState()) {
refresh();
}
final UserStateRepository _repository;
Future<void> refresh() async {
state = ProfileState(
favorites: await _repository.getFavorites(),
savedListens: await _repository.getSavedListens(),
history: await _repository.getHistory(),
);
}
Future<void> toggleFavorite(String reportId) async {
await _repository.toggleFavorite(reportId);
await refresh();
}
Future<void> toggleSavedListen(String reportId) async {
await _repository.toggleSavedListen(reportId);
await refresh();
}
Future<void> addHistory(String reportId) async {
await _repository.addHistory(reportId);
await refresh();
}
}
class DetailNavigationController extends StateNotifier<DetailNavigationState> {
DetailNavigationController() : super(const DetailNavigationState());
void rememberTabScroll(AppTab tab, double scrollTop) {
state = state.copyWith(tabScroll: {...state.tabScroll, tab: scrollTop});
}
void push(DetailStackEntry entry, {required AppTab originTab}) {
final stack = [...state.stack, entry];
state = state.copyWith(originTab: originTab, stack: stack);
}
void updateCurrentScroll(double scrollTop) {
if (state.stack.isEmpty) return;
final stack = [...state.stack];
stack[stack.length - 1] = stack.last.copyWith(scrollTop: scrollTop);
state = state.copyWith(stack: stack);
}
DetailStackEntry? pop() {
if (state.stack.isEmpty) return null;
final stack = [...state.stack]..removeLast();
state = state.copyWith(stack: stack);
return stack.isEmpty ? null : stack.last;
}
void reset() {
state = const DetailNavigationState();
}
}
class SheetController extends StateNotifier<SheetState> {
SheetController() : super(const SheetState.hidden());
void show(SheetIntent intent) {
state = SheetState.visible(intent);
}
void hide() {
state = const SheetState.hidden();
}
}
class ProfileListBuilder {
const ProfileListBuilder(this.reports);
final List<ReportCardModel> reports;
List<ReportCardModel> byIds(Iterable<String> ids) {
final byId = {for (final report in reports) report.id: report};
return ids.map((id) => byId[id]).whereType<ReportCardModel>().toList();
}
}