diff --git a/Habitica/res/drawable/seekbar_thumb.xml b/Habitica/res/drawable/seekbar_thumb.xml
new file mode 100644
index 000000000..9babaf6f2
--- /dev/null
+++ b/Habitica/res/drawable/seekbar_thumb.xml
@@ -0,0 +1,20 @@
+
+
+-
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Habitica/res/values/strings.xml b/Habitica/res/values/strings.xml
index e9f18edee..3e5e0472e 100644
--- a/Habitica/res/values/strings.xml
+++ b/Habitica/res/values/strings.xml
@@ -711,4 +711,5 @@
Assigns the same number of points to each attribute.
Assigns more points to the attributes important to your Class.
Assigns points based on the Strength, Intelligence, Constitution, and Perception categories associated with the tasks you complete.
+ Allocating Points
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/api/ApiService.java b/Habitica/src/main/java/com/habitrpg/android/habitica/api/ApiService.java
index c276e202e..a3633d5a7 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/api/ApiService.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/api/ApiService.java
@@ -350,4 +350,7 @@ public interface ApiService {
@POST("user/allocate")
Observable> allocatePoint(@Query("stat") String stat);
+
+ @POST("user/allocate-bulk")
+ Observable> bulkAllocatePoints(@Body Map stats);
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/ApiClient.java b/Habitica/src/main/java/com/habitrpg/android/habitica/data/ApiClient.java
index 025542e56..d6bb7d381 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/ApiClient.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/ApiClient.java
@@ -249,4 +249,6 @@ public interface ApiClient {
Observable updatePassword(String newPassword, String oldPassword, String oldPasswordConfirmation);
Observable allocatePoint(String stat);
+
+ Observable bulkAllocatePoints(int strength, int intelligence, int constitution, int perception);
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/UserRepository.java b/Habitica/src/main/java/com/habitrpg/android/habitica/data/UserRepository.java
index a2473d79d..e926d74b7 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/UserRepository.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/UserRepository.java
@@ -77,4 +77,7 @@ public interface UserRepository extends BaseRepository {
@NotNull
Observable allocatePoint(@Nullable User user, @Stats.StatsTypes String s);
+
+ @NotNull
+ Observable bulkAllocatePoints(int strength, int intelligence, int constitution, int perception);
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ApiClientImpl.java b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ApiClientImpl.java
index 75c384e67..e46f402de 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ApiClientImpl.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ApiClientImpl.java
@@ -986,4 +986,14 @@ public class ApiClientImpl implements Action1, ApiClient {
public Observable allocatePoint(String stat) {
return apiService.allocatePoint(stat).compose(configureApiCallObserver());
}
+
+ @Override
+ public Observable bulkAllocatePoints(int strength, int intelligence, int constitution, int perception) {
+ Map stats = new HashMap<>();
+ stats.put("str", strength);
+ stats.put("int", intelligence);
+ stats.put("con", constitution);
+ stats.put("per", perception);
+ return apiService.bulkAllocatePoints(stats).compose(configureApiCallObserver());
+ }
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/UserRepositoryImpl.java b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/UserRepositoryImpl.java
index 87e2d832c..9f3ec3e0b 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/UserRepositoryImpl.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/UserRepositoryImpl.java
@@ -311,6 +311,12 @@ public class UserRepositoryImpl extends BaseRepositoryImpl
});
}
+ @NotNull
+ @Override
+ public Observable bulkAllocatePoints(int strength, int intelligence, int constitution, int perception) {
+ return apiClient.bulkAllocatePoints(strength, intelligence, constitution, perception);
+ }
+
@Override
public void runCron(List tasks) {
Observable> observable;
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 98a588dd4..79b07e451 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
@@ -122,8 +122,11 @@ class StatsFragment: BaseMainFragment() {
}
private fun showBulkAllocateDialog() {
- val dialog = BulkAllocateStatsDialog(context, HabiticaBaseApplication.getComponent())
- dialog.show()
+ val context = context
+ if (context != null) {
+ 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/views/BulkAllocateStatsDialog.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/BulkAllocateStatsDialog.kt
index b8f9c15c9..71fa6b428 100644
--- 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
@@ -1,9 +1,10 @@
package com.habitrpg.android.habitica.ui.views
-import android.app.AlertDialog
+import android.app.ProgressDialog
import android.content.Context
import android.os.Bundle
import android.support.v4.content.ContextCompat
+import android.support.v7.app.AlertDialog
import android.view.LayoutInflater
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.components.AppComponent
@@ -12,10 +13,11 @@ 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.Action0
import rx.functions.Action1
import javax.inject.Inject
-class BulkAllocateStatsDialog(context: Context?, component: AppComponent) : AlertDialog(context) {
+class BulkAllocateStatsDialog(context: Context, component: AppComponent) : AlertDialog(context) {
@Inject
lateinit var userRepository: UserRepository
@@ -62,11 +64,27 @@ class BulkAllocateStatsDialog(context: Context?, component: AppComponent) : Aler
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.setButton(AlertDialog.BUTTON_POSITIVE, context.getString(R.string.save)) { _, _ ->
+ saveChanges()
+ }
+ this.setButton(AlertDialog.BUTTON_NEUTRAL, context.getString(R.string.action_cancel)) { _, _ ->
this.dismiss()
}
}
+ private fun saveChanges() {
+ val progressDialog = ProgressDialog.show(context, context.getString(R.string.allocating_points), null, true)
+ userRepository.bulkAllocatePoints(strengthSliderView.currentValue, intelligenceSliderView.currentValue, constitutionSliderView.currentValue, perceptionSliderView.currentValue)
+ .subscribe({
+ progressDialog.dismiss()
+ this.dismiss()
+ }, {
+ RxErrorHandler.reportError(it)
+ progressDialog.dismiss()
+ this.dismiss()
+ })
+ }
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
subscription = userRepository.user.subscribe(Action1 {
@@ -74,19 +92,59 @@ class BulkAllocateStatsDialog(context: Context?, component: AppComponent) : Aler
}, RxErrorHandler.handleEmptyError())
strengthSliderView.allocateAction = {
+ checkRedistribution(strengthSliderView)
updateTitle()
}
intelligenceSliderView.allocateAction = {
+ checkRedistribution(intelligenceSliderView)
updateTitle()
}
constitutionSliderView.allocateAction = {
+ checkRedistribution(constitutionSliderView)
updateTitle()
}
perceptionSliderView.allocateAction = {
+ checkRedistribution(perceptionSliderView)
updateTitle()
}
}
+ private fun checkRedistribution(excludedSlider: StatsSliderView) {
+ val diff = allocatedPoints - pointsToAllocate
+ if (diff > 0) {
+ var highestSlider: StatsSliderView? = null
+ if (excludedSlider != strengthSliderView) {
+ highestSlider = getSliderWithHigherValue(highestSlider, strengthSliderView)
+ }
+ if (excludedSlider != intelligenceSliderView) {
+ highestSlider = getSliderWithHigherValue(highestSlider, intelligenceSliderView)
+ }
+ if (excludedSlider != constitutionSliderView) {
+ highestSlider = getSliderWithHigherValue(highestSlider, constitutionSliderView)
+ }
+ if (excludedSlider != perceptionSliderView) {
+ highestSlider = getSliderWithHigherValue(highestSlider, perceptionSliderView)
+ }
+ if (highestSlider != null) {
+ highestSlider.currentValue -= diff
+ }
+ }
+ }
+
+ private fun getSliderWithHigherValue(firstSlider: StatsSliderView?, secondSlider: StatsSliderView?): StatsSliderView? {
+ if (firstSlider == null) {
+ return secondSlider
+ }
+ if (secondSlider == null) {
+ return firstSlider
+ }
+ if (firstSlider.currentValue > secondSlider.currentValue) {
+ return firstSlider
+ } else {
+ return secondSlider
+ }
+ }
+
override fun dismiss() {
subscription?.unsubscribe()
super.dismiss()
@@ -99,5 +157,7 @@ class BulkAllocateStatsDialog(context: Context?, component: AppComponent) : Aler
} else {
titleView.setBackgroundColor(ContextCompat.getColor(context, R.color.gray_400))
}
+
+ getButton(AlertDialog.BUTTON_POSITIVE).isEnabled = allocatedPoints > 0
}
}
\ 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
index 25e0f68fa..e95278078 100644
--- 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
@@ -1,7 +1,10 @@
package com.habitrpg.android.habitica.ui.views
import android.content.Context
+import android.content.res.ColorStateList
import android.graphics.PorterDuff
+import android.os.Build
+import android.support.v4.content.ContextCompat
import android.util.AttributeSet
import android.view.Gravity
import android.view.View
@@ -11,7 +14,7 @@ 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) {
+class StatsSliderView(context: Context, attrs: AttributeSet?) : LinearLayout(context, attrs) {
var previousValue = 0
set(value) {
@@ -44,8 +47,14 @@ class StatsSliderView(context: Context?, attrs: AttributeSet?) : LinearLayout(co
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)
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ statsSeekBar.progressTintList = ColorStateList.valueOf(statColor)
+ } else {
+ statsSeekBar.progressDrawable.setColorFilter(statColor, PorterDuff.Mode.SRC_IN)
+ }
+ val thumbDrawable = ContextCompat.getDrawable(context, R.drawable.seekbar_thumb)
+ thumbDrawable?.setColorFilter(statColor, PorterDuff.Mode.MULTIPLY)
+ statsSeekBar.thumb = thumbDrawable
}
statsSeekBar.setOnSeekBarChangeListener(object: SeekBar.OnSeekBarChangeListener {