Rename setups and add provider reauthentication

This commit is contained in:
iris committed 2026-09-12 22:56:43 -04:00
1 parent e9a0f1b9da
commit 7d9df5d572
36 files changed
+1866 -684

No files matched your search

@@ -15,6 +15,10 @@ import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@@ -30,7 +34,13 @@ import java.time.OffsetDateTime
* own, so the only thing its Back could ever have meant was "put this away".
*/
@Composable
fun UsageDialog(feed: UsageFeed, session: SessionSummary, onDismiss: () -> Unit) {
fun UsageDialog(
settings: ServerSettings,
feed: UsageFeed,
session: SessionSummary,
onDismiss: () -> Unit,
) {
var signingIn by remember { mutableStateOf(false) }
// A plain Dialog rather than an AlertDialog, for the spacing alone. AlertDialog fixes the gaps
// between its title, content and buttons at sizes meant for a sentence of prose and a decision;
// this is a dense read-out, and those gaps left a band of empty dialog above Close that was
@@ -73,12 +83,12 @@ fun UsageDialog(feed: UsageFeed, session: SessionSummary, onDismiss: () -> Unit)
LoadState.Loaded(
usageSnapshotsFor(
snapshots.value,
session.setup,
session.machine,
session.usageProvider,
)
)
}
UsageBody(state)
UsageBody(state, onSignIn = { signingIn = true })
}
TextButton(onClick = onDismiss, modifier = Modifier.align(Alignment.End)) {
Text("Close")
@@ -86,11 +96,24 @@ fun UsageDialog(feed: UsageFeed, session: SessionSummary, onDismiss: () -> Unit)
}
}
}
if (signingIn) {
ProviderLoginDialog(
settings = settings,
machineId = session.machine,
machineName = session.machineName,
provider = session.provider,
onDismiss = { signingIn = false },
onSignedIn = {
signingIn = false
feed.refresh()
},
)
}
}
/** What came back, or why nothing did. Split out so the dialog above reads as its own shape. */
@Composable
private fun UsageBody(state: LoadState<List<UsageSnapshot>>) {
private fun UsageBody(state: LoadState<List<UsageSnapshot>>, onSignIn: () -> Unit) {
Column {
when (val current = state) {
is LoadState.Loading -> CircularProgressIndicator()
@@ -122,7 +145,7 @@ private fun UsageBody(state: LoadState<List<UsageSnapshot>>) {
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant,
)
SnapshotState(snapshot)
SnapshotState(snapshot, onSignIn)
snapshot.windows.forEachIndexed { windowIndex, window ->
// Between the bars, not after the last one: a trailing gap here is what
// put a band of empty dialog above the Close button.
@@ -138,7 +161,7 @@ private fun UsageBody(state: LoadState<List<UsageSnapshot>>) {
}
private fun usageSectionTitle(snapshot: UsageSnapshot): String {
val machine = snapshot.setupName.ifEmpty { snapshot.setup }
val machine = snapshot.machineName.ifEmpty { snapshot.machine }
val provider = snapshot.provider
val pool =
if (provider == "codex" && snapshot.limitId != "codex") {
@@ -156,15 +179,25 @@ private fun usageSectionTitle(snapshot: UsageSnapshot): String {
*
* The distinction the old single message could not draw. A machine nobody has logged in on is
* working exactly as somebody set it up, so it reads as a plain statement -- marking it would be
* the interface nagging about a decision already made. Only the two faults are coloured as faults.
* the interface nagging about a decision already made. It still offers the direct sign-in action;
* unreachable and provider failures are the states coloured as faults.
*/
@Composable
private fun SnapshotState(snapshot: UsageSnapshot) {
private fun SnapshotState(snapshot: UsageSnapshot, onSignIn: () -> Unit) {
when (snapshot.state) {
"ok" -> {}
"notLoggedIn" ->
"notLoggedIn",
"loginRequired" -> {
Text(
"No Claude account on this machine.",
snapshot.detail ?: "No Claude account on this machine.",
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant,
)
TextButton(onClick = onSignIn) { Text("Sign in") }
}
"authenticating" ->
Text(
"Claude sign-in is in progress.",
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant,
)