add deeplinks

This commit is contained in:
bwees 2025-07-03 11:12:42 -05:00
parent 42e53232c3
commit 403b5dd930
No known key found for this signature in database
4 changed files with 53 additions and 17 deletions

View File

@ -94,14 +94,20 @@ class ImageDownloadWorker(
if (serverConfig == null) {
if (!currentImgUUID.isNullOrEmpty()) {
deleteImage(currentImgUUID)
updateWidget(glanceId, "", "", WidgetState.LOG_IN)
updateWidget(
glanceId,
"",
"",
"immich://",
WidgetState.LOG_IN
)
}
return Result.success()
}
// fetch new image
val (newBitmap, subtitle) = when (widgetType) {
val entry = when (widgetType) {
WidgetType.RANDOM -> fetchRandom(serverConfig, widgetConfig)
WidgetType.MEMORIES -> fetchMemory(serverConfig)
}
@ -113,10 +119,10 @@ class ImageDownloadWorker(
// save a new image
val imgUUID = UUID.randomUUID().toString()
saveImage(newBitmap, imgUUID)
saveImage(entry.image, imgUUID)
// trigger the update routine with new image uuid
updateWidget(glanceId, imgUUID, subtitle)
updateWidget(glanceId, imgUUID, entry.subtitle, entry.deeplink)
Result.success()
} catch (e: Exception) {
@ -133,6 +139,7 @@ class ImageDownloadWorker(
glanceId: GlanceId,
imageUUID: String,
subtitle: String?,
deeplink: String?,
widgetState: WidgetState = WidgetState.SUCCESS
) {
updateAppWidgetState(context, glanceId) { prefs ->
@ -140,6 +147,7 @@ class ImageDownloadWorker(
prefs[kImageUUID] = imageUUID
prefs[kWidgetState] = widgetState.toString()
prefs[kSubtitleText] = subtitle ?: ""
prefs[kDeeplinkURL] = deeplink ?: ""
}
PhotoWidget().update(context,glanceId)
@ -148,7 +156,7 @@ class ImageDownloadWorker(
private suspend fun fetchRandom(
serverConfig: ServerConfig,
widgetConfig: Preferences
): Pair<Bitmap, String?> {
): WidgetEntry {
val api = ImmichAPI(serverConfig)
val filters = SearchFilters(AssetType.IMAGE, size=1)
@ -164,17 +172,21 @@ class ImageDownloadWorker(
val random = api.fetchSearchResults(filters).first()
val image = api.fetchImage(random)
return Pair(image, subtitle)
return WidgetEntry(
image,
subtitle,
assetDeeplink(random)
)
}
private suspend fun fetchMemory(
serverConfig: ServerConfig
): Pair<Bitmap, String?> {
): WidgetEntry {
val api = ImmichAPI(serverConfig)
val today = LocalDate.now()
val memories = api.fetchMemory(today)
val asset: SearchResult
val asset: Asset
var subtitle: String? = null
if (memories.isNotEmpty()) {
@ -189,7 +201,11 @@ class ImageDownloadWorker(
}
val image = api.fetchImage(asset)
return Pair(image, subtitle)
return WidgetEntry(
image,
subtitle,
assetDeeplink(asset)
)
}
private suspend fun deleteImage(uuid: String) = withContext(Dispatchers.IO) {

View File

@ -53,7 +53,7 @@ class ImmichAPI(cfg: ServerConfig) {
return URL(urlString.toString())
}
suspend fun fetchSearchResults(filters: SearchFilters): List<SearchResult> = withContext(Dispatchers.IO) {
suspend fun fetchSearchResults(filters: SearchFilters): List<Asset> = withContext(Dispatchers.IO) {
val url = buildRequestURL("/search/random")
val connection = (url.openConnection() as HttpURLConnection).apply {
requestMethod = "POST"
@ -69,7 +69,7 @@ class ImmichAPI(cfg: ServerConfig) {
}
val response = connection.inputStream.bufferedReader().readText()
val type = object : TypeToken<List<SearchResult>>() {}.type
val type = object : TypeToken<List<Asset>>() {}.type
gson.fromJson(response, type)
}
@ -85,7 +85,7 @@ class ImmichAPI(cfg: ServerConfig) {
gson.fromJson(response, type)
}
suspend fun fetchImage(asset: SearchResult): Bitmap = withContext(Dispatchers.IO) {
suspend fun fetchImage(asset: Asset): Bitmap = withContext(Dispatchers.IO) {
val url = buildRequestURL("/assets/${asset.id}/thumbnail", listOf("size" to "preview"))
val connection = url.openConnection()
val data = connection.getInputStream().readBytes()

View File

@ -1,5 +1,6 @@
package app.alextran.immich.widget
import android.graphics.Bitmap
import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.doublePreferencesKey
import androidx.datastore.preferences.core.longPreferencesKey
@ -12,9 +13,9 @@ enum class AssetType {
IMAGE, VIDEO, AUDIO, OTHER
}
data class SearchResult(
data class Asset(
val id: String,
val type: AssetType
val type: AssetType,
)
data class SearchFilters(
@ -25,7 +26,7 @@ data class SearchFilters(
data class MemoryResult(
val id: String,
var assets: List<SearchResult>,
var assets: List<Asset>,
val type: String,
val data: MemoryData
) {
@ -47,6 +48,12 @@ enum class WidgetState {
LOADING, SUCCESS, LOG_IN;
}
data class WidgetEntry (
val image: Bitmap,
val subtitle: String?,
val deeplink: String?
)
data class ServerConfig(val serverEndpoint: String, val sessionKey: String)
// MARK: Widget State Keys
@ -57,6 +64,7 @@ val kWidgetState = stringPreferencesKey("state")
val kSelectedAlbum = stringPreferencesKey("albumID")
val kSelectedAlbumName = stringPreferencesKey("albumName")
val kShowAlbumName = booleanPreferencesKey("showAlbumName")
val kDeeplinkURL = stringPreferencesKey("deeplink")
const val kWorkerWidgetType = "widgetType"
const val kWorkerWidgetID = "widgetId"
@ -64,3 +72,7 @@ const val kWorkerWidgetID = "widgetId"
fun imageFilename(id: String): String {
return "widget_image_$id.jpg"
}
fun assetDeeplink(asset: Asset): String {
return "immich://asset?id=${asset.id}"
}

View File

@ -1,9 +1,11 @@
package app.alextran.immich.widget
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.*
import androidx.core.net.toUri
import androidx.datastore.preferences.core.MutablePreferences
import androidx.glance.appwidget.*
import androidx.glance.*
@ -25,7 +27,8 @@ class PhotoWidget : GlanceAppWidget() {
val prefs = currentState<MutablePreferences>()
val imageUUID = prefs[kImageUUID]
val subtitle: String? = prefs[kSubtitleText]
val subtitle = prefs[kSubtitleText]
val deeplinkURL = prefs[kDeeplinkURL]?.toUri()
var bitmap: Bitmap? = null
if (imageUUID != null) {
@ -42,6 +45,11 @@ class PhotoWidget : GlanceAppWidget() {
modifier = GlanceModifier
.fillMaxSize()
.background(Color.White)
.clickable {
val intent = Intent(Intent.ACTION_VIEW, deeplinkURL ?: "immich://".toUri())
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
context.startActivity(intent)
}
) {
if (bitmap != null) {
Image(