Skip to content

Commit

Permalink
fixup! fixup! Added redux/domain and presentation layer for audio rec…
Browse files Browse the repository at this point in the history
…ording
  • Loading branch information
KhaledNjim committed Jun 26, 2024
1 parent cdf6958 commit c40312a
Show file tree
Hide file tree
Showing 10 changed files with 364 additions and 68 deletions.
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

import 'package:domain/domain.dart';

class AudioRecorderSuccessViewState extends Success {
Expand All @@ -12,13 +13,23 @@ class AudioRecorderStarted extends Success {
@override
List<Object> get props => [];
}
class AudioRecorderPaused extends Success {
@override
List<Object> get props => [];
}


class AudioRecorderFailed extends FeatureFailure {
@override
List<Object> get props => [];
}

class AudioPermissionDenied extends FeatureFailure {

final bool isPermanentlyDenied;

AudioPermissionDenied(this.isPermanentlyDenied);

@override
List<Object> get props => [];
List<Object> get props => [isPermanentlyDenied];
}
8 changes: 8 additions & 0 deletions lib/presentation/redux/actions/audio_recorder_action.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
import 'package:dartz/dartz.dart';
import 'package:domain/domain.dart';
import 'package:linshare_flutter_app/presentation/redux/actions/app_action.dart';

class AudioRecorderAction extends ActionOffline {
final Either<Failure, Success> viewState;

AudioRecorderAction(this.viewState);
}

class StartRecording extends ActionOffline {}

class PauseRecording extends ActionOffline {}
Expand Down
20 changes: 16 additions & 4 deletions lib/presentation/redux/reducers/audio_recorder_reducer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,33 +28,45 @@
// <http://www.gnu.org/licenses/> for the GNU Affero General Public License version
// 3 and <http://www.linshare.org/licenses/LinShare-License_AfferoGPL-v3.pdf> for
// the Additional Terms applicable to LinShare software.

import 'package:dartz/dartz.dart';
import 'package:domain/domain.dart';
import 'package:linshare_flutter_app/presentation/redux/actions/audio_recorder_action.dart';
import 'package:linshare_flutter_app/presentation/redux/states/audio_recorder_state.dart';
import 'package:redux/redux.dart';

final audioRecorderReducer = combineReducers<AudioRecorderState>([

TypedReducer<AudioRecorderState, AudioRecorderAction>(_updateAudioViewState),
TypedReducer<AudioRecorderState, StartRecording>(_startRecording),
TypedReducer<AudioRecorderState, PauseRecording>(_pauseRecording),
TypedReducer<AudioRecorderState, ResumeRecording>(_resumeRecording),
TypedReducer<AudioRecorderState, StopRecording>(_stopRecording),
]);

AudioRecorderState _updateAudioViewState(
AudioRecorderState state, AudioRecorderAction action) {
return state.sendViewState(viewState: action.viewState);
}

AudioRecorderState _startRecording(
AudioRecorderState state, StartRecording action) {
return AudioRecorderState(status: RecordingStatus.recording);
return AudioRecorderState(Right(AudioRecorderStarted()));
}



AudioRecorderState _pauseRecording(
AudioRecorderState state, PauseRecording action) {
return AudioRecorderState(status: RecordingStatus.paused);
return AudioRecorderState(Right(AudioRecorderPaused()));
}

AudioRecorderState _resumeRecording(
AudioRecorderState state, ResumeRecording action) {
return AudioRecorderState(status: RecordingStatus.recording);
return AudioRecorderState(Right(AudioRecorderStarted()));
}

AudioRecorderState _stopRecording(
AudioRecorderState state, StopRecording action) {
return AudioRecorderState(status: RecordingStatus.idle);
return AudioRecorderState(Right(IdleState()));
}
37 changes: 26 additions & 11 deletions lib/presentation/redux/states/audio_recorder_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,29 +29,44 @@
// 3 and <http://www.linshare.org/licenses/LinShare-License_AfferoGPL-v3.pdf> for
// the Additional Terms applicable to LinShare software.

import 'package:domain/src/state/success.dart';
import 'package:domain/src/state/failure.dart';
import 'package:dartz/dartz.dart';
import 'package:equatable/equatable.dart';
import 'package:linshare_flutter_app/presentation/redux/states/linshare_state.dart';

enum RecordingStatus { idle, recording, paused, stopped }

class AudioRecorderState with EquatableMixin {
final RecordingStatus status;

AudioRecorderState({
required this.status,
}) : super();
class AudioRecorderState extends LinShareState with EquatableMixin {
AudioRecorderState(Either<Failure, Success> viewState) : super(viewState);

factory AudioRecorderState.initial() {
return AudioRecorderState(
status: RecordingStatus.idle,
Right(IdleState()),
);
}

AudioRecorderState setRecordingState({required RecordingStatus status}) {
return AudioRecorderState(
status: status,
AudioRecorderState setRecordingState(viewState) {
return AudioRecorderState(viewState
);
}

@override
List<Object> get props => [status];
AudioRecorderState clearViewState() {
return AudioRecorderState(Right(IdleState()));
}

@override
AudioRecorderState sendViewState(
{required Either<Failure, Success> viewState}) {
return AudioRecorderState(viewState);
}

@override
AudioRecorderState startLoadingState() {
return AudioRecorderState(Right(LoadingState()));
}

@override
List<Object> get props => [viewState];
}
66 changes: 48 additions & 18 deletions lib/presentation/util/audio_recorder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,21 +33,25 @@ import 'dart:io';
import 'package:audio_waveforms/audio_waveforms.dart';
import 'package:dartz/dartz.dart';
import 'package:domain/domain.dart';
import 'package:linshare_flutter_app/presentation/util/permission_service.dart';
import 'package:permission_handler/permission_handler.dart';

class AudioRecorder {
final RecorderController recorderController = RecorderController();
final PermissionService permissionService = PermissionService();

Future<Either<Failure, Success>> startRecordingAudio() async {
try {
final permission = await recorderController.checkPermission();
if (permission) {
final permission =
await permissionService.checkPermissionForAudioRecordingActions();
if (permission.isGranted) {
final tempPath = Directory.systemTemp.path;
final currentTime = DateTime.now().millisecondsSinceEpoch;
final fileName = 'audio_$currentTime.m4a';
await recorderController.record('$tempPath/$fileName');
return Right(AudioRecorderStarted());
} else {
return Left(AudioPermissionDenied());
return Left(AudioPermissionDenied(permission.isPermanentlyDenied));
}
} catch (exception) {
return Left(AudioRecorderFailed());
Expand All @@ -58,29 +62,55 @@ class AudioRecorder {
stopRecordingAndSave() async {
FileInfo file;
List<FileInfo> pickedFiles = [];
await recorderController.stop().then((value) {
if (value != null) {
var recordedFile = File(value);
file = FileInfo(recordedFile.path.split('/').last,
'${recordedFile.parent.path}/', recordedFile.lengthSync());
pickedFiles.add(file);
try {
await recorderController.stop().then((value) {
if (value != null) {
var recordedFile = File(value);
file = FileInfo(recordedFile.path.split('/').last,
'${recordedFile.parent.path}/', recordedFile.lengthSync());
pickedFiles.add(file);
}
});
if (pickedFiles.isNotEmpty) {
return Right(AudioRecorderSuccessViewState(pickedFiles));
}
});
if (pickedFiles.isNotEmpty) {
return Right(AudioRecorderSuccessViewState(pickedFiles));
return Left(AudioRecorderFailed());
} catch (exception) {
return Left(AudioRecorderFailed());
}
return Left(AudioRecorderFailed());
}

void pauseRecording() {
Either<Failure, Success> pauseRecording() {
try {
recorderController.pause();
return Right(AudioRecorderPaused());
} catch (exception) {
return Left(AudioRecorderFailed());
}
}

Either<Failure, Success> stopRecording() {
try {
recorderController.stop();
return Right(AudioRecorderPaused());
} catch (exception) {
return Left(AudioRecorderFailed());
}
}

void stopRecording() {
recorderController.stop();
Either<Failure, Success> resumeRecording() {
try {
recorderController.record();
return Right(AudioRecorderPaused());
} catch (exception) {
return Left(AudioRecorderFailed());
}
}

void resumeRecording() {
recorderController.recorderState;
String formatElapsedTime(int elapsedMilliseconds) {
final minutes = elapsedMilliseconds ~/ 60000;
final seconds = (elapsedMilliseconds ~/ 1000) % 60;
final remainingMilliseconds = (elapsedMilliseconds % 1000) ~/ 10;
return '${minutes.toString().padLeft(2, '0')}:${seconds.toString().padLeft(2, '0')}.${remainingMilliseconds.toString().padLeft(2, '0')}';
}
}
19 changes: 19 additions & 0 deletions lib/presentation/util/toast_message_handler.dart
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ import 'package:linshare_flutter_app/presentation/redux/actions/upload_request_g
import 'package:linshare_flutter_app/presentation/redux/actions/upload_request_group_archived_action.dart';
import 'package:linshare_flutter_app/presentation/redux/actions/upload_request_group_created_action.dart';
import 'package:linshare_flutter_app/presentation/redux/states/app_state.dart';
import 'package:linshare_flutter_app/presentation/redux/states/audio_recorder_state.dart';
import 'package:linshare_flutter_app/presentation/redux/states/delete_shared_space_members_state.dart';
import 'package:linshare_flutter_app/presentation/redux/states/my_space_state.dart';
import 'package:linshare_flutter_app/presentation/redux/states/network_connectivity_state.dart';
Expand Down Expand Up @@ -96,6 +97,7 @@ class ToastMessageHandler {
_handleActiveClosedUploadRequestInsideToastMessage(context, event.activeClosedUploadRequestInsideState);
_handleCreatedUploadRequestInsideToastMessage(context, event.createdUploadRequestInsideState);
_handleArchivedUploadRequestInsideToastMessage(context, event.archivedUploadRequestInsideState);
_handleAudioRecorderToastMessage(context, event.audioRecorderState);
});
}

Expand Down Expand Up @@ -679,6 +681,23 @@ class ToastMessageHandler {
});
}

void _handleAudioRecorderToastMessage(
BuildContext context, AudioRecorderState audioRecorderState) {
audioRecorderState.viewState.fold((failure) {
debugPrint(audioRecorderState.toString());
if (failure is AudioRecorderFailed) {
appToast.showErrorToast(AppLocalizations.of(context).error_while_recording);
} else if (failure is AudioPermissionDenied) {
appToast.showErrorToast(AppLocalizations.of(context).permission_denied);
}
}, (success) {
debugPrint(audioRecorderState.toString());
if (success is AudioRecorderSuccessViewState) {
appToast.showToast(AppLocalizations.of(context).recording_saved);
}
});
}

void _cleanActiveClosedUploadRequestInsideViewState() {
_store.dispatch(CleanActiveClosedUploadRequestInsideAction());
}
Expand Down
Loading

0 comments on commit c40312a

Please sign in to comment.