Merge pull request #1806 from vitorpamplona/claude/namecoin-settings-route-qFW0S

Extract Namecoin settings to dedicated screen
This commit is contained in:
Vitor Pamplona
2026-03-11 12:21:57 -04:00
committed by GitHub
6 changed files with 101 additions and 35 deletions
@@ -102,6 +102,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.newUser.ImportFollowListSel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.NotificationScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.NotificationScreen
import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.publicMessages.NewPublicMessageScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.publicMessages.NewPublicMessageScreen
import com.vitorpamplona.amethyst.ui.screen.loggedIn.privacy.PrivacyOptionsScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.privacy.PrivacyOptionsScreen
import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.NamecoinSettingsScreen
import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.ProfileScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.ProfileScreen
import com.vitorpamplona.amethyst.ui.screen.loggedIn.qrcode.ShowQRScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.qrcode.ShowQRScreen
import com.vitorpamplona.amethyst.ui.screen.loggedIn.redirect.LoadRedirectScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.redirect.LoadRedirectScreen
@@ -174,7 +175,8 @@ fun AppNavigation(
composableFromEnd<Route.AllSettings> { AllSettingsScreen(accountViewModel, nav) } composableFromEnd<Route.AllSettings> { AllSettingsScreen(accountViewModel, nav) }
composableFromEnd<Route.AccountBackup> { AccountBackupScreen(accountViewModel, nav) } composableFromEnd<Route.AccountBackup> { AccountBackupScreen(accountViewModel, nav) }
composableFromEnd<Route.SecurityFilters> { SecurityFiltersScreen(accountViewModel, nav) } composableFromEnd<Route.SecurityFilters> { SecurityFiltersScreen(accountViewModel, nav) }
composableFromEnd<Route.PrivacyOptions> { PrivacyOptionsScreen(Amethyst.instance.torPrefs.value, Amethyst.instance.namecoinPrefs, nav) } composableFromEnd<Route.PrivacyOptions> { PrivacyOptionsScreen(Amethyst.instance.torPrefs.value, nav) }
composableFromEnd<Route.NamecoinSettings> { NamecoinSettingsScreen(Amethyst.instance.namecoinPrefs, nav) }
composableFromEnd<Route.Bookmarks> { BookmarkListScreen(accountViewModel, nav) } composableFromEnd<Route.Bookmarks> { BookmarkListScreen(accountViewModel, nav) }
composableFromEnd<Route.Drafts> { DraftListScreen(accountViewModel, nav) } composableFromEnd<Route.Drafts> { DraftListScreen(accountViewModel, nav) }
composableFromEnd<Route.Settings> { SettingsScreen(accountViewModel, nav) } composableFromEnd<Route.Settings> { SettingsScreen(accountViewModel, nav) }
@@ -49,6 +49,8 @@ sealed class Route {
@Serializable object PrivacyOptions : Route() @Serializable object PrivacyOptions : Route()
@Serializable object NamecoinSettings : Route()
@Serializable object Bookmarks : Route() @Serializable object Bookmarks : Route()
@Serializable object BookmarkGroups : Route() @Serializable object BookmarkGroups : Route()
@@ -21,38 +21,29 @@
package com.vitorpamplona.amethyst.ui.screen.loggedIn.privacy package com.vitorpamplona.amethyst.ui.screen.loggedIn.privacy
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.model.preferences.NamecoinSharedPreferences
import com.vitorpamplona.amethyst.ui.navigation.navs.INav import com.vitorpamplona.amethyst.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.ui.navigation.topbars.SavingTopBar import com.vitorpamplona.amethyst.ui.navigation.topbars.SavingTopBar
import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.NamecoinSettingsSection
import com.vitorpamplona.amethyst.ui.tor.PrivacySettingsBody import com.vitorpamplona.amethyst.ui.tor.PrivacySettingsBody
import com.vitorpamplona.amethyst.ui.tor.TorDialogViewModel import com.vitorpamplona.amethyst.ui.tor.TorDialogViewModel
import com.vitorpamplona.amethyst.ui.tor.TorSettings import com.vitorpamplona.amethyst.ui.tor.TorSettings
import com.vitorpamplona.amethyst.ui.tor.TorSettingsFlow import com.vitorpamplona.amethyst.ui.tor.TorSettingsFlow
import kotlinx.coroutines.launch
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun PrivacyOptionsScreen( fun PrivacyOptionsScreen(
torSettingsFlow: TorSettingsFlow, torSettingsFlow: TorSettingsFlow,
namecoinPrefs: NamecoinSharedPreferences,
nav: INav, nav: INav,
) { ) {
val dialogViewModel = viewModel<TorDialogViewModel>() val dialogViewModel = viewModel<TorDialogViewModel>()
@@ -67,20 +58,16 @@ fun PrivacyOptionsScreen(
torSettings torSettings
} }
PrivacyOptionsScreenContents(dialogViewModel, namecoinPrefs, onPost = torSettingsFlow::update, nav) PrivacyOptionsScreenContents(dialogViewModel, onPost = torSettingsFlow::update, nav)
} }
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun PrivacyOptionsScreenContents( fun PrivacyOptionsScreenContents(
dialogViewModel: TorDialogViewModel, dialogViewModel: TorDialogViewModel,
namecoinPrefs: NamecoinSharedPreferences,
onPost: (TorSettings) -> Unit, onPost: (TorSettings) -> Unit,
nav: INav, nav: INav,
) { ) {
val namecoinSettings by namecoinPrefs.settings.collectAsState()
val scope = rememberCoroutineScope()
Scaffold( Scaffold(
topBar = { topBar = {
SavingTopBar( SavingTopBar(
@@ -104,26 +91,6 @@ fun PrivacyOptionsScreenContents(
).padding(horizontal = 10.dp), ).padding(horizontal = 10.dp),
) { ) {
PrivacySettingsBody(dialogViewModel) PrivacySettingsBody(dialogViewModel)
Spacer(Modifier.height(16.dp))
NamecoinSettingsSection(
settings = namecoinSettings,
onToggleEnabled = { enabled ->
scope.launch { namecoinPrefs.setEnabled(enabled) }
},
onAddServer = { server ->
scope.launch { namecoinPrefs.addServer(server) }
},
onRemoveServer = { server ->
scope.launch { namecoinPrefs.removeServer(server) }
},
onReset = {
scope.launch { namecoinPrefs.reset() }
},
)
Spacer(Modifier.height(16.dp))
} }
} }
} }
@@ -146,6 +146,13 @@ fun AllSettingsScreen(
onClick = { nav.nav(Route.PrivacyOptions) }, onClick = { nav.nav(Route.PrivacyOptions) },
) )
HorizontalDivider() HorizontalDivider()
SettingsNavigationRow(
title = R.string.namecoin_settings,
icon = Icons.Outlined.Security,
tint = tint,
onClick = { nav.nav(Route.NamecoinSettings) },
)
HorizontalDivider()
SettingsNavigationRow( SettingsNavigationRow(
title = R.string.ui_preferences, title = R.string.ui_preferences,
icon = Icons.Outlined.Settings, icon = Icons.Outlined.Settings,
@@ -0,0 +1,87 @@
/*
* Copyright (c) 2025 Vitor Pamplona
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* 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.
*/
package com.vitorpamplona.amethyst.ui.screen.loggedIn.settings
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.model.preferences.NamecoinSharedPreferences
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.ui.navigation.topbars.TopBarWithBackButton
import com.vitorpamplona.amethyst.ui.stringRes
import kotlinx.coroutines.launch
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun NamecoinSettingsScreen(
namecoinPrefs: NamecoinSharedPreferences,
nav: INav,
) {
val namecoinSettings by namecoinPrefs.settings.collectAsState()
val scope = rememberCoroutineScope()
Scaffold(
topBar = {
TopBarWithBackButton(stringRes(id = R.string.namecoin_settings), nav::popBack)
},
) {
Column(
Modifier
.padding(it)
.fillMaxSize()
.verticalScroll(rememberScrollState())
.padding(horizontal = 10.dp),
) {
Spacer(Modifier.height(16.dp))
NamecoinSettingsSection(
settings = namecoinSettings,
onToggleEnabled = { enabled ->
scope.launch { namecoinPrefs.setEnabled(enabled) }
},
onAddServer = { server ->
scope.launch { namecoinPrefs.addServer(server) }
},
onRemoveServer = { server ->
scope.launch { namecoinPrefs.removeServer(server) }
},
onReset = {
scope.launch { namecoinPrefs.reset() }
},
)
Spacer(Modifier.height(16.dp))
}
}
}
+1
View File
@@ -1745,4 +1745,5 @@
<string name="import_follows_tips">"Enter the profile of a friend or community leader. You can use their npub, NIP-05 address, or a Namecoin name like alice@example.bit or id/alice for blockchain-verified identities."</string> <string name="import_follows_tips">"Enter the profile of a friend or community leader. You can use their npub, NIP-05 address, or a Namecoin name like alice@example.bit or id/alice for blockchain-verified identities."</string>
<string name="select_all">Select All</string> <string name="select_all">Select All</string>
<string name="uptime">%1$d%% uptime</string> <string name="uptime">%1$d%% uptime</string>
<string name="namecoin_settings">Namecoin Settings</string>
</resources> </resources>