Add: Main app, main activity and navigation handling

This commit is contained in:
Carlos Martinez
2021-06-15 22:08:27 -04:00
parent e85196ad03
commit 7a62f260ee
16 changed files with 370 additions and 3 deletions

View File

@@ -0,0 +1,33 @@
package dev.carlos.core.domain
sealed class Either<out L, out R> {
data class Left<out L>(val a: L) : Either<L, Nothing>()
data class Right<out R>(val b: R) : Either<Nothing, R>()
val isRight get() = this is Right<R>
val isLeft get() = this is Left<L>
fun <L> left(a: L) = Left(a)
fun <R> right(b: R) = Right(b)
fun either(fnL: (L) -> Any, fnR: (R) -> Any): Any =
when (this) {
is Left -> fnL(a)
is Right -> fnR(b)
}
}
fun <A, B, C> ((A) -> B).c(f: (B) -> C): (A) -> C = {
f(this(it))
}
fun <T, L, R> Either<L, R>.flatMap(fn: (R) -> Either<L, T>): Either<L, T> =
when (this) {
is Either.Left -> Either.Left(
a
)
is Either.Right -> fn(b)
}
fun <T, L, R> Either<L, R>.map(fn: (R) -> (T)): Either<L, T> = this.flatMap(fn.c(::right))

View File

@@ -0,0 +1,36 @@
package dev.carlos.core.domain.network
import dev.carlos.core.BuildConfig
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
import retrofit2.converter.gson.GsonConverterFactory
import timber.log.Timber
import java.util.concurrent.TimeUnit
private const val TIMEOUT_IN_SECONDS = 60L
class RemoteClient(endpoint: String) {
private val logger = HttpLoggingInterceptor { message -> Timber.d(message) }.setLevel(getLoggerLevel())
private val client = OkHttpClient.Builder()
.addInterceptor(logger)
.readTimeout(TIMEOUT_IN_SECONDS, TimeUnit.SECONDS)
.connectTimeout(TIMEOUT_IN_SECONDS, TimeUnit.SECONDS)
.build()
private val retrofit: Retrofit = Retrofit.Builder()
.baseUrl(endpoint)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(client)
.build()
fun <T> getClient(api: Class<T>): T = retrofit.create(api)
private fun getLoggerLevel() = when (BuildConfig.DEBUG) {
true -> HttpLoggingInterceptor.Level.BASIC
false -> HttpLoggingInterceptor.Level.NONE
}
}

View File

@@ -0,0 +1,8 @@
package dev.carlos.core.domain.network
sealed class RequestStatus {
object Ready : RequestStatus()
object Loading : RequestStatus()
object Errored : RequestStatus()
object Empty : RequestStatus()
}

View File

@@ -0,0 +1,8 @@
package dev.carlos.core.extensions
import android.content.Context
import android.widget.Toast
fun Context.toast(message: String) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}

View File

@@ -0,0 +1,15 @@
package dev.carlos.core.extensions
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
fun <T> LiveData<T>.observeNonNull(owner: LifecycleOwner, func: (T) -> Unit) {
observe(owner, Observer {
it?.let {
func(it)
}
})
}
fun Int.wasUpdated() = this > 0

View File

@@ -0,0 +1,32 @@
package dev.carlos.core.extensions
import android.os.Bundle
import android.view.View
import androidx.annotation.IdRes
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.navigation.fragment.NavHostFragment
fun AppCompatActivity.findNavHostFragment(@IdRes id: Int) =
supportFragmentManager.findFragmentById(id) as NavHostFragment
fun NavHostFragment.registerOnFragmentViewCreated(
recursive: Boolean = true,
listener: (currentFragment: Fragment) -> Unit
) {
childFragmentManager
.registerFragmentLifecycleCallbacks(object : FragmentManager.FragmentLifecycleCallbacks() {
override fun onFragmentViewCreated(
fm: FragmentManager,
f: Fragment,
v: View,
savedInstanceState: Bundle?
) {
super.onFragmentViewCreated(fm, f, v, savedInstanceState)
listener(f)
}
}, recursive)
}
fun buildNavigation(@IdRes id: Int, bundle: Bundle = Bundle()) = Pair(id, bundle)

View File

@@ -0,0 +1,60 @@
package dev.carlos.core.extensions
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.annotation.LayoutRes
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
fun View.enable() {
isEnabled = true
}
fun View.disable() {
isEnabled = false
}
fun View.visible() {
visibility = View.VISIBLE
}
fun View.invisible() {
visibility = View.INVISIBLE
}
fun View.transparent() {
alpha = 0f
}
fun View.opaque() {
alpha = 1f
}
fun View.gone() {
visibility = View.GONE
}
fun ViewGroup.inflate(@LayoutRes layout: Int, attachToRoot: Boolean = false): View =
LayoutInflater
.from(context)
.inflate(layout, this, attachToRoot)
fun <T> RecyclerView.Adapter<*>.autoNotify(oldList: List<T>, newList: List<T>, compare: (T, T) -> Boolean) {
val diff = DiffUtil.calculateDiff(object : DiffUtil.Callback() {
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return compare(oldList[oldItemPosition], newList[newItemPosition])
}
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return oldList[oldItemPosition] == newList[newItemPosition]
}
override fun getOldListSize() = oldList.size
override fun getNewListSize() = newList.size
})
diff.dispatchUpdatesTo(this)
}

View File

@@ -0,0 +1,7 @@
package dev.carlos.core.navigation
interface NavigationEvent
interface NavigationController {
fun sendNavigation(event: NavigationEvent)
}

View File

@@ -0,0 +1,13 @@
package dev.carlos.core.navigation
class NavigationRouter : NavigationController {
private var onNavigationEvent: (NavigationEvent) -> Unit = {}
override fun sendNavigation(event: NavigationEvent) {
onNavigationEvent(event)
}
fun setOnNavigationEvent(listener: (NavigationEvent) -> Unit) {
onNavigationEvent = listener
}
}