mirror of
https://github.com/iSoron/uhabits.git
synced 2025-12-06 01:08:50 -06:00
introducing confetti animation using konfetti library
This commit is contained in:
@@ -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")
|
||||
|
||||
@@ -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<LinearLayout>(R.id.konfettiLayout)
|
||||
when (v) {
|
||||
YES_MANUAL -> showConfetti(konfettiView)
|
||||
}
|
||||
}
|
||||
view.yesBtn.setOnClickListener { onClick(YES_MANUAL) }
|
||||
view.noBtn.setOnClickListener { onClick(NO) }
|
||||
|
||||
@@ -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<LinearLayout>(R.id.konfettiLayout)
|
||||
|
||||
if (value > 0.0) {
|
||||
showConfetti(v)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
||||
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<LinearLayout>(R.id.konfettiLayout)
|
||||
val kv = view.findViewById<KonfettiView>(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)
|
||||
|
||||
29
uhabits-android/src/main/res/layout/konfetti.xml
Normal file
29
uhabits-android/src/main/res/layout/konfetti.xml
Normal file
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (C) 2013 The Android Open Source Project
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/konfettiLayout"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:focusable="false"
|
||||
android:orientation="vertical" >
|
||||
|
||||
<nl.dionsegijn.konfetti.xml.KonfettiView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/konfettttiView"/>
|
||||
|
||||
</LinearLayout>
|
||||
Reference in New Issue
Block a user