fix(client/android): a pinned console tile is a shortcut, not a second host
The touch grid withholds Edit / Forget / Wake from a pinned card on purpose — a pin is a shortcut to one host+profile combination, and offering the host's destructive actions on it blurs exactly that. The console carousel didn't: its pinned tiles carried the host record, so Up on one opened the full host options (including Forget), and Y opened the host's library. They now carry which profile they pin, so the options dialog offers the one action a pin has — Unpin — and says what unpinning does and doesn't touch.
This commit is contained in:
@@ -275,7 +275,7 @@ fun ConnectScreen(
|
|||||||
var editTarget by remember { mutableStateOf<KnownHost?>(null) }
|
var editTarget by remember { mutableStateOf<KnownHost?>(null) }
|
||||||
// A saved host whose console options menu (Wake / Edit / Forget) is open — reached with Up on the
|
// A saved host whose console options menu (Wake / Edit / Forget) is open — reached with Up on the
|
||||||
// carousel (the console counterpart of the touch host card's overflow menu).
|
// carousel (the console counterpart of the touch host card's overflow menu).
|
||||||
var optionsTarget by remember { mutableStateOf<KnownHost?>(null) }
|
var optionsTarget by remember { mutableStateOf<HostCardEntry?>(null) }
|
||||||
|
|
||||||
// Discovered hosts not already saved — a saved host (paired or TOFU) belongs in "Saved hosts",
|
// Discovered hosts not already saved — a saved host (paired or TOFU) belongs in "Saved hosts",
|
||||||
// not also in "Discovered", so we hide the overlap (matched by fingerprint when both carry it, so
|
// not also in "Discovered", so we hide the overlap (matched by fingerprint when both carry it, so
|
||||||
@@ -718,6 +718,7 @@ fun ConnectScreen(
|
|||||||
online = kh.isOnline(discovered, reachable),
|
online = kh.isOnline(discovered, reachable),
|
||||||
paired = kh.paired,
|
paired = kh.paired,
|
||||||
knownHost = kh,
|
knownHost = kh,
|
||||||
|
pinnedProfileId = p.id,
|
||||||
activate = { connect(kh.address, kh.port, oneOffProfile = p.id) },
|
activate = { connect(kh.address, kh.port, oneOffProfile = p.id) },
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@@ -758,7 +759,11 @@ fun ConnectScreen(
|
|||||||
onActivate = { it.activate() },
|
onActivate = { it.activate() },
|
||||||
onOpenLibrary = { it.knownHost?.let(onOpenLibrary) },
|
onOpenLibrary = { it.knownHost?.let(onOpenLibrary) },
|
||||||
onOpenSettings = onOpenSettings,
|
onOpenSettings = onOpenSettings,
|
||||||
onOptions = { it.knownHost?.let { kh -> optionsTarget = kh } },
|
onOptions = { tile ->
|
||||||
|
tile.knownHost?.let { kh ->
|
||||||
|
optionsTarget = HostCardEntry(kh, tile.pinnedProfileId?.let(profileStore::byId))
|
||||||
|
}
|
||||||
|
},
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
Box(Modifier.fillMaxSize()) {
|
Box(Modifier.fillMaxSize()) {
|
||||||
@@ -1028,7 +1033,9 @@ fun ConnectScreen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Console host options (Up on a saved carousel tile): Wake / Edit / Forget.
|
// Console host options (Up on a saved carousel tile): Wake / Edit / Forget.
|
||||||
optionsTarget?.let { kh ->
|
optionsTarget?.let { entry ->
|
||||||
|
val kh = entry.host
|
||||||
|
val pin = entry.pin
|
||||||
val offline = !kh.isOnline(discovered, reachable)
|
val offline = !kh.isOnline(discovered, reachable)
|
||||||
GamepadHostOptionsDialog(
|
GamepadHostOptionsDialog(
|
||||||
hostName = kh.name,
|
hostName = kh.name,
|
||||||
@@ -1048,7 +1055,7 @@ fun ConnectScreen(
|
|||||||
},
|
},
|
||||||
// A saved host always has a library (it's a knownHost) → offer it when the setting's on,
|
// A saved host always has a library (it's a knownHost) → offer it when the setting's on,
|
||||||
// so a TV remote reaches the library here instead of via the Y face button.
|
// so a TV remote reaches the library here instead of via the Y face button.
|
||||||
onLibrary = if (settings.libraryEnabled) {
|
onLibrary = if (settings.libraryEnabled && pin == null) {
|
||||||
{ optionsTarget = null; onOpenLibrary(kh) }
|
{ optionsTarget = null; onOpenLibrary(kh) }
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
@@ -1060,6 +1067,9 @@ fun ConnectScreen(
|
|||||||
optionsTarget = null
|
optionsTarget = null
|
||||||
},
|
},
|
||||||
onDismiss = { optionsTarget = null },
|
onDismiss = { optionsTarget = null },
|
||||||
|
// A pin's only action: unpinning touches neither the host nor the profile.
|
||||||
|
onUnpin = pin?.let { p -> { togglePin(kh, p); optionsTarget = null } },
|
||||||
|
profileName = pin?.name,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -213,11 +213,23 @@ fun GamepadHostOptionsDialog(
|
|||||||
onEdit: () -> Unit,
|
onEdit: () -> Unit,
|
||||||
onForget: () -> Unit,
|
onForget: () -> Unit,
|
||||||
onDismiss: () -> Unit,
|
onDismiss: () -> Unit,
|
||||||
|
/**
|
||||||
|
* Non-null when this is a PINNED host+profile tile, whose only action is to unpin. A pin is a
|
||||||
|
* shortcut, not a second host — offering the host's destructive actions on it would blur
|
||||||
|
* exactly that, and the touch grid withholds them for the same reason.
|
||||||
|
*/
|
||||||
|
onUnpin: (() -> Unit)? = null,
|
||||||
|
profileName: String? = null,
|
||||||
) {
|
) {
|
||||||
GamepadDialog(
|
GamepadDialog(
|
||||||
title = hostName,
|
title = if (profileName != null) "$hostName · $profileName" else hostName,
|
||||||
onDismiss = onDismiss,
|
onDismiss = onDismiss,
|
||||||
actions = buildList {
|
actions = buildList {
|
||||||
|
if (onUnpin != null) {
|
||||||
|
add(DialogAction("Unpin card", primary = true, onClick = onUnpin))
|
||||||
|
add(DialogAction("Cancel", onClick = onDismiss))
|
||||||
|
return@buildList
|
||||||
|
}
|
||||||
if (onLibrary != null) add(DialogAction("Library", primary = true, onClick = onLibrary))
|
if (onLibrary != null) add(DialogAction("Library", primary = true, onClick = onLibrary))
|
||||||
if (canWake) add(DialogAction("Wake host", onClick = onWake))
|
if (canWake) add(DialogAction("Wake host", onClick = onWake))
|
||||||
add(DialogAction("Edit…", primary = onLibrary == null, onClick = onEdit))
|
add(DialogAction("Edit…", primary = onLibrary == null, onClick = onEdit))
|
||||||
@@ -225,7 +237,14 @@ fun GamepadHostOptionsDialog(
|
|||||||
add(DialogAction("Cancel", onClick = onDismiss))
|
add(DialogAction("Cancel", onClick = onDismiss))
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
DialogText("Manage this saved host.")
|
DialogText(
|
||||||
|
if (onUnpin != null) {
|
||||||
|
"This card is a shortcut to this host with one profile. Unpinning it changes " +
|
||||||
|
"nothing about the host or the profile."
|
||||||
|
} else {
|
||||||
|
"Manage this saved host."
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -73,11 +73,17 @@ class HomeTile(
|
|||||||
val connecting: Boolean = false,
|
val connecting: Boolean = false,
|
||||||
val isAdd: Boolean = false, // the trailing Add Host tile (plus icon, not a monogram)
|
val isAdd: Boolean = false, // the trailing Add Host tile (plus icon, not a monogram)
|
||||||
val knownHost: KnownHost? = null, // set for saved hosts → enables the library (Y)
|
val knownHost: KnownHost? = null, // set for saved hosts → enables the library (Y)
|
||||||
|
/**
|
||||||
|
* Set when this tile is a PINNED host+profile combination rather than the host's own tile.
|
||||||
|
* A pin is a shortcut, not a second host: the host-level actions (wake, edit, forget, library)
|
||||||
|
* belong to the host's own tile, and this one offers only Unpin.
|
||||||
|
*/
|
||||||
|
val pinnedProfileId: String? = null,
|
||||||
val activate: () -> Unit,
|
val activate: () -> Unit,
|
||||||
) {
|
) {
|
||||||
// Any SAVED host offers the library (matches Apple) — the fetch itself returns a clear "pair
|
// Any SAVED host offers the library (matches Apple) — the fetch itself returns a clear "pair
|
||||||
// first" message if the host hasn't authorized this device for its management API.
|
// first" message if the host hasn't authorized this device for its management API.
|
||||||
val hasLibrary: Boolean get() = knownHost != null
|
val hasLibrary: Boolean get() = knownHost != null && pinnedProfileId == null
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user