implement bulk attribute point allocation. Fixes #821

This commit is contained in:
Phillip Thelen 2017-10-30 13:27:19 +01:00
parent 418b2ee8aa
commit 95b1be7415
10 changed files with 125 additions and 8 deletions

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:bottom="2dp"
android:left="2dp"
android:right="2dp"
android:top="2dp">
<rotate android:fromDegrees="45">
<shape>
<size
android:width="10dp"
android:height="10dp" />
<solid android:color="@color/white" />
<stroke
android:width="1dp"
android:color="@color/gray_400" />
</shape>
</rotate>
</item>
</layer-list>

View file

@ -711,4 +711,5 @@
<string name="distribute_evenly_help">Assigns the same number of points to each attribute.</string>
<string name="distribute_class_help">Assigns more points to the attributes important to your Class.</string>
<string name="distribute_task_help">Assigns points based on the Strength, Intelligence, Constitution, and Perception categories associated with the tasks you complete.</string>
<string name="allocating_points">Allocating Points</string>
</resources>

View file

@ -350,4 +350,7 @@ public interface ApiService {
@POST("user/allocate")
Observable<HabitResponse<Stats>> allocatePoint(@Query("stat") String stat);
@POST("user/allocate-bulk")
Observable<HabitResponse<Stats>> bulkAllocatePoints(@Body Map<String, Integer> stats);
}

View file

@ -249,4 +249,6 @@ public interface ApiClient {
Observable<Void> updatePassword(String newPassword, String oldPassword, String oldPasswordConfirmation);
Observable<Stats> allocatePoint(String stat);
Observable<Stats> bulkAllocatePoints(int strength, int intelligence, int constitution, int perception);
}

View file

@ -77,4 +77,7 @@ public interface UserRepository extends BaseRepository {
@NotNull
Observable<Stats> allocatePoint(@Nullable User user, @Stats.StatsTypes String s);
@NotNull
Observable<Stats> bulkAllocatePoints(int strength, int intelligence, int constitution, int perception);
}

View file

@ -986,4 +986,14 @@ public class ApiClientImpl implements Action1<Throwable>, ApiClient {
public Observable<Stats> allocatePoint(String stat) {
return apiService.allocatePoint(stat).compose(configureApiCallObserver());
}
@Override
public Observable<Stats> bulkAllocatePoints(int strength, int intelligence, int constitution, int perception) {
Map<String, Integer> 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());
}
}

View file

@ -311,6 +311,12 @@ public class UserRepositoryImpl extends BaseRepositoryImpl<UserLocalRepository>
});
}
@NotNull
@Override
public Observable<Stats> bulkAllocatePoints(int strength, int intelligence, int constitution, int perception) {
return apiClient.bulkAllocatePoints(strength, intelligence, constitution, perception);
}
@Override
public void runCron(List<Task> tasks) {
Observable<List<TaskScoringResult>> observable;

View file

@ -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) {

View file

@ -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
}
}

View file

@ -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 {