mirror of
https://github.com/sudoxnym/habitica-android.git
synced 2026-04-14 19:56:32 +00:00
Begin redesigning chat
This commit is contained in:
parent
58fb5e465a
commit
5040574bf0
32 changed files with 362 additions and 338 deletions
4
Habitica/res/drawable/rounded_avatar_bg.xml
Normal file
4
Habitica/res/drawable/rounded_avatar_bg.xml
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="oval">
|
||||
<solid android:color="@color/transparent" />
|
||||
</shape>
|
||||
|
|
@ -3,89 +3,84 @@
|
|||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:orientation="vertical">
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:orientation="horizontal"
|
||||
android:background="@color/gray_600"
|
||||
android:paddingLeft="@dimen/chat_horizontal_inset"
|
||||
android:paddingRight="@dimen/chat_horizontal_inset"
|
||||
android:paddingTop="@dimen/spacing_small"
|
||||
android:paddingBottom="@dimen/spacing_small">
|
||||
<com.habitrpg.android.habitica.ui.RoundedFrameLayout
|
||||
android:layout_width="@dimen/avatar_chat_size"
|
||||
android:layout_height="@dimen/avatar_chat_size"
|
||||
android:clipChildren="true"
|
||||
android:layout_marginRight="@dimen/spacing_medium"
|
||||
android:layout_marginEnd="@dimen/spacing_medium"
|
||||
android:background="@drawable/rounded_avatar_bg">
|
||||
<com.habitrpg.android.habitica.ui.AvatarView
|
||||
android:id="@+id/avatar_view"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="60dp"
|
||||
android:layout_gravity="center"
|
||||
app:showMount="false"
|
||||
app:showPet="false" />
|
||||
</com.habitrpg.android.habitica.ui.RoundedFrameLayout>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
style="@style/CardContent.Compact">
|
||||
style="@style/CardContent.Compact"
|
||||
android:background="@drawable/layout_rounded_bg"
|
||||
android:padding="@dimen/spacing_medium">
|
||||
<LinearLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:weightSum="1.0"
|
||||
android:baselineAligned="false"
|
||||
android:gravity="center_vertical">
|
||||
<com.habitrpg.android.habitica.ui.views.social.UsernameLabel
|
||||
android:id="@+id/user_label"
|
||||
style="@style/ChatMessageUserTextViewStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:weightSum="1.0"
|
||||
android:baselineAligned="false">
|
||||
|
||||
<LinearLayout
|
||||
android:clickable="true"
|
||||
tools:text="Username"
|
||||
android:focusable="true" />
|
||||
<TextView
|
||||
android:id="@+id/ago_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"
|
||||
android:lines="1"
|
||||
android:ellipsize="end"
|
||||
tools:text="2d ago"
|
||||
android:textSize="12sp"
|
||||
android:textColor="@color/gray_300"
|
||||
android:layout_marginLeft="@dimen/spacing_medium"
|
||||
android:layout_marginStart="@dimen/spacing_medium"/>
|
||||
<View
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="0.5">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/user_background_layout"
|
||||
android:layout_width="wrap_content"
|
||||
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="left|center"
|
||||
android:layout_margin="10dp"
|
||||
android:background="@drawable/layout_rounded_bg">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/user_label"
|
||||
style="@style/ChatMessageUserTextViewStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="5dp"
|
||||
android:ellipsize="middle"
|
||||
android:lines="1"
|
||||
android:singleLine="true"
|
||||
tools:text="Username" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
android:layout_height="1dp"
|
||||
android:layout_weight="1" />
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:id="@+id/like_background_layout"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="0.5"
|
||||
android:gravity="right">
|
||||
android:layout_gravity="center_vertical|right"
|
||||
|
||||
<LinearLayout
|
||||
android:layout_marginLeft="5dp"
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/layout_rounded_bg">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvLikes"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center|right"
|
||||
android:layout_margin="5dp">
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/like_background_layout"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical|right"
|
||||
|
||||
android:layout_marginLeft="5dp"
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/layout_rounded_bg">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvLikes"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="5dp"
|
||||
android:clickable="true"
|
||||
android:gravity="center_vertical" />
|
||||
</LinearLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/btn_options"
|
||||
android:layout_width="25dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginRight="8dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:layout_weight="0.06"
|
||||
android:src="@drawable/ic_action_more_vert" />
|
||||
</LinearLayout>
|
||||
android:layout_margin="5dp"
|
||||
android:clickable="true"
|
||||
android:gravity="center_vertical"
|
||||
android:focusable="true" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
|
|
@ -96,15 +91,42 @@
|
|||
android:layout_margin="8dp"
|
||||
android:lineSpacingMultiplier="1.0"
|
||||
tools:text="This is the chat message"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/ago_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center|right"
|
||||
android:layout_marginRight="8dp"
|
||||
android:singleLine="true"
|
||||
android:lines="1"
|
||||
android:ellipsize="end"/>
|
||||
<LinearLayout
|
||||
android:id="@+id/buttons_wrapper"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="36dp">
|
||||
<Button
|
||||
android:id="@+id/reply_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
style="@style/Base.Widget.AppCompat.Button.Borderless"
|
||||
android:textSize="12sp"
|
||||
android:textColor="@color/gray_300"
|
||||
android:text="@string/reply" />
|
||||
<Button
|
||||
android:id="@+id/copy_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
style="@style/Base.Widget.AppCompat.Button.Borderless"
|
||||
android:textSize="12sp"
|
||||
android:textColor="@color/gray_300"
|
||||
android:text="@string/copy" />
|
||||
<Button
|
||||
android:id="@+id/report_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
style="@style/Base.Widget.AppCompat.Button.Borderless"
|
||||
android:textSize="12sp"
|
||||
android:textColor="@color/gray_300"
|
||||
android:text="@string/report" />
|
||||
<Button
|
||||
android:id="@+id/delete_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
style="@style/Base.Widget.AppCompat.Button.Borderless"
|
||||
android:textSize="12sp"
|
||||
android:textColor="@color/gray_300"
|
||||
android:text="@string/delete" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
|
@ -125,5 +125,7 @@
|
|||
<dimen name="snackbar_image_size">46dp</dimen>
|
||||
<dimen name="bullet_size">6dp</dimen>
|
||||
<dimen name="icon_size">18dp</dimen>
|
||||
<dimen name="chat_horizontal_inset">16dp</dimen>
|
||||
<dimen name="avatar_chat_size">36dp</dimen>
|
||||
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -301,12 +301,12 @@
|
|||
<string name="quest.invitation">Quest Invitation</string>
|
||||
<string name="quest_begin_message">Are you sure? Only %1$d of your %2$d party members have joined this quest! Quests start automatically when all players have joined or rejected the invitation.</string>
|
||||
<string name="quest.invitation.text">You have been invited to participate in a quest!</string>
|
||||
<string name="ago_1day">1 day ago</string>
|
||||
<string name="ago_days">%d days ago</string>
|
||||
<string name="ago_1Minute">1 minute ago</string>
|
||||
<string name="ago_minutes">%d minutes ago</string>
|
||||
<string name="ago_hours">%d hours ago</string>
|
||||
<string name="ago_1hour">1 hour ago</string>
|
||||
<string name="ago_1day">1d ago</string>
|
||||
<string name="ago_days">%dd ago</string>
|
||||
<string name="ago_1Minute">1m ago</string>
|
||||
<string name="ago_minutes">%dm ago</string>
|
||||
<string name="ago_hours">%dh ago</string>
|
||||
<string name="ago_1hour">1h ago</string>
|
||||
<string name="today">Today</string>
|
||||
<string name="sidebar_items">Items</string>
|
||||
<string name="eggs">Eggs</string>
|
||||
|
|
@ -779,4 +779,7 @@
|
|||
<string name="seasonalShop_owner_long">Seasonal Sorceress</string>
|
||||
<string name="rage_attack">Rage attack:</string>
|
||||
<string name="tavern_description_world_boss">Oh dear, pay no heed to the monster below -- this is still a safe haven to chat on your breaks.</string>
|
||||
<string name="report">Report</string>
|
||||
<string name="like">Like</string>
|
||||
<string name="reply">Reply</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ class InventoryRepositoryImpl(localRepository: InventoryLocalRepository, apiClie
|
|||
item.owned = item.owned - 1
|
||||
}
|
||||
if (user.stats != null) {
|
||||
user1.stats.userId = user.id
|
||||
user1.stats?.userId = user.id
|
||||
val stats = realm.copyToRealmOrUpdate(user1.stats)
|
||||
user.stats = stats
|
||||
}
|
||||
|
|
@ -190,21 +190,21 @@ class InventoryRepositoryImpl(localRepository: InventoryLocalRepository, apiClie
|
|||
copiedUser.items = buyResponse.items
|
||||
}
|
||||
if (buyResponse.hp != null) {
|
||||
copiedUser.stats.hp = buyResponse.hp
|
||||
copiedUser.stats?.hp = buyResponse.hp
|
||||
}
|
||||
if (buyResponse.exp != null) {
|
||||
copiedUser.stats.exp = buyResponse.exp
|
||||
copiedUser.stats?.exp = buyResponse.exp
|
||||
}
|
||||
if (buyResponse.mp != null) {
|
||||
copiedUser.stats.mp = buyResponse.mp
|
||||
copiedUser.stats?.mp = buyResponse.mp
|
||||
}
|
||||
if (buyResponse.gp != null) {
|
||||
copiedUser.stats.gp = buyResponse.gp
|
||||
copiedUser.stats?.gp = buyResponse.gp
|
||||
} else {
|
||||
copiedUser.stats.gp = copiedUser.stats.gp ?: 0 - value
|
||||
copiedUser.stats?.gp = copiedUser.stats?.gp ?: 0 - value
|
||||
}
|
||||
if (buyResponse.lvl != null) {
|
||||
copiedUser.stats.lvl = buyResponse.lvl
|
||||
copiedUser.stats?.lvl = buyResponse.lvl
|
||||
}
|
||||
localRepository.save(copiedUser)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -86,15 +86,15 @@ constructor(private val context: Context) : SetupCustomizationRepository {
|
|||
"body" -> {
|
||||
return when (subcategory) {
|
||||
"size" -> sizes
|
||||
"shirt" -> getShirts(user.preferences.size ?: "slim")
|
||||
"shirt" -> getShirts(user.preferences?.size ?: "slim")
|
||||
else -> emptyList()
|
||||
}
|
||||
}
|
||||
"skin" -> return skins
|
||||
"hair" -> {
|
||||
return when (subcategory) {
|
||||
"bangs" -> getBangs(user.preferences.hair!!.color)
|
||||
"ponytail" -> getHairBases(user.preferences.hair!!.color)
|
||||
"bangs" -> getBangs(user.preferences?.hair!!.color)
|
||||
"ponytail" -> getHairBases(user.preferences?.hair!!.color)
|
||||
"color" -> hairColors
|
||||
else -> emptyList()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,11 +71,11 @@ class TaskRepositoryImpl(localRepository: TaskLocalRepository, apiClient: ApiCli
|
|||
val stats = user.stats
|
||||
|
||||
result.taskValueDelta = res.delta
|
||||
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.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.hp = res.hp
|
||||
stats.exp = res.exp
|
||||
stats.mp = res.mp
|
||||
stats.gp = res.gp
|
||||
stats.lvl = 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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ class UserRepositoryImpl(localRepository: UserLocalRepository, apiClient: ApiCli
|
|||
}
|
||||
|
||||
override fun sleep(user: User): Flowable<User> {
|
||||
localRepository.executeTransaction { user.preferences.isSleep = !user.preferences.sleep }
|
||||
localRepository.executeTransaction { user.preferences?.isSleep = !(user.preferences?.sleep ?: false) }
|
||||
return apiClient.sleep().map { user }
|
||||
}
|
||||
|
||||
|
|
@ -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.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.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,24 +211,24 @@ class UserRepositoryImpl(localRepository: UserLocalRepository, apiClient: ApiCli
|
|||
if (user != null && user.isManaged) {
|
||||
localRepository.executeTransaction {
|
||||
when (stat) {
|
||||
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()
|
||||
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 = user.stats.points?.dec()
|
||||
user.stats?.points = user.stats?.points?.dec()
|
||||
}
|
||||
}
|
||||
return apiClient.allocatePoint(stat)
|
||||
.doOnNext { stats ->
|
||||
if (user != null && user.isManaged) {
|
||||
localRepository.executeTransaction {
|
||||
user.stats.str = stats.str
|
||||
user.stats.con = stats.con
|
||||
user.stats.per = stats.per
|
||||
user.stats._int = stats._int
|
||||
user.stats.points = stats.points
|
||||
user.stats.mp = stats.mp
|
||||
user.stats?.str = stats.str
|
||||
user.stats?.con = stats.con
|
||||
user.stats?.per = stats.per
|
||||
user.stats?._int = stats._int
|
||||
user.stats?.points = stats.points
|
||||
user.stats?.mp = stats.mp
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -239,12 +239,12 @@ class UserRepositoryImpl(localRepository: UserLocalRepository, apiClient: ApiCli
|
|||
.doOnNext { stats ->
|
||||
if (user != null && user.isManaged) {
|
||||
localRepository.executeTransaction {
|
||||
user.stats.str = stats.str
|
||||
user.stats.con = stats.con
|
||||
user.stats.per = stats.per
|
||||
user.stats._int = stats._int
|
||||
user.stats.points = stats.points
|
||||
user.stats.mp = stats.mp
|
||||
user.stats?.str = stats.str
|
||||
user.stats?.con = stats.con
|
||||
user.stats?.per = stats.per
|
||||
user.stats?._int = stats._int
|
||||
user.stats?.points = stats.points
|
||||
user.stats?.mp = stats.mp
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -288,7 +288,7 @@ class UserRepositoryImpl(localRepository: UserLocalRepository, apiClient: ApiCli
|
|||
copiedUser.flags = newUser.flags
|
||||
}
|
||||
if (newUser.stats != null) {
|
||||
copiedUser.stats.merge(newUser.stats)
|
||||
copiedUser.stats?.merge(newUser.stats)
|
||||
}
|
||||
|
||||
localRepository.saveUser(copiedUser)
|
||||
|
|
|
|||
|
|
@ -73,17 +73,17 @@ class RealmUserLocalRepository(realm: Realm) : RealmBaseLocalRepository(realm),
|
|||
}
|
||||
|
||||
override fun getSkills(user: User): Flowable<RealmResults<Skill>> {
|
||||
val habitClass = if (user.preferences.disableClasses) "none" else user.stats.habitClass
|
||||
val habitClass = if (user.preferences?.disableClasses == true) "none" else user.stats?.habitClass
|
||||
return realm.where(Skill::class.java)
|
||||
.equalTo("habitClass", habitClass)
|
||||
.lessThanOrEqualTo("lvl", user.stats.lvl ?: 0)
|
||||
.lessThanOrEqualTo("lvl", user.stats?.lvl ?: 0)
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { it.isLoaded }
|
||||
}
|
||||
|
||||
override fun getSpecialItems(user: User): Flowable<RealmResults<Skill>> {
|
||||
val specialItems = user.items.special
|
||||
val specialItems = user.items?.special
|
||||
val ownedItems = ArrayList<String>()
|
||||
if (specialItems != null) {
|
||||
if (specialItems.snowball > 0) {
|
||||
|
|
|
|||
|
|
@ -11,20 +11,24 @@ import com.habitrpg.android.habitica.models.user.Stats;
|
|||
*/
|
||||
|
||||
public interface Avatar {
|
||||
@Nullable
|
||||
String getCurrentMount();
|
||||
|
||||
@Nullable
|
||||
String getCurrentPet();
|
||||
|
||||
String getBackground();
|
||||
|
||||
boolean getSleep();
|
||||
|
||||
@Nullable
|
||||
Stats getStats();
|
||||
|
||||
@Nullable
|
||||
AvatarPreferences getPreferences();
|
||||
|
||||
@Nullable
|
||||
Integer getGemCount();
|
||||
|
||||
@Nullable
|
||||
Integer getHourglassCount();
|
||||
|
||||
@Nullable
|
||||
|
|
|
|||
|
|
@ -183,14 +183,6 @@ public class Member extends RealmObject implements Avatar {
|
|||
this.currentPet = currentPet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBackground() {
|
||||
if (getPreferences() != null) {
|
||||
return getPreferences().getBackground();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getSleep() {
|
||||
return getPreferences() != null && getPreferences().getSleep();
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ open class ChatMessage : RealmObject() {
|
|||
set(value) {
|
||||
field = value
|
||||
likes?.forEach { it.messageId = value }
|
||||
userStyles?.id = id
|
||||
contributor?.userId = id
|
||||
}
|
||||
|
||||
var text: String? = null
|
||||
|
|
@ -46,34 +48,7 @@ open class ChatMessage : RealmObject() {
|
|||
|
||||
var isInboxMessage: Boolean = false
|
||||
|
||||
val contributorColor: Int
|
||||
get() {
|
||||
var rColor = android.R.color.black
|
||||
|
||||
val level = contributor?.level
|
||||
if (level != null) {
|
||||
if (ContributorInfo.CONTRIBUTOR_COLOR_DICT.get(level, -1) > 0) {
|
||||
rColor = ContributorInfo.CONTRIBUTOR_COLOR_DICT[level]
|
||||
}
|
||||
}
|
||||
|
||||
if (backer?.npc != null) {
|
||||
rColor = android.R.color.black
|
||||
}
|
||||
|
||||
return rColor
|
||||
}
|
||||
|
||||
val contributorForegroundColor: Int
|
||||
get() {
|
||||
var rColor = android.R.color.white
|
||||
|
||||
if (backer?.npc != null) {
|
||||
rColor = R.color.contributor_npc_font
|
||||
}
|
||||
|
||||
return rColor
|
||||
}
|
||||
var userStyles: UserStyles? = null
|
||||
|
||||
val isSystemMessage: Boolean
|
||||
get() = uuid == "system"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,61 @@
|
|||
package com.habitrpg.android.habitica.models.social
|
||||
|
||||
import com.habitrpg.android.habitica.models.Avatar
|
||||
import com.habitrpg.android.habitica.models.AvatarPreferences
|
||||
import com.habitrpg.android.habitica.models.user.*
|
||||
import io.realm.RealmObject
|
||||
import io.realm.annotations.PrimaryKey
|
||||
|
||||
open class UserStyles : RealmObject(), Avatar {
|
||||
@PrimaryKey
|
||||
var id: String? = null
|
||||
set(value) {
|
||||
field = value
|
||||
stats?.userId = id
|
||||
preferences?.userId = id
|
||||
items?.userId = id
|
||||
}
|
||||
override fun getCurrentMount(): String? {
|
||||
return items?.currentMount
|
||||
}
|
||||
|
||||
override fun getCurrentPet(): String? {
|
||||
return items?.currentPet
|
||||
}
|
||||
|
||||
override fun getSleep(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun getStats(): Stats? {
|
||||
return stats
|
||||
}
|
||||
|
||||
override fun getPreferences(): AvatarPreferences? {
|
||||
return preferences
|
||||
}
|
||||
|
||||
override fun getGemCount(): Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
override fun getHourglassCount(): Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
override fun getCostume(): Outfit? {
|
||||
return items?.gear?.costume
|
||||
}
|
||||
|
||||
override fun getEquipped(): Outfit? {
|
||||
return items?.gear?.equipped
|
||||
}
|
||||
|
||||
override fun hasClass(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
private var stats: Stats? = null
|
||||
private var preferences: Preferences? = null
|
||||
private var items: Items? = null
|
||||
}
|
||||
|
|
@ -105,7 +105,7 @@ open class Preferences : RealmObject(), AvatarPreferences {
|
|||
return userId
|
||||
}
|
||||
|
||||
fun setUserId(userId: String) {
|
||||
fun setUserId(userId: String?) {
|
||||
this.userId = userId
|
||||
if (hair?.isManaged == false) {
|
||||
hair?.userId = userId
|
||||
|
|
|
|||
|
|
@ -289,14 +289,6 @@ public class User extends RealmObject implements Avatar {
|
|||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBackground() {
|
||||
if (getPreferences() != null) {
|
||||
return getPreferences().getBackground();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getSleep() {
|
||||
return getPreferences() != null && getPreferences().getSleep();
|
||||
|
|
|
|||
|
|
@ -173,7 +173,7 @@ class AvatarView : View {
|
|||
if (resetHasAttributes) hasPet = true
|
||||
}
|
||||
|
||||
val backgroundName = avatar.background
|
||||
val backgroundName = avatar.preferences?.background
|
||||
if (showBackground && !TextUtils.isEmpty(backgroundName)) {
|
||||
layerMap[LayerType.BACKGROUND] = "background_$backgroundName"
|
||||
if (resetHasAttributes) hasBackground = true
|
||||
|
|
@ -202,8 +202,8 @@ class AvatarView : View {
|
|||
|
||||
var hasVisualBuffs = false
|
||||
|
||||
if (avatar.stats != null && avatar.stats.buffs != null) {
|
||||
val buffs = avatar.stats.buffs
|
||||
if (avatar.stats != null && avatar.stats?.buffs != null) {
|
||||
val buffs = avatar.stats?.buffs
|
||||
|
||||
if (buffs?.snowball == true) {
|
||||
layerMap[AvatarView.LayerType.VISUAL_BUFF] = "snowman"
|
||||
|
|
@ -216,7 +216,7 @@ class AvatarView : View {
|
|||
}
|
||||
|
||||
if (buffs?.shinySeed == true) {
|
||||
layerMap[AvatarView.LayerType.VISUAL_BUFF] = "avatar_floral_" + avatar.stats.habitClass
|
||||
layerMap[AvatarView.LayerType.VISUAL_BUFF] = "avatar_floral_" + avatar.stats?.habitClass
|
||||
hasVisualBuffs = true
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ class AvatarWithBarsViewModel(private val context: Context, view: View, userRepo
|
|||
fun updateData(user: Avatar) {
|
||||
userObject = user
|
||||
|
||||
val stats = user.stats
|
||||
val stats = user.stats ?: return
|
||||
|
||||
var userClass = ""
|
||||
|
||||
|
|
@ -69,13 +69,13 @@ class AvatarWithBarsViewModel(private val context: Context, view: View, userRepo
|
|||
userClass = stats.getTranslatedClassName(context)
|
||||
}
|
||||
|
||||
mpBar.visibility = if (stats.habitClass == null || stats.lvl ?: 0 < 10 || user.preferences.disableClasses) View.GONE else View.VISIBLE
|
||||
mpBar.visibility = if (stats.habitClass == null || stats.lvl ?: 0 < 10 || user.preferences?.disableClasses == true) View.GONE else View.VISIBLE
|
||||
|
||||
if (!user.hasClass()) {
|
||||
lvlText.text = context.getString(R.string.user_level, user.stats.lvl)
|
||||
lvlText.text = context.getString(R.string.user_level, stats.lvl)
|
||||
lvlText.setCompoundDrawables(null, null, null, null)
|
||||
} else {
|
||||
lvlText.text = context.getString(R.string.user_level_with_class, user.stats.lvl, userClass.substring(0, 1).toUpperCase(Locale.getDefault()) + userClass.substring(1))
|
||||
lvlText.text = context.getString(R.string.user_level_with_class, stats.lvl, userClass.substring(0, 1).toUpperCase(Locale.getDefault()) + userClass.substring(1))
|
||||
var drawable: Drawable? = null
|
||||
when (stats.habitClass) {
|
||||
Stats.WARRIOR -> drawable = BitmapDrawable(context.resources, HabiticaIconsHelper.imageOfWarriorDarkBg())
|
||||
|
|
@ -93,7 +93,7 @@ class AvatarWithBarsViewModel(private val context: Context, view: View, userRepo
|
|||
|
||||
currencyView.gold = stats.gp ?: 0.0
|
||||
if (user is User) {
|
||||
currencyView.hourglasses = user.getHourglassCount().toDouble()
|
||||
currencyView.hourglasses = user.hourglassCount?.toDouble() ?: 0.0
|
||||
currencyView.gems = user.gemCount.toDouble()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
package com.habitrpg.android.habitica.ui
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Path
|
||||
import android.graphics.RectF
|
||||
import android.util.AttributeSet
|
||||
import android.widget.FrameLayout
|
||||
|
||||
|
||||
class RoundedFrameLayout @JvmOverloads constructor(
|
||||
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
|
||||
) : FrameLayout(context, attrs, defStyleAttr) {
|
||||
|
||||
var radius = 4f
|
||||
var isCirclular = true
|
||||
|
||||
override fun onDraw(canvas: Canvas) {
|
||||
val clipPath = Path()
|
||||
val radius = if (isCirclular) (canvas.height/2).toFloat() else radius
|
||||
clipPath.addRoundRect(RectF(canvas.clipBounds), radius, radius, Path.Direction.CW)
|
||||
canvas.clipPath(clipPath)
|
||||
super.onDraw(canvas)
|
||||
}
|
||||
}
|
||||
|
|
@ -43,7 +43,6 @@ class SpeechBubbleView(context: Context, attrs: AttributeSet) : FrameLayout(cont
|
|||
this.setOnClickListener(this)
|
||||
}
|
||||
|
||||
|
||||
fun setConfirmationButtonVisibility(visibility: Int) {
|
||||
confirmationButtons.visibility = visibility
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ class FixCharacterValuesActivity: BaseActivity() {
|
|||
levelEditText.text = user.stats?.lvl.toString()
|
||||
streakEditText.text = user.streakCount.toString()
|
||||
|
||||
when (user.stats.habitClass) {
|
||||
when (user.stats?.habitClass) {
|
||||
Stats.WARRIOR -> {
|
||||
levelEditText.iconBackgroundColor = ContextCompat.getColor(this, R.color.red_500)
|
||||
levelEditText.setIconBitmap(HabiticaIconsHelper.imageOfWarriorLightBg())
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import com.habitrpg.android.habitica.components.AppComponent
|
|||
import com.habitrpg.android.habitica.data.ApiClient
|
||||
import com.habitrpg.android.habitica.data.InventoryRepository
|
||||
import com.habitrpg.android.habitica.data.SocialRepository
|
||||
import com.habitrpg.android.habitica.extensions.notNull
|
||||
import com.habitrpg.android.habitica.helpers.RxErrorHandler
|
||||
import com.habitrpg.android.habitica.helpers.UserStatComputer
|
||||
import com.habitrpg.android.habitica.models.AchievementGroup
|
||||
|
|
@ -73,7 +74,7 @@ class FullProfileActivity : BaseActivity() {
|
|||
|
||||
private var userId = ""
|
||||
private var userName: String? = null
|
||||
private var avatarWithBars = AvatarWithBarsViewModel(this, avatar_with_bars)
|
||||
private var avatarWithBars: AvatarWithBarsViewModel? = null
|
||||
private var attributeStrSum = 0f
|
||||
private var attributeIntSum = 0f
|
||||
private var attributeConSum = 0f
|
||||
|
|
@ -92,12 +93,14 @@ class FullProfileActivity : BaseActivity() {
|
|||
|
||||
socialRepository.getMember(this.userId).subscribe(Consumer { this.updateView(it) }, RxErrorHandler.handleEmptyError())
|
||||
|
||||
avatarWithBars.valueBarLabelsToBlack()
|
||||
avatarWithBars?.valueBarLabelsToBlack()
|
||||
|
||||
avatar_with_bars.setBackgroundColor(ContextCompat.getColor(this, R.color.transparent))
|
||||
|
||||
attributeRows.clear()
|
||||
attributesCardView.setOnClickListener { toggleAttributeDetails() }
|
||||
|
||||
avatarWithBars = AvatarWithBarsViewModel(this, avatar_with_bars)
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
|
|
@ -186,11 +189,11 @@ class FullProfileActivity : BaseActivity() {
|
|||
|
||||
|
||||
avatarView.setAvatar(user)
|
||||
avatarWithBars.updateData(user)
|
||||
avatarWithBars?.updateData(user)
|
||||
|
||||
loadItemDataByOutfit(user.equipped).subscribe(Consumer { gear -> this.gotGear(gear, user) }, RxErrorHandler.handleEmptyError())
|
||||
|
||||
if (user.preferences.costume) {
|
||||
if (user.preferences?.costume == true) {
|
||||
loadItemDataByOutfit(user.costume).subscribe(Consumer<RealmResults<Equipment>> { this.gotCostume(it) }, RxErrorHandler.handleEmptyError())
|
||||
} else {
|
||||
costumeCard.visibility = View.GONE
|
||||
|
|
@ -300,7 +303,7 @@ class FullProfileActivity : BaseActivity() {
|
|||
}
|
||||
|
||||
private fun addLevelAttributes(user: Member) {
|
||||
val byLevelStat = Math.min((user.stats.lvl ?: 0) / 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)
|
||||
}
|
||||
|
|
@ -341,7 +344,7 @@ class FullProfileActivity : BaseActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
addNormalAddBuffAttributes(user.stats)
|
||||
user.stats.notNull { addNormalAddBuffAttributes(it) }
|
||||
}
|
||||
|
||||
private fun gotCostume(obj: List<Equipment>) {
|
||||
|
|
|
|||
|
|
@ -3,13 +3,11 @@ package com.habitrpg.android.habitica.ui.adapter.social
|
|||
import android.content.Context
|
||||
import android.content.res.Resources
|
||||
import android.support.v4.content.ContextCompat
|
||||
import android.support.v7.widget.PopupMenu
|
||||
import android.support.v7.widget.RecyclerView
|
||||
import android.text.method.LinkMovementMethod
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.Button
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import com.habitrpg.android.habitica.R
|
||||
|
|
@ -17,9 +15,11 @@ import com.habitrpg.android.habitica.extensions.inflate
|
|||
import com.habitrpg.android.habitica.extensions.notNull
|
||||
import com.habitrpg.android.habitica.models.social.ChatMessage
|
||||
import com.habitrpg.android.habitica.models.user.User
|
||||
import com.habitrpg.android.habitica.ui.AvatarView
|
||||
import com.habitrpg.android.habitica.ui.helpers.DataBindingUtils
|
||||
import com.habitrpg.android.habitica.ui.helpers.MarkdownParser
|
||||
import com.habitrpg.android.habitica.ui.helpers.bindView
|
||||
import com.habitrpg.android.habitica.ui.views.social.UsernameLabel
|
||||
import io.reactivex.BackpressureStrategy
|
||||
import io.reactivex.Flowable
|
||||
import io.reactivex.Maybe
|
||||
|
|
@ -33,13 +33,13 @@ import net.pherth.android.emoji_library.EmojiTextView
|
|||
class ChatRecyclerViewAdapter(data: OrderedRealmCollection<ChatMessage>?, autoUpdate: Boolean, private val user: User?, private val isTavern: Boolean) : RealmRecyclerViewAdapter<ChatMessage, ChatRecyclerViewAdapter.ChatRecyclerViewHolder>(data, autoUpdate) {
|
||||
private var uuid: String = ""
|
||||
private var sendingUser: User? = null
|
||||
private var expandedMessageId: String? = null
|
||||
|
||||
private val likeMessageEvents = PublishSubject.create<ChatMessage>()
|
||||
private val userLabelClickEvents = PublishSubject.create<String>()
|
||||
private val privateMessageClickEvents = PublishSubject.create<String>()
|
||||
private val deleteMessageEvents = PublishSubject.create<ChatMessage>()
|
||||
private val flagMessageEvents = PublishSubject.create<ChatMessage>()
|
||||
private val copyMessageAsTodoEvents = PublishSubject.create<ChatMessage>()
|
||||
private val replyMessageEvents = PublishSubject.create<String>()
|
||||
private val copyMessageEvents = PublishSubject.create<ChatMessage>()
|
||||
|
||||
init {
|
||||
|
|
@ -66,10 +66,6 @@ class ChatRecyclerViewAdapter(data: OrderedRealmCollection<ChatMessage>?, autoUp
|
|||
return userLabelClickEvents.toFlowable(BackpressureStrategy.DROP)
|
||||
}
|
||||
|
||||
fun getPrivateMessageClickFlowable(): Flowable<String> {
|
||||
return privateMessageClickEvents.toFlowable(BackpressureStrategy.DROP)
|
||||
}
|
||||
|
||||
fun getFlagMessageClickFlowable(): Flowable<ChatMessage> {
|
||||
return flagMessageEvents.toFlowable(BackpressureStrategy.DROP)
|
||||
}
|
||||
|
|
@ -78,8 +74,8 @@ class ChatRecyclerViewAdapter(data: OrderedRealmCollection<ChatMessage>?, autoUp
|
|||
return deleteMessageEvents.toFlowable(BackpressureStrategy.DROP)
|
||||
}
|
||||
|
||||
fun getCopyMessageAsTodoFlowable(): Flowable<ChatMessage> {
|
||||
return copyMessageAsTodoEvents.toFlowable(BackpressureStrategy.DROP)
|
||||
fun getReplyMessageEvents(): Flowable<String> {
|
||||
return replyMessageEvents.toFlowable(BackpressureStrategy.DROP)
|
||||
}
|
||||
|
||||
fun getCopyMessageFlowable(): Flowable<ChatMessage> {
|
||||
|
|
@ -87,23 +83,39 @@ class ChatRecyclerViewAdapter(data: OrderedRealmCollection<ChatMessage>?, autoUp
|
|||
}
|
||||
|
||||
|
||||
inner class ChatRecyclerViewHolder(itemView: View, private val userId: String, private val isTavern: Boolean) : RecyclerView.ViewHolder(itemView), View.OnClickListener, PopupMenu.OnMenuItemClickListener {
|
||||
inner class ChatRecyclerViewHolder(itemView: View, private val userId: String, private val isTavern: Boolean) : RecyclerView.ViewHolder(itemView) {
|
||||
|
||||
private val btnOptions: ImageView by bindView(R.id.btn_options)
|
||||
private val userBackground: LinearLayout by bindView(R.id.user_background_layout)
|
||||
private val userLabel: TextView by bindView(R.id.user_label)
|
||||
private val avatarView: AvatarView by bindView(R.id.avatar_view)
|
||||
private val userLabel: UsernameLabel by bindView(R.id.user_label)
|
||||
private val messageText: EmojiTextView by bindView(R.id.message_text)
|
||||
private val agoLabel: TextView by bindView(R.id.ago_label)
|
||||
private val likeBackground: LinearLayout by bindView(R.id.like_background_layout)
|
||||
private val tvLikes: TextView by bindView(R.id.tvLikes)
|
||||
private val buttonsWrapper: LinearLayout by bindView(R.id.buttons_wrapper)
|
||||
private val replyButton: Button by bindView(R.id.reply_button)
|
||||
private val copyButton: Button by bindView(R.id.copy_button)
|
||||
private val reportButton: Button by bindView(R.id.report_button)
|
||||
private val deleteButton: Button by bindView(R.id.delete_button)
|
||||
|
||||
val context: Context = itemView.context
|
||||
val res: Resources = itemView.resources
|
||||
private var chatMessage: ChatMessage? = null
|
||||
|
||||
init {
|
||||
btnOptions.setOnClickListener(this)
|
||||
tvLikes.setOnClickListener { toggleLike() }
|
||||
itemView.setOnClickListener {
|
||||
expandedMessageId = if (expandedMessageId == chatMessage?.id) {
|
||||
null
|
||||
} else {
|
||||
chatMessage?.id
|
||||
}
|
||||
notifyItemChanged(adapterPosition)
|
||||
}
|
||||
tvLikes.setOnClickListener { chatMessage.notNull { likeMessageEvents.onNext(it) } }
|
||||
userLabel.setOnClickListener { chatMessage?.uuid.notNull {userLabelClickEvents.onNext(it) } }
|
||||
replyButton.setOnClickListener { chatMessage?.text.notNull { replyMessageEvents.onNext(it) } }
|
||||
copyButton.setOnClickListener { chatMessage.notNull { copyMessageEvents.onNext(it) } }
|
||||
reportButton.setOnClickListener { chatMessage.notNull { flagMessageEvents.onNext(it) } }
|
||||
deleteButton.setOnClickListener { chatMessage.notNull { deleteMessageEvents.onNext(it) } }
|
||||
}
|
||||
|
||||
fun bind(msg: ChatMessage) {
|
||||
|
|
@ -112,26 +124,21 @@ class ChatRecyclerViewAdapter(data: OrderedRealmCollection<ChatMessage>?, autoUp
|
|||
setLikeProperties()
|
||||
|
||||
if (msg.sent != null && msg.sent == "true" && sendingUser != null) {
|
||||
DataBindingUtils.setRoundedBackgroundInt(userBackground, sendingUser!!.contributorColor)
|
||||
userLabel.tier = sendingUser?.contributor?.level ?: 0
|
||||
} else {
|
||||
DataBindingUtils.setRoundedBackgroundInt(userBackground, msg.contributorColor)
|
||||
userLabel.tier = msg.contributor?.level ?: 0
|
||||
}
|
||||
|
||||
if (msg.sent != null && msg.sent == "true") {
|
||||
userLabel.text = sendingUser?.profile?.name
|
||||
userLabel.username = sendingUser?.profile?.name
|
||||
} else {
|
||||
if (msg.user != null && msg.user?.isNotEmpty() == true) {
|
||||
userLabel.text = msg.user
|
||||
userLabel.username = msg.user
|
||||
} else {
|
||||
userLabel.setText(R.string.system)
|
||||
userLabel.username = context.getString(R.string.system)
|
||||
}
|
||||
}
|
||||
|
||||
userLabel.isClickable = true
|
||||
userLabel.setOnClickListener { view -> userLabelClickEvents.onNext(msg.uuid ?: "") }
|
||||
|
||||
DataBindingUtils.setForegroundTintColor(userLabel, msg.contributorForegroundColor)
|
||||
|
||||
messageText.text = chatMessage?.parsedText
|
||||
if (msg.parsedText == null) {
|
||||
messageText.text = chatMessage?.text
|
||||
|
|
@ -147,6 +154,18 @@ class ChatRecyclerViewAdapter(data: OrderedRealmCollection<ChatMessage>?, autoUp
|
|||
this.messageText.movementMethod = LinkMovementMethod.getInstance()
|
||||
|
||||
agoLabel.text = msg.getAgoString(res)
|
||||
|
||||
msg.userStyles.notNull {
|
||||
avatarView.setAvatar(it)
|
||||
}
|
||||
|
||||
if (expandedMessageId == msg.id) {
|
||||
buttonsWrapper.visibility = View.VISIBLE
|
||||
deleteButton.visibility = if (shouldShowDelete()) View.VISIBLE else View.GONE
|
||||
replyButton.visibility = if (chatMessage?.isInboxMessage == true) View.GONE else View.VISIBLE
|
||||
} else {
|
||||
buttonsWrapper.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
private fun setLikeProperties() {
|
||||
|
|
@ -173,91 +192,8 @@ class ChatRecyclerViewAdapter(data: OrderedRealmCollection<ChatMessage>?, autoUp
|
|||
tvLikes.setTextColor(ContextCompat.getColor(context, foregroundColorRes))
|
||||
}
|
||||
|
||||
override fun onClick(v: View) {
|
||||
if (chatMessage != null) {
|
||||
if (btnOptions === v) {
|
||||
val popupMenu = PopupMenu(context, v)
|
||||
|
||||
//set my own listener giving the View that activates the event onClick (i.e. YOUR ImageView)
|
||||
popupMenu.setOnMenuItemClickListener(this)
|
||||
//inflate your PopUpMenu
|
||||
popupMenu.menuInflater.inflate(R.menu.chat_message, popupMenu.menu)
|
||||
|
||||
// Force icons to show
|
||||
var menuHelper: Any? = null
|
||||
var argTypes: Array<Class<*>>
|
||||
try {
|
||||
val fMenuHelper = PopupMenu::class.java.getDeclaredField("mPopup")
|
||||
fMenuHelper.isAccessible = true
|
||||
menuHelper = fMenuHelper.get(popupMenu)
|
||||
argTypes = arrayOf(Boolean::class.java)
|
||||
menuHelper?.javaClass?.getDeclaredMethod("setForceShowIcon", *argTypes)?.invoke(menuHelper, true)
|
||||
} catch (ignored: Exception) {
|
||||
}
|
||||
|
||||
|
||||
popupMenu.menu.findItem(R.id.menu_chat_delete).isVisible = shouldShowDelete(chatMessage)
|
||||
popupMenu.menu.findItem(R.id.menu_chat_flag).isVisible = chatMessage?.uuid != "system"
|
||||
popupMenu.menu.findItem(R.id.menu_chat_copy_as_todo).isVisible = false
|
||||
popupMenu.menu.findItem(R.id.menu_chat_send_pm).isVisible = false
|
||||
|
||||
popupMenu.show()
|
||||
|
||||
// Try to force some horizontal offset
|
||||
try {
|
||||
val fListPopup = menuHelper?.javaClass?.getDeclaredField("mPopup")
|
||||
fListPopup?.isAccessible = true
|
||||
val listPopup = fListPopup?.get(menuHelper)
|
||||
argTypes = arrayOf(Int::class.java)
|
||||
val listPopupClass = listPopup?.javaClass
|
||||
|
||||
// Get the width of the popup window
|
||||
val width = listPopupClass?.getDeclaredMethod("getWidth")?.invoke(listPopup) as Int?
|
||||
|
||||
// Invoke setHorizontalOffset() with the negative width to move left by that distance
|
||||
listPopupClass?.getDeclaredMethod("setHorizontalOffset", *argTypes)?.invoke(listPopup, -(width ?: 0))
|
||||
|
||||
// Invoke show() to update the window's position
|
||||
listPopupClass?.getDeclaredMethod("show")?.invoke(listPopup)
|
||||
} catch (ignored: Exception) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun shouldShowDelete(chatMsg: ChatMessage?): Boolean {
|
||||
return chatMsg?.isSystemMessage != true && (chatMsg?.uuid == userId || user?.contributor != null && user.contributor.admin)
|
||||
}
|
||||
|
||||
fun toggleLike() {
|
||||
chatMessage.notNull { likeMessageEvents.onNext(it) }
|
||||
}
|
||||
|
||||
override fun onMenuItemClick(item: MenuItem): Boolean {
|
||||
chatMessage.notNull {
|
||||
when (item.itemId) {
|
||||
R.id.menu_chat_delete -> {
|
||||
deleteMessageEvents.onNext(it)
|
||||
}
|
||||
R.id.menu_chat_flag -> {
|
||||
flagMessageEvents.onNext(it)
|
||||
}
|
||||
R.id.menu_chat_copy_as_todo -> {
|
||||
copyMessageAsTodoEvents.onNext(it)
|
||||
}
|
||||
|
||||
R.id.menu_chat_send_pm -> {
|
||||
privateMessageClickEvents.onNext(it.uuid ?: "")
|
||||
}
|
||||
|
||||
R.id.menu_chat_copy -> {
|
||||
copyMessageEvents.onNext(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
private fun shouldShowDelete(): Boolean {
|
||||
return chatMessage?.isSystemMessage != true && (chatMessage?.uuid == userId || user?.contributor != null && user.contributor.admin)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package com.habitrpg.android.habitica.ui.adapter.social
|
||||
|
||||
import android.content.Context
|
||||
import android.support.v4.content.ContextCompat
|
||||
import android.support.v7.widget.RecyclerView
|
||||
import android.view.View
|
||||
|
|
@ -58,13 +57,13 @@ class PartyMemberRecyclerViewAdapter(data: OrderedRealmCollection<Member>?, auto
|
|||
fun bind(user: Member) {
|
||||
avatarView.setAvatar(user)
|
||||
|
||||
AvatarWithBarsViewModel.setHpBarData(hpBar, user.stats)
|
||||
user.stats.notNull { AvatarWithBarsViewModel.setHpBarData(hpBar, it) }
|
||||
|
||||
lvl.text = itemView.context.getString(R.string.user_level, user.stats.lvl)
|
||||
lvl.text = itemView.context.getString(R.string.user_level, user.stats?.lvl)
|
||||
|
||||
classLabel.text = user.stats.getTranslatedClassName(itemView.context)
|
||||
classLabel.text = user.stats?.getTranslatedClassName(itemView.context)
|
||||
|
||||
val colorResourceID: Int = when (user.stats.habitClass) {
|
||||
val colorResourceID: Int = when (user.stats?.habitClass) {
|
||||
Stats.HEALER -> {
|
||||
R.color.class_healer
|
||||
}
|
||||
|
|
|
|||
|
|
@ -204,7 +204,7 @@ class StatsFragment: BaseMainFragment() {
|
|||
|
||||
private fun updateStats() {
|
||||
val currentUser = user ?: return
|
||||
val levelStat = Math.min((currentUser.stats.lvl ?: 0) / 2.0f, 50f).toInt()
|
||||
val levelStat = Math.min((currentUser.stats?.lvl ?: 0) / 2.0f, 50f).toInt()
|
||||
|
||||
totalStrength = levelStat
|
||||
totalIntelligence = levelStat
|
||||
|
|
@ -225,14 +225,14 @@ class StatsFragment: BaseMainFragment() {
|
|||
constitutionStatsView.buffValue = currentUser.stats?.buffs?.con?.toInt() ?: 0
|
||||
perceptionStatsView.buffValue = currentUser.stats?.buffs?.per?.toInt() ?: 0
|
||||
|
||||
totalStrength += currentUser.stats?.str?.toInt() ?: 0
|
||||
totalIntelligence += currentUser.stats?._int?.toInt() ?: 0
|
||||
totalConstitution += currentUser.stats?.con?.toInt() ?: 0
|
||||
totalPerception += currentUser.stats?.per?.toInt() ?: 0
|
||||
strengthStatsView.allocatedValue = currentUser.stats?.str?.toInt() ?: 0
|
||||
intelligenceStatsView.allocatedValue = currentUser.stats?._int?.toInt() ?: 0
|
||||
constitutionStatsView.allocatedValue = currentUser.stats?.con?.toInt() ?: 0
|
||||
perceptionStatsView.allocatedValue = currentUser.stats?.per?.toInt() ?: 0
|
||||
totalStrength += currentUser.stats?.str ?: 0
|
||||
totalIntelligence += currentUser.stats?._int ?: 0
|
||||
totalConstitution += currentUser.stats?.con ?: 0
|
||||
totalPerception += currentUser.stats?.per ?: 0
|
||||
strengthStatsView.allocatedValue = currentUser.stats?.str ?: 0
|
||||
intelligenceStatsView.allocatedValue = currentUser.stats?._int ?: 0
|
||||
constitutionStatsView.allocatedValue = currentUser.stats?.con ?: 0
|
||||
perceptionStatsView.allocatedValue = currentUser.stats?.per ?: 0
|
||||
|
||||
val outfit = currentUser.items.gear.equipped
|
||||
val outfitList = ArrayList<String>()
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ class AvatarOverviewFragment : BaseMainFragment(), AdapterView.OnItemSelectedLis
|
|||
override fun onItemSelected(parent: AdapterView<*>, view: View, position: Int, id: Long) {
|
||||
val newSize: String = if (position == 0) "slim" else "broad"
|
||||
|
||||
if (this.user != null && this.user!!.preferences.size != newSize) {
|
||||
if (this.user != null && this.user!!.preferences?.size != newSize) {
|
||||
userRepository.updateUser(user, "preferences.size", newSize)
|
||||
.subscribe(Consumer { }, RxErrorHandler.handleEmptyError())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -228,7 +228,7 @@ class PreferencesFragment : BasePreferencesFragment(), SharedPreferences.OnShare
|
|||
this.user = user
|
||||
if (10 <= user?.stats?.lvl ?: 0) {
|
||||
if (user?.flags?.classSelected == true) {
|
||||
if (user.preferences.disableClasses) {
|
||||
if (user.preferences?.disableClasses == true) {
|
||||
classSelectionPreference?.title = getString(R.string.enable_class)
|
||||
} else {
|
||||
classSelectionPreference?.title = getString(R.string.change_class)
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ class SkillsFragment : BaseMainFragment() {
|
|||
|
||||
private fun displaySkillResult(usedSkill: Skill?, response: SkillResponse) {
|
||||
removeProgressDialog()
|
||||
adapter?.mana = response.user.stats.mp ?: 0.0
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import android.support.v7.widget.LinearLayoutManager
|
|||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.components.AppComponent
|
||||
import com.habitrpg.android.habitica.data.SocialRepository
|
||||
|
|
@ -110,7 +111,7 @@ class ChatListFragment : BaseFragment(), SwipeRefreshLayout.OnRefreshListener {
|
|||
}, RxErrorHandler.handleEmptyError()))
|
||||
compositeSubscription.add(it.getDeleteMessageFlowable().subscribe(Consumer { this.showDeleteConfirmationDialog(it) }, RxErrorHandler.handleEmptyError()))
|
||||
compositeSubscription.add(it.getFlagMessageClickFlowable().subscribe(Consumer { this.showFlagConfirmationDialog(it) }, RxErrorHandler.handleEmptyError()))
|
||||
compositeSubscription.add(it.getCopyMessageAsTodoFlowable().subscribe(Consumer{ this.copyMessageAsTodo(it) }, RxErrorHandler.handleEmptyError()))
|
||||
compositeSubscription.add(it.getReplyMessageEvents().subscribe(Consumer{ chatEditText.setText(it, TextView.BufferType.EDITABLE) }, RxErrorHandler.handleEmptyError()))
|
||||
compositeSubscription.add(it.getCopyMessageFlowable().subscribe(Consumer { this.copyMessageToClipboard(it) }, RxErrorHandler.handleEmptyError()))
|
||||
compositeSubscription.add(it.getLikeMessageFlowable().flatMap<ChatMessage> { socialRepository.likeMessage(it) }.subscribe(Consumer { }, RxErrorHandler.handleEmptyError()))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import android.support.v7.widget.LinearLayoutManager
|
|||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.components.AppComponent
|
||||
import com.habitrpg.android.habitica.data.SocialRepository
|
||||
|
|
@ -64,10 +65,9 @@ class InboxMessageListFragment : BaseMainFragment(), SwipeRefreshLayout.OnRefres
|
|||
compositeSubscription.add(it.getUserLabelClickFlowable().subscribe(Consumer<String> {
|
||||
context.notNull { context -> FullProfileActivity.open(context, it) }
|
||||
}, RxErrorHandler.handleEmptyError()))
|
||||
compositeSubscription.add(it.getDeleteMessageFlowable().subscribe(Consumer<ChatMessage> { this.showDeleteConfirmationDialog(it) }, RxErrorHandler.handleEmptyError()))
|
||||
compositeSubscription.add(it.getFlagMessageClickFlowable().subscribe(Consumer<ChatMessage> { this.showFlagConfirmationDialog(it) }, RxErrorHandler.handleEmptyError()))
|
||||
compositeSubscription.add(it.getCopyMessageAsTodoFlowable().subscribe(Consumer<ChatMessage> { this.copyMessageAsTodo(it) }, RxErrorHandler.handleEmptyError()))
|
||||
compositeSubscription.add(it.getCopyMessageFlowable().subscribe(Consumer<ChatMessage> { this.copyMessageToClipboard(it) }, RxErrorHandler.handleEmptyError()))
|
||||
compositeSubscription.add(it.getDeleteMessageFlowable().subscribe(Consumer { this.showDeleteConfirmationDialog(it) }, RxErrorHandler.handleEmptyError()))
|
||||
compositeSubscription.add(it.getFlagMessageClickFlowable().subscribe(Consumer { this.showFlagConfirmationDialog(it) }, RxErrorHandler.handleEmptyError()))
|
||||
compositeSubscription.add(it.getCopyMessageFlowable().subscribe(Consumer { this.copyMessageToClipboard(it) }, RxErrorHandler.handleEmptyError()))
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ class PurchaseDialog(context: Context, component: AppComponent?, val item: ShopI
|
|||
return
|
||||
}
|
||||
|
||||
if (shopItem.habitClass != null && shopItem.habitClass != "special" && user.stats.habitClass != shopItem.habitClass) {
|
||||
if (shopItem.habitClass != "special" && user.stats?.habitClass != shopItem.habitClass) {
|
||||
limitedTextView.text = context.getString(R.string.class_equipment_shop_dialog)
|
||||
limitedTextView.visibility = View.VISIBLE
|
||||
limitedTextView.setBackgroundColor(ContextCompat.getColor(context, R.color.gray_100))
|
||||
|
|
@ -152,9 +152,9 @@ class PurchaseDialog(context: Context, component: AppComponent?, val item: ShopI
|
|||
|
||||
private fun setUser(user: User) {
|
||||
this.user = user
|
||||
currencyView.gold = user.stats.gp ?: 0.0
|
||||
currencyView.gold = user.stats?.gp ?: 0.0
|
||||
currencyView.gems = user.gemCount.toDouble()
|
||||
currencyView.hourglasses = user.hourglassCount.toDouble()
|
||||
currencyView.hourglasses = user.hourglassCount?.toDouble() ?: 0.0
|
||||
|
||||
if ("gems" == shopItem.purchaseType) {
|
||||
val gemsLeft = if (shopItem.limitedNumberLeft != null) shopItem.limitedNumberLeft else 0
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ class UsernameLabel(context: Context?, attrs: AttributeSet?) : LinearLayout(cont
|
|||
private val textView = TextView(context)
|
||||
private val tierIconView = ImageView(context)
|
||||
|
||||
var username: String = ""
|
||||
var username: String? = ""
|
||||
set(value) {
|
||||
textView.text = value
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,23 +7,22 @@ import com.google.gson.JsonParseException
|
|||
import com.habitrpg.android.habitica.models.social.Backer
|
||||
import com.habitrpg.android.habitica.models.social.ChatMessage
|
||||
import com.habitrpg.android.habitica.models.social.ChatMessageLike
|
||||
import com.habitrpg.android.habitica.models.social.UserStyles
|
||||
import com.habitrpg.android.habitica.models.user.ContributorInfo
|
||||
import io.realm.RealmList
|
||||
import java.lang.reflect.Type
|
||||
import java.util.*
|
||||
|
||||
class ChatMessageDeserializer : JsonDeserializer<ChatMessage> {
|
||||
@Throws(JsonParseException::class)
|
||||
override fun deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): ChatMessage {
|
||||
val message = ChatMessage()
|
||||
val obj = json.asJsonObject
|
||||
if (obj.has("id")) {
|
||||
message.id = obj.get("id").asString
|
||||
}
|
||||
if (obj.has("text") && !obj.get("text").isJsonNull && obj.get("text").isJsonPrimitive) {
|
||||
message.text = obj.get("text").asString
|
||||
}
|
||||
if (obj.has("timestamp")) {
|
||||
message.timestamp = obj.get("timestamp").asLong
|
||||
message.timestamp = context.deserialize<Date>(obj.get("timestamp"), Date::class.java).time
|
||||
}
|
||||
if (obj.has("likes")) {
|
||||
message.likes = RealmList()
|
||||
|
|
@ -66,6 +65,13 @@ class ChatMessageDeserializer : JsonDeserializer<ChatMessage> {
|
|||
message.sent = obj.get("sent").asString
|
||||
}
|
||||
|
||||
if (obj.has("userStyles")) {
|
||||
message.userStyles = context.deserialize<UserStyles>(obj.get("userStyles"), UserStyles::class.java)
|
||||
}
|
||||
if (obj.has("id")) {
|
||||
message.id = obj.get("id").asString
|
||||
}
|
||||
|
||||
return message
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue