diff --git a/Habitica/res/values/strings.xml b/Habitica/res/values/strings.xml
index 574378e09..92f524b3c 100644
--- a/Habitica/res/values/strings.xml
+++ b/Habitica/res/values/strings.xml
@@ -1383,6 +1383,8 @@
New gear is released during the seasonal Galas. Until then, theres %d pieces of gear in the Enchanted Armoire to find!
New gear is released during the seasonal Galas. The Enchanted Armoire gets new stock every month too!
Unlock %s gear and skills
+ Rescind Invite
+ Rescinded
- You
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/party/PartySeekingFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/party/PartySeekingFragment.kt
index 4b66f8dc8..44f3fc5ca 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/party/PartySeekingFragment.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/party/PartySeekingFragment.kt
@@ -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() {
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() }
val inviteStates = remember { mutableMapOf() }
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()
}
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/LoadingButton.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/LoadingButton.kt
index 026b6fabf..6a7cdb249 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/LoadingButton.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/LoadingButton.kt
@@ -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 = {
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/UsernameLabel.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/UsernameLabel.kt
index 153e26711..e49cd80f6 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/UsernameLabel.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/UsernameLabel.kt
@@ -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
+ )
+ }
+ }
+ }
+}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/social/PartySeekingListItem.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/social/PartySeekingListItem.kt
new file mode 100644
index 000000000..6f130a113
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/social/PartySeekingListItem.kt
@@ -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 {
+
+ 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
+ get() {
+ val list = mutableListOf()
+ 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 = {})
+}
diff --git a/common/src/main/res/values-night/colors.xml b/common/src/main/res/values-night/colors.xml
index 3a0c54faa..81e86ef21 100644
--- a/common/src/main/res/values-night/colors.xml
+++ b/common/src/main/res/values-night/colors.xml
@@ -19,4 +19,5 @@
@color/blue_100
@color/teal_100
#40502B94
+ @color/gray_100
diff --git a/version.properties b/version.properties
index 0cbb8ab3d..c5da90060 100644
--- a/version.properties
+++ b/version.properties
@@ -1,2 +1,2 @@
NAME=4.2
-CODE=5951
\ No newline at end of file
+CODE=5961
\ No newline at end of file