From 25cff3d9b02c108ef79d67001a8b5721de4bffd4 Mon Sep 17 00:00:00 2001 From: Quentin Hibon Date: Mon, 7 Aug 2023 23:04:37 +0200 Subject: [PATCH 01/11] Check android lint violations against current baseline --- build.sh | 1 + uhabits-android/build.gradle.kts | 5 + uhabits-android/lint-baseline.xml | 7966 +++++++++++++++++++++++++++++ 3 files changed, 7972 insertions(+) create mode 100644 uhabits-android/lint-baseline.xml diff --git a/build.sh b/build.sh index ac81802e1..3a9937a58 100755 --- a/build.sh +++ b/build.sh @@ -64,6 +64,7 @@ fail() { core_build() { log_info "Building uhabits-core..." $GRADLE ktlintCheck || fail + $GRADLE lintDebug || fail $GRADLE :uhabits-core:build || fail } diff --git a/uhabits-android/build.gradle.kts b/uhabits-android/build.gradle.kts index 5bcfef429..d8f6b23b9 100644 --- a/uhabits-android/build.gradle.kts +++ b/uhabits-android/build.gradle.kts @@ -76,6 +76,11 @@ android { buildFeatures { viewBinding = true } + + lint { + baseline = file("lint-baseline.xml") + warningsAsErrors = true + } } dependencies { diff --git a/uhabits-android/lint-baseline.xml b/uhabits-android/lint-baseline.xml new file mode 100644 index 000000000..2607914ff --- /dev/null +++ b/uhabits-android/lint-baseline.xml @@ -0,0 +1,7966 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 08410c59d000d7aaed552745fb54ccd038e0c8ca Mon Sep 17 00:00:00 2001 From: Gokul K Date: Fri, 16 Jun 2023 19:01:56 +0530 Subject: [PATCH 02/11] introducing confetti animation using konfetti library --- uhabits-android/build.gradle.kts | 1 + .../common/dialogs/CheckmarkDialog.kt | 6 +++ .../activities/common/dialogs/NumberDialog.kt | 8 ++++ .../habits/list/ListHabitsRootView.kt | 3 ++ .../habits/list/views/CheckmarkButtonView.kt | 10 +++-- .../isoron/uhabits/utils/ViewExtensions.kt | 37 ++++++++++++++++++- .../src/main/res/layout/konfetti.xml | 29 +++++++++++++++ 7 files changed, 89 insertions(+), 5 deletions(-) create mode 100644 uhabits-android/src/main/res/layout/konfetti.xml diff --git a/uhabits-android/build.gradle.kts b/uhabits-android/build.gradle.kts index ed6968598..9b816432a 100644 --- a/uhabits-android/build.gradle.kts +++ b/uhabits-android/build.gradle.kts @@ -129,6 +129,7 @@ dependencies { implementation("androidx.legacy:legacy-support-v4:1.0.0") implementation("com.google.android.material:material:1.11.0") implementation("com.opencsv:opencsv:5.9") + implementation("nl.dionsegijn:konfetti-xml:2.0.2") implementation(project(":uhabits-core")) kapt("com.google.dagger:dagger-compiler:$daggerVersion") kaptAndroidTest("com.google.dagger:dagger-compiler:$daggerVersion") 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 5df8ffd7b..bc1e8e4cb 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,6 +24,7 @@ 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,6 +35,7 @@ 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.sres +import org.isoron.uhabits.utils.showConfetti class CheckmarkDialog : AppCompatDialogFragment() { var onToggle: (Int, String) -> Unit = { _, _ -> } @@ -64,6 +66,10 @@ class CheckmarkDialog : AppCompatDialogFragment() { val notes = view.notes.text.toString().trim() onToggle(v, notes) 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 5b749b8b6..9adcfc0fd 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,6 +9,7 @@ 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 @@ -16,6 +17,7 @@ import org.isoron.uhabits.core.models.Entry import org.isoron.uhabits.databinding.CheckmarkPopupBinding import org.isoron.uhabits.utils.InterfaceUtils 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 @@ -115,5 +117,11 @@ class NumberDialog : AppCompatDialogFragment() { val notes = view.notes.text.toString() onToggle(value, notes) requireDialog().dismiss() + val v = requireActivity().findViewById(R.id.konfettiLayout) + + if (value > 0.0) { + showConfetti(v) + + } } } 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 62fe3f00c..79f154bb7 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 @@ -44,6 +44,7 @@ import org.isoron.uhabits.utils.addAtBottom import org.isoron.uhabits.utils.addAtTop import org.isoron.uhabits.utils.addBelow import org.isoron.uhabits.utils.buildToolbar +import org.isoron.uhabits.utils.buildKonfettiView import org.isoron.uhabits.utils.currentTheme import org.isoron.uhabits.utils.dim import org.isoron.uhabits.utils.dp @@ -69,6 +70,7 @@ class ListHabitsRootView @Inject constructor( val listView: HabitCardListView = habitCardListViewFactory.create() val llEmpty = EmptyListView(context) val tbar = buildToolbar() + val konfettiView = buildKonfettiView() val progressBar = TaskProgressBar(context, runner) val hintView: HintView val header = HeaderView(context, preferences, midnightTimer) @@ -80,6 +82,7 @@ class ListHabitsRootView @Inject constructor( val rootView = RelativeLayout(context).apply { background = sres.getDrawable(R.attr.windowBackgroundColor) + addAtTop(konfettiView) addAtTop(tbar) addBelow(header, tbar) addBelow(listView, header, height = MATCH_PARENT) 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 3cf77789e..a450a506e 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,6 +39,7 @@ 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 @@ -88,7 +89,7 @@ class CheckmarkButtonView( setOnLongClickListener(this) } - fun performToggle() { + fun performToggle(v: View) { value = Entry.nextToggleValue( value = value, isSkipEnabled = preferences.isSkipEnabled, @@ -96,12 +97,15 @@ class CheckmarkButtonView( ) onToggle(value, notes) performHapticFeedback(HapticFeedbackConstants.LONG_PRESS) + when (value) { + YES_MANUAL -> showConfetti(v.rootView) + } invalidate() } override fun onClick(v: View) { if (preferences.isShortToggleEnabled) { - performToggle() + performToggle(v) } else { onEdit() } @@ -111,7 +115,7 @@ class CheckmarkButtonView( if (preferences.isShortToggleEnabled) { onEdit() } else { - performToggle() + performToggle(v) } return true } 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 abf98970c..9334ab569 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,6 +36,7 @@ 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 @@ -46,6 +47,10 @@ 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 @@ -53,6 +58,7 @@ 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, @@ -77,7 +83,9 @@ fun RelativeLayout.addAtBottom( view.layoutParams = RelativeLayout.LayoutParams(width, height).apply { addRule(ALIGN_PARENT_BOTTOM) } - view.id = View.generateViewId() + if (view.id == null) { + view.id = View.generateViewId() + } this.addView(view) } @@ -89,7 +97,10 @@ fun RelativeLayout.addAtTop( view.layoutParams = RelativeLayout.LayoutParams(width, height).apply { addRule(ALIGN_PARENT_TOP) } - view.id = View.generateViewId() + + if (view.id == null) { + view.id = View.generateViewId() + } this.addView(view) } @@ -98,6 +109,28 @@ 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.konfettttiView + val linearLayout = view.findViewById(R.id.konfettiLayout) + val kv = view.findViewById(viewId) + 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) + ) + kv.start(party) +} + fun View.showMessage(msg: String) { try { val snackbar = Snackbar.make(this, msg, Snackbar.LENGTH_SHORT) diff --git a/uhabits-android/src/main/res/layout/konfetti.xml b/uhabits-android/src/main/res/layout/konfetti.xml new file mode 100644 index 000000000..49bd60daa --- /dev/null +++ b/uhabits-android/src/main/res/layout/konfetti.xml @@ -0,0 +1,29 @@ + + + + + + + From ad8738180c6c116cf29a698925cd71e899e716d0 Mon Sep 17 00:00:00 2001 From: Gokul K Date: Tue, 4 Jul 2023 18:50:28 +0530 Subject: [PATCH 03/11] fixing some comments from @hiqua --- .../uhabits/activities/common/dialogs/NumberDialog.kt | 6 +++--- .../activities/habits/list/views/CheckmarkButtonView.kt | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) 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 9adcfc0fd..1f344b173 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 @@ -117,11 +117,11 @@ class NumberDialog : AppCompatDialogFragment() { val notes = view.notes.text.toString() onToggle(value, notes) requireDialog().dismiss() - val v = requireActivity().findViewById(R.id.konfettiLayout) + val konfettiView = requireActivity().findViewById(R.id.konfettiLayout) if (value > 0.0) { - showConfetti(v) - + //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/views/CheckmarkButtonView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkButtonView.kt index a450a506e..e572bda07 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 @@ -89,7 +89,7 @@ class CheckmarkButtonView( setOnLongClickListener(this) } - fun performToggle(v: View) { + fun performToggle(view: View) { value = Entry.nextToggleValue( value = value, isSkipEnabled = preferences.isSkipEnabled, @@ -98,7 +98,7 @@ class CheckmarkButtonView( onToggle(value, notes) performHapticFeedback(HapticFeedbackConstants.LONG_PRESS) when (value) { - YES_MANUAL -> showConfetti(v.rootView) + YES_MANUAL -> showConfetti(view.rootView) } invalidate() } From e30636a447925a94dab6c5faf8e98628edf10d42 Mon Sep 17 00:00:00 2001 From: Gokul K Date: Tue, 4 Jul 2023 20:53:26 +0530 Subject: [PATCH 04/11] fixed ktlint erorrs and is building successfully now --- .../isoron/uhabits/activities/common/dialogs/CheckmarkDialog.kt | 2 +- .../isoron/uhabits/activities/common/dialogs/NumberDialog.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 bc1e8e4cb..93ffd2c80 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 @@ -34,8 +34,8 @@ 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.sres import org.isoron.uhabits.utils.showConfetti +import org.isoron.uhabits.utils.sres class CheckmarkDialog : AppCompatDialogFragment() { var onToggle: (Int, String) -> Unit = { _, _ -> } 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 1f344b173..adac2bb3a 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 @@ -120,7 +120,7 @@ class NumberDialog : AppCompatDialogFragment() { val konfettiView = requireActivity().findViewById(R.id.konfettiLayout) if (value > 0.0) { - //To motivate, show confetti even if some value is present + // To motivate, show confetti even if some value is present showConfetti(konfettiView) } } From b09306e793324fc357c70ada44d635aca2480bf6 Mon Sep 17 00:00:00 2001 From: Gokul K Date: Wed, 5 Jul 2023 12:05:10 +0530 Subject: [PATCH 05/11] fixing another lint error --- .../isoron/uhabits/activities/habits/list/ListHabitsRootView.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 79f154bb7..e3e8f076c 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 @@ -43,8 +43,8 @@ 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.buildToolbar import org.isoron.uhabits.utils.buildKonfettiView +import org.isoron.uhabits.utils.buildToolbar import org.isoron.uhabits.utils.currentTheme import org.isoron.uhabits.utils.dim import org.isoron.uhabits.utils.dp From 1280e798d21d3d03f8705e8b0db2b48e89ee551f Mon Sep 17 00:00:00 2001 From: Gokul K Date: Tue, 11 Jul 2023 18:48:55 +0530 Subject: [PATCH 06/11] rendering only if layout and konfetti view exists - to avoid null reference errors --- .../java/org/isoron/uhabits/utils/ViewExtensions.kt | 10 +++++++--- uhabits-android/src/main/res/layout/konfetti.xml | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) 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 9334ab569..583bc5048 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 @@ -115,10 +115,12 @@ fun ViewGroup.buildKonfettiView(): View { } fun showConfetti(view: View) { - val viewId = R.id.konfettttiView + val viewId = R.id.konfetttiView val linearLayout = view.findViewById(R.id.konfettiLayout) val kv = view.findViewById(viewId) - linearLayout.bringToFront() + if (linearLayout != null) { + linearLayout.bringToFront() + } val party = Party( speed = 0f, maxSpeed = 32f, @@ -128,7 +130,9 @@ fun showConfetti(view: View) { position = Position.Relative(0.5, 0.3), emitter = Emitter(duration = 300, TimeUnit.MILLISECONDS).max(300) ) - kv.start(party) + if (kv != null) { + kv.start(party) + } } fun View.showMessage(msg: String) { diff --git a/uhabits-android/src/main/res/layout/konfetti.xml b/uhabits-android/src/main/res/layout/konfetti.xml index 49bd60daa..1f7f918dc 100644 --- a/uhabits-android/src/main/res/layout/konfetti.xml +++ b/uhabits-android/src/main/res/layout/konfetti.xml @@ -24,6 +24,6 @@ + android:id="@+id/konfetttiView"/> From 4b3910aea89507a9a3a744b517741bdae1ac4116 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Apr 2024 03:45:40 +0000 Subject: [PATCH 07/11] Bump com.google.guava:guava from 33.0.0-android to 33.1.0-android Bumps [com.google.guava:guava](https://github.com/google/guava) from 33.0.0-android to 33.1.0-android. - [Release notes](https://github.com/google/guava/releases) - [Commits](https://github.com/google/guava/commits) --- updated-dependencies: - dependency-name: com.google.guava:guava dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- uhabits-android/build.gradle.kts | 2 +- uhabits-core/build.gradle.kts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/uhabits-android/build.gradle.kts b/uhabits-android/build.gradle.kts index ed6968598..b2d7ba174 100644 --- a/uhabits-android/build.gradle.kts +++ b/uhabits-android/build.gradle.kts @@ -116,7 +116,7 @@ dependencies { implementation("com.github.AppIntro:AppIntro:6.3.1") implementation("com.google.code.findbugs:jsr305:3.0.2") implementation("com.google.dagger:dagger:$daggerVersion") - implementation("com.google.guava:guava:33.0.0-android") + implementation("com.google.guava:guava:33.1.0-android") implementation("io.ktor:ktor-client-android:$ktorVersion") implementation("io.ktor:ktor-client-core:$ktorVersion") implementation("io.ktor:ktor-client-jackson:$ktorVersion") diff --git a/uhabits-core/build.gradle.kts b/uhabits-core/build.gradle.kts index 6a7ca5c93..46676a5a0 100644 --- a/uhabits-core/build.gradle.kts +++ b/uhabits-core/build.gradle.kts @@ -45,7 +45,7 @@ kotlin { dependencies { implementation(kotlin("stdlib-jdk8")) compileOnly("com.google.dagger:dagger:2.50") - implementation("com.google.guava:guava:33.0.0-android") + implementation("com.google.guava:guava:33.1.0-android") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.7.3") implementation("androidx.annotation:annotation:1.7.1") implementation("com.google.code.findbugs:jsr305:3.0.2") From 936986e110a1be16e9fefdcee0b0a7d569fcf5e1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Apr 2024 16:12:14 +0000 Subject: [PATCH 08/11] Bump daggerVersion from 2.50 to 2.51.1 Bumps `daggerVersion` from 2.50 to 2.51.1. Updates `com.google.dagger:dagger` from 2.50 to 2.51.1 - [Release notes](https://github.com/google/dagger/releases) - [Changelog](https://github.com/google/dagger/blob/master/CHANGELOG.md) - [Commits](https://github.com/google/dagger/compare/dagger-2.50...dagger-2.51.1) Updates `com.google.dagger:dagger-compiler` from 2.50 to 2.51.1 - [Release notes](https://github.com/google/dagger/releases) - [Changelog](https://github.com/google/dagger/blob/master/CHANGELOG.md) - [Commits](https://github.com/google/dagger/compare/dagger-2.50...dagger-2.51.1) --- updated-dependencies: - dependency-name: com.google.dagger:dagger dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: com.google.dagger:dagger-compiler dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- uhabits-android/build.gradle.kts | 2 +- uhabits-core/build.gradle.kts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/uhabits-android/build.gradle.kts b/uhabits-android/build.gradle.kts index b2d7ba174..b163e8075 100644 --- a/uhabits-android/build.gradle.kts +++ b/uhabits-android/build.gradle.kts @@ -94,7 +94,7 @@ android { } dependencies { - val daggerVersion = "2.50" + val daggerVersion = "2.51.1" val kotlinVersion = "1.9.22" val kxCoroutinesVersion = "1.7.3" val ktorVersion = "1.6.8" diff --git a/uhabits-core/build.gradle.kts b/uhabits-core/build.gradle.kts index 46676a5a0..930b7819a 100644 --- a/uhabits-core/build.gradle.kts +++ b/uhabits-core/build.gradle.kts @@ -44,7 +44,7 @@ kotlin { val jvmMain by getting { dependencies { implementation(kotlin("stdlib-jdk8")) - compileOnly("com.google.dagger:dagger:2.50") + compileOnly("com.google.dagger:dagger:2.51.1") implementation("com.google.guava:guava:33.1.0-android") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.7.3") implementation("androidx.annotation:annotation:1.7.1") From e48452f724b3c712f61ca2741a7fb6886c9eda2f Mon Sep 17 00:00:00 2001 From: "Alinson S. Xavier" Date: Sat, 3 Feb 2024 22:45:15 -0600 Subject: [PATCH 09/11] Move showConfetti to ListHabitsScreen; use button location; other tweaks --- .../common/dialogs/CheckmarkDialog.kt | 15 ++--- .../activities/common/dialogs/NumberDialog.kt | 14 ++--- .../habits/list/ListHabitsRootView.kt | 6 +- .../habits/list/ListHabitsScreen.kt | 31 +++++++++- .../habits/list/views/CheckmarkButtonView.kt | 10 +--- .../habits/list/views/HabitCardView.kt | 30 +++++++++- .../habits/show/ShowHabitActivity.kt | 4 +- .../org/isoron/uhabits/utils/ColorUtils.kt | 7 +++ .../isoron/uhabits/utils/ViewExtensions.kt | 56 ++++++------------- .../src/main/res/layout/konfetti.xml | 29 ---------- .../screens/habits/list/ListHabitsBehavior.kt | 34 +++++++++-- .../screens/habits/show/views/HistoryCard.kt | 4 +- .../habits/list/ListHabitsBehaviorTest.kt | 6 +- 13 files changed, 134 insertions(+), 112 deletions(-) delete mode 100644 uhabits-android/src/main/res/layout/konfetti.xml 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()) } From 093591fbafd7f547295776ff3a699851c614226f Mon Sep 17 00:00:00 2001 From: "Alinson S. Xavier" Date: Thu, 4 Apr 2024 21:24:09 -0500 Subject: [PATCH 10/11] Update lint baseline --- uhabits-android/lint-baseline.xml | 456 ++++++++++++++++++++++++------ 1 file changed, 371 insertions(+), 85 deletions(-) diff --git a/uhabits-android/lint-baseline.xml b/uhabits-android/lint-baseline.xml index 2607914ff..35b787313 100644 --- a/uhabits-android/lint-baseline.xml +++ b/uhabits-android/lint-baseline.xml @@ -1,5 +1,27 @@ - + + + + + + + + + @@ -30,7 +52,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -41,7 +63,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -52,7 +74,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -63,7 +85,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -123,13 +145,13 @@ + id="UnusedAttribute" + message="Attribute `localeConfig` is only used in API level 33 and higher (current min is 28)" + errorLine1=" android:localeConfig="@xml/locales_config"" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -140,7 +162,7 @@ errorLine2=" ~~~~~~~~~"> @@ -195,7 +217,7 @@ errorLine2=" ~~~~"> @@ -217,7 +239,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -245,57 +267,13 @@ - - - - - - - - + message="A newer version of androidx.test.uiautomator:uiautomator than 2.2.0 is available: 2.3.0" + errorLine1=" androidTestImplementation("androidx.test.uiautomator:uiautomator:2.2.0")" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> - - - - - - - - + column="32"/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1252,7 +1538,7 @@ errorLine2=" ~~~~~"> @@ -1285,7 +1571,7 @@ errorLine2=" ~~~~~~~~~~~~~~~"> @@ -4152,7 +4438,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -4163,7 +4449,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~"> @@ -4174,7 +4460,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -4185,7 +4471,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -4196,7 +4482,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~"> @@ -4207,7 +4493,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -4853,13 +5139,13 @@ id="IconDipSize" message="The image `ic_launcher_monochrome.png` varies significantly in its density-independent (dip) size across the various density versions: mipmap-hdpi/ic_launcher_monochrome.png: 108x108 dp (162x162 px), mipmap-mdpi/ic_launcher_monochrome.png: 162x162 dp (162x162 px), mipmap-xhdpi/ic_launcher_monochrome.png: 108x108 dp (216x216 px), mipmap-xxhdpi/ic_launcher_monochrome.png: 108x108 dp (324x324 px), mipmap-xxxhdpi/ic_launcher_monochrome.png: 108x108 dp (432x432 px)"> + file="src/main/res/mipmap-xxhdpi/ic_launcher_monochrome.png"/> - + @@ -5110,7 +5396,7 @@ errorLine2=" ~~~~~~~~~~~~~"> @@ -5143,7 +5429,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~"> @@ -5205,7 +5491,7 @@ @@ -7767,7 +8053,7 @@ Date: Thu, 4 Apr 2024 21:36:51 -0500 Subject: [PATCH 11/11] lint: disable GradleDependency --- uhabits-android/build.gradle.kts | 1 + 1 file changed, 1 insertion(+) diff --git a/uhabits-android/build.gradle.kts b/uhabits-android/build.gradle.kts index 7dbd220d7..28154d587 100644 --- a/uhabits-android/build.gradle.kts +++ b/uhabits-android/build.gradle.kts @@ -94,6 +94,7 @@ android { lint { baseline = file("lint-baseline.xml") + disable += "GradleDependency" warningsAsErrors = true } }