stufff...
|
|
@ -150,7 +150,7 @@ android {
|
|||
buildConfigField "String", "TESTING_LEVEL", "\"production\""
|
||||
resConfigs 'en', 'bg', 'de', 'en-rGB', 'es', 'fr', 'hr-rHR', 'in', 'it', 'iw', 'ja', 'ko', 'lt', 'nl', 'pl', 'pt-rBR', 'pt-rPT', 'ru', 'tr', 'zh', 'zh-rTW'
|
||||
|
||||
versionCode 3520
|
||||
versionCode 4000
|
||||
versionName app_version_name
|
||||
|
||||
targetSdkVersion target_sdk
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ import android.util.Log
|
|||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.core.content.edit
|
||||
import androidx.preference.PreferenceManager
|
||||
import coil.annotation.ExperimentalCoilApi
|
||||
import com.amplitude.api.Amplitude
|
||||
import com.amplitude.api.Identify
|
||||
import com.google.firebase.analytics.FirebaseAnalytics
|
||||
|
|
@ -60,7 +59,6 @@ abstract class HabiticaBaseApplication : Application(), Application.ActivityLife
|
|||
*/
|
||||
// endregion
|
||||
|
||||
@OptIn(ExperimentalCoilApi::class)
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
registerActivityLifecycleCallbacks(this)
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ import android.widget.TextView
|
|||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import coil.load
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.components.UserComponent
|
||||
import com.habitrpg.android.habitica.data.ApiClient
|
||||
|
|
@ -212,7 +211,7 @@ class FullProfileActivity : BaseActivity() {
|
|||
if (imageUrl == null || imageUrl.isEmpty()) {
|
||||
binding.profileImage.visibility = View.GONE
|
||||
} else {
|
||||
binding.profileImage.load(imageUrl)
|
||||
//binding.profileImage.load(imageUrl)
|
||||
}
|
||||
|
||||
val blurbText = profile.blurb
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import android.view.LayoutInflater
|
|||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.content.ContextCompat
|
||||
import coil.load
|
||||
import com.habitrpg.android.habitica.HabiticaBaseApplication
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.databinding.CustomizationGridItemBinding
|
||||
|
|
@ -15,16 +14,16 @@ import com.habitrpg.android.habitica.helpers.MainNavigationController
|
|||
import com.habitrpg.android.habitica.models.inventory.Customization
|
||||
import com.habitrpg.android.habitica.models.inventory.CustomizationSet
|
||||
import com.habitrpg.android.habitica.models.shops.ShopItem
|
||||
import com.habitrpg.common.habitica.extensions.loadImage
|
||||
import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog
|
||||
import com.habitrpg.android.habitica.ui.views.shops.PurchaseDialog
|
||||
import com.habitrpg.common.habitica.extensions.loadImage
|
||||
import com.habitrpg.common.habitica.models.Avatar
|
||||
import com.habitrpg.common.habitica.views.AvatarView
|
||||
import io.reactivex.rxjava3.core.BackpressureStrategy
|
||||
import io.reactivex.rxjava3.core.Flowable
|
||||
import io.reactivex.rxjava3.subjects.PublishSubject
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
import java.util.Date
|
||||
import java.util.EnumMap
|
||||
|
||||
class CustomizationRecyclerViewAdapter() : androidx.recyclerview.widget.RecyclerView.Adapter<androidx.recyclerview.widget.RecyclerView.ViewHolder>() {
|
||||
|
||||
|
|
@ -151,7 +150,7 @@ class CustomizationRecyclerViewAdapter() : androidx.recyclerview.widget.Recycler
|
|||
this.customization = customization
|
||||
|
||||
if (customization.type == "background" && customization.identifier == "") {
|
||||
binding.imageView.load(R.drawable.no_background)
|
||||
binding.imageView.setImageResource(R.drawable.no_background)
|
||||
binding.imageView.bitmap = null
|
||||
} else {
|
||||
binding.imageView.loadImage(customization.getIconName(userSize, hairColor))
|
||||
|
|
|
|||
|
|
@ -5,12 +5,10 @@ import android.util.AttributeSet
|
|||
import android.view.Gravity
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import coil.load
|
||||
import com.habitrpg.common.habitica.extensions.dpToPx
|
||||
import com.habitrpg.android.habitica.extensions.fromHtml
|
||||
import com.habitrpg.android.habitica.models.inventory.QuestContent
|
||||
import com.habitrpg.android.habitica.models.shops.ShopItem
|
||||
import com.habitrpg.common.habitica.extensions.DataBindingUtils
|
||||
import com.habitrpg.common.habitica.extensions.dpToPx
|
||||
import com.habitrpg.common.habitica.extensions.loadImage
|
||||
import com.habitrpg.common.habitica.views.PixelArtView
|
||||
|
||||
|
|
@ -30,7 +28,7 @@ abstract class PurchaseDialogContent @JvmOverloads constructor(
|
|||
|
||||
open fun setItem(item: ShopItem) {
|
||||
if (item.path?.contains("timeTravelBackgrounds") == true) {
|
||||
imageView.load("${DataBindingUtils.BASE_IMAGE_URL}${item.imageName?.replace("icon_", "")}.gif")
|
||||
// imageView.load("${DataBindingUtils.BASE_IMAGE_URL}${item.imageName?.replace("icon_", "")}.gif")
|
||||
val params = imageView.layoutParams
|
||||
params.height = 147.dpToPx(context)
|
||||
params.width = 140.dpToPx(context)
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
package com.habitrpg.common.habitica.models.responses
|
||||
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
import com.habitrpg.common.habitica.models.AvatarStats
|
||||
|
||||
class TaskScoringResult() {
|
||||
class TaskScoringResult(): Parcelable {
|
||||
constructor(data: TaskDirectionData, stats: AvatarStats?) : this() {
|
||||
hasLeveledUp = data.lvl > stats?.lvl ?: 0
|
||||
hasLeveledUp = data.lvl > (stats?.lvl ?: 0)
|
||||
healthDelta = data.hp - (stats?.hp ?: 0.0)
|
||||
if (hasLeveledUp) {
|
||||
experienceDelta = (stats?.toNextLevel ?: 0).toDouble() - (stats?.exp ?: 0.0) + data.exp
|
||||
|
|
@ -28,4 +30,40 @@ class TaskScoringResult() {
|
|||
var level: Int? = null
|
||||
var questDamage: Double? = null
|
||||
var questItemsFound: Int? = null
|
||||
|
||||
constructor(parcel: Parcel) : this() {
|
||||
experienceDelta = parcel.readValue(Double::class.java.classLoader) as? Double
|
||||
healthDelta = parcel.readValue(Double::class.java.classLoader) as? Double
|
||||
goldDelta = parcel.readValue(Double::class.java.classLoader) as? Double
|
||||
manaDelta = parcel.readValue(Double::class.java.classLoader) as? Double
|
||||
hasLeveledUp = parcel.readByte() != 0.toByte()
|
||||
level = parcel.readValue(Int::class.java.classLoader) as? Int
|
||||
questDamage = parcel.readValue(Double::class.java.classLoader) as? Double
|
||||
questItemsFound = parcel.readValue(Int::class.java.classLoader) as? Int
|
||||
}
|
||||
|
||||
override fun writeToParcel(parcel: Parcel, flags: Int) {
|
||||
parcel.writeValue(experienceDelta)
|
||||
parcel.writeValue(healthDelta)
|
||||
parcel.writeValue(goldDelta)
|
||||
parcel.writeValue(manaDelta)
|
||||
parcel.writeByte(if (hasLeveledUp) 1 else 0)
|
||||
parcel.writeValue(level)
|
||||
parcel.writeValue(questDamage)
|
||||
parcel.writeValue(questItemsFound)
|
||||
}
|
||||
|
||||
override fun describeContents(): Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
companion object CREATOR : Parcelable.Creator<TaskScoringResult> {
|
||||
override fun createFromParcel(parcel: Parcel): TaskScoringResult {
|
||||
return TaskScoringResult(parcel)
|
||||
}
|
||||
|
||||
override fun newArray(size: Int): Array<TaskScoringResult?> {
|
||||
return arrayOfNulls(size)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ public class HabiticaIconsHelper {
|
|||
if (imageOfExperience != null)
|
||||
return imageOfExperience;
|
||||
|
||||
int size = scaleSize(24);
|
||||
int size = scaleSize(18);
|
||||
imageOfExperience = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
|
||||
Canvas canvas = new Canvas(imageOfExperience);
|
||||
canvas.scale(displayDensity, displayDensity);
|
||||
|
|
@ -45,7 +45,7 @@ public class HabiticaIconsHelper {
|
|||
if (imageOfMagic != null)
|
||||
return imageOfMagic;
|
||||
|
||||
int size = scaleSize(24);
|
||||
int size = scaleSize(18);
|
||||
imageOfMagic = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
|
||||
Canvas canvas = new Canvas(imageOfMagic);
|
||||
canvas.scale(displayDensity, displayDensity);
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ android {
|
|||
applicationId "com.habitrpg.android.habitica"
|
||||
minSdk 26
|
||||
targetSdk target_sdk
|
||||
versionCode 3521
|
||||
versionCode 4001
|
||||
versionName app_version_name
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@
|
|||
<activity android:name="com.habitrpg.wearos.habitica.ui.activities.TaskListActivity" />
|
||||
<activity android:name="com.habitrpg.wearos.habitica.ui.activities.TaskFormActivity" />
|
||||
<activity android:name="com.habitrpg.wearos.habitica.ui.activities.HabitDirectionActivity" />
|
||||
<activity android:name="com.habitrpg.wearos.habitica.ui.activities.TaskResultActivity" />
|
||||
|
||||
<activity android:name="com.habitrpg.wearos.habitica.ui.activities.AvatarActivity" />
|
||||
<activity android:name="com.habitrpg.wearos.habitica.ui.activities.StatsActivity" />
|
||||
|
|
|
|||
|
|
@ -48,7 +48,9 @@ class TaskLocalRepository @Inject constructor() {
|
|||
} else {
|
||||
oldList?.add(0, task)
|
||||
}
|
||||
tasks[task.type]?.value = oldList
|
||||
oldList?.let {
|
||||
tasks[task.type]?.value = it
|
||||
}
|
||||
}
|
||||
|
||||
fun getTask(taskID: String): Flow<Task?> {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import com.habitrpg.common.habitica.models.tasks.TaskType
|
|||
import com.habitrpg.wearos.habitica.data.ApiClient
|
||||
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 kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.emptyFlow
|
||||
import javax.inject.Inject
|
||||
|
|
@ -20,14 +21,14 @@ class TaskRepository @Inject constructor(val apiClient: ApiClient, val localRepo
|
|||
fun getTasks(taskType: TaskType): Flow<List<Task>> = localRepository.getTasks(taskType)
|
||||
|
||||
|
||||
suspend fun scoreTask(task: Task, direction: TaskDirection): TaskScoringResult? {
|
||||
suspend fun scoreTask(user: User?, task: Task, direction: TaskDirection): TaskScoringResult? {
|
||||
val id = task.id ?: return null
|
||||
val result = apiClient.scoreTask(id, direction.text)
|
||||
if (result != null) {
|
||||
task.completed = direction == TaskDirection.UP
|
||||
localRepository.updateTask(task)
|
||||
}
|
||||
return result?.let { TaskScoringResult(it, null) }
|
||||
return result?.let { TaskScoringResult(it, user?.stats) }
|
||||
}
|
||||
|
||||
fun getTask(taskID: String?): Flow<Task?> {
|
||||
|
|
|
|||
|
|
@ -1,14 +1,8 @@
|
|||
package com.habitrpg.wearos.habitica.ui.activities
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import androidx.activity.viewModels
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.wear.activity.ConfirmationActivity
|
||||
import androidx.wear.widget.WearableLinearLayoutManager
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.databinding.ActivityTasklistBinding
|
||||
|
|
@ -24,8 +18,6 @@ import com.habitrpg.wearos.habitica.ui.adapters.ToDoListAdapter
|
|||
import com.habitrpg.wearos.habitica.ui.viewmodels.TaskListViewModel
|
||||
import com.habitrpg.wearos.habitica.util.HabiticaScrollingLayoutCallback
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import java.lang.Float.max
|
||||
import java.lang.Float.min
|
||||
|
||||
@AndroidEntryPoint
|
||||
class TaskListActivity: BaseActivity<ActivityTasklistBinding, TaskListViewModel>() {
|
||||
|
|
@ -51,6 +43,10 @@ class TaskListActivity: BaseActivity<ActivityTasklistBinding, TaskListViewModel>
|
|||
scoreTask(it)
|
||||
}
|
||||
|
||||
viewModel.user.observe(this) {
|
||||
|
||||
}
|
||||
|
||||
binding.addTaskButton.setOnClickListener { openTaskFormActivity() }
|
||||
}
|
||||
|
||||
|
|
@ -76,12 +72,7 @@ class TaskListActivity: BaseActivity<ActivityTasklistBinding, TaskListViewModel>
|
|||
}
|
||||
|
||||
private fun showTaskScoringResult(result: TaskScoringResult) {
|
||||
val intent = Intent(this, ConfirmationActivity::class.java).apply {
|
||||
putExtra(ConfirmationActivity.EXTRA_ANIMATION_TYPE, ConfirmationActivity.SUCCESS_ANIMATION)
|
||||
putExtra(ConfirmationActivity.EXTRA_MESSAGE, result.experienceDelta?.toString())
|
||||
putExtra(ConfirmationActivity.EXTRA_ANIMATION_DURATION_MILLIS, 3000)
|
||||
}
|
||||
startActivity(intent)
|
||||
TaskResultActivity.show(this, result)
|
||||
}
|
||||
|
||||
private fun openTaskFormActivity() {
|
||||
|
|
@ -127,37 +118,4 @@ class TaskListActivity: BaseActivity<ActivityTasklistBinding, TaskListViewModel>
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ScrollAwayBehavior<V : View>(context: Context, attrs: AttributeSet) :
|
||||
CoordinatorLayout.Behavior<V>(context, attrs) {
|
||||
|
||||
override fun onStartNestedScroll(
|
||||
coordinatorLayout: CoordinatorLayout, child: V, directTargetChild: View, target: View, axes: Int, type: Int
|
||||
): Boolean {
|
||||
return axes == ViewCompat.SCROLL_AXIS_VERTICAL
|
||||
}
|
||||
|
||||
override fun onNestedPreScroll(
|
||||
coordinatorLayout: CoordinatorLayout, child: V, target: View, dx: Int, dy: Int, consumed: IntArray, type: Int
|
||||
) {
|
||||
super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed, type)
|
||||
child.translationY = max(0f, min(child.height.toFloat(), child.translationY + dy))
|
||||
}
|
||||
|
||||
override fun onStopNestedScroll(
|
||||
coordinatorLayout: CoordinatorLayout,
|
||||
child: V,
|
||||
target: View,
|
||||
type: Int
|
||||
) {
|
||||
super.onStopNestedScroll(coordinatorLayout, child, target, type)
|
||||
if (child.translationY != 0f && child.translationY != child.height.toFloat()) {
|
||||
if (child.translationY < (child.height.toFloat() / 2f)) {
|
||||
child.translationY = 0f
|
||||
} else {
|
||||
child.translationY = child.height.toFloat()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,161 @@
|
|||
package com.habitrpg.wearos.habitica.ui.activities
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.Gravity
|
||||
import android.view.animation.AlphaAnimation
|
||||
import android.widget.GridLayout
|
||||
import androidx.activity.viewModels
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.databinding.ActivityTaskResultBinding
|
||||
import com.habitrpg.android.habitica.databinding.TaskRewardDropBinding
|
||||
import com.habitrpg.common.habitica.extensions.dpToPx
|
||||
import com.habitrpg.common.habitica.extensions.loadImage
|
||||
import com.habitrpg.common.habitica.models.responses.TaskScoringResult
|
||||
import com.habitrpg.common.habitica.views.HabiticaIconsHelper
|
||||
import com.habitrpg.wearos.habitica.ui.viewmodels.TaskResultViewModel
|
||||
import com.habitrpg.wearos.habitica.ui.views.TaskRewardChip
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
||||
@AndroidEntryPoint
|
||||
class TaskResultActivity : BaseActivity<ActivityTaskResultBinding, TaskResultViewModel>() {
|
||||
override val viewModel: TaskResultViewModel by viewModels()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
binding = ActivityTaskResultBinding.inflate(layoutInflater)
|
||||
super.onCreate(savedInstanceState)
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
makeChips()
|
||||
}
|
||||
|
||||
private fun makeChips() {
|
||||
binding.gridLayout.removeAllViews()
|
||||
var chips = mutableListOf<TaskRewardChip>()
|
||||
if ((viewModel.result?.healthDelta ?: 0.0) != 0.0) {
|
||||
val chip = TaskRewardChip(this)
|
||||
chip.set(
|
||||
viewModel.result?.healthDelta,
|
||||
HabiticaIconsHelper.imageOfHeartDarkBg()
|
||||
)
|
||||
chips.add(chip)
|
||||
}
|
||||
if ((viewModel.result?.experienceDelta ?: 0.0) != 0.0) {
|
||||
val chip = TaskRewardChip(this)
|
||||
chip.set(
|
||||
viewModel.result?.experienceDelta,
|
||||
HabiticaIconsHelper.imageOfExperience()
|
||||
)
|
||||
chips.add(chip)
|
||||
}
|
||||
if ((viewModel.result?.goldDelta ?: 0.0) != 0.0) {
|
||||
val chip = TaskRewardChip(this)
|
||||
chip.set(
|
||||
viewModel.result?.goldDelta,
|
||||
HabiticaIconsHelper.imageOfGold()
|
||||
)
|
||||
chips.add(chip)
|
||||
}
|
||||
if ((viewModel.result?.manaDelta ?: 0.0) > 0.0) {
|
||||
val chip = TaskRewardChip(this)
|
||||
chip.set(
|
||||
viewModel.result?.manaDelta,
|
||||
HabiticaIconsHelper.imageOfMagic()
|
||||
)
|
||||
chips.add(chip)
|
||||
}
|
||||
if ((viewModel.result?.questDamage ?: 0.0) > 0.0) {
|
||||
val chip = TaskRewardChip(this)
|
||||
chip.set(
|
||||
viewModel.result?.questDamage,
|
||||
HabiticaIconsHelper.imageOfDamage()
|
||||
)
|
||||
chips.add(chip)
|
||||
}
|
||||
var index = 0
|
||||
var currentRow = 0
|
||||
var currentColumn = 0
|
||||
val hasDrop = viewModel.hasDrop
|
||||
val margin = 6.dpToPx(this)
|
||||
val chipSize = when {
|
||||
hasDrop -> TaskRewardChip.Size.SMALL
|
||||
chips.size <= 2 -> TaskRewardChip.Size.LARGE
|
||||
chips.size == 5 -> TaskRewardChip.Size.SMALL
|
||||
else -> TaskRewardChip.Size.MEDIUM
|
||||
}
|
||||
if (chips.size > 4 && hasDrop || (chips.size > 5 && !hasDrop)) {
|
||||
chips = chips.subList(0, if (hasDrop) 4 else 5)
|
||||
}
|
||||
chips.forEach {
|
||||
binding.gridLayout.addView(it)
|
||||
it.size = chipSize
|
||||
val layoutParams = GridLayout.LayoutParams()
|
||||
layoutParams.height = GridLayout.LayoutParams.WRAP_CONTENT
|
||||
layoutParams.width = GridLayout.LayoutParams.WRAP_CONTENT
|
||||
layoutParams.setGravity(Gravity.CENTER)
|
||||
layoutParams.rowSpec = GridLayout.spec(currentRow)
|
||||
if (index == 0 || currentRow == 2) {
|
||||
layoutParams.columnSpec = GridLayout.spec(0, 3, GridLayout.CENTER)
|
||||
currentRow += 1
|
||||
} else {
|
||||
layoutParams.columnSpec = GridLayout.spec(currentColumn, 1)
|
||||
if (currentColumn > 0) {
|
||||
layoutParams.marginStart = margin
|
||||
}
|
||||
currentColumn += 1
|
||||
if ((index == 2 && !hasDrop && chips.size == 4) || (index == 3 && !hasDrop && chips.size == 5)) {
|
||||
currentRow += 1
|
||||
currentColumn = 0
|
||||
}
|
||||
}
|
||||
layoutParams.bottomMargin = margin
|
||||
index += 1
|
||||
it.layoutParams = layoutParams
|
||||
|
||||
val animator = AlphaAnimation(0f, 1f)
|
||||
animator.startOffset = (index * 150).toLong() + 200
|
||||
animator.duration = 300
|
||||
animator.fillAfter = true
|
||||
animator.fillBefore = true
|
||||
it.startAnimation(animator)
|
||||
}
|
||||
if (hasDrop) {
|
||||
val dropBinding = TaskRewardDropBinding.inflate(layoutInflater, binding.gridLayout, true)
|
||||
val layoutParams = GridLayout.LayoutParams()
|
||||
layoutParams.height = GridLayout.LayoutParams.WRAP_CONTENT
|
||||
layoutParams.width = GridLayout.LayoutParams.WRAP_CONTENT
|
||||
layoutParams.setGravity(Gravity.CENTER)
|
||||
layoutParams.rowSpec = GridLayout.spec(2)
|
||||
layoutParams.columnSpec = GridLayout.spec(0, 3, GridLayout.CENTER)
|
||||
dropBinding.root.layoutParams = layoutParams
|
||||
val elements = mutableListOf<String>()
|
||||
if ((viewModel.result?.questItemsFound?: 0) != 0) {
|
||||
if (viewModel.result?.questItemsFound == 1) {
|
||||
elements.add(getString(R.string.one_quest_item))
|
||||
} else {
|
||||
elements.add(getString(R.string.x_quest_item, viewModel.result?.questItemsFound))
|
||||
}
|
||||
}
|
||||
if (viewModel.result?.drop?.key != null) {
|
||||
elements.add(getString(R.string.some_x, viewModel.result?.drop?.type))
|
||||
dropBinding.imageView.loadImage(viewModel.result?.drop?.key)
|
||||
}
|
||||
dropBinding.textView.text = when (elements.size) {
|
||||
1 -> elements[0]
|
||||
2 -> getString(R.string.x_and_y, elements[0], elements[1])
|
||||
else -> elements.joinToString(", ")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun show(context: Activity, result: TaskScoringResult) {
|
||||
val intent = Intent(context, TaskResultActivity::class.java)
|
||||
intent.putExtra("result", result)
|
||||
context.startActivity(intent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -20,6 +20,7 @@ class DailyViewHolder(itemView: View) : TaskViewHolder(itemView) {
|
|||
|
||||
override fun bind(data: Task) {
|
||||
super.bind(data)
|
||||
binding.checkbox.isChecked = data.completed
|
||||
binding.checkbox.backgroundTintList = ColorStateList.valueOf(ContextCompat.getColor(itemView.context, data.mediumTaskColor))
|
||||
}
|
||||
}
|
||||
|
|
@ -20,6 +20,7 @@ class ToDoViewHolder(itemView: View) : TaskViewHolder(itemView) {
|
|||
|
||||
override fun bind(data: Task) {
|
||||
super.bind(data)
|
||||
binding.checkbox.isChecked = data.completed
|
||||
binding.checkbox.backgroundTintList = ColorStateList.valueOf(ContextCompat.getColor(itemView.context, data.mediumTaskColor))
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,7 @@
|
|||
package com.habitrpg.wearos.habitica.ui.viewmodels
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.asLiveData
|
||||
import com.habitrpg.wearos.habitica.data.repositories.UserRepository
|
||||
import com.habitrpg.wearos.habitica.models.user.User
|
||||
import com.habitrpg.wearos.habitica.util.ExceptionHandlerBuilder
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import javax.inject.Inject
|
||||
|
|
@ -16,9 +14,5 @@ class AvatarViewModel @Inject constructor(
|
|||
userRepository,
|
||||
exceptionBuilder
|
||||
) {
|
||||
var user: LiveData<User>
|
||||
|
||||
init {
|
||||
user = userRepository.getUser().asLiveData()
|
||||
}
|
||||
var user = userRepository.getUser().asLiveData()
|
||||
}
|
||||
|
|
@ -21,9 +21,11 @@ class HabitDrectionViewModel @Inject constructor(
|
|||
val taskID = savedStateHandle.get<String>("task_id")
|
||||
val task = taskRepository.getTask(taskID).asLiveData()
|
||||
|
||||
val user = userRepository.getUser().asLiveData()
|
||||
|
||||
fun scoreTask(direction: TaskDirection) {
|
||||
viewModelScope.launch(exceptionBuilder.userFacing(this)) {
|
||||
task.value?.let { taskRepository.scoreTask(it, direction) }
|
||||
task.value?.let { taskRepository.scoreTask(user.value, it, direction) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,9 @@
|
|||
package com.habitrpg.wearos.habitica.ui.viewmodels
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.asLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.habitrpg.common.habitica.api.HostConfig
|
||||
import com.habitrpg.wearos.habitica.data.repositories.TaskRepository
|
||||
import com.habitrpg.wearos.habitica.data.repositories.UserRepository
|
||||
import com.habitrpg.wearos.habitica.models.user.User
|
||||
import com.habitrpg.wearos.habitica.util.ExceptionHandlerBuilder
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
|
|
@ -14,19 +11,13 @@ import javax.inject.Inject
|
|||
|
||||
@HiltViewModel
|
||||
class MainViewModel @Inject constructor(
|
||||
val hostConfig: HostConfig,
|
||||
userRepository: UserRepository,
|
||||
val taskRepository: TaskRepository,
|
||||
exceptionBuilder: ExceptionHandlerBuilder
|
||||
) : BaseViewModel(userRepository, exceptionBuilder) {
|
||||
val isAuthenticated: Boolean
|
||||
get() {
|
||||
return hostConfig.hasAuthentication()
|
||||
}
|
||||
var user: LiveData<User>
|
||||
var user = userRepository.getUser().asLiveData()
|
||||
|
||||
init {
|
||||
user = userRepository.getUser().asLiveData()
|
||||
viewModelScope.launch(exceptionBuilder.userFacing(this)) {
|
||||
userRepository.retrieveUser()
|
||||
taskRepository.retrieveTasks()
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package com.habitrpg.wearos.habitica.ui.viewmodels
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.asLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
|
|
@ -22,17 +21,16 @@ class TaskListViewModel @Inject constructor(
|
|||
userRepository: UserRepository,
|
||||
exceptionBuilder: ExceptionHandlerBuilder
|
||||
) : BaseViewModel(userRepository, exceptionBuilder) {
|
||||
val taskType = TaskType.from(savedStateHandle.get<String>("task_type"))
|
||||
val tasks = taskRepository.getTasks(taskType ?: TaskType.HABIT).asLiveData()
|
||||
val user = userRepository.getUser()
|
||||
.asLiveData()
|
||||
|
||||
fun scoreTask(task: Task, direction: TaskDirection, onResult: (TaskScoringResult?) -> Unit) {
|
||||
viewModelScope.launch(exceptionBuilder.userFacing(this)) {
|
||||
val result = taskRepository.scoreTask(task, direction)
|
||||
val result = taskRepository.scoreTask(user.value, task, direction)
|
||||
onResult(result)
|
||||
}
|
||||
}
|
||||
|
||||
var tasks: LiveData<List<Task>>
|
||||
val taskType = TaskType.from(savedStateHandle.get<String>("task_type"))
|
||||
|
||||
init {
|
||||
tasks = taskRepository.getTasks(taskType ?: TaskType.HABIT).asLiveData()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package com.habitrpg.wearos.habitica.ui.viewmodels
|
||||
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import com.habitrpg.common.habitica.models.responses.TaskScoringResult
|
||||
import com.habitrpg.wearos.habitica.data.repositories.UserRepository
|
||||
import com.habitrpg.wearos.habitica.util.ExceptionHandlerBuilder
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class TaskResultViewModel @Inject constructor(savedStateHandle: SavedStateHandle, userRepository: UserRepository,
|
||||
exceptionBuilder: ExceptionHandlerBuilder
|
||||
) : BaseViewModel(userRepository, exceptionBuilder) {
|
||||
val hasDrop: Boolean
|
||||
get() {
|
||||
return result?.drop?.key?.isNotBlank() == true || (result?.questItemsFound ?: 0) > 0
|
||||
}
|
||||
val result = savedStateHandle.get<TaskScoringResult>("result")
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
package com.habitrpg.wearos.habitica.ui.views
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.ColorStateList
|
||||
import android.graphics.Bitmap
|
||||
import android.util.AttributeSet
|
||||
import android.util.TypedValue
|
||||
import android.view.Gravity
|
||||
import android.widget.LinearLayout
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.databinding.TaskRewardChipBinding
|
||||
import com.habitrpg.android.habitica.extensions.round
|
||||
import com.habitrpg.android.habitica.extensions.setScaledPadding
|
||||
import com.habitrpg.common.habitica.extensions.layoutInflater
|
||||
import java.math.RoundingMode
|
||||
import java.text.NumberFormat
|
||||
|
||||
class TaskRewardChip @JvmOverloads constructor(
|
||||
context: Context, attrs: AttributeSet? = null
|
||||
) : LinearLayout(context, attrs) {
|
||||
enum class Size {
|
||||
SMALL,
|
||||
MEDIUM,
|
||||
LARGE
|
||||
}
|
||||
|
||||
val binding = TaskRewardChipBinding.inflate(context.layoutInflater, this)
|
||||
|
||||
var size: Size = Size.MEDIUM
|
||||
set(value) {
|
||||
field = value
|
||||
binding.textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, when (field) {
|
||||
Size.SMALL -> 14f
|
||||
Size.MEDIUM -> 16f
|
||||
Size.LARGE -> 20f
|
||||
})
|
||||
when (field) {
|
||||
Size.SMALL -> setScaledPadding(context, 10, 9, 10, 9)
|
||||
Size.MEDIUM -> setScaledPadding(context, 17, 9, 17, 9)
|
||||
Size.LARGE -> setScaledPadding(context, 21, 12, 21, 12)
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
background = ContextCompat.getDrawable(context, R.drawable.row_background)
|
||||
gravity = Gravity.CENTER
|
||||
}
|
||||
|
||||
fun set(value: Double?, icon: Bitmap) {
|
||||
binding.iconView.setImageBitmap(icon)
|
||||
var text = formatter.format(value?.round(1))
|
||||
if (text.firstOrNull() == '0') {
|
||||
text = text.substring(1)
|
||||
}
|
||||
binding.textView.text = text
|
||||
backgroundTintList = if ((value ?: 0.0) > 0.0) {
|
||||
ColorStateList.valueOf(ContextCompat.getColor(context, R.color.watch_green_100))
|
||||
} else {
|
||||
ColorStateList.valueOf(ContextCompat.getColor(context, R.color.watch_red_100))
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val formatter = NumberFormat.getInstance().apply {
|
||||
maximumFractionDigits = 1
|
||||
roundingMode = RoundingMode.UP
|
||||
isGroupingUsed = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
package com.habitrpg.wearos.habitica.util
|
||||
|
||||
import android.content.Context
|
||||
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
|
||||
|
||||
class ScrollAwayBehavior<V : View>(context: Context, attrs: AttributeSet) :
|
||||
CoordinatorLayout.Behavior<V>(context, attrs) {
|
||||
|
||||
override fun onStartNestedScroll(
|
||||
coordinatorLayout: CoordinatorLayout, child: V, directTargetChild: View, target: View, axes: Int, type: Int
|
||||
): Boolean {
|
||||
return axes == ViewCompat.SCROLL_AXIS_VERTICAL
|
||||
}
|
||||
|
||||
override fun onNestedPreScroll(
|
||||
coordinatorLayout: CoordinatorLayout, child: V, target: View, dx: Int, dy: Int, consumed: IntArray, type: Int
|
||||
) {
|
||||
super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed, type)
|
||||
child.translationY =
|
||||
Float.max(0f, Float.min(child.height.toFloat(), child.translationY + dy))
|
||||
}
|
||||
|
||||
override fun onStopNestedScroll(
|
||||
coordinatorLayout: CoordinatorLayout,
|
||||
child: V,
|
||||
target: View,
|
||||
type: Int
|
||||
) {
|
||||
super.onStopNestedScroll(coordinatorLayout, child, target, type)
|
||||
if (child.translationY != 0f && child.translationY != child.height.toFloat()) {
|
||||
if (child.translationY < (child.height.toFloat() / 2f)) {
|
||||
child.translationY = 0f
|
||||
} else {
|
||||
child.translationY = child.height.toFloat()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
wearos/src/main/res/drawable-hdpi/experience.png
Normal file
|
After Width: | Height: | Size: 390 B |
BIN
wearos/src/main/res/drawable-hdpi/magic.png
Normal file
|
After Width: | Height: | Size: 422 B |
BIN
wearos/src/main/res/drawable-mdpi/experience.png
Normal file
|
After Width: | Height: | Size: 324 B |
BIN
wearos/src/main/res/drawable-mdpi/magic.png
Normal file
|
After Width: | Height: | Size: 365 B |
BIN
wearos/src/main/res/drawable-xhdpi/experience.png
Normal file
|
After Width: | Height: | Size: 469 B |
BIN
wearos/src/main/res/drawable-xhdpi/magic.png
Normal file
|
After Width: | Height: | Size: 529 B |
BIN
wearos/src/main/res/drawable-xxhdpi/experience.png
Normal file
|
After Width: | Height: | Size: 569 B |
BIN
wearos/src/main/res/drawable-xxhdpi/magic.png
Normal file
|
After Width: | Height: | Size: 647 B |
BIN
wearos/src/main/res/drawable-xxxhdpi/experience.png
Normal file
|
After Width: | Height: | Size: 707 B |
BIN
wearos/src/main/res/drawable-xxxhdpi/magic.png
Normal file
|
After Width: | Height: | Size: 743 B |
18
wearos/src/main/res/layout/activity_task_result.xml
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
<GridLayout
|
||||
android:id="@+id/grid_layout"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:columnCount="3"
|
||||
android:rowCount="3"
|
||||
android:alignmentMode="alignBounds"
|
||||
android:layout_gravity="center">
|
||||
|
||||
</GridLayout>
|
||||
</FrameLayout>
|
||||
|
|
@ -14,5 +14,5 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="38dp"
|
||||
android:layout_gravity="center|bottom"
|
||||
app:layout_behavior="com.habitrpg.wearos.habitica.ui.activities.ScrollAwayBehavior"/>
|
||||
app:layout_behavior="com.habitrpg.wearos.habitica.util.ScrollAwayBehavior"/>
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
24
wearos/src/main/res/layout/task_reward_chip.xml
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:parentTag="android.widget.LinearLayout">
|
||||
<TextView
|
||||
android:id="@+id/text_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="sans-serif-medium"
|
||||
android:textSize="16sp"
|
||||
android:textColor="@color/black"/>
|
||||
<ImageView
|
||||
android:id="@+id/icon_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:scaleType="center"
|
||||
android:layout_marginStart="6dp"
|
||||
android:layout_marginEnd="0dp"
|
||||
android:layout_gravity="center"/>
|
||||
|
||||
</merge>
|
||||
25
wearos/src/main/res/layout/task_reward_drop.xml
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center">
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="12sp"
|
||||
android:textColor="@color/white"
|
||||
android:text="@string/you_found"/>
|
||||
<TextView
|
||||
android:id="@+id/text_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="sans-serif-medium"
|
||||
android:textSize="14sp"
|
||||
android:textColor="@color/white"
|
||||
/>
|
||||
<com.habitrpg.common.habitica.views.PixelArtView
|
||||
android:id="@+id/image_view"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp" />
|
||||
</LinearLayout>
|
||||
|
|
@ -2,4 +2,9 @@
|
|||
<string name="ok">OK</string>
|
||||
<string name="syncing_account">Syncing Account from Phone</string>
|
||||
<string name="how_did_you_do">How did you do?</string>
|
||||
<string name="you_found">You found…</string>
|
||||
<string name="one_quest_item">1 Quest item</string>
|
||||
<string name="x_quest_item">%d Quest items</string>
|
||||
<string name="x_and_y">%s and %s</string>
|
||||
<string name="some_x">some %s</string>
|
||||
</resources>
|
||||