introducing confetti animation using konfetti library

pull/1972/head
Gokul K 2 years ago committed by Alinson S. Xavier
parent 3a0603605b
commit 08410c59d0
Signed by: isoron
GPG Key ID: 0DA8E4B9E1109DCA

@ -129,6 +129,7 @@ dependencies {
implementation("androidx.legacy:legacy-support-v4:1.0.0") implementation("androidx.legacy:legacy-support-v4:1.0.0")
implementation("com.google.android.material:material:1.11.0") implementation("com.google.android.material:material:1.11.0")
implementation("com.opencsv:opencsv:5.9") implementation("com.opencsv:opencsv:5.9")
implementation("nl.dionsegijn:konfetti-xml:2.0.2")
implementation(project(":uhabits-core")) implementation(project(":uhabits-core"))
kapt("com.google.dagger:dagger-compiler:$daggerVersion") kapt("com.google.dagger:dagger-compiler:$daggerVersion")
kaptAndroidTest("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.LayoutInflater
import android.view.View.GONE import android.view.View.GONE
import android.view.View.VISIBLE import android.view.View.VISIBLE
import android.widget.LinearLayout
import androidx.appcompat.app.AppCompatDialogFragment import androidx.appcompat.app.AppCompatDialogFragment
import org.isoron.uhabits.HabitsApplication import org.isoron.uhabits.HabitsApplication
import org.isoron.uhabits.R 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.databinding.CheckmarkPopupBinding
import org.isoron.uhabits.utils.InterfaceUtils.getFontAwesome import org.isoron.uhabits.utils.InterfaceUtils.getFontAwesome
import org.isoron.uhabits.utils.sres import org.isoron.uhabits.utils.sres
import org.isoron.uhabits.utils.showConfetti
class CheckmarkDialog : AppCompatDialogFragment() { class CheckmarkDialog : AppCompatDialogFragment() {
var onToggle: (Int, String) -> Unit = { _, _ -> } var onToggle: (Int, String) -> Unit = { _, _ -> }
@ -64,6 +66,10 @@ class CheckmarkDialog : AppCompatDialogFragment() {
val notes = view.notes.text.toString().trim() val notes = view.notes.text.toString().trim()
onToggle(v, notes) onToggle(v, notes)
requireDialog().dismiss() requireDialog().dismiss()
val konfettiView = requireActivity().findViewById<LinearLayout>(R.id.konfettiLayout)
when (v) {
YES_MANUAL -> showConfetti(konfettiView)
}
} }
view.yesBtn.setOnClickListener { onClick(YES_MANUAL) } view.yesBtn.setOnClickListener { onClick(YES_MANUAL) }
view.noBtn.setOnClickListener { onClick(NO) } view.noBtn.setOnClickListener { onClick(NO) }

@ -9,6 +9,7 @@ import android.view.LayoutInflater
import android.view.MotionEvent import android.view.MotionEvent
import android.view.View import android.view.View
import android.view.inputmethod.EditorInfo import android.view.inputmethod.EditorInfo
import android.widget.LinearLayout
import androidx.appcompat.app.AppCompatDialogFragment import androidx.appcompat.app.AppCompatDialogFragment
import org.isoron.uhabits.HabitsApplication import org.isoron.uhabits.HabitsApplication
import org.isoron.uhabits.R 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.databinding.CheckmarkPopupBinding
import org.isoron.uhabits.utils.InterfaceUtils import org.isoron.uhabits.utils.InterfaceUtils
import org.isoron.uhabits.utils.requestFocusWithKeyboard import org.isoron.uhabits.utils.requestFocusWithKeyboard
import org.isoron.uhabits.utils.showConfetti
import org.isoron.uhabits.utils.sres import org.isoron.uhabits.utils.sres
import java.text.DecimalFormat import java.text.DecimalFormat
import java.text.DecimalFormatSymbols import java.text.DecimalFormatSymbols
@ -115,5 +117,11 @@ class NumberDialog : AppCompatDialogFragment() {
val notes = view.notes.text.toString() val notes = view.notes.text.toString()
onToggle(value, notes) onToggle(value, notes)
requireDialog().dismiss() 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.addAtTop
import org.isoron.uhabits.utils.addBelow import org.isoron.uhabits.utils.addBelow
import org.isoron.uhabits.utils.buildToolbar import org.isoron.uhabits.utils.buildToolbar
import org.isoron.uhabits.utils.buildKonfettiView
import org.isoron.uhabits.utils.currentTheme import org.isoron.uhabits.utils.currentTheme
import org.isoron.uhabits.utils.dim import org.isoron.uhabits.utils.dim
import org.isoron.uhabits.utils.dp import org.isoron.uhabits.utils.dp
@ -69,6 +70,7 @@ class ListHabitsRootView @Inject constructor(
val listView: HabitCardListView = habitCardListViewFactory.create() val listView: HabitCardListView = habitCardListViewFactory.create()
val llEmpty = EmptyListView(context) val llEmpty = EmptyListView(context)
val tbar = buildToolbar() val tbar = buildToolbar()
val konfettiView = buildKonfettiView()
val progressBar = TaskProgressBar(context, runner) val progressBar = TaskProgressBar(context, runner)
val hintView: HintView val hintView: HintView
val header = HeaderView(context, preferences, midnightTimer) val header = HeaderView(context, preferences, midnightTimer)
@ -80,6 +82,7 @@ class ListHabitsRootView @Inject constructor(
val rootView = RelativeLayout(context).apply { val rootView = RelativeLayout(context).apply {
background = sres.getDrawable(R.attr.windowBackgroundColor) background = sres.getDrawable(R.attr.windowBackgroundColor)
addAtTop(konfettiView)
addAtTop(tbar) addAtTop(tbar)
addBelow(header, tbar) addBelow(header, tbar)
addBelow(listView, header, height = MATCH_PARENT) 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.inject.ActivityContext
import org.isoron.uhabits.utils.drawNotesIndicator import org.isoron.uhabits.utils.drawNotesIndicator
import org.isoron.uhabits.utils.getFontAwesome import org.isoron.uhabits.utils.getFontAwesome
import org.isoron.uhabits.utils.showConfetti
import org.isoron.uhabits.utils.sp import org.isoron.uhabits.utils.sp
import org.isoron.uhabits.utils.sres import org.isoron.uhabits.utils.sres
import org.isoron.uhabits.utils.toMeasureSpec import org.isoron.uhabits.utils.toMeasureSpec
@ -88,7 +89,7 @@ class CheckmarkButtonView(
setOnLongClickListener(this) setOnLongClickListener(this)
} }
fun performToggle() { fun performToggle(v: View) {
value = Entry.nextToggleValue( value = Entry.nextToggleValue(
value = value, value = value,
isSkipEnabled = preferences.isSkipEnabled, isSkipEnabled = preferences.isSkipEnabled,
@ -96,12 +97,15 @@ class CheckmarkButtonView(
) )
onToggle(value, notes) onToggle(value, notes)
performHapticFeedback(HapticFeedbackConstants.LONG_PRESS) performHapticFeedback(HapticFeedbackConstants.LONG_PRESS)
when (value) {
YES_MANUAL -> showConfetti(v.rootView)
}
invalidate() invalidate()
} }
override fun onClick(v: View) { override fun onClick(v: View) {
if (preferences.isShortToggleEnabled) { if (preferences.isShortToggleEnabled) {
performToggle() performToggle(v)
} else { } else {
onEdit() onEdit()
} }
@ -111,7 +115,7 @@ class CheckmarkButtonView(
if (preferences.isShortToggleEnabled) { if (preferences.isShortToggleEnabled) {
onEdit() onEdit()
} else { } else {
performToggle() performToggle(v)
} }
return true return true
} }

@ -36,6 +36,7 @@ import android.view.ViewGroup
import android.view.ViewGroup.LayoutParams.MATCH_PARENT import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
import android.view.WindowManager import android.view.WindowManager
import android.widget.LinearLayout
import android.widget.RelativeLayout import android.widget.RelativeLayout
import android.widget.RelativeLayout.ALIGN_PARENT_BOTTOM import android.widget.RelativeLayout.ALIGN_PARENT_BOTTOM
import android.widget.RelativeLayout.ALIGN_PARENT_TOP import android.widget.RelativeLayout.ALIGN_PARENT_TOP
@ -46,6 +47,10 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar import androidx.appcompat.widget.Toolbar
import androidx.core.content.FileProvider import androidx.core.content.FileProvider
import com.google.android.material.snackbar.Snackbar 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.platform.gui.toInt
import org.isoron.uhabits.HabitsApplication import org.isoron.uhabits.HabitsApplication
import org.isoron.uhabits.R 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.models.PaletteColor
import org.isoron.uhabits.core.ui.views.Theme import org.isoron.uhabits.core.ui.views.Theme
import java.io.File import java.io.File
import java.util.concurrent.TimeUnit
fun RelativeLayout.addBelow( fun RelativeLayout.addBelow(
view: View, view: View,
@ -77,7 +83,9 @@ fun RelativeLayout.addAtBottom(
view.layoutParams = RelativeLayout.LayoutParams(width, height).apply { view.layoutParams = RelativeLayout.LayoutParams(width, height).apply {
addRule(ALIGN_PARENT_BOTTOM) addRule(ALIGN_PARENT_BOTTOM)
} }
view.id = View.generateViewId() if (view.id == null) {
view.id = View.generateViewId()
}
this.addView(view) this.addView(view)
} }
@ -89,7 +97,10 @@ fun RelativeLayout.addAtTop(
view.layoutParams = RelativeLayout.LayoutParams(width, height).apply { view.layoutParams = RelativeLayout.LayoutParams(width, height).apply {
addRule(ALIGN_PARENT_TOP) addRule(ALIGN_PARENT_TOP)
} }
view.id = View.generateViewId()
if (view.id == null) {
view.id = View.generateViewId()
}
this.addView(view) this.addView(view)
} }
@ -98,6 +109,28 @@ fun ViewGroup.buildToolbar(): Toolbar {
return inflater.inflate(R.layout.toolbar, null) as 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) { fun View.showMessage(msg: String) {
try { try {
val snackbar = Snackbar.make(this, msg, Snackbar.LENGTH_SHORT) val snackbar = Snackbar.make(this, msg, Snackbar.LENGTH_SHORT)

@ -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>
Loading…
Cancel
Save