mirror of
https://github.com/LawnchairLauncher/lawnchair.git
synced 2026-02-27 15:26:58 +00:00
fixup : pop-up wallpaper carousel
- fixed item duplication
This commit is contained in:
@@ -26,6 +26,7 @@ import app.lawnchair.wallpaper.service.Wallpaper
|
||||
import com.android.launcher3.R
|
||||
import com.android.launcher3.util.Themes
|
||||
import com.android.launcher3.views.ActivityContext
|
||||
import java.io.File
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -129,13 +130,25 @@ class WallpaperCarouselView @JvmOverloads constructor(
|
||||
addView(cardView)
|
||||
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val bitmap = BitmapFactory.decodeFile(wallpaper.imagePath)
|
||||
withContext(Dispatchers.Main) {
|
||||
(cardView.getChildAt(0) as? ImageView)?.apply {
|
||||
setImageBitmap(bitmap)
|
||||
val wallpaperFile = File(wallpaper.imagePath)
|
||||
if (wallpaperFile.exists()) {
|
||||
val bitmap = BitmapFactory.decodeFile(wallpaper.imagePath)
|
||||
withContext(Dispatchers.Main) {
|
||||
(cardView.getChildAt(0) as? ImageView)?.apply {
|
||||
setImageBitmap(bitmap)
|
||||
}
|
||||
if (index == currentItemIndex) {
|
||||
addIconFrameToCenter(cardView)
|
||||
}
|
||||
}
|
||||
if (index == currentItemIndex) {
|
||||
addIconFrameToCenter(cardView)
|
||||
} else {
|
||||
Log.e("WallpaperCarouselView", "File not found: ${wallpaper.imagePath}")
|
||||
withContext(Dispatchers.Main) {
|
||||
(cardView.getChildAt(0) as? ImageView)?.apply {
|
||||
setImageDrawable(
|
||||
ContextCompat.getDrawable(context, R.drawable.ic_deepshortcut_placeholder),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -163,6 +176,8 @@ class WallpaperCarouselView @JvmOverloads constructor(
|
||||
|
||||
wallpaperManager.setBitmap(bitmap, null, true, WallpaperManager.FLAG_SYSTEM)
|
||||
|
||||
viewModel.updateWallpaperRank(wallpaper)
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
currentCardView.removeView(loadingSpinner)
|
||||
addIconFrameToCenter(currentCardView)
|
||||
|
||||
@@ -5,17 +5,13 @@ import android.content.Context
|
||||
import app.lawnchair.util.MainThreadInitializedObject
|
||||
import app.lawnchair.util.requireSystemService
|
||||
import app.lawnchair.wallpaper.WallpaperColorsCompat.Companion.HINT_SUPPORTS_DARK_THEME
|
||||
import app.lawnchair.wallpaper.service.WallpaperService
|
||||
import com.android.launcher3.Utilities
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
sealed class WallpaperManagerCompat(val context: Context) {
|
||||
|
||||
private val listeners = mutableListOf<OnColorsChangedListener>()
|
||||
private val colorHints: Int get() = wallpaperColors?.colorHints ?: 0
|
||||
protected val wallpaperManager: WallpaperManager = context.requireSystemService()
|
||||
val wallpaperManager: WallpaperManager = context.requireSystemService()
|
||||
|
||||
abstract val wallpaperColors: WallpaperColorsCompat?
|
||||
|
||||
@@ -33,10 +29,6 @@ sealed class WallpaperManagerCompat(val context: Context) {
|
||||
listeners.toTypedArray().forEach {
|
||||
it.onColorsChanged()
|
||||
}
|
||||
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
WallpaperService(context).saveWallpaper(wallpaperManager)
|
||||
}
|
||||
}
|
||||
|
||||
interface OnColorsChangedListener {
|
||||
|
||||
@@ -1,28 +1,65 @@
|
||||
package app.lawnchair.wallpaper.model
|
||||
|
||||
import android.app.WallpaperManager
|
||||
import android.content.Context
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import app.lawnchair.wallpaper.WallpaperManagerCompat
|
||||
import app.lawnchair.wallpaper.service.Wallpaper
|
||||
import app.lawnchair.wallpaper.service.WallpaperDatabase
|
||||
import app.lawnchair.wallpaper.service.WallpaperService
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
|
||||
class WallpaperViewModel(context: Context) : ViewModel() {
|
||||
private val dao = WallpaperDatabase.INSTANCE.get(context).wallpaperDao()
|
||||
private val service = WallpaperService.INSTANCE.get(context)
|
||||
|
||||
private val wallpaperManagerCompat = WallpaperManagerCompat.INSTANCE.get(context)
|
||||
|
||||
private val _wallpapers = MutableLiveData<List<Wallpaper>>()
|
||||
val wallpapers: LiveData<List<Wallpaper>> = _wallpapers
|
||||
|
||||
private val mutex = Mutex()
|
||||
|
||||
private val listener = object : WallpaperManagerCompat.OnColorsChangedListener {
|
||||
override fun onColorsChanged() {
|
||||
viewModelScope.launch {
|
||||
mutex.withLock {
|
||||
saveWallpaper(wallpaperManagerCompat.wallpaperManager)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
loadTopWallpapers()
|
||||
wallpaperManagerCompat.addOnChangeListener(listener)
|
||||
}
|
||||
|
||||
private suspend fun saveWallpaper(wallpaperManager: WallpaperManager) {
|
||||
service.saveWallpaper(wallpaperManager)
|
||||
refreshWallpapers()
|
||||
}
|
||||
|
||||
private suspend fun refreshWallpapers() {
|
||||
val topWallpapers = dao.getTopWallpapers()
|
||||
_wallpapers.postValue(topWallpapers)
|
||||
}
|
||||
|
||||
private fun loadTopWallpapers() {
|
||||
viewModelScope.launch {
|
||||
val topWallpapers = dao.getTopWallpapers()
|
||||
_wallpapers.postValue(topWallpapers)
|
||||
mutex.withLock {
|
||||
refreshWallpapers()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun updateWallpaperRank(wallpaper: Wallpaper) {
|
||||
service.updateWallpaperRank(wallpaper)
|
||||
loadTopWallpapers()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,4 +9,5 @@ data class Wallpaper(
|
||||
val imagePath: String,
|
||||
val rank: Int,
|
||||
val timestamp: Long,
|
||||
val checksum: String? = null,
|
||||
)
|
||||
|
||||
@@ -17,6 +17,9 @@ interface WallpaperDao {
|
||||
@Query("UPDATE wallpapers SET rank = rank + 1 WHERE rank >= :rank")
|
||||
suspend fun updateRank(rank: Int)
|
||||
|
||||
@Query("UPDATE wallpapers SET rank = :rank, timestamp = :timestamp WHERE id = :id")
|
||||
suspend fun updateWallpaper(id: Long, rank: Int, timestamp: Long)
|
||||
|
||||
@Query("DELETE FROM wallpapers WHERE id = :id")
|
||||
suspend fun deleteWallpaper(id: Long)
|
||||
|
||||
|
||||
@@ -3,11 +3,13 @@ package app.lawnchair.wallpaper.service
|
||||
import androidx.room.Database
|
||||
import androidx.room.Room
|
||||
import androidx.room.RoomDatabase
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SimpleSQLiteQuery
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
import app.lawnchair.util.MainThreadInitializedObject
|
||||
import kotlinx.coroutines.runBlocking
|
||||
|
||||
@Database(entities = [Wallpaper::class], version = 1, exportSchema = false)
|
||||
@Database(entities = [Wallpaper::class], version = 2, exportSchema = false)
|
||||
abstract class WallpaperDatabase : RoomDatabase() {
|
||||
|
||||
abstract fun wallpaperDao(): WallpaperDao
|
||||
@@ -23,12 +25,17 @@ abstract class WallpaperDatabase : RoomDatabase() {
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val MIGRATION_1_2 = object : Migration(1, 2) {
|
||||
override fun migrate(db: SupportSQLiteDatabase) {
|
||||
db.execSQL("ALTER TABLE wallpapers ADD COLUMN checksum TEXT DEFAULT 'undefined'")
|
||||
}
|
||||
}
|
||||
val INSTANCE = MainThreadInitializedObject { context ->
|
||||
Room.databaseBuilder(
|
||||
context,
|
||||
WallpaperDatabase::class.java,
|
||||
"wallpaper_database",
|
||||
).build()
|
||||
).addMigrations(MIGRATION_1_2).build()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import com.android.launcher3.util.MainThreadInitializedObject
|
||||
import com.android.launcher3.util.SafeCloseable
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.security.MessageDigest
|
||||
import kotlinx.coroutines.runBlocking
|
||||
|
||||
class WallpaperService(val context: Context) : SafeCloseable {
|
||||
@@ -29,35 +30,60 @@ class WallpaperService(val context: Context) : SafeCloseable {
|
||||
}
|
||||
}
|
||||
|
||||
private fun calculateChecksum(imageData: ByteArray): String {
|
||||
return MessageDigest.getInstance("MD5")
|
||||
.digest(imageData)
|
||||
.joinToString("") { "%02x".format(it) }
|
||||
}
|
||||
|
||||
private suspend fun saveWallpaper(imageData: ByteArray) {
|
||||
val timestamp = System.currentTimeMillis()
|
||||
|
||||
val topWallpapers = dao.getTopWallpapers()
|
||||
|
||||
val imagePath = saveImageToAppStorage(imageData)
|
||||
|
||||
if (topWallpapers.size < 4) {
|
||||
val wallpaper = Wallpaper(imagePath = imagePath, rank = topWallpapers.size, timestamp = timestamp)
|
||||
val checksum = calculateChecksum(imageData)
|
||||
|
||||
val existingWallpapers = dao.getTopWallpapers()
|
||||
|
||||
if (existingWallpapers.any { it.checksum == checksum }) {
|
||||
Log.d("WallpaperService", "Wallpaper already exists with checksum: $checksum")
|
||||
return
|
||||
}
|
||||
|
||||
if (existingWallpapers.size < 4) {
|
||||
val wallpaper = Wallpaper(imagePath = imagePath, rank = existingWallpapers.size, timestamp = timestamp, checksum = checksum)
|
||||
dao.insert(wallpaper)
|
||||
} else {
|
||||
val lowestRankedWallpaper = topWallpapers.minByOrNull { it.timestamp }
|
||||
val lowestRankedWallpaper = existingWallpapers.minByOrNull { it.timestamp }
|
||||
|
||||
if (lowestRankedWallpaper != null) {
|
||||
dao.deleteWallpaper(lowestRankedWallpaper.id)
|
||||
deleteWallpaperFile(lowestRankedWallpaper.imagePath)
|
||||
}
|
||||
|
||||
for (wallpaper in topWallpapers) {
|
||||
for (wallpaper in existingWallpapers) {
|
||||
if (wallpaper.rank >= (lowestRankedWallpaper?.rank ?: 0)) {
|
||||
dao.updateRank(wallpaper.rank)
|
||||
}
|
||||
}
|
||||
|
||||
val wallpaper = Wallpaper(imagePath = imagePath, rank = 0, timestamp = timestamp)
|
||||
val wallpaper = Wallpaper(imagePath = imagePath, rank = 0, timestamp = timestamp, checksum = checksum)
|
||||
dao.insert(wallpaper)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun updateWallpaperRank(selectedWallpaper: Wallpaper) {
|
||||
val topWallpapers = dao.getTopWallpapers()
|
||||
val currentTime = System.currentTimeMillis()
|
||||
|
||||
dao.updateWallpaper(selectedWallpaper.id, rank = 0, timestamp = currentTime)
|
||||
|
||||
for (wallpaper in topWallpapers) {
|
||||
if (wallpaper.id != selectedWallpaper.id) {
|
||||
dao.updateRank(wallpaper.rank)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getTopWallpapers(): List<Wallpaper> = runBlocking {
|
||||
val wallpapers = dao.getTopWallpapers()
|
||||
wallpapers.ifEmpty { emptyList() }
|
||||
|
||||
Reference in New Issue
Block a user