Moves LnInvoice, Tags, BechLinks and Previews to LaunchedEffect
This commit is contained in:
@@ -5,10 +5,34 @@ import android.net.Uri
|
|||||||
import androidx.compose.foundation.text.ClickableText
|
import androidx.compose.foundation.text.ClickableText
|
||||||
import androidx.compose.material.LocalTextStyle
|
import androidx.compose.material.LocalTextStyle
|
||||||
import androidx.compose.material.MaterialTheme
|
import androidx.compose.material.MaterialTheme
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.material.Text
|
||||||
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.text.AnnotatedString
|
import androidx.compose.ui.text.AnnotatedString
|
||||||
|
import androidx.compose.ui.text.style.TextDirection
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
|
import com.vitorpamplona.amethyst.service.lnurl.LnWithdrawalUtil
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun MayBeWithdrawal(lnurlWord: String) {
|
||||||
|
var lnWithdrawal by remember { mutableStateOf<String?>(null) }
|
||||||
|
|
||||||
|
LaunchedEffect(key1 = lnurlWord) {
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
lnWithdrawal = LnWithdrawalUtil.findWithdrawal(lnurlWord)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lnWithdrawal?.let {
|
||||||
|
ClickableWithdrawal(withdrawalString = it)
|
||||||
|
}
|
||||||
|
?: Text(
|
||||||
|
text = "$lnurlWord ",
|
||||||
|
style = LocalTextStyle.current.copy(textDirection = TextDirection.Content)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ClickableWithdrawal(withdrawalString: String) {
|
fun ClickableWithdrawal(withdrawalString: String) {
|
||||||
|
|||||||
@@ -9,13 +9,8 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
|||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.Button
|
import androidx.compose.material.*
|
||||||
import androidx.compose.material.ButtonDefaults
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.material.Divider
|
|
||||||
import androidx.compose.material.Icon
|
|
||||||
import androidx.compose.material.MaterialTheme
|
|
||||||
import androidx.compose.material.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
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
|
||||||
@@ -24,22 +19,48 @@ import androidx.compose.ui.platform.LocalContext
|
|||||||
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.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.text.style.TextDirection
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import androidx.core.content.ContextCompat.startActivity
|
import androidx.core.content.ContextCompat.startActivity
|
||||||
import com.vitorpamplona.amethyst.R
|
import com.vitorpamplona.amethyst.R
|
||||||
import com.vitorpamplona.amethyst.service.lnurl.LnInvoiceUtil
|
import com.vitorpamplona.amethyst.service.lnurl.LnInvoiceUtil
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import java.math.BigDecimal
|
||||||
import java.text.NumberFormat
|
import java.text.NumberFormat
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun InvoicePreview(lnInvoice: String) {
|
fun MayBeInvoicePreview(lnbcWord: String) {
|
||||||
val amount = try {
|
var lnInvoice by remember { mutableStateOf<Pair<String, BigDecimal?>?>(null) }
|
||||||
LnInvoiceUtil.getAmountInSats(lnInvoice)
|
|
||||||
|
LaunchedEffect(key1 = lnbcWord) {
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
val myInvoice = LnInvoiceUtil.findInvoice(lnbcWord)
|
||||||
|
if (myInvoice != null) {
|
||||||
|
val myInvoiceAmount = try {
|
||||||
|
LnInvoiceUtil.getAmountInSats(myInvoice)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lnInvoice = Pair(myInvoice, myInvoiceAmount)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lnInvoice?.let {
|
||||||
|
InvoicePreview(it.first, it.second)
|
||||||
|
}
|
||||||
|
?: Text(
|
||||||
|
text = "$lnbcWord ",
|
||||||
|
style = LocalTextStyle.current.copy(textDirection = TextDirection.Content)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun InvoicePreview(lnInvoice: String, amount: BigDecimal?) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package com.vitorpamplona.amethyst.ui.components
|
|||||||
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.util.Patterns
|
import android.util.Patterns
|
||||||
import androidx.compose.animation.animateContentSize
|
|
||||||
import androidx.compose.foundation.background
|
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.*
|
||||||
@@ -14,7 +13,7 @@ import androidx.compose.material.Icon
|
|||||||
import androidx.compose.material.LocalTextStyle
|
import androidx.compose.material.LocalTextStyle
|
||||||
import androidx.compose.material.MaterialTheme
|
import androidx.compose.material.MaterialTheme
|
||||||
import androidx.compose.material.Text
|
import androidx.compose.material.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.*
|
||||||
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
|
||||||
@@ -34,12 +33,15 @@ import com.halilibo.richtext.ui.RichTextStyle
|
|||||||
import com.halilibo.richtext.ui.material.MaterialRichText
|
import com.halilibo.richtext.ui.material.MaterialRichText
|
||||||
import com.halilibo.richtext.ui.resolveDefaults
|
import com.halilibo.richtext.ui.resolveDefaults
|
||||||
import com.vitorpamplona.amethyst.model.LocalCache
|
import com.vitorpamplona.amethyst.model.LocalCache
|
||||||
|
import com.vitorpamplona.amethyst.model.Note
|
||||||
|
import com.vitorpamplona.amethyst.model.User
|
||||||
import com.vitorpamplona.amethyst.model.checkForHashtagWithIcon
|
import com.vitorpamplona.amethyst.model.checkForHashtagWithIcon
|
||||||
import com.vitorpamplona.amethyst.service.lnurl.LnInvoiceUtil
|
|
||||||
import com.vitorpamplona.amethyst.service.lnurl.LnWithdrawalUtil
|
import com.vitorpamplona.amethyst.service.lnurl.LnWithdrawalUtil
|
||||||
import com.vitorpamplona.amethyst.service.nip19.Nip19
|
import com.vitorpamplona.amethyst.service.nip19.Nip19
|
||||||
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 kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
import java.net.MalformedURLException
|
import java.net.MalformedURLException
|
||||||
import java.net.URISyntaxException
|
import java.net.URISyntaxException
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
@@ -114,7 +116,7 @@ fun RichTextViewer(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
Column(modifier = modifier.animateContentSize()) {
|
Column(modifier = modifier) {
|
||||||
if (content.startsWith("# ") ||
|
if (content.startsWith("# ") ||
|
||||||
content.contains("##") ||
|
content.contains("##") ||
|
||||||
content.contains("**") ||
|
content.contains("**") ||
|
||||||
@@ -164,25 +166,9 @@ fun RichTextViewer(
|
|||||||
UrlPreview(word, "$word ")
|
UrlPreview(word, "$word ")
|
||||||
}
|
}
|
||||||
} else if (word.startsWith("lnbc", true)) {
|
} else if (word.startsWith("lnbc", true)) {
|
||||||
val lnInvoice = LnInvoiceUtil.findInvoice(word)
|
MayBeInvoicePreview(word)
|
||||||
if (lnInvoice != null) {
|
|
||||||
InvoicePreview(lnInvoice)
|
|
||||||
} else {
|
|
||||||
Text(
|
|
||||||
text = "$word ",
|
|
||||||
style = LocalTextStyle.current.copy(textDirection = TextDirection.Content)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else if (word.startsWith("lnurl", true)) {
|
} else if (word.startsWith("lnurl", true)) {
|
||||||
val lnWithdrawal = LnWithdrawalUtil.findWithdrawal(word)
|
MayBeWithdrawal(word)
|
||||||
if (lnWithdrawal != null) {
|
|
||||||
ClickableWithdrawal(withdrawalString = lnWithdrawal)
|
|
||||||
} else {
|
|
||||||
Text(
|
|
||||||
text = "$word ",
|
|
||||||
style = LocalTextStyle.current.copy(textDirection = TextDirection.Content)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else if (Patterns.EMAIL_ADDRESS.matcher(word).matches()) {
|
} else if (Patterns.EMAIL_ADDRESS.matcher(word).matches()) {
|
||||||
ClickableEmail(word)
|
ClickableEmail(word)
|
||||||
} else if (word.length > 6 && Patterns.PHONE.matcher(word).matches()) {
|
} else if (word.length > 6 && Patterns.PHONE.matcher(word).matches()) {
|
||||||
@@ -304,17 +290,27 @@ fun isBechLink(word: String): Boolean {
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun BechLink(word: String, canPreview: Boolean, backgroundColor: Color, accountViewModel: AccountViewModel, navController: NavController) {
|
fun BechLink(word: String, canPreview: Boolean, backgroundColor: Color, accountViewModel: AccountViewModel, navController: NavController) {
|
||||||
val nip19Route = Nip19.uriToRoute(word)
|
var nip19Route by remember { mutableStateOf<Nip19.Return?>(null) }
|
||||||
|
var baseNotePair by remember { mutableStateOf<Pair<Note, String?>?>(null) }
|
||||||
|
|
||||||
if (nip19Route == null) {
|
LaunchedEffect(key1 = word) {
|
||||||
Text(text = "$word ")
|
withContext(Dispatchers.IO) {
|
||||||
|
Nip19.uriToRoute(word)?.let {
|
||||||
|
if (it.type == Nip19.Type.NOTE || it.type == Nip19.Type.EVENT || it.type == Nip19.Type.ADDRESS) {
|
||||||
|
LocalCache.checkGetOrCreateNote(it.hex)?.let { note ->
|
||||||
|
baseNotePair = Pair(note, it.additionalChars)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (nip19Route.type == Nip19.Type.NOTE || nip19Route.type == Nip19.Type.EVENT || nip19Route.type == Nip19.Type.ADDRESS) {
|
nip19Route = nip19Route
|
||||||
val note = LocalCache.checkGetOrCreateNote(nip19Route.hex)
|
}
|
||||||
if (note != null) {
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (canPreview) {
|
if (canPreview) {
|
||||||
|
baseNotePair?.let {
|
||||||
NoteCompose(
|
NoteCompose(
|
||||||
baseNote = note,
|
baseNote = it.first,
|
||||||
accountViewModel = accountViewModel,
|
accountViewModel = accountViewModel,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(top = 2.dp, bottom = 0.dp, start = 0.dp, end = 0.dp)
|
.padding(top = 2.dp, bottom = 0.dp, start = 0.dp, end = 0.dp)
|
||||||
@@ -330,23 +326,30 @@ fun BechLink(word: String, canPreview: Boolean, backgroundColor: Color, accountV
|
|||||||
isQuotedNote = true,
|
isQuotedNote = true,
|
||||||
navController = navController
|
navController = navController
|
||||||
)
|
)
|
||||||
} else {
|
Text(
|
||||||
ClickableRoute(nip19Route, navController)
|
"${it.second} "
|
||||||
|
)
|
||||||
|
} ?: nip19Route?.let {
|
||||||
|
ClickableRoute(it, navController)
|
||||||
}
|
}
|
||||||
|
?: Text(text = "$word ")
|
||||||
} else {
|
} else {
|
||||||
ClickableRoute(nip19Route, navController)
|
nip19Route?.let {
|
||||||
}
|
ClickableRoute(it, navController)
|
||||||
} else {
|
|
||||||
ClickableRoute(nip19Route, navController)
|
|
||||||
}
|
}
|
||||||
|
?: Text(text = "$word ")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun HashTag(word: String, accountViewModel: AccountViewModel, navController: NavController) {
|
fun HashTag(word: String, accountViewModel: AccountViewModel, navController: NavController) {
|
||||||
|
var tagSuffixPair by remember { mutableStateOf<Pair<String, String?>?>(null) }
|
||||||
|
|
||||||
|
LaunchedEffect(key1 = word) {
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
val hashtagMatcher = hashTagsPattern.matcher(word)
|
val hashtagMatcher = hashTagsPattern.matcher(word)
|
||||||
|
|
||||||
val (tag, suffix) = try {
|
val (myTag, mySuffix) = try {
|
||||||
hashtagMatcher.find()
|
hashtagMatcher.find()
|
||||||
Pair(hashtagMatcher.group(1), hashtagMatcher.group(2))
|
Pair(hashtagMatcher.group(1), hashtagMatcher.group(2))
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
@@ -354,17 +357,23 @@ fun HashTag(word: String, accountViewModel: AccountViewModel, navController: Nav
|
|||||||
Pair(null, null)
|
Pair(null, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tag != null) {
|
if (myTag != null) {
|
||||||
val hashtagIcon = checkForHashtagWithIcon(tag)
|
tagSuffixPair = Pair(myTag, mySuffix)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tagSuffixPair?.let { tagPair ->
|
||||||
|
val hashtagIcon = checkForHashtagWithIcon(tagPair.first)
|
||||||
ClickableText(
|
ClickableText(
|
||||||
text = buildAnnotatedString {
|
text = buildAnnotatedString {
|
||||||
withStyle(
|
withStyle(
|
||||||
LocalTextStyle.current.copy(color = MaterialTheme.colors.primary).toSpanStyle()
|
LocalTextStyle.current.copy(color = MaterialTheme.colors.primary).toSpanStyle()
|
||||||
) {
|
) {
|
||||||
append("#$tag")
|
append("#${tagPair.first}")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onClick = { navController.navigate("Hashtag/$tag") }
|
onClick = { navController.navigate("Hashtag/${tagPair.first}") }
|
||||||
)
|
)
|
||||||
|
|
||||||
if (hashtagIcon != null) {
|
if (hashtagIcon != null) {
|
||||||
@@ -387,7 +396,6 @@ fun HashTag(word: String, accountViewModel: AccountViewModel, navController: Nav
|
|||||||
placeholderVerticalAlign = PlaceholderVerticalAlign.Center
|
placeholderVerticalAlign = PlaceholderVerticalAlign.Center
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
if (hashtagIcon != null) {
|
|
||||||
Icon(
|
Icon(
|
||||||
painter = painterResource(hashtagIcon.icon),
|
painter = painterResource(hashtagIcon.icon),
|
||||||
contentDescription = hashtagIcon.description,
|
contentDescription = hashtagIcon.description,
|
||||||
@@ -395,7 +403,6 @@ fun HashTag(word: String, accountViewModel: AccountViewModel, navController: Nav
|
|||||||
modifier = hashtagIcon.modifier
|
modifier = hashtagIcon.modifier
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -405,17 +412,21 @@ fun HashTag(word: String, accountViewModel: AccountViewModel, navController: Nav
|
|||||||
inlineContent = inlineContent
|
inlineContent = inlineContent
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Text(text = "$suffix ")
|
tagPair.second?.ifBlank { null }?.let {
|
||||||
} else {
|
Text(text = "$it ")
|
||||||
Text(text = "$word ")
|
|
||||||
}
|
}
|
||||||
|
} ?: Text(text = "$word ")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun TagLink(word: String, tags: List<List<String>>, canPreview: Boolean, backgroundColor: Color, accountViewModel: AccountViewModel, navController: NavController) {
|
fun TagLink(word: String, tags: List<List<String>>, canPreview: Boolean, backgroundColor: Color, accountViewModel: AccountViewModel, navController: NavController) {
|
||||||
val matcher = tagIndex.matcher(word)
|
var baseUserPair by remember { mutableStateOf<Pair<User, String?>?>(null) }
|
||||||
|
var baseNotePair by remember { mutableStateOf<Pair<Note, String?>?>(null) }
|
||||||
|
|
||||||
val (index, extraCharacters) = try {
|
LaunchedEffect(key1 = word) {
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
val matcher = tagIndex.matcher(word)
|
||||||
|
val (index, suffix) = try {
|
||||||
matcher.find()
|
matcher.find()
|
||||||
Pair(matcher.group(1)?.toInt(), matcher.group(2) ?: "")
|
Pair(matcher.group(1)?.toInt(), matcher.group(2) ?: "")
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
@@ -423,26 +434,33 @@ fun TagLink(word: String, tags: List<List<String>>, canPreview: Boolean, backgro
|
|||||||
Pair(null, null)
|
Pair(null, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index == null) {
|
if (index != null && index >= 0 && index < tags.size) {
|
||||||
return Text(text = "$word ")
|
val tag = tags[index]
|
||||||
|
|
||||||
|
if (tag.size > 1) {
|
||||||
|
if (tag[0] == "p") {
|
||||||
|
LocalCache.checkGetOrCreateUser(tags[index][1])?.let {
|
||||||
|
baseUserPair = Pair(it, suffix)
|
||||||
|
}
|
||||||
|
} else if (tag[0] == "e" || tag[0] == "a") {
|
||||||
|
LocalCache.checkGetOrCreateNote(tags[index][1])?.let {
|
||||||
|
baseNotePair = Pair(it, suffix)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index >= 0 && index < tags.size) {
|
baseUserPair?.let {
|
||||||
if (tags[index][0] == "p") {
|
ClickableUserTag(it.first, navController)
|
||||||
val baseUser = LocalCache.checkGetOrCreateUser(tags[index][1])
|
Text(text = "${it.second} ")
|
||||||
if (baseUser != null) {
|
|
||||||
ClickableUserTag(baseUser, navController)
|
|
||||||
Text(text = "$extraCharacters ")
|
|
||||||
} else {
|
|
||||||
// if here the tag is not a valid Nostr Hex
|
|
||||||
Text(text = "$word ")
|
|
||||||
}
|
}
|
||||||
} else if (tags[index][0] == "e") {
|
|
||||||
val note = LocalCache.checkGetOrCreateNote(tags[index][1])
|
baseNotePair?.let {
|
||||||
if (note != null) {
|
|
||||||
if (canPreview) {
|
if (canPreview) {
|
||||||
NoteCompose(
|
NoteCompose(
|
||||||
baseNote = note,
|
baseNote = it.first,
|
||||||
accountViewModel = accountViewModel,
|
accountViewModel = accountViewModel,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(top = 2.dp, bottom = 0.dp, start = 0.dp, end = 0.dp)
|
.padding(top = 2.dp, bottom = 0.dp, start = 0.dp, end = 0.dp)
|
||||||
@@ -458,16 +476,16 @@ fun TagLink(word: String, tags: List<List<String>>, canPreview: Boolean, backgro
|
|||||||
isQuotedNote = true,
|
isQuotedNote = true,
|
||||||
navController = navController
|
navController = navController
|
||||||
)
|
)
|
||||||
} else {
|
it.second?.ifBlank { null }?.let {
|
||||||
ClickableNoteTag(note, navController)
|
Text(text = "$it ")
|
||||||
Text(text = "$extraCharacters ")
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// if here the tag is not a valid Nostr Hex
|
ClickableNoteTag(it.first, navController)
|
||||||
Text(text = "$word ")
|
Text(text = "${it.second} ")
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
if (baseNotePair == null && baseUserPair == null) {
|
||||||
Text(text = "$word ")
|
Text(text = "$word ")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ import kotlin.math.ceil
|
|||||||
import kotlin.time.ExperimentalTime
|
import kotlin.time.ExperimentalTime
|
||||||
import kotlin.time.measureTimedValue
|
import kotlin.time.measureTimedValue
|
||||||
|
|
||||||
@OptIn(ExperimentalFoundationApi::class, ExperimentalTime::class)
|
@OptIn(ExperimentalTime::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun NoteCompose(
|
fun NoteCompose(
|
||||||
baseNote: Note,
|
baseNote: Note,
|
||||||
@@ -130,6 +130,19 @@ fun NoteComposeInner(
|
|||||||
|
|
||||||
var moreActionsExpanded by remember { mutableStateOf(false) }
|
var moreActionsExpanded by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
var isAcceptable by remember { mutableStateOf(true) }
|
||||||
|
var canPreview by remember { mutableStateOf(true) }
|
||||||
|
|
||||||
|
LaunchedEffect(key1 = noteReportsState) {
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
canPreview = note?.author === account.userProfile() ||
|
||||||
|
(note?.author?.let { account.userProfile().isFollowingCached(it) } ?: true) ||
|
||||||
|
!noteForReports.hasAnyReports()
|
||||||
|
|
||||||
|
isAcceptable = account.isAcceptable(noteForReports)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val noteEvent = note?.event
|
val noteEvent = note?.event
|
||||||
val baseChannel = note?.channel()
|
val baseChannel = note?.channel()
|
||||||
|
|
||||||
@@ -141,7 +154,7 @@ fun NoteComposeInner(
|
|||||||
),
|
),
|
||||||
isBoostedNote
|
isBoostedNote
|
||||||
)
|
)
|
||||||
} else if (!account.isAcceptable(noteForReports) && !showHiddenNote) {
|
} else if (!isAcceptable && !showHiddenNote) {
|
||||||
if (!account.isHidden(noteForReports.author!!)) {
|
if (!account.isHidden(noteForReports.author!!)) {
|
||||||
HiddenNote(
|
HiddenNote(
|
||||||
account.getRelevantReports(noteForReports),
|
account.getRelevantReports(noteForReports),
|
||||||
@@ -343,11 +356,6 @@ fun NoteComposeInner(
|
|||||||
Spacer(modifier = Modifier.height(3.dp))
|
Spacer(modifier = Modifier.height(3.dp))
|
||||||
|
|
||||||
if (!makeItShort && noteEvent is TextNoteEvent && (note.replyTo != null || noteEvent.mentions().isNotEmpty())) {
|
if (!makeItShort && noteEvent is TextNoteEvent && (note.replyTo != null || noteEvent.mentions().isNotEmpty())) {
|
||||||
val sortedMentions = noteEvent.mentions()
|
|
||||||
.mapNotNull { LocalCache.checkGetOrCreateUser(it) }
|
|
||||||
.toSet()
|
|
||||||
.sortedBy { account.userProfile().isFollowingCached(it) }
|
|
||||||
|
|
||||||
val replyingDirectlyTo = note.replyTo?.lastOrNull()
|
val replyingDirectlyTo = note.replyTo?.lastOrNull()
|
||||||
if (replyingDirectlyTo != null && unPackReply) {
|
if (replyingDirectlyTo != null && unPackReply) {
|
||||||
NoteCompose(
|
NoteCompose(
|
||||||
@@ -369,7 +377,7 @@ fun NoteComposeInner(
|
|||||||
navController = navController
|
navController = navController
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
ReplyInformation(note.replyTo, sortedMentions, account, navController)
|
ReplyInformation(note.replyTo, noteEvent.mentions(), account, navController)
|
||||||
}
|
}
|
||||||
Spacer(modifier = Modifier.height(5.dp))
|
Spacer(modifier = Modifier.height(5.dp))
|
||||||
} else if (!makeItShort && noteEvent is ChannelMessageEvent && (note.replyTo != null || noteEvent.mentions().isNotEmpty())) {
|
} else if (!makeItShort && noteEvent is ChannelMessageEvent && (note.replyTo != null || noteEvent.mentions().isNotEmpty())) {
|
||||||
@@ -501,10 +509,6 @@ fun NoteComposeInner(
|
|||||||
} else {
|
} else {
|
||||||
val eventContent = accountViewModel.decrypt(note)
|
val eventContent = accountViewModel.decrypt(note)
|
||||||
|
|
||||||
val canPreview = note.author == account.userProfile() ||
|
|
||||||
(note.author?.let { account.userProfile().isFollowingCached(it) } ?: true) ||
|
|
||||||
!noteForReports.hasAnyReports()
|
|
||||||
|
|
||||||
if (eventContent != null) {
|
if (eventContent != null) {
|
||||||
if (makeItShort && note.author == account.userProfile()) {
|
if (makeItShort && note.author == account.userProfile()) {
|
||||||
Text(
|
Text(
|
||||||
@@ -524,7 +528,7 @@ fun NoteComposeInner(
|
|||||||
navController
|
navController
|
||||||
)
|
)
|
||||||
|
|
||||||
DisplayUncitedHashtags(noteEvent, eventContent, navController)
|
DisplayUncitedHashtags(noteEvent.hashtags(), eventContent, navController)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (noteEvent is PollNoteEvent) {
|
if (noteEvent is PollNoteEvent) {
|
||||||
@@ -582,11 +586,10 @@ fun DisplayFollowingHashtagsInPost(
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun DisplayUncitedHashtags(
|
fun DisplayUncitedHashtags(
|
||||||
noteEvent: EventInterface,
|
hashtags: List<String>,
|
||||||
eventContent: String,
|
eventContent: String,
|
||||||
navController: NavController
|
navController: NavController
|
||||||
) {
|
) {
|
||||||
val hashtags = noteEvent.hashtags()
|
|
||||||
if (hashtags.isNotEmpty()) {
|
if (hashtags.isNotEmpty()) {
|
||||||
FlowRow(
|
FlowRow(
|
||||||
modifier = Modifier.padding(top = 5.dp)
|
modifier = Modifier.padding(top = 5.dp)
|
||||||
@@ -868,7 +871,11 @@ private fun RelayBadges(baseNote: Note) {
|
|||||||
items(relaysToDisplay.size) {
|
items(relaysToDisplay.size) {
|
||||||
val url = relaysToDisplay[it].removePrefix("wss://").removePrefix("ws://")
|
val url = relaysToDisplay[it].removePrefix("wss://").removePrefix("ws://")
|
||||||
|
|
||||||
Box(Modifier.padding(1.dp).size(15.dp)) {
|
Box(
|
||||||
|
Modifier
|
||||||
|
.padding(1.dp)
|
||||||
|
.size(15.dp)
|
||||||
|
) {
|
||||||
RobohashFallbackAsyncImage(
|
RobohashFallbackAsyncImage(
|
||||||
robot = "https://$url/favicon.ico",
|
robot = "https://$url/favicon.ico",
|
||||||
model = "https://$url/favicon.ico",
|
model = "https://$url/favicon.ico",
|
||||||
|
|||||||
@@ -16,14 +16,15 @@ import androidx.compose.ui.unit.sp
|
|||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import com.google.accompanist.flowlayout.FlowRow
|
import com.google.accompanist.flowlayout.FlowRow
|
||||||
import com.vitorpamplona.amethyst.R
|
import com.vitorpamplona.amethyst.R
|
||||||
import com.vitorpamplona.amethyst.model.Account
|
import com.vitorpamplona.amethyst.model.*
|
||||||
import com.vitorpamplona.amethyst.model.Channel
|
|
||||||
import com.vitorpamplona.amethyst.model.Note
|
|
||||||
import com.vitorpamplona.amethyst.model.User
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ReplyInformation(replyTo: List<Note>?, mentions: List<User>?, account: Account, navController: NavController) {
|
fun ReplyInformation(replyTo: List<Note>?, mentions: List<String>, account: Account, navController: NavController) {
|
||||||
ReplyInformation(replyTo, mentions, account) {
|
val sortedMentions = mentions.mapNotNull { LocalCache.checkGetOrCreateUser(it) }
|
||||||
|
.toSet()
|
||||||
|
.sortedBy { account.userProfile().isFollowingCached(it) }
|
||||||
|
|
||||||
|
ReplyInformation(replyTo, sortedMentions, account) {
|
||||||
navController.navigate("User/${it.pubkeyHex}")
|
navController.navigate("User/${it.pubkeyHex}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user