From 0732b0500e22e1ac1fdeb33a1623cdcea595c673 Mon Sep 17 00:00:00 2001 From: Phillip Thelen Date: Mon, 30 Oct 2017 09:25:33 +0100 Subject: [PATCH] begin implementing bulk allocation --- Habitica/res/layout/dialog_bulk_allocate.xml | 69 ++++++++++++ Habitica/res/layout/fragment_stats.xml | 1 + Habitica/res/layout/stats_slider_view.xml | 52 +++++++++ Habitica/res/values/attrs.xml | 11 +- Habitica/res/values/strings.xml | 8 +- .../habitica/components/AppComponent.java | 3 + .../extensions/AttributeSet-Extentions.kt | 8 ++ .../android/habitica/models/tasks/Task.kt | 4 +- .../android/habitica/models/user/Stats.java | 12 +- .../habitica/ui/fragments/StatsFragment.kt | 13 +++ .../tasks/ChecklistedViewHolder.java | 8 +- .../ui/views/BulkAllocateStatsDialog.kt | 103 ++++++++++++++++++ .../habitica/ui/views/StatsSliderView.kt | 70 ++++++++++++ 13 files changed, 344 insertions(+), 18 deletions(-) create mode 100644 Habitica/res/layout/dialog_bulk_allocate.xml create mode 100644 Habitica/res/layout/stats_slider_view.xml create mode 100644 Habitica/src/main/java/com/habitrpg/android/habitica/extensions/AttributeSet-Extentions.kt create mode 100644 Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/BulkAllocateStatsDialog.kt create mode 100644 Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/StatsSliderView.kt diff --git a/Habitica/res/layout/dialog_bulk_allocate.xml b/Habitica/res/layout/dialog_bulk_allocate.xml new file mode 100644 index 000000000..3cddcfc2b --- /dev/null +++ b/Habitica/res/layout/dialog_bulk_allocate.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/Habitica/res/layout/fragment_stats.xml b/Habitica/res/layout/fragment_stats.xml index e3f6473fa..f791918cf 100644 --- a/Habitica/res/layout/fragment_stats.xml +++ b/Habitica/res/layout/fragment_stats.xml @@ -16,6 +16,7 @@ android:paddingTop="12dp" android:paddingBottom="20dp"> + + + + + + + + \ No newline at end of file diff --git a/Habitica/res/values/attrs.xml b/Habitica/res/values/attrs.xml index 78e6237a3..9eecd2238 100644 --- a/Habitica/res/values/attrs.xml +++ b/Habitica/res/values/attrs.xml @@ -1,4 +1,6 @@ + + @@ -50,10 +52,15 @@ - - + + + + + + + diff --git a/Habitica/res/values/strings.xml b/Habitica/res/values/strings.xml index 4ceeb1636..e9f18edee 100644 --- a/Habitica/res/values/strings.xml +++ b/Habitica/res/values/strings.xml @@ -641,10 +641,10 @@ %d Experience points %d Gold Quest Owner Rewards - Str: - Per: - Int: - Con: + Str + Per + Int + Con Reset Account WARNING! This resets many parts of your account. This is highly discouraged, but some people find it useful in the beginning after playing with the site for a short time.\n\nYou will lose all your levels, gold, and experience points. All your tasks (except those from challenges) will be deleted permanently and you will lose all of their historical data. You will lose all your equipment but you will be able to buy it all back, including all limited edition equipment or subscriber Mystery items that you already own (you will need to be in the correct class to re-buy class-specific gear). You will keep your current class and your pets and mounts. You might prefer to use an Orb of Rebirth instead, which is a much safer option and which will preserve your tasks and equipment. Delete Account diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/components/AppComponent.java b/Habitica/src/main/java/com/habitrpg/android/habitica/components/AppComponent.java index 927a1c228..077a29182 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/components/AppComponent.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/components/AppComponent.java @@ -87,6 +87,7 @@ import com.habitrpg.android.habitica.ui.fragments.social.party.PartyInviteFragme import com.habitrpg.android.habitica.ui.fragments.social.party.PartyMemberListFragment; import com.habitrpg.android.habitica.ui.fragments.tasks.TaskRecyclerViewFragment; import com.habitrpg.android.habitica.ui.fragments.tasks.TasksFragment; +import com.habitrpg.android.habitica.ui.views.BulkAllocateStatsDialog; import com.habitrpg.android.habitica.ui.views.shops.PurchaseDialog; import com.habitrpg.android.habitica.ui.views.tasks.TaskFilterDialog; import com.habitrpg.android.habitica.widget.AvatarStatsWidgetProvider; @@ -290,4 +291,6 @@ public interface AppComponent { void inject(@NotNull APIPreferenceFragment apiPreferenceFragment); void inject(@NotNull StatsFragment statsFragment); + + void inject(@NotNull BulkAllocateStatsDialog bulkAllocateStatsDialog); } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/extensions/AttributeSet-Extentions.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/extensions/AttributeSet-Extentions.kt new file mode 100644 index 000000000..d5ed2213c --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/extensions/AttributeSet-Extentions.kt @@ -0,0 +1,8 @@ +package com.habitrpg.android.habitica.extensions + +import android.content.Context +import android.content.res.TypedArray +import android.util.AttributeSet + +fun AttributeSet.styledAttributes(context: Context?, style: IntArray?): TypedArray? = + context?.theme?.obtainStyledAttributes(this, style, 0, 0) \ No newline at end of file diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/Task.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/Task.kt index 4d5524bb3..9d381943c 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/Task.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/Task.kt @@ -55,9 +55,9 @@ open class Task : RealmObject, Parcelable { // used for buyable items var specialTag: String = "" @Ignore - var parsedText: CharSequence = "" + var parsedText: CharSequence? = null @Ignore - var parsedNotes: CharSequence = "" + var parsedNotes: CharSequence? = null @PrimaryKey @SerializedName("_id") var id: String = "" diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Stats.java b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Stats.java index d12961300..eac181d56 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Stats.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Stats.java @@ -43,9 +43,9 @@ public class Stats extends RealmObject { private String userId; User user; - public Float con, str, per; + public Integer con, str, per; @SerializedName("int") - public Float _int; + public Integer _int; public Training training; public Buffs buffs; public Integer points, lvl; @@ -179,19 +179,19 @@ public class Stats extends RealmObject { return buffs; } - public Float getStr() { + public Integer getStr() { return str; } - public Float get_int() { + public Integer get_int() { return _int; } - public Float getCon() { + public Integer getCon() { return con; } - public Float getPer() { + public Integer getPer() { return per; } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/StatsFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/StatsFragment.kt index 36c927848..98a588dd4 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/StatsFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/StatsFragment.kt @@ -6,6 +6,7 @@ import android.support.v4.content.ContextCompat import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import com.habitrpg.android.habitica.HabiticaBaseApplication import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.components.AppComponent import com.habitrpg.android.habitica.data.InventoryRepository @@ -16,6 +17,7 @@ import com.habitrpg.android.habitica.helpers.UserStatComputer import com.habitrpg.android.habitica.models.user.Stats import com.habitrpg.android.habitica.modules.AppModule import com.habitrpg.android.habitica.extensions.setScaledPadding +import com.habitrpg.android.habitica.ui.views.BulkAllocateStatsDialog import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper import kotlinx.android.synthetic.main.fragment_stats.* import rx.functions.Action1 @@ -111,6 +113,17 @@ class StatsFragment: BaseMainFragment() { distributeEvenlyHelpButton.setOnClickListener { showHelpAlert(R.string.distribute_evenly_help) } distributeClassHelpButton.setOnClickListener { showHelpAlert(R.string.distribute_class_help) } distributeTaskHelpButton.setOnClickListener { showHelpAlert(R.string.distribute_task_help) } + + statsAllocationButton.setOnClickListener { + if (user?.stats?.points ?: 0 > 0) { + showBulkAllocateDialog() + } + } + } + + private fun showBulkAllocateDialog() { + val dialog = BulkAllocateStatsDialog(context, HabiticaBaseApplication.getComponent()) + dialog.show() } private fun changeAutoAllocationMode(@Stats.AutoAllocationTypes allocationMode: String) { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/ChecklistedViewHolder.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/ChecklistedViewHolder.java index ff88efd9d..e5bd5b62f 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/ChecklistedViewHolder.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/ChecklistedViewHolder.java @@ -34,7 +34,7 @@ import rx.schedulers.Schedulers; public abstract class ChecklistedViewHolder extends BaseTaskViewHolder implements CompoundButton.OnCheckedChangeListener { - static Integer expandedChecklistRow = null; + private static Integer expandedChecklistRow = null; @BindView(R.id.checkBoxHolder) ViewGroup checkboxHolder; @@ -93,13 +93,13 @@ public abstract class ChecklistedViewHolder extends BaseTaskViewHolder implement public void updateChecklistDisplay() { //This needs to be a LinearLayout, as ListViews can not be inside other ListViews. if (this.checklistView != null) { - if (this.shouldDisplayExpandedChecklist() && this.task.getChecklist() != null) { + if (this.shouldDisplayExpandedChecklist()) { LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); if (this.task.getChecklist().isValid()) { for (ChecklistItem item : this.task.getChecklist()) { LinearLayout itemView = (LinearLayout) layoutInflater.inflate(R.layout.checklist_item_row, this.checklistView, false); - CheckBox checkbox = (CheckBox) itemView.findViewById(R.id.checkBox); - EmojiTextView textView = (EmojiTextView) itemView.findViewById(R.id.checkedTextView); + CheckBox checkbox = itemView.findViewById(R.id.checkBox); + EmojiTextView textView = itemView.findViewById(R.id.checkedTextView); // Populate the data into the template view using the data object textView.setText(item.getText()); diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/BulkAllocateStatsDialog.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/BulkAllocateStatsDialog.kt new file mode 100644 index 000000000..b8f9c15c9 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/BulkAllocateStatsDialog.kt @@ -0,0 +1,103 @@ +package com.habitrpg.android.habitica.ui.views + +import android.app.AlertDialog +import android.content.Context +import android.os.Bundle +import android.support.v4.content.ContextCompat +import android.view.LayoutInflater +import com.habitrpg.android.habitica.R +import com.habitrpg.android.habitica.components.AppComponent +import com.habitrpg.android.habitica.data.UserRepository +import com.habitrpg.android.habitica.helpers.RxErrorHandler +import com.habitrpg.android.habitica.models.user.User +import kotlinx.android.synthetic.main.dialog_bulk_allocate.* +import rx.Subscription +import rx.functions.Action1 +import javax.inject.Inject + +class BulkAllocateStatsDialog(context: Context?, component: AppComponent) : AlertDialog(context) { + + @Inject + lateinit var userRepository: UserRepository + + var subscription: Subscription? = null + + private var allocatedPoints: Int + get() { + var value = 0 + value += strengthSliderView.currentValue + value += intelligenceSliderView.currentValue + value += constitutionSliderView.currentValue + value += perceptionSliderView.currentValue + return value + } + set(value) { + return + } + + private var pointsToAllocate = 0 + set(value) { + field = value + updateTitle() + strengthSliderView.maxValue = pointsToAllocate + intelligenceSliderView.maxValue = pointsToAllocate + constitutionSliderView.maxValue = pointsToAllocate + perceptionSliderView.maxValue = pointsToAllocate + } + + private var user: User? = null + set(value) { + field = value + pointsToAllocate = user?.stats?.points ?: 0 + strengthSliderView.previousValue = user?.stats?.str ?: 0 + intelligenceSliderView.previousValue = user?.stats?._int ?: 0 + constitutionSliderView.previousValue = user?.stats?.con ?: 0 + perceptionSliderView.previousValue = user?.stats?.per ?: 0 + } + + init { + component.inject(this) + + val inflater = LayoutInflater.from(context) + val view = inflater.inflate(R.layout.dialog_bulk_allocate, null) + + setView(view) + this.setButton(android.support.v7.app.AlertDialog.BUTTON_POSITIVE, context?.getString(R.string.done)) { _, _ -> + this.dismiss() + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + subscription = userRepository.user.subscribe(Action1 { + user = it + }, RxErrorHandler.handleEmptyError()) + + strengthSliderView.allocateAction = { + updateTitle() + } + intelligenceSliderView.allocateAction = { + updateTitle() + } + constitutionSliderView.allocateAction = { + updateTitle() + } + perceptionSliderView.allocateAction = { + updateTitle() + } + } + + override fun dismiss() { + subscription?.unsubscribe() + super.dismiss() + } + + private fun updateTitle() { + allocatedTitle.text = allocatedPoints.toString() + "/" + pointsToAllocate.toString() + if (allocatedPoints > 0) { + titleView.setBackgroundColor(ContextCompat.getColor(context, R.color.brand_400)) + } else { + titleView.setBackgroundColor(ContextCompat.getColor(context, R.color.gray_400)) + } + } +} \ No newline at end of file diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/StatsSliderView.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/StatsSliderView.kt new file mode 100644 index 000000000..25e0f68fa --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/StatsSliderView.kt @@ -0,0 +1,70 @@ +package com.habitrpg.android.habitica.ui.views + +import android.content.Context +import android.graphics.PorterDuff +import android.util.AttributeSet +import android.view.Gravity +import android.view.View +import android.widget.LinearLayout +import android.widget.SeekBar +import com.habitrpg.android.habitica.R +import com.habitrpg.android.habitica.extensions.styledAttributes +import kotlinx.android.synthetic.main.stats_slider_view.view.* + +class StatsSliderView(context: Context?, attrs: AttributeSet?) : LinearLayout(context, attrs) { + + var previousValue = 0 + set(value) { + field = value + previousValueTextView.text = value.toString() + } + + var maxValue = 0 + set(value) { + field = value + statsSeekBar.max = field + } + + var currentValue = 0 + set(value) { + field = value + statsSeekBar.progress = value + valueEditText.setText(value.toString()) + } + + var allocateAction: ((Int) -> Unit)? = null + + init { + View.inflate(context, R.layout.stats_slider_view, this) + gravity = Gravity.CENTER_VERTICAL + + val attributes = attrs?.styledAttributes(context, R.styleable.StatsSliderView) + + if (attributes != null) { + statTypeTitle.text = attributes.getString(R.styleable.StatsSliderView_statsTitle) + val statColor = attributes.getColor(R.styleable.StatsSliderView_statsColor, 0) + statTypeTitle.setTextColor(attributes.getColor(R.styleable.StatsSliderView_statsTextColor, 0)) + statsSeekBar.progressDrawable.setColorFilter(statColor, PorterDuff.Mode.MULTIPLY) + statsSeekBar.thumb.setColorFilter(statColor, PorterDuff.Mode.MULTIPLY) + } + + statsSeekBar.setOnSeekBarChangeListener(object: SeekBar.OnSeekBarChangeListener { + override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) { + currentValue = progress + if (fromUser) { + allocateAction?.invoke(currentValue) + } + } + + override fun onStartTrackingTouch(seekBar: SeekBar?) { + } + + override fun onStopTrackingTouch(seekBar: SeekBar?) { + } + }) + + currentValue = 0 + } + +} +