Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions compose/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -51,16 +51,17 @@ kover {
classes(
"com.naturecurly.deck.compose.DeckKt",
"com.naturecurly.deck.compose.DeckComposeContainerUi",
"com.naturecurly.deck.compose.DeckInitializer",
"com.naturecurly.deck.compose.DeckScope",
"com.naturecurly.deck.compose.DeckScopeImpl",
"com.naturecurly.deck.compose.di.*",
"hilt_aggregated_deps.*",
)
}
}
verify {
rule {
minBound(95, CoverageUnit.LINE)
minBound(80, CoverageUnit.BRANCH)
minBound(75, CoverageUnit.BRANCH)
}
}
}
Expand All @@ -69,7 +70,6 @@ kover {
dependencies {
api(projects.core)
implementation(platform(libs.androidx.compose.bom))
implementation(libs.androidx.compose.runtime)
implementation(libs.androidx.compose.ui)
implementation(libs.hilt)
ksp(libs.hilt.compiler)
Expand Down
16 changes: 0 additions & 16 deletions compose/src/main/AndroidManifest.xml

This file was deleted.

17 changes: 5 additions & 12 deletions compose/src/main/java/com/naturecurly/deck/compose/WharfImpl.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@
package com.naturecurly.deck.compose

import android.app.Application
import android.content.Context
import com.naturecurly.deck.DeckContainer
import com.naturecurly.deck.DeckProvider
import com.naturecurly.deck.Wharf
import com.naturecurly.deck.compose.log.DeckLog
Expand All @@ -34,36 +32,31 @@ import kotlin.reflect.KClass
class WharfImpl : Wharf() {
private var application: Application? = null

// synchronizedMap is used to make the map thread-safe?
private val entryPoints: MutableMap<Class<*>, Class<out DeckDependencies>> = mutableMapOf()

internal fun init(context: Context) {
internal fun init(app: Application) {
entryPoints.clear()
deckEntry.clear()
runCatching {
entryPoints.putAll(
EntryPoints.get(context, DeckDependenciesEntryPoint::class.java).dependencies(),
EntryPoints.get(app, DeckDependenciesEntryPoint::class.java).dependencies(),
)
}.onFailure {
DeckLog.e("WharfImpl initialization failed", it)
return
}
if (context is Application) {
application = context
} else {
DeckLog.w("Context is not an instance of Application")
}
application = app
}

@Suppress("UNCHECKED_CAST")
override fun <INPUT> registerNewProvider(
override fun registerNewProvider(
providerClass: KClass<out DeckProvider<*>>,
providerIdentity: Int,
) {
entryPoints[providerClass.java]?.let { dep ->
application?.let { app ->
val dependencies = EntryPoints.get(app, dep)
val containers = dependencies.containers() as Set<DeckContainer<INPUT, *>>
val containers = dependencies.containers()
deckEntry.addProvider(providerIdentity)
containers.forEach {
deckEntry.addContainer(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,29 @@
* SOFTWARE.
*/

package com.naturecurly.deck
package com.naturecurly.deck.compose.di

internal object WharfLocal {
private lateinit var wharf: Wharf
internal fun init(wharf: Wharf) {
this.wharf = wharf
import android.app.Application
import com.naturecurly.deck.Wharf
import com.naturecurly.deck.WharfAccess
import com.naturecurly.deck.WharfAccessImpl
import com.naturecurly.deck.compose.WharfImpl
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton

@Module
@InstallIn(SingletonComponent::class)
class WharfModule {
@Provides
@Singleton
fun provideWharf(app: Application): Wharf = WharfImpl().apply {
init(app)
}

internal fun get() = wharf
@Provides
@Singleton
fun provideWharfAccess(wharf: Wharf): WharfAccess = WharfAccessImpl(wharf)
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,14 @@
package com.naturecurly.deck.compose

import android.app.Application
import android.content.Context
import android.util.Log
import com.naturecurly.deck.ContainerEvent
import com.naturecurly.deck.DeckContainer
import com.naturecurly.deck.DeckContainerUi
import com.naturecurly.deck.DeckProvider
import com.naturecurly.deck.Wharf
import com.naturecurly.deck.WharfAccess
import com.naturecurly.deck.WharfAccessImpl
import com.naturecurly.deck.compose.log.DeckLog
import dagger.hilt.EntryPoints
import io.mockk.every
Expand Down Expand Up @@ -92,30 +94,6 @@ class WharfImplTest {
verify { DeckLog.e(any(), any()) }
}

@Test
fun `verify WharfImpl with non Application context`() {
// Given
val mockedContext: Context = mockk(relaxed = true)
val entryPoints: DeckDependenciesEntryPoint = object : DeckDependenciesEntryPoint {
override fun dependencies(): Map<Class<*>, @JvmSuppressWildcards Class<out DeckDependencies>> {
return mapOf()
}
}
mockkStatic(EntryPoints::class)
every {
EntryPoints.get(
mockedContext,
DeckDependenciesEntryPoint::class.java,
)
} returns entryPoints
// When
val wharf = WharfImpl()
wharf.init(mockedContext)
// Then
verify(exactly = 0) { DeckLog.e(any(), any()) }
verify { DeckLog.w(any()) }
}

@Test
fun `verify WharfImpl registerNewProvider`() {
// Given
Expand All @@ -142,7 +120,7 @@ class WharfImplTest {
// When
val wharf = WharfImpl()
wharf.init(mockedContext)
wharf.registerNewProvider<String>(DeckProviderTest::class, 123)
wharf.registerNewProvider(DeckProviderTest::class, 123)
// Then
verify(exactly = 0) { DeckLog.e(any(), any()) }
verify(exactly = 0) { DeckLog.w(any()) }
Expand All @@ -153,10 +131,12 @@ class WharfImplTest {
// Given
// When
val wharf = WharfImpl()
wharf.registerNewProvider<String>(DeckProviderTest::class, 123)
wharf.registerNewProvider(DeckProviderTest::class, 123)
}

class DeckProviderTest : DeckProvider<String> {
class DeckProviderTest(wharf: Wharf) :
DeckProvider<String>,
WharfAccess by WharfAccessImpl(wharf) {
override fun onContainerEvent(containerEvent: ContainerEvent) {
}
}
Expand Down
10 changes: 5 additions & 5 deletions core/src/main/java/com/naturecurly/deck/DeckProvider.kt
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,14 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.launch

interface DeckProvider<OUTPUT> {
interface DeckProvider<OUTPUT> : WharfAccess {
private val containers: Set<DeckContainer<OUTPUT, *>>
get() = WharfLocal.get().getDeckContainers(System.identityHashCode(this))
get() = getDeckContainers(System.identityHashCode(this))
val containerUis: Map<String, DeckContainerUi<*, *>>
get() = WharfLocal.get().getDeckContainerUis(System.identityHashCode(this))
get() = getDeckContainerUis(System.identityHashCode(this))

fun initDeckProvider(scope: CoroutineScope) {
WharfLocal.get().registerNewProvider<OUTPUT>(this::class, System.identityHashCode(this))
registerNewProvider<OUTPUT>(this::class, System.identityHashCode(this))
containers.forEach { it.init(scope) }
val containersFlow = merge(*(containers.map { it.containerEventFlow }.toTypedArray()))
scope.launch {
Expand All @@ -50,6 +50,6 @@ interface DeckProvider<OUTPUT> {
fun onContainerEvent(containerEvent: ContainerEvent)

fun onDeckClear() {
WharfLocal.get().clearProvider(System.identityHashCode(this))
clearProvider(System.identityHashCode(this))
}
}
12 changes: 7 additions & 5 deletions core/src/main/java/com/naturecurly/deck/Wharf.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,11 @@
package com.naturecurly.deck

import com.naturecurly.deck.model.DeckEntry
import kotlin.reflect.KClass

abstract class Wharf : ProviderRegister {
abstract class Wharf {
protected val deckEntry = DeckEntry()

init {
WharfLocal.init(this)
}

internal fun <INPUT> getDeckContainers(
providerIdentity: Int,
): Set<DeckContainer<INPUT, *>> {
Expand All @@ -57,4 +54,9 @@ abstract class Wharf : ProviderRegister {
internal fun clearProvider(providerIdentity: Int) {
deckEntry.clearProvider(providerIdentity)
}

abstract fun registerNewProvider(
providerClass: KClass<out DeckProvider<*>>,
providerIdentity: Int,
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,13 @@ package com.naturecurly.deck

import kotlin.reflect.KClass

interface ProviderRegister {
interface WharfAccess {
fun <INPUT> registerNewProvider(
providerClass: KClass<out DeckProvider<*>>,
providerIdentity: Int,
)

fun <INPUT> getDeckContainers(providerIdentity: Int): Set<DeckContainer<INPUT, *>>
fun getDeckContainerUis(providerIdentity: Int): Map<String, DeckContainerUi<*, *>>
fun clearProvider(providerIdentity: Int)
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,27 @@
* SOFTWARE.
*/

package com.naturecurly.deck.compose
package com.naturecurly.deck

import android.content.Context
import androidx.startup.Initializer
import kotlin.reflect.KClass

class DeckInitializer : Initializer<WharfImpl> {
override fun create(context: Context): WharfImpl =
WharfImpl().apply {
init(context)
}
class WharfAccessImpl(private val wharf: Wharf) : WharfAccess {
override fun <INPUT> getDeckContainers(providerIdentity: Int): Set<DeckContainer<INPUT, *>> {
return wharf.getDeckContainers<INPUT>(providerIdentity)
}

override fun dependencies(): List<Class<out Initializer<*>?>?> = emptyList()
override fun getDeckContainerUis(providerIdentity: Int): Map<String, DeckContainerUi<*, *>> {
return wharf.getDeckContainerUis(providerIdentity)
}

override fun clearProvider(providerIdentity: Int) {
return wharf.clearProvider(providerIdentity)
}

override fun <INPUT> registerNewProvider(
providerClass: KClass<out DeckProvider<*>>,
providerIdentity: Int,
) {
wharf.registerNewProvider(providerClass, providerIdentity)
}
}
10 changes: 5 additions & 5 deletions core/src/test/kotlin/com/naturecurly/deck/DeckProviderTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,13 @@ class DeckProviderTest {

@Before
fun setUp() {
every { wharf.registerNewProvider<String>(any(), any()) } just runs
every { wharf.registerNewProvider(any(), any()) } just runs
every { wharf.getDeckContainers<String>(any()) } returns setOf(mockedContainer)
every { wharf.getDeckContainerUis(any()) } returns mapOf("1" to mockedContainerUi)
every { wharf.clearProvider(any()) } just runs
every { mockedContainer.init(any()) } just runs
every { mockedContainer.onDataReady(any(), any()) } just runs
every { mockedContainer.containerEventFlow } returns mockedContainerEventFlow
WharfLocal.init(wharf)
}

@Test
Expand All @@ -68,7 +67,7 @@ class DeckProviderTest {
provider.initDeckProvider(testScope)
mockedContainerEventFlow.emit(RefreshProvider)
// Then
verify { wharf.registerNewProvider<String>(provider::class, any()) }
verify { wharf.registerNewProvider(provider::class, any()) }
verify { mockedContainer.init(testScope) }
assertThat(events.first()).isEqualTo(RefreshProvider)
}
Expand All @@ -90,7 +89,7 @@ class DeckProviderTest {
provider.initDeckProvider(testScope)
provider.onDeckReady(testScope, "test")
// Then
verify { wharf.registerNewProvider<String>(provider::class, any()) }
verify { wharf.registerNewProvider(provider::class, any()) }
verify { mockedContainer.init(testScope) }
verify { mockedContainer.onDataReady(testScope, "test") }
}
Expand All @@ -105,7 +104,8 @@ class DeckProviderTest {
}

private fun getDeckProvider(eventList: MutableList<ContainerEvent> = mutableListOf()): DeckProvider<String> {
val provider = object : DeckProvider<String> {
val mockedWharfAccess: WharfAccess = WharfAccessImpl(wharf)
val provider = object : DeckProvider<String>, WharfAccess by mockedWharfAccess {
override fun onContainerEvent(containerEvent: ContainerEvent) {
eventList.add(containerEvent)
}
Expand Down
17 changes: 4 additions & 13 deletions core/src/test/kotlin/com/naturecurly/deck/WharfTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class WharfTest {
listOf(mockContainerUiToContainerPairOne, mockContainerUiToContainerPairTwo),
)
// When
wharfImpl.registerNewProvider<Any>(providerClass, 123)
wharfImpl.registerNewProvider(providerClass, 123)
val containers = wharfImpl.getDeckContainers<Any>(providerIdentity = 123)
// Then
assertThat(containers).isNotEmpty()
Expand All @@ -59,7 +59,7 @@ class WharfTest {
listOf(mockContainerUiToContainerPairOne, mockContainerUiToContainerPairTwo),
)
// When
wharfImpl.registerNewProvider<Any>(providerClass, 123)
wharfImpl.registerNewProvider(providerClass, 123)
val containers = wharfImpl.getDeckContainers<Any>(providerIdentity = 123)
var containerUis = wharfImpl.getDeckContainerUis(123, filterDisabled = false)
// Then
Expand Down Expand Up @@ -94,7 +94,7 @@ class WharfTest {
listOf(mockContainerUiToContainerPairOne, mockContainerUiToContainerPairTwo),
)
// When
wharfImpl.registerNewProvider<Any>(providerClass, 123)
wharfImpl.registerNewProvider(providerClass, 123)
val containers = wharfImpl.getDeckContainers<Any>(providerIdentity = 123)
wharfImpl.clearProvider(123)
// Then
Expand All @@ -103,17 +103,8 @@ class WharfTest {
assertThat(wharfImpl.getDeckContainerUis(123, filterDisabled = false)).isEmpty()
}

@Test
fun `verify WharfLocal`() {
// Given
val wharfImpl = WharfTest(listOf())
val actual = WharfLocal.get()
// Then
assertThat(actual).isEqualTo(wharfImpl)
}

class WharfTest(private val containerContainerUiPairs: List<Pair<DeckContainerUi<*, *>, DeckContainer<*, *>>>) : Wharf() {
override fun <INPUT> registerNewProvider(
override fun registerNewProvider(
providerClass: KClass<out DeckProvider<*>>,
providerIdentity: Int,
) {
Expand Down
Loading