diff --git a/Habitica/build.gradle b/Habitica/build.gradle index a384d0889..661f8e427 100644 --- a/Habitica/build.gradle +++ b/Habitica/build.gradle @@ -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 diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/HabiticaBaseApplication.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/HabiticaBaseApplication.kt index 84e9a66da..920a0db64 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/HabiticaBaseApplication.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/HabiticaBaseApplication.kt @@ -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) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/FullProfileActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/FullProfileActivity.kt index e72a3ece3..3bdd27755 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/FullProfileActivity.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/FullProfileActivity.kt @@ -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 diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/CustomizationRecyclerViewAdapter.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/CustomizationRecyclerViewAdapter.kt index 916ae0372..bf8ed01e6 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/CustomizationRecyclerViewAdapter.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/CustomizationRecyclerViewAdapter.kt @@ -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() { @@ -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)) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialogContent.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialogContent.kt index 40358da72..b21c16a72 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialogContent.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialogContent.kt @@ -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) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/extensions/ViewExt.kt b/common/src/main/java/com/habitrpg/common/habitica/extensions/ViewExt.kt similarity index 100% rename from Habitica/src/main/java/com/habitrpg/android/habitica/extensions/ViewExt.kt rename to common/src/main/java/com/habitrpg/common/habitica/extensions/ViewExt.kt diff --git a/common/src/main/java/com/habitrpg/common/habitica/models/responses/TaskScoringResult.kt b/common/src/main/java/com/habitrpg/common/habitica/models/responses/TaskScoringResult.kt index 36beae667..15aad3a07 100644 --- a/common/src/main/java/com/habitrpg/common/habitica/models/responses/TaskScoringResult.kt +++ b/common/src/main/java/com/habitrpg/common/habitica/models/responses/TaskScoringResult.kt @@ -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 { + override fun createFromParcel(parcel: Parcel): TaskScoringResult { + return TaskScoringResult(parcel) + } + + override fun newArray(size: Int): Array { + return arrayOfNulls(size) + } + } } diff --git a/common/src/main/java/com/habitrpg/common/habitica/views/HabiticaIconsHelper.java b/common/src/main/java/com/habitrpg/common/habitica/views/HabiticaIconsHelper.java index 5efcf5f0a..5263e360f 100644 --- a/common/src/main/java/com/habitrpg/common/habitica/views/HabiticaIconsHelper.java +++ b/common/src/main/java/com/habitrpg/common/habitica/views/HabiticaIconsHelper.java @@ -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); diff --git a/wearos/build.gradle b/wearos/build.gradle index 0424d3541..51dea440d 100644 --- a/wearos/build.gradle +++ b/wearos/build.gradle @@ -13,7 +13,7 @@ android { applicationId "com.habitrpg.android.habitica" minSdk 26 targetSdk target_sdk - versionCode 3521 + versionCode 4001 versionName app_version_name } diff --git a/wearos/src/main/AndroidManifest.xml b/wearos/src/main/AndroidManifest.xml index 541a59495..0747d61fd 100644 --- a/wearos/src/main/AndroidManifest.xml +++ b/wearos/src/main/AndroidManifest.xml @@ -38,6 +38,7 @@ + diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/data/repositories/TaskLocalRepository.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/data/repositories/TaskLocalRepository.kt index 1df2dace4..214bb1e33 100644 --- a/wearos/src/main/java/com/habitrpg/wearos/habitica/data/repositories/TaskLocalRepository.kt +++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/data/repositories/TaskLocalRepository.kt @@ -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 { diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/data/repositories/TaskRepository.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/data/repositories/TaskRepository.kt index e0640a1be..d7da7cf13 100644 --- a/wearos/src/main/java/com/habitrpg/wearos/habitica/data/repositories/TaskRepository.kt +++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/data/repositories/TaskRepository.kt @@ -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> = 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 { diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/TaskListActivity.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/TaskListActivity.kt index 904de10a7..07db4c8fc 100644 --- a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/TaskListActivity.kt +++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/TaskListActivity.kt @@ -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() { @@ -51,6 +43,10 @@ class TaskListActivity: BaseActivity scoreTask(it) } + viewModel.user.observe(this) { + + } + binding.addTaskButton.setOnClickListener { openTaskFormActivity() } } @@ -76,12 +72,7 @@ class TaskListActivity: BaseActivity } 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 } } } -} - -class ScrollAwayBehavior(context: Context, attrs: AttributeSet) : - CoordinatorLayout.Behavior(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() - } - } - } } \ No newline at end of file diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/TaskResultActivity.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/TaskResultActivity.kt new file mode 100644 index 000000000..7923b94ae --- /dev/null +++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/TaskResultActivity.kt @@ -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() { + 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() + 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() + 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) + } + } +} \ No newline at end of file diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewHolders/tasks/DailyViewHolder.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewHolders/tasks/DailyViewHolder.kt index d64576634..0d21e6dd0 100644 --- a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewHolders/tasks/DailyViewHolder.kt +++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewHolders/tasks/DailyViewHolder.kt @@ -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)) } } \ No newline at end of file diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewHolders/tasks/ToDoViewHolder.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewHolders/tasks/ToDoViewHolder.kt index cd00cc327..31f136b3b 100644 --- a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewHolders/tasks/ToDoViewHolder.kt +++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewHolders/tasks/ToDoViewHolder.kt @@ -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)) } } \ No newline at end of file diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewmodels/AvatarViewModel.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewmodels/AvatarViewModel.kt index 7079fe085..cd186e209 100644 --- a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewmodels/AvatarViewModel.kt +++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewmodels/AvatarViewModel.kt @@ -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 - - init { - user = userRepository.getUser().asLiveData() - } + var user = userRepository.getUser().asLiveData() } \ No newline at end of file diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewmodels/HabitDrectionViewModel.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewmodels/HabitDrectionViewModel.kt index e3236e0a5..093d35367 100644 --- a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewmodels/HabitDrectionViewModel.kt +++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewmodels/HabitDrectionViewModel.kt @@ -21,9 +21,11 @@ class HabitDrectionViewModel @Inject constructor( val taskID = savedStateHandle.get("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) } } } } diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewmodels/MainViewModel.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewmodels/MainViewModel.kt index 46a545873..b38f54a7a 100644 --- a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewmodels/MainViewModel.kt +++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewmodels/MainViewModel.kt @@ -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 + var user = userRepository.getUser().asLiveData() init { - user = userRepository.getUser().asLiveData() viewModelScope.launch(exceptionBuilder.userFacing(this)) { userRepository.retrieveUser() taskRepository.retrieveTasks() diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewmodels/TaskListViewModel.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewmodels/TaskListViewModel.kt index 697898af4..7e4a69c7f 100644 --- a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewmodels/TaskListViewModel.kt +++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewmodels/TaskListViewModel.kt @@ -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("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> - val taskType = TaskType.from(savedStateHandle.get("task_type")) - - init { - tasks = taskRepository.getTasks(taskType ?: TaskType.HABIT).asLiveData() - } } \ No newline at end of file diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewmodels/TaskResultViewModel.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewmodels/TaskResultViewModel.kt new file mode 100644 index 000000000..af1ffab3f --- /dev/null +++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewmodels/TaskResultViewModel.kt @@ -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("result") +} diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/views/TaskRewardChip.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/views/TaskRewardChip.kt new file mode 100644 index 000000000..99184f337 --- /dev/null +++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/views/TaskRewardChip.kt @@ -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 + } + } +} \ No newline at end of file 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 new file mode 100644 index 000000000..8e9033c65 --- /dev/null +++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/util/ScrollAwayBehavior.kt @@ -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(context: Context, attrs: AttributeSet) : + CoordinatorLayout.Behavior(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() + } + } + } +} \ No newline at end of file diff --git a/wearos/src/main/res/drawable-hdpi/experience.png b/wearos/src/main/res/drawable-hdpi/experience.png new file mode 100644 index 000000000..a0f4a06b7 Binary files /dev/null and b/wearos/src/main/res/drawable-hdpi/experience.png differ diff --git a/wearos/src/main/res/drawable-hdpi/magic.png b/wearos/src/main/res/drawable-hdpi/magic.png new file mode 100644 index 000000000..88a1f5607 Binary files /dev/null and b/wearos/src/main/res/drawable-hdpi/magic.png differ diff --git a/wearos/src/main/res/drawable-mdpi/experience.png b/wearos/src/main/res/drawable-mdpi/experience.png new file mode 100644 index 000000000..cd22d0e25 Binary files /dev/null and b/wearos/src/main/res/drawable-mdpi/experience.png differ diff --git a/wearos/src/main/res/drawable-mdpi/magic.png b/wearos/src/main/res/drawable-mdpi/magic.png new file mode 100644 index 000000000..e9cc12874 Binary files /dev/null and b/wearos/src/main/res/drawable-mdpi/magic.png differ diff --git a/wearos/src/main/res/drawable-xhdpi/experience.png b/wearos/src/main/res/drawable-xhdpi/experience.png new file mode 100644 index 000000000..2cb5dc1f2 Binary files /dev/null and b/wearos/src/main/res/drawable-xhdpi/experience.png differ diff --git a/wearos/src/main/res/drawable-xhdpi/magic.png b/wearos/src/main/res/drawable-xhdpi/magic.png new file mode 100644 index 000000000..3bb78d2af Binary files /dev/null and b/wearos/src/main/res/drawable-xhdpi/magic.png differ diff --git a/wearos/src/main/res/drawable-xxhdpi/experience.png b/wearos/src/main/res/drawable-xxhdpi/experience.png new file mode 100644 index 000000000..47d16b80f Binary files /dev/null and b/wearos/src/main/res/drawable-xxhdpi/experience.png differ diff --git a/wearos/src/main/res/drawable-xxhdpi/magic.png b/wearos/src/main/res/drawable-xxhdpi/magic.png new file mode 100644 index 000000000..aeec05d78 Binary files /dev/null and b/wearos/src/main/res/drawable-xxhdpi/magic.png differ diff --git a/wearos/src/main/res/drawable-xxxhdpi/experience.png b/wearos/src/main/res/drawable-xxxhdpi/experience.png new file mode 100644 index 000000000..a69d690d9 Binary files /dev/null and b/wearos/src/main/res/drawable-xxxhdpi/experience.png differ diff --git a/wearos/src/main/res/drawable-xxxhdpi/magic.png b/wearos/src/main/res/drawable-xxxhdpi/magic.png new file mode 100644 index 000000000..09645056c Binary files /dev/null and b/wearos/src/main/res/drawable-xxxhdpi/magic.png differ diff --git a/wearos/src/main/res/layout/activity_task_result.xml b/wearos/src/main/res/layout/activity_task_result.xml new file mode 100644 index 000000000..6d7e7b7ca --- /dev/null +++ b/wearos/src/main/res/layout/activity_task_result.xml @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file diff --git a/wearos/src/main/res/layout/activity_tasklist.xml b/wearos/src/main/res/layout/activity_tasklist.xml index 4f6206294..04a6733c4 100644 --- a/wearos/src/main/res/layout/activity_tasklist.xml +++ b/wearos/src/main/res/layout/activity_tasklist.xml @@ -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"/> \ No newline at end of file diff --git a/wearos/src/main/res/layout/task_reward_chip.xml b/wearos/src/main/res/layout/task_reward_chip.xml new file mode 100644 index 000000000..c6cb51cf7 --- /dev/null +++ b/wearos/src/main/res/layout/task_reward_chip.xml @@ -0,0 +1,24 @@ + + + + + + \ No newline at end of file diff --git a/wearos/src/main/res/layout/task_reward_drop.xml b/wearos/src/main/res/layout/task_reward_drop.xml new file mode 100644 index 000000000..260ba6949 --- /dev/null +++ b/wearos/src/main/res/layout/task_reward_drop.xml @@ -0,0 +1,25 @@ + + + + + + \ No newline at end of file diff --git a/wearos/src/main/res/values/strings.xml b/wearos/src/main/res/values/strings.xml index 4c236dd9d..5c3a60937 100644 --- a/wearos/src/main/res/values/strings.xml +++ b/wearos/src/main/res/values/strings.xml @@ -2,4 +2,9 @@ OK Syncing Account from Phone How did you do? + You found… + 1 Quest item + %d Quest items + %s and %s + some %s \ No newline at end of file