created dialog to show relay information

pull/462/head
greenart7c3 2023-06-21 10:41:15 -03:00
rodzic fbe0f584af
commit 4506ff9c93
8 zmienionych plików z 790 dodań i 73 usunięć

Wyświetl plik

@ -0,0 +1,250 @@
package com.vitorpamplona.amethyst.model
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.JsonArray
import com.google.gson.JsonElement
import com.google.gson.JsonObject
import com.google.gson.JsonSerializationContext
import com.google.gson.JsonSerializer
import java.lang.reflect.Type
class RelayInformation(
val name: String?,
val description: String?,
val pubkey: String?,
val contact: String?,
val supported_nips: List<Int>?,
val supported_nip_extensions: List<String>?,
val software: String?,
val version: String?,
val limitation: RelayInformationLimitation?,
val relay_countries: List<String>?,
val language_tags: List<String>?,
val tags: List<String>?,
val posting_policy: String?,
val payments_url: String?,
val fees: RelayInformationFees?,
) {
companion object {
val gson: Gson = GsonBuilder()
.disableHtmlEscaping()
.registerTypeAdapter(RelayInformation::class.java, RelayInformationSerializer())
.registerTypeAdapter(RelayInformationLimitation::class.java, RelayInformationLimitationSerializer())
.registerTypeAdapter(RelayInformationFees::class.java, RelayInformationFeesSerializer())
.registerTypeAdapter(RelayInformationFee::class.java, RelayInformationFeeSerializer())
.create()
fun fromJson(json: String): RelayInformation = gson.fromJson(json, RelayInformation::class.java)
}
}
class RelayInformationFee(
val amount: Int?,
val unit: String?,
val period: Int?,
val kinds: List<Int>?
) {
companion object {
val gson: Gson = GsonBuilder()
.disableHtmlEscaping()
.registerTypeAdapter(RelayInformationFee::class.java, RelayInformationFeeSerializer())
.create()
fun fromJson(json: String): RelayInformationFee = gson.fromJson(json, RelayInformationFee::class.java)
}
}
private class RelayInformationFeeSerializer : JsonSerializer<RelayInformationFee> {
override fun serialize(
src: RelayInformationFee,
typeOfSrc: Type?,
context: JsonSerializationContext?
): JsonElement {
return JsonObject().apply {
addProperty("amount", src.amount)
addProperty("unit", src.unit)
addProperty("period", src.period)
add(
"kinds",
JsonArray().also { kinds ->
src.kinds?.forEach { kind ->
kinds.add(
kind
)
}
}
)
}
}
}
class RelayInformationFees(
val admission: List<RelayInformationFee>?,
val subscription: List<RelayInformationFee>?,
val publication: List<RelayInformationFee>?,
) {
companion object {
val gson: Gson = GsonBuilder()
.disableHtmlEscaping()
.registerTypeAdapter(RelayInformationFees::class.java, RelayInformationFeesSerializer())
.create()
fun fromJson(json: String): RelayInformationFees = gson.fromJson(json, RelayInformationFees::class.java)
}
}
private class RelayInformationFeesSerializer : JsonSerializer<RelayInformationFees> {
override fun serialize(
src: RelayInformationFees,
typeOfSrc: Type?,
context: JsonSerializationContext?
): JsonElement {
return JsonObject().apply {
add(
"admission",
JsonArray().also { admissions ->
src.admission?.forEach { admission ->
admissions.add(
admission.toString()
)
}
}
)
add(
"publication",
JsonArray().also { publications ->
src.publication?.forEach { publication ->
publications.add(
publication.toString()
)
}
}
)
add(
"subscription",
JsonArray().also { subscriptions ->
src.subscription?.forEach { subscription ->
subscriptions.add(
subscription.toString()
)
}
}
)
}
}
}
class RelayInformationLimitation(
val max_message_length: Int?,
val max_subscriptions: Int?,
val max_filters: Int?,
val max_limit: Int?,
val max_subid_length: Int?,
val min_prefix: Int?,
val max_event_tags: Int?,
val max_content_length: Int?,
val min_pow_difficulty: Int?,
val auth_required: Boolean?,
val payment_required: Boolean?
) {
companion object {
val gson: Gson = GsonBuilder()
.disableHtmlEscaping()
.registerTypeAdapter(RelayInformationLimitation::class.java, RelayInformationLimitationSerializer())
.create()
fun fromJson(json: String): RelayInformationLimitation = gson.fromJson(json, RelayInformationLimitation::class.java)
}
}
private class RelayInformationLimitationSerializer : JsonSerializer<RelayInformationLimitation> {
override fun serialize(
src: RelayInformationLimitation,
typeOfSrc: Type?,
context: JsonSerializationContext?
): JsonElement {
return JsonObject().apply {
addProperty("max_message_length", src.max_message_length)
addProperty("max_subscriptions", src.max_subscriptions)
addProperty("max_filters", src.max_filters)
addProperty("max_limit", src.max_limit)
addProperty("max_subid_length", src.max_subid_length)
addProperty("min_prefix", src.min_prefix)
addProperty("max_event_tags", src.max_event_tags)
addProperty("max_content_length", src.max_content_length)
addProperty("min_pow_difficulty", src.min_pow_difficulty)
addProperty("auth_required", src.auth_required)
addProperty("payment_required", src.payment_required)
}
}
}
private class RelayInformationSerializer : JsonSerializer<RelayInformation> {
override fun serialize(
src: RelayInformation,
typeOfSrc: Type?,
context: JsonSerializationContext?
): JsonElement {
return JsonObject().apply {
addProperty("name", src.name)
addProperty("description", src.description)
addProperty("pubkey", src.pubkey)
addProperty("contact", src.contact)
add(
"supported_nip_extensions",
JsonArray().also { supported_nip_extensions ->
src.supported_nip_extensions?.forEach { nip ->
supported_nip_extensions.add(
nip
)
}
}
)
add(
"supported_nips",
JsonArray().also { supported_nips ->
src.supported_nips?.forEach { nip ->
supported_nips.add(
nip
)
}
}
)
addProperty("software", src.software)
addProperty("version", src.version)
add(
"relay_countries",
JsonArray().also { relay_countries ->
src.relay_countries?.forEach { country ->
relay_countries.add(
country
)
}
}
)
add(
"language_tags",
JsonArray().also { language_tags ->
src.language_tags?.forEach { language_tag ->
language_tags.add(
language_tag
)
}
}
)
add(
"tags",
JsonArray().also { tags ->
src.tags?.forEach { tag ->
tags.add(
tag
)
}
}
)
addProperty("posting_policy", src.posting_policy)
addProperty("payments_url", src.payments_url)
}
}
}

Wyświetl plik

@ -2,6 +2,7 @@ package com.vitorpamplona.amethyst.ui.actions
import android.widget.Toast
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.clickable
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
@ -53,17 +54,25 @@ import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
import androidx.lifecycle.viewmodel.compose.viewModel
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.model.LocalCache
import com.vitorpamplona.amethyst.model.RelayInformation
import com.vitorpamplona.amethyst.model.RelaySetupInfo
import com.vitorpamplona.amethyst.service.HttpClient
import com.vitorpamplona.amethyst.service.NostrUserProfileDataSource
import com.vitorpamplona.amethyst.service.relays.FeedType
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.theme.ButtonBorder
import com.vitorpamplona.amethyst.ui.theme.Size35dp
import com.vitorpamplona.amethyst.ui.theme.placeholderText
import kotlinx.coroutines.launch
import okhttp3.Call
import okhttp3.Callback
import okhttp3.Request
import okhttp3.Response
import java.lang.Math.round
@Composable
fun NewRelayListView(onClose: () -> Unit, accountViewModel: AccountViewModel, relayToAdd: String = "") {
fun NewRelayListView(onClose: () -> Unit, accountViewModel: AccountViewModel, relayToAdd: String = "", nav: (String) -> Unit) {
val postViewModel: NewRelayListViewModel = viewModel()
val feedState by postViewModel.relays.collectAsState()
@ -125,7 +134,9 @@ fun NewRelayListView(onClose: () -> Unit, accountViewModel: AccountViewModel, re
onToggleGlobal = { postViewModel.toggleGlobal(it) },
onToggleSearch = { postViewModel.toggleSearch(it) },
onDelete = { postViewModel.deleteRelay(it) }
onDelete = { postViewModel.deleteRelay(it) },
accountViewModel = accountViewModel,
nav = nav
)
}
}
@ -222,10 +233,31 @@ fun ServerConfig(
onToggleGlobal: (RelaySetupInfo) -> Unit,
onToggleSearch: (RelaySetupInfo) -> Unit,
onDelete: (RelaySetupInfo) -> Unit
onDelete: (RelaySetupInfo) -> Unit,
accountViewModel: AccountViewModel,
nav: (String) -> Unit
) {
val context = LocalContext.current
val scope = rememberCoroutineScope()
var relayInfo: RelayInformation? by remember { mutableStateOf(null) }
if (relayInfo != null) {
val user = LocalCache.getOrCreateUser(relayInfo!!.pubkey ?: "")
NostrUserProfileDataSource.loadUserProfile(user)
NostrUserProfileDataSource.start()
RelayInformationDialog(
onClose = {
relayInfo = null
NostrUserProfileDataSource.loadUserProfile(null)
NostrUserProfileDataSource.stop()
},
relayInfo = relayInfo!!,
user,
accountViewModel,
nav
)
}
Column(Modifier.fillMaxWidth()) {
Row(
verticalAlignment = Alignment.CenterVertically,
@ -251,7 +283,55 @@ fun ServerConfig(
Row(verticalAlignment = Alignment.CenterVertically) {
Text(
text = item.url.removePrefix("wss://"),
modifier = Modifier.weight(1f),
modifier = Modifier
.weight(1f)
.clickable {
val client = HttpClient.getHttpClient()
val url = item.url
.replace("wss://", "https://")
.replace("ws://", "http://")
val request: Request = Request
.Builder()
.header("Accept", "application/nostr+json")
.url(url)
.build()
client
.newCall(request)
.enqueue(object : Callback {
override fun onResponse(call: Call, response: Response) {
response.use {
if (it.isSuccessful) {
relayInfo =
RelayInformation.fromJson(it.body.string())
} else {
scope.launch {
Toast
.makeText(
context,
"An error ocurred trying to get relay information",
Toast.LENGTH_SHORT
)
.show()
}
}
}
}
override fun onFailure(call: Call, e: java.io.IOException) {
e.printStackTrace()
scope.launch {
Toast
.makeText(
context,
"An error ocurred trying to get relay information",
Toast.LENGTH_SHORT
)
.show()
}
}
})
},
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
@ -275,11 +355,13 @@ fun ServerConfig(
onClick = { onToggleFollows(item) },
onLongClick = {
scope.launch {
Toast.makeText(
context,
context.getString(R.string.home_feed),
Toast.LENGTH_SHORT
).show()
Toast
.makeText(
context,
context.getString(R.string.home_feed),
Toast.LENGTH_SHORT
)
.show()
}
}
),
@ -306,11 +388,13 @@ fun ServerConfig(
onClick = { onTogglePrivateDMs(item) },
onLongClick = {
scope.launch {
Toast.makeText(
context,
context.getString(R.string.private_message_feed),
Toast.LENGTH_SHORT
).show()
Toast
.makeText(
context,
context.getString(R.string.private_message_feed),
Toast.LENGTH_SHORT
)
.show()
}
}
),
@ -337,11 +421,13 @@ fun ServerConfig(
onClick = { onTogglePublicChats(item) },
onLongClick = {
scope.launch {
Toast.makeText(
context,
context.getString(R.string.public_chat_feed),
Toast.LENGTH_SHORT
).show()
Toast
.makeText(
context,
context.getString(R.string.public_chat_feed),
Toast.LENGTH_SHORT
)
.show()
}
}
),
@ -368,11 +454,13 @@ fun ServerConfig(
onClick = { onToggleGlobal(item) },
onLongClick = {
scope.launch {
Toast.makeText(
context,
context.getString(R.string.global_feed),
Toast.LENGTH_SHORT
).show()
Toast
.makeText(
context,
context.getString(R.string.global_feed),
Toast.LENGTH_SHORT
)
.show()
}
}
),
@ -400,11 +488,13 @@ fun ServerConfig(
onClick = { onToggleSearch(item) },
onLongClick = {
scope.launch {
Toast.makeText(
context,
context.getString(R.string.search_feed),
Toast.LENGTH_SHORT
).show()
Toast
.makeText(
context,
context.getString(R.string.search_feed),
Toast.LENGTH_SHORT
)
.show()
}
}
),
@ -436,11 +526,13 @@ fun ServerConfig(
onClick = { onToggleDownload(item) },
onLongClick = {
scope.launch {
Toast.makeText(
context,
context.getString(R.string.read_from_relay),
Toast.LENGTH_SHORT
).show()
Toast
.makeText(
context,
context.getString(R.string.read_from_relay),
Toast.LENGTH_SHORT
)
.show()
}
}
),
@ -476,11 +568,13 @@ fun ServerConfig(
onClick = { onToggleUpload(item) },
onLongClick = {
scope.launch {
Toast.makeText(
context,
context.getString(R.string.write_to_relay),
Toast.LENGTH_SHORT
).show()
Toast
.makeText(
context,
context.getString(R.string.write_to_relay),
Toast.LENGTH_SHORT
)
.show()
}
}
),
@ -512,11 +606,13 @@ fun ServerConfig(
onClick = { },
onLongClick = {
scope.launch {
Toast.makeText(
context,
context.getString(R.string.errors),
Toast.LENGTH_SHORT
).show()
Toast
.makeText(
context,
context.getString(R.string.errors),
Toast.LENGTH_SHORT
)
.show()
}
}
),
@ -541,11 +637,13 @@ fun ServerConfig(
onClick = { },
onLongClick = {
scope.launch {
Toast.makeText(
context,
context.getString(R.string.spam),
Toast.LENGTH_SHORT
).show()
Toast
.makeText(
context,
context.getString(R.string.spam),
Toast.LENGTH_SHORT
)
.show()
}
}
),

Wyświetl plik

@ -0,0 +1,365 @@
package com.vitorpamplona.amethyst.ui.actions
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.text.ClickableText
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Icon
import androidx.compose.material.LocalTextStyle
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Downloading
import androidx.compose.material.icons.filled.Report
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.model.RelayInformation
import com.vitorpamplona.amethyst.model.User
import com.vitorpamplona.amethyst.ui.components.ClickableEmail
import com.vitorpamplona.amethyst.ui.components.ClickableUrl
import com.vitorpamplona.amethyst.ui.components.CreateTextWithEmoji
import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer
import com.vitorpamplona.amethyst.ui.components.nip05VerificationAsAState
import com.vitorpamplona.amethyst.ui.note.UserPicture
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.DisplayLNAddress
import com.vitorpamplona.amethyst.ui.theme.Nip05
import com.vitorpamplona.amethyst.ui.theme.placeholderText
@Composable
fun Section(text: String) {
Spacer(modifier = Modifier.height(10.dp))
Text(
text = text,
fontWeight = FontWeight.Bold,
fontSize = 25.sp
)
Spacer(modifier = Modifier.height(10.dp))
}
@Composable
fun SectionContent(text: String) {
Text(
modifier = Modifier.padding(start = 10.dp),
text = text
)
}
@OptIn(ExperimentalLayoutApi::class)
@Composable
fun RelayInformationDialog(onClose: () -> Unit, relayInfo: RelayInformation, baseUser: User, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
val userState by baseUser.live().metadata.observeAsState()
val user = remember(userState) { userState?.user } ?: return
val tags = remember(userState) { userState?.user?.info?.latestMetadata?.tags?.toImmutableListOfLists() }
val lud16 = remember(userState) { user.info?.lud16?.trim() ?: user.info?.lud06?.trim() }
val pubkeyHex = remember { baseUser.pubkeyHex }
val uri = LocalUriHandler.current
val scrollState = rememberScrollState()
Dialog(
onDismissRequest = { onClose() },
properties = DialogProperties(
usePlatformDefaultWidth = false,
dismissOnClickOutside = false
)
) {
Surface {
Column(
modifier = Modifier
.padding(10.dp)
.fillMaxSize()
.verticalScroll(scrollState)
) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
CloseButton(onCancel = {
onClose()
})
}
Row(
modifier = Modifier.fillMaxWidth()
) {
Section(relayInfo.name ?: "")
}
SectionContent(relayInfo.description ?: "")
Section("Owner")
Row {
UserPicture(
baseUser = user,
accountViewModel = accountViewModel,
size = 100.dp,
modifier = Modifier.border(
3.dp,
MaterialTheme.colors.background,
CircleShape
),
onClick = {
nav("User/${user.pubkeyHex}")
}
)
Column(Modifier.padding(start = 10.dp)) {
(user.bestDisplayName() ?: user.bestUsername())?.let {
Row(verticalAlignment = Alignment.Bottom, modifier = Modifier.padding(top = 7.dp)) {
CreateTextWithEmoji(
text = it,
tags = tags,
fontWeight = FontWeight.Bold,
fontSize = 25.sp
)
}
}
if (user.bestDisplayName() != null) {
user.bestUsername()?.let {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.padding(top = 1.dp, bottom = 1.dp)
) {
CreateTextWithEmoji(
text = "@$it",
tags = tags,
color = MaterialTheme.colors.placeholderText
)
}
}
}
user.nip05()?.let { nip05 ->
if (nip05.split("@").size == 2) {
val nip05Verified by nip05VerificationAsAState(user.info!!, user.pubkeyHex)
Row(verticalAlignment = Alignment.CenterVertically) {
if (nip05Verified == null) {
Icon(
tint = Color.Yellow,
imageVector = Icons.Default.Downloading,
contentDescription = "Downloading",
modifier = Modifier.size(16.dp)
)
} else if (nip05Verified == true) {
Icon(
painter = painterResource(R.drawable.ic_verified),
"NIP-05 Verified",
tint = Nip05,
modifier = Modifier.size(16.dp)
)
} else {
Icon(
tint = Color.Red,
imageVector = Icons.Default.Report,
contentDescription = "Invalid Nip05",
modifier = Modifier.size(16.dp)
)
}
var domainPadStart = 5.dp
if (nip05.split("@")[0] != "_") {
Text(
text = AnnotatedString(nip05.split("@")[0] + "@"),
modifier = Modifier.padding(top = 1.dp, bottom = 1.dp, start = 5.dp),
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
domainPadStart = 0.dp
}
ClickableText(
text = AnnotatedString(nip05.split("@")[1]),
onClick = { nip05.let { runCatching { uri.openUri("https://${it.split("@")[1]}") } } },
style = LocalTextStyle.current.copy(color = MaterialTheme.colors.primary),
modifier = Modifier.padding(top = 1.dp, bottom = 1.dp, start = domainPadStart),
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
}
}
}
DisplayLNAddress(lud16, pubkeyHex, accountViewModel.account)
user.info?.about?.let {
Row(
modifier = Modifier.padding(top = 5.dp, bottom = 5.dp)
) {
val defaultBackground = MaterialTheme.colors.background
val background = remember {
mutableStateOf(defaultBackground)
}
TranslatableRichTextViewer(
content = it,
canPreview = false,
tags = remember { ImmutableListOfLists(emptyList()) },
backgroundColor = background,
accountViewModel = accountViewModel,
nav = nav
)
}
}
}
}
Section("Software")
val url = (relayInfo.software ?: "").replace("git+", "")
Box(modifier = Modifier.padding(start = 10.dp)) {
ClickableUrl(
urlText = url,
url = url
)
}
Section("Version")
SectionContent(relayInfo.version ?: "")
Section("Contact")
Box(modifier = Modifier.padding(start = 10.dp)) {
ClickableEmail(relayInfo.contact ?: "")
}
Section("Supports")
FlowRow {
relayInfo.supported_nips?.forEach { item ->
val text = item.toString().padStart(2, '0')
Box(Modifier.padding(10.dp)) {
ClickableUrl(
urlText = "Nip-$text",
url = "https://github.com/nostr-protocol/nips/blob/master/$text.md"
)
}
}
relayInfo.supported_nip_extensions?.forEach { item ->
val text = item.padStart(2, '0')
Box(Modifier.padding(10.dp)) {
ClickableUrl(
urlText = "Nip-$text",
url = "https://github.com/nostr-protocol/nips/blob/master/$text.md"
)
}
}
}
relayInfo.fees?.admission?.let {
if (it.isNotEmpty()) {
Section("Admission Fees")
it.forEach { item ->
SectionContent("${item.amount?.div(1000) ?: 0} sats")
}
}
}
relayInfo.payments_url?.let {
Section("Payments url")
Box(modifier = Modifier.padding(start = 10.dp)) {
ClickableUrl(
urlText = it,
url = it
)
}
}
relayInfo.limitation?.let {
Section("Limitations")
Column {
SectionContent("Message length: ${it.max_message_length ?: 0}")
SectionContent("Subscriptions: ${it.max_subscriptions ?: 0}")
SectionContent("Filters: ${it.max_subscriptions ?: 0}")
SectionContent("Subscription id length: ${it.max_subid_length ?: 0}")
SectionContent("Minimum prefix: ${it.min_prefix ?: 0}")
SectionContent("Maximum event tags: ${it.max_event_tags ?: 0}")
SectionContent("Content length: ${it.max_content_length ?: 0}")
SectionContent("Minimum PoW: ${it.min_pow_difficulty ?: 0}")
SectionContent("Auth: ${it.auth_required ?: false}")
SectionContent("Payment: ${it.payment_required ?: false}")
}
}
relayInfo.relay_countries?.let {
Section("Countries")
FlowRow {
it.forEach { item ->
SectionContent(item)
}
}
}
relayInfo.language_tags?.let {
Section("Languages")
FlowRow {
it.forEach { item ->
SectionContent(item)
}
}
}
relayInfo.tags?.let {
Section("Tags")
FlowRow {
it.forEach { item ->
SectionContent(item)
}
}
}
relayInfo.posting_policy?.let {
Section("Posting policy")
Box(Modifier.padding(10.dp)) {
ClickableUrl(
it,
it
)
}
}
}
}
}
}

Wyświetl plik

@ -96,7 +96,8 @@ fun AppTopBar(
followLists: FollowListViewModel,
navEntryState: State<NavBackStackEntry?>,
scaffoldState: ScaffoldState,
accountViewModel: AccountViewModel
accountViewModel: AccountViewModel,
nav: (String) -> Unit
) {
val currentRoute by remember(navEntryState.value) {
derivedStateOf {
@ -104,7 +105,7 @@ fun AppTopBar(
}
}
RenderTopRouteBar(currentRoute, followLists, scaffoldState, accountViewModel)
RenderTopRouteBar(currentRoute, followLists, scaffoldState, accountViewModel, nav)
}
@Composable
@ -112,16 +113,17 @@ private fun RenderTopRouteBar(
currentRoute: String?,
followLists: FollowListViewModel,
scaffoldState: ScaffoldState,
accountViewModel: AccountViewModel
accountViewModel: AccountViewModel,
nav: (String) -> Unit
) {
when (currentRoute) {
Route.Channel.base -> NoTopBar()
Route.Room.base -> NoTopBar()
// Route.Profile.route -> TopBarWithBackButton(nav)
Route.Home.base -> HomeTopBar(followLists, scaffoldState, accountViewModel)
Route.Video.base -> StoriesTopBar(followLists, scaffoldState, accountViewModel)
Route.Notification.base -> NotificationTopBar(followLists, scaffoldState, accountViewModel)
else -> MainTopBar(scaffoldState, accountViewModel)
Route.Home.base -> HomeTopBar(followLists, scaffoldState, accountViewModel, nav)
Route.Video.base -> StoriesTopBar(followLists, scaffoldState, accountViewModel, nav)
Route.Notification.base -> NotificationTopBar(followLists, scaffoldState, accountViewModel, nav)
else -> MainTopBar(scaffoldState, accountViewModel, nav)
}
}
@ -151,8 +153,8 @@ fun StoriesTopBar(followLists: FollowListViewModel, scaffoldState: ScaffoldState
}
@Composable
fun HomeTopBar(followLists: FollowListViewModel, scaffoldState: ScaffoldState, accountViewModel: AccountViewModel) {
GenericTopBar(scaffoldState, accountViewModel) { accountViewModel ->
fun HomeTopBar(followLists: FollowListViewModel, scaffoldState: ScaffoldState, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
GenericTopBar(scaffoldState, accountViewModel, nav) { accountViewModel ->
val accountState by accountViewModel.accountLiveData.observeAsState()
val list by remember(accountState) {
@ -172,8 +174,8 @@ fun HomeTopBar(followLists: FollowListViewModel, scaffoldState: ScaffoldState, a
}
@Composable
fun NotificationTopBar(followLists: FollowListViewModel, scaffoldState: ScaffoldState, accountViewModel: AccountViewModel) {
GenericTopBar(scaffoldState, accountViewModel) { accountViewModel ->
fun NotificationTopBar(followLists: FollowListViewModel, scaffoldState: ScaffoldState, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
GenericTopBar(scaffoldState, accountViewModel, nav) { accountViewModel ->
val accountState by accountViewModel.accountLiveData.observeAsState()
val list by remember(accountState) {
@ -193,15 +195,15 @@ fun NotificationTopBar(followLists: FollowListViewModel, scaffoldState: Scaffold
}
@Composable
fun MainTopBar(scaffoldState: ScaffoldState, accountViewModel: AccountViewModel) {
GenericTopBar(scaffoldState, accountViewModel) {
fun MainTopBar(scaffoldState: ScaffoldState, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
GenericTopBar(scaffoldState, accountViewModel, nav) {
AmethystIcon()
}
}
@OptIn(coil.annotation.ExperimentalCoilApi::class)
@Composable
fun GenericTopBar(scaffoldState: ScaffoldState, accountViewModel: AccountViewModel, content: @Composable (AccountViewModel) -> Unit) {
fun GenericTopBar(scaffoldState: ScaffoldState, accountViewModel: AccountViewModel, nav: (String) -> Unit, content: @Composable (AccountViewModel) -> Unit) {
val coroutineScope = rememberCoroutineScope()
var wantsToEditRelays by remember {
@ -209,7 +211,7 @@ fun GenericTopBar(scaffoldState: ScaffoldState, accountViewModel: AccountViewMod
}
if (wantsToEditRelays) {
NewRelayListView({ wantsToEditRelays = false }, accountViewModel)
NewRelayListView({ wantsToEditRelays = false }, accountViewModel, nav = nav)
}
Column(modifier = Modifier.height(50.dp)) {

Wyświetl plik

@ -1200,7 +1200,7 @@ fun DisplayRelaySet(
)
Column(modifier = Modifier.padding(start = 10.dp)) {
RelayOptionsAction(relay, accountViewModel)
RelayOptionsAction(relay, accountViewModel, nav)
}
}
}
@ -1235,7 +1235,8 @@ fun DisplayRelaySet(
@Composable
private fun RelayOptionsAction(
relay: String,
accountViewModel: AccountViewModel
accountViewModel: AccountViewModel,
nav: (String) -> Unit
) {
val userStateRelayInfo by accountViewModel.account.userProfile().live().relayInfo.observeAsState()
val isCurrentlyOnTheUsersList by remember(userStateRelayInfo) {
@ -1249,7 +1250,7 @@ private fun RelayOptionsAction(
}
if (wantsToAddRelay.isNotEmpty()) {
NewRelayListView({ wantsToAddRelay = "" }, accountViewModel, wantsToAddRelay)
NewRelayListView({ wantsToAddRelay = "" }, accountViewModel, wantsToAddRelay, nav = nav)
}
if (isCurrentlyOnTheUsersList) {

Wyświetl plik

@ -98,6 +98,7 @@ class RelayFeedViewModel : ViewModel() {
fun RelayFeedView(
viewModel: RelayFeedViewModel,
accountViewModel: AccountViewModel,
nav: (String) -> Unit,
enablePullRefresh: Boolean = true
) {
val feedState by viewModel.feedContent.collectAsState()
@ -107,7 +108,7 @@ fun RelayFeedView(
}
if (wantsToAddRelay.isNotEmpty()) {
NewRelayListView({ wantsToAddRelay = "" }, accountViewModel, wantsToAddRelay)
NewRelayListView({ wantsToAddRelay = "" }, accountViewModel, wantsToAddRelay, nav = nav)
}
var refreshing by remember { mutableStateOf(false) }

Wyświetl plik

@ -173,7 +173,7 @@ fun MainScreen(accountViewModel: AccountViewModel, accountStateViewModel: Accoun
AppBottomBar(accountViewModel, navState, navBottomRow)
},
topBar = {
AppTopBar(followLists, navState, scaffoldState, accountViewModel)
AppTopBar(followLists, navState, scaffoldState, accountViewModel, nav = nav)
},
drawerContent = {
DrawerContent(nav, scaffoldState, sheetState, accountViewModel)

Wyświetl plik

@ -315,7 +315,7 @@ private fun CreateAndRenderPages(
4 -> TabReceivedZaps(baseUser, zapFeedViewModel, accountViewModel, nav)
5 -> TabBookmarks(baseUser, accountViewModel, nav)
6 -> TabReports(baseUser, accountViewModel, nav)
7 -> TabRelays(baseUser, accountViewModel)
7 -> TabRelays(baseUser, accountViewModel, nav)
}
}
@ -782,7 +782,7 @@ private fun DrawAdditionalInfo(
}
@Composable
private fun DisplayLNAddress(
fun DisplayLNAddress(
lud16: String?,
userHex: String,
account: Account
@ -1287,7 +1287,7 @@ private fun WatchReportsAndUpdateFeed(
}
@Composable
fun TabRelays(user: User, accountViewModel: AccountViewModel) {
fun TabRelays(user: User, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
val feedViewModel: RelayFeedViewModel = viewModel()
val lifeCycleOwner = LocalLifecycleOwner.current
@ -1316,7 +1316,7 @@ fun TabRelays(user: User, accountViewModel: AccountViewModel) {
Column(
modifier = Modifier.padding(vertical = 0.dp)
) {
RelayFeedView(feedViewModel, accountViewModel, enablePullRefresh = false)
RelayFeedView(feedViewModel, accountViewModel, enablePullRefresh = false, nav = nav)
}
}
}