Update readme and build dependency graph

pull/1902/head
Clara Fok 4 weeks ago
parent 9985a029e6
commit a059e42612

@ -85,7 +85,6 @@ dependencies {
implementation(projects.core.data)
implementation(projects.core.model)
implementation(projects.core.analytics)
implementation(projects.core.navigation)
implementation(projects.sync.work)
implementation(libs.androidx.activity.compose)

@ -41,9 +41,9 @@ import com.google.samples.apps.nowinandroid.core.data.repository.UserNewsResourc
import com.google.samples.apps.nowinandroid.core.data.util.NetworkMonitor
import com.google.samples.apps.nowinandroid.core.data.util.TimeZoneMonitor
import com.google.samples.apps.nowinandroid.core.designsystem.theme.NiaTheme
import com.google.samples.apps.nowinandroid.core.ui.LocalTimeZone
import com.google.samples.apps.nowinandroid.core.navigation.NiaBackStackViewModel
import com.google.samples.apps.nowinandroid.core.navigation.NiaNavKey
import com.google.samples.apps.nowinandroid.core.ui.LocalTimeZone
import com.google.samples.apps.nowinandroid.ui.NiaApp
import com.google.samples.apps.nowinandroid.ui.rememberNiaAppState
import com.google.samples.apps.nowinandroid.util.isSystemInDarkTheme
@ -160,7 +160,7 @@ class MainActivity : ComponentActivity() {
) {
NiaApp(
appState,
entryProviderBuilders
entryProviderBuilders,
)
}
}

@ -44,8 +44,8 @@ object BackStackProvider {
@Provides
@Singleton
fun provideSerializersModule(
polymorphicModuleBuilders: Set<@JvmSuppressWildcards PolymorphicModuleBuilder<NiaNavKey>.() -> Unit>
) : SerializersModule = SerializersModule {
polymorphicModuleBuilders: Set<@JvmSuppressWildcards PolymorphicModuleBuilder<NiaNavKey>.() -> Unit>,
): SerializersModule = SerializersModule {
polymorphic(NiaNavKey::class) {
polymorphicModuleBuilders.forEach { it() }
}

@ -49,7 +49,7 @@ enum class TopLevelDestination(
@StringRes val iconTextId: Int,
@StringRes val titleTextId: Int,
val route: KClass<*>,
val key: NiaNavKey
val key: NiaNavKey,
) {
FOR_YOU(
selectedIcon = NiaIcons.Upcoming,
@ -57,7 +57,7 @@ enum class TopLevelDestination(
iconTextId = forYouR.string.feature_foryou_api_title,
titleTextId = R.string.app_name,
route = ForYouRoute::class,
key = ForYouRoute
key = ForYouRoute,
),
BOOKMARKS(
selectedIcon = NiaIcons.Bookmarks,
@ -65,7 +65,7 @@ enum class TopLevelDestination(
iconTextId = bookmarksR.string.feature_bookmarks_api_title,
titleTextId = bookmarksR.string.feature_bookmarks_api_title,
route = BookmarksRoute::class,
key = BookmarksRoute
key = BookmarksRoute,
),
INTERESTS(
selectedIcon = NiaIcons.Grid3x3,
@ -73,7 +73,7 @@ enum class TopLevelDestination(
iconTextId = searchR.string.feature_search_api_interests,
titleTextId = searchR.string.feature_search_api_interests,
route = InterestsRoute::class,
key = InterestsRoute(null)
key = InterestsRoute(null),
),
}

@ -271,4 +271,4 @@ private fun Modifier.notificationDot(): Modifier =
),
)
}
}
}

@ -18,7 +18,6 @@ package com.google.samples.apps.nowinandroid.ui
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.snapshotFlow
@ -125,6 +124,6 @@ private fun NavigationTrackingSideEffect(niaBackStack: NiaBackStack) {
val stack = niaBackStack.backStack.toList()
metricsHolder.state?.putState("Navigation", stack.lastOrNull().toString())
}
onDispose { }
onDispose { }
}
}
}

@ -125,7 +125,7 @@ class NiaAppScreenSizesScreenshotTests {
networkMonitor = networkMonitor,
userNewsResourceRepository = userNewsResourceRepository,
timeZoneMonitor = timeZoneMonitor,
niaBackStack = mockNiaBackStack()
niaBackStack = mockNiaBackStack(),
)
NiaApp(
fakeAppState,
@ -230,4 +230,4 @@ class NiaAppScreenSizesScreenshotTests {
"expandedWidth_expandedHeight_showsNavigationRail",
)
}
}
}

@ -145,4 +145,4 @@ class NiaAppStateTest {
state.currentTimeZone.value,
)
}
}
}

@ -213,7 +213,7 @@ class SnackbarInsetsScreenshotTests {
CompositionLocalProvider(
// Replaces images with placeholders
LocalInspectionMode provides true,
LocalSnackbarHostState provides snackbarHostState
LocalSnackbarHostState provides snackbarHostState,
) {
scope = rememberCoroutineScope()
@ -250,7 +250,7 @@ class SnackbarInsetsScreenshotTests {
networkMonitor = networkMonitor,
userNewsResourceRepository = userNewsResourceRepository,
timeZoneMonitor = timeZoneMonitor,
niaBackStack = mockNiaBackStack()
niaBackStack = mockNiaBackStack(),
)
NiaApp(
appState = appState,

@ -186,7 +186,7 @@ class SnackbarScreenshotTests {
CompositionLocalProvider(
// Replaces images with placeholders
LocalInspectionMode provides true,
LocalSnackbarHostState provides snackbarHostState
LocalSnackbarHostState provides snackbarHostState,
) {
scope = rememberCoroutineScope()
@ -200,7 +200,7 @@ class SnackbarScreenshotTests {
networkMonitor = networkMonitor,
userNewsResourceRepository = userNewsResourceRepository,
timeZoneMonitor = timeZoneMonitor,
niaBackStack = mockNiaBackStack()
niaBackStack = mockNiaBackStack(),
)
NiaApp(
appState = appState,

@ -26,12 +26,12 @@ import com.google.samples.apps.nowinandroid.feature.foryou.impl.ForYouScreen
val MockEntryProvider: Set<EntryProviderBuilder<NiaNavKey>.() -> Unit> =
setOf(
{
entry<ForYouRoute>{
entry<ForYouRoute> {
ForYouScreen({})
}
},
)
)
private val startKey = ForYouRoute
fun mockNiaBackStack() = NiaBackStack(startKey)
fun mockNiaBackStack() = NiaBackStack(startKey)

@ -0,0 +1,3 @@
# :benchmarks module
## Dependency graph
![Dependency graph](../docs/images/graphs/dep_graph_benchmarks.svg)

@ -28,7 +28,6 @@ class AndroidFeatureApiConventionPlugin : Plugin<Project> {
dependencies {
"api"(project(":core:navigation"))
"implementation"(project(":core:data"))
}
}
}

@ -0,0 +1,3 @@
# :core:navigation module
## Dependency graph
![Dependency graph](../../docs/images/graphs/dep_graph_core_navigation.svg)

@ -1,3 +1,19 @@
/*
* Copyright 2025 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
plugins {
alias(libs.plugins.nowinandroid.android.library)
alias(libs.plugins.nowinandroid.hilt)

@ -42,7 +42,6 @@ class NiaBackStackViewModelTest {
subclass(TestTopLevelKeySecond::class, TestTopLevelKeySecond.serializer())
subclass(TestKeyFirst::class, TestKeyFirst.serializer())
subclass(TestKeySecond::class, TestKeySecond.serializer())
}
}
@ -57,7 +56,8 @@ class NiaBackStackViewModelTest {
rule.setContent {
val viewModel = createViewModel()
assertThat(viewModel.backStackMap).containsEntry(
TestStartKey, mutableListOf(TestStartKey),
TestStartKey,
mutableListOf(TestStartKey),
)
}
}
@ -72,7 +72,8 @@ class NiaBackStackViewModelTest {
}
assertThat(viewModel.backStackMap).containsEntry(
TestStartKey, mutableListOf(TestStartKey, TestKeyFirst),
TestStartKey,
mutableListOf(TestStartKey, TestKeyFirst),
)
}
@ -87,8 +88,10 @@ class NiaBackStackViewModelTest {
}
assertThat(viewModel.backStackMap).containsExactly(
TestStartKey, mutableListOf(TestStartKey, TestKeyFirst),
TestTopLevelKeyFirst, mutableListOf(TestTopLevelKeyFirst),
TestStartKey,
mutableListOf(TestStartKey, TestKeyFirst),
TestTopLevelKeyFirst,
mutableListOf(TestTopLevelKeyFirst),
).inOrder()
}
@ -102,8 +105,10 @@ class NiaBackStackViewModelTest {
}
assertThat(viewModel.backStackMap).containsExactly(
TestStartKey, mutableListOf(TestStartKey, TestKeyFirst),
TestTopLevelKeyFirst, mutableListOf(TestTopLevelKeyFirst, TestKeySecond),
TestStartKey,
mutableListOf(TestStartKey, TestKeyFirst),
TestTopLevelKeyFirst,
mutableListOf(TestTopLevelKeyFirst, TestKeySecond),
).inOrder()
}
@ -115,12 +120,14 @@ class NiaBackStackViewModelTest {
backStack.navigate(TestKeyFirst)
assertThat(viewModel.backStackMap).containsExactly(
TestStartKey, mutableListOf(TestStartKey, TestKeyFirst),
TestStartKey,
mutableListOf(TestStartKey, TestKeyFirst),
)
backStack.popLast()
assertThat(viewModel.backStackMap).containsExactly(
TestStartKey, mutableListOf(TestStartKey),
TestStartKey,
mutableListOf(TestStartKey),
)
}
}
@ -141,7 +148,8 @@ class NiaBackStackViewModelTest {
rule.runOnIdle {
scenario.viewModel.niaBackStack.navigate(TestKeyFirst)
assertThat(scenario.viewModel.niaBackStack.backStack).containsExactly(
TestStartKey, TestKeyFirst,
TestStartKey,
TestKeyFirst,
).inOrder()
}
@ -149,7 +157,8 @@ class NiaBackStackViewModelTest {
rule.runOnIdle {
assertThat(scenario.viewModel.niaBackStack.backStack).containsExactly(
TestStartKey, TestKeyFirst,
TestStartKey,
TestKeyFirst,
).inOrder()
}
}
@ -173,7 +182,10 @@ class NiaBackStackViewModelTest {
scenario.viewModel.niaBackStack.navigate(TestKeySecond)
assertThat(scenario.viewModel.niaBackStack.backStack).containsExactly(
TestStartKey, TestKeyFirst, TestTopLevelKeyFirst, TestKeySecond,
TestStartKey,
TestKeyFirst,
TestTopLevelKeyFirst,
TestKeySecond,
).inOrder()
}
@ -181,38 +193,41 @@ class NiaBackStackViewModelTest {
rule.runOnIdle {
assertThat(scenario.viewModel.niaBackStack.backStack).containsExactly(
TestStartKey, TestKeyFirst, TestTopLevelKeyFirst, TestKeySecond,
TestStartKey,
TestKeyFirst,
TestTopLevelKeyFirst,
TestKeySecond,
).inOrder()
}
}
}
@Serializable
private object TestStartKey: NiaNavKey {
private object TestStartKey : NiaNavKey {
override val isTopLevel: Boolean
get() = true
}
@Serializable
private object TestTopLevelKeyFirst: NiaNavKey {
private object TestTopLevelKeyFirst : NiaNavKey {
override val isTopLevel: Boolean
get() = true
}
@Serializable
private object TestTopLevelKeySecond: NiaNavKey {
private object TestTopLevelKeySecond : NiaNavKey {
override val isTopLevel: Boolean
get() = true
}
@Serializable
private object TestKeyFirst: NiaNavKey {
private object TestKeyFirst : NiaNavKey {
override val isTopLevel: Boolean
get() = false
}
@Serializable
private object TestKeySecond: NiaNavKey {
private object TestKeySecond : NiaNavKey {
override val isTopLevel: Boolean
get() = false
}
}

@ -24,7 +24,6 @@ import androidx.compose.runtime.snapshots.SnapshotStateList
import org.jetbrains.annotations.VisibleForTesting
import kotlin.collections.mutableListOf
// TODO refine back behavior - perhaps take a lambda so that each screen / use site can customize back behavior?
// https://github.com/android/nowinandroid/issues/1934
class NiaBackStack(
@ -32,10 +31,9 @@ class NiaBackStack(
) {
internal var backStackMap: LinkedHashMap<NiaNavKey, MutableList<NiaNavKey>> =
linkedMapOf(
startKey to mutableListOf(startKey)
startKey to mutableListOf(startKey),
)
@VisibleForTesting
val backStack: SnapshotStateList<NiaNavKey> = mutableStateListOf(startKey)
@ -58,11 +56,10 @@ class NiaBackStack(
val tempStack = mapOf(startKey to backStackMap[startKey]!!)
backStackMap.clear()
backStackMap.putAll(tempStack)
// else either restore an existing substack or initiate new one
// else either restore an existing substack or initiate new one
} else {
backStackMap[key] = backStackMap.remove(key) ?: mutableListOf(key)
}
}
// not top level - add to current substack
else -> {
@ -73,7 +70,6 @@ class NiaBackStack(
}
currentStack.add(key)
}
}
updateBackStack()
}
@ -105,7 +101,7 @@ class NiaBackStack(
backStack.apply {
clear()
backStack.addAll(
backStackMap.flatMap { it.value }
backStackMap.flatMap { it.value },
)
}
@ -128,4 +124,4 @@ private fun popErrorMessage(count: Int, lastPopped: NiaNavKey) =
"""
Failed to pop $count entries. BackStack has been popped to an empty stack. Last
popped key is $lastPopped.
""".trimIndent()
""".trimIndent()

@ -23,20 +23,20 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.serialization.saved
import androidx.lifecycle.viewModelScope
import androidx.savedstate.serialization.SavedStateConfiguration
import javax.inject.Inject
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import kotlinx.serialization.builtins.MapSerializer
import kotlinx.serialization.modules.SerializersModule
import kotlinx.serialization.serializer
import javax.inject.Inject
@HiltViewModel
class NiaBackStackViewModel @Inject constructor(
savedStateHandle: SavedStateHandle,
val niaBackStack: NiaBackStack,
serializersModules: SerializersModule,
): ViewModel() {
) : ViewModel() {
private val config = SavedStateConfiguration { serializersModule = serializersModules }
@ -53,11 +53,10 @@ class NiaBackStackViewModel @Inject constructor(
// Restore backstack from saved state handle if not emtpy
@Suppress("UNCHECKED_CAST")
niaBackStack.restore(
backStackMap as LinkedHashMap<NiaNavKey, MutableList<NiaNavKey>>
backStackMap as LinkedHashMap<NiaNavKey, MutableList<NiaNavKey>>,
)
}
// Start observing changes to the backStack and save backStack whenever it updates
viewModelScope.launch {
snapshotFlow {

@ -57,13 +57,15 @@ class NiaBackStackTest {
niaBackStack.navigate(TestKeyFirst)
assertThat(niaBackStack.backStack).containsExactly(
TestStartKey, TestKeyFirst
TestStartKey,
TestKeyFirst,
).inOrder()
niaBackStack.navigate(TestKeyFirst)
assertThat(niaBackStack.backStack).containsExactly(
TestStartKey, TestKeyFirst
TestStartKey,
TestKeyFirst,
).inOrder()
}
@ -73,13 +75,16 @@ class NiaBackStackTest {
niaBackStack.navigate(TestKeyFirst)
assertThat(niaBackStack.backStack).containsExactly(
TestStartKey, TestTopLevelKey, TestKeyFirst
TestStartKey,
TestTopLevelKey,
TestKeyFirst,
).inOrder()
niaBackStack.navigate(TestTopLevelKey)
assertThat(niaBackStack.backStack).containsExactly(
TestStartKey, TestTopLevelKey
TestStartKey,
TestTopLevelKey,
).inOrder()
}
@ -130,12 +135,15 @@ class NiaBackStackTest {
niaBackStack.restore(
linkedMapOf(
TestStartKey to mutableListOf(TestStartKey, TestKeyFirst),
TestTopLevelKey to mutableListOf(TestTopLevelKey, TestKeySecond)
)
TestTopLevelKey to mutableListOf(TestTopLevelKey, TestKeySecond),
),
)
assertThat(niaBackStack.backStack).containsExactly(
TestStartKey, TestKeyFirst, TestTopLevelKey, TestKeySecond
TestStartKey,
TestKeyFirst,
TestTopLevelKey,
TestKeySecond,
).inOrder()
assertThat(niaBackStack.currentKey).isEqualTo(TestKeySecond)
@ -148,13 +156,16 @@ class NiaBackStackTest {
niaBackStack.navigate(TestKeySecond)
assertThat(niaBackStack.backStack).containsExactly(
TestStartKey, TestKeyFirst, TestKeySecond
TestStartKey,
TestKeyFirst,
TestKeySecond,
).inOrder()
niaBackStack.popLast()
assertThat(niaBackStack.backStack).containsExactly(
TestStartKey, TestKeyFirst
TestStartKey,
TestKeyFirst,
).inOrder()
assertThat(niaBackStack.currentKey).isEqualTo(TestKeyFirst)
@ -167,7 +178,9 @@ class NiaBackStackTest {
niaBackStack.navigate(TestTopLevelKey)
assertThat(niaBackStack.backStack).containsExactly(
TestStartKey, TestKeyFirst, TestTopLevelKey
TestStartKey,
TestKeyFirst,
TestTopLevelKey,
).inOrder()
assertThat(niaBackStack.currentKey).isEqualTo(TestTopLevelKey)
@ -177,7 +190,8 @@ class NiaBackStackTest {
niaBackStack.popLast()
assertThat(niaBackStack.backStack).containsExactly(
TestStartKey, TestKeyFirst
TestStartKey,
TestKeyFirst,
).inOrder()
assertThat(niaBackStack.currentKey).isEqualTo(TestKeyFirst)
@ -190,13 +204,15 @@ class NiaBackStackTest {
niaBackStack.navigate(TestKeySecond)
assertThat(niaBackStack.backStack).containsExactly(
TestStartKey, TestKeyFirst, TestKeySecond
TestStartKey,
TestKeyFirst,
TestKeySecond,
).inOrder()
niaBackStack.popLast(2)
assertThat(niaBackStack.backStack).containsExactly(
TestStartKey
TestStartKey,
).inOrder()
assertThat(niaBackStack.currentKey).isEqualTo(TestStartKey)
@ -205,7 +221,7 @@ class NiaBackStackTest {
@Test
fun popMultipleTopLevel() {
val TestTopLevelKeyTwo = object: NiaNavKey {
val testTopLevelKeyTwo = object : NiaNavKey {
override val isTopLevel: Boolean
get() = true
}
@ -214,17 +230,21 @@ class NiaBackStackTest {
niaBackStack.navigate(TestTopLevelKey)
niaBackStack.navigate(TestKeyFirst)
// third sub-stack
niaBackStack.navigate(TestTopLevelKeyTwo)
niaBackStack.navigate(testTopLevelKeyTwo)
niaBackStack.navigate(TestKeySecond)
assertThat(niaBackStack.backStack).containsExactly(
TestStartKey, TestTopLevelKey, TestKeyFirst, TestTopLevelKeyTwo, TestKeySecond,
TestStartKey,
TestTopLevelKey,
TestKeyFirst,
testTopLevelKeyTwo,
TestKeySecond,
).inOrder()
niaBackStack.popLast(4)
assertThat(niaBackStack.backStack).containsExactly(
TestStartKey
TestStartKey,
).inOrder()
assertThat(niaBackStack.currentKey).isEqualTo(TestStartKey)
@ -239,23 +259,22 @@ class NiaBackStackTest {
}
}
private object TestStartKey: NiaNavKey {
private object TestStartKey : NiaNavKey {
override val isTopLevel: Boolean
get() = true
}
private object TestTopLevelKey: NiaNavKey {
private object TestTopLevelKey : NiaNavKey {
override val isTopLevel: Boolean
get() = true
}
private object TestKeyFirst: NiaNavKey {
private object TestKeyFirst : NiaNavKey {
override val isTopLevel: Boolean
get() = false
}
private object TestKeySecond: NiaNavKey {
private object TestKeySecond : NiaNavKey {
override val isTopLevel: Boolean
get() = false
}

@ -1,305 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1616" height="404pt" viewBox="0 0 1212.13 404">
<g class="graph">
<path fill="#fff" d="M0 404V0h1212.13v404z"/>
<g class="node" transform="translate(4 400)">
<ellipse cx="645.13" cy="-378" fill="none" stroke="#000" rx="27.66" ry="18"/>
<text x="645.13" y="-373.8" font-family="Times,serif" font-size="14" text-anchor="middle">:app</text>
</g>
<g class="node" transform="translate(4 400)">
<ellipse cx="297.13" cy="-306" fill="none" stroke="#000" rx="75.39" ry="18"/>
<text x="297.13" y="-301.8" font-family="Times,serif" font-size="14" text-anchor="middle">:feature:interests</text>
</g>
<g stroke="red" stroke-width="2" class="edge">
<path fill="none" d="M622.9 28.25C575.45 37.76 472.2 58.45 385.13 76c-5.51 1.11-11.23 2.26-16.96 3.42"/>
<path fill="red" d="m370.62 82.5-10.5-1.45 9.11-5.41z"/>
</g>
<g class="node" transform="translate(4 400)">
<ellipse cx="135.13" cy="-306" fill="none" stroke="#000" rx="68.95" ry="18"/>
<text x="135.13" y="-301.8" font-family="Times,serif" font-size="14" text-anchor="middle">:feature:foryou</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M621.71 25.48C553.19 31.85 369.1 50.17 217.13 76c-5.5.93-11.19 1.99-16.88 3.12"/>
<path d="m201.33 82.47-10.5-1.43 9.1-5.43z"/>
</g>
<g class="node" transform="translate(4 400)">
<ellipse cx="812.13" cy="-306" fill="none" stroke="#000" rx="86.12" ry="18"/>
<text x="812.13" y="-301.8" font-family="Times,serif" font-size="14" text-anchor="middle">:feature:bookmarks</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M672 32.59c24.72 10.36 64.82 27.17 96.45 40.43"/>
<path d="m769.56 69.68 7.87 7.1-10.58-.64z"/>
</g>
<g class="node" transform="translate(4 400)">
<ellipse cx="645.13" cy="-306" fill="none" stroke="#000" rx="62.51" ry="18"/>
<text x="645.13" y="-301.8" font-family="Times,serif" font-size="14" text-anchor="middle">:feature:topic</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M649.13 40.3v24.16"/>
<path d="m652.63 64.38-3.5 10-3.5-10z"/>
</g>
<g class="node" transform="translate(4 400)">
<ellipse cx="458.13" cy="-306" fill="none" stroke="#000" rx="67.87" ry="18"/>
<text x="458.13" y="-301.8" font-family="Times,serif" font-size="14" text-anchor="middle">:feature:search</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M625.45 31.87C596.73 42.61 547.61 61 510.72 74.81"/>
<path d="m512.19 78-10.59.22 8.14-6.78z"/>
</g>
<g class="node" transform="translate(4 400)">
<ellipse cx="989.13" cy="-306" fill="none" stroke="#000" rx="72.71" ry="18"/>
<text x="989.13" y="-301.8" font-family="Times,serif" font-size="14" text-anchor="middle">:feature:settings</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M675.54 28.3c47.27 9.49 149.44 30.06 235.59 47.7 5.47 1.12 11.14 2.29 16.83 3.46"/>
<path d="m928.32 75.96 9.08 5.45-10.5 1.4z"/>
</g>
<g class="node" transform="translate(4 400)">
<ellipse cx="795.13" cy="-18" fill="none" stroke="#000" rx="66.81" ry="18"/>
<text x="795.13" y="-13.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:common</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M676.95 22.77c93.64-.29 395.91 2.79 476.18 53.23 39.37 24.74 55 42.5 55 89v74c0 44.13-8.03 63.44-44 89-52.76 37.49-225.24 24.92-289 36-5.22.91-10.62 1.93-16.03 3.02"/>
<path d="m860.04 370.4-10.51-1.38 9.08-5.47z"/>
</g>
<g class="node" transform="translate(4 400)">
<ellipse cx="553.13" cy="-234" fill="none" stroke="#000" rx="40.53" ry="18"/>
<text x="553.13" y="-229.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:ui</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M627.54 33.44C611.2 42.46 589.52 57.03 577.13 76c-11.72 17.95-16.64 41.79-18.67 60.29"/>
<path d="m561.96 136.38-4.33 9.66-2.64-10.26z"/>
</g>
<g class="node" transform="translate(4 400)">
<ellipse cx="774.13" cy="-162" fill="none" stroke="#000" rx="85.06" ry="18"/>
<text x="774.13" y="-157.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:designsystem</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M677 24.37c90.47 4.71 371.67 21.68 398.13 51.63 10.59 11.99 8.85 22.67 0 36-14.26 21.47-161.89 76.8-243.49 106.12"/>
<path d="m832.85 221.41-10.6.07 8.24-6.66z"/>
</g>
<g class="node" transform="translate(4 400)">
<ellipse cx="584.13" cy="-162" fill="none" stroke="#000" rx="49.1" ry="18"/>
<text x="584.13" y="-157.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:data</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M621.3 23.36C509.79 25.07 99.33 34.2 61.13 76-73.67 223.49 362.28 237.49 527.4 237.64"/>
<path d="m527.29 234.14 10 3.49-10 3.51z"/>
</g>
<g class="node" transform="translate(4 400)">
<ellipse cx="412.13" cy="-18" fill="none" stroke="#000" rx="57.16" ry="18"/>
<text x="412.13" y="-13.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:model</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M621.23 23.65C507.4 26.52 81.9 39.63 35.13 76c-33.07 25.71-31 47.11-31 89v74c0 72.85 233.17 116.46 348.68 133.59"/>
<path d="m353.06 369.09 9.39 4.9-10.4 2.02z"/>
</g>
<g class="node" transform="translate(4 400)">
<ellipse cx="1084.13" cy="-90" fill="none" stroke="#000" rx="67.34" ry="18"/>
<text x="1084.13" y="-85.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:analytics</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M676.84 24.37c96.52 5 414 23.46 449.29 51.63 38.51 30.74 36.4 60.07 25 108-8.61 36.2-29.46 73.82-44.83 98.2"/>
<path d="m1109.29 284.03-8.36 6.5 2.48-10.3z"/>
</g>
<g class="node" transform="translate(4 400)">
<ellipse cx="1084.13" cy="-234" fill="none" stroke="#000" rx="53.95" ry="18"/>
<text x="1084.13" y="-229.8" font-family="Times,serif" font-size="14" text-anchor="middle">:sync:work</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M676.8 24.09c94.84 4.04 402.48 19.53 431.33 51.91 15.09 16.94 7.03 42.79-3 62.27"/>
<path d="m1108.33 139.73-7.93 7.02 1.82-10.44z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M349.28 108.17c46.73 12.77 117.11 32.02 162.77 44.5"/>
<path d="m512.91 149.28 8.73 6.02-10.57.73z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M335.47 110.31c53.99 24.01 154.4 68.34 171.66 73.69 62.31 19.31 134.94 33.06 189.32 41.71"/>
<path d="m696.93 222.25 9.34 5-10.42 1.91z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M322.57 111.56c25.82 19.36 71.03 51.41 113.56 72.44 33.02 16.33 72.34 29.89 102.71 39.21"/>
<path d="m539.58 219.78 8.56 6.23-10.58.47z"/>
</g>
<g class="node" transform="translate(4 400)">
<ellipse cx="280.13" cy="-234" fill="none" stroke="#000" rx="61.99" ry="18"/>
<text x="280.13" y="-229.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:domain</text>
</g>
<g stroke="red" stroke-width="2" class="edge">
<path fill="none" d="M296.93 112.3c-1.79 7.38-3.93 16.18-5.94 24.45"/>
<path fill="red" d="m294.76 136.06-5.76 8.89-1.04-10.54z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M189.81 106.51c9.08 1.93 18.46 3.84 27.32 5.49 102.76 19.19 223.91 36.91 290.28 46.2"/>
<path d="m507.84 154.73 9.42 4.84-10.39 2.09z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M189.66 106.67c58.87 13.72 150.08 35.36 165.47 41.33 31.15 12.08 34.32 25.38 66 36 25.5 8.55 177.39 29.47 274.66 42.32"/>
<path d="m696.12 222.84 9.45 4.77-10.37 2.17z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M148.05 112.02c11.87 20.76 34.89 55.14 65.08 71.98 52.8 29.45 223.23 43.94 315.06 49.76"/>
<path d="m528.25 230.26 9.77 4.11-10.2 2.88z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M170.95 110.36c21.25 10.26 49.41 23.85 72.31 34.91"/>
<path d="m244.53 142 7.48 7.5-10.52-1.2z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M764.96 108.83c-47.43 12.82-117.32 31.71-162.71 43.98"/>
<path d="m603.29 156.15-10.56-.77 8.74-5.99z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M811.47 112.41c-6.45 24.09-18.15 67.84-25.84 96.56"/>
<path d="m789.07 209.67-5.97 8.76-.8-10.57z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M787.58 111.42c-17.78 10.32-41.08 24.02-61.45 36.58-36.53 22.52-77.81 49.32-105.62 67.59"/>
<path d="m622.44 218.51-10.27 2.57 6.43-8.42z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M627.79 111.24c-12.51 9.51-28.47 21.66-42.05 31.99"/>
<path d="m588.06 145.86-10.07 3.27 5.83-8.84z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M664.43 111.85c22.5 24.76 64.67 71.18 90.84 99.99"/>
<path d="m757.69 209.3 4.14 9.75-9.32-5.04z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M641.77 112.13c-10.4 24.2-29.49 68.66-41.87 97.48"/>
<path d="m603.27 210.61-7.16 7.81.73-10.57z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M484.16 111.24c12.92 9.51 29.4 21.66 43.43 31.99"/>
<path d="m529.64 140.4 5.98 8.75-10.13-3.11z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M503.63 108.57c29.3 9.97 69.29 24.35 103.5 39.43 46.63 20.55 98.27 48.14 132.48 67.12"/>
<path d="m741.29 212.05 7.03 7.93-10.44-1.82z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M467.8 112.32c6.93 19.2 20.17 50.26 39.33 71.68 11.92 13.33 27.94 24.74 42.57 33.52"/>
<path d="m551.31 214.4 6.93 8.01-10.42-1.94z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M425.25 109.5c-27.48 10.81-65.2 25.64-94.72 37.25"/>
<path d="m332.05 149.92-10.59.4 8.03-6.92z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M939.84 106.5c-9.54 1.93-19.41 3.84-28.71 5.5-108 19.26-235.39 37.16-304.07 46.42"/>
<path d="m607.62 161.87-10.37-2.13 9.44-4.8z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M968.47 111.29c-38.36 25.33-112.4 74.23-155.97 103.01"/>
<path d="m814.7 217.04-10.27 2.59 6.42-8.43z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M952.44 109.27c-76.15 26.7-239.67 84.03-319.13 111.89"/>
<path d="m634.7 224.38-10.59.01 8.27-6.62z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="m589.26 177.18 131.95 41.79"/>
<path d="m722.19 215.61 8.47 6.36-10.59.31z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M522.04 175.53C471.55 189.9 380.2 224.25 341.13 292c-7.99 13.86-7.36 21.79 0 36 7.13 13.76 19.66 24.72 32.46 33.01"/>
<path d="m375.25 357.93 6.8 8.13-10.38-2.12z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M582.63 180.21c18.33 9.97 43.28 24.49 63.5 39.79 18.55 14.04 16.89 26.22 38 36 133.07 61.65 183.33 11.96 328 36 5.23.87 10.63 1.87 16.04 2.94"/>
<path d="m1028.66 291.47 9.08 5.45-10.5 1.4z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M626.36 249.67c8.15 2.17 16.73 4.39 24.77 6.33 74.65 18.01 120.68-23.69 169 36 14.16 17.49 6.2 42.9-3.73 62.09"/>
<path d="m819.51 355.71-7.95 7 1.85-10.43z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M625.21 250.09c8.46 2.23 17.45 4.36 25.92 5.91 158.59 29.1 201.81 10.35 361 36 5.31.86 10.8 1.86 16.3 2.93"/>
<path d="m1029.07 291.49 9.09 5.45-10.5 1.41z"/>
</g>
<g class="node" transform="translate(4 400)">
<ellipse cx="412.13" cy="-90" fill="none" stroke="#000" rx="66.26" ry="18"/>
<text x="412.13" y="-85.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:database</text>
</g>
<g stroke="red" stroke-width="2" class="edge">
<path fill="none" d="m556.18 252-93.88 38.21"/>
<path fill="red" d="m465.15 292.83-10.58.53 7.94-7.02z"/>
</g>
<g class="node" transform="translate(4 400)">
<ellipse cx="931.13" cy="-90" fill="none" stroke="#000" rx="67.87" ry="18"/>
<text x="931.13" y="-85.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:datastore</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M625.98 249.79c8.25 2.19 16.97 4.38 25.15 6.21 88.99 19.9 112.45 18.74 202 36 6.31 1.22 12.89 2.52 19.45 3.84"/>
<path d="m872.97 292.35 9.1 5.43-10.49 1.43z"/>
</g>
<g class="node" transform="translate(4 400)">
<ellipse cx="742.13" cy="-90" fill="none" stroke="#000" rx="64.66" ry="18"/>
<text x="742.13" y="-85.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:network</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M618.59 252.5c23.83 10.55 57.28 25.37 83.94 37.19"/>
<path d="m703.65 286.35 7.72 7.25-10.56-.85z"/>
</g>
<g class="node" transform="translate(4 400)">
<ellipse cx="578.13" cy="-90" fill="none" stroke="#000" rx="81.29" ry="18"/>
<text x="578.13" y="-85.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:notifications</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M586.65 256.3c-.63 7.29-1.37 15.97-2.07 24.16"/>
<path d="m588.07 280.72-4.35 9.67-2.63-10.26z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M1037.64 172.89c-76.58 9.09-226.61 27.56-353.51 47.11-13.59 2.09-28.23 4.57-41.87 6.98"/>
<path d="m643.02 230.4-10.46-1.69 9.23-5.2z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M1088.13 184.41v96.17"/>
<path d="m1091.63 280.38-3.5 10-3.5-10z"/>
</g>
<g stroke="red" stroke-width="2" class="edge">
<path fill="none" d="M331.63 177.94c55.58 12.79 147.28 33.91 204.66 47.12"/>
<path fill="red" d="m535.38 221.26 8.96 5.66-10.53 1.16z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M281.82 184.44c-3.23 31.81-5.55 99.99 26.31 143.56 13.06 17.87 33.81 30.02 53.65 38.13"/>
<path d="m362.8 362.78 8.12 6.81-10.59-.26z"/>
</g>
<g stroke="red" stroke-width="2" class="edge">
<path fill="none" d="M416.13 328.3v24.16"/>
<path fill="red" d="m419.63 350.87-3.5 10-3.5-10z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M904.95 326.54c-19.28 9.92-44.51 22.9-65.5 33.71"/>
<path d="m841.07 363.35-10.5 1.47 7.29-7.69z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M877.24 319.75c-18.26 2.7-38.52 5.66-57.11 8.25-120.2 16.77-260.74 34.86-340.37 44.98"/>
<path d="m480.33 376.43-10.37-2.21 9.48-4.73z"/>
</g>
<g class="node" transform="translate(4 400)">
<ellipse cx="971.13" cy="-18" fill="none" stroke="#000" rx="91.47" ry="18"/>
<text x="971.13" y="-13.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:datastore-proto</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M945.02 328.3c4.45 7.8 9.82 17.19 14.78 25.87"/>
<path d="m962.68 352.16 1.92 10.42-8-6.94z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M758.96 327.95c6.18 8.16 13.74 18.14 20.62 27.23"/>
<path d="M782.26 352.92 785.5 363l-8.82-5.86z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M697.6 322.31c-8.48 1.93-17.23 3.89-25.47 5.69-67.75 14.79-145.82 30.81-197.76 41.32"/>
<path d="m475.36 372.69-10.5-1.45 9.11-5.41z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M626.83 325.42c34.89 11.26 83.44 26.92 120.11 38.75"/>
<path d="m747.55 360.68 8.44 6.4-10.59.26z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M545.7 326.36c-25.25 10.65-59 24.88-85.72 36.15"/>
<path d="m461.34 365.73-10.57.66 7.85-7.11z"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 0 B

@ -1,45 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="616" height="188pt" viewBox="0 0 462.21 188">
<g class="graph">
<path fill="#fff" d="M0 188V0h462.21v188z"/>
<g class="node" transform="translate(4 184)">
<ellipse cx="169.06" cy="-162" fill="none" stroke="#000" rx="73.77" ry="18"/>
<text x="169.06" y="-157.8" font-family="Times,serif" font-size="14" text-anchor="middle">:app-nia-catalog</text>
</g>
<g class="node" transform="translate(4 184)">
<ellipse cx="85.06" cy="-18" fill="none" stroke="#000" rx="85.06" ry="18"/>
<text x="85.06" y="-13.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:designsystem</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M162.93 40.13c-14.38 24.31-40.85 69.05-57.89 97.86"/>
<path d="m108.1 139.68-8.1 6.83 2.08-10.39z"/>
</g>
<g class="node" transform="translate(4 184)">
<ellipse cx="229.06" cy="-90" fill="none" stroke="#000" rx="40.53" ry="18"/>
<text x="229.06" y="-85.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:ui</text>
</g>
<g stroke="red" stroke-width="2" class="edge">
<path fill="none" d="M187.58 39.95c7.26 8.46 16.17 18.86 24.18 28.21"/>
<path fill="red" d="m213.26 64.52 3.85 9.87-9.17-5.31z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M206.31 108c-20.76 10.09-49.96 24.29-74.03 35.99"/>
<path d="m133.87 147.11-10.53 1.22 7.47-7.52z"/>
</g>
<g class="node" transform="translate(4 184)">
<ellipse cx="255.06" cy="-18" fill="none" stroke="#000" rx="67.34" ry="18"/>
<text x="255.06" y="-13.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:analytics</text>
</g>
<g stroke="red" stroke-width="2" class="edge">
<path fill="none" d="M239.35 111.95c2.8 7.53 6.17 16.61 9.33 25.11"/>
<path fill="red" d="m251.39 134.29.2 10.6-6.77-8.16z"/>
</g>
<g class="node" transform="translate(4 184)">
<ellipse cx="397.06" cy="-18" fill="none" stroke="#000" rx="57.16" ry="18"/>
<text x="397.06" y="-13.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:model</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M261.94 107.03c26.15 10.9 65.07 27.11 95.09 39.63"/>
<path d="m358.37 143.42 7.89 7.08-10.58-.62z"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 0 B

@ -1,9 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="143pt" height="44pt" viewBox="0 0 142.68 44">
<g class="graph">
<path fill="#fff" d="M0 44V0h142.68v44z"/>
<g class="node" transform="translate(4 40)">
<ellipse cx="67.34" cy="-18" fill="none" stroke="#000" rx="67.34" ry="18"/>
<text x="67.34" y="-13.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:analytics</text>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 459 B

After

Width:  |  Height:  |  Size: 0 B

@ -1,9 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="142pt" height="44pt" viewBox="0 0 141.63 44">
<g class="graph">
<path fill="#fff" d="M0 44V0h141.63v44z"/>
<g class="node" transform="translate(4 40)">
<ellipse cx="66.81" cy="-18" fill="none" stroke="#000" rx="66.81" ry="18"/>
<text x="66.81" y="-13.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:common</text>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 456 B

After

Width:  |  Height:  |  Size: 0 B

@ -1,97 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="791pt" height="188pt" viewBox="0 0 791.3 188">
<g class="graph">
<path fill="#fff" d="M0 188V0h791.3v188z"/>
<g class="node" transform="translate(4 184)">
<ellipse cx="327.95" cy="-162" fill="none" stroke="#000" rx="49.1" ry="18"/>
<text x="327.95" y="-157.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:data</text>
</g>
<g class="node" transform="translate(4 184)">
<ellipse cx="91.95" cy="-18" fill="none" stroke="#000" rx="66.81" ry="18"/>
<text x="91.95" y="-13.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:common</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M282.66 23.68C201.49 25.96 45.21 35.62 10.95 76c-10.35 12.2-7.76 22.01 0 36 8.1 14.58 22.05 25.67 36.34 33.84"/>
<path d="m48.61 142.58 7.22 7.76-10.48-1.56z"/>
</g>
<g class="node" transform="translate(4 184)">
<ellipse cx="563.95" cy="-90" fill="none" stroke="#000" rx="66.26" ry="18"/>
<text x="563.95" y="-85.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:database</text>
</g>
<g stroke="red" stroke-width="2" class="edge">
<path fill="none" d="M369.35 34.09c38.82 11.52 99.94 29.64 144.13 42.75"/>
<path fill="red" d="m512.83 73 8.59 6.2-10.58.51z"/>
</g>
<g class="node" transform="translate(4 184)">
<ellipse cx="411.95" cy="-90" fill="none" stroke="#000" rx="67.87" ry="18"/>
<text x="411.95" y="-85.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:datastore</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M351.02 38.88c10.72 8.94 24.32 20.27 36.3 30.26"/>
<path d="m389.49 66.39 5.44 9.09-9.92-3.71z"/>
</g>
<g class="node" transform="translate(4 184)">
<ellipse cx="80.95" cy="-90" fill="none" stroke="#000" rx="64.66" ry="18"/>
<text x="80.95" y="-85.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:network</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M293.9 33.78C252.69 45.47 186.56 64.2 139.75 77.47"/>
<path d="m140.92 80.78-10.57-.64 8.66-6.1z"/>
</g>
<g class="node" transform="translate(4 184)">
<ellipse cx="715.95" cy="-90" fill="none" stroke="#000" rx="67.34" ry="18"/>
<text x="715.95" y="-85.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:analytics</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M376.63 29.91C437.15 39.44 548.48 57.53 642.95 76c5.19 1.01 10.56 2.11 15.95 3.24"/>
<path d="m659.38 75.76 9.05 5.51-10.51 1.34z"/>
</g>
<g class="node" transform="translate(4 184)">
<ellipse cx="244.95" cy="-90" fill="none" stroke="#000" rx="81.29" ry="18"/>
<text x="244.95" y="-85.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:notifications</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M313.12 38.88c-10.52 8.88-23.84 20.11-35.62 30.04"/>
<path d="m279.93 71.46-9.9 3.77 5.39-9.13z"/>
</g>
<g class="node" transform="translate(4 184)">
<ellipse cx="244.95" cy="-18" fill="none" stroke="#000" rx="57.16" ry="18"/>
<text x="244.95" y="-13.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:model</text>
</g>
<g stroke="red" stroke-width="2" class="edge">
<path fill="none" d="M518.77 106.31c-8.6 1.93-17.46 3.89-25.82 5.69-78.48 16.87-98.73 18.12-177 36-4.28.98-8.71 2.03-13.16 3.1"/>
<path fill="red" d="m305.26 154.1-10.55-1.01 8.88-5.79z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M365.01 106.27c-8.69 1.91-17.63 3.88-26.06 5.73-61.62 13.52-132.06 28.88-181.18 39.56"/>
<path d="m158.69 154.95-10.52-1.3 9.03-5.54z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M380.95 109.67c-25.67 10.76-60.7 25.44-88.22 36.98"/>
<path d="m294.18 149.84-10.57.64 7.87-7.1z"/>
</g>
<g class="node" transform="translate(4 184)">
<ellipse cx="411.95" cy="-18" fill="none" stroke="#000" rx="91.47" ry="18"/>
<text x="411.95" y="-13.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:datastore-proto</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M415.95 112.3v24.16"/>
<path d="m419.45 136.38-3.5 10-3.5-10z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M87.67 112.3c1.16 7.38 2.55 16.18 3.85 24.45"/>
<path d="m94.94 135.98-1.91 10.42-5.01-9.33z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M119.33 109.67c25.13 10.73 59.38 25.35 86.37 36.87"/>
<path d="m206.8 143.2 7.83 7.15-10.57-.71z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M214.62 110.71c-22.33 10.22-51.64 23.63-75.54 34.56"/>
<path d="m140.79 148.34-10.55.97 7.64-7.34z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M248.95 112.3v24.16"/>
<path d="m252.45 136.38-3.5 10-3.5-10z"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 0 B

@ -1,105 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="791pt" height="260pt" viewBox="0 0 791.3 260">
<g class="graph">
<path fill="#fff" d="M0 260V0h791.3v260z"/>
<g class="node" transform="translate(4 256)">
<ellipse cx="327.95" cy="-234" fill="none" stroke="#000" rx="65.73" ry="18"/>
<text x="327.95" y="-229.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:data-test</text>
</g>
<g class="node" transform="translate(4 256)">
<ellipse cx="327.95" cy="-162" fill="none" stroke="#000" rx="49.1" ry="18"/>
<text x="327.95" y="-157.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:data</text>
</g>
<g stroke="red" stroke-width="2" class="edge">
<path fill="none" d="M331.95 40.3v24.16"/>
<path fill="red" d="m335.45 62.87-3.5 10-3.5-10z"/>
</g>
<g class="node" transform="translate(4 256)">
<ellipse cx="91.95" cy="-18" fill="none" stroke="#000" rx="66.81" ry="18"/>
<text x="91.95" y="-13.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:common</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M282.66 95.68C201.49 97.96 45.21 107.62 10.95 148c-10.35 12.2-7.76 22.01 0 36 8.1 14.58 22.05 25.67 36.34 33.84"/>
<path d="m48.61 214.58 7.22 7.76-10.48-1.56z"/>
</g>
<g class="node" transform="translate(4 256)">
<ellipse cx="563.95" cy="-90" fill="none" stroke="#000" rx="66.26" ry="18"/>
<text x="563.95" y="-85.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:database</text>
</g>
<g stroke="red" stroke-width="2" class="edge">
<path fill="none" d="M369.35 106.09c38.82 11.52 99.94 29.64 144.13 42.75"/>
<path fill="red" d="m512.83 145 8.59 6.2-10.58.51z"/>
</g>
<g class="node" transform="translate(4 256)">
<ellipse cx="411.95" cy="-90" fill="none" stroke="#000" rx="67.87" ry="18"/>
<text x="411.95" y="-85.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:datastore</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M351.02 110.88c10.72 8.94 24.32 20.27 36.3 30.26"/>
<path d="m389.49 138.39 5.44 9.09-9.92-3.71z"/>
</g>
<g class="node" transform="translate(4 256)">
<ellipse cx="80.95" cy="-90" fill="none" stroke="#000" rx="64.66" ry="18"/>
<text x="80.95" y="-85.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:network</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M293.9 105.78c-41.21 11.69-107.34 30.42-154.15 43.69"/>
<path d="m140.92 152.78-10.57-.64 8.66-6.1z"/>
</g>
<g class="node" transform="translate(4 256)">
<ellipse cx="715.95" cy="-90" fill="none" stroke="#000" rx="67.34" ry="18"/>
<text x="715.95" y="-85.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:analytics</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M376.63 101.91c60.52 9.53 171.85 27.62 266.32 46.09 5.19 1.01 10.56 2.11 15.95 3.24"/>
<path d="m659.38 147.76 9.05 5.51-10.51 1.34z"/>
</g>
<g class="node" transform="translate(4 256)">
<ellipse cx="244.95" cy="-90" fill="none" stroke="#000" rx="81.29" ry="18"/>
<text x="244.95" y="-85.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:notifications</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M313.12 110.88c-10.52 8.88-23.84 20.11-35.62 30.04"/>
<path d="m279.93 143.46-9.9 3.77 5.39-9.13z"/>
</g>
<g class="node" transform="translate(4 256)">
<ellipse cx="244.95" cy="-18" fill="none" stroke="#000" rx="57.16" ry="18"/>
<text x="244.95" y="-13.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:model</text>
</g>
<g stroke="red" stroke-width="2" class="edge">
<path fill="none" d="M518.77 178.31c-8.6 1.93-17.46 3.89-25.82 5.69-78.48 16.87-98.73 18.12-177 36-4.28.98-8.71 2.03-13.16 3.1"/>
<path fill="red" d="m305.26 226.1-10.55-1.01 8.88-5.79z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M365.01 178.27c-8.69 1.91-17.63 3.88-26.06 5.73-61.62 13.52-132.06 28.88-181.18 39.56"/>
<path d="m158.69 226.95-10.52-1.3 9.03-5.54z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M380.95 181.67c-25.67 10.76-60.7 25.44-88.22 36.98"/>
<path d="m294.18 221.84-10.57.64 7.87-7.1z"/>
</g>
<g class="node" transform="translate(4 256)">
<ellipse cx="411.95" cy="-18" fill="none" stroke="#000" rx="91.47" ry="18"/>
<text x="411.95" y="-13.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:datastore-proto</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M415.95 184.3v24.16"/>
<path d="m419.45 208.38-3.5 10-3.5-10z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M87.67 184.3c1.16 7.38 2.55 16.18 3.85 24.45"/>
<path d="m94.94 207.98-1.91 10.42-5.01-9.33z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M119.33 181.67c25.13 10.73 59.38 25.35 86.37 36.87"/>
<path d="m206.8 215.2 7.83 7.15-10.57-.71z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M214.62 182.71c-22.33 10.22-51.64 23.63-75.54 34.56"/>
<path d="m140.79 220.34-10.55.97 7.64-7.34z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M248.95 184.3v24.16"/>
<path d="m252.45 208.38-3.5 10-3.5-10z"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 6.0 KiB

After

Width:  |  Height:  |  Size: 0 B

@ -1,17 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="188" height="116pt" viewBox="0 0 140.52 116">
<g class="graph">
<path fill="#fff" d="M0 116V0h140.52v116z"/>
<g class="node" transform="translate(4 112)">
<ellipse cx="66.26" cy="-90" fill="none" stroke="#000" rx="66.26" ry="18"/>
<text x="66.26" y="-85.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:database</text>
</g>
<g class="node" transform="translate(4 112)">
<ellipse cx="66.26" cy="-18" fill="none" stroke="#000" rx="57.16" ry="18"/>
<text x="66.26" y="-13.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:model</text>
</g>
<g stroke="red" stroke-width="2" class="edge">
<path fill="none" d="M70.26 40.3v24.16"/>
<path fill="red" d="m73.76 62.87-3.5 10-3.5-10z"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 920 B

After

Width:  |  Height:  |  Size: 0 B

@ -1,33 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="475pt" height="116pt" viewBox="0 0 475.29 116">
<g class="graph">
<path fill="#fff" d="M0 116V0h475.29v116z"/>
<g class="node" transform="translate(4 112)">
<ellipse cx="258.47" cy="-90" fill="none" stroke="#000" rx="67.87" ry="18"/>
<text x="258.47" y="-85.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:datastore</text>
</g>
<g class="node" transform="translate(4 112)">
<ellipse cx="91.47" cy="-18" fill="none" stroke="#000" rx="91.47" ry="18"/>
<text x="91.47" y="-13.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:datastore-proto</text>
</g>
<g stroke="red" stroke-width="2" class="edge">
<path fill="none" d="M227.47 37.67c-24.41 10.23-57.26 24.01-84.09 35.25"/>
<path fill="red" d="m146.42 75.44-10.58.64 7.87-7.09z"/>
</g>
<g class="node" transform="translate(4 112)">
<ellipse cx="258.47" cy="-18" fill="none" stroke="#000" rx="57.16" ry="18"/>
<text x="258.47" y="-13.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:model</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M262.47 40.3v24.16"/>
<path d="m265.97 64.38-3.5 10-3.5-10z"/>
</g>
<g class="node" transform="translate(4 112)">
<ellipse cx="400.47" cy="-18" fill="none" stroke="#000" rx="66.81" ry="18"/>
<text x="400.47" y="-13.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:common</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M293.64 38.36c20.44 10.08 47.39 23.36 69.6 34.31"/>
<path d="m364.61 69.44 7.42 7.56-10.52-1.28z"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 0 B

@ -1,9 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="191pt" height="44pt" viewBox="0 0 190.95 44">
<g class="graph">
<path fill="#fff" d="M0 44V0h190.95v44z"/>
<g class="node" transform="translate(4 40)">
<ellipse cx="91.47" cy="-18" fill="none" stroke="#000" rx="91.47" ry="18"/>
<text x="91.47" y="-13.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:datastore-proto</text>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 465 B

After

Width:  |  Height:  |  Size: 0 B

@ -1,45 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="475pt" height="188pt" viewBox="0 0 474.97 188">
<g class="graph">
<path fill="#fff" d="M0 188V0h474.97v188z"/>
<g class="node" transform="translate(4 184)">
<ellipse cx="154.81" cy="-162" fill="none" stroke="#000" rx="84.5" ry="18"/>
<text x="154.81" y="-157.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:datastore-test</text>
</g>
<g class="node" transform="translate(4 184)">
<ellipse cx="66.81" cy="-18" fill="none" stroke="#000" rx="66.81" ry="18"/>
<text x="66.81" y="-13.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:common</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M148.2 40.13c-15.13 24.41-43.04 69.44-60.88 98.23"/>
<path d="m90.51 139.87-8.25 6.65 2.3-10.34z"/>
</g>
<g class="node" transform="translate(4 184)">
<ellipse cx="222.81" cy="-90" fill="none" stroke="#000" rx="67.87" ry="18"/>
<text x="222.81" y="-85.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:datastore</text>
</g>
<g stroke="red" stroke-width="2" class="edge">
<path fill="none" d="M175.27 39.95c8.19 8.42 18.24 18.77 27.29 28.08"/>
<path fill="red" d="m203.94 64.43 4.46 9.61-9.48-4.73z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M193.35 110.02c-23.03 10.33-53.85 24.16-78.82 35.37"/>
<path d="m116.16 148.49-10.55.9 7.69-7.29z"/>
</g>
<g class="node" transform="translate(4 184)">
<ellipse cx="242.81" cy="-18" fill="none" stroke="#000" rx="91.47" ry="18"/>
<text x="242.81" y="-13.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:datastore-proto</text>
</g>
<g stroke="red" stroke-width="2" class="edge">
<path fill="none" d="M231.76 112.3c2.13 7.46 4.68 16.38 7.06 24.73"/>
<path fill="red" d="m241.71 134.41-.61 10.58-6.12-8.66z"/>
</g>
<g class="node" transform="translate(4 184)">
<ellipse cx="409.81" cy="-18" fill="none" stroke="#000" rx="57.16" ry="18"/>
<text x="409.81" y="-13.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:model</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M264.66 109.17c29.59 11.07 70.88 26.53 102.52 38.37"/>
<path d="m368.38 144.25 8.13 6.79-10.59-.23z"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 0 B

@ -1,9 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="178pt" height="44pt" viewBox="0 0 178.11 44">
<g class="graph">
<path fill="#fff" d="M0 44V0h178.11v44z"/>
<g class="node" transform="translate(4 40)">
<ellipse cx="85.06" cy="-18" fill="none" stroke="#000" rx="85.06" ry="18"/>
<text x="85.06" y="-13.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:designsystem</text>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 462 B

After

Width:  |  Height:  |  Size: 0 B

@ -1,109 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="857pt" height="260pt" viewBox="0 0 857.47 260">
<g class="graph">
<path fill="#fff" d="M0 260V0h857.47v260z"/>
<g class="node" transform="translate(4 256)">
<ellipse cx="644.47" cy="-234" fill="none" stroke="#000" rx="61.99" ry="18"/>
<text x="644.47" y="-229.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:domain</text>
</g>
<g class="node" transform="translate(4 256)">
<ellipse cx="432.47" cy="-162" fill="none" stroke="#000" rx="49.1" ry="18"/>
<text x="432.47" y="-157.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:data</text>
</g>
<g stroke="red" stroke-width="2" class="edge">
<path fill="none" d="M608.6 36.17c-35.81 11.82-88.38 29.18-125.99 41.6"/>
<path fill="red" d="m485.41 80.53-10.59-.19 8.4-6.46z"/>
</g>
<g class="node" transform="translate(4 256)">
<ellipse cx="596.47" cy="-18" fill="none" stroke="#000" rx="57.16" ry="18"/>
<text x="596.47" y="-13.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:model</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M688.75 36.01C759.51 60.94 893.9 118.79 841.47 184c-21.58 26.85-111.18 40.88-174.8 47.61"/>
<path d="m667.32 235.06-10.31-2.47 9.6-4.5z"/>
</g>
<g class="node" transform="translate(4 256)">
<ellipse cx="350.47" cy="-18" fill="none" stroke="#000" rx="66.81" ry="18"/>
<text x="350.47" y="-13.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:common</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M388.98 99.32c-59.59 6.51-156.66 21.12-178.51 48.68-9.93 12.54-9.15 22.88 0 36 16.41 23.52 44.49 36.64 71.52 43.93"/>
<path d="m282.71 224.51 8.89 5.76-10.55 1.04z"/>
</g>
<g class="node" transform="translate(4 256)">
<ellipse cx="762.47" cy="-90" fill="none" stroke="#000" rx="66.26" ry="18"/>
<text x="762.47" y="-85.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:database</text>
</g>
<g stroke="red" stroke-width="2" class="edge">
<path fill="none" d="M478.76 103.63c50.44 10.34 137.3 28.29 211.71 44.37 4.89 1.06 9.96 2.16 15.04 3.28"/>
<path fill="red" d="m704.66 147.51 9.01 5.58-10.52 1.25z"/>
</g>
<g class="node" transform="translate(4 256)">
<ellipse cx="91.47" cy="-90" fill="none" stroke="#000" rx="67.87" ry="18"/>
<text x="91.47" y="-85.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:datastore</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M394.3 103.6c-51.27 10.45-140.4 28.66-216.83 44.4-6.2 1.28-12.66 2.61-19.13 3.95"/>
<path d="m159.51 155.28-10.5-1.4 9.08-5.45z"/>
</g>
<g class="node" transform="translate(4 256)">
<ellipse cx="432.47" cy="-90" fill="none" stroke="#000" rx="64.66" ry="18"/>
<text x="432.47" y="-85.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:network</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M436.47 112.3v24.16"/>
<path d="m439.97 136.38-3.5 10-3.5-10z"/>
</g>
<g class="node" transform="translate(4 256)">
<ellipse cx="282.47" cy="-90" fill="none" stroke="#000" rx="67.34" ry="18"/>
<text x="282.47" y="-85.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:analytics</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M406.84 108.83c-22.19 10.35-52.86 24.67-77.69 36.26"/>
<path d="m330.82 148.17-10.54 1.05 7.58-7.4z"/>
</g>
<g class="node" transform="translate(4 256)">
<ellipse cx="596.47" cy="-90" fill="none" stroke="#000" rx="81.29" ry="18"/>
<text x="596.47" y="-85.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:notifications</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M467.71 108.33c24.28 10.37 58.36 24.91 85.91 36.67"/>
<path d="m555 141.78 7.82 7.15-10.57-.71z"/>
</g>
<g stroke="red" stroke-width="2" class="edge">
<path fill="none" d="M731.68 181.67c-25.43 10.73-60.1 25.35-87.42 36.87"/>
<path fill="red" d="m647.18 221.11-10.58.66 7.86-7.11z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M153.37 175.69c18.26 2.71 38.52 5.67 57.1 8.31 115.27 16.35 249.85 34.41 326.98 44.67"/>
<path d="m537.45 225.14 9.45 4.78-10.37 2.15z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M141.78 179.51c43.64 11.8 109.15 29.5 155.92 42.15"/>
<path d="m298.37 218.21 8.74 5.99-10.57.77z"/>
</g>
<g class="node" transform="translate(4 256)">
<ellipse cx="91.47" cy="-18" fill="none" stroke="#000" rx="91.47" ry="18"/>
<text x="91.47" y="-13.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:datastore-proto</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M95.47 184.3v24.16"/>
<path d="m98.97 208.38-3.5 10-3.5-10z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M470.85 181.67c25.13 10.73 59.38 25.35 86.37 36.87"/>
<path d="m558.32 215.2 7.83 7.15-10.57-.71z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M417.04 183.59c-10.31 8.8-23.17 19.78-34.55 29.49"/>
<path d="m384.8 215.72-9.88 3.83 5.33-9.16z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M600.47 184.3v24.16"/>
<path d="m603.97 208.38-3.5 10-3.5-10z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M551.87 180.83c-40.74 11.59-98.94 28.15-141.58 40.29"/>
<path d="m411.28 224.47-10.58-.62 8.66-6.11z"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 0 B

@ -1,9 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="122pt" height="44pt" viewBox="0 0 122.31 44">
<g class="graph">
<path fill="#fff" d="M0 44V0h122.31v44z"/>
<g class="node" transform="translate(4 40)">
<ellipse cx="57.16" cy="-18" fill="none" stroke="#000" rx="57.16" ry="18"/>
<text x="57.16" y="-13.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:model</text>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 455 B

After

Width:  |  Height:  |  Size: 0 B

@ -1,25 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="274pt" height="116pt" viewBox="0 0 273.97 116">
<g class="graph">
<path fill="#fff" d="M0 116V0h273.97v116z"/>
<g class="node" transform="translate(4 112)">
<ellipse cx="137.81" cy="-90" fill="none" stroke="#000" rx="64.66" ry="18"/>
<text x="137.81" y="-85.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:network</text>
</g>
<g class="node" transform="translate(4 112)">
<ellipse cx="66.81" cy="-18" fill="none" stroke="#000" rx="66.81" ry="18"/>
<text x="66.81" y="-13.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:common</text>
</g>
<g stroke="red" stroke-width="2" class="edge">
<path fill="none" d="M124.99 39.59c-8.76 8.63-19.63 19.35-29.33 28.91"/>
<path fill="red" d="m99.25 69.88-9.58 4.52 4.67-9.51z"/>
</g>
<g class="node" transform="translate(4 112)">
<ellipse cx="208.81" cy="-18" fill="none" stroke="#000" rx="57.16" ry="18"/>
<text x="208.81" y="-13.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:model</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M158.64 39.59c8.75 8.63 19.63 19.35 29.33 28.91"/>
<path d="m190.37 65.95 4.66 9.52-9.58-4.53z"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 0 B

@ -1,25 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="274pt" height="116pt" viewBox="0 0 273.97 116">
<g class="graph">
<path fill="#fff" d="M0 116V0h273.97v116z"/>
<g class="node" transform="translate(4 112)">
<ellipse cx="128.16" cy="-90" fill="none" stroke="#000" rx="81.29" ry="18"/>
<text x="128.16" y="-85.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:notifications</text>
</g>
<g class="node" transform="translate(4 112)">
<ellipse cx="57.16" cy="-18" fill="none" stroke="#000" rx="57.16" ry="18"/>
<text x="57.16" y="-13.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:model</text>
</g>
<g stroke="red" stroke-width="2" class="edge">
<path fill="none" d="M114.97 39.95c-8.76 8.63-19.57 19.29-29.2 28.78"/>
<path fill="red" d="m89.43 70.04-9.58 4.53 4.67-9.52z"/>
</g>
<g class="node" transform="translate(4 112)">
<ellipse cx="199.16" cy="-18" fill="none" stroke="#000" rx="66.81" ry="18"/>
<text x="199.16" y="-13.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:common</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M149.34 39.95c8.64 8.51 19.26 18.98 28.78 28.37"/>
<path d="m180.39 65.64 4.66 9.51-9.58-4.53z"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 0 B

@ -1,17 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="284" height="116pt" viewBox="0 0 213.49 116">
<g class="graph">
<path fill="#fff" d="M0 116V0h213.49v116z"/>
<g class="node" transform="translate(4 112)">
<ellipse cx="102.74" cy="-90" fill="none" stroke="#000" rx="102.74" ry="18"/>
<text x="102.74" y="-85.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:screenshot-testing</text>
</g>
<g class="node" transform="translate(4 112)">
<ellipse cx="102.74" cy="-18" fill="none" stroke="#000" rx="85.06" ry="18"/>
<text x="102.74" y="-13.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:designsystem</text>
</g>
<g stroke="red" stroke-width="2" class="edge">
<path fill="none" d="M106.74 40.3v24.16"/>
<path fill="red" d="m110.24 62.87-3.5 10-3.5-10z"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 944 B

After

Width:  |  Height:  |  Size: 0 B

@ -1,121 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="860pt" height="260pt" viewBox="0 0 859.61 260">
<g class="graph">
<path fill="#fff" d="M0 260V0h859.61v260z"/>
<g class="node" transform="translate(4 256)">
<ellipse cx="359.72" cy="-234" fill="none" stroke="#000" rx="58.77" ry="18"/>
<text x="359.72" y="-229.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:testing</text>
</g>
<g class="node" transform="translate(4 256)">
<ellipse cx="93.72" cy="-90" fill="none" stroke="#000" rx="67.34" ry="18"/>
<text x="93.72" y="-85.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:analytics</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M335.26 38.2c-47.85 25.54-144.45 77.11-198.56 105.99"/>
<path d="m138.6 147.15-10.47 1.62 7.17-7.8z"/>
</g>
<g class="node" transform="translate(4 256)">
<ellipse cx="359.72" cy="-18" fill="none" stroke="#000" rx="66.81" ry="18"/>
<text x="359.72" y="-13.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:common</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M308.51 28.66C191.4 42.71-64.42 85.41 21.72 184c39.25 44.92 207.29 25.48 266 36 5.22.93 10.62 1.98 16.02 3.08"/>
<path d="m304.24 219.61 9.07 5.49-10.51 1.36z"/>
</g>
<g class="node" transform="translate(4 256)">
<ellipse cx="359.72" cy="-162" fill="none" stroke="#000" rx="49.1" ry="18"/>
<text x="359.72" y="-157.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:data</text>
</g>
<g stroke="red" stroke-width="2" class="edge">
<path fill="none" d="M363.72 40.3v24.16"/>
<path fill="red" d="m367.22 62.87-3.5 10-3.5-10z"/>
</g>
<g class="node" transform="translate(4 256)">
<ellipse cx="584.72" cy="-18" fill="none" stroke="#000" rx="57.16" ry="18"/>
<text x="584.72" y="-13.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:model</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M418.59 28.91C533.39 42.54 792.65 80.29 844.72 148c51.56 67.05-95.5 83.82-187.67 87.86"/>
<path d="m657.46 239.35-10.13-3.11 9.85-3.89z"/>
</g>
<g class="node" transform="translate(4 256)">
<ellipse cx="750.72" cy="-90" fill="none" stroke="#000" rx="81.29" ry="18"/>
<text x="750.72" y="-85.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:notifications</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M400.51 36.36c70.04 25.44 222.72 80.88 302.82 109.97"/>
<path d="m704.04 142.87 8.2 6.7-10.59-.12z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M324.76 105.25c-44.63 11.75-118.2 31.11-169.45 44.6"/>
<path d="m156.44 153.17-10.56-.84 8.78-5.93z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M315.28 97.72c-35.07 4.8-80.25 17.47-103.56 50.28-9.26 13.04-9.26 22.96 0 36 11.01 15.5 53.26 29.5 90.43 39.21"/>
<path d="m302.68 219.73 8.83 5.85-10.56.94z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M407.47 102.59c58.44 10.17 165.19 28.86 256.25 45.41 6.39 1.16 13.02 2.38 19.66 3.6"/>
<path d="m683.85 148.13 9.19 5.26-10.47 1.62z"/>
</g>
<g class="node" transform="translate(4 256)">
<ellipse cx="584.72" cy="-90" fill="none" stroke="#000" rx="66.26" ry="18"/>
<text x="584.72" y="-85.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:database</text>
</g>
<g stroke="red" stroke-width="2" class="edge">
<path fill="none" d="M400.37 106.4c36.7 11.42 93.54 29.1 135.19 42.06"/>
<path fill="red" d="m534.93 144.6 8.51 6.31-10.58.37z"/>
</g>
<g class="node" transform="translate(4 256)">
<ellipse cx="284.72" cy="-90" fill="none" stroke="#000" rx="67.87" ry="18"/>
<text x="284.72" y="-85.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:datastore</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M346.33 111.24c-9.33 8.7-21.02 19.61-31.43 29.33"/>
<path d="m317.35 143.07-9.7 4.26 4.92-9.38z"/>
</g>
<g class="node" transform="translate(4 256)">
<ellipse cx="435.72" cy="-90" fill="none" stroke="#000" rx="64.66" ry="18"/>
<text x="435.72" y="-85.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:network</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M381.35 111.24c9.55 8.79 21.54 19.83 32.16 29.62"/>
<path d="m415.57 137.99 4.98 9.35-9.73-4.2z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M694.53 178.33c-10.27 1.91-20.84 3.86-30.81 5.67-80.46 14.62-173.17 30.92-233.98 41.53"/>
<path d="m430.71 228.91-10.45-1.73 9.25-5.16z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M718.29 182.36c-25.24 10.65-58.99 24.88-85.72 36.15"/>
<path d="m633.94 221.73-10.58.66 7.86-7.11z"/>
</g>
<g stroke="red" stroke-width="2" class="edge">
<path fill="none" d="M588.72 184.3v24.16"/>
<path fill="red" d="m592.22 206.87-3.5 10-3.5-10z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M306.5 183.59c9.27 8.65 20.79 19.41 31.06 28.99"/>
<path d="m339.79 209.87 4.92 9.38-9.7-4.26z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M338.6 178.64c53.46 12.47 138.16 32.24 193.94 45.25"/>
<path d="m533.22 220.46 8.95 5.68-10.54 1.13z"/>
</g>
<g class="node" transform="translate(4 256)">
<ellipse cx="183.72" cy="-18" fill="none" stroke="#000" rx="91.47" ry="18"/>
<text x="183.72" y="-13.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:datastore-proto</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M265.3 183.24c-13.2 9.14-29.89 20.71-44.41 30.77"/>
<path d="m223.18 216.68-10.21 2.82 6.22-8.57z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M421.71 183.59c-9.39 8.65-21.07 19.41-31.48 28.99"/>
<path d="m392.71 215.06-9.73 4.2 4.99-9.35z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M471.69 182.02c22.2 10.42 51.97 24.41 75.93 35.67"/>
<path d="m548.9 214.42 7.56 7.42-10.54-1.08z"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 6.8 KiB

After

Width:  |  Height:  |  Size: 0 B

@ -1,33 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="616" height="116pt" viewBox="0 0 462.5 116">
<g class="graph">
<path fill="#fff" d="M0 116V0h462.5v116z"/>
<g class="node" transform="translate(4 112)">
<ellipse cx="237.34" cy="-90" fill="none" stroke="#000" rx="40.53" ry="18"/>
<text x="237.34" y="-85.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:ui</text>
</g>
<g class="node" transform="translate(4 112)">
<ellipse cx="67.34" cy="-18" fill="none" stroke="#000" rx="67.34" ry="18"/>
<text x="67.34" y="-13.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:analytics</text>
</g>
<g stroke="red" stroke-width="2" class="edge">
<path fill="none" d="M212.5 34.87c-26.1 10.75-64.98 26.76-95.34 39.26"/>
<path fill="red" d="m120.2 76.67-10.58.57 7.91-7.04z"/>
</g>
<g class="node" transform="translate(4 112)">
<ellipse cx="237.34" cy="-18" fill="none" stroke="#000" rx="85.06" ry="18"/>
<text x="237.34" y="-13.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:designsystem</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M241.34 40.3v24.16"/>
<path d="m244.84 64.38-3.5 10-3.5-10z"/>
</g>
<g class="node" transform="translate(4 112)">
<ellipse cx="397.34" cy="-18" fill="none" stroke="#000" rx="57.16" ry="18"/>
<text x="397.34" y="-13.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:model</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M269.58 35.35c24.66 10.79 60.82 26.61 89.02 38.95"/>
<path d="m359.84 71.02 7.76 7.22-10.57-.81z"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 0 B

@ -1,121 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="791pt" height="332pt" viewBox="0 0 791.39 332">
<g class="graph">
<path fill="#fff" d="M0 332V0h791.39v332z"/>
<g class="node" transform="translate(4 328)">
<ellipse cx="453.04" cy="-306" fill="none" stroke="#000" rx="68.43" ry="18"/>
<text x="453.04" y="-301.8" font-family="Times,serif" font-size="14" text-anchor="middle">:sync:sync-test</text>
</g>
<g class="node" transform="translate(4 328)">
<ellipse cx="412.04" cy="-162" fill="none" stroke="#000" rx="49.1" ry="18"/>
<text x="412.04" y="-157.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:data</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M448.89 40.37c-4.55 10.2-10.05 23.45-13.85 35.63-6.18 19.86-11.03 42.82-14.28 60.45"/>
<path d="m424.22 136.97-5.19 9.24-1.7-10.46z"/>
</g>
<g class="node" transform="translate(4 328)">
<ellipse cx="494.04" cy="-234" fill="none" stroke="#000" rx="53.95" ry="18"/>
<text x="494.04" y="-229.8" font-family="Times,serif" font-size="14" text-anchor="middle">:sync:work</text>
</g>
<g stroke="red" stroke-width="2" class="edge">
<path fill="none" d="M466.97 39.95c4.63 7.91 10.26 17.51 15.44 26.36"/>
<path fill="red" d="m484.65 63.2 2.03 10.4-8.07-6.86z"/>
</g>
<g class="node" transform="translate(4 328)">
<ellipse cx="92.04" cy="-18" fill="none" stroke="#000" rx="66.81" ry="18"/>
<text x="92.04" y="-13.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:common</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M367.83 169.79C265.55 176.21 34.29 193.52 11.04 220c-10.55 12.03-7.76 22.01 0 36 8.09 14.58 22.05 25.67 36.34 33.84"/>
<path d="m48.7 286.58 7.21 7.76-10.47-1.56z"/>
</g>
<g class="node" transform="translate(4 328)">
<ellipse cx="564.04" cy="-90" fill="none" stroke="#000" rx="66.26" ry="18"/>
<text x="564.04" y="-85.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:database</text>
</g>
<g stroke="red" stroke-width="2" class="edge">
<path fill="none" d="M445.71 180.66c22.53 10.38 53.84 24.8 79.14 36.45"/>
<path fill="red" d="m524.92 213.29 7.62 7.36-10.55-1z"/>
</g>
<g class="node" transform="translate(4 328)">
<ellipse cx="412.04" cy="-90" fill="none" stroke="#000" rx="67.87" ry="18"/>
<text x="412.04" y="-85.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:datastore</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M416.04 184.3v24.16"/>
<path d="m419.54 208.38-3.5 10-3.5-10z"/>
</g>
<g class="node" transform="translate(4 328)">
<ellipse cx="81.04" cy="-90" fill="none" stroke="#000" rx="64.66" ry="18"/>
<text x="81.04" y="-85.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:network</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M373.69 175.43c-50.99 10.22-139.2 28.13-214.65 44.57-4.63 1.01-9.43 2.07-14.25 3.15"/>
<path d="m145.57 226.56-10.52-1.21 8.98-5.61z"/>
</g>
<g class="node" transform="translate(4 328)">
<ellipse cx="716.04" cy="-90" fill="none" stroke="#000" rx="67.34" ry="18"/>
<text x="716.04" y="-85.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:analytics</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M456.73 176.37c52.01 11.97 142.52 32.82 202.68 46.67"/>
<path d="m659.84 219.55 8.96 5.65-10.53 1.17z"/>
</g>
<g class="node" transform="translate(4 328)">
<ellipse cx="245.04" cy="-90" fill="none" stroke="#000" rx="81.29" ry="18"/>
<text x="245.04" y="-85.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:notifications</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M384.63 180.17c-24.88 10.43-60.04 25.16-88.32 37.02"/>
<path d="m297.82 220.35-10.58.64 7.87-7.09z"/>
</g>
<g stroke="red" stroke-width="2" class="edge">
<path fill="none" d="M479.03 111.24c-10.64 9.07-24.07 20.54-35.79 30.55"/>
<path fill="red" d="m446.86 143.3-9.88 3.83 5.33-9.16z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M522.22 110.47c39.47 25.24 117.88 75.4 163.23 104.4"/>
<path d="m687.06 211.75 6.54 8.33-10.31-2.44z"/>
</g>
<g class="node" transform="translate(4 328)">
<ellipse cx="245.04" cy="-18" fill="none" stroke="#000" rx="57.16" ry="18"/>
<text x="245.04" y="-13.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:model</text>
</g>
<g stroke="red" stroke-width="2" class="edge">
<path fill="none" d="M518.86 250.31c-8.6 1.93-17.46 3.89-25.82 5.69-78.48 16.87-98.73 18.12-177 36-4.28.98-8.72 2.03-13.16 3.1"/>
<path fill="red" d="m305.35 298.1-10.55-1.01 8.87-5.79z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M365.1 250.27c-8.69 1.91-17.63 3.88-26.06 5.73-61.62 13.52-132.06 28.88-181.18 39.56"/>
<path d="m158.78 298.95-10.52-1.3 9.03-5.54z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M381.03 253.67c-25.66 10.76-60.69 25.44-88.21 36.98"/>
<path d="m294.27 293.84-10.57.64 7.87-7.1z"/>
</g>
<g class="node" transform="translate(4 328)">
<ellipse cx="412.04" cy="-18" fill="none" stroke="#000" rx="91.47" ry="18"/>
<text x="412.04" y="-13.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:datastore-proto</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M416.04 256.3v24.16"/>
<path d="m419.54 280.38-3.5 10-3.5-10z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M87.76 256.3c1.16 7.38 2.54 16.18 3.84 24.45"/>
<path d="m95.03 279.98-1.91 10.42-5.01-9.33z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M119.42 253.67c25.13 10.73 59.38 25.35 86.36 36.87"/>
<path d="m206.89 287.2 7.83 7.15-10.58-.71z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M214.71 254.71c-22.34 10.22-51.64 23.63-75.54 34.56"/>
<path d="m140.88 292.34-10.55.97 7.64-7.34z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M249.04 256.3v24.16"/>
<path d="m252.54 280.38-3.5 10-3.5-10z"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 0 B

@ -1,109 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1084" height="260pt" viewBox="0 0 812.6 260">
<g class="graph">
<path fill="#fff" d="M0 260V0h812.6v260z"/>
<g class="node" transform="translate(4 256)">
<ellipse cx="161.34" cy="-234" fill="none" stroke="#000" rx="53.95" ry="18"/>
<text x="161.34" y="-229.8" font-family="Times,serif" font-size="14" text-anchor="middle">:sync:work</text>
</g>
<g class="node" transform="translate(4 256)">
<ellipse cx="67.34" cy="-90" fill="none" stroke="#000" rx="67.34" ry="18"/>
<text x="67.34" y="-85.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:analytics</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="m154.19 39.85-65.45 98.86"/>
<path d="m91.75 140.51-8.43 6.4 2.6-10.27z"/>
</g>
<g class="node" transform="translate(4 256)">
<ellipse cx="255.34" cy="-162" fill="none" stroke="#000" rx="49.1" ry="18"/>
<text x="255.34" y="-157.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:data</text>
</g>
<g stroke="red" stroke-width="2" class="edge">
<path fill="none" d="M186.67 38.88c12.59 9.38 28.72 21.39 42.58 31.71"/>
<path fill="red" d="m230.06 66.83 5.93 8.78-10.11-3.16z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M225.73 107.51c-29.45 10.97-72.61 27.04-105.81 39.4"/>
<path d="m121.53 150.05-10.6.21 8.15-6.77z"/>
</g>
<g class="node" transform="translate(4 256)">
<ellipse cx="266.34" cy="-18" fill="none" stroke="#000" rx="66.81" ry="18"/>
<text x="266.34" y="-13.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:common</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M228.51 108.42c-16 8.75-34.07 21.87-43.17 39.58-7.31 14.23-7.76 22.01 0 36 8.09 14.58 22.04 25.67 36.33 33.84"/>
<path d="m222.99 214.58 7.22 7.76-10.48-1.56z"/>
</g>
<g class="node" transform="translate(4 256)">
<ellipse cx="738.34" cy="-90" fill="none" stroke="#000" rx="66.26" ry="18"/>
<text x="738.34" y="-85.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:database</text>
</g>
<g stroke="red" stroke-width="2" class="edge">
<path fill="none" d="M306.37 99.66c76.16 7.87 231.05 25.23 360.97 48.34 5.15.92 10.48 1.95 15.82 3.04"/>
<path fill="red" d="m682.05 147.23 9.05 5.5-10.51 1.35z"/>
</g>
<g class="node" transform="translate(4 256)">
<ellipse cx="586.34" cy="-90" fill="none" stroke="#000" rx="67.87" ry="18"/>
<text x="586.34" y="-85.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:datastore</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M301.62 103.67c50.44 10.37 137.29 28.35 211.72 44.33 4.88 1.05 9.92 2.14 14.99 3.24"/>
<path d="m528.92 147.79 9.02 5.56-10.52 1.28z"/>
</g>
<g class="node" transform="translate(4 256)">
<ellipse cx="255.34" cy="-90" fill="none" stroke="#000" rx="64.66" ry="18"/>
<text x="255.34" y="-85.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:network</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M259.34 112.3v24.16"/>
<path d="m262.84 136.38-3.5 10-3.5-10z"/>
</g>
<g class="node" transform="translate(4 256)">
<ellipse cx="419.34" cy="-90" fill="none" stroke="#000" rx="81.29" ry="18"/>
<text x="419.34" y="-85.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:notifications</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M290.58 108.33c24.28 10.37 58.36 24.91 85.91 36.67"/>
<path d="m377.86 141.78 7.83 7.15-10.57-.71z"/>
</g>
<g class="node" transform="translate(4 256)">
<ellipse cx="419.34" cy="-18" fill="none" stroke="#000" rx="57.16" ry="18"/>
<text x="419.34" y="-13.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:model</text>
</g>
<g stroke="red" stroke-width="2" class="edge">
<path fill="none" d="M693.16 178.31c-8.6 1.93-17.46 3.89-25.82 5.69-78.48 16.87-98.74 18.12-177 36-4.28.98-8.72 2.03-13.16 3.1"/>
<path fill="red" d="m479.65 226.1-10.55-1.01 8.87-5.79z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M539.4 178.27c-8.69 1.91-17.63 3.88-26.06 5.73-61.62 13.52-132.07 28.88-181.18 39.56"/>
<path d="m333.07 226.95-10.51-1.3 9.03-5.54z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M555.33 181.67c-25.67 10.76-60.69 25.44-88.21 36.98"/>
<path d="m468.57 221.84-10.58.64 7.87-7.1z"/>
</g>
<g class="node" transform="translate(4 256)">
<ellipse cx="586.34" cy="-18" fill="none" stroke="#000" rx="91.47" ry="18"/>
<text x="586.34" y="-13.8" font-family="Times,serif" font-size="14" text-anchor="middle">:core:datastore-proto</text>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M590.34 184.3v24.16"/>
<path d="m593.84 208.38-3.5 10-3.5-10z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M262.06 184.3c1.16 7.38 2.54 16.18 3.84 24.45"/>
<path d="m269.32 207.98-1.9 10.42-5.01-9.33z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M293.72 181.67c25.13 10.73 59.38 25.35 86.36 36.87"/>
<path d="m381.19 215.2 7.82 7.15-10.57-.71z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M389.01 182.71c-22.34 10.22-51.64 23.63-75.54 34.56"/>
<path d="m315.18 220.34-10.55.97 7.64-7.34z"/>
</g>
<g stroke="#000" class="edge">
<path fill="none" d="M423.34 184.3v24.16"/>
<path d="m426.84 208.38-3.5 10-3.5-10z"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 0 B

@ -0,0 +1,3 @@
# :feature:bookmarks:api module
## Dependency graph
![Dependency graph](../../../docs/images/graphs/dep_graph_feature_bookmarks_api.svg)

@ -20,7 +20,7 @@ import com.google.samples.apps.nowinandroid.core.navigation.NiaNavKey
import kotlinx.serialization.Serializable
@Serializable
object BookmarksRoute: NiaNavKey{
object BookmarksRoute : NiaNavKey {
override val isTopLevel: Boolean
get() = true
}

@ -0,0 +1,3 @@
# :feature:bookmarks:impl module
## Dependency graph
![Dependency graph](../../../docs/images/graphs/dep_graph_feature_bookmarks_impl.svg)

@ -35,7 +35,7 @@ import dagger.multibindings.IntoSet
@Module
@InstallIn(ActivityComponent::class)
object BookmarksModule {
object BookmarksEntryProvider {
@Provides
@IntoSet
@ -52,7 +52,7 @@ object BookmarksModule {
actionLabel = action,
duration = Short,
) == ActionPerformed
}
},
)
}
}

@ -34,7 +34,7 @@ import kotlinx.serialization.modules.PolymorphicModuleBuilder
object BookmarksSerializerModule {
@Provides
@IntoSet
fun provideSearchPolymorphicModuleBuilder(): PolymorphicModuleBuilder<@JvmSuppressWildcards NiaNavKey>.() -> Unit = {
fun provideBookmarksPolymorphicModuleBuilder(): PolymorphicModuleBuilder<@JvmSuppressWildcards NiaNavKey>.() -> Unit = {
subclass(BookmarksRoute::class, BookmarksRoute.serializer())
}
}

@ -0,0 +1,3 @@
# :feature:foryou:api module
## Dependency graph
![Dependency graph](../../../docs/images/graphs/dep_graph_feature_foryou_api.svg)

@ -20,7 +20,7 @@ import com.google.samples.apps.nowinandroid.core.navigation.NiaNavKey
import kotlinx.serialization.Serializable
@Serializable
object ForYouRoute: NiaNavKey{ // route to ForYou screen
object ForYouRoute : NiaNavKey { // route to ForYou screen
override val isTopLevel: Boolean
get() = true
}

@ -0,0 +1,3 @@
# :feature:foryou:impl module
## Dependency graph
![Dependency graph](../../../docs/images/graphs/dep_graph_feature_foryou_impl.svg)

@ -26,7 +26,6 @@ android {
dependencies {
implementation(libs.accompanist.permissions)
implementation(projects.core.data)
implementation(projects.core.domain)
implementation(projects.core.notifications)
implementation(projects.feature.foryou.api)

@ -154,12 +154,12 @@ class ForYouScreenTest {
ForYouScreen(
isSyncing = false,
onboardingUiState =
OnboardingUiState.Shown(
// Follow one topic
topics = followableTopicTestData.mapIndexed { index, testTopic ->
testTopic.copy(isFollowed = index == 1)
},
),
OnboardingUiState.Shown(
// Follow one topic
topics = followableTopicTestData.mapIndexed { index, testTopic ->
testTopic.copy(isFollowed = index == 1)
},
),
feedState = NewsFeedUiState.Success(
feed = emptyList(),
),
@ -201,9 +201,9 @@ class ForYouScreenTest {
ForYouScreen(
isSyncing = false,
onboardingUiState =
OnboardingUiState.Shown(
topics = followableTopicTestData
),
OnboardingUiState.Shown(
topics = followableTopicTestData,
),
feedState = NewsFeedUiState.Loading,
deepLinkedUserNewsResource = null,
onTopicCheckedChanged = { _, _ -> },

@ -31,7 +31,7 @@ import dagger.multibindings.IntoSet
@Module
@InstallIn(ActivityComponent::class)
object ForYouModule {
object ForYouEntryProvider {
/**
* The ForYou composable for the app. It can also display information about topics.
* This should be supplied from a separate module.
@ -43,8 +43,8 @@ object ForYouModule {
): EntryProviderBuilder<NiaNavKey>.() -> Unit = {
entry<ForYouRoute> {
ForYouScreen(
onTopicClick = backStack::navigateToTopic
onTopicClick = backStack::navigateToTopic,
)
}
}
}
}

@ -34,7 +34,7 @@ import kotlinx.serialization.modules.PolymorphicModuleBuilder
object ForYouRouteSerializerModule {
@Provides
@IntoSet
fun provideSearchPolymorphicModuleBuilder(): PolymorphicModuleBuilder<@JvmSuppressWildcards NiaNavKey>.() -> Unit = {
fun provideForYouPolymorphicModuleBuilder(): PolymorphicModuleBuilder<@JvmSuppressWildcards NiaNavKey>.() -> Unit = {
subclass(ForYouRoute::class, ForYouRoute.serializer())
}
}
}

@ -0,0 +1,3 @@
# :feature:interests:api module
## Dependency graph
![Dependency graph](../../../docs/images/graphs/dep_graph_feature_interests_api.svg)

@ -23,7 +23,7 @@ import kotlinx.serialization.Serializable
data class InterestsRoute(
// The ID of the topic which will be initially selected at this destination
val initialTopicId: String? = null,
): NiaNavKey {
) : NiaNavKey {
override val isTopLevel: Boolean
get() = true
}
}

@ -6,14 +6,14 @@
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="64dp"
android:height="64dp"

@ -18,4 +18,5 @@
<string name="feature_interests_api_title">Interests</string>
<string name="feature_interests_api_loading">Loading data</string>
<string name="feature_interests_api_empty_header">"No available data"</string>
<string name="feature_interests_api_select_an_interest">Select an Interest</string>
</resources>

@ -0,0 +1,3 @@
# :feature:interests:impl module
## Dependency graph
![Dependency graph](../../../docs/images/graphs/dep_graph_feature_interests_impl.svg)

@ -24,7 +24,6 @@ android {
}
dependencies {
implementation(projects.core.data)
implementation(projects.core.domain)
implementation(projects.feature.topic.api)
implementation(projects.feature.interests.api)

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.feature.topic.api
package com.google.samples.apps.nowinandroid.feature.interests.impl
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
@ -33,9 +33,10 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.google.samples.apps.nowinandroid.core.designsystem.theme.NiaTheme
import com.google.samples.apps.nowinandroid.feature.interests.api.R
@Composable
fun TopicDetailPlaceholder(modifier: Modifier = Modifier) {
fun InterestsDetailPlaceholder(modifier: Modifier = Modifier) {
Card(
modifier = modifier,
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceVariant),
@ -50,12 +51,12 @@ fun TopicDetailPlaceholder(modifier: Modifier = Modifier) {
),
) {
Icon(
painter = painterResource(id = R.drawable.feature_topic_api_ic_topic_placeholder),
painter = painterResource(id = R.drawable.feature_interests_api_ic_detail_placeholder),
contentDescription = null,
tint = MaterialTheme.colorScheme.primary,
)
Text(
text = stringResource(id = R.string.feature_topic_api_select_an_interest),
text = stringResource(id = R.string.feature_interests_api_select_an_interest),
style = MaterialTheme.typography.titleLarge,
)
}
@ -66,6 +67,6 @@ fun TopicDetailPlaceholder(modifier: Modifier = Modifier) {
@Composable
fun TopicDetailPlaceholderPreview() {
NiaTheme {
TopicDetailPlaceholder()
InterestsDetailPlaceholder()
}
}

@ -71,7 +71,7 @@ class InterestsViewModel @AssistedInject constructor(
}
@AssistedFactory
interface Factory{
interface Factory {
fun create(key: InterestsRoute): InterestsViewModel
}
}

@ -16,8 +16,6 @@
package com.google.samples.apps.nowinandroid.feature.interests.impl
import android.graphics.Color.RED
import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
@ -32,11 +30,9 @@ import androidx.compose.foundation.layout.windowInsetsBottomHeight
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.unit.dp
import com.google.samples.apps.nowinandroid.core.designsystem.component.scrollbar.DraggableScrollbar
@ -108,4 +104,4 @@ fun TopicsTabContent(
}
}
val LIST_PANE_TEST_TAG = "interests:topics"
val LIST_PANE_TEST_TAG = "interests:topics"

@ -24,9 +24,9 @@ import androidx.navigation3.runtime.entry
import com.google.samples.apps.nowinandroid.core.navigation.NiaBackStack
import com.google.samples.apps.nowinandroid.core.navigation.NiaNavKey
import com.google.samples.apps.nowinandroid.feature.interests.api.navigation.InterestsRoute
import com.google.samples.apps.nowinandroid.feature.interests.impl.InterestsDetailPlaceholder
import com.google.samples.apps.nowinandroid.feature.interests.impl.InterestsScreen
import com.google.samples.apps.nowinandroid.feature.interests.impl.InterestsViewModel
import com.google.samples.apps.nowinandroid.feature.topic.api.TopicDetailPlaceholder
import com.google.samples.apps.nowinandroid.feature.topic.api.navigation.navigateToTopic
import dagger.Module
import dagger.Provides
@ -36,18 +36,18 @@ import dagger.multibindings.IntoSet
@Module
@InstallIn(ActivityComponent::class)
object InterestsModule {
object InterestsEntryProvider {
@OptIn(ExperimentalMaterial3AdaptiveApi::class)
@Provides
@IntoSet
fun provideInterestsEntryProviderBuilder(
backStack: NiaBackStack
backStack: NiaBackStack,
): EntryProviderBuilder<NiaNavKey>.() -> Unit = {
entry<InterestsRoute>(
metadata = ListDetailSceneStrategy.listPane {
TopicDetailPlaceholder()
}
InterestsDetailPlaceholder()
},
) { key ->
val viewModel = hiltViewModel<InterestsViewModel, InterestsViewModel.Factory> {
it.create(key)
@ -55,8 +55,8 @@ object InterestsModule {
InterestsScreen(
onTopicClick = backStack::navigateToTopic,
shouldHighlightSelectedTopic = false,
viewModel = viewModel
viewModel = viewModel,
)
}
}
}
}

@ -34,7 +34,7 @@ import kotlinx.serialization.modules.PolymorphicModuleBuilder
object InterestsSerializerModule {
@Provides
@IntoSet
fun provideSearchPolymorphicModuleBuilder(): PolymorphicModuleBuilder<@JvmSuppressWildcards NiaNavKey>.() -> Unit = {
fun provideInterestsPolymorphicModuleBuilder(): PolymorphicModuleBuilder<@JvmSuppressWildcards NiaNavKey>.() -> Unit = {
subclass(InterestsRoute::class, InterestsRoute.serializer())
}
}

@ -37,8 +37,9 @@ import com.google.samples.apps.nowinandroid.core.data.repository.TopicsRepositor
import com.google.samples.apps.nowinandroid.core.designsystem.theme.NiaTheme
import com.google.samples.apps.nowinandroid.core.model.data.Topic
import com.google.samples.apps.nowinandroid.core.navigation.NiaBackStack
import com.google.samples.apps.nowinandroid.core.navigation.NiaNavKey
import com.google.samples.apps.nowinandroid.core.navigation.NiaBackStackViewModel
import com.google.samples.apps.nowinandroid.core.navigation.NiaNavKey
import com.google.samples.apps.nowinandroid.feature.interests.api.R
import com.google.samples.apps.nowinandroid.feature.interests.api.navigation.InterestsRoute
import com.google.samples.apps.nowinandroid.feature.interests.impl.LIST_PANE_TEST_TAG
import com.google.samples.apps.nowinandroid.uitesthiltmanifest.HiltComponentActivity
@ -47,6 +48,7 @@ import dagger.Provides
import dagger.hilt.EntryPoint
import dagger.hilt.EntryPoints
import dagger.hilt.InstallIn
import dagger.hilt.android.components.ActivityComponent
import dagger.hilt.android.testing.HiltAndroidRule
import dagger.hilt.android.testing.HiltAndroidTest
import dagger.hilt.android.testing.HiltTestApplication
@ -64,10 +66,8 @@ import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.properties.ReadOnlyProperty
import com.google.samples.apps.nowinandroid.feature.topic.api.R as FeatureTopicR
import dagger.hilt.android.components.ActivityComponent
import kotlin.getValue
import kotlin.properties.ReadOnlyProperty
private const val EXPANDED_WIDTH = "w1200dp-h840dp"
private const val COMPACT_WIDTH = "w412dp-h915dp"
@ -87,7 +87,7 @@ class InterestsListDetailScreenTest {
@EntryPoint
@InstallIn(ActivityComponent::class)
interface EntryProvidersEntryPoint {
fun getEntryProviders() : Set<@JvmSuppressWildcards EntryProviderBuilder<NiaNavKey>.() -> Unit>
fun getEntryProviders(): Set<@JvmSuppressWildcards EntryProviderBuilder<NiaNavKey>.() -> Unit>
}
@Inject
@ -99,7 +99,7 @@ class InterestsListDetailScreenTest {
}
// The strings used for matching in these tests.
private val placeholderText by composeTestRule.stringResource(FeatureTopicR.string.feature_topic_api_select_an_interest)
private val placeholderText by composeTestRule.stringResource(R.string.feature_interests_api_select_an_interest)
private val Topic.testTag
get() = "topic:${this.id}"
@ -257,10 +257,10 @@ object BackStackProvider {
@Provides
@Singleton
fun provideSerializersModule(
polymorphicModuleBuilders: Set<@JvmSuppressWildcards PolymorphicModuleBuilder<NiaNavKey>.() -> Unit>
) : SerializersModule = SerializersModule {
polymorphicModuleBuilders: Set<@JvmSuppressWildcards PolymorphicModuleBuilder<NiaNavKey>.() -> Unit>,
): SerializersModule = SerializersModule {
polymorphic(NiaNavKey::class) {
polymorphicModuleBuilders.forEach { it() }
}
}
}
}

@ -37,7 +37,6 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
import kotlin.intArrayOf
import kotlin.test.assertEquals
/**
@ -73,7 +72,7 @@ class InterestsViewModelTest {
),
userDataRepository = userDataRepository,
getFollowableTopics = getFollowableTopicsUseCase,
InterestsRoute(initialTopicId = testInputTopics[0].topic.id)
InterestsRoute(initialTopicId = testInputTopics[0].topic.id),
)
}

@ -0,0 +1,3 @@
# :feature:search:api module
## Dependency graph
![Dependency graph](../../../docs/images/graphs/dep_graph_feature_search_api.svg)

@ -21,11 +21,11 @@ import com.google.samples.apps.nowinandroid.core.navigation.NiaNavKey
import kotlinx.serialization.Serializable
@Serializable
object SearchRoute: NiaNavKey {
object SearchRoute : NiaNavKey {
override val isTopLevel: Boolean
get() = false
}
fun NiaBackStack.navigateToSearch() {
navigate(SearchRoute)
}
}

@ -0,0 +1,3 @@
# :feature:search:impl module
## Dependency graph
![Dependency graph](../../../docs/images/graphs/dep_graph_feature_search_impl.svg)

@ -25,7 +25,6 @@ android {
}
dependencies {
implementation(projects.core.data)
implementation(projects.core.domain)
implementation(projects.feature.interests.api)
implementation(projects.feature.search.api)

@ -32,7 +32,7 @@ import dagger.multibindings.IntoSet
@Module
@InstallIn(ActivityComponent::class)
object SearchModule {
object SearchEntryProvider {
@Provides
@IntoSet
@ -47,4 +47,4 @@ object SearchModule {
)
}
}
}
}

@ -0,0 +1,3 @@
# :feature:settings:api module
## Dependency graph
![Dependency graph](../../../docs/images/graphs/dep_graph_feature_settings_api.svg)

@ -1,19 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2022 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ https://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
Copyright 2022 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<activity

@ -0,0 +1,3 @@
# :feature:topic:api module
## Dependency graph
![Dependency graph](../../../docs/images/graphs/dep_graph_feature_topic_api.svg)

@ -22,12 +22,4 @@ plugins {
android {
namespace = "com.google.samples.apps.nowinandroid.feature.topic.api"
}
dependencies {
testImplementation(projects.core.testing)
testImplementation(libs.robolectric)
androidTestImplementation(libs.bundles.androidx.compose.ui.test)
androidTestImplementation(projects.core.testing)
}

@ -21,7 +21,7 @@ import com.google.samples.apps.nowinandroid.core.navigation.NiaNavKey
import kotlinx.serialization.Serializable
@Serializable
data class TopicRoute(val id: String): NiaNavKey{
data class TopicRoute(val id: String) : NiaNavKey {
override val isTopLevel: Boolean
get() = false
}
@ -30,4 +30,4 @@ fun NiaBackStack.navigateToTopic(
topicId: String,
) {
navigate(TopicRoute(topicId))
}
}

@ -33,7 +33,7 @@ import kotlinx.serialization.modules.PolymorphicModuleBuilder
object TopicSerializerModule {
@Provides
@IntoSet
fun provideSearchPolymorphicModuleBuilder(): PolymorphicModuleBuilder<@JvmSuppressWildcards NiaNavKey>.() -> Unit = {
fun provideTopicPolymorphicModuleBuilder(): PolymorphicModuleBuilder<@JvmSuppressWildcards NiaNavKey>.() -> Unit = {
subclass(TopicRoute::class, TopicRoute.serializer())
}
}

@ -16,5 +16,4 @@
-->
<resources>
<string name="feature_topic_api_loading">Loading topic</string>
<string name="feature_topic_api_select_an_interest">Select an Interest</string>
</resources>

@ -0,0 +1,3 @@
# :feature:topic:impl module
## Dependency graph
![Dependency graph](../../../docs/images/graphs/dep_graph_feature_topic_impl.svg)

@ -1,18 +1,18 @@
/*
* Copyright 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
* Copyright 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
plugins {
alias(libs.plugins.nowinandroid.android.feature.impl)

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.feature.topic.api
package com.google.samples.apps.nowinandroid.feature.topic.impl
import androidx.activity.ComponentActivity
import androidx.compose.ui.test.hasScrollToNodeAction
@ -26,6 +26,7 @@ import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performScrollToNode
import com.google.samples.apps.nowinandroid.core.testing.data.followableTopicTestData
import com.google.samples.apps.nowinandroid.core.testing.data.userNewsResourcesTestData
import com.google.samples.apps.nowinandroid.feature.topic.api.R
import org.junit.Before
import org.junit.Rule
import org.junit.Test

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.feature.topic.api
package com.google.samples.apps.nowinandroid.feature.topic.impl
import androidx.annotation.VisibleForTesting
import androidx.compose.foundation.gestures.Orientation
@ -64,11 +64,12 @@ import com.google.samples.apps.nowinandroid.core.designsystem.theme.NiaTheme
import com.google.samples.apps.nowinandroid.core.model.data.FollowableTopic
import com.google.samples.apps.nowinandroid.core.model.data.UserNewsResource
import com.google.samples.apps.nowinandroid.core.ui.DevicePreviews
import com.google.samples.apps.nowinandroid.core.ui.R as UiR
import com.google.samples.apps.nowinandroid.core.ui.TrackScreenViewEvent
import com.google.samples.apps.nowinandroid.core.ui.TrackScrollJank
import com.google.samples.apps.nowinandroid.core.ui.UserNewsResourcePreviewParameterProvider
import com.google.samples.apps.nowinandroid.core.ui.userNewsResourceCardItems
import com.google.samples.apps.nowinandroid.feature.topic.api.R.string
import com.google.samples.apps.nowinandroid.feature.topic.api.R as TopicR
@Composable
fun TopicScreen(
@ -124,7 +125,7 @@ internal fun TopicScreen(
TopicUiState.Loading -> item {
NiaLoadingWheel(
modifier = modifier,
contentDesc = stringResource(id = string.feature_topic_api_loading),
contentDesc = stringResource(id = TopicR.string.feature_topic_api_loading),
)
}
@ -292,7 +293,7 @@ private fun TopicToolbar(
Icon(
imageVector = NiaIcons.ArrowBack,
contentDescription = stringResource(
id = com.google.samples.apps.nowinandroid.core.ui.R.string.core_ui_back,
id = UiR.string.core_ui_back,
),
)
}

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.feature.topic.api
package com.google.samples.apps.nowinandroid.feature.topic.impl
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope

@ -25,9 +25,9 @@ import com.google.samples.apps.nowinandroid.core.navigation.NiaBackStack
import com.google.samples.apps.nowinandroid.core.navigation.NiaNavKey
import com.google.samples.apps.nowinandroid.feature.topic.api.navigation.TopicRoute
import com.google.samples.apps.nowinandroid.feature.topic.api.navigation.navigateToTopic
import com.google.samples.apps.nowinandroid.feature.topic.api.TopicScreen
import com.google.samples.apps.nowinandroid.feature.topic.api.TopicViewModel
import com.google.samples.apps.nowinandroid.feature.topic.api.TopicViewModel.Factory
import com.google.samples.apps.nowinandroid.feature.topic.impl.TopicScreen
import com.google.samples.apps.nowinandroid.feature.topic.impl.TopicViewModel
import com.google.samples.apps.nowinandroid.feature.topic.impl.TopicViewModel.Factory
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
@ -36,7 +36,7 @@ import dagger.multibindings.IntoSet
@Module
@InstallIn(ActivityComponent::class)
object TopicModule {
object TopicEntryProvider {
@OptIn(ExperimentalMaterial3AdaptiveApi::class)
@Provides
@ -45,7 +45,7 @@ object TopicModule {
backStack: NiaBackStack,
): EntryProviderBuilder<NiaNavKey>.() -> Unit = {
entry<TopicRoute>(
metadata = ListDetailSceneStrategy.detailPane()
metadata = ListDetailSceneStrategy.detailPane(),
) { key ->
val id = key.id
TopicScreen(
@ -60,4 +60,4 @@ object TopicModule {
)
}
}
}
}

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.feature.topic.api
package com.google.samples.apps.nowinandroid.feature.topic.impl
import com.google.samples.apps.nowinandroid.core.data.repository.CompositeUserNewsResourceRepository
import com.google.samples.apps.nowinandroid.core.model.data.FollowableTopic

@ -0,0 +1,3 @@
# :lint module
## Dependency graph
![Dependency graph](../docs/images/graphs/dep_graph_lint.svg)

@ -0,0 +1,3 @@
# :ui-test-hilt-manifest module
## Dependency graph
![Dependency graph](../docs/images/graphs/dep_graph_ui_test_hilt_manifest.svg)
Loading…
Cancel
Save