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 @@
-