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 9b5558a9961..b8407e15c5b 100644 --- a/mobile/src/main/java/org/openhab/habdroid/ui/WidgetAdapter.kt +++ b/mobile/src/main/java/org/openhab/habdroid/ui/WidgetAdapter.kt @@ -130,7 +130,6 @@ class WidgetAdapter( val itemList: List get() = items private val widgetsById = mutableMapOf() private val widgetsByParentId = mutableMapOf>() - val widgetsByParentIdMap: Map> get() = widgetsByParentId val hasVisibleWidgets: Boolean get() = items.any { widget -> shouldShowWidget(widget) } @@ -172,9 +171,9 @@ class WidgetAdapter( widgetsByParentId.clear() widgets.forEach { w -> widgetsById[w.id] = w - w.parentId?.let { parentId -> - widgetsByParentId.getOrPut(parentId) { mutableListOf() }.add(w) - } + w.parentId + ?.let { parentId -> widgetsByParentId.getOrPut(parentId) { mutableListOf() } } + ?.add(w) } notifyDataSetChanged() } @@ -239,7 +238,7 @@ class WidgetAdapter( TYPE_LOCATION -> MapViewHelper.createViewHolder(initData) TYPE_INPUT -> InputViewHolder(initData) TYPE_DATETIMEINPUT -> DateTimeInputViewHolder(initData) - TYPE_BUTTONGRID -> ButtongridViewHolder(initData) + TYPE_BUTTONGRID -> ButtongridViewHolder(initData) { id -> widgetsByParentId[id] } TYPE_INVISIBLE -> InvisibleWidgetViewHolder(initData) else -> throw IllegalArgumentException("View type $viewType is not known") } @@ -305,15 +304,10 @@ class WidgetAdapter( val oldWidget = items[position] items[position] = widget widgetsById[widget.id] = widget - widgetsByParentId[oldWidget.parentId]?.let { - it.remove(oldWidget) - if (it.isEmpty()) { - widgetsByParentId.remove(oldWidget.parentId) - } - } - widget.parentId?.let { parentId -> - widgetsByParentId.getOrPut(parentId) { mutableListOf() }.add(widget) - } + widgetsByParentId[oldWidget.parentId]?.remove(oldWidget) + widget.parentId + ?.let { parentId -> widgetsByParentId.getOrPut(parentId) { mutableListOf() } } + ?.add(widget) // If visibility of a container with at least one child changes, refresh the whole list to make sure // the child visibility is also updated. Otherwise it's sufficient to update the single widget only. if (oldWidget.visibility != widget.visibility && items.any { w -> w.parentId == widget.id }) { @@ -321,8 +315,9 @@ class WidgetAdapter( } else { // update the parent Buttongrid if the updated widget is a button if (widget.type == Widget.Type.Button && widget.parentId != null) { - items.indexOfFirst { w -> w.id == widget.parentId }?.let { position -> - notifyItemChanged(position) + val parentPosition = items.indexOfFirst { w -> w.id == widget.parentId } + if (parentPosition >= 0) { + notifyItemChanged(parentPosition) } } else { notifyItemChanged(position) @@ -839,13 +834,15 @@ class WidgetAdapter( } } - class ButtongridViewHolder internal constructor(private val initData: ViewHolderInitData) : - LabeledItemBaseViewHolder(initData, R.layout.widgetlist_buttongriditem), + class ButtongridViewHolder internal constructor( + private val initData: ViewHolderInitData, + private val childWidgetCallback: (String) -> List? + ) : LabeledItemBaseViewHolder(initData, R.layout.widgetlist_buttongriditem), View.OnClickListener, View.OnTouchListener { private val table: GridLayout = itemView.findViewById(R.id.widget_content) private val maxColumns = itemView.resources.getInteger(R.integer.section_switch_max_buttons) - private val buttonViews = mutableMapOf, MaterialButton>() + private val spareViews = mutableListOf() override fun bind(widget: Widget) { super.bind(widget) @@ -855,39 +852,21 @@ class WidgetAdapter( labelView.isVisible = showLabelAndIcon iconView.isVisible = showLabelAndIcon - val buttons = - widget.mappings.mapIndexed { index, it -> it.toWidget("$widget.id-mappings-$index", widget.item) } + - (bindingAdapter as WidgetAdapter).widgetsByParentIdMap[widget.id].orEmpty() + val buttons = childWidgetCallback(widget.id).orEmpty() + + widget.mappings.mapIndexed { index, it -> it.toWidget("$widget.id-mappings-$index", widget.item) } val rowCount = buttons.maxOfOrNull { it.row ?: 0 } ?: 0 val columnCount = min(buttons.maxOfOrNull { it.column ?: 0 } ?: 0, maxColumns) - buttonViews.filter { (position, buttonView) -> - position.first >= rowCount || - position.second >= columnCount || - (buttonView.tag as? Widget)?.parentId != widget.id - } - .forEach { (position, buttonView) -> - table.removeView(buttonView) - buttonViews.remove(position) - } + spareViews.addAll(table.children.map { it as? MaterialButton }.filterNotNull()) + table.removeAllViews() table.rowCount = rowCount table.columnCount = columnCount (0 until table.rowCount).forEach { row -> (0 until table.columnCount).forEach { column -> - val position = Pair(row, column) - val buttonView = buttonViews.getOrPut(position) { - val newButton = initData.inflater.inflate(R.layout.widgetlist_sectionswitchitem_button, table, false) + val buttonView = spareViews.removeFirstOrNull() + ?: initData.inflater.inflate(R.layout.widgetlist_sectionswitchitem_button, table, false) as MaterialButton - table.addView( - newButton, - GridLayout.LayoutParams( - GridLayout.spec(row, GridLayout.FILL, 1f), - GridLayout.spec(column, GridLayout.FILL, 1f) - ) - ) - newButton - } // Rows and columns start with 1 in Sitemap definition, thus decrement them here val button = buttons.firstOrNull { (it.row ?: 0) - 1 == row && (it.column ?: 0) - 1 == column } @@ -905,11 +884,18 @@ class WidgetAdapter( iconColor = button.iconColor, mapper = colorMapper ) - buttonView.isCheckable = button.stateless?.not() ?: false + buttonView.isCheckable = button.stateless == true buttonView.isChecked = button.item?.state?.asString == button.command buttonView.visibility = View.VISIBLE } buttonView.maxWidth = table.width / table.columnCount + table.addView( + buttonView, + GridLayout.LayoutParams( + GridLayout.spec(row, GridLayout.FILL, 1f), + GridLayout.spec(column, GridLayout.FILL, 1f) + ) + ) } } }