add b/w filter to random widget (android)

This commit is contained in:
Valentin Bischof 2025-08-31 15:21:31 +02:00
parent 03dafba522
commit b42a627c82
4 changed files with 71 additions and 1 deletions

View file

@ -2,6 +2,10 @@ package app.alextran.immich.widget
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Canvas
import android.graphics.ColorMatrix
import android.graphics.ColorMatrixColorFilter
import android.graphics.Paint
import java.io.File
fun loadScaledBitmap(file: File, reqWidth: Int, reqHeight: Int): Bitmap? {
@ -31,3 +35,24 @@ fun calculateInSampleSize(options: BitmapFactory.Options, reqWidth: Int, reqHeig
return inSampleSize
}
fun applyBlackWhiteFilter(src: Bitmap): Bitmap {
val config = src.config ?: Bitmap.Config.ARGB_8888
val outputBitmap = Bitmap.createBitmap(src.width, src.height, config)
outputBitmap.setHasAlpha(src.hasAlpha())
val canvas = Canvas(outputBitmap)
val paint = Paint().apply {
isFilterBitmap = true
val colorMatrix = ColorMatrix().apply {
setSaturation(0f)
}
colorFilter = ColorMatrixColorFilter(colorMatrix)
}
canvas.drawBitmap(src, 0f, 0f, paint)
return outputBitmap
}

View file

@ -122,6 +122,13 @@ class ImageDownloadWorker(
WidgetType.MEMORIES -> fetchMemory(serverConfig)
}
// if needed apply our filter
val filter = WidgetImageFilter.fromString(widgetConfig[kImageFilter])
val filteredImage = when (filter) {
WidgetImageFilter.BLACK_WHITE -> applyBlackWhiteFilter(entry.image)
WidgetImageFilter.NONE -> entry.image
}
// clear current image if it exists
if (!currentImgUUID.isNullOrEmpty()) {
deleteImage(currentImgUUID)
@ -129,7 +136,7 @@ class ImageDownloadWorker(
// save a new image
val imgUUID = UUID.randomUUID().toString()
saveImage(entry.image, imgUUID)
saveImage(filteredImage, imgUUID)
// trigger the update routine with new image uuid
updateWidget(glanceId, imgUUID, entry.subtitle, entry.deeplink)

View file

@ -64,6 +64,7 @@ fun RandomConfiguration(context: Context, appWidgetId: Int, glanceId: GlanceId,
var selectedAlbum by remember { mutableStateOf<DropdownItem?>(null) }
var showAlbumName by remember { mutableStateOf(false) }
var selectedFilter by remember { mutableStateOf<DropdownItem?>(null) }
var availableAlbums by remember { mutableStateOf<List<DropdownItem>>(listOf()) }
var state by remember { mutableStateOf(WidgetConfigState.LOADING) }
@ -104,6 +105,16 @@ fun RandomConfiguration(context: Context, appWidgetId: Int, glanceId: GlanceId,
val albumEntity = availableAlbums.firstOrNull { it.id == currentAlbumId }
selectedAlbum = albumEntity ?: availableAlbums.first()
// load filter configuration
val availableFilters = listOf(
DropdownItem("None", WidgetImageFilter.NONE.name),
DropdownItem("Black & White", WidgetImageFilter.BLACK_WHITE.name)
)
val savedFilterId = currentState[kImageFilter] ?: WidgetImageFilter.NONE.name
val selectedFilterItem = availableFilters.firstOrNull { it.id == savedFilterId }
selectedFilter = selectedFilterItem ?: availableFilters.first()
// load showAlbumName
showAlbumName = currentState[kShowAlbumName] == true
}
@ -113,6 +124,7 @@ fun RandomConfiguration(context: Context, appWidgetId: Int, glanceId: GlanceId,
prefs[kSelectedAlbum] = selectedAlbum?.id ?: ""
prefs[kSelectedAlbumName] = selectedAlbum?.label ?: ""
prefs[kShowAlbumName] = showAlbumName
prefs[kImageFilter] = selectedFilter?.id ?: WidgetImageFilter.NONE.name
}
ImageDownloadWorker.singleShot(context, appWidgetId, WidgetType.RANDOM)
@ -187,6 +199,17 @@ fun RandomConfiguration(context: Context, appWidgetId: Int, glanceId: GlanceId,
enabled = (state != WidgetConfigState.NO_CONNECTION)
)
Text("Filter")
Dropdown(
items = listOf(
DropdownItem("None", WidgetImageFilter.NONE.name),
DropdownItem("Black & White", WidgetImageFilter.BLACK_WHITE.name)
),
selectedItem = selectedFilter,
onItemSelected = { selectedFilter = it },
enabled = (state != WidgetConfigState.NO_CONNECTION)
)
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween,

View file

@ -49,6 +49,20 @@ enum class WidgetConfigState {
LOADING, SUCCESS, LOG_IN, NO_CONNECTION
}
enum class WidgetImageFilter {
NONE, BLACK_WHITE;
companion object {
fun fromString(value: String?): WidgetImageFilter {
return try {
valueOf(value ?: NONE.name)
} catch (e: IllegalArgumentException) {
NONE
}
}
}
}
data class WidgetEntry (
val image: Bitmap,
val subtitle: String?,
@ -70,6 +84,7 @@ val kSelectedAlbum = stringPreferencesKey("albumID")
val kSelectedAlbumName = stringPreferencesKey("albumName")
val kShowAlbumName = booleanPreferencesKey("showAlbumName")
val kDeeplinkURL = stringPreferencesKey("deeplink")
val kImageFilter = stringPreferencesKey("imageFiler")
const val kWorkerWidgetType = "widgetType"
const val kWorkerWidgetID = "widgetId"