diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml
index 8e408ab..b0a61c8 100644
--- a/.idea/deploymentTargetSelector.xml
+++ b/.idea/deploymentTargetSelector.xml
@@ -13,6 +13,9 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index d676a9f..8766be7 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -55,6 +55,7 @@
> = emptyList(), navController: NavController) {
@@ -352,4 +353,4 @@ private fun HomeScreenPreview() {
}
val navController = rememberNavController()
HomeScreen(sections = sections, navController = navController)
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/com/example/deepsea/ui/screens/feature/VoiceAssistantScreen.kt b/app/src/main/java/com/example/deepsea/ui/screens/feature/VoiceAssistantScreen.kt
index bff6eb6..d893846 100644
--- a/app/src/main/java/com/example/deepsea/ui/screens/feature/VoiceAssistantScreen.kt
+++ b/app/src/main/java/com/example/deepsea/ui/screens/feature/VoiceAssistantScreen.kt
@@ -1,6 +1,8 @@
package com.example.deepsea.AI_assistant
import android.Manifest
+import android.content.Context
+import android.content.Intent
import android.content.pm.PackageManager
import android.os.Bundle
import android.speech.RecognitionListener
@@ -9,16 +11,28 @@ import android.speech.SpeechRecognizer
import android.speech.tts.TextToSpeech
import android.util.Log
import androidx.activity.ComponentActivity
+import androidx.activity.compose.setContent
+import androidx.compose.animation.core.animateFloat
+import androidx.compose.animation.core.infiniteRepeatable
+import androidx.compose.animation.core.keyframes
+import androidx.compose.animation.core.rememberInfiniteTransition
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
+import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.material3.*
+import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.CircularProgressIndicator
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.material3.TextField
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.core.app.ActivityCompat
@@ -31,6 +45,58 @@ import org.json.JSONObject
private const val TAG = "VoiceAssistant"
+class VoiceAssistantActivity : ComponentActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ // Yêu cầu quyền thu âm nếu chưa có
+ if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO)
+ != PackageManager.PERMISSION_GRANTED
+ ) {
+ ActivityCompat.requestPermissions(
+ this,
+ arrayOf(Manifest.permission.RECORD_AUDIO),
+ PackageManager.PERMISSION_GRANTED
+ )
+ }
+
+ setContent {
+ VoiceAssistantScreen()
+ }
+ }
+}
+
+@Composable
+fun DotIndicator(isActive: Boolean) {
+ val infiniteTransition = rememberInfiniteTransition()
+ val offsetX by infiniteTransition.animateFloat(
+ initialValue = -2f,
+ targetValue = 2f,
+ animationSpec = infiniteRepeatable(
+ animation = keyframes {
+ durationMillis = 300
+ -2f at 0
+ 2f at 150
+ -2f at 300
+ }
+ )
+ )
+
+ Box(
+ modifier = Modifier
+ .size(12.dp)
+ .offset(x = if (isActive) offsetX.dp else 0.dp)
+ .clip(CircleShape)
+ .background(
+ if (isActive)
+ MaterialTheme.colorScheme.primary
+ else
+ MaterialTheme.colorScheme.onSurface.copy(alpha = 0.3f)
+ )
+ )
+}
+
+@Preview(showBackground = true)
@Composable
fun VoiceAssistantScreen() {
val context = LocalContext.current
@@ -43,9 +109,8 @@ fun VoiceAssistantScreen() {
val apiKey = "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"
val endpoint = "https://api.openai.com/v1/chat/completions"
- // Initialize TextToSpeech
+ // Khởi tạo TextToSpeech
val isTtsReady = remember { mutableStateOf(false) }
-
val textToSpeech = remember {
TextToSpeech(context) { status ->
if (status != TextToSpeech.ERROR) {
@@ -54,13 +119,12 @@ fun VoiceAssistantScreen() {
}
}
- // Initialize SpeechRecognizer
+ // Khởi tạo SpeechRecognizer
val recognizerIntent = remember {
- android.content.Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH).apply {
+ Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH).apply {
putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM)
putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1)
putExtra(RecognizerIntent.EXTRA_PARTIAL_RESULTS, true)
- putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 3000)
putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS, 1500)
}
}
@@ -68,61 +132,44 @@ fun VoiceAssistantScreen() {
val speechRecognizer = remember {
SpeechRecognizer.createSpeechRecognizer(context).apply {
setRecognitionListener(object : RecognitionListener {
- override fun onResults(bundle: Bundle) {
- val matches = bundle.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION)
- matches?.let {
- if (it.isNotEmpty()) {
- val query = it[0]
- inputText = query
- callChatGPT(
- context = context,
- input = query,
- apiKey = apiKey,
- endpoint = endpoint,
- onStart = { isProcessing = true },
- onResponse = { response ->
- outputText = response
- isProcessing = false
- if (!textToSpeech.isSpeaking) {
- textToSpeech.speak(response, TextToSpeech.QUEUE_FLUSH, null, null)
- }
- },
- onError = { error ->
- outputText = "Error: $error"
- isProcessing = false
+ override fun onReadyForSpeech(params: Bundle?) {}
+ override fun onBeginningOfSpeech() {}
+ override fun onRmsChanged(rmsdB: Float) {}
+ override fun onBufferReceived(buffer: ByteArray?) {}
+ override fun onEndOfSpeech() { isListening = false }
+ override fun onError(error: Int) { isListening = false }
+ override fun onResults(bundle: Bundle?) {
+ val matches = bundle
+ ?.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION)
+ matches?.firstOrNull()?.let { query ->
+ inputText = query
+ callChatGPT(
+ context = context,
+ input = query,
+ apiKey = apiKey,
+ endpoint = endpoint,
+ onStart = { isProcessing = true },
+ onResponse = { response ->
+ outputText = response
+ isProcessing = false
+ if (!textToSpeech.isSpeaking) {
+ textToSpeech.speak(response, TextToSpeech.QUEUE_FLUSH, null, "tts1")
}
- )
- }
+ },
+ onError = { error ->
+ outputText = "Error: $error"
+ isProcessing = false
+ }
+ )
}
}
-
- // Required implementations for RecognitionListener
- override fun onReadyForSpeech(bundle: Bundle) {}
- override fun onBeginningOfSpeech() {}
- override fun onRmsChanged(v: Float) {}
- override fun onBufferReceived(bytes: ByteArray) {}
- override fun onEndOfSpeech() { isListening = false }
- override fun onError(i: Int) { isListening = false }
- override fun onPartialResults(bundle: Bundle) {}
- override fun onEvent(i: Int, bundle: Bundle) {}
+ override fun onPartialResults(partialResults: Bundle?) {}
+ override fun onEvent(eventType: Int, params: Bundle?) {}
})
}
}
- // Request permissions
- LaunchedEffect(Unit) {
- if (ContextCompat.checkSelfPermission(context, Manifest.permission.RECORD_AUDIO)
- != PackageManager.PERMISSION_GRANTED
- ) {
- ActivityCompat.requestPermissions(
- context as ComponentActivity,
- arrayOf(Manifest.permission.RECORD_AUDIO),
- PackageManager.PERMISSION_GRANTED
- )
- }
- }
-
- // Clean up resources when the screen is closed
+ // Dọn dẹp khi đóng
DisposableEffect(Unit) {
onDispose {
textToSpeech.stop()
@@ -137,25 +184,32 @@ fun VoiceAssistantScreen() {
.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
- Text(
- text = "AI Voice Assistant",
- fontSize = 24.sp,
- modifier = Modifier.fillMaxWidth(),
- textAlign = TextAlign.Center
- )
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.Center,
+ modifier = Modifier.fillMaxWidth()
+ ) {
+ Text(
+ text = "AI Voice Assistant",
+ fontSize = 24.sp,
+ textAlign = TextAlign.Center
+ )
+ Spacer(modifier = Modifier.width(8.dp))
+ DotIndicator(isActive = isProcessing || textToSpeech.isSpeaking)
+ }
- // Input display
+ // Hiển thị input
TextField(
value = inputText,
- onValueChange = { inputText = it },
+ onValueChange = {},
+ readOnly = true,
modifier = Modifier
.fillMaxWidth()
.height(80.dp),
- label = { Text("Your question") },
- readOnly = true
+ label = { Text("Your question") }
)
- // Output display
+ // Hiển thị output
Box(
modifier = Modifier
.fillMaxWidth()
@@ -165,38 +219,35 @@ fun VoiceAssistantScreen() {
.padding(16.dp)
) {
if (isProcessing) {
- CircularProgressIndicator(
- modifier = Modifier.align(Alignment.Center)
- )
+ CircularProgressIndicator(modifier = Modifier.align(Alignment.Center))
} else {
- Text(
- text = outputText,
- fontSize = 16.sp,
- modifier = Modifier
- .fillMaxSize()
- )
+ Text(text = outputText, fontSize = 16.sp)
}
}
- // Control button
+ // Nút điều khiển
Button(
onClick = {
- if (textToSpeech.isSpeaking) {
- textToSpeech.stop()
- } else if (!isListening) {
- isListening = true
- speechRecognizer.startListening(recognizerIntent)
- } else {
- speechRecognizer.stopListening()
- isListening = false
+ when {
+ textToSpeech.isSpeaking -> textToSpeech.stop()
+ isListening -> {
+ speechRecognizer.stopListening()
+ isListening = false
+ }
+ else -> {
+ isListening = true
+ speechRecognizer.startListening(recognizerIntent)
+ }
}
},
modifier = Modifier
.fillMaxWidth()
.height(56.dp),
colors = ButtonDefaults.buttonColors(
- containerColor = if (isListening) MaterialTheme.colorScheme.error
- else MaterialTheme.colorScheme.primary
+ containerColor = if (isListening)
+ MaterialTheme.colorScheme.error
+ else
+ MaterialTheme.colorScheme.primary
)
) {
Text(
@@ -211,7 +262,7 @@ fun VoiceAssistantScreen() {
}
private fun callChatGPT(
- context: android.content.Context,
+ context: Context,
input: String,
apiKey: String,
endpoint: String,
@@ -260,13 +311,11 @@ private fun callChatGPT(
}
}
- // Set timeout
jsonRequest.retryPolicy = DefaultRetryPolicy(
60000,
DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT
)
- // Add to queue
Volley.newRequestQueue(context).add(jsonRequest)
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/com/example/deepsea/ui/screens/feature/game/GamePlayScreen.kt b/app/src/main/java/com/example/deepsea/ui/screens/feature/game/GamePlayScreen.kt
index 9da3f1e..26e5b06 100644
--- a/app/src/main/java/com/example/deepsea/ui/screens/feature/game/GamePlayScreen.kt
+++ b/app/src/main/java/com/example/deepsea/ui/screens/feature/game/GamePlayScreen.kt
@@ -32,6 +32,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.example.deepsea.ui.components.PlayerScoreCard
diff --git a/app/src/main/java/com/example/deepsea/ui/viewmodel/auth/AuthViewModel.kt b/app/src/main/java/com/example/deepsea/ui/viewmodel/auth/AuthViewModel.kt
index 7e39fe5..677e575 100644
--- a/app/src/main/java/com/example/deepsea/ui/viewmodel/auth/AuthViewModel.kt
+++ b/app/src/main/java/com/example/deepsea/ui/viewmodel/auth/AuthViewModel.kt
@@ -127,6 +127,9 @@ class AuthViewModel(application: Application) : AndroidViewModel(application) {
}
}
+ fun resetRegisterState() {
+ _registerState.value = RegisterState.Idle
+ }
fun signup(name:String , username: String, email: String, password: String, avatar: Uri? = null) {
viewModelScope.launch {
@@ -149,7 +152,7 @@ class AuthViewModel(application: Application) : AndroidViewModel(application) {
val response = RetrofitClient.authApi.register(registerRequest)
if (response.isSuccessful && response.body() != null) {
- _registerState.value = RegisterState.Success(response.body()!!.message + "fwiejfwejfwfhudhaiojasidsaidcvn")
+ _registerState.value = RegisterState.Success(response.body()!!.message + "Vjp Bro")
} else {
_registerState.value = RegisterState.Error("Registration failed: ${response.message()}")
}