Refactor pets and mounts screens

This commit is contained in:
Phillip Thelen 2020-07-24 12:19:56 +02:00
parent d74feb0042
commit 9bc66ac90b
26 changed files with 509 additions and 522 deletions

View file

@ -43,20 +43,27 @@
android:paddingEnd="@dimen/spacing_large"
android:paddingBottom="@dimen/spacing_large">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/text_input_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/TaskFormTextInputLayoutAppearance">
style="@style/TaskFormTextInputLayoutAppearance"
app:boxStrokeColor="?attr/colorPrimaryDark"
android:alpha="0.75">
<androidx.appcompat.widget.AppCompatEditText
android:id="@+id/text_edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/task_title"
android:textColor="?attr/toolbarContentColor"
android:inputType="textCapSentences|textAutoCorrect"/>
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/notes_input_layout"
style="@style/TaskFormTextInputLayoutAppearance"
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
app:boxStrokeColor="?attr/colorPrimaryDark"
android:alpha="0.75">
<androidx.appcompat.widget.AppCompatEditText
android:id="@+id/notes_edit_text"
android:layout_width="match_parent"
@ -64,6 +71,7 @@
android:hint="@string/notes"
android:minLines="3"
android:gravity="top"
android:textColor="?attr/toolbarContentColor"
android:inputType="textCapSentences|textAutoCorrect|textMultiLine"/>
</com.google.android.material.textfield.TextInputLayout>
<TextView

View file

@ -3,8 +3,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="65dp"
android:paddingTop="16dp"
android:layout_height="55dp"
android:gravity="bottom">
<TextView
android:id="@+id/label"

View file

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.habitrpg.android.habitica.ui.helpers.RecyclerViewEmptySupport
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbarSize="3dp"
android:scrollbarThumbVertical="@color/scrollbarThumb"
android:scrollbars="vertical"
android:clipToPadding="false"
android:paddingStart="@dimen/spacing_medium"
android:paddingEnd="@dimen/spacing_medium"
android:background="@color/white"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/emptyView"
style="@style/EmptyView"
android:visibility="gone"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View file

@ -18,14 +18,16 @@
<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/imageView"
android:layout_width="64dp"
android:layout_height="60dp"
android:layout_width="81dp"
android:layout_height="0dp"
android:layout_weight="1"
android:maxHeight="99dp"
android:layout_gravity="center_horizontal"
app:actualImageScaleType="fitCenter" />
<TextView
android:layout_width="match_parent"
android:layout_height="16dp"
android:layout_height="18dp"
android:layout_gravity="center_horizontal"
android:id="@+id/titleTextView"
android:textSize="12sp"

View file

@ -9,8 +9,8 @@
android:padding="8dp">
<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/imageView"
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_width="65dp"
android:layout_height="65dp"
android:layout_gravity="center"
app:actualImageScaleType="fitCenter"/>
@ -25,23 +25,6 @@
android:layout_marginStart="7dp"
android:layout_marginEnd="7dp"
android:max="50" />
<LinearLayout
android:id="@+id/items_available_wrapper"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center">
<ImageView
android:id="@+id/egg_available_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/pet_status_egg"
android:layout_marginEnd="8dp"/>
<ImageView
android:id="@+id/potion_available_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/pet_status_potion" />
</LinearLayout>
<RelativeLayout
android:id="@+id/item_wrapper"
android:layout_width="86dp"
@ -66,4 +49,12 @@
android:layout_height="10dp"
android:src="@drawable/pet_checkmark"
android:layout_gravity="center" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:id="@+id/titleTextView"
android:textSize="12sp"
android:gravity="center"
style="@style/RowTitle" />
</LinearLayout>

View file

@ -18,15 +18,15 @@
<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/imageView"
android:layout_width="@dimen/pet_image_width"
android:layout_height="60dp"
android:layout_height="58dp"
android:layout_gravity="center_horizontal"
app:actualImageScaleType="fitCenter" />
<TextView
android:layout_width="match_parent"
android:layout_height="16dp"
android:layout_height="18dp"
android:layout_gravity="center_horizontal"
android:id="@+id/titleTextView"
android:textSize="13sp"
android:textSize="12sp"
android:gravity="center"
style="@style/RowTitle"/>
<TextView

View file

@ -9,7 +9,9 @@
<com.habitrpg.android.habitica.ui.views.NPCBannerView
android:id="@+id/npcBannerView"
android:layout_width="match_parent"
android:layout_height="@dimen/shop_scene_height"/>
android:layout_height="@dimen/shop_scene_height"
android:paddingStart="-8dp"
android:paddingEnd="-8dp"/>
<View
android:layout_width="match_parent"

View file

@ -9,6 +9,7 @@
<attr name="textColorSecondary" format="color" />
<attr name="textColorPrimaryDark" format="color" />
<attr name="barColor" format="color" />
<attr name="toolbarContentColor" format="color" />
<attr name="taskFormTint" format="color" />
<attr name="textColorSecondaryDark" format="color" />
<attr name="statsColor" format="color" />

View file

@ -23,7 +23,7 @@
<color name="red_50">#F74E52</color>
<color name="red_10">#F23035</color>
<color name="red_5">#BF262B</color>
<color name="red_1">#6C0406</color>
<color name="red_1">#6c0406</color>
<color name="orange_500">#ffc8a7</color>
<color name="orange_100">#FF944C</color>
@ -151,4 +151,9 @@
<color name="animalitem_all_eggs">#6ECDB2</color>
<color name="dark_brown">#794b00</color>
<color name="blue_1">#033f5e</color>
<color name="teal_1">#005158</color>
<color name="green_1">#005737</color>
<color name="yellow_1">#794b00</color>
<color name="orange_1">#7f3300</color>
</resources>

View file

@ -1015,7 +1015,7 @@
<string name="read_more">Read More</string>
<string name="purchase_amount_error">You are unable to buy that amount.</string>
<string name="still_questions">Still have a question?</string>
<string name="pet_ownership_fraction">%1$d/%2$d</string>
<string name="pet_ownership_fraction">%1$d / %2$d</string>
<string name="task_display">Task list display</string>
<string name="onboarding_tasks">Onboarding Tasks</string>
<string name="complete_for_gold"><![CDATA[Complete to earn <font color="#EE9109"><b>100 Gold</b></font>!]]></string>

View file

@ -48,6 +48,7 @@
<item name="android:navigationBarColor">@color/brand_50</item>
<item name="searchViewStyle">@style/SearchViewStyle</item>
<item name="toolbarContentColor">@color/white</item>
</style>
@ -65,7 +66,8 @@
<item name="android:textColorLink">@color/red_100</item>
<item name="textColorPrimaryDark">@color/red_500</item>
<item name="barColor">@color/red_5</item>
<item name="taskFormTint">@color/red_100</item>
<item name="taskFormTint">@color/red_50</item>
<item name="toolbarContentColor">@color/red_1</item>
</style>
<style name="MainAppTheme.Maroon">
@ -82,7 +84,7 @@
<item name="android:textColorLink">@color/maroon_100</item>
<item name="textColorPrimaryDark">@color/red_500</item>
<item name="barColor">@color/red_1</item>
<item name="taskFormTint">@color/maroon_100</item>
<item name="taskFormTint">@color/maroon_50</item>
</style>
<style name="MainAppTheme.Orange">
@ -99,7 +101,8 @@
<item name="android:textColorLink">@color/orange_100</item>
<item name="textColorPrimaryDark">@color/orange_500</item>
<item name="barColor">@color/orange_10</item>
<item name="taskFormTint">@color/orange_100</item>
<item name="taskFormTint">@color/orange_50</item>
<item name="toolbarContentColor">@color/orange_1</item>
</style>
<style name="MainAppTheme.Yellow">
@ -116,7 +119,8 @@
<item name="android:textColorLink">@color/yellow_100</item>
<item name="textColorPrimaryDark">@color/yellow_500</item>
<item name="barColor">@color/yellow_10</item>
<item name="taskFormTint">@color/yellow_100</item>
<item name="taskFormTint">@color/yellow_10</item>
<item name="toolbarContentColor">@color/yellow_1</item>
</style>
<style name="MainAppTheme.Green">
@ -133,7 +137,8 @@
<item name="android:textColorLink">@color/green_100</item>
<item name="textColorPrimaryDark">@color/green_500</item>
<item name="barColor">@color/green_10</item>
<item name="taskFormTint">@color/green_100</item>
<item name="taskFormTint">@color/green_50</item>
<item name="toolbarContentColor">@color/green_1</item>
</style>
<style name="MainAppTheme.Teal">
@ -150,7 +155,8 @@
<item name="android:textColorLink">@color/teal_100</item>
<item name="textColorPrimaryDark">@color/teal_500</item>
<item name="barColor">@color/teal_10</item>
<item name="taskFormTint">@color/teal_100</item>
<item name="taskFormTint">@color/teal_50</item>
<item name="toolbarContentColor">@color/teal_1</item>
</style>
<style name="MainAppTheme.Blue">
@ -167,7 +173,8 @@
<item name="android:textColorLink">@color/blue_100</item>
<item name="textColorPrimaryDark">@color/blue_500</item>
<item name="barColor">@color/blue_10</item>
<item name="taskFormTint">@color/blue_100</item>
<item name="taskFormTint">@color/blue_50</item>
<item name="toolbarContentColor">@color/blue_1</item>
</style>
<style name="BottomSheetTheme" parent="Theme.AppCompat.NoActionBar">
@ -256,8 +263,11 @@
<!-- used activity_main.xml -->
<style name="Toolbar" parent="Base.ThemeOverlay.AppCompat.ActionBar">
<item name="android:textColorPrimary">@color/white</item>
<item name="android:textColorPrimary">?attr/toolbarContentColor</item>
<item name="textColorSecondary">?attr/toolbarContentColor</item>
<item name="background">?attr/colorPrimaryDark</item>
<item name="actionMenuTextColor">?attr/toolbarContentColor</item>
<item name="android:actionMenuTextColor">?attr/toolbarContentColor</item>
</style>
<style name="HabitButton" parent="android:Widget.Button">
@ -617,6 +627,14 @@
<item name="android:textColor">@color/textColorLight</item>
<item name="android:textColorHint">@color/textColorLight</item>
<item name="colorControlNormal">@color/white</item>
<item name="hintTextAppearance">@style/TaskFormHintTextAppearance</item>
</style>
<style name="TaskFormHintTextAppearance">
<item name="colorPrimary">?attr/toolbarContentColor</item>
<item name="android:textSize">12sp</item>
<item name="android:fontFamily">@string/font_family_medium</item>
<item name="fontFamily">@string/font_family_medium</item>
</style>
<style name="TextInputLayoutAppearanceTheme">

View file

@ -4,6 +4,7 @@ import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.res.ColorStateList
import android.graphics.Typeface
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.os.Handler
@ -19,6 +20,7 @@ import androidx.core.content.ContextCompat
import androidx.core.view.children
import androidx.core.view.forEachIndexed
import androidx.core.widget.NestedScrollView
import com.google.android.material.textfield.TextInputLayout
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.components.UserComponent
import com.habitrpg.android.habitica.data.*
@ -60,7 +62,9 @@ class TaskFormActivity : BaseActivity() {
private val toolbar: Toolbar by bindView(R.id.toolbar)
private val scrollView: NestedScrollView by bindView(R.id.scroll_view)
private val upperTextWrapper: LinearLayout by bindView(R.id.upper_text_wrapper)
private val textInputLayout: TextInputLayout by bindView(R.id.text_input_layout)
private val textEditText: EditText by bindView(R.id.text_edit_text)
private val notesInputLayout: TextInputLayout by bindView(R.id.notes_input_layout)
private val notesEditText: EditText by bindView(R.id.notes_edit_text)
private val habitScoringButtons: HabitScoringButtonsView by bindView(R.id.habit_scoring_buttons)
private val checklistTitleView: TextView by bindView(R.id.checklist_title)
@ -176,6 +180,12 @@ class TaskFormActivity : BaseActivity() {
textEditText.addTextChangedListener(OnChangeTextWatcher { _, _, _, _ ->
checkCanSave()
})
textEditText.onFocusChangeListener = View.OnFocusChangeListener { view, isFocused ->
textInputLayout.alpha = if (isFocused) 1.0f else 0.75f
}
notesEditText.onFocusChangeListener = View.OnFocusChangeListener { view, isFocused ->
notesInputLayout.alpha = if (isFocused) 1.0f else 0.75f
}
statStrengthButton.setOnClickListener { selectedStat = Stats.STRENGTH }
statIntelligenceButton.setOnClickListener { selectedStat = Stats.INTELLIGENCE }
statConstitutionButton.setOnClickListener { selectedStat = Stats.CONSTITUTION }
@ -385,6 +395,11 @@ class TaskFormActivity : BaseActivity() {
button.background.setTint(if (isSelected) tintColor else ContextCompat.getColor(this, R.color.taskform_gray))
val textColorID = if (isSelected) R.color.white else R.color.gray_100
button.setTextColor(ContextCompat.getColor(this, textColorID))
if (isSelected) {
button.typeface = Typeface.create("sans-serif-medium", Typeface.NORMAL)
} else {
button.typeface = Typeface.create("sans-serif", Typeface.NORMAL)
}
}
private fun updateTagViewsColors() {

View file

@ -1,36 +1,18 @@
package com.habitrpg.android.habitica.ui.adapter.inventory
import android.content.Context
import android.content.res.Resources
import android.graphics.drawable.BitmapDrawable
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import com.facebook.drawee.view.SimpleDraweeView
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.extensions.inflate
import com.habitrpg.android.habitica.helpers.RxErrorHandler
import com.habitrpg.android.habitica.models.inventory.Mount
import com.habitrpg.android.habitica.models.inventory.Pet
import com.habitrpg.android.habitica.models.inventory.StableSection
import com.habitrpg.android.habitica.models.user.OwnedMount
import com.habitrpg.android.habitica.ui.helpers.DataBindingUtils
import com.habitrpg.android.habitica.ui.helpers.bindView
import com.habitrpg.android.habitica.ui.menu.BottomSheetMenu
import com.habitrpg.android.habitica.ui.menu.BottomSheetMenuItem
import com.habitrpg.android.habitica.ui.viewHolders.MountViewHolder
import com.habitrpg.android.habitica.ui.viewHolders.SectionViewHolder
import io.reactivex.BackpressureStrategy
import io.reactivex.Flowable
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.functions.Consumer
import io.reactivex.subjects.PublishSubject
import io.realm.OrderedRealmCollection
import io.realm.RealmRecyclerViewAdapter
class MountDetailRecyclerAdapter : androidx.recyclerview.widget.RecyclerView.Adapter<androidx.recyclerview.widget.RecyclerView.ViewHolder>() {
var itemType: String? = null
var context: Context? = null
private var ownedMounts: Map<String, OwnedMount>? = null
private val equipEvents = PublishSubject.create<String>()
@ -48,44 +30,18 @@ class MountDetailRecyclerAdapter : androidx.recyclerview.widget.RecyclerView.Ada
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): androidx.recyclerview.widget.RecyclerView.ViewHolder =
when (viewType) {
0 -> {
val view = parent.inflate(R.layout.shop_header)
StableRecyclerAdapter.StableHeaderViewHolder(view)
}
1 -> {
val view = parent.inflate(R.layout.customization_section_header)
SectionViewHolder(view)
}
else -> {
MountViewHolder(parent.inflate(R.layout.mount_overview_item))
}
1 -> SectionViewHolder(parent)
else -> MountViewHolder(parent, equipEvents)
}
override fun onBindViewHolder(holder: androidx.recyclerview.widget.RecyclerView.ViewHolder, position: Int) {
val obj = this.itemList[position]
when {
obj.javaClass == String::class.java -> {
(holder as? SectionViewHolder)?.bind(obj as? String ?: "")
}
else -> {
(obj as? Mount)?.let { (holder as? MountViewHolder)?.bind(it, ownedMounts?.get(it.key ?: "")) }
}
when (val obj = this.itemList[position]) {
is String -> (holder as? SectionViewHolder)?.bind(obj)
is Mount -> (holder as? MountViewHolder)?.bind(obj, ownedMounts?.get(obj.key ?: "")?.owned == true)
}
}
override fun getItemViewType(position: Int): Int {
val item = itemList[position]
return if (item.javaClass == String::class.java) {
1
}
else if (itemType == "pets") {
2
}
else {
3
}
}
override fun getItemViewType(position: Int): Int = if (itemList[position] is StableSection) 1 else 2
override fun getItemCount(): Int = itemList.size
@ -93,59 +49,4 @@ class MountDetailRecyclerAdapter : androidx.recyclerview.widget.RecyclerView.Ada
this.ownedMounts = ownedMounts
notifyDataSetChanged()
}
inner class MountViewHolder(itemView: View) : androidx.recyclerview.widget.RecyclerView.ViewHolder(itemView), View.OnClickListener {
var animal: Mount? = null
private var ownedMount: OwnedMount? = null
private val imageView: SimpleDraweeView by bindView(R.id.imageView)
private val titleView: TextView by bindView(R.id.titleTextView)
private val ownedTextView: TextView by bindView(R.id.ownedTextView)
var resources: Resources = itemView.resources
init {
itemView.setOnClickListener(this)
}
fun bind(item: Mount, ownedMount: OwnedMount?) {
animal = item
this.ownedMount = ownedMount
titleView.text = when {
item.color == "Veggie" -> context?.getString(R.string.garden)
item.type == "special" ->item.text
else -> item.color
}
ownedTextView.visibility = View.GONE
val imageName = "Mount_Icon_" + itemType + "-" + item.color
this.imageView.alpha = 1.0f
if (ownedMount?.owned != true) {
this.imageView.alpha = 0.1f
}
imageView.background = null
val owned = ownedMount?.owned ?: false
DataBindingUtils.loadImage(imageName) {
val drawable = BitmapDrawable(context?.resources, if (owned) it else it.extractAlpha())
Observable.just(drawable)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(Consumer {
imageView.background = drawable
}, RxErrorHandler.handleEmptyError())
}
}
override fun onClick(v: View) {
if (ownedMount?.owned != true) {
return
}
val menu = BottomSheetMenu(itemView.context)
menu.setTitle(animal?.text)
menu.addMenuItem(BottomSheetMenuItem(resources.getString(R.string.equip)))
menu.setSelectionRunnable {
animal?.let { equipEvents.onNext(it.key) }
}
menu.show()
}
}
}

View file

@ -1,43 +1,20 @@
package com.habitrpg.android.habitica.ui.adapter.inventory
import android.content.Context
import android.graphics.PorterDuff
import android.graphics.drawable.BitmapDrawable
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.ProgressBar
import androidx.recyclerview.widget.GridLayoutManager
import com.facebook.drawee.view.SimpleDraweeView
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.events.commands.FeedCommand
import com.habitrpg.android.habitica.extensions.inflate
import com.habitrpg.android.habitica.helpers.RxErrorHandler
import com.habitrpg.android.habitica.models.inventory.*
import com.habitrpg.android.habitica.models.user.OwnedItem
import com.habitrpg.android.habitica.models.user.OwnedMount
import com.habitrpg.android.habitica.models.user.OwnedPet
import com.habitrpg.android.habitica.ui.helpers.DataBindingUtils
import com.habitrpg.android.habitica.ui.helpers.bindView
import com.habitrpg.android.habitica.ui.menu.BottomSheetMenu
import com.habitrpg.android.habitica.ui.menu.BottomSheetMenuItem
import com.habitrpg.android.habitica.ui.viewHolders.PetViewHolder
import com.habitrpg.android.habitica.ui.viewHolders.SectionViewHolder
import com.habitrpg.android.habitica.ui.views.dialogs.PetSuggestHatchDialog
import io.reactivex.BackpressureStrategy
import io.reactivex.Flowable
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.functions.Consumer
import io.reactivex.subjects.PublishSubject
import io.realm.OrderedRealmCollection
import io.realm.RealmRecyclerViewAdapter
import io.realm.RealmResults
import org.greenrobot.eventbus.EventBus
class PetDetailRecyclerAdapter : androidx.recyclerview.widget.RecyclerView.Adapter<androidx.recyclerview.widget.RecyclerView.ViewHolder>() {
var itemType: String? = null
var context: Context? = null
private var existingMounts: RealmResults<Mount>? = null
private var ownedPets: Map<String, OwnedPet>? = null
private var ownedMounts: Map<String, OwnedMount>? = null
@ -58,46 +35,49 @@ class PetDetailRecyclerAdapter : androidx.recyclerview.widget.RecyclerView.Adapt
var animalIngredientsRetriever: ((Animal) -> Pair<Egg?, HatchingPotion?>)? = null
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): androidx.recyclerview.widget.RecyclerView.ViewHolder =
when (viewType) {
0 -> {
val view = parent.inflate(R.layout.shop_header)
StableRecyclerAdapter.StableHeaderViewHolder(view)
}
1 -> {
val view = parent.inflate(R.layout.customization_section_header)
SectionViewHolder(view)
}
else -> {
PetViewHolder(parent.inflate(R.layout.pet_detail_item))
}
private fun canRaiseToMount(pet: Pet): Boolean {
for (mount in existingMounts ?: emptyList<Mount>()) {
if (mount.key == pet.key) {
return !(ownedMounts?.get(mount.key)?.owned ?: false)
}
}
return false
}
private fun hasEgg(pet: Pet): Boolean {
return ownedItems?.get(pet.animal + "-eggs")?.numberOwned ?: 0 > 0
}
private fun hasPotion(pet: Pet): Boolean {
return ownedItems?.get(pet.color + "-hatchingPotions")?.numberOwned ?: 0 > 0
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): androidx.recyclerview.widget.RecyclerView.ViewHolder =
when (viewType) {
1 -> SectionViewHolder(parent)
else -> PetViewHolder(parent, equipEvents, animalIngredientsRetriever)
}
override fun onBindViewHolder(holder: androidx.recyclerview.widget.RecyclerView.ViewHolder, position: Int) {
val obj = this.itemList[position]
when {
obj.javaClass == String::class.java -> {
(holder as? SectionViewHolder)?.bind(obj as? String ?: "")
when (val obj = this.itemList[position]) {
is StableSection -> {
(holder as? SectionViewHolder)?.bind(obj)
}
else -> {
(obj as? Pet)?.let { (holder as? PetViewHolder)?.bind(it, ownedPets?.get(it.key ?: "")) }
is Pet -> {
(holder as? PetViewHolder)?.bind(obj,
ownedPets?.get(obj.key ?: "")?.trained ?: 0,
hasEgg(obj),
hasPotion(obj),
canRaiseToMount(obj),
ownsSaddles,
ownedItems?.get(obj.animal + "-eggs") != null,
ownedItems?.get(obj.color + "-hatchingPotions") != null,
ownedMounts?.containsKey(obj.key) == true
)
}
}
}
override fun getItemViewType(position: Int): Int {
val item = itemList[position]
return if (item.javaClass == String::class.java) {
1
}
else if (itemType == "pets") {
2
}
else {
3
}
}
override fun getItemViewType(position: Int): Int = if (itemList[position] is StableSection) 1 else 2
override fun getItemCount(): Int = itemList.size
@ -126,155 +106,4 @@ class PetDetailRecyclerAdapter : androidx.recyclerview.widget.RecyclerView.Adapt
this.ownsSaddles = ownsSaddles
notifyDataSetChanged()
}
inner class PetViewHolder(itemView: View) : androidx.recyclerview.widget.RecyclerView.ViewHolder(itemView), View.OnClickListener {
var animal: Pet? = null
var ownedPet: OwnedPet? = null
private val imageView: SimpleDraweeView by bindView(R.id.imageView)
private val trainedProgressbar: ProgressBar by bindView(R.id.trainedProgressBar)
private val availableWrapper: ViewGroup by bindView(R.id.items_available_wrapper)
private val eggAvailableView: ImageView by bindView(R.id.egg_available_view)
private val potionAvailableView: ImageView by bindView(R.id.potion_available_view)
private val itemWrapper: ViewGroup by bindView(R.id.item_wrapper)
private val eggView: SimpleDraweeView by bindView(R.id.egg_view)
private val hatchingPotionView: SimpleDraweeView by bindView(R.id.hatchingPotion_view)
private val checkMarkView: ImageView by bindView(R.id.checkmark_view)
private val isOwned: Boolean
get() = this.ownedPet?.trained ?: 0 > 0
private val canRaiseToMount: Boolean
get() {
for (mount in existingMounts ?: emptyList<Mount>()) {
if (mount.key == animal?.key) {
return !(ownedMounts?.get(mount.key)?.owned ?: false)
}
}
return false
}
private val hasEgg: Boolean
get() {
return ownedItems?.get(animal?.animal + "-eggs")?.numberOwned ?: 0 > 0
}
private val hasPotion: Boolean
get() {
return ownedItems?.get(animal?.color + "-hatchingPotions")?.numberOwned ?: 0 > 0
}
private val canHatch: Boolean
get() {
return hasEgg && hasPotion
}
init {
itemView.setOnClickListener(this)
}
fun bind(item: Pet, ownedPet: OwnedPet?) {
this.animal = item
this.ownedPet = ownedPet
this.imageView.alpha = 1.0f
imageView.visibility = View.VISIBLE
itemWrapper.visibility = View.GONE
checkMarkView.visibility = View.GONE
availableWrapper.visibility = View.GONE
val imageName = "social_Pet-$itemType-${item.color}"
itemView.setBackgroundResource(R.drawable.layout_rounded_bg_gray_700)
if (this.ownedPet?.trained ?: 0 > 0) {
if (this.canRaiseToMount) {
this.trainedProgressbar.visibility = View.VISIBLE
this.trainedProgressbar.progress = ownedPet?.trained ?: 0
} else {
this.trainedProgressbar.visibility = View.GONE
}
} else {
this.trainedProgressbar.visibility = View.GONE
this.imageView.alpha = 0.1f
if (canHatch) {
imageView.visibility = View.GONE
availableWrapper.visibility = View.GONE
itemWrapper.visibility = View.VISIBLE
checkMarkView.visibility = View.VISIBLE
itemView.setBackgroundResource(R.drawable.layout_rounded_bg_gray_700_brand_border)
DataBindingUtils.loadImage(eggView, "Pet_Egg_${item.animal}")
DataBindingUtils.loadImage(hatchingPotionView, "Pet_HatchingPotion_${item.color}")
}
}
if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.LOLLIPOP_MR1) {
trainedProgressbar.progressBackgroundTintMode = PorterDuff.Mode.SRC_OVER
}
imageView.background = null
val trained = ownedPet?.trained ?: 0
DataBindingUtils.loadImage(imageName) {
val resources = context?.resources ?: return@loadImage
val drawable = BitmapDrawable(resources, if (trained == 0) it.extractAlpha() else it)
Observable.just(drawable)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(Consumer {
imageView.background = drawable
}, RxErrorHandler.handleEmptyError())
}
}
override fun onClick(v: View) {
if (!this.isOwned) {
showRequirementsDialog()
return
}
val context = context ?: return
val menu = BottomSheetMenu(context)
menu.setTitle(animal?.text)
menu.addMenuItem(BottomSheetMenuItem(itemView.resources.getString(R.string.equip)))
if (canRaiseToMount) {
menu.addMenuItem(BottomSheetMenuItem(itemView.resources.getString(R.string.feed)))
if (ownsSaddles) {
menu.addMenuItem(BottomSheetMenuItem(itemView.resources.getString(R.string.use_saddle)))
}
}
menu.setSelectionRunnable { index ->
when (index) {
0 -> {
animal?.let {
equipEvents.onNext(it.key)
}
}
1 -> {
val event = FeedCommand()
event.usingPet = animal
EventBus.getDefault().post(event)
}
2 -> {
val event = FeedCommand()
event.usingPet = animal
val saddle = Food()
saddle.key = "Saddle"
event.usingFood = saddle
EventBus.getDefault().post(event)
}
}
}
menu.show()
}
private fun showRequirementsDialog() {
val context = context ?: return
val dialog = PetSuggestHatchDialog(context)
animal?.let {
val ingredients = animalIngredientsRetriever?.invoke(it)
dialog.configure(it,
ingredients?.first,
ingredients?.second,
hasEgg,
hasPotion,
ownedItems?.get(animal?.animal + "-eggs") != null,
ownedItems?.get(animal?.color + "-hatchingPotions") != null,
ownedMounts?.containsKey(it.key) == true)
}
dialog.show()
}
}
}

View file

@ -84,18 +84,9 @@ class ShopRecyclerAdapter(private val configManager: AppConfigManager) : android
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): androidx.recyclerview.widget.RecyclerView.ViewHolder =
when (viewType) {
0 -> {
val view = parent.inflate(R.layout.shop_header)
ShopHeaderViewHolder(view)
}
1 -> {
val view = parent.inflate(R.layout.shop_section_header)
SectionViewHolder(view)
}
2 -> {
val view = parent.inflate(emptyViewResource)
EmptyStateViewHolder(view)
}
0 -> ShopHeaderViewHolder(parent)
1 -> SectionViewHolder(parent)
2 -> EmptyStateViewHolder(parent.inflate(emptyViewResource))
else -> {
val view = parent.inflate(R.layout.row_shopitem)
val viewHolder = ShopItemViewHolder(view)
@ -221,7 +212,7 @@ class ShopRecyclerAdapter(private val configManager: AppConfigManager) : android
this.notifyDataSetChanged()
}
internal class ShopHeaderViewHolder(itemView: View) : androidx.recyclerview.widget.RecyclerView.ViewHolder(itemView) {
internal class ShopHeaderViewHolder(parent: ViewGroup) : androidx.recyclerview.widget.RecyclerView.ViewHolder(parent.inflate(R.layout.shop_header)) {
private val descriptionView: TextView by bindView(itemView, R.id.descriptionView)
private val npcBannerView: NPCBannerView by bindView(itemView, R.id.npcBannerView)

View file

@ -1,43 +1,31 @@
package com.habitrpg.android.habitica.ui.adapter.inventory
import android.content.Context
import android.graphics.Color
import android.graphics.drawable.BitmapDrawable
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.facebook.drawee.view.SimpleDraweeView
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.events.commands.FeedCommand
import com.habitrpg.android.habitica.databinding.ShopHeaderBinding
import com.habitrpg.android.habitica.extensions.inflate
import com.habitrpg.android.habitica.helpers.MainNavigationController
import com.habitrpg.android.habitica.helpers.RxErrorHandler
import com.habitrpg.android.habitica.models.inventory.Animal
import com.habitrpg.android.habitica.models.inventory.StableSection
import com.habitrpg.android.habitica.ui.activities.MainActivity
import com.habitrpg.android.habitica.models.inventory.*
import com.habitrpg.android.habitica.ui.fragments.inventory.stable.StableFragmentDirections
import com.habitrpg.android.habitica.ui.helpers.DataBindingUtils
import com.habitrpg.android.habitica.ui.helpers.bindView
import com.habitrpg.android.habitica.ui.menu.BottomSheetMenu
import com.habitrpg.android.habitica.ui.menu.BottomSheetMenuItem
import com.habitrpg.android.habitica.ui.helpers.loadImage
import com.habitrpg.android.habitica.ui.viewHolders.MountViewHolder
import com.habitrpg.android.habitica.ui.viewHolders.PetViewHolder
import com.habitrpg.android.habitica.ui.viewHolders.SectionViewHolder
import com.habitrpg.android.habitica.ui.views.NPCBannerView
import io.reactivex.BackpressureStrategy
import io.reactivex.Flowable
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.functions.Consumer
import io.reactivex.subjects.PublishSubject
import org.greenrobot.eventbus.EventBus
class StableRecyclerAdapter : androidx.recyclerview.widget.RecyclerView.Adapter<androidx.recyclerview.widget.RecyclerView.ViewHolder>() {
class StableRecyclerAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
var animalIngredientsRetriever: ((Animal) -> Pair<Egg?, HatchingPotion?>)? = null
var itemType: String? = null
var context: Context? = null
var activity: MainActivity? = null
private val equipEvents = PublishSubject.create<String>()
fun getEquipFlowable(): Flowable<String> {
@ -51,80 +39,84 @@ class StableRecyclerAdapter : androidx.recyclerview.widget.RecyclerView.Adapter<
this.notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): androidx.recyclerview.widget.RecyclerView.ViewHolder =
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder =
when (viewType) {
0 -> {
val view = parent.inflate(R.layout.shop_header)
StableHeaderViewHolder(view)
}
1 -> {
val view = parent.inflate(R.layout.customization_section_header)
SectionViewHolder(view)
}
2 -> {
val view = parent.inflate(R.layout.pet_overview_item)
StableViewHolder(view)
}
else -> {
val view = parent.inflate(R.layout.mount_overview_item)
StableViewHolder(view)
}
1 -> SectionViewHolder(parent)
4 -> StableViewHolder(parent.inflate(R.layout.pet_overview_item))
5 -> StableViewHolder(parent.inflate(R.layout.mount_overview_item))
2 -> PetViewHolder(parent, equipEvents, animalIngredientsRetriever)
3 -> MountViewHolder(parent, equipEvents)
else -> StableHeaderViewHolder(parent)
}
override fun onBindViewHolder(holder: androidx.recyclerview.widget.RecyclerView.ViewHolder, position: Int) {
val obj = this.itemList[position]
when {
obj == "header" -> {
(holder as? StableHeaderViewHolder)?.bind()
}
obj.javaClass == StableSection::class.java -> {
if (obj == "Standard") {
val params = holder.itemView.layoutParams as GridLayoutManager.LayoutParams
params.height = 135
holder.itemView.layoutParams = params
}
(holder as? SectionViewHolder)?.bind(obj as StableSection)
}
else -> {
(obj as? Animal)?.let { (holder as? StableViewHolder)?.bind(it) }
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (val item = this.itemList[position]) {
"header" -> (holder as? StableHeaderViewHolder)?.bind()
is StableSection -> (holder as? SectionViewHolder)?.bind(item)
is Animal -> {
val isIndividualAnimal = item.type == "special" || item.type == "wacky"
if (isIndividualAnimal) {
if (item is Pet) {
(holder as? PetViewHolder)?.bind(item,
item.numberOwned,
canRaiseToMount = false,
hasEgg = false,
hasPotion = false,
ownsSaddles = false,
hasUnlockedEgg = false,
hasUnlockedPotion = false,
hasMount = false)
} else if (item is Mount) {
(holder as? MountViewHolder)?.bind(item, item.numberOwned > 0)
}
return
}
(holder as? StableViewHolder)?.bind(item)
}
}
}
override fun getItemViewType(position: Int): Int {
var item = itemList[position]
val item = itemList[position]
return if (item == "header") {
0
}
else if (item.javaClass == StableSection::class.java) {
} else if (item is StableSection) {
1
}
else if (itemType == "pets") {
2
}
else {
3
} else if (item is Animal) {
val isIndividualAnimal = item.type == "special" || item.type == "wacky"
if (isIndividualAnimal) {
if (itemType == "pets") {
2
} else {
3
}
} else {
if (itemType == "pets") {
4
} else {
5
}
}
} else {
0
}
}
override fun getItemCount(): Int = itemList.size
internal class StableHeaderViewHolder(itemView: View) : androidx.recyclerview.widget.RecyclerView.ViewHolder(itemView) {
internal class StableHeaderViewHolder(parent: ViewGroup) : RecyclerView.ViewHolder(parent.inflate(R.layout.shop_header)) {
private val npcBannerView: NPCBannerView by bindView(itemView, R.id.npcBannerView)
private val namePlate: TextView by bindView(itemView, R.id.namePlate)
private val descriptionView: TextView by bindView(itemView, R.id.descriptionView)
private var binding: ShopHeaderBinding = ShopHeaderBinding.bind(itemView)
fun bind() {
npcBannerView.identifier = "stable"
namePlate.setText(R.string.stable_owner)
descriptionView.visibility = View.GONE
binding.npcBannerView.identifier = "stable"
binding.namePlate.setText(R.string.stable_owner)
binding.descriptionView.visibility = View.GONE
}
}
internal inner class StableViewHolder(itemView: View) : androidx.recyclerview.widget.RecyclerView.ViewHolder(itemView), View.OnClickListener {
internal inner class StableViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), View.OnClickListener {
private var animal: Animal? = null
private val imageView: SimpleDraweeView by bindView(itemView, R.id.imageView)
@ -137,82 +129,38 @@ class StableRecyclerAdapter : androidx.recyclerview.widget.RecyclerView.Adapter<
fun bind(item: Animal) {
this.animal = item
val isIndividualAnimal = item.type == "special" || animal?.type == "wacky"
titleView.text = if (isIndividualAnimal) {
item.text
} else {
item.animal
}
val context = itemView.context
titleView.text = item.animal
ownedTextView.visibility = View.VISIBLE
this.imageView.alpha = 1.0f
this.titleView.alpha = 1.0f
this.ownedTextView.alpha = 1.0f
val imageName = if (itemType == "pets") {
if (isIndividualAnimal) {
"social_Pet-" + animal?.key
} else {
"Pet_Egg_" + item.animal
}
"Pet_Egg_" + item.animal
} else {
"Mount_Icon_" + item.key
}
context?.let {
val owned = item.numberOwned
val totalNum = item.totalNumber
this.ownedTextView.text = context.getString(R.string.pet_ownership_fraction, item.numberOwned, item.totalNumber)
this.ownedTextView.background = context.getDrawable(R.drawable.layout_rounded_bg_shopitem_price)
this.ownedTextView.text = context?.getString(R.string.pet_ownership_fraction, owned, totalNum)
this.ownedTextView.background = context?.getDrawable(R.drawable.layout_rounded_bg_shopitem_price)
this.ownedTextView.setTextColor(ContextCompat.getColor(context, R.color.gray_200))
this.ownedTextView.setTextColor(ContextCompat.getColor(it, R.color.gray_200) )
ownedTextView.visibility = View.VISIBLE
imageView.loadImage(imageName)
ownedTextView.visibility = if (isIndividualAnimal) View.GONE else View.VISIBLE
imageView.background = null
val numberOwned = item.numberOwned == 0
DataBindingUtils.loadImage(imageName) {bitmap ->
val drawable = if (isIndividualAnimal) {
BitmapDrawable(context?.resources, if (numberOwned) bitmap.extractAlpha() else bitmap)
} else {
BitmapDrawable(context?.resources, bitmap)
}
Observable.just(drawable)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(Consumer {
imageView.background = drawable
}, RxErrorHandler.handleEmptyError())
}
if (item.numberOwned <= 0) {
this.imageView.alpha = 0.2f
this.titleView.alpha = 0.2f
this.ownedTextView.alpha = 0.2f
}
val alpha = if (item.numberOwned <= 0) 0.2f else 1.0f
this.imageView.alpha = alpha
this.titleView.alpha = alpha
this.ownedTextView.alpha = alpha
if (item.numberOwned == item.totalNumber) {
this.ownedTextView.background = context?.getDrawable(R.drawable.layout_rounded_bg_animalitem_complete)
this.ownedTextView.setTextColor(ContextCompat.getColor(it, R.color.white))
}
if (item.numberOwned == item.totalNumber) {
this.ownedTextView.background = context.getDrawable(R.drawable.layout_rounded_bg_animalitem_complete)
this.ownedTextView.setTextColor(ContextCompat.getColor(context, R.color.white))
}
}
override fun onClick(v: View) {
val animal = this.animal
if (animal != null) {
if (animal.type == "special" || animal.type == "wacky") {
if (animal.numberOwned == 0) return
val context = context ?: return
val menu = BottomSheetMenu(context)
menu.setTitle(animal.text)
menu.addMenuItem(BottomSheetMenuItem(itemView.resources.getString(R.string.equip)))
menu.setSelectionRunnable {
animal.let {
equipEvents.onNext(it.key)
}
}
menu.show()
return
}
val color = if (animal.type == "special") animal.color else null
if (animal.numberOwned > 0) {
if (itemType == "pets") {

View file

@ -12,6 +12,7 @@ import com.habitrpg.android.habitica.extensions.getTranslatedType
import com.habitrpg.android.habitica.helpers.RxErrorHandler
import com.habitrpg.android.habitica.models.inventory.Mount
import com.habitrpg.android.habitica.models.inventory.Pet
import com.habitrpg.android.habitica.models.inventory.StableSection
import com.habitrpg.android.habitica.models.user.OwnedMount
import com.habitrpg.android.habitica.ui.adapter.inventory.MountDetailRecyclerAdapter
import com.habitrpg.android.habitica.ui.fragments.BaseMainFragment
@ -77,8 +78,6 @@ class MountDetailRecyclerFragment : BaseMainFragment() {
adapter = recyclerView.adapter as? MountDetailRecyclerAdapter
if (adapter == null) {
adapter = MountDetailRecyclerAdapter()
adapter?.itemType = this.animalType
adapter?.context = context
recyclerView.adapter = adapter
recyclerView.itemAnimator = SafeDefaultItemAnimator()
this.loadItems()
@ -103,7 +102,7 @@ class MountDetailRecyclerFragment : BaseMainFragment() {
private fun setGridSpanCount(width: Int) {
var spanCount = 0
context?.resources?.let { resources
val itemWidth: Float = resources.getDimension(R.dimen.pet_width)
val itemWidth: Float = resources.getDimension(R.dimen.mount_width)
spanCount = (width / itemWidth).toInt()
}
@ -130,7 +129,7 @@ class MountDetailRecyclerFragment : BaseMainFragment() {
for (mount in it) {
if (mount.type == "wacky" || mount.type == "special") continue
if (mount.type != lastMount?.type) {
items.add(mount.getTranslatedType(context))
items.add(StableSection(mount.type, mount.getTranslatedType(context)))
}
items.add(mount)
lastMount = mount

View file

@ -10,10 +10,7 @@ import com.habitrpg.android.habitica.data.InventoryRepository
import com.habitrpg.android.habitica.events.commands.FeedCommand
import com.habitrpg.android.habitica.extensions.getTranslatedType
import com.habitrpg.android.habitica.helpers.RxErrorHandler
import com.habitrpg.android.habitica.models.inventory.Egg
import com.habitrpg.android.habitica.models.inventory.HatchingPotion
import com.habitrpg.android.habitica.models.inventory.Mount
import com.habitrpg.android.habitica.models.inventory.Pet
import com.habitrpg.android.habitica.models.inventory.*
import com.habitrpg.android.habitica.models.user.Items
import com.habitrpg.android.habitica.models.user.OwnedMount
import com.habitrpg.android.habitica.models.user.OwnedPet
@ -87,9 +84,11 @@ class PetDetailRecyclerFragment : BaseMainFragment() {
}
recyclerView.layoutManager = layoutManager
recyclerView.addItemDecoration(MarginDecoration(getActivity()))
adapter.context = this.getActivity()
adapter.itemType = this.animalType
adapter.animalIngredientsRetriever = {
val egg = inventoryRepository.getItems(Egg::class.java, arrayOf(it.animal), null).firstElement().blockingGet().firstOrNull()
val potion = inventoryRepository.getItems(HatchingPotion::class.java, arrayOf(it.color), null).firstElement().blockingGet().firstOrNull()
Pair(egg as? Egg, potion as? HatchingPotion)
}
recyclerView.adapter = adapter
recyclerView.itemAnimator = SafeDefaultItemAnimator()
this.loadItems()
@ -97,11 +96,7 @@ class PetDetailRecyclerFragment : BaseMainFragment() {
compositeSubscription.add(adapter.getEquipFlowable()
.flatMap<Items> { key -> inventoryRepository.equip(user, "pet", key) }
.subscribe(Consumer { }, RxErrorHandler.handleEmptyError()))
adapter.animalIngredientsRetriever = {
val egg = inventoryRepository.getItems(Egg::class.java, arrayOf(it.animal), null).firstElement().blockingGet().firstOrNull()
val potion = inventoryRepository.getItems(HatchingPotion::class.java, arrayOf(it.color), null).firstElement().blockingGet().firstOrNull()
Pair(egg as? Egg, potion as? HatchingPotion)
}
view.post { setGridSpanCount(view.width) }
}
@ -149,7 +144,7 @@ class PetDetailRecyclerFragment : BaseMainFragment() {
for (pet in it) {
if (pet.type == "wacky" || pet.type == "special") continue
if (pet.type != lastPet?.type) {
items.add(pet.getTranslatedType(context))
items.add(StableSection(pet.type, pet.getTranslatedType(context)))
}
items.add(pet)
lastPet = pet

View file

@ -12,6 +12,8 @@ import com.habitrpg.android.habitica.extensions.getTranslatedType
import com.habitrpg.android.habitica.extensions.inflate
import com.habitrpg.android.habitica.helpers.RxErrorHandler
import com.habitrpg.android.habitica.models.inventory.Animal
import com.habitrpg.android.habitica.models.inventory.Egg
import com.habitrpg.android.habitica.models.inventory.HatchingPotion
import com.habitrpg.android.habitica.models.inventory.StableSection
import com.habitrpg.android.habitica.models.user.*
import com.habitrpg.android.habitica.ui.activities.MainActivity
@ -45,7 +47,7 @@ class StableRecyclerFragment : BaseFragment() {
this.itemType = savedInstanceState.getString(ITEM_TYPE_KEY, "")
}
return container?.inflate(R.layout.fragment_recyclerview)
return container?.inflate(R.layout.fragment_recyclerview_stable)
}
override fun onDestroy() {
@ -84,9 +86,12 @@ class StableRecyclerFragment : BaseFragment() {
adapter = recyclerView?.adapter as? StableRecyclerAdapter
if (adapter == null) {
adapter = StableRecyclerAdapter()
adapter?.activity = this.activity as? MainActivity
adapter?.animalIngredientsRetriever = {
val egg = inventoryRepository.getItems(Egg::class.java, arrayOf(it.animal), null).firstElement().blockingGet().firstOrNull()
val potion = inventoryRepository.getItems(HatchingPotion::class.java, arrayOf(it.color), null).firstElement().blockingGet().firstOrNull()
Pair(egg as? Egg, potion as? HatchingPotion)
}
adapter?.itemType = this.itemType
adapter?.context = context
recyclerView?.adapter = adapter
recyclerView?.itemAnimator = SafeDefaultItemAnimator()
@ -110,8 +115,8 @@ class StableRecyclerFragment : BaseFragment() {
private fun setGridSpanCount(width: Int) {
var spanCount = 0
if (context != null && context?.resources != null) {
var animal_width = if (itemType == "pets") R.dimen.pet_width else R.dimen.mount_width
val itemWidth: Float = context?.resources?.getDimension(animal_width) ?: 0.toFloat()
val animalWidth = if (itemType == "pets") R.dimen.pet_width else R.dimen.mount_width
val itemWidth: Float = context?.resources?.getDimension(animalWidth) ?: 0.toFloat()
spanCount = (width / itemWidth).toInt()
}

View file

@ -0,0 +1,68 @@
package com.habitrpg.android.habitica.ui.viewHolders
import android.content.res.Resources
import android.graphics.drawable.BitmapDrawable
import android.view.View
import android.view.ViewGroup
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.databinding.MountOverviewItemBinding
import com.habitrpg.android.habitica.extensions.inflate
import com.habitrpg.android.habitica.helpers.RxErrorHandler
import com.habitrpg.android.habitica.models.inventory.Mount
import com.habitrpg.android.habitica.ui.helpers.DataBindingUtils
import com.habitrpg.android.habitica.ui.menu.BottomSheetMenu
import com.habitrpg.android.habitica.ui.menu.BottomSheetMenuItem
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.functions.Consumer
import io.reactivex.subjects.PublishSubject
class MountViewHolder(parent: ViewGroup, private val equipEvents: PublishSubject<String>) : androidx.recyclerview.widget.RecyclerView.ViewHolder(parent.inflate(R.layout.mount_overview_item)), View.OnClickListener {
private var binding: MountOverviewItemBinding = MountOverviewItemBinding.bind(itemView)
private var owned: Boolean = false
var animal: Mount? = null
var resources: Resources = itemView.resources
init {
itemView.setOnClickListener(this)
}
fun bind(item: Mount, owned: Boolean) {
animal = item
this.owned = owned
if (item.type == "special" || item.type == "wacky") {
binding.titleTextView.text = item.text
} else {
binding.titleTextView.visibility = View.GONE
}
binding.ownedTextView.visibility = View.GONE
val imageName = "Mount_Icon_" + item.animal + "-" + item.color
binding.imageView.alpha = 1.0f
if (!owned) {
binding.imageView.alpha = 0.2f
}
binding.imageView.background = null
DataBindingUtils.loadImage(imageName) {
val drawable = BitmapDrawable(itemView.context.resources, if (owned) it else it.extractAlpha())
Observable.just(drawable)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(Consumer {
binding.imageView.background = drawable
}, RxErrorHandler.handleEmptyError())
}
}
override fun onClick(v: View) {
if (!owned) {
return
}
val menu = BottomSheetMenu(itemView.context)
menu.setTitle(animal?.text)
menu.addMenuItem(BottomSheetMenuItem(resources.getString(R.string.equip)))
menu.setSelectionRunnable {
animal?.let { equipEvents.onNext(it.key) }
}
menu.show()
}
}

View file

@ -0,0 +1,168 @@
package com.habitrpg.android.habitica.ui.viewHolders
import android.graphics.PorterDuff
import android.graphics.drawable.BitmapDrawable
import android.view.View
import android.view.ViewGroup
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.databinding.PetDetailItemBinding
import com.habitrpg.android.habitica.events.commands.FeedCommand
import com.habitrpg.android.habitica.extensions.inflate
import com.habitrpg.android.habitica.helpers.RxErrorHandler
import com.habitrpg.android.habitica.models.inventory.*
import com.habitrpg.android.habitica.ui.helpers.DataBindingUtils
import com.habitrpg.android.habitica.ui.menu.BottomSheetMenu
import com.habitrpg.android.habitica.ui.menu.BottomSheetMenuItem
import com.habitrpg.android.habitica.ui.views.dialogs.PetSuggestHatchDialog
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.functions.Consumer
import io.reactivex.subjects.PublishSubject
import org.greenrobot.eventbus.EventBus
class PetViewHolder(parent: ViewGroup, private val equipEvents: PublishSubject<String>, private val animalIngredientsRetriever: ((Animal) -> Pair<Egg?, HatchingPotion?>)?) : androidx.recyclerview.widget.RecyclerView.ViewHolder(parent.inflate(R.layout.pet_detail_item)), View.OnClickListener {
private var hasMount: Boolean = false
private var hasUnlockedPotion: Boolean = false
private var hasUnlockedEgg: Boolean = false
private var hasEgg: Boolean = false
private var hasPotion: Boolean = false
private var ownsSaddles = false
private var animal: Pet? = null
private var binding: PetDetailItemBinding = PetDetailItemBinding.bind(itemView)
private var isOwned: Boolean = false
private var canRaiseToMount: Boolean = false
private val canHatch: Boolean
get() = hasEgg && hasPotion
init {
itemView.setOnClickListener(this)
}
fun bind(item: Pet,
trained: Int,
canRaiseToMount: Boolean,
hasEgg: Boolean,
hasPotion: Boolean,
ownsSaddles: Boolean,
hasUnlockedEgg: Boolean,
hasUnlockedPotion: Boolean,
hasMount: Boolean) {
this.animal = item
isOwned = trained > 0
binding.imageView.alpha = 1.0f
this.canRaiseToMount = canRaiseToMount
this.hasEgg = hasEgg
this.hasPotion = hasPotion
this.ownsSaddles = ownsSaddles
this.hasUnlockedEgg = hasUnlockedEgg
this.hasUnlockedPotion = hasUnlockedPotion
this.hasMount = hasMount
binding.imageView.visibility = View.VISIBLE
binding.itemWrapper.visibility = View.GONE
binding.checkmarkView.visibility = View.GONE
if (item.type == "special" || item.type == "wacky") {
binding.titleTextView.text = item.text
binding.titleTextView.visibility =View.VISIBLE
} else {
binding.titleTextView.visibility = View.GONE
}
val imageName = "social_Pet-${item.animal}-${item.color}"
itemView.setBackgroundResource(R.drawable.layout_rounded_bg_gray_700)
if (trained > 0) {
if (this.canRaiseToMount) {
binding.trainedProgressBar.visibility = View.VISIBLE
binding.trainedProgressBar.progress = trained
} else {
binding.trainedProgressBar.visibility = View.GONE
}
} else {
binding.trainedProgressBar.visibility = View.GONE
binding.imageView.alpha = 0.2f
if (canHatch) {
binding.imageView.visibility = View.GONE
binding.itemWrapper.visibility = View.VISIBLE
binding.checkmarkView.visibility = View.VISIBLE
itemView.setBackgroundResource(R.drawable.layout_rounded_bg_gray_700_brand_border)
DataBindingUtils.loadImage(binding.eggView, "Pet_Egg_${item.animal}")
DataBindingUtils.loadImage(binding.hatchingPotionView, "Pet_HatchingPotion_${item.color}")
}
}
if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.LOLLIPOP_MR1) {
binding.trainedProgressBar.progressBackgroundTintMode = PorterDuff.Mode.SRC_OVER
}
binding.imageView.background = null
DataBindingUtils.loadImage(imageName) {
val resources = itemView.context.resources ?: return@loadImage
val drawable = BitmapDrawable(resources, if (trained == 0) it.extractAlpha() else it)
Observable.just(drawable)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(Consumer {
binding.imageView.background = drawable
}, RxErrorHandler.handleEmptyError())
}
}
override fun onClick(v: View) {
if (!isOwned) {
showRequirementsDialog()
return
}
val context = itemView.context
val menu = BottomSheetMenu(context)
menu.setTitle(animal?.text)
menu.addMenuItem(BottomSheetMenuItem(itemView.resources.getString(R.string.equip)))
if (canRaiseToMount) {
menu.addMenuItem(BottomSheetMenuItem(itemView.resources.getString(R.string.feed)))
if (ownsSaddles) {
menu.addMenuItem(BottomSheetMenuItem(itemView.resources.getString(R.string.use_saddle)))
}
}
menu.setSelectionRunnable { index ->
when (index) {
0 -> {
animal?.let {
equipEvents.onNext(it.key)
}
}
1 -> {
val event = FeedCommand()
event.usingPet = animal
EventBus.getDefault().post(event)
}
2 -> {
val event = FeedCommand()
event.usingPet = animal
val saddle = Food()
saddle.key = "Saddle"
event.usingFood = saddle
EventBus.getDefault().post(event)
}
}
}
menu.show()
}
private fun showRequirementsDialog() {
val context = itemView.context
val dialog = PetSuggestHatchDialog(context)
animal?.let {
val ingredients = animalIngredientsRetriever?.invoke(it)
dialog.configure(it,
ingredients?.first,
ingredients?.second,
hasEgg,
hasPotion,
hasUnlockedEgg,
hasUnlockedPotion,
hasMount)
}
dialog.show()
}
}

View file

@ -2,12 +2,14 @@ package com.habitrpg.android.habitica.ui.viewHolders
import android.content.Context
import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.ArrayAdapter
import android.widget.Spinner
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.extensions.inflate
import com.habitrpg.android.habitica.models.inventory.StableSection
import com.habitrpg.android.habitica.ui.helpers.bindView
@ -21,6 +23,8 @@ class SectionViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var spinnerSelectionChanged: (() -> Unit)? = null
constructor(parent: ViewGroup) : this(parent.inflate(R.layout.customization_section_header))
init {
itemView.findViewById<View?>(R.id.purchaseSetButton)?.visibility = View.GONE
selectionSpinner?.onItemSelectedListener = object: AdapterView.OnItemSelectedListener {
@ -50,7 +54,7 @@ class SectionViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
} else {
countPill?.visibility = View.VISIBLE
}
countPill?.text = "${section.ownedCount} / ${section.totalCount}"
countPill?.text = itemView.context.getString(R.string.pet_ownership_fraction, section.ownedCount, section.totalCount)
}
var spinnerAdapter: ArrayAdapter<CharSequence>? = null

View file

@ -1,6 +1,7 @@
package com.habitrpg.android.habitica.ui.views.tasks.form
import android.content.Context
import android.graphics.Typeface
import android.util.AttributeSet
import android.view.Gravity
import android.view.View
@ -66,9 +67,11 @@ class HabitResetStreakButtons @JvmOverloads constructor(
if (isActive) {
button.background.setTint(tintColor)
button.setTextColor(ContextCompat.getColor(context, R.color.white))
button.typeface = Typeface.create("sans-serif-medium", Typeface.NORMAL)
} else {
button.background.setTint(ContextCompat.getColor(context, R.color.taskform_gray))
button.setTextColor(ContextCompat.getColor(context, R.color.gray_100))
button.typeface = Typeface.create("sans-serif", Typeface.NORMAL)
}
button.setOnClickListener {
selectedResetOption = resetOption

View file

@ -1,6 +1,7 @@
package com.habitrpg.android.habitica.ui.views.tasks.form
import android.content.Context
import android.graphics.Typeface
import android.util.AttributeSet
import android.view.Gravity
import android.view.View
@ -36,9 +37,11 @@ class HabitScoringButtonsView @JvmOverloads constructor(
if (value) {
positiveTextView.setTextColor(tintColor)
positiveView.contentDescription = toContentDescription(R.string.positive_habit_form, R.string.on)
positiveTextView.typeface = Typeface.create("sans-serif-medium", Typeface.NORMAL)
} else {
positiveTextView.setTextColor(ContextCompat.getColor(context, R.color.gray_100))
positiveView.contentDescription = toContentDescription(R.string.positive_habit_form, R.string.off)
positiveTextView.typeface = Typeface.create("sans-serif", Typeface.NORMAL)
}
}
@ -49,9 +52,11 @@ class HabitScoringButtonsView @JvmOverloads constructor(
if (value) {
negativeTextView.setTextColor(tintColor)
negativeView.contentDescription = toContentDescription(R.string.negative_habit_form, R.string.on)
negativeTextView.typeface = Typeface.create("sans-serif-medium", Typeface.NORMAL)
} else {
negativeTextView.setTextColor(ContextCompat.getColor(context, R.color.gray_100))
negativeView.contentDescription = toContentDescription(R.string.negative_habit_form, R.string.off)
negativeTextView.typeface = Typeface.create("sans-serif", Typeface.NORMAL)
}
}

View file

@ -1,6 +1,7 @@
package com.habitrpg.android.habitica.ui.views.tasks.form
import android.content.Context
import android.graphics.Typeface
import android.util.AttributeSet
import android.view.View
import android.view.accessibility.AccessibilityEvent
@ -58,10 +59,12 @@ class TaskDifficultyButtons @JvmOverloads constructor(
if (isActive) {
view.findViewById<ImageView>(R.id.image_view).background.mutate().setTint(tintColor)
view.findViewById<TextView>(R.id.text_view).setTextColor(tintColor)
view.findViewById<TextView>(R.id.text_view).typeface = Typeface.create("sans-serif-medium", Typeface.NORMAL)
} else {
view.findViewById<ImageView>(R.id.image_view).background.mutate().setTint(ContextCompat.getColor(context, R.color.taskform_gray))
view.findViewById<TextView>(R.id.text_view).setTextColor(ContextCompat.getColor(context, R.color.gray_100))
difficultyColor = ContextCompat.getColor(context, R.color.gray_400)
view.findViewById<TextView>(R.id.text_view).typeface = Typeface.create("sans-serif", Typeface.NORMAL)
}
val drawable = HabiticaIconsHelper.imageOfTaskDifficultyStars(difficultyColor, difficulty.value, true).asDrawable(resources)
view.findViewById<ImageView>(R.id.image_view).setImageDrawable(drawable)

View file

@ -68,6 +68,7 @@ class ContentDeserializer : JsonDeserializer<ContentResult> {
mount.animal = mountObj.getAsString("egg")
mount.color = mountObj.getAsString("potion")
mount.key = mountObj.getAsString("key")
mount.text = mountObj.getAsString("text")
mount.type = mountObj.getAsString("type")
if (mount.type == "special") {
mount.animal = mount.key.split("-")[0]