diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/CheckmarkDialog.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/CheckmarkDialog.kt index 93ffd2c80..13e5f55f6 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/CheckmarkDialog.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/CheckmarkDialog.kt @@ -24,7 +24,6 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View.GONE import android.view.View.VISIBLE -import android.widget.LinearLayout import androidx.appcompat.app.AppCompatDialogFragment import org.isoron.uhabits.HabitsApplication import org.isoron.uhabits.R @@ -34,18 +33,19 @@ import org.isoron.uhabits.core.models.Entry.Companion.UNKNOWN import org.isoron.uhabits.core.models.Entry.Companion.YES_MANUAL import org.isoron.uhabits.databinding.CheckmarkPopupBinding import org.isoron.uhabits.utils.InterfaceUtils.getFontAwesome -import org.isoron.uhabits.utils.showConfetti +import org.isoron.uhabits.utils.getCenter import org.isoron.uhabits.utils.sres class CheckmarkDialog : AppCompatDialogFragment() { - var onToggle: (Int, String) -> Unit = { _, _ -> } + var onToggle: (Int, String, Float, Float) -> Unit = { _, _, _, _ -> } override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { val appComponent = (requireActivity().application as HabitsApplication).component val prefs = appComponent.preferences val view = CheckmarkPopupBinding.inflate(LayoutInflater.from(context)) + val color = requireArguments().getInt("color") arrayOf(view.yesBtn, view.skipBtn).forEach { - it.setTextColor(requireArguments().getInt("color")) + it.setTextColor(color) } arrayOf(view.noBtn, view.unknownBtn).forEach { it.setTextColor(view.root.sres.getColor(R.attr.contrast60)) @@ -64,12 +64,9 @@ class CheckmarkDialog : AppCompatDialogFragment() { } fun onClick(v: Int) { val notes = view.notes.text.toString().trim() - onToggle(v, notes) + val location = view.yesBtn.getCenter() + onToggle(v, notes, location.x, location.y) requireDialog().dismiss() - val konfettiView = requireActivity().findViewById(R.id.konfettiLayout) - when (v) { - YES_MANUAL -> showConfetti(konfettiView) - } } view.yesBtn.setOnClickListener { onClick(YES_MANUAL) } view.noBtn.setOnClickListener { onClick(NO) } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/NumberDialog.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/NumberDialog.kt index adac2bb3a..d8ba1ed59 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/NumberDialog.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/NumberDialog.kt @@ -9,15 +9,14 @@ import android.view.LayoutInflater import android.view.MotionEvent import android.view.View import android.view.inputmethod.EditorInfo -import android.widget.LinearLayout import androidx.appcompat.app.AppCompatDialogFragment import org.isoron.uhabits.HabitsApplication import org.isoron.uhabits.R import org.isoron.uhabits.core.models.Entry import org.isoron.uhabits.databinding.CheckmarkPopupBinding import org.isoron.uhabits.utils.InterfaceUtils +import org.isoron.uhabits.utils.getCenter import org.isoron.uhabits.utils.requestFocusWithKeyboard -import org.isoron.uhabits.utils.showConfetti import org.isoron.uhabits.utils.sres import java.text.DecimalFormat import java.text.DecimalFormatSymbols @@ -26,7 +25,7 @@ import java.text.ParseException class NumberDialog : AppCompatDialogFragment() { - var onToggle: (Double, String) -> Unit = { _, _ -> } + var onToggle: (Double, String, Float, Float) -> Unit = { _, _, _, _ -> } var onDismiss: () -> Unit = {} private var originalNotes: String = "" @@ -115,13 +114,8 @@ class NumberDialog : AppCompatDialogFragment() { // NOP } val notes = view.notes.text.toString() - onToggle(value, notes) + val location = view.saveBtn.getCenter() + onToggle(value, notes, location.x, location.y) requireDialog().dismiss() - val konfettiView = requireActivity().findViewById(R.id.konfettiLayout) - - if (value > 0.0) { - // To motivate, show confetti even if some value is present - showConfetti(konfettiView) - } } } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsRootView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsRootView.kt index e3e8f076c..f0a542a0d 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsRootView.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsRootView.kt @@ -23,6 +23,7 @@ import android.content.Context import android.view.ViewGroup.LayoutParams.MATCH_PARENT import android.widget.FrameLayout import android.widget.RelativeLayout +import nl.dionsegijn.konfetti.xml.KonfettiView import org.isoron.uhabits.R import org.isoron.uhabits.activities.common.views.ScrollableChart import org.isoron.uhabits.activities.common.views.TaskProgressBar @@ -43,7 +44,6 @@ import org.isoron.uhabits.inject.ActivityScope import org.isoron.uhabits.utils.addAtBottom import org.isoron.uhabits.utils.addAtTop import org.isoron.uhabits.utils.addBelow -import org.isoron.uhabits.utils.buildKonfettiView import org.isoron.uhabits.utils.buildToolbar import org.isoron.uhabits.utils.currentTheme import org.isoron.uhabits.utils.dim @@ -70,7 +70,9 @@ class ListHabitsRootView @Inject constructor( val listView: HabitCardListView = habitCardListViewFactory.create() val llEmpty = EmptyListView(context) val tbar = buildToolbar() - val konfettiView = buildKonfettiView() + val konfettiView = KonfettiView(context).apply { + translationZ = 10f + } val progressBar = TaskProgressBar(context, runner) val hintView: HintView val header = HeaderView(context, preferences, midnightTimer) 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 c525e624a..e1f0418a3 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 @@ -25,6 +25,9 @@ import android.content.Intent import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import dagger.Lazy +import nl.dionsegijn.konfetti.core.Party +import nl.dionsegijn.konfetti.core.Position +import nl.dionsegijn.konfetti.core.emitter.Emitter import org.isoron.platform.gui.toInt import org.isoron.uhabits.R import org.isoron.uhabits.activities.common.dialogs.CheckmarkDialog @@ -63,6 +66,7 @@ import org.isoron.uhabits.intents.IntentFactory import org.isoron.uhabits.tasks.ExportDBTaskFactory import org.isoron.uhabits.tasks.ImportDataTask import org.isoron.uhabits.tasks.ImportDataTaskFactory +import org.isoron.uhabits.utils.ColorUtils import org.isoron.uhabits.utils.copyTo import org.isoron.uhabits.utils.currentTheme import org.isoron.uhabits.utils.dismissCurrentAndShow @@ -72,6 +76,7 @@ import org.isoron.uhabits.utils.showSendEmailScreen import org.isoron.uhabits.utils.showSendFileScreen import java.io.File import java.io.IOException +import java.util.concurrent.TimeUnit import javax.inject.Inject const val RESULT_IMPORT_DATA = 101 @@ -218,6 +223,28 @@ class ListHabitsScreen activity.showSendFileScreen(filename) } + override fun showConfetti(color: PaletteColor, x: Float, y: Float) { + val baseColor = themeSwitcher.currentTheme!!.color(color).toInt() + rootView.get().konfettiView.start( + Party( + speed = 0f, + maxSpeed = 16f, + damping = 0.9f, + spread = 360, + angle = 0, + colors = listOf( + ColorUtils.changeHue(baseColor, 180f), + ColorUtils.changeHue(baseColor, 20f), + ColorUtils.changeHue(baseColor, -20f), + baseColor + ), + position = Position.Absolute(x, y), + emitter = Emitter(duration = 25, TimeUnit.MILLISECONDS).max(25), + timeToLive = 0 + ) + ) + } + override fun showSettingsScreen() { val intent = intentFactory.startSettingsActivity(activity) activity.startActivityForResult(intent, REQUEST_SETTINGS) @@ -240,7 +267,7 @@ class ListHabitsScreen putDouble("value", value) putString("notes", notes) } - dialog.onToggle = { v, n -> callback.onNumberPicked(v, n) } + dialog.onToggle = { v, n, x, y -> callback.onNumberPicked(v, n, x, y) } dialog.dismissCurrentAndShow(fm, "numberDialog") } @@ -258,7 +285,7 @@ class ListHabitsScreen putInt("value", selectedValue) putString("notes", notes) } - dialog.onToggle = { v, n -> callback.onNotesSaved(v, n) } + dialog.onToggle = { v, n, x, y -> callback.onNotesSaved(v, n, x, y) } dialog.dismissCurrentAndShow(fm, "checkmarkDialog") } 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 e572bda07..3cf77789e 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 @@ -39,7 +39,6 @@ import org.isoron.uhabits.core.preferences.Preferences import org.isoron.uhabits.inject.ActivityContext import org.isoron.uhabits.utils.drawNotesIndicator import org.isoron.uhabits.utils.getFontAwesome -import org.isoron.uhabits.utils.showConfetti import org.isoron.uhabits.utils.sp import org.isoron.uhabits.utils.sres import org.isoron.uhabits.utils.toMeasureSpec @@ -89,7 +88,7 @@ class CheckmarkButtonView( setOnLongClickListener(this) } - fun performToggle(view: View) { + fun performToggle() { value = Entry.nextToggleValue( value = value, isSkipEnabled = preferences.isSkipEnabled, @@ -97,15 +96,12 @@ class CheckmarkButtonView( ) onToggle(value, notes) performHapticFeedback(HapticFeedbackConstants.LONG_PRESS) - when (value) { - YES_MANUAL -> showConfetti(view.rootView) - } invalidate() } override fun onClick(v: View) { if (preferences.isShortToggleEnabled) { - performToggle(v) + performToggle() } else { onEdit() } @@ -115,7 +111,7 @@ class CheckmarkButtonView( if (preferences.isShortToggleEnabled) { onEdit() } else { - performToggle(v) + performToggle() } return true } 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 8e5e9d21e..84bd001fc 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 @@ -20,6 +20,7 @@ package org.isoron.uhabits.activities.habits.list.views import android.content.Context +import android.graphics.PointF import android.graphics.text.LineBreaker.BREAK_STRATEGY_BALANCED import android.os.Build import android.os.Build.VERSION.SDK_INT @@ -154,7 +155,17 @@ class HabitCardView( checkmarkPanel = checkmarkPanelFactory.create().apply { onToggle = { timestamp, value, notes -> triggerRipple(timestamp) - habit?.let { behavior.onToggle(it, timestamp, value, notes) } + val location = getAbsoluteButtonLocation(timestamp) + habit?.let { + behavior.onToggle( + it, + timestamp, + value, + notes, + location.x, + location.y + ) + } } onEdit = { timestamp -> triggerRipple(timestamp) @@ -206,12 +217,27 @@ class HabitCardView( } fun triggerRipple(timestamp: Timestamp) { + val location = getRelativeButtonLocation(timestamp) + triggerRipple(location.x, location.y) + } + + private fun getRelativeButtonLocation(timestamp: Timestamp): PointF { val today = DateUtils.getTodayWithOffset() val offset = timestamp.daysUntil(today) - dataOffset val button = checkmarkPanel.buttons[offset] val y = button.height / 2.0f val x = checkmarkPanel.x + button.x + (button.width / 2).toFloat() - triggerRipple(x, y) + return PointF(x, y) + } + + private fun getAbsoluteButtonLocation(timestamp: Timestamp): PointF { + val containerLocation = IntArray(2) + this.getLocationOnScreen(containerLocation) + val relButtonLocation = getRelativeButtonLocation(timestamp) + return PointF( + containerLocation[0].toFloat() + relButtonLocation.x, + containerLocation[1].toFloat() - relButtonLocation.y + ) } override fun onAttachedToWindow() { 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 21289a0bd..14baee148 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 @@ -179,7 +179,7 @@ class ShowHabitActivity : AppCompatActivity(), CommandRunner.Listener { putDouble("value", value) putString("notes", notes) } - dialog.onToggle = { v, n -> callback.onNumberPicked(v, n) } + dialog.onToggle = { v, n, x, y -> callback.onNumberPicked(v, n, x, y) } dialog.dismissCurrentAndShow(supportFragmentManager, "numberDialog") } @@ -196,7 +196,7 @@ class ShowHabitActivity : AppCompatActivity(), CommandRunner.Listener { putInt("value", selectedValue) putString("notes", notes) } - dialog.onToggle = { v, n -> callback.onNotesSaved(v, n) } + dialog.onToggle = { v, n, x, y -> callback.onNotesSaved(v, n, x, y) } dialog.dismissCurrentAndShow(supportFragmentManager, "checkmarkDialog") } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/utils/ColorUtils.kt b/uhabits-android/src/main/java/org/isoron/uhabits/utils/ColorUtils.kt index c3806f5c6..b993a5bc2 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/utils/ColorUtils.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/utils/ColorUtils.kt @@ -36,6 +36,13 @@ object ColorUtils { return a or r or g or b } + fun changeHue(color: Int, delta: Float): Int { + val hsv = FloatArray(3) + Color.colorToHSV(color, hsv) + hsv[0] = (hsv[0] + delta).mod(360f) + return Color.HSVToColor(hsv) + } + @JvmStatic fun setAlpha(color: Int, newAlpha: Float): Int { val intAlpha = (newAlpha * 255).toInt() 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 583bc5048..3c92e7e1b 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 @@ -26,6 +26,7 @@ import android.content.Intent import android.graphics.Canvas import android.graphics.Color import android.graphics.Paint +import android.graphics.PointF import android.graphics.drawable.ColorDrawable import android.os.Handler import android.os.SystemClock @@ -36,7 +37,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.LinearLayout import android.widget.RelativeLayout import android.widget.RelativeLayout.ALIGN_PARENT_BOTTOM import android.widget.RelativeLayout.ALIGN_PARENT_TOP @@ -47,10 +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 nl.dionsegijn.konfetti.core.Party -import nl.dionsegijn.konfetti.core.Position -import nl.dionsegijn.konfetti.core.emitter.Emitter -import nl.dionsegijn.konfetti.xml.KonfettiView import org.isoron.platform.gui.toInt import org.isoron.uhabits.HabitsApplication import org.isoron.uhabits.R @@ -58,7 +54,6 @@ import org.isoron.uhabits.activities.AndroidThemeSwitcher import org.isoron.uhabits.core.models.PaletteColor import org.isoron.uhabits.core.ui.views.Theme import java.io.File -import java.util.concurrent.TimeUnit fun RelativeLayout.addBelow( view: View, @@ -83,9 +78,7 @@ fun RelativeLayout.addAtBottom( view.layoutParams = RelativeLayout.LayoutParams(width, height).apply { addRule(ALIGN_PARENT_BOTTOM) } - if (view.id == null) { - view.id = View.generateViewId() - } + view.id = View.generateViewId() this.addView(view) } @@ -97,10 +90,7 @@ fun RelativeLayout.addAtTop( view.layoutParams = RelativeLayout.LayoutParams(width, height).apply { addRule(ALIGN_PARENT_TOP) } - - if (view.id == null) { - view.id = View.generateViewId() - } + view.id = View.generateViewId() this.addView(view) } @@ -109,32 +99,6 @@ fun ViewGroup.buildToolbar(): Toolbar { return inflater.inflate(R.layout.toolbar, null) as Toolbar } -fun ViewGroup.buildKonfettiView(): View { - val inflater = LayoutInflater.from(context) - return inflater.inflate(R.layout.konfetti, null) as View -} - -fun showConfetti(view: View) { - val viewId = R.id.konfetttiView - val linearLayout = view.findViewById(R.id.konfettiLayout) - val kv = view.findViewById(viewId) - if (linearLayout != null) { - linearLayout.bringToFront() - } - val party = Party( - speed = 0f, - maxSpeed = 32f, - damping = 0.9f, - spread = 360, - colors = listOf(0xfce18a, 0xff726d, 0xf4306d, 0xb48def, 0x818181, 0x81a48c), - position = Position.Relative(0.5, 0.3), - emitter = Emitter(duration = 300, TimeUnit.MILLISECONDS).max(300) - ) - if (kv != null) { - kv.start(party) - } -} - fun View.showMessage(msg: String) { try { val snackbar = Snackbar.make(this, msg, Snackbar.LENGTH_SHORT) @@ -172,7 +136,11 @@ fun Activity.startActivitySafely(intent: Intent) { } } -fun Activity.showSendEmailScreen(@StringRes toId: Int, @StringRes subjectId: Int, content: String?) { +fun Activity.showSendEmailScreen( + @StringRes toId: Int, + @StringRes subjectId: Int, + content: String? +) { val to = this.getString(toId) val subject = this.getString(subjectId) this.startActivity( @@ -269,3 +237,11 @@ fun View.requestFocusWithKeyboard() { dispatchTouchEvent(MotionEvent.obtain(time, time, MotionEvent.ACTION_UP, 0f, 0f, 0)) }, 250) } + +fun View.getCenter(): PointF { + val viewLocation = IntArray(2) + this.getLocationOnScreen(viewLocation) + viewLocation[0] += this.width / 2 + viewLocation[1] -= this.height / 2 + return PointF(viewLocation[0].toFloat(), viewLocation[1].toFloat()) +} diff --git a/uhabits-android/src/main/res/layout/konfetti.xml b/uhabits-android/src/main/res/layout/konfetti.xml deleted file mode 100644 index 1f7f918dc..000000000 --- a/uhabits-android/src/main/res/layout/konfetti.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - 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 3db3cdbaf..b66b08be6 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 @@ -20,9 +20,12 @@ package org.isoron.uhabits.core.ui.screens.habits.list import org.isoron.uhabits.core.commands.CommandRunner import org.isoron.uhabits.core.commands.CreateRepetitionCommand +import org.isoron.uhabits.core.models.Entry.Companion.YES_MANUAL import org.isoron.uhabits.core.models.Habit import org.isoron.uhabits.core.models.HabitList import org.isoron.uhabits.core.models.HabitType +import org.isoron.uhabits.core.models.NumericalHabitType.AT_LEAST +import org.isoron.uhabits.core.models.NumericalHabitType.AT_MOST import org.isoron.uhabits.core.models.PaletteColor import org.isoron.uhabits.core.models.Timestamp import org.isoron.uhabits.core.preferences.Preferences @@ -52,8 +55,16 @@ open class ListHabitsBehavior @Inject constructor( val entry = habit.computedEntries.get(timestamp!!) if (habit.type == HabitType.NUMERICAL) { val oldValue = entry.value.toDouble() / 1000 - screen.showNumberPopup(oldValue, entry.notes) { newValue: Double, newNotes: String -> + screen.showNumberPopup(oldValue, entry.notes) { newValue: Double, newNotes: String, x: Float, y: Float -> val value = (newValue * 1000).roundToInt() + if (newValue != oldValue) { + if ( + (habit.targetType == AT_LEAST && newValue >= habit.targetValue) || + (habit.targetType == AT_MOST && newValue <= habit.targetValue) + ) { + screen.showConfetti(habit.color, x, y) + } + } commandRunner.run(CreateRepetitionCommand(habitList, habit, timestamp, value, newNotes)) } } else { @@ -61,7 +72,8 @@ open class ListHabitsBehavior @Inject constructor( entry.value, entry.notes, habit.color - ) { newValue, newNotes -> + ) { newValue: Int, newNotes: String, x: Float, y: Float -> + if (newValue != entry.value && newValue == YES_MANUAL) screen.showConfetti(habit.color, x, y) commandRunner.run(CreateRepetitionCommand(habitList, habit, timestamp, newValue, newNotes)) } } @@ -117,10 +129,11 @@ open class ListHabitsBehavior @Inject constructor( if (prefs.isFirstRun) onFirstRun() } - fun onToggle(habit: Habit, timestamp: Timestamp, value: Int, notes: String) { + fun onToggle(habit: Habit, timestamp: Timestamp, value: Int, notes: String, x: Float, y: Float) { commandRunner.run( CreateRepetitionCommand(habitList, habit, timestamp, value, notes) ) + if (value == YES_MANUAL) screen.showConfetti(habit.color, x, y) } enum class Message { @@ -144,12 +157,22 @@ open class ListHabitsBehavior @Inject constructor( } fun interface NumberPickerCallback { - fun onNumberPicked(newValue: Double, notes: String) + fun onNumberPicked( + newValue: Double, + notes: String, + x: Float, + y: Float + ) fun onNumberPickerDismissed() {} } fun interface CheckMarkDialogCallback { - fun onNotesSaved(value: Int, notes: String) + fun onNotesSaved( + value: Int, + notes: String, + x: Float, + y: Float + ) fun onNotesDismissed() {} } @@ -170,5 +193,6 @@ open class ListHabitsBehavior @Inject constructor( ) fun showSendBugReportToDeveloperScreen(log: String) fun showSendFileScreen(filename: String) + fun showConfetti(color: PaletteColor, x: Float, y: Float) } } 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 cfbe5e0f3..0a28c801f 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 @@ -98,7 +98,7 @@ class HistoryCardPresenter( entry.value, entry.notes, habit.color - ) { newValue, newNotes -> + ) { newValue, newNotes, _: Float, _: Float -> commandRunner.run( CreateRepetitionCommand( habitList, @@ -135,7 +135,7 @@ class HistoryCardPresenter( screen.showNumberPopup( value = oldValue / 1000.0, notes = entry.notes - ) { newValue: Double, newNotes: String -> + ) { newValue: Double, newNotes: String, _: Float, _: Float -> val thousands = (newValue * 1000).roundToInt() commandRunner.run( CreateRepetitionCommand( 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 ead82c1e9..26dd82df8 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 @@ -84,7 +84,7 @@ class ListHabitsBehaviorTest : BaseUnitTest() { eq(""), picker.capture() ) - picker.lastValue.onNumberPicked(100.0, "") + picker.lastValue.onNumberPicked(100.0, "", 0f, 0f) val today = getTodayWithOffset() assertThat(habit2.computedEntries.get(today).value, equalTo(100000)) } @@ -168,7 +168,9 @@ class ListHabitsBehaviorTest : BaseUnitTest() { habit = habit1, timestamp = getToday(), value = Entry.NO, - notes = "" + notes = "", + x = 0f, + y = 0f ) assertFalse(habit1.isCompletedToday()) }