126 lines
3.2 KiB
Dart
126 lines
3.2 KiB
Dart
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||
|
|
import '../models/speaking_scenario.dart';
|
||
|
|
import '../models/conversation.dart';
|
||
|
|
import '../services/speaking_service.dart';
|
||
|
|
|
||
|
|
/// 口语任务状态
|
||
|
|
class SpeakingTasksState {
|
||
|
|
final List<SpeakingTask> tasks;
|
||
|
|
final bool isLoading;
|
||
|
|
final String? error;
|
||
|
|
|
||
|
|
SpeakingTasksState({
|
||
|
|
this.tasks = const [],
|
||
|
|
this.isLoading = false,
|
||
|
|
this.error,
|
||
|
|
});
|
||
|
|
|
||
|
|
SpeakingTasksState copyWith({
|
||
|
|
List<SpeakingTask>? tasks,
|
||
|
|
bool? isLoading,
|
||
|
|
String? error,
|
||
|
|
}) {
|
||
|
|
return SpeakingTasksState(
|
||
|
|
tasks: tasks ?? this.tasks,
|
||
|
|
isLoading: isLoading ?? this.isLoading,
|
||
|
|
error: error,
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// 口语任务 Notifier
|
||
|
|
class SpeakingTasksNotifier extends StateNotifier<SpeakingTasksState> {
|
||
|
|
final SpeakingService _speakingService;
|
||
|
|
|
||
|
|
SpeakingTasksNotifier(this._speakingService) : super(SpeakingTasksState());
|
||
|
|
|
||
|
|
/// 加载口语场景列表
|
||
|
|
Future<void> loadScenarios({
|
||
|
|
SpeakingScenario? scenario,
|
||
|
|
SpeakingDifficulty? difficulty,
|
||
|
|
int page = 1,
|
||
|
|
}) async {
|
||
|
|
state = state.copyWith(isLoading: true, error: null);
|
||
|
|
|
||
|
|
try {
|
||
|
|
final response = await _speakingService.getSpeakingScenarios(
|
||
|
|
scenario: scenario,
|
||
|
|
difficulty: difficulty,
|
||
|
|
page: page,
|
||
|
|
);
|
||
|
|
|
||
|
|
if (response.success && response.data != null) {
|
||
|
|
state = state.copyWith(tasks: response.data!, isLoading: false);
|
||
|
|
} else {
|
||
|
|
state = state.copyWith(
|
||
|
|
isLoading: false,
|
||
|
|
error: response.message,
|
||
|
|
);
|
||
|
|
}
|
||
|
|
} catch (e) {
|
||
|
|
state = state.copyWith(
|
||
|
|
isLoading: false,
|
||
|
|
error: e.toString(),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// 获取推荐任务
|
||
|
|
Future<void> loadRecommendedTasks() async {
|
||
|
|
state = state.copyWith(isLoading: true, error: null);
|
||
|
|
|
||
|
|
try {
|
||
|
|
final response = await _speakingService.getRecommendedTasks();
|
||
|
|
|
||
|
|
if (response.success && response.data != null) {
|
||
|
|
state = state.copyWith(tasks: response.data!, isLoading: false);
|
||
|
|
} else {
|
||
|
|
state = state.copyWith(
|
||
|
|
isLoading: false,
|
||
|
|
error: response.message,
|
||
|
|
);
|
||
|
|
}
|
||
|
|
} catch (e) {
|
||
|
|
state = state.copyWith(
|
||
|
|
isLoading: false,
|
||
|
|
error: e.toString(),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// 口语服务 Provider
|
||
|
|
final speakingServiceProvider = Provider<SpeakingService>((ref) {
|
||
|
|
return SpeakingService();
|
||
|
|
});
|
||
|
|
|
||
|
|
/// 口语任务列表 Provider
|
||
|
|
final speakingTasksProvider = StateNotifierProvider<SpeakingTasksNotifier, SpeakingTasksState>((ref) {
|
||
|
|
final service = ref.watch(speakingServiceProvider);
|
||
|
|
return SpeakingTasksNotifier(service);
|
||
|
|
});
|
||
|
|
|
||
|
|
/// 推荐口语任务 Provider
|
||
|
|
final recommendedSpeakingTasksProvider = FutureProvider<List<SpeakingTask>>((ref) async {
|
||
|
|
final service = ref.watch(speakingServiceProvider);
|
||
|
|
|
||
|
|
try {
|
||
|
|
final response = await service.getRecommendedTasks();
|
||
|
|
return response.data ?? [];
|
||
|
|
} catch (e) {
|
||
|
|
return [];
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
/// 用户口语历史 Provider
|
||
|
|
final userSpeakingHistoryProvider = FutureProvider<List<Conversation>>((ref) async {
|
||
|
|
final service = ref.watch(speakingServiceProvider);
|
||
|
|
|
||
|
|
try {
|
||
|
|
final response = await service.getUserSpeakingHistory(limit: 5);
|
||
|
|
return response.data ?? [];
|
||
|
|
} catch (e) {
|
||
|
|
return [];
|
||
|
|
}
|
||
|
|
});
|