Sunday, 9 April 2023

Run Intent from within @HiltViewModel and get results

This code below works. But it sits in the MainActivity.kt, the spoken words are retrieved under the resultLauncher code.

fun askSpeechInput(context: Context, viewModel: SettingsViewModel) {
        if (!SpeechRecognizer.isRecognitionAvailable(context)) {
            Toast.makeText(context, "Speech not Available", Toast.LENGTH_SHORT).show()
        } else {
            val intent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH)
            intent.putExtra(
                RecognizerIntent.EXTRA_LANGUAGE_MODEL,
                RecognizerIntent.LANGUAGE_MODEL_WEB_SEARCH
            )
            intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.getDefault())
            intent.putExtra(RecognizerIntent.EXTRA_PROMPT, "Talk")
            intent.putExtra()
            resultLauncher.launch(intent).let {
                viewModel.reactToSpeech(speechInput.value.toString().lowercase())
            }
        }
    }

    private var resultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult())
    { result ->
        if(result.resultCode == Activity.RESULT_OK){
            val data: Intent? = result.data
            val result = data?.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS)
            speechInput.value = result?.get(0).toString()
        }
    }

I am trying to do them same with this code below, but, this does not respond. Is it possible to achieve the same functionality from within a ViewModel class? If yes, how can I run the Intent.

@HiltViewModel
class SettingsViewModel @Inject constructor(
    private val settingsRepository: SettingsRepository
) : ViewModel(), RecognitionListener
{
    data class SpeechState(
        val spokenText: String = "",
        val error: String = ""
    )

    private val _settings = MutableStateFlow(value = Settings())
    val settings: StateFlow<HomeSettings> = _settings.asStateFlow()
    private val speechState = MutableStateFlow(value = SpeechState())

    private val speechRecognizer: SpeechRecognizer = createSpeechRecognizer(application.applicationContext).apply {
        setRecognitionListener(this@SettingsViewModel)
    }


    private fun updateResults(speechBundle: Bundle?) {
        val userSaid = speechBundle?.getStringArrayList(RESULTS_RECOGNITION)
        speechState.value = speechState.value.copy(spokenText = userSaid?.get(0) ?: "")
        reactToSpeech(speechState.value.spokenText)
    }

    override fun onEndOfSpeech() = speechRecognizer.stopListening()
    override fun onResults(results: Bundle?) = updateResults(speechBundle = results)
    override fun onPartialResults(results: Bundle?) = updateResults(speechBundle = results)


    override fun onError(errorCode: Int) {}

    private val recognizerIntent: Intent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH).apply {
        putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM)
        putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, application.packageName)
        putExtra(
            RecognizerIntent.EXTRA_LANGUAGE_MODEL,
            RecognizerIntent.LANGUAGE_MODEL_WEB_SEARCH
        )
        putExtra(RecognizerIntent.EXTRA_PROMPT, "Talk")
        //putExtra(RecognizerIntent.EXTRA_PARTIAL_RESULTS, true)
    }

    init {}

    fun startListening(){
        speechRecognizer.startListening(recognizerIntent)
    }

    private fun reactToSpeech(speech: String){
        when(speech){
            "run" -> Log.w("App", "Running!")
            "stop" -> Log.w("App", "Stopped!")
            else -> {}
        }
    }

    override fun onReadyForSpeech(p0: Bundle?) {}
    override fun onBeginningOfSpeech() {}
    override fun onRmsChanged(p0: Float) {}
    override fun onBufferReceived(p0: ByteArray?) {}
    override fun onEvent(p0: Int, p1: Bundle?) {}
}


from Run Intent from within @HiltViewModel and get results

No comments:

Post a Comment