Skip to content

Instantly share code, notes, and snippets.

@Aidanvii7
Last active October 1, 2021 09:56
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Aidanvii7/f5a4183697c153f5e8cc9c722b0bf4cc to your computer and use it in GitHub Desktop.
Save Aidanvii7/f5a4183697c153f5e8cc9c722b0bf4cc to your computer and use it in GitHub Desktop.
A Kotlin way to use Android Bundles. Offers type safety unlike android ktx's version of bundleOf
import android.os.Bundle
import android.os.Parcelable
import android.util.Size
import java.io.Serializable
typealias BundleContext = Bundle.() -> Unit
/**
* ```
* fun example(someParcelable: Parcelable, someOtherBundle: Bundle) {
* val bundle = bundleOf {
* strings["string_key"] = "value"
* integers["int_key"] = 1
* integers["int_key"] = null // removes key/value
* booleans["bool_key"] = true
* parcelables["parcelable_key"] = someParcelable
* bundles["bundle_key"] = someOtherBundle
* bundles.flattenWith(someOtherBundle)
* }
* }
* ```
*/
inline fun bundleOf(bundleContext: BundleContext): Bundle =
Bundle().apply(bundleContext)
inline val Bundle.strings
get() = BundleStrings(this)
inline val Bundle.integers
get() = BundleIntegers(this)
inline val Bundle.floats
get() = BundleFloats(this)
inline val Bundle.bytes
get() = BundleBytes(this)
inline val Bundle.booleans
get() = BundleBooleans(this)
inline val Bundle.parcelables
get() = BundleParcelables(this)
inline val Bundle.sizes
get() = BundleSizes(this)
inline val Bundle.bundles
get() = BundleBundles(this)
@JvmInline
value class BundleStrings(val bundle: Bundle) {
operator fun set(key: String, value: String) {
bundle.putString(key, value)
}
fun remove(key: String) {
bundle.remove(key)
}
operator fun get(key: String): String? = bundle.getString(key)
}
@JvmInline
value class BundleParcelables(val bundle: Bundle) {
operator fun set(key: String, value: Parcelable?) {
bundle.apply {
if (value != null) putParcelable(key, value) else remove(key)
}
}
inline fun <reified T : Parcelable> set(value: T?) {
this[T::class.qualifiedName!!] = value
}
inline operator fun <reified T : Parcelable> get(key: String = T::class.qualifiedName!!): T? =
bundle.getParcelable(key)
}
@JvmInline
value class BundleSerializables(val bundle: Bundle) {
operator fun set(key: String, value: Serializable?) {
bundle.apply {
if (value != null) putSerializable(key, value) else remove(key)
}
}
inline fun <reified T : Serializable> set(value: T?) {
this[T::class.qualifiedName!!] = value
}
inline operator fun <reified T : Serializable> get(key: String = T::class.qualifiedName!!): T? =
bundle.getSerializable(key) as? T
}
@JvmInline
value class BundleIntegers(val bundle: Bundle) {
operator fun set(key: String, value: Int) {
bundle.putInt(key, value)
}
operator fun set(key: String, value: Int?) {
bundle.apply {
if (value != null) putInt(key, value) else remove(key)
}
}
operator fun get(key: String): Int? =
if (bundle.containsKey(key)) bundle.getInt(key) else null
}
@JvmInline
value class BundleFloats(val bundle: Bundle) {
operator fun set(key: String, value: Float) {
bundle.putFloat(key, value)
}
operator fun set(key: String, value: Float?) {
bundle.apply {
if (value != null) putFloat(key, value) else remove(key)
}
}
operator fun get(key: String): Float? =
if (bundle.containsKey(key)) bundle.getFloat(key) else null
}
@JvmInline
value class BundleBytes(val bundle: Bundle) {
operator fun set(key: String, value: Byte) {
bundle.putByte(key, value)
}
operator fun set(key: String, value: Byte?) {
bundle.apply {
if (value != null) putByte(key, value) else remove(key)
}
}
operator fun get(key: String): Byte? =
if (bundle.containsKey(key)) bundle.getByte(key) else null
}
@JvmInline
value class BundleBooleans(val bundle: Bundle) {
operator fun set(key: String, value: Boolean) {
bundle.putBoolean(key, value)
}
operator fun set(key: String, value: Boolean?) {
bundle.apply {
if (value != null) putBoolean(key, value) else remove(key)
}
}
operator fun get(key: String): Boolean? =
if (bundle.containsKey(key)) bundle.getBoolean(key) else null
}
@JvmInline
value class BundleSizes(val bundle: Bundle) {
operator fun set(key: String, value: Size?) {
bundle.apply {
if (value != null) putSize(key, value) else remove(key)
}
}
operator fun get(key: String): Size? =
bundle.getSize(key)
}
@JvmInline
value class BundleBundles(val bundle: Bundle) {
operator fun set(key: String, value: Bundle) {
bundle.putBundle(key, value)
}
operator fun get(key: String): Bundle? = bundle.getBundle(key)
fun flattenWith(otherBundle: Bundle, recursive: Boolean = false): Bundle =
bundle.apply {
otherBundle.toMap().forEach { (key, value) ->
when (value) {
is String -> strings[key] = value
is Int -> integers[key] = value
is Float -> floats[key] = value
is Byte -> bytes[key] = value
is Boolean -> booleans[key] = value
is Parcelable -> parcelables[key] = value
is Size -> sizes[key] = value
is Bundle -> if (recursive) flattenWith(value)
}
}
}
}
fun Bundle.toMap(): Map<String, Any> =
keySet().mapNotNull { key ->
when (val value = this[key]) {
null -> null
is String -> value
is Int -> value
is Float -> value
is Byte -> value
is Boolean -> value
is Parcelable -> value
is Size -> value
is Bundle -> value
else -> null //unsupported type for now
}?.let { value -> key to value }
}.toMap()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment