mirror of
https://github.com/immich-app/immich.git
synced 2025-07-09 03:04:16 -04:00
add deeplinks
This commit is contained in:
parent
42e53232c3
commit
403b5dd930
@ -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()) {
|
||||
@ -182,14 +194,18 @@ class ImageDownloadWorker(
|
||||
val memory = memories.random()
|
||||
asset = memory.assets.random()
|
||||
|
||||
subtitle = "${today.year-memory.data.year} years ago"
|
||||
subtitle = "${today.year - memory.data.year} years ago"
|
||||
} else {
|
||||
val filters = SearchFilters(AssetType.IMAGE, size=1)
|
||||
asset = api.fetchSearchResults(filters).first()
|
||||
}
|
||||
|
||||
val image = api.fetchImage(asset)
|
||||
return Pair(image, subtitle)
|
||||
return WidgetEntry(
|
||||
image,
|
||||
subtitle,
|
||||
assetDeeplink(asset)
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun deleteImage(uuid: String) = withContext(Dispatchers.IO) {
|
||||
|
@ -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()
|
||||
|
@ -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}"
|
||||
}
|
||||
|
@ -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(
|
||||
|
Loading…
x
Reference in New Issue
Block a user