diff --git a/lib/services/api_service.dart b/lib/services/api_service.dart index a245536..6316a15 100644 --- a/lib/services/api_service.dart +++ b/lib/services/api_service.dart @@ -506,10 +506,11 @@ class ApiService { final Response response = await _service.dio .get('$kBaseUrl/api/$kApiVersionUrl/$kModulesUrl/$id/$kPracticesUrl'); + print('MODULE PRACTICES: ${response.data}'); if (response.statusCode == 200) { var data = response.data; - var decodedData = data['data'] as List; + var decodedData = data['data']['practices'] as List; practices = decodedData.map( (e) { return LearnPractice.fromJson(e); diff --git a/lib/services/audio_player_service.dart b/lib/services/audio_player_service.dart index b0b352d..1e9cb3e 100644 --- a/lib/services/audio_player_service.dart +++ b/lib/services/audio_player_service.dart @@ -1,3 +1,6 @@ +import 'dart:async'; + +import 'package:async/async.dart'; import 'package:audioplayers/audioplayers.dart'; import 'package:stacked/stacked.dart'; @@ -9,13 +12,19 @@ class AudioPlayerService with ListenableServiceMixin { AudioPlayer get player => _player; + final _durationController = StreamController.broadcast(); + AudioPlayerService() { _player.setReleaseMode(ReleaseMode.stop); } // Streams + Stream get durationStream => StreamGroup.merge([ + _player.onDurationChanged, + _durationController.stream, + ]); + Stream get positionStream => _player.onPositionChanged; - Stream get durationStream => _player.onDurationChanged; // Optional: player state Stream get stateStream => _player.onPlayerStateChanged; @@ -28,10 +37,16 @@ class AudioPlayerService with ListenableServiceMixin { } await _player.play(UrlSource(playableUrl)); + + // 👇 Force duration fetch + final dur = await _player.getDuration(); + if (dur != null) { + _durationController.add(dur); + } } Future playLocal(String url) async { - await _player.play(UrlSource(url)); + await _player.play(DeviceFileSource(url)); } Future pause() async => await _player.pause(); diff --git a/lib/services/authentication_service.dart b/lib/services/authentication_service.dart index 12928ca..82a0bf6 100644 --- a/lib/services/authentication_service.dart +++ b/lib/services/authentication_service.dart @@ -148,6 +148,8 @@ class AuthenticationService with ListenableServiceMixin { // Get user data Future getUser() async { + print('GENDER:'); + print(await _secureService.getString('gender')); _user = User( userId: await _secureService.getInt('userId'), email: await _secureService.getString('email'), diff --git a/lib/services/voice_recorder_service.dart b/lib/services/voice_recorder_service.dart index 6b4a58e..cacd540 100644 --- a/lib/services/voice_recorder_service.dart +++ b/lib/services/voice_recorder_service.dart @@ -1,7 +1,5 @@ import 'dart:io'; - -import 'package:image_picker/image_picker.dart'; -import 'package:path/path.dart'; +import 'dart:math'; import 'package:path_provider/path_provider.dart'; import 'package:stacked/stacked.dart'; import 'package:waveform_recorder/waveform_recorder.dart'; @@ -39,25 +37,19 @@ class VoiceRecorderService with ListenableServiceMixin { // Get recorded audio Future getRecordedAudio() async { - final file = _waveController.file; - print('RECORDED $file'); - if (file == null) return null; + final recorded = _waveController.file; + if (recorded == null) return null; - await _saveRecordedAudio(file); + final generator = Random(); - // return file.path; - String? voice = await _saveRecordedAudio(file); - return voice; - } + int random = generator.nextInt(100); - Future _saveRecordedAudio(XFile? file) async { - late File voice; - final voiceName = basename(file?.name ?? ''); - final Directory appDir = await getApplicationDocumentsDirectory(); + final dir = await getTemporaryDirectory(); - final localImagePath = join(appDir.path, voiceName); - voice = File(localImagePath); - //voice.writeAsBytes(await file?.); - return voice.path; + final playable = File('${dir.path}/temp_audio_$random.aac'); + + await playable.writeAsBytes(await recorded.readAsBytes(), flush: true); + + return playable.path; } } diff --git a/lib/ui/views/learn_practice/learn_practice_viewmodel.dart b/lib/ui/views/learn_practice/learn_practice_viewmodel.dart index fec9c70..6b90c40 100644 --- a/lib/ui/views/learn_practice/learn_practice_viewmodel.dart +++ b/lib/ui/views/learn_practice/learn_practice_viewmodel.dart @@ -59,10 +59,12 @@ class LearnPracticeViewModel extends ReactiveViewModel { Duration get duration => _duration; double get progress { + print('DURATION: ${_duration.inMilliseconds}'); if (_duration.inMilliseconds == 0) return 0; return _position.inMilliseconds / _duration.inMilliseconds; } + // Voice recorder WaveformRecorderController get _waveController => _voiceRecorderService.waveController; @@ -127,15 +129,15 @@ class LearnPracticeViewModel extends ReactiveViewModel { // Play practice audio void _listenToAudio() { - _audioPlayerService.durationStream.listen((dur) { + _audioPlayerService.durationStream.listen((dur) { + if (dur.inMilliseconds > 0) { _duration = dur; - print('DURATION: $_duration'); rebuildUi(); - }); + } + }); _audioPlayerService.positionStream.listen((pos) { _position = pos; - print('POSITION: $_position'); rebuildUi(); }); } @@ -255,13 +257,14 @@ class LearnPracticeViewModel extends ReactiveViewModel { if (await _statusChecker.checkConnection()) { if (practice == LearnPractices.course) { _practices = await _apiService.getLearnCoursePractices(id); + await _getLearnPracticeQuestions(_practices.first.questionSetId ?? 0); } else if (practice == LearnPractices.module) { _practices = await _apiService.getLearnModulePractices(id); await _getLearnPracticeQuestions(_practices.first.questionSetId ?? 0); } else { _practices = await _apiService.getLearnLessonPractices(id); - print('PRACTICE LENGTH: ${_practices.length}'); + await _getLearnPracticeQuestions(_practices.first.questionSetId ?? 0); } } diff --git a/lib/ui/views/profile_detail/profile_detail_view.dart b/lib/ui/views/profile_detail/profile_detail_view.dart index c600054..2ae98fe 100644 --- a/lib/ui/views/profile_detail/profile_detail_view.dart +++ b/lib/ui/views/profile_detail/profile_detail_view.dart @@ -370,7 +370,7 @@ class ProfileDetailView extends StackedView Widget _buildMaleRadioTile(ProfileDetailViewModel viewModel) => RadioListTile( - value: 'Male', + value: 'male', title: _buildMaleTitle(), activeColor: kcPrimaryColor, contentPadding: EdgeInsets.zero, @@ -400,7 +400,7 @@ class ProfileDetailView extends StackedView Widget _buildFemaleRadioTile(ProfileDetailViewModel viewModel) => RadioListTile( - value: 'Female', + value: 'female', title: _buildFemaleTitle(), activeColor: kcPrimaryColor, contentPadding: EdgeInsets.zero, diff --git a/lib/ui/widgets/learn_practice_answer_card.dart b/lib/ui/widgets/learn_practice_answer_card.dart index 92d5321..67cccb3 100644 --- a/lib/ui/widgets/learn_practice_answer_card.dart +++ b/lib/ui/widgets/learn_practice_answer_card.dart @@ -1,6 +1,7 @@ import 'package:audioplayers/audioplayers.dart'; import 'package:flutter/material.dart'; import 'package:stacked/stacked.dart'; +import 'package:yimaru_app/ui/widgets/custom_circular_progress_indicator.dart'; import '../common/app_colors.dart'; import '../common/enmus.dart'; @@ -50,13 +51,22 @@ class LearnPracticeAnswerCard extends ViewModelWidget { ); Widget _buildButtonState(LearnPracticeViewModel viewModel) => - (viewModel.busy(answer['busy_object']) && viewModel.playing == voice) || - (viewModel.busyObject == answer['busy_object'] && - viewModel.playing == voice && - viewModel.player.state == PlayerState.playing) - ? _buildPauseIcon() + viewModel.busyObject == answer['busy_object'] && + viewModel.playing == voice + ? viewModel.busy(answer['busy_object']) + ? _buildProgressIndicatorWrapper() + : viewModel.player.state == PlayerState.playing + ? _buildPauseIcon() + : _buildPlayIcon() : _buildPlayIcon(); + Widget _buildProgressIndicatorWrapper() => Center( + child: _buildProgressIndicator(), + ); + + Widget _buildProgressIndicator() => + const CustomCircularProgressIndicator(color: kcWhite); + Widget _buildPlayIcon() => const Icon( Icons.play_arrow_rounded, size: 25, diff --git a/pubspec.lock b/pubspec.lock index 8b2e1dd..5a0b585 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -50,13 +50,13 @@ packages: source: hosted version: "2.7.0" async: - dependency: transitive + dependency: "direct main" description: name: async - sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" + sha256: e2eb0491ba5ddb6177742d2da23904574082139b07c1e33b8503b9f46f3e1a37 url: "https://pub.dev" source: hosted - version: "2.13.0" + version: "2.13.1" audioplayers: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 2fdb46a..a2872a2 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -12,6 +12,7 @@ dependencies: intl: any dio: ^5.9.0 path: ^1.9.1 + async: ^2.13.1 pinput: ^6.0.1 stacked: ^3.4.0 iconsax: ^0.0.8