Minor performance improvements throughout the code
This commit is contained in:
@@ -490,9 +490,9 @@ class NoteLiveData(val note: Note) : LiveData<NoteState>(NoteState(note)) {
|
|||||||
|
|
||||||
fun invalidateData() {
|
fun invalidateData() {
|
||||||
bundler.invalidate() {
|
bundler.invalidate() {
|
||||||
// if (hasObservers()) {
|
if (hasActiveObservers()) {
|
||||||
postValue(NoteState(note))
|
postValue(NoteState(note))
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -144,8 +144,10 @@ class User(val pubkeyHex: String) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun updateAcceptedBadges(note: AddressableNote) {
|
fun updateAcceptedBadges(note: AddressableNote) {
|
||||||
acceptedBadges = note
|
if (acceptedBadges?.idHex != note.idHex) {
|
||||||
liveSet?.badges?.invalidateData()
|
acceptedBadges = note
|
||||||
|
liveSet?.badges?.invalidateData()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addZap(zapRequest: Note, zap: Note?) {
|
fun addZap(zapRequest: Note, zap: Note?) {
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ class RepostEvent(
|
|||||||
sig: HexKey
|
sig: HexKey
|
||||||
) : Event(id, pubKey, createdAt, kind, tags, content, sig) {
|
) : Event(id, pubKey, createdAt, kind, tags, content, sig) {
|
||||||
|
|
||||||
fun boostedPost() = tags.filter { it.firstOrNull() == "e" }.mapNotNull { it.getOrNull(1) }
|
fun boostedPost() = taggedEvents()
|
||||||
fun originalAuthor() = tags.filter { it.firstOrNull() == "p" }.mapNotNull { it.getOrNull(1) }
|
fun originalAuthor() = taggedUsers()
|
||||||
|
|
||||||
fun containedPost() = try {
|
fun containedPost() = try {
|
||||||
fromJson(content, Client.lenient)
|
fromJson(content, Client.lenient)
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.TextSpinner
|
|||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.UserLine
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.UserLine
|
||||||
import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange
|
import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange
|
||||||
import com.vitorpamplona.amethyst.ui.theme.ButtonBorder
|
import com.vitorpamplona.amethyst.ui.theme.ButtonBorder
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.Font14SP
|
||||||
import com.vitorpamplona.amethyst.ui.theme.QuoteBorder
|
import com.vitorpamplona.amethyst.ui.theme.QuoteBorder
|
||||||
import com.vitorpamplona.amethyst.ui.theme.mediumImportanceLink
|
import com.vitorpamplona.amethyst.ui.theme.mediumImportanceLink
|
||||||
import com.vitorpamplona.amethyst.ui.theme.placeholderText
|
import com.vitorpamplona.amethyst.ui.theme.placeholderText
|
||||||
@@ -621,7 +622,7 @@ private fun ForwardZapTo(
|
|||||||
Text(
|
Text(
|
||||||
text = stringResource(R.string.zap_forward_lnAddress),
|
text = stringResource(R.string.zap_forward_lnAddress),
|
||||||
color = MaterialTheme.colors.placeholderText,
|
color = MaterialTheme.colors.placeholderText,
|
||||||
fontSize = 14.sp
|
fontSize = Font14SP
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
colors = TextFieldDefaults
|
colors = TextFieldDefaults
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ import com.vitorpamplona.amethyst.model.RelaySetupInfo
|
|||||||
import com.vitorpamplona.amethyst.service.relays.FeedType
|
import com.vitorpamplona.amethyst.service.relays.FeedType
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||||
import com.vitorpamplona.amethyst.ui.theme.ButtonBorder
|
import com.vitorpamplona.amethyst.ui.theme.ButtonBorder
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.Font14SP
|
||||||
import com.vitorpamplona.amethyst.ui.theme.Size35dp
|
import com.vitorpamplona.amethyst.ui.theme.Size35dp
|
||||||
import com.vitorpamplona.amethyst.ui.theme.placeholderText
|
import com.vitorpamplona.amethyst.ui.theme.placeholderText
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@@ -167,7 +168,7 @@ fun ServerConfigHeader() {
|
|||||||
Text(
|
Text(
|
||||||
text = stringResource(R.string.bytes),
|
text = stringResource(R.string.bytes),
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
fontSize = 14.sp,
|
fontSize = Font14SP,
|
||||||
modifier = Modifier.weight(1.2f),
|
modifier = Modifier.weight(1.2f),
|
||||||
color = MaterialTheme.colors.placeholderText
|
color = MaterialTheme.colors.placeholderText
|
||||||
)
|
)
|
||||||
@@ -177,7 +178,7 @@ fun ServerConfigHeader() {
|
|||||||
Text(
|
Text(
|
||||||
text = stringResource(id = R.string.bytes),
|
text = stringResource(id = R.string.bytes),
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
fontSize = 14.sp,
|
fontSize = Font14SP,
|
||||||
modifier = Modifier.weight(1.2f),
|
modifier = Modifier.weight(1.2f),
|
||||||
color = MaterialTheme.colors.placeholderText
|
color = MaterialTheme.colors.placeholderText
|
||||||
)
|
)
|
||||||
@@ -187,7 +188,7 @@ fun ServerConfigHeader() {
|
|||||||
Text(
|
Text(
|
||||||
text = stringResource(R.string.errors),
|
text = stringResource(R.string.errors),
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
fontSize = 14.sp,
|
fontSize = Font14SP,
|
||||||
modifier = Modifier.weight(1f),
|
modifier = Modifier.weight(1f),
|
||||||
color = MaterialTheme.colors.placeholderText
|
color = MaterialTheme.colors.placeholderText
|
||||||
)
|
)
|
||||||
@@ -197,7 +198,7 @@ fun ServerConfigHeader() {
|
|||||||
Text(
|
Text(
|
||||||
text = stringResource(R.string.spam),
|
text = stringResource(R.string.spam),
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
fontSize = 14.sp,
|
fontSize = Font14SP,
|
||||||
modifier = Modifier.weight(1f),
|
modifier = Modifier.weight(1f),
|
||||||
color = MaterialTheme.colors.placeholderText
|
color = MaterialTheme.colors.placeholderText
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package com.vitorpamplona.amethyst.ui.components
|
|||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.util.LruCache
|
import android.util.LruCache
|
||||||
import android.util.Patterns
|
import android.util.Patterns
|
||||||
import androidx.compose.foundation.background
|
|
||||||
import androidx.compose.foundation.border
|
import androidx.compose.foundation.border
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.text.ClickableText
|
import androidx.compose.foundation.text.ClickableText
|
||||||
@@ -19,16 +18,13 @@ import androidx.compose.runtime.livedata.observeAsState
|
|||||||
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.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.compositeOver
|
|
||||||
import androidx.compose.ui.platform.LocalUriHandler
|
import androidx.compose.ui.platform.LocalUriHandler
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.text.*
|
import androidx.compose.ui.text.*
|
||||||
import androidx.compose.ui.text.font.FontFamily
|
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.style.TextDirection
|
import androidx.compose.ui.text.style.TextDirection
|
||||||
import androidx.compose.ui.unit.TextUnit
|
import androidx.compose.ui.unit.TextUnit
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.em
|
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import com.halilibo.richtext.markdown.Markdown
|
import com.halilibo.richtext.markdown.Markdown
|
||||||
import com.halilibo.richtext.markdown.MarkdownParseOptions
|
import com.halilibo.richtext.markdown.MarkdownParseOptions
|
||||||
@@ -47,7 +43,9 @@ 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.note.NoteCompose
|
import com.vitorpamplona.amethyst.ui.note.NoteCompose
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.MarkdownTextStyle
|
||||||
import com.vitorpamplona.amethyst.ui.theme.QuoteBorder
|
import com.vitorpamplona.amethyst.ui.theme.QuoteBorder
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.markdownStyle
|
||||||
import com.vitorpamplona.amethyst.ui.theme.subtleBorder
|
import com.vitorpamplona.amethyst.ui.theme.subtleBorder
|
||||||
import com.vitorpamplona.amethyst.ui.uriToRoute
|
import com.vitorpamplona.amethyst.ui.uriToRoute
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
@@ -439,42 +437,6 @@ fun RenderCustomEmoji(word: String, state: RichTextViewerState) {
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun RenderContentAsMarkdown(content: String, backgroundColor: MutableState<Color>, tags: ImmutableListOfLists<String>?, nav: (String) -> Unit) {
|
private fun RenderContentAsMarkdown(content: String, backgroundColor: MutableState<Color>, tags: ImmutableListOfLists<String>?, nav: (String) -> Unit) {
|
||||||
val myMarkDownStyle = richTextDefaults.copy(
|
|
||||||
paragraphSpacing = DefaultParagraphSpacing,
|
|
||||||
headingStyle = DefaultHeadingStyle,
|
|
||||||
codeBlockStyle = richTextDefaults.codeBlockStyle?.copy(
|
|
||||||
textStyle = TextStyle(
|
|
||||||
fontFamily = FontFamily.Monospace,
|
|
||||||
fontSize = 14.sp
|
|
||||||
),
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(0.dp)
|
|
||||||
.fillMaxWidth()
|
|
||||||
.clip(shape = QuoteBorder)
|
|
||||||
.border(
|
|
||||||
1.dp,
|
|
||||||
MaterialTheme.colors.subtleBorder,
|
|
||||||
QuoteBorder
|
|
||||||
)
|
|
||||||
.background(
|
|
||||||
MaterialTheme.colors.onSurface
|
|
||||||
.copy(alpha = 0.05f)
|
|
||||||
.compositeOver(backgroundColor.value)
|
|
||||||
)
|
|
||||||
),
|
|
||||||
stringStyle = richTextDefaults.stringStyle?.copy(
|
|
||||||
linkStyle = SpanStyle(
|
|
||||||
color = MaterialTheme.colors.primary
|
|
||||||
),
|
|
||||||
codeStyle = SpanStyle(
|
|
||||||
fontFamily = FontFamily.Monospace,
|
|
||||||
fontSize = 14.sp,
|
|
||||||
background = MaterialTheme.colors.onSurface.copy(alpha = 0.22f)
|
|
||||||
.compositeOver(backgroundColor.value)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
val uri = LocalUriHandler.current
|
val uri = LocalUriHandler.current
|
||||||
val onClick = { link: String ->
|
val onClick = { link: String ->
|
||||||
val route = uriToRoute(link)
|
val route = uriToRoute(link)
|
||||||
@@ -486,9 +448,9 @@ private fun RenderContentAsMarkdown(content: String, backgroundColor: MutableSta
|
|||||||
Unit
|
Unit
|
||||||
}
|
}
|
||||||
|
|
||||||
ProvideTextStyle(TextStyle(lineHeight = 1.30.em)) {
|
ProvideTextStyle(MarkdownTextStyle) {
|
||||||
MaterialRichText(
|
MaterialRichText(
|
||||||
style = myMarkDownStyle
|
style = MaterialTheme.colors.markdownStyle
|
||||||
) {
|
) {
|
||||||
RefreshableContent(content, tags) {
|
RefreshableContent(content, tags) {
|
||||||
Markdown(
|
Markdown(
|
||||||
|
|||||||
@@ -29,8 +29,8 @@ import androidx.compose.ui.focus.FocusRequester
|
|||||||
import androidx.compose.ui.focus.focusRequester
|
import androidx.compose.ui.focus.focusRequester
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
|
||||||
import androidx.compose.ui.window.Dialog
|
import androidx.compose.ui.window.Dialog
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.Font14SP
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -120,7 +120,7 @@ fun SpinnerSelectionDialog(
|
|||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
) {
|
) {
|
||||||
Text(text = it, color = Color.Gray, fontSize = 14.sp)
|
Text(text = it, color = Color.Gray, fontSize = Font14SP)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,7 +96,6 @@ import com.vitorpamplona.amethyst.service.model.BaseTextNoteEvent
|
|||||||
import com.vitorpamplona.amethyst.service.model.ChannelCreateEvent
|
import com.vitorpamplona.amethyst.service.model.ChannelCreateEvent
|
||||||
import com.vitorpamplona.amethyst.service.model.ChannelMessageEvent
|
import com.vitorpamplona.amethyst.service.model.ChannelMessageEvent
|
||||||
import com.vitorpamplona.amethyst.service.model.ChannelMetadataEvent
|
import com.vitorpamplona.amethyst.service.model.ChannelMetadataEvent
|
||||||
import com.vitorpamplona.amethyst.service.model.EventInterface
|
|
||||||
import com.vitorpamplona.amethyst.service.model.FileHeaderEvent
|
import com.vitorpamplona.amethyst.service.model.FileHeaderEvent
|
||||||
import com.vitorpamplona.amethyst.service.model.FileStorageHeaderEvent
|
import com.vitorpamplona.amethyst.service.model.FileStorageHeaderEvent
|
||||||
import com.vitorpamplona.amethyst.service.model.GenericRepostEvent
|
import com.vitorpamplona.amethyst.service.model.GenericRepostEvent
|
||||||
@@ -142,14 +141,28 @@ 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.DiviserThickness
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.DoubleHorzSpacer
|
||||||
import com.vitorpamplona.amethyst.ui.theme.DoubleVertSpacer
|
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.Font14SP
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.HalfPadding
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.HalfVertSpacer
|
||||||
import com.vitorpamplona.amethyst.ui.theme.QuoteBorder
|
import com.vitorpamplona.amethyst.ui.theme.QuoteBorder
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.Size25dp
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.Size30Modifier
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.Size30dp
|
||||||
import com.vitorpamplona.amethyst.ui.theme.Size35dp
|
import com.vitorpamplona.amethyst.ui.theme.Size35dp
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.Size55Modifier
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.Size55dp
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.StdStartPadding
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.WidthAuthorPictureModifier
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.lessImportantLink
|
||||||
import com.vitorpamplona.amethyst.ui.theme.mediumImportanceLink
|
import com.vitorpamplona.amethyst.ui.theme.mediumImportanceLink
|
||||||
import com.vitorpamplona.amethyst.ui.theme.newItemBackgroundColor
|
import com.vitorpamplona.amethyst.ui.theme.newItemBackgroundColor
|
||||||
import com.vitorpamplona.amethyst.ui.theme.placeholderText
|
import com.vitorpamplona.amethyst.ui.theme.placeholderText
|
||||||
import com.vitorpamplona.amethyst.ui.theme.replyBackground
|
import com.vitorpamplona.amethyst.ui.theme.replyBackground
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.repostProfileBorder
|
||||||
import com.vitorpamplona.amethyst.ui.theme.subtleBorder
|
import com.vitorpamplona.amethyst.ui.theme.subtleBorder
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import kotlinx.collections.immutable.ImmutableSet
|
import kotlinx.collections.immutable.ImmutableSet
|
||||||
@@ -181,9 +194,13 @@ fun NoteCompose(
|
|||||||
nav: (String) -> Unit
|
nav: (String) -> Unit
|
||||||
) {
|
) {
|
||||||
val noteState by baseNote.live().metadata.observeAsState()
|
val noteState by baseNote.live().metadata.observeAsState()
|
||||||
val noteEvent = remember(noteState) { noteState?.note?.event }
|
val missingEvent by remember(noteState) {
|
||||||
|
derivedStateOf {
|
||||||
|
noteState?.note?.event == null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (noteEvent == null) {
|
if (missingEvent) {
|
||||||
LongPressToQuickAction(baseNote = baseNote, accountViewModel = accountViewModel) { showPopup ->
|
LongPressToQuickAction(baseNote = baseNote, accountViewModel = accountViewModel) { showPopup ->
|
||||||
BlankNote(
|
BlankNote(
|
||||||
remember {
|
remember {
|
||||||
@@ -337,12 +354,12 @@ fun WatchForReports(
|
|||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
onChange: (Boolean, Boolean, Set<Note>) -> Unit
|
onChange: (Boolean, Boolean, Set<Note>) -> Unit
|
||||||
) {
|
) {
|
||||||
val accountState by accountViewModel.accountLiveData.observeAsState()
|
val userFollowsState by accountViewModel.userFollows.observeAsState()
|
||||||
val noteReportsState by note.live().reports.observeAsState()
|
val noteReportsState by note.live().reports.observeAsState()
|
||||||
|
|
||||||
LaunchedEffect(key1 = noteReportsState, key2 = accountState) {
|
LaunchedEffect(key1 = noteReportsState, key2 = userFollowsState) {
|
||||||
launch(Dispatchers.Default) {
|
launch(Dispatchers.Default) {
|
||||||
accountState?.account?.let { loggedIn ->
|
accountViewModel.account.let { loggedIn ->
|
||||||
val newCanPreview = note.author?.pubkeyHex == loggedIn.userProfile().pubkeyHex ||
|
val newCanPreview = note.author?.pubkeyHex == loggedIn.userProfile().pubkeyHex ||
|
||||||
(note.author?.let { loggedIn.userProfile().isFollowingCached(it) } ?: true) ||
|
(note.author?.let { loggedIn.userProfile().isFollowingCached(it) } ?: true) ||
|
||||||
noteReportsState?.note?.hasAnyReports() != true
|
noteReportsState?.note?.hasAnyReports() != true
|
||||||
@@ -376,10 +393,22 @@ fun NormalNote(
|
|||||||
nav: (String) -> Unit
|
nav: (String) -> Unit
|
||||||
) {
|
) {
|
||||||
val noteEvent = remember { baseNote.event }
|
val noteEvent = remember { baseNote.event }
|
||||||
val channelHex = remember { baseNote.channelHex() }
|
|
||||||
|
|
||||||
if ((noteEvent is ChannelCreateEvent || noteEvent is ChannelMetadataEvent) && channelHex != null) {
|
val isChannelHeader by remember {
|
||||||
ChannelHeader(channelHex = channelHex, showVideo = !makeItShort, showBottomDiviser = true, accountViewModel = accountViewModel, nav = nav)
|
derivedStateOf {
|
||||||
|
(baseNote.event is ChannelCreateEvent || baseNote.event is ChannelMetadataEvent) && baseNote.channelHex() != null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isChannelHeader) {
|
||||||
|
ChannelHeader(
|
||||||
|
channelNote = baseNote,
|
||||||
|
showVideo = !makeItShort,
|
||||||
|
showBottomDiviser = true,
|
||||||
|
accountViewModel =
|
||||||
|
accountViewModel,
|
||||||
|
nav = nav
|
||||||
|
)
|
||||||
} else if (noteEvent is BadgeDefinitionEvent) {
|
} else if (noteEvent is BadgeDefinitionEvent) {
|
||||||
BadgeDisplay(baseNote = baseNote)
|
BadgeDisplay(baseNote = baseNote)
|
||||||
} else if (noteEvent is FileHeaderEvent) {
|
} else if (noteEvent is FileHeaderEvent) {
|
||||||
@@ -387,20 +416,23 @@ fun NormalNote(
|
|||||||
} else if (noteEvent is FileStorageHeaderEvent) {
|
} else if (noteEvent is FileStorageHeaderEvent) {
|
||||||
FileStorageHeaderDisplay(baseNote)
|
FileStorageHeaderDisplay(baseNote)
|
||||||
} else {
|
} else {
|
||||||
CheckNewAndRenderNote(
|
LongPressToQuickAction(baseNote = baseNote, accountViewModel = accountViewModel) { showPopup ->
|
||||||
baseNote,
|
CheckNewAndRenderNote(
|
||||||
routeForLastRead,
|
baseNote,
|
||||||
modifier,
|
routeForLastRead,
|
||||||
isBoostedNote,
|
modifier,
|
||||||
isQuotedNote,
|
isBoostedNote,
|
||||||
unPackReply,
|
isQuotedNote,
|
||||||
makeItShort,
|
unPackReply,
|
||||||
addMarginTop,
|
makeItShort,
|
||||||
canPreview,
|
addMarginTop,
|
||||||
parentBackgroundColor,
|
canPreview,
|
||||||
accountViewModel,
|
parentBackgroundColor,
|
||||||
nav
|
accountViewModel,
|
||||||
)
|
showPopup,
|
||||||
|
nav
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -417,6 +449,7 @@ private fun CheckNewAndRenderNote(
|
|||||||
canPreview: Boolean = true,
|
canPreview: Boolean = true,
|
||||||
parentBackgroundColor: MutableState<Color>? = null,
|
parentBackgroundColor: MutableState<Color>? = null,
|
||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
|
showPopup: () -> Unit,
|
||||||
nav: (String) -> Unit
|
nav: (String) -> Unit
|
||||||
) {
|
) {
|
||||||
val newItemColor = MaterialTheme.colors.newItemBackgroundColor
|
val newItemColor = MaterialTheme.colors.newItemBackgroundColor
|
||||||
@@ -464,22 +497,20 @@ private fun CheckNewAndRenderNote(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LongPressToQuickAction(baseNote = baseNote, accountViewModel = accountViewModel) { showPopup ->
|
RenderNoteWithReactions(
|
||||||
RenderNoteWithReactions(
|
modifier = updatedModifier,
|
||||||
modifier = updatedModifier,
|
backgroundColor = backgroundColor,
|
||||||
backgroundColor = backgroundColor,
|
baseNote = baseNote,
|
||||||
baseNote = baseNote,
|
isBoostedNote = isBoostedNote,
|
||||||
isBoostedNote = isBoostedNote,
|
isQuotedNote = isQuotedNote,
|
||||||
isQuotedNote = isQuotedNote,
|
addMarginTop = addMarginTop,
|
||||||
addMarginTop = addMarginTop,
|
unPackReply = unPackReply,
|
||||||
unPackReply = unPackReply,
|
makeItShort = makeItShort,
|
||||||
makeItShort = makeItShort,
|
canPreview = canPreview,
|
||||||
canPreview = canPreview,
|
accountViewModel = accountViewModel,
|
||||||
accountViewModel = accountViewModel,
|
showPopup = showPopup,
|
||||||
showPopup = showPopup,
|
nav = nav
|
||||||
nav = nav
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -539,8 +570,8 @@ private fun RenderNoteWithReactions(
|
|||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
if (notBoostedNorQuote) {
|
if (notBoostedNorQuote) {
|
||||||
DrawAuthorImages(baseNote, accountViewModel, nav)
|
AuthorAndRelayInformation(baseNote, accountViewModel, nav)
|
||||||
Spacer(modifier = Modifier.width(10.dp))
|
Spacer(modifier = DoubleHorzSpacer)
|
||||||
}
|
}
|
||||||
|
|
||||||
NoteBody(
|
NoteBody(
|
||||||
@@ -556,22 +587,25 @@ private fun RenderNoteWithReactions(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!makeItShort && baseNote.event !is RepostEvent && baseNote.event !is GenericRepostEvent) {
|
val isRepost = remember { baseNote.event is RepostEvent || baseNote.event is GenericRepostEvent }
|
||||||
ReactionsRow(
|
if (!isRepost) {
|
||||||
baseNote = baseNote,
|
if (!makeItShort) {
|
||||||
showReactionDetail = notBoostedNorQuote,
|
ReactionsRow(
|
||||||
accountViewModel = accountViewModel,
|
baseNote = baseNote,
|
||||||
nav = nav
|
showReactionDetail = notBoostedNorQuote,
|
||||||
)
|
accountViewModel = accountViewModel,
|
||||||
} else {
|
nav = nav
|
||||||
if (!isBoostedNote && baseNote.event !is RepostEvent && baseNote.event !is GenericRepostEvent) {
|
)
|
||||||
Spacer(modifier = Modifier.height(10.dp))
|
} else {
|
||||||
|
if (!isBoostedNote) {
|
||||||
|
Spacer(modifier = DoubleVertSpacer)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isQuotedNote && !isBoostedNote) {
|
if (!isQuotedNote && !isBoostedNote) {
|
||||||
Divider(
|
Divider(
|
||||||
thickness = 0.25.dp
|
thickness = DiviserThickness
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -605,7 +639,7 @@ private fun NoteBody(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(2.dp))
|
Spacer(modifier = HalfVertSpacer)
|
||||||
|
|
||||||
if (!makeItShort) {
|
if (!makeItShort) {
|
||||||
ReplyRow(
|
ReplyRow(
|
||||||
@@ -1766,38 +1800,40 @@ private fun FirstUserInfoRow(
|
|||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
nav: (String) -> Unit
|
nav: (String) -> Unit
|
||||||
) {
|
) {
|
||||||
val eventNote = remember { baseNote.event } ?: return
|
val isRepost = remember { baseNote.event is RepostEvent || baseNote.event is GenericRepostEvent }
|
||||||
val time = remember { baseNote.createdAt() } ?: return
|
|
||||||
val padding = remember {
|
|
||||||
Modifier.padding(horizontal = 5.dp)
|
|
||||||
}
|
|
||||||
|
|
||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
Row(verticalAlignment = CenterVertically) {
|
||||||
if (showAuthorPicture) {
|
if (showAuthorPicture) {
|
||||||
NoteAuthorPicture(baseNote, nav, accountViewModel, remember { 25.dp })
|
NoteAuthorPicture(baseNote, nav, accountViewModel, Size25dp)
|
||||||
Spacer(padding)
|
Spacer(HalfPadding)
|
||||||
NoteUsernameDisplay(baseNote, remember { Modifier.weight(1f) })
|
NoteUsernameDisplay(baseNote, remember { Modifier.weight(1f) })
|
||||||
} else {
|
} else {
|
||||||
NoteUsernameDisplay(baseNote, remember { Modifier.weight(1f) })
|
NoteUsernameDisplay(baseNote, remember { Modifier.weight(1f) })
|
||||||
}
|
}
|
||||||
|
|
||||||
if (eventNote is RepostEvent || eventNote is GenericRepostEvent) {
|
if (isRepost) {
|
||||||
Text(
|
BoostedMark()
|
||||||
" ${stringResource(id = R.string.boosted)}",
|
|
||||||
fontWeight = FontWeight.Bold,
|
|
||||||
color = MaterialTheme.colors.placeholderText,
|
|
||||||
maxLines = 1
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
DisplayFollowingHashtagsInPost(eventNote, accountViewModel, nav)
|
DisplayFollowingHashtagsInPost(baseNote, accountViewModel, nav)
|
||||||
}
|
}
|
||||||
|
|
||||||
TimeAgo(time)
|
TimeAgo(baseNote)
|
||||||
|
|
||||||
MoreOptionsButton(baseNote, accountViewModel)
|
MoreOptionsButton(baseNote, accountViewModel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun BoostedMark() {
|
||||||
|
Text(
|
||||||
|
stringResource(id = R.string.boosted),
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
color = MaterialTheme.colors.placeholderText,
|
||||||
|
maxLines = 1,
|
||||||
|
modifier = StdStartPadding
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun MoreOptionsButton(
|
private fun MoreOptionsButton(
|
||||||
baseNote: Note,
|
baseNote: Note,
|
||||||
@@ -1825,19 +1861,16 @@ private fun MoreOptionsButton(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun TimeAgo(note: Note) {
|
||||||
|
val time = remember { note.createdAt() } ?: return
|
||||||
|
TimeAgo(time)
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun TimeAgo(time: Long) {
|
fun TimeAgo(time: Long) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
var timeStr by remember { mutableStateOf("") }
|
val timeStr by remember { mutableStateOf(timeAgo(time, context = context)) }
|
||||||
|
|
||||||
LaunchedEffect(key1 = time) {
|
|
||||||
launch(Dispatchers.IO) {
|
|
||||||
val newTimeStr = timeAgo(time, context = context)
|
|
||||||
if (newTimeStr != timeStr) {
|
|
||||||
timeStr = newTimeStr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = timeStr,
|
text = timeStr,
|
||||||
@@ -1847,35 +1880,60 @@ fun TimeAgo(time: Long) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun DrawAuthorImages(baseNote: Note, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
private fun AuthorAndRelayInformation(baseNote: Note, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
||||||
val baseChannelHex = remember { baseNote.channelHex() }
|
Column(WidthAuthorPictureModifier) {
|
||||||
val modifier = remember { Modifier.width(55.dp) }
|
|
||||||
|
|
||||||
Column(modifier) {
|
|
||||||
// Draws the boosted picture outside the boosted card.
|
// Draws the boosted picture outside the boosted card.
|
||||||
Box(modifier = modifier, contentAlignment = Alignment.BottomEnd) {
|
Box(modifier = Size55Modifier, contentAlignment = Alignment.BottomEnd) {
|
||||||
NoteAuthorPicture(baseNote, nav, accountViewModel, 55.dp)
|
RenderAuthorImages(baseNote, nav, accountViewModel)
|
||||||
|
|
||||||
if (baseNote.event is RepostEvent || baseNote.event is GenericRepostEvent) {
|
|
||||||
RepostNoteAuthorPicture(baseNote, accountViewModel, nav)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (baseNote.event is ChannelMessageEvent && baseChannelHex != null) {
|
|
||||||
LoadChannel(baseChannelHex) { channel ->
|
|
||||||
ChannelNotePicture(channel)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (baseNote.event is RepostEvent || baseNote.event is GenericRepostEvent) {
|
BadgeBox(baseNote, accountViewModel, nav)
|
||||||
val baseReply = remember {
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun BadgeBox(
|
||||||
|
baseNote: Note,
|
||||||
|
accountViewModel: AccountViewModel,
|
||||||
|
nav: (String) -> Unit
|
||||||
|
) {
|
||||||
|
val isRepost = remember { baseNote.event is RepostEvent || baseNote.event is GenericRepostEvent }
|
||||||
|
|
||||||
|
if (isRepost) {
|
||||||
|
val baseReply by remember {
|
||||||
|
derivedStateOf {
|
||||||
baseNote.replyTo?.lastOrNull()
|
baseNote.replyTo?.lastOrNull()
|
||||||
}
|
}
|
||||||
baseReply?.let {
|
}
|
||||||
RelayBadges(it, accountViewModel, nav)
|
baseReply?.let {
|
||||||
|
RelayBadges(it, accountViewModel, nav)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
RelayBadges(baseNote, accountViewModel, nav)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun RenderAuthorImages(
|
||||||
|
baseNote: Note,
|
||||||
|
nav: (String) -> Unit,
|
||||||
|
accountViewModel: AccountViewModel
|
||||||
|
) {
|
||||||
|
val isRepost = remember { baseNote.event is RepostEvent || baseNote.event is GenericRepostEvent }
|
||||||
|
val isChannel = remember { baseNote.event is ChannelMessageEvent && baseNote.channelHex() != null }
|
||||||
|
|
||||||
|
NoteAuthorPicture(baseNote, nav, accountViewModel, Size55dp)
|
||||||
|
|
||||||
|
if (isRepost) {
|
||||||
|
RepostNoteAuthorPicture(baseNote, accountViewModel, nav)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isChannel) {
|
||||||
|
val baseChannelHex = remember { baseNote.channelHex() }
|
||||||
|
if (baseChannelHex != null) {
|
||||||
|
LoadChannel(baseChannelHex) { channel ->
|
||||||
|
ChannelNotePicture(channel)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
RelayBadges(baseNote, accountViewModel, nav)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1945,24 +2003,20 @@ private fun RepostNoteAuthorPicture(
|
|||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
nav: (String) -> Unit
|
nav: (String) -> Unit
|
||||||
) {
|
) {
|
||||||
val baseRepost = remember { baseNote.replyTo?.lastOrNull() }
|
val baseRepost by remember {
|
||||||
|
derivedStateOf {
|
||||||
val modifier = remember {
|
baseNote.replyTo?.lastOrNull()
|
||||||
Modifier.size(30.dp)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
baseRepost?.let {
|
baseRepost?.let {
|
||||||
Box(modifier) {
|
Box(Size30Modifier) {
|
||||||
NoteAuthorPicture(
|
NoteAuthorPicture(
|
||||||
baseNote = it,
|
baseNote = it,
|
||||||
nav = nav,
|
nav = nav,
|
||||||
accountViewModel = accountViewModel,
|
accountViewModel = accountViewModel,
|
||||||
size = remember { 30.dp },
|
size = Size30dp,
|
||||||
pictureModifier = Modifier.border(
|
pictureModifier = MaterialTheme.colors.repostProfileBorder
|
||||||
2.dp,
|
|
||||||
MaterialTheme.colors.background,
|
|
||||||
CircleShape
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2073,10 +2127,12 @@ private fun LoadAndDisplayUser(
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun DisplayFollowingHashtagsInPost(
|
fun DisplayFollowingHashtagsInPost(
|
||||||
noteEvent: EventInterface,
|
baseNote: Note,
|
||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
nav: (String) -> Unit
|
nav: (String) -> Unit
|
||||||
) {
|
) {
|
||||||
|
val noteEvent = remember { baseNote.event } ?: return
|
||||||
|
|
||||||
val accountState by accountViewModel.accountLiveData.observeAsState()
|
val accountState by accountViewModel.accountLiveData.observeAsState()
|
||||||
var firstTag by remember { mutableStateOf<String?>(null) }
|
var firstTag by remember { mutableStateOf<String?>(null) }
|
||||||
|
|
||||||
@@ -2148,12 +2204,14 @@ fun DisplayUncitedHashtags(
|
|||||||
fun DisplayPoW(
|
fun DisplayPoW(
|
||||||
pow: Int
|
pow: Int
|
||||||
) {
|
) {
|
||||||
|
val powStr = remember(pow) {
|
||||||
|
"PoW-$pow"
|
||||||
|
}
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
"PoW-$pow",
|
powStr,
|
||||||
color = MaterialTheme.colors.primary.copy(
|
color = MaterialTheme.colors.lessImportantLink,
|
||||||
alpha = 0.52f
|
fontSize = Font14SP,
|
||||||
),
|
|
||||||
fontSize = 14.sp,
|
|
||||||
fontWeight = FontWeight.Bold,
|
fontWeight = FontWeight.Bold,
|
||||||
maxLines = 1
|
maxLines = 1
|
||||||
)
|
)
|
||||||
@@ -2673,19 +2731,23 @@ private fun CreateImageHeader(
|
|||||||
painter = painterResource(R.drawable.profile_banner),
|
painter = painterResource(R.drawable.profile_banner),
|
||||||
contentDescription = stringResource(R.string.profile_banner),
|
contentDescription = stringResource(R.string.profile_banner),
|
||||||
contentScale = ContentScale.FillWidth,
|
contentScale = ContentScale.FillWidth,
|
||||||
modifier = Modifier
|
modifier = remember {
|
||||||
.fillMaxWidth()
|
Modifier
|
||||||
.height(150.dp)
|
.fillMaxWidth()
|
||||||
|
.height(150.dp)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
Box(
|
Box(
|
||||||
Modifier
|
remember {
|
||||||
.width(75.dp)
|
Modifier
|
||||||
.height(75.dp)
|
.width(75.dp)
|
||||||
.padding(10.dp)
|
.height(75.dp)
|
||||||
.align(Alignment.BottomStart)
|
.padding(10.dp)
|
||||||
|
.align(Alignment.BottomStart)
|
||||||
|
}
|
||||||
) {
|
) {
|
||||||
NoteAuthorPicture(baseNote = note, accountViewModel = accountViewModel, size = 55.dp)
|
NoteAuthorPicture(baseNote = note, accountViewModel = accountViewModel, size = Size55dp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ import androidx.compose.ui.text.font.FontWeight
|
|||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.unit.IntOffset
|
import androidx.compose.ui.unit.IntOffset
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
|
||||||
import androidx.compose.ui.window.Popup
|
import androidx.compose.ui.window.Popup
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import com.vitorpamplona.amethyst.R
|
import com.vitorpamplona.amethyst.R
|
||||||
@@ -32,6 +31,7 @@ import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer
|
|||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||||
import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange
|
import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange
|
||||||
import com.vitorpamplona.amethyst.ui.theme.ButtonBorder
|
import com.vitorpamplona.amethyst.ui.theme.ButtonBorder
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.Font14SP
|
||||||
import com.vitorpamplona.amethyst.ui.theme.QuoteBorder
|
import com.vitorpamplona.amethyst.ui.theme.QuoteBorder
|
||||||
import com.vitorpamplona.amethyst.ui.theme.mediumImportanceLink
|
import com.vitorpamplona.amethyst.ui.theme.mediumImportanceLink
|
||||||
import com.vitorpamplona.amethyst.ui.theme.placeholderText
|
import com.vitorpamplona.amethyst.ui.theme.placeholderText
|
||||||
@@ -428,9 +428,12 @@ fun ZapVote(
|
|||||||
|
|
||||||
// only show tallies after a user has zapped note
|
// only show tallies after a user has zapped note
|
||||||
if (!pollViewModel.canZap()) {
|
if (!pollViewModel.canZap()) {
|
||||||
|
val amountStr = remember(poolOption.zappedValue) {
|
||||||
|
showAmount(poolOption.zappedValue)
|
||||||
|
}
|
||||||
Text(
|
Text(
|
||||||
showAmount(poolOption.zappedValue),
|
text = amountStr,
|
||||||
fontSize = 14.sp,
|
fontSize = Font14SP,
|
||||||
color = MaterialTheme.colors.placeholderText,
|
color = MaterialTheme.colors.placeholderText,
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -45,12 +45,12 @@ import androidx.compose.runtime.remember
|
|||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Alignment.Companion.Center
|
||||||
import androidx.compose.ui.Alignment.Companion.CenterVertically
|
import androidx.compose.ui.Alignment.Companion.CenterVertically
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.ColorFilter
|
import androidx.compose.ui.graphics.ColorFilter
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.platform.LocalUriHandler
|
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.semantics.Role
|
import androidx.compose.ui.semantics.Role
|
||||||
@@ -59,21 +59,34 @@ import androidx.compose.ui.unit.Dp
|
|||||||
import androidx.compose.ui.unit.IntOffset
|
import androidx.compose.ui.unit.IntOffset
|
||||||
import androidx.compose.ui.unit.TextUnit
|
import androidx.compose.ui.unit.TextUnit
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
|
||||||
import androidx.compose.ui.window.Popup
|
import androidx.compose.ui.window.Popup
|
||||||
import coil.compose.AsyncImage
|
import coil.compose.AsyncImage
|
||||||
import coil.request.CachePolicy
|
import coil.request.CachePolicy
|
||||||
import coil.request.ImageRequest
|
import coil.request.ImageRequest
|
||||||
import com.vitorpamplona.amethyst.R
|
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.ui.actions.NewPostView
|
import com.vitorpamplona.amethyst.ui.actions.NewPostView
|
||||||
import com.vitorpamplona.amethyst.ui.screen.CombinedZap
|
import com.vitorpamplona.amethyst.ui.screen.CombinedZap
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||||
import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange
|
import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange
|
||||||
import com.vitorpamplona.amethyst.ui.theme.ButtonBorder
|
import com.vitorpamplona.amethyst.ui.theme.ButtonBorder
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.DarkerGreen
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.Font14SP
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.HalfDoubleVertSpacer
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.NoSoTinyBorders
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.ReactionRowExpandButton
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.ReactionRowHeight
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.ReactionRowZapraiserSize
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.Size18dp
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.Size19dp
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.Size20Modifier
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.Size20dp
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.Size22Modifier
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.Size24dp
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.TinyBorders
|
||||||
import com.vitorpamplona.amethyst.ui.theme.mediumImportanceLink
|
import com.vitorpamplona.amethyst.ui.theme.mediumImportanceLink
|
||||||
import com.vitorpamplona.amethyst.ui.theme.placeholderText
|
import com.vitorpamplona.amethyst.ui.theme.placeholderText
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.subtleButton
|
||||||
import kotlinx.collections.immutable.toImmutableList
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import kotlinx.collections.immutable.toImmutableMap
|
import kotlinx.collections.immutable.toImmutableMap
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
@@ -84,67 +97,118 @@ import java.math.RoundingMode
|
|||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ReactionsRow(baseNote: Note, showReactionDetail: Boolean, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
fun ReactionsRow(
|
||||||
val grayTint = MaterialTheme.colors.placeholderText
|
baseNote: Note,
|
||||||
|
showReactionDetail: Boolean,
|
||||||
|
accountViewModel: AccountViewModel,
|
||||||
|
nav: (String) -> Unit
|
||||||
|
) {
|
||||||
val wantsToSeeReactions = remember {
|
val wantsToSeeReactions = remember {
|
||||||
mutableStateOf<Boolean>(false)
|
mutableStateOf(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
val zapraiserAmount = remember {
|
Spacer(modifier = HalfDoubleVertSpacer)
|
||||||
baseNote.event?.zapraiserAmount()
|
|
||||||
}
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(7.dp))
|
InnerReactionRow(baseNote, showReactionDetail, wantsToSeeReactions, accountViewModel, nav)
|
||||||
|
|
||||||
Row(verticalAlignment = CenterVertically, modifier = Modifier.padding(start = 10.dp)) {
|
LoadAndDisplayZapraiser(baseNote, showReactionDetail, wantsToSeeReactions, accountViewModel)
|
||||||
if (showReactionDetail) {
|
|
||||||
Row(
|
|
||||||
verticalAlignment = CenterVertically,
|
|
||||||
modifier = Modifier
|
|
||||||
.width(65.dp)
|
|
||||||
.padding(start = 31.dp),
|
|
||||||
horizontalArrangement = Arrangement.Start
|
|
||||||
) {
|
|
||||||
ExpandButton(baseNote, wantsToSeeReactions)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Row(verticalAlignment = CenterVertically, modifier = remember { Modifier.weight(1f) }) {
|
|
||||||
ReplyReactionWithDialog(accountViewModel, nav, baseNote, grayTint)
|
|
||||||
}
|
|
||||||
Row(verticalAlignment = CenterVertically, modifier = remember { Modifier.weight(1f) }) {
|
|
||||||
BoostWithDialog(accountViewModel, nav, baseNote, grayTint)
|
|
||||||
}
|
|
||||||
Row(verticalAlignment = CenterVertically, modifier = remember { Modifier.weight(1f) }) {
|
|
||||||
LikeReaction(baseNote, grayTint, accountViewModel)
|
|
||||||
}
|
|
||||||
Row(verticalAlignment = CenterVertically, modifier = remember { Modifier.weight(1f) }) {
|
|
||||||
ZapReaction(baseNote, grayTint, accountViewModel)
|
|
||||||
}
|
|
||||||
Row(verticalAlignment = CenterVertically, modifier = remember { Modifier.weight(1f) }) {
|
|
||||||
ViewCountReaction(baseNote.idHex, grayTint)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (zapraiserAmount != null && zapraiserAmount > 0) {
|
|
||||||
Spacer(modifier = Modifier.height(4.dp))
|
|
||||||
Row(
|
|
||||||
verticalAlignment = CenterVertically,
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(start = if (showReactionDetail) 75.dp else 0.dp),
|
|
||||||
horizontalArrangement = Arrangement.Start
|
|
||||||
) {
|
|
||||||
RenderZapRaiser(baseNote, zapraiserAmount, wantsToSeeReactions.value, accountViewModel)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (showReactionDetail && wantsToSeeReactions.value) {
|
if (showReactionDetail && wantsToSeeReactions.value) {
|
||||||
ReactionDetailGallery(baseNote, nav, accountViewModel)
|
ReactionDetailGallery(baseNote, nav, accountViewModel)
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(7.dp))
|
Spacer(modifier = HalfDoubleVertSpacer)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun InnerReactionRow(
|
||||||
|
baseNote: Note,
|
||||||
|
showReactionDetail: Boolean,
|
||||||
|
wantsToSeeReactions: MutableState<Boolean>,
|
||||||
|
accountViewModel: AccountViewModel,
|
||||||
|
nav: (String) -> Unit
|
||||||
|
) {
|
||||||
|
Row(verticalAlignment = CenterVertically, modifier = ReactionRowHeight) {
|
||||||
|
if (showReactionDetail) {
|
||||||
|
Column(
|
||||||
|
verticalArrangement = Arrangement.Center,
|
||||||
|
modifier = ReactionRowExpandButton
|
||||||
|
) {
|
||||||
|
Row(verticalAlignment = CenterVertically) {
|
||||||
|
ExpandButton(baseNote, wantsToSeeReactions)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Column(
|
||||||
|
verticalArrangement = Arrangement.Center,
|
||||||
|
modifier = remember { Modifier.weight(1f) }
|
||||||
|
) {
|
||||||
|
Row(verticalAlignment = CenterVertically) {
|
||||||
|
ReplyReactionWithDialog(baseNote, MaterialTheme.colors.placeholderText, accountViewModel, nav)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Column(
|
||||||
|
verticalArrangement = Arrangement.Center,
|
||||||
|
modifier = remember { Modifier.weight(1f) }
|
||||||
|
) {
|
||||||
|
Row(verticalAlignment = CenterVertically) {
|
||||||
|
BoostWithDialog(baseNote, MaterialTheme.colors.placeholderText, accountViewModel, nav)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Column(
|
||||||
|
verticalArrangement = Arrangement.Center,
|
||||||
|
modifier = remember { Modifier.weight(1f) }
|
||||||
|
) {
|
||||||
|
Row(verticalAlignment = CenterVertically) {
|
||||||
|
LikeReaction(baseNote, MaterialTheme.colors.placeholderText, accountViewModel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Column(
|
||||||
|
verticalArrangement = Arrangement.Center,
|
||||||
|
modifier = remember { Modifier.weight(1f) }
|
||||||
|
) {
|
||||||
|
Row(verticalAlignment = CenterVertically) {
|
||||||
|
ZapReaction(baseNote, MaterialTheme.colors.placeholderText, accountViewModel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Column(
|
||||||
|
verticalArrangement = Arrangement.Center,
|
||||||
|
modifier = remember { Modifier.weight(1f) }
|
||||||
|
) {
|
||||||
|
Row(verticalAlignment = CenterVertically) {
|
||||||
|
ViewCountReaction(baseNote.idHex, MaterialTheme.colors.placeholderText)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun LoadAndDisplayZapraiser(
|
||||||
|
baseNote: Note,
|
||||||
|
showReactionDetail: Boolean,
|
||||||
|
wantsToSeeReactions: MutableState<Boolean>,
|
||||||
|
accountViewModel: AccountViewModel
|
||||||
|
) {
|
||||||
|
val zapraiserAmount by remember {
|
||||||
|
derivedStateOf {
|
||||||
|
baseNote.event?.zapraiserAmount() ?: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (zapraiserAmount > 0) {
|
||||||
|
Spacer(modifier = remember { Modifier.height(4.dp) })
|
||||||
|
Row(
|
||||||
|
verticalAlignment = CenterVertically,
|
||||||
|
modifier = remember {
|
||||||
|
Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(start = if (showReactionDetail) 75.dp else 0.dp)
|
||||||
|
},
|
||||||
|
horizontalArrangement = Arrangement.Start
|
||||||
|
) {
|
||||||
|
RenderZapRaiser(baseNote, zapraiserAmount, wantsToSeeReactions.value, accountViewModel)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -165,11 +229,17 @@ fun RenderZapRaiser(baseNote: Note, zapraiserAmount: Long, details: Boolean, acc
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Math.abs(zapraiserProgress - percentage) > 0.001) {
|
if (Math.abs(zapraiserProgress - percentage) > 0.001) {
|
||||||
zapraiserProgress = percentage
|
val newZapraiserProgress = percentage
|
||||||
if (percentage > 0.99) {
|
val newZapraiserLeft = if (percentage > 0.99) {
|
||||||
zapraiserLeft = "0"
|
"0"
|
||||||
} else {
|
} else {
|
||||||
zapraiserLeft = showAmount((zapraiserAmount * (1 - percentage)).toBigDecimal())
|
showAmount((zapraiserAmount * (1 - percentage)).toBigDecimal())
|
||||||
|
}
|
||||||
|
if (zapraiserLeft != newZapraiserLeft) {
|
||||||
|
zapraiserLeft = newZapraiserLeft
|
||||||
|
}
|
||||||
|
if (zapraiserProgress != newZapraiserProgress) {
|
||||||
|
zapraiserProgress = newZapraiserProgress
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -177,34 +247,34 @@ fun RenderZapRaiser(baseNote: Note, zapraiserAmount: Long, details: Boolean, acc
|
|||||||
}
|
}
|
||||||
|
|
||||||
val color = if (zapraiserProgress > 0.99) {
|
val color = if (zapraiserProgress > 0.99) {
|
||||||
Color.Green.copy(alpha = 0.32f)
|
DarkerGreen
|
||||||
} else {
|
} else {
|
||||||
MaterialTheme.colors.mediumImportanceLink
|
MaterialTheme.colors.mediumImportanceLink
|
||||||
}
|
}
|
||||||
|
|
||||||
Box(
|
Box(ReactionRowZapraiserSize) {
|
||||||
Modifier.padding(end = 10.dp).fillMaxWidth()
|
|
||||||
) {
|
|
||||||
LinearProgressIndicator(
|
LinearProgressIndicator(
|
||||||
modifier = Modifier.matchParentSize(),
|
modifier = ReactionRowZapraiserSize,
|
||||||
color = color,
|
color = color,
|
||||||
progress = zapraiserProgress
|
progress = zapraiserProgress
|
||||||
)
|
)
|
||||||
|
|
||||||
Row(
|
if (details) {
|
||||||
verticalAlignment = CenterVertically,
|
Row(
|
||||||
modifier = Modifier.padding(2.dp)
|
verticalAlignment = CenterVertically,
|
||||||
) {
|
modifier = TinyBorders
|
||||||
if (details) {
|
) {
|
||||||
val totalPercentage = remember(zapraiserProgress) {
|
val totalPercentage by remember(zapraiserProgress) {
|
||||||
"${(zapraiserProgress * 100).roundToInt()}%"
|
derivedStateOf {
|
||||||
|
"${(zapraiserProgress * 100).roundToInt()}%"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(id = R.string.sats_to_complete, totalPercentage, zapraiserLeft),
|
text = stringResource(id = R.string.sats_to_complete, totalPercentage, zapraiserLeft),
|
||||||
modifier = Modifier.padding(start = 5.dp, end = 5.dp, top = 2.dp, bottom = 2.dp),
|
modifier = NoSoTinyBorders,
|
||||||
color = MaterialTheme.colors.placeholderText,
|
color = MaterialTheme.colors.placeholderText,
|
||||||
fontSize = 14.sp
|
fontSize = Font14SP
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -226,27 +296,32 @@ private fun ExpandButton(baseNote: Note, wantsToSeeReactions: MutableState<Boole
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (hasReactions) {
|
if (hasReactions) {
|
||||||
IconButton(
|
RenderShowIndividualReactionsButton(wantsToSeeReactions)
|
||||||
onClick = {
|
}
|
||||||
wantsToSeeReactions.value = !wantsToSeeReactions.value
|
}
|
||||||
},
|
|
||||||
modifier = Modifier.size(20.dp)
|
@Composable
|
||||||
) {
|
private fun RenderShowIndividualReactionsButton(wantsToSeeReactions: MutableState<Boolean>) {
|
||||||
if (wantsToSeeReactions.value) {
|
IconButton(
|
||||||
Icon(
|
onClick = {
|
||||||
imageVector = Icons.Default.ExpandLess,
|
wantsToSeeReactions.value = !wantsToSeeReactions.value
|
||||||
null,
|
},
|
||||||
modifier = Modifier.size(22.dp),
|
modifier = Size20Modifier
|
||||||
tint = MaterialTheme.colors.onSurface.copy(alpha = 0.22f)
|
) {
|
||||||
)
|
if (wantsToSeeReactions.value) {
|
||||||
} else {
|
Icon(
|
||||||
Icon(
|
imageVector = Icons.Default.ExpandLess,
|
||||||
imageVector = Icons.Default.ExpandMore,
|
null,
|
||||||
null,
|
modifier = Size22Modifier,
|
||||||
modifier = Modifier.size(22.dp),
|
tint = MaterialTheme.colors.subtleButton
|
||||||
tint = MaterialTheme.colors.onSurface.copy(alpha = 0.22f)
|
)
|
||||||
)
|
} else {
|
||||||
}
|
Icon(
|
||||||
|
imageVector = Icons.Default.ExpandMore,
|
||||||
|
null,
|
||||||
|
modifier = Size22Modifier,
|
||||||
|
tint = MaterialTheme.colors.subtleButton
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -320,10 +395,10 @@ private fun ReactionDetailGallery(
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun BoostWithDialog(
|
private fun BoostWithDialog(
|
||||||
accountViewModel: AccountViewModel,
|
|
||||||
nav: (String) -> Unit,
|
|
||||||
baseNote: Note,
|
baseNote: Note,
|
||||||
grayTint: Color
|
grayTint: Color,
|
||||||
|
accountViewModel: AccountViewModel,
|
||||||
|
nav: (String) -> Unit
|
||||||
) {
|
) {
|
||||||
var wantsToQuote by remember {
|
var wantsToQuote by remember {
|
||||||
mutableStateOf<Note?>(null)
|
mutableStateOf<Note?>(null)
|
||||||
@@ -340,10 +415,10 @@ private fun BoostWithDialog(
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun ReplyReactionWithDialog(
|
private fun ReplyReactionWithDialog(
|
||||||
accountViewModel: AccountViewModel,
|
|
||||||
nav: (String) -> Unit,
|
|
||||||
baseNote: Note,
|
baseNote: Note,
|
||||||
grayTint: Color
|
grayTint: Color,
|
||||||
|
accountViewModel: AccountViewModel,
|
||||||
|
nav: (String) -> Unit
|
||||||
) {
|
) {
|
||||||
var wantsToReplyTo by remember {
|
var wantsToReplyTo by remember {
|
||||||
mutableStateOf<Note?>(null)
|
mutableStateOf<Note?>(null)
|
||||||
@@ -364,7 +439,7 @@ fun ReplyReaction(
|
|||||||
grayTint: Color,
|
grayTint: Color,
|
||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
showCounter: Boolean = true,
|
showCounter: Boolean = true,
|
||||||
iconSize: Dp = 18.dp,
|
iconSize: Dp = Size18dp,
|
||||||
onPress: () -> Unit
|
onPress: () -> Unit
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
@@ -418,7 +493,7 @@ fun ReplyCounter(baseNote: Note, textColor: Color) {
|
|||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = replyCount,
|
text = replyCount,
|
||||||
fontSize = 14.sp,
|
fontSize = Font14SP,
|
||||||
color = textColor
|
color = textColor
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -462,33 +537,33 @@ fun BoostReaction(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
if (wantsToBoost) {
|
BoostIcon(baseNote, iconSize, grayTint, accountViewModel)
|
||||||
BoostTypeChoicePopup(
|
}
|
||||||
baseNote,
|
|
||||||
accountViewModel,
|
|
||||||
onDismiss = {
|
|
||||||
wantsToBoost = false
|
|
||||||
},
|
|
||||||
onQuote = {
|
|
||||||
wantsToBoost = false
|
|
||||||
onQuotePress()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
BoostIcon(baseNote, iconSize, grayTint, accountViewModel.userProfile())
|
if (wantsToBoost) {
|
||||||
|
BoostTypeChoicePopup(
|
||||||
|
baseNote,
|
||||||
|
accountViewModel,
|
||||||
|
onDismiss = {
|
||||||
|
wantsToBoost = false
|
||||||
|
},
|
||||||
|
onQuote = {
|
||||||
|
wantsToBoost = false
|
||||||
|
onQuotePress()
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
BoostText(baseNote, grayTint)
|
BoostText(baseNote, grayTint)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun BoostIcon(baseNote: Note, iconSize: Dp = 20.dp, grayTint: Color, loggedIn: User) {
|
fun BoostIcon(baseNote: Note, iconSize: Dp = Size20dp, grayTint: Color, accountViewModel: AccountViewModel) {
|
||||||
val boostsState by baseNote.live().boosts.observeAsState()
|
val boostsState by baseNote.live().boosts.observeAsState()
|
||||||
|
|
||||||
val iconTint by remember(boostsState) {
|
val iconTint by remember(boostsState) {
|
||||||
derivedStateOf {
|
derivedStateOf {
|
||||||
if (boostsState?.note?.isBoostedBy(loggedIn) == true) Color.Unspecified else grayTint
|
if (boostsState?.note?.isBoostedBy(accountViewModel.userProfile()) == true) Color.Unspecified else grayTint
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -514,8 +589,8 @@ fun BoostText(baseNote: Note, grayTint: Color) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
boostCount,
|
text = boostCount,
|
||||||
fontSize = 14.sp,
|
fontSize = Font14SP,
|
||||||
color = grayTint
|
color = grayTint
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -528,7 +603,7 @@ fun LikeReaction(
|
|||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
iconSize: Dp = 20.dp,
|
iconSize: Dp = 20.dp,
|
||||||
heartSize: Dp = 16.dp,
|
heartSize: Dp = 16.dp,
|
||||||
iconFontSize: TextUnit = 14.sp
|
iconFontSize: TextUnit = Font14SP
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
@@ -540,13 +615,12 @@ fun LikeReaction(
|
|||||||
var wantsToChangeReactionSymbol by remember { mutableStateOf(false) }
|
var wantsToChangeReactionSymbol by remember { mutableStateOf(false) }
|
||||||
var wantsToReact by remember { mutableStateOf(false) }
|
var wantsToReact by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
Row(
|
Box(
|
||||||
verticalAlignment = CenterVertically,
|
contentAlignment = Center,
|
||||||
horizontalArrangement = Arrangement.Center,
|
|
||||||
modifier = iconButtonModifier.combinedClickable(
|
modifier = iconButtonModifier.combinedClickable(
|
||||||
role = Role.Button,
|
role = Role.Button,
|
||||||
interactionSource = remember { MutableInteractionSource() },
|
interactionSource = remember { MutableInteractionSource() },
|
||||||
indication = rememberRipple(bounded = false, radius = 24.dp),
|
indication = rememberRipple(bounded = false, radius = Size24dp),
|
||||||
onClick = {
|
onClick = {
|
||||||
likeClick(
|
likeClick(
|
||||||
baseNote,
|
baseNote,
|
||||||
@@ -563,37 +637,37 @@ fun LikeReaction(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
LikeIcon(baseNote, iconFontSize, heartSize, grayTint, accountViewModel.userProfile())
|
LikeIcon(baseNote, iconFontSize, heartSize, grayTint, accountViewModel)
|
||||||
|
|
||||||
if (wantsToChangeReactionSymbol) {
|
|
||||||
UpdateReactionTypeDialog({ wantsToChangeReactionSymbol = false }, accountViewModel = accountViewModel)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wantsToReact) {
|
|
||||||
ReactionChoicePopup(
|
|
||||||
baseNote,
|
|
||||||
accountViewModel,
|
|
||||||
onDismiss = {
|
|
||||||
wantsToReact = false
|
|
||||||
},
|
|
||||||
onChangeAmount = {
|
|
||||||
wantsToReact = false
|
|
||||||
wantsToChangeReactionSymbol = true
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LikeText(baseNote, grayTint)
|
LikeText(baseNote, grayTint)
|
||||||
|
|
||||||
|
if (wantsToChangeReactionSymbol) {
|
||||||
|
UpdateReactionTypeDialog({ wantsToChangeReactionSymbol = false }, accountViewModel = accountViewModel)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wantsToReact) {
|
||||||
|
ReactionChoicePopup(
|
||||||
|
baseNote,
|
||||||
|
accountViewModel,
|
||||||
|
onDismiss = {
|
||||||
|
wantsToReact = false
|
||||||
|
},
|
||||||
|
onChangeAmount = {
|
||||||
|
wantsToReact = false
|
||||||
|
wantsToChangeReactionSymbol = true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun LikeIcon(
|
fun LikeIcon(
|
||||||
baseNote: Note,
|
baseNote: Note,
|
||||||
iconFontSize: TextUnit = 14.sp,
|
iconFontSize: TextUnit = Font14SP,
|
||||||
iconSize: Dp = 20.dp,
|
iconSize: Dp = Size20dp,
|
||||||
grayTint: Color,
|
grayTint: Color,
|
||||||
loggedIn: User
|
accountViewModel: AccountViewModel
|
||||||
) {
|
) {
|
||||||
val reactionsState by baseNote.live().reactions.observeAsState()
|
val reactionsState by baseNote.live().reactions.observeAsState()
|
||||||
|
|
||||||
@@ -603,37 +677,59 @@ fun LikeIcon(
|
|||||||
|
|
||||||
LaunchedEffect(key1 = reactionsState) {
|
LaunchedEffect(key1 = reactionsState) {
|
||||||
launch(Dispatchers.Default) {
|
launch(Dispatchers.Default) {
|
||||||
val newReactionType = reactionsState?.note?.isReactedBy(loggedIn)
|
val newReactionType = reactionsState?.note?.isReactedBy(accountViewModel.userProfile())?.take(2)
|
||||||
if (reactionType != newReactionType) {
|
if (reactionType != newReactionType) {
|
||||||
reactionType = newReactionType?.take(2)
|
reactionType = newReactionType
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (reactionType != null) {
|
||||||
|
RenderReactionType(reactionType!!, iconSize, iconFontSize)
|
||||||
|
} else {
|
||||||
|
RenderLikeIcon(iconSize, grayTint)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun RenderLikeIcon(
|
||||||
|
iconSize: Dp = Size20dp,
|
||||||
|
grayTint: Color
|
||||||
|
) {
|
||||||
val iconModifier = remember {
|
val iconModifier = remember {
|
||||||
Modifier.size(iconSize)
|
Modifier.size(iconSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reactionType != null) {
|
Icon(
|
||||||
when (reactionType) {
|
painter = painterResource(R.drawable.ic_like),
|
||||||
"+" -> {
|
null,
|
||||||
Icon(
|
modifier = iconModifier,
|
||||||
painter = painterResource(R.drawable.ic_liked),
|
tint = grayTint
|
||||||
null,
|
)
|
||||||
modifier = iconModifier,
|
}
|
||||||
tint = Color.Unspecified
|
|
||||||
)
|
@Composable
|
||||||
}
|
private fun RenderReactionType(
|
||||||
"-" -> Text(text = "\uD83D\uDC4E", fontSize = iconFontSize)
|
reactionType: String,
|
||||||
else -> Text(text = reactionType!!, fontSize = iconFontSize)
|
iconSize: Dp = Size20dp,
|
||||||
|
iconFontSize: TextUnit
|
||||||
|
) {
|
||||||
|
val iconModifier = remember {
|
||||||
|
Modifier.size(iconSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
when (reactionType) {
|
||||||
|
"+" -> {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(R.drawable.ic_liked),
|
||||||
|
null,
|
||||||
|
modifier = iconModifier,
|
||||||
|
tint = Color.Unspecified
|
||||||
|
)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
Icon(
|
"-" -> Text(text = "\uD83D\uDC4E", fontSize = iconFontSize)
|
||||||
painter = painterResource(R.drawable.ic_like),
|
else -> Text(text = reactionType, fontSize = iconFontSize)
|
||||||
null,
|
|
||||||
modifier = iconModifier,
|
|
||||||
tint = grayTint
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -655,8 +751,8 @@ fun LikeText(baseNote: Note, grayTint: Color) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
reactionsCount,
|
text = reactionsCount,
|
||||||
fontSize = 14.sp,
|
fontSize = Font14SP,
|
||||||
color = grayTint
|
color = grayTint
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -727,7 +823,7 @@ fun ZapReaction(
|
|||||||
.combinedClickable(
|
.combinedClickable(
|
||||||
role = Role.Button,
|
role = Role.Button,
|
||||||
interactionSource = remember { MutableInteractionSource() },
|
interactionSource = remember { MutableInteractionSource() },
|
||||||
indication = rememberRipple(bounded = false, radius = 24.dp),
|
indication = rememberRipple(bounded = false, radius = Size24dp),
|
||||||
onClick = {
|
onClick = {
|
||||||
zapClick(
|
zapClick(
|
||||||
baseNote,
|
baseNote,
|
||||||
@@ -930,8 +1026,8 @@ private fun ZapAmountText(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
zapAmountTxt,
|
text = zapAmountTxt,
|
||||||
fontSize = 14.sp,
|
fontSize = Font14SP,
|
||||||
color = grayTint
|
color = grayTint
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -940,17 +1036,38 @@ private fun ZapAmountText(
|
|||||||
fun ViewCountReaction(
|
fun ViewCountReaction(
|
||||||
idHex: String,
|
idHex: String,
|
||||||
grayTint: Color,
|
grayTint: Color,
|
||||||
iconSize: Dp = 20.dp,
|
barChartSize: Dp = Size19dp,
|
||||||
barChartSize: Dp = 19.dp,
|
numberSize: Dp = Size24dp
|
||||||
numberSize: Dp = 24.dp
|
|
||||||
) {
|
) {
|
||||||
val uri = LocalUriHandler.current
|
DrawViewCountIcon(barChartSize, grayTint)
|
||||||
val context = LocalContext.current
|
DrawViewCount(idHex, numberSize, grayTint)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun DrawViewCountIcon(
|
||||||
|
barChartSize: Dp = Size19dp,
|
||||||
|
grayTint: Color
|
||||||
|
) {
|
||||||
val iconButtonModifier = remember {
|
val iconButtonModifier = remember {
|
||||||
Modifier.size(barChartSize)
|
Modifier.size(barChartSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Outlined.BarChart,
|
||||||
|
null,
|
||||||
|
modifier = iconButtonModifier,
|
||||||
|
tint = grayTint
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun DrawViewCount(
|
||||||
|
idHex: String,
|
||||||
|
numberSize: Dp = Size24dp,
|
||||||
|
grayTint: Color
|
||||||
|
) {
|
||||||
|
val context = LocalContext.current
|
||||||
|
|
||||||
val iconModifier = remember {
|
val iconModifier = remember {
|
||||||
Modifier.height(numberSize)
|
Modifier.height(numberSize)
|
||||||
}
|
}
|
||||||
@@ -959,34 +1076,18 @@ fun ViewCountReaction(
|
|||||||
ColorFilter.tint(grayTint)
|
ColorFilter.tint(grayTint)
|
||||||
}
|
}
|
||||||
|
|
||||||
IconButton(
|
AsyncImage(
|
||||||
modifier = Modifier.size(iconSize),
|
model = remember(idHex) {
|
||||||
onClick = { uri.openUri("https://counter.amethyst.social/$idHex/") }
|
ImageRequest.Builder(context)
|
||||||
) {
|
.data("https://counter.amethyst.social/$idHex.svg?label=+&color=00000000")
|
||||||
Icon(
|
.diskCachePolicy(CachePolicy.DISABLED)
|
||||||
imageVector = Icons.Outlined.BarChart,
|
.memoryCachePolicy(CachePolicy.ENABLED)
|
||||||
null,
|
.build()
|
||||||
modifier = iconButtonModifier,
|
},
|
||||||
tint = grayTint
|
contentDescription = stringResource(R.string.view_count),
|
||||||
)
|
modifier = iconModifier,
|
||||||
}
|
colorFilter = colorFilter
|
||||||
|
)
|
||||||
val request = remember {
|
|
||||||
ImageRequest.Builder(context)
|
|
||||||
.data("https://counter.amethyst.social/$idHex.svg?label=+&color=00000000")
|
|
||||||
.diskCachePolicy(CachePolicy.DISABLED)
|
|
||||||
.memoryCachePolicy(CachePolicy.ENABLED)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
Row {
|
|
||||||
AsyncImage(
|
|
||||||
model = request,
|
|
||||||
contentDescription = stringResource(R.string.view_count),
|
|
||||||
modifier = iconModifier,
|
|
||||||
colorFilter = colorFilter
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalLayoutApi::class)
|
@OptIn(ExperimentalLayoutApi::class)
|
||||||
|
|||||||
@@ -60,7 +60,6 @@ import androidx.compose.ui.text.input.TextFieldValue
|
|||||||
import androidx.compose.ui.text.input.VisualTransformation
|
import androidx.compose.ui.text.input.VisualTransformation
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
|
||||||
import androidx.compose.ui.window.Dialog
|
import androidx.compose.ui.window.Dialog
|
||||||
import androidx.compose.ui.window.DialogProperties
|
import androidx.compose.ui.window.DialogProperties
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
@@ -78,6 +77,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
|||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.TextSpinner
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.TextSpinner
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.getFragmentActivity
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.getFragmentActivity
|
||||||
import com.vitorpamplona.amethyst.ui.theme.ButtonBorder
|
import com.vitorpamplona.amethyst.ui.theme.ButtonBorder
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.Font14SP
|
||||||
import com.vitorpamplona.amethyst.ui.theme.placeholderText
|
import com.vitorpamplona.amethyst.ui.theme.placeholderText
|
||||||
import kotlinx.collections.immutable.toImmutableList
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
@@ -415,7 +415,7 @@ fun UpdateZapAmountDialog(onClose: () -> Unit, nip47uri: String? = null, account
|
|||||||
stringResource(id = R.string.wallet_connect_service_explainer),
|
stringResource(id = R.string.wallet_connect_service_explainer),
|
||||||
Modifier.weight(1f),
|
Modifier.weight(1f),
|
||||||
color = MaterialTheme.colors.placeholderText,
|
color = MaterialTheme.colors.placeholderText,
|
||||||
fontSize = 14.sp
|
fontSize = Font14SP
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ open class CardFeedViewModel(val localFilter: FeedFilter<Note>) : ViewModel() {
|
|||||||
val updatedCards = (oldNotesState.feed.value + newCards)
|
val updatedCards = (oldNotesState.feed.value + newCards)
|
||||||
.sortedWith(compareBy({ it.createdAt() }, { it.id() }))
|
.sortedWith(compareBy({ it.createdAt() }, { it.id() }))
|
||||||
.reversed()
|
.reversed()
|
||||||
.take(1000)
|
.take(localFilter.limit())
|
||||||
.toImmutableList()
|
.toImmutableList()
|
||||||
|
|
||||||
if (!equalImmutableLists(oldNotesState.feed.value, updatedCards)) {
|
if (!equalImmutableLists(oldNotesState.feed.value, updatedCards)) {
|
||||||
@@ -115,7 +115,7 @@ open class CardFeedViewModel(val localFilter: FeedFilter<Note>) : ViewModel() {
|
|||||||
val cards = convertToCard(notes)
|
val cards = convertToCard(notes)
|
||||||
.sortedWith(compareBy({ it.createdAt() }, { it.id() }))
|
.sortedWith(compareBy({ it.createdAt() }, { it.id() }))
|
||||||
.reversed()
|
.reversed()
|
||||||
.take(1000)
|
.take(localFilter.limit())
|
||||||
.toImmutableList()
|
.toImmutableList()
|
||||||
|
|
||||||
updateFeed(cards)
|
updateFeed(cards)
|
||||||
@@ -255,7 +255,7 @@ open class CardFeedViewModel(val localFilter: FeedFilter<Note>) : ViewModel() {
|
|||||||
val updatedCards = (oldNotesState.feed.value + newCards)
|
val updatedCards = (oldNotesState.feed.value + newCards)
|
||||||
.sortedWith(compareBy({ it.createdAt() }, { it.id() }))
|
.sortedWith(compareBy({ it.createdAt() }, { it.id() }))
|
||||||
.reversed()
|
.reversed()
|
||||||
.take(1000)
|
.take(localFilter.limit())
|
||||||
.toImmutableList()
|
.toImmutableList()
|
||||||
|
|
||||||
if (!equalImmutableLists(oldNotesState.feed.value, updatedCards)) {
|
if (!equalImmutableLists(oldNotesState.feed.value, updatedCards)) {
|
||||||
|
|||||||
@@ -288,7 +288,7 @@ fun NoteMaster(
|
|||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
NoteUsernameDisplay(baseNote, Modifier.weight(1f))
|
NoteUsernameDisplay(baseNote, Modifier.weight(1f))
|
||||||
|
|
||||||
DisplayFollowingHashtagsInPost(noteEvent, accountViewModel, nav)
|
DisplayFollowingHashtagsInPost(baseNote, accountViewModel, nav)
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
timeAgo(note.createdAt(), context = context),
|
timeAgo(note.createdAt(), context = context),
|
||||||
|
|||||||
@@ -364,14 +364,18 @@ fun EditFieldRow(
|
|||||||
onSendNewMessage()
|
onSendNewMessage()
|
||||||
},
|
},
|
||||||
isActive = channelScreenModel.message.text.isNotBlank() && !channelScreenModel.isUploadingImage,
|
isActive = channelScreenModel.message.text.isNotBlank() && !channelScreenModel.isUploadingImage,
|
||||||
modifier = Modifier.height(32.dp).padding(end = 10.dp)
|
modifier = Modifier
|
||||||
|
.height(32.dp)
|
||||||
|
.padding(end = 10.dp)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
leadingIcon = {
|
leadingIcon = {
|
||||||
UploadFromGallery(
|
UploadFromGallery(
|
||||||
isUploading = channelScreenModel.isUploadingImage,
|
isUploading = channelScreenModel.isUploadingImage,
|
||||||
tint = MaterialTheme.colors.placeholderText,
|
tint = MaterialTheme.colors.placeholderText,
|
||||||
modifier = Modifier.height(32.dp).padding(start = 2.dp)
|
modifier = Modifier
|
||||||
|
.height(32.dp)
|
||||||
|
.padding(start = 2.dp)
|
||||||
) {
|
) {
|
||||||
val fileServer = if (isPrivate) {
|
val fileServer = if (isPrivate) {
|
||||||
// TODO: Make private servers
|
// TODO: Make private servers
|
||||||
@@ -478,6 +482,31 @@ fun MyTextField(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ChannelHeader(
|
||||||
|
channelNote: Note,
|
||||||
|
showVideo: Boolean,
|
||||||
|
showBottomDiviser: Boolean,
|
||||||
|
modifier: Modifier = StdPadding,
|
||||||
|
accountViewModel: AccountViewModel,
|
||||||
|
nav: (String) -> Unit
|
||||||
|
) {
|
||||||
|
val channelHex by remember {
|
||||||
|
derivedStateOf {
|
||||||
|
channelNote.channelHex()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
channelHex?.let {
|
||||||
|
ChannelHeader(
|
||||||
|
channelHex = it,
|
||||||
|
showVideo = showVideo,
|
||||||
|
showBottomDiviser = showBottomDiviser,
|
||||||
|
accountViewModel = accountViewModel,
|
||||||
|
nav = nav
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ChannelHeader(
|
fun ChannelHeader(
|
||||||
channelHex: String,
|
channelHex: String,
|
||||||
|
|||||||
@@ -397,7 +397,7 @@ fun ReactionsColumn(baseNote: Note, accountViewModel: AccountViewModel, nav: (St
|
|||||||
}*/
|
}*/
|
||||||
LikeReaction(baseNote, grayTint = MaterialTheme.colors.onBackground, accountViewModel, iconSize = 40.dp, heartSize = Size35dp, 28.sp)
|
LikeReaction(baseNote, grayTint = MaterialTheme.colors.onBackground, accountViewModel, iconSize = 40.dp, heartSize = Size35dp, 28.sp)
|
||||||
ZapReaction(baseNote, grayTint = MaterialTheme.colors.onBackground, accountViewModel, iconSize = 40.dp, animationSize = Size35dp)
|
ZapReaction(baseNote, grayTint = MaterialTheme.colors.onBackground, accountViewModel, iconSize = 40.dp, animationSize = Size35dp)
|
||||||
ViewCountReaction(baseNote.idHex, grayTint = MaterialTheme.colors.onBackground, iconSize = 40.dp, barChartSize = 39.dp)
|
ViewCountReaction(baseNote.idHex, grayTint = MaterialTheme.colors.onBackground, barChartSize = 39.dp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,11 +35,11 @@ import androidx.compose.ui.text.input.*
|
|||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.text.style.TextDecoration
|
import androidx.compose.ui.text.style.TextDecoration
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
|
||||||
import com.vitorpamplona.amethyst.R
|
import com.vitorpamplona.amethyst.R
|
||||||
import com.vitorpamplona.amethyst.ui.qrcode.SimpleQrCodeScanner
|
import com.vitorpamplona.amethyst.ui.qrcode.SimpleQrCodeScanner
|
||||||
import com.vitorpamplona.amethyst.ui.screen.AccountStateViewModel
|
import com.vitorpamplona.amethyst.ui.screen.AccountStateViewModel
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.ConnectOrbotDialog
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.ConnectOrbotDialog
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.Font14SP
|
||||||
import com.vitorpamplona.amethyst.ui.theme.Size35dp
|
import com.vitorpamplona.amethyst.ui.theme.Size35dp
|
||||||
import com.vitorpamplona.amethyst.ui.theme.placeholderText
|
import com.vitorpamplona.amethyst.ui.theme.placeholderText
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@@ -305,7 +305,7 @@ fun LoginPage(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
style = TextStyle(
|
style = TextStyle(
|
||||||
fontSize = 14.sp,
|
fontSize = Font14SP,
|
||||||
textDecoration = TextDecoration.Underline,
|
textDecoration = TextDecoration.Underline,
|
||||||
color = MaterialTheme.colors.primary,
|
color = MaterialTheme.colors.primary,
|
||||||
textAlign = TextAlign.Center
|
textAlign = TextAlign.Center
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ val Nip05 = Color(0xFF01BAFF)
|
|||||||
val FollowsFollow = Color.Yellow
|
val FollowsFollow = Color.Yellow
|
||||||
val NIP05Verified = Color.Blue
|
val NIP05Verified = Color.Blue
|
||||||
|
|
||||||
|
val DarkerGreen = Color.Green.copy(alpha = 0.32f)
|
||||||
|
|
||||||
val WarningColor = Color(0xFFC62828)
|
val WarningColor = Color(0xFFC62828)
|
||||||
|
|
||||||
val RelayIconFilter = ColorFilter.colorMatrix(ColorMatrix().apply { setToSaturation(0.5f) })
|
val RelayIconFilter = ColorFilter.colorMatrix(ColorMatrix().apply { setToSaturation(0.5f) })
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package com.vitorpamplona.amethyst.ui.theme
|
package com.vitorpamplona.amethyst.ui.theme
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.defaultMinSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
@@ -23,17 +25,46 @@ val ChatBubbleShapeMe = RoundedCornerShape(15.dp, 15.dp, 3.dp, 15.dp)
|
|||||||
val ChatBubbleShapeThem = RoundedCornerShape(3.dp, 15.dp, 15.dp, 15.dp)
|
val ChatBubbleShapeThem = RoundedCornerShape(3.dp, 15.dp, 15.dp, 15.dp)
|
||||||
|
|
||||||
val StdButtonSizeModifier = Modifier.size(20.dp)
|
val StdButtonSizeModifier = Modifier.size(20.dp)
|
||||||
|
|
||||||
|
val HalfVertSpacer = Modifier.height(2.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.height(10.dp)
|
val DoubleVertSpacer = Modifier.height(10.dp)
|
||||||
|
|
||||||
|
val HalfDoubleVertSpacer = Modifier.height(7.dp)
|
||||||
|
|
||||||
val Size13dp = 13.dp
|
val Size13dp = 13.dp
|
||||||
val Size16dp = 16.dp
|
val Size16dp = 16.dp
|
||||||
|
val Size18dp = 18.dp
|
||||||
|
val Size19dp = 19.dp
|
||||||
|
val Size20dp = 20.dp
|
||||||
|
val Size24dp = 24.dp
|
||||||
val Size25dp = 25.dp
|
val Size25dp = 25.dp
|
||||||
|
val Size30dp = 30.dp
|
||||||
val Size35dp = 35.dp
|
val Size35dp = 35.dp
|
||||||
val Size55dp = 55.dp
|
val Size55dp = 55.dp
|
||||||
|
|
||||||
|
val StdStartPadding = Modifier.padding(start = 10.dp)
|
||||||
|
|
||||||
|
val HalfPadding = Modifier.padding(5.dp)
|
||||||
val StdPadding = Modifier.padding(10.dp)
|
val StdPadding = Modifier.padding(10.dp)
|
||||||
|
|
||||||
val Size15Modifier = Modifier.size(15.dp)
|
val Size15Modifier = Modifier.size(15.dp)
|
||||||
|
val Size20Modifier = Modifier.size(20.dp)
|
||||||
|
val Size22Modifier = Modifier.size(22.dp)
|
||||||
|
val Size30Modifier = Modifier.size(30.dp)
|
||||||
|
val Size55Modifier = Modifier.size(55.dp)
|
||||||
|
|
||||||
|
val TinyBorders = Modifier.padding(2.dp)
|
||||||
|
val NoSoTinyBorders = Modifier.padding(start = 5.dp, end = 5.dp, top = 2.dp, bottom = 2.dp)
|
||||||
|
val ReactionRowZapraiserSize = Modifier.defaultMinSize(minHeight = 4.dp).fillMaxWidth()
|
||||||
|
val ReactionRowExpandButton = Modifier.width(65.dp).padding(start = 31.dp)
|
||||||
|
|
||||||
|
val WidthAuthorPictureModifier = Modifier.width(55.dp)
|
||||||
|
|
||||||
|
val DiviserThickness = 0.25.dp
|
||||||
|
|
||||||
|
val ReactionRowHeight = Modifier.padding(start = 22.dp).padding(start = 10.dp)
|
||||||
|
|||||||
@@ -1,17 +1,32 @@
|
|||||||
package com.vitorpamplona.amethyst.ui.theme
|
package com.vitorpamplona.amethyst.ui.theme
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
|
import androidx.compose.foundation.border
|
||||||
import androidx.compose.foundation.isSystemInDarkTheme
|
import androidx.compose.foundation.isSystemInDarkTheme
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.material.Colors
|
import androidx.compose.material.Colors
|
||||||
import androidx.compose.material.MaterialTheme
|
import androidx.compose.material.MaterialTheme
|
||||||
import androidx.compose.material.darkColors
|
import androidx.compose.material.darkColors
|
||||||
import androidx.compose.material.lightColors
|
import androidx.compose.material.lightColors
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.SideEffect
|
import androidx.compose.runtime.SideEffect
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.draw.drawBehind
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.compositeOver
|
import androidx.compose.ui.graphics.compositeOver
|
||||||
import androidx.compose.ui.graphics.toArgb
|
import androidx.compose.ui.graphics.toArgb
|
||||||
import androidx.compose.ui.platform.LocalView
|
import androidx.compose.ui.platform.LocalView
|
||||||
|
import androidx.compose.ui.text.SpanStyle
|
||||||
|
import androidx.compose.ui.text.TextStyle
|
||||||
|
import androidx.compose.ui.text.font.FontFamily
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.halilibo.richtext.ui.RichTextStyle
|
||||||
|
import com.vitorpamplona.amethyst.ui.components.DefaultHeadingStyle
|
||||||
|
import com.vitorpamplona.amethyst.ui.components.DefaultParagraphSpacing
|
||||||
|
import com.vitorpamplona.amethyst.ui.components.richTextDefaults
|
||||||
|
|
||||||
private val DarkColorPalette = darkColors(
|
private val DarkColorPalette = darkColors(
|
||||||
primary = Purple200,
|
primary = Purple200,
|
||||||
@@ -30,9 +45,6 @@ private val LightColorPalette = lightColors(
|
|||||||
private val DarkNewItemBackground = DarkColorPalette.primary.copy(0.12f)
|
private val DarkNewItemBackground = DarkColorPalette.primary.copy(0.12f)
|
||||||
private val LightNewItemBackground = LightColorPalette.primary.copy(0.12f)
|
private val LightNewItemBackground = LightColorPalette.primary.copy(0.12f)
|
||||||
|
|
||||||
private val DarkReplyItemBackground = DarkColorPalette.onSurface.copy(alpha = 0.05f)
|
|
||||||
private val LightReplyItemBackground = LightColorPalette.onSurface.copy(alpha = 0.05f)
|
|
||||||
|
|
||||||
private val DarkSelectedNote = DarkNewItemBackground.compositeOver(DarkColorPalette.background)
|
private val DarkSelectedNote = DarkNewItemBackground.compositeOver(DarkColorPalette.background)
|
||||||
private val LightSelectedNote = LightNewItemBackground.compositeOver(LightColorPalette.background)
|
private val LightSelectedNote = LightNewItemBackground.compositeOver(LightColorPalette.background)
|
||||||
|
|
||||||
@@ -54,9 +66,15 @@ 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)
|
||||||
|
|
||||||
|
private val DarkSubtleButton = DarkColorPalette.onSurface.copy(alpha = 0.22f)
|
||||||
|
private val LightSubtleButton = LightColorPalette.onSurface.copy(alpha = 0.22f)
|
||||||
|
|
||||||
private val DarkSubtleBorder = DarkColorPalette.onSurface.copy(alpha = 0.12f)
|
private val DarkSubtleBorder = DarkColorPalette.onSurface.copy(alpha = 0.12f)
|
||||||
private val LightSubtleBorder = LightColorPalette.onSurface.copy(alpha = 0.12f)
|
private val LightSubtleBorder = LightColorPalette.onSurface.copy(alpha = 0.12f)
|
||||||
|
|
||||||
|
private val DarkReplyItemBackground = DarkColorPalette.onSurface.copy(alpha = 0.05f)
|
||||||
|
private val LightReplyItemBackground = LightColorPalette.onSurface.copy(alpha = 0.05f)
|
||||||
|
|
||||||
private val DarkZapraiserBackground = BitcoinOrange.copy(0.52f).compositeOver(DarkColorPalette.background)
|
private val DarkZapraiserBackground = BitcoinOrange.copy(0.52f).compositeOver(DarkColorPalette.background)
|
||||||
private val LightZapraiserBackground = BitcoinOrange.copy(0.52f).compositeOver(LightColorPalette.background)
|
private val LightZapraiserBackground = BitcoinOrange.copy(0.52f).compositeOver(LightColorPalette.background)
|
||||||
|
|
||||||
@@ -66,6 +84,84 @@ private val LightImageVerifier = Nip05.copy(0.52f).compositeOver(LightColorPalet
|
|||||||
private val DarkOverPictureBackground = DarkColorPalette.background.copy(0.62f)
|
private val DarkOverPictureBackground = DarkColorPalette.background.copy(0.62f)
|
||||||
private val LightOverPictureBackground = LightColorPalette.background.copy(0.62f)
|
private val LightOverPictureBackground = LightColorPalette.background.copy(0.62f)
|
||||||
|
|
||||||
|
val RepostPictureBorderDark = Modifier.border(
|
||||||
|
2.dp,
|
||||||
|
DarkColorPalette.background,
|
||||||
|
CircleShape
|
||||||
|
)
|
||||||
|
|
||||||
|
val RepostPictureBorderLight = Modifier.border(
|
||||||
|
2.dp,
|
||||||
|
LightColorPalette.background,
|
||||||
|
CircleShape
|
||||||
|
)
|
||||||
|
|
||||||
|
val MarkDownStyleOnDark = richTextDefaults.copy(
|
||||||
|
paragraphSpacing = DefaultParagraphSpacing,
|
||||||
|
headingStyle = DefaultHeadingStyle,
|
||||||
|
codeBlockStyle = richTextDefaults.codeBlockStyle?.copy(
|
||||||
|
textStyle = TextStyle(
|
||||||
|
fontFamily = FontFamily.Monospace,
|
||||||
|
fontSize = Font14SP
|
||||||
|
),
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(0.dp)
|
||||||
|
.fillMaxWidth()
|
||||||
|
.clip(shape = QuoteBorder)
|
||||||
|
.border(
|
||||||
|
1.dp,
|
||||||
|
DarkSubtleBorder,
|
||||||
|
QuoteBorder
|
||||||
|
)
|
||||||
|
.drawBehind {
|
||||||
|
drawRect(DarkColorPalette.onSurface.copy(alpha = 0.05f))
|
||||||
|
}
|
||||||
|
),
|
||||||
|
stringStyle = richTextDefaults.stringStyle?.copy(
|
||||||
|
linkStyle = SpanStyle(
|
||||||
|
color = DarkColorPalette.primary
|
||||||
|
),
|
||||||
|
codeStyle = SpanStyle(
|
||||||
|
fontFamily = FontFamily.Monospace,
|
||||||
|
fontSize = Font14SP,
|
||||||
|
background = DarkColorPalette.onSurface.copy(alpha = 0.22f)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
val MarkDownStyleOnLight = richTextDefaults.copy(
|
||||||
|
paragraphSpacing = DefaultParagraphSpacing,
|
||||||
|
headingStyle = DefaultHeadingStyle,
|
||||||
|
codeBlockStyle = richTextDefaults.codeBlockStyle?.copy(
|
||||||
|
textStyle = TextStyle(
|
||||||
|
fontFamily = FontFamily.Monospace,
|
||||||
|
fontSize = Font14SP
|
||||||
|
),
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(0.dp)
|
||||||
|
.fillMaxWidth()
|
||||||
|
.clip(shape = QuoteBorder)
|
||||||
|
.border(
|
||||||
|
1.dp,
|
||||||
|
LightSubtleBorder,
|
||||||
|
QuoteBorder
|
||||||
|
)
|
||||||
|
.drawBehind {
|
||||||
|
drawRect(LightColorPalette.onSurface.copy(alpha = 0.05f))
|
||||||
|
}
|
||||||
|
),
|
||||||
|
stringStyle = richTextDefaults.stringStyle?.copy(
|
||||||
|
linkStyle = SpanStyle(
|
||||||
|
color = LightColorPalette.primary
|
||||||
|
),
|
||||||
|
codeStyle = SpanStyle(
|
||||||
|
fontFamily = FontFamily.Monospace,
|
||||||
|
fontSize = Font14SP,
|
||||||
|
background = LightColorPalette.onSurface.copy(alpha = 0.22f)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
val Colors.newItemBackgroundColor: Color
|
val Colors.newItemBackgroundColor: Color
|
||||||
get() = if (isLight) LightNewItemBackground else DarkNewItemBackground
|
get() = if (isLight) LightNewItemBackground else DarkNewItemBackground
|
||||||
|
|
||||||
@@ -98,12 +194,21 @@ val Colors.grayText: Color
|
|||||||
val Colors.subtleBorder: Color
|
val Colors.subtleBorder: Color
|
||||||
get() = if (isLight) LightSubtleBorder else DarkSubtleBorder
|
get() = if (isLight) LightSubtleBorder else DarkSubtleBorder
|
||||||
|
|
||||||
|
val Colors.subtleButton: Color
|
||||||
|
get() = if (isLight) LightSubtleButton else DarkSubtleButton
|
||||||
|
|
||||||
val Colors.hashVerified: Color
|
val Colors.hashVerified: Color
|
||||||
get() = if (isLight) LightImageVerifier else DarkImageVerifier
|
get() = if (isLight) LightImageVerifier else DarkImageVerifier
|
||||||
|
|
||||||
val Colors.overPictureBackground: Color
|
val Colors.overPictureBackground: Color
|
||||||
get() = if (isLight) LightOverPictureBackground else DarkOverPictureBackground
|
get() = if (isLight) LightOverPictureBackground else DarkOverPictureBackground
|
||||||
|
|
||||||
|
val Colors.markdownStyle: RichTextStyle
|
||||||
|
get() = if (isLight) MarkDownStyleOnLight else MarkDownStyleOnDark
|
||||||
|
|
||||||
|
val Colors.repostProfileBorder: Modifier
|
||||||
|
get() = if (isLight) RepostPictureBorderLight else RepostPictureBorderDark
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun AmethystTheme(darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit) {
|
fun AmethystTheme(darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit) {
|
||||||
val colors = if (darkTheme) {
|
val colors = if (darkTheme) {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import androidx.compose.material.Typography
|
|||||||
import androidx.compose.ui.text.TextStyle
|
import androidx.compose.ui.text.TextStyle
|
||||||
import androidx.compose.ui.text.font.FontFamily
|
import androidx.compose.ui.text.font.FontFamily
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.unit.em
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
|
|
||||||
// Set of Material typography styles to start with
|
// Set of Material typography styles to start with
|
||||||
@@ -17,7 +18,7 @@ val Typography = Typography(
|
|||||||
button = TextStyle(
|
button = TextStyle(
|
||||||
fontFamily = FontFamily.Default,
|
fontFamily = FontFamily.Default,
|
||||||
fontWeight = FontWeight.W500,
|
fontWeight = FontWeight.W500,
|
||||||
fontSize = 14.sp
|
fontSize = Font14SP
|
||||||
),
|
),
|
||||||
caption = TextStyle(
|
caption = TextStyle(
|
||||||
fontFamily = FontFamily.Default,
|
fontFamily = FontFamily.Default,
|
||||||
@@ -26,3 +27,7 @@ val Typography = Typography(
|
|||||||
)
|
)
|
||||||
*/
|
*/
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val Font14SP = 14.sp
|
||||||
|
|
||||||
|
val MarkdownTextStyle = TextStyle(lineHeight = 1.30.em)
|
||||||
|
|||||||
Reference in New Issue
Block a user