Removes old image proxy classes
This commit is contained in:
@@ -1,83 +0,0 @@
|
|||||||
package com.vitorpamplona.amethyst.ui.components
|
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.runtime.Immutable
|
|
||||||
import androidx.compose.ui.Alignment
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.graphics.ColorFilter
|
|
||||||
import androidx.compose.ui.graphics.DefaultAlpha
|
|
||||||
import androidx.compose.ui.graphics.FilterQuality
|
|
||||||
import androidx.compose.ui.graphics.drawscope.DrawScope
|
|
||||||
import androidx.compose.ui.graphics.painter.Painter
|
|
||||||
import androidx.compose.ui.layout.ContentScale
|
|
||||||
import androidx.compose.ui.unit.Dp
|
|
||||||
import coil.compose.AsyncImage
|
|
||||||
import coil.compose.AsyncImagePainter
|
|
||||||
import java.util.Base64
|
|
||||||
|
|
||||||
@Immutable
|
|
||||||
data class ResizeImage(val url: String?, val size: Dp) {
|
|
||||||
fun proxyUrl(): String? {
|
|
||||||
if (url == null) return null
|
|
||||||
|
|
||||||
// Fixes Image size to reduce pings to servers for each size used in the app
|
|
||||||
val imgPx = 200 // with(LocalDensity.current) { model.size.toPx().toInt() }
|
|
||||||
val base64 = Base64.getUrlEncoder().encodeToString(url.toByteArray())
|
|
||||||
|
|
||||||
return url // "https://d12fidohs5rlxk.cloudfront.net/preset:sharp/rs:fit:$imgPx:$imgPx:0/gravity:sm/$base64"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun AsyncImageProxy(
|
|
||||||
model: ResizeImage,
|
|
||||||
contentDescription: String?,
|
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
placeholder: Painter? = null,
|
|
||||||
error: Painter? = null,
|
|
||||||
fallback: Painter? = error,
|
|
||||||
onLoading: ((AsyncImagePainter.State.Loading) -> Unit)? = null,
|
|
||||||
onSuccess: ((AsyncImagePainter.State.Success) -> Unit)? = null,
|
|
||||||
onError: ((AsyncImagePainter.State.Error) -> Unit)? = null,
|
|
||||||
alignment: Alignment = Alignment.Center,
|
|
||||||
contentScale: ContentScale = ContentScale.Fit,
|
|
||||||
alpha: Float = DefaultAlpha,
|
|
||||||
colorFilter: ColorFilter? = null,
|
|
||||||
filterQuality: FilterQuality = DrawScope.DefaultFilterQuality
|
|
||||||
) {
|
|
||||||
if (model.url == null) {
|
|
||||||
AsyncImage(
|
|
||||||
model = model.url,
|
|
||||||
contentDescription = contentDescription,
|
|
||||||
modifier = modifier,
|
|
||||||
placeholder = placeholder,
|
|
||||||
error = error,
|
|
||||||
fallback = fallback,
|
|
||||||
onLoading = onLoading,
|
|
||||||
onSuccess = onSuccess,
|
|
||||||
onError = onError,
|
|
||||||
alignment = alignment,
|
|
||||||
contentScale = contentScale,
|
|
||||||
alpha = alpha,
|
|
||||||
colorFilter = colorFilter,
|
|
||||||
filterQuality = filterQuality
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
AsyncImage(
|
|
||||||
model = model.proxyUrl(),
|
|
||||||
contentDescription = contentDescription,
|
|
||||||
modifier = modifier,
|
|
||||||
placeholder = placeholder,
|
|
||||||
error = error,
|
|
||||||
fallback = fallback,
|
|
||||||
onLoading = onLoading,
|
|
||||||
onSuccess = onSuccess,
|
|
||||||
onError = onError,
|
|
||||||
alignment = alignment,
|
|
||||||
contentScale = contentScale,
|
|
||||||
alpha = alpha,
|
|
||||||
colorFilter = colorFilter,
|
|
||||||
filterQuality = filterQuality
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -10,7 +10,6 @@ import androidx.compose.ui.graphics.FilterQuality
|
|||||||
import androidx.compose.ui.graphics.drawscope.DrawScope
|
import androidx.compose.ui.graphics.drawscope.DrawScope
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.unit.Dp
|
|
||||||
import coil.compose.AsyncImage
|
import coil.compose.AsyncImage
|
||||||
import coil.compose.AsyncImagePainter
|
import coil.compose.AsyncImagePainter
|
||||||
import coil.compose.rememberAsyncImagePainter
|
import coil.compose.rememberAsyncImagePainter
|
||||||
@@ -19,7 +18,6 @@ import java.util.Date
|
|||||||
@Composable
|
@Composable
|
||||||
fun RobohashAsyncImage(
|
fun RobohashAsyncImage(
|
||||||
robot: String,
|
robot: String,
|
||||||
robotSize: Dp,
|
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
contentDescription: String? = null,
|
contentDescription: String? = null,
|
||||||
transform: (AsyncImagePainter.State) -> AsyncImagePainter.State = AsyncImagePainter.DefaultTransform,
|
transform: (AsyncImagePainter.State) -> AsyncImagePainter.State = AsyncImagePainter.DefaultTransform,
|
||||||
@@ -55,7 +53,6 @@ var imageErrors = mapOf<String, Long>()
|
|||||||
@Composable
|
@Composable
|
||||||
fun RobohashFallbackAsyncImage(
|
fun RobohashFallbackAsyncImage(
|
||||||
robot: String,
|
robot: String,
|
||||||
robotSize: Dp,
|
|
||||||
model: String,
|
model: String,
|
||||||
contentDescription: String?,
|
contentDescription: String?,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
@@ -70,7 +67,6 @@ fun RobohashFallbackAsyncImage(
|
|||||||
if (errorCache != null && (Date().time / 1000) - errorCache < (60 * 5)) {
|
if (errorCache != null && (Date().time / 1000) - errorCache < (60 * 5)) {
|
||||||
RobohashAsyncImage(
|
RobohashAsyncImage(
|
||||||
robot = robot,
|
robot = robot,
|
||||||
robotSize = robotSize,
|
|
||||||
contentDescription = contentDescription,
|
contentDescription = contentDescription,
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
alignment = alignment,
|
alignment = alignment,
|
||||||
@@ -107,7 +103,7 @@ fun RobohashFallbackAsyncImage(
|
|||||||
@Composable
|
@Composable
|
||||||
fun RobohashAsyncImageProxy(
|
fun RobohashAsyncImageProxy(
|
||||||
robot: String,
|
robot: String,
|
||||||
model: ResizeImage,
|
model: String?,
|
||||||
contentDescription: String?,
|
contentDescription: String?,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
alignment: Alignment = Alignment.Center,
|
alignment: Alignment = Alignment.Center,
|
||||||
@@ -116,12 +112,9 @@ fun RobohashAsyncImageProxy(
|
|||||||
colorFilter: ColorFilter? = null,
|
colorFilter: ColorFilter? = null,
|
||||||
filterQuality: FilterQuality = DrawScope.DefaultFilterQuality
|
filterQuality: FilterQuality = DrawScope.DefaultFilterQuality
|
||||||
) {
|
) {
|
||||||
val proxy = remember(model) { model.proxyUrl() }
|
if (model == null) {
|
||||||
|
|
||||||
if (proxy == null) {
|
|
||||||
RobohashAsyncImage(
|
RobohashAsyncImage(
|
||||||
robot = robot,
|
robot = robot,
|
||||||
robotSize = model.size,
|
|
||||||
contentDescription = contentDescription,
|
contentDescription = contentDescription,
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
alignment = alignment,
|
alignment = alignment,
|
||||||
@@ -133,8 +126,7 @@ fun RobohashAsyncImageProxy(
|
|||||||
} else {
|
} else {
|
||||||
RobohashFallbackAsyncImage(
|
RobohashFallbackAsyncImage(
|
||||||
robot = robot,
|
robot = robot,
|
||||||
robotSize = model.size,
|
model = model,
|
||||||
model = proxy,
|
|
||||||
contentDescription = contentDescription,
|
contentDescription = contentDescription,
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
alignment = alignment,
|
alignment = alignment,
|
||||||
|
|||||||
+1
-2
@@ -52,7 +52,6 @@ import com.vitorpamplona.amethyst.model.decodePublicKey
|
|||||||
import com.vitorpamplona.amethyst.model.toHexKey
|
import com.vitorpamplona.amethyst.model.toHexKey
|
||||||
import com.vitorpamplona.amethyst.ui.actions.toImmutableListOfLists
|
import com.vitorpamplona.amethyst.ui.actions.toImmutableListOfLists
|
||||||
import com.vitorpamplona.amethyst.ui.components.CreateTextWithEmoji
|
import com.vitorpamplona.amethyst.ui.components.CreateTextWithEmoji
|
||||||
import com.vitorpamplona.amethyst.ui.components.ResizeImage
|
|
||||||
import com.vitorpamplona.amethyst.ui.components.RobohashAsyncImageProxy
|
import com.vitorpamplona.amethyst.ui.components.RobohashAsyncImageProxy
|
||||||
import com.vitorpamplona.amethyst.ui.note.toShortenHex
|
import com.vitorpamplona.amethyst.ui.note.toShortenHex
|
||||||
import com.vitorpamplona.amethyst.ui.screen.AccountStateViewModel
|
import com.vitorpamplona.amethyst.ui.screen.AccountStateViewModel
|
||||||
@@ -200,7 +199,7 @@ private fun AccountPicture(user: User) {
|
|||||||
val userState by user.live().metadata.observeAsState()
|
val userState by user.live().metadata.observeAsState()
|
||||||
val profilePicture by remember(userState) {
|
val profilePicture by remember(userState) {
|
||||||
derivedStateOf {
|
derivedStateOf {
|
||||||
ResizeImage(userState?.user?.profilePicture(), 55.dp)
|
userState?.user?.profilePicture()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -74,7 +74,6 @@ import com.vitorpamplona.amethyst.service.model.PeopleListEvent
|
|||||||
import com.vitorpamplona.amethyst.service.relays.Client
|
import com.vitorpamplona.amethyst.service.relays.Client
|
||||||
import com.vitorpamplona.amethyst.service.relays.RelayPool
|
import com.vitorpamplona.amethyst.service.relays.RelayPool
|
||||||
import com.vitorpamplona.amethyst.ui.actions.NewRelayListView
|
import com.vitorpamplona.amethyst.ui.actions.NewRelayListView
|
||||||
import com.vitorpamplona.amethyst.ui.components.ResizeImage
|
|
||||||
import com.vitorpamplona.amethyst.ui.components.RobohashAsyncImageProxy
|
import com.vitorpamplona.amethyst.ui.components.RobohashAsyncImageProxy
|
||||||
import com.vitorpamplona.amethyst.ui.screen.RelayPoolViewModel
|
import com.vitorpamplona.amethyst.ui.screen.RelayPoolViewModel
|
||||||
import com.vitorpamplona.amethyst.ui.screen.equalImmutableLists
|
import com.vitorpamplona.amethyst.ui.screen.equalImmutableLists
|
||||||
@@ -342,7 +341,7 @@ private fun LoggedInUserPictureDrawer(
|
|||||||
val accountUserState by accountViewModel.account.userProfile().live().metadata.observeAsState()
|
val accountUserState by accountViewModel.account.userProfile().live().metadata.observeAsState()
|
||||||
|
|
||||||
val pubkeyHex = remember { accountUserState?.user?.pubkeyHex ?: "" }
|
val pubkeyHex = remember { accountUserState?.user?.pubkeyHex ?: "" }
|
||||||
val profilePicture = remember(accountUserState) { ResizeImage(accountUserState?.user?.profilePicture(), 34.dp) }
|
val profilePicture = remember(accountUserState) { accountUserState?.user?.profilePicture() }
|
||||||
|
|
||||||
IconButton(
|
IconButton(
|
||||||
onClick = onClick,
|
onClick = onClick,
|
||||||
|
|||||||
@@ -62,7 +62,6 @@ import com.vitorpamplona.amethyst.model.User
|
|||||||
import com.vitorpamplona.amethyst.service.HttpClient
|
import com.vitorpamplona.amethyst.service.HttpClient
|
||||||
import com.vitorpamplona.amethyst.ui.actions.toImmutableListOfLists
|
import com.vitorpamplona.amethyst.ui.actions.toImmutableListOfLists
|
||||||
import com.vitorpamplona.amethyst.ui.components.CreateTextWithEmoji
|
import com.vitorpamplona.amethyst.ui.components.CreateTextWithEmoji
|
||||||
import com.vitorpamplona.amethyst.ui.components.ResizeImage
|
|
||||||
import com.vitorpamplona.amethyst.ui.components.RobohashAsyncImageProxy
|
import com.vitorpamplona.amethyst.ui.components.RobohashAsyncImageProxy
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountBackupDialog
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountBackupDialog
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||||
@@ -127,7 +126,7 @@ fun ProfileContent(
|
|||||||
val profilePubHex = remember(accountUserState) { accountUserState?.user?.pubkeyHex } ?: return
|
val profilePubHex = remember(accountUserState) { accountUserState?.user?.pubkeyHex } ?: return
|
||||||
|
|
||||||
val profileBanner = remember(accountUserState) { accountUserState?.user?.info?.banner?.ifBlank { null } }
|
val profileBanner = remember(accountUserState) { accountUserState?.user?.info?.banner?.ifBlank { null } }
|
||||||
val profilePicture = remember(accountUserState) { accountUserState?.user?.profilePicture()?.ifBlank { null }?.let { ResizeImage(it, 100.dp) } }
|
val profilePicture = remember(accountUserState) { accountUserState?.user?.profilePicture() }
|
||||||
val bestUserName = remember(accountUserState) { accountUserState?.user?.bestUsername() }
|
val bestUserName = remember(accountUserState) { accountUserState?.user?.bestUsername() }
|
||||||
val bestDisplayName = remember(accountUserState) { accountUserState?.user?.bestDisplayName() }
|
val bestDisplayName = remember(accountUserState) { accountUserState?.user?.bestDisplayName() }
|
||||||
val tags = remember(accountUserState) { accountUserState?.user?.info?.latestMetadata?.tags?.toImmutableListOfLists() }
|
val tags = remember(accountUserState) { accountUserState?.user?.info?.latestMetadata?.tags?.toImmutableListOfLists() }
|
||||||
|
|||||||
@@ -47,9 +47,10 @@ import com.vitorpamplona.amethyst.model.User
|
|||||||
import com.vitorpamplona.amethyst.service.model.ChannelCreateEvent
|
import com.vitorpamplona.amethyst.service.model.ChannelCreateEvent
|
||||||
import com.vitorpamplona.amethyst.service.model.ChannelMetadataEvent
|
import com.vitorpamplona.amethyst.service.model.ChannelMetadataEvent
|
||||||
import com.vitorpamplona.amethyst.service.model.PrivateDmEvent
|
import com.vitorpamplona.amethyst.service.model.PrivateDmEvent
|
||||||
import com.vitorpamplona.amethyst.ui.components.ResizeImage
|
|
||||||
import com.vitorpamplona.amethyst.ui.components.RobohashAsyncImageProxy
|
import com.vitorpamplona.amethyst.ui.components.RobohashAsyncImageProxy
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.Size55dp
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.grayText
|
||||||
import com.vitorpamplona.amethyst.ui.theme.placeholderText
|
import com.vitorpamplona.amethyst.ui.theme.placeholderText
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@@ -68,20 +69,23 @@ fun ChatroomCompose(
|
|||||||
noteState?.note?.channelHex()
|
noteState?.note?.channelHex()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
val isBlank = remember(noteState) {
|
||||||
|
note?.event == null
|
||||||
|
}
|
||||||
|
|
||||||
if (note?.event == null) {
|
if (isBlank) {
|
||||||
BlankNote(Modifier)
|
BlankNote(Modifier)
|
||||||
} else if (channelHex != null) {
|
} else if (channelHex != null) {
|
||||||
LoadChannel(baseChannelHex = channelHex!!) { channel ->
|
LoadChannel(baseChannelHex = channelHex!!) { channel ->
|
||||||
ChannelRoomCompose(note, channel, accountViewModel, nav)
|
ChannelRoomCompose(baseNote, channel, accountViewModel, nav)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val userRoomHex = remember(noteState, accountViewModel) {
|
val userRoomHex = remember(noteState, accountViewModel) {
|
||||||
(note.event as? PrivateDmEvent)?.talkingWith(accountViewModel.userProfile().pubkeyHex)
|
(baseNote.event as? PrivateDmEvent)?.talkingWith(accountViewModel.userProfile().pubkeyHex)
|
||||||
} ?: return
|
} ?: return
|
||||||
|
|
||||||
LoadUser(userRoomHex) { user ->
|
LoadUser(userRoomHex) { user ->
|
||||||
UserRoomCompose(note, user, accountViewModel, nav)
|
UserRoomCompose(baseNote, user, accountViewModel, nav)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -138,8 +142,21 @@ private fun ChannelRoomCompose(
|
|||||||
channelIdHex = chanHex,
|
channelIdHex = chanHex,
|
||||||
channelPicture = channelPicture,
|
channelPicture = channelPicture,
|
||||||
channelTitle = { modifier ->
|
channelTitle = { modifier ->
|
||||||
Text(
|
ChannelTitleWithBoostInfo(channelName, modifier)
|
||||||
text = buildAnnotatedString {
|
},
|
||||||
|
channelLastTime = remember(note) { note.createdAt() },
|
||||||
|
channelLastContent = remember(note) { "$authorName: $description" },
|
||||||
|
hasNewMessages = hasNewMessages,
|
||||||
|
onClick = { nav(route) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ChannelTitleWithBoostInfo(channelName: String, modifier: Modifier) {
|
||||||
|
val boosted = stringResource(id = R.string.public_chat)
|
||||||
|
val placeHolderColor = MaterialTheme.colors.placeholderText
|
||||||
|
val channelNameAndBoostInfo = remember {
|
||||||
|
buildAnnotatedString {
|
||||||
withStyle(
|
withStyle(
|
||||||
SpanStyle(
|
SpanStyle(
|
||||||
fontWeight = FontWeight.Bold
|
fontWeight = FontWeight.Bold
|
||||||
@@ -150,23 +167,21 @@ private fun ChannelRoomCompose(
|
|||||||
|
|
||||||
withStyle(
|
withStyle(
|
||||||
SpanStyle(
|
SpanStyle(
|
||||||
color = MaterialTheme.colors.placeholderText,
|
color = placeHolderColor,
|
||||||
fontWeight = FontWeight.Normal
|
fontWeight = FontWeight.Normal
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
append(" ${stringResource(id = R.string.public_chat)}")
|
append(" $boosted")
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = channelNameAndBoostInfo,
|
||||||
fontWeight = FontWeight.Bold,
|
fontWeight = FontWeight.Bold,
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
style = LocalTextStyle.current.copy(textDirection = TextDirection.Content)
|
style = LocalTextStyle.current.copy(textDirection = TextDirection.Content)
|
||||||
)
|
)
|
||||||
},
|
|
||||||
channelLastTime = remember(note) { note.createdAt() },
|
|
||||||
channelLastContent = remember(note) { "$authorName: $description" },
|
|
||||||
hasNewMessages = hasNewMessages,
|
|
||||||
onClick = { nav(route) }
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -191,9 +206,9 @@ private fun UserRoomCompose(
|
|||||||
ChannelName(
|
ChannelName(
|
||||||
channelPicture = {
|
channelPicture = {
|
||||||
UserPicture(
|
UserPicture(
|
||||||
user,
|
baseUser = user,
|
||||||
accountViewModel = accountViewModel,
|
accountViewModel = accountViewModel,
|
||||||
size = 55.dp
|
size = Size55dp
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
channelTitle = { UsernameDisplay(user, it) },
|
channelTitle = { UsernameDisplay(user, it) },
|
||||||
@@ -256,12 +271,14 @@ fun ChannelName(
|
|||||||
channelPicture = {
|
channelPicture = {
|
||||||
RobohashAsyncImageProxy(
|
RobohashAsyncImageProxy(
|
||||||
robot = channelIdHex,
|
robot = channelIdHex,
|
||||||
model = ResizeImage(channelPicture, 55.dp),
|
model = channelPicture,
|
||||||
contentDescription = stringResource(R.string.channel_image),
|
contentDescription = stringResource(R.string.channel_image),
|
||||||
modifier = Modifier
|
modifier = remember {
|
||||||
.width(55.dp)
|
Modifier
|
||||||
.height(55.dp)
|
.width(Size55dp)
|
||||||
|
.height(Size55dp)
|
||||||
.clip(shape = CircleShape)
|
.clip(shape = CircleShape)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
channelTitle,
|
channelTitle,
|
||||||
@@ -281,31 +298,30 @@ fun ChannelName(
|
|||||||
hasNewMessages: Boolean,
|
hasNewMessages: Boolean,
|
||||||
onClick: () -> Unit
|
onClick: () -> Unit
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
Column(modifier = remember { Modifier.clickable(onClick = onClick) }) {
|
||||||
Column(modifier = Modifier.clickable(onClick = onClick)) {
|
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.padding(start = 12.dp, end = 12.dp, top = 10.dp)
|
modifier = remember { Modifier.padding(start = 12.dp, end = 12.dp, top = 10.dp) }
|
||||||
) {
|
) {
|
||||||
channelPicture()
|
channelPicture()
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.padding(start = 10.dp),
|
modifier = remember { Modifier.padding(start = 10.dp) },
|
||||||
verticalArrangement = Arrangement.SpaceAround
|
verticalArrangement = Arrangement.SpaceAround
|
||||||
) {
|
) {
|
||||||
Row(
|
FirstRow(channelTitle, channelLastTime)
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
SecondRow(channelLastContent, hasNewMessages)
|
||||||
modifier = Modifier.padding(bottom = 4.dp)
|
}
|
||||||
) {
|
}
|
||||||
channelTitle(Modifier.weight(1f))
|
|
||||||
|
|
||||||
channelLastTime?.let {
|
Divider(
|
||||||
Text(
|
modifier = remember { Modifier.padding(top = 10.dp) },
|
||||||
timeAgo(channelLastTime, context),
|
thickness = 0.25.dp
|
||||||
color = MaterialTheme.colors.onSurface.copy(alpha = 0.52f)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun SecondRow(channelLastContent: String?, hasNewMessages: Boolean) {
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
@@ -313,7 +329,7 @@ fun ChannelName(
|
|||||||
if (channelLastContent != null) {
|
if (channelLastContent != null) {
|
||||||
Text(
|
Text(
|
||||||
channelLastContent,
|
channelLastContent,
|
||||||
color = MaterialTheme.colors.onSurface.copy(alpha = 0.52f),
|
color = MaterialTheme.colors.grayText,
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
style = LocalTextStyle.current.copy(textDirection = TextDirection.Content),
|
style = LocalTextStyle.current.copy(textDirection = TextDirection.Content),
|
||||||
@@ -322,7 +338,7 @@ fun ChannelName(
|
|||||||
} else {
|
} else {
|
||||||
Text(
|
Text(
|
||||||
stringResource(R.string.referenced_event_not_found),
|
stringResource(R.string.referenced_event_not_found),
|
||||||
color = MaterialTheme.colors.onSurface.copy(alpha = 0.52f),
|
color = MaterialTheme.colors.grayText,
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
modifier = Modifier.weight(1f)
|
modifier = Modifier.weight(1f)
|
||||||
@@ -334,12 +350,30 @@ fun ChannelName(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Divider(
|
@Composable
|
||||||
modifier = Modifier.padding(top = 10.dp),
|
private fun FirstRow(
|
||||||
thickness = 0.25.dp
|
channelTitle: @Composable (Modifier) -> Unit,
|
||||||
|
channelLastTime: Long?
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
modifier = remember { Modifier.padding(bottom = 4.dp) }
|
||||||
|
) {
|
||||||
|
channelTitle(
|
||||||
|
remember {
|
||||||
|
Modifier.weight(1f)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
channelLastTime?.let {
|
||||||
|
val context = LocalContext.current
|
||||||
|
val timeAgo = remember(channelLastTime) { timeAgo(channelLastTime, context) }
|
||||||
|
Text(
|
||||||
|
timeAgo,
|
||||||
|
color = MaterialTheme.colors.grayText
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -60,7 +60,6 @@ import com.vitorpamplona.amethyst.ui.actions.ImmutableListOfLists
|
|||||||
import com.vitorpamplona.amethyst.ui.actions.toImmutableListOfLists
|
import com.vitorpamplona.amethyst.ui.actions.toImmutableListOfLists
|
||||||
import com.vitorpamplona.amethyst.ui.components.CreateClickableTextWithEmoji
|
import com.vitorpamplona.amethyst.ui.components.CreateClickableTextWithEmoji
|
||||||
import com.vitorpamplona.amethyst.ui.components.CreateTextWithEmoji
|
import com.vitorpamplona.amethyst.ui.components.CreateTextWithEmoji
|
||||||
import com.vitorpamplona.amethyst.ui.components.ResizeImage
|
|
||||||
import com.vitorpamplona.amethyst.ui.components.RobohashAsyncImageProxy
|
import com.vitorpamplona.amethyst.ui.components.RobohashAsyncImageProxy
|
||||||
import com.vitorpamplona.amethyst.ui.components.RobohashFallbackAsyncImage
|
import com.vitorpamplona.amethyst.ui.components.RobohashFallbackAsyncImage
|
||||||
import com.vitorpamplona.amethyst.ui.components.SensitivityWarning
|
import com.vitorpamplona.amethyst.ui.components.SensitivityWarning
|
||||||
@@ -70,7 +69,6 @@ import com.vitorpamplona.amethyst.ui.theme.ChatBubbleShapeMe
|
|||||||
import com.vitorpamplona.amethyst.ui.theme.ChatBubbleShapeThem
|
import com.vitorpamplona.amethyst.ui.theme.ChatBubbleShapeThem
|
||||||
import com.vitorpamplona.amethyst.ui.theme.DoubleHorzSpacer
|
import com.vitorpamplona.amethyst.ui.theme.DoubleHorzSpacer
|
||||||
import com.vitorpamplona.amethyst.ui.theme.RelayIconFilter
|
import com.vitorpamplona.amethyst.ui.theme.RelayIconFilter
|
||||||
import com.vitorpamplona.amethyst.ui.theme.Size13dp
|
|
||||||
import com.vitorpamplona.amethyst.ui.theme.Size15Modifier
|
import com.vitorpamplona.amethyst.ui.theme.Size15Modifier
|
||||||
import com.vitorpamplona.amethyst.ui.theme.Size16dp
|
import com.vitorpamplona.amethyst.ui.theme.Size16dp
|
||||||
import com.vitorpamplona.amethyst.ui.theme.Size25dp
|
import com.vitorpamplona.amethyst.ui.theme.Size25dp
|
||||||
@@ -730,7 +728,7 @@ private fun WatchAndDisplayUser(
|
|||||||
|
|
||||||
val userProfilePicture by remember(userState) {
|
val userProfilePicture by remember(userState) {
|
||||||
derivedStateOf {
|
derivedStateOf {
|
||||||
ResizeImage(userState?.user?.profilePicture(), Size25dp)
|
userState?.user?.profilePicture()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -750,7 +748,7 @@ private fun WatchAndDisplayUser(
|
|||||||
@Composable
|
@Composable
|
||||||
private fun UserIcon(
|
private fun UserIcon(
|
||||||
pubkeyHex: String,
|
pubkeyHex: String,
|
||||||
userProfilePicture: ResizeImage,
|
userProfilePicture: String?,
|
||||||
nav: (String) -> Unit,
|
nav: (String) -> Unit,
|
||||||
route: String
|
route: String
|
||||||
) {
|
) {
|
||||||
@@ -875,7 +873,6 @@ fun RenderRelay(dirtyUrl: String) {
|
|||||||
) {
|
) {
|
||||||
RobohashFallbackAsyncImage(
|
RobohashFallbackAsyncImage(
|
||||||
robot = iconUrl,
|
robot = iconUrl,
|
||||||
robotSize = Size13dp,
|
|
||||||
model = iconUrl,
|
model = iconUrl,
|
||||||
contentDescription = stringResource(id = R.string.relay_icon),
|
contentDescription = stringResource(id = R.string.relay_icon),
|
||||||
colorFilter = RelayIconFilter,
|
colorFilter = RelayIconFilter,
|
||||||
|
|||||||
@@ -122,7 +122,6 @@ import com.vitorpamplona.amethyst.ui.components.CreateClickableTextWithEmoji
|
|||||||
import com.vitorpamplona.amethyst.ui.components.CreateTextWithEmoji
|
import com.vitorpamplona.amethyst.ui.components.CreateTextWithEmoji
|
||||||
import com.vitorpamplona.amethyst.ui.components.LoadThumbAndThenVideoView
|
import com.vitorpamplona.amethyst.ui.components.LoadThumbAndThenVideoView
|
||||||
import com.vitorpamplona.amethyst.ui.components.ObserveDisplayNip05Status
|
import com.vitorpamplona.amethyst.ui.components.ObserveDisplayNip05Status
|
||||||
import com.vitorpamplona.amethyst.ui.components.ResizeImage
|
|
||||||
import com.vitorpamplona.amethyst.ui.components.RobohashAsyncImage
|
import com.vitorpamplona.amethyst.ui.components.RobohashAsyncImage
|
||||||
import com.vitorpamplona.amethyst.ui.components.RobohashAsyncImageProxy
|
import com.vitorpamplona.amethyst.ui.components.RobohashAsyncImageProxy
|
||||||
import com.vitorpamplona.amethyst.ui.components.SensitivityWarning
|
import com.vitorpamplona.amethyst.ui.components.SensitivityWarning
|
||||||
@@ -143,6 +142,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
|||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.ChannelHeader
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.ChannelHeader
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.ReportNoteDialog
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.ReportNoteDialog
|
||||||
import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange
|
import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.DoubleVertSpacer
|
||||||
import com.vitorpamplona.amethyst.ui.theme.Following
|
import com.vitorpamplona.amethyst.ui.theme.Following
|
||||||
import com.vitorpamplona.amethyst.ui.theme.QuoteBorder
|
import com.vitorpamplona.amethyst.ui.theme.QuoteBorder
|
||||||
import com.vitorpamplona.amethyst.ui.theme.Size35dp
|
import com.vitorpamplona.amethyst.ui.theme.Size35dp
|
||||||
@@ -1925,7 +1925,7 @@ private fun ChannelNotePicture(baseChannel: Channel) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val model = remember(channelState) {
|
val model = remember(channelState) {
|
||||||
ResizeImage(channel.profilePicture(), 30.dp)
|
channel.profilePicture()
|
||||||
}
|
}
|
||||||
|
|
||||||
Box(boxModifier) {
|
Box(boxModifier) {
|
||||||
@@ -2710,7 +2710,7 @@ private fun RelayBadges(baseNote: Note) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer(remember { Modifier.height(10.dp) })
|
Spacer(DoubleVertSpacer)
|
||||||
|
|
||||||
if (expanded) {
|
if (expanded) {
|
||||||
VerticalRelayPanelWithFlow(lazyRelayList)
|
VerticalRelayPanelWithFlow(lazyRelayList)
|
||||||
@@ -2819,7 +2819,6 @@ fun NoteAuthorPicture(
|
|||||||
|
|
||||||
RobohashAsyncImage(
|
RobohashAsyncImage(
|
||||||
robot = "authornotfound",
|
robot = "authornotfound",
|
||||||
robotSize = size,
|
|
||||||
contentDescription = stringResource(R.string.unknown_author),
|
contentDescription = stringResource(R.string.unknown_author),
|
||||||
modifier = nullModifier
|
modifier = nullModifier
|
||||||
)
|
)
|
||||||
@@ -2836,8 +2835,14 @@ fun UserPicture(
|
|||||||
size: Dp,
|
size: Dp,
|
||||||
pictureModifier: Modifier = Modifier
|
pictureModifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
|
val route by remember {
|
||||||
|
derivedStateOf {
|
||||||
|
"User/${user.pubkeyHex}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
UserPicture(user, size, accountViewModel, pictureModifier) {
|
UserPicture(user, size, accountViewModel, pictureModifier) {
|
||||||
nav("User/${it.pubkeyHex}")
|
nav(route)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2914,9 +2919,7 @@ fun UserPicture(
|
|||||||
Box(myBoxModifier, contentAlignment = TopEnd) {
|
Box(myBoxModifier, contentAlignment = TopEnd) {
|
||||||
RobohashAsyncImageProxy(
|
RobohashAsyncImageProxy(
|
||||||
robot = userHex,
|
robot = userHex,
|
||||||
model = remember(userPicture) {
|
model = userPicture,
|
||||||
ResizeImage(userPicture, size)
|
|
||||||
},
|
|
||||||
contentDescription = stringResource(id = R.string.profile_image),
|
contentDescription = stringResource(id = R.string.profile_image),
|
||||||
modifier = myImageModifier
|
modifier = myImageModifier
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import androidx.compose.material.Text
|
|||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.outlined.PlayCircle
|
import androidx.compose.material.icons.outlined.PlayCircle
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.derivedStateOf
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.livedata.observeAsState
|
import androidx.compose.runtime.livedata.observeAsState
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
@@ -42,10 +43,26 @@ fun NoteUsernameDisplay(baseNote: Note, weight: Modifier = Modifier) {
|
|||||||
@Composable
|
@Composable
|
||||||
fun UsernameDisplay(baseUser: User, weight: Modifier = Modifier) {
|
fun UsernameDisplay(baseUser: User, weight: Modifier = Modifier) {
|
||||||
val userState by baseUser.live().metadata.observeAsState()
|
val userState by baseUser.live().metadata.observeAsState()
|
||||||
val bestUserName = remember(userState) { userState?.user?.bestUsername() }
|
val bestUserName by remember(userState) {
|
||||||
val bestDisplayName = remember(userState) { userState?.user?.bestDisplayName() }
|
derivedStateOf {
|
||||||
val npubDisplay = remember { baseUser.pubkeyDisplayHex() }
|
userState?.user?.bestUsername()
|
||||||
val tags = remember(userState) { userState?.user?.info?.latestMetadata?.tags?.toImmutableListOfLists() }
|
}
|
||||||
|
}
|
||||||
|
val bestDisplayName by remember(userState) {
|
||||||
|
derivedStateOf {
|
||||||
|
userState?.user?.bestDisplayName()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val npubDisplay by remember {
|
||||||
|
derivedStateOf {
|
||||||
|
baseUser.pubkeyDisplayHex()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val tags by remember(userState) {
|
||||||
|
derivedStateOf {
|
||||||
|
userState?.user?.info?.latestMetadata?.tags?.toImmutableListOfLists()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
UserNameDisplay(bestUserName, bestDisplayName, npubDisplay, tags, weight)
|
UserNameDisplay(bestUserName, bestDisplayName, npubDisplay, tags, weight)
|
||||||
}
|
}
|
||||||
@@ -58,48 +75,19 @@ private fun UserNameDisplay(
|
|||||||
tags: ImmutableListOfLists<String>?,
|
tags: ImmutableListOfLists<String>?,
|
||||||
modifier: Modifier
|
modifier: Modifier
|
||||||
) {
|
) {
|
||||||
if (bestUserName != null && bestDisplayName != null) {
|
if (bestUserName != null && bestDisplayName != null && bestDisplayName != bestUserName) {
|
||||||
CreateTextWithEmoji(
|
UserAndUsernameDisplay(bestDisplayName, tags, bestUserName, modifier)
|
||||||
text = bestDisplayName,
|
|
||||||
tags = tags,
|
|
||||||
fontWeight = FontWeight.Bold,
|
|
||||||
maxLines = 1
|
|
||||||
)
|
|
||||||
if (bestDisplayName != bestUserName) {
|
|
||||||
CreateTextWithEmoji(
|
|
||||||
text = remember { "@$bestUserName" },
|
|
||||||
tags = tags,
|
|
||||||
color = MaterialTheme.colors.placeholderText,
|
|
||||||
maxLines = 1,
|
|
||||||
overflow = TextOverflow.Ellipsis,
|
|
||||||
modifier = modifier
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Spacer(StdHorzSpacer)
|
|
||||||
DrawPlayName(bestDisplayName)
|
|
||||||
} else if (bestDisplayName != null) {
|
} else if (bestDisplayName != null) {
|
||||||
CreateTextWithEmoji(
|
UserDisplay(bestDisplayName, tags, modifier)
|
||||||
text = bestDisplayName,
|
|
||||||
tags = tags,
|
|
||||||
fontWeight = FontWeight.Bold,
|
|
||||||
maxLines = 1,
|
|
||||||
overflow = TextOverflow.Ellipsis,
|
|
||||||
modifier = modifier
|
|
||||||
)
|
|
||||||
Spacer(StdHorzSpacer)
|
|
||||||
DrawPlayName(bestDisplayName)
|
|
||||||
} else if (bestUserName != null) {
|
} else if (bestUserName != null) {
|
||||||
CreateTextWithEmoji(
|
UserDisplay(bestUserName, tags, modifier)
|
||||||
text = bestUserName,
|
|
||||||
tags = tags,
|
|
||||||
fontWeight = FontWeight.Bold,
|
|
||||||
maxLines = 1,
|
|
||||||
overflow = TextOverflow.Ellipsis,
|
|
||||||
modifier = modifier
|
|
||||||
)
|
|
||||||
Spacer(StdHorzSpacer)
|
|
||||||
DrawPlayName(bestUserName)
|
|
||||||
} else {
|
} else {
|
||||||
|
NPubDisplay(npubDisplay, modifier)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun NPubDisplay(npubDisplay: String, modifier: Modifier) {
|
||||||
Text(
|
Text(
|
||||||
text = npubDisplay,
|
text = npubDisplay,
|
||||||
fontWeight = FontWeight.Bold,
|
fontWeight = FontWeight.Bold,
|
||||||
@@ -108,6 +96,48 @@ private fun UserNameDisplay(
|
|||||||
modifier = modifier
|
modifier = modifier
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun UserDisplay(
|
||||||
|
bestDisplayName: String,
|
||||||
|
tags: ImmutableListOfLists<String>?,
|
||||||
|
modifier: Modifier
|
||||||
|
) {
|
||||||
|
CreateTextWithEmoji(
|
||||||
|
text = bestDisplayName,
|
||||||
|
tags = tags,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
maxLines = 1,
|
||||||
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
modifier = modifier
|
||||||
|
)
|
||||||
|
Spacer(StdHorzSpacer)
|
||||||
|
DrawPlayName(bestDisplayName)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun UserAndUsernameDisplay(
|
||||||
|
bestDisplayName: String,
|
||||||
|
tags: ImmutableListOfLists<String>?,
|
||||||
|
bestUserName: String,
|
||||||
|
modifier: Modifier
|
||||||
|
) {
|
||||||
|
CreateTextWithEmoji(
|
||||||
|
text = bestDisplayName,
|
||||||
|
tags = tags,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
maxLines = 1
|
||||||
|
)
|
||||||
|
CreateTextWithEmoji(
|
||||||
|
text = remember { "@$bestUserName" },
|
||||||
|
tags = tags,
|
||||||
|
color = MaterialTheme.colors.placeholderText,
|
||||||
|
maxLines = 1,
|
||||||
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
modifier = modifier
|
||||||
|
)
|
||||||
|
Spacer(StdHorzSpacer)
|
||||||
|
DrawPlayName(bestDisplayName)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ import com.vitorpamplona.amethyst.model.User
|
|||||||
import com.vitorpamplona.amethyst.ui.actions.CloseButton
|
import com.vitorpamplona.amethyst.ui.actions.CloseButton
|
||||||
import com.vitorpamplona.amethyst.ui.actions.toImmutableListOfLists
|
import com.vitorpamplona.amethyst.ui.actions.toImmutableListOfLists
|
||||||
import com.vitorpamplona.amethyst.ui.components.CreateTextWithEmoji
|
import com.vitorpamplona.amethyst.ui.components.CreateTextWithEmoji
|
||||||
import com.vitorpamplona.amethyst.ui.components.ResizeImage
|
|
||||||
import com.vitorpamplona.amethyst.ui.components.RobohashAsyncImageProxy
|
import com.vitorpamplona.amethyst.ui.components.RobohashAsyncImageProxy
|
||||||
import com.vitorpamplona.amethyst.ui.qrcode.NIP19QrCodeScanner
|
import com.vitorpamplona.amethyst.ui.qrcode.NIP19QrCodeScanner
|
||||||
import com.vitorpamplona.amethyst.ui.theme.Size35dp
|
import com.vitorpamplona.amethyst.ui.theme.Size35dp
|
||||||
@@ -76,7 +75,7 @@ fun ShowQRDialog(user: User, onScan: (String) -> Unit, onClose: () -> Unit) {
|
|||||||
Row(horizontalArrangement = Arrangement.Center, modifier = Modifier.fillMaxWidth()) {
|
Row(horizontalArrangement = Arrangement.Center, modifier = Modifier.fillMaxWidth()) {
|
||||||
RobohashAsyncImageProxy(
|
RobohashAsyncImageProxy(
|
||||||
robot = user.pubkeyHex,
|
robot = user.pubkeyHex,
|
||||||
model = ResizeImage(user.profilePicture(), 100.dp),
|
model = user.profilePicture(),
|
||||||
contentDescription = stringResource(R.string.profile_image),
|
contentDescription = stringResource(R.string.profile_image),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.width(100.dp)
|
.width(100.dp)
|
||||||
|
|||||||
@@ -2,27 +2,17 @@ package com.vitorpamplona.amethyst.ui.screen
|
|||||||
|
|
||||||
import androidx.compose.animation.Crossfade
|
import androidx.compose.animation.Crossfade
|
||||||
import androidx.compose.animation.core.tween
|
import androidx.compose.animation.core.tween
|
||||||
import androidx.compose.foundation.layout.Box
|
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.defaultMinSize
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.itemsIndexed
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
import androidx.compose.material.ExperimentalMaterialApi
|
|
||||||
import androidx.compose.material.pullrefresh.PullRefreshIndicator
|
|
||||||
import androidx.compose.material.pullrefresh.pullRefresh
|
|
||||||
import androidx.compose.material.pullrefresh.rememberPullRefreshState
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.MutableState
|
import androidx.compose.runtime.MutableState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
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 androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
@@ -30,22 +20,26 @@ import com.vitorpamplona.amethyst.service.model.PrivateDmEvent
|
|||||||
import com.vitorpamplona.amethyst.ui.note.ChatroomCompose
|
import com.vitorpamplona.amethyst.ui.note.ChatroomCompose
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterialApi::class)
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ChatroomListFeedView(
|
fun ChatroomListFeedView(
|
||||||
viewModel: FeedViewModel,
|
viewModel: FeedViewModel,
|
||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
nav: (String) -> Unit,
|
nav: (String) -> Unit,
|
||||||
markAsRead: MutableState<Boolean>
|
markAsRead: MutableState<Boolean>
|
||||||
|
) {
|
||||||
|
RefresheableView(viewModel, true) {
|
||||||
|
CorssFadeState(viewModel, accountViewModel, nav, markAsRead)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun CorssFadeState(
|
||||||
|
viewModel: FeedViewModel,
|
||||||
|
accountViewModel: AccountViewModel,
|
||||||
|
nav: (String) -> Unit,
|
||||||
|
markAsRead: MutableState<Boolean>
|
||||||
) {
|
) {
|
||||||
val feedState by viewModel.feedContent.collectAsStateWithLifecycle()
|
val feedState by viewModel.feedContent.collectAsStateWithLifecycle()
|
||||||
|
|
||||||
var refreshing by remember { mutableStateOf(false) }
|
|
||||||
val refresh = { refreshing = true; viewModel.invalidateData(); refreshing = false }
|
|
||||||
val pullRefreshState = rememberPullRefreshState(refreshing, onRefresh = refresh)
|
|
||||||
|
|
||||||
Box(Modifier.pullRefresh(pullRefreshState)) {
|
|
||||||
Column() {
|
|
||||||
Crossfade(
|
Crossfade(
|
||||||
targetState = feedState,
|
targetState = feedState,
|
||||||
animationSpec = tween(durationMillis = 100)
|
animationSpec = tween(durationMillis = 100)
|
||||||
@@ -53,20 +47,17 @@ fun ChatroomListFeedView(
|
|||||||
when (state) {
|
when (state) {
|
||||||
is FeedState.Empty -> {
|
is FeedState.Empty -> {
|
||||||
FeedEmpty {
|
FeedEmpty {
|
||||||
refreshing = true
|
viewModel.invalidateData()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
is FeedState.FeedError -> {
|
is FeedState.FeedError -> {
|
||||||
FeedError(state.errorMessage) {
|
FeedError(state.errorMessage) {
|
||||||
refreshing = true
|
viewModel.invalidateData()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
is FeedState.Loaded -> {
|
is FeedState.Loaded -> {
|
||||||
if (refreshing) {
|
|
||||||
refreshing = false
|
|
||||||
}
|
|
||||||
FeedLoaded(state, accountViewModel, nav, markAsRead)
|
FeedLoaded(state, accountViewModel, nav, markAsRead)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,10 +68,6 @@ fun ChatroomListFeedView(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PullRefreshIndicator(refreshing, pullRefreshState, Modifier.align(Alignment.TopCenter))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun FeedLoaded(
|
private fun FeedLoaded(
|
||||||
state: FeedState.Loaded,
|
state: FeedState.Loaded,
|
||||||
@@ -120,7 +107,7 @@ private fun FeedLoaded(
|
|||||||
state.feed.value,
|
state.feed.value,
|
||||||
key = { index, item -> if (index == 0) index else item.idHex }
|
key = { index, item -> if (index == 0) index else item.idHex }
|
||||||
) { _, item ->
|
) { _, item ->
|
||||||
Row(Modifier.fillMaxWidth().defaultMinSize(minHeight = 75.dp)) {
|
Row(Modifier.fillMaxWidth()) {
|
||||||
ChatroomCompose(
|
ChatroomCompose(
|
||||||
item,
|
item,
|
||||||
accountViewModel = accountViewModel,
|
accountViewModel = accountViewModel,
|
||||||
|
|||||||
@@ -61,11 +61,13 @@ fun RefresheableView(
|
|||||||
val refresh = { refreshing = true; viewModel.invalidateData(); refreshing = false }
|
val refresh = { refreshing = true; viewModel.invalidateData(); refreshing = false }
|
||||||
val pullRefreshState = rememberPullRefreshState(refreshing, onRefresh = refresh)
|
val pullRefreshState = rememberPullRefreshState(refreshing, onRefresh = refresh)
|
||||||
|
|
||||||
val modifier = if (enablePullRefresh) {
|
val modifier = remember {
|
||||||
|
if (enablePullRefresh) {
|
||||||
Modifier.pullRefresh(pullRefreshState)
|
Modifier.pullRefresh(pullRefreshState)
|
||||||
} else {
|
} else {
|
||||||
Modifier
|
Modifier
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Box(modifier) {
|
Box(modifier) {
|
||||||
Column {
|
Column {
|
||||||
@@ -73,7 +75,13 @@ fun RefresheableView(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (enablePullRefresh) {
|
if (enablePullRefresh) {
|
||||||
PullRefreshIndicator(refreshing, pullRefreshState, Modifier.align(Alignment.TopCenter))
|
PullRefreshIndicator(
|
||||||
|
refreshing = refreshing,
|
||||||
|
state = pullRefreshState,
|
||||||
|
modifier = remember {
|
||||||
|
Modifier.align(Alignment.TopCenter)
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,7 +89,6 @@ import com.vitorpamplona.amethyst.ui.actions.NewPostViewModel
|
|||||||
import com.vitorpamplona.amethyst.ui.actions.PostButton
|
import com.vitorpamplona.amethyst.ui.actions.PostButton
|
||||||
import com.vitorpamplona.amethyst.ui.actions.ServersAvailable
|
import com.vitorpamplona.amethyst.ui.actions.ServersAvailable
|
||||||
import com.vitorpamplona.amethyst.ui.actions.UploadFromGallery
|
import com.vitorpamplona.amethyst.ui.actions.UploadFromGallery
|
||||||
import com.vitorpamplona.amethyst.ui.components.ResizeImage
|
|
||||||
import com.vitorpamplona.amethyst.ui.components.RobohashAsyncImageProxy
|
import com.vitorpamplona.amethyst.ui.components.RobohashAsyncImageProxy
|
||||||
import com.vitorpamplona.amethyst.ui.components.VideoView
|
import com.vitorpamplona.amethyst.ui.components.VideoView
|
||||||
import com.vitorpamplona.amethyst.ui.navigation.Route
|
import com.vitorpamplona.amethyst.ui.navigation.Route
|
||||||
@@ -549,7 +548,7 @@ fun ChannelHeader(
|
|||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
RobohashAsyncImageProxy(
|
RobohashAsyncImageProxy(
|
||||||
robot = channel.idHex,
|
robot = channel.idHex,
|
||||||
model = ResizeImage(channel.profilePicture(), Size35dp),
|
model = channel.profilePicture(),
|
||||||
contentDescription = context.getString(R.string.profile_image),
|
contentDescription = context.getString(R.string.profile_image),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.width(Size35dp)
|
.width(Size35dp)
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import androidx.compose.runtime.livedata.observeAsState
|
|||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.draw.drawBehind
|
||||||
import androidx.compose.ui.geometry.Offset
|
import androidx.compose.ui.geometry.Offset
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
|
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
|
||||||
@@ -1040,32 +1041,37 @@ private fun WatchAndRenderBadgeImage(
|
|||||||
) {
|
) {
|
||||||
val noteState by baseNote.live().metadata.observeAsState()
|
val noteState by baseNote.live().metadata.observeAsState()
|
||||||
val eventId = remember(noteState) { noteState?.note?.idHex } ?: return
|
val eventId = remember(noteState) { noteState?.note?.idHex } ?: return
|
||||||
val image = remember(noteState) {
|
val image by remember(noteState) {
|
||||||
|
derivedStateOf {
|
||||||
val event = noteState?.note?.event as? BadgeDefinitionEvent
|
val event = noteState?.note?.event as? BadgeDefinitionEvent
|
||||||
event?.thumb()?.ifBlank { null } ?: event?.image()?.ifBlank { null }
|
event?.thumb()?.ifBlank { null } ?: event?.image()?.ifBlank { null }
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val bgColor = MaterialTheme.colors.background
|
||||||
|
|
||||||
if (image == null) {
|
if (image == null) {
|
||||||
RobohashAsyncImage(
|
RobohashAsyncImage(
|
||||||
robot = "authornotfound",
|
robot = "authornotfound",
|
||||||
robotSize = size,
|
|
||||||
contentDescription = stringResource(R.string.unknown_author),
|
contentDescription = stringResource(R.string.unknown_author),
|
||||||
modifier = pictureModifier
|
modifier = remember {
|
||||||
|
pictureModifier
|
||||||
.width(size)
|
.width(size)
|
||||||
.height(size)
|
.height(size)
|
||||||
.background(MaterialTheme.colors.background)
|
.drawBehind { drawRect(bgColor) }
|
||||||
|
}
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
RobohashFallbackAsyncImage(
|
RobohashFallbackAsyncImage(
|
||||||
robot = eventId,
|
robot = eventId,
|
||||||
robotSize = size,
|
model = image!!,
|
||||||
model = image,
|
|
||||||
contentDescription = stringResource(id = R.string.profile_image),
|
contentDescription = stringResource(id = R.string.profile_image),
|
||||||
modifier = pictureModifier
|
modifier = remember {
|
||||||
|
pictureModifier
|
||||||
.width(size)
|
.width(size)
|
||||||
.height(size)
|
.height(size)
|
||||||
.clip(shape = CircleShape)
|
.clip(shape = CircleShape)
|
||||||
.background(MaterialTheme.colors.background)
|
.drawBehind { drawRect(bgColor) }
|
||||||
.run {
|
.run {
|
||||||
if (onClick != null) {
|
if (onClick != null) {
|
||||||
this.clickable(onClick = { onClick(eventId) })
|
this.clickable(onClick = { onClick(eventId) })
|
||||||
@@ -1073,6 +1079,7 @@ private fun WatchAndRenderBadgeImage(
|
|||||||
this
|
this
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,12 +26,13 @@ val StdButtonSizeModifier = Modifier.size(20.dp)
|
|||||||
val StdHorzSpacer = Modifier.width(5.dp)
|
val StdHorzSpacer = Modifier.width(5.dp)
|
||||||
val StdVertSpacer = Modifier.height(5.dp)
|
val StdVertSpacer = Modifier.height(5.dp)
|
||||||
val DoubleHorzSpacer = Modifier.width(10.dp)
|
val DoubleHorzSpacer = Modifier.width(10.dp)
|
||||||
val DoubleVertSpacer = Modifier.width(10.dp)
|
val DoubleVertSpacer = Modifier.height(10.dp)
|
||||||
|
|
||||||
val Size13dp = 13.dp
|
val Size13dp = 13.dp
|
||||||
val Size16dp = 16.dp
|
val Size16dp = 16.dp
|
||||||
val Size25dp = 25.dp
|
val Size25dp = 25.dp
|
||||||
val Size35dp = 35.dp
|
val Size35dp = 35.dp
|
||||||
|
val Size55dp = 55.dp
|
||||||
|
|
||||||
val StdPadding = Modifier.padding(10.dp)
|
val StdPadding = Modifier.padding(10.dp)
|
||||||
|
|
||||||
|
|||||||
@@ -48,6 +48,9 @@ private val LightMediumImportantLink = LightColorPalette.primary.copy(alpha = 0.
|
|||||||
private val DarkVeryImportantLink = DarkColorPalette.primary.copy(alpha = 0.12f)
|
private val DarkVeryImportantLink = DarkColorPalette.primary.copy(alpha = 0.12f)
|
||||||
private val LightVeryImportantLink = LightColorPalette.primary.copy(alpha = 0.12f)
|
private val LightVeryImportantLink = LightColorPalette.primary.copy(alpha = 0.12f)
|
||||||
|
|
||||||
|
private val DarkGrayText = DarkColorPalette.onSurface.copy(alpha = 0.52f)
|
||||||
|
private val LightGrayText = LightColorPalette.onSurface.copy(alpha = 0.52f)
|
||||||
|
|
||||||
private val DarkPlaceholderText = DarkColorPalette.onSurface.copy(alpha = 0.32f)
|
private val DarkPlaceholderText = DarkColorPalette.onSurface.copy(alpha = 0.32f)
|
||||||
private val LightPlaceholderText = LightColorPalette.onSurface.copy(alpha = 0.32f)
|
private val LightPlaceholderText = LightColorPalette.onSurface.copy(alpha = 0.32f)
|
||||||
|
|
||||||
@@ -89,6 +92,9 @@ val Colors.veryImportantLink: Color
|
|||||||
val Colors.placeholderText: Color
|
val Colors.placeholderText: Color
|
||||||
get() = if (isLight) LightPlaceholderText else DarkPlaceholderText
|
get() = if (isLight) LightPlaceholderText else DarkPlaceholderText
|
||||||
|
|
||||||
|
val Colors.grayText: Color
|
||||||
|
get() = if (isLight) LightGrayText else DarkGrayText
|
||||||
|
|
||||||
val Colors.subtleBorder: Color
|
val Colors.subtleBorder: Color
|
||||||
get() = if (isLight) LightSubtleBorder else DarkSubtleBorder
|
get() = if (isLight) LightSubtleBorder else DarkSubtleBorder
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user