diff --git a/mobile/src/main/java/org/openhab/habdroid/ui/ImageWidgetActivity.kt b/mobile/src/main/java/org/openhab/habdroid/ui/ImageWidgetActivity.kt index 4000588fd3..7d557f52c4 100644 --- a/mobile/src/main/java/org/openhab/habdroid/ui/ImageWidgetActivity.kt +++ b/mobile/src/main/java/org/openhab/habdroid/ui/ImageWidgetActivity.kt @@ -20,6 +20,7 @@ import android.util.Base64 import android.util.Log import android.view.Menu import android.view.MenuItem +import com.faltenreich.skeletonlayout.Skeleton import com.github.chrisbanes.photoview.PhotoView import kotlin.math.max import kotlinx.coroutines.Dispatchers @@ -40,6 +41,7 @@ import org.openhab.habdroid.util.orDefaultIfEmpty class ImageWidgetActivity : AbstractBaseActivity() { private lateinit var imageView: PhotoView + private lateinit var skeleton: Skeleton private var connection: Connection? = null private var refreshJob: Job? = null private var delay: Long = 0 @@ -52,7 +54,9 @@ class ImageWidgetActivity : AbstractBaseActivity() { supportActionBar?.title = intent.getStringExtra(WIDGET_LABEL).orDefaultIfEmpty(getString(R.string.widget_type_image)) - imageView = findViewById(R.id.activity_content) + imageView = findViewById(R.id.photo_view) + skeleton = findViewById(R.id.activity_content) + delay = intent.getIntExtra(WIDGET_REFRESH, 0).toLong() } @@ -106,6 +110,7 @@ class ImageWidgetActivity : AbstractBaseActivity() { private suspend fun loadImage() { val widgetUrl = intent.getStringExtra(WIDGET_URL) val conn = connection ?: return finish() + skeleton.showSkeleton() val bitmap = if (widgetUrl != null) { Log.d(TAG, "Load image from url") val displayMetrics = resources.displayMetrics @@ -149,6 +154,7 @@ class ImageWidgetActivity : AbstractBaseActivity() { imageView.getSuppMatrix(matrix) imageView.setImageBitmap(bitmap) imageView.setSuppMatrix(matrix) + skeleton.showOriginal() } private fun scheduleRefresh() { diff --git a/mobile/src/main/java/org/openhab/habdroid/ui/widget/WidgetImageView.kt b/mobile/src/main/java/org/openhab/habdroid/ui/widget/WidgetImageView.kt index ab05a67dbb..68233d79d0 100644 --- a/mobile/src/main/java/org/openhab/habdroid/ui/widget/WidgetImageView.kt +++ b/mobile/src/main/java/org/openhab/habdroid/ui/widget/WidgetImageView.kt @@ -22,6 +22,9 @@ import android.util.AttributeSet import android.util.Base64 import android.util.Log import androidx.appcompat.widget.AppCompatImageView +import com.faltenreich.skeletonlayout.Skeleton +import com.faltenreich.skeletonlayout.SkeletonLayout +import com.faltenreich.skeletonlayout.createSkeleton import kotlin.random.Random import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -43,8 +46,8 @@ import org.openhab.habdroid.util.isDebugModeEnabled class WidgetImageView(context: Context, attrs: AttributeSet?) : AppCompatImageView(context, attrs) { private var scope: CoroutineScope? = null private val fallback: Drawable? - private val progressDrawable: Drawable? + private var skeleton: Skeleton? = null private var originalScaleType: ScaleType? = null private var originalAdjustViewBounds: Boolean = false private val emptyHeightToWidthRatio: Float @@ -64,7 +67,6 @@ class WidgetImageView(context: Context, attrs: AttributeSet?) : AppCompatImageVi init { context.obtainStyledAttributes(attrs, R.styleable.WidgetImageView).apply { fallback = getDrawable(R.styleable.WidgetImageView_fallback) - progressDrawable = getDrawable(R.styleable.WidgetImageView_progressIndicator) emptyHeightToWidthRatio = getFraction(R.styleable.WidgetImageView_emptyHeightToWidthRatio, 1, 1, 0f) addRandomnessToUrl = getBoolean(R.styleable.WidgetImageView_addRandomnessToUrl, false) val imageScalingType = getInt(R.styleable.WidgetImageView_imageScalingType, 0) @@ -73,6 +75,12 @@ class WidgetImageView(context: Context, attrs: AttributeSet?) : AppCompatImageVi } recycle() } + // In some cases it's required to add the skeleton manually to XML. + // In these cases, set the parent as skeleton here, otherwise create it in applyProgressDrawable() + val parent = parent + if (parent is SkeletonLayout) { + skeleton = parent + } } fun setImageUrl( @@ -166,9 +174,7 @@ class WidgetImageView(context: Context, attrs: AttributeSet?) : AppCompatImageVi override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { super.onMeasure(widthMeasureSpec, heightMeasureSpec) val d = drawable - val isEmpty = d == null || d === progressDrawable - - if (isEmpty && emptyHeightToWidthRatio > 0) { + if (d == null && emptyHeightToWidthRatio > 0) { val specWidth = MeasureSpec.getSize(widthMeasureSpec) val specMode = MeasureSpec.getMode(widthMeasureSpec) if (specMode == MeasureSpec.AT_MOST || specMode == MeasureSpec.EXACTLY) { @@ -240,7 +246,7 @@ class WidgetImageView(context: Context, attrs: AttributeSet?) : AppCompatImageVi cancelRefresh() lastRequest = null refreshInterval = 0 - removeProgressDrawable() + removeSkeleton() } private fun doLoad(client: HttpClient, url: HttpUrl, timeoutMillis: Long, forceLoad: Boolean) { @@ -254,8 +260,8 @@ class WidgetImageView(context: Context, attrs: AttributeSet?) : AppCompatImageVi if (cached != null) { applyLoadedBitmap(cached) - } else if (progressDrawable != null || lastRequest?.statelessUrlEquals(url) != true) { - applyProgressDrawable() + } else if (lastRequest?.statelessUrlEquals(url) != true) { + applySkeleton() } if (cached == null || forceLoad) { @@ -287,7 +293,7 @@ class WidgetImageView(context: Context, attrs: AttributeSet?) : AppCompatImageVi } private fun applyLoadedBitmap(bitmap: Bitmap) { - removeProgressDrawable() + removeSkeleton() if (imageScalingType == ImageScalingType.ScaleToFitWithViewAdjustmentDownscaleOnly) { // Make sure that view only shrinks to accommodate bitmap size, but doesn't enlarge ... that is, // adjust view bounds only if width is larger than target size or height is larger than the maximum height @@ -309,22 +315,15 @@ class WidgetImageView(context: Context, attrs: AttributeSet?) : AppCompatImageVi super.setImageDrawable(fallback) } - private fun applyProgressDrawable() { - if (originalScaleType == null) { - originalScaleType = scaleType - super.setScaleType(ScaleType.CENTER) - super.setAdjustViewBounds(false) + private fun applySkeleton() { + if (skeleton == null) { + skeleton = createSkeleton() } - super.setImageDrawable(progressDrawable) + skeleton?.showSkeleton() } - private fun removeProgressDrawable() { - if (originalScaleType != null) { - super.setAdjustViewBounds(originalAdjustViewBounds) - super.setScaleType(originalScaleType) - originalScaleType = null - } - super.setImageDrawable(null) + private fun removeSkeleton() { + skeleton?.showOriginal() } private inner class HttpImageRequest( @@ -378,7 +377,7 @@ class WidgetImageView(context: Context, attrs: AttributeSet?) : AppCompatImageVi if (context.getPrefs().isDebugModeEnabled()) { Log.d(TAG, "Failed to load image '$url', HTTP code ${e.statusCode}", e) } - removeProgressDrawable() + removeSkeleton() applyFallbackDrawable() } } diff --git a/mobile/src/main/res/drawable-night/ic_image_loading_themed.xml b/mobile/src/main/res/drawable-night/ic_image_loading_themed.xml deleted file mode 100644 index c500914f20..0000000000 --- a/mobile/src/main/res/drawable-night/ic_image_loading_themed.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - \ No newline at end of file diff --git a/mobile/src/main/res/drawable/ic_image_loading_themed.xml b/mobile/src/main/res/drawable/ic_image_loading_themed.xml deleted file mode 100644 index cd92817b0a..0000000000 --- a/mobile/src/main/res/drawable/ic_image_loading_themed.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - \ No newline at end of file diff --git a/mobile/src/main/res/layout/activity_chart.xml b/mobile/src/main/res/layout/activity_chart.xml index d833be6ae4..1fe098cd80 100644 --- a/mobile/src/main/res/layout/activity_chart.xml +++ b/mobile/src/main/res/layout/activity_chart.xml @@ -2,6 +2,7 @@ @@ -14,13 +15,17 @@ android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior"> - + android:layout_height="match_parent"> + + diff --git a/mobile/src/main/res/layout/activity_image.xml b/mobile/src/main/res/layout/activity_image.xml index 2f66ac91c2..524b189073 100644 --- a/mobile/src/main/res/layout/activity_image.xml +++ b/mobile/src/main/res/layout/activity_image.xml @@ -8,10 +8,17 @@ - + app:layout_behavior="@string/appbar_scrolling_view_behavior"> + + + diff --git a/mobile/src/main/res/layout/itempickerlist_item.xml b/mobile/src/main/res/layout/itempickerlist_item.xml index e13ec7bdab..5bb33ca7cc 100644 --- a/mobile/src/main/res/layout/itempickerlist_item.xml +++ b/mobile/src/main/res/layout/itempickerlist_item.xml @@ -19,7 +19,6 @@ android:layout_height="40dp" android:layout_gravity="center_vertical" app:imageScalingType="noScaling" - app:progressIndicator="@drawable/ic_openhab_appicon_24dp" app:fallback="@drawable/ic_openhab_appicon_24dp" tools:src="@drawable/ic_openhab_appicon_24dp" /> diff --git a/mobile/src/main/res/layout/notificationlist_item.xml b/mobile/src/main/res/layout/notificationlist_item.xml index 2cd1dce190..921e524f7f 100644 --- a/mobile/src/main/res/layout/notificationlist_item.xml +++ b/mobile/src/main/res/layout/notificationlist_item.xml @@ -19,7 +19,6 @@ android:layout_height="40dp" android:layout_gravity="center_vertical" app:imageScalingType="noScaling" - app:progressIndicator="@drawable/ic_openhab_appicon_24dp" app:fallback="@drawable/ic_openhab_appicon_24dp" tools:src="@drawable/ic_openhab_appicon_24dp" /> diff --git a/mobile/src/main/res/layout/widgetlist_chartitem.xml b/mobile/src/main/res/layout/widgetlist_chartitem.xml index b458ce5911..4775cee526 100644 --- a/mobile/src/main/res/layout/widgetlist_chartitem.xml +++ b/mobile/src/main/res/layout/widgetlist_chartitem.xml @@ -20,7 +20,6 @@ android:layout_height="wrap_content" app:imageScalingType="scaleToFitWithViewAdjustment" app:emptyHeightToWidthRatio="50%" - app:progressIndicator="@drawable/ic_image_loading_themed" app:addRandomnessToUrl="true" /> diff --git a/mobile/src/main/res/layout/widgetlist_imageitem.xml b/mobile/src/main/res/layout/widgetlist_imageitem.xml index 3486c83069..26f600efcd 100644 --- a/mobile/src/main/res/layout/widgetlist_imageitem.xml +++ b/mobile/src/main/res/layout/widgetlist_imageitem.xml @@ -12,8 +12,7 @@ + android:layout_height="wrap_content" /> diff --git a/mobile/src/main/res/layout/widgetlist_videomjpegitem.xml b/mobile/src/main/res/layout/widgetlist_videomjpegitem.xml index ecafd9dcb2..ce3cea6d0e 100644 --- a/mobile/src/main/res/layout/widgetlist_videomjpegitem.xml +++ b/mobile/src/main/res/layout/widgetlist_videomjpegitem.xml @@ -14,8 +14,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:contentDescription="@string/content_description_video" - app:imageScalingType="scaleToFitWithViewAdjustment" - app:progressIndicator="@drawable/ic_image_loading_themed" /> + app:imageScalingType="scaleToFitWithViewAdjustment" /> diff --git a/mobile/src/main/res/values/attrs.xml b/mobile/src/main/res/values/attrs.xml index 5b5903981e..336eb25b24 100644 --- a/mobile/src/main/res/values/attrs.xml +++ b/mobile/src/main/res/values/attrs.xml @@ -2,7 +2,6 @@ -