Libraries written in Kotlin and used in most EL Passion Android projects.

https://jitpack.io/#elpassion/android-commons

1. Overview

In EL Passion we believe that every library should be as small as possible, and do one thing, but do it well.

That’s why we follow highly modularized approach.

1.1. Building with JitPack

repositories {
    maven { url "https://jitpack.io" }
}

2. Espresso

Espresso module contains useful stuff when writing tests using espresso framework.

For example instead of writing

    Espresso.onView(ViewMatchers.withId(R.id.button))
    .check(ViewAssertions.matches(ViewMatchers.isDisplayed()))

Leveraging the kotlin expressiveness we can write:

onId(existingId).isDisplayed()

2.1. Download:

androidTestImplementation "com.github.elpassion.android-commons:espresso:0.0.23"

Back to Overview

3. RxJava2-test

RxJava2-test module basically contains two things.

  1. Set of extension methods useful when stubbing api

    For example instead of writing:

    whenever(api.makeRequest()).thenReturn(Completable.error(RuntimeException()))

    We can write:

    whenever(api.invoke()).thenError(error)

    There are corresponding methods for Observable, and Single classes as well.

  2. Set of assertions for testObservers

    • assertValueThat

      Observable.just(4, -1).test().assertValueThat { it > 0 }
    • assertValuesThat

      Observable.just(2, 3, 4).test().assertValuesThat { it > 0 }
    • assertLastValueThat

      Observable.just(1, 2).test().assertLastValue(2)

3.1. Download:

androidTestImplementation "com.github.elpassion.android-commons:rxjava-test:0.0.23"

Back to Overview

4. SharedPreferences

This is a core module which provides an abstraction over android shared preferences.

interface SharedPreferenceRepository<T> {

    fun write(key: String, value: T?)

    fun read(key: String): T?

    fun contains(key: String): Boolean
}

To create an instance of it use the factory method:

val repository = createSharedPrefs<String>(sharedPreferences, jsonAdapter)

A JsonAdapter is a class which fulfills following contract:

interface JsonConverterAdapter<T> {
    fun toJson(t: T?): String

    fun fromJson(t: String): T?
}

As you see any class that can serialize objects to strings and later deserialize them will do.

We have created two adapters for the most commonly used serialization libraries:

There is also an extension method which binds any field into specific key from shared preferences

var secretKey by repository.asProperty("secret-key")

or you can use its non-nullable variant

var secretKeyWithDefault by repository.asPropertyWithDefault("secret-key", "12345678")

If you are reading very often we suggest you to wrap your sharedPreferences instance with CachingSharedPreferences wrapper. It uses the same interface so it is transparent from the usage perspective. Keep in mind that in order to cache values and properly invalidate them, every interactions with sharedPreferences must now go through the same instance of the caching wrapper.

4.1. Download:

implementation "com.github.elpassion.android-commons:shared-preferences:0.0.23"

Back to Overview

5. SharedPreferences-Moshi

It is a moshi adapter for our sharedPreferences library.

To create an instance of it use a factory function:

val jsonAdapter = moshiConverterAdapter<String>()

5.1. Download:

implementation "com.github.elpassion.android-commons:shared-preferences-moshi-converter-adapter:0.0.23"

Back to Overview

6. SharedPreferences-Gson

It is a gson adapter for our sharedPreferences library.

To create an instance of it use a factory function:

val jsonAdapter = gsonConverterAdapter<String>()

6.1. Download:

implementation "com.github.elpassion.android-commons:shared-preferences-gson-converter-adapter:0.0.23"

Back to Overview

7. View

This module contains useful extensions defined for both View and ViewGroup classes.

  1. View

    • show - sets the visibility property of view to VISIBLE

      view.show()
    • hide - sets the visibility property of view to GONE

      view.hide()
    • isVisible - property of type boolean. If it is true the view’s visibility is VISIBLE otherwise is GONE

      view.isVisible = true
    • enable - sets the enable property of view to true

      view.enable()
    • disable - sets the enable property of view to false

    view.disable()
  2. ViewGroup

    • TBD

7.1. Download:

implementation "com.github.elpassion.android-commons:view:0.0.23"

Back to Overview

8. Pager

TBD

8.1. Download:

implementation "com.github.elpassion.android-commons:pager:0.0.23"

Back to Overview

9. Recycler

Using recycler-view have never been easier.

If all of your views are going to be the same type you can just write

val examples = listOf(
        ExampleItem(name = BasicListActivity.DESCRIPTION,
                onClick = { BasicListActivity.start(this) }),
        ExampleItem(name = BasicRecyclerWithSectionActivity.DESCRIPTION,
                onClick = { BasicRecyclerWithSectionActivity.start(this) }),
        ExampleItem(name = BasicMutableRecyclerWithSectionsActivity.DESCRIPTION,
                onClick = { BasicMutableRecyclerWithSectionsActivity.start(this) }),
        ExampleItem(name = BasicContactsListActivity.DESCRIPTION,
                onClick = { BasicContactsListActivity.start(this) })
)

recyclerView.adapter = basicAdapterWithLayoutAndBinder(examples, R.layout.example_item) { holder, item ->
    holder.itemView.example_name.text = item.name
    holder.itemView.setOnClickListener { item.onClick() }
}

If you want to get benefits of using stableIds all you need to do is to make your item implement WithStableId interface and of course tell the adapter to use stable ids: adapter.setHasStableId(true)

On the other hand if you need to have different views for different types of items you just need to write

    val users = createManyUsers()

    recyclerView.adapter = basicAdapterWithConstructors(users) { position ->
        getLayoutAndConstructor(users[position])
    }
}

private fun getLayoutAndConstructor(user: User) = when (user.organization) {
    "A" -> R.layout.github_item to ::SimpleUserViewHolder
    else -> R.layout.other_github_item to ::OtherSimpleUserViewHolder
}

Where a view holder may look like this

class SimpleUserViewHolder(itemView: View) : ViewHolderBinder<User>(itemView) {

    override fun bind(item: User) {
        itemView.userName.text = item.name
        itemView.organization.text = item.organization
    }
}

Dividing your data set into logical pieces is supported by ListWithSections class. Here is an example:

val users = createManyUsers()
        .groupByTo(LinkedHashMap(), User::organization)
        .mapValuesTo(LinkedHashMap()) { it.value }
        .asBasicListWithMutableSections()
    val adapter = basicAdapterWithConstructors(users) { position ->
        when (users[position].organization) {
            "A" -> R.layout.github_item to ::SimpleUserViewHolder
            else -> R.layout.other_github_item to ::OtherSimpleUserViewHolder
        }
    }

There is also a mutable equivalent of this class ListWithMutableSections. With use of it you can e.g. clear all section at once

users.sections["Organization 1"]!!.clear()
adapter.notifyDataSetChanged()

9.1. Download:

implementation "com.github.elpassion.android-commons:recycler:0.0.23"

Back to Overview