From 84abd6d3ee466e1d8bf33a0b4dad475885daf6ad Mon Sep 17 00:00:00 2001 From: Tomek Zebrowski Date: Fri, 18 Sep 2026 12:30:42 +0200 Subject: [PATCH 1/4] fix(dtc): keep module picker buttons visible with long module lists The module ListView used WRAP_CONTENT, so with many modules it claimed its full height and pushed the Cancel/Select All/Confirm bar out of the dialog. Use 0 height + weight 1 so the list shrinks and scrolls instead. Co-Authored-By: Claude Opus 5 --- .../dtc/DiagnosticTroubleCodePreferenceDialogFragment.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/obd/graphs/preferences/dtc/DiagnosticTroubleCodePreferenceDialogFragment.kt b/app/src/main/java/org/obd/graphs/preferences/dtc/DiagnosticTroubleCodePreferenceDialogFragment.kt index 7ce66ba4..bea41302 100644 --- a/app/src/main/java/org/obd/graphs/preferences/dtc/DiagnosticTroubleCodePreferenceDialogFragment.kt +++ b/app/src/main/java/org/obd/graphs/preferences/dtc/DiagnosticTroubleCodePreferenceDialogFragment.kt @@ -256,11 +256,15 @@ internal class DiagnosticTroubleCodePreferenceDialogFragment : CoreDialogFragmen setItemChecked(index, true) } } + // Zero height + weight lets the LinearLayout shrink the list (which scrolls on its own) + // when there are more modules than fit on screen - with WRAP_CONTENT it would claim its + // full height and push the button bar below out of the dialog. container.addView( listView, android.widget.LinearLayout.LayoutParams( android.widget.LinearLayout.LayoutParams.MATCH_PARENT, - android.widget.LinearLayout.LayoutParams.WRAP_CONTENT + 0, + 1f ) ) From 7a6e03fdfd1379a0bc0342094cbd76963637d3de Mon Sep 17 00:00:00 2001 From: Tomek Zebrowski Date: Fri, 18 Sep 2026 16:48:28 +0200 Subject: [PATCH 2/4] fix(dtc): cap module picker list height and show persistent scrollbar The weighted ListView alone still claimed the full dialog height with long module lists, hiding the button bar. Replace it with MaxHeightListView, capped at 40% of the screen height, and give it an always-visible custom scrollbar thumb so it's clear more modules sit below the fold. Co-Authored-By: Claude Opus 5 --- ...sticTroubleCodePreferenceDialogFragment.kt | 6 ++- .../preferences/dtc/MaxHeightListView.kt | 50 +++++++++++++++++++ .../dtc_module_list_scrollbar_thumb.xml | 7 +++ app/src/main/res/layout/dtc_module_list.xml | 11 ++++ 4 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/org/obd/graphs/preferences/dtc/MaxHeightListView.kt create mode 100644 app/src/main/res/drawable/dtc_module_list_scrollbar_thumb.xml create mode 100644 app/src/main/res/layout/dtc_module_list.xml diff --git a/app/src/main/java/org/obd/graphs/preferences/dtc/DiagnosticTroubleCodePreferenceDialogFragment.kt b/app/src/main/java/org/obd/graphs/preferences/dtc/DiagnosticTroubleCodePreferenceDialogFragment.kt index bea41302..a715d783 100644 --- a/app/src/main/java/org/obd/graphs/preferences/dtc/DiagnosticTroubleCodePreferenceDialogFragment.kt +++ b/app/src/main/java/org/obd/graphs/preferences/dtc/DiagnosticTroubleCodePreferenceDialogFragment.kt @@ -243,9 +243,11 @@ internal class DiagnosticTroubleCodePreferenceDialogFragment : CoreDialogFragmen } ) + // Inflated from XML (rather than constructed in code) so it can carry a custom, always-on + // scrollbar thumb on every API level - the theme default is thin and barely visible, and + // it's the only hint that more modules sit below the fold. val listView = - android.widget.ListView(context).apply { - choiceMode = android.widget.ListView.CHOICE_MODE_MULTIPLE + (LayoutInflater.from(context).inflate(R.layout.dtc_module_list, container, false) as MaxHeightListView).apply { adapter = android.widget.ArrayAdapter( context, diff --git a/app/src/main/java/org/obd/graphs/preferences/dtc/MaxHeightListView.kt b/app/src/main/java/org/obd/graphs/preferences/dtc/MaxHeightListView.kt new file mode 100644 index 00000000..56daed2e --- /dev/null +++ b/app/src/main/java/org/obd/graphs/preferences/dtc/MaxHeightListView.kt @@ -0,0 +1,50 @@ +/* + * Copyright 2019-2026, Tomasz Żebrowski + * + *

Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.obd.graphs.preferences.dtc + +import android.content.Context +import android.util.AttributeSet +import android.widget.ListView + +// A ListView that never grows beyond a fraction of the screen height. Inside the DTC module +// picker (an AlertDialog custom view) a plain wrap_content/weighted ListView still claimed the +// whole dialog height when the module list was long, pushing the button bar out of view - an +// explicit cap keeps room for the buttons regardless of how the dialog window gets measured. +class MaxHeightListView + @JvmOverloads + constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = android.R.attr.listViewStyle + ) : ListView(context, attrs, defStyleAttr) { + var maxHeightRatio: Float = 0.4f + + override fun onMeasure( + widthMeasureSpec: Int, + heightMeasureSpec: Int + ) { + val maxHeight = (resources.displayMetrics.heightPixels * maxHeightRatio).toInt() + val size = MeasureSpec.getSize(heightMeasureSpec) + val cappedSpec = + when (MeasureSpec.getMode(heightMeasureSpec)) { + MeasureSpec.UNSPECIFIED -> MeasureSpec.makeMeasureSpec(maxHeight, MeasureSpec.AT_MOST) + MeasureSpec.EXACTLY -> MeasureSpec.makeMeasureSpec(minOf(size, maxHeight), MeasureSpec.EXACTLY) + else -> MeasureSpec.makeMeasureSpec(minOf(size, maxHeight), MeasureSpec.AT_MOST) + } + super.onMeasure(widthMeasureSpec, cappedSpec) + } + } diff --git a/app/src/main/res/drawable/dtc_module_list_scrollbar_thumb.xml b/app/src/main/res/drawable/dtc_module_list_scrollbar_thumb.xml new file mode 100644 index 00000000..9608b1b7 --- /dev/null +++ b/app/src/main/res/drawable/dtc_module_list_scrollbar_thumb.xml @@ -0,0 +1,7 @@ + + + + + + diff --git a/app/src/main/res/layout/dtc_module_list.xml b/app/src/main/res/layout/dtc_module_list.xml new file mode 100644 index 00000000..c32e6562 --- /dev/null +++ b/app/src/main/res/layout/dtc_module_list.xml @@ -0,0 +1,11 @@ + + From c26c2b25b68846f893455681a0747f4f6340fe8e Mon Sep 17 00:00:00 2001 From: Tomek Zebrowski Date: Fri, 18 Sep 2026 20:30:21 +0200 Subject: [PATCH 3/4] fix(dtc): align DTC dialog action buttons in each row Horizontal LinearLayouts baseline-align children by default, so a disabled Share button (different background padding) pushed Close out of line. Disable baseline alignment on both button rows. Co-Authored-By: Claude Opus 5 --- app/src/main/res/layout/dialog_dtc.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/res/layout/dialog_dtc.xml b/app/src/main/res/layout/dialog_dtc.xml index 4dac29b4..bcf33eb6 100644 --- a/app/src/main/res/layout/dialog_dtc.xml +++ b/app/src/main/res/layout/dialog_dtc.xml @@ -70,6 +70,7 @@