Skip to content

Commit 0c45496

Browse files
authored
Merge pull request #30 from atiqmlbd/feature/detekt
feat: detekt implemented
2 parents e481f3c + e540d19 commit 0c45496

23 files changed

+476
-92
lines changed

app/build.gradle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ android {
8282
}
8383
}
8484

85+
86+
8587
dependencies {
8688

8789
implementation ("org.jetbrains.kotlin:kotlin-stdlib:${versions.kotlin}")

app/src/main/java/com/monstarlab/arch/data/Repository.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@ package com.monstarlab.arch.data
33
/**
44
* Empty for now, but could allow us to add cache helpers etc
55
*/
6-
abstract class Repository constructor()
6+
abstract class Repository

app/src/main/java/com/monstarlab/arch/data/SingleSharedPreferenceDataStore.kt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ package com.monstarlab.arch.data
22

33
import android.content.SharedPreferences
44
import kotlinx.serialization.KSerializer
5+
import kotlinx.serialization.SerializationException
56
import kotlinx.serialization.json.Json
7+
import timber.log.Timber
8+
import java.io.IOException
69

710
abstract class SingleSharedPreferenceDataStore<T> constructor(
811
private val sharedPreferences: SharedPreferences,
@@ -16,7 +19,7 @@ abstract class SingleSharedPreferenceDataStore<T> constructor(
1619
val json = sharedPreferences.getString(key, "") ?: ""
1720
val entries = Json.decodeFromString(serializer, json)
1821
entries
19-
} catch (e: Exception) {
22+
} catch (e: SerializationException) {
2023
null
2124
}
2225
}
@@ -25,7 +28,8 @@ abstract class SingleSharedPreferenceDataStore<T> constructor(
2528
try {
2629
val json = Json.encodeToString(serializer, item)
2730
sharedPreferences.edit().putString(key, json).apply()
28-
} catch (e: Exception) {
31+
} catch (e: SerializationException) {
32+
Timber.e(e)
2933
}
3034
}
3135

app/src/main/java/com/monstarlab/arch/extensions/FlowExtensions.kt

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,9 @@ import kotlinx.coroutines.launch
5858
* @return [Flow] that only emits items from `this` upstream flow when the [lifecycle] is at
5959
* least in the [minActiveState].
6060
*/
61+
6162
@OptIn(ExperimentalCoroutinesApi::class)
62-
public fun <T> Flow<T>.flowWithLifecycle(
63+
fun <T> Flow<T>.flowWithLifecycle(
6364
lifecycle: Lifecycle,
6465
minActiveState: Lifecycle.State = Lifecycle.State.STARTED
6566
): Flow<T> = callbackFlow {
@@ -71,7 +72,11 @@ public fun <T> Flow<T>.flowWithLifecycle(
7172
close()
7273
}
7374

74-
fun <T1, T2> CoroutineScope.combineFlows(flow1: Flow<T1>, flow2: Flow<T2>, collectBlock: (suspend (T1, T2) -> Unit)) {
75+
fun <T1, T2> CoroutineScope.combineFlows(
76+
flow1: Flow<T1>,
77+
flow2: Flow<T2>,
78+
collectBlock: (suspend (T1, T2) -> Unit)
79+
) {
7580
launch {
7681
flow1.combine(flow2) { v1, v2 ->
7782
collectBlock.invoke(v1, v2)
@@ -81,7 +86,12 @@ fun <T1, T2> CoroutineScope.combineFlows(flow1: Flow<T1>, flow2: Flow<T2>, colle
8186
}
8287
}
8388

84-
fun <T1, T2, T3> CoroutineScope.combineFlows(flow1: Flow<T1>, flow2: Flow<T2>, flow3: Flow<T3>, collectBlock: (suspend (T1, T2, T3) -> Unit)) {
89+
fun <T1, T2, T3> CoroutineScope.combineFlows(
90+
flow1: Flow<T1>,
91+
flow2: Flow<T2>,
92+
flow3: Flow<T3>,
93+
collectBlock: (suspend (T1, T2, T3) -> Unit)
94+
) {
8595
launch {
8696
combine(flow1, flow2, flow3) { v1, v2, v3 ->
8797
collectBlock.invoke(v1, v2, v3)
@@ -91,7 +101,13 @@ fun <T1, T2, T3> CoroutineScope.combineFlows(flow1: Flow<T1>, flow2: Flow<T2>, f
91101
}
92102
}
93103

94-
fun <T1, T2, T3, T4> CoroutineScope.combineFlows(flow1: Flow<T1>, flow2: Flow<T2>, flow3: Flow<T3>, flow4: Flow<T4>, collectBlock: (suspend (T1, T2, T3, T4) -> Unit)) {
104+
fun <T1, T2, T3, T4> CoroutineScope.combineFlows(
105+
flow1: Flow<T1>,
106+
flow2: Flow<T2>,
107+
flow3: Flow<T3>,
108+
flow4: Flow<T4>,
109+
collectBlock: (suspend (T1, T2, T3, T4) -> Unit)
110+
) {
95111
launch {
96112
combine(flow1, flow2, flow3, flow4) { v1, v2, v3, v4 ->
97113
collectBlock.invoke(v1, v2, v3, v4)

app/src/main/java/com/monstarlab/arch/extensions/FragmentViewBindingDelegate.kt

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@ class FragmentViewBindingDelegate<T : ViewBinding>(
1111
private val fragment: Fragment,
1212
private val viewBinder: (View) -> T,
1313
private val disposeEvents: T.() -> Unit = {}
14-
) : ReadOnlyProperty<Fragment, T>, LifecycleObserver {
14+
) : ReadOnlyProperty<Fragment, T>, DefaultLifecycleObserver {
1515

16-
private inline fun Fragment.observeLifecycleOwnerThroughLifecycleCreation(crossinline viewOwner: LifecycleOwner.() -> Unit) {
16+
private inline fun Fragment.observeLifecycleOwnerThroughLifecycleCreation(
17+
crossinline viewOwner: LifecycleOwner.() -> Unit
18+
) {
1719
lifecycle.addObserver(object : DefaultLifecycleObserver {
1820
override fun onCreate(owner: LifecycleOwner) {
1921
viewLifecycleOwnerLiveData.observe(
@@ -28,8 +30,12 @@ class FragmentViewBindingDelegate<T : ViewBinding>(
2830

2931
private var fragmentBinding: T? = null
3032

31-
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
32-
fun disposeBinding() {
33+
override fun onDestroy(owner: LifecycleOwner) {
34+
disposeBinding()
35+
super.onDestroy(owner)
36+
}
37+
38+
private fun disposeBinding() {
3339
fragmentBinding?.disposeEvents()
3440
fragmentBinding = null
3541
}

app/src/main/java/com/monstarlab/arch/extensions/RepeatOnLifecycle.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ public fun LifecycleOwner.addRepeatingJob(
8787
* again.
8888
* @param block The block to run when the lifecycle is at least in [state] state.
8989
*/
90+
@Suppress("LongMethod")
9091
public suspend fun Lifecycle.repeatOnLifecycle(
9192
state: Lifecycle.State,
9293
block: suspend CoroutineScope.() -> Unit
@@ -138,4 +139,4 @@ public suspend fun Lifecycle.repeatOnLifecycle(
138139
}
139140
}
140141
}
141-
}
142+
}

app/src/main/java/com/monstarlab/arch/extensions/UseCaseExtensions.kt renamed to app/src/main/java/com/monstarlab/arch/extensions/UseCaseResult.kt

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ suspend inline fun <T> safeUseCase(
2323
UseCaseResult.Error(e.toError())
2424
}
2525

26+
@Suppress("TooGenericExceptionCaught")
2627
inline fun <T> useCaseFlow(
2728
crossinline block: suspend () -> T,
2829
): Flow<UseCaseResult<T>> = flow {
@@ -36,25 +37,28 @@ inline fun <T> useCaseFlow(
3637
}
3738
}
3839

39-
fun <T> observableFlow(block: suspend FlowCollector<T>.() -> Unit): Flow<UseCaseResult<T>> = flow(block)
40-
.catch { exception ->
41-
Timber.e(exception)
42-
UseCaseResult.Error(exception.toError())
43-
}
44-
.map {
45-
UseCaseResult.Success(it)
46-
}
40+
fun <T> observableFlow(block: suspend FlowCollector<T>.() -> Unit): Flow<UseCaseResult<T>> =
41+
flow(block)
42+
.catch { exception ->
43+
Timber.e(exception)
44+
UseCaseResult.Error(exception.toError())
45+
}
46+
.map {
47+
UseCaseResult.Success(it)
48+
}
4749

48-
fun <T> Flow<UseCaseResult<T>>.onSuccess(action: suspend (T) -> Unit): Flow<UseCaseResult<T>> = transform { result ->
49-
if (result is UseCaseResult.Success<T>) {
50-
action(result.value)
50+
fun <T> Flow<UseCaseResult<T>>.onSuccess(action: suspend (T) -> Unit): Flow<UseCaseResult<T>> =
51+
transform { result ->
52+
if (result is UseCaseResult.Success<T>) {
53+
action(result.value)
54+
}
55+
return@transform emit(result)
5156
}
52-
return@transform emit(result)
53-
}
5457

55-
fun <T> Flow<UseCaseResult<T>>.onError(action: suspend (ErrorModel) -> Unit): Flow<UseCaseResult<T>> = transform { result ->
56-
if (result is UseCaseResult.Error) {
57-
action(result.error)
58+
fun <T> Flow<UseCaseResult<T>>.onError(action: suspend (ErrorModel) -> Unit): Flow<UseCaseResult<T>> =
59+
transform { result ->
60+
if (result is UseCaseResult.Error) {
61+
action(result.error)
62+
}
63+
return@transform emit(result)
5864
}
59-
return@transform emit(result)
60-
}
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.monstarlab.core.data.network.dtos
22

3+
import kotlinx.serialization.SerialName
34
import kotlinx.serialization.Serializable
45

56
@Serializable
@@ -8,5 +9,6 @@ data class ResourceDto(
89
val name: String,
910
val year: Int,
1011
val color: String,
11-
val pantone_value: String
12+
@SerialName("pantone_value")
13+
val pantoneValue: String
1214
)

app/src/main/java/com/monstarlab/core/data/network/dtos/ResourceMapping.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@ fun ResourceDto.toEntity(): Resource {
88
name = name,
99
year = year,
1010
color = color,
11-
pantoneValue = pantone_value
11+
pantoneValue = pantoneValue
1212
)
1313
}
Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
package com.monstarlab.core.data.network.dtos
22

3+
import kotlinx.serialization.SerialName
34
import kotlinx.serialization.Serializable
45

56
@Serializable
67
data class UserDto(
78
val id: Int,
89
val email: String,
9-
val first_name: String,
10-
val last_name: String,
10+
@SerialName("first_name")
11+
val firstName: String,
12+
@SerialName("last_name")
13+
val lastName: String,
1114
val avatar: String
1215
)

app/src/main/java/com/monstarlab/core/data/network/dtos/UserMapping.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import com.monstarlab.core.domain.model.User
55
fun UserDto.toUser(): User {
66
return User(
77
email = email,
8-
firstName = first_name,
9-
lastName = last_name,
8+
firstName = firstName,
9+
lastName = lastName,
1010
avatar = avatar
1111
)
1212
}
Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
package com.monstarlab.core.data.network.responses
22

33
import com.monstarlab.core.data.network.dtos.ResourceDto
4+
import kotlinx.serialization.SerialName
45
import kotlinx.serialization.Serializable
56

67
@Serializable
78
data class ResourcesResponse(
89
val page: Int,
9-
val per_page: Int,
10+
@SerialName("per_page")
11+
val perPage: Int,
1012
val total: Int,
11-
val total_pages: Int,
13+
@SerialName("total_pages")
14+
val totalPages: Int,
1215
val data: List<ResourceDto>
1316
)

app/src/main/java/com/monstarlab/core/domain/error/ErrorMapping.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import java.io.IOException
66
import java.net.SocketTimeoutException
77
import java.net.UnknownHostException
88

9+
@Suppress("MagicNumber")
910
fun <T> Response<T>.toError(): ErrorModel.Http {
1011
return when {
1112
code() == 400 -> ErrorModel.Http.BadRequest

app/src/main/java/com/monstarlab/core/domain/mock/MockFlows.kt

Lines changed: 0 additions & 21 deletions
This file was deleted.

app/src/main/java/com/monstarlab/core/domain/mock/MockSuspends.kt

Lines changed: 0 additions & 11 deletions
This file was deleted.

app/src/main/java/com/monstarlab/core/sharedui/errorhandling/ViewErrorController.kt

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@ import com.google.android.material.snackbar.Snackbar
77
import com.monstarlab.core.domain.error.ErrorModel
88
import javax.inject.Inject
99

10-
fun Fragment.showErrorDialog(error: ViewError, cancelable: Boolean = true, dismissAction: (() -> Unit)? = null) {
10+
fun Fragment.showErrorDialog(
11+
error: ViewError,
12+
cancelable: Boolean = true,
13+
dismissAction: (() -> Unit)? = null
14+
) {
1115
val builder = AlertDialog.Builder(requireContext())
1216
builder.setTitle(error.title)
1317
builder.setMessage(error.message)
@@ -26,7 +30,12 @@ fun Fragment.showErrorDialog(error: ViewError, cancelable: Boolean = true, dismi
2630
}
2731
}
2832

29-
fun Fragment.showErrorSnackbar(view: View, error: ViewError, showAction: Boolean = false, dismissAction: (() -> Unit)? = null) {
33+
fun Fragment.showErrorSnackbar(
34+
view: View,
35+
error: ViewError,
36+
showAction: Boolean = false,
37+
dismissAction: (() -> Unit)? = null,
38+
) {
3039
val showLength = if (showAction) Snackbar.LENGTH_INDEFINITE else Snackbar.LENGTH_LONG
3140
val snackbar = Snackbar.make(view, error.message, showLength)
3241
if (showAction) {
@@ -41,6 +50,7 @@ fun Fragment.showErrorSnackbar(view: View, error: ViewError, showAction: Boolean
4150
}
4251
}
4352

53+
@Suppress("LongMethod")
4454
fun ErrorModel.mapToViewError(): ViewError {
4555
return when (this) {
4656
is ErrorModel.Http.Forbidden,

app/src/main/java/com/monstarlab/features/login/LoginFragment.kt

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,7 @@ import androidx.lifecycle.viewErrorFlow
1010
import androidx.navigation.fragment.findNavController
1111
import androidx.transition.TransitionManager
1212
import com.monstarlab.R
13-
import com.monstarlab.arch.extensions.collectFlow
14-
import com.monstarlab.arch.extensions.onClick
15-
import com.monstarlab.arch.extensions.snackErrorFlow
16-
import com.monstarlab.arch.extensions.viewBinding
17-
import com.monstarlab.arch.extensions.visibilityFlow
13+
import com.monstarlab.arch.extensions.*
1814
import com.monstarlab.databinding.FragmentLoginBinding
1915
import dagger.hilt.android.AndroidEntryPoint
2016

@@ -26,26 +22,32 @@ class LoginFragment : Fragment(R.layout.fragment_login) {
2622

2723
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
2824
super.onViewCreated(view, savedInstanceState)
25+
bindEvent()
26+
collectFlows()
27+
}
2928

29+
private fun bindEvent() {
3030
binding.loginButton.onClick {
3131
viewModel.login(
3232
binding.loginEmailEditText.text.toString(),
3333
binding.loginPasswordEditText.text.toString()
3434
)
3535
}
36+
}
3637

38+
private fun collectFlows() {
3739
collectFlow(viewModel.loginResultFlow) {
3840
findNavController().navigate(R.id.resourceFragment)
3941
}
4042

41-
snackErrorFlow(viewModel.viewErrorFlow, view)
42-
visibilityFlow(viewModel.loadingFlow, binding.loginProgressBar)
43-
4443
collectFlow(viewModel.loadingFlow) { loading ->
4544
TransitionManager.beginDelayedTransition(binding.root)
4645
binding.loginEmailEditText.isEnabled = !loading
4746
binding.loginPasswordEditText.isEnabled = !loading
4847
binding.loginButton.isVisible = !loading
4948
}
49+
50+
snackErrorFlow(viewModel.viewErrorFlow, binding.root)
51+
visibilityFlow(viewModel.loadingFlow, binding.loginProgressBar)
5052
}
5153
}

0 commit comments

Comments
 (0)