Skip to content

Commit

Permalink
Prepare Circuit in a more DI framework consistent fashion (#1154)
Browse files Browse the repository at this point in the history
* Prepare Circuit in a more DI framework consistent fashion

* Restore fully drawn reporting

* Remove unused imports

---------

Co-authored-by: Ashley Davies <[email protected]>
  • Loading branch information
ashdavies and ashdavies authored Sep 5, 2024
1 parent 9e88594 commit 2350250
Show file tree
Hide file tree
Showing 20 changed files with 155 additions and 229 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package io.ashdavies.playground

import android.content.Context
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext
import com.slack.circuit.foundation.CircuitCompositionLocals
import com.slack.circuit.foundation.NavigableCircuitContent
Expand All @@ -22,9 +21,9 @@ internal fun LauncherApp(context: Context = LocalContext.current, extra: (String
}
},
) {
CircuitCompositionLocals(remember { Circuit(context) }) {
ContentWithOverlays {
LauncherContent(context) {
LauncherContent(context) {
CircuitCompositionLocals(rememberCircuit(context)) {
ContentWithOverlays {
val backStack = rememberSaveableBackStack(extra("route"))

NavigableCircuitContent(
Expand Down
3 changes: 2 additions & 1 deletion app-launcher/common/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@ kotlin {
commonMain.dependencies {
implementation(projects.analytics)
implementation(projects.appCheck.appCheckClient)
implementation(projects.circuitSupport)
implementation(projects.composeMaterial)
implementation(projects.dominionApp)
implementation(projects.httpClient)
implementation(projects.identityManager)
implementation(projects.mapRoutes)
implementation(projects.platformScaffold)
implementation(projects.platformSupport)
implementation(projects.sqlCompose)
implementation(projects.sqlDriver)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,40 @@
package io.ashdavies.playground

import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import com.slack.circuit.foundation.Circuit
import com.slack.circuit.runtime.presenter.presenterOf
import io.ashdavies.common.PlaygroundDatabase
import io.ashdavies.content.PlatformContext
import io.ashdavies.dominion.dominionPresenterFactory
import io.ashdavies.dominion.dominionUiFactory
import io.ashdavies.routes.routePresenterFactory
import io.ashdavies.routes.routeUiFactory
import io.ashdavies.content.reportFullyDrawn
import io.ashdavies.dominion.addDominionBoxSetDetailsPresenter
import io.ashdavies.dominion.addDominionBoxSetDetailsUi
import io.ashdavies.dominion.addDominionBoxSetListPresenter
import io.ashdavies.dominion.addDominionBoxSetListUi
import io.ashdavies.http.LocalHttpClient
import io.ashdavies.routes.addRoutePresenter
import io.ashdavies.routes.addRouteUi
import io.ashdavies.sql.LocalTransacter
import io.ktor.client.HttpClient

public fun Circuit(context: PlatformContext): Circuit = Circuit.Builder()
.addPresenterFactories(getPresenterFactories(context))
.addUiFactories(getUiFactories(context))
.build()

private fun getPresenterFactories(context: PlatformContext) = listOf(
dominionPresenterFactory(),
launcherPresenterFactory(),
routePresenterFactory(context),
)

private fun getUiFactories(context: PlatformContext) = listOf(
dominionUiFactory(),
launcherUiFactory(),
routeUiFactory(context),
)
@Composable
public fun rememberCircuit(
platformContext: PlatformContext,
playgroundDatabase: PlaygroundDatabase = LocalTransacter.current as PlaygroundDatabase,
httpClient: HttpClient = LocalHttpClient.current,
): Circuit = remember(platformContext) {
Circuit.Builder()
.addPresenter<LauncherScreen, LauncherScreen.State> { _, navigator, _ ->
presenterOf { LauncherPresenter(navigator) }
}
.addDominionBoxSetListPresenter(playgroundDatabase, httpClient)
.addDominionBoxSetDetailsPresenter(playgroundDatabase, httpClient)
.addRoutePresenter(platformContext)
.addUi<LauncherScreen, LauncherScreen.State> { state, modifier ->
LauncherScreen(state, modifier, platformContext::reportFullyDrawn)
}
.addDominionBoxSetListUi()
.addDominionBoxSetDetailsUi()
.addRouteUi()
.build()
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
Expand Down Expand Up @@ -61,6 +62,7 @@ internal object LauncherScreen : Parcelable, Screen {
internal fun LauncherScreen(
state: LauncherScreen.State,
modifier: Modifier = Modifier,
onFullyDrawn: () -> Unit,
) {
val eventSink = state.eventSink

Expand All @@ -80,6 +82,10 @@ internal fun LauncherScreen(
}
}
}

LaunchedEffect(Unit) {
onFullyDrawn()
}
}

@Composable
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package io.ashdavies.playground

import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Window
Expand Down Expand Up @@ -37,18 +36,18 @@ private class LauncherCommand : CliktCommand() {

@Composable
internal fun LauncherApp(route: String?, onClose: () -> Unit) {
val circuit = remember { Circuit(PlatformContext.Default) }
ProvideHttpClient(
config = {
install(DefaultRequest) {
header("User-Agent", System.getProperty("os.name"))
header("X-API-Key", BuildConfig.BROWSER_API_KEY)
}
},
) {
LauncherContent(PlatformContext.Default) {
val circuit = rememberCircuit(PlatformContext.Default)

CircuitCompositionLocals(circuit) {
ProvideHttpClient(
config = {
install(DefaultRequest) {
header("User-Agent", System.getProperty("os.name"))
header("X-API-Key", BuildConfig.BROWSER_API_KEY)
}
},
) {
LauncherContent(PlatformContext.Default) {
CircuitCompositionLocals(circuit) {
val backStack = rememberSaveableBackStack(route)

NavigableCircuitContent(
Expand Down

This file was deleted.

17 changes: 0 additions & 17 deletions circuit-support/src/commonMain/kotlin/io/ashdavies/circuit/Ui.kt

This file was deleted.

2 changes: 0 additions & 2 deletions conferences-app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@ kotlin {
implementation(projects.analytics)
implementation(projects.appCheck.appCheckClient)
implementation(projects.asgService)
implementation(projects.circuitSupport)
implementation(projects.composeMaterial)
implementation(projects.httpClient)
implementation(projects.httpCommon)
Expand All @@ -99,7 +98,6 @@ kotlin {
implementation(projects.platformSupport)
implementation(projects.remoteConfig)
implementation(projects.sqlCommon)
implementation(projects.remoteConfig)
implementation(projects.sqlCompose)
implementation(projects.sqlDriver)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,16 +65,16 @@ private fun LauncherApp(context: Context = LocalContext.current) {
}
},
) {
CircuitCompositionLocals(rememberCircuit(context)) {
ContentWithOverlays {
ProvideAppCheckToken {
val transacter = rememberTransacter(
schema = PlaygroundDatabase.Schema,
context = context,
) { PlaygroundDatabase(it) }
ProvideAppCheckToken {
val transacter = rememberTransacter(
schema = PlaygroundDatabase.Schema,
context = context,
) { PlaygroundDatabase(it) }

ProvideTransacter(transacter) {
MaterialTheme(dynamicColorScheme()) {
ProvideTransacter(transacter) {
MaterialTheme(dynamicColorScheme()) {
CircuitCompositionLocals(rememberCircuit(context)) {
ContentWithOverlays {
val backStack = rememberSaveableBackStack(HomeScreen)

NavigableCircuitContent(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
package io.ashdavies.party.config

import androidx.compose.runtime.Composable
import androidx.compose.runtime.RememberObserver
import androidx.compose.runtime.Stable
import androidx.compose.runtime.remember
import androidx.paging.Pager
import com.slack.circuit.foundation.Circuit
import com.slack.circuit.retained.rememberRetained
import com.slack.circuit.runtime.presenter.presenterOf
import io.ashdavies.content.PlatformContext
import io.ashdavies.content.reportFullyDrawn
import io.ashdavies.identity.IdentityManager
import io.ashdavies.party.coroutines.rememberRetainedCoroutineScope
import io.ashdavies.party.events.EventsPresenter
import io.ashdavies.party.events.EventsScreen
import io.ashdavies.party.events.paging.rememberEventPager
Expand All @@ -22,14 +21,8 @@ import io.ashdavies.party.home.HomeScreen
import io.ashdavies.playground.PlaygroundDatabase
import io.ashdavies.sql.LocalTransacter
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.cancel
import kotlin.coroutines.CoroutineContext
import io.ashdavies.party.events.Event as DatabaseEvent

private const val COROUTINE_SCOPE = "COROUTINE_SCOPE"

@Composable
public fun rememberCircuit(
platformContext: PlatformContext,
Expand All @@ -51,7 +44,7 @@ public fun rememberCircuit(
presenterOf { GalleryPresenter(platformContext) }
}
.addUi<HomeScreen, HomeScreen.State> { state, modifier ->
HomeScreen(state, modifier)
HomeScreen(state, modifier, platformContext::reportFullyDrawn)
}
.addUi<EventsScreen, EventsScreen.State> { state, modifier ->
EventsScreen(state, modifier)
Expand All @@ -61,22 +54,3 @@ public fun rememberCircuit(
}
.build()
}

@Stable
private class StableCoroutineScope(scope: CoroutineScope) : CoroutineScope by scope

@Composable
private fun rememberRetainedCoroutineScope(
key: String = COROUTINE_SCOPE,
context: CoroutineContext = Dispatchers.Main.immediate,
): StableCoroutineScope = rememberRetained(key) {
val coroutineScope = StableCoroutineScope(CoroutineScope(context + Job()))
rememberObserver(coroutineScope::cancel)
coroutineScope
}

private fun rememberObserver(onForgotten: () -> Unit) = object : RememberObserver {
override fun onAbandoned() = onForgotten()
override fun onForgotten() = onForgotten()
override fun onRemembered() = Unit
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package io.ashdavies.party.coroutines

import androidx.compose.runtime.Composable
import androidx.compose.runtime.RememberObserver
import androidx.compose.runtime.Stable
import com.slack.circuit.retained.rememberRetained
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.cancel
import kotlin.coroutines.CoroutineContext

private const val COROUTINE_SCOPE = "COROUTINE_SCOPE"

@Stable
internal class StableCoroutineScope(scope: CoroutineScope) : CoroutineScope by scope

@Composable
internal fun rememberRetainedCoroutineScope(
context: CoroutineContext = Dispatchers.Main.immediate,
): StableCoroutineScope = rememberRetained(COROUTINE_SCOPE) {
val coroutineScope = StableCoroutineScope(CoroutineScope(context + Job()))
rememberObserver(coroutineScope::cancel)
coroutineScope
}

private fun rememberObserver(onForgotten: () -> Unit) = object : RememberObserver {
override fun onAbandoned() = onForgotten()
override fun onForgotten() = onForgotten()
override fun onRemembered() = Unit
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import androidx.compose.material3.TopAppBarDefaults.enterAlwaysScrollBehavior
import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.ColorFilter
Expand Down Expand Up @@ -62,6 +63,7 @@ internal object HomeScreen : Parcelable, Screen {
internal fun HomeScreen(
state: HomeScreen.State,
modifier: Modifier = Modifier,
onFullyDrawn: () -> Unit,
) {
val isProfileEnabled by booleanConfigAsState { isProfileEnabled() }
val isHomeEnabled by booleanConfigAsState { isHomeEnabled() }
Expand Down Expand Up @@ -103,6 +105,10 @@ internal fun HomeScreen(
},
)
}

LaunchedEffect(Unit) {
onFullyDrawn()
}
}

@Composable
Expand Down
2 changes: 0 additions & 2 deletions dominion-app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,8 @@ android {
kotlin {
sourceSets.commonMain.dependencies {
implementation(projects.analytics)
implementation(projects.circuitSupport)
implementation(projects.httpClient)
implementation(projects.pagingCompose)
implementation(projects.platformScaffold)
implementation(projects.platformSupport)
implementation(projects.sqlCommon)
implementation(projects.sqlCompose)
Expand Down
Loading

0 comments on commit 2350250

Please sign in to comment.