Kotlinify
Kotlinify is a suite of extension and classes for easier daily android development in kotlin. I've created it after my own needs and i decided i should publish it and save time for others.
The library contanis 4 modules:
- Core extensions.
- Reactive extensions.
- Jackson extensions.
- Custom edition of JakeWharton/timber
Installiton
In your app's build.gradle add the following.
repositories {
maven {
url "https://jitpack.io"
}
}
dependencies {
You can add each module seperatly
//All of the modules
implementation 'com.github.GilGoldzweig:kotlinify:latestVersion'
// Core module
implementation 'com.github.GilGoldzweig.kotlinify:core:latestVersion'
// Reactive module
implementation 'com.github.GilGoldzweig.kotlinify:reactive:latestVersion'
// Jackson module
implementation 'com.github.GilGoldzweig.kotlinify:jackson:latestVersion'
// Timber module
implementation 'com.github.GilGoldzweig.kotlinify:timber:latestVersion'
}
Core
The core module provides the following classes and extensions.
Bundlify
Let's you create bundles in a simple way and with operators.
val bundle = bundle {
//put key(String), value(Any)
//String
put("key", "value")
//Int
put("key", 1)
//Long
put("key", 1L)
//Float
put("key", 1.5131F)
//parcelable
put("key", Parcelable) //Some parcelable object
//parcelable array
put("key", Array<Parcelable>()) //Some parcelable Array
//parcelable arrayList
put("key", ArrayList<Parcelable>())//Some parcelable ArrayList
"key" += 5
this += "keyPair" to 6L
//remove
remove("keyToRemove")
this - ""
}
"key" in bundle
GlobalSharedPreferences
GlobalSharedPrefrences a SharedPreferences object that let you use it anywhere without the direct access to context. The class also contains an easy usage
First initialize it in your application class //You don't have to provide a name if nothing is placed it will use the default value GlobalSharedPreferences.initialize(application, "sharedPreferencesName") pref {
//put key(String), value(Any)
//String
put("key", "value")
//Int
put("key", 1)
//Long
put("key", 1L)
//Float
put("key", 1.5131F)
"key" += 5
this += "keyPair" to 6L
//remove
remove("keyToRemove")
this - ""
}
//not need to apply inside pref
"key" in GlobalSharedPreferences // return's Boolean
(GlobalSharedPreferences += "keyPair" to 6L).apply()
(GlobalSharedPreferences - "key").apply()
Fragment
An easier way to create a fragment using a dsl extension of fragment
fragment(layoutRes = R.layout.fragment_test) {
//every field in fragment is accessable from here
arguments = bundle // we use the bundle from before to insert the arguments (optinal, you can use a normal Bundle)
var name: TextView // declaring your views
onViewCreated {
view, context, savedInstanceState ->
name = view.findViewById(R.id.text) //accessing the views
}
}
//return's a ready to use fragment
Notification
//You can use but it did not get tested so i'm not writing description //will be added soon
GenericRecyclerAdapter
An abstract extension of RecyclerView.Adapter that reduces the creating time of a RecyclerView. In additon you receive a lot of extension function to make the adapter work simieler to List so by extending the class you receive a lot of bounses
The adapter class CustomRecyclerAdapter(context: Context, // Require context to make it easily accessible
listOfObjects: ArrayList<String> = ArrayList() //Put your list of objects ):
GenericRecyclerAdapter<String>(context,
ArrayList()
//the list of objects could by empty and it will use the default value
, R.layout.item_recycler_test // the item's layout currently one one view type supported
) {
override fun View.onBind(currentElementPosition: Int,
currentElement: String, // the current element with the type provided above in this example a String
holder: GenericViewHolder) {
//because of the extension of View i can just call
// findViewById and that's it you don't need to call holder.view.findViewById
}
}
extension given
val customRecyclerAdapter = CustomRecyclerAdapter(this, ArrayList()) customRecyclerAdapter - "" //removing item and notifying the adapter if you are on uiThread customRecyclerAdapter - 2 //removing item and notifying the adapter if you are on uiThread customRecyclerAdapter + "" //adding item and notifying the adapter if you are on uiThread customRecyclerAdapter.add("",5) customRecyclerAdapter[""] //getItem by object customRecyclerAdapter[12] //getItem by position customRecyclerAdapter - (1..4) //removing position range and notifying the adapter if you are on uiThread customRecyclerAdapter - (listOf("", "")) //removing list of objects and notifying the adapter if you are on uiThread customRecyclerAdapter.setItem(5, "gg") customRecyclerAdapter.clear() customRecyclerAdapter.count() customRecyclerAdapter.setItems(listOf("", "", "", "", "")) //replace the current list and notifying the adapter if you are on uiThread customRecyclerAdapter.isEmpty() customRecyclerAdapter.isNotEmpty()
threads
//single function to run in background
runInBackground {
}
//multiple functions to run in background
runInBackground({
}
, {
}
, {
}
)
//function to run on ui thread
runOnUI {
}
//run's a task after 2 secounds on UI thread
runAfter(millis = 2000, thread = RunnableThread.UI) {
}
//run's a task after 2 secounds in background
runAfter(millis = 2000, thread = RunnableThread.BACKGROUND) {
}
//run's a task after 2 secounds on the current thread
runAfter(millis = 2000, thread = RunnableThread.CURRENT) {
}
//run's a task after 2 secounds
runAfter(millis = 2000) {
}
isUiThread() //Boolean is the current thread is UI
views
val group = LinearLayout(this)//LinearLayout as example can be any ViewGroup group += TextView(this) group += TextView(this) group += TextView(this) group += TextView(this) "in" in TextView(this) group -= TextView(this) group[0] for (view in group.iterator()) {
}
group.first() group.last() group.forEach {
}
group.forEachIndexed {
i, view ->
}
group.forEachRevered {
}
group.forEachReveredIndexed {
i, view ->
}
group.inflate(R.layout.some_layout) this.inflate(R.layout.some_layout, false, group) //this = context View(this).onClick {
}
View(this).onLongClick {
}
View(this).hide() View(this).hide() View(this).show() View(this).invisible() View(this).toggleVisibility() View(this).isVisible()
collections
val testMap = mapOf(0 to 9, 0 to 9, 0 to 9, 0 to 9, 0 to 9) val testSet = setOf(0 to 9, 0 to 9, 0 to 9, 0 to 9, 0 to 9) val testList = listOf(0 to 9, 0 to 9, 0 to 9, 0 to 9, 0 to 9) val testArrayList = ArrayList<Int>() testMap.isNullOrEmpty() testMap.isNotNullOrEmpty() testSet.isNullOrEmpty() testSet.isNotNullOrEmpty() testArrayList.isNullOrEmpty() testArrayList.isNotNullOrEmpty() testArrayList addIfNotExist 5 testArrayList removeIfExist 5
testList.isNullOrEmpty() testList.isNotNullOrEmpty() testList / 3 //returns a map of page number and the amount of items given in this case 3 testList.random() //returns a random element from the list
resourses
Provides two extensions
15.toDp() //return's the number as a convertion from px to dp 15.toPx()//return's the number as a convertion from dp to px
permission
Provides few functions
isVersionAbove(26) // boolean isVersionAbove(14) // boolean same as above but with diffrent version isMarshmallowOrAbove() //boolean is current version is at least Marshmallow(23) isLollipopOrAbove() //boolean is current version is at least Lollipop(21) Context.isGranted("StringPermission") // boolean checks if the permission is granted or not
ColorGenerator
A class with 2 lists of colors one normal colors and one material design colors the class let's you get all the colors or a random color
ColorGenerator.DEFAULT_COLOR_LIST ColorGenerator.instance.randomColor ColorGenerator.MATERIAL_COLOR_LIST ColorGenerator.materialInstance.randomColor
Reactive
The Reactive module provides the following extensions.
Provides two extension functions to most if not all reactive types
/** * observe on main thread * subscribe on new thread * unsubsidised on error and on complete and removes the need to handle it afterwards * @usage * someObservable //or any other reactive type * .runSafeOnMain() * .subscribe({
}
, {
]) */ fun <T> Observable<T>.runSafeOnMain(): Observable<T> =
observeOn(mainThread)
.subscribeOn(newThread)
.doOnError({
unsubscribeOn(newThread)
}
)
.doOnComplete {
unsubscribeOn(newThread)
}
/** * observe on io thread * subscribe on new thread * unsubsidised on error and on complete and removes the need to handle it afterwards * @usage * someObservable //or any other reactive type * .runSafeOnIO() * .subscribe({
}
, {
]) */ fun <T> Observable<T>.runSafeOnIO(): Observable<T> =
observeOn(ioThread)
.subscribeOn(newThread)
.doOnError({
unsubscribeOn(newThread)
}
)
.doOnComplete {
unsubscribeOn(newThread)
}
Jackson
The jackson module provides a few extension functions and an annotation
val locationObject = LocationObject("Tel-Aviv", arrayOf(5.152155, 1512.5120)) val jsonString = "{
\"locationText\":\"Tel-Aviv\",\"locationCoordinates\":[5.152155,1512.512]
}
" locationObject.toJson() //{
"locationText":"Tel-Aviv","locationCoordinates":[5.152155,1512.512]
}
locationObject.toPrettyJson() /** {
"locationText": "Tel-Aviv",
"locationCoordinates": [
5.152155,
1512.512
]
}
*/
jsonString.fromJson<LocationObject>() // A new LocationObject
LocationObject
@JsonIgnoreUnknown //A new annotation to make it easier to use jackson instad of @JsonIgnoreProperties(ignoreUnknown = true) data class LocationObject(val locationText: String, val locationCoordinates: Array<Double>)
Timber
The timber module provides the following class.
Adds a possibilty to print any object using timber a very small change but saves a lot of annying toString()
You can use it like so or just put the object Timber.d(someObject.toString()) Timber.d(5.toString()) Timber.d(someBoolean.toString()) //you can just do like so Timber.d(someObject) Timber.d(5) Timber.d(someBoolean) someObject.d()// no need to call Timber someOtherObject.e()// no need to call Timber someOtherObject.i()// no need to call Timber someOtherObject.wtf()// no need to call Timber someOtherObject.w()// no need to call Timber
License
MIT
Free Software, Hell Yeah!