mirror of
https://github.com/sudoxnym/habitica-android.git
synced 2026-05-19 20:29:02 +00:00
First RYA implementation
This commit is contained in:
parent
f464e61b9a
commit
253210d0c2
17 changed files with 216 additions and 34 deletions
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<List<Void>>
|
||||
|
||||
@POST("cron")
|
||||
suspend fun runCron(): WearableHabitResponse<Void>
|
||||
suspend fun runCron(): WearableHabitResponse<EmptyResponse>
|
||||
}
|
||||
|
|
@ -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()
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
package com.habitrpg.wearos.habitica.models
|
||||
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
class EmptyResponse
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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<ActivityRyaBinding, RYAViewModel>() {
|
||||
class RYAActivity : BaseActivity<ActivityRyaBinding, RYAViewModel>() {
|
||||
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<Task>) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -18,8 +18,8 @@ import kotlinx.coroutines.launch
|
|||
@AndroidEntryPoint
|
||||
class SplashActivity: BaseActivity<ActivitySplashBinding, SplashViewModel>() {
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -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<Task>()
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<V : View>(context: Context, attrs: AttributeSet) :
|
||||
CoordinatorLayout.Behavior<V>(context, attrs) {
|
||||
|
|
@ -24,7 +22,7 @@ class ScrollAwayBehavior<V : View>(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(
|
||||
|
|
|
|||
|
|
@ -1,7 +1,67 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<com.habitrpg.wearos.habitica.ui.views.HabiticaScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical">
|
||||
<TextView
|
||||
android:id="@+id/title_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="14sp"
|
||||
android:textColor="@color/watch_purple_200"
|
||||
android:text="@string/day_start"
|
||||
android:fontFamily="sans-serif-medium"
|
||||
android:layout_marginBottom="10dp"/>
|
||||
<TextView
|
||||
android:id="@+id/description_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/rya_description"
|
||||
android:gravity="center"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="16sp"
|
||||
android:layout_marginBottom="@dimen/spacing_large"/>
|
||||
<Button
|
||||
android:id="@+id/rya_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/review_dailies"
|
||||
style="@style/ChipButton.Purple"
|
||||
android:layout_marginBottom="@dimen/spacing_small"/>
|
||||
<Button
|
||||
android:id="@+id/phone_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/check_on_phone"
|
||||
android:drawableStart="@drawable/handoff"
|
||||
style="@style/ChipButton"/>
|
||||
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:id="@+id/task_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone"/>
|
||||
<Button
|
||||
android:id="@+id/start_day_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/ChipButton.Purple"
|
||||
android:text="@string/start_new_day"
|
||||
android:layout_marginTop="2dp"
|
||||
android:visibility="gone"/>
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/checklist_disclaimer"
|
||||
android:textColor="@color/gray_400"
|
||||
android:gravity="center"
|
||||
android:layout_marginTop="@dimen/spacing_large"
|
||||
android:textSize="14sp" />
|
||||
</LinearLayout>
|
||||
</com.habitrpg.wearos.habitica.ui.views.HabiticaScrollView>
|
||||
|
|
@ -17,4 +17,11 @@
|
|||
<string name="continue_text">Continue</string>
|
||||
<string name="you_ran_out_of_hp">You ran out of HP</string>
|
||||
<string name="faint_description">You lost a Level, Exp, and Gold. Don’t give up!</string>
|
||||
<string name="day_start">Day start</string>
|
||||
<string name="rya_description">There are incomplete Dailies from yesterday</string>
|
||||
<string name="review_dailies">Review dailies</string>
|
||||
<string name="check_on_phone">Check on phone</string>
|
||||
<string name="checklist_disclaimer">Task checklists are available on the phone</string>
|
||||
<string name="start_new_day">Start new day</string>
|
||||
<string name="check_off_yesterday">Check off any you did yesterday:</string>
|
||||
</resources>
|
||||
|
|
@ -17,37 +17,31 @@
|
|||
<item name="android:paddingHorizontal">@dimen/row_padding_horizontal</item>
|
||||
<item name="android:paddingVertical">@dimen/row_padding_vertical</item>
|
||||
<item name="android:background">@drawable/row_background</item>
|
||||
<item name="android:textSize">14sp</item>
|
||||
<item name="android:textSize">16sp</item>
|
||||
<item name="fontFamily">sans-serif-medium</item>
|
||||
<item name="android:gravity">center</item>
|
||||
<item name="android:minHeight">52dp</item>
|
||||
<item name="android:textAllCaps">false</item>
|
||||
<item name="android:letterSpacing">0.05</item>
|
||||
<item name="android:letterSpacing">0.01</item>
|
||||
<item name="android:drawablePadding">8dp</item>
|
||||
</style>
|
||||
|
||||
<style name="ChipButton.Small">
|
||||
<item name="android:paddingHorizontal">@dimen/row_padding_horizontal</item>
|
||||
<item name="android:paddingVertical">@dimen/row_padding_vertical</item>
|
||||
<item name="android:background">@drawable/row_background</item>
|
||||
<style name="ChipButton.Small" parent="ChipButton">
|
||||
<item name="android:textSize">14sp</item>
|
||||
<item name="fontFamily">sans-serif-medium</item>
|
||||
<item name="android:gravity">center</item>
|
||||
<item name="android:minHeight">32dp</item>
|
||||
<item name="android:textAllCaps">false</item>
|
||||
<item name="android:letterSpacing">0.05</item>
|
||||
<item name="android:drawablePadding">8dp</item>
|
||||
</style>
|
||||
|
||||
<style name="ChipButton.Purple">
|
||||
<style name="ChipButton.Purple" parent="ChipButton">
|
||||
<item name="android:backgroundTint">@color/watch_purple_100</item>
|
||||
<item name="android:textColor">@color/black</item>
|
||||
</style>
|
||||
|
||||
<style name="ChipButton.Red">
|
||||
<style name="ChipButton.Red" parent="ChipButton">
|
||||
<item name="android:backgroundTint">@color/watch_red_200</item>
|
||||
<item name="android:textColor">@color/black</item>
|
||||
</style>
|
||||
|
||||
<style name="ChipButton.Small.Red">
|
||||
<style name="ChipButton.Small.Red" parent="ChipButton.Small">
|
||||
<item name="android:backgroundTint">@color/watch_red_200</item>
|
||||
<item name="android:textColor">@color/black</item>
|
||||
</style>
|
||||
|
|
|
|||
Loading…
Reference in a new issue