From d1de3a852b06d16763f2ac862862de2c74707967 Mon Sep 17 00:00:00 2001 From: "Alinson S. Xavier" Date: Thu, 12 May 2022 09:27:06 -0500 Subject: [PATCH 01/10] Implement NumberPopup --- .../common/dialogs/CheckmarkPopup.kt | 2 + .../activities/common/dialogs/NumberPopup.kt | 112 ++++++++++++++++++ .../habits/list/ListHabitsScreen.kt | 32 ++++- .../habits/list/views/NumberButtonView.kt | 9 +- .../habits/list/views/NumberPanelView.kt | 3 +- .../habits/show/ShowHabitActivity.kt | 2 +- .../isoron/uhabits/utils/ViewExtensions.kt | 16 +++ .../src/main/res/layout/checkmark_popup.xml | 34 +++++- .../src/main/res/values/styles.xml | 15 +++ .../screens/habits/list/ListHabitsBehavior.kt | 16 +-- .../habits/list/ListHabitsBehaviorTest.kt | 7 +- 11 files changed, 222 insertions(+), 26 deletions(-) create mode 100644 uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/NumberPopup.kt diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/CheckmarkPopup.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/CheckmarkPopup.kt index 85d7fdfc1..bf4033a73 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/CheckmarkPopup.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/CheckmarkPopup.kt @@ -25,6 +25,7 @@ import android.view.Gravity import android.view.LayoutInflater import android.view.View import android.view.View.GONE +import android.view.View.VISIBLE import android.widget.PopupWindow import org.isoron.platform.gui.ScreenLocation import org.isoron.uhabits.R @@ -59,6 +60,7 @@ class CheckmarkPopup( } init { + view.booleanButtons.visibility = VISIBLE initColors() initTypefaces() hideDisabledButtons() diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/NumberPopup.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/NumberPopup.kt new file mode 100644 index 000000000..6a6a557fa --- /dev/null +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/NumberPopup.kt @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +package org.isoron.uhabits.activities.common.dialogs + +import android.content.Context +import android.view.Gravity +import android.view.KeyEvent.KEYCODE_ENTER +import android.view.LayoutInflater +import android.view.MotionEvent.ACTION_DOWN +import android.view.View +import android.view.View.GONE +import android.view.View.VISIBLE +import android.widget.PopupWindow +import org.isoron.platform.gui.ScreenLocation +import org.isoron.uhabits.core.models.Entry +import org.isoron.uhabits.core.preferences.Preferences +import org.isoron.uhabits.databinding.CheckmarkPopupBinding +import org.isoron.uhabits.utils.dimBehind +import org.isoron.uhabits.utils.dp +import org.isoron.uhabits.utils.requestFocusWithKeyboard +import java.text.DecimalFormat + +class NumberPopup( + private val context: Context, + private var notes: String, + private var value: Double, + private val prefs: Preferences, + private val anchor: View, +) { + var onToggle: (Double, String) -> Unit = { _, _ -> } + private val originalValue = value + + private val view = CheckmarkPopupBinding.inflate(LayoutInflater.from(context)).apply { + // Required for round corners + container.clipToOutline = true + } + + init { + view.numberButtons.visibility = VISIBLE + hideDisabledButtons() + populate() + } + + private fun hideDisabledButtons() { + if (!prefs.isSkipEnabled) view.skipBtnNumber.visibility = GONE + } + + private fun populate() { + view.notes.setText(notes) + view.value.setText( + when { + value < 0.01 -> "0" + else -> DecimalFormat("#.##").format(value) + } + ) + } + + fun show(location: ScreenLocation) { + val popup = PopupWindow() + popup.contentView = view.root + popup.width = view.root.dp(POPUP_WIDTH).toInt() + popup.height = view.root.dp(POPUP_HEIGHT).toInt() + popup.isFocusable = true + popup.elevation = view.root.dp(24f) + popup.setOnDismissListener { + save() + } + view.value.setOnKeyListener { _, keyCode, event -> + if (event.action == ACTION_DOWN && keyCode == KEYCODE_ENTER) { + popup.dismiss() + return@setOnKeyListener true + } + return@setOnKeyListener false + } + view.saveBtn.setOnClickListener { popup.dismiss() } + view.skipBtnNumber.setOnClickListener { + view.value.setText((Entry.SKIP.toDouble() / 1000).toString()) + popup.dismiss() + } + popup.showAtLocation( + anchor, + Gravity.NO_GRAVITY, + view.root.dp(location.x.toFloat()).toInt(), + view.root.dp(location.y.toFloat()).toInt(), + ) + view.value.requestFocusWithKeyboard() + popup.dimBehind() + } + + fun save() { + val value = view.value.text.toString().toDoubleOrNull() ?: originalValue + val notes = view.notes.text.toString() + onToggle(value, notes) + } +} diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsScreen.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsScreen.kt index d5794a388..9fda6370b 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsScreen.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsScreen.kt @@ -31,6 +31,7 @@ import org.isoron.uhabits.activities.common.dialogs.CheckmarkPopup import org.isoron.uhabits.activities.common.dialogs.ColorPickerDialogFactory import org.isoron.uhabits.activities.common.dialogs.ConfirmDeleteDialog import org.isoron.uhabits.activities.common.dialogs.NumberPickerFactory +import org.isoron.uhabits.activities.common.dialogs.NumberPopup import org.isoron.uhabits.activities.common.dialogs.POPUP_WIDTH import org.isoron.uhabits.activities.habits.edit.HabitTypeDialog import org.isoron.uhabits.activities.habits.list.views.HabitCardListAdapter @@ -242,6 +243,25 @@ class ListHabitsScreen numberPickerFactory.create(value, unit, notes, dateString, frequency, callback).show() } + override fun showNumberPopup( + value: Double, + notes: String, + location: ScreenLocation, + callback: ListHabitsBehavior.NumberPickerCallback + ) { + val view = rootView.get() + NumberPopup( + context = context, + prefs = preferences, + anchor = view, + notes = notes, + value = value, + ).apply { + onToggle = { value, notes -> callback.onNumberPicked(value, notes) } + show(getPopupLocation(location)) + } + } + override fun showCheckmarkPopup( selectedValue: Int, notes: String, @@ -259,15 +279,15 @@ class ListHabitsScreen value = selectedValue, ).apply { onToggle = { value, notes -> callback.onNotesSaved(value, notes) } - show( - ScreenLocation( - x = location.x - POPUP_WIDTH / 2, - y = location.y - ) - ) + show(getPopupLocation(location)) } } + private fun getPopupLocation(clickLocation: ScreenLocation) = ScreenLocation( + x = clickLocation.x - POPUP_WIDTH / 2, + y = clickLocation.y + ) + private fun getExecuteString(command: Command): String? { when (command) { is ArchiveHabitsCommand -> { diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/NumberButtonView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/NumberButtonView.kt index 4d8bdda05..7f476015e 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/NumberButtonView.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/NumberButtonView.kt @@ -28,6 +28,7 @@ import android.text.TextPaint import android.view.View import android.view.View.OnClickListener import android.view.View.OnLongClickListener +import org.isoron.platform.gui.ScreenLocation import org.isoron.uhabits.R import org.isoron.uhabits.core.models.Entry import org.isoron.uhabits.core.models.NumericalHabitType.AT_LEAST @@ -37,6 +38,7 @@ import org.isoron.uhabits.inject.ActivityContext import org.isoron.uhabits.utils.InterfaceUtils.getDimension import org.isoron.uhabits.utils.dim import org.isoron.uhabits.utils.drawNotesIndicator +import org.isoron.uhabits.utils.getCenter import org.isoron.uhabits.utils.getFontAwesome import org.isoron.uhabits.utils.sres import java.text.DecimalFormat @@ -108,7 +110,8 @@ class NumberButtonView( invalidate() } - var onEdit: () -> Unit = {} + var onEdit: (ScreenLocation) -> Unit = { _ -> } + private var drawer: Drawer = Drawer(context) init { @@ -117,11 +120,11 @@ class NumberButtonView( } override fun onClick(v: View) { - onEdit() + onEdit(getCenter()) } override fun onLongClick(v: View): Boolean { - onEdit() + onEdit(getCenter()) return true } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/NumberPanelView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/NumberPanelView.kt index dc49b557b..c6ce2089f 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/NumberPanelView.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/NumberPanelView.kt @@ -26,7 +26,6 @@ import org.isoron.uhabits.core.models.Timestamp import org.isoron.uhabits.core.preferences.Preferences import org.isoron.uhabits.core.utils.DateUtils import org.isoron.uhabits.inject.ActivityContext -import org.isoron.uhabits.utils.getCenter import javax.inject.Inject class NumberPanelViewFactory @@ -106,7 +105,7 @@ class NumberPanelView( button.targetType = targetType button.threshold = threshold button.units = units - button.onEdit = { onEdit(getCenter(), timestamp) } + button.onEdit = { location -> onEdit(location, timestamp) } } } } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitActivity.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitActivity.kt index 6eadb1b59..397c6f4ff 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitActivity.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitActivity.kt @@ -205,7 +205,7 @@ class ShowHabitActivity : AppCompatActivity(), CommandRunner.Listener { prefs = preferences, notes = notes, color = view.currentTheme().color(color).toInt(), - anchor = view, + anchor = anchor, value = selectedValue, ).apply { onToggle = { v, n -> callback.onNotesSaved(v, n) } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/utils/ViewExtensions.kt b/uhabits-android/src/main/java/org/isoron/uhabits/utils/ViewExtensions.kt index df140aa79..0a6cbf16d 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/utils/ViewExtensions.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/utils/ViewExtensions.kt @@ -28,12 +28,15 @@ import android.graphics.Color import android.graphics.Paint import android.graphics.drawable.ColorDrawable import android.os.Handler +import android.os.SystemClock import android.view.LayoutInflater +import android.view.MotionEvent import android.view.View import android.view.ViewGroup import android.view.ViewGroup.LayoutParams.MATCH_PARENT import android.view.ViewGroup.LayoutParams.WRAP_CONTENT import android.view.WindowManager +import android.widget.EditText import android.widget.PopupWindow import android.widget.RelativeLayout import android.widget.RelativeLayout.ALIGN_PARENT_BOTTOM @@ -256,3 +259,16 @@ fun View.getTopLeftCorner(): ScreenLocation { y = (loc[1] / density).toDouble(), ) } + +fun View.requestFocusWithKeyboard() { + // For some reason, Android does not open the soft keyboard by default when view.requestFocus + // is called. Several online solutions suggest using InputMethodManager, but these solutions + // are not reliable; sometimes the keyboard does not show, and sometimes it does not go away + // after focus is lost. Here, we simulate a click on the view, which triggers the keyboard. + // Based on: https://stackoverflow.com/a/7699556 + postDelayed({ + val time = SystemClock.uptimeMillis() + dispatchTouchEvent(MotionEvent.obtain(time, time, MotionEvent.ACTION_DOWN, 0f, 0f, 0)) + dispatchTouchEvent(MotionEvent.obtain(time, time, MotionEvent.ACTION_UP, 0f, 0f, 0)) + }, 250) +} diff --git a/uhabits-android/src/main/res/layout/checkmark_popup.xml b/uhabits-android/src/main/res/layout/checkmark_popup.xml index f1aa569a6..72dc79786 100644 --- a/uhabits-android/src/main/res/layout/checkmark_popup.xml +++ b/uhabits-android/src/main/res/layout/checkmark_popup.xml @@ -42,6 +42,8 @@ android:text="" /> - + + + + + + + + + \ No newline at end of file diff --git a/uhabits-android/src/main/res/values/styles.xml b/uhabits-android/src/main/res/values/styles.xml index f25602748..8a016d96d 100644 --- a/uhabits-android/src/main/res/values/styles.xml +++ b/uhabits-android/src/main/res/values/styles.xml @@ -398,4 +398,19 @@ @dimen/smallerTextSize + + diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehavior.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehavior.kt index b14ecc591..5a8fe1459 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehavior.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehavior.kt @@ -53,14 +53,8 @@ open class ListHabitsBehavior @Inject constructor( fun onEdit(location: ScreenLocation, habit: Habit, timestamp: Timestamp?) { val entry = habit.computedEntries.get(timestamp!!) if (habit.type == HabitType.NUMERICAL) { - val oldValue = entry.value.toDouble() - screen.showNumberPicker( - oldValue / 1000, - habit.unit, - entry.notes, - timestamp.toDialogDateString(), - habit.frequency - ) { newValue: Double, newNotes: String, -> + val oldValue = entry.value.toDouble() / 1000 + screen.showNumberPopup(oldValue, entry.notes, location) { newValue: Double, newNotes: String -> val value = (newValue * 1000).roundToInt() commandRunner.run(CreateRepetitionCommand(habitList, habit, timestamp, value, newNotes)) } @@ -170,6 +164,12 @@ open class ListHabitsBehavior @Inject constructor( frequency: Frequency, callback: NumberPickerCallback ) + fun showNumberPopup( + value: Double, + notes: String, + location: ScreenLocation, + callback: NumberPickerCallback + ) fun showCheckmarkPopup( selectedValue: Int, notes: String, diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehaviorTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehaviorTest.kt index c147fa524..97778338a 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehaviorTest.kt +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehaviorTest.kt @@ -34,7 +34,6 @@ import org.hamcrest.core.IsEqual.equalTo import org.isoron.platform.gui.ScreenLocation import org.isoron.uhabits.core.BaseUnitTest import org.isoron.uhabits.core.models.Entry -import org.isoron.uhabits.core.models.Frequency import org.isoron.uhabits.core.models.Habit import org.isoron.uhabits.core.preferences.Preferences import org.isoron.uhabits.core.utils.DateUtils.Companion.getToday @@ -81,12 +80,10 @@ class ListHabitsBehaviorTest : BaseUnitTest() { @Test fun testOnEdit() { behavior.onEdit(ScreenLocation(0.0, 0.0), habit2, getToday()) - verify(screen).showNumberPicker( + verify(screen).showNumberPopup( eq(0.1), - eq("miles"), eq(""), - eq("Jan 25, 2015"), - eq(Frequency.DAILY), + any(), picker.capture() ) picker.lastValue.onNumberPicked(100.0, "") From 2a012619a77c4dc88897dd123d10c3ab831afc0a Mon Sep 17 00:00:00 2001 From: "Alinson S. Xavier" Date: Thu, 12 May 2022 10:38:12 -0500 Subject: [PATCH 02/10] Use NumberPopup in widgets --- uhabits-android/src/main/AndroidManifest.xml | 2 +- .../isoron/uhabits/utils/ViewExtensions.kt | 1 - .../NumericalCheckmarkWidgetActivity.kt | 49 +++++++++++++------ .../src/main/res/values/styles.xml | 9 ++++ 4 files changed, 44 insertions(+), 17 deletions(-) diff --git a/uhabits-android/src/main/AndroidManifest.xml b/uhabits-android/src/main/AndroidManifest.xml index 3b0851207..721a10ae5 100644 --- a/uhabits-android/src/main/AndroidManifest.xml +++ b/uhabits-android/src/main/AndroidManifest.xml @@ -125,7 +125,7 @@ android:exported="true" android:label="NumericalCheckmarkWidget" android:noHistory="true" - android:theme="@style/Theme.AppCompat.Light.Dialog"> + android:theme="@style/Theme.Transparent"> diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/utils/ViewExtensions.kt b/uhabits-android/src/main/java/org/isoron/uhabits/utils/ViewExtensions.kt index 0a6cbf16d..16d4e6369 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/utils/ViewExtensions.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/utils/ViewExtensions.kt @@ -36,7 +36,6 @@ import android.view.ViewGroup import android.view.ViewGroup.LayoutParams.MATCH_PARENT import android.view.ViewGroup.LayoutParams.WRAP_CONTENT import android.view.WindowManager -import android.widget.EditText import android.widget.PopupWindow import android.widget.RelativeLayout import android.widget.RelativeLayout.ALIGN_PARENT_BOTTOM diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/activities/NumericalCheckmarkWidgetActivity.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/activities/NumericalCheckmarkWidgetActivity.kt index b7bc7f229..080e7916e 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/activities/NumericalCheckmarkWidgetActivity.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/activities/NumericalCheckmarkWidgetActivity.kt @@ -22,16 +22,21 @@ package org.isoron.uhabits.widgets.activities import android.app.Activity import android.content.Context import android.os.Bundle -import android.view.Window +import android.view.View +import android.view.ViewGroup.LayoutParams.MATCH_PARENT import android.widget.FrameLayout +import org.isoron.platform.gui.ScreenLocation import org.isoron.uhabits.HabitsApplication import org.isoron.uhabits.activities.AndroidThemeSwitcher -import org.isoron.uhabits.activities.common.dialogs.NumberPickerFactory +import org.isoron.uhabits.activities.common.dialogs.NumberPopup +import org.isoron.uhabits.activities.common.dialogs.POPUP_HEIGHT +import org.isoron.uhabits.activities.common.dialogs.POPUP_WIDTH import org.isoron.uhabits.core.ui.screens.habits.list.ListHabitsBehavior import org.isoron.uhabits.core.ui.widgets.WidgetBehavior import org.isoron.uhabits.core.utils.DateUtils import org.isoron.uhabits.intents.IntentParser import org.isoron.uhabits.utils.SystemUtils +import org.isoron.uhabits.utils.getCenter import org.isoron.uhabits.widgets.WidgetUpdater class NumericalCheckmarkWidgetActivity : Activity(), ListHabitsBehavior.NumberPickerCallback { @@ -39,11 +44,13 @@ class NumericalCheckmarkWidgetActivity : Activity(), ListHabitsBehavior.NumberPi private lateinit var behavior: WidgetBehavior private lateinit var data: IntentParser.CheckmarkIntentData private lateinit var widgetUpdater: WidgetUpdater + private lateinit var rootView: View override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - requestWindowFeature(Window.FEATURE_NO_TITLE) - setContentView(FrameLayout(this)) + rootView = FrameLayout(this) + rootView.layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT) + setContentView(rootView) val app = this.applicationContext as HabitsApplication val component = app.component val parser = app.component.intentParser @@ -55,8 +62,9 @@ class NumericalCheckmarkWidgetActivity : Activity(), ListHabitsBehavior.NumberPi component.preferences ) widgetUpdater = component.widgetUpdater - showNumberSelector(this) - + rootView.post { + showNumberSelector(this) + } SystemUtils.unlockScreen(this) } @@ -73,17 +81,28 @@ class NumericalCheckmarkWidgetActivity : Activity(), ListHabitsBehavior.NumberPi private fun showNumberSelector(context: Context) { val app = this.applicationContext as HabitsApplication AndroidThemeSwitcher(this, app.component.preferences).apply() - val numberPickerFactory = NumberPickerFactory(context) val today = DateUtils.getTodayWithOffset() val entry = data.habit.computedEntries.get(today) - numberPickerFactory.create( - entry.value / 1000.0, - data.habit.unit, - entry.notes, - today.toDialogDateString(), - data.habit.frequency, - this - ).show() + NumberPopup( + context = context, + prefs = app.component.preferences, + anchor = rootView, + notes = entry.notes, + value = entry.value / 1000.0, + ).apply { + onToggle = { value, notes -> + onNumberPicked(value, notes) + finish() + overridePendingTransition(0, 0) + } + val center = rootView.getCenter() + show( + ScreenLocation( + x = center.x - POPUP_WIDTH / 2, + y = center.y - POPUP_HEIGHT / 2 + ) + ) + } } companion object { diff --git a/uhabits-android/src/main/res/values/styles.xml b/uhabits-android/src/main/res/values/styles.xml index 8a016d96d..a3b2be8ba 100644 --- a/uhabits-android/src/main/res/values/styles.xml +++ b/uhabits-android/src/main/res/values/styles.xml @@ -413,4 +413,13 @@ + + From 555873354cb246afe9c817e76263ab279673f98d Mon Sep 17 00:00:00 2001 From: "Alinson S. Xavier" Date: Thu, 12 May 2022 11:25:27 -0500 Subject: [PATCH 03/10] Use NumberPopup in HistoryCard --- .../habits/show/ShowHabitActivity.kt | 48 ++++++++++++++----- .../screens/habits/show/views/HistoryCard.kt | 25 ++++++---- 2 files changed, 52 insertions(+), 21 deletions(-) diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitActivity.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitActivity.kt index 397c6f4ff..6d8528b76 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitActivity.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitActivity.kt @@ -23,6 +23,7 @@ import android.os.Bundle import android.view.HapticFeedbackConstants import android.view.Menu import android.view.MenuItem +import android.view.View import androidx.appcompat.app.AppCompatActivity import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -38,6 +39,7 @@ import org.isoron.uhabits.activities.common.dialogs.CheckmarkPopup import org.isoron.uhabits.activities.common.dialogs.ConfirmDeleteDialog import org.isoron.uhabits.activities.common.dialogs.HistoryEditorDialog import org.isoron.uhabits.activities.common.dialogs.NumberPickerFactory +import org.isoron.uhabits.activities.common.dialogs.NumberPopup import org.isoron.uhabits.activities.common.dialogs.POPUP_WIDTH import org.isoron.uhabits.core.commands.Command import org.isoron.uhabits.core.commands.CommandRunner @@ -187,6 +189,26 @@ class ShowHabitActivity : AppCompatActivity(), CommandRunner.Listener { ).show() } + override fun showNumberPopup( + value: Double, + notes: String, + preferences: Preferences, + location: ScreenLocation, + callback: ListHabitsBehavior.NumberPickerCallback + ) { + val anchor = getPopupAnchor() ?: return + NumberPopup( + context = this@ShowHabitActivity, + prefs = preferences, + notes = notes, + anchor = anchor, + value = value, + ).apply { + onToggle = { v, n -> callback.onNumberPicked(v, n) } + show(computePopupLocation(anchor, location)) + } + } + override fun showCheckmarkPopup( selectedValue: Int, notes: String, @@ -195,11 +217,7 @@ class ShowHabitActivity : AppCompatActivity(), CommandRunner.Listener { location: ScreenLocation, callback: ListHabitsBehavior.CheckMarkDialogCallback ) { - val dialog = - supportFragmentManager.findFragmentByTag("historyEditor") as HistoryEditorDialog? - ?: return - val view = dialog.dataView - val corner = view.getTopLeftCorner() + val anchor = getPopupAnchor() ?: return CheckmarkPopup( context = this@ShowHabitActivity, prefs = preferences, @@ -209,15 +227,23 @@ class ShowHabitActivity : AppCompatActivity(), CommandRunner.Listener { value = selectedValue, ).apply { onToggle = { v, n -> callback.onNotesSaved(v, n) } - show( - ScreenLocation( - x = corner.x + location.x - POPUP_WIDTH / 2, - y = corner.y + location.y, - ) - ) + show(computePopupLocation(anchor, location)) } } + private fun getPopupAnchor(): View? { + val dialog = supportFragmentManager.findFragmentByTag("historyEditor") as HistoryEditorDialog? + return dialog?.dataView + } + + private fun computePopupLocation(anchor: View, clickLocation: ScreenLocation): ScreenLocation { + val corner = anchor.getTopLeftCorner() + return ScreenLocation( + x = corner.x + clickLocation.x - POPUP_WIDTH / 2, + y = corner.y + clickLocation.y, + ) + } + override fun showEditHabitScreen(habit: Habit) { startActivity(IntentFactory().startEditActivity(this@ShowHabitActivity, habit)) } diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/show/views/HistoryCard.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/show/views/HistoryCard.kt index a6f9fd98b..b2ec71f99 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/show/views/HistoryCard.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/show/views/HistoryCard.kt @@ -70,7 +70,7 @@ class HistoryCardPresenter( val timestamp = Timestamp.fromLocalDate(date) screen.showFeedback() if (habit.isNumerical) { - showNumberPicker(timestamp) + showNumberPopup(location, timestamp) } else { if (preferences.isShortToggleEnabled) showCheckmarkPopup(location, timestamp) else toggle(timestamp) @@ -81,7 +81,7 @@ class HistoryCardPresenter( val timestamp = Timestamp.fromLocalDate(date) screen.showFeedback() if (habit.isNumerical) { - showNumberPicker(timestamp) + showNumberPopup(location, timestamp) } else { if (preferences.isShortToggleEnabled) toggle(timestamp) else showCheckmarkPopup(location, timestamp) @@ -127,15 +127,14 @@ class HistoryCardPresenter( ) } - private fun showNumberPicker(timestamp: Timestamp) { + private fun showNumberPopup(location: ScreenLocation, timestamp: Timestamp) { val entry = habit.computedEntries.get(timestamp) val oldValue = entry.value - screen.showNumberPicker( - oldValue / 1000.0, - habit.unit, - entry.notes, - timestamp.toDialogDateString(), - frequency = habit.frequency + screen.showNumberPopup( + value = oldValue / 1000.0, + notes = entry.notes, + preferences = preferences, + location = location, ) { newValue: Double, newNotes: String -> val thousands = (newValue * 1000).roundToInt() commandRunner.run( @@ -213,7 +212,13 @@ class HistoryCardPresenter( frequency: Frequency, callback: ListHabitsBehavior.NumberPickerCallback ) - + fun showNumberPopup( + value: Double, + notes: String, + preferences: Preferences, + location: ScreenLocation, + callback: ListHabitsBehavior.NumberPickerCallback, + ) fun showCheckmarkPopup( selectedValue: Int, notes: String, From 9045ae5c2412fbc029a0d21c5c20fce721100082 Mon Sep 17 00:00:00 2001 From: "Alinson S. Xavier" Date: Thu, 12 May 2022 11:28:43 -0500 Subject: [PATCH 04/10] Remove previous NumberPicker --- .../common/dialogs/NumberPickerFactory.kt | 205 ------------------ .../habits/list/ListHabitsScreen.kt | 14 -- .../habits/show/ShowHabitActivity.kt | 20 -- .../screens/habits/list/ListHabitsBehavior.kt | 8 - .../screens/habits/show/views/HistoryCard.kt | 8 - 5 files changed, 255 deletions(-) delete mode 100644 uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/NumberPickerFactory.kt diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/NumberPickerFactory.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/NumberPickerFactory.kt deleted file mode 100644 index 0ee4dad34..000000000 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/NumberPickerFactory.kt +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.activities.common.dialogs - -import android.annotation.SuppressLint -import android.content.Context -import android.content.DialogInterface -import android.content.DialogInterface.BUTTON_NEGATIVE -import android.text.InputFilter -import android.text.Spanned -import android.view.LayoutInflater -import android.view.View -import android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE -import android.view.inputmethod.EditorInfo -import android.view.inputmethod.InputMethodManager -import android.widget.EditText -import android.widget.NumberPicker -import android.widget.TextView -import androidx.appcompat.app.AlertDialog -import org.isoron.uhabits.HabitsApplication -import org.isoron.uhabits.R -import org.isoron.uhabits.core.models.Entry -import org.isoron.uhabits.core.models.Frequency -import org.isoron.uhabits.core.models.Frequency.Companion.DAILY -import org.isoron.uhabits.core.ui.screens.habits.list.ListHabitsBehavior -import org.isoron.uhabits.inject.ActivityContext -import org.isoron.uhabits.utils.InterfaceUtils -import java.text.DecimalFormatSymbols -import javax.inject.Inject -import kotlin.math.roundToLong - -class NumberPickerFactory -@Inject constructor( - @ActivityContext private val context: Context -) { - @SuppressLint("SetTextI18n") - fun create( - value: Double, - unit: String, - notes: String, - dateString: String, - frequency: Frequency, - callback: ListHabitsBehavior.NumberPickerCallback - ): AlertDialog { - clearCurrentDialog() - - val inflater = LayoutInflater.from(context) - val view = inflater.inflate(R.layout.number_picker_dialog, null) - - val picker = view.findViewById(R.id.picker) - val picker2 = view.findViewById(R.id.picker2) - val etNotes = view.findViewById(R.id.etNotes) - - // Install filter to intercept decimal separator before it is parsed - val watcherFilter: InputFilter = SeparatorWatcherInputFilter(picker2) - val pickerInputText = getNumberPickerInputText(picker) - pickerInputText.filters = arrayOf(watcherFilter).plus(pickerInputText.filters) - - // Install custom focus listener to replace "5" by "50" instead of "05" - val picker2InputText = getNumberPickerInputText(picker2) - val prevFocusChangeListener = picker2InputText.onFocusChangeListener - picker2InputText.onFocusChangeListener = View.OnFocusChangeListener { v, hasFocus -> - val str = picker2InputText.text.toString() - if (str.length == 1) picker2InputText.setText("${str}0") - prevFocusChangeListener.onFocusChange(v, hasFocus) - } - - view.findViewById(R.id.tvUnit).text = unit - view.findViewById(R.id.tvSeparator).text = - DecimalFormatSymbols.getInstance().decimalSeparator.toString() - - val intValue = (value * 100).roundToLong().toInt() - - picker.minValue = 0 - picker.maxValue = Integer.MAX_VALUE / 100 - picker.value = intValue / 100 - picker.wrapSelectorWheel = false - - picker2.minValue = 0 - picker2.maxValue = 99 - picker2.setFormatter { v -> String.format("%02d", v) } - picker2.value = intValue % 100 - - etNotes.setText(notes) - val dialogBuilder = AlertDialog.Builder(context) - .setView(view) - .setTitle(dateString) - .setPositiveButton(R.string.save) { _, _ -> - picker.clearFocus() - picker2.clearFocus() - val v = picker.value + 0.01 * picker2.value - val note = etNotes.text.toString().trim() - callback.onNumberPicked(v, note) - } - .setNegativeButton(android.R.string.cancel) { _, _ -> - callback.onNumberPickerDismissed() - } - .setOnDismissListener { - callback.onNumberPickerDismissed() - currentDialog = null - } - - if (frequency == DAILY) { - dialogBuilder.setNegativeButton(R.string.skip_day) { _, _ -> - picker.clearFocus() - val v = Entry.SKIP.toDouble() / 1000 - val note = etNotes.text.toString() - callback.onNumberPicked(v, note) - } - } - - val dialog = dialogBuilder.create() - - dialog.setOnShowListener { - val preferences = - (context.applicationContext as HabitsApplication).component.preferences - if (!preferences.isSkipEnabled) { - dialog.getButton(BUTTON_NEGATIVE).visibility = View.GONE - } - showSoftInput(dialog, pickerInputText) - } - - InterfaceUtils.setupEditorAction( - picker - ) { _, actionId, _ -> - if (actionId == EditorInfo.IME_ACTION_DONE) { - dialog.getButton(DialogInterface.BUTTON_POSITIVE).performClick() - } - false - } - - InterfaceUtils.setupEditorAction( - picker2 - ) { _, actionId, _ -> - if (actionId == EditorInfo.IME_ACTION_DONE) { - dialog.getButton(DialogInterface.BUTTON_POSITIVE).performClick() - } - false - } - - currentDialog = dialog - return dialog - } - - @SuppressLint("DiscouragedPrivateApi") - private fun getNumberPickerInputText(picker: NumberPicker): EditText { - val f = NumberPicker::class.java.getDeclaredField("mInputText") - f.isAccessible = true - return f.get(picker) as EditText - } - - private fun showSoftInput(dialog: AlertDialog, v: View) { - dialog.window?.setSoftInputMode(SOFT_INPUT_STATE_ALWAYS_VISIBLE) - v.requestFocus() - val inputMethodManager = context.getSystemService(InputMethodManager::class.java) - inputMethodManager?.showSoftInput(v, 0) - } - - companion object { - private var currentDialog: AlertDialog? = null - fun clearCurrentDialog() { - currentDialog?.dismiss() - currentDialog = null - } - } -} - -class SeparatorWatcherInputFilter(private val nextPicker: NumberPicker) : InputFilter { - override fun filter( - source: CharSequence?, - start: Int, - end: Int, - dest: Spanned?, - dstart: Int, - dend: Int - ): CharSequence { - if (source == null || source.isEmpty()) { - return "" - } - for (c in source) { - if (c == DecimalFormatSymbols.getInstance().decimalSeparator || c == '.' || c == ',') { - nextPicker.performLongClick() - break - } - } - return source - } -} diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsScreen.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsScreen.kt index 9fda6370b..bba63e8a5 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsScreen.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsScreen.kt @@ -30,7 +30,6 @@ import org.isoron.uhabits.R import org.isoron.uhabits.activities.common.dialogs.CheckmarkPopup import org.isoron.uhabits.activities.common.dialogs.ColorPickerDialogFactory import org.isoron.uhabits.activities.common.dialogs.ConfirmDeleteDialog -import org.isoron.uhabits.activities.common.dialogs.NumberPickerFactory import org.isoron.uhabits.activities.common.dialogs.NumberPopup import org.isoron.uhabits.activities.common.dialogs.POPUP_WIDTH import org.isoron.uhabits.activities.habits.edit.HabitTypeDialog @@ -43,7 +42,6 @@ import org.isoron.uhabits.core.commands.CreateHabitCommand import org.isoron.uhabits.core.commands.DeleteHabitsCommand import org.isoron.uhabits.core.commands.EditHabitCommand import org.isoron.uhabits.core.commands.UnarchiveHabitsCommand -import org.isoron.uhabits.core.models.Frequency import org.isoron.uhabits.core.models.Habit import org.isoron.uhabits.core.models.PaletteColor import org.isoron.uhabits.core.preferences.Preferences @@ -96,7 +94,6 @@ class ListHabitsScreen private val exportDBFactory: ExportDBTaskFactory, private val importTaskFactory: ImportDataTaskFactory, private val colorPickerFactory: ColorPickerDialogFactory, - private val numberPickerFactory: NumberPickerFactory, private val behavior: Lazy, private val preferences: Preferences, private val rootView: Lazy, @@ -232,17 +229,6 @@ class ListHabitsScreen picker.show(activity.supportFragmentManager, "picker") } - override fun showNumberPicker( - value: Double, - unit: String, - notes: String, - dateString: String, - frequency: Frequency, - callback: ListHabitsBehavior.NumberPickerCallback - ) { - numberPickerFactory.create(value, unit, notes, dateString, frequency, callback).show() - } - override fun showNumberPopup( value: Double, notes: String, diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitActivity.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitActivity.kt index 6d8528b76..e643d30d4 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitActivity.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitActivity.kt @@ -38,12 +38,10 @@ import org.isoron.uhabits.activities.HabitsDirFinder import org.isoron.uhabits.activities.common.dialogs.CheckmarkPopup import org.isoron.uhabits.activities.common.dialogs.ConfirmDeleteDialog import org.isoron.uhabits.activities.common.dialogs.HistoryEditorDialog -import org.isoron.uhabits.activities.common.dialogs.NumberPickerFactory import org.isoron.uhabits.activities.common.dialogs.NumberPopup import org.isoron.uhabits.activities.common.dialogs.POPUP_WIDTH import org.isoron.uhabits.core.commands.Command import org.isoron.uhabits.core.commands.CommandRunner -import org.isoron.uhabits.core.models.Frequency import org.isoron.uhabits.core.models.Habit import org.isoron.uhabits.core.models.PaletteColor import org.isoron.uhabits.core.preferences.Preferences @@ -171,24 +169,6 @@ class ShowHabitActivity : AppCompatActivity(), CommandRunner.Listener { window.decorView.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY) } - override fun showNumberPicker( - value: Double, - unit: String, - notes: String, - dateString: String, - frequency: Frequency, - callback: ListHabitsBehavior.NumberPickerCallback - ) { - NumberPickerFactory(this@ShowHabitActivity).create( - value, - unit, - notes, - dateString, - frequency, - callback - ).show() - } - override fun showNumberPopup( value: Double, notes: String, diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehavior.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehavior.kt index 5a8fe1459..28f1c9b8b 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehavior.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehavior.kt @@ -156,14 +156,6 @@ open class ListHabitsBehavior @Inject constructor( fun showHabitScreen(h: Habit) fun showIntroScreen() fun showMessage(m: Message) - fun showNumberPicker( - value: Double, - unit: String, - notes: String, - dateString: String, - frequency: Frequency, - callback: NumberPickerCallback - ) fun showNumberPopup( value: Double, notes: String, diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/show/views/HistoryCard.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/show/views/HistoryCard.kt index b2ec71f99..276253bc6 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/show/views/HistoryCard.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/show/views/HistoryCard.kt @@ -204,14 +204,6 @@ class HistoryCardPresenter( interface Screen { fun showHistoryEditorDialog(listener: OnDateClickedListener) fun showFeedback() - fun showNumberPicker( - value: Double, - unit: String, - notes: String, - dateString: String, - frequency: Frequency, - callback: ListHabitsBehavior.NumberPickerCallback - ) fun showNumberPopup( value: Double, notes: String, From 25aeafb75913c5b0608a71d2c43f690dc6fb4798 Mon Sep 17 00:00:00 2001 From: "Alinson S. Xavier" Date: Thu, 12 May 2022 12:01:47 -0500 Subject: [PATCH 05/10] Remove unused imports --- .../uhabits/core/ui/screens/habits/list/ListHabitsBehavior.kt | 1 - .../uhabits/core/ui/screens/habits/show/views/HistoryCard.kt | 1 - 2 files changed, 2 deletions(-) diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehavior.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehavior.kt index 28f1c9b8b..f1a88f411 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehavior.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehavior.kt @@ -21,7 +21,6 @@ package org.isoron.uhabits.core.ui.screens.habits.list import org.isoron.platform.gui.ScreenLocation import org.isoron.uhabits.core.commands.CommandRunner import org.isoron.uhabits.core.commands.CreateRepetitionCommand -import org.isoron.uhabits.core.models.Frequency import org.isoron.uhabits.core.models.Habit import org.isoron.uhabits.core.models.HabitList import org.isoron.uhabits.core.models.HabitType diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/show/views/HistoryCard.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/show/views/HistoryCard.kt index 276253bc6..18c044bc2 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/show/views/HistoryCard.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/show/views/HistoryCard.kt @@ -28,7 +28,6 @@ import org.isoron.uhabits.core.models.Entry import org.isoron.uhabits.core.models.Entry.Companion.SKIP import org.isoron.uhabits.core.models.Entry.Companion.YES_AUTO import org.isoron.uhabits.core.models.Entry.Companion.YES_MANUAL -import org.isoron.uhabits.core.models.Frequency import org.isoron.uhabits.core.models.Habit import org.isoron.uhabits.core.models.HabitList import org.isoron.uhabits.core.models.NumericalHabitType.AT_LEAST From d2d45991b044ab1b2f403764de2dc3c0a0d135cc Mon Sep 17 00:00:00 2001 From: "Alinson S. Xavier" Date: Fri, 13 May 2022 06:37:41 -0500 Subject: [PATCH 06/10] Always show popups at the center of the screen; remove ScreenLocation --- .../habits/list/views/EntryButtonViewTest.kt | 2 +- .../habits/list/views/NumberPanelViewTest.kt | 4 +- .../common/dialogs/CheckmarkPopup.kt | 10 +---- .../activities/common/dialogs/NumberPopup.kt | 10 +---- .../habits/list/ListHabitsScreen.kt | 13 +----- .../habits/list/views/CheckmarkButtonView.kt | 8 ++-- .../habits/list/views/CheckmarkPanelView.kt | 5 +-- .../habits/list/views/HabitCardView.kt | 8 ++-- .../habits/list/views/NumberButtonView.kt | 8 ++-- .../habits/list/views/NumberPanelView.kt | 5 +-- .../habits/show/ShowHabitActivity.kt | 17 +------- .../isoron/uhabits/utils/ViewExtensions.kt | 29 ------------- .../NumericalCheckmarkWidgetActivity.kt | 12 +----- .../screens/habits/list/ListHabitsBehavior.kt | 8 +--- .../screens/habits/show/views/HistoryCard.kt | 21 ++++------ .../uhabits/core/ui/views/HistoryChart.kt | 10 ++--- .../habits/list/ListHabitsBehaviorTest.kt | 4 +- .../uhabits/core/ui/views/HistoryChartTest.kt | 41 ++++--------------- 18 files changed, 49 insertions(+), 166 deletions(-) diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/EntryButtonViewTest.kt b/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/EntryButtonViewTest.kt index 9b807c764..f37cc1838 100644 --- a/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/EntryButtonViewTest.kt +++ b/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/EntryButtonViewTest.kt @@ -45,7 +45,7 @@ class EntryButtonViewTest : BaseViewTest() { value = Entry.NO color = PaletteUtils.getAndroidTestColor(5) onToggle = { _, _, _ -> toggled = true } - onEdit = { _ -> edited = true } + onEdit = { edited = true } } measureView(view, dpToPixels(48), dpToPixels(48)) } diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/NumberPanelViewTest.kt b/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/NumberPanelViewTest.kt index fb816f4d4..6d9ce4e8e 100644 --- a/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/NumberPanelViewTest.kt +++ b/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/NumberPanelViewTest.kt @@ -76,7 +76,7 @@ class NumberPanelViewTest : BaseViewTest() { @Test fun testEdit() { val timestamps = mutableListOf() - view.onEdit = { _, t -> timestamps.plusAssign(t) } + view.onEdit = { t -> timestamps.plusAssign(t) } view.buttons[0].performLongClick() view.buttons[2].performLongClick() view.buttons[3].performLongClick() @@ -87,7 +87,7 @@ class NumberPanelViewTest : BaseViewTest() { fun testEdit_withOffset() { val timestamps = mutableListOf() view.dataOffset = 3 - view.onEdit = { _, t -> timestamps += t } + view.onEdit = { t -> timestamps += t } view.buttons[0].performLongClick() view.buttons[2].performLongClick() view.buttons[3].performLongClick() diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/CheckmarkPopup.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/CheckmarkPopup.kt index bf4033a73..fd06005cc 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/CheckmarkPopup.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/CheckmarkPopup.kt @@ -27,7 +27,6 @@ import android.view.View import android.view.View.GONE import android.view.View.VISIBLE import android.widget.PopupWindow -import org.isoron.platform.gui.ScreenLocation import org.isoron.uhabits.R import org.isoron.uhabits.core.models.Entry.Companion.NO import org.isoron.uhabits.core.models.Entry.Companion.SKIP @@ -100,7 +99,7 @@ class CheckmarkPopup( view.notes.setText(notes) } - fun show(location: ScreenLocation) { + fun show() { val popup = PopupWindow() popup.contentView = view.root popup.width = view.root.dp(POPUP_WIDTH).toInt() @@ -118,12 +117,7 @@ class CheckmarkPopup( popup.setOnDismissListener { onToggle(value, view.notes.text.toString()) } - popup.showAtLocation( - anchor, - Gravity.NO_GRAVITY, - view.root.dp(location.x.toFloat()).toInt(), - view.root.dp(location.y.toFloat()).toInt(), - ) + popup.showAtLocation(anchor, Gravity.CENTER, 0, 0) popup.dimBehind() } } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/NumberPopup.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/NumberPopup.kt index 6a6a557fa..fe699175b 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/NumberPopup.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/NumberPopup.kt @@ -28,7 +28,6 @@ import android.view.View import android.view.View.GONE import android.view.View.VISIBLE import android.widget.PopupWindow -import org.isoron.platform.gui.ScreenLocation import org.isoron.uhabits.core.models.Entry import org.isoron.uhabits.core.preferences.Preferences import org.isoron.uhabits.databinding.CheckmarkPopupBinding @@ -72,7 +71,7 @@ class NumberPopup( ) } - fun show(location: ScreenLocation) { + fun show() { val popup = PopupWindow() popup.contentView = view.root popup.width = view.root.dp(POPUP_WIDTH).toInt() @@ -94,12 +93,7 @@ class NumberPopup( view.value.setText((Entry.SKIP.toDouble() / 1000).toString()) popup.dismiss() } - popup.showAtLocation( - anchor, - Gravity.NO_GRAVITY, - view.root.dp(location.x.toFloat()).toInt(), - view.root.dp(location.y.toFloat()).toInt(), - ) + popup.showAtLocation(anchor, Gravity.CENTER, 0, 0) view.value.requestFocusWithKeyboard() popup.dimBehind() } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsScreen.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsScreen.kt index bba63e8a5..343b50644 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsScreen.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsScreen.kt @@ -24,14 +24,12 @@ import android.content.Context import android.content.Intent import androidx.appcompat.app.AppCompatActivity import dagger.Lazy -import org.isoron.platform.gui.ScreenLocation import org.isoron.platform.gui.toInt import org.isoron.uhabits.R import org.isoron.uhabits.activities.common.dialogs.CheckmarkPopup import org.isoron.uhabits.activities.common.dialogs.ColorPickerDialogFactory import org.isoron.uhabits.activities.common.dialogs.ConfirmDeleteDialog import org.isoron.uhabits.activities.common.dialogs.NumberPopup -import org.isoron.uhabits.activities.common.dialogs.POPUP_WIDTH import org.isoron.uhabits.activities.habits.edit.HabitTypeDialog import org.isoron.uhabits.activities.habits.list.views.HabitCardListAdapter import org.isoron.uhabits.core.commands.ArchiveHabitsCommand @@ -232,7 +230,6 @@ class ListHabitsScreen override fun showNumberPopup( value: Double, notes: String, - location: ScreenLocation, callback: ListHabitsBehavior.NumberPickerCallback ) { val view = rootView.get() @@ -244,7 +241,7 @@ class ListHabitsScreen value = value, ).apply { onToggle = { value, notes -> callback.onNumberPicked(value, notes) } - show(getPopupLocation(location)) + show() } } @@ -252,7 +249,6 @@ class ListHabitsScreen selectedValue: Int, notes: String, color: PaletteColor, - location: ScreenLocation, callback: ListHabitsBehavior.CheckMarkDialogCallback ) { val view = rootView.get() @@ -265,15 +261,10 @@ class ListHabitsScreen value = selectedValue, ).apply { onToggle = { value, notes -> callback.onNotesSaved(value, notes) } - show(getPopupLocation(location)) + show() } } - private fun getPopupLocation(clickLocation: ScreenLocation) = ScreenLocation( - x = clickLocation.x - POPUP_WIDTH / 2, - y = clickLocation.y - ) - private fun getExecuteString(command: Command): String? { when (command) { is ArchiveHabitsCommand -> { diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkButtonView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkButtonView.kt index a408f92ee..176cec62a 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkButtonView.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkButtonView.kt @@ -28,7 +28,6 @@ import android.text.TextPaint import android.view.HapticFeedbackConstants import android.view.View import android.view.View.MeasureSpec.EXACTLY -import org.isoron.platform.gui.ScreenLocation import org.isoron.uhabits.R import org.isoron.uhabits.core.models.Entry import org.isoron.uhabits.core.models.Entry.Companion.NO @@ -39,7 +38,6 @@ import org.isoron.uhabits.core.models.Entry.Companion.YES_MANUAL import org.isoron.uhabits.core.preferences.Preferences import org.isoron.uhabits.inject.ActivityContext import org.isoron.uhabits.utils.drawNotesIndicator -import org.isoron.uhabits.utils.getCenter import org.isoron.uhabits.utils.getFontAwesome import org.isoron.uhabits.utils.sp import org.isoron.uhabits.utils.sres @@ -83,7 +81,7 @@ class CheckmarkButtonView( var onToggle: (Int, String, Long) -> Unit = { _, _, _ -> } - var onEdit: (ScreenLocation) -> Unit = { _ -> } + var onEdit: () -> Unit = { } private var drawer = Drawer() @@ -105,11 +103,11 @@ class CheckmarkButtonView( override fun onClick(v: View) { if (preferences.isShortToggleEnabled) performToggle(TOGGLE_DELAY_MILLIS) - else onEdit(getCenter()) + else onEdit() } override fun onLongClick(v: View): Boolean { - if (preferences.isShortToggleEnabled) onEdit(getCenter()) + if (preferences.isShortToggleEnabled) onEdit() else performToggle(TOGGLE_DELAY_MILLIS) return true } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkPanelView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkPanelView.kt index 62fb3e436..35f639691 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkPanelView.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkPanelView.kt @@ -20,7 +20,6 @@ package org.isoron.uhabits.activities.habits.list.views import android.content.Context -import org.isoron.platform.gui.ScreenLocation import org.isoron.uhabits.core.models.Entry.Companion.UNKNOWN import org.isoron.uhabits.core.models.Timestamp import org.isoron.uhabits.core.preferences.Preferences @@ -67,7 +66,7 @@ class CheckmarkPanelView( setupButtons() } - var onEdit: (ScreenLocation, Timestamp) -> Unit = { _, _ -> } + var onEdit: (Timestamp) -> Unit = { _ -> } set(value) { field = value setupButtons() @@ -91,7 +90,7 @@ class CheckmarkPanelView( } button.color = color button.onToggle = { value, notes, delay -> onToggle(timestamp, value, notes, delay) } - button.onEdit = { location -> onEdit(location, timestamp) } + button.onEdit = { onEdit(timestamp) } } } } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardView.kt index 7296575e7..424aae50b 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardView.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardView.kt @@ -167,17 +167,17 @@ class HabitCardView( { runPendingToggles(taskId) }.delay(delay) } } - onEdit = { location, timestamp -> + onEdit = { timestamp -> triggerRipple(timestamp) - habit?.let { behavior.onEdit(location, it, timestamp) } + habit?.let { behavior.onEdit(it, timestamp) } } } numberPanel = numberPanelFactory.create().apply { visibility = GONE - onEdit = { location, timestamp -> + onEdit = { timestamp -> triggerRipple(timestamp) - habit?.let { behavior.onEdit(location, it, timestamp) } + habit?.let { behavior.onEdit(it, timestamp) } } } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/NumberButtonView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/NumberButtonView.kt index 7f476015e..03fe66e53 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/NumberButtonView.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/NumberButtonView.kt @@ -28,7 +28,6 @@ import android.text.TextPaint import android.view.View import android.view.View.OnClickListener import android.view.View.OnLongClickListener -import org.isoron.platform.gui.ScreenLocation import org.isoron.uhabits.R import org.isoron.uhabits.core.models.Entry import org.isoron.uhabits.core.models.NumericalHabitType.AT_LEAST @@ -38,7 +37,6 @@ import org.isoron.uhabits.inject.ActivityContext import org.isoron.uhabits.utils.InterfaceUtils.getDimension import org.isoron.uhabits.utils.dim import org.isoron.uhabits.utils.drawNotesIndicator -import org.isoron.uhabits.utils.getCenter import org.isoron.uhabits.utils.getFontAwesome import org.isoron.uhabits.utils.sres import java.text.DecimalFormat @@ -110,7 +108,7 @@ class NumberButtonView( invalidate() } - var onEdit: (ScreenLocation) -> Unit = { _ -> } + var onEdit: () -> Unit = { } private var drawer: Drawer = Drawer(context) @@ -120,11 +118,11 @@ class NumberButtonView( } override fun onClick(v: View) { - onEdit(getCenter()) + onEdit() } override fun onLongClick(v: View): Boolean { - onEdit(getCenter()) + onEdit() return true } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/NumberPanelView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/NumberPanelView.kt index c6ce2089f..0c7d142bb 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/NumberPanelView.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/NumberPanelView.kt @@ -20,7 +20,6 @@ package org.isoron.uhabits.activities.habits.list.views import android.content.Context -import org.isoron.platform.gui.ScreenLocation import org.isoron.uhabits.core.models.NumericalHabitType import org.isoron.uhabits.core.models.Timestamp import org.isoron.uhabits.core.preferences.Preferences @@ -79,7 +78,7 @@ class NumberPanelView( setupButtons() } - var onEdit: (ScreenLocation, Timestamp) -> Unit = { _, _ -> } + var onEdit: (Timestamp) -> Unit = { _ -> } set(value) { field = value setupButtons() @@ -105,7 +104,7 @@ class NumberPanelView( button.targetType = targetType button.threshold = threshold button.units = units - button.onEdit = { location -> onEdit(location, timestamp) } + button.onEdit = { onEdit(timestamp) } } } } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitActivity.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitActivity.kt index e643d30d4..1e90e1ae9 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitActivity.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitActivity.kt @@ -28,7 +28,6 @@ import androidx.appcompat.app.AppCompatActivity import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch -import org.isoron.platform.gui.ScreenLocation import org.isoron.platform.gui.toInt import org.isoron.uhabits.AndroidDirFinder import org.isoron.uhabits.HabitsApplication @@ -39,7 +38,6 @@ import org.isoron.uhabits.activities.common.dialogs.CheckmarkPopup import org.isoron.uhabits.activities.common.dialogs.ConfirmDeleteDialog import org.isoron.uhabits.activities.common.dialogs.HistoryEditorDialog import org.isoron.uhabits.activities.common.dialogs.NumberPopup -import org.isoron.uhabits.activities.common.dialogs.POPUP_WIDTH import org.isoron.uhabits.core.commands.Command import org.isoron.uhabits.core.commands.CommandRunner import org.isoron.uhabits.core.models.Habit @@ -52,7 +50,6 @@ import org.isoron.uhabits.core.ui.screens.habits.show.ShowHabitPresenter import org.isoron.uhabits.core.ui.views.OnDateClickedListener import org.isoron.uhabits.intents.IntentFactory import org.isoron.uhabits.utils.currentTheme -import org.isoron.uhabits.utils.getTopLeftCorner import org.isoron.uhabits.utils.showMessage import org.isoron.uhabits.utils.showSendFileScreen import org.isoron.uhabits.widgets.WidgetUpdater @@ -173,7 +170,6 @@ class ShowHabitActivity : AppCompatActivity(), CommandRunner.Listener { value: Double, notes: String, preferences: Preferences, - location: ScreenLocation, callback: ListHabitsBehavior.NumberPickerCallback ) { val anchor = getPopupAnchor() ?: return @@ -185,7 +181,7 @@ class ShowHabitActivity : AppCompatActivity(), CommandRunner.Listener { value = value, ).apply { onToggle = { v, n -> callback.onNumberPicked(v, n) } - show(computePopupLocation(anchor, location)) + show() } } @@ -194,7 +190,6 @@ class ShowHabitActivity : AppCompatActivity(), CommandRunner.Listener { notes: String, preferences: Preferences, color: PaletteColor, - location: ScreenLocation, callback: ListHabitsBehavior.CheckMarkDialogCallback ) { val anchor = getPopupAnchor() ?: return @@ -207,7 +202,7 @@ class ShowHabitActivity : AppCompatActivity(), CommandRunner.Listener { value = selectedValue, ).apply { onToggle = { v, n -> callback.onNotesSaved(v, n) } - show(computePopupLocation(anchor, location)) + show() } } @@ -216,14 +211,6 @@ class ShowHabitActivity : AppCompatActivity(), CommandRunner.Listener { return dialog?.dataView } - private fun computePopupLocation(anchor: View, clickLocation: ScreenLocation): ScreenLocation { - val corner = anchor.getTopLeftCorner() - return ScreenLocation( - x = corner.x + clickLocation.x - POPUP_WIDTH / 2, - y = corner.y + clickLocation.y, - ) - } - override fun showEditHabitScreen(habit: Habit) { startActivity(IntentFactory().startEditActivity(this@ShowHabitActivity, habit)) } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/utils/ViewExtensions.kt b/uhabits-android/src/main/java/org/isoron/uhabits/utils/ViewExtensions.kt index 16d4e6369..d0f1f3f92 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/utils/ViewExtensions.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/utils/ViewExtensions.kt @@ -47,7 +47,6 @@ import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.widget.Toolbar import androidx.core.content.FileProvider import com.google.android.material.snackbar.Snackbar -import org.isoron.platform.gui.ScreenLocation import org.isoron.platform.gui.toInt import org.isoron.uhabits.HabitsApplication import org.isoron.uhabits.R @@ -231,34 +230,6 @@ fun PopupWindow.dimBehind() { wm.updateViewLayout(container, p) } -/** - * Returns the absolute screen coordinates for the center of this view (in density-independent - * pixels). - */ -fun View.getCenter(): ScreenLocation { - val density = resources.displayMetrics.density - val loc = IntArray(2) - this.getLocationInWindow(loc) - return ScreenLocation( - x = ((loc[0] + width / 2) / density).toDouble(), - y = ((loc[1] + height / 2) / density).toDouble(), - ) -} - -/** - * Returns the absolute screen coordinates for the top left corner of this view (in - * density-independent pixels). - */ -fun View.getTopLeftCorner(): ScreenLocation { - val density = resources.displayMetrics.density - val loc = IntArray(2) - this.getLocationInWindow(loc) - return ScreenLocation( - x = (loc[0] / density).toDouble(), - y = (loc[1] / density).toDouble(), - ) -} - fun View.requestFocusWithKeyboard() { // For some reason, Android does not open the soft keyboard by default when view.requestFocus // is called. Several online solutions suggest using InputMethodManager, but these solutions diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/activities/NumericalCheckmarkWidgetActivity.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/activities/NumericalCheckmarkWidgetActivity.kt index 080e7916e..a7305521e 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/activities/NumericalCheckmarkWidgetActivity.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/activities/NumericalCheckmarkWidgetActivity.kt @@ -25,18 +25,14 @@ import android.os.Bundle import android.view.View import android.view.ViewGroup.LayoutParams.MATCH_PARENT import android.widget.FrameLayout -import org.isoron.platform.gui.ScreenLocation import org.isoron.uhabits.HabitsApplication import org.isoron.uhabits.activities.AndroidThemeSwitcher import org.isoron.uhabits.activities.common.dialogs.NumberPopup -import org.isoron.uhabits.activities.common.dialogs.POPUP_HEIGHT -import org.isoron.uhabits.activities.common.dialogs.POPUP_WIDTH import org.isoron.uhabits.core.ui.screens.habits.list.ListHabitsBehavior import org.isoron.uhabits.core.ui.widgets.WidgetBehavior import org.isoron.uhabits.core.utils.DateUtils import org.isoron.uhabits.intents.IntentParser import org.isoron.uhabits.utils.SystemUtils -import org.isoron.uhabits.utils.getCenter import org.isoron.uhabits.widgets.WidgetUpdater class NumericalCheckmarkWidgetActivity : Activity(), ListHabitsBehavior.NumberPickerCallback { @@ -95,13 +91,7 @@ class NumericalCheckmarkWidgetActivity : Activity(), ListHabitsBehavior.NumberPi finish() overridePendingTransition(0, 0) } - val center = rootView.getCenter() - show( - ScreenLocation( - x = center.x - POPUP_WIDTH / 2, - y = center.y - POPUP_HEIGHT / 2 - ) - ) + show() } } diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehavior.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehavior.kt index f1a88f411..5041ab066 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehavior.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehavior.kt @@ -18,7 +18,6 @@ */ package org.isoron.uhabits.core.ui.screens.habits.list -import org.isoron.platform.gui.ScreenLocation import org.isoron.uhabits.core.commands.CommandRunner import org.isoron.uhabits.core.commands.CreateRepetitionCommand import org.isoron.uhabits.core.models.Habit @@ -49,11 +48,11 @@ open class ListHabitsBehavior @Inject constructor( screen.showHabitScreen(h) } - fun onEdit(location: ScreenLocation, habit: Habit, timestamp: Timestamp?) { + fun onEdit(habit: Habit, timestamp: Timestamp?) { val entry = habit.computedEntries.get(timestamp!!) if (habit.type == HabitType.NUMERICAL) { val oldValue = entry.value.toDouble() / 1000 - screen.showNumberPopup(oldValue, entry.notes, location) { newValue: Double, newNotes: String -> + screen.showNumberPopup(oldValue, entry.notes) { newValue: Double, newNotes: String -> val value = (newValue * 1000).roundToInt() commandRunner.run(CreateRepetitionCommand(habitList, habit, timestamp, value, newNotes)) } @@ -62,7 +61,6 @@ open class ListHabitsBehavior @Inject constructor( entry.value, entry.notes, habit.color, - location, ) { newValue, newNotes -> commandRunner.run(CreateRepetitionCommand(habitList, habit, timestamp, newValue, newNotes)) } @@ -158,14 +156,12 @@ open class ListHabitsBehavior @Inject constructor( fun showNumberPopup( value: Double, notes: String, - location: ScreenLocation, callback: NumberPickerCallback ) fun showCheckmarkPopup( selectedValue: Int, notes: String, color: PaletteColor, - location: ScreenLocation, callback: CheckMarkDialogCallback ) fun showSendBugReportToDeveloperScreen(log: String) diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/show/views/HistoryCard.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/show/views/HistoryCard.kt index 18c044bc2..7cde6f0d1 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/show/views/HistoryCard.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/show/views/HistoryCard.kt @@ -19,7 +19,6 @@ package org.isoron.uhabits.core.ui.screens.habits.show.views -import org.isoron.platform.gui.ScreenLocation import org.isoron.platform.time.DayOfWeek import org.isoron.platform.time.LocalDate import org.isoron.uhabits.core.commands.CommandRunner @@ -65,36 +64,35 @@ class HistoryCardPresenter( val screen: Screen, ) : OnDateClickedListener { - override fun onDateLongPress(location: ScreenLocation, date: LocalDate) { + override fun onDateLongPress(date: LocalDate) { val timestamp = Timestamp.fromLocalDate(date) screen.showFeedback() if (habit.isNumerical) { - showNumberPopup(location, timestamp) + showNumberPopup(timestamp) } else { - if (preferences.isShortToggleEnabled) showCheckmarkPopup(location, timestamp) + if (preferences.isShortToggleEnabled) showCheckmarkPopup(timestamp) else toggle(timestamp) } } - override fun onDateShortPress(location: ScreenLocation, date: LocalDate) { + override fun onDateShortPress(date: LocalDate) { val timestamp = Timestamp.fromLocalDate(date) screen.showFeedback() if (habit.isNumerical) { - showNumberPopup(location, timestamp) + showNumberPopup(timestamp) } else { if (preferences.isShortToggleEnabled) toggle(timestamp) - else showCheckmarkPopup(location, timestamp) + else showCheckmarkPopup(timestamp) } } - private fun showCheckmarkPopup(location: ScreenLocation, timestamp: Timestamp) { + private fun showCheckmarkPopup(timestamp: Timestamp) { val entry = habit.computedEntries.get(timestamp) screen.showCheckmarkPopup( entry.value, entry.notes, preferences, habit.color, - location, ) { newValue, newNotes -> commandRunner.run( CreateRepetitionCommand( @@ -126,14 +124,13 @@ class HistoryCardPresenter( ) } - private fun showNumberPopup(location: ScreenLocation, timestamp: Timestamp) { + private fun showNumberPopup(timestamp: Timestamp) { val entry = habit.computedEntries.get(timestamp) val oldValue = entry.value screen.showNumberPopup( value = oldValue / 1000.0, notes = entry.notes, preferences = preferences, - location = location, ) { newValue: Double, newNotes: String -> val thousands = (newValue * 1000).roundToInt() commandRunner.run( @@ -207,7 +204,6 @@ class HistoryCardPresenter( value: Double, notes: String, preferences: Preferences, - location: ScreenLocation, callback: ListHabitsBehavior.NumberPickerCallback, ) fun showCheckmarkPopup( @@ -215,7 +211,6 @@ class HistoryCardPresenter( notes: String, preferences: Preferences, color: PaletteColor, - location: ScreenLocation, callback: ListHabitsBehavior.CheckMarkDialogCallback, ) } diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/views/HistoryChart.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/views/HistoryChart.kt index 8d7435540..a752e271c 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/views/HistoryChart.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/views/HistoryChart.kt @@ -22,7 +22,6 @@ package org.isoron.uhabits.core.ui.views import org.isoron.platform.gui.Canvas import org.isoron.platform.gui.Color import org.isoron.platform.gui.DataView -import org.isoron.platform.gui.ScreenLocation import org.isoron.platform.gui.TextAlign import org.isoron.platform.time.DayOfWeek import org.isoron.platform.time.LocalDate @@ -34,8 +33,8 @@ import kotlin.math.min import kotlin.math.round interface OnDateClickedListener { - fun onDateShortPress(location: ScreenLocation, date: LocalDate) {} - fun onDateLongPress(location: ScreenLocation, date: LocalDate) {} + fun onDateShortPress(date: LocalDate) {} + fun onDateLongPress(date: LocalDate) {} } class HistoryChart( @@ -91,11 +90,10 @@ class HistoryChart( if (x - padding < 0 || row == 0 || row > 7 || col == nColumns) return val clickedDate = topLeftDate.plus(offset) if (clickedDate.isNewerThan(today)) return - val location = ScreenLocation(x, y) if (isLongClick) { - onDateClickedListener.onDateLongPress(location, clickedDate) + onDateClickedListener.onDateLongPress(clickedDate) } else { - onDateClickedListener.onDateShortPress(location, clickedDate) + onDateClickedListener.onDateShortPress(clickedDate) } } diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehaviorTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehaviorTest.kt index 97778338a..c5e5f7b44 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehaviorTest.kt +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehaviorTest.kt @@ -31,7 +31,6 @@ import junit.framework.Assert.assertTrue import org.apache.commons.io.FileUtils import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.core.IsEqual.equalTo -import org.isoron.platform.gui.ScreenLocation import org.isoron.uhabits.core.BaseUnitTest import org.isoron.uhabits.core.models.Entry import org.isoron.uhabits.core.models.Habit @@ -79,11 +78,10 @@ class ListHabitsBehaviorTest : BaseUnitTest() { @Test fun testOnEdit() { - behavior.onEdit(ScreenLocation(0.0, 0.0), habit2, getToday()) + behavior.onEdit(habit2, getToday()) verify(screen).showNumberPopup( eq(0.1), eq(""), - any(), picker.capture() ) picker.lastValue.onNumberPicked(100.0, "") diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/views/HistoryChartTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/views/HistoryChartTest.kt index 8373805b7..d25483fb1 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/views/HistoryChartTest.kt +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/views/HistoryChartTest.kt @@ -24,7 +24,6 @@ import com.nhaarman.mockitokotlin2.reset import com.nhaarman.mockitokotlin2.verify import com.nhaarman.mockitokotlin2.verifyNoMoreInteractions import kotlinx.coroutines.runBlocking -import org.isoron.platform.gui.ScreenLocation import org.isoron.platform.gui.assertRenders import org.isoron.platform.time.DayOfWeek import org.isoron.platform.time.DayOfWeek.SUNDAY @@ -90,32 +89,20 @@ class HistoryChartTest { // Click top left date view.onClick(20.0, 46.0) - verify(dateClickedListener).onDateShortPress( - ScreenLocation(20.0, 46.0), - LocalDate(2014, 10, 26) - ) + verify(dateClickedListener).onDateShortPress(LocalDate(2014, 10, 26)) reset(dateClickedListener) view.onClick(2.0, 28.0) - verify(dateClickedListener).onDateShortPress( - ScreenLocation(2.0, 28.0), - LocalDate(2014, 10, 26) - ) + verify(dateClickedListener).onDateShortPress(LocalDate(2014, 10, 26)) reset(dateClickedListener) // Click date in the middle view.onClick(163.0, 113.0) - verify(dateClickedListener).onDateShortPress( - ScreenLocation(163.0, 113.0), - LocalDate(2014, 12, 10) - ) + verify(dateClickedListener).onDateShortPress(LocalDate(2014, 12, 10)) reset(dateClickedListener) // Click today view.onClick(336.0, 37.0) - verify(dateClickedListener).onDateShortPress( - ScreenLocation(336.0, 37.0), - LocalDate(2015, 1, 25) - ) + verify(dateClickedListener).onDateShortPress(LocalDate(2015, 1, 25)) reset(dateClickedListener) // Click header @@ -133,32 +120,20 @@ class HistoryChartTest { // Click top left date view.onLongClick(20.0, 46.0) - verify(dateClickedListener).onDateLongPress( - ScreenLocation(20.0, 46.0), - LocalDate(2014, 10, 26) - ) + verify(dateClickedListener).onDateLongPress(LocalDate(2014, 10, 26)) reset(dateClickedListener) view.onLongClick(2.0, 28.0) - verify(dateClickedListener).onDateLongPress( - ScreenLocation(2.0, 28.0), - LocalDate(2014, 10, 26) - ) + verify(dateClickedListener).onDateLongPress(LocalDate(2014, 10, 26)) reset(dateClickedListener) // Click date in the middle view.onLongClick(163.0, 113.0) - verify(dateClickedListener).onDateLongPress( - ScreenLocation(163.0, 113.0), - LocalDate(2014, 12, 10) - ) + verify(dateClickedListener).onDateLongPress(LocalDate(2014, 12, 10)) reset(dateClickedListener) // Click today view.onLongClick(336.0, 37.0) - verify(dateClickedListener).onDateLongPress( - ScreenLocation(336.0, 37.0), - LocalDate(2015, 1, 25) - ) + verify(dateClickedListener).onDateLongPress(LocalDate(2015, 1, 25)) reset(dateClickedListener) // Click header From b0a4f26e7a3b121a1e7efee80cca781302c5c044 Mon Sep 17 00:00:00 2001 From: "Alinson S. Xavier" Date: Sun, 24 Jul 2022 05:31:15 -0500 Subject: [PATCH 07/10] Popup: Fix crash on suggestions --- .../uhabits/activities/common/dialogs/CheckmarkPopup.kt | 6 ++++++ .../isoron/uhabits/activities/common/dialogs/NumberPopup.kt | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/CheckmarkPopup.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/CheckmarkPopup.kt index fd06005cc..ffb1aa905 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/CheckmarkPopup.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/CheckmarkPopup.kt @@ -21,12 +21,14 @@ package org.isoron.uhabits.activities.common.dialogs import android.content.Context import android.graphics.drawable.ColorDrawable +import android.text.InputType import android.view.Gravity import android.view.LayoutInflater import android.view.View import android.view.View.GONE import android.view.View.VISIBLE import android.widget.PopupWindow +import kotlinx.android.synthetic.main.checkmark_popup.view.* import org.isoron.uhabits.R import org.isoron.uhabits.core.models.Entry.Companion.NO import org.isoron.uhabits.core.models.Entry.Companion.SKIP @@ -56,6 +58,10 @@ class CheckmarkPopup( private val view = CheckmarkPopupBinding.inflate(LayoutInflater.from(context)).apply { // Required for round corners container.clipToOutline = true + + // Android bugfix: Allowing suggestions in a popup causes a crash. + // stackoverflow.com/questions/4829718 + container.notes.inputType = InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS } init { diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/NumberPopup.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/NumberPopup.kt index fe699175b..a7183323f 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/NumberPopup.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/NumberPopup.kt @@ -20,6 +20,7 @@ package org.isoron.uhabits.activities.common.dialogs import android.content.Context +import android.text.InputType import android.view.Gravity import android.view.KeyEvent.KEYCODE_ENTER import android.view.LayoutInflater @@ -28,6 +29,7 @@ import android.view.View import android.view.View.GONE import android.view.View.VISIBLE import android.widget.PopupWindow +import kotlinx.android.synthetic.main.checkmark_popup.view.* import org.isoron.uhabits.core.models.Entry import org.isoron.uhabits.core.preferences.Preferences import org.isoron.uhabits.databinding.CheckmarkPopupBinding @@ -49,6 +51,10 @@ class NumberPopup( private val view = CheckmarkPopupBinding.inflate(LayoutInflater.from(context)).apply { // Required for round corners container.clipToOutline = true + + // Android bugfix: Allowing suggestions in a popup causes a crash. + // stackoverflow.com/questions/4829718 + container.notes.inputType = InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS } init { From 7649119db78e151b41df7c00ff48851d7e749072 Mon Sep 17 00:00:00 2001 From: "Alinson S. Xavier" Date: Sun, 24 Jul 2022 05:41:52 -0500 Subject: [PATCH 08/10] Popup: Do not save on dismiss --- .../activities/common/dialogs/CheckmarkPopup.kt | 14 ++++++++------ .../activities/common/dialogs/NumberPopup.kt | 15 ++++++++------- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/CheckmarkPopup.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/CheckmarkPopup.kt index ffb1aa905..0b7129387 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/CheckmarkPopup.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/CheckmarkPopup.kt @@ -54,6 +54,7 @@ class CheckmarkPopup( private val anchor: View, ) { var onToggle: (Int, String) -> Unit = { _, _ -> } + private lateinit var popup: PopupWindow private val view = CheckmarkPopupBinding.inflate(LayoutInflater.from(context)).apply { // Required for round corners @@ -101,12 +102,11 @@ class CheckmarkPopup( SKIP -> if (prefs.isSkipEnabled) view.skipBtn else view.noBtn else -> null } - selectedBtn?.background = ColorDrawable(view.root.sres.getColor(R.attr.contrast40)) view.notes.setText(notes) } fun show() { - val popup = PopupWindow() + popup = PopupWindow() popup.contentView = view.root popup.width = view.root.dp(POPUP_WIDTH).toInt() popup.height = view.root.dp(POPUP_HEIGHT).toInt() @@ -114,16 +114,18 @@ class CheckmarkPopup( popup.elevation = view.root.dp(24f) fun onClick(v: Int) { this.value = v - popup.dismiss() + save() } view.yesBtn.setOnClickListener { onClick(YES_MANUAL) } view.noBtn.setOnClickListener { onClick(NO) } view.skipBtn.setOnClickListener { onClick(SKIP) } view.unknownBtn.setOnClickListener { onClick(UNKNOWN) } - popup.setOnDismissListener { - onToggle(value, view.notes.text.toString()) - } popup.showAtLocation(anchor, Gravity.CENTER, 0, 0) popup.dimBehind() } + + fun save() { + onToggle(value, view.notes.text.toString().trim()) + popup.dismiss() + } } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/NumberPopup.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/NumberPopup.kt index a7183323f..d0ed17a9b 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/NumberPopup.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/NumberPopup.kt @@ -47,6 +47,7 @@ class NumberPopup( ) { var onToggle: (Double, String) -> Unit = { _, _ -> } private val originalValue = value + private lateinit var popup: PopupWindow private val view = CheckmarkPopupBinding.inflate(LayoutInflater.from(context)).apply { // Required for round corners @@ -78,26 +79,25 @@ class NumberPopup( } fun show() { - val popup = PopupWindow() + popup = PopupWindow() popup.contentView = view.root popup.width = view.root.dp(POPUP_WIDTH).toInt() popup.height = view.root.dp(POPUP_HEIGHT).toInt() popup.isFocusable = true popup.elevation = view.root.dp(24f) - popup.setOnDismissListener { - save() - } view.value.setOnKeyListener { _, keyCode, event -> if (event.action == ACTION_DOWN && keyCode == KEYCODE_ENTER) { - popup.dismiss() + save() return@setOnKeyListener true } return@setOnKeyListener false } - view.saveBtn.setOnClickListener { popup.dismiss() } + view.saveBtn.setOnClickListener { + save() + } view.skipBtnNumber.setOnClickListener { view.value.setText((Entry.SKIP.toDouble() / 1000).toString()) - popup.dismiss() + save() } popup.showAtLocation(anchor, Gravity.CENTER, 0, 0) view.value.requestFocusWithKeyboard() @@ -108,5 +108,6 @@ class NumberPopup( val value = view.value.text.toString().toDoubleOrNull() ?: originalValue val notes = view.notes.text.toString() onToggle(value, notes) + popup.dismiss() } } From 3021e408a7ff0a1ccdc54742aaf8835a81937938 Mon Sep 17 00:00:00 2001 From: "Alinson S. Xavier" Date: Sun, 24 Jul 2022 06:01:40 -0500 Subject: [PATCH 09/10] Remove unused imports --- .../isoron/uhabits/activities/common/dialogs/CheckmarkPopup.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/CheckmarkPopup.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/CheckmarkPopup.kt index 0b7129387..85d4d3d7d 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/CheckmarkPopup.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/CheckmarkPopup.kt @@ -20,7 +20,6 @@ package org.isoron.uhabits.activities.common.dialogs import android.content.Context -import android.graphics.drawable.ColorDrawable import android.text.InputType import android.view.Gravity import android.view.LayoutInflater From e4b16f6d5936c3647f7e851c172d9ac0544ae70b Mon Sep 17 00:00:00 2001 From: "Alinson S. Xavier" Date: Sat, 30 Jul 2022 16:33:16 -0500 Subject: [PATCH 10/10] Replace PopupWindow by Dialog Fixes issues with copy & paste, text selection and spell checking. --- .../common/dialogs/CheckmarkPopup.kt | 33 ++++++++---------- .../activities/common/dialogs/NumberPopup.kt | 34 +++++++++---------- .../isoron/uhabits/utils/ViewExtensions.kt | 15 +++----- 3 files changed, 35 insertions(+), 47 deletions(-) diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/CheckmarkPopup.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/CheckmarkPopup.kt index 85d4d3d7d..9a862076f 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/CheckmarkPopup.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/CheckmarkPopup.kt @@ -19,15 +19,12 @@ package org.isoron.uhabits.activities.common.dialogs +import android.app.Dialog import android.content.Context -import android.text.InputType -import android.view.Gravity import android.view.LayoutInflater import android.view.View import android.view.View.GONE import android.view.View.VISIBLE -import android.widget.PopupWindow -import kotlinx.android.synthetic.main.checkmark_popup.view.* import org.isoron.uhabits.R import org.isoron.uhabits.core.models.Entry.Companion.NO import org.isoron.uhabits.core.models.Entry.Companion.SKIP @@ -53,15 +50,11 @@ class CheckmarkPopup( private val anchor: View, ) { var onToggle: (Int, String) -> Unit = { _, _ -> } - private lateinit var popup: PopupWindow + private lateinit var dialog: Dialog private val view = CheckmarkPopupBinding.inflate(LayoutInflater.from(context)).apply { // Required for round corners container.clipToOutline = true - - // Android bugfix: Allowing suggestions in a popup causes a crash. - // stackoverflow.com/questions/4829718 - container.notes.inputType = InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS } init { @@ -105,12 +98,15 @@ class CheckmarkPopup( } fun show() { - popup = PopupWindow() - popup.contentView = view.root - popup.width = view.root.dp(POPUP_WIDTH).toInt() - popup.height = view.root.dp(POPUP_HEIGHT).toInt() - popup.isFocusable = true - popup.elevation = view.root.dp(24f) + dialog = Dialog(context, android.R.style.Theme_NoTitleBar) + dialog.setContentView(view.root) + dialog.window?.apply { + setLayout( + view.root.dp(POPUP_WIDTH).toInt(), + view.root.dp(POPUP_HEIGHT).toInt() + ) + setBackgroundDrawableResource(android.R.color.transparent) + } fun onClick(v: Int) { this.value = v save() @@ -119,12 +115,13 @@ class CheckmarkPopup( view.noBtn.setOnClickListener { onClick(NO) } view.skipBtn.setOnClickListener { onClick(SKIP) } view.unknownBtn.setOnClickListener { onClick(UNKNOWN) } - popup.showAtLocation(anchor, Gravity.CENTER, 0, 0) - popup.dimBehind() + dialog.setCanceledOnTouchOutside(true) + dialog.dimBehind() + dialog.show() } fun save() { onToggle(value, view.notes.text.toString().trim()) - popup.dismiss() + dialog.dismiss() } } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/NumberPopup.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/NumberPopup.kt index d0ed17a9b..11f63215f 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/NumberPopup.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/NumberPopup.kt @@ -19,17 +19,14 @@ package org.isoron.uhabits.activities.common.dialogs +import android.app.Dialog import android.content.Context -import android.text.InputType -import android.view.Gravity import android.view.KeyEvent.KEYCODE_ENTER import android.view.LayoutInflater import android.view.MotionEvent.ACTION_DOWN import android.view.View import android.view.View.GONE import android.view.View.VISIBLE -import android.widget.PopupWindow -import kotlinx.android.synthetic.main.checkmark_popup.view.* import org.isoron.uhabits.core.models.Entry import org.isoron.uhabits.core.preferences.Preferences import org.isoron.uhabits.databinding.CheckmarkPopupBinding @@ -47,15 +44,11 @@ class NumberPopup( ) { var onToggle: (Double, String) -> Unit = { _, _ -> } private val originalValue = value - private lateinit var popup: PopupWindow + private lateinit var dialog: Dialog private val view = CheckmarkPopupBinding.inflate(LayoutInflater.from(context)).apply { // Required for round corners container.clipToOutline = true - - // Android bugfix: Allowing suggestions in a popup causes a crash. - // stackoverflow.com/questions/4829718 - container.notes.inputType = InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS } init { @@ -79,12 +72,16 @@ class NumberPopup( } fun show() { - popup = PopupWindow() - popup.contentView = view.root - popup.width = view.root.dp(POPUP_WIDTH).toInt() - popup.height = view.root.dp(POPUP_HEIGHT).toInt() - popup.isFocusable = true - popup.elevation = view.root.dp(24f) + dialog = Dialog(context, android.R.style.Theme_NoTitleBar) + dialog.setContentView(view.root) + dialog.window?.apply { + setLayout( + view.root.dp(POPUP_WIDTH).toInt(), + view.root.dp(POPUP_HEIGHT).toInt() + ) + setBackgroundDrawableResource(android.R.color.transparent) + } + view.value.setOnKeyListener { _, keyCode, event -> if (event.action == ACTION_DOWN && keyCode == KEYCODE_ENTER) { save() @@ -99,15 +96,16 @@ class NumberPopup( view.value.setText((Entry.SKIP.toDouble() / 1000).toString()) save() } - popup.showAtLocation(anchor, Gravity.CENTER, 0, 0) view.value.requestFocusWithKeyboard() - popup.dimBehind() + dialog.setCanceledOnTouchOutside(true) + dialog.dimBehind() + dialog.show() } fun save() { val value = view.value.text.toString().toDoubleOrNull() ?: originalValue val notes = view.notes.text.toString() onToggle(value, notes) - popup.dismiss() + dialog.dismiss() } } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/utils/ViewExtensions.kt b/uhabits-android/src/main/java/org/isoron/uhabits/utils/ViewExtensions.kt index d0f1f3f92..35a8cecbd 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/utils/ViewExtensions.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/utils/ViewExtensions.kt @@ -20,8 +20,8 @@ package org.isoron.uhabits.utils import android.app.Activity +import android.app.Dialog import android.content.ActivityNotFoundException -import android.content.Context import android.content.Intent import android.graphics.Canvas import android.graphics.Color @@ -36,7 +36,6 @@ import android.view.ViewGroup import android.view.ViewGroup.LayoutParams.MATCH_PARENT import android.view.ViewGroup.LayoutParams.WRAP_CONTENT import android.view.WindowManager -import android.widget.PopupWindow import android.widget.RelativeLayout import android.widget.RelativeLayout.ALIGN_PARENT_BOTTOM import android.widget.RelativeLayout.ALIGN_PARENT_TOP @@ -219,15 +218,9 @@ fun View.drawNotesIndicator(canvas: Canvas, color: Int, size: Float, notes: Stri val View.sres: StyledResources get() = StyledResources(context) -fun PopupWindow.dimBehind() { - // https://stackoverflow.com/questions/35874001/dim-the-background-using-popupwindow-in-android - val container = contentView.rootView - val context = contentView.context - val wm = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager - val p = container.layoutParams as WindowManager.LayoutParams - p.flags = p.flags or WindowManager.LayoutParams.FLAG_DIM_BEHIND - p.dimAmount = 0.5f - wm.updateViewLayout(container, p) +fun Dialog.dimBehind() { + window?.addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND) + window?.setDimAmount(0.5f) } fun View.requestFocusWithKeyboard() {