From a7b97607e78045a94672e15eb0e390c5e3966c7b Mon Sep 17 00:00:00 2001 From: Futsch1 <63090558+Futsch1@users.noreply.github.com> Date: Sat, 9 May 2026 10:20:25 +0200 Subject: [PATCH 1/5] Start fixing charts --- .../medtimer/statistics/ChartsFragment.kt | 40 +++++++------------ .../medtimer/statistics/ChartsViewModel.kt | 3 +- 2 files changed, 17 insertions(+), 26 deletions(-) diff --git a/app/src/main/java/com/futsch1/medtimer/statistics/ChartsFragment.kt b/app/src/main/java/com/futsch1/medtimer/statistics/ChartsFragment.kt index 88afc1816..83bd412e7 100644 --- a/app/src/main/java/com/futsch1/medtimer/statistics/ChartsFragment.kt +++ b/app/src/main/java/com/futsch1/medtimer/statistics/ChartsFragment.kt @@ -94,8 +94,8 @@ class ChartsFragment : Fragment() { takenSkippedTotalChartView = statisticsView.findViewById(R.id.takenSkippedChartTotal) setupTakenSkippedCharts() + setupMedicinesPerDayChart() lifecycleScope.launch(backgroundDispatcher) { - setupMedicinesPerDayChart() viewModel.uiState.filterNotNull().collect { state -> withContext(mainDispatcher) { updateMedicinesPerDayChart(state) @@ -148,17 +148,13 @@ class ChartsFragment : Fragment() { ) ) pieChart.plotPaddingTop = requireContext().resources.dpToPx(5.0f) - pieChart.backgroundPaint.setColor( - requireContext().getMaterialColor( - com.google.android.material.R.attr.colorSurface, - "TakenSkippedChart" - ) + pieChart.backgroundPaint.color = requireContext().getMaterialColor( + com.google.android.material.R.attr.colorSurface, + "TakenSkippedChart" ) - pieChart.title.labelPaint.setColor( - requireContext().getMaterialColor( - com.google.android.material.R.attr.colorOnSurface, - "TakenSkippedChart" - ) + pieChart.title.labelPaint.color = requireContext().getMaterialColor( + com.google.android.material.R.attr.colorOnSurface, + "TakenSkippedChart" ) val renderer = pieChart.getRenderer(PieRenderer::class.java) renderer.setDonutSize(0.0f, PieRenderer.DonutMode.PERCENT) @@ -168,9 +164,7 @@ class ChartsFragment : Fragment() { val formatter = SegmentFormatter( requireContext().getMaterialColor(colorSegment, "TakenSkippedChart") ) - formatter.labelPaint.setColor( - requireContext().getMaterialColor(colorText, "TakenSkippedChart") - ) + formatter.labelPaint.color = requireContext().getMaterialColor(colorText, "TakenSkippedChart") return formatter } @@ -222,7 +216,7 @@ class ChartsFragment : Fragment() { private fun Paint.applyAxisLabelStyle() { val context = requireContext() textSize = context.resources.dpToPx(10.0f) - setColor(context.getMaterialColor(com.google.android.material.R.attr.colorOnSurface, "TakenSkippedChart")) + color = context.getMaterialColor(com.google.android.material.R.attr.colorOnSurface, "TakenSkippedChart") } private fun setupBottomLine() { @@ -286,12 +280,10 @@ class ChartsFragment : Fragment() { private fun getBarFormatter(color: Int): MedicinePerDayChartFormatter { val formatter = MedicinePerDayChartFormatter() - formatter.fillPaint.setColor(color) - formatter.borderPaint.setColor( - requireContext().getMaterialColor( - androidx.appcompat.R.attr.colorPrimary, - "TakenSkippedChart" - ) + formatter.fillPaint.color = color + formatter.borderPaint.color = requireContext().getMaterialColor( + androidx.appcompat.R.attr.colorPrimary, + "TakenSkippedChart" ) return formatter } @@ -328,10 +320,8 @@ class ChartsFragment : Fragment() { } fun setDays(days: Int) { - if (isAdded) { - viewModel.setDays(days) - } - } + viewModel.setDays(days) + } private inner class DaysSinceEpochFormat : NumberFormat() { override fun format( diff --git a/app/src/main/java/com/futsch1/medtimer/statistics/ChartsViewModel.kt b/app/src/main/java/com/futsch1/medtimer/statistics/ChartsViewModel.kt index af77e1054..b79f965cc 100644 --- a/app/src/main/java/com/futsch1/medtimer/statistics/ChartsViewModel.kt +++ b/app/src/main/java/com/futsch1/medtimer/statistics/ChartsViewModel.kt @@ -85,9 +85,10 @@ class ChartsViewModel @Inject constructor( } private suspend fun computeSeriesColors(series: List): List { + val allMedicines = medicineRepository.getAll() var colorIndex = 0 return series.map { xySeries -> - medicineRepository.getAll() + allMedicines .firstOrNull { it.name == xySeries.title && it.useColor } ?.color ?: COLORS[colorIndex++ % COLORS.size] From a69f7ff6f4c7e5d4e0ffc22466c4f50faec44883 Mon Sep 17 00:00:00 2001 From: Futsch1 <63090558+Futsch1@users.noreply.github.com> Date: Sat, 9 May 2026 11:02:36 +0200 Subject: [PATCH 2/5] Fix charts always showing and updating --- .../medtimer/statistics/ChartsFragment.kt | 27 ++----------------- .../medtimer/statistics/ChartsViewModel.kt | 2 +- .../medtimer/statistics/StatisticsFragment.kt | 6 +++-- 3 files changed, 7 insertions(+), 28 deletions(-) diff --git a/app/src/main/java/com/futsch1/medtimer/statistics/ChartsFragment.kt b/app/src/main/java/com/futsch1/medtimer/statistics/ChartsFragment.kt index 83bd412e7..3bf39b079 100644 --- a/app/src/main/java/com/futsch1/medtimer/statistics/ChartsFragment.kt +++ b/app/src/main/java/com/futsch1/medtimer/statistics/ChartsFragment.kt @@ -45,7 +45,7 @@ import kotlin.math.roundToInt @AndroidEntryPoint class ChartsFragment : Fragment() { - private val viewModel: ChartsViewModel by viewModels() + private val viewModel: ChartsViewModel by viewModels({ requireParentFragment() }) @Inject @Dispatcher(MedTimerDispatchers.Main) @@ -69,19 +69,6 @@ class ChartsFragment : Fragment() { private var medicinesPerDayChartInitialized = false - companion object { - private const val DAYS_BUNDLE_KEY = "days" - - fun newInstance(days: Int) = ChartsFragment().apply { - arguments = Bundle().apply { putInt(DAYS_BUNDLE_KEY, days) } - } - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - viewModel.setDays(arguments?.getInt(DAYS_BUNDLE_KEY) ?: 0) - } - override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -95,7 +82,7 @@ class ChartsFragment : Fragment() { setupTakenSkippedCharts() setupMedicinesPerDayChart() - lifecycleScope.launch(backgroundDispatcher) { + viewLifecycleOwner.lifecycleScope.launch(backgroundDispatcher) { viewModel.uiState.filterNotNull().collect { state -> withContext(mainDispatcher) { updateMedicinesPerDayChart(state) @@ -313,16 +300,6 @@ class ChartsFragment : Fragment() { } } - override fun onResume() { - super.onResume() - // Re-trigger data load with current days on resume - viewModel.setDays(viewModel.uiState.value?.days ?: (arguments?.getInt(DAYS_BUNDLE_KEY) ?: 0)) - } - - fun setDays(days: Int) { - viewModel.setDays(days) - } - private inner class DaysSinceEpochFormat : NumberFormat() { override fun format( value: Double, buffer: StringBuffer, field: FieldPosition diff --git a/app/src/main/java/com/futsch1/medtimer/statistics/ChartsViewModel.kt b/app/src/main/java/com/futsch1/medtimer/statistics/ChartsViewModel.kt index b79f965cc..34283b7b3 100644 --- a/app/src/main/java/com/futsch1/medtimer/statistics/ChartsViewModel.kt +++ b/app/src/main/java/com/futsch1/medtimer/statistics/ChartsViewModel.kt @@ -51,7 +51,7 @@ class ChartsViewModel @Inject constructor( val uiState: StateFlow = _days .flatMapLatest { days -> flow { emit(loadState(days)) } } .flowOn(ioDispatcher) - .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), null) + .stateIn(viewModelScope, SharingStarted.WhileSubscribed(0), null) fun setDays(days: Int) { _days.value = days diff --git a/app/src/main/java/com/futsch1/medtimer/statistics/StatisticsFragment.kt b/app/src/main/java/com/futsch1/medtimer/statistics/StatisticsFragment.kt index c1d1175ce..803834a81 100644 --- a/app/src/main/java/com/futsch1/medtimer/statistics/StatisticsFragment.kt +++ b/app/src/main/java/com/futsch1/medtimer/statistics/StatisticsFragment.kt @@ -22,6 +22,7 @@ import javax.inject.Inject @AndroidEntryPoint class StatisticsFragment : Fragment() { private val medicineViewModel: MedicineViewModel by viewModels() + private val chartsViewModel: ChartsViewModel by viewModels() private lateinit var timeSpinner: Spinner private lateinit var chartsFragment: ChartsFragment @@ -35,7 +36,8 @@ class StatisticsFragment : Fragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - chartsFragment = ChartsFragment.newInstance(persistentDataDataSource.data.value.analysisDays) + chartsFragment = ChartsFragment() + chartsViewModel.setDays(persistentDataDataSource.data.value.analysisDays) optionsMenu = optionsMenuFactory.create( this, @@ -150,7 +152,7 @@ class StatisticsFragment : Fragment() { val days = AnalysisDays.getDays(requireContext(), position) persistentDataDataSource.setAnalysisDays(days) - chartsFragment.setDays(days) + chartsViewModel.setDays(days) } } From 35af4061503c7dc1dca4c6b8b8135bca46a2a696 Mon Sep 17 00:00:00 2001 From: Futsch1 <63090558+Futsch1@users.noreply.github.com> Date: Sat, 9 May 2026 12:06:04 +0200 Subject: [PATCH 3/5] Fix timing related crash --- .../java/com/futsch1/medtimer/statistics/ChartsFragment.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/futsch1/medtimer/statistics/ChartsFragment.kt b/app/src/main/java/com/futsch1/medtimer/statistics/ChartsFragment.kt index 3bf39b079..8d860e3be 100644 --- a/app/src/main/java/com/futsch1/medtimer/statistics/ChartsFragment.kt +++ b/app/src/main/java/com/futsch1/medtimer/statistics/ChartsFragment.kt @@ -82,8 +82,9 @@ class ChartsFragment : Fragment() { setupTakenSkippedCharts() setupMedicinesPerDayChart() + val uiState = viewModel.uiState viewLifecycleOwner.lifecycleScope.launch(backgroundDispatcher) { - viewModel.uiState.filterNotNull().collect { state -> + uiState.filterNotNull().collect { state -> withContext(mainDispatcher) { updateMedicinesPerDayChart(state) updateTakenSkipped( From 660df068bdebc499a9255f1720e4d1b107d2caae Mon Sep 17 00:00:00 2001 From: Futsch1 <63090558+Futsch1@users.noreply.github.com> Date: Sat, 9 May 2026 15:35:00 +0200 Subject: [PATCH 4/5] Test reliability improvements --- .../java/com/futsch1/medtimer/AndroidTestHelper.kt | 7 ++++++- .../androidTest/java/com/futsch1/medtimer/ReminderTest.kt | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/app/src/androidTest/java/com/futsch1/medtimer/AndroidTestHelper.kt b/app/src/androidTest/java/com/futsch1/medtimer/AndroidTestHelper.kt index fa284dc75..c960968ac 100644 --- a/app/src/androidTest/java/com/futsch1/medtimer/AndroidTestHelper.kt +++ b/app/src/androidTest/java/com/futsch1/medtimer/AndroidTestHelper.kt @@ -32,6 +32,7 @@ object AndroidTestHelper { clickOn(R.id.addReminder) clickOn(R.id.timeBasedCard) writeTo(R.id.editAmount, amount) + closeKeyboard() if (time != null) { clickOn(R.id.editReminderTime) @@ -60,8 +61,12 @@ object AndroidTestHelper { clickOn(com.google.android.material.R.id.material_timepicker_mode_button) writeTo(com.google.android.material.R.id.material_hour_text_input, hour.toString()) + // Close the keyboard before clicking the minute field – on tablets the soft keyboard + // causes the time-picker dialog to be shifted (adjustPan) and the minute field leaves + // the global visible rect, making Espresso unable to click it and eventually + // dismissing the dialog entirely. + closeKeyboard() clickOn(com.google.android.material.R.id.material_minute_text_input) - clickOn(com.google.android.material.R.id.material_minute_text_input) // Fails sometimes, do this twice Espresso.onView( Matchers.allOf( ViewMatchers.isDescendantOfA(ViewMatchers.withId(com.google.android.material.R.id.material_minute_text_input)), diff --git a/app/src/androidTest/java/com/futsch1/medtimer/ReminderTest.kt b/app/src/androidTest/java/com/futsch1/medtimer/ReminderTest.kt index e0d06a1cb..50535c626 100644 --- a/app/src/androidTest/java/com/futsch1/medtimer/ReminderTest.kt +++ b/app/src/androidTest/java/com/futsch1/medtimer/ReminderTest.kt @@ -419,7 +419,7 @@ class ReminderTest : BaseTestHelper() { // Mark event as taken AndroidTestHelper.navigateTo(MainMenu.OVERVIEW) - clickOn(R.id.stateButton) + clickListItemChild(R.id.reminders, 0, R.id.stateButton) clickOn(R.id.takenButton) // Check if cyclic information is present From 53a8723175911eb8858157c63575a41aa972f63e Mon Sep 17 00:00:00 2001 From: Futsch1 <63090558+Futsch1@users.noreply.github.com> Date: Sat, 9 May 2026 16:02:06 +0200 Subject: [PATCH 5/5] More test reliability improvements --- .../androidTest/java/com/futsch1/medtimer/AndroidTestHelper.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/androidTest/java/com/futsch1/medtimer/AndroidTestHelper.kt b/app/src/androidTest/java/com/futsch1/medtimer/AndroidTestHelper.kt index c960968ac..195a3bb0f 100644 --- a/app/src/androidTest/java/com/futsch1/medtimer/AndroidTestHelper.kt +++ b/app/src/androidTest/java/com/futsch1/medtimer/AndroidTestHelper.kt @@ -82,6 +82,7 @@ object AndroidTestHelper { val dateString = dateToStringForDateEdit(date) clickOn(com.google.android.material.R.id.mtrl_picker_header_toggle) writeTo(com.google.android.material.R.id.mtrl_picker_text_input_date, dateString) + closeKeyboard() clickOn(com.google.android.material.R.id.confirm_button) } @@ -114,6 +115,7 @@ object AndroidTestHelper { @JvmStatic fun setValue(value: String) { writeTo(android.R.id.edit, value) + closeKeyboard() clickDialogPositiveButton() }