Kotlinity

Additional

Language
Kotlin
Version
1.4.0-beta1 (Oct 15, 2018)
Created
Sep 13, 2017
Updated
Jan 9, 2019 (Retired)
Owner
Gil Goldzweig (gilgoldzweig)
Contributor
Gil Goldzweig (gilgoldzweig)
1
Activity
Badge
Generate
Download
Source code

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!