Yimaru-Mobile/lib/ui/views/learn_practice/learn_practice_viewmodel.dart
BisratHailu 35baae8d92 - fix(learn): Modify overall learn hierarchy.
- fix(learn): Modify learn path flow according to the new hierarchy.
- add(learn): Add additionl screens for the new hierarchy levels.
2026-04-18 22:04:56 +03:00

201 lines
5.4 KiB
Dart

import 'package:audioplayers/audioplayers.dart';
import 'package:stacked/stacked.dart';
import 'package:stacked_services/stacked_services.dart';
import 'package:waveform_recorder/waveform_recorder.dart';
import 'package:yimaru_app/models/user.dart';
import 'package:yimaru_app/services/authentication_service.dart';
import 'package:yimaru_app/services/voice_recorder_service.dart';
import 'package:yimaru_app/ui/common/enmus.dart';
import '../../../app/app.locator.dart';
import '../../../services/audio_player_service.dart';
import '../../common/app_colors.dart';
class LearnPracticeViewModel extends ReactiveViewModel {
// Dependency injection
final _dialogService = locator<DialogService>();
final _navigationService = locator<NavigationService>();
final _audioPlayerService = locator<AudioPlayerService>();
final _voiceRecorderService = locator<VoiceRecorderService>();
final _authenticationService = locator<AuthenticationService>();
LearnPracticeViewModel() {
_listenToAudio();
}
@override
List<ListenableServiceMixin> get listenableServices =>
[_audioPlayerService, _voiceRecorderService, _authenticationService];
// User
User? get _user => _authenticationService.user;
User? get user => _user;
// AudioPlayer
AudioPlayer get _player => _audioPlayerService.player;
AudioPlayer get player => _player;
Duration _duration = Duration.zero;
Duration _position = Duration.zero;
Duration get position => _position;
Duration get duration => _duration;
double get progress {
if (_duration.inMilliseconds == 0) return 0;
return _position.inMilliseconds / _duration.inMilliseconds;
}
// Voice recorder
WaveformRecorderController get _waveController =>
_voiceRecorderService.waveController;
WaveformRecorderController get waveController => _waveController;
// Voice recorder state
VoiceRecordingState get _recordingState =>
_voiceRecorderService.recordingState;
VoiceRecordingState get recordingState => _recordingState;
// Busy object
StateObjects _busyObject = StateObjects.none;
StateObjects get busyObject => _busyObject;
// In-app navigation
int _currentPage = 0;
int get currentPage => _currentPage;
// Practice
Map<String, dynamic> _selectedPractice = {};
Map<String, dynamic> get selectedPractice => _selectedPractice;
// Voice recorder
Future<void> stopRecording() async =>
await _voiceRecorderService.stopRecording();
Future<void> startRecording() async => await runBusyFuture(_startRecording(),
busyObject: StateObjects.recordLearnPracticeAnswer);
Future<void> _startRecording() async =>
await _voiceRecorderService.startRecording();
// Sample audio
Future<void> playSampleAudio() async =>
await runBusyFuture(_playSampleAudio(),
busyObject: StateObjects.learnPracticeSample);
Future<void> _playSampleAudio() async {
setBusyObject(StateObjects.learnPracticeSample);
await _audioPlayerService.playUrl(_selectedPractice['sample_answer']);
}
Future<void> pauseSampleAudio() async =>
await runBusyFuture(_pauseSampleAudio(),
busyObject: StateObjects.learnPracticeSample);
Future<void> _pauseSampleAudio() async {
setBusyObject(StateObjects.learnPracticeSample);
await _audioPlayerService.pause();
}
// Play practice audio
void _listenToAudio() {
_audioPlayerService.durationStream.listen((dur) {
_duration = dur;
print('DURATION: $_duration');
rebuildUi();
});
_audioPlayerService.positionStream.listen((pos) {
_position = pos;
print('POSITION: $_position');
rebuildUi();
});
}
Future<void> playQuestionAudio() async =>
await runBusyFuture(_playQuestionAudio(),
busyObject: StateObjects.learnPracticeQuestion);
Future<void> _playQuestionAudio() async {
goTo(3);
await _audioPlayerService.playUrl(_selectedPractice['question_audio_url']);
}
// Recorded audio
Future<void> playRecordedAudio() async =>
await runBusyFuture(_playRecordedAudio(),
busyObject: StateObjects.learnPracticeAnswer);
Future<void> _playRecordedAudio() async {
setBusyObject(StateObjects.learnPracticeAnswer);
await _audioPlayerService
.playLocal(await _voiceRecorderService.getRecordedAudio() ?? '');
}
Future<void> pauseRecordedAudio() async =>
await runBusyFuture(_pauseRecordedAudio(),
busyObject: StateObjects.learnPracticeAnswer);
Future<void> _pauseRecordedAudio() async {
setBusyObject(StateObjects.learnPracticeAnswer);
await _audioPlayerService.pause();
}
// Set busy object
void setBusyObject(StateObjects object) {
_busyObject = object;
notifyListeners();
}
// Practice
void setPractice(Map<String, dynamic> practice) {
_selectedPractice = practice;
goTo(1);
}
// Dialogue
Future<bool?> showAbortDialog() async {
DialogResponse? response = await _dialogService.showDialog(
cancelTitle: 'No',
title: 'Recording',
buttonTitle: 'Yes',
barrierDismissible: true,
cancelTitleColor: kcDarkGrey,
buttonTitleColor: kcPrimaryColor,
description: 'Are you sure you want to stop recording?',
);
return response?.confirmed;
}
// In-app navigation
void goTo(int page) {
_currentPage = page;
rebuildUi();
}
void goBack() {
if (_currentPage == 0) {
pop();
} else {
_currentPage--;
rebuildUi();
}
}
// Navigation
void pop() => _navigationService.back();
}