Why Wand?
-
Consistency
Adds consistency to your code when working with your app's resources or common APIs.
-
Ease of Use
Many utilities in Wand serve as an extension of system APIs and improving upon them. No long setups or boilerplate needed.
ColorWand
+ extensions
ColorWand
resolves colors only after calling .getColor(context)
. In some cases it's only used
as a pass-through to resolve colors immediately. For instance when calling color extension methods
directly on context, it will use ColorWand
however immediately resolves the value.
// requires app context, optionally works with themed context
context.colorStateList(R.color.primary_color) // returns entire state list
context.color(R.color.primary_color) // returns default color
// requires themed context
context.attribute(R.attr.colorPrimary) // returns default color for attribute
In cases in which you need to save the value and resolve later, you can use as
methods.
var wand: ColorWand
wand = asColor(0x000000)
wand = asColorRes(R.color.primary_color)
wand = asColorStateList(R.color.primary_color)
wand = asColorAttr(R.attr.colorPrimary)
// … some time later
wand.getColor(context)
TextWand
+ extensions
TextWand
too works as a static holder up until the point you want to resolve the values
context.text(R.string.my_string, username)
context.quantityText(R.plurals.days, dayCount, dayCount)
Or save and resolve later
var wand: TextWand
wand = asText("My string")
wand = asText(R.string.my_string)
wand = asText(R.plurals.my_string, dayCount, dayCount)
Working with insets was never easy on Android, however if you do figure them out, apps look infinitely better and more modern. Why not giving it a try?
In Activity
override fun onCreate(/**/) {
val wand = InsetsWand(this)
lifecycleScope.launch {
wand.collect { //it: InsetsWand
// todo save / apply insets
}
}
}
In Fragment
override fun onViewCreated(/**/) {
val wand = InsetsWand(this)
lifecycleScope.launch {
wand.collect { //it: InsetsWand
// todo save / apply insets
}
}
}
In View
override fun onAttachedToWindow() {
val wand = InsetsWand(this)
viewScope.launch {
wand.collect { //it: InsetsWand
// todo save / apply insets
}
}
}
Unfortunately Android framework doesn't provide clear and concise way to automatically adjust status and navigation bar colors based on system version and theme colors. One simple extension method comes to the rescue. It works wonderfully with InsetsWand!
In Activity
override fun onCreate(/**/) {
applyWindowAppearance()
}
This declaration alone will not do any wonders. You need to implement themes, which might be somewhat difficult too, so here's a helpful guide.
values/styles.xml
<style name="Foundation" parent="Theme.MaterialComponents.DayNight.NoActionBar">
<item name="android:windowTranslucentStatus">@bool/windowTranslucentStatus</item>
<item name="android:windowTranslucentNavigation">@bool/windowTranslucentNavigation</item>
<item name="android:navigationBarColor">@color/colorNavigationBar</item>
<item name="android:statusBarColor">@color/colorStatusBar</item>
</style>
<style name="Foundation.Extras" />
<style name="AppTheme" parent="Foundation.Extras">
<!-- This is really important as it sets the window background without which the WindowAppearance tool won't work -->
<item name="colorSurface">@color/colorSurface</item>
<!-- Declare other colors here -->
</style>
values-v23/styles.xml
<style name="Foundation.Extras">
<item name="android:windowLightStatusBar">@bool/light_mode</item>
</style>
values-v27/styles.xml
<style name="Foundation.Extras">
<item name="android:windowLightStatusBar">@bool/light_mode</item>
<item name="android:windowLightNavigationBar">@bool/light_mode</item>
</style>
You might find a healthy amount of helpful extensions here:
Often than not we all find ourselves using RecyclerViews with the pesky adapters and view holders. We aim to solve this with some easy boilerplate reducers.
It merges principles of
AdapterListDiffer and
BindingViewHolder.
Only thing you really need to do is provide layout resources through getItemViewType
. Fetching
specific items can be done through
getItemAt(position)
.
class MyAdapter(
differ: DiffUtil.ItemCallback<MyData>,
extras: ExtrasBinder? = null
) : AsyncBindingAdapter<MyData>(differ, extras) {
override fun getItemViewType(position: Int) {
val item = getItemAt(position)
return when(item) {
null -> R.layout.placeholder
else -> R.layout.item_my_data
}
}
}
You can also bind extras (additional data, callbacks, etc…) to your items through ExtrasBinder
Logo by smalllikeart