Skip to content

Commit 75e649f

Browse files
Kotlin DSL Component: Building AlertDialogs using Kotlin DSL (#95)
1 parent a1a7a9d commit 75e649f

File tree

4 files changed

+138
-0
lines changed

4 files changed

+138
-0
lines changed

app/src/main/java/com/rocketinsights/android/ui/MainFragment.kt

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import com.rocketinsights.android.extensions.setupActionBar
2525
import com.rocketinsights.android.extensions.show
2626
import com.rocketinsights.android.extensions.showToast
2727
import com.rocketinsights.android.extensions.viewBinding
28+
import com.rocketinsights.android.ui.components.dialog
2829
import com.rocketinsights.android.viewmodels.MainMessageState
2930
import com.rocketinsights.android.viewmodels.MainViewModel
3031
import com.rocketinsights.android.viewmodels.PhotoViewModel
@@ -113,10 +114,33 @@ class MainFragment : Fragment(R.layout.fragment_main) {
113114
setFadeThroughTransition()
114115
item.onNavDestinationSelected(findNavController())
115116
}
117+
R.id.dialog -> {
118+
showDslDialog()
119+
true
120+
}
116121
else -> super.onOptionsItemSelected(item)
117122
}
118123
}
119124

125+
private fun showDslDialog() {
126+
dialog {
127+
titleRes = R.string.dialog_title
128+
contentRes = R.string.dialog_content
129+
cancelable = false
130+
positiveText = "Positive"
131+
negativeText = "Negative"
132+
positiveAction = {
133+
requireContext().showToast("Positive Action Clicked")
134+
}
135+
negativeAction = {
136+
requireContext().showToast("Negative Action Clicked")
137+
}
138+
dismissAction = {
139+
requireContext().showToast("Alert Dismissed")
140+
}
141+
}
142+
}
143+
120144
private fun setupControls() {
121145
binding.stockImage.setOnClickListener {
122146
val extras = FragmentNavigatorExtras(
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package com.rocketinsights.android.ui.components
2+
3+
import android.app.Activity
4+
import android.content.Context
5+
import android.view.View
6+
import androidx.annotation.StringRes
7+
import androidx.appcompat.app.AlertDialog
8+
import androidx.fragment.app.Fragment
9+
import com.google.android.material.dialog.MaterialAlertDialogBuilder
10+
11+
/**
12+
* DialogDsl is an example of how to create components using Kotlin DSL. The main advantage of this
13+
* is the reduction of the boilerplate code, and therefore improves the readability of our code.
14+
*
15+
* These components make sense when it is actually used in many parts of our code and/or it is a
16+
* very customizable component.
17+
*/
18+
@DslMarker
19+
annotation class DslDialog
20+
21+
@DslDialog
22+
class DialogBuilder(
23+
val context: Context,
24+
val setup: DialogBuilder.() -> Unit = {}
25+
) {
26+
27+
@StringRes
28+
var titleRes: Int? = null
29+
var title: String? = null
30+
31+
@StringRes
32+
var contentRes: Int? = null
33+
var content: String? = null
34+
35+
@StringRes
36+
var positiveTextRes: Int? = null
37+
var positiveText: String? = null
38+
39+
@StringRes
40+
var negativeTextRes: Int? = null
41+
var negativeText: String? = null
42+
43+
var customLayout: View? = null
44+
45+
var positiveAction: (() -> Unit)? = null
46+
var negativeAction: (() -> Unit)? = null
47+
var dismissAction: (() -> Unit)? = null
48+
49+
var cancelable: Boolean = true
50+
51+
fun build(): AlertDialog {
52+
setup()
53+
54+
return MaterialAlertDialogBuilder(context).apply {
55+
quartus(title, { setTitle(it) }, titleRes, { setTitle(it) })
56+
quartus(content, { setMessage(it) }, contentRes, { setMessage(it) })
57+
58+
customLayout?.let {
59+
setView(it)
60+
}
61+
62+
negativeAction?.let { action ->
63+
quartus(
64+
negativeText, { setNegativeButton(it) { _, _ -> action.invoke() } },
65+
negativeTextRes, { setNegativeButton(it) { _, _ -> action.invoke() } }
66+
)
67+
}
68+
69+
positiveAction?.let { action ->
70+
quartus(
71+
positiveText, { setPositiveButton(it) { _, _ -> action.invoke() } },
72+
positiveTextRes, { setPositiveButton(it) { _, _ -> action.invoke() } }
73+
)
74+
}
75+
76+
dismissAction?.let {
77+
setOnDismissListener {
78+
dismissAction?.invoke()
79+
}
80+
}
81+
82+
setCancelable(cancelable)
83+
}.create()
84+
}
85+
}
86+
87+
private fun <T, U> Any.quartus(
88+
primaryValue: T?,
89+
primaryAction: ((T) -> Unit)? = null,
90+
secondaryValue: U?,
91+
secondaryAction: ((U) -> Unit)? = null
92+
) {
93+
primaryValue?.let {
94+
primaryAction?.invoke(it)
95+
} ?: run {
96+
secondaryValue?.let {
97+
secondaryAction?.invoke(it)
98+
}
99+
}
100+
}
101+
102+
fun Fragment.dialog(setup: DialogBuilder.() -> Unit) =
103+
DialogBuilder(requireContext(), setup = setup).build().show()
104+
105+
fun Activity.dialog(setup: DialogBuilder.() -> Unit) =
106+
DialogBuilder(this, setup = setup).build().show()

app/src/main/res/menu/main_menu.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
<item
1818
android:id="@+id/calendar_fragment"
1919
android:title="@string/calendar" />
20+
<item
21+
android:id="@+id/dialog"
22+
android:title="@string/dialog" />
2023
<item
2124
android:id="@+id/menu_login"
2225
android:title="@string/login" />

app/src/main/res/values/strings.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,9 @@
8383
<string name="lottie">Lottie</string>
8484
<string name="property">Property</string>
8585
<string name="container">Container</string>
86+
87+
<!-- Dialog -->
88+
<string name="dialog">Dsl Dialog</string>
89+
<string name="dialog_title">Dialog Title</string>
90+
<string name="dialog_content">Dialog Content</string>
8691
</resources>

0 commit comments

Comments
 (0)