fixedup : clean up carousel view

This commit is contained in:
MrSluffy
2025-01-09 16:32:54 +08:00
parent 042ee8cdea
commit 80fbd9b2de
4 changed files with 90 additions and 94 deletions
@@ -39,22 +39,13 @@ class WallpaperCarouselView @JvmOverloads constructor(
) : LinearLayout(context, attrs, defStyleAttr) {
private val viewModel: WallpaperViewModel
private val deviceProfile = ActivityContext.lookupContext<LawnchairLauncher>(context).deviceProfile
private var currentItemIndex = 0
private val iconFrame = IconFrame(context).apply {
setIcon(R.drawable.ic_tick)
setBackgroundWithRadius(
bgColor = Themes.getColorAccent(context),
cornerRadius = 100F,
)
}
private val loadingView: ProgressBar = ProgressBar(context).apply {
isIndeterminate = true
visibility = VISIBLE
setBackgroundWithRadius(bgColor = Themes.getColorAccent(context), cornerRadius = 100F)
}
private val loadingView: ProgressBar = ProgressBar(context).apply { isIndeterminate = true }
init {
orientation = HORIZONTAL
@@ -71,102 +62,97 @@ class WallpaperCarouselView @JvmOverloads constructor(
visibility = GONE
loadingView.visibility = GONE
} else {
try {
visibility = VISIBLE
displayWallpapers(wallpapers)
} catch (e: Exception) {
Log.e("WallpaperCarouselView", "Error displaying wallpapers: ${e.message}")
}
visibility = VISIBLE
displayWallpapers(wallpapers)
}
}
}
@SuppressLint("ClickableViewAccessibility")
private fun displayWallpapers(wallpapers: List<Wallpaper>) {
removeAllViews()
val isLandscape = deviceProfile.isLandscape
val totalWidth = width.takeIf { it > 0 } ?: (deviceProfile.widthPx * if (isLandscape) 0.5 else 0.8).toInt()
val firstItemWidth = totalWidth * 0.5
val remainingWidth = totalWidth - firstItemWidth
val marginBetweenItems = totalWidth * 0.02
val itemWidth = (remainingWidth - (marginBetweenItems * (wallpapers.size - 1))) / (wallpapers.size - 1)
wallpapers.forEachIndexed { index, wallpaper ->
val cardView = CardView(context).apply {
radius = Themes.getDialogCornerRadius(context) / 2
layoutParams = LayoutParams(
when (index) {
currentItemIndex -> firstItemWidth.toInt()
else -> itemWidth.toInt()
},
LayoutParams.MATCH_PARENT,
).apply {
setMargins(
if (index > 0) marginBetweenItems.toInt() else 0,
0,
0,
0,
)
}
setOnTouchListener { _, _ ->
if (index != currentItemIndex) {
animateWidthTransition(index, firstItemWidth, itemWidth)
} else {
setWallpaper(wallpaper)
}
true
}
}
val placeholderImageView = ImageView(context).apply {
setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_deepshortcut_placeholder))
scaleType = ImageView.ScaleType.CENTER_CROP
}
cardView.addView(placeholderImageView)
val cardView = createCardView(index, firstItemWidth, itemWidth, marginBetweenItems, wallpaper)
addView(cardView)
CoroutineScope(Dispatchers.IO).launch {
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)
}
}
} 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),
)
}
}
}
}
// Load the wallpaper image only if necessary
loadWallpaperImage(wallpaper, cardView, index == currentItemIndex)
}
loadingView.visibility = GONE
requestLayout()
}
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(w, h, oldw, oldh)
if (viewModel.wallpapers.value?.isNotEmpty() == true) {
displayWallpapers(viewModel.wallpapers.value!!)
@SuppressLint("ClickableViewAccessibility")
private fun createCardView(
index: Int,
firstItemWidth: Double,
itemWidth: Double,
marginBetweenItems: Double,
wallpaper: Wallpaper,
): CardView {
return CardView(context).apply {
radius = Themes.getDialogCornerRadius(context) / 2
layoutParams = LayoutParams(
when (index) {
currentItemIndex -> firstItemWidth.toInt()
else -> itemWidth.toInt()
},
LayoutParams.MATCH_PARENT,
).apply {
setMargins(
if (index > 0) marginBetweenItems.toInt() else 0,
0,
0,
0,
)
}
setOnTouchListener { _, _ ->
if (index != currentItemIndex) {
animateWidthTransition(index, firstItemWidth, itemWidth)
} else {
setWallpaper(wallpaper)
}
true
}
}
}
private fun loadWallpaperImage(wallpaper: Wallpaper, cardView: CardView, isCurrent: Boolean) {
CoroutineScope(Dispatchers.IO).launch {
val wallpaperFile = File(wallpaper.imagePath)
val bitmap = if (wallpaperFile.exists()) {
BitmapFactory.decodeFile(wallpaper.imagePath)
} else {
null
}
withContext(Dispatchers.Main) {
val imageView = ImageView(context).apply {
setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_deepshortcut_placeholder))
scaleType = ImageView.ScaleType.CENTER_CROP
}
cardView.addView(imageView)
if (bitmap != null) {
imageView.setImageBitmap(bitmap)
if (isCurrent) addIconFrameToCenter(cardView)
} else {
Log.e("WallpaperCarouselView", "File not found: ${wallpaper.imagePath}")
imageView.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_deepshortcut_placeholder))
}
}
}
}
private fun setWallpaper(wallpaper: Wallpaper) {
val currentCardView = getChildAt(currentItemIndex) as CardView
val loadingSpinner = ProgressBar(context).apply {
isIndeterminate = true
layoutParams = FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT).apply {
@@ -174,7 +160,6 @@ class WallpaperCarouselView @JvmOverloads constructor(
}
}
val currentCardView = getChildAt(currentItemIndex) as CardView
currentCardView.removeView(iconFrame)
currentCardView.addView(loadingSpinner)
@@ -184,7 +169,6 @@ class WallpaperCarouselView @JvmOverloads constructor(
val bitmap = BitmapFactory.decodeFile(wallpaper.imagePath)
wallpaperManager.setBitmap(bitmap, null, true, WallpaperManager.FLAG_SYSTEM)
viewModel.updateWallpaperRank(wallpaper)
withContext(Dispatchers.Main) {
@@ -216,12 +200,18 @@ class WallpaperCarouselView @JvmOverloads constructor(
cardView.addView(iconFrame, params)
}
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(w, h, oldw, oldh)
if (viewModel.wallpapers.value?.isNotEmpty() == true) {
displayWallpapers(viewModel.wallpapers.value!!)
}
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
val isLandscape = deviceProfile.isLandscape
val valWidth = if (isLandscape) (deviceProfile.widthPx * 0.5).toInt() else (deviceProfile.widthPx * 0.8).toInt()
val width = MeasureSpec.makeMeasureSpec(valWidth, MeasureSpec.EXACTLY)
super.onMeasure(width, heightMeasureSpec)
requestLayout()
}
private fun animateWidthTransition(
@@ -5,13 +5,18 @@ 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
val wallpaperManager: WallpaperManager = context.requireSystemService()
val service = WallpaperService(context)
abstract val wallpaperColors: WallpaperColorsCompat?
@@ -26,6 +31,12 @@ sealed class WallpaperManagerCompat(val context: Context) {
}
protected fun notifyChange() {
if (service.getTopWallpapers().isEmpty()) {
CoroutineScope(Dispatchers.IO).launch {
service.saveWallpaper(wallpaperManager)
}
}
listeners.toTypedArray().forEach {
it.onColorsChanged()
}
@@ -8,16 +8,11 @@ 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>>()
@@ -41,12 +36,12 @@ class WallpaperViewModel(context: Context) : ViewModel() {
}
private suspend fun saveWallpaper(wallpaperManager: WallpaperManager) {
service.saveWallpaper(wallpaperManager)
wallpaperManagerCompat.service.saveWallpaper(wallpaperManager)
refreshWallpapers()
}
private suspend fun refreshWallpapers() {
val topWallpapers = dao.getTopWallpapers()
val topWallpapers = wallpaperManagerCompat.service.dao.getTopWallpapers()
_wallpapers.postValue(topWallpapers)
}
@@ -59,7 +54,7 @@ class WallpaperViewModel(context: Context) : ViewModel() {
}
suspend fun updateWallpaperRank(wallpaper: Wallpaper) {
service.updateWallpaperRank(wallpaper)
wallpaperManagerCompat.service.updateWallpaperRank(wallpaper)
loadTopWallpapers()
}
}
@@ -15,7 +15,7 @@ import kotlinx.coroutines.runBlocking
class WallpaperService(val context: Context) : SafeCloseable {
private val dao = WallpaperDatabase.INSTANCE.get(context).wallpaperDao()
val dao = WallpaperDatabase.INSTANCE.get(context).wallpaperDao()
suspend fun saveWallpaper(wallpaperManager: WallpaperManager) {
try {