Showing the list option in all Follow Buttons

This commit is contained in:
Vitor Pamplona
2025-11-05 19:03:01 -05:00
parent c2c3442b74
commit 178582f3c4
4 changed files with 91 additions and 80 deletions

View File

@@ -25,16 +25,27 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.model.User
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.observeAccountIsHiddenUser
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserIsFollowing
import com.vitorpamplona.amethyst.ui.navigation.navs.EmptyNav.nav
import com.vitorpamplona.amethyst.ui.navigation.navs.INav import com.vitorpamplona.amethyst.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.ui.navigation.routes.Route
import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.FollowButton
import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.ListButton
import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.UnfollowButton
import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.zaps.ShowUserButton
import com.vitorpamplona.amethyst.ui.theme.Size55dp import com.vitorpamplona.amethyst.ui.theme.Size55dp
import com.vitorpamplona.amethyst.ui.theme.StdPadding import com.vitorpamplona.amethyst.ui.theme.StdPadding
import com.vitorpamplona.amethyst.ui.theme.StdStartPadding
@Composable @Composable
fun UserCompose( fun UserCompose(
@@ -49,7 +60,7 @@ fun UserCompose(
) { ) {
UserPicture(baseUser, Size55dp, accountViewModel = accountViewModel, nav = nav) UserPicture(baseUser, Size55dp, accountViewModel = accountViewModel, nav = nav)
Column(modifier = remember { Modifier.padding(start = 10.dp).weight(1f) }) { Column(modifier = remember { StdStartPadding.weight(1f) }) {
Row(verticalAlignment = Alignment.CenterVertically) { Row(verticalAlignment = Alignment.CenterVertically) {
UsernameDisplay(baseUser, accountViewModel = accountViewModel) UsernameDisplay(baseUser, accountViewModel = accountViewModel)
} }
@@ -57,8 +68,55 @@ fun UserCompose(
AboutDisplay(baseUser, accountViewModel) AboutDisplay(baseUser, accountViewModel)
} }
Column(modifier = remember { Modifier.padding(start = 10.dp) }) { Row(modifier = StdStartPadding) {
UserActionOptions(baseUser, accountViewModel) UserActionOptions(baseUser, accountViewModel, nav)
}
}
}
@Composable
fun UserActionOptions(
baseAuthor: User,
accountViewModel: AccountViewModel,
nav: INav,
) {
val isHidden by observeAccountIsHiddenUser(accountViewModel.account, baseAuthor)
if (isHidden) {
ShowUserButton { accountViewModel.show(baseAuthor) }
} else {
ShowFollowingOrUnfollowingButton(baseAuthor, accountViewModel)
ListButton { nav.nav(Route.PeopleListManagement(baseAuthor.pubkeyHex)) }
}
}
@Composable
fun ShowFollowingOrUnfollowingButton(
baseAuthor: User,
accountViewModel: AccountViewModel,
) {
val isFollowing = observeUserIsFollowing(accountViewModel.account.userProfile(), baseAuthor, accountViewModel)
if (isFollowing.value) {
UnfollowButton(true) {
if (!accountViewModel.isWriteable()) {
accountViewModel.toastManager.toast(
R.string.read_only_user,
R.string.login_with_a_private_key_to_be_able_to_unfollow,
)
} else {
accountViewModel.unfollow(baseAuthor)
}
}
} else {
FollowButton(R.string.follow, true) {
if (!accountViewModel.isWriteable()) {
accountViewModel.toastManager.toast(
R.string.read_only_user,
R.string.login_with_a_private_key_to_be_able_to_follow,
)
} else {
accountViewModel.follow(baseAuthor)
}
} }
} }
} }

View File

@@ -39,22 +39,17 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.model.User
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.observeAccountIsHiddenUser
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNote import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNote
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserAboutMe import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserAboutMe
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserIsFollowing
import com.vitorpamplona.amethyst.ui.navigation.navs.INav import com.vitorpamplona.amethyst.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.FollowButton
import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.UnfollowButton
import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.zaps.ShowUserButton
import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.zaps.ZapReqResponse import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.zaps.ZapReqResponse
import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange
import com.vitorpamplona.amethyst.ui.theme.Size55dp import com.vitorpamplona.amethyst.ui.theme.Size55dp
import com.vitorpamplona.amethyst.ui.theme.StdStartPadding
import com.vitorpamplona.amethyst.ui.theme.placeholderText import com.vitorpamplona.amethyst.ui.theme.placeholderText
import com.vitorpamplona.quartz.nip57Zaps.LnZapEvent import com.vitorpamplona.quartz.nip57Zaps.LnZapEvent
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@@ -112,21 +107,21 @@ private fun RenderZapNote(
UserPicture(baseAuthor, Size55dp, accountViewModel = accountViewModel, nav = nav) UserPicture(baseAuthor, Size55dp, accountViewModel = accountViewModel, nav = nav)
Column( Column(
modifier = remember { Modifier.padding(start = 10.dp).weight(1f) }, modifier = remember { StdStartPadding.weight(1f) },
) { ) {
Row(verticalAlignment = Alignment.CenterVertically) { UsernameDisplay(baseAuthor, accountViewModel = accountViewModel) } Row(verticalAlignment = Alignment.CenterVertically) { UsernameDisplay(baseAuthor, accountViewModel = accountViewModel) }
Row(verticalAlignment = Alignment.CenterVertically) { AboutDisplay(baseAuthor, accountViewModel) } Row(verticalAlignment = Alignment.CenterVertically) { AboutDisplay(baseAuthor, accountViewModel) }
} }
Column( Column(
modifier = remember { Modifier.padding(start = 10.dp) }, modifier = StdStartPadding,
verticalArrangement = Arrangement.Center, verticalArrangement = Arrangement.Center,
) { ) {
ZapAmount(zapNote, accountViewModel) ZapAmount(zapNote, accountViewModel)
} }
Column(modifier = Modifier.padding(start = 10.dp)) { Row(modifier = StdStartPadding) {
UserActionOptions(baseAuthor, accountViewModel) UserActionOptions(baseAuthor, accountViewModel, nav)
} }
} }
} }
@@ -159,51 +154,6 @@ private fun ZapAmount(
} }
} }
@Composable
fun UserActionOptions(
baseAuthor: User,
accountViewModel: AccountViewModel,
) {
val isHidden by observeAccountIsHiddenUser(accountViewModel.account, baseAuthor)
if (isHidden) {
ShowUserButton { accountViewModel.show(baseAuthor) }
} else {
ShowFollowingOrUnfollowingButton(baseAuthor, accountViewModel)
}
}
@Composable
fun ShowFollowingOrUnfollowingButton(
baseAuthor: User,
accountViewModel: AccountViewModel,
) {
val isFollowing = observeUserIsFollowing(accountViewModel.account.userProfile(), baseAuthor, accountViewModel)
if (isFollowing.value) {
UnfollowButton {
if (!accountViewModel.isWriteable()) {
accountViewModel.toastManager.toast(
R.string.read_only_user,
R.string.login_with_a_private_key_to_be_able_to_unfollow,
)
} else {
accountViewModel.unfollow(baseAuthor)
}
}
} else {
FollowButton {
if (!accountViewModel.isWriteable()) {
accountViewModel.toastManager.toast(
R.string.read_only_user,
R.string.login_with_a_private_key_to_be_able_to_follow,
)
} else {
accountViewModel.follow(baseAuthor)
}
}
}
}
@Composable @Composable
fun AboutDisplay( fun AboutDisplay(
baseAuthor: User, baseAuthor: User,

View File

@@ -21,8 +21,14 @@
package com.vitorpamplona.amethyst.ui.screen.loggedIn.profile package com.vitorpamplona.amethyst.ui.screen.loggedIn.profile
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.CornerSize
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.List
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.FilledTonalButton import androidx.compose.material3.FilledTonalButton
import androidx.compose.material3.Icon
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
@@ -32,6 +38,7 @@ import com.vitorpamplona.amethyst.ui.stringRes
import com.vitorpamplona.amethyst.ui.theme.ButtonBorder import com.vitorpamplona.amethyst.ui.theme.ButtonBorder
import com.vitorpamplona.amethyst.ui.theme.ButtonPadding import com.vitorpamplona.amethyst.ui.theme.ButtonPadding
import com.vitorpamplona.amethyst.ui.theme.LeftHalfCircleButtonBorder import com.vitorpamplona.amethyst.ui.theme.LeftHalfCircleButtonBorder
import com.vitorpamplona.amethyst.ui.theme.ZeroPadding
@Composable @Composable
fun FollowButton( fun FollowButton(
@@ -64,3 +71,18 @@ fun UnfollowButton(
Text(text = stringRes(R.string.unfollow)) Text(text = stringRes(R.string.unfollow))
} }
} }
@Composable
fun ListButton(onClick: () -> Unit) {
TextButton(
onClick = onClick,
shape = ButtonBorder.copy(topStart = CornerSize(0f), bottomStart = CornerSize(0f)),
colors = ButtonDefaults.filledTonalButtonColors(),
contentPadding = ZeroPadding,
) {
Icon(
imageVector = Icons.AutoMirrored.Filled.List,
contentDescription = stringRes(R.string.follow_set_profile_actions_menu_description),
)
}
}

View File

@@ -20,26 +20,17 @@
*/ */
package com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.header package com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.header
import androidx.compose.foundation.shape.CornerSize
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.List
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.model.User
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.observeAccountIsHiddenUser import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.observeAccountIsHiddenUser
import com.vitorpamplona.amethyst.ui.navigation.navs.INav import com.vitorpamplona.amethyst.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.ui.navigation.routes.Route import com.vitorpamplona.amethyst.ui.navigation.routes.Route
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.ListButton
import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.zaps.ShowUserButton import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.zaps.ShowUserButton
import com.vitorpamplona.amethyst.ui.stringRes
import com.vitorpamplona.amethyst.ui.theme.ButtonBorder
import com.vitorpamplona.amethyst.ui.theme.ZeroPadding
@Composable @Composable
fun ProfileActions( fun ProfileActions(
@@ -63,16 +54,6 @@ fun ProfileActions(
} else { } else {
DisplayFollowUnfollowButton(baseUser, accountViewModel) DisplayFollowUnfollowButton(baseUser, accountViewModel)
TextButton( ListButton { nav.nav(Route.PeopleListManagement(baseUser.pubkeyHex)) }
onClick = { nav.nav(Route.PeopleListManagement(baseUser.pubkeyHex)) },
shape = ButtonBorder.copy(topStart = CornerSize(0f), bottomStart = CornerSize(0f)),
colors = ButtonDefaults.filledTonalButtonColors(),
contentPadding = ZeroPadding,
) {
Icon(
imageVector = Icons.AutoMirrored.Filled.List,
contentDescription = stringRes(R.string.follow_set_profile_actions_menu_description),
)
}
} }
} }