Update intent parsing to allow for user switching to home page (#1962)

## Description
Makes the `itemId` parameter optional allowing just passing
`serverId`/`userId` to switch the user and load the app at the home page
for that user.

Dev note: I added a new assert function `assertIs` which asserts that an
object `is` of a type. It also has a contract so the compiler will
smart-cast usages after the `assertIs`. Checking a result type is a very
common pattern in the unit tests, so this assert will simplify a lot of
current & future tests.

### Related issues
Closes https://github.com/damontecres/Wholphin/discussions/1824

### Testing
Emulator and added unit tests for `parseIntent`

## Screenshots
N/A

## AI or LLM usage
None
This commit is contained in:
Damontecres 2026-09-15 13:07:08 -04:00 • committed by GitHub
parent 8effd2b1e7
commit ffdebd43c3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 321 additions and 24 deletions

View file

@ -55,30 +55,37 @@ class IntentService
val query = intent.getStringParam(SearchManager.QUERY)
return IntentResult.Target(listOf(Destination.Search(query ?: "")))
}
val itemId =
intent.getStringParam("itemId")?.toUUIDOrNull()
?: return IntentResult.Error("No item id provided")
val itemId = intent.getStringParam("itemId")?.toUUIDOrNull()
val item =
try {
api.userLibraryApi
.getItem(itemId)
.content
.let { BaseItem(it) }
} catch (ex: Exception) {
Timber.w(ex, "Error fetching item %s", itemId)
return IntentResult.Error("Could not fetch item $itemId")
itemId?.let {
try {
api.userLibraryApi
.getItem(itemId)
.content
.let { BaseItem(it) }
} catch (ex: Exception) {
Timber.w(ex, "Error fetching item %s", itemId)
return IntentResult.Error("Could not fetch item $itemId")
}
}
val itemDestination = item.destination()
val itemDestination = item?.destination()
val destinations =
when (action) {
Intent.ACTION_VIEW, "view" -> {
listOf(itemDestination)
if (itemDestination != null) {
listOf(itemDestination)
} else {
// Will go to the home page
emptyList()
}
}
"com.github.damontecres.wholphin.PLAYBACK", "play" -> {
ACTION_PLAYBACK, "play" -> {
if (itemId == null || itemDestination == null) {
return IntentResult.Error("Cannot start playback with no itemId")
}
val position = intent.getLongParam("position")?.coerceAtLeast(0)
val shuffle = intent.getBooleanExtra("shuffle", false)
@ -104,7 +111,7 @@ class IntentService
}
}
return IntentResult.Target(destinations)
return IntentResult.Target(destinations, true)
}
internal suspend fun prepare(intent: Intent): IntentResult? {
@ -195,6 +202,8 @@ class IntentService
const val INTENT_SEASON_ID = "seaId"
const val INTENT_SERVER_ID = "serverId"
const val INTENT_USER_ID = "userId"
const val ACTION_PLAYBACK = "com.github.damontecres.wholphin.PLAYBACK"
}
}