Display assigned avatars

This commit is contained in:
Phillip Thelen 2022-12-06 08:33:08 +01:00
parent dc33e91010
commit d32fe481e4
26 changed files with 162 additions and 69 deletions

View file

@ -1270,6 +1270,8 @@
<string name="edit_assignees">Edit assignees</string>
<string name="assign_to">Assign to...</string>
<string name="promote_to_manager">Promote to Manager</string>
<string name="manager">Manager</string>
<string name="member_list">Member List</string>
<plurals name="you_x_others">
<item quantity="zero">You</item>
<item quantity="one">You, %d other</item>

View file

@ -119,4 +119,5 @@ interface SocialRepository : BaseRepository {
fun getGroupMembership(id: String): Flow<GroupMembership?>
fun getGroupMemberships(): Flow<List<GroupMembership>>
suspend fun blockMember(userID: String): List<String>?
fun getMember(userID: String?): Flow<Member?>
}

View file

@ -40,6 +40,10 @@ class SocialRepositoryImpl(
return apiClient.blockMember(userID)
}
override fun getMember(userID: String?): Flow<Member?> {
return localRepository.getMember(userID)
}
override fun getGroupMembership(id: String) = localRepository.getGroupMembership(userID, id)
override fun getGroupMemberships(): Flow<List<GroupMembership>> {

View file

@ -54,4 +54,5 @@ interface SocialLocalRepository : BaseLocalRepository {
page: Int
)
fun saveInboxConversations(userID: String, conversations: List<InboxConversation>)
fun getMember(userID: String?): Flow<Member?>
}

View file

@ -102,6 +102,15 @@ class RealmSocialLocalRepository(realm: Realm) : RealmBaseLocalRepository(realm)
}
}
override fun getMember(userID: String?): Flow<Member?> {
return realm.where(Member::class.java)
.equalTo("id", userID)
.findAll()
.toFlow()
.filter { member -> member.isLoaded && member.isValid }
.map { member -> member.firstOrNull() }
}
override fun saveGroupMemberships(userID: String?, memberships: List<GroupMembership>) {
save(memberships)
if (userID != null) {

View file

@ -11,7 +11,7 @@ class BuyRewardUseCase @Inject
constructor(
private val taskRepository: TaskRepository,
private val soundManager: SoundManager,
) : FlowUseCase<BuyRewardUseCase.RequestValues, TaskScoringResult?>() {
) : UseCase<BuyRewardUseCase.RequestValues, TaskScoringResult?>() {
override suspend fun run(requestValues: RequestValues): TaskScoringResult? {
val response = taskRepository.taskChecked(requestValues.user, requestValues.task, false, false, requestValues.notifyFunc)
@ -23,5 +23,5 @@ constructor(
internal val user: User?,
val task: Task,
val notifyFunc: (TaskScoringResult) -> Unit
) : FlowUseCase.RequestValues
) : UseCase.RequestValues
}

View file

@ -7,7 +7,7 @@ import com.habitrpg.android.habitica.models.user.User
import com.habitrpg.android.habitica.ui.activities.ClassSelectionActivity
import javax.inject.Inject
class CheckClassSelectionUseCase @Inject constructor() : FlowUseCase<CheckClassSelectionUseCase.RequestValues, Unit>() {
class CheckClassSelectionUseCase @Inject constructor() : UseCase<CheckClassSelectionUseCase.RequestValues, Unit>() {
override suspend fun run(requestValues: RequestValues) {
val user = requestValues.user
@ -42,5 +42,5 @@ class CheckClassSelectionUseCase @Inject constructor() : FlowUseCase<CheckClassS
val isInitialSelection: Boolean,
val currentClass: String?,
val activity: Activity
) : FlowUseCase.RequestValues
) : UseCase.RequestValues
}

View file

@ -14,7 +14,7 @@ import javax.inject.Inject
class DisplayItemDropUseCase @Inject
constructor(private val soundManager: SoundManager):
FlowUseCase<DisplayItemDropUseCase.RequestValues, Unit>() {
UseCase<DisplayItemDropUseCase.RequestValues, Unit>() {
override suspend fun run(requestValues: RequestValues) {
val data = requestValues.data
@ -49,5 +49,5 @@ constructor(private val soundManager: SoundManager):
val context: AppCompatActivity,
val snackbarTargetView: ViewGroup,
val showQuestItems: Boolean
) : FlowUseCase.RequestValues
) : UseCase.RequestValues
}

View file

@ -20,7 +20,7 @@ import javax.inject.Inject
class FeedPetUseCase @Inject
constructor(
private val inventoryRepository: InventoryRepository,
) : FlowUseCase<FeedPetUseCase.RequestValues, FeedResponse?>() {
) : UseCase<FeedPetUseCase.RequestValues, FeedResponse?>() {
override suspend fun run(requestValues: FeedPetUseCase.RequestValues): FeedResponse? {
val feedResponse = inventoryRepository.feedPet(requestValues.pet, requestValues.food)
(requestValues.context as? SnackbarActivity)?.showSnackbar(content = feedResponse?.message)
@ -77,5 +77,5 @@ constructor(
}
class RequestValues(val pet: Pet, val food: Food, val context: Context) :
FlowUseCase.RequestValues
UseCase.RequestValues
}

View file

@ -20,7 +20,7 @@ import javax.inject.Inject
class HatchPetUseCase @Inject
constructor(
private val inventoryRepository: InventoryRepository) : FlowUseCase<HatchPetUseCase.RequestValues, Items?>() {
private val inventoryRepository: InventoryRepository) : UseCase<HatchPetUseCase.RequestValues, Items?>() {
override suspend fun run(requestValues: RequestValues): Items? {
return inventoryRepository.hatchPet(requestValues.egg, requestValues.potion) {
val petWrapper = View.inflate(requestValues.context, R.layout.pet_imageview, null) as? FrameLayout
@ -52,5 +52,5 @@ constructor(
}
}
class RequestValues(val potion: HatchingPotion, val egg: Egg, val context: Context) : FlowUseCase.RequestValues
class RequestValues(val potion: HatchingPotion, val egg: Egg, val context: Context) : UseCase.RequestValues
}

View file

@ -20,7 +20,7 @@ class LevelUpUseCase @Inject
constructor(
private val soundManager: SoundManager,
private val checkClassSelectionUseCase: CheckClassSelectionUseCase
) : FlowUseCase<LevelUpUseCase.RequestValues, Stats?>() {
) : UseCase<LevelUpUseCase.RequestValues, Stats?>() {
override suspend fun run(requestValues: RequestValues): Stats? {
soundManager.loadAndPlayAudio(SoundManager.SoundLevelUp)
@ -99,7 +99,7 @@ constructor(
val level: Int?,
val activity: BaseActivity,
val snackbarTargetView: ViewGroup
) : FlowUseCase.RequestValues {
) : UseCase.RequestValues {
val newLevel: Int = level ?: 0
}
}

View file

@ -27,7 +27,7 @@ class NotifyUserUseCase @Inject
constructor(
private val levelUpUseCase: LevelUpUseCase,
private val userRepository: UserRepository
) : FlowUseCase<NotifyUserUseCase.RequestValues, Stats?>() {
) : UseCase<NotifyUserUseCase.RequestValues, Stats?>() {
override suspend fun run(requestValues: RequestValues): Stats? {
if (requestValues.user == null) {
@ -57,7 +57,7 @@ constructor(
val questDamage: Double?,
val hasLeveledUp: Boolean?,
val level: Int?
) : FlowUseCase.RequestValues
) : UseCase.RequestValues
companion object {
val formatter = NumberFormat.getInstance().apply {

View file

@ -3,7 +3,7 @@ package com.habitrpg.android.habitica.interactors
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
abstract class FlowUseCase<Q : FlowUseCase.RequestValues?, T> {
abstract class UseCase<Q : UseCase.RequestValues?, T> {
protected abstract suspend fun run(requestValues: Q): T
suspend fun callInteractor(requestValues: Q): T {
return withContext(Dispatchers.Main) {

View file

@ -16,6 +16,9 @@ import android.view.ViewGroup
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels
import androidx.appcompat.app.ActionBarDrawerToggle
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.core.os.bundleOf
import androidx.core.view.children
import androidx.drawerlayout.widget.DrawerLayout
@ -240,7 +243,9 @@ open class MainActivity : BaseActivity(), SnackbarActivity {
HabiticaTheme {
AppHeaderView(viewModel.userViewModel) {
showAsBottomSheet { onClose ->
GroupPlanMemberList(it, {
val group by viewModel.userViewModel.currentTeamPlanGroup.collectAsState(null)
val members by viewModel.userViewModel.currentTeamPlanMembers.observeAsState()
GroupPlanMemberList(members, group, {
onClose()
FullProfileActivity.open(it)
}, { member ->

View file

@ -18,6 +18,7 @@ import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Alignment
@ -42,25 +43,35 @@ import androidx.lifecycle.asLiveData
import com.google.accompanist.systemuicontroller.rememberSystemUiController
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.components.UserComponent
import com.habitrpg.android.habitica.data.SocialRepository
import com.habitrpg.android.habitica.data.TaskRepository
import com.habitrpg.android.habitica.helpers.MainNavigationController
import com.habitrpg.android.habitica.helpers.TaskDescriptionBuilder
import com.habitrpg.android.habitica.models.members.Member
import com.habitrpg.android.habitica.ui.theme.HabiticaTheme
import com.habitrpg.android.habitica.ui.viewmodels.BaseViewModel
import com.habitrpg.android.habitica.ui.views.CompletedAt
import com.habitrpg.android.habitica.ui.views.UserRow
import com.habitrpg.shared.habitica.models.tasks.TaskType
import kotlinx.coroutines.flow.Flow
import javax.inject.Inject
class TaskSummaryViewModel(val taskId: String) : BaseViewModel() {
@Inject
lateinit var taskRespository: TaskRepository
@Inject
lateinit var socialRepository: SocialRepository
val task = taskRespository.getTask(taskId).asLiveData()
override fun inject(component: UserComponent) {
component.inject(this)
}
fun getMember(userID: String?): Flow<Member?> {
return socialRepository.getMember(userID)
}
@Suppress("UNCHECKED_CAST")
class Factory(private val taskID: String) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
@ -230,8 +241,9 @@ fun TaskSummaryView(viewModel: TaskSummaryViewModel) {
modifier = titleModifier.padding(bottom = 4.dp)
)
for (item in task?.group?.assignedUsersDetail ?: emptyList()) {
val member = viewModel.getMember(item.assignedUserID).collectAsState(null)
UserRow(
item.assignedUsername ?: "", Modifier
item.assignedUsername ?: "", member.value, Modifier
.padding(vertical = 4.dp)
.background(
colorResource(

View file

@ -135,7 +135,7 @@ object HabiticaTheme {
contentBackgroundOffset = Color(context.getThemeColor(R.attr.colorContentBackgroundOffset)),
textPrimary = Color(context.getThemeColor(R.attr.textColorPrimary)),
textSecondary = Color(context.getThemeColor(R.attr.textColorSecondary)),
textTertiary = Color(context.getThemeColor(R.attr.colorTertiary)),
textTertiary = Color(ContextCompat.getColor(context, R.color.text_ternary)),
textDimmed = Color(ContextCompat.getColor(context, R.color.text_dimmed)),
)
}

View file

@ -44,7 +44,6 @@ import androidx.compose.ui.unit.sp
import androidx.core.os.bundleOf
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.helpers.MainNavigationController
import com.habitrpg.android.habitica.models.members.Member
import com.habitrpg.android.habitica.models.user.User
import com.habitrpg.android.habitica.ui.viewmodels.MainUserViewModel
@ -72,7 +71,7 @@ fun UserLevelText(user: User) {
@Composable
fun AppHeaderView(
viewModel: MainUserViewModel,
onMemberRowClicked: (List<Member>) -> Unit
onMemberRowClicked: () -> Unit
) {
val user by viewModel.user.observeAsState(null)
val teamPlan by viewModel.currentTeamPlan.collectAsState(null)
@ -181,7 +180,7 @@ fun AppHeaderView(
colorResource(R.color.window_background)
)
.clickable {
teamPlanMembers?.let { onMemberRowClicked(it) }
onMemberRowClicked()
}
) {
for (member in teamPlanMembers?.filter { it.id != user?.id }?.take(6) ?: emptyList()) {
@ -205,11 +204,20 @@ fun AppHeaderView(
ClassIcon(className = user?.stats?.habitClass, hasClass = user?.hasClass ?: false, modifier = Modifier.padding(4.dp))
user?.let { UserLevelText(it) }
Spacer(Modifier.weight(1f))
user?.hourglassCount?.toDouble()
?.let { CurrencyText("hourglasses", it, modifier = Modifier.padding(end = 12.dp)) }
if (user?.isSubscribed == true) {
user?.hourglassCount?.toDouble()
?.let {
CurrencyText(
"hourglasses",
it,
modifier = Modifier.padding(end = 12.dp).clickable {
MainNavigationController.navigate(R.id.subscriptionPurchaseActivity)
})
}
}
CurrencyText("gold", user?.stats?.gp ?: 0.0, modifier = Modifier.padding(end = 12.dp))
CurrencyText("gems", user?.gemCount?.toDouble() ?: 0.0, modifier = Modifier.clickable {
MainNavigationController.navigate(R.id.gemPurchaseActivity, bundleOf(Pair("openSubscription", false)))
MainNavigationController.navigate(R.id.gemPurchaseActivity)
})
}
}

View file

@ -74,21 +74,24 @@ private fun BottomSheetWrapper(
val modalBottomSheetState = rememberModalBottomSheetState(ModalBottomSheetValue.Hidden)
var isSheetOpened by remember { mutableStateOf(false) }
val radius = 20.dp
ModalBottomSheetLayout(
sheetBackgroundColor = Color.Transparent,
sheetState = modalBottomSheetState,
sheetShape = RoundedCornerShape(topStart = radius, topEnd = radius),
sheetContent = {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.padding(horizontal = 4.dp)
.border(
2.dp,
colorResource(R.color.window_background),
RoundedCornerShape(topStart = 12.dp, topEnd = 12.dp)
RoundedCornerShape(topStart = radius, topEnd = radius)
)
.background(
MaterialTheme.colors.background,
RoundedCornerShape(topStart = 12.dp, topEnd = 12.dp)
RoundedCornerShape(topStart = radius, topEnd = radius)
)
.padding(vertical = 8.dp)
) {

View file

@ -23,7 +23,7 @@ fun CurrencyText(
decimals: Int = 2,
minForAbbrevation: Int = 0
) {
Row(verticalAlignment = Alignment.CenterVertically) {
Row(verticalAlignment = Alignment.CenterVertically, modifier = modifier) {
when (currency) {
"gold" -> HabiticaIconsHelper.imageOfGold()
"gems" -> HabiticaIconsHelper.imageOfGem()
@ -39,8 +39,7 @@ fun CurrencyText(
else -> colorResource(R.color.text_primary)
},
fontSize = 12.sp,
fontWeight = FontWeight.SemiBold,
modifier = modifier
fontWeight = FontWeight.SemiBold
)
}
}

View file

@ -14,18 +14,15 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.Text
import androidx.compose.material.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
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.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
@ -34,24 +31,52 @@ 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.social.Group
import com.habitrpg.android.habitica.models.user.Authentication
import com.habitrpg.android.habitica.models.user.Profile
import com.habitrpg.android.habitica.models.user.Stats
import com.habitrpg.android.habitica.ui.theme.HabiticaTheme
import com.habitrpg.common.habitica.extensions.getThemeColor
import kotlin.random.Random
@Composable
fun GroupPlanMemberList(
members: List<Member>,
members: List<Member>?,
group: Group?,
onMemberClicked: (String) -> Unit,
onMoreClicked: (Member) -> Unit
) {
LazyColumn {
for (member in members) {
item {
Text(stringResource(R.string.member_list),
fontSize = 16.sp,
fontWeight = FontWeight.Medium,
color = HabiticaTheme.colors.textTertiary,
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth()
.padding(bottom = 20.dp)
)
}
for (member in members?.sortedWith(compareByDescending<Member> {
group?.isLeader(
it.id ?: ""
)
}.thenByDescending {
group?.isManager(
it.id ?: ""
)
}.thenBy { it.username }) ?: emptyList()) {
item {
val role = if (group?.isLeader(member.id ?: "") == true) {
stringResource(R.string.owner)
} else if (group?.isManager(member.id ?: "") == true) {
stringResource(R.string.manager)
} else {
stringResource(R.string.member)
}
MemberItem(
member,
role,
onMemberClicked,
onMoreClicked,
modifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp)
@ -64,6 +89,7 @@ fun GroupPlanMemberList(
@Composable
fun MemberItem(
member: Member,
role: String,
onMemberClicked: (String) -> Unit,
onMoreClicked: (Member) -> Unit,
modifier: Modifier = Modifier
@ -77,23 +103,14 @@ fun MemberItem(
member.id?.let { onMemberClicked(it) }
}
) {
TextButton(
onClick = { onMoreClicked(member) }, modifier = Modifier
.size(32.dp)
.background(
Color(LocalContext.current.getThemeColor(R.attr.colorAccent)),
WobblyCircle
)
.align(Alignment.TopEnd)
) {
Image(painterResource(R.drawable.menu_messages), null)
}
Row(
horizontalArrangement = Arrangement.spacedBy(16.dp),
modifier = Modifier.padding(14.dp)
horizontalArrangement = Arrangement.spacedBy(10.dp),
modifier = Modifier.padding(8.dp)
) {
ComposableAvatarView(avatar = member, modifier = Modifier.size(94.dp, 98.dp))
Column(verticalArrangement = Arrangement.SpaceBetween, modifier = Modifier.height(100.dp)) {
ComposableAvatarView(avatar = member, modifier = Modifier
.padding(6.dp)
.size(94.dp, 98.dp))
Column(verticalArrangement = Arrangement.SpaceBetween, modifier = Modifier.height(104.dp).padding(end = 6.dp)) {
Text(
member.displayName,
fontWeight = FontWeight.SemiBold,
@ -101,17 +118,16 @@ fun MemberItem(
color = HabiticaTheme.colors.textPrimary
)
Row(
horizontalArrangement = Arrangement.spacedBy(4.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp),
verticalAlignment = Alignment.CenterVertically
) {
Text(
member.formattedUsername ?: "",
color = HabiticaTheme.colors.textSecondary
color = HabiticaTheme.colors.textTertiary
)
Spacer(
Modifier
.weight(1.0f)
.background(Color.Red)
)
ClassIcon(
member.stats?.habitClass,
@ -126,14 +142,16 @@ fun MemberItem(
barColor = HabiticaTheme.colors.contentBackgroundOffset,
value = member.stats?.hp ?: 0.0,
maxValue = (member.stats?.maxHealth ?: 0).toDouble(),
displayCompact = true
displayCompact = true,
barHeight = 5.dp
)
LabeledBar(
color = colorResource(R.color.xpColor),
barColor = HabiticaTheme.colors.contentBackgroundOffset,
value = member.stats?.exp ?: 0.0,
maxValue = (member.stats?.toNextLevel ?: 0).toDouble(),
displayCompact = true
displayCompact = true,
barHeight = 5.dp
)
if (member.hasClass) {
LabeledBar(
@ -141,7 +159,8 @@ fun MemberItem(
barColor = HabiticaTheme.colors.contentBackgroundOffset,
value = member.stats?.mp ?: 0.0,
maxValue = (member.stats?.maxMP ?: 0).toDouble(),
displayCompact = true
displayCompact = true,
barHeight = 5.dp
)
}
Row(horizontalArrangement = Arrangement.SpaceBetween) {
@ -149,11 +168,12 @@ fun MemberItem(
stringResource(R.string.level_unabbreviated, member.stats?.lvl ?: 0),
fontSize = 14.sp,
fontWeight = FontWeight.Normal,
color = HabiticaTheme.colors.textPrimary
color = HabiticaTheme.colors.textTertiary
)
Spacer(Modifier.weight(1f))
Text(
"", fontWeight = FontWeight.SemiBold, fontSize = 14.sp,
color = HabiticaTheme.colors.textPrimary
role, fontWeight = FontWeight.SemiBold, fontSize = 14.sp,
color = HabiticaTheme.colors.textSecondary
)
}
}
@ -197,5 +217,5 @@ private class MemberProvider : PreviewParameterProvider<Member> {
@Composable
@Preview
private fun Preview(@PreviewParameter(MemberProvider::class) member: Member) {
MemberItem(member = member, onMemberClicked = {}, onMoreClicked = {})
MemberItem(member = member, role = "Manager", onMemberClicked = {}, onMoreClicked = {})
}

View file

@ -29,6 +29,7 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.habitrpg.android.habitica.R
@ -44,7 +45,8 @@ fun LabeledBar(
barColor: Color = HabiticaTheme.colors.windowBackground,
value: Double,
maxValue: Double,
displayCompact: Boolean,
displayCompact: Boolean = false,
barHeight: Dp = 8.dp,
disabled: Boolean = false
) {
val cleanedMaxVlaue = java.lang.Double.max(1.0, maxValue)
@ -72,7 +74,7 @@ fun LabeledBar(
Modifier
.fillMaxWidth()
.clip(CircleShape)
.height(8.dp),
.height(barHeight),
backgroundColor = barColor,
color = color
)

View file

@ -1,27 +1,51 @@
package com.habitrpg.android.habitica.ui.views
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.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.requiredSize
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.habitrpg.shared.habitica.models.Avatar
@Composable
fun UserRow(
username: String,
avatar: Avatar?,
modifier: Modifier = Modifier,
extraContent: @Composable (() -> Unit)? = null,
endContent: @Composable (() -> Unit)? = null,
color: Color? = null
) {
Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.SpaceBetween, modifier = modifier.fillMaxWidth()) {
Row(verticalAlignment = Alignment.CenterVertically, modifier = modifier.fillMaxWidth()) {
Box(modifier = Modifier
.padding(end = 12.dp)
.clip(CircleShape)
.size(40.dp)
.padding(end = 12.dp, top = if (avatar?.currentMount?.isNotBlank() == true) 24.dp else 12.dp)) {
if (avatar != null) {
ComposableAvatarView(
avatar = avatar,
Modifier
.size(96.dp)
.requiredSize(96.dp)
)
}
}
Column {
Text(
"@$username",
@ -33,6 +57,7 @@ fun UserRow(
extraContent()
}
}
Spacer(Modifier.weight(1f))
if (endContent != null) {
endContent()
}

View file

@ -16,7 +16,6 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.material.TextButton
@ -122,7 +121,7 @@ fun StatsViewPreview() {
levelValue = 10,
equipmentValue = 5,
buffValue = 4,
allocatedValue = 8,
allocatedValue = 20,
canAllocate = true
) {}
}

View file

@ -94,6 +94,7 @@ fun AssignSheet(
}
UserRow(
username = member.displayName,
avatar = member,
color = colorResource(R.color.text_primary),
extraContent = {
Text(

View file

@ -46,7 +46,9 @@ fun AssignedView(
.fillMaxWidth()
for (assignable in assigned) {
UserRow(
username = assignable.identifiableName, modifier = rowModifier,
username = assignable.identifiableName,
avatar = assignable.avatar,
modifier = rowModifier,
color = color,
extraContent = {
completedAt[assignable.id]?.let { CompletedAt(completedAt = it) }

View file

@ -1,2 +1,2 @@
NAME=4.1
CODE=4781
CODE=4791