Skip to content

Commit 028b59f

Browse files
authored
:mvi-base -> :feature-main (#40)
* :mvi-base * implements * implements * refactor tests * up * up * up * addtests * addtests * addtests * addtests * addtests * add tests * add tests
1 parent 65cd63f commit 028b59f

File tree

37 files changed

+919
-163
lines changed

37 files changed

+919
-163
lines changed

.idea/gradle.xml

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ android {
1919
}
2020

2121
buildTypes {
22-
getByName("release") {
22+
release {
2323
isMinifyEnabled = true
2424
isShrinkResources = true
2525
proguardFiles(

build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ buildscript {
1111
}
1212
dependencies {
1313
classpath("com.android.tools.build:gradle:7.0.2")
14-
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion")
14+
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.30")
1515
classpath("com.diffplug.spotless:spotless-plugin-gradle:5.16.0")
1616
classpath("dev.ahmedmourad.nocopy:nocopy-gradle-plugin:1.4.0")
1717
classpath("org.jacoco:org.jacoco.core:0.8.7")

buildSrc/src/main/kotlin/deps.kt

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,14 @@ inline val DependencyHandler.data get() = project(":data")
9393
inline val DependencyHandler.featureMain get() = project(":feature-main")
9494
inline val DependencyHandler.featureAdd get() = project(":feature-add")
9595
inline val DependencyHandler.featureSearch get() = project(":feature-search")
96+
inline val DependencyHandler.mviBase get() = project(":mvi-base")
97+
inline val DependencyHandler.mviTesting get() = project(":mvi-testing")
9698

97-
fun DependencyHandler.addUnitTest() {
98-
add("testImplementation", deps.test.junit)
99-
add("testImplementation", deps.test.mockk)
100-
add("testImplementation", deps.test.kotlinJUnit)
101-
add("testImplementation", deps.coroutines.test)
99+
fun DependencyHandler.addUnitTest(testImplementation: Boolean = true) {
100+
val configName = if (testImplementation) "testImplementation" else "implementation"
101+
102+
add(configName, deps.test.junit)
103+
add(configName, deps.test.mockk)
104+
add(configName, deps.test.kotlinJUnit)
105+
add(configName, deps.coroutines.test)
102106
}

core/build.gradle.kts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,11 @@ android {
1212
targetSdk = appConfig.targetSdkVersion
1313

1414
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
15+
consumerProguardFiles("consumer-rules.pro")
1516
}
1617

1718
buildTypes {
18-
getByName("release") {
19+
release {
1920
isMinifyEnabled = true
2021
proguardFiles(
2122
getDefaultProguardFile("proguard-android-optimize.txt"),
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package com.hoc.flowmvi.core
2+
3+
@Suppress("unused")
4+
inline val Any?.unit
5+
get() = Unit

data/build.gradle.kts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,11 @@ android {
1212
targetSdk = appConfig.targetSdkVersion
1313

1414
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
15+
consumerProguardFiles("consumer-rules.pro")
1516
}
1617

1718
buildTypes {
18-
getByName("release") {
19+
release {
1920
isMinifyEnabled = true
2021
proguardFiles(
2122
getDefaultProguardFile("proguard-android-optimize.txt"),

feature-add/build.gradle.kts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,11 @@ android {
1212
targetSdk = appConfig.targetSdkVersion
1313

1414
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
15+
consumerProguardFiles("consumer-rules.pro")
1516
}
1617

1718
buildTypes {
18-
getByName("release") {
19+
release {
1920
isMinifyEnabled = true
2021
proguardFiles(
2122
getDefaultProguardFile("proguard-android-optimize.txt"),
@@ -40,6 +41,7 @@ android {
4041
dependencies {
4142
implementation(domain)
4243
implementation(core)
44+
implementation(mviBase)
4345

4446
implementation(deps.androidx.appCompat)
4547
implementation(deps.androidx.coreKtx)

feature-main/build.gradle.kts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,11 @@ android {
1212
targetSdk = appConfig.targetSdkVersion
1313

1414
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
15+
consumerProguardFiles("consumer-rules.pro")
1516
}
1617

1718
buildTypes {
18-
getByName("release") {
19+
release {
1920
isMinifyEnabled = true
2021
proguardFiles(
2122
getDefaultProguardFile("proguard-android-optimize.txt"),
@@ -47,6 +48,7 @@ android {
4748
dependencies {
4849
implementation(domain)
4950
implementation(core)
51+
implementation(mviBase)
5052

5153
implementation(deps.androidx.appCompat)
5254
implementation(deps.androidx.coreKtx)
@@ -66,4 +68,5 @@ dependencies {
6668
implementation(deps.flowExt)
6769

6870
addUnitTest()
71+
testImplementation(mviTesting)
6972
}

feature-main/src/main/java/com/hoc/flowmvi/ui/main/MainActivity.kt

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import com.hoc.flowmvi.core.collectIn
1717
import com.hoc.flowmvi.core.navigator.Navigator
1818
import com.hoc.flowmvi.core.refreshes
1919
import com.hoc.flowmvi.core.toast
20+
import com.hoc.flowmvi.mvi_base.MviView
2021
import com.hoc.flowmvi.ui.main.databinding.ActivityMainBinding
2122
import com.hoc081098.viewbindingdelegate.viewBinding
2223
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -34,7 +35,9 @@ import org.koin.androidx.viewmodel.ext.android.viewModel
3435

3536
@FlowPreview
3637
@ExperimentalCoroutinesApi
37-
class MainActivity : AppCompatActivity(R.layout.activity_main) {
38+
class MainActivity :
39+
AppCompatActivity(R.layout.activity_main),
40+
MviView<ViewIntent, ViewState, SingleEvent> {
3841
private val mainVM by viewModel<MainVM>()
3942
private val navigator by inject<Navigator>()
4043

@@ -93,20 +96,19 @@ class MainActivity : AppCompatActivity(R.layout.activity_main) {
9396
.collectIn(this) { handleSingleEvent(it) }
9497

9598
// pass view intent to view model
96-
intents()
99+
viewIntents()
97100
.onEach { mainVM.processIntent(it) }
98101
.launchIn(lifecycleScope)
99102
}
100103

101-
@Suppress("NOTHING_TO_INLINE")
102-
private inline fun intents(): Flow<ViewIntent> = merge(
104+
override fun viewIntents(): Flow<ViewIntent> = merge(
103105
flowOf(ViewIntent.Initial),
104106
mainBinding.swipeRefreshLayout.refreshes().map { ViewIntent.Refresh },
105107
mainBinding.retryButton.clicks().map { ViewIntent.Retry },
106108
removeChannel.consumeAsFlow().map { ViewIntent.RemoveUser(it) }
107109
)
108110

109-
private fun handleSingleEvent(event: SingleEvent) {
111+
override fun handleSingleEvent(event: SingleEvent) {
110112
Log.d("MainActivity", "handleSingleEvent $event")
111113
return when (event) {
112114
SingleEvent.Refresh.Success -> toast("Refresh success")
@@ -117,7 +119,7 @@ class MainActivity : AppCompatActivity(R.layout.activity_main) {
117119
}
118120
}
119121

120-
private fun render(viewState: ViewState) {
122+
override fun render(viewState: ViewState) {
121123
Log.d("MainActivity", "render $viewState")
122124

123125
userAdapter.submitList(viewState.userItems)

feature-main/src/main/java/com/hoc/flowmvi/ui/main/MainContract.kt

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
package com.hoc.flowmvi.ui.main
22

33
import com.hoc.flowmvi.domain.entity.User
4+
import com.hoc.flowmvi.mvi_base.MviIntent
5+
import com.hoc.flowmvi.mvi_base.MviSingleEvent
6+
import com.hoc.flowmvi.mvi_base.MviViewState
47

5-
internal data class UserItem(
8+
data class UserItem(
69
val id: String,
710
val email: String,
811
val avatar: String,
@@ -28,19 +31,19 @@ internal data class UserItem(
2831
)
2932
}
3033

31-
internal sealed interface ViewIntent {
34+
sealed interface ViewIntent : MviIntent {
3235
object Initial : ViewIntent
3336
object Refresh : ViewIntent
3437
object Retry : ViewIntent
3538
data class RemoveUser(val user: UserItem) : ViewIntent
3639
}
3740

38-
internal data class ViewState(
41+
data class ViewState(
3942
val userItems: List<UserItem>,
4043
val isLoading: Boolean,
4144
val error: Throwable?,
4245
val isRefreshing: Boolean
43-
) {
46+
) : MviViewState {
4447
companion object {
4548
fun initial() = ViewState(
4649
userItems = emptyList(),
@@ -100,7 +103,7 @@ internal sealed interface PartialChange {
100103
}
101104
}
102105

103-
internal sealed interface SingleEvent {
106+
sealed interface SingleEvent : MviSingleEvent {
104107
sealed interface Refresh : SingleEvent {
105108
object Success : Refresh
106109
data class Failure(val error: Throwable) : Refresh

feature-main/src/main/java/com/hoc/flowmvi/ui/main/MainVM.kt

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ package com.hoc.flowmvi.ui.main
33
import android.util.Log
44
import androidx.lifecycle.ViewModel
55
import androidx.lifecycle.viewModelScope
6+
import com.hoc.flowmvi.core.unit
67
import com.hoc.flowmvi.domain.usecase.GetUsersUseCase
78
import com.hoc.flowmvi.domain.usecase.RefreshGetUsersUseCase
89
import com.hoc.flowmvi.domain.usecase.RemoveUserUseCase
10+
import com.hoc.flowmvi.mvi_base.MviViewModel
911
import com.hoc081098.flowext.flatMapFirst
1012
import kotlinx.coroutines.ExperimentalCoroutinesApi
1113
import kotlinx.coroutines.FlowPreview
@@ -36,18 +38,17 @@ import kotlinx.coroutines.flow.take
3638
@Suppress("USELESS_CAST")
3739
@FlowPreview
3840
@ExperimentalCoroutinesApi
39-
internal class MainVM(
41+
class MainVM(
4042
private val getUsersUseCase: GetUsersUseCase,
4143
private val refreshGetUsers: RefreshGetUsersUseCase,
4244
private val removeUser: RemoveUserUseCase,
43-
) : ViewModel() {
45+
) : ViewModel(), MviViewModel<ViewIntent, ViewState, SingleEvent> {
4446
private val _eventChannel = Channel<SingleEvent>(Channel.BUFFERED)
4547
private val _intentFlow = MutableSharedFlow<ViewIntent>(extraBufferCapacity = 64)
4648

47-
val viewState: StateFlow<ViewState>
48-
val singleEvent: Flow<SingleEvent> get() = _eventChannel.receiveAsFlow()
49-
50-
fun processIntent(intent: ViewIntent) = _intentFlow.tryEmit(intent)
49+
override val viewState: StateFlow<ViewState>
50+
override val singleEvent: Flow<SingleEvent> get() = _eventChannel.receiveAsFlow()
51+
override fun processIntent(intent: ViewIntent) = _intentFlow.tryEmit(intent).unit
5152

5253
init {
5354
val initialVS = ViewState.initial()
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package com.hoc.flowmvi.ui.main
2+
3+
import com.hoc.flowmvi.domain.entity.User
4+
import kotlin.test.Test
5+
import kotlin.test.assertEquals
6+
7+
class MainContractTest {
8+
@Test
9+
fun test_userItem_equals() {
10+
assertEquals(
11+
UserItem(
12+
id = "0",
13+
email = "test@gmail.com",
14+
avatar = "avatar.png",
15+
firstName = "first",
16+
lastName = "last"
17+
),
18+
UserItem(
19+
id = "0",
20+
email = "test@gmail.com",
21+
avatar = "avatar.png",
22+
firstName = "first",
23+
lastName = "last"
24+
)
25+
)
26+
}
27+
28+
@Test
29+
fun test_userItem_hashCode() {
30+
assertEquals(
31+
UserItem(
32+
id = "0",
33+
email = "test@gmail.com",
34+
avatar = "avatar.png",
35+
firstName = "first",
36+
lastName = "last"
37+
).hashCode(),
38+
UserItem(
39+
id = "0",
40+
email = "test@gmail.com",
41+
avatar = "avatar.png",
42+
firstName = "first",
43+
lastName = "last"
44+
).hashCode()
45+
)
46+
}
47+
48+
@Test
49+
fun test_userItem_fullName() {
50+
assertEquals(
51+
UserItem(
52+
id = "0",
53+
email = "test@gmail.com",
54+
avatar = "avatar.png",
55+
firstName = "first",
56+
lastName = "last"
57+
).fullName,
58+
"first last",
59+
)
60+
}
61+
62+
@Test
63+
fun test_userItem_toDomain() {
64+
assertEquals(
65+
UserItem(
66+
id = "0",
67+
email = "test@gmail.com",
68+
avatar = "avatar.png",
69+
firstName = "first",
70+
lastName = "last"
71+
).toDomain(),
72+
User(
73+
id = "0",
74+
email = "test@gmail.com",
75+
firstName = "first",
76+
lastName = "last",
77+
avatar = "avatar.png",
78+
)
79+
)
80+
}
81+
82+
@Test
83+
fun test_userItem_fromDomain() {
84+
assertEquals(
85+
UserItem(
86+
domain = User(
87+
id = "0",
88+
email = "test@gmail.com",
89+
firstName = "first",
90+
lastName = "last",
91+
avatar = "avatar.png",
92+
)
93+
),
94+
UserItem(
95+
id = "0",
96+
email = "test@gmail.com",
97+
avatar = "avatar.png",
98+
firstName = "first",
99+
lastName = "last"
100+
),
101+
)
102+
}
103+
}

0 commit comments

Comments
 (0)