mirror of
https://github.com/sudoxnym/habitica-android.git
synced 2026-07-13 17:51:57 +00:00
implement bulk attribute point allocation. Fixes #821
This commit is contained in:
parent
54256023c2
commit
2aaa8ccdaa
10 changed files with 125 additions and 8 deletions
20
Habitica/res/drawable/seekbar_thumb.xml
Normal file
20
Habitica/res/drawable/seekbar_thumb.xml
Normal 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>
|
||||||
|
|
@ -709,4 +709,5 @@
|
||||||
<string name="distribute_evenly_help">Assigns the same number of points to each attribute.</string>
|
<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_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="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>
|
</resources>
|
||||||
|
|
|
||||||
|
|
@ -350,4 +350,7 @@ public interface ApiService {
|
||||||
|
|
||||||
@POST("user/allocate")
|
@POST("user/allocate")
|
||||||
Observable<HabitResponse<Stats>> allocatePoint(@Query("stat") String stat);
|
Observable<HabitResponse<Stats>> allocatePoint(@Query("stat") String stat);
|
||||||
|
|
||||||
|
@POST("user/allocate-bulk")
|
||||||
|
Observable<HabitResponse<Stats>> bulkAllocatePoints(@Body Map<String, Integer> stats);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -249,4 +249,6 @@ public interface ApiClient {
|
||||||
Observable<Void> updatePassword(String newPassword, String oldPassword, String oldPasswordConfirmation);
|
Observable<Void> updatePassword(String newPassword, String oldPassword, String oldPasswordConfirmation);
|
||||||
|
|
||||||
Observable<Stats> allocatePoint(String stat);
|
Observable<Stats> allocatePoint(String stat);
|
||||||
|
|
||||||
|
Observable<Stats> bulkAllocatePoints(int strength, int intelligence, int constitution, int perception);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -77,4 +77,7 @@ public interface UserRepository extends BaseRepository {
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
Observable<Stats> allocatePoint(@Nullable User user, @Stats.StatsTypes String s);
|
Observable<Stats> allocatePoint(@Nullable User user, @Stats.StatsTypes String s);
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
Observable<Stats> bulkAllocatePoints(int strength, int intelligence, int constitution, int perception);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -986,4 +986,14 @@ public class ApiClientImpl implements Action1<Throwable>, ApiClient {
|
||||||
public Observable<Stats> allocatePoint(String stat) {
|
public Observable<Stats> allocatePoint(String stat) {
|
||||||
return apiService.allocatePoint(stat).compose(configureApiCallObserver());
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
@Override
|
||||||
public void runCron(List<Task> tasks) {
|
public void runCron(List<Task> tasks) {
|
||||||
Observable<List<TaskScoringResult>> observable;
|
Observable<List<TaskScoringResult>> observable;
|
||||||
|
|
|
||||||
|
|
@ -122,8 +122,11 @@ class StatsFragment: BaseMainFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showBulkAllocateDialog() {
|
private fun showBulkAllocateDialog() {
|
||||||
val dialog = BulkAllocateStatsDialog(context, HabiticaBaseApplication.getComponent())
|
val context = context
|
||||||
dialog.show()
|
if (context != null) {
|
||||||
|
val dialog = BulkAllocateStatsDialog(context, HabiticaBaseApplication.getComponent())
|
||||||
|
dialog.show()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun changeAutoAllocationMode(@Stats.AutoAllocationTypes allocationMode: String) {
|
private fun changeAutoAllocationMode(@Stats.AutoAllocationTypes allocationMode: String) {
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
package com.habitrpg.android.habitica.ui.views
|
package com.habitrpg.android.habitica.ui.views
|
||||||
|
|
||||||
import android.app.AlertDialog
|
import android.app.ProgressDialog
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.support.v4.content.ContextCompat
|
import android.support.v4.content.ContextCompat
|
||||||
|
import android.support.v7.app.AlertDialog
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import com.habitrpg.android.habitica.R
|
import com.habitrpg.android.habitica.R
|
||||||
import com.habitrpg.android.habitica.components.AppComponent
|
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 com.habitrpg.android.habitica.models.user.User
|
||||||
import kotlinx.android.synthetic.main.dialog_bulk_allocate.*
|
import kotlinx.android.synthetic.main.dialog_bulk_allocate.*
|
||||||
import rx.Subscription
|
import rx.Subscription
|
||||||
|
import rx.functions.Action0
|
||||||
import rx.functions.Action1
|
import rx.functions.Action1
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class BulkAllocateStatsDialog(context: Context?, component: AppComponent) : AlertDialog(context) {
|
class BulkAllocateStatsDialog(context: Context, component: AppComponent) : AlertDialog(context) {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var userRepository: UserRepository
|
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)
|
val view = inflater.inflate(R.layout.dialog_bulk_allocate, null)
|
||||||
|
|
||||||
setView(view)
|
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()
|
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?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
subscription = userRepository.user.subscribe(Action1 {
|
subscription = userRepository.user.subscribe(Action1 {
|
||||||
|
|
@ -74,19 +92,59 @@ class BulkAllocateStatsDialog(context: Context?, component: AppComponent) : Aler
|
||||||
}, RxErrorHandler.handleEmptyError())
|
}, RxErrorHandler.handleEmptyError())
|
||||||
|
|
||||||
strengthSliderView.allocateAction = {
|
strengthSliderView.allocateAction = {
|
||||||
|
checkRedistribution(strengthSliderView)
|
||||||
updateTitle()
|
updateTitle()
|
||||||
}
|
}
|
||||||
intelligenceSliderView.allocateAction = {
|
intelligenceSliderView.allocateAction = {
|
||||||
|
checkRedistribution(intelligenceSliderView)
|
||||||
updateTitle()
|
updateTitle()
|
||||||
}
|
}
|
||||||
constitutionSliderView.allocateAction = {
|
constitutionSliderView.allocateAction = {
|
||||||
|
checkRedistribution(constitutionSliderView)
|
||||||
updateTitle()
|
updateTitle()
|
||||||
}
|
}
|
||||||
perceptionSliderView.allocateAction = {
|
perceptionSliderView.allocateAction = {
|
||||||
|
checkRedistribution(perceptionSliderView)
|
||||||
updateTitle()
|
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() {
|
override fun dismiss() {
|
||||||
subscription?.unsubscribe()
|
subscription?.unsubscribe()
|
||||||
super.dismiss()
|
super.dismiss()
|
||||||
|
|
@ -99,5 +157,7 @@ class BulkAllocateStatsDialog(context: Context?, component: AppComponent) : Aler
|
||||||
} else {
|
} else {
|
||||||
titleView.setBackgroundColor(ContextCompat.getColor(context, R.color.gray_400))
|
titleView.setBackgroundColor(ContextCompat.getColor(context, R.color.gray_400))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getButton(AlertDialog.BUTTON_POSITIVE).isEnabled = allocatedPoints > 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
package com.habitrpg.android.habitica.ui.views
|
package com.habitrpg.android.habitica.ui.views
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.content.res.ColorStateList
|
||||||
import android.graphics.PorterDuff
|
import android.graphics.PorterDuff
|
||||||
|
import android.os.Build
|
||||||
|
import android.support.v4.content.ContextCompat
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.view.Gravity
|
import android.view.Gravity
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
|
@ -11,7 +14,7 @@ import com.habitrpg.android.habitica.R
|
||||||
import com.habitrpg.android.habitica.extensions.styledAttributes
|
import com.habitrpg.android.habitica.extensions.styledAttributes
|
||||||
import kotlinx.android.synthetic.main.stats_slider_view.view.*
|
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
|
var previousValue = 0
|
||||||
set(value) {
|
set(value) {
|
||||||
|
|
@ -44,8 +47,14 @@ class StatsSliderView(context: Context?, attrs: AttributeSet?) : LinearLayout(co
|
||||||
statTypeTitle.text = attributes.getString(R.styleable.StatsSliderView_statsTitle)
|
statTypeTitle.text = attributes.getString(R.styleable.StatsSliderView_statsTitle)
|
||||||
val statColor = attributes.getColor(R.styleable.StatsSliderView_statsColor, 0)
|
val statColor = attributes.getColor(R.styleable.StatsSliderView_statsColor, 0)
|
||||||
statTypeTitle.setTextColor(attributes.getColor(R.styleable.StatsSliderView_statsTextColor, 0))
|
statTypeTitle.setTextColor(attributes.getColor(R.styleable.StatsSliderView_statsTextColor, 0))
|
||||||
statsSeekBar.progressDrawable.setColorFilter(statColor, PorterDuff.Mode.MULTIPLY)
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
statsSeekBar.thumb.setColorFilter(statColor, PorterDuff.Mode.MULTIPLY)
|
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 {
|
statsSeekBar.setOnSeekBarChangeListener(object: SeekBar.OnSeekBarChangeListener {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue