The UI now responds to recording/not recording and messages appears in chat, still some crashes
This commit is contained in:
parent
7baa44a8aa
commit
c24d07bb26
@ -61,6 +61,7 @@ dependencies {
|
||||
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.0'
|
||||
implementation 'com.github.squti:Android-Wave-Recorder:1.6.0'
|
||||
implementation("com.squareup.okhttp3:okhttp:4.9.3")
|
||||
implementation 'com.google.code.gson:gson:2.8.9'
|
||||
implementation 'androidx.activity:activity-compose:1.4.0'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
|
||||
debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
|
||||
|
@ -0,0 +1,36 @@
|
||||
package ch.mathieubroillet.jarvis.android.audio
|
||||
|
||||
import android.content.Context
|
||||
import com.github.squti.androidwaverecorder.WaveRecorder
|
||||
import java.io.File
|
||||
|
||||
|
||||
class AudioRecorder(
|
||||
private var audioTempFileOutput: String = "",
|
||||
var waveRecorder: WaveRecorder
|
||||
) {
|
||||
|
||||
|
||||
fun startRecording() {
|
||||
waveRecorder.startRecording()
|
||||
}
|
||||
|
||||
fun stopRecording() {
|
||||
waveRecorder.stopRecording()
|
||||
|
||||
|
||||
}
|
||||
|
||||
fun getOutputFile(): File {
|
||||
return File(audioTempFileOutput)
|
||||
}
|
||||
}
|
||||
|
||||
fun getAudioRecorder(context: Context): AudioRecorder {
|
||||
val outputFile = context.filesDir.absolutePath + "/temp_recording.wav"
|
||||
|
||||
val waveRecorder: WaveRecorder = WaveRecorder(outputFile)
|
||||
waveRecorder.noiseSuppressorActive = true
|
||||
|
||||
return AudioRecorder(audioTempFileOutput = outputFile, waveRecorder = waveRecorder)
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
package ch.mathieubroillet.jarvis.android.audio
|
||||
|
||||
import android.content.Context
|
||||
import ch.mathieubroillet.jarvis.android.utils.contactServerWithFileAudioRecording
|
||||
import com.github.squti.androidwaverecorder.RecorderState
|
||||
import com.github.squti.androidwaverecorder.WaveRecorder
|
||||
import java.io.File
|
||||
import kotlin.concurrent.thread
|
||||
|
||||
private var audioTempFileOutput: String = ""
|
||||
private var waveRecorder: WaveRecorder? = null
|
||||
private var isRecording: Boolean = false
|
||||
|
||||
fun startRecording() {
|
||||
if (waveRecorder != null) {
|
||||
waveRecorder!!.startRecording()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun stopRecording() {
|
||||
if (waveRecorder != null) {
|
||||
waveRecorder!!.stopRecording()
|
||||
}
|
||||
|
||||
thread {
|
||||
contactServerWithFileAudioRecording(getOutputFile())
|
||||
getOutputFile().delete()
|
||||
}
|
||||
}
|
||||
|
||||
fun getOutputFile(): File {
|
||||
return File(audioTempFileOutput)
|
||||
}
|
||||
|
||||
fun isRecording(): Boolean {
|
||||
return isRecording
|
||||
}
|
||||
|
||||
fun registerRecorder(context: Context) {
|
||||
if (waveRecorder == null) {
|
||||
audioTempFileOutput = context.filesDir.absolutePath + "/temp_recording.wav"
|
||||
waveRecorder = WaveRecorder(audioTempFileOutput)
|
||||
waveRecorder!!.noiseSuppressorActive = true
|
||||
|
||||
|
||||
waveRecorder!!.onStateChangeListener = {
|
||||
when (it) {
|
||||
RecorderState.RECORDING -> {
|
||||
isRecording = true
|
||||
}
|
||||
RecorderState.STOP -> {
|
||||
isRecording = false
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,12 +1,14 @@
|
||||
package ch.mathieubroillet.jarvis.android.nav
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.compose.NavHost
|
||||
import androidx.navigation.compose.composable
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import ch.mathieubroillet.jarvis.android.R
|
||||
import ch.mathieubroillet.jarvis.android.audio.getAudioRecorder
|
||||
import ch.mathieubroillet.jarvis.android.chat.ConversationUiState
|
||||
import ch.mathieubroillet.jarvis.android.chat.Message
|
||||
import ch.mathieubroillet.jarvis.android.pages.DisplayMainPage
|
||||
@ -52,7 +54,8 @@ fun MainScreen(navController: NavController) {
|
||||
stringResource(id = R.string.demo_message_1)
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
getAudioRecorder(LocalContext.current)
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -5,26 +5,25 @@ import androidx.compose.material.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.DpOffset
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import ch.mathieubroillet.jarvis.android.R
|
||||
import ch.mathieubroillet.jarvis.android.audio.*
|
||||
import ch.mathieubroillet.jarvis.android.audio.AudioRecorder
|
||||
import ch.mathieubroillet.jarvis.android.chat.ConversationUiState
|
||||
import ch.mathieubroillet.jarvis.android.chat.Message
|
||||
import ch.mathieubroillet.jarvis.android.chat.Messages
|
||||
import ch.mathieubroillet.jarvis.android.nav.Screen
|
||||
import ch.mathieubroillet.jarvis.android.ui.theme.JarvisComposeTheme
|
||||
import ch.mathieubroillet.jarvis.android.ui.theme.productSansFont
|
||||
import ch.mathieubroillet.jarvis.android.utils.DefaultBox
|
||||
import ch.mathieubroillet.jarvis.android.utils.IconAlertDialogTextField
|
||||
import com.github.squti.androidwaverecorder.WaveRecorder
|
||||
import ch.mathieubroillet.jarvis.android.utils.contactServerWithFileAudioRecording
|
||||
import com.github.squti.androidwaverecorder.RecorderState
|
||||
import org.json.JSONObject
|
||||
import kotlin.concurrent.thread
|
||||
|
||||
|
||||
//Draws the base of the main activity, that includes the 3-dots menu and the "hi text".
|
||||
@ -91,7 +90,7 @@ fun DropDownSettingsMenu(navController: NavController) {
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun StartRecordingFAB() {
|
||||
fun StartRecordingFAB(onClick: () -> Unit, isRecording: Boolean) {
|
||||
//We create a row that we align to the bottom center of the parent box
|
||||
Row(
|
||||
Modifier
|
||||
@ -99,13 +98,9 @@ fun StartRecordingFAB() {
|
||||
verticalAlignment = Alignment.Bottom,
|
||||
horizontalArrangement = Arrangement.Center
|
||||
) {
|
||||
var isRecording by remember { mutableStateOf(isRecording()) }
|
||||
|
||||
|
||||
//Microphone floating button to manually start/stop listening
|
||||
FloatingActionButton(onClick = {
|
||||
if (isRecording) stopRecording() else startRecording()
|
||||
}, modifier = Modifier.size(70.dp)) {
|
||||
FloatingActionButton(onClick = onClick, modifier = Modifier.size(70.dp)) {
|
||||
Icon(
|
||||
painter = painterResource(id = if (isRecording) R.drawable.ic_baseline_shield_24 else R.drawable.ic_baseline_mic_24),
|
||||
contentDescription = "microphone"
|
||||
@ -116,9 +111,12 @@ fun StartRecordingFAB() {
|
||||
|
||||
|
||||
@Composable
|
||||
fun DisplayMainPage(navController: NavController, uiState: ConversationUiState) {
|
||||
fun DisplayMainPage(
|
||||
navController: NavController,
|
||||
uiState: ConversationUiState,
|
||||
audioRecorder: AudioRecorder
|
||||
) {
|
||||
|
||||
registerRecorder(LocalContext.current)
|
||||
|
||||
//We create a main box with basic padding to avoid having stuff too close to every side.
|
||||
DefaultBox {
|
||||
@ -140,20 +138,48 @@ fun DisplayMainPage(navController: NavController, uiState: ConversationUiState)
|
||||
.align(Alignment.BottomCenter)
|
||||
.padding(bottom = 40.dp)
|
||||
) {
|
||||
StartRecordingFAB()
|
||||
var listening: Boolean by remember { mutableStateOf(false) }
|
||||
|
||||
audioRecorder.waveRecorder.onStateChangeListener = {
|
||||
when (it) {
|
||||
RecorderState.RECORDING -> listening = true
|
||||
RecorderState.STOP -> {
|
||||
listening = false
|
||||
|
||||
thread {
|
||||
val requestOutput =
|
||||
contactServerWithFileAudioRecording(audioRecorder.getOutputFile())
|
||||
|
||||
val json: JSONObject = JSONObject(requestOutput)
|
||||
val sent = JSONObject(requestOutput).getString("sent").replace("\"", "")
|
||||
.replace("[", "").replace("]", "").replace(",", " ")
|
||||
sent.replaceFirstChar { sent.first().uppercase() }
|
||||
uiState.addMessage(Message(false, sent))
|
||||
Thread.sleep(1000)
|
||||
uiState.addMessage(Message(true, json.getString("response")))
|
||||
audioRecorder.getOutputFile().delete()
|
||||
}
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
StartRecordingFAB(
|
||||
onClick = { if (listening) audioRecorder.stopRecording() else audioRecorder.startRecording() },
|
||||
isRecording = listening
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Preview(showBackground = true)
|
||||
/*@Preview(showBackground = true)
|
||||
@Composable
|
||||
fun MainPagePreview() {
|
||||
JarvisComposeTheme {
|
||||
DisplayMainPage(
|
||||
rememberNavController(), ConversationUiState(
|
||||
listOf(Message(true, stringResource(id = R.string.demo_message_1)))
|
||||
)
|
||||
), null
|
||||
)
|
||||
}
|
||||
}
|
||||
}*/
|
@ -7,7 +7,7 @@ import okhttp3.RequestBody.Companion.asRequestBody
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
|
||||
fun contactServerWithFileAudioRecording(file: File) {
|
||||
fun contactServerWithFileAudioRecording(file: File): String {
|
||||
val client = OkHttpClient()
|
||||
|
||||
val request = Request.Builder()
|
||||
@ -17,7 +17,6 @@ fun contactServerWithFileAudioRecording(file: File) {
|
||||
|
||||
client.newCall(request).execute().use { response ->
|
||||
if (!response.isSuccessful) throw IOException("Unexpected code $response")
|
||||
|
||||
println(response.body!!.string())
|
||||
return response.body!!.string()
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user