Skip to content

Commit

Permalink
refactor all (#174)
Browse files Browse the repository at this point in the history
* refactor(base)

* refactor(base)

* refactor(main): MainVM

* refactor(main): MainVM

* refactor(base)

* refactor(base): sealed interface

* refactor(add): viewmodel

* refactor(add): fix viewmodel

* refactor(add): vm

* refactor(add): fix tests

* refactor(main): MainVM

* refactor(main): MainVM

* refactor(add): vm

* refactor(search): vm

* refactor(search): fix tests

* done

* done

* rename

* validated nes

* fix tests

* fix tests

* fix tests

* rename
  • Loading branch information
hoc081098 authored Dec 12, 2022
1 parent 4212b1e commit 088697e
Show file tree
Hide file tree
Showing 44 changed files with 919 additions and 511 deletions.
3 changes: 3 additions & 0 deletions app/src/test/java/com/hoc/flowmvi/CheckModulesTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package com.hoc.flowmvi
import androidx.lifecycle.SavedStateHandle
import com.hoc.flowmvi.test_utils.TestCoroutineDispatcherRule
import io.mockk.every
import io.mockk.just
import io.mockk.mockk
import io.mockk.runs
import kotlin.test.Test
import kotlin.time.ExperimentalTime
import kotlinx.coroutines.ExperimentalCoroutinesApi
Expand All @@ -26,6 +28,7 @@ class CheckModulesTest : AutoCloseKoinTest() {
SavedStateHandle::class -> {
mockk<SavedStateHandle> {
every { get<Any?>(any()) } returns null
every { setSavedStateProvider(any(), any()) } just runs
}
}
else -> error("Unknown class: $clazz")
Expand Down
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ allprojects {
kotlinOptions {
val version = JavaVersion.VERSION_11.toString()
jvmTarget = version
languageVersion = "1.8"
}
}

Expand Down
31 changes: 31 additions & 0 deletions buildSrc/gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx2048m

# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
org.gradle.parallel=true

# Enable the Build Cache
org.gradle.caching=true

# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app's APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true

# Automatically convert third-party libraries to use AndroidX
android.enableJetifier=false

# Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official

# Enable Kotlin incremental compilation
kotlin.incremental=true
Binary file added buildSrc/gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
6 changes: 6 additions & 0 deletions buildSrc/gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-all.zip
networkTimeout=10000
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
1 change: 1 addition & 0 deletions buildSrc/src/main/kotlin/deps.kt
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ inline val PDsS.kotlinAndroid: PDS get() = id("kotlin-android")
inline val PDsS.kotlin: PDS get() = id("kotlin")
inline val PDsS.kotlinKapt: PDS get() = id("kotlin-kapt")
inline val PDsS.kotlinParcelize: PDS get() = id("kotlin-parcelize")
inline val PDsS.nocopyPlugin: PDS get() = id("dev.ahmedmourad.nocopy.nocopy-gradle-plugin")

inline val DependencyHandler.domain get() = project(":domain")
inline val DependencyHandler.core get() = project(":core")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.hoc.flowmvi.core_ui

import kotlin.coroutines.ContinuationInterceptor
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.currentCoroutineContext
import timber.log.Timber

suspend fun debugCheckImmediateMainDispatcher() {
if (BuildConfig.DEBUG) {
val interceptor = currentCoroutineContext()[ContinuationInterceptor]
Timber.d("debugCheckImmediateMainDispatcher: interceptor=$interceptor")

check(interceptor === Dispatchers.Main.immediate) {
"Expected ContinuationInterceptor to be Dispatchers.Main.immediate but was $interceptor"
}
}
}
3 changes: 2 additions & 1 deletion core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ java {
}

dependencies {
implementation(deps.coroutines.core)
api(deps.coroutines.core)
api(deps.arrow.core)
addUnitTest()
}
64 changes: 64 additions & 0 deletions core/src/main/java/com/hoc/flowmvi/core/NonEmptySet.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package com.hoc.flowmvi.core

/**
* `NonEmptySet` is a data type used to model sets that guarantee to have at least one value.
*/
class NonEmptySet<out T>
@Throws(IllegalArgumentException::class)
private constructor(val set: Set<T>) : AbstractSet<T>() {
init {
require(set.isNotEmpty()) { "Set must not be empty" }
require(set !is NonEmptySet<T>) { "Set must not be NonEmptySet" }
}

override val size: Int get() = set.size
override fun iterator(): Iterator<T> = set.iterator()
override fun isEmpty(): Boolean = false

operator fun plus(l: NonEmptySet<@UnsafeVariance T>): NonEmptySet<T> =
NonEmptySet(set + l.set)

@Suppress("RedundantOverride")
override fun equals(other: Any?): Boolean = super.equals(other)

@Suppress("RedundantOverride")
override fun hashCode(): Int = super.hashCode()

override fun toString(): String =
"NonEmptySet(${set.joinToString()})"

companion object {
/**
* Creates a [NonEmptySet] from the given [Collection].
* @return null if [this] is empty.
*/
@JvmStatic
fun <T> Collection<T>.toNonEmptySetOrNull(): NonEmptySet<T>? =
if (isEmpty()) null else NonEmptySet(toSet())

/**
* Creates a [NonEmptySet] from the given [Set].
* @return null if [this] is empty.
*/
@JvmStatic
fun <T> Set<T>.toNonEmptySetOrNull(): NonEmptySet<T>? = (this as? NonEmptySet<T>)
?: if (isEmpty()) null else NonEmptySet(this)

/**
* Creates a [NonEmptySet] from the given values.
*/
@JvmStatic
fun <T> of(element: T, vararg elements: T): NonEmptySet<T> = NonEmptySet(
buildSet(capacity = 1 + elements.size) {
add(element)
addAll(elements)
}
)

/**
* Creates a [NonEmptySet] that contains only the specified [element].
*/
@JvmStatic
fun <T> of(element: T): NonEmptySet<T> = NonEmptySet(setOf(element))
}
}
22 changes: 22 additions & 0 deletions core/src/main/java/com/hoc/flowmvi/core/ValidatedNes.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.hoc.flowmvi.core

import arrow.core.Validated
import arrow.typeclasses.Semigroup

typealias ValidatedNes<E, A> = Validated<NonEmptySet<E>, A>

@Suppress("NOTHING_TO_INLINE")
inline fun <A> A.validNes(): ValidatedNes<Nothing, A> =
Validated.Valid(this)

@Suppress("NOTHING_TO_INLINE")
inline fun <E> E.invalidNes(): ValidatedNes<E, Nothing> =
Validated.Invalid(NonEmptySet.of(this))

object NonEmptySetSemigroup : Semigroup<NonEmptySet<Any?>> {
override fun NonEmptySet<Any?>.combine(b: NonEmptySet<Any?>): NonEmptySet<Any?> = this + b
}

@Suppress("UNCHECKED_CAST")
fun <T> Semigroup.Companion.nonEmptySet(): Semigroup<NonEmptySet<T>> =
NonEmptySetSemigroup as Semigroup<NonEmptySet<T>>
84 changes: 84 additions & 0 deletions core/src/main/java/com/hoc/flowmvi/core/selfReference.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package com.hoc.flowmvi.core

import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty

// Generic inline classes is an Experimental feature.
// It may be dropped or changed at any time.
// Opt-in is required with the -language-version 1.8 compiler option.
// See https://kotlinlang.org/docs/inline-classes.html for more information.
@JvmInline
value class SelfReference<T>(val value: T) : ReadOnlyProperty<Any?, T> {
override fun getValue(thisRef: Any?, property: KProperty<*>): T = value
}

/**
* A delegate that allows to reference the object itself.
* This is useful to avoid initialization order issues.
*
* This is a alternative way to:
* - `lateinit var` (mutable variables can be modified by mistake).
* - [lazy] (lazy evaluation is unnecessary in this case).
*
* NOTE: Do **NOT** access the value of the return delegate synchronously inside [initializer].
* Eg: `val x: Int by selfReferenced { x + 1 }` is a wrong usage, it will cause an exception.
*
* ### Example
* Below is an example of how to use it:
*
* ```kotlin
* import kotlinx.coroutines.flow.*
* import kotlinx.coroutines.*
*
* class Demo {
* private val trigger = MutableSharedFlow<Unit>()
* private val scope = CoroutineScope(Dispatchers.Default)
*
* val intStateFlow: StateFlow<Int?> by selfReferenced {
* merge(
* flow {
* var c = 0
* while (true) { emit(c++); delay(300) }
* },
* trigger.mapNotNull {
* println("access to $intStateFlow")
* intStateFlow.value?.minus(1)
* }
* )
* .stateIn(scope, SharingStarted.Eagerly, null)
* }
*
* fun trigger() = scope.launch { trigger.emit(Unit) }
* }
*
* fun main(): Unit = runBlocking {
* val demo = Demo()
* val job = demo.intStateFlow
* .onEach(::println)
* .launchIn(this)
*
* delay(1_000)
* demo.trigger()
*
* delay(500)
* demo.trigger()
*
* delay(500)
* job.cancel()
*
* // null
* // 0
* // 1
* // 2
* // 3
* // access to kotlinx.coroutines.flow.ReadonlyStateFlow@2cfeac11
* // 2
* // 4
* // access to kotlinx.coroutines.flow.ReadonlyStateFlow@2cfeac11
* // 3
* // 5
* // 6
* }
* ```
*/
fun <T> selfReferenced(initializer: () -> T) = SelfReference(initializer())
Loading

0 comments on commit 088697e

Please sign in to comment.