Skip to content

Live Templates

Lopez Mikhael edited this page Jun 5, 2020 · 2 revisions

File and Code Templates are available on Android Studio. It's a very powerful feature but not often used. When using an architecture such as this one it is essential to use it to increase your productivity especially for the creation of your scenes.

You can add File and Code Templates here: Preferences > Editor > File and Code Templates
After adding them, all you have to do is New and choose your template.

🎁 Bonus: RecyclerViewAdapter.kt

ViewModel.kt:

#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME}#end

data class ${NAME}(val loadingState: LoadingState = LoadingState.NONE,
                   val contentState: ContentState = ContentState.NONE,
                   val data: ${DataType}? = null,
                   val errorMessage: String? = null,
                   val snackMessage: String? = null) {

    companion object {
        fun createLoading() = ${NAME}(loadingState = LoadingState.LOADING, contentState = ContentState.CONTENT)

        fun createRetryLoading() = ${NAME}(loadingState = LoadingState.RETRY, contentState = ContentState.ERROR)

        fun createData(data: ${DataType}) = ${NAME}(contentState = ContentState.CONTENT, data = data)

        fun createError(error: String) = ${NAME}(contentState = ContentState.ERROR, errorMessage = error)

        fun createSnack(snackMessage: String) = ${NAME}(contentState = ContentState.CONTENT, snackMessage = snackMessage)
    }

}

LoadDataView.kt:

#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME}#end

import io.reactivex.Observable

interface ${NAME} : LoadDataView<${Scene_Name}ViewModel> {

    fun intentLoadData(): Observable<${Param}>

    fun intentRefreshData(): Observable<${Param}>

    fun intentErrorRetry(): Observable<${Param}>

}

Router.kt:

#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME}#end

import androidx.appcompat.app.AppCompatActivity
import javax.inject.Inject

class ${NAME}
@Inject internal constructor(private val activity: AppCompatActivity) {

    fun routeToSample() {
        //activity.startActivity(SampleActivity.newIntent(activity.applicationContext))
    }

}

Presenter.kt:

#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME}#end

import io.reactivex.Observable
import io.reactivex.Scheduler
import io.reactivex.Single
import io.reactivex.rxkotlin.addTo
import javax.inject.Inject

class ${NAME}
@Inject constructor(private val getData: ${GetDataUsecase},
                    private val router: ${Scene_Name}Router,
                    private val scheduler: Scheduler,
                    errorMessageFactory: ErrorMessageFactory)
    : APresenter<${Scene_Name}View, ${Scene_Name}ViewModel>(errorMessageFactory) {

    override fun attach(view: ${Scene_Name}View) {
        val loadData = view.intentLoadData().flatMap { loadData(it) }
        val refreshData = view.intentRefreshData().flatMap { refreshData(it) }
        val retryData = view.intentErrorRetry().flatMap { retryData(it) }

        subscribeViewModel(view, loadData, refreshData, retryData)
    }

    //region USE CASES TO VIEW MODEL
    private fun getData(param: ${ParamUseCase}): Observable<${Scene_Name}ViewModel> =
            getData.execute(param).toObservable()
                    .map { ${Scene_Name}ViewModel.createData(it) }
    
    private fun loadData(param: ${ParamUseCase}): Observable<${Scene_Name}ViewModel> =
            getData(param)
                    .startWith(${Scene_Name}ViewModel.createLoading())
                    .onErrorReturn { onError(it) }

    private fun refreshData(param: ${ParamUseCase}): Observable<${Scene_Name}ViewModel> =
            getData(param)
                    .onErrorReturn { ${Scene_Name}ViewModel.createSnack(getErrorMessage(it)) }

    private fun retryData(param: ${ParamUseCase}): Observable<${Scene_Name}ViewModel> =
            getData(param)
                    .startWith(${Scene_Name}ViewModel.createRetryLoading())
                    .onErrorResumeNext(DelayFunction<${Scene_Name}ViewModel>(scheduler))
                    .onErrorReturn { onError(it) }
    //endregion

    private fun onError(error: Throwable): ${Scene_Name}ViewModel =
            ${Scene_Name}ViewModel.createError(getErrorMessage(error))

}

DataFragment.kt:

#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME}#end

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.jakewharton.rxbinding3.swiperefreshlayout.refreshes
import com.jakewharton.rxbinding3.view.clicks
import io.reactivex.Observable
import javax.inject.Inject

class ${NAME} : ABaseDataFragment(R.layout.${Layout_ID}), ${Scene_Name}View {

    companion object {
        fun newInstance(): ${NAME} = ${NAME}()
    }

    @Inject
    lateinit var presenter: ${Scene_Name}Presenter

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        activityComponent.inject(this)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        initView()
    }

    override fun onResume() {
        super.onResume()
        presenter.attach(this)
    }

    override fun onPause() {
        super.onPause()
        presenter.detach()
    }

    private fun initView() {

    }

    //region INTENTS
    override fun intentLoadData(): Observable<Unit> = Observable.just(Unit)

    override fun intentRefreshData(): Observable<Unit> = swipeRefreshLayout.refreshes().map { Unit }

    override fun intentErrorRetry(): Observable<Unit> = btnErrorRetry.clicks().map { Unit }
    //endregion

    //region RENDER
    override fun render(viewModel: ${Scene_Name}ViewModel) {
        TimberWrapper.d { "Render: " + viewModel }

        showLoading(viewModel.loadingState == LoadingState.LOADING)
        showRefreshingLoading(swipeRefreshLayout, false)
        showRetryLoading(viewModel.loadingState == LoadingState.RETRY)
        showContent(content, viewModel.contentState == ContentState.CONTENT)
        showError(viewModel.contentState == ContentState.ERROR)

        renderData(viewModel.data)
        renderError(viewModel.errorMessage)
        renderSnack(viewModel.snackMessage)
    }

    private fun renderData(data: ${Data_Type}?) {
        data?.also {
            // TODO
        }
    }
    //endregion

}

BaseContainerActivity.kt:

#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME}#end

import android.content.Context
import android.content.Intent
import android.os.Bundle

class ${NAME} : ABaseActivity(R.layout.${Layout_ID}) {

    companion object {
        fun newIntent(context: Context): Intent =
                Intent(context, ${NAME}::class.java)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        initializeActivity(savedInstanceState)
    }

    private fun initializeActivity(savedInstanceState: Bundle?) {
        if (savedInstanceState == null) {
            addFragment(R.id.container, ${Scene_Name}Fragment.newInstance())
        }
    }

}

RecyclerViewAdapter.kt:

#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME}#end

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView

class ${NAME} : RecyclerView.Adapter<${NAME}.ViewHolder>() {

    var data: List<${Model}> = emptyList()
        set(value) {
            field = value
            notifyDataSetChanged()
        }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder =
        ViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.${Item_Layout_ID}, parent, false))

    override fun onBindViewHolder(holder: ViewHolder, position: Int) = holder.bind(data[position])
    
    override fun getItemCount() = data.size

    class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        fun bind(item: ${Model}) = with(itemView) {
            // TODO: Bind the data with View
        }
    }
}