Replace Timber with Logger

This commit is contained in:
Kirill Kamakin
2022-08-05 20:16:29 +02:00
parent ba5f7322ab
commit 107bb64256
49 changed files with 458 additions and 260 deletions

View File

@@ -1,22 +1,22 @@
package gq.kirmanak.mealient.extensions
import gq.kirmanak.mealient.data.network.NetworkError
import gq.kirmanak.mealient.logging.Logger
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.SerializationException
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.decodeFromStream
import retrofit2.HttpException
import retrofit2.Response
import timber.log.Timber
import java.io.InputStream
inline fun <T, reified R> Response<T>.decodeErrorBodyOrNull(json: Json): R? =
errorBody()?.byteStream()?.let { json.decodeFromStreamOrNull<R>(it) }
inline fun <T, reified R> Response<T>.decodeErrorBodyOrNull(json: Json, logger: Logger): R? =
errorBody()?.byteStream()?.let { json.decodeFromStreamOrNull<R>(it, logger) }
@OptIn(ExperimentalSerializationApi::class)
inline fun <reified T> Json.decodeFromStreamOrNull(stream: InputStream): T? =
inline fun <reified T> Json.decodeFromStreamOrNull(stream: InputStream, logger: Logger): T? =
runCatching { decodeFromStream<T>(stream) }
.onFailure { Timber.e(it, "decodeFromStreamOrNull: can't decode") }
.onFailure { logger.e(it) { "decodeFromStreamOrNull: can't decode" } }
.getOrNull()
fun Throwable.mapToNetworkError(): NetworkError = when (this) {
@@ -24,8 +24,12 @@ fun Throwable.mapToNetworkError(): NetworkError = when (this) {
else -> NetworkError.NoServerConnection(this)
}
inline fun <T> logAndMapErrors(block: () -> T, logProvider: () -> String): T =
inline fun <T> logAndMapErrors(
logger: Logger,
block: () -> T,
noinline logProvider: () -> String
): T =
runCatchingExceptCancel(block).getOrElse {
Timber.e(it, logProvider())
logger.e(it, messageSupplier = logProvider)
throw it.mapToNetworkError()
}

View File

@@ -15,6 +15,7 @@ import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import com.google.android.material.textfield.TextInputLayout
import gq.kirmanak.mealient.logging.Logger
import kotlinx.coroutines.channels.ChannelResult
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.channels.onClosed
@@ -24,61 +25,60 @@ import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import timber.log.Timber
fun SwipeRefreshLayout.refreshRequestFlow(): Flow<Unit> = callbackFlow {
Timber.v("refreshRequestFlow() called")
fun SwipeRefreshLayout.refreshRequestFlow(logger: Logger): Flow<Unit> = callbackFlow {
logger.v { "refreshRequestFlow() called" }
val listener = SwipeRefreshLayout.OnRefreshListener {
Timber.v("refreshRequestFlow: listener called")
trySend(Unit).logErrors("refreshesFlow")
logger.v { "refreshRequestFlow: listener called" }
trySend(Unit).logErrors("refreshesFlow", logger)
}
setOnRefreshListener(listener)
awaitClose {
Timber.v("Removing refresh request listener")
logger.v { "Removing refresh request listener" }
setOnRefreshListener(null)
}
}
fun Activity.setSystemUiVisibility(isVisible: Boolean) {
Timber.v("setSystemUiVisibility() called with: isVisible = $isVisible")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) setSystemUiVisibilityV30(isVisible)
else setSystemUiVisibilityV1(isVisible)
fun Activity.setSystemUiVisibility(isVisible: Boolean, logger: Logger) {
logger.v { "setSystemUiVisibility() called with: isVisible = $isVisible" }
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) setSystemUiVisibilityV30(isVisible, logger)
else setSystemUiVisibilityV1(isVisible, logger)
}
@Suppress("DEPRECATION")
private fun Activity.setSystemUiVisibilityV1(isVisible: Boolean) {
Timber.v("setSystemUiVisibilityV1() called with: isVisible = $isVisible")
private fun Activity.setSystemUiVisibilityV1(isVisible: Boolean, logger: Logger) {
logger.v { "setSystemUiVisibilityV1() called with: isVisible = $isVisible" }
window.decorView.systemUiVisibility = if (isVisible) 0 else View.SYSTEM_UI_FLAG_FULLSCREEN
}
@RequiresApi(Build.VERSION_CODES.R)
private fun Activity.setSystemUiVisibilityV30(isVisible: Boolean) {
Timber.v("setSystemUiVisibilityV30() called with: isVisible = $isVisible")
private fun Activity.setSystemUiVisibilityV30(isVisible: Boolean, logger: Logger) {
logger.v { "setSystemUiVisibilityV30() called with: isVisible = $isVisible" }
val systemBars = WindowInsets.Type.systemBars()
window.insetsController?.apply { if (isVisible) show(systemBars) else hide(systemBars) }
?: Timber.w("setSystemUiVisibilityV30: insets controller is null")
?: logger.w { "setSystemUiVisibilityV30: insets controller is null" }
}
fun AppCompatActivity.setActionBarVisibility(isVisible: Boolean) {
Timber.v("setActionBarVisibility() called with: isVisible = $isVisible")
fun AppCompatActivity.setActionBarVisibility(isVisible: Boolean, logger: Logger) {
logger.v { "setActionBarVisibility() called with: isVisible = $isVisible" }
supportActionBar?.apply { if (isVisible) show() else hide() }
?: Timber.w("setActionBarVisibility: action bar is null")
?: logger.w { "setActionBarVisibility: action bar is null" }
}
fun TextView.textChangesFlow(): Flow<CharSequence?> = callbackFlow {
Timber.v("textChangesFlow() called")
fun TextView.textChangesFlow(logger: Logger): Flow<CharSequence?> = callbackFlow {
logger.v { "textChangesFlow() called" }
val textWatcher = doAfterTextChanged {
trySend(it).logErrors("textChangesFlow")
trySend(it).logErrors("textChangesFlow", logger)
}
awaitClose {
Timber.d("textChangesFlow: flow is closing")
logger.d { "textChangesFlow: flow is closing" }
removeTextChangedListener(textWatcher)
}
}
fun <T> ChannelResult<T>.logErrors(methodName: String): ChannelResult<T> {
onFailure { Timber.e(it, "$methodName: can't send event") }
onClosed { Timber.e(it, "$methodName: flow has been closed") }
fun <T> ChannelResult<T>.logErrors(methodName: String, logger: Logger): ChannelResult<T> {
onFailure { logger.e(it) { "$methodName: can't send event" } }
onClosed { logger.e(it) { "$methodName: flow has been closed" } }
return this
}
@@ -87,29 +87,31 @@ fun EditText.checkIfInputIsEmpty(
lifecycleOwner: LifecycleOwner,
@StringRes stringId: Int,
trim: Boolean = true,
logger: Logger,
): String? {
val input = if (trim) text?.trim() else text
val text = input?.toString().orEmpty()
Timber.d("Input text is \"$text\"")
logger.d { "Input text is \"$text\"" }
return text.ifEmpty {
inputLayout.error = resources.getString(stringId)
lifecycleOwner.lifecycleScope.launch {
waitUntilNotEmpty()
waitUntilNotEmpty(logger)
inputLayout.error = null
}
null
}
}
suspend fun EditText.waitUntilNotEmpty() {
textChangesFlow().filterNotNull().first { it.isNotEmpty() }
Timber.v("waitUntilNotEmpty() returned")
suspend fun EditText.waitUntilNotEmpty(logger: Logger) {
textChangesFlow(logger).filterNotNull().first { it.isNotEmpty() }
logger.v { "waitUntilNotEmpty() returned" }
}
fun <T> SharedPreferences.prefsChangeFlow(
logger: Logger,
valueReader: SharedPreferences.() -> T,
): Flow<T> = callbackFlow {
fun sendValue() = trySend(valueReader()).logErrors("prefsChangeFlow")
fun sendValue() = trySend(valueReader()).logErrors("prefsChangeFlow", logger)
val listener = SharedPreferences.OnSharedPreferenceChangeListener { _, _ -> sendValue() }
sendValue()
registerOnSharedPreferenceChangeListener(listener)