diff --git a/app/src/main/kotlin/app/aaps/activities/HistoryBrowseActivity.kt b/app/src/main/kotlin/app/aaps/activities/HistoryBrowseActivity.kt
index 3ee691cede2..a65e30d9f85 100644
--- a/app/src/main/kotlin/app/aaps/activities/HistoryBrowseActivity.kt
+++ b/app/src/main/kotlin/app/aaps/activities/HistoryBrowseActivity.kt
@@ -33,6 +33,7 @@ import app.aaps.core.ui.activities.TranslatedDaggerAppCompatActivity
import app.aaps.core.ui.extensions.toVisibility
import app.aaps.core.ui.extensions.toVisibilityKeepSpace
import app.aaps.databinding.ActivityHistorybrowseBinding
+import app.aaps.plugins.main.R
import app.aaps.plugins.main.general.overview.graphData.GraphData
import com.google.android.material.datepicker.MaterialDatePicker
import com.jjoe64.graphview.GraphView
@@ -141,7 +142,7 @@ class HistoryBrowseActivity : TranslatedDaggerAppCompatActivity() {
binding.bgGraph.gridLabelRenderer?.reloadStyles()
binding.bgGraph.gridLabelRenderer?.labelVerticalWidth = axisWidth
- overviewMenus.setupChartMenu(context, binding.chartMenuButton)
+ overviewMenus.setupChartMenu(binding.chartMenuButton, binding.scaleButton)
prepareGraphsIfNeeded(overviewMenus.setting.size)
savedInstanceState?.let { bundle ->
rangeToDisplay = bundle.getInt("rangeToDisplay", 0)
@@ -301,7 +302,7 @@ class HistoryBrowseActivity : TranslatedDaggerAppCompatActivity() {
aapsLogger.debug(LTag.UI, "updateGui $from")
updateDate()
-
+ binding.scaleButton.text = overviewMenus.scaleString(rangeToDisplay)
val pump = activePlugin.activePump
val graphData = GraphData(injector, binding.bgGraph, historyBrowserData.overviewData)
val menuChartSettings = overviewMenus.setting
diff --git a/app/src/main/res/layout/activity_historybrowse.xml b/app/src/main/res/layout/activity_historybrowse.xml
index 5e309f77e09..0d6275f6769 100644
--- a/app/src/main/res/layout/activity_historybrowse.xml
+++ b/app/src/main/res/layout/activity_historybrowse.xml
@@ -78,14 +78,27 @@
android:layout_width="wrap_content"
android:layout_height="match_parent" />
+
+
diff --git a/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/overview/OverviewMenus.kt b/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/overview/OverviewMenus.kt
index 48436e1c87b..9fe3862b54b 100644
--- a/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/overview/OverviewMenus.kt
+++ b/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/overview/OverviewMenus.kt
@@ -1,6 +1,6 @@
package app.aaps.core.interfaces.overview
-import android.content.Context
+import android.widget.Button
import android.widget.ImageButton
interface OverviewMenus {
@@ -23,7 +23,8 @@ interface OverviewMenus {
val setting: List>
fun loadGraphConfig()
- fun setupChartMenu(context: Context, chartButton: ImageButton)
+ fun setupChartMenu(chartButton: ImageButton, scaleButton: Button)
fun enabledTypes(graph: Int): String
fun isEnabledIn(type: CharType): Int
+ fun scaleString(rangeToDisplay: Int): String
}
diff --git a/core/ui/src/main/res/values-night/styles.xml b/core/ui/src/main/res/values-night/styles.xml
index a5c788e5871..4611069e3b2 100644
--- a/core/ui/src/main/res/values-night/styles.xml
+++ b/core/ui/src/main/res/values-night/styles.xml
@@ -91,6 +91,7 @@
- @color/ribbonTextWarning
- @color/defaultBackground
+ - @color/ribbonTextWarning
- @color/toastBase
- @color/buttonBackground
diff --git a/core/ui/src/main/res/values/attrs.xml b/core/ui/src/main/res/values/attrs.xml
index a59a442dfcc..2c199155225 100644
--- a/core/ui/src/main/res/values/attrs.xml
+++ b/core/ui/src/main/res/values/attrs.xml
@@ -63,6 +63,7 @@
+
diff --git a/core/ui/src/main/res/values/styles.xml b/core/ui/src/main/res/values/styles.xml
index 3e5bda9b1ff..975f56850cf 100644
--- a/core/ui/src/main/res/values/styles.xml
+++ b/core/ui/src/main/res/values/styles.xml
@@ -96,6 +96,7 @@
- @color/ribbonTextWarning
- @color/white
+ - @color/white
- @color/toastBase
- @color/colorLightGray
diff --git a/plugins/main/src/main/kotlin/app/aaps/plugins/main/general/overview/OverviewFragment.kt b/plugins/main/src/main/kotlin/app/aaps/plugins/main/general/overview/OverviewFragment.kt
index cadb99aa0b7..dd593a3aef4 100644
--- a/plugins/main/src/main/kotlin/app/aaps/plugins/main/general/overview/OverviewFragment.kt
+++ b/plugins/main/src/main/kotlin/app/aaps/plugins/main/general/overview/OverviewFragment.kt
@@ -221,7 +221,9 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
false
}
prepareGraphsIfNeeded(overviewMenus.setting.size)
- context?.let { overviewMenus.setupChartMenu(it, binding.graphsLayout.chartMenuButton) }
+ overviewMenus.setupChartMenu(binding.graphsLayout.chartMenuButton, binding.graphsLayout.scaleButton)
+ binding.graphsLayout.scaleButton.text = overviewMenus.scaleString(overviewData.rangeToDisplay)
+
binding.graphsLayout.chartMenuButton.visibility = preferences.simpleMode.not().toVisibility()
binding.activeProfile.setOnClickListener(this)
@@ -914,6 +916,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
private fun updateTime() {
_binding ?: return
+ binding.graphsLayout.scaleButton.text = overviewMenus.scaleString(overviewData.rangeToDisplay)
binding.infoLayout.time.text = dateUtil.timeString(dateUtil.now())
// Status lights
val pump = activePlugin.activePump
diff --git a/plugins/main/src/main/kotlin/app/aaps/plugins/main/general/overview/OverviewMenusImpl.kt b/plugins/main/src/main/kotlin/app/aaps/plugins/main/general/overview/OverviewMenusImpl.kt
index f1d8682a2d2..594842d27d5 100644
--- a/plugins/main/src/main/kotlin/app/aaps/plugins/main/general/overview/OverviewMenusImpl.kt
+++ b/plugins/main/src/main/kotlin/app/aaps/plugins/main/general/overview/OverviewMenusImpl.kt
@@ -1,15 +1,26 @@
package app.aaps.plugins.main.general.overview
import android.content.Context
+import android.graphics.drawable.ColorDrawable
import android.text.SpannableString
import android.text.style.BackgroundColorSpan
import android.text.style.ForegroundColorSpan
+import android.view.Gravity
import android.view.Menu
import android.view.View
+import android.view.ViewGroup
+import android.widget.Button
+import android.widget.CheckBox
+import android.widget.CompoundButton
+import android.widget.HorizontalScrollView
import android.widget.ImageButton
+import android.widget.PopupWindow
+import android.widget.ScrollView
+import android.widget.TextView
import androidx.annotation.AttrRes
import androidx.annotation.StringRes
import androidx.appcompat.widget.PopupMenu
+import androidx.gridlayout.widget.GridLayout
import app.aaps.core.interfaces.aps.Loop
import app.aaps.core.interfaces.configuration.Config
import app.aaps.core.interfaces.logging.AAPSLogger
@@ -67,7 +78,6 @@ class OverviewMenusImpl @Inject constructor(
companion object {
const val MAX_GRAPHS = 5 // including main
- const val SCALE_ID = 1001
}
override fun enabledTypes(graph: Int): String {
@@ -81,11 +91,20 @@ class OverviewMenusImpl @Inject constructor(
}
private var _setting: MutableList> = ArrayList()
+ get() = field.also {
+ while (it.size < MAX_GRAPHS)
+ it.add(Array(CharTypeData.entries.size) { false })
+ }
override val setting: List>
@Synchronized get() =
- if (!preferences.simpleMode)
- _setting.toMutableList() // implicitly does a list copy
+ if (!preferences.simpleMode) // implicitly does a list copy and update according to number of graphs
+ _setting.toMutableList().also {
+ for (i in it.size - 1 downTo 1) {
+ if (!it[i].any { it })
+ it.removeAt(i)
+ }
+ }
else
listOf(
arrayOf(true, true, true, false, false, false, false, false, false, false, false, false, false, false),
@@ -109,113 +128,183 @@ class OverviewMenusImpl @Inject constructor(
// reset when new CharType added
for (s in _setting)
if (s.size != OverviewMenus.CharType.entries.size) {
- _setting = ArrayList()
- _setting.add(Array(OverviewMenus.CharType.entries.size) { CharTypeData.entries[it].enabledByDefault })
+ _setting = ArrayList>().also { it.add(Array(OverviewMenus.CharType.entries.size) { CharTypeData.entries[it].enabledByDefault }) }
}
} else {
- _setting = ArrayList()
- _setting.add(Array(OverviewMenus.CharType.entries.size) { CharTypeData.entries[it].enabledByDefault })
+ _setting = ArrayList>().also { it.add(Array(OverviewMenus.CharType.entries.size) { CharTypeData.entries[it].enabledByDefault }) }
}
}
- override fun setupChartMenu(context: Context, chartButton: ImageButton) {
- val settingsCopy = setting
- val numOfGraphs = settingsCopy.size // 1 main + x secondary
-
+ override fun setupChartMenu(chartButton: ImageButton, scaleButton: Button) {
+ chartButton.setColorFilter(rh.gac(chartButton.context, app.aaps.core.ui.R.attr.defaultTextColor))
+ scaleButton.setCompoundDrawablesWithIntrinsicBounds(
+ null,
+ null,
+ rh.gd(R.drawable.ic_arrow_drop_down_white_24dp)?.also { it.setTint(rh.gac(scaleButton.context, app.aaps.core.ui.R.attr.defaultTextColor))},
+ null
+ )
chartButton.setOnClickListener { v: View ->
+ var itemRow = 0
val predictionsAvailable: Boolean = when {
config.APS -> loop.lastRun?.request?.hasPredictions ?: false
config.NSCLIENT -> true
else -> false
}
- val popup = PopupMenu(v.context, v)
+ val popup = PopupWindow(v.context)
+ popup.setBackgroundDrawable(ColorDrawable(rh.gac(chartButton.context, app.aaps.core.ui.R.attr.popupWindowBackground)))
+ val scrollView = ScrollView(v.context) // required to be able to scroll menu on low res screen
+ val horizontalScrollView = HorizontalScrollView(v.context) // Workaround because I was not able to manage first column width for long labels
+ horizontalScrollView.addView(scrollView)
- popup.menu.addSubMenu(Menu.NONE, SCALE_ID, Menu.NONE, rh.gs(R.string.graph_scale)).also {
- it.add(Menu.NONE, SCALE_ID + 6, Menu.NONE, "6")
- it.add(Menu.NONE, SCALE_ID + 12, Menu.NONE, "12")
- it.add(Menu.NONE, SCALE_ID + 18, Menu.NONE, "18")
- it.add(Menu.NONE, SCALE_ID + 24, Menu.NONE, "24")
- }
+ val layout = GridLayout(v.context)
+ layout.layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) // not sure it works
- val used = arrayListOf()
+ scrollView.addView(layout)
+ layout.columnCount = MAX_GRAPHS
- for (g in 0 until numOfGraphs) {
- if (g != 0) {
- val dividerItem = popup.menu.add(Menu.NONE, g, Menu.NONE, "------- ${rh.gs(R.string.graph_menu_divider_header)} $g -------")
- dividerItem.isCheckable = true
- dividerItem.isChecked = true
- }
- CharTypeData.entries.forEach { m ->
- if (g == 0 && !m.primary) return@forEach
- if (g > 0 && !m.secondary) return@forEach
- var insert = true
- if (m == CharTypeData.PRE) insert = predictionsAvailable
- if (m == CharTypeData.DEVSLOPE) insert = config.isDev()
- if (used.contains(m.ordinal)) insert = false
- for (g2 in g + 1 until numOfGraphs) {
- if (settingsCopy[g2][m.ordinal]) insert = false
- }
- if (insert) {
- val item = popup.menu.add(Menu.NONE, m.ordinal + 100 * (g + 1), Menu.NONE, rh.gs(m.nameId))
- val title = item.title
- val s = SpannableString(" $title ")
- s.setSpan(ForegroundColorSpan(rh.gac(m.attrTextId)), 0, s.length, 0)
- s.setSpan(BackgroundColorSpan(rh.gac(m.attrId)), 0, s.length, 0)
- item.title = s
- item.isCheckable = true
- item.isChecked = settingsCopy[g][m.ordinal]
- if (settingsCopy[g][m.ordinal]) used.add(m.ordinal)
- }
+ // instert primary items
+ CharTypeData.entries.forEach { m ->
+ var insert = true
+ if (m == CharTypeData.PRE) insert = predictionsAvailable
+ if (insert && m.primary) {
+ createCustomMenuItemView(v.context, m, itemRow, layout, true)
+ itemRow++
}
}
- if (numOfGraphs < MAX_GRAPHS) {
- val dividerItem = popup.menu.add(Menu.NONE, numOfGraphs, Menu.NONE, "------- ${rh.gs(R.string.graph_menu_divider_header)} $numOfGraphs -------")
- dividerItem.isCheckable = true
- dividerItem.isChecked = false
+
+ // insert hearder row
+ var layoutParamsLabel = GridLayout.LayoutParams(GridLayout.spec(itemRow, 1), GridLayout.spec(0, 1))
+ val textView = TextView(v.context).also {
+ it.text = " ${rh.gs(R.string.graph_menu_divider_header)}"
+ it.maxLines = 3 // don't works currently
+ }
+ layout.addView(textView, layoutParamsLabel)
+ for (i in 1..(MAX_GRAPHS - 1)) {
+ val item = TextView(v.context).also {
+ it.gravity = Gravity.CENTER
+ it.text = "$i"
+ }
+ layoutParamsLabel = GridLayout.LayoutParams(GridLayout.spec(itemRow, 1), GridLayout.spec(i, 1)).apply {
+ setGravity(Gravity.CENTER)
+ }
+ layout.addView(item, layoutParamsLabel)
}
+ itemRow++
- popup.setOnMenuItemClickListener {
- synchronized(this) {
- try {
- // id < 100 graph header - divider 1, 2, 3 .....
- when {
- it.itemId == SCALE_ID -> {
- // do nothing, submenu
- }
-
- it.itemId > SCALE_ID && it.itemId < SCALE_ID + 100 -> {
- val hours = it.itemId - SCALE_ID // 6,12,....
- rxBus.send(EventScale(hours))
- }
-
- it.itemId == numOfGraphs -> {
- // add new empty
- _setting.add(Array(CharTypeData.entries.size) { false })
- }
-
- it.itemId < 100 -> {
- // remove graph
- _setting.removeAt(it.itemId)
- }
-
- else -> {
- val graphNumber = it.itemId / 100 - 1
- val item = it.itemId % 100
- _setting[graphNumber][item] = !it.isChecked
- }
- }
- } catch (exception: Exception) {
- fabricPrivacy.logException(exception)
+ // instert secondary items
+ CharTypeData.entries.forEach { m ->
+ var insert = true
+ if (m == CharTypeData.DEVSLOPE) insert = config.isDev()
+ if (insert && m.secondary) {
+ createCustomMenuItemView(v.context, m, itemRow, layout, false)
+ itemRow++
+ }
+ }
+ popup.contentView = horizontalScrollView
+ // Permettre la fermeture de la PopupWindow en touchant en dehors
+ popup.isOutsideTouchable = true
+ popup.isFocusable = true
+ popup.setOnDismissListener { // remove empty graphs
+ chartButton.setImageResource(R.drawable.ic_arrow_drop_down_white_24dp)
+ _setting.let {
+ for (i in it.size - 1 downTo 1) {
+ if (!isSecondary(it[i]))
+ it.removeAt(i)
}
}
storeGraphConfig()
- setupChartMenu(context, chartButton)
rxBus.send(EventRefreshOverview("OnMenuItemClickListener", now = true))
- return@setOnMenuItemClickListener true
}
chartButton.setImageResource(R.drawable.ic_arrow_drop_up_white_24dp)
- popup.setOnDismissListener { chartButton.setImageResource(R.drawable.ic_arrow_drop_down_white_24dp) }
+ popup.showAsDropDown(v)
+ }
+
+ scaleButton.setOnClickListener { v: View ->
+ val popup = PopupMenu(v.context, v)
+ popup.menu.add(Menu.NONE, 6, Menu.NONE, rh.gs(R.string.graph_long_scale_6h))
+ popup.menu.add(Menu.NONE, 12, Menu.NONE, rh.gs(R.string.graph_long_scale_12h))
+ popup.menu.add(Menu.NONE, 18, Menu.NONE, rh.gs(R.string.graph_long_scale_18h))
+ popup.menu.add(Menu.NONE, 24, Menu.NONE, rh.gs(R.string.graph_long_scale_24h))
+ popup.setOnMenuItemClickListener {
+ // id == Range to display ...
+ rxBus.send(EventScale(it.itemId))
+ return@setOnMenuItemClickListener true
+ }
+ scaleButton.setCompoundDrawablesWithIntrinsicBounds(
+ null,
+ null,
+ rh.gd(R.drawable.ic_arrow_drop_up_white_24dp)?.also { it.setTint(rh.gac(v.context, app.aaps.core.ui.R.attr.defaultTextColor))},
+ null
+ )
+ popup.setOnDismissListener {
+ scaleButton.setCompoundDrawablesWithIntrinsicBounds(
+ null,
+ null,
+ rh.gd(R.drawable.ic_arrow_drop_down_white_24dp)?.also { it.setTint(rh.gac(v.context, app.aaps.core.ui.R.attr.defaultTextColor))},
+ null
+ )
+ }
popup.show()
+ false
+ }
+ }
+
+ fun isSecondary(graphArray: Array): Boolean = graphArray.filterIndexed { index, _ -> CharTypeData.entries[index].secondary }.reduce { acc, b -> acc || b }
+
+ private fun createCustomMenuItemView(context: Context, m: CharTypeData, rowIndex: Int, layout: GridLayout, primary: Boolean) {
+ var layoutParamsLabel = GridLayout.LayoutParams(GridLayout.spec(rowIndex, 1), GridLayout.spec(0, 1))
+ val textView = TextView(context).also {
+ it.text = formatedText(m)
+ it.maxLines = 3 // don't works currently
+ }
+ layout.addView(textView, layoutParamsLabel)
+
+ val checkBoxes = mutableListOf()
+
+ // Create one or 4 checkbox
+ for (i in 1..(MAX_GRAPHS - 1)) {
+ val item = if (!primary || i == (MAX_GRAPHS - 1)) CheckBox(context) else TextView(context)
+ item.id = i
+ if (item is CheckBox) {
+ if (primary)
+ item.isChecked = _setting[0][m.ordinal]
+ else
+ item.isChecked = _setting[i][m.ordinal]
+ checkBoxes.add(item)
+ }
+ layoutParamsLabel = GridLayout.LayoutParams(GridLayout.spec(rowIndex, 1), GridLayout.spec(i, 1))
+ layout.addView(item, layoutParamsLabel)
+ }
+
+ val checkBoxListener = CompoundButton.OnCheckedChangeListener { buttonView, isChecked ->
+ // Update other Checkboxes on same row to allow a curve to only one subgraph
+ if (isChecked) {
+ checkBoxes.forEach { checkBox ->
+ if (checkBox != buttonView) {
+ checkBox.isChecked = false
+ }
+ }
+ }
+ if (m.primary)
+ _setting[0][m.ordinal] = checkBoxes[0].isChecked
+ else {
+ checkBoxes.forEach { checkBox ->
+ _setting[checkBox.id][m.ordinal] = checkBox.isChecked
+ }
+ }
+ storeGraphConfig()
+ rxBus.send(EventRefreshOverview("OnMenuItemClickListener", now = true))
+ }
+
+ checkBoxes.forEach { checkBox ->
+ checkBox.setOnCheckedChangeListener(checkBoxListener)
+ }
+ }
+
+ private fun formatedText(m: CharTypeData): SpannableString {
+ return SpannableString(" ${rh.gs(m.nameId)} ").also {
+ it.setSpan(ForegroundColorSpan(rh.gac(m.attrTextId)), 0, it.length, 0)
+ it.setSpan(BackgroundColorSpan(rh.gac(m.attrId)), 0, it.length, 0)
}
}
@@ -225,5 +314,12 @@ class OverviewMenusImpl @Inject constructor(
for (g in 0 until numOfGraphs) if (settingsCopy[g][type.ordinal]) return g
return -1
}
+ override fun scaleString(rangeToDisplay: Int): String = when (rangeToDisplay) {
+ 6 -> rh.gs(R.string.graph_scale_6h)
+ 12 -> rh.gs(R.string.graph_scale_12h)
+ 18 -> rh.gs(R.string.graph_scale_18h)
+ 24 -> rh.gs(R.string.graph_scale_24h)
+ else -> ""
+ }
}
diff --git a/plugins/main/src/main/res/layout/overview_graphs_layout.xml b/plugins/main/src/main/res/layout/overview_graphs_layout.xml
index 1bca74a8093..9585f013617 100644
--- a/plugins/main/src/main/res/layout/overview_graphs_layout.xml
+++ b/plugins/main/src/main/res/layout/overview_graphs_layout.xml
@@ -17,15 +17,27 @@
android:layout_height="200dp"
android:contentDescription="@string/a11y_graph" />
+
+
diff --git a/plugins/main/src/main/res/values/strings.xml b/plugins/main/src/main/res/values/strings.xml
index 7bbb87e7e8d..fbe96678e06 100644
--- a/plugins/main/src/main/res/values/strings.xml
+++ b/plugins/main/src/main/res/values/strings.xml
@@ -203,7 +203,20 @@
Threshold warning pump battery level [%]
Threshold critical pump battery level [%]
Copy settings from NS
+ 6h
+ 12h
+ 18h
+ 24h
+ 6 hours
+ 12 hours
+ 18 hours
+ 24 hours
graph
+ selet graph scale
+ graph scale 6 hours
+ graph scale 12 hours
+ graph scale 18 hours
+ graph scale 24 hours
insulin
Chart menu
blood glucose quality