mirror of
https://github.com/LawnchairLauncher/lawnchair.git
synced 2026-02-27 15:26:58 +00:00
enh : refactor carousel imp
This commit is contained in:
@@ -1,17 +1,15 @@
|
||||
package app.lawnchair.ui.popup
|
||||
|
||||
import android.animation.LayoutTransition
|
||||
import android.animation.ValueAnimator
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.WallpaperManager
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.util.AttributeSet
|
||||
import android.util.Log
|
||||
import android.view.Gravity
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.animation.AccelerateDecelerateInterpolator
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
@@ -46,82 +44,68 @@ class WallpaperCarouselView @JvmOverloads constructor(
|
||||
private var currentItemIndex = 0
|
||||
private val iconFrame = IconFrame(context).apply {
|
||||
setIcon(R.drawable.ic_tick)
|
||||
setBackgroundWithRadius(bgColor = Themes.getColorAccent(context), cornerRadius = 100F)
|
||||
setBackgroundWithRadius(Themes.getColorAccent(context), 100F)
|
||||
}
|
||||
private val loadingView: ProgressBar = ProgressBar(context).apply { isIndeterminate = true }
|
||||
private val loadingView = ProgressBar(context).apply { isIndeterminate = true }
|
||||
|
||||
init {
|
||||
orientation = HORIZONTAL
|
||||
setLayoutTransition(
|
||||
LayoutTransition().apply {
|
||||
enableTransitionType(LayoutTransition.CHANGING)
|
||||
setDuration(200L)
|
||||
},
|
||||
)
|
||||
|
||||
addView(loadingView)
|
||||
val factory = WallpaperViewModelFactory(context)
|
||||
viewModel = ViewModelProvider(context as ViewModelStoreOwner, factory)[WallpaperViewModel::class.java]
|
||||
viewModel = ViewModelProvider(
|
||||
context as ViewModelStoreOwner,
|
||||
WallpaperViewModelFactory(context),
|
||||
)[WallpaperViewModel::class.java]
|
||||
|
||||
observeWallpapers()
|
||||
}
|
||||
|
||||
private fun observeWallpapers() {
|
||||
viewModel.wallpapers.observe(context as LifecycleOwner) { wallpapers ->
|
||||
if (wallpapers.isEmpty()) {
|
||||
visibility = GONE
|
||||
loadingView.visibility = GONE
|
||||
} else {
|
||||
visibility = VISIBLE
|
||||
displayWallpapers(wallpapers)
|
||||
}
|
||||
visibility = if (wallpapers.isEmpty()) GONE else VISIBLE
|
||||
loadingView.visibility = if (wallpapers.isEmpty()) GONE else VISIBLE
|
||||
if (wallpapers.isNotEmpty()) displayWallpapers(wallpapers)
|
||||
}
|
||||
}
|
||||
|
||||
private fun displayWallpapers(wallpapers: List<Wallpaper>) {
|
||||
removeAllViews()
|
||||
val isLandscape = deviceProfile.isLandscape || deviceProfile.isTablet
|
||||
val totalWidth = width.takeIf { it > 0 } ?: (deviceProfile.widthPx * if (isLandscape) 0.5 else 0.8).toInt()
|
||||
val totalWidth = calculateTotalWidth()
|
||||
val firstItemWidth = totalWidth * 0.4
|
||||
val remainingWidth = totalWidth - firstItemWidth
|
||||
val marginBetweenItems = totalWidth * 0.03
|
||||
val itemWidth = (remainingWidth - (marginBetweenItems * (wallpapers.size - 1))) / (wallpapers.size - 1)
|
||||
val itemWidth = calculateItemWidth(totalWidth, wallpapers.size, firstItemWidth)
|
||||
val margin = (totalWidth * 0.03).toInt()
|
||||
|
||||
wallpapers.forEachIndexed { index, wallpaper ->
|
||||
val cardView = createCardView(index, firstItemWidth, itemWidth, marginBetweenItems, wallpaper)
|
||||
val cardView = createCardView(index, firstItemWidth, itemWidth, margin, wallpaper)
|
||||
addView(cardView)
|
||||
|
||||
// Load the wallpaper image only if necessary
|
||||
loadWallpaperImage(wallpaper, cardView, index == currentItemIndex)
|
||||
}
|
||||
|
||||
loadingView.visibility = GONE
|
||||
}
|
||||
|
||||
private fun calculateTotalWidth(): Int {
|
||||
return width.takeIf { it > 0 } ?: (deviceProfile.widthPx * if (deviceProfile.isLandscape || deviceProfile.isTablet) 0.5 else 0.8).toInt()
|
||||
}
|
||||
|
||||
private fun calculateItemWidth(totalWidth: Int, itemCount: Int, firstItemWidth: Double): Double {
|
||||
val remainingWidth = totalWidth - firstItemWidth
|
||||
val marginBetweenItems = totalWidth * 0.03
|
||||
return (remainingWidth - (marginBetweenItems * (itemCount - 1))) / (itemCount - 1)
|
||||
}
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
private fun createCardView(
|
||||
index: Int,
|
||||
firstItemWidth: Double,
|
||||
itemWidth: Double,
|
||||
marginBetweenItems: Double,
|
||||
margin: Int,
|
||||
wallpaper: Wallpaper,
|
||||
): CardView {
|
||||
return CardView(context).apply {
|
||||
radius = Themes.getDialogCornerRadius(context) / 2
|
||||
layoutParams = LayoutParams(
|
||||
when (index) {
|
||||
currentItemIndex -> firstItemWidth.toInt()
|
||||
else -> itemWidth.toInt()
|
||||
},
|
||||
if (index == currentItemIndex) firstItemWidth.toInt() else itemWidth.toInt(),
|
||||
LayoutParams.MATCH_PARENT,
|
||||
).apply {
|
||||
setMargins(
|
||||
if (index > 0) marginBetweenItems.toInt() else 0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
)
|
||||
}
|
||||
).apply { setMargins(if (index > 0) margin else 0, 0, 0, 0) }
|
||||
|
||||
setOnTouchListener { _, _ ->
|
||||
if (index != currentItemIndex) {
|
||||
@@ -136,128 +120,98 @@ class WallpaperCarouselView @JvmOverloads constructor(
|
||||
|
||||
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
|
||||
}
|
||||
val bitmap = File(wallpaper.imagePath).takeIf { it.exists() }?.let { BitmapFactory.decodeFile(it.path) }
|
||||
withContext(Dispatchers.Main) { addImageView(cardView, bitmap, isCurrent) }
|
||||
}
|
||||
}
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
val imageView = ImageView(context).apply {
|
||||
setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_deepshortcut_placeholder))
|
||||
scaleType = ImageView.ScaleType.CENTER_CROP
|
||||
alpha = 0f
|
||||
}
|
||||
cardView.addView(imageView)
|
||||
|
||||
if (bitmap != null) {
|
||||
imageView.setLayerType(View.LAYER_TYPE_HARDWARE, null)
|
||||
|
||||
imageView.setImageBitmap(bitmap)
|
||||
imageView.animate()
|
||||
.alpha(1f)
|
||||
.setDuration(200L)
|
||||
.setInterpolator(AccelerateDecelerateInterpolator())
|
||||
.withEndAction {
|
||||
imageView.setLayerType(View.LAYER_TYPE_NONE, null)
|
||||
if (isCurrent) addIconFrameToCenter(cardView)
|
||||
}
|
||||
.start()
|
||||
} else {
|
||||
Log.e("WallpaperCarouselView", "File not found: ${wallpaper.imagePath}")
|
||||
imageView.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_deepshortcut_placeholder))
|
||||
}
|
||||
}
|
||||
private fun addImageView(cardView: CardView, bitmap: Bitmap?, isCurrent: Boolean) {
|
||||
val imageView = ImageView(context).apply {
|
||||
setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_deepshortcut_placeholder))
|
||||
scaleType = ImageView.ScaleType.CENTER_CROP
|
||||
alpha = 0f
|
||||
}
|
||||
cardView.addView(imageView)
|
||||
if (bitmap != null) {
|
||||
imageView.setImageBitmap(bitmap)
|
||||
imageView.animate().alpha(1f).setDuration(200L).withEndAction {
|
||||
if (isCurrent) addIconFrameToCenter(cardView)
|
||||
}.start()
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
gravity = Gravity.CENTER
|
||||
}
|
||||
}
|
||||
val spinner = createLoadingSpinner()
|
||||
|
||||
currentCardView.removeView(iconFrame)
|
||||
currentCardView.addView(loadingSpinner)
|
||||
currentCardView.addView(spinner)
|
||||
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
try {
|
||||
val wallpaperManager = WallpaperManager.getInstance(context)
|
||||
val bitmap = BitmapFactory.decodeFile(wallpaper.imagePath)
|
||||
|
||||
wallpaperManager.setBitmap(bitmap, null, true, WallpaperManager.FLAG_SYSTEM)
|
||||
WallpaperManager.getInstance(context).setBitmap(
|
||||
BitmapFactory.decodeFile(wallpaper.imagePath),
|
||||
null,
|
||||
true,
|
||||
WallpaperManager.FLAG_SYSTEM,
|
||||
)
|
||||
viewModel.updateWallpaperRank(wallpaper)
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
currentCardView.removeView(loadingSpinner)
|
||||
addIconFrameToCenter(currentCardView)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e("WallpaperCarouselView", "Failed to set wallpaper: ${e.message}")
|
||||
} finally {
|
||||
withContext(Dispatchers.Main) {
|
||||
currentCardView.removeView(loadingSpinner)
|
||||
currentCardView.removeView(spinner)
|
||||
addIconFrameToCenter(currentCardView)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun addIconFrameToCenter(cardView: CardView) {
|
||||
if (iconFrame.parent != null) {
|
||||
(iconFrame.parent as ViewGroup).removeView(iconFrame)
|
||||
}
|
||||
|
||||
val params = FrameLayout.LayoutParams(
|
||||
LayoutParams.WRAP_CONTENT,
|
||||
LayoutParams.WRAP_CONTENT,
|
||||
).apply {
|
||||
private fun createLoadingSpinner() = ProgressBar(context).apply {
|
||||
isIndeterminate = true
|
||||
layoutParams = FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT).apply {
|
||||
gravity = Gravity.CENTER
|
||||
}
|
||||
}
|
||||
|
||||
cardView.addView(iconFrame, params)
|
||||
private fun addIconFrameToCenter(cardView: CardView? = getChildAt(currentItemIndex) as CardView) {
|
||||
(iconFrame.parent as? ViewGroup)?.removeView(iconFrame)
|
||||
cardView?.addView(
|
||||
iconFrame,
|
||||
FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT).apply {
|
||||
gravity = Gravity.CENTER
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
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!!)
|
||||
}
|
||||
viewModel.wallpapers.value?.let { displayWallpapers(it) }
|
||||
}
|
||||
|
||||
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
||||
val isLandscape = deviceProfile.isLandscape || deviceProfile.isTablet
|
||||
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)
|
||||
super.onMeasure(
|
||||
MeasureSpec.makeMeasureSpec(calculateTotalWidth(), MeasureSpec.EXACTLY),
|
||||
heightMeasureSpec,
|
||||
)
|
||||
}
|
||||
|
||||
private fun animateWidthTransition(
|
||||
newIndex: Int,
|
||||
firstItemWidth: Double,
|
||||
itemWidth: Double,
|
||||
) {
|
||||
private fun animateWidthTransition(newIndex: Int, firstItemWidth: Double, itemWidth: Double) {
|
||||
currentItemIndex = newIndex
|
||||
for (i in 0 until childCount) {
|
||||
val cardView = getChildAt(i) as? CardView ?: continue
|
||||
val targetWidth = if (i == currentItemIndex) firstItemWidth.toInt() else itemWidth.toInt()
|
||||
|
||||
if (cardView.layoutParams.width != targetWidth) {
|
||||
val animator = ValueAnimator.ofInt(cardView.layoutParams.width, targetWidth).apply {
|
||||
duration = 300L
|
||||
addUpdateListener { animation ->
|
||||
val animatedValue = animation.animatedValue as Int
|
||||
cardView.layoutParams = cardView.layoutParams.apply { width = animatedValue }
|
||||
cardView.requestLayout()
|
||||
(getChildAt(i) as? CardView)?.let { cardView ->
|
||||
val targetWidth = if (i == currentItemIndex) firstItemWidth.toInt() else itemWidth.toInt()
|
||||
if (cardView.layoutParams.width != targetWidth) {
|
||||
ValueAnimator.ofInt(cardView.layoutParams.width, targetWidth).apply {
|
||||
duration = 300L
|
||||
addUpdateListener {
|
||||
cardView.layoutParams.width = it.animatedValue as Int
|
||||
cardView.requestLayout()
|
||||
}
|
||||
start()
|
||||
}
|
||||
}
|
||||
animator.start()
|
||||
}
|
||||
if (i == currentItemIndex) {
|
||||
addIconFrameToCenter(cardView)
|
||||
if (i == currentItemIndex) addIconFrameToCenter(cardView)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user