fix(learn): Fix user recorded voice playing issue
This commit is contained in:
parent
c2fc40fc3b
commit
539d8bf6c2
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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<Duration>.broadcast();
|
||||
|
||||
AudioPlayerService() {
|
||||
_player.setReleaseMode(ReleaseMode.stop);
|
||||
}
|
||||
|
||||
// Streams
|
||||
Stream<Duration> get durationStream => StreamGroup.merge([
|
||||
_player.onDurationChanged,
|
||||
_durationController.stream,
|
||||
]);
|
||||
|
||||
Stream<Duration> get positionStream => _player.onPositionChanged;
|
||||
Stream<Duration> get durationStream => _player.onDurationChanged;
|
||||
|
||||
// Optional: player state
|
||||
Stream<PlayerState> 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<void> playLocal(String url) async {
|
||||
await _player.play(UrlSource(url));
|
||||
await _player.play(DeviceFileSource(url));
|
||||
}
|
||||
|
||||
Future<void> pause() async => await _player.pause();
|
||||
|
|
|
|||
|
|
@ -148,6 +148,8 @@ class AuthenticationService with ListenableServiceMixin {
|
|||
|
||||
// Get user data
|
||||
Future<User?> getUser() async {
|
||||
print('GENDER:');
|
||||
print(await _secureService.getString('gender'));
|
||||
_user = User(
|
||||
userId: await _secureService.getInt('userId'),
|
||||
email: await _secureService.getString('email'),
|
||||
|
|
|
|||
|
|
@ -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<String?> 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<String?> _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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -128,14 +130,14 @@ class LearnPracticeViewModel extends ReactiveViewModel {
|
|||
// Play practice audio
|
||||
void _listenToAudio() {
|
||||
_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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -370,7 +370,7 @@ class ProfileDetailView extends StackedView<ProfileDetailViewModel>
|
|||
|
||||
Widget _buildMaleRadioTile(ProfileDetailViewModel viewModel) =>
|
||||
RadioListTile<String?>(
|
||||
value: 'Male',
|
||||
value: 'male',
|
||||
title: _buildMaleTitle(),
|
||||
activeColor: kcPrimaryColor,
|
||||
contentPadding: EdgeInsets.zero,
|
||||
|
|
@ -400,7 +400,7 @@ class ProfileDetailView extends StackedView<ProfileDetailViewModel>
|
|||
|
||||
Widget _buildFemaleRadioTile(ProfileDetailViewModel viewModel) =>
|
||||
RadioListTile<String?>(
|
||||
value: 'Female',
|
||||
value: 'female',
|
||||
title: _buildFemaleTitle(),
|
||||
activeColor: kcPrimaryColor,
|
||||
contentPadding: EdgeInsets.zero,
|
||||
|
|
|
|||
|
|
@ -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<LearnPracticeViewModel> {
|
|||
);
|
||||
|
||||
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)
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user