feat: auto-publish key package on MarmotGroupListScreen entry
Replace the manual KeyPackage publish button with a LaunchedEffect that auto-publishes if no key package exists yet. The subscription already correctly downloads our own kind:30443 via ownKeyPackageFilter() on home relays, and rotation is handled reactively when Welcome messages are processed. https://claude.ai/code/session_01LhfCp8DHqNVx6mSiYfpQny
This commit is contained in:
+12
-57
@@ -36,8 +36,6 @@ import androidx.compose.foundation.shape.CircleShape
|
|||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||||
import androidx.compose.material.icons.filled.Add
|
import androidx.compose.material.icons.filled.Add
|
||||||
import androidx.compose.material.icons.filled.VpnKey
|
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.FloatingActionButton
|
import androidx.compose.material3.FloatingActionButton
|
||||||
import androidx.compose.material3.HorizontalDivider
|
import androidx.compose.material3.HorizontalDivider
|
||||||
@@ -45,8 +43,6 @@ import androidx.compose.material3.Icon
|
|||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.SnackbarHost
|
|
||||||
import androidx.compose.material3.SnackbarHostState
|
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TopAppBar
|
import androidx.compose.material3.TopAppBar
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
@@ -54,12 +50,10 @@ import androidx.compose.runtime.LaunchedEffect
|
|||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
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.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.StrokeCap
|
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
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.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
@@ -71,8 +65,6 @@ import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
|||||||
import com.vitorpamplona.amethyst.ui.navigation.routes.Route
|
import com.vitorpamplona.amethyst.ui.navigation.routes.Route
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
@@ -81,10 +73,6 @@ fun MarmotGroupListScreen(
|
|||||||
nav: INav,
|
nav: INav,
|
||||||
) {
|
) {
|
||||||
var groupList by remember { mutableStateOf(listOf<Pair<HexKey, MarmotGroupChatroom>>()) }
|
var groupList by remember { mutableStateOf(listOf<Pair<HexKey, MarmotGroupChatroom>>()) }
|
||||||
val scope = rememberCoroutineScope()
|
|
||||||
val snackbarHostState = remember { SnackbarHostState() }
|
|
||||||
var isPublishing by remember { mutableStateOf(false) }
|
|
||||||
var hasPublishedKeyPackage by remember { mutableStateOf(accountViewModel.hasPublishedKeyPackage()) }
|
|
||||||
|
|
||||||
// Load group list
|
// Load group list
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
@@ -98,6 +86,17 @@ fun MarmotGroupListScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Auto-publish KeyPackage if none exists yet
|
||||||
|
LaunchedEffect(Unit) {
|
||||||
|
if (!accountViewModel.hasPublishedKeyPackage()) {
|
||||||
|
try {
|
||||||
|
accountViewModel.publishMarmotKeyPackage()
|
||||||
|
} catch (_: Exception) {
|
||||||
|
// Silently retry on next screen visit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
@@ -110,47 +109,8 @@ fun MarmotGroupListScreen(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
title = { Text("Marmot Groups") },
|
title = { Text("Marmot Groups") },
|
||||||
actions = {
|
|
||||||
if (isPublishing) {
|
|
||||||
CircularProgressIndicator(
|
|
||||||
modifier = Modifier.padding(12.dp).size(24.dp),
|
|
||||||
strokeWidth = 2.dp,
|
|
||||||
strokeCap = StrokeCap.Round,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
IconButton(
|
|
||||||
onClick = {
|
|
||||||
isPublishing = true
|
|
||||||
scope.launch(Dispatchers.IO) {
|
|
||||||
try {
|
|
||||||
accountViewModel.publishMarmotKeyPackage()
|
|
||||||
hasPublishedKeyPackage = true
|
|
||||||
snackbarHostState.showSnackbar("KeyPackage published successfully")
|
|
||||||
} catch (e: Exception) {
|
|
||||||
snackbarHostState.showSnackbar("Failed to publish KeyPackage: ${e.message}")
|
|
||||||
} finally {
|
|
||||||
isPublishing = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Default.VpnKey,
|
|
||||||
contentDescription =
|
|
||||||
if (hasPublishedKeyPackage) "Republish KeyPackage" else "Publish KeyPackage",
|
|
||||||
tint =
|
|
||||||
if (hasPublishedKeyPackage) {
|
|
||||||
MaterialTheme.colorScheme.primary
|
|
||||||
} else {
|
|
||||||
MaterialTheme.colorScheme.onSurfaceVariant
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
snackbarHost = { SnackbarHost(snackbarHostState) },
|
|
||||||
floatingActionButton = {
|
floatingActionButton = {
|
||||||
FloatingActionButton(onClick = { nav.nav(Route.CreateMarmotGroup) }, shape = CircleShape) {
|
FloatingActionButton(onClick = { nav.nav(Route.CreateMarmotGroup) }, shape = CircleShape) {
|
||||||
Icon(Icons.Default.Add, contentDescription = "Create Group")
|
Icon(Icons.Default.Add, contentDescription = "Create Group")
|
||||||
@@ -168,12 +128,7 @@ fun MarmotGroupListScreen(
|
|||||||
style = MaterialTheme.typography.titleMedium,
|
style = MaterialTheme.typography.titleMedium,
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
text =
|
text = "Create a group or wait for an invitation.",
|
||||||
if (hasPublishedKeyPackage) {
|
|
||||||
"Your KeyPackage is published. Waiting for group invitations."
|
|
||||||
} else {
|
|
||||||
"Tap the key icon above to publish your KeyPackage and receive invitations."
|
|
||||||
},
|
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
modifier = Modifier.padding(top = 4.dp),
|
modifier = Modifier.padding(top = 4.dp),
|
||||||
|
|||||||
Reference in New Issue
Block a user