stats screen design tweaks

This commit is contained in:
Phillip Thelen 2017-10-18 13:19:10 +02:00
parent fcbf02075a
commit 79cb82e8d8
14 changed files with 268 additions and 57 deletions

View file

@ -2,7 +2,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.habitrpg.android.habitica"
android:versionCode="1945"
android:versionCode="1946"
android:versionName="1.3"
android:screenOrientation="portrait"
android:installLocation="auto" >

View file

@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
@ -12,10 +11,10 @@
android:focusableInTouchMode="true"
android:orientation="vertical"
android:background="@color/brand"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingStart="16dp"
android:paddingEnd="16dp">
android:paddingLeft="@dimen/header_border_spacing"
android:paddingRight="@dimen/header_border_spacing"
android:paddingStart="@dimen/header_border_spacing"
android:paddingEnd="@dimen/header_border_spacing">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">

View file

@ -29,7 +29,7 @@
android:id="@+id/editText"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:inputType="number"
android:inputType="numberDecimal"
android:background="@android:color/transparent"/>
</android.support.design.widget.TextInputLayout>
<ImageView

View file

@ -18,7 +18,9 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center">
android:gravity="center"
android:layout_marginTop="6dp"
android:layout_marginBottom="18dp">
<ImageView
android:id="@+id/leftSparklesView"
android:layout_width="77dp"
@ -28,10 +30,8 @@
android:id="@+id/numberOfPointsTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:layout_marginLeft="12dp"
android:layout_marginRight="12dp"
android:layout_marginBottom="24dp"/>
android:layout_marginRight="12dp"/>
<ImageView
android:id="@+id/rightSparklesView"
android:layout_width="77dp"
@ -78,7 +78,7 @@
android:layout_marginLeft="@dimen/content_border"
android:layout_marginRight="@dimen/content_border"
android:layout_marginBottom="20dp"/>
<RadioGroup
<LinearLayout
android:id="@+id/autoAllocationModeWrapper"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -86,25 +86,59 @@
android:paddingRight="@dimen/content_border"
android:background="@color/gray_700"
android:paddingTop="16dp"
android:paddingBottom="16dp">
<RadioButton
android:id="@+id/distributeEvenlyButton"
android:paddingBottom="16dp"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/distribute_evenly"
android:layout_marginBottom="4dp"/>
<RadioButton
android:id="@+id/distributeClassButton"
android:layout_marginBottom="8dp"
android:gravity="center_vertical">
<RadioButton
android:id="@+id/distributeEvenlyButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/distribute_evenly"/>
<ImageButton
android:id="@+id/distributeEvenlyHelpButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/transparent"
android:layout_marginLeft="12dp"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/distribute_class"
android:layout_marginBottom="4dp"/>
<RadioButton
android:id="@+id/distributeTaskButton"
android:layout_marginBottom="8dp"
android:gravity="center_vertical">
<RadioButton
android:id="@+id/distributeClassButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/distribute_class"/>
<ImageButton
android:id="@+id/distributeClassHelpButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/transparent"
android:layout_marginLeft="12dp"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/distribute_task"/>
</RadioGroup>
android:gravity="center_vertical">
<RadioButton
android:id="@+id/distributeTaskButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/distribute_task"/>
<ImageButton
android:id="@+id/distributeTaskHelpButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/transparent"
android:layout_marginLeft="12dp"/>
</LinearLayout>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"

View file

@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="content_inset">6dp</dimen>
<dimen name="header_border_spacing">8dp</dimen>
</resources>

View file

@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="content_inset">21dp</dimen>
<dimen name="header_border_spacing">16dp</dimen>
</resources>

View file

@ -120,4 +120,5 @@
<dimen name="snackbar_image_size">46dp</dimen>
<dimen name="setup_vertical_spacing">28dp</dimen>
<dimen name="content_inset">21dp</dimen>
<dimen name="header_border_spacing">16dp</dimen>
</resources>

View file

@ -708,4 +708,7 @@
<string name="distribute_task">Distribute based on task activity</string>
<string name="no_points_to_allocate">No Points to Allocate</string>
<string name="points_to_allocate" formatted="false">%d Points to Allocate</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_task_help">Assigns points based on the Strength, Intelligence, Constitution, and Perception categories associated with the tasks you complete.</string>
</resources>

View file

@ -283,7 +283,18 @@ public class UserRepositoryImpl extends BaseRepositoryImpl<UserLocalRepository>
@Override
public Observable<Stats> allocatePoint(@Nullable User user, String stat) {
if (user != null && user.isManaged()) {
localRepository.executeTransaction(realm -> user.getStats().points -= 1);
localRepository.executeTransaction(realm -> {
if (Stats.STRENGTH.equals(stat)) {
user.getStats().str += 1;
} else if (Stats.INTELLIGENCE.equals(stat)) {
user.getStats()._int += 1;
} else if (Stats.CONSTITUTION.equals(stat)) {
user.getStats().con += 1;
} else if (Stats.PERCEPTION.equals(stat)) {
user.getStats().per += 1;
}
user.getStats().points -= 1;
});
}
return apiClient.allocatePoint(stat)
.doOnNext(stats -> {

View file

@ -0,0 +1,31 @@
package com.habitrpg.android.habitica.extensions
import android.app.AlertDialog
import android.content.DialogInterface
import com.habitrpg.android.habitica.R
public fun AlertDialog.Builder.setOkButton(listener: ((DialogInterface, Int) -> Unit)? = null): AlertDialog.Builder {
this.setPositiveButton(R.string.ok, { dialog, which ->
listener?.invoke(dialog, which)
})
return this
}
public fun AlertDialog.Builder.setCloseButton(listener: ((DialogInterface, Int) -> Unit)? = null): AlertDialog.Builder {
this.setPositiveButton(R.string.close, { dialog, which ->
listener?.invoke(dialog, which)
})
return this
}
public fun AlertDialog.setOkButton(whichButton: Int = AlertDialog.BUTTON_POSITIVE, listener: ((DialogInterface, Int) -> Unit)? = null) {
this.setButton(whichButton, context.getString(R.string.ok), { dialog, which ->
listener?.invoke(dialog, which)
})
}
public fun AlertDialog.setCloseButton(whichButton: Int = AlertDialog.BUTTON_POSITIVE, listener: ((DialogInterface, Int) -> Unit)? = null) {
this.setButton(whichButton, context.getString(R.string.close), { dialog, which ->
listener?.invoke(dialog, which)
})
}

View file

@ -19,11 +19,17 @@ public class Stats extends RealmObject {
public static final String INTELLIGENCE = "int";
public static final String CONSTITUTION = "con";
public static final String PERCEPTION = "per";
@StringDef({Stats.STRENGTH, Stats.INTELLIGENCE, Stats.CONSTITUTION, Stats.PERCEPTION})
@Retention(RetentionPolicy.SOURCE)
public @interface StatsTypes {}
public static final String AUTO_ALLOCATE_FLAT = "flat";
public static final String AUTO_ALLOCATE_CLASSBASED = "classbased";
public static final String AUTO_ALLOCATE_TASKBASED = "taskbased";
@StringDef({Stats.AUTO_ALLOCATE_FLAT, Stats.AUTO_ALLOCATE_CLASSBASED, Stats.AUTO_ALLOCATE_TASKBASED})
@Retention(RetentionPolicy.SOURCE)
public @interface AutoAllocationTypes {}
@PrimaryKey
private String userId;

View file

@ -1,5 +1,6 @@
package com.habitrpg.android.habitica.ui.fragments
import android.app.AlertDialog
import android.os.Bundle
import android.support.v4.content.ContextCompat
import android.view.LayoutInflater
@ -8,6 +9,7 @@ import android.view.ViewGroup
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.components.AppComponent
import com.habitrpg.android.habitica.data.InventoryRepository
import com.habitrpg.android.habitica.extensions.setOkButton
import com.habitrpg.android.habitica.helpers.RxErrorHandler
import com.habitrpg.android.habitica.helpers.UserStatComputer
import com.habitrpg.android.habitica.models.user.Stats
@ -51,14 +53,28 @@ class StatsFragment: BaseMainFragment() {
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
super.onCreateView(inflater, container, savedInstanceState)
hideToolbar()
return inflater?.inflate(R.layout.fragment_stats, container, false)
}
override fun onDestroyView() {
showToolbar()
super.onDestroyView()
}
override fun onDestroy() {
inventoryRepository.close()
super.onDestroy()
}
override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
leftSparklesView.setImageBitmap(HabiticaIconsHelper.imageOfAttributeSparklesLeft())
rightSparklesView.setImageBitmap(HabiticaIconsHelper.imageOfAttributeSparklesRight())
distributeEvenlyHelpButton.setImageBitmap(HabiticaIconsHelper.imageOfInfoIcon())
distributeClassHelpButton.setImageBitmap(HabiticaIconsHelper.imageOfInfoIcon())
distributeTaskHelpButton.setImageBitmap(HabiticaIconsHelper.imageOfInfoIcon())
compositeSubscription.add(userRepository.getUser(userId).subscribe(Action1 {
user = it
@ -66,31 +82,49 @@ class StatsFragment: BaseMainFragment() {
updateAttributePoints()
}, RxErrorHandler.handleEmptyError()))
autoAllocationModeWrapper.setOnCheckedChangeListener { _, checkedId ->
val allocationMode = when (checkedId) {
R.id.distributeEvenlyButton -> "flat"
R.id.distributeClassButton -> "classbased"
R.id.distributeTaskButton -> "taskbased"
else -> ""
distributeEvenlyButton.setOnCheckedChangeListener { button, isChecked ->
if (isChecked) {
changeAutoAllocationMode(Stats.AUTO_ALLOCATE_FLAT)
}
userRepository.updateUser(user, "preferences.allocationMode", allocationMode).subscribe(Action1 {}, RxErrorHandler.handleEmptyError())
}
distributeClassButton.setOnCheckedChangeListener { button, isChecked ->
if (isChecked) {
changeAutoAllocationMode(Stats.AUTO_ALLOCATE_CLASSBASED)
}
}
distributeTaskButton.setOnCheckedChangeListener { button, isChecked ->
if (isChecked) {
changeAutoAllocationMode(Stats.AUTO_ALLOCATE_TASKBASED)
}
}
automaticAllocationSwitch.setOnCheckedChangeListener{ _, isChecked ->
userRepository.updateUser(user, "preferences.automaticAllocation", isChecked).subscribe(Action1 {}, RxErrorHandler.handleEmptyError())
}
strengthStatsView.allocateAction = {
allocatePoint(Stats.STRENGTH)
}
intelligenceStatsView.allocateAction = {
allocatePoint(Stats.INTELLIGENCE)
}
constitutionStatsView.allocateAction = {
allocatePoint(Stats.CONSTITUTION)
}
perceptionStatsView.allocateAction = {
allocatePoint(Stats.PERCEPTION)
}
strengthStatsView.allocateAction = { allocatePoint(Stats.STRENGTH) }
intelligenceStatsView.allocateAction = { allocatePoint(Stats.INTELLIGENCE) }
constitutionStatsView.allocateAction = { allocatePoint(Stats.CONSTITUTION) }
perceptionStatsView.allocateAction = { allocatePoint(Stats.PERCEPTION) }
distributeEvenlyHelpButton.setOnClickListener { showHelpAlert(R.string.distribute_evenly_help) }
distributeClassHelpButton.setOnClickListener { showHelpAlert(R.string.distribute_class_help) }
distributeTaskHelpButton.setOnClickListener { showHelpAlert(R.string.distribute_task_help) }
}
private fun changeAutoAllocationMode(@Stats.AutoAllocationTypes allocationMode: String) {
userRepository.updateUser(user, "preferences.allocationMode", allocationMode).subscribe(Action1 {}, RxErrorHandler.handleEmptyError())
distributeEvenlyButton.isChecked = allocationMode == Stats.AUTO_ALLOCATE_FLAT
distributeClassButton.isChecked = allocationMode == Stats.AUTO_ALLOCATE_CLASSBASED
distributeTaskButton.isChecked = allocationMode == Stats.AUTO_ALLOCATE_TASKBASED
}
private fun showHelpAlert(resourceId: Int) {
val builder = AlertDialog.Builder(context)
.setMessage(resourceId)
.setOkButton()
builder.show()
}
private fun allocatePoint(@Stats.StatsTypes stat: String) {
@ -101,18 +135,17 @@ class StatsFragment: BaseMainFragment() {
val automaticAllocation = user?.preferences?.automaticAllocation ?: false
automaticAllocationSwitch.isChecked = automaticAllocation
autoAllocationModeWrapper.visibility = if (automaticAllocation) View.VISIBLE else View.GONE
when (user?.preferences?.allocationMode ?: "") {
"flat" -> distributeEvenlyButton.isChecked = true
"classbased" -> distributeClassButton.isChecked = true
"taskbased" -> distributeTaskButton.isChecked = true
}
val canDistributePoints = !automaticAllocation && 0 < (user?.stats?.points ?: 0)
val allocationMode = user?.preferences?.allocationMode ?: ""
distributeEvenlyButton.isChecked = allocationMode == Stats.AUTO_ALLOCATE_FLAT
distributeClassButton.isChecked = allocationMode == Stats.AUTO_ALLOCATE_CLASSBASED
distributeTaskButton.isChecked = allocationMode == Stats.AUTO_ALLOCATE_TASKBASED
val canDistributePoints =0 < (user?.stats?.points ?: 0)
strengthStatsView.canDistributePoints = canDistributePoints
intelligenceStatsView.canDistributePoints = canDistributePoints
constitutionStatsView.canDistributePoints = canDistributePoints
perceptionStatsView.canDistributePoints = canDistributePoints
numberOfPointsTextView.visibility = View.VISIBLE
if (canDistributePoints) {
val points = user?.stats?.points ?: 0
numberOfPointsTextView.text = getString(R.string.points_to_allocate, points)
@ -121,9 +154,6 @@ class StatsFragment: BaseMainFragment() {
leftSparklesView.visibility = View.VISIBLE
rightSparklesView.visibility = View.VISIBLE
} else {
if (automaticAllocation) {
numberOfPointsTextView.visibility = View.GONE
}
numberOfPointsTextView.text = getString(R.string.no_points_to_allocate)
numberOfPointsTextView.setTextColor(ContextCompat.getColor(context, R.color.gray_300))
numberOfPointsTextView.setBackgroundColor(ContextCompat.getColor(context, R.color.transparent))

View file

@ -16,7 +16,7 @@ import java.util.Stack;
/**
* Created by Phillip Thelen on 17.10.17.
* Created by Phillip Thelen on 18.10.17.
* Copyright © 2017 HabitRPG Inc.. All rights reserved.
*
* Generated by PaintCode
@ -7146,6 +7146,74 @@ public class HabiticaIcons {
canvas.restore();
}
private static class CacheForInfoIcon {
private static Paint paint = new Paint();
private static RectF originalFrame = new RectF(0f, 0f, 20f, 20f);
private static RectF resizedFrame = new RectF();
private static RectF bezierRect = new RectF();
private static Path bezierPath = new Path();
}
public static void drawInfoIcon(Canvas canvas) {
HabiticaIcons.drawInfoIcon(canvas, new RectF(0f, 0f, 20f, 20f), ResizingBehavior.AspectFit);
}
public static void drawInfoIcon(Canvas canvas, RectF targetFrame, ResizingBehavior resizing) {
// General Declarations
Paint paint = CacheForInfoIcon.paint;
// Local Colors
int fillColor18 = Color.argb(255, 154, 98, 255);
// Resize to Target Frame
canvas.save();
RectF resizedFrame = CacheForInfoIcon.resizedFrame;
HabiticaIcons.resizingBehaviorApply(resizing, CacheForInfoIcon.originalFrame, targetFrame, resizedFrame);
canvas.translate(resizedFrame.left, resizedFrame.top);
canvas.scale(resizedFrame.width() / 20f, resizedFrame.height() / 20f);
// Bezier
RectF bezierRect = CacheForInfoIcon.bezierRect;
bezierRect.set(0f, 0f, 20f, 20f);
Path bezierPath = CacheForInfoIcon.bezierPath;
bezierPath.reset();
bezierPath.moveTo(9f, 7f);
bezierPath.lineTo(11f, 7f);
bezierPath.lineTo(11f, 5f);
bezierPath.lineTo(9f, 5f);
bezierPath.lineTo(9f, 7f);
bezierPath.close();
bezierPath.moveTo(10f, 18f);
bezierPath.cubicTo(5.59f, 18f, 2f, 14.41f, 2f, 10f);
bezierPath.cubicTo(2f, 5.59f, 5.59f, 2f, 10f, 2f);
bezierPath.cubicTo(14.41f, 2f, 18f, 5.59f, 18f, 10f);
bezierPath.cubicTo(18f, 14.41f, 14.41f, 18f, 10f, 18f);
bezierPath.lineTo(10f, 18f);
bezierPath.close();
bezierPath.moveTo(10f, 0f);
bezierPath.cubicTo(4.48f, 0f, 0f, 4.48f, 0f, 10f);
bezierPath.cubicTo(0f, 15.52f, 4.48f, 20f, 10f, 20f);
bezierPath.cubicTo(15.52f, 20f, 20f, 15.52f, 20f, 10f);
bezierPath.cubicTo(20f, 4.48f, 15.52f, 0f, 10f, 0f);
bezierPath.lineTo(10f, 0f);
bezierPath.close();
bezierPath.moveTo(9f, 15f);
bezierPath.lineTo(11f, 15f);
bezierPath.lineTo(11f, 9f);
bezierPath.lineTo(9f, 9f);
bezierPath.lineTo(9f, 15f);
bezierPath.close();
paint.reset();
paint.setFlags(Paint.ANTI_ALIAS_FLAG);
bezierPath.setFillType(Path.FillType.EVEN_ODD);
paint.setStyle(Paint.Style.FILL);
paint.setColor(fillColor18);
canvas.drawPath(bezierPath, paint);
canvas.restore();
}
// Canvas Images
// Tab
@ -7550,6 +7618,18 @@ public class HabiticaIcons {
return imageOfAttributeAllocateButton;
}
private static Bitmap imageOfInfoIcon = null;
public static Bitmap imageOfInfoIcon() {
if (imageOfInfoIcon != null)
return imageOfInfoIcon;
imageOfInfoIcon = Bitmap.createBitmap(20, 20, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(imageOfInfoIcon);
HabiticaIcons.drawInfoIcon(canvas);
return imageOfInfoIcon;
}
// Resizing Behavior
public static void resizingBehaviorApply(ResizingBehavior behavior, RectF rect, RectF target, RectF result) {

View file

@ -472,4 +472,18 @@ public class HabiticaIconsHelper {
return imageOfAttributeAllocateButton;
}
private static Bitmap imageOfInfoIcon = null;
public static Bitmap imageOfInfoIcon() {
if (imageOfInfoIcon != null)
return imageOfInfoIcon;
int size = scaleSize(20);
imageOfInfoIcon = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(imageOfInfoIcon);
canvas.scale(displayDensity, displayDensity);
HabiticaIcons.drawInfoIcon(canvas);
return imageOfInfoIcon;
}
}