From 6672180705793b6474a888d1ccc77878b40d5665 Mon Sep 17 00:00:00 2001 From: mueller-ma Date: Sun, 12 Nov 2023 09:49:59 +0100 Subject: [PATCH] Implement icon in button mappings Closes #3493 Signed-off-by: mueller-ma --- .idea/kotlinc.xml | 2 +- .../openhab/habdroid/model/LabeledValue.kt | 11 +++--- .../java/org/openhab/habdroid/model/Widget.kt | 2 +- .../org/openhab/habdroid/ui/ViewExtensions.kt | 34 +++++++++++++++++++ .../org/openhab/habdroid/ui/WidgetAdapter.kt | 4 +-- .../widgetlist_sectionswitchitem_button.xml | 2 ++ ...tlist_sectionswitchitem_button_compact.xml | 2 ++ .../org/openhab/habdroid/model/ItemTest.kt | 7 ++-- 8 files changed, 53 insertions(+), 11 deletions(-) diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml index f8467b458e4..e805548aaa8 100644 --- a/.idea/kotlinc.xml +++ b/.idea/kotlinc.xml @@ -1,6 +1,6 @@ - \ No newline at end of file diff --git a/mobile/src/main/java/org/openhab/habdroid/model/LabeledValue.kt b/mobile/src/main/java/org/openhab/habdroid/model/LabeledValue.kt index 26daba272f9..b648841ddd2 100644 --- a/mobile/src/main/java/org/openhab/habdroid/model/LabeledValue.kt +++ b/mobile/src/main/java/org/openhab/habdroid/model/LabeledValue.kt @@ -18,12 +18,15 @@ import android.os.Parcelable import kotlinx.parcelize.Parcelize import org.json.JSONException import org.json.JSONObject +import org.openhab.habdroid.util.optStringOrNull @Parcelize -data class LabeledValue internal constructor(val value: String, val label: String) : Parcelable +data class LabeledValue internal constructor(val value: String, val label: String, val icon: IconResource?) : Parcelable @Throws(JSONException::class) -fun JSONObject.toLabeledValue(keyName: String, valueName: String): LabeledValue { - val value = getString(keyName) - return LabeledValue(value, optString(valueName, value)) +fun JSONObject.toLabeledValue(valueKey: String, labelKey: String): LabeledValue { + val value = getString(valueKey) + val label = optString(labelKey, value) + val icon = optStringOrNull("icon")?.toOH2IconResource() + return LabeledValue(value, label, icon) } diff --git a/mobile/src/main/java/org/openhab/habdroid/model/Widget.kt b/mobile/src/main/java/org/openhab/habdroid/model/Widget.kt index f76525a7567..66d493546f3 100644 --- a/mobile/src/main/java/org/openhab/habdroid/model/Widget.kt +++ b/mobile/src/main/java/org/openhab/habdroid/model/Widget.kt @@ -286,7 +286,7 @@ fun Node.collectWidgets(parent: Widget?): List { "label" -> mappingLabel = childNode.textContent } } - mappings.add(LabeledValue(mappingCommand, mappingLabel)) + mappings.add(LabeledValue(mappingCommand, mappingLabel, null)) } else -> {} } diff --git a/mobile/src/main/java/org/openhab/habdroid/ui/ViewExtensions.kt b/mobile/src/main/java/org/openhab/habdroid/ui/ViewExtensions.kt index 66a6491d8a5..66ea1a40225 100644 --- a/mobile/src/main/java/org/openhab/habdroid/ui/ViewExtensions.kt +++ b/mobile/src/main/java/org/openhab/habdroid/ui/ViewExtensions.kt @@ -16,6 +16,7 @@ package org.openhab.habdroid.ui import android.annotation.SuppressLint import android.content.Context import android.os.Build +import android.util.Log import android.view.View import android.view.inputmethod.InputMethodManager import android.webkit.WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE @@ -26,11 +27,21 @@ import android.widget.ImageView import android.widget.RemoteViews import androidx.appcompat.widget.TooltipCompat import androidx.core.graphics.drawable.DrawableCompat +import androidx.core.graphics.drawable.toDrawable import androidx.core.net.toUri import androidx.swiperefreshlayout.widget.SwipeRefreshLayout +import com.google.android.material.button.MaterialButton +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import okhttp3.HttpUrl import org.openhab.habdroid.R import org.openhab.habdroid.core.connection.Connection +import org.openhab.habdroid.model.LabeledValue +import org.openhab.habdroid.util.HttpClient +import org.openhab.habdroid.util.ImageConversionPolicy import org.openhab.habdroid.util.openInBrowser import org.openhab.habdroid.util.resolveThemedColor @@ -111,3 +122,26 @@ fun RemoteViews.duplicate(): RemoteViews { clone() } } + +fun MaterialButton.setTextAndIcon(connection: Connection, mapping: LabeledValue) { + val iconUrl = mapping.icon?.toUrl(context, true) + if (iconUrl == null) { + icon = null + text = mapping.label + return + } + CoroutineScope(Dispatchers.IO + Job()).launch { + val drawable = try { + connection.httpClient.get(iconUrl, caching = HttpClient.CachingMode.DEFAULT) + .asBitmap(100, 0, ImageConversionPolicy.ForceTargetSize).response + .toDrawable(resources) + } catch (e: HttpClient.HttpException) { + Log.d(WidgetAdapter.TAG, "Error getting icon for button", e) + null + } + withContext(Dispatchers.Main) { + icon = drawable + text = if (drawable == null) mapping.label else null + } + } +} diff --git a/mobile/src/main/java/org/openhab/habdroid/ui/WidgetAdapter.kt b/mobile/src/main/java/org/openhab/habdroid/ui/WidgetAdapter.kt index f55cdef3ce7..e597bdee086 100644 --- a/mobile/src/main/java/org/openhab/habdroid/ui/WidgetAdapter.kt +++ b/mobile/src/main/java/org/openhab/habdroid/ui/WidgetAdapter.kt @@ -967,8 +967,8 @@ class WidgetAdapter( // bind views mappings.slice(0 until buttonCount).forEachIndexed { index, mapping -> with(group[index] as MaterialButton) { - text = mapping.label tag = mapping.value + setTextAndIcon(connection, mapping) } } @@ -1037,8 +1037,8 @@ class WidgetAdapter( val applyMapping = { button: MaterialButton, mapping: LabeledValue? -> button.isGone = mapping == null if (mapping != null) { - button.text = mapping.label button.isChecked = widget.state?.asString == mapping.value + button.setTextAndIcon(connection, mapping) button.tag = mapping.value } } diff --git a/mobile/src/main/res/layout/widgetlist_sectionswitchitem_button.xml b/mobile/src/main/res/layout/widgetlist_sectionswitchitem_button.xml index e6bad6fd86c..98f7bf63e90 100644 --- a/mobile/src/main/res/layout/widgetlist_sectionswitchitem_button.xml +++ b/mobile/src/main/res/layout/widgetlist_sectionswitchitem_button.xml @@ -14,4 +14,6 @@ android:textAppearance="?attr/textAppearanceLabelMedium" app:toggleCheckedStateOnClick="false" tools:layout_width="wrap_content" + app:iconGravity="textStart" + app:iconPadding="0dp" tools:text="Action 1" /> diff --git a/mobile/src/main/res/layout/widgetlist_sectionswitchitem_button_compact.xml b/mobile/src/main/res/layout/widgetlist_sectionswitchitem_button_compact.xml index 1cf7fded08a..5d502f8ac4b 100644 --- a/mobile/src/main/res/layout/widgetlist_sectionswitchitem_button_compact.xml +++ b/mobile/src/main/res/layout/widgetlist_sectionswitchitem_button_compact.xml @@ -12,4 +12,6 @@ android:paddingBottom="2dp" android:textAppearance="?attr/textAppearanceLabelMedium" app:toggleCheckedStateOnClick="false" + app:iconGravity="textStart" + app:iconPadding="0dp" tools:text="Action 1" /> diff --git a/mobile/src/test/java/org/openhab/habdroid/model/ItemTest.kt b/mobile/src/test/java/org/openhab/habdroid/model/ItemTest.kt index 9c3ad0e228d..cc03185ce11 100644 --- a/mobile/src/test/java/org/openhab/habdroid/model/ItemTest.kt +++ b/mobile/src/test/java/org/openhab/habdroid/model/ItemTest.kt @@ -107,8 +107,8 @@ class ItemTest { @Test fun getCommandOptions() { val sut = itemWithCommandOptions.toItem() - assertEquals(LabeledValue("1", "One"), sut.options!!.component1()) - assertEquals(LabeledValue("2", "Two"), sut.options!!.component2()) + assertEquals(LabeledValue("1", "One", "switch"), sut.options!!.component1()) + assertEquals(LabeledValue("2", "Two", null), sut.options!!.component2()) } @Test @@ -208,7 +208,8 @@ class ItemTest { 'commandOptions': [ { 'command': '1', - 'label': 'One' + 'label': 'One', + 'icon': 'switch' }, { 'command': '2',