mirror of
https://github.com/sudoxnym/habitica-android.git
synced 2026-05-21 13:19:02 +00:00
Fix header
This commit is contained in:
parent
4d1a684932
commit
692d8ab723
23 changed files with 229 additions and 315 deletions
|
|
@ -24,7 +24,7 @@
|
|||
app:tabMode="fixed" />
|
||||
|
||||
<android.support.v4.view.ViewPager
|
||||
android:id="@+id/viewpager"
|
||||
android:id="@+id/viewPager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0px"
|
||||
android:layout_weight="1"
|
||||
|
|
|
|||
|
|
@ -190,21 +190,21 @@ class InventoryRepositoryImpl(localRepository: InventoryLocalRepository, apiClie
|
|||
copiedUser.items = buyResponse.items
|
||||
}
|
||||
if (buyResponse.hp != null) {
|
||||
copiedUser.stats.setHp(buyResponse.hp)
|
||||
copiedUser.stats.hp = buyResponse.hp
|
||||
}
|
||||
if (buyResponse.exp != null) {
|
||||
copiedUser.stats.setExp(buyResponse.exp)
|
||||
copiedUser.stats.exp = buyResponse.exp
|
||||
}
|
||||
if (buyResponse.mp != null) {
|
||||
copiedUser.stats.setMp(buyResponse.mp)
|
||||
copiedUser.stats.mp = buyResponse.mp
|
||||
}
|
||||
if (buyResponse.gp != null) {
|
||||
copiedUser.stats.setGp(buyResponse.gp)
|
||||
copiedUser.stats.gp = buyResponse.gp
|
||||
} else {
|
||||
copiedUser.stats.setGp(copiedUser.stats.getGp()!! - value)
|
||||
copiedUser.stats.gp = copiedUser.stats.gp ?: 0 - value
|
||||
}
|
||||
if (buyResponse.lvl != null) {
|
||||
copiedUser.stats.setLvl(buyResponse.lvl)
|
||||
copiedUser.stats.lvl = buyResponse.lvl
|
||||
}
|
||||
localRepository.save(copiedUser)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,11 +71,11 @@ class TaskRepositoryImpl(localRepository: TaskLocalRepository, apiClient: ApiCli
|
|||
val stats = user.stats
|
||||
|
||||
result.taskValueDelta = res.delta
|
||||
result.healthDelta = res.hp - stats.getHp()
|
||||
result.experienceDelta = res.exp - stats.getExp()
|
||||
result.manaDelta = res.mp - stats.getMp()
|
||||
result.goldDelta = res.gp - stats.getGp()
|
||||
result.hasLeveledUp = res.lvl > stats.getLvl()
|
||||
result.healthDelta = res.hp - (stats.hp ?: 0.0)
|
||||
result.experienceDelta = res.exp - (stats.exp ?: 0.0)
|
||||
result.manaDelta = res.mp - (stats.mp ?: 0.0)
|
||||
result.goldDelta = res.gp - (stats.gp ?: 0.0)
|
||||
result.hasLeveledUp = res.lvl > stats.lvl ?: 0
|
||||
result.questDamage = res._tmp.quest?.progressDelta
|
||||
if (res._tmp != null) {
|
||||
result.drop = res._tmp.drop
|
||||
|
|
@ -90,11 +90,11 @@ class TaskRepositoryImpl(localRepository: TaskLocalRepository, apiClient: ApiCli
|
|||
task.completed = up
|
||||
}
|
||||
}
|
||||
stats.setHp(res.hp)
|
||||
stats.setExp(res.exp)
|
||||
stats.setMp(res.mp)
|
||||
stats.setGp(res.gp)
|
||||
stats.setLvl(res.lvl)
|
||||
stats.hp = res.hp
|
||||
stats.exp = res.exp
|
||||
stats.mp = res.mp
|
||||
stats.gp = res.gp
|
||||
stats.lvl = res.lvl
|
||||
user.party?.quest?.progress?.up = (user.party?.quest?.progress?.up ?: 0F) + (res._tmp.quest?.progressDelta?.toFloat() ?: 0F)
|
||||
user.stats = stats
|
||||
}
|
||||
|
|
|
|||
|
|
@ -121,9 +121,9 @@ class UserRepositoryImpl(localRepository: UserLocalRepository, apiClient: ApiCli
|
|||
override fun useSkill(user: User?, key: String, target: String): Flowable<SkillResponse> {
|
||||
return apiClient.useSkill(key, target)
|
||||
.map { response ->
|
||||
response.hpDiff = response.user.stats.getHp() - (user?.stats?.getHp() ?: 0.0)
|
||||
response.expDiff = response.user.stats.getExp() - (user?.stats?.getExp() ?: 0.0)
|
||||
response.goldDiff = response.user.stats.getGp() - (user?.stats?.getGp() ?: 0.0)
|
||||
response.hpDiff = response.user.stats.hp ?: 0 - (user?.stats?.hp ?: 0.0)
|
||||
response.expDiff = response.user.stats.exp ?: 0 - (user?.stats?.exp ?: 0.0)
|
||||
response.goldDiff = response.user.stats.gp ?: 0 - (user?.stats?.gp ?: 0.0)
|
||||
response
|
||||
}
|
||||
.doOnNext { skillResponse ->
|
||||
|
|
@ -211,12 +211,12 @@ class UserRepositoryImpl(localRepository: UserLocalRepository, apiClient: ApiCli
|
|||
if (user != null && user.isManaged) {
|
||||
localRepository.executeTransaction {
|
||||
when (stat) {
|
||||
Stats.STRENGTH -> user.stats.str += 1
|
||||
Stats.INTELLIGENCE -> user.stats._int += 1
|
||||
Stats.CONSTITUTION -> user.stats.con += 1
|
||||
Stats.PERCEPTION -> user.stats.per += 1
|
||||
Stats.STRENGTH -> user.stats.str = user.stats.str?.inc()
|
||||
Stats.INTELLIGENCE -> user.stats._int = user.stats._int?.inc()
|
||||
Stats.CONSTITUTION -> user.stats.con= user.stats.con?.inc()
|
||||
Stats.PERCEPTION -> user.stats.per = user.stats.per?.inc()
|
||||
}
|
||||
user.stats.points -= 1
|
||||
user.stats.points = user.stats.points?.dec()
|
||||
}
|
||||
}
|
||||
return apiClient.allocatePoint(stat)
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ class RealmUserLocalRepository(realm: Realm) : RealmBaseLocalRepository(realm),
|
|||
val habitClass = if (user.preferences.disableClasses) "none" else user.stats.habitClass
|
||||
return realm.where(Skill::class.java)
|
||||
.equalTo("habitClass", habitClass)
|
||||
.lessThanOrEqualTo("lvl", user.stats.lvl)
|
||||
.lessThanOrEqualTo("lvl", user.stats.lvl ?: 0)
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { it.isLoaded }
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ public class Member extends RealmObject implements Avatar {
|
|||
|
||||
@Override
|
||||
public boolean hasClass() {
|
||||
return getPreferences() != null && (!getPreferences().getDisableClasses() && getStats().habitClass.length() != 0);
|
||||
return getPreferences() != null && (!getPreferences().getDisableClasses() && getStats().getHabitClass().length() != 0);
|
||||
}
|
||||
|
||||
public void setEquipped(Outfit equipped) {
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ open class ShopItem : RealmObject() {
|
|||
get() = "pets" == purchaseType || "mounts" == purchaseType
|
||||
|
||||
fun canAfford(user: User?): Boolean = when(currency) {
|
||||
"gold" -> value <= user?.stats?.getGp() ?: 0.0
|
||||
"gold" -> value <= user?.stats?.gp ?: 0.0
|
||||
"gems" -> value <= user?.gemCount ?: 0
|
||||
"hourglasses" -> value <= user?.purchased?.plan?.consecutive?.trinkets ?: 0
|
||||
else -> false
|
||||
|
|
|
|||
|
|
@ -1,215 +0,0 @@
|
|||
package com.habitrpg.android.habitica.models.user;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.StringDef;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import com.habitrpg.android.habitica.R;
|
||||
import com.habitrpg.android.habitica.models.HabitRpgClass;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
import io.realm.RealmObject;
|
||||
import io.realm.annotations.PrimaryKey;
|
||||
|
||||
|
||||
public class Stats extends RealmObject {
|
||||
public static final String STRENGTH = "str";
|
||||
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 WARRIOR = "warrior";
|
||||
public static final String MAGE = "wizard";
|
||||
public static final String HEALER = "healer";
|
||||
public static final String ROGUE = "rogue";
|
||||
@StringDef({Stats.WARRIOR, Stats.MAGE, Stats.HEALER, Stats.ROGUE})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface HabiticaClassTypes {}
|
||||
|
||||
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;
|
||||
|
||||
User user;
|
||||
public Integer con, str, per;
|
||||
@SerializedName("int")
|
||||
public Integer _int;
|
||||
public Training training;
|
||||
public Buffs buffs;
|
||||
public Integer points, lvl;
|
||||
@SerializedName("class")
|
||||
@HabiticaClassTypes
|
||||
public String habitClass;
|
||||
public Double gp, exp, mp, hp;
|
||||
private Integer toNextLevel, maxHealth, maxMP;
|
||||
|
||||
|
||||
public Integer getToNextLevel() {
|
||||
return toNextLevel != null ? toNextLevel : Integer.valueOf(0);
|
||||
}
|
||||
|
||||
public void setToNextLevel(Integer toNextLevel) {
|
||||
if (toNextLevel != 0) {
|
||||
this.toNextLevel = toNextLevel;
|
||||
}
|
||||
}
|
||||
|
||||
public Integer getMaxHealth() {
|
||||
return maxHealth != null ? maxHealth : Integer.valueOf(50);
|
||||
}
|
||||
|
||||
public void setMaxHealth(Integer maxHealth) {
|
||||
this.maxHealth = maxHealth;
|
||||
}
|
||||
|
||||
public Integer getMaxMP() {
|
||||
return maxMP != null ? maxMP : Integer.valueOf(0);
|
||||
}
|
||||
|
||||
public void setMaxMP(Integer maxMP) {
|
||||
if (maxMP != 0) {
|
||||
this.maxMP = maxMP;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public String getTranslatedClassName(Context context) {
|
||||
switch (habitClass) {
|
||||
case HEALER:
|
||||
return context.getString(R.string.healer);
|
||||
case ROGUE:
|
||||
return context.getString(R.string.rogue);
|
||||
case WARRIOR:
|
||||
return context.getString(R.string.warrior);
|
||||
case MAGE:
|
||||
return context.getString(R.string.mage);
|
||||
default:
|
||||
return context.getString(R.string.warrior);
|
||||
}
|
||||
}
|
||||
|
||||
public void merge(Stats stats) {
|
||||
if (stats == null) {
|
||||
return;
|
||||
}
|
||||
this.con = stats.con != null ? stats.con : this.con;
|
||||
this.str = stats.str != null ? stats.str : this.str;
|
||||
this.per = stats.per != null ? stats.per : this.per;
|
||||
this._int = stats._int != null ? stats._int : this._int;
|
||||
if (training != null) {
|
||||
this.training.merge(stats.training);
|
||||
}
|
||||
if (buffs != null) {
|
||||
this.buffs.merge(stats.buffs);
|
||||
}
|
||||
this.points = stats.points != null ? stats.points : this.points;
|
||||
this.lvl = stats.lvl != null ? stats.lvl : this.lvl;
|
||||
this.habitClass = stats.habitClass != null ? stats.habitClass : this.habitClass;
|
||||
this.gp = stats.gp != null ? stats.gp : this.gp;
|
||||
this.exp = stats.exp != null ? stats.exp : this.exp;
|
||||
this.hp = stats.hp != null ? stats.hp : this.hp;
|
||||
this.mp = stats.mp != null ? stats.mp : this.mp;
|
||||
this.toNextLevel = stats.toNextLevel != null ? stats.toNextLevel : this.toNextLevel;
|
||||
this.maxHealth = stats.maxHealth != null ? stats.maxHealth : this.maxHealth;
|
||||
this.maxMP = stats.maxMP != null ? stats.maxMP : this.maxMP;
|
||||
}
|
||||
|
||||
public String getHabitClass() {
|
||||
return habitClass;
|
||||
}
|
||||
|
||||
public void setHabitClass(String habitClass) {
|
||||
this.habitClass = habitClass;
|
||||
}
|
||||
|
||||
public Double getGp() {
|
||||
return gp;
|
||||
}
|
||||
|
||||
public Double getExp() {
|
||||
return exp;
|
||||
}
|
||||
|
||||
public Double getHp() {
|
||||
return hp;
|
||||
}
|
||||
|
||||
public Double getMp() {
|
||||
return mp;
|
||||
}
|
||||
|
||||
public Integer getLvl() {
|
||||
return lvl;
|
||||
}
|
||||
|
||||
public void setExp(double exp) {
|
||||
this.exp = exp;
|
||||
}
|
||||
|
||||
public void setHp(double hp) {
|
||||
this.hp = hp;
|
||||
}
|
||||
|
||||
public void setGp(double gp) {
|
||||
this.gp = gp;
|
||||
}
|
||||
|
||||
public void setMp(double mp) {
|
||||
this.mp = mp;
|
||||
}
|
||||
|
||||
public void setLvl(Integer lvl) {
|
||||
this.lvl = lvl;
|
||||
}
|
||||
|
||||
public Buffs getBuffs() {
|
||||
return buffs;
|
||||
}
|
||||
|
||||
public Integer getStr() {
|
||||
return str;
|
||||
}
|
||||
|
||||
public Integer get_int() {
|
||||
return _int;
|
||||
}
|
||||
|
||||
public Integer getCon() {
|
||||
return con;
|
||||
}
|
||||
|
||||
public Integer getPer() {
|
||||
return per;
|
||||
}
|
||||
|
||||
public void setHabitClass(HabitRpgClass habitRpgClass) {
|
||||
habitClass = habitRpgClass.toString();
|
||||
}
|
||||
|
||||
public String getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void setUserId(String userId) {
|
||||
this.userId = userId;
|
||||
if (buffs != null && !buffs.isManaged()) {
|
||||
buffs.setUserId(userId);
|
||||
}
|
||||
if (training != null && !training.isManaged()) {
|
||||
training.setUserId(userId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
package com.habitrpg.android.habitica.models.user
|
||||
|
||||
import android.content.Context
|
||||
import android.support.annotation.StringDef
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.models.HabitRpgClass
|
||||
|
||||
import java.lang.annotation.Retention
|
||||
import java.lang.annotation.RetentionPolicy
|
||||
|
||||
import io.realm.RealmObject
|
||||
import io.realm.annotations.PrimaryKey
|
||||
|
||||
|
||||
open class Stats : RealmObject() {
|
||||
|
||||
@PrimaryKey
|
||||
var userId: String? = null
|
||||
set(userId) {
|
||||
field = userId
|
||||
if (buffs?.isManaged == false) {
|
||||
buffs?.userId = userId
|
||||
}
|
||||
if (training?.isManaged == false) {
|
||||
training?.userId = userId
|
||||
}
|
||||
}
|
||||
|
||||
internal var user: User? = null
|
||||
var con: Int? = null
|
||||
var str: Int? = null
|
||||
var per: Int? = null
|
||||
@SerializedName("int")
|
||||
var _int: Int? = null
|
||||
var training: Training? = null
|
||||
var buffs: Buffs? = null
|
||||
var points: Int? = null
|
||||
var lvl: Int? = null
|
||||
@SerializedName("class")
|
||||
@HabiticaClassTypes
|
||||
var habitClass: String? = null
|
||||
var gp: Double? = null
|
||||
var exp: Double? = null
|
||||
var mp: Double? = null
|
||||
var hp: Double? = null
|
||||
var toNextLevel: Int? = null
|
||||
get() = if (field != null) field else 0
|
||||
set(value) {
|
||||
if (value != 0) {
|
||||
field = value
|
||||
}
|
||||
}
|
||||
var maxHealth: Int? = null
|
||||
get() = if (field != null) field else 0
|
||||
set(value) {
|
||||
if (value != 0) {
|
||||
field = value
|
||||
}
|
||||
}
|
||||
var maxMP: Int? = null
|
||||
get() = if (field != null) field else 0
|
||||
set(value) {
|
||||
if (value != 0) {
|
||||
field = value
|
||||
}
|
||||
}
|
||||
|
||||
@StringDef(Stats.STRENGTH, Stats.INTELLIGENCE, Stats.CONSTITUTION, Stats.PERCEPTION)
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
annotation class StatsTypes
|
||||
|
||||
@StringDef(Stats.WARRIOR, Stats.MAGE, Stats.HEALER, Stats.ROGUE)
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
annotation class HabiticaClassTypes
|
||||
|
||||
@StringDef(Stats.AUTO_ALLOCATE_FLAT, Stats.AUTO_ALLOCATE_CLASSBASED, Stats.AUTO_ALLOCATE_TASKBASED)
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
annotation class AutoAllocationTypes
|
||||
|
||||
fun getTranslatedClassName(context: Context): String {
|
||||
return when (habitClass) {
|
||||
HEALER -> context.getString(R.string.healer)
|
||||
ROGUE -> context.getString(R.string.rogue)
|
||||
WARRIOR -> context.getString(R.string.warrior)
|
||||
MAGE -> context.getString(R.string.mage)
|
||||
else -> context.getString(R.string.warrior)
|
||||
}
|
||||
}
|
||||
|
||||
fun merge(stats: Stats?) {
|
||||
if (stats == null) {
|
||||
return
|
||||
}
|
||||
this.con = if (stats.con != null) stats.con else this.con
|
||||
this.str = if (stats.str != null) stats.str else this.str
|
||||
this.per = if (stats.per != null) stats.per else this.per
|
||||
this._int = if (stats._int != null) stats._int else this._int
|
||||
this.training?.merge(stats.training)
|
||||
this.buffs?.merge(stats.buffs)
|
||||
this.points = if (stats.points != null) stats.points else this.points
|
||||
this.lvl = if (stats.lvl != null) stats.lvl else this.lvl
|
||||
this.habitClass = if (stats.habitClass != null) stats.habitClass else this.habitClass
|
||||
this.gp = if (stats.gp != null) stats.gp else this.gp
|
||||
this.exp = if (stats.exp != null) stats.exp else this.exp
|
||||
this.hp = if (stats.hp != null) stats.hp else this.hp
|
||||
this.mp = if (stats.mp != null) stats.mp else this.mp
|
||||
this.toNextLevel = if (stats.toNextLevel != null) stats.toNextLevel else this.toNextLevel
|
||||
this.maxHealth = if (stats.maxHealth != null) stats.maxHealth else this.maxHealth
|
||||
this.maxMP = if (stats.maxMP != null) stats.maxMP else this.maxMP
|
||||
}
|
||||
|
||||
fun setHabitClass(habitRpgClass: HabitRpgClass) {
|
||||
habitClass = habitRpgClass.toString()
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val STRENGTH = "str"
|
||||
const val INTELLIGENCE = "int"
|
||||
const val CONSTITUTION = "con"
|
||||
const val PERCEPTION = "per"
|
||||
|
||||
|
||||
const val WARRIOR = "warrior"
|
||||
const val MAGE = "wizard"
|
||||
const val HEALER = "healer"
|
||||
const val ROGUE = "rogue"
|
||||
|
||||
const val AUTO_ALLOCATE_FLAT = "flat"
|
||||
const val AUTO_ALLOCATE_CLASSBASED = "classbased"
|
||||
const val AUTO_ALLOCATE_TASKBASED = "taskbased"
|
||||
}
|
||||
}
|
||||
|
|
@ -216,7 +216,7 @@ public class User extends RealmObject implements Avatar {
|
|||
|
||||
@Override
|
||||
public boolean hasClass() {
|
||||
return getPreferences() != null && getFlags() != null && (!getPreferences().getDisableClasses() && getFlags().getClassSelected() && getStats().habitClass.length() != 0);
|
||||
return getPreferences() != null && getFlags() != null && (!getPreferences().getDisableClasses() && getFlags().getClassSelected() && getStats().getHabitClass().length() != 0);
|
||||
}
|
||||
|
||||
public void setBalance(double balance) {
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ class AvatarView : View {
|
|||
}
|
||||
|
||||
override fun onFailure(id: String?, throwable: Throwable?) {
|
||||
Log.e(TAG, "Error loading layer: " + layerName, throwable)
|
||||
Log.e(TAG, "Error loading layer: $layerName", throwable)
|
||||
onLayerComplete()
|
||||
}
|
||||
})
|
||||
|
|
@ -162,20 +162,20 @@ class AvatarView : View {
|
|||
|
||||
val mountName = avatar.currentMount
|
||||
if (showMount && !TextUtils.isEmpty(mountName)) {
|
||||
layerMap[LayerType.MOUNT_BODY] = "Mount_Body_" + mountName
|
||||
layerMap[LayerType.MOUNT_HEAD] = "Mount_Head_" + mountName
|
||||
layerMap[LayerType.MOUNT_BODY] = "Mount_Body_$mountName"
|
||||
layerMap[LayerType.MOUNT_HEAD] = "Mount_Head_$mountName"
|
||||
if (resetHasAttributes) hasMount = true
|
||||
}
|
||||
|
||||
val petName = avatar.currentPet
|
||||
if (showPet && !TextUtils.isEmpty(petName)) {
|
||||
layerMap[LayerType.PET] = "Pet-" + petName
|
||||
layerMap[LayerType.PET] = "Pet-$petName"
|
||||
if (resetHasAttributes) hasPet = true
|
||||
}
|
||||
|
||||
val backgroundName = avatar.background
|
||||
if (showBackground && !TextUtils.isEmpty(backgroundName)) {
|
||||
layerMap[LayerType.BACKGROUND] = "background_" + backgroundName
|
||||
layerMap[LayerType.BACKGROUND] = "background_$backgroundName"
|
||||
if (resetHasAttributes) hasBackground = true
|
||||
}
|
||||
|
||||
|
|
@ -202,25 +202,25 @@ class AvatarView : View {
|
|||
|
||||
var hasVisualBuffs = false
|
||||
|
||||
if (avatar.stats != null && avatar.stats.getBuffs() != null) {
|
||||
val buffs = avatar.stats.getBuffs()
|
||||
if (avatar.stats != null && avatar.stats.buffs != null) {
|
||||
val buffs = avatar.stats.buffs
|
||||
|
||||
if (buffs.snowball) {
|
||||
if (buffs?.snowball == true) {
|
||||
layerMap[AvatarView.LayerType.VISUAL_BUFF] = "snowman"
|
||||
hasVisualBuffs = true
|
||||
}
|
||||
|
||||
if (buffs.seafoam) {
|
||||
if (buffs?.seafoam == true) {
|
||||
layerMap[AvatarView.LayerType.VISUAL_BUFF] = "seafoam_star"
|
||||
hasVisualBuffs = true
|
||||
}
|
||||
|
||||
if (buffs.shinySeed) {
|
||||
layerMap[AvatarView.LayerType.VISUAL_BUFF] = "avatar_floral_" + avatar.stats.getHabitClass()
|
||||
if (buffs?.shinySeed == true) {
|
||||
layerMap[AvatarView.LayerType.VISUAL_BUFF] = "avatar_floral_" + avatar.stats.habitClass
|
||||
hasVisualBuffs = true
|
||||
}
|
||||
|
||||
if (buffs.spookySparkles) {
|
||||
if (buffs?.spookySparkles == true) {
|
||||
layerMap[AvatarView.LayerType.VISUAL_BUFF] = "ghost"
|
||||
hasVisualBuffs = true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import android.os.Build
|
|||
import android.view.View
|
||||
import android.widget.TextView
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.data.UserRepository
|
||||
import com.habitrpg.android.habitica.events.BoughtGemsEvent
|
||||
import com.habitrpg.android.habitica.events.commands.OpenGemPurchaseFragmentCommand
|
||||
import com.habitrpg.android.habitica.events.commands.OpenMenuItemCommand
|
||||
|
|
@ -19,11 +20,12 @@ import com.habitrpg.android.habitica.ui.helpers.bindView
|
|||
import com.habitrpg.android.habitica.ui.views.CurrencyViews
|
||||
import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper
|
||||
import com.habitrpg.android.habitica.ui.views.ValueBar
|
||||
import io.reactivex.disposables.Disposable
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import java.util.*
|
||||
|
||||
class AvatarWithBarsViewModel(private val context: Context, view: View) {
|
||||
class AvatarWithBarsViewModel(private val context: Context, view: View, userRepository: UserRepository? = null) {
|
||||
private val hpBar: ValueBar by bindView(view, R.id.hpBar)
|
||||
private val xpBar: ValueBar by bindView(view, R.id.xpBar)
|
||||
private val mpBar: ValueBar by bindView(view, R.id.mpBar)
|
||||
|
|
@ -37,6 +39,8 @@ class AvatarWithBarsViewModel(private val context: Context, view: View) {
|
|||
private var cachedMaxExp: Int = 0
|
||||
private var cachedMaxMana: Int = 0
|
||||
|
||||
private var disposable: Disposable? = null
|
||||
|
||||
init {
|
||||
hpBar.setIcon(HabiticaIconsHelper.imageOfHeartLightBg())
|
||||
xpBar.setIcon(HabiticaIconsHelper.imageOfExperience())
|
||||
|
|
@ -45,6 +49,10 @@ class AvatarWithBarsViewModel(private val context: Context, view: View) {
|
|||
setHpBarData(0f, 50)
|
||||
setXpBarData(0f, 1)
|
||||
setMpBarData(0f, 1)
|
||||
|
||||
if (userRepository != null) {
|
||||
disposable = userRepository.getUser().subscribe { updateData(it) }
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
|
||||
|
|
@ -57,39 +65,36 @@ class AvatarWithBarsViewModel(private val context: Context, view: View) {
|
|||
|
||||
avatarView.setAvatar(user)
|
||||
|
||||
if (stats.getHabitClass() != null) {
|
||||
if (stats.habitClass != null) {
|
||||
userClass = stats.getTranslatedClassName(context)
|
||||
}
|
||||
|
||||
mpBar.visibility = if (stats.getHabitClass() == null || stats.getLvl() < 10 || user.preferences.disableClasses) View.GONE else View.VISIBLE
|
||||
mpBar.visibility = if (stats.habitClass == null || stats.lvl ?: 0 < 10 || user.preferences.disableClasses) View.GONE else View.VISIBLE
|
||||
|
||||
if (!user.hasClass()) {
|
||||
lvlText.text = context.getString(R.string.user_level, user.stats.getLvl())
|
||||
lvlText.text = context.getString(R.string.user_level, user.stats.lvl)
|
||||
lvlText.setCompoundDrawables(null, null, null, null)
|
||||
} else {
|
||||
lvlText.text = context.getString(R.string.user_level_with_class, user.stats.getLvl(), userClass.substring(0, 1).toUpperCase(Locale.getDefault()) + userClass.substring(1))
|
||||
lvlText.text = context.getString(R.string.user_level_with_class, user.stats.lvl, userClass.substring(0, 1).toUpperCase(Locale.getDefault()) + userClass.substring(1))
|
||||
var drawable: Drawable? = null
|
||||
when (stats.getHabitClass()) {
|
||||
when (stats.habitClass) {
|
||||
Stats.WARRIOR -> drawable = BitmapDrawable(context.resources, HabiticaIconsHelper.imageOfWarriorDarkBg())
|
||||
Stats.ROGUE -> drawable = BitmapDrawable(context.resources, HabiticaIconsHelper.imageOfRogueDarkBg())
|
||||
Stats.MAGE -> drawable = BitmapDrawable(context.resources, HabiticaIconsHelper.imageOfMageDarkBg())
|
||||
Stats.HEALER -> drawable = BitmapDrawable(context.resources, HabiticaIconsHelper.imageOfHealerDarkBg())
|
||||
}
|
||||
if (drawable != null) {
|
||||
drawable.setBounds(0, 0, drawable.minimumWidth,
|
||||
drawable.minimumHeight)
|
||||
}
|
||||
drawable?.setBounds(0, 0, drawable.minimumWidth, drawable.minimumHeight)
|
||||
lvlText.setCompoundDrawables(drawable, null, null, null)
|
||||
}
|
||||
|
||||
setHpBarData(stats.hp.toFloat(), stats.maxHealth)
|
||||
setXpBarData(stats.exp.toFloat(), stats.toNextLevel)
|
||||
setMpBarData(stats.mp.toFloat(), stats.maxMP)
|
||||
setHpBarData(stats.hp?.toFloat() ?: 0.toFloat(), stats.maxHealth ?: 0)
|
||||
setXpBarData(stats.exp?.toFloat() ?: 0.toFloat(), stats.toNextLevel ?: 0)
|
||||
setMpBarData(stats.mp?.toFloat() ?: 0.toFloat(), stats.maxMP ?: 0)
|
||||
|
||||
currencyView.gold = stats.getGp()
|
||||
currencyView.gold = stats.gp ?: 0.0
|
||||
if (user is User) {
|
||||
currencyView.hourglasses = user.getHourglassCount().toDouble()
|
||||
currencyView.gems = user.getGemCount().toDouble()
|
||||
currencyView.gems = user.gemCount.toDouble()
|
||||
}
|
||||
|
||||
currencyView.setOnClickListener {
|
||||
|
|
@ -137,14 +142,13 @@ class AvatarWithBarsViewModel(private val context: Context, view: View) {
|
|||
}
|
||||
|
||||
companion object {
|
||||
|
||||
fun setHpBarData(valueBar: ValueBar, stats: Stats) {
|
||||
var maxHP = stats.maxHealth
|
||||
if (maxHP == null || maxHP == 0) {
|
||||
maxHP = 50
|
||||
}
|
||||
|
||||
valueBar.set(Math.ceil(stats.hp.toDouble()), maxHP.toDouble())
|
||||
valueBar.set(Math.ceil(stats.hp ?: 0.0), maxHP.toDouble())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -300,7 +300,7 @@ class FullProfileActivity : BaseActivity() {
|
|||
}
|
||||
|
||||
private fun addLevelAttributes(user: Member) {
|
||||
val byLevelStat = Math.min(user.stats.getLvl() / 2.0f, 50f)
|
||||
val byLevelStat = Math.min((user.stats.lvl ?: 0) / 2.0f, 50f)
|
||||
|
||||
addAttributeRow(getString(R.string.profile_level), byLevelStat, byLevelStat, byLevelStat, byLevelStat, true, false)
|
||||
}
|
||||
|
|
@ -353,10 +353,10 @@ class FullProfileActivity : BaseActivity() {
|
|||
}
|
||||
|
||||
private fun addNormalAddBuffAttributes(stats: Stats) {
|
||||
val buffs = stats.getBuffs()
|
||||
val buffs = stats.buffs
|
||||
|
||||
addAttributeRow(getString(R.string.profile_allocated), stats.getStr().toFloat(), stats.get_int().toFloat(), stats.getCon().toFloat(), stats.getPer().toFloat(), true, false)
|
||||
addAttributeRow(getString(R.string.profile_boosts), buffs.getStr(), buffs.get_int(), buffs.getCon(), buffs.getPer(), true, false)
|
||||
addAttributeRow(getString(R.string.profile_allocated), stats.str?.toFloat() ?: 0f, stats._int?.toFloat() ?: 0f, stats.con?.toFloat() ?: 0f, stats.per?.toFloat() ?: 0f, true, false)
|
||||
addAttributeRow(getString(R.string.profile_boosts), buffs?.getStr() ?: 0f, buffs?.get_int() ?: 0f, buffs?.getCon() ?: 0f, buffs?.getPer() ?: 0f, true, false)
|
||||
|
||||
// Summary row
|
||||
addAttributeRow("", attributeStrSum, attributeIntSum, attributeConSum, attributePerSum, false, true)
|
||||
|
|
|
|||
|
|
@ -188,7 +188,7 @@ open class MainActivity : BaseActivity(), TutorialView.OnTutorialReaction {
|
|||
|
||||
setupToolbar(toolbar)
|
||||
|
||||
avatarInHeader = AvatarWithBarsViewModel(this, avatarWithBars)
|
||||
avatarInHeader = AvatarWithBarsViewModel(this, avatarWithBars, userRepository)
|
||||
sideAvatarView = AvatarView(this, true, false, false)
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
|
|
@ -202,11 +202,11 @@ open class MainActivity : BaseActivity(), TutorialView.OnTutorialReaction {
|
|||
avatarWithBars.setPadding(px.toInt(), statusBarHeight, px.toInt(), 0)
|
||||
}
|
||||
|
||||
userRepository.getUser(hostConfig.user)
|
||||
compositeSubscription.add(userRepository.getUser(hostConfig.user)
|
||||
.subscribe(Consumer { newUser ->
|
||||
this@MainActivity.user = newUser
|
||||
this@MainActivity.setUserData()
|
||||
}, RxErrorHandler.handleEmptyError())
|
||||
}, RxErrorHandler.handleEmptyError()))
|
||||
|
||||
val drawerLayout = findViewById<DrawerLayout>(R.id.drawer_layout)
|
||||
|
||||
|
|
@ -340,13 +340,11 @@ open class MainActivity : BaseActivity(), TutorialView.OnTutorialReaction {
|
|||
|
||||
private fun setUserData() {
|
||||
if (user != null) {
|
||||
|
||||
val preferences = user?.preferences
|
||||
|
||||
preferences?.language.notNull { apiClient.setLanguageCode(it) }
|
||||
preferences?.language.notNull { soundManager.soundTheme = it }
|
||||
runOnUiThread {
|
||||
updateHeader()
|
||||
updateSidebar()
|
||||
if (activeFragment != null && activeFragment?.get() != null) {
|
||||
activeFragment?.get()?.updateUserData(user)
|
||||
|
|
@ -387,13 +385,6 @@ open class MainActivity : BaseActivity(), TutorialView.OnTutorialReaction {
|
|||
}*/
|
||||
}
|
||||
|
||||
private fun updateHeader() {
|
||||
user.notNull { avatarInHeader?.updateData(it) }
|
||||
if (activeFragment != null) {
|
||||
setTranslatedFragmentTitle(activeFragment?.get())
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateSidebar() {
|
||||
drawerFragment?.setUsername(user?.profile?.name)
|
||||
|
||||
|
|
@ -411,7 +402,7 @@ open class MainActivity : BaseActivity(), TutorialView.OnTutorialReaction {
|
|||
if (user?.hasClass() == false && (!hasSpecialItems)) {
|
||||
item.isVisible = false
|
||||
} else {
|
||||
if (user?.stats?.getLvl() ?: 0 < HabiticaSnackbar.MIN_LEVEL_FOR_SKILLS && (!hasSpecialItems)) {
|
||||
if (user?.stats?.lvl ?: 0 < HabiticaSnackbar.MIN_LEVEL_FOR_SKILLS && (!hasSpecialItems)) {
|
||||
item.additionalInfo = getString(R.string.unlock_lvl_11)
|
||||
} else {
|
||||
item.additionalInfo = null
|
||||
|
|
@ -493,13 +484,13 @@ open class MainActivity : BaseActivity(), TutorialView.OnTutorialReaction {
|
|||
fun onEvent(event: BuyRewardCommand) {
|
||||
val rewardKey = event.Reward.id
|
||||
|
||||
if (user?.stats?.getGp() ?: 0.toDouble() < event.Reward.value) {
|
||||
if (user?.stats?.gp ?: 0.toDouble() < event.Reward.value) {
|
||||
HabiticaSnackbar.showSnackbar(floatingMenuWrapper, getString(R.string.no_gold), SnackbarDisplayType.FAILURE)
|
||||
return
|
||||
}
|
||||
|
||||
if ("potion" == rewardKey) {
|
||||
val currentHp = user?.stats?.getHp()?.toInt()
|
||||
val currentHp = user?.stats?.gp?.toInt()
|
||||
val maxHp = user?.stats?.maxHealth
|
||||
|
||||
if (currentHp == maxHp) {
|
||||
|
|
@ -646,7 +637,7 @@ open class MainActivity : BaseActivity(), TutorialView.OnTutorialReaction {
|
|||
|
||||
private fun displayDeathDialogIfNeeded() {
|
||||
|
||||
if (user?.stats?.getHp() == null || user?.stats?.getHp() ?: 0.toDouble() > 0) {
|
||||
if (user?.stats?.hp ?: 0.0 > 0) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ class SkillsRecyclerViewAdapter : RecyclerView.Adapter<SkillsRecyclerViewAdapter
|
|||
private val magicDrawable: Drawable
|
||||
private val skillImageView: SimpleDraweeView by bindView(R.id.skill_image)
|
||||
private val skillNameTextView: TextView by bindView(R.id.skill_text)
|
||||
private val skillNotesTextView: TextView by bindView(R.id.skill_image)
|
||||
private val skillNotesTextView: TextView by bindView(R.id.skill_notes)
|
||||
private val priceButton: Button by bindView(itemView, R.id.price_button)
|
||||
|
||||
var skill: Skill? = null
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ class PartyMemberRecyclerViewAdapter(data: OrderedRealmCollection<Member>?, auto
|
|||
|
||||
AvatarWithBarsViewModel.setHpBarData(hpBar, user.stats)
|
||||
|
||||
lvl.text = itemView.context.getString(R.string.user_level, user.stats.getLvl())
|
||||
lvl.text = itemView.context.getString(R.string.user_level, user.stats.lvl)
|
||||
|
||||
classLabel.text = user.stats.getTranslatedClassName(itemView.context)
|
||||
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ class StatsFragment: BaseMainFragment() {
|
|||
|
||||
statsAllocationButton.setOnClickListener {
|
||||
if (user?.stats?.points ?: 0 > 0) {
|
||||
val lvl = user?.stats?.getLvl()
|
||||
val lvl = user?.stats?.lvl
|
||||
if (lvl != null && lvl >= 10) {
|
||||
showBulkAllocateDialog()
|
||||
}
|
||||
|
|
@ -204,7 +204,7 @@ class StatsFragment: BaseMainFragment() {
|
|||
|
||||
private fun updateStats() {
|
||||
val currentUser = user ?: return
|
||||
val levelStat = Math.min(currentUser.stats.getLvl() / 2.0f, 50f).toInt()
|
||||
val levelStat = Math.min((currentUser.stats.lvl ?: 0) / 2.0f, 50f).toInt()
|
||||
|
||||
totalStrength = levelStat
|
||||
totalIntelligence = levelStat
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ class ShopsFragment : BaseMainFragment() {
|
|||
if (user == null) {
|
||||
return
|
||||
}
|
||||
currencyView.gold = user?.stats?.getGp()?.toDouble() ?: 0.0
|
||||
currencyView.gold = user?.stats?.gp ?: 0.0
|
||||
currencyView.gems = user?.gemCount?.toDouble() ?: 0.0
|
||||
currencyView.hourglasses = user?.hourglassCount?.toDouble() ?: 0.0
|
||||
}
|
||||
|
|
|
|||
|
|
@ -226,7 +226,7 @@ class PreferencesFragment : BasePreferencesFragment(), SharedPreferences.OnShare
|
|||
|
||||
fun setUser(user: User?) {
|
||||
this.user = user
|
||||
if (10 <= user?.stats?.getLvl() ?: 0) {
|
||||
if (10 <= user?.stats?.lvl ?: 0) {
|
||||
if (user?.flags?.classSelected == true) {
|
||||
if (user.preferences.disableClasses) {
|
||||
classSelectionPreference?.title = getString(R.string.enable_class)
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ class SkillsFragment : BaseMainFragment() {
|
|||
return
|
||||
}
|
||||
|
||||
adapter?.mana = this.user?.stats?.getMp() ?: 0.toDouble()
|
||||
adapter?.mana = this.user?.stats?.mp ?: 0.toDouble()
|
||||
|
||||
user?.let {
|
||||
Observable.concat(userRepository.getSkills(it).firstElement().toObservable().flatMap { Observable.fromIterable(it) }, userRepository.getSpecialItems(it).firstElement().toObservable().flatMap { Observable.fromIterable(it) })
|
||||
|
|
@ -108,7 +108,7 @@ class SkillsFragment : BaseMainFragment() {
|
|||
|
||||
private fun displaySkillResult(usedSkill: Skill?, response: SkillResponse) {
|
||||
removeProgressDialog()
|
||||
adapter?.mana = response.user.stats.mp
|
||||
adapter?.mana = response.user.stats.mp ?: 0.0
|
||||
val activity = activity ?: return
|
||||
if ("special" == usedSkill?.habitClass) {
|
||||
showSnackbar(activity.floatingMenuWrapper, context!!.getString(R.string.used_skill_without_mana, usedSkill.text), HabiticaSnackbar.SnackbarDisplayType.BLUE)
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ class PartyFragment : BaseMainFragment() {
|
|||
@Inject
|
||||
internal lateinit var inventoryRepository: InventoryRepository
|
||||
|
||||
private val viewPager: ViewPager? by bindView(R.id.viewpager)
|
||||
private val viewPager: ViewPager? by bindView(R.id.viewPager)
|
||||
private var group: Group? = null
|
||||
private var partyMemberListFragment: PartyMemberListFragment? = null
|
||||
private var chatListFragment: ChatListFragment? = null
|
||||
|
|
|
|||
|
|
@ -30,13 +30,13 @@ abstract class BaseTaskViewHolder constructor(itemView: View) : RecyclerView.Vie
|
|||
private val titleTextView: EmojiTextView by bindView(itemView, R.id.checkedTextView)
|
||||
private val notesTextView: EmojiTextView by bindView(itemView, R.id.notesTextView)
|
||||
internal val rightBorderView: View? by bindOptionalView(itemView, R.id.rightBorderView)
|
||||
protected val taskGray: Int by bindColor(itemView.context, R.color.task_gray)
|
||||
protected val specialTaskTextView: TextView? by bindOptionalView(itemView, R.id.specialTaskText)
|
||||
private val iconViewChallenge: ImageView by bindView(itemView, R.id.iconviewChallenge)
|
||||
private val iconViewChallenge: ImageView? by bindView(itemView, R.id.iconviewChallenge)
|
||||
private val iconViewReminder: ImageView? by bindOptionalView(itemView, R.id.iconviewReminder)
|
||||
private val iconViewTag: ImageView by bindView(itemView, R.id.iconviewTag)
|
||||
private val taskIconWrapper: LinearLayout by bindView(itemView, R.id.taskIconWrapper)
|
||||
private val approvalRequiredTextView: TextView by bindView(itemView, R.id.approvalRequiredTextField)
|
||||
private val iconViewTag: ImageView? by bindView(itemView, R.id.iconviewTag)
|
||||
private val taskIconWrapper: LinearLayout? by bindView(itemView, R.id.taskIconWrapper)
|
||||
private val approvalRequiredTextView: TextView? by bindView(itemView, R.id.approvalRequiredTextField)
|
||||
protected val taskGray: Int by bindColor(itemView.context, R.color.task_gray)
|
||||
|
||||
private var openTaskDisabled: Boolean = false
|
||||
private var taskActionsDisabled: Boolean = false
|
||||
|
|
@ -48,10 +48,10 @@ abstract class BaseTaskViewHolder constructor(itemView: View) : RecyclerView.Vie
|
|||
if (iconViewReminder?.visibility == View.VISIBLE) {
|
||||
isVisible = true
|
||||
}
|
||||
if (iconViewTag.visibility == View.VISIBLE) {
|
||||
if (iconViewTag?.visibility == View.VISIBLE) {
|
||||
isVisible = true
|
||||
}
|
||||
if (iconViewChallenge.visibility == View.VISIBLE) {
|
||||
if (iconViewChallenge?.visibility == View.VISIBLE) {
|
||||
isVisible = true
|
||||
}
|
||||
if (iconViewReminder?.visibility == View.VISIBLE) {
|
||||
|
|
@ -118,18 +118,18 @@ abstract class BaseTaskViewHolder constructor(itemView: View) : RecyclerView.Vie
|
|||
|
||||
rightBorderView?.setBackgroundResource(newTask.lightTaskColor)
|
||||
iconViewReminder?.visibility = if (newTask.reminders?.size ?: 0 > 0) View.VISIBLE else View.GONE
|
||||
iconViewTag.visibility = if (newTask.tags?.size ?: 0 > 0) View.VISIBLE else View.GONE
|
||||
iconViewTag?.visibility = if (newTask.tags?.size ?: 0 > 0) View.VISIBLE else View.GONE
|
||||
|
||||
iconViewChallenge.visibility = View.GONE
|
||||
iconViewChallenge?.visibility = View.GONE
|
||||
|
||||
configureSpecialTaskTextView(newTask)
|
||||
|
||||
taskIconWrapper.visibility = if (taskIconWrapperIsVisible) View.VISIBLE else View.GONE
|
||||
taskIconWrapper?.visibility = if (taskIconWrapperIsVisible) View.VISIBLE else View.GONE
|
||||
|
||||
if (newTask.isPendingApproval) {
|
||||
approvalRequiredTextView.visibility = View.VISIBLE
|
||||
approvalRequiredTextView?.visibility = View.VISIBLE
|
||||
} else {
|
||||
approvalRequiredTextView.visibility = View.GONE
|
||||
approvalRequiredTextView?.visibility = View.GONE
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ class PurchaseDialog(context: Context, component: AppComponent?, val item: ShopI
|
|||
|
||||
private fun setUser(user: User) {
|
||||
this.user = user
|
||||
currencyView.gold = user.stats.getGp()
|
||||
currencyView.gold = user.stats.gp ?: 0.0
|
||||
currencyView.gems = user.gemCount.toDouble()
|
||||
currencyView.hourglasses = user.hourglassCount.toDouble()
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue