From 001f616b62d82a3b7d42928f2435be317a433444 Mon Sep 17 00:00:00 2001 From: Juri Date: Wed, 11 May 2022 21:54:04 +0200 Subject: [PATCH 01/15] Allow user to move a piece with voice + basic error msg --- .../DelegatingSpeechRecognizerState.kt | 46 +++++++++++++++---- .../ch/epfl/sdp/mobile/ui/i18n/English.kt | 4 ++ .../sdp/mobile/ui/i18n/LocalizedStrings.kt | 4 ++ 3 files changed, 45 insertions(+), 9 deletions(-) diff --git a/mobile/src/main/java/ch/epfl/sdp/mobile/state/game/delegating/DelegatingSpeechRecognizerState.kt b/mobile/src/main/java/ch/epfl/sdp/mobile/state/game/delegating/DelegatingSpeechRecognizerState.kt index 898e15ebf..67a8a483d 100644 --- a/mobile/src/main/java/ch/epfl/sdp/mobile/state/game/delegating/DelegatingSpeechRecognizerState.kt +++ b/mobile/src/main/java/ch/epfl/sdp/mobile/state/game/delegating/DelegatingSpeechRecognizerState.kt @@ -5,12 +5,13 @@ package ch.epfl.sdp.mobile.state.game.delegating import androidx.compose.foundation.MutatePriority import androidx.compose.foundation.MutatorMutex import androidx.compose.material.SnackbarHostState +import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue -import ch.epfl.sdp.mobile.application.chess.engine.Position import ch.epfl.sdp.mobile.application.chess.voice.VoiceInput import ch.epfl.sdp.mobile.application.speech.SpeechFacade +import ch.epfl.sdp.mobile.state.LocalLocalizedStrings import ch.epfl.sdp.mobile.state.game.core.MutableGameDelegate import ch.epfl.sdp.mobile.ui.game.SpeechRecognizerState import com.google.accompanist.permissions.ExperimentalPermissionsApi @@ -62,14 +63,17 @@ constructor( snackbarHostState.showSnackbar("Internal failure") is SpeechFacade.RecognitionResult.Success -> { - val parsedValue = VoiceInput.parseInput(speech.results) - snackbarHostState.showSnackbar(parsedValue.toString()) - - // TODO(Chau) : Do something more interesting - Position.all() - .flatMap { delegate.game.actions(it) } - .onEach { delegate.tryPerformAction(it) } - .firstOrNull() + // Parsed the input + val parsedAction = VoiceInput.parseInput(speech.results) + if (parsedAction != null) { + // Try to perform the action + val isSuccessful = delegate.tryPerformAction(parsedAction) + if (!isSuccessful) + // If the action is illegal show in the snackbar + snackbarHostState.showSnackbar(SpeechRecognizerError.IllegalAction.toString()) + } else { // If cannot be parsed show error message + snackbarHostState.showSnackbar(SpeechRecognizerError.UnknownCommand.toString()) + } } } } @@ -80,3 +84,27 @@ constructor( } } } + +/** Enum class that defined different error related to the speech recognizer */ +enum class SpeechRecognizerError { + + // FIXME General error, temporary + InternalError, + + /** The asked command cannot be performed */ + IllegalAction, + + /** The command cannot be parsed */ + UnknownCommand +} + +/** Transform a [SpeechRecognizerError] into a [String] */ +@Composable +fun SpeechRecognizerError.toString() { + val strings = LocalLocalizedStrings.current + when (this) { + SpeechRecognizerError.InternalError -> strings.gameSnackBarInternalFailure + SpeechRecognizerError.IllegalAction -> strings.gameSnackBarIllegalAction + SpeechRecognizerError.UnknownCommand -> strings.gameSnackBarUnknownCommand + } +} diff --git a/mobile/src/main/java/ch/epfl/sdp/mobile/ui/i18n/English.kt b/mobile/src/main/java/ch/epfl/sdp/mobile/ui/i18n/English.kt index 08f4d5145..fe378ebd8 100644 --- a/mobile/src/main/java/ch/epfl/sdp/mobile/ui/i18n/English.kt +++ b/mobile/src/main/java/ch/epfl/sdp/mobile/ui/i18n/English.kt @@ -52,6 +52,10 @@ object English : LocalizedStrings { override val gamePromoteTitle = "Promote to:" override val gamePromoteConfirm = "Ok".uppercase() + override val gameSnackBarIllegalAction: String = "Illegal action, please try again" + override val gameSnackBarInternalFailure = "Internal failure" + override val gameSnackBarUnknownCommand: String = "Unknown command, please try again" + override val profileMatchTitle = { opponent: String -> "Against $opponent" } override val profileWonByCheckmate = { moves: Int -> "Won by checkmate after $moves moves" } override val profileWonByForfeit = { moves: Int -> "Won by forfeit after $moves moves" } diff --git a/mobile/src/main/java/ch/epfl/sdp/mobile/ui/i18n/LocalizedStrings.kt b/mobile/src/main/java/ch/epfl/sdp/mobile/ui/i18n/LocalizedStrings.kt index 8fa5ca65f..41cbe5504 100644 --- a/mobile/src/main/java/ch/epfl/sdp/mobile/ui/i18n/LocalizedStrings.kt +++ b/mobile/src/main/java/ch/epfl/sdp/mobile/ui/i18n/LocalizedStrings.kt @@ -77,6 +77,10 @@ interface LocalizedStrings { val gamePromoteTitle: String val gamePromoteConfirm: String + val gameSnackBarIllegalAction : String + val gameSnackBarInternalFailure : String + val gameSnackBarUnknownCommand : String + val socialFollowingTitle: String val socialPerformPlay: String val socialPerformFollow: String From c396c0bd2988318c59ef46798be67d9a19352c79 Mon Sep 17 00:00:00 2001 From: Juri Date: Wed, 11 May 2022 22:09:20 +0200 Subject: [PATCH 02/15] Fix formating --- .../java/ch/epfl/sdp/mobile/ui/i18n/LocalizedStrings.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mobile/src/main/java/ch/epfl/sdp/mobile/ui/i18n/LocalizedStrings.kt b/mobile/src/main/java/ch/epfl/sdp/mobile/ui/i18n/LocalizedStrings.kt index 41cbe5504..364524789 100644 --- a/mobile/src/main/java/ch/epfl/sdp/mobile/ui/i18n/LocalizedStrings.kt +++ b/mobile/src/main/java/ch/epfl/sdp/mobile/ui/i18n/LocalizedStrings.kt @@ -77,9 +77,9 @@ interface LocalizedStrings { val gamePromoteTitle: String val gamePromoteConfirm: String - val gameSnackBarIllegalAction : String - val gameSnackBarInternalFailure : String - val gameSnackBarUnknownCommand : String + val gameSnackBarIllegalAction: String + val gameSnackBarInternalFailure: String + val gameSnackBarUnknownCommand: String val socialFollowingTitle: String val socialPerformPlay: String From 24343ed08d272817ef6fe99e2d2e83dc0cf5ee62 Mon Sep 17 00:00:00 2001 From: Juri Date: Thu, 12 May 2022 09:47:57 +0200 Subject: [PATCH 03/15] Create a compoable for snackbar (Not working) --- .../test/state/StatefulGameScreenTest.kt | 3 +- .../sdp/mobile/test/ui/game/GameScreenTest.kt | 10 +++--- .../sdp/mobile/state/StatefulGameScreen.kt | 30 ++++++++++++++++ .../state/game/ActualGameScreenState.kt | 3 +- .../DelegatingSpeechRecognizerState.kt | 35 ++++--------------- .../sdp/mobile/ui/game/GameScreenState.kt | 2 +- .../mobile/ui/game/SpeechRecognizerState.kt | 16 +++++++++ 7 files changed, 62 insertions(+), 37 deletions(-) diff --git a/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/state/StatefulGameScreenTest.kt b/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/state/StatefulGameScreenTest.kt index 9d8d07ae7..8ac8d8906 100644 --- a/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/state/StatefulGameScreenTest.kt +++ b/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/state/StatefulGameScreenTest.kt @@ -41,6 +41,7 @@ import ch.epfl.sdp.mobile.ui.game.ChessBoardState import ch.epfl.sdp.mobile.ui.game.ChessBoardState.Color.Black import ch.epfl.sdp.mobile.ui.game.ChessBoardState.Color.White import ch.epfl.sdp.mobile.ui.game.ChessBoardState.Rank.* +import ch.epfl.sdp.mobile.ui.game.SpeechRecognizerState.SpeechRecognizerError.* import com.google.accompanist.permissions.ExperimentalPermissionsApi import com.google.accompanist.permissions.PermissionState import com.google.common.truth.Truth.assertThat @@ -735,7 +736,7 @@ class StatefulGameScreenTest { audioPermission = GrantedPermissionState, ) robot.onNodeWithLocalizedContentDescription { gameMicOffContentDescription }.performClick() - robot.onNodeWithText("Internal failure").assertExists() + robot.onNodeWithText(robot.strings.gameSnackBarInternalFailure).assertExists() } @Test diff --git a/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/ui/game/GameScreenTest.kt b/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/ui/game/GameScreenTest.kt index d9dba2aca..813ef7981 100644 --- a/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/ui/game/GameScreenTest.kt +++ b/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/ui/game/GameScreenTest.kt @@ -6,12 +6,11 @@ import androidx.compose.ui.test.onNodeWithContentDescription import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.performClick import ch.epfl.sdp.mobile.test.state.setContentWithLocalizedStrings +import ch.epfl.sdp.mobile.ui.game.* import ch.epfl.sdp.mobile.ui.game.ChessBoardState.Piece -import ch.epfl.sdp.mobile.ui.game.GameScreen -import ch.epfl.sdp.mobile.ui.game.GameScreenState -import ch.epfl.sdp.mobile.ui.game.MovableChessBoardState import ch.epfl.sdp.mobile.ui.game.MovesInfoState.Move -import ch.epfl.sdp.mobile.ui.game.PlayersInfoState +import ch.epfl.sdp.mobile.ui.game.SpeechRecognizerState.SpeechRecognizerError +import ch.epfl.sdp.mobile.ui.game.SpeechRecognizerState.SpeechRecognizerError.* import org.junit.Rule import org.junit.Test @@ -21,6 +20,9 @@ class GameScreenTest { private class SnapshotGameScreenState : GameScreenState, MovableChessBoardState by ChessBoardTest.SinglePieceSnapshotChessBoardState() { + + override var currentError: SpeechRecognizerError = None + override val moves: List get() = listOf( diff --git a/mobile/src/main/java/ch/epfl/sdp/mobile/state/StatefulGameScreen.kt b/mobile/src/main/java/ch/epfl/sdp/mobile/state/StatefulGameScreen.kt index 078e4b800..a7c329ec9 100644 --- a/mobile/src/main/java/ch/epfl/sdp/mobile/state/StatefulGameScreen.kt +++ b/mobile/src/main/java/ch/epfl/sdp/mobile/state/StatefulGameScreen.kt @@ -11,6 +11,7 @@ import ch.epfl.sdp.mobile.application.authentication.AuthenticatedUser import ch.epfl.sdp.mobile.application.chess.Match import ch.epfl.sdp.mobile.state.game.ActualGameScreenState import ch.epfl.sdp.mobile.ui.game.* +import ch.epfl.sdp.mobile.ui.game.SpeechRecognizerState.SpeechRecognizerError import com.google.accompanist.permissions.ExperimentalPermissionsApi import com.google.accompanist.permissions.PermissionState import com.google.accompanist.permissions.rememberPermissionState @@ -67,6 +68,8 @@ fun StatefulGameScreen( StatefulPromoteDialog(gameScreenState) + StatefulSnackBar(gameScreenState, snackbarHostState) + GameScreen( state = gameScreenState, modifier = modifier, @@ -99,3 +102,30 @@ private fun StatefulPromoteDialog( ) } } + +@Composable +private fun StatefulSnackBar( + state: SpeechRecognizerState, + snackbarHostState: SnackbarHostState, +) { + + // FIXME : Why this don't launch we we change the currentError ? + LaunchedEffect(state) { + if (state.currentError != SpeechRecognizerError.None) { + // FIXME : Why we can't call toMessage() ? + snackbarHostState.showSnackbar(state.currentError.toString()) + } + } +} + +/** Transform a [SpeechRecognizerError] into a [String] */ +@Composable +fun SpeechRecognizerError.toMessage(): String { + val strings = LocalLocalizedStrings.current + return when (this) { + SpeechRecognizerError.InternalError -> strings.gameSnackBarInternalFailure + SpeechRecognizerError.IllegalAction -> strings.gameSnackBarIllegalAction + SpeechRecognizerError.UnknownCommand -> strings.gameSnackBarUnknownCommand + SpeechRecognizerError.None -> "" + } +} diff --git a/mobile/src/main/java/ch/epfl/sdp/mobile/state/game/ActualGameScreenState.kt b/mobile/src/main/java/ch/epfl/sdp/mobile/state/game/ActualGameScreenState.kt index 8ade8b397..0a38a43d3 100644 --- a/mobile/src/main/java/ch/epfl/sdp/mobile/state/game/ActualGameScreenState.kt +++ b/mobile/src/main/java/ch/epfl/sdp/mobile/state/game/ActualGameScreenState.kt @@ -65,8 +65,7 @@ fun ActualGameScreenState( promotionState = promotions, movesInfo = moves, playersInfo = players, - speechRecognizer = speechRecognizer, - ) + speechRecognizer = speechRecognizer) } /** diff --git a/mobile/src/main/java/ch/epfl/sdp/mobile/state/game/delegating/DelegatingSpeechRecognizerState.kt b/mobile/src/main/java/ch/epfl/sdp/mobile/state/game/delegating/DelegatingSpeechRecognizerState.kt index 67a8a483d..6803ddc1f 100644 --- a/mobile/src/main/java/ch/epfl/sdp/mobile/state/game/delegating/DelegatingSpeechRecognizerState.kt +++ b/mobile/src/main/java/ch/epfl/sdp/mobile/state/game/delegating/DelegatingSpeechRecognizerState.kt @@ -5,13 +5,11 @@ package ch.epfl.sdp.mobile.state.game.delegating import androidx.compose.foundation.MutatePriority import androidx.compose.foundation.MutatorMutex import androidx.compose.material.SnackbarHostState -import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import ch.epfl.sdp.mobile.application.chess.voice.VoiceInput import ch.epfl.sdp.mobile.application.speech.SpeechFacade -import ch.epfl.sdp.mobile.state.LocalLocalizedStrings import ch.epfl.sdp.mobile.state.game.core.MutableGameDelegate import ch.epfl.sdp.mobile.ui.game.SpeechRecognizerState import com.google.accompanist.permissions.ExperimentalPermissionsApi @@ -38,6 +36,9 @@ constructor( private val scope: CoroutineScope, ) : SpeechRecognizerState { + override var currentError: SpeechRecognizerState.SpeechRecognizerError = + SpeechRecognizerState.SpeechRecognizerError.None + override var listening: Boolean by mutableStateOf(false) private set @@ -60,7 +61,7 @@ constructor( when (val speech = facade.recognize()) { // TODO : Display an appropriate message, otherwise act on the board. SpeechFacade.RecognitionResult.Failure.Internal -> - snackbarHostState.showSnackbar("Internal failure") + currentError = SpeechRecognizerState.SpeechRecognizerError.InternalError is SpeechFacade.RecognitionResult.Success -> { // Parsed the input @@ -69,10 +70,10 @@ constructor( // Try to perform the action val isSuccessful = delegate.tryPerformAction(parsedAction) if (!isSuccessful) + currentError = SpeechRecognizerState.SpeechRecognizerError.IllegalAction // If the action is illegal show in the snackbar - snackbarHostState.showSnackbar(SpeechRecognizerError.IllegalAction.toString()) } else { // If cannot be parsed show error message - snackbarHostState.showSnackbar(SpeechRecognizerError.UnknownCommand.toString()) + currentError = SpeechRecognizerState.SpeechRecognizerError.UnknownCommand } } } @@ -84,27 +85,3 @@ constructor( } } } - -/** Enum class that defined different error related to the speech recognizer */ -enum class SpeechRecognizerError { - - // FIXME General error, temporary - InternalError, - - /** The asked command cannot be performed */ - IllegalAction, - - /** The command cannot be parsed */ - UnknownCommand -} - -/** Transform a [SpeechRecognizerError] into a [String] */ -@Composable -fun SpeechRecognizerError.toString() { - val strings = LocalLocalizedStrings.current - when (this) { - SpeechRecognizerError.InternalError -> strings.gameSnackBarInternalFailure - SpeechRecognizerError.IllegalAction -> strings.gameSnackBarIllegalAction - SpeechRecognizerError.UnknownCommand -> strings.gameSnackBarUnknownCommand - } -} diff --git a/mobile/src/main/java/ch/epfl/sdp/mobile/ui/game/GameScreenState.kt b/mobile/src/main/java/ch/epfl/sdp/mobile/ui/game/GameScreenState.kt index d35339cfb..dd8bf6590 100644 --- a/mobile/src/main/java/ch/epfl/sdp/mobile/ui/game/GameScreenState.kt +++ b/mobile/src/main/java/ch/epfl/sdp/mobile/ui/game/GameScreenState.kt @@ -10,7 +10,7 @@ import androidx.compose.runtime.Stable */ @Stable interface GameScreenState : - MovableChessBoardState, MovesInfoState, PlayersInfoState, SpeechRecognizerState { + MovableChessBoardState, MovesInfoState, PlayersInfoState, SpeechRecognizerState{ /** A callback which will be invoked when the user clicks on the AR button. */ fun onArClick() diff --git a/mobile/src/main/java/ch/epfl/sdp/mobile/ui/game/SpeechRecognizerState.kt b/mobile/src/main/java/ch/epfl/sdp/mobile/ui/game/SpeechRecognizerState.kt index 639a6c3f6..a411e87f9 100644 --- a/mobile/src/main/java/ch/epfl/sdp/mobile/ui/game/SpeechRecognizerState.kt +++ b/mobile/src/main/java/ch/epfl/sdp/mobile/ui/game/SpeechRecognizerState.kt @@ -6,6 +6,22 @@ import androidx.compose.runtime.Stable @Stable interface SpeechRecognizerState { + var currentError: SpeechRecognizerError + + /** Enum class that defined different error related to the speech recognizer */ + enum class SpeechRecognizerError { + + // FIXME General error, temporary + InternalError, + + /** The asked command cannot be performed */ + IllegalAction, + + /** The command cannot be parsed */ + UnknownCommand, + None + } + /** A [Boolean] which indicates if the device is currently listening to voice inputs. */ val listening: Boolean From 76c8b0f3ac191da6ee7356283c6d01776d976543 Mon Sep 17 00:00:00 2001 From: Juri Date: Thu, 12 May 2022 10:16:30 +0200 Subject: [PATCH 04/15] Fix Snackbar that doesn't show --- .../ch/epfl/sdp/mobile/state/StatefulGameScreen.kt | 8 ++++---- .../delegating/DelegatingSpeechRecognizerState.kt | 11 +++++------ .../ch/epfl/sdp/mobile/ui/game/GameScreenState.kt | 2 +- .../epfl/sdp/mobile/ui/game/SpeechRecognizerState.kt | 2 +- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/mobile/src/main/java/ch/epfl/sdp/mobile/state/StatefulGameScreen.kt b/mobile/src/main/java/ch/epfl/sdp/mobile/state/StatefulGameScreen.kt index a7c329ec9..609baf710 100644 --- a/mobile/src/main/java/ch/epfl/sdp/mobile/state/StatefulGameScreen.kt +++ b/mobile/src/main/java/ch/epfl/sdp/mobile/state/StatefulGameScreen.kt @@ -4,6 +4,7 @@ package ch.epfl.sdp.mobile.state import android.Manifest.permission.RECORD_AUDIO import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.material.SnackbarDuration import androidx.compose.material.SnackbarHostState import androidx.compose.runtime.* import androidx.compose.ui.Modifier @@ -108,12 +109,11 @@ private fun StatefulSnackBar( state: SpeechRecognizerState, snackbarHostState: SnackbarHostState, ) { - - // FIXME : Why this don't launch we we change the currentError ? - LaunchedEffect(state) { + LaunchedEffect(state.currentError) { if (state.currentError != SpeechRecognizerError.None) { // FIXME : Why we can't call toMessage() ? - snackbarHostState.showSnackbar(state.currentError.toString()) + snackbarHostState.showSnackbar( + state.currentError.toString(), duration = SnackbarDuration.Long) } } } diff --git a/mobile/src/main/java/ch/epfl/sdp/mobile/state/game/delegating/DelegatingSpeechRecognizerState.kt b/mobile/src/main/java/ch/epfl/sdp/mobile/state/game/delegating/DelegatingSpeechRecognizerState.kt index 6803ddc1f..2b0fb6924 100644 --- a/mobile/src/main/java/ch/epfl/sdp/mobile/state/game/delegating/DelegatingSpeechRecognizerState.kt +++ b/mobile/src/main/java/ch/epfl/sdp/mobile/state/game/delegating/DelegatingSpeechRecognizerState.kt @@ -12,6 +12,7 @@ import ch.epfl.sdp.mobile.application.chess.voice.VoiceInput import ch.epfl.sdp.mobile.application.speech.SpeechFacade import ch.epfl.sdp.mobile.state.game.core.MutableGameDelegate import ch.epfl.sdp.mobile.ui.game.SpeechRecognizerState +import ch.epfl.sdp.mobile.ui.game.SpeechRecognizerState.* import com.google.accompanist.permissions.ExperimentalPermissionsApi import com.google.accompanist.permissions.PermissionState import kotlinx.coroutines.CoroutineScope @@ -36,8 +37,7 @@ constructor( private val scope: CoroutineScope, ) : SpeechRecognizerState { - override var currentError: SpeechRecognizerState.SpeechRecognizerError = - SpeechRecognizerState.SpeechRecognizerError.None + override var currentError by mutableStateOf(SpeechRecognizerError.None) override var listening: Boolean by mutableStateOf(false) private set @@ -61,7 +61,7 @@ constructor( when (val speech = facade.recognize()) { // TODO : Display an appropriate message, otherwise act on the board. SpeechFacade.RecognitionResult.Failure.Internal -> - currentError = SpeechRecognizerState.SpeechRecognizerError.InternalError + currentError = SpeechRecognizerError.InternalError is SpeechFacade.RecognitionResult.Success -> { // Parsed the input @@ -69,11 +69,10 @@ constructor( if (parsedAction != null) { // Try to perform the action val isSuccessful = delegate.tryPerformAction(parsedAction) - if (!isSuccessful) - currentError = SpeechRecognizerState.SpeechRecognizerError.IllegalAction + if (!isSuccessful) currentError = SpeechRecognizerError.IllegalAction // If the action is illegal show in the snackbar } else { // If cannot be parsed show error message - currentError = SpeechRecognizerState.SpeechRecognizerError.UnknownCommand + currentError = SpeechRecognizerError.UnknownCommand } } } diff --git a/mobile/src/main/java/ch/epfl/sdp/mobile/ui/game/GameScreenState.kt b/mobile/src/main/java/ch/epfl/sdp/mobile/ui/game/GameScreenState.kt index dd8bf6590..d35339cfb 100644 --- a/mobile/src/main/java/ch/epfl/sdp/mobile/ui/game/GameScreenState.kt +++ b/mobile/src/main/java/ch/epfl/sdp/mobile/ui/game/GameScreenState.kt @@ -10,7 +10,7 @@ import androidx.compose.runtime.Stable */ @Stable interface GameScreenState : - MovableChessBoardState, MovesInfoState, PlayersInfoState, SpeechRecognizerState{ + MovableChessBoardState, MovesInfoState, PlayersInfoState, SpeechRecognizerState { /** A callback which will be invoked when the user clicks on the AR button. */ fun onArClick() diff --git a/mobile/src/main/java/ch/epfl/sdp/mobile/ui/game/SpeechRecognizerState.kt b/mobile/src/main/java/ch/epfl/sdp/mobile/ui/game/SpeechRecognizerState.kt index a411e87f9..793509b64 100644 --- a/mobile/src/main/java/ch/epfl/sdp/mobile/ui/game/SpeechRecognizerState.kt +++ b/mobile/src/main/java/ch/epfl/sdp/mobile/ui/game/SpeechRecognizerState.kt @@ -6,7 +6,7 @@ import androidx.compose.runtime.Stable @Stable interface SpeechRecognizerState { - var currentError: SpeechRecognizerError + val currentError: SpeechRecognizerError /** Enum class that defined different error related to the speech recognizer */ enum class SpeechRecognizerError { From 28cbc972514b15db3872c12045271fec8f0eb431 Mon Sep 17 00:00:00 2001 From: Juri Date: Thu, 12 May 2022 10:22:34 +0200 Subject: [PATCH 05/15] Transform the error into a user readable message --- .../test/state/StatefulGameScreenTest.kt | 3 +- .../sdp/mobile/state/StatefulGameScreen.kt | 32 +++++++++---------- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/state/StatefulGameScreenTest.kt b/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/state/StatefulGameScreenTest.kt index 8ac8d8906..3ee44a686 100644 --- a/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/state/StatefulGameScreenTest.kt +++ b/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/state/StatefulGameScreenTest.kt @@ -723,8 +723,7 @@ class StatefulGameScreenTest { audioPermission = GrantedPermissionState, ) robot.onNodeWithLocalizedContentDescription { gameMicOffContentDescription }.performClick() - // Print null because the input in not recognized - robot.onNodeWithText("null").assertExists() + robot.onNodeWithText(robot.strings.gameSnackBarUnknownCommand).assertExists() } @Test diff --git a/mobile/src/main/java/ch/epfl/sdp/mobile/state/StatefulGameScreen.kt b/mobile/src/main/java/ch/epfl/sdp/mobile/state/StatefulGameScreen.kt index 609baf710..0313432f2 100644 --- a/mobile/src/main/java/ch/epfl/sdp/mobile/state/StatefulGameScreen.kt +++ b/mobile/src/main/java/ch/epfl/sdp/mobile/state/StatefulGameScreen.kt @@ -104,28 +104,28 @@ private fun StatefulPromoteDialog( } } +/** + * A composable which displays a snackbar to show the [SpeechRecognizerState.currentError] when it's + * modified + * + * @param state the [SpeechRecognizerState] which backs this dialog. + * @param snackbarHostState the [SnackbarHostState] used to display some results. + */ @Composable private fun StatefulSnackBar( state: SpeechRecognizerState, snackbarHostState: SnackbarHostState, ) { - LaunchedEffect(state.currentError) { - if (state.currentError != SpeechRecognizerError.None) { - // FIXME : Why we can't call toMessage() ? - snackbarHostState.showSnackbar( - state.currentError.toString(), duration = SnackbarDuration.Long) - } - } -} -/** Transform a [SpeechRecognizerError] into a [String] */ -@Composable -fun SpeechRecognizerError.toMessage(): String { val strings = LocalLocalizedStrings.current - return when (this) { - SpeechRecognizerError.InternalError -> strings.gameSnackBarInternalFailure - SpeechRecognizerError.IllegalAction -> strings.gameSnackBarIllegalAction - SpeechRecognizerError.UnknownCommand -> strings.gameSnackBarUnknownCommand - SpeechRecognizerError.None -> "" + LaunchedEffect(state.currentError) { + val msg = + when (state.currentError) { + SpeechRecognizerError.InternalError -> strings.gameSnackBarInternalFailure + SpeechRecognizerError.IllegalAction -> strings.gameSnackBarIllegalAction + SpeechRecognizerError.UnknownCommand -> strings.gameSnackBarUnknownCommand + SpeechRecognizerError.None -> return@LaunchedEffect // Nothing to show + } + snackbarHostState.showSnackbar(msg, duration = SnackbarDuration.Long) } } From 209f1580c3cd9f8871d6f339ac886e00b975f731 Mon Sep 17 00:00:00 2001 From: ChauYingKot Date: Thu, 12 May 2022 11:28:29 +0200 Subject: [PATCH 06/15] Reset the `currentError` after the message is displayed --- .../java/ch/epfl/sdp/mobile/ui/game/SpeechRecognizerState.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mobile/src/main/java/ch/epfl/sdp/mobile/ui/game/SpeechRecognizerState.kt b/mobile/src/main/java/ch/epfl/sdp/mobile/ui/game/SpeechRecognizerState.kt index 793509b64..a411e87f9 100644 --- a/mobile/src/main/java/ch/epfl/sdp/mobile/ui/game/SpeechRecognizerState.kt +++ b/mobile/src/main/java/ch/epfl/sdp/mobile/ui/game/SpeechRecognizerState.kt @@ -6,7 +6,7 @@ import androidx.compose.runtime.Stable @Stable interface SpeechRecognizerState { - val currentError: SpeechRecognizerError + var currentError: SpeechRecognizerError /** Enum class that defined different error related to the speech recognizer */ enum class SpeechRecognizerError { From edee3d4e9cc83065cf6ee4630365ac89018a3b7f Mon Sep 17 00:00:00 2001 From: ChauYingKot Date: Thu, 12 May 2022 11:29:31 +0200 Subject: [PATCH 07/15] Shorten the snackbar duration --- .../main/java/ch/epfl/sdp/mobile/state/StatefulGameScreen.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mobile/src/main/java/ch/epfl/sdp/mobile/state/StatefulGameScreen.kt b/mobile/src/main/java/ch/epfl/sdp/mobile/state/StatefulGameScreen.kt index 0313432f2..2fb77062e 100644 --- a/mobile/src/main/java/ch/epfl/sdp/mobile/state/StatefulGameScreen.kt +++ b/mobile/src/main/java/ch/epfl/sdp/mobile/state/StatefulGameScreen.kt @@ -4,7 +4,6 @@ package ch.epfl.sdp.mobile.state import android.Manifest.permission.RECORD_AUDIO import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.material.SnackbarDuration import androidx.compose.material.SnackbarHostState import androidx.compose.runtime.* import androidx.compose.ui.Modifier @@ -126,6 +125,7 @@ private fun StatefulSnackBar( SpeechRecognizerError.UnknownCommand -> strings.gameSnackBarUnknownCommand SpeechRecognizerError.None -> return@LaunchedEffect // Nothing to show } - snackbarHostState.showSnackbar(msg, duration = SnackbarDuration.Long) + snackbarHostState.showSnackbar(msg) + state.currentError = SpeechRecognizerError.None } } From c33d85f0634c189ca17138cd726edb84cef4b775 Mon Sep 17 00:00:00 2001 From: ChauYingKot Date: Thu, 12 May 2022 11:44:20 +0200 Subject: [PATCH 08/15] Add more tests - Recognized command but illegal action - Recognized command and legal action --- .../speech/IllegalSpeechRecognizerFactory.kt | 31 +++++++++++++++++++ .../speech/LegalSpeechRecognizerFactory.kt | 31 +++++++++++++++++++ .../test/state/StatefulGameScreenTest.kt | 29 ++++++++++++++--- 3 files changed, 87 insertions(+), 4 deletions(-) create mode 100644 mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/infrastructure/speech/IllegalSpeechRecognizerFactory.kt create mode 100644 mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/infrastructure/speech/LegalSpeechRecognizerFactory.kt diff --git a/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/infrastructure/speech/IllegalSpeechRecognizerFactory.kt b/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/infrastructure/speech/IllegalSpeechRecognizerFactory.kt new file mode 100644 index 000000000..6aeb004fb --- /dev/null +++ b/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/infrastructure/speech/IllegalSpeechRecognizerFactory.kt @@ -0,0 +1,31 @@ +package ch.epfl.sdp.mobile.test.infrastructure.speech + +import ch.epfl.sdp.mobile.infrastructure.speech.SpeechRecognizer +import ch.epfl.sdp.mobile.infrastructure.speech.SpeechRecognizerFactory + +/** + * An implementation of [SpeechRecognizerFactory] which is recognized but the resulting action is + * illegal. + */ +object IllegalActionSpeechRecognizerFactory : SpeechRecognizerFactory { + override fun createSpeechRecognizer() = LegalActionSpeechRecognizer() +} + +class IllegalActionSpeechRecognizer : SpeechRecognizer { + + companion object { + + /** The results which will always be returned on success. */ + val Results = listOf("King a3 to b3", "World") + } + + private var listener: SpeechRecognizer.Listener? = null + override fun setListener(listener: SpeechRecognizer.Listener) { + this.listener = listener + } + override fun startListening() { + listener?.onResults(Results) + } + override fun stopListening() = Unit + override fun destroy() = Unit +} diff --git a/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/infrastructure/speech/LegalSpeechRecognizerFactory.kt b/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/infrastructure/speech/LegalSpeechRecognizerFactory.kt new file mode 100644 index 000000000..d3abd677a --- /dev/null +++ b/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/infrastructure/speech/LegalSpeechRecognizerFactory.kt @@ -0,0 +1,31 @@ +package ch.epfl.sdp.mobile.test.infrastructure.speech + +import ch.epfl.sdp.mobile.infrastructure.speech.SpeechRecognizer +import ch.epfl.sdp.mobile.infrastructure.speech.SpeechRecognizerFactory + +/** + * An implementation of [SpeechRecognizerFactory] which is recognized but the resulting action is + * illegal. + */ +object LegalActionSpeechRecognizerFactory : SpeechRecognizerFactory { + override fun createSpeechRecognizer() = LegalActionSpeechRecognizer() +} + +class LegalActionSpeechRecognizer : SpeechRecognizer { + + companion object { + + /** The results which will always be returned on success. */ + val Results = listOf("Pawn e2 to e4", "World") + } + + private var listener: SpeechRecognizer.Listener? = null + override fun setListener(listener: SpeechRecognizer.Listener) { + this.listener = listener + } + override fun startListening() { + listener?.onResults(Results) + } + override fun stopListening() = Unit + override fun destroy() = Unit +} diff --git a/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/state/StatefulGameScreenTest.kt b/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/state/StatefulGameScreenTest.kt index 3ee44a686..ac4f90aa9 100644 --- a/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/state/StatefulGameScreenTest.kt +++ b/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/state/StatefulGameScreenTest.kt @@ -30,9 +30,7 @@ import ch.epfl.sdp.mobile.test.infrastructure.assets.fake.emptyAssets import ch.epfl.sdp.mobile.test.infrastructure.persistence.auth.emptyAuth import ch.epfl.sdp.mobile.test.infrastructure.persistence.store.buildStore import ch.epfl.sdp.mobile.test.infrastructure.persistence.store.document -import ch.epfl.sdp.mobile.test.infrastructure.speech.FailingSpeechRecognizerFactory -import ch.epfl.sdp.mobile.test.infrastructure.speech.SuccessfulSpeechRecognizerFactory -import ch.epfl.sdp.mobile.test.infrastructure.speech.SuspendingSpeechRecognizerFactory +import ch.epfl.sdp.mobile.test.infrastructure.speech.* import ch.epfl.sdp.mobile.test.ui.game.ChessBoardRobot import ch.epfl.sdp.mobile.test.ui.game.click import ch.epfl.sdp.mobile.test.ui.game.drag @@ -41,7 +39,6 @@ import ch.epfl.sdp.mobile.ui.game.ChessBoardState import ch.epfl.sdp.mobile.ui.game.ChessBoardState.Color.Black import ch.epfl.sdp.mobile.ui.game.ChessBoardState.Color.White import ch.epfl.sdp.mobile.ui.game.ChessBoardState.Rank.* -import ch.epfl.sdp.mobile.ui.game.SpeechRecognizerState.SpeechRecognizerError.* import com.google.accompanist.permissions.ExperimentalPermissionsApi import com.google.accompanist.permissions.PermissionState import com.google.common.truth.Truth.assertThat @@ -738,6 +735,30 @@ class StatefulGameScreenTest { robot.onNodeWithText(robot.strings.gameSnackBarInternalFailure).assertExists() } + @Test + fun given_legalActionRecognizer_when_clicksListening_then_noneMessagesDisplayed() { + val robot = + emptyGameAgainstOneselfRobot( + recognizer = LegalActionSpeechRecognizerFactory, + audioPermission = GrantedPermissionState, + ) + robot.onNodeWithLocalizedContentDescription { gameMicOffContentDescription }.performClick() + robot.onNodeWithText(robot.strings.gameSnackBarIllegalAction).assertDoesNotExist() + robot.onNodeWithText(robot.strings.gameSnackBarUnknownCommand).assertDoesNotExist() + robot.onNodeWithText(robot.strings.gameSnackBarInternalFailure).assertDoesNotExist() + } + + @Test + fun given_illegalActionRecognizer_when_clicksListening_then_displayIllegalActionErrorMsg() { + val robot = + emptyGameAgainstOneselfRobot( + recognizer = IllegalActionSpeechRecognizerFactory, + audioPermission = GrantedPermissionState, + ) + robot.onNodeWithLocalizedContentDescription { gameMicOffContentDescription }.performClick() + robot.onNodeWithText(robot.strings.gameSnackBarIllegalAction).assertExists() + } + @Test fun given_noPermission_when_clicksListening_then_requestsPermission() { val permission = MissingPermissionState() From 03c43eacadd1a6b3a3ee6ca35acb728aec2837bc Mon Sep 17 00:00:00 2001 From: ChauYingKot Date: Thu, 12 May 2022 11:46:11 +0200 Subject: [PATCH 09/15] Update old tests name and related function --- .../epfl/sdp/mobile/test/application/SpeechFacadeTest.kt | 4 ++-- ...actory.kt => UnknownCommandSpeechRecognizerFactory.kt} | 2 +- .../test/state/AuthenticatedUserProfileScreenStateTest.kt | 4 ++-- .../sdp/mobile/test/state/ClassicChessBoardStateTest.kt | 4 ++-- .../epfl/sdp/mobile/test/state/StatefulGameScreenTest.kt | 6 ++---- .../ch/epfl/sdp/mobile/test/state/StatefulHomeTest.kt | 8 ++++---- 6 files changed, 13 insertions(+), 15 deletions(-) rename mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/infrastructure/speech/{SuccessfulSpeechRecognizerFactory.kt => UnknownCommandSpeechRecognizerFactory.kt} (92%) diff --git a/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/application/SpeechFacadeTest.kt b/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/application/SpeechFacadeTest.kt index 593b30b39..661975202 100644 --- a/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/application/SpeechFacadeTest.kt +++ b/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/application/SpeechFacadeTest.kt @@ -4,7 +4,7 @@ import ch.epfl.sdp.mobile.application.speech.SpeechFacade import ch.epfl.sdp.mobile.application.speech.SpeechFacade.RecognitionResult.* import ch.epfl.sdp.mobile.test.infrastructure.speech.FailingSpeechRecognizerFactory import ch.epfl.sdp.mobile.test.infrastructure.speech.SuccessfulSpeechRecognizer -import ch.epfl.sdp.mobile.test.infrastructure.speech.SuccessfulSpeechRecognizerFactory +import ch.epfl.sdp.mobile.test.infrastructure.speech.UnknownCommandSpeechRecognizerFactory import ch.epfl.sdp.mobile.test.infrastructure.speech.SuspendingSpeechRecognizerFactory import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.cancelAndJoin @@ -31,7 +31,7 @@ class SpeechFacadeTest { @Test fun given_successfulRecognizer_when_recognizes_then_returnsResults() = runTest { - val facade = SpeechFacade(SuccessfulSpeechRecognizerFactory) + val facade = SpeechFacade(UnknownCommandSpeechRecognizerFactory) assertThat(facade.recognize()).isEqualTo(Success(SuccessfulSpeechRecognizer.Results)) } } diff --git a/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/infrastructure/speech/SuccessfulSpeechRecognizerFactory.kt b/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/infrastructure/speech/UnknownCommandSpeechRecognizerFactory.kt similarity index 92% rename from mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/infrastructure/speech/SuccessfulSpeechRecognizerFactory.kt rename to mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/infrastructure/speech/UnknownCommandSpeechRecognizerFactory.kt index 0f2f9840b..6179766f4 100644 --- a/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/infrastructure/speech/SuccessfulSpeechRecognizerFactory.kt +++ b/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/infrastructure/speech/UnknownCommandSpeechRecognizerFactory.kt @@ -4,7 +4,7 @@ import ch.epfl.sdp.mobile.infrastructure.speech.SpeechRecognizer import ch.epfl.sdp.mobile.infrastructure.speech.SpeechRecognizerFactory /** An implementation of [SpeechRecognizerFactory] which always succeeds. */ -object SuccessfulSpeechRecognizerFactory : SpeechRecognizerFactory { +object UnknownCommandSpeechRecognizerFactory : SpeechRecognizerFactory { override fun createSpeechRecognizer() = SuccessfulSpeechRecognizer() } diff --git a/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/state/AuthenticatedUserProfileScreenStateTest.kt b/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/state/AuthenticatedUserProfileScreenStateTest.kt index f5935d2e0..396a01646 100644 --- a/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/state/AuthenticatedUserProfileScreenStateTest.kt +++ b/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/state/AuthenticatedUserProfileScreenStateTest.kt @@ -14,7 +14,7 @@ import ch.epfl.sdp.mobile.state.StatefulSettingsScreen import ch.epfl.sdp.mobile.test.infrastructure.assets.fake.emptyAssets import ch.epfl.sdp.mobile.test.infrastructure.persistence.auth.emptyAuth import ch.epfl.sdp.mobile.test.infrastructure.persistence.store.emptyStore -import ch.epfl.sdp.mobile.test.infrastructure.speech.SuccessfulSpeechRecognizerFactory +import ch.epfl.sdp.mobile.test.infrastructure.speech.UnknownCommandSpeechRecognizerFactory import io.mockk.every import io.mockk.mockk import kotlinx.coroutines.test.runTest @@ -41,7 +41,7 @@ class AuthenticatedUserProfileScreenStateTest { val chessFacade = ChessFacade(auth, store, assets) val socialFacade = SocialFacade(auth, store) val authenticationFacade = AuthenticationFacade(auth, store) - val speechFacade = SpeechFacade(SuccessfulSpeechRecognizerFactory) + val speechFacade = SpeechFacade(UnknownCommandSpeechRecognizerFactory) val tournamentFacade = TournamentFacade(auth, store) rule.setContent { diff --git a/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/state/ClassicChessBoardStateTest.kt b/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/state/ClassicChessBoardStateTest.kt index 778d39573..c3aecbf3e 100644 --- a/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/state/ClassicChessBoardStateTest.kt +++ b/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/state/ClassicChessBoardStateTest.kt @@ -12,7 +12,7 @@ import ch.epfl.sdp.mobile.test.infrastructure.assets.fake.emptyAssets import ch.epfl.sdp.mobile.test.infrastructure.persistence.auth.emptyAuth import ch.epfl.sdp.mobile.test.infrastructure.persistence.store.buildStore import ch.epfl.sdp.mobile.test.infrastructure.persistence.store.document -import ch.epfl.sdp.mobile.test.infrastructure.speech.SuccessfulSpeechRecognizerFactory +import ch.epfl.sdp.mobile.test.infrastructure.speech.UnknownCommandSpeechRecognizerFactory import ch.epfl.sdp.mobile.ui.game.ChessBoardState import com.google.accompanist.permissions.ExperimentalPermissionsApi import com.google.common.truth.Truth.assertThat @@ -38,7 +38,7 @@ class ClassicChessBoardStateTest { collection("games") { document("id", ChessDocument(whiteId = "id1", blackId = "id2")) } } val facade = ChessFacade(auth, store, assets) - val speechFacade = SpeechFacade(SuccessfulSpeechRecognizerFactory) + val speechFacade = SpeechFacade(UnknownCommandSpeechRecognizerFactory) val user = mockk() every { user.uid } returns "id1" diff --git a/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/state/StatefulGameScreenTest.kt b/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/state/StatefulGameScreenTest.kt index ac4f90aa9..666ace958 100644 --- a/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/state/StatefulGameScreenTest.kt +++ b/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/state/StatefulGameScreenTest.kt @@ -712,11 +712,10 @@ class StatefulGameScreenTest { } @Test - fun given_successfulRecognizer_when_clicksListening_then_displaysRecognitionResults() { - // This will fail once we want to move the pieces instead. + fun given_successfulRecognizer_when_clicksListening_then_displaysUnknownCmdResults() { val robot = emptyGameAgainstOneselfRobot( - recognizer = SuccessfulSpeechRecognizerFactory, + recognizer = UnknownCommandSpeechRecognizerFactory, audioPermission = GrantedPermissionState, ) robot.onNodeWithLocalizedContentDescription { gameMicOffContentDescription }.performClick() @@ -725,7 +724,6 @@ class StatefulGameScreenTest { @Test fun given_failingRecognizer_when_clicksListening_then_displaysFailedRecognitionResults() { - // This will fail once we want to move the pieces instead. val robot = emptyGameAgainstOneselfRobot( recognizer = FailingSpeechRecognizerFactory, diff --git a/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/state/StatefulHomeTest.kt b/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/state/StatefulHomeTest.kt index a43f1ad9b..153d0158e 100644 --- a/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/state/StatefulHomeTest.kt +++ b/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/state/StatefulHomeTest.kt @@ -27,7 +27,7 @@ import ch.epfl.sdp.mobile.test.infrastructure.persistence.store.buildStore import ch.epfl.sdp.mobile.test.infrastructure.persistence.store.document import ch.epfl.sdp.mobile.test.infrastructure.persistence.store.emptyStore import ch.epfl.sdp.mobile.test.infrastructure.speech.FailingSpeechRecognizerFactory -import ch.epfl.sdp.mobile.test.infrastructure.speech.SuccessfulSpeechRecognizerFactory +import ch.epfl.sdp.mobile.test.infrastructure.speech.UnknownCommandSpeechRecognizerFactory import kotlinx.coroutines.flow.filterIsInstance import kotlinx.coroutines.flow.first import kotlinx.coroutines.test.runTest @@ -448,7 +448,7 @@ class StatefulHomeTest { val authFacade = AuthenticationFacade(auth, store) val chessFacade = ChessFacade(auth, store, assets) val socialFacade = SocialFacade(auth, store) - val speechFacade = SpeechFacade(SuccessfulSpeechRecognizerFactory) + val speechFacade = SpeechFacade(UnknownCommandSpeechRecognizerFactory) val tournamentFacade = TournamentFacade(auth, store) authFacade.signInWithEmail("email@example.org", "password") @@ -491,7 +491,7 @@ class StatefulHomeTest { val authFacade = AuthenticationFacade(auth, store) val chessFacade = ChessFacade(auth, store, assets) val socialFacade = SocialFacade(auth, store) - val speechFacade = SpeechFacade(SuccessfulSpeechRecognizerFactory) + val speechFacade = SpeechFacade(UnknownCommandSpeechRecognizerFactory) val tournamentFacade = TournamentFacade(auth, store) authFacade.signInWithEmail("email@example.org", "password") @@ -631,7 +631,7 @@ class StatefulHomeTest { val authFacade = AuthenticationFacade(auth, store) val chessFacade = ChessFacade(auth, store, assets) val socialFacade = SocialFacade(auth, store) - val speechFacade = SpeechFacade(SuccessfulSpeechRecognizerFactory) + val speechFacade = SpeechFacade(UnknownCommandSpeechRecognizerFactory) val tournamentFacade = TournamentFacade(auth, store) authFacade.signUpWithEmail("email@example.org", "user", "password") From e3339071764675909921d96fdd02659038684887 Mon Sep 17 00:00:00 2001 From: ChauYingKot Date: Thu, 12 May 2022 11:46:48 +0200 Subject: [PATCH 10/15] Fix bad rename --- .../infrastructure/speech/IllegalSpeechRecognizerFactory.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/infrastructure/speech/IllegalSpeechRecognizerFactory.kt b/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/infrastructure/speech/IllegalSpeechRecognizerFactory.kt index 6aeb004fb..08bc82b8f 100644 --- a/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/infrastructure/speech/IllegalSpeechRecognizerFactory.kt +++ b/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/infrastructure/speech/IllegalSpeechRecognizerFactory.kt @@ -8,7 +8,7 @@ import ch.epfl.sdp.mobile.infrastructure.speech.SpeechRecognizerFactory * illegal. */ object IllegalActionSpeechRecognizerFactory : SpeechRecognizerFactory { - override fun createSpeechRecognizer() = LegalActionSpeechRecognizer() + override fun createSpeechRecognizer() = IllegalActionSpeechRecognizer() } class IllegalActionSpeechRecognizer : SpeechRecognizer { From 6ad33c2215a215cbeea30da28bd7094098b0695c Mon Sep 17 00:00:00 2001 From: ChauYingKot Date: Thu, 12 May 2022 11:49:29 +0200 Subject: [PATCH 11/15] Fix comment error --- .../test/infrastructure/speech/LegalSpeechRecognizerFactory.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/infrastructure/speech/LegalSpeechRecognizerFactory.kt b/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/infrastructure/speech/LegalSpeechRecognizerFactory.kt index d3abd677a..01c350906 100644 --- a/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/infrastructure/speech/LegalSpeechRecognizerFactory.kt +++ b/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/infrastructure/speech/LegalSpeechRecognizerFactory.kt @@ -5,7 +5,7 @@ import ch.epfl.sdp.mobile.infrastructure.speech.SpeechRecognizerFactory /** * An implementation of [SpeechRecognizerFactory] which is recognized but the resulting action is - * illegal. + * legal. */ object LegalActionSpeechRecognizerFactory : SpeechRecognizerFactory { override fun createSpeechRecognizer() = LegalActionSpeechRecognizer() From 829d79a0ffaf568b58bbdd591572606733b15272 Mon Sep 17 00:00:00 2001 From: ChauYingKot Date: Thu, 12 May 2022 11:50:22 +0200 Subject: [PATCH 12/15] Fix formating --- .../ch/epfl/sdp/mobile/test/application/SpeechFacadeTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/application/SpeechFacadeTest.kt b/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/application/SpeechFacadeTest.kt index 661975202..fa3affe39 100644 --- a/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/application/SpeechFacadeTest.kt +++ b/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/application/SpeechFacadeTest.kt @@ -4,8 +4,8 @@ import ch.epfl.sdp.mobile.application.speech.SpeechFacade import ch.epfl.sdp.mobile.application.speech.SpeechFacade.RecognitionResult.* import ch.epfl.sdp.mobile.test.infrastructure.speech.FailingSpeechRecognizerFactory import ch.epfl.sdp.mobile.test.infrastructure.speech.SuccessfulSpeechRecognizer -import ch.epfl.sdp.mobile.test.infrastructure.speech.UnknownCommandSpeechRecognizerFactory import ch.epfl.sdp.mobile.test.infrastructure.speech.SuspendingSpeechRecognizerFactory +import ch.epfl.sdp.mobile.test.infrastructure.speech.UnknownCommandSpeechRecognizerFactory import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.cancelAndJoin import kotlinx.coroutines.launch From 2eac9ec45ce843604a4355cb00db971f32ab5e58 Mon Sep 17 00:00:00 2001 From: ChauYingKot Date: Thu, 12 May 2022 11:55:42 +0200 Subject: [PATCH 13/15] Improve comments --- .../speech/IllegalSpeechRecognizerFactory.kt | 4 ++-- .../infrastructure/speech/LegalSpeechRecognizerFactory.kt | 4 ++-- .../epfl/sdp/mobile/state/game/ActualGameScreenState.kt | 3 ++- .../ch/epfl/sdp/mobile/ui/game/SpeechRecognizerState.kt | 8 +++++++- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/infrastructure/speech/IllegalSpeechRecognizerFactory.kt b/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/infrastructure/speech/IllegalSpeechRecognizerFactory.kt index 08bc82b8f..138d68847 100644 --- a/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/infrastructure/speech/IllegalSpeechRecognizerFactory.kt +++ b/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/infrastructure/speech/IllegalSpeechRecognizerFactory.kt @@ -4,8 +4,8 @@ import ch.epfl.sdp.mobile.infrastructure.speech.SpeechRecognizer import ch.epfl.sdp.mobile.infrastructure.speech.SpeechRecognizerFactory /** - * An implementation of [SpeechRecognizerFactory] which is recognized but the resulting action is - * illegal. + * An implementation of [SpeechRecognizerFactory] which result is recognized but lead to a illegal + * move. */ object IllegalActionSpeechRecognizerFactory : SpeechRecognizerFactory { override fun createSpeechRecognizer() = IllegalActionSpeechRecognizer() diff --git a/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/infrastructure/speech/LegalSpeechRecognizerFactory.kt b/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/infrastructure/speech/LegalSpeechRecognizerFactory.kt index 01c350906..7429de040 100644 --- a/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/infrastructure/speech/LegalSpeechRecognizerFactory.kt +++ b/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/infrastructure/speech/LegalSpeechRecognizerFactory.kt @@ -4,8 +4,8 @@ import ch.epfl.sdp.mobile.infrastructure.speech.SpeechRecognizer import ch.epfl.sdp.mobile.infrastructure.speech.SpeechRecognizerFactory /** - * An implementation of [SpeechRecognizerFactory] which is recognized but the resulting action is - * legal. + * An implementation of [SpeechRecognizerFactory] which result is recognized but and lead to a legal + * move. */ object LegalActionSpeechRecognizerFactory : SpeechRecognizerFactory { override fun createSpeechRecognizer() = LegalActionSpeechRecognizer() diff --git a/mobile/src/main/java/ch/epfl/sdp/mobile/state/game/ActualGameScreenState.kt b/mobile/src/main/java/ch/epfl/sdp/mobile/state/game/ActualGameScreenState.kt index 0a38a43d3..8ade8b397 100644 --- a/mobile/src/main/java/ch/epfl/sdp/mobile/state/game/ActualGameScreenState.kt +++ b/mobile/src/main/java/ch/epfl/sdp/mobile/state/game/ActualGameScreenState.kt @@ -65,7 +65,8 @@ fun ActualGameScreenState( promotionState = promotions, movesInfo = moves, playersInfo = players, - speechRecognizer = speechRecognizer) + speechRecognizer = speechRecognizer, + ) } /** diff --git a/mobile/src/main/java/ch/epfl/sdp/mobile/ui/game/SpeechRecognizerState.kt b/mobile/src/main/java/ch/epfl/sdp/mobile/ui/game/SpeechRecognizerState.kt index a411e87f9..97253835c 100644 --- a/mobile/src/main/java/ch/epfl/sdp/mobile/ui/game/SpeechRecognizerState.kt +++ b/mobile/src/main/java/ch/epfl/sdp/mobile/ui/game/SpeechRecognizerState.kt @@ -6,6 +6,10 @@ import androidx.compose.runtime.Stable @Stable interface SpeechRecognizerState { + /** + * Store the current error value, if there are not error involved the value is set to + * [SpeechRecognizerError.None] + */ var currentError: SpeechRecognizerError /** Enum class that defined different error related to the speech recognizer */ @@ -19,7 +23,9 @@ interface SpeechRecognizerState { /** The command cannot be parsed */ UnknownCommand, - None + + /** None error */ + None, } /** A [Boolean] which indicates if the device is currently listening to voice inputs. */ From dfebfa3034b3076349c9172373c24ee564eb6d8a Mon Sep 17 00:00:00 2001 From: Juri Date: Thu, 12 May 2022 19:31:31 +0200 Subject: [PATCH 14/15] Fix comment issues (bad comment + bad emplacement) --- .../state/game/delegating/DelegatingSpeechRecognizerState.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mobile/src/main/java/ch/epfl/sdp/mobile/state/game/delegating/DelegatingSpeechRecognizerState.kt b/mobile/src/main/java/ch/epfl/sdp/mobile/state/game/delegating/DelegatingSpeechRecognizerState.kt index 2b0fb6924..195951fb1 100644 --- a/mobile/src/main/java/ch/epfl/sdp/mobile/state/game/delegating/DelegatingSpeechRecognizerState.kt +++ b/mobile/src/main/java/ch/epfl/sdp/mobile/state/game/delegating/DelegatingSpeechRecognizerState.kt @@ -69,9 +69,10 @@ constructor( if (parsedAction != null) { // Try to perform the action val isSuccessful = delegate.tryPerformAction(parsedAction) + + // If the action is illegal if (!isSuccessful) currentError = SpeechRecognizerError.IllegalAction - // If the action is illegal show in the snackbar - } else { // If cannot be parsed show error message + } else { // If cannot be parsed currentError = SpeechRecognizerError.UnknownCommand } } From 04ad760f0127ec0ba042273aaed7b252710deee3 Mon Sep 17 00:00:00 2001 From: Juri Date: Thu, 12 May 2022 20:20:23 +0200 Subject: [PATCH 15/15] Fix merge : use new class name --- .../java/ch/epfl/sdp/mobile/test/state/StatefulHomeTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/state/StatefulHomeTest.kt b/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/state/StatefulHomeTest.kt index f40056230..8e7da8154 100644 --- a/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/state/StatefulHomeTest.kt +++ b/mobile/src/androidTest/java/ch/epfl/sdp/mobile/test/state/StatefulHomeTest.kt @@ -764,7 +764,7 @@ class StatefulHomeTest { val authFacade = AuthenticationFacade(auth, store) val chessFacade = ChessFacade(auth, store, assets) val socialFacade = SocialFacade(auth, store) - val speechFacade = SpeechFacade(SuccessfulSpeechRecognizerFactory) + val speechFacade = SpeechFacade(UnknownCommandSpeechRecognizerFactory) val tournamentFacade = TournamentFacade(auth, store) val user = authFacade.currentUser.filterIsInstance().first()