mirror of
https://github.com/sudoxnym/habitica-android.git
synced 2026-07-15 02:31:57 +00:00
l4p fixes
This commit is contained in:
parent
c2547252de
commit
5c46ffeaa0
7 changed files with 322 additions and 146 deletions
|
|
@ -1383,6 +1383,8 @@
|
|||
<string name="shop_armoire_description">New gear is released during the seasonal Galas. Until then, theres %d pieces of gear in the Enchanted Armoire to find!</string>
|
||||
<string name="shop_armoire_empty_description">New gear is released during the seasonal Galas. The Enchanted Armoire gets new stock every month too!</string>
|
||||
<string name="unlock_gear_and_skills">Unlock %s gear and skills</string>
|
||||
<string name="rescind_invite">Rescind Invite</string>
|
||||
<string name="rescinded">Rescinded</string>
|
||||
|
||||
<plurals name="you_x_others">
|
||||
<item quantity="zero">You</item>
|
||||
|
|
|
|||
|
|
@ -5,18 +5,15 @@ import android.view.LayoutInflater
|
|||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.material.Divider
|
||||
import androidx.compose.material.ButtonDefaults
|
||||
import androidx.compose.material.ExperimentalMaterialApi
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.pullrefresh.pullRefresh
|
||||
|
|
@ -28,7 +25,7 @@ import androidx.compose.runtime.remember
|
|||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
|
|
@ -55,18 +52,19 @@ import com.habitrpg.android.habitica.ui.fragments.BaseFragment
|
|||
import com.habitrpg.android.habitica.ui.theme.HabiticaTheme
|
||||
import com.habitrpg.android.habitica.ui.viewmodels.BaseViewModel
|
||||
import com.habitrpg.android.habitica.ui.viewmodels.MainUserViewModel
|
||||
import com.habitrpg.android.habitica.ui.views.ClassText
|
||||
import com.habitrpg.android.habitica.ui.views.ComposableAvatarView
|
||||
import com.habitrpg.android.habitica.ui.views.LoadingButton
|
||||
import com.habitrpg.android.habitica.ui.views.LoadingButtonState
|
||||
import com.habitrpg.android.habitica.ui.views.progress.HabiticaCircularProgressView
|
||||
import com.habitrpg.android.habitica.ui.views.progress.HabiticaPullRefreshIndicator
|
||||
import com.habitrpg.android.habitica.ui.views.social.PartySeekingListItem
|
||||
import com.habitrpg.common.habitica.helpers.launchCatching
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import java.util.Locale
|
||||
import javax.inject.Inject
|
||||
import kotlin.time.DurationUnit
|
||||
import kotlin.time.toDuration
|
||||
|
||||
@HiltViewModel
|
||||
class PartySeekingViewModel @Inject constructor(
|
||||
|
|
@ -96,6 +94,10 @@ class PartySeekingViewModel @Inject constructor(
|
|||
)
|
||||
)?.firstOrNull()
|
||||
}
|
||||
|
||||
suspend fun rescindInvite(member : Member) : Member? {
|
||||
return socialRepository.removeMemberFromGroup("party", member.id)?.firstOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
@AndroidEntryPoint
|
||||
|
|
@ -129,93 +131,24 @@ class PartySeekingFragment : BaseFragment<FragmentComposeBinding>() {
|
|||
fun InviteButton(
|
||||
state : LoadingButtonState,
|
||||
onClick : () -> Unit,
|
||||
modifier : Modifier = Modifier
|
||||
) {
|
||||
LoadingButton(state = state, onClick = onClick, modifier = modifier, successContent = {
|
||||
Text(stringResource(R.string.invited))
|
||||
}) {
|
||||
Text(stringResource(R.string.send_invite))
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun PartySeekingListItem(
|
||||
user : Member,
|
||||
modifier : Modifier = Modifier,
|
||||
inviteState : LoadingButtonState = LoadingButtonState.LOADING,
|
||||
onInvite : (Member) -> Unit
|
||||
isAlreadyInvited: Boolean = false,
|
||||
) {
|
||||
Column(
|
||||
modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 14.dp, vertical = 4.dp)
|
||||
.background(HabiticaTheme.colors.windowBackground, HabiticaTheme.shapes.large)
|
||||
.padding(14.dp)
|
||||
) {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(14.dp),
|
||||
verticalAlignment = Alignment.Top
|
||||
) {
|
||||
ComposableAvatarView(user, Modifier.size(94.dp, 98.dp))
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(2.dp),
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Text(
|
||||
user.displayName,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
fontSize = 16.sp,
|
||||
color = HabiticaTheme.colors.textPrimary
|
||||
)
|
||||
Text(
|
||||
user.formattedUsername ?: "",
|
||||
fontSize = 14.sp,
|
||||
color = HabiticaTheme.colors.textTertiary
|
||||
)
|
||||
Divider(
|
||||
color = colorResource(R.color.divider_color),
|
||||
thickness = 1.dp,
|
||||
modifier = Modifier.padding(vertical = 4.dp)
|
||||
)
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Text(
|
||||
stringResource(R.string.level_abbreviated, user.stats?.lvl ?: 0),
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 14.sp,
|
||||
color = HabiticaTheme.colors.textPrimary
|
||||
)
|
||||
ClassText(
|
||||
user.stats?.habitClass,
|
||||
fontSize = 14.sp,
|
||||
iconSize = 18.dp,
|
||||
hasClass = user.hasClass
|
||||
)
|
||||
}
|
||||
Text(
|
||||
stringResource(R.string.x_checkins, user.loginIncentives),
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 14.sp,
|
||||
color = HabiticaTheme.colors.textPrimary
|
||||
)
|
||||
Text(
|
||||
Locale(user.preferences?.language ?: "en").getDisplayName(Locale.getDefault()),
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 14.sp,
|
||||
color = HabiticaTheme.colors.textPrimary
|
||||
)
|
||||
}
|
||||
LoadingButton(state = state, onClick = onClick, colors = ButtonDefaults.buttonColors(
|
||||
backgroundColor = if (isAlreadyInvited) HabiticaTheme.colors.errorBackground else HabiticaTheme.colors.tintedUiSub,
|
||||
contentColor = Color.White,
|
||||
), modifier = modifier, successContent = {
|
||||
if (isAlreadyInvited) {
|
||||
Text(stringResource(R.string.invited))
|
||||
} else {
|
||||
Text(stringResource(R.string.rescinded))
|
||||
}
|
||||
}) {
|
||||
if (isAlreadyInvited) {
|
||||
Text(stringResource(R.string.rescind_invite))
|
||||
} else {
|
||||
Text(stringResource(R.string.send_invite))
|
||||
}
|
||||
InviteButton(
|
||||
state = inviteState,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 8.dp),
|
||||
onClick = {
|
||||
onInvite(user)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -230,6 +163,7 @@ fun PartySeekingView(
|
|||
val pullRefreshState = rememberPullRefreshState(refreshing, { pageData.refresh() })
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
val successfulInvites = remember { mutableListOf<String>() }
|
||||
val inviteStates = remember { mutableMapOf<String, LoadingButtonState>() }
|
||||
|
||||
Box(
|
||||
|
|
@ -276,17 +210,25 @@ fun PartySeekingView(
|
|||
PartySeekingListItem(
|
||||
user = it,
|
||||
inviteState = inviteStates[it.id] ?: LoadingButtonState.CONTENT,
|
||||
isInvited = successfulInvites.contains(it.id),
|
||||
modifier = Modifier.animateItemPlacement()
|
||||
) { member ->
|
||||
scope.launchCatching({
|
||||
inviteStates[member.id] = LoadingButtonState.FAILED
|
||||
}) {
|
||||
inviteStates[member.id] = LoadingButtonState.LOADING
|
||||
val response = viewModel.inviteUser(member)
|
||||
inviteStates[member.id] = if (response != null) {
|
||||
LoadingButtonState.SUCCESS
|
||||
val response = if (successfulInvites.contains(member.id)) viewModel.inviteUser(member) else viewModel.inviteUser(member)
|
||||
if (response != null) {
|
||||
if (successfulInvites.contains(member.id)) {
|
||||
successfulInvites.remove(member.id)
|
||||
} else {
|
||||
successfulInvites.add(member.id)
|
||||
}
|
||||
inviteStates[member.id] = LoadingButtonState.SUCCESS
|
||||
delay(4.toDuration(DurationUnit.SECONDS))
|
||||
inviteStates[member.id] = LoadingButtonState.CONTENT
|
||||
} else {
|
||||
LoadingButtonState.FAILED
|
||||
inviteStates[member.id] = LoadingButtonState.FAILED
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -304,7 +246,6 @@ fun PartySeekingView(
|
|||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center,
|
||||
) {
|
||||
|
||||
HabiticaCircularProgressView()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ import androidx.compose.material.ButtonDefaults
|
|||
import androidx.compose.material.ButtonElevation
|
||||
import androidx.compose.material.CircularProgressIndicator
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.ProvideTextStyle
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
|
|
@ -44,8 +45,11 @@ import androidx.compose.ui.graphics.Color
|
|||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.ui.theme.HabiticaTheme
|
||||
import kotlinx.coroutines.delay
|
||||
|
|
@ -125,53 +129,55 @@ fun LoadingButton(
|
|||
colors = buttonColors,
|
||||
contentPadding = PaddingValues(0.dp)
|
||||
) {
|
||||
AnimatedContent(
|
||||
targetState = state,
|
||||
transitionSpec = {
|
||||
val isInitialShowingContent =
|
||||
initialState == LoadingButtonState.CONTENT || initialState == LoadingButtonState.DISABLED || (initialState == LoadingButtonState.SUCCESS && successContent == null)
|
||||
val isTargetShowingContent =
|
||||
targetState == LoadingButtonState.CONTENT || targetState == LoadingButtonState.DISABLED || (targetState == LoadingButtonState.SUCCESS && successContent == null)
|
||||
if (targetState == LoadingButtonState.FAILED) {
|
||||
fadeIn(
|
||||
animationSpec = tween(220, delayMillis = 90)
|
||||
) +
|
||||
slideInHorizontally(
|
||||
animationSpec = spring(
|
||||
dampingRatio = 0.2f,
|
||||
stiffness = StiffnessMediumLow,
|
||||
)
|
||||
) with
|
||||
fadeOut(animationSpec = tween(90))
|
||||
} else if (isInitialShowingContent && isTargetShowingContent) {
|
||||
fadeIn() with fadeOut()
|
||||
} else {
|
||||
fadeIn(animationSpec = tween(220, delayMillis = 90)) +
|
||||
scaleIn(
|
||||
initialScale = 0.92f,
|
||||
animationSpec = tween(220, delayMillis = 90, FastOutSlowInEasing)
|
||||
) with
|
||||
fadeOut(animationSpec = tween(90))
|
||||
}
|
||||
},
|
||||
contentAlignment = Alignment.Center,
|
||||
modifier = Modifier.padding(contentPadding)
|
||||
) { state ->
|
||||
when (state) {
|
||||
LoadingButtonState.LOADING ->
|
||||
CircularProgressIndicator(
|
||||
color = contentColor.value,
|
||||
modifier = Modifier.size(16.dp)
|
||||
)
|
||||
ProvideTextStyle(value = TextStyle(fontSize = 16.sp, fontWeight = FontWeight.SemiBold)) {
|
||||
AnimatedContent(
|
||||
targetState = state,
|
||||
transitionSpec = {
|
||||
val isInitialShowingContent =
|
||||
initialState == LoadingButtonState.CONTENT || initialState == LoadingButtonState.DISABLED || (initialState == LoadingButtonState.SUCCESS && successContent == null)
|
||||
val isTargetShowingContent =
|
||||
targetState == LoadingButtonState.CONTENT || targetState == LoadingButtonState.DISABLED || (targetState == LoadingButtonState.SUCCESS && successContent == null)
|
||||
if (targetState == LoadingButtonState.FAILED) {
|
||||
fadeIn(
|
||||
animationSpec = tween(220, delayMillis = 90)
|
||||
) +
|
||||
slideInHorizontally(
|
||||
animationSpec = spring(
|
||||
dampingRatio = 0.2f,
|
||||
stiffness = StiffnessMediumLow,
|
||||
)
|
||||
) with
|
||||
fadeOut(animationSpec = tween(90))
|
||||
} else if (isInitialShowingContent && isTargetShowingContent) {
|
||||
fadeIn() with fadeOut()
|
||||
} else {
|
||||
fadeIn(animationSpec = tween(220, delayMillis = 90)) +
|
||||
scaleIn(
|
||||
initialScale = 0.92f,
|
||||
animationSpec = tween(220, delayMillis = 90, FastOutSlowInEasing)
|
||||
) with
|
||||
fadeOut(animationSpec = tween(90))
|
||||
}
|
||||
},
|
||||
contentAlignment = Alignment.Center,
|
||||
modifier = Modifier.padding(contentPadding)
|
||||
) { state ->
|
||||
when (state) {
|
||||
LoadingButtonState.LOADING ->
|
||||
CircularProgressIndicator(
|
||||
color = contentColor.value,
|
||||
modifier = Modifier.size(16.dp)
|
||||
)
|
||||
|
||||
LoadingButtonState.SUCCESS -> successContent?.let { it() } ?: content()
|
||||
LoadingButtonState.FAILED ->
|
||||
failedContent?.let { it() } ?: Image(
|
||||
painterResource(R.drawable.failed_loading),
|
||||
stringResource(R.string.failed),
|
||||
Modifier.padding(horizontal = 8.dp)
|
||||
)
|
||||
else -> content()
|
||||
LoadingButtonState.SUCCESS -> successContent?.let { it() } ?: content()
|
||||
LoadingButtonState.FAILED ->
|
||||
failedContent?.let { it() } ?: Image(
|
||||
painterResource(R.drawable.failed_loading),
|
||||
stringResource(R.string.failed),
|
||||
Modifier.padding(horizontal = 8.dp)
|
||||
)
|
||||
else -> content()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -208,7 +214,10 @@ private fun Preview() {
|
|||
}, content = {
|
||||
Text("Do something")
|
||||
}, modifier = Modifier.fillMaxWidth())
|
||||
LoadingButton(LoadingButtonState.LOADING, {}, content = {
|
||||
LoadingButton(LoadingButtonState.LOADING, {}, colors = ButtonDefaults.buttonColors(
|
||||
backgroundColor = HabiticaTheme.colors.successBackground,
|
||||
contentColor = Color.White
|
||||
), content = {
|
||||
Text("Do something")
|
||||
})
|
||||
LoadingButton(LoadingButtonState.LOADING, {}, content = {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,21 @@ import android.widget.FrameLayout
|
|||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.material.ProvideTextStyle
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.asImageBitmap
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.habitrpg.common.habitica.R
|
||||
import com.habitrpg.common.habitica.models.PlayerTier
|
||||
|
|
@ -45,7 +60,7 @@ class UsernameLabel @JvmOverloads constructor(
|
|||
tierIconView.visibility = View.GONE
|
||||
} else {
|
||||
tierIconView.visibility = View.VISIBLE
|
||||
tierIconView.setImageBitmap(com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper.imageOfContributorBadge(value.toFloat(), isNPC))
|
||||
tierIconView.setImageBitmap(HabiticaIconsHelper.imageOfContributorBadge(value.toFloat(), isNPC))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -68,3 +83,24 @@ class UsernameLabel @JvmOverloads constructor(
|
|||
addView(tierIconView, iconViewParams)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Composable
|
||||
fun ComposableUsernameLabel(
|
||||
username: String,
|
||||
tier: Int,
|
||||
modifier : Modifier = Modifier,
|
||||
isNPC: Boolean = false
|
||||
) {
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(2.dp), verticalAlignment = Alignment.CenterVertically, modifier = modifier) {
|
||||
ProvideTextStyle(value = TextStyle(fontWeight = FontWeight.SemiBold)) {
|
||||
Text(username, color = if (isNPC) colorResource(id = R.color.contributor_npc) else Color(PlayerTier.getColorForTier(LocalContext.current, tier)))
|
||||
if (tier > 0) {
|
||||
Image(
|
||||
bitmap = HabiticaIconsHelper.imageOfContributorBadge(tier.toFloat(), isNPC).asImageBitmap(),
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,187 @@
|
|||
package com.habitrpg.android.habitica.ui.views.social
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material.Divider
|
||||
import androidx.compose.material.ProvideTextStyle
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.models.auth.LocalAuthentication
|
||||
import com.habitrpg.android.habitica.models.members.Member
|
||||
import com.habitrpg.android.habitica.models.members.MemberFlags
|
||||
import com.habitrpg.android.habitica.models.members.MemberPreferences
|
||||
import com.habitrpg.android.habitica.models.user.Authentication
|
||||
import com.habitrpg.android.habitica.models.user.ContributorInfo
|
||||
import com.habitrpg.android.habitica.models.user.Profile
|
||||
import com.habitrpg.android.habitica.models.user.Stats
|
||||
import com.habitrpg.android.habitica.ui.fragments.social.party.InviteButton
|
||||
import com.habitrpg.android.habitica.ui.theme.HabiticaTheme
|
||||
import com.habitrpg.android.habitica.ui.views.ClassText
|
||||
import com.habitrpg.android.habitica.ui.views.ComposableAvatarView
|
||||
import com.habitrpg.android.habitica.ui.views.ComposableUsernameLabel
|
||||
import com.habitrpg.android.habitica.ui.views.LoadingButtonState
|
||||
import java.util.Locale
|
||||
import kotlin.random.Random
|
||||
|
||||
@Composable
|
||||
fun PartySeekingListItem(
|
||||
user : Member,
|
||||
modifier : Modifier = Modifier,
|
||||
inviteState : LoadingButtonState = LoadingButtonState.LOADING,
|
||||
isInvited: Boolean = false,
|
||||
onInvite : (Member) -> Unit
|
||||
) {
|
||||
Column(
|
||||
modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 14.dp)
|
||||
.padding(bottom = 4.dp)
|
||||
.background(HabiticaTheme.colors.windowBackground, HabiticaTheme.shapes.large)
|
||||
.padding(14.dp)
|
||||
) {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(14.dp),
|
||||
verticalAlignment = Alignment.Top
|
||||
) {
|
||||
ComposableAvatarView(user,
|
||||
Modifier
|
||||
.size(94.dp, 98.dp)
|
||||
.padding(top = 4.dp))
|
||||
Column(
|
||||
verticalArrangement = Arrangement.Top,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
ProvideTextStyle(value = TextStyle(fontSize = 14.sp)) {
|
||||
ComposableUsernameLabel(
|
||||
user.displayName,
|
||||
user.contributor?.level ?: 0
|
||||
)
|
||||
}
|
||||
Text(
|
||||
user.formattedUsername ?: "",
|
||||
fontSize = 14.sp,
|
||||
color = HabiticaTheme.colors.textTertiary
|
||||
)
|
||||
Divider(
|
||||
color = colorResource(R.color.divider_color),
|
||||
thickness = 1.dp,
|
||||
modifier = Modifier.padding(vertical = 6.dp)
|
||||
)
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Text(
|
||||
stringResource(R.string.level_abbreviated, user.stats?.lvl ?: 0),
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 14.sp,
|
||||
color = HabiticaTheme.colors.textPrimary
|
||||
)
|
||||
ClassText(
|
||||
user.stats?.habitClass,
|
||||
fontSize = 14.sp,
|
||||
iconSize = 18.dp,
|
||||
hasClass = user.hasClass
|
||||
)
|
||||
}
|
||||
Text(
|
||||
stringResource(R.string.x_checkins, user.loginIncentives),
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 14.sp,
|
||||
color = HabiticaTheme.colors.textPrimary
|
||||
)
|
||||
Text(
|
||||
Locale(user.preferences?.language ?: "en").getDisplayName(Locale.getDefault()),
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 14.sp,
|
||||
color = HabiticaTheme.colors.textPrimary
|
||||
)
|
||||
}
|
||||
}
|
||||
InviteButton(
|
||||
state = inviteState,
|
||||
isAlreadyInvited = isInvited,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 8.dp),
|
||||
onClick = {
|
||||
onInvite(user)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private class MemberProvider: PreviewParameterProvider<Member> {
|
||||
|
||||
private fun generateMember() : Member {
|
||||
val member = Member()
|
||||
member.profile = Profile()
|
||||
member.profile?.name = "User"
|
||||
member.authentication = Authentication()
|
||||
member.authentication?.localAuthentication = LocalAuthentication()
|
||||
member.authentication?.localAuthentication?.username = "username"
|
||||
member.preferences = MemberPreferences()
|
||||
member.preferences?.disableClasses = false
|
||||
member.flags = MemberFlags()
|
||||
member.flags?.classSelected = true
|
||||
member.stats = Stats()
|
||||
member.stats?.hp = Random.nextDouble(from = 0.0, until = 50.0)
|
||||
member.stats?.maxHealth = 50
|
||||
member.stats?.toNextLevel = Random.nextInt(from = 0, until = 10000)
|
||||
member.stats?.exp =
|
||||
Random.nextDouble(until = (member.stats?.toNextLevel ?: 0).toDouble())
|
||||
member.stats?.maxMP = Random.nextInt(from = 0, until = 10000)
|
||||
member.stats?.mp = Random.nextDouble(until = (member.stats?.maxMP ?: 0).toDouble())
|
||||
member.stats?.lvl = Random.nextInt(from = 0, until = 9999)
|
||||
return member
|
||||
}
|
||||
|
||||
override val values : Sequence<Member>
|
||||
get() {
|
||||
val list = mutableListOf<Member>()
|
||||
val earlyMember = generateMember()
|
||||
earlyMember.stats?.lvl = 5
|
||||
list.add(earlyMember)
|
||||
val needsClass = generateMember()
|
||||
needsClass.stats?.lvl = 24
|
||||
needsClass.stats?.habitClass = "healer"
|
||||
needsClass.flags?.classSelected = false
|
||||
needsClass.contributor = ContributorInfo()
|
||||
needsClass.contributor?.level = 4
|
||||
list.add(needsClass)
|
||||
val classDisabled = generateMember()
|
||||
classDisabled.stats?.lvl = 24
|
||||
classDisabled.stats?.habitClass = "rogue"
|
||||
classDisabled.preferences?.disableClasses = true
|
||||
list.add(classDisabled)
|
||||
val subscriber = generateMember()
|
||||
subscriber.stats?.habitClass = "warrior"
|
||||
list.add(subscriber)
|
||||
val onlyHourglasses = generateMember()
|
||||
onlyHourglasses.stats?.habitClass = "wizard"
|
||||
list.add(onlyHourglasses)
|
||||
return list.asSequence()
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun Preview(@PreviewParameter(MemberProvider::class) data: Member) {
|
||||
PartySeekingListItem(user = data, onInvite = {})
|
||||
}
|
||||
|
|
@ -19,4 +19,5 @@
|
|||
<color name="text_blue">@color/blue_100</color>
|
||||
<color name="text_teal">@color/teal_100</color>
|
||||
<color name="dim_background">#40502B94</color>
|
||||
<color name="divider_color">@color/gray_100</color>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
NAME=4.2
|
||||
CODE=5951
|
||||
CODE=5961
|
||||
Loading…
Reference in a new issue