Adds DM relays to the relay list.

This commit is contained in:
Vitor Pamplona
2024-05-28 11:49:13 -04:00
parent 6a17a8a871
commit e98a77b37f
7 changed files with 174 additions and 69 deletions

View File

@ -49,6 +49,7 @@ import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.model.RelayBriefInfoCache import com.vitorpamplona.amethyst.model.RelayBriefInfoCache
import com.vitorpamplona.amethyst.service.Nip11Retriever import com.vitorpamplona.amethyst.service.Nip11Retriever
import com.vitorpamplona.amethyst.service.relays.Relay import com.vitorpamplona.amethyst.service.relays.Relay
import com.vitorpamplona.amethyst.ui.actions.relays.RelayInformationDialog
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.theme.FeedPadding import com.vitorpamplona.amethyst.ui.theme.FeedPadding
import com.vitorpamplona.quartz.encoders.Nip11RelayInformation import com.vitorpamplona.quartz.encoders.Nip11RelayInformation

View File

@ -27,6 +27,7 @@ import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
@ -46,12 +47,13 @@ import androidx.compose.ui.window.DialogProperties
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.service.relays.Constants.defaultRelays import com.vitorpamplona.amethyst.service.relays.Constants
import com.vitorpamplona.amethyst.ui.actions.CloseButton import com.vitorpamplona.amethyst.ui.actions.CloseButton
import com.vitorpamplona.amethyst.ui.actions.SaveButton import com.vitorpamplona.amethyst.ui.actions.SaveButton
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.theme.DoubleHorzSpacer import com.vitorpamplona.amethyst.ui.theme.DoubleHorzSpacer
import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.ui.theme.FeedPadding
import com.vitorpamplona.amethyst.ui.theme.grayText
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
@ -61,11 +63,15 @@ fun AllRelayListView(
accountViewModel: AccountViewModel, accountViewModel: AccountViewModel,
nav: (String) -> Unit, nav: (String) -> Unit,
) { ) {
val postViewModel: Kind3RelayListViewModel = viewModel() val kind3ViewModel: Kind3RelayListViewModel = viewModel()
val dmViewModel: DMRelayListViewModel = viewModel() val dmViewModel: DMRelayListViewModel = viewModel()
val feedState by postViewModel.relays.collectAsStateWithLifecycle() val kind3FeedState by kind3ViewModel.relays.collectAsStateWithLifecycle()
val dmFeedState by dmViewModel.relays.collectAsStateWithLifecycle()
LaunchedEffect(Unit) { postViewModel.load(accountViewModel.account) } LaunchedEffect(Unit) {
kind3ViewModel.load(accountViewModel.account)
dmViewModel.load(accountViewModel.account)
}
Dialog( Dialog(
onDismissRequest = onClose, onDismissRequest = onClose,
@ -77,24 +83,12 @@ fun AllRelayListView(
title = { title = {
Row( Row(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween, horizontalArrangement = Arrangement.End,
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
) { ) {
Spacer(modifier = StdHorzSpacer)
Button(
onClick = {
postViewModel.deleteAll()
defaultRelays.forEach { postViewModel.addRelay(it) }
postViewModel.loadRelayDocuments()
},
) {
Text(stringResource(R.string.default_relays))
}
SaveButton( SaveButton(
onPost = { onPost = {
postViewModel.create() kind3ViewModel.create()
onClose() onClose()
}, },
true, true,
@ -105,7 +99,7 @@ fun AllRelayListView(
Spacer(modifier = DoubleHorzSpacer) Spacer(modifier = DoubleHorzSpacer)
CloseButton( CloseButton(
onPress = { onPress = {
postViewModel.clear() kind3ViewModel.clear()
onClose() onClose()
}, },
) )
@ -119,16 +113,100 @@ fun AllRelayListView(
) { pad -> ) { pad ->
Column( Column(
modifier = modifier =
Modifier.fillMaxSize().padding( Modifier
16.dp, .fillMaxSize()
pad.calculateTopPadding(), .padding(
16.dp, 16.dp,
pad.calculateBottomPadding(), pad.calculateTopPadding(),
), 16.dp,
pad.calculateBottomPadding(),
),
verticalArrangement = Arrangement.SpaceAround, verticalArrangement = Arrangement.SpaceAround,
) { ) {
Kind3RelayListView(feedState, postViewModel, accountViewModel, onClose, nav, relayToAdd) LazyColumn(contentPadding = FeedPadding) {
item {
SettingsCategory(
stringResource(R.string.private_inbox_section),
stringResource(R.string.private_inbox_section_explainer),
Modifier.padding(bottom = 8.dp),
)
}
renderDMItems(dmFeedState, dmViewModel, accountViewModel, onClose, nav)
item {
SettingsCategoryWithButton(
stringResource(R.string.kind_3_section),
stringResource(R.string.kind_3_section_description),
action = {
ResetKind3Relays(kind3ViewModel)
},
)
}
renderKind3Items(kind3FeedState, kind3ViewModel, accountViewModel, onClose, nav, relayToAdd)
}
} }
} }
} }
} }
@Composable
fun ResetKind3Relays(postViewModel: Kind3RelayListViewModel) {
Button(
onClick = {
postViewModel.deleteAll()
Constants.defaultRelays.forEach { postViewModel.addRelay(it) }
postViewModel.loadRelayDocuments()
},
) {
Text(stringResource(R.string.default_relays))
}
}
@Composable
fun SettingsCategory(
title: String,
description: String? = null,
modifier: Modifier = Modifier.padding(top = 24.dp, bottom = 8.dp),
) {
Column(modifier) {
Text(
text = title,
color = MaterialTheme.colorScheme.primary,
style = MaterialTheme.typography.titleSmall,
)
if (description != null) {
Text(
description,
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.grayText,
)
}
}
}
@Composable
fun SettingsCategoryWithButton(
title: String,
description: String? = null,
action: @Composable () -> Unit,
modifier: Modifier = Modifier.padding(top = 24.dp, bottom = 8.dp),
) {
Row(modifier) {
Column(modifier = Modifier.weight(1f)) {
Text(
text = title,
color = MaterialTheme.colorScheme.primary,
style = MaterialTheme.typography.titleSmall,
)
if (description != null) {
Text(
text = description,
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.grayText,
)
}
}
action()
}
}

View File

@ -32,6 +32,7 @@ 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.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Cancel import androidx.compose.material.icons.filled.Cancel
@ -68,7 +69,6 @@ import com.vitorpamplona.amethyst.model.RelayBriefInfoCache
import com.vitorpamplona.amethyst.service.Nip11CachedRetriever import com.vitorpamplona.amethyst.service.Nip11CachedRetriever
import com.vitorpamplona.amethyst.service.Nip11Retriever import com.vitorpamplona.amethyst.service.Nip11Retriever
import com.vitorpamplona.amethyst.ui.actions.RelayInfoDialog import com.vitorpamplona.amethyst.ui.actions.RelayInfoDialog
import com.vitorpamplona.amethyst.ui.actions.RelayInformationDialog
import com.vitorpamplona.amethyst.ui.note.RenderRelayIcon import com.vitorpamplona.amethyst.ui.note.RenderRelayIcon
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
@ -100,22 +100,33 @@ fun DMRelayList(
LazyColumn( LazyColumn(
contentPadding = FeedPadding, contentPadding = FeedPadding,
) { ) {
itemsIndexed(feedState, key = { _, item -> item.url }) { index, item -> renderDMItems(feedState, postViewModel, accountViewModel, onClose, nav)
DMServerConfig( }
item, }
onDelete = { postViewModel.deleteRelay(item) }, }
accountViewModel = accountViewModel,
) { fun LazyListScope.renderDMItems(
onClose() feedState: List<DMRelayListViewModel.DMRelaySetupInfo>,
nav(it) postViewModel: DMRelayListViewModel,
} accountViewModel: AccountViewModel,
} onClose: () -> Unit,
nav: (String) -> Unit,
) {
itemsIndexed(feedState, key = { _, item -> item.url }) { index, item ->
DMServerConfig(
item,
onDelete = { postViewModel.deleteRelay(item) },
accountViewModel = accountViewModel,
) {
onClose()
nav(it)
} }
} }
Spacer(modifier = StdVertSpacer) item {
Spacer(modifier = StdVertSpacer)
DMEditableServerConfig { postViewModel.addRelay(it) } DMEditableServerConfig { postViewModel.addRelay(it) }
}
} }
@Composable @Composable

View File

@ -31,6 +31,7 @@ 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.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Cancel import androidx.compose.material.icons.filled.Cancel
@ -74,7 +75,6 @@ import com.vitorpamplona.amethyst.service.Nip11Retriever
import com.vitorpamplona.amethyst.service.relays.Constants import com.vitorpamplona.amethyst.service.relays.Constants
import com.vitorpamplona.amethyst.service.relays.FeedType import com.vitorpamplona.amethyst.service.relays.FeedType
import com.vitorpamplona.amethyst.ui.actions.RelayInfoDialog import com.vitorpamplona.amethyst.ui.actions.RelayInfoDialog
import com.vitorpamplona.amethyst.ui.actions.RelayInformationDialog
import com.vitorpamplona.amethyst.ui.note.RenderRelayIcon import com.vitorpamplona.amethyst.ui.note.RenderRelayIcon
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
@ -104,35 +104,44 @@ fun Kind3RelayListView(
relayToAdd: String, relayToAdd: String,
) { ) {
Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) { Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
LazyColumn( LazyColumn(contentPadding = FeedPadding) {
contentPadding = FeedPadding, renderKind3Items(feedState, postViewModel, accountViewModel, onClose, nav, relayToAdd)
) {
itemsIndexed(feedState, key = { _, item -> item.url }) { index, item ->
LoadRelayInfo(
item,
onToggleDownload = { postViewModel.toggleDownload(it) },
onToggleUpload = { postViewModel.toggleUpload(it) },
onToggleFollows = { postViewModel.toggleFollows(it) },
onTogglePrivateDMs = { postViewModel.toggleMessages(it) },
onTogglePublicChats = { postViewModel.togglePublicChats(it) },
onToggleGlobal = { postViewModel.toggleGlobal(it) },
onToggleSearch = { postViewModel.toggleSearch(it) },
onDelete = { postViewModel.deleteRelay(it) },
accountViewModel = accountViewModel,
) {
onClose()
nav(it)
}
}
item {
Spacer(modifier = StdVertSpacer)
Kind3RelayEditBox(relayToAdd) { postViewModel.addRelay(it) }
}
} }
} }
} }
fun LazyListScope.renderKind3Items(
feedState: List<RelaySetupInfo>,
postViewModel: Kind3RelayListViewModel,
accountViewModel: AccountViewModel,
onClose: () -> Unit,
nav: (String) -> Unit,
relayToAdd: String,
) {
itemsIndexed(feedState, key = { _, item -> item.url }) { index, item ->
LoadRelayInfo(
item,
onToggleDownload = { postViewModel.toggleDownload(it) },
onToggleUpload = { postViewModel.toggleUpload(it) },
onToggleFollows = { postViewModel.toggleFollows(it) },
onTogglePrivateDMs = { postViewModel.toggleMessages(it) },
onTogglePublicChats = { postViewModel.togglePublicChats(it) },
onToggleGlobal = { postViewModel.toggleGlobal(it) },
onToggleSearch = { postViewModel.toggleSearch(it) },
onDelete = { postViewModel.deleteRelay(it) },
accountViewModel = accountViewModel,
) {
onClose()
nav(it)
}
}
item {
Spacer(modifier = StdVertSpacer)
Kind3RelayEditBox(relayToAdd) { postViewModel.addRelay(it) }
}
}
@Preview @Preview
@Composable @Composable
fun ServerConfigPreview() { fun ServerConfigPreview() {

View File

@ -18,7 +18,7 @@
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
package com.vitorpamplona.amethyst.ui.actions package com.vitorpamplona.amethyst.ui.actions.relays
import androidx.compose.animation.Crossfade import androidx.compose.animation.Crossfade
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
@ -48,6 +48,7 @@ import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties import androidx.compose.ui.window.DialogProperties
import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.model.RelayBriefInfoCache import com.vitorpamplona.amethyst.model.RelayBriefInfoCache
import com.vitorpamplona.amethyst.ui.actions.CloseButton
import com.vitorpamplona.amethyst.ui.components.ClickableEmail import com.vitorpamplona.amethyst.ui.components.ClickableEmail
import com.vitorpamplona.amethyst.ui.components.ClickableUrl import com.vitorpamplona.amethyst.ui.components.ClickableUrl
import com.vitorpamplona.amethyst.ui.note.LoadUser import com.vitorpamplona.amethyst.ui.note.LoadUser

View File

@ -52,7 +52,7 @@ import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.model.RelayBriefInfoCache import com.vitorpamplona.amethyst.model.RelayBriefInfoCache
import com.vitorpamplona.amethyst.service.Nip11CachedRetriever import com.vitorpamplona.amethyst.service.Nip11CachedRetriever
import com.vitorpamplona.amethyst.service.Nip11Retriever import com.vitorpamplona.amethyst.service.Nip11Retriever
import com.vitorpamplona.amethyst.ui.actions.RelayInformationDialog import com.vitorpamplona.amethyst.ui.actions.relays.RelayInformationDialog
import com.vitorpamplona.amethyst.ui.components.RobohashFallbackAsyncImage import com.vitorpamplona.amethyst.ui.components.RobohashFallbackAsyncImage
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.theme.RelayIconFilter import com.vitorpamplona.amethyst.ui.theme.RelayIconFilter

View File

@ -812,6 +812,11 @@
<string name="dm_relays_not_found_editing">Insert between 1-3 relays to serve as your private inbox. DM Inbox relays should accept any message from anyone, but only allow you to download them.</string> <string name="dm_relays_not_found_editing">Insert between 1-3 relays to serve as your private inbox. DM Inbox relays should accept any message from anyone, but only allow you to download them.</string>
<string name="dm_relays_not_found_create_now">Set up now</string> <string name="dm_relays_not_found_create_now">Set up now</string>
<string name="private_inbox_section">DM Inbox Relays</string>
<string name="private_inbox_section_explainer">Insert between 1-3 relays to serve as your private inbox. Others will use these relays to send DMs to you. DM Inbox relays should accept any message from anyone, but only allow you to download them. Good options are:\n - inbox.nostr.wine (paid)\n - you.nostr1.com (personal relays - paid)</string>
<string name="kind_3_section">General Relays</string>
<string name="kind_3_section_description">Amethyst uses these relays to download posts for you.</string>
<string name="zap_the_devs_title">Zap the Devs!</string> <string name="zap_the_devs_title">Zap the Devs!</string>
<string name="zap_the_devs_description">Your donation helps us make a difference. Every sat counts!</string> <string name="zap_the_devs_description">Your donation helps us make a difference. Every sat counts!</string>
<string name="donate_now">Donate Now</string> <string name="donate_now">Donate Now</string>