diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/receivers/DeviceCommunicationService.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/receivers/DeviceCommunicationService.kt
index a3e2eb3fe..5ced9de91 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/receivers/DeviceCommunicationService.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/receivers/DeviceCommunicationService.kt
@@ -26,17 +26,18 @@ class DeviceCommunicationService : WearableListenerService() {
super.onMessageReceived(event)
when (event.path) {
DeviceCommunication.REQUEST_AUTH -> processAuthRequest(event)
- DeviceCommunication.SHOW_REGISTER -> openActivity(LoginActivity::class.java)
- DeviceCommunication.SHOW_LOGIN -> openActivity(LoginActivity::class.java)
- DeviceCommunication.SHOW_RYA -> openActivity(MainActivity::class.java)
+ DeviceCommunication.SHOW_REGISTER -> openActivity(event, LoginActivity::class.java)
+ DeviceCommunication.SHOW_LOGIN -> openActivity(event, LoginActivity::class.java)
+ DeviceCommunication.SHOW_RYA -> openActivity(event, MainActivity::class.java)
DeviceCommunication.SHOW_TASK_EDIT -> openTaskForm(event)
}
}
- private fun openActivity(activityClass: Class<*>) {
+ private fun openActivity(event: MessageEvent, activityClass: Class<*>) {
val intent = Intent(this, activityClass)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(intent)
+ messageClient.sendMessage(event.sourceNodeId, "/action_completed", null)
}
private fun openTaskForm(event: MessageEvent) {
@@ -44,7 +45,8 @@ class DeviceCommunicationService : WearableListenerService() {
val startIntent = Intent(this, TaskFormActivity::class.java).apply {
putExtra(TaskFormActivity.TASK_ID_KEY, taskID)
}
- startActivity(startIntent)
+ startActivity(startIntent)
+ messageClient.sendMessage(event.sourceNodeId, "/action_completed", null)
}
private fun processAuthRequest(event: MessageEvent) {
diff --git a/version.properties b/version.properties
index 3ba3383af..d89172c60 100644
--- a/version.properties
+++ b/version.properties
@@ -1,2 +1,2 @@
NAME=4.0
-CODE=4190
\ No newline at end of file
+CODE=4200
\ No newline at end of file
diff --git a/wearos/src/main/AndroidManifest.xml b/wearos/src/main/AndroidManifest.xml
index 225c637e6..72cf9cb4a 100644
--- a/wearos/src/main/AndroidManifest.xml
+++ b/wearos/src/main/AndroidManifest.xml
@@ -52,6 +52,7 @@
+
\ No newline at end of file
diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/MainApplication.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/MainApplication.kt
index 9472780e5..dfd35ac60 100644
--- a/wearos/src/main/java/com/habitrpg/wearos/habitica/MainApplication.kt
+++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/MainApplication.kt
@@ -58,7 +58,9 @@ class MainApplication : Application() {
}
private fun logLaunch() {
- Firebase.analytics.logEvent("wear_launched", null)
+ if (!BuildConfig.DEBUG) {
+ Firebase.analytics.logEvent("wear_launched", null)
+ }
}
private fun setupFirebase() {
diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/data/ApiClient.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/data/ApiClient.kt
index 6c3ae574d..626569909 100644
--- a/wearos/src/main/java/com/habitrpg/wearos/habitica/data/ApiClient.kt
+++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/data/ApiClient.kt
@@ -123,7 +123,7 @@ class ApiClient @Inject constructor(
val responseBuilder = response.newBuilder()
responseBuilder.header("was-cached", (response.networkResponse == null).toString())
if (request.method == "GET") {
- if (response.code == 504) {
+ if (response.code == 504 || response.request.header("x-api-user") != hostConfig.userID) {
// Cache miss. Network might be down, but retry call without cache to be sure.
chain.proceed(request.newBuilder()
.header("Cache-Control", "no-cache")
diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/BaseActivity.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/BaseActivity.kt
index a38df5e3b..62890276a 100644
--- a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/BaseActivity.kt
+++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/BaseActivity.kt
@@ -87,9 +87,12 @@ abstract class BaseActivity : ComponentActivi
}
}
- internal fun openRemoteActivity(url: String) {
+ internal fun openRemoteActivity(url: String, keepActive: Boolean = false) {
sendMessage("open_activity", url, null)
- startActivity(Intent(this, ContinuePhoneActivity::class.java))
+ startActivity(Intent(this, ContinuePhoneActivity::class.java)
+ .apply {
+ putExtra("keep_active", keepActive)
+ })
}
internal fun sendMessage(
diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/ContinuePhoneActivity.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/ContinuePhoneActivity.kt
index 1011af0b6..9334208d5 100644
--- a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/ContinuePhoneActivity.kt
+++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/ContinuePhoneActivity.kt
@@ -20,7 +20,7 @@ import kotlin.time.toDuration
class ContinuePhoneActivity : BaseActivity() {
override val viewModel: ContinuePhoneViewModel by viewModels()
- private var secondsToShow = 2
+ private var secondsToShow = 5
override fun onCreate(savedInstanceState: Bundle?) {
binding = ActivityContinuePhoneBinding.inflate(layoutInflater)
@@ -29,16 +29,23 @@ class ContinuePhoneActivity : BaseActivity() {
+ override val viewModel: InputViewModel by viewModels()
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ binding = ActivityInputBinding.inflate(layoutInflater)
+ super.onCreate(savedInstanceState)
+ binding.titleView.text = viewModel.title
+
+ binding.speechInput.setOnClickListener {
+ showSpeechInput()
+ }
+ binding.keyboardInput.setOnClickListener {
+ showKeyboard()
+ }
+
+ binding.editText.setOnEditorActionListener { _, actionId, _ ->
+ if (actionId == EditorInfo.IME_ACTION_SEARCH || actionId == EditorInfo.IME_ACTION_DONE) {
+ if (binding.editText.text?.isNotEmpty() == true) {
+ returnInput(binding.editText.text.toString())
+ }
+ }
+ false
+ }
+ }
+
+ private fun returnInput(inputString: String?) {
+ val data = Intent()
+ data.putExtra("input", inputString)
+ setResult(Activity.RESULT_OK, data)
+ finish()
+ }
+
+ private fun showKeyboard() {
+ binding.editText.hint = binding.titleView.text
+ binding.editText.requestFocus()
+ binding.editText.postDelayed(100) {
+ val imm: InputMethodManager =
+ getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
+ imm.showSoftInput(binding.editText, InputMethodManager.SHOW_FORCED)
+ }
+ }
+
+ private val speechInputResult = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
+ if (it.resultCode == Activity.RESULT_OK) {
+ val spokenText: String? = it.data?.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS)?.firstOrNull()
+ returnInput(spokenText)
+ }
+ }
+
+ private fun showSpeechInput() {
+ val intent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH).apply {
+ putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM)
+ putExtra(RecognizerIntent.EXTRA_PROMPT, binding.titleView.text)
+ }
+ speechInputResult.launch(intent)
+ }
+}
\ No newline at end of file
diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/LoginActivity.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/LoginActivity.kt
index 7ac08bc65..43fd23a86 100644
--- a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/LoginActivity.kt
+++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/LoginActivity.kt
@@ -87,7 +87,7 @@ class LoginActivity: BaseActivity() {
}
private fun openRegisterOnPhone() {
- openRemoteActivity(DeviceCommunication.SHOW_REGISTER)
+ openRemoteActivity(DeviceCommunication.SHOW_REGISTER, true)
}
private fun openLoginOnPhone() {
diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/SplashActivity.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/SplashActivity.kt
index dde4ac344..f9c85abb2 100644
--- a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/SplashActivity.kt
+++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/SplashActivity.kt
@@ -30,8 +30,13 @@ class SplashActivity: BaseActivity() {
startLoginActivity()
}
}
+ }
+ override fun onStart() {
+ super.onStart()
messageClient.addListener(viewModel)
+
+ if (!viewModel.hasAuthentication) {
sendMessage("provide_auth", "/request/auth", null) {
if (it) {
showAccountLoader(true)
@@ -40,6 +45,13 @@ class SplashActivity: BaseActivity() {
startLoginActivity()
}
}
+ }
+ }
+
+
+ override fun onStop() {
+ messageClient.removeListener(viewModel)
+ super.onStop()
}
private fun startMainActivity() {
@@ -64,9 +76,4 @@ class SplashActivity: BaseActivity() {
binding.textView.isVisible = show
}
}
-
- override fun onPause() {
- messageClient.removeListener(viewModel)
- super.onPause()
- }
}
\ No newline at end of file
diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/TaskFormActivity.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/TaskFormActivity.kt
index 6dfcd5ffe..072e683cc 100644
--- a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/TaskFormActivity.kt
+++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/TaskFormActivity.kt
@@ -1,17 +1,14 @@
package com.habitrpg.wearos.habitica.ui.activities
import android.app.Activity
-import android.content.Context
import android.content.Intent
import android.content.res.ColorStateList
import android.os.Bundle
-import android.view.inputmethod.EditorInfo
-import android.view.inputmethod.InputMethodManager
import android.widget.TextView
+import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
-import androidx.core.view.postDelayed
import androidx.lifecycle.lifecycleScope
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.databinding.ActivityTaskFormBinding
@@ -45,23 +42,16 @@ class TaskFormActivity : BaseActivity
- if (actionId == EditorInfo.IME_ACTION_SEARCH || actionId == EditorInfo.IME_ACTION_DONE) {
- if (binding.editText.text?.isNotEmpty() == true) {
- binding.editTaskWrapper.isVisible = false
- binding.taskConfirmationWrapper.isVisible = true
- binding.confirmationText.text = binding.editText.text
- binding.editText.clearFocus()
- }
- }
- false
+ binding.editText.setOnClickListener {
+ it.clearFocus()
+ requestInput()
}
+
binding.editButton.setOnClickListener {
binding.editTaskWrapper.isVisible = true
binding.taskConfirmationWrapper.isVisible = false
if (intent.extras?.containsKey("task_type") == true) {
- binding.editText.requestFocus()
- showKeyboard()
+ requestInput()
}
}
binding.todoButton.setOnClickListener { taskType = TaskType.TODO }
@@ -91,26 +81,28 @@ class TaskFormActivity : BaseActivity("keep_active") ?: false
+ var onActionCompleted: (() -> Unit)? = null
+ override fun onMessageReceived(event: MessageEvent) {
+ when (event.path) {
+ "/action_completed" -> onActionCompleted?.invoke()
+ }
+ }
}
diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewmodels/InputViewModel.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewmodels/InputViewModel.kt
new file mode 100644
index 000000000..4a5661809
--- /dev/null
+++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewmodels/InputViewModel.kt
@@ -0,0 +1,20 @@
+package com.habitrpg.wearos.habitica.ui.viewmodels
+
+import androidx.lifecycle.SavedStateHandle
+import com.habitrpg.wearos.habitica.data.repositories.TaskRepository
+import com.habitrpg.wearos.habitica.data.repositories.UserRepository
+import com.habitrpg.wearos.habitica.managers.LoadingManager
+import com.habitrpg.wearos.habitica.util.ExceptionHandlerBuilder
+import dagger.hilt.android.lifecycle.HiltViewModel
+import javax.inject.Inject
+
+@HiltViewModel
+class InputViewModel @Inject constructor(
+ savedStateHandle: SavedStateHandle,
+ userRepository: UserRepository,
+ taskRepository: TaskRepository,
+ exceptionBuilder: ExceptionHandlerBuilder,
+ loadingManager: LoadingManager
+) : BaseViewModel(userRepository, taskRepository, exceptionBuilder, loadingManager) {
+ val title = savedStateHandle.get("title") ?: ""
+}
diff --git a/wearos/src/main/res/drawable/ic_microphone.xml b/wearos/src/main/res/drawable/ic_microphone.xml
new file mode 100644
index 000000000..05ab75366
--- /dev/null
+++ b/wearos/src/main/res/drawable/ic_microphone.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/wearos/src/main/res/layout/activity_input.xml b/wearos/src/main/res/layout/activity_input.xml
new file mode 100644
index 000000000..b7b1c97d3
--- /dev/null
+++ b/wearos/src/main/res/layout/activity_input.xml
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/wearos/src/main/res/layout/activity_task_form.xml b/wearos/src/main/res/layout/activity_task_form.xml
index 8d7e7a697..1e6158e8b 100644
--- a/wearos/src/main/res/layout/activity_task_form.xml
+++ b/wearos/src/main/res/layout/activity_task_form.xml
@@ -65,6 +65,7 @@
android:paddingHorizontal="18dp"
android:hint="@string/task_title_hint"
android:background="@drawable/row_background_outline"
+ android:focusable="false"
android:inputType="textCapSentences" />