From f05095ffaef16cb52e3f5dbb1fc463fe3dc4035f Mon Sep 17 00:00:00 2001 From: Matt Ramotar Date: Sat, 11 May 2024 08:32:33 -0400 Subject: [PATCH] Use Swipe --- .../sample/scoop/android/app/build.gradle.kts | 1 + .../monster/scoop/android/app/MainActivity.kt | 21 +- .../android/app/circuit/ScoopUiFactory.kt | 2 +- .../scoop/tooling/plugins/build.gradle.kts | 5 + ...linComposeMultiplatformConventionPlugin.kt | 103 +++++++ .../KotlinMultiplatformConventionPlugin.kt | 2 +- .../xplat/common/market/build.gradle.kts | 2 +- .../xplat/domain/story/api/build.gradle.kts | 2 +- .../xplat/domain/story/impl/build.gradle.kts | 2 +- .../xplat/feat/homeTab/impl/build.gradle.kts | 3 + .../xplat/feat/homeTab/impl/HomeTabUi.kt | 62 ---- .../xplat/feat/homeTab/impl/ui/HomeTabUi.kt | 23 ++ .../homeTab/impl/ui/compose/HomeTabFeed.kt | 256 +++++++++++++++++ .../foundation/designSystem/build.gradle.kts | 34 +++ .../foundation/designSystem/theme/Color.kt | 219 +++++++++++++++ .../foundation/designSystem/theme/Theme.kt | 264 ++++++++++++++++++ .../xplat/foundation/di/build.gradle.kts | 2 +- gradle/libs.versions.toml | 9 +- settings.gradle | 3 +- 19 files changed, 939 insertions(+), 76 deletions(-) create mode 100644 experimental/sample/scoop/tooling/plugins/src/main/kotlin/monster/scoop/tooling/plugins/KotlinComposeMultiplatformConventionPlugin.kt delete mode 100644 experimental/sample/scoop/xplat/feat/homeTab/impl/src/commonMain/kotlin/monster/scoop/xplat/feat/homeTab/impl/HomeTabUi.kt create mode 100644 experimental/sample/scoop/xplat/feat/homeTab/impl/src/commonMain/kotlin/monster/scoop/xplat/feat/homeTab/impl/ui/HomeTabUi.kt create mode 100644 experimental/sample/scoop/xplat/feat/homeTab/impl/src/commonMain/kotlin/monster/scoop/xplat/feat/homeTab/impl/ui/compose/HomeTabFeed.kt create mode 100644 experimental/sample/scoop/xplat/foundation/designSystem/build.gradle.kts create mode 100644 experimental/sample/scoop/xplat/foundation/designSystem/src/commonMain/kotlin/monster/scoop/xplat/foundation/designSystem/theme/Color.kt create mode 100644 experimental/sample/scoop/xplat/foundation/designSystem/src/commonMain/kotlin/monster/scoop/xplat/foundation/designSystem/theme/Theme.kt diff --git a/experimental/sample/scoop/android/app/build.gradle.kts b/experimental/sample/scoop/android/app/build.gradle.kts index a7bc3b9de..183001a85 100644 --- a/experimental/sample/scoop/android/app/build.gradle.kts +++ b/experimental/sample/scoop/android/app/build.gradle.kts @@ -43,6 +43,7 @@ dependencies { implementation(libs.ktor.negotiation) implementation(libs.compose.webview.multiplatform) + implementation(project(":experimental:sample:scoop:xplat:foundation:designSystem")) implementation(project(":experimental:market")) implementation(project(":experimental:market:warehouse")) diff --git a/experimental/sample/scoop/android/app/src/main/kotlin/monster/scoop/android/app/MainActivity.kt b/experimental/sample/scoop/android/app/src/main/kotlin/monster/scoop/android/app/MainActivity.kt index cb6adc255..5d7f18148 100644 --- a/experimental/sample/scoop/android/app/src/main/kotlin/monster/scoop/android/app/MainActivity.kt +++ b/experimental/sample/scoop/android/app/src/main/kotlin/monster/scoop/android/app/MainActivity.kt @@ -5,6 +5,12 @@ import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.background import androidx.compose.foundation.layout.padding +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.twotone.Home +import androidx.compose.material.icons.twotone.Person +import androidx.compose.material.icons.twotone.Search +import androidx.compose.material3.BottomAppBar +import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.runtime.remember @@ -14,7 +20,7 @@ import com.slack.circuit.foundation.* import me.tatarka.inject.annotations.Inject import monster.scoop.android.app.di.CoreComponent import monster.scoop.android.app.di.create -import monster.scoop.android.app.theme.ScoopTheme +import monster.scoop.xplat.foundation.designSystem.theme.AppTheme @Inject @@ -42,8 +48,17 @@ class MainActivity : ComponentActivity() { val navigator = rememberCircuitNavigator(backStack) CircuitCompositionLocals(circuit) { - ScoopTheme { - Scaffold { innerPadding -> + + AppTheme(true) { + Scaffold( + bottomBar = { + BottomAppBar { + Icon(Icons.TwoTone.Home, "Home") + Icon(Icons.TwoTone.Search, "Search") + Icon(Icons.TwoTone.Person, "Person") + } + } + ) { innerPadding -> NavigableCircuitContent( navigator, backStack, diff --git a/experimental/sample/scoop/android/app/src/main/kotlin/monster/scoop/android/app/circuit/ScoopUiFactory.kt b/experimental/sample/scoop/android/app/src/main/kotlin/monster/scoop/android/app/circuit/ScoopUiFactory.kt index 1dd050fd4..214a2d204 100644 --- a/experimental/sample/scoop/android/app/src/main/kotlin/monster/scoop/android/app/circuit/ScoopUiFactory.kt +++ b/experimental/sample/scoop/android/app/src/main/kotlin/monster/scoop/android/app/circuit/ScoopUiFactory.kt @@ -5,7 +5,7 @@ import com.slack.circuit.runtime.screen.Screen import com.slack.circuit.runtime.ui.Ui import me.tatarka.inject.annotations.Inject import monster.scoop.xplat.feat.homeTab.api.HomeTab -import monster.scoop.xplat.feat.homeTab.impl.HomeTabUi +import monster.scoop.xplat.feat.homeTab.impl.ui.HomeTabUi import monster.scoop.xplat.foundation.di.UserScope @Inject diff --git a/experimental/sample/scoop/tooling/plugins/build.gradle.kts b/experimental/sample/scoop/tooling/plugins/build.gradle.kts index f0d1804fc..582f58c6e 100644 --- a/experimental/sample/scoop/tooling/plugins/build.gradle.kts +++ b/experimental/sample/scoop/tooling/plugins/build.gradle.kts @@ -44,5 +44,10 @@ gradlePlugin { id = "plugin.scoop.kotlin.multiplatform" implementationClass = "monster.scoop.tooling.plugins.KotlinMultiplatformConventionPlugin" } + + register("kotlinComposeMultiplatformPlugin") { + id = "plugin.scoop.kotlin.compose.multiplatform" + implementationClass = "monster.scoop.tooling.plugins.KotlinComposeMultiplatformConventionPlugin" + } } } diff --git a/experimental/sample/scoop/tooling/plugins/src/main/kotlin/monster/scoop/tooling/plugins/KotlinComposeMultiplatformConventionPlugin.kt b/experimental/sample/scoop/tooling/plugins/src/main/kotlin/monster/scoop/tooling/plugins/KotlinComposeMultiplatformConventionPlugin.kt new file mode 100644 index 000000000..2bca48d01 --- /dev/null +++ b/experimental/sample/scoop/tooling/plugins/src/main/kotlin/monster/scoop/tooling/plugins/KotlinComposeMultiplatformConventionPlugin.kt @@ -0,0 +1,103 @@ +package monster.scoop.tooling.plugins + +import com.android.build.gradle.LibraryExtension +import monster.scoop.tooling.extensions.configureAndroidCompose +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.configurationcache.extensions.capitalized +import org.gradle.kotlin.dsl.configure +import org.gradle.kotlin.dsl.dependencies +import org.gradle.kotlin.dsl.getByType +import org.gradle.kotlin.dsl.withType +import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension +import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType +import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget +import monster.scoop.tooling.extensions.configureKotlin +import monster.scoop.tooling.extensions.libs + +class KotlinComposeMultiplatformConventionPlugin : Plugin { + override fun apply(target: Project) = with(target) { + with(pluginManager) { + apply("org.jetbrains.kotlin.multiplatform") + } + + version = libs.findVersion("scoop") + + extensions.configure { + applyDefaultHierarchyTemplate() + + if (pluginManager.hasPlugin("com.android.library")) { + androidTarget() + } + + jvm() + + iosX64() + iosArm64() + iosSimulatorArm64() + + targets.all { + compilations.all { + compilerOptions.configure { + freeCompilerArgs.add("-Xexpect-actual-classes") + } + } + } + + targets.withType().configureEach { + compilations.configureEach { + compilerOptions.configure { + freeCompilerArgs.add("-Xallocator=custom") + freeCompilerArgs.add("-XXLanguage:+ImplicitSignedToUnsignedIntegerConversion") + freeCompilerArgs.add("-Xadd-light-debug=enable") + + freeCompilerArgs.addAll( + "-opt-in=kotlin.RequiresOptIn", + "-opt-in=kotlin.time.ExperimentalTime", + "-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi", + "-opt-in=kotlinx.coroutines.FlowPreview", + "-opt-in=kotlinx.cinterop.ExperimentalForeignApi", + "-opt-in=kotlinx.cinterop.BetaInteropApi", + + ) + } + } + } + + configureKotlin() + + } + + extensions.configure { + buildFeatures { + compose = true + } + + composeOptions { + kotlinCompilerExtensionVersion = libs.findVersion("compose-compiler").get().toString() + } + } + + } +} + + +private fun Project.addKspDependencyForAllTargets( + configurationNameSuffix: String, + dependencyNotation: Any, +) { + val kmpExtension = extensions.getByType() + dependencies { + kmpExtension.targets + .asSequence() + .filter { target -> + target.platformType != KotlinPlatformType.common + } + .forEach { target -> + add( + "ksp${target.targetName.capitalized()}$configurationNameSuffix", + dependencyNotation, + ) + } + } +} \ No newline at end of file diff --git a/experimental/sample/scoop/tooling/plugins/src/main/kotlin/monster/scoop/tooling/plugins/KotlinMultiplatformConventionPlugin.kt b/experimental/sample/scoop/tooling/plugins/src/main/kotlin/monster/scoop/tooling/plugins/KotlinMultiplatformConventionPlugin.kt index 8d1c1bb16..0e2ad8335 100644 --- a/experimental/sample/scoop/tooling/plugins/src/main/kotlin/monster/scoop/tooling/plugins/KotlinMultiplatformConventionPlugin.kt +++ b/experimental/sample/scoop/tooling/plugins/src/main/kotlin/monster/scoop/tooling/plugins/KotlinMultiplatformConventionPlugin.kt @@ -19,7 +19,7 @@ class KotlinMultiplatformConventionPlugin : Plugin { apply("org.jetbrains.kotlin.multiplatform") } - version = libs.findVersion("trails") + version = libs.findVersion("scoop") extensions.configure { applyDefaultHierarchyTemplate() diff --git a/experimental/sample/scoop/xplat/common/market/build.gradle.kts b/experimental/sample/scoop/xplat/common/market/build.gradle.kts index b74563967..cc24439ce 100644 --- a/experimental/sample/scoop/xplat/common/market/build.gradle.kts +++ b/experimental/sample/scoop/xplat/common/market/build.gradle.kts @@ -24,4 +24,4 @@ kotlin { android { namespace = "monster.scoop.xplat.common.market" -} \ No newline at end of file +} diff --git a/experimental/sample/scoop/xplat/domain/story/api/build.gradle.kts b/experimental/sample/scoop/xplat/domain/story/api/build.gradle.kts index fa29b4919..da964076c 100644 --- a/experimental/sample/scoop/xplat/domain/story/api/build.gradle.kts +++ b/experimental/sample/scoop/xplat/domain/story/api/build.gradle.kts @@ -25,4 +25,4 @@ kotlin { android { namespace = "monster.scoop.xplat.domain.story.api" -} \ No newline at end of file +} diff --git a/experimental/sample/scoop/xplat/domain/story/impl/build.gradle.kts b/experimental/sample/scoop/xplat/domain/story/impl/build.gradle.kts index 8095c4675..0827c01dc 100644 --- a/experimental/sample/scoop/xplat/domain/story/impl/build.gradle.kts +++ b/experimental/sample/scoop/xplat/domain/story/impl/build.gradle.kts @@ -42,4 +42,4 @@ dependencies { android { namespace = "monster.scoop.xplat.domain.story.impl" -} \ No newline at end of file +} diff --git a/experimental/sample/scoop/xplat/feat/homeTab/impl/build.gradle.kts b/experimental/sample/scoop/xplat/feat/homeTab/impl/build.gradle.kts index 96cc74df1..69ede6dfc 100644 --- a/experimental/sample/scoop/xplat/feat/homeTab/impl/build.gradle.kts +++ b/experimental/sample/scoop/xplat/feat/homeTab/impl/build.gradle.kts @@ -19,6 +19,7 @@ kotlin { implementation(compose.material3) implementation(libs.kotlinx.coroutines.core) implementation(libs.kotlinInject.runtime) + implementation(compose.materialIconsExtended) api(project(":experimental:market:warehouse")) api(project(":experimental:sample:scoop:xplat:common:market")) @@ -27,6 +28,8 @@ kotlin { implementation(libs.coil.compose) implementation(libs.coil.network) implementation(libs.ktor.core) + implementation(libs.swipe) + implementation(compose.components.uiToolingPreview) } } diff --git a/experimental/sample/scoop/xplat/feat/homeTab/impl/src/commonMain/kotlin/monster/scoop/xplat/feat/homeTab/impl/HomeTabUi.kt b/experimental/sample/scoop/xplat/feat/homeTab/impl/src/commonMain/kotlin/monster/scoop/xplat/feat/homeTab/impl/HomeTabUi.kt deleted file mode 100644 index 522708b44..000000000 --- a/experimental/sample/scoop/xplat/feat/homeTab/impl/src/commonMain/kotlin/monster/scoop/xplat/feat/homeTab/impl/HomeTabUi.kt +++ /dev/null @@ -1,62 +0,0 @@ -package monster.scoop.xplat.feat.homeTab.impl - -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import coil3.compose.AsyncImage -import me.tatarka.inject.annotations.Inject -import monster.scoop.xplat.feat.homeTab.api.HomeTab -import monster.scoop.xplat.feat.homeTab.api.HomeTabStory - -@Inject -class HomeTabUi : HomeTab.Ui { - @Composable - override fun Content(state: HomeTab.State, modifier: Modifier) { - Column { - HomeTabFeed(state.stories) - } - } - - @Composable - private fun HomeTabFeed(stories: List) { - - LazyColumn { - - stories.forEach { story -> - when (story) { - is HomeTabStory.Loaded -> { - item { - HomeTabFeedItem(story) - } - } - - HomeTabStory.Placeholder -> { - item { - HomeTabPlaceholderItem() - } - } - } - } - } - } - - @Composable - private fun HomeTabFeedItem(story: HomeTabStory.Loaded) { - Column { - story.imageUrl?.let { - AsyncImage(it, null) - } - Text(story.title, color = Color.White) - } - } - - @Composable - private fun HomeTabPlaceholderItem() { - Column { - Text("Placeholder", color = Color.White) - } - } -} \ No newline at end of file diff --git a/experimental/sample/scoop/xplat/feat/homeTab/impl/src/commonMain/kotlin/monster/scoop/xplat/feat/homeTab/impl/ui/HomeTabUi.kt b/experimental/sample/scoop/xplat/feat/homeTab/impl/src/commonMain/kotlin/monster/scoop/xplat/feat/homeTab/impl/ui/HomeTabUi.kt new file mode 100644 index 000000000..dbbd650bd --- /dev/null +++ b/experimental/sample/scoop/xplat/feat/homeTab/impl/src/commonMain/kotlin/monster/scoop/xplat/feat/homeTab/impl/ui/HomeTabUi.kt @@ -0,0 +1,23 @@ +package monster.scoop.xplat.feat.homeTab.impl.ui + + +import androidx.compose.foundation.layout.Column +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import me.tatarka.inject.annotations.Inject +import monster.scoop.xplat.feat.homeTab.api.HomeTab +import monster.scoop.xplat.feat.homeTab.impl.ui.compose.HomeTabFeed + +@Inject +class HomeTabUi : HomeTab.Ui { + @Composable + override fun Content(state: HomeTab.State, modifier: Modifier) { + Column { + if (state.stories.isEmpty()) { + // Show loading indicator + } else { + HomeTabFeed(state.stories) + } + } + } +} diff --git a/experimental/sample/scoop/xplat/feat/homeTab/impl/src/commonMain/kotlin/monster/scoop/xplat/feat/homeTab/impl/ui/compose/HomeTabFeed.kt b/experimental/sample/scoop/xplat/feat/homeTab/impl/src/commonMain/kotlin/monster/scoop/xplat/feat/homeTab/impl/ui/compose/HomeTabFeed.kt new file mode 100644 index 000000000..0230b6773 --- /dev/null +++ b/experimental/sample/scoop/xplat/feat/homeTab/impl/src/commonMain/kotlin/monster/scoop/xplat/feat/homeTab/impl/ui/compose/HomeTabFeed.kt @@ -0,0 +1,256 @@ +package monster.scoop.xplat.feat.homeTab.impl.ui.compose + +import androidx.compose.animation.animateContentSize +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.twotone.ReplyAll +import androidx.compose.material.icons.twotone.Archive +import androidx.compose.material.icons.twotone.Snooze +import androidx.compose.material3.* +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.shadow +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.RectangleShape +import androidx.compose.ui.graphics.vector.rememberVectorPainter +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.unit.dp +import coil3.compose.AsyncImage +import me.saket.swipe.SwipeAction +import me.saket.swipe.SwipeableActionsBox +import monster.scoop.xplat.feat.homeTab.api.HomeTabStory + +@Composable +internal fun HomeTabFeed(stories: List) { + val (trendingStories, otherStories) = stories.partition { stories.indexOf(it) < 5 } + + LazyColumn(verticalArrangement = Arrangement.spacedBy(12.dp)) { + item { + TrendingStories(trendingStories.filterIsInstance()) + } + + items(otherStories) { story -> + when (story) { + is HomeTabStory.Loaded -> HomeTabFeedItem(story) + HomeTabStory.Placeholder -> HomeTabPlaceholderItem() + } + } + } +} + +@Composable +private fun HomeTabFeedItem(story: HomeTabStory.Loaded) { + Card( + onClick = {}, + modifier = Modifier.fillMaxWidth(), + shape = RectangleShape, + colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.background), + ) { + SwipeableHomeTabFeedItem { isSnoozed, isArchived -> + HomeTabStoryContent(story, isSnoozed = isSnoozed, isArchived = isArchived) + } + } +} + +@Composable +private fun HomeTabPlaceholderItem() { + Card(onClick = {}, modifier = Modifier, enabled = true) { + Text("Placeholder") + } +} + + +@Composable +private fun TrendingStories(stories: List) { + Column(modifier = Modifier.background(MaterialTheme.colorScheme.surfaceColorAtElevation(8.dp))) { + Text("Trending Stories", style = MaterialTheme.typography.headlineSmall) + + stories.forEachIndexed { index, story -> + + SwipeableHomeTabFeedItem { isSnoozed, isArchived -> + + HomeTabStoryContent( + story = story, + index = index, + divider = index != stories.lastIndex, + isSnoozed = isSnoozed, + isArchived = isArchived, + isTrending = true + ) + } + } + } +} + +@Composable +private fun HomeTabStoryContent( + story: HomeTabStory.Loaded, + modifier: Modifier = Modifier, + index: Int = 0, + divider: Boolean = false, + isSnoozed: Boolean = false, + isArchived: Boolean = false, + isTrending: Boolean = false +) { + val contentModifier = modifier + .fillMaxWidth() + .shadow(1.dp) + .background(MaterialTheme.colorScheme.surfaceColorAtElevation(8.dp)) + .padding(vertical = 16.dp, horizontal = 20.dp) + .animateContentSize() + + if (isTrending) { + Column(contentModifier) { + TrendingStoryContent(story, index, divider, isSnoozed, isArchived) + } + } else { + Row(contentModifier) { + FeedItemContent(story, isSnoozed, isArchived, Modifier.weight(0.6f)) + } + } +} + +@Composable +private fun FeedItemContent( + story: HomeTabStory.Loaded, + isSnoozed: Boolean, + isArchived: Boolean, + modifier: Modifier = Modifier +) { + + HomeTabStoryInfo(story, isSnoozed, isArchived, modifier.padding(horizontal = 16.dp)) + + story.imageUrl?.let { + AsyncImage(it, null, modifier = Modifier.size(100.dp), contentScale = ContentScale.Crop) + } +} + +@Composable +private fun TrendingStoryContent( + story: HomeTabStory.Loaded, + index: Int, + divider: Boolean, + isSnoozed: Boolean, + isArchived: Boolean, + modifier: Modifier = Modifier +) { + Row( + modifier + .fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically + ) { + Box( + Modifier + .padding(top = 2.dp) + .size(52.dp) + .background(MaterialTheme.colorScheme.primary, CircleShape), + contentAlignment = Alignment.Center + ) { + Text((index + 1).toString()) + } + + HomeTabStoryInfo( + story, isSnoozed, isArchived, modifier = Modifier + .padding(horizontal = 16.dp) + .fillMaxHeight() + ) + } + + if (divider) { + HorizontalDivider(modifier = Modifier.padding(start = (52 + 16).dp, top = 16.dp)) + } +} + +@Composable +private fun HomeTabStoryInfo( + story: HomeTabStory.Loaded, + isSnoozed: Boolean, + isArchived: Boolean, + modifier: Modifier = Modifier +) { + Column( + modifier, + verticalArrangement = Arrangement.Center + ) { + Text( + text = story.title, + style = MaterialTheme.typography.titleSmall + ) + + if (isSnoozed) { + Text( + modifier = Modifier + .padding(top = 16.dp) + .background(Color.SeaBuckthorn.copy(alpha = 0.4f), RoundedCornerShape(4.dp)) + .padding(horizontal = 8.dp, vertical = 4.dp), + text = "Snoozed until tomorrow", + style = MaterialTheme.typography.labelLarge + ) + } + + if (isArchived) { + Text( + modifier = Modifier + .padding(top = 16.dp) + .background(Color.Fern.copy(alpha = 0.4f), RoundedCornerShape(4.dp)) + .padding(horizontal = 8.dp, vertical = 4.dp), + text = "Archived", + style = MaterialTheme.typography.labelLarge + ) + } + } +} + +@Composable +private fun SwipeableHomeTabFeedItem( + modifier: Modifier = Modifier, + content: @Composable (isSnoozed: Boolean, isArchived: Boolean) -> Unit +) { + var isSnoozed by rememberSaveable { mutableStateOf(false) } + var isArchived by rememberSaveable { mutableStateOf(false) } + + val swipeActions = listOf( + SwipeAction( + icon = rememberVectorPainter(Icons.AutoMirrored.TwoTone.ReplyAll), + background = Color.Perfume, + onSwipe = { /* Handle reply action */ }, + isUndo = false + ), + SwipeAction( + icon = rememberVectorPainter(Icons.TwoTone.Snooze), + background = Color.SeaBuckthorn, + onSwipe = { isSnoozed = !isSnoozed }, + isUndo = isSnoozed + ), + SwipeAction( + icon = rememberVectorPainter(Icons.TwoTone.Archive), + background = Color.Fern, + onSwipe = { isArchived = !isArchived }, + isUndo = isArchived + ) + ) + + SwipeableActionsBox( + modifier = modifier, + startActions = swipeActions.take(1), + endActions = swipeActions.drop(1), + swipeThreshold = 40.dp, + backgroundUntilSwipeThreshold = MaterialTheme.colorScheme.surfaceColorAtElevation(40.dp) + ) { + content(isSnoozed, isArchived) + } +} + +private val Color.Companion.SeaBuckthorn get() = Color(0xFFF9A825) +private val Color.Companion.Fern get() = Color(0xFF66BB6A) +private val Color.Companion.Perfume get() = Color(0xFFD0BCFF) \ No newline at end of file diff --git a/experimental/sample/scoop/xplat/foundation/designSystem/build.gradle.kts b/experimental/sample/scoop/xplat/foundation/designSystem/build.gradle.kts new file mode 100644 index 000000000..9ff1e0d88 --- /dev/null +++ b/experimental/sample/scoop/xplat/foundation/designSystem/build.gradle.kts @@ -0,0 +1,34 @@ +plugins { + id("plugin.scoop.android.library") + id("plugin.scoop.kotlin.compose.multiplatform") + alias(libs.plugins.serialization) + alias(libs.plugins.compose) +} + +kotlin { + sourceSets { + commonMain { + dependencies { + api(compose.runtime) + api(compose.ui) + api(compose.foundation) + api(compose.material3) + api(compose.components.resources) + api(libs.circuit.foundation) + implementation(libs.kotlinInject.runtime) + + implementation(compose.material3) + implementation(libs.kotlinx.coroutines.core) + implementation(libs.kotlinInject.runtime) + implementation(compose.materialIconsExtended) + + implementation(libs.swipe) + implementation(compose.components.uiToolingPreview) + } + } + } +} + +android { + namespace = "monster.scoop.xplat.foundation.designSystem" +} diff --git a/experimental/sample/scoop/xplat/foundation/designSystem/src/commonMain/kotlin/monster/scoop/xplat/foundation/designSystem/theme/Color.kt b/experimental/sample/scoop/xplat/foundation/designSystem/src/commonMain/kotlin/monster/scoop/xplat/foundation/designSystem/theme/Color.kt new file mode 100644 index 000000000..7f1d4c31b --- /dev/null +++ b/experimental/sample/scoop/xplat/foundation/designSystem/src/commonMain/kotlin/monster/scoop/xplat/foundation/designSystem/theme/Color.kt @@ -0,0 +1,219 @@ +package monster.scoop.xplat.foundation.designSystem.theme + +import androidx.compose.ui.graphics.Color + +val primaryLight = Color(0xFF006399) +val onPrimaryLight = Color(0xFFFFFFFF) +val primaryContainerLight = Color(0xFF35ADFF) +val onPrimaryContainerLight = Color(0xFF001D31) +val secondaryLight = Color(0xFF000000) +val onSecondaryLight = Color(0xFFFFFFFF) +val secondaryContainerLight = Color(0xFF232629) +val onSecondaryContainerLight = Color(0xFFAFB1B5) +val tertiaryLight = Color(0xFF415260) +val onTertiaryLight = Color(0xFFFFFFFF) +val tertiaryContainerLight = Color(0xFF657786) +val onTertiaryContainerLight = Color(0xFFFFFFFF) +val errorLight = Color(0xFFBA1A1A) +val onErrorLight = Color(0xFFFFFFFF) +val errorContainerLight = Color(0xFFFFDAD6) +val onErrorContainerLight = Color(0xFF410002) +val backgroundLight = Color(0xFFF7F9FF) +val onBackgroundLight = Color(0xFF171C21) +val surfaceLight = Color(0xFFFCF9F8) +val onSurfaceLight = Color(0xFF1B1B1C) +val surfaceVariantLight = Color(0xFFDFE3E7) +val onSurfaceVariantLight = Color(0xFF43474A) +val outlineLight = Color(0xFF74777B) +val outlineVariantLight = Color(0xFFC3C7CB) +val scrimLight = Color(0xFF000000) +val inverseSurfaceLight = Color(0xFF303030) +val inverseOnSurfaceLight = Color(0xFFF3F0F0) +val inversePrimaryLight = Color(0xFF95CCFF) +val surfaceDimLight = Color(0xFFDCD9D9) +val surfaceBrightLight = Color(0xFFFCF9F8) +val surfaceContainerLowestLight = Color(0xFFFFFFFF) +val surfaceContainerLowLight = Color(0xFFF6F3F3) +val surfaceContainerLight = Color(0xFFF0EDED) +val surfaceContainerHighLight = Color(0xFFEAE7E7) +val surfaceContainerHighestLight = Color(0xFFE5E2E2) + +val primaryLightMediumContrast = Color(0xFF00466F) +val onPrimaryLightMediumContrast = Color(0xFFFFFFFF) +val primaryContainerLightMediumContrast = Color(0xFF007ABC) +val onPrimaryContainerLightMediumContrast = Color(0xFFFFFFFF) +val secondaryLightMediumContrast = Color(0xFF000000) +val onSecondaryLightMediumContrast = Color(0xFFFFFFFF) +val secondaryContainerLightMediumContrast = Color(0xFF232629) +val onSecondaryContainerLightMediumContrast = Color(0xFFDBDCE0) +val tertiaryLightMediumContrast = Color(0xFF334552) +val onTertiaryLightMediumContrast = Color(0xFFFFFFFF) +val tertiaryContainerLightMediumContrast = Color(0xFF657786) +val onTertiaryContainerLightMediumContrast = Color(0xFFFFFFFF) +val errorLightMediumContrast = Color(0xFF8C0009) +val onErrorLightMediumContrast = Color(0xFFFFFFFF) +val errorContainerLightMediumContrast = Color(0xFFDA342E) +val onErrorContainerLightMediumContrast = Color(0xFFFFFFFF) +val backgroundLightMediumContrast = Color(0xFFF7F9FF) +val onBackgroundLightMediumContrast = Color(0xFF171C21) +val surfaceLightMediumContrast = Color(0xFFFCF9F8) +val onSurfaceLightMediumContrast = Color(0xFF1B1B1C) +val surfaceVariantLightMediumContrast = Color(0xFFDFE3E7) +val onSurfaceVariantLightMediumContrast = Color(0xFF3F4346) +val outlineLightMediumContrast = Color(0xFF5B6063) +val outlineVariantLightMediumContrast = Color(0xFF777B7F) +val scrimLightMediumContrast = Color(0xFF000000) +val inverseSurfaceLightMediumContrast = Color(0xFF303030) +val inverseOnSurfaceLightMediumContrast = Color(0xFFF3F0F0) +val inversePrimaryLightMediumContrast = Color(0xFF95CCFF) +val surfaceDimLightMediumContrast = Color(0xFFDCD9D9) +val surfaceBrightLightMediumContrast = Color(0xFFFCF9F8) +val surfaceContainerLowestLightMediumContrast = Color(0xFFFFFFFF) +val surfaceContainerLowLightMediumContrast = Color(0xFFF6F3F3) +val surfaceContainerLightMediumContrast = Color(0xFFF0EDED) +val surfaceContainerHighLightMediumContrast = Color(0xFFEAE7E7) +val surfaceContainerHighestLightMediumContrast = Color(0xFFE5E2E2) + +val primaryLightHighContrast = Color(0xFF00243C) +val onPrimaryLightHighContrast = Color(0xFFFFFFFF) +val primaryContainerLightHighContrast = Color(0xFF00466F) +val onPrimaryContainerLightHighContrast = Color(0xFFFFFFFF) +val secondaryLightHighContrast = Color(0xFF000000) +val onSecondaryLightHighContrast = Color(0xFFFFFFFF) +val secondaryContainerLightHighContrast = Color(0xFF232629) +val onSecondaryContainerLightHighContrast = Color(0xFFFFFFFF) +val tertiaryLightHighContrast = Color(0xFF122431) +val onTertiaryLightHighContrast = Color(0xFFFFFFFF) +val tertiaryContainerLightHighContrast = Color(0xFF334552) +val onTertiaryContainerLightHighContrast = Color(0xFFFFFFFF) +val errorLightHighContrast = Color(0xFF4E0002) +val onErrorLightHighContrast = Color(0xFFFFFFFF) +val errorContainerLightHighContrast = Color(0xFF8C0009) +val onErrorContainerLightHighContrast = Color(0xFFFFFFFF) +val backgroundLightHighContrast = Color(0xFFF7F9FF) +val onBackgroundLightHighContrast = Color(0xFF171C21) +val surfaceLightHighContrast = Color(0xFFFCF9F8) +val onSurfaceLightHighContrast = Color(0xFF000000) +val surfaceVariantLightHighContrast = Color(0xFFDFE3E7) +val onSurfaceVariantLightHighContrast = Color(0xFF202427) +val outlineLightHighContrast = Color(0xFF3F4346) +val outlineVariantLightHighContrast = Color(0xFF3F4346) +val scrimLightHighContrast = Color(0xFF000000) +val inverseSurfaceLightHighContrast = Color(0xFF303030) +val inverseOnSurfaceLightHighContrast = Color(0xFFFFFFFF) +val inversePrimaryLightHighContrast = Color(0xFFDFEEFF) +val surfaceDimLightHighContrast = Color(0xFFDCD9D9) +val surfaceBrightLightHighContrast = Color(0xFFFCF9F8) +val surfaceContainerLowestLightHighContrast = Color(0xFFFFFFFF) +val surfaceContainerLowLightHighContrast = Color(0xFFF6F3F3) +val surfaceContainerLightHighContrast = Color(0xFFF0EDED) +val surfaceContainerHighLightHighContrast = Color(0xFFEAE7E7) +val surfaceContainerHighestLightHighContrast = Color(0xFFE5E2E2) + +val primaryDark = Color(0xFF95CCFF) +val onPrimaryDark = Color(0xFF003352) +val primaryContainerDark = Color(0xFF0099E9) +val onPrimaryContainerDark = Color(0xFF000000) +val secondaryDark = Color(0xFFC5C6CA) +val onSecondaryDark = Color(0xFF2E3134) +val secondaryContainerDark = Color(0xFF0D1013) +val onSecondaryContainerDark = Color(0xFF9C9EA2) +val tertiaryDark = Color(0xFFB6C9DA) +val onTertiaryDark = Color(0xFF21323F) +val tertiaryContainerDark = Color(0xFF5B6D7C) +val onTertiaryContainerDark = Color(0xFFFFFFFF) +val errorDark = Color(0xFFFFB4AB) +val onErrorDark = Color(0xFF690005) +val errorContainerDark = Color(0xFF93000A) +val onErrorContainerDark = Color(0xFFFFDAD6) +val backgroundDark = Color(0xFF0F1419) +val onBackgroundDark = Color(0xFFDFE3EA) +val surfaceDark = Color(0xFF131314) +val onSurfaceDark = Color(0xFFE5E2E2) +val surfaceVariantDark = Color(0xFF43474A) +val onSurfaceVariantDark = Color(0xFFC3C7CB) +val outlineDark = Color(0xFF8D9195) +val outlineVariantDark = Color(0xFF43474A) +val scrimDark = Color(0xFF000000) +val inverseSurfaceDark = Color(0xFFE5E2E2) +val inverseOnSurfaceDark = Color(0xFF303030) +val inversePrimaryDark = Color(0xFF006399) +val surfaceDimDark = Color(0xFF131314) +val surfaceBrightDark = Color(0xFF393939) +val surfaceContainerLowestDark = Color(0xFF0E0E0E) +val surfaceContainerLowDark = Color(0xFF1B1B1C) +val surfaceContainerDark = Color(0xFF201F20) +val surfaceContainerHighDark = Color(0xFF2A2A2A) +val surfaceContainerHighestDark = Color(0xFF353535) + +val primaryDarkMediumContrast = Color(0xFF9ED0FF) +val onPrimaryDarkMediumContrast = Color(0xFF00182A) +val primaryContainerDarkMediumContrast = Color(0xFF0099E9) +val onPrimaryContainerDarkMediumContrast = Color(0xFF000000) +val secondaryDarkMediumContrast = Color(0xFFC9CBCF) +val onSecondaryDarkMediumContrast = Color(0xFF14171A) +val secondaryContainerDarkMediumContrast = Color(0xFF8E9195) +val onSecondaryContainerDarkMediumContrast = Color(0xFF000000) +val tertiaryDarkMediumContrast = Color(0xFFBACDDE) +val onTertiaryDarkMediumContrast = Color(0xFF051824) +val tertiaryContainerDarkMediumContrast = Color(0xFF8193A3) +val onTertiaryContainerDarkMediumContrast = Color(0xFF000000) +val errorDarkMediumContrast = Color(0xFFFFBAB1) +val onErrorDarkMediumContrast = Color(0xFF370001) +val errorContainerDarkMediumContrast = Color(0xFFFF5449) +val onErrorContainerDarkMediumContrast = Color(0xFF000000) +val backgroundDarkMediumContrast = Color(0xFF0F1419) +val onBackgroundDarkMediumContrast = Color(0xFFDFE3EA) +val surfaceDarkMediumContrast = Color(0xFF131314) +val onSurfaceDarkMediumContrast = Color(0xFFFDFAFA) +val surfaceVariantDarkMediumContrast = Color(0xFF43474A) +val onSurfaceVariantDarkMediumContrast = Color(0xFFC8CBCF) +val outlineDarkMediumContrast = Color(0xFFA0A3A7) +val outlineVariantDarkMediumContrast = Color(0xFF808487) +val scrimDarkMediumContrast = Color(0xFF000000) +val inverseSurfaceDarkMediumContrast = Color(0xFFE5E2E2) +val inverseOnSurfaceDarkMediumContrast = Color(0xFF2A2A2A) +val inversePrimaryDarkMediumContrast = Color(0xFF004C77) +val surfaceDimDarkMediumContrast = Color(0xFF131314) +val surfaceBrightDarkMediumContrast = Color(0xFF393939) +val surfaceContainerLowestDarkMediumContrast = Color(0xFF0E0E0E) +val surfaceContainerLowDarkMediumContrast = Color(0xFF1B1B1C) +val surfaceContainerDarkMediumContrast = Color(0xFF201F20) +val surfaceContainerHighDarkMediumContrast = Color(0xFF2A2A2A) +val surfaceContainerHighestDarkMediumContrast = Color(0xFF353535) + +val primaryDarkHighContrast = Color(0xFFF9FAFF) +val onPrimaryDarkHighContrast = Color(0xFF000000) +val primaryContainerDarkHighContrast = Color(0xFF9ED0FF) +val onPrimaryContainerDarkHighContrast = Color(0xFF000000) +val secondaryDarkHighContrast = Color(0xFFF9FBFF) +val onSecondaryDarkHighContrast = Color(0xFF000000) +val secondaryContainerDarkHighContrast = Color(0xFFC9CBCF) +val onSecondaryContainerDarkHighContrast = Color(0xFF000000) +val tertiaryDarkHighContrast = Color(0xFFF9FBFF) +val onTertiaryDarkHighContrast = Color(0xFF000000) +val tertiaryContainerDarkHighContrast = Color(0xFFBACDDE) +val onTertiaryContainerDarkHighContrast = Color(0xFF000000) +val errorDarkHighContrast = Color(0xFFFFF9F9) +val onErrorDarkHighContrast = Color(0xFF000000) +val errorContainerDarkHighContrast = Color(0xFFFFBAB1) +val onErrorContainerDarkHighContrast = Color(0xFF000000) +val backgroundDarkHighContrast = Color(0xFF0F1419) +val onBackgroundDarkHighContrast = Color(0xFFDFE3EA) +val surfaceDarkHighContrast = Color(0xFF131314) +val onSurfaceDarkHighContrast = Color(0xFFFFFFFF) +val surfaceVariantDarkHighContrast = Color(0xFF43474A) +val onSurfaceVariantDarkHighContrast = Color(0xFFF8FBFF) +val outlineDarkHighContrast = Color(0xFFC8CBCF) +val outlineVariantDarkHighContrast = Color(0xFFC8CBCF) +val scrimDarkHighContrast = Color(0xFF000000) +val inverseSurfaceDarkHighContrast = Color(0xFFE5E2E2) +val inverseOnSurfaceDarkHighContrast = Color(0xFF000000) +val inversePrimaryDarkHighContrast = Color(0xFF002C48) +val surfaceDimDarkHighContrast = Color(0xFF131314) +val surfaceBrightDarkHighContrast = Color(0xFF393939) +val surfaceContainerLowestDarkHighContrast = Color(0xFF0E0E0E) +val surfaceContainerLowDarkHighContrast = Color(0xFF1B1B1C) +val surfaceContainerDarkHighContrast = Color(0xFF201F20) +val surfaceContainerHighDarkHighContrast = Color(0xFF2A2A2A) +val surfaceContainerHighestDarkHighContrast = Color(0xFF353535) diff --git a/experimental/sample/scoop/xplat/foundation/designSystem/src/commonMain/kotlin/monster/scoop/xplat/foundation/designSystem/theme/Theme.kt b/experimental/sample/scoop/xplat/foundation/designSystem/src/commonMain/kotlin/monster/scoop/xplat/foundation/designSystem/theme/Theme.kt new file mode 100644 index 000000000..a3a6285c6 --- /dev/null +++ b/experimental/sample/scoop/xplat/foundation/designSystem/src/commonMain/kotlin/monster/scoop/xplat/foundation/designSystem/theme/Theme.kt @@ -0,0 +1,264 @@ +package monster.scoop.xplat.foundation.designSystem.theme + + +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.Immutable +import androidx.compose.ui.graphics.Color + +val lightScheme = lightColorScheme( + primary = primaryLight, + onPrimary = onPrimaryLight, + primaryContainer = primaryContainerLight, + onPrimaryContainer = onPrimaryContainerLight, + secondary = secondaryLight, + onSecondary = onSecondaryLight, + secondaryContainer = secondaryContainerLight, + onSecondaryContainer = onSecondaryContainerLight, + tertiary = tertiaryLight, + onTertiary = onTertiaryLight, + tertiaryContainer = tertiaryContainerLight, + onTertiaryContainer = onTertiaryContainerLight, + error = errorLight, + onError = onErrorLight, + errorContainer = errorContainerLight, + onErrorContainer = onErrorContainerLight, + background = backgroundLight, + onBackground = onBackgroundLight, + surface = surfaceLight, + onSurface = onSurfaceLight, + surfaceVariant = surfaceVariantLight, + onSurfaceVariant = onSurfaceVariantLight, + outline = outlineLight, + outlineVariant = outlineVariantLight, + scrim = scrimLight, + inverseSurface = inverseSurfaceLight, + inverseOnSurface = inverseOnSurfaceLight, + inversePrimary = inversePrimaryLight, + surfaceDim = surfaceDimLight, + surfaceBright = surfaceBrightLight, + surfaceContainerLowest = surfaceContainerLowestLight, + surfaceContainerLow = surfaceContainerLowLight, + surfaceContainer = surfaceContainerLight, + surfaceContainerHigh = surfaceContainerHighLight, + surfaceContainerHighest = surfaceContainerHighestLight, +) + +val darkScheme = darkColorScheme( + primary = primaryDark, + onPrimary = onPrimaryDark, + primaryContainer = primaryContainerDark, + onPrimaryContainer = onPrimaryContainerDark, + secondary = secondaryDark, + onSecondary = onSecondaryDark, + secondaryContainer = secondaryContainerDark, + onSecondaryContainer = onSecondaryContainerDark, + tertiary = tertiaryDark, + onTertiary = onTertiaryDark, + tertiaryContainer = tertiaryContainerDark, + onTertiaryContainer = onTertiaryContainerDark, + error = errorDark, + onError = onErrorDark, + errorContainer = errorContainerDark, + onErrorContainer = onErrorContainerDark, + background = backgroundDark, + onBackground = onBackgroundDark, + surface = surfaceDark, + onSurface = onSurfaceDark, + surfaceVariant = surfaceVariantDark, + onSurfaceVariant = onSurfaceVariantDark, + outline = outlineDark, + outlineVariant = outlineVariantDark, + scrim = scrimDark, + inverseSurface = inverseSurfaceDark, + inverseOnSurface = inverseOnSurfaceDark, + inversePrimary = inversePrimaryDark, + surfaceDim = surfaceDimDark, + surfaceBright = surfaceBrightDark, + surfaceContainerLowest = surfaceContainerLowestDark, + surfaceContainerLow = surfaceContainerLowDark, + surfaceContainer = surfaceContainerDark, + surfaceContainerHigh = surfaceContainerHighDark, + surfaceContainerHighest = surfaceContainerHighestDark, +) + +val mediumContrastLightColorScheme = lightColorScheme( + primary = primaryLightMediumContrast, + onPrimary = onPrimaryLightMediumContrast, + primaryContainer = primaryContainerLightMediumContrast, + onPrimaryContainer = onPrimaryContainerLightMediumContrast, + secondary = secondaryLightMediumContrast, + onSecondary = onSecondaryLightMediumContrast, + secondaryContainer = secondaryContainerLightMediumContrast, + onSecondaryContainer = onSecondaryContainerLightMediumContrast, + tertiary = tertiaryLightMediumContrast, + onTertiary = onTertiaryLightMediumContrast, + tertiaryContainer = tertiaryContainerLightMediumContrast, + onTertiaryContainer = onTertiaryContainerLightMediumContrast, + error = errorLightMediumContrast, + onError = onErrorLightMediumContrast, + errorContainer = errorContainerLightMediumContrast, + onErrorContainer = onErrorContainerLightMediumContrast, + background = backgroundLightMediumContrast, + onBackground = onBackgroundLightMediumContrast, + surface = surfaceLightMediumContrast, + onSurface = onSurfaceLightMediumContrast, + surfaceVariant = surfaceVariantLightMediumContrast, + onSurfaceVariant = onSurfaceVariantLightMediumContrast, + outline = outlineLightMediumContrast, + outlineVariant = outlineVariantLightMediumContrast, + scrim = scrimLightMediumContrast, + inverseSurface = inverseSurfaceLightMediumContrast, + inverseOnSurface = inverseOnSurfaceLightMediumContrast, + inversePrimary = inversePrimaryLightMediumContrast, + surfaceDim = surfaceDimLightMediumContrast, + surfaceBright = surfaceBrightLightMediumContrast, + surfaceContainerLowest = surfaceContainerLowestLightMediumContrast, + surfaceContainerLow = surfaceContainerLowLightMediumContrast, + surfaceContainer = surfaceContainerLightMediumContrast, + surfaceContainerHigh = surfaceContainerHighLightMediumContrast, + surfaceContainerHighest = surfaceContainerHighestLightMediumContrast, +) + +val highContrastLightColorScheme = lightColorScheme( + primary = primaryLightHighContrast, + onPrimary = onPrimaryLightHighContrast, + primaryContainer = primaryContainerLightHighContrast, + onPrimaryContainer = onPrimaryContainerLightHighContrast, + secondary = secondaryLightHighContrast, + onSecondary = onSecondaryLightHighContrast, + secondaryContainer = secondaryContainerLightHighContrast, + onSecondaryContainer = onSecondaryContainerLightHighContrast, + tertiary = tertiaryLightHighContrast, + onTertiary = onTertiaryLightHighContrast, + tertiaryContainer = tertiaryContainerLightHighContrast, + onTertiaryContainer = onTertiaryContainerLightHighContrast, + error = errorLightHighContrast, + onError = onErrorLightHighContrast, + errorContainer = errorContainerLightHighContrast, + onErrorContainer = onErrorContainerLightHighContrast, + background = backgroundLightHighContrast, + onBackground = onBackgroundLightHighContrast, + surface = surfaceLightHighContrast, + onSurface = onSurfaceLightHighContrast, + surfaceVariant = surfaceVariantLightHighContrast, + onSurfaceVariant = onSurfaceVariantLightHighContrast, + outline = outlineLightHighContrast, + outlineVariant = outlineVariantLightHighContrast, + scrim = scrimLightHighContrast, + inverseSurface = inverseSurfaceLightHighContrast, + inverseOnSurface = inverseOnSurfaceLightHighContrast, + inversePrimary = inversePrimaryLightHighContrast, + surfaceDim = surfaceDimLightHighContrast, + surfaceBright = surfaceBrightLightHighContrast, + surfaceContainerLowest = surfaceContainerLowestLightHighContrast, + surfaceContainerLow = surfaceContainerLowLightHighContrast, + surfaceContainer = surfaceContainerLightHighContrast, + surfaceContainerHigh = surfaceContainerHighLightHighContrast, + surfaceContainerHighest = surfaceContainerHighestLightHighContrast, +) + +val mediumContrastDarkColorScheme = darkColorScheme( + primary = primaryDarkMediumContrast, + onPrimary = onPrimaryDarkMediumContrast, + primaryContainer = primaryContainerDarkMediumContrast, + onPrimaryContainer = onPrimaryContainerDarkMediumContrast, + secondary = secondaryDarkMediumContrast, + onSecondary = onSecondaryDarkMediumContrast, + secondaryContainer = secondaryContainerDarkMediumContrast, + onSecondaryContainer = onSecondaryContainerDarkMediumContrast, + tertiary = tertiaryDarkMediumContrast, + onTertiary = onTertiaryDarkMediumContrast, + tertiaryContainer = tertiaryContainerDarkMediumContrast, + onTertiaryContainer = onTertiaryContainerDarkMediumContrast, + error = errorDarkMediumContrast, + onError = onErrorDarkMediumContrast, + errorContainer = errorContainerDarkMediumContrast, + onErrorContainer = onErrorContainerDarkMediumContrast, + background = backgroundDarkMediumContrast, + onBackground = onBackgroundDarkMediumContrast, + surface = surfaceDarkMediumContrast, + onSurface = onSurfaceDarkMediumContrast, + surfaceVariant = surfaceVariantDarkMediumContrast, + onSurfaceVariant = onSurfaceVariantDarkMediumContrast, + outline = outlineDarkMediumContrast, + outlineVariant = outlineVariantDarkMediumContrast, + scrim = scrimDarkMediumContrast, + inverseSurface = inverseSurfaceDarkMediumContrast, + inverseOnSurface = inverseOnSurfaceDarkMediumContrast, + inversePrimary = inversePrimaryDarkMediumContrast, + surfaceDim = surfaceDimDarkMediumContrast, + surfaceBright = surfaceBrightDarkMediumContrast, + surfaceContainerLowest = surfaceContainerLowestDarkMediumContrast, + surfaceContainerLow = surfaceContainerLowDarkMediumContrast, + surfaceContainer = surfaceContainerDarkMediumContrast, + surfaceContainerHigh = surfaceContainerHighDarkMediumContrast, + surfaceContainerHighest = surfaceContainerHighestDarkMediumContrast, +) + +val highContrastDarkColorScheme = darkColorScheme( + primary = primaryDarkHighContrast, + onPrimary = onPrimaryDarkHighContrast, + primaryContainer = primaryContainerDarkHighContrast, + onPrimaryContainer = onPrimaryContainerDarkHighContrast, + secondary = secondaryDarkHighContrast, + onSecondary = onSecondaryDarkHighContrast, + secondaryContainer = secondaryContainerDarkHighContrast, + onSecondaryContainer = onSecondaryContainerDarkHighContrast, + tertiary = tertiaryDarkHighContrast, + onTertiary = onTertiaryDarkHighContrast, + tertiaryContainer = tertiaryContainerDarkHighContrast, + onTertiaryContainer = onTertiaryContainerDarkHighContrast, + error = errorDarkHighContrast, + onError = onErrorDarkHighContrast, + errorContainer = errorContainerDarkHighContrast, + onErrorContainer = onErrorContainerDarkHighContrast, + background = backgroundDarkHighContrast, + onBackground = onBackgroundDarkHighContrast, + surface = surfaceDarkHighContrast, + onSurface = onSurfaceDarkHighContrast, + surfaceVariant = surfaceVariantDarkHighContrast, + onSurfaceVariant = onSurfaceVariantDarkHighContrast, + outline = outlineDarkHighContrast, + outlineVariant = outlineVariantDarkHighContrast, + scrim = scrimDarkHighContrast, + inverseSurface = inverseSurfaceDarkHighContrast, + inverseOnSurface = inverseOnSurfaceDarkHighContrast, + inversePrimary = inversePrimaryDarkHighContrast, + surfaceDim = surfaceDimDarkHighContrast, + surfaceBright = surfaceBrightDarkHighContrast, + surfaceContainerLowest = surfaceContainerLowestDarkHighContrast, + surfaceContainerLow = surfaceContainerLowDarkHighContrast, + surfaceContainer = surfaceContainerDarkHighContrast, + surfaceContainerHigh = surfaceContainerHighDarkHighContrast, + surfaceContainerHighest = surfaceContainerHighestDarkHighContrast, +) + +@Immutable +data class ColorFamily( + val color: Color, + val onColor: Color, + val colorContainer: Color, + val onColorContainer: Color + +) + + +@Composable +fun AppTheme( + darkTheme: Boolean = isSystemInDarkTheme(), + content: @Composable() () -> Unit +) { + val colorScheme = when { + darkTheme -> darkScheme + else -> lightScheme + } + + MaterialTheme( + colorScheme = colorScheme, + content = content + ) +} \ No newline at end of file diff --git a/experimental/sample/scoop/xplat/foundation/di/build.gradle.kts b/experimental/sample/scoop/xplat/foundation/di/build.gradle.kts index 03b4043bd..5ce1681f8 100644 --- a/experimental/sample/scoop/xplat/foundation/di/build.gradle.kts +++ b/experimental/sample/scoop/xplat/foundation/di/build.gradle.kts @@ -20,4 +20,4 @@ kotlin { android { namespace = "monster.scoop.xplat.foundation.di" -} \ No newline at end of file +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2ac6089e6..1381e6619 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -90,14 +90,15 @@ apollo-runtime = { module = "com.apollographql.apollo3:apollo-runtime", version. apollo-normalized-cache = { module = "com.apollographql.apollo3:apollo-normalized-cache", version.ref = "apolloVerson" } coil = { module = "io.coil-kt.coil3:coil", version.ref = "coil" } coil-compose = { module = "io.coil-kt.coil3:coil-compose", version.ref = "coil" } -coil-network = {module = "io.coil-kt.coil3:coil-network-ktor", version.ref = "coil"} -ktor-client-android = {module = "io.ktor:ktor-client-android", version.ref = "ktor"} +coil-network = { module = "io.coil-kt.coil3:coil-network-ktor", version.ref = "coil" } +ktor-client-android = { module = "io.ktor:ktor-client-android", version.ref = "ktor" } ktor-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" } ktor-negotiation = { module = "io.ktor:ktor-client-content-negotiation", version.ref = "ktor" } ktor-serialization = { module = "io.ktor:ktor-client-serialization", version.ref = "ktor" } ktor-serialization-json = { module = "io.ktor:ktor-serialization-kotlinx-json", version.ref = "ktor" } -ktor-serialization-xml = {module = "io.ktor:ktor-serialization-kotlinx-xml", version.ref = "ktor"} -compose-webview-multiplatform = {module = "io.github.kevinnzou:compose-webview-multiplatform", version.ref = "compose-webview"} +ktor-serialization-xml = { module = "io.ktor:ktor-serialization-kotlinx-xml", version.ref = "ktor" } +compose-webview-multiplatform = { module = "io.github.kevinnzou:compose-webview-multiplatform", version.ref = "compose-webview" } +swipe = { module = "me.saket.swipe:swipe", version = "1.3.0" } # Gradle Plugins android-desugarJdkLibs = { module = "com.android.tools:desugar_jdk_libs", version.ref = "desugar" } diff --git a/settings.gradle b/settings.gradle index 6525794cd..11cb4761a 100644 --- a/settings.gradle +++ b/settings.gradle @@ -26,4 +26,5 @@ include ':experimental:sample:scoop:xplat:domain:story:api' include ':experimental:sample:scoop:xplat:domain:story:impl' include ':experimental:sample:scoop:xplat:feat:homeTab:api' include ':experimental:sample:scoop:xplat:feat:homeTab:impl' -include ':experimental:sample:scoop:android:app' \ No newline at end of file +include ':experimental:sample:scoop:android:app' +include ':experimental:sample:scoop:xplat:foundation:designSystem' \ No newline at end of file