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 c237ed7c3..51d76226a 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 @@ -5,6 +5,8 @@ import com.google.android.gms.wearable.MessageEvent import com.google.android.gms.wearable.Wearable import com.google.android.gms.wearable.WearableListenerService import com.habitrpg.android.habitica.HabiticaBaseApplication +import com.habitrpg.android.habitica.ui.activities.LoginActivity +import com.habitrpg.android.habitica.ui.activities.MainActivity import com.habitrpg.android.habitica.ui.activities.TaskFormActivity import com.habitrpg.common.habitica.api.HostConfig import javax.inject.Inject @@ -23,10 +25,17 @@ class DeviceCommunicationService : WearableListenerService() { super.onMessageReceived(event) when (event.path) { "/request/auth" -> processAuthRequest(event) + "/show/register" -> openActivity(LoginActivity::class.java) + "/show/rya" -> openActivity(MainActivity::class.java) "/tasks/edit" -> openTaskForm(event) } } + private fun openActivity(activityClass: Class<*>) { + val intent = Intent(this, activityClass) + startActivity(intent) + } + private fun openTaskForm(event: MessageEvent) { val taskID = String(event.data) val startIntent = Intent(this, TaskFormActivity::class.java).apply { 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 79a1a37cc..6570ecbb8 100644 --- a/wearos/src/main/java/com/habitrpg/wearos/habitica/MainApplication.kt +++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/MainApplication.kt @@ -8,6 +8,7 @@ import com.habitrpg.common.habitica.views.HabiticaIconsHelper import com.habitrpg.wearos.habitica.data.repositories.UserRepository import com.habitrpg.wearos.habitica.ui.activities.BaseActivity import com.habitrpg.wearos.habitica.ui.activities.FaintActivity +import com.habitrpg.wearos.habitica.ui.activities.RYAActivity import dagger.hilt.android.HiltAndroidApp import kotlinx.coroutines.MainScope import kotlinx.coroutines.flow.collect @@ -32,6 +33,10 @@ class MainApplication : Application() { val intent = Intent(this@MainApplication, FaintActivity::class.java) intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) startActivity(intent) + } else if (it.needsCron && BaseActivity.currentActivityClassName != RYAActivity::class.java.name) { + val intent = Intent(this@MainApplication, RYAActivity::class.java) + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + startActivity(intent) } }.collect() } diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/data/ApiService.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/data/ApiService.kt index 52b2deff5..f4f546c32 100644 --- a/wearos/src/main/java/com/habitrpg/wearos/habitica/data/ApiService.kt +++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/data/ApiService.kt @@ -4,11 +4,12 @@ import com.habitrpg.common.habitica.models.auth.UserAuth import com.habitrpg.common.habitica.models.auth.UserAuthResponse import com.habitrpg.common.habitica.models.auth.UserAuthSocial import com.habitrpg.common.habitica.models.responses.TaskDirectionData -import com.habitrpg.wearos.habitica.models.user.User +import com.habitrpg.wearos.habitica.models.EmptyResponse import com.habitrpg.wearos.habitica.models.WearableHabitResponse import com.habitrpg.wearos.habitica.models.tasks.BulkTaskScoringData import com.habitrpg.wearos.habitica.models.tasks.Task import com.habitrpg.wearos.habitica.models.tasks.TaskList +import com.habitrpg.wearos.habitica.models.user.User import retrofit2.http.Body import retrofit2.http.DELETE import retrofit2.http.GET @@ -92,5 +93,5 @@ interface ApiService { suspend fun removePushDevice(@Path("regId") regId: String): WearableHabitResponse> @POST("cron") - suspend fun runCron(): WearableHabitResponse + suspend fun runCron(): WearableHabitResponse } \ No newline at end of file diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/data/repositories/UserRepository.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/data/repositories/UserRepository.kt index 3579c703c..e3e3a80db 100644 --- a/wearos/src/main/java/com/habitrpg/wearos/habitica/data/repositories/UserRepository.kt +++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/data/repositories/UserRepository.kt @@ -21,4 +21,5 @@ class UserRepository @Inject constructor(val apiClient: ApiClient, val localRepo suspend fun sleep() = apiClient.sleep() suspend fun revive() = apiClient.revive() + suspend fun runCron() = apiClient.runCron() } \ No newline at end of file diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/models/EmptyResponse.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/models/EmptyResponse.kt new file mode 100644 index 000000000..89550dcd7 --- /dev/null +++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/models/EmptyResponse.kt @@ -0,0 +1,6 @@ +package com.habitrpg.wearos.habitica.models + +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +class EmptyResponse diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/models/user/User.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/models/user/User.kt index 6941ab48e..551328668 100644 --- a/wearos/src/main/java/com/habitrpg/wearos/habitica/models/user/User.kt +++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/models/user/User.kt @@ -24,6 +24,8 @@ class User: Avatar { get() = items?.gear?.equipped override val hasClass: Boolean = false + var needsCron: Boolean = false + var profile: Profile? = null override fun isValid(): Boolean { diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/RYAActivity.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/RYAActivity.kt index 79eeb3a91..582f8db14 100644 --- a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/RYAActivity.kt +++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/RYAActivity.kt @@ -2,16 +2,72 @@ package com.habitrpg.wearos.habitica.ui.activities import android.os.Bundle import androidx.activity.viewModels +import androidx.core.view.children +import androidx.core.view.isVisible +import com.google.android.gms.wearable.CapabilityClient +import com.google.android.gms.wearable.MessageClient +import com.google.android.gms.wearable.Wearable +import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.databinding.ActivityRyaBinding +import com.habitrpg.android.habitica.databinding.RowDailyBinding +import com.habitrpg.common.habitica.extensions.dpToPx +import com.habitrpg.wearos.habitica.models.tasks.Task +import com.habitrpg.wearos.habitica.ui.viewHolders.tasks.DailyViewHolder import com.habitrpg.wearos.habitica.ui.viewmodels.RYAViewModel import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint -class RYAActivity: BaseActivity() { +class RYAActivity : BaseActivity() { + val messageClient: MessageClient by lazy { Wearable.getMessageClient(this) } + val capabilityClient: CapabilityClient by lazy { Wearable.getCapabilityClient(this) } override val viewModel: RYAViewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { binding = ActivityRyaBinding.inflate(layoutInflater) super.onCreate(savedInstanceState) + + viewModel.tasks.observe(this) { + createTaskListViews(it) + } + + binding.ryaButton.setOnClickListener { + binding.titleView.text = getString(R.string.check_off_yesterday) + binding.descriptionView.isVisible = false + binding.ryaButton.isVisible = false + binding.phoneButton.isVisible = false + binding.taskView.isVisible = true + binding.startDayButton.isVisible = true + } + + binding.phoneButton.setOnClickListener { + + } + + binding.startDayButton.setOnClickListener { + startAnimatingProgress() + binding.startDayButton.isEnabled = false + viewModel.runCron { + stopAnimatingProgress() + if (it) { + finish() + } else { + binding.startDayButton.isEnabled = true + } + } + } + } + + private fun createTaskListViews(list: List) { + binding.taskView.removeAllViews() + for (task in list) { + val taskBinding = RowDailyBinding.inflate(layoutInflater, binding.taskView, true) + val holder = DailyViewHolder(taskBinding.root) + taskBinding.root.setOnClickListener { + viewModel.tappedTask(task) + } + val verticalPadding = 2.dpToPx(this) + taskBinding.root.children.first().setPadding(0, verticalPadding, 0, verticalPadding) + holder.bind(task) + } } } \ No newline at end of file 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 383bd811b..38080c4a3 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 @@ -18,8 +18,8 @@ import kotlinx.coroutines.launch @AndroidEntryPoint class SplashActivity: BaseActivity() { override val viewModel: SplashViewModel by viewModels() - val messageClient: MessageClient by lazy { Wearable.getMessageClient(this) } - val capabilityClient: CapabilityClient by lazy { Wearable.getCapabilityClient(this) } + private val messageClient: MessageClient by lazy { Wearable.getMessageClient(this) } + private val capabilityClient: CapabilityClient by lazy { Wearable.getCapabilityClient(this) } override fun onCreate(savedInstanceState: Bundle?) { binding = ActivitySplashBinding.inflate(layoutInflater) diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewmodels/RYAViewModel.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewmodels/RYAViewModel.kt index b09aa2db8..c66128225 100644 --- a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewmodels/RYAViewModel.kt +++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewmodels/RYAViewModel.kt @@ -1,13 +1,49 @@ package com.habitrpg.wearos.habitica.ui.viewmodels +import androidx.lifecycle.asLiveData +import androidx.lifecycle.viewModelScope +import com.habitrpg.common.habitica.models.responses.TaskDirection +import com.habitrpg.common.habitica.models.tasks.TaskType +import com.habitrpg.wearos.habitica.data.repositories.TaskRepository import com.habitrpg.wearos.habitica.data.repositories.UserRepository +import com.habitrpg.wearos.habitica.models.tasks.Task import com.habitrpg.wearos.habitica.util.ExceptionHandlerBuilder import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.launch import javax.inject.Inject @HiltViewModel -class RYAViewModel @Inject constructor(userRepository: UserRepository, +class RYAViewModel @Inject constructor( + userRepository: UserRepository, + val taskRepository: TaskRepository, exceptionBuilder: ExceptionHandlerBuilder ) : BaseViewModel(userRepository, exceptionBuilder) { + val tasks = taskRepository.getTasks(TaskType.DAILY).asLiveData() + private val tasksToComplete = mutableListOf() + + fun tappedTask(task: Task) { + task.completed = !task.completed + taskRepository.localRepository.updateTask(task) + if (task.completed) { + if (!tasksToComplete.contains(task)) { + tasksToComplete.add(task) + } + } else { + if (tasksToComplete.contains(task)) { + tasksToComplete.remove(task) + } + } + } + + fun runCron(function: (Boolean) -> Unit) { + viewModelScope.launch(exceptionBuilder.userFacing(this)) { + for (task in tasksToComplete) { + taskRepository.scoreTask(null, task, TaskDirection.UP) + } + userRepository.runCron() + userRepository.retrieveUser() + function(true) + } + } } diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewmodels/TaskFormViewModel.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewmodels/TaskFormViewModel.kt index 1831c218f..2879e311d 100644 --- a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewmodels/TaskFormViewModel.kt +++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewmodels/TaskFormViewModel.kt @@ -1,6 +1,5 @@ package com.habitrpg.wearos.habitica.ui.viewmodels -import androidx.lifecycle.SavedStateHandle import com.habitrpg.common.habitica.models.tasks.Frequency import com.habitrpg.common.habitica.models.tasks.TaskType import com.habitrpg.wearos.habitica.data.repositories.TaskRepository @@ -12,7 +11,6 @@ import javax.inject.Inject @HiltViewModel class TaskFormViewModel @Inject constructor( - savedStateHandle: SavedStateHandle, userRepository: UserRepository, val taskRepository: TaskRepository, exceptionBuilder: ExceptionHandlerBuilder diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/views/HabiticaScrollView.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/views/HabiticaScrollView.kt index 73cb259be..eff5944c3 100644 --- a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/views/HabiticaScrollView.kt +++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/views/HabiticaScrollView.kt @@ -4,7 +4,6 @@ import android.content.Context import android.content.res.Resources import android.util.AttributeSet import androidx.core.view.children -import androidx.core.view.setPadding import androidx.core.widget.NestedScrollView class HabiticaScrollView @JvmOverloads constructor( @@ -15,8 +14,17 @@ class HabiticaScrollView @JvmOverloads constructor( super.onLayout(changed, l, t, r, b) if (changed) { if (context.resources.configuration.isScreenRound) { + val verticalPadding = + (0.146467f * Resources.getSystem().displayMetrics.widthPixels).toInt() + val horizontalPadding = + (0.1f * Resources.getSystem().displayMetrics.widthPixels).toInt() children.firstOrNull() - ?.setPadding((0.146467f * Resources.getSystem().displayMetrics.widthPixels).toInt()) + ?.setPadding( + horizontalPadding, + verticalPadding, + horizontalPadding, + verticalPadding + ) } } } diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/views/IndeterminateProgressView.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/views/IndeterminateProgressView.kt index afe82d8a5..9127735a7 100644 --- a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/views/IndeterminateProgressView.kt +++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/views/IndeterminateProgressView.kt @@ -18,16 +18,17 @@ class IndeterminateProgressView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : View(context, attrs, defStyleAttr) { - var progressBarWidth = 4f.dpToPx(context) + var progressBarWidth = 5f.dpToPx(context) private val rainbow = listOf( + ContextCompat.getColor(context, R.color.black), ContextCompat.getColor(context, R.color.watch_red_100), ContextCompat.getColor(context, R.color.watch_orange_100), ContextCompat.getColor(context, R.color.watch_yellow_100), ContextCompat.getColor(context, R.color.watch_green_100), ContextCompat.getColor(context, R.color.watch_blue_100), ContextCompat.getColor(context, R.color.watch_purple_100), - ContextCompat.getColor(context, R.color.watch_red_100), + ContextCompat.getColor(context, R.color.black), ).toIntArray() val gradient = SweepGradient(225f, 225f, rainbow, null) private val paint = Paint() diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/util/DateJSONAdapter.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/util/DateJSONAdapter.kt index 765530922..572f9590d 100644 --- a/wearos/src/main/java/com/habitrpg/wearos/habitica/util/DateJSONAdapter.kt +++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/util/DateJSONAdapter.kt @@ -29,7 +29,7 @@ var customDateAdapter: Any = object : Any() { var index = 0 while (index < dateFormats.size && date == null) { try { - date = dateFormats[index].parse(s) + date = s?.let { dateFormats[index].parse(it) } } catch (_: ParseException) {} index += 1 } diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/util/ScrollAwayBehavior.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/util/ScrollAwayBehavior.kt index 8e9033c65..478d49bdd 100644 --- a/wearos/src/main/java/com/habitrpg/wearos/habitica/util/ScrollAwayBehavior.kt +++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/util/ScrollAwayBehavior.kt @@ -5,10 +5,8 @@ import android.util.AttributeSet import android.view.View import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.core.view.ViewCompat -import java.lang.Float -import kotlin.Boolean -import kotlin.Int -import kotlin.IntArray +import kotlin.math.max +import kotlin.math.min class ScrollAwayBehavior(context: Context, attrs: AttributeSet) : CoordinatorLayout.Behavior(context, attrs) { @@ -24,7 +22,7 @@ class ScrollAwayBehavior(context: Context, attrs: AttributeSet) : ) { super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed, type) child.translationY = - Float.max(0f, Float.min(child.height.toFloat(), child.translationY + dy)) + max(0f, min(child.height.toFloat(), child.translationY + dy)) } override fun onStopNestedScroll( diff --git a/wearos/src/main/res/layout/activity_rya.xml b/wearos/src/main/res/layout/activity_rya.xml index d829e291c..07db7919e 100644 --- a/wearos/src/main/res/layout/activity_rya.xml +++ b/wearos/src/main/res/layout/activity_rya.xml @@ -1,7 +1,67 @@ - + + + +