├── app
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── values
│ │ │ │ ├── strings.xml
│ │ │ │ ├── themes.xml
│ │ │ │ └── colors.xml
│ │ │ ├── drawable
│ │ │ │ ├── john.png
│ │ │ │ ├── rose.png
│ │ │ │ ├── space.png
│ │ │ │ ├── ic_arrow_drop_down.xml
│ │ │ │ ├── ic_add.xml
│ │ │ │ ├── ic_home.xml
│ │ │ │ ├── ic_check.xml
│ │ │ │ ├── ic_keyboard_arrow_down.xml
│ │ │ │ ├── ic_close.xml
│ │ │ │ ├── ic_credit_card.xml
│ │ │ │ ├── ic_apps.xml
│ │ │ │ ├── ic_check_circle.xml
│ │ │ │ ├── ic_person.xml
│ │ │ │ ├── ic_heart.xml
│ │ │ │ ├── ic_library_books.xml
│ │ │ │ ├── ic_card_travel.xml
│ │ │ │ ├── ic_contact_support.xml
│ │ │ │ ├── ic_access_time.xml
│ │ │ │ ├── ic_attach_money.xml
│ │ │ │ └── ic_launcher_background.xml
│ │ │ ├── font
│ │ │ │ ├── plex_sans_bold.ttf
│ │ │ │ └── plex_sans_regular.ttf
│ │ │ ├── mipmap-hdpi
│ │ │ │ ├── ic_launcher.webp
│ │ │ │ └── ic_launcher_round.webp
│ │ │ ├── mipmap-mdpi
│ │ │ │ ├── ic_launcher.webp
│ │ │ │ └── ic_launcher_round.webp
│ │ │ ├── mipmap-xhdpi
│ │ │ │ ├── ic_launcher.webp
│ │ │ │ └── ic_launcher_round.webp
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ ├── ic_launcher.webp
│ │ │ │ └── ic_launcher_round.webp
│ │ │ ├── mipmap-xxxhdpi
│ │ │ │ ├── ic_launcher.webp
│ │ │ │ └── ic_launcher_round.webp
│ │ │ ├── mipmap-anydpi-v26
│ │ │ │ ├── ic_launcher.xml
│ │ │ │ └── ic_launcher_round.xml
│ │ │ ├── xml
│ │ │ │ ├── backup_rules.xml
│ │ │ │ └── data_extraction_rules.xml
│ │ │ └── drawable-v24
│ │ │ │ └── ic_launcher_foreground.xml
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── compose
│ │ │ │ └── designsystem
│ │ │ │ ├── application
│ │ │ │ ├── first
│ │ │ │ │ ├── domain
│ │ │ │ │ │ ├── Transaction.kt
│ │ │ │ │ │ └── TransactionType.kt
│ │ │ │ │ ├── data
│ │ │ │ │ │ └── TransactionRepository.kt
│ │ │ │ │ └── FirstSpaceScreen.kt
│ │ │ │ ├── fifth
│ │ │ │ │ └── FifthSpaceScreen.kt
│ │ │ │ ├── third
│ │ │ │ │ └── ThirdSpaceScreen.kt
│ │ │ │ ├── forth
│ │ │ │ │ └── ForthSpaceScreen.kt
│ │ │ │ └── second
│ │ │ │ │ └── SecondSpaceScreen.kt
│ │ │ │ ├── space
│ │ │ │ ├── organisms
│ │ │ │ │ ├── Form.kt
│ │ │ │ │ ├── BottomSheetScreen.kt
│ │ │ │ │ ├── Drawer.kt
│ │ │ │ │ ├── Prompt.kt
│ │ │ │ │ └── Profile.kt
│ │ │ │ ├── theme
│ │ │ │ │ ├── SpaceTheme.kt
│ │ │ │ │ ├── SpaceShapes.kt
│ │ │ │ │ ├── SpaceTypography.kt
│ │ │ │ │ ├── SpaceIcons.kt
│ │ │ │ │ └── SpaceColors.kt
│ │ │ │ ├── molecules
│ │ │ │ │ ├── Tabs.kt
│ │ │ │ │ ├── SelectGroup.kt
│ │ │ │ │ ├── InputGroup.kt
│ │ │ │ │ └── NavBar.kt
│ │ │ │ └── atoms
│ │ │ │ │ ├── basic
│ │ │ │ │ ├── Divider.kt
│ │ │ │ │ ├── Text.kt
│ │ │ │ │ ├── Icon.kt
│ │ │ │ │ └── Surface.kt
│ │ │ │ │ ├── Button.kt
│ │ │ │ │ ├── Tab.kt
│ │ │ │ │ ├── Link.kt
│ │ │ │ │ ├── IconButton.kt
│ │ │ │ │ ├── Select.kt
│ │ │ │ │ ├── NavTab.kt
│ │ │ │ │ ├── Avatar.kt
│ │ │ │ │ └── Input.kt
│ │ │ │ ├── ui
│ │ │ │ └── theme
│ │ │ │ │ └── Theme.kt
│ │ │ │ └── MainActivity.kt
│ │ └── AndroidManifest.xml
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── compose
│ │ │ └── designsystem
│ │ │ └── ExampleUnitTest.kt
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── compose
│ │ └── designsystem
│ │ └── ExampleInstrumentedTest.kt
├── proguard-rules.pro
└── build.gradle
├── .idea
├── .gitignore
├── compiler.xml
└── misc.xml
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── README.md
├── settings.gradle
├── gradle.properties
├── .gitignore
├── gradlew.bat
└── gradlew
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | ComposeDesignSystem
3 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZadorozhnyiSemen/ComposeDesignSystem/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/app/src/main/res/drawable/john.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZadorozhnyiSemen/ComposeDesignSystem/HEAD/app/src/main/res/drawable/john.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/rose.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZadorozhnyiSemen/ComposeDesignSystem/HEAD/app/src/main/res/drawable/rose.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/space.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZadorozhnyiSemen/ComposeDesignSystem/HEAD/app/src/main/res/drawable/space.png
--------------------------------------------------------------------------------
/app/src/main/res/font/plex_sans_bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZadorozhnyiSemen/ComposeDesignSystem/HEAD/app/src/main/res/font/plex_sans_bold.ttf
--------------------------------------------------------------------------------
/app/src/main/res/font/plex_sans_regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZadorozhnyiSemen/ComposeDesignSystem/HEAD/app/src/main/res/font/plex_sans_regular.ttf
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZadorozhnyiSemen/ComposeDesignSystem/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZadorozhnyiSemen/ComposeDesignSystem/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZadorozhnyiSemen/ComposeDesignSystem/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZadorozhnyiSemen/ComposeDesignSystem/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZadorozhnyiSemen/ComposeDesignSystem/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ComposeDesignSystem
2 | Custom Space design system for [article](https://szadorozhnyi.medium.com/custom-design-system-using-jetpack-compose-17a59b1ae38d)
3 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZadorozhnyiSemen/ComposeDesignSystem/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZadorozhnyiSemen/ComposeDesignSystem/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZadorozhnyiSemen/ComposeDesignSystem/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZadorozhnyiSemen/ComposeDesignSystem/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZadorozhnyiSemen/ComposeDesignSystem/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/java/com/compose/designsystem/application/first/domain/Transaction.kt:
--------------------------------------------------------------------------------
1 | package com.compose.designsystem.application.first.domain
2 |
3 | data class Transaction(
4 | val transactionType: TransactionType,
5 | val amount: Double,
6 | )
7 |
--------------------------------------------------------------------------------
/app/src/main/java/com/compose/designsystem/application/first/domain/TransactionType.kt:
--------------------------------------------------------------------------------
1 | package com.compose.designsystem.application.first.domain
2 |
3 | sealed interface TransactionType {
4 | object Fund : TransactionType
5 | object Sale : TransactionType
6 | }
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Aug 26 13:21:48 GET 2022
2 | distributionBase=GRADLE_USER_HOME
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
4 | distributionPath=wrapper/dists
5 | zipStorePath=wrapper/dists
6 | zipStoreBase=GRADLE_USER_HOME
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_arrow_drop_down.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_add.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_home.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_check.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_keyboard_arrow_down.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | gradlePluginPortal()
4 | google()
5 | mavenCentral()
6 | }
7 | }
8 | dependencyResolutionManagement {
9 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
10 | repositories {
11 | google()
12 | mavenCentral()
13 | }
14 | }
15 | rootProject.name = "ComposeDesignSystem"
16 | include ':app'
17 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_close.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFBB86FC
4 | #FF6200EE
5 | #FF3700B3
6 | #FF03DAC5
7 | #FF018786
8 | #FF000000
9 | #FFFFFFFF
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_credit_card.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/test/java/com/compose/designsystem/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.compose.designsystem
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_apps.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_check_circle.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_person.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_heart.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_library_books.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_card_travel.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/backup_rules.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
13 |
--------------------------------------------------------------------------------
/app/src/main/java/com/compose/designsystem/space/organisms/Form.kt:
--------------------------------------------------------------------------------
1 | package com.compose.designsystem.space.organisms
2 |
3 | import androidx.compose.foundation.layout.Column
4 | import androidx.compose.foundation.layout.ColumnScope
5 | import androidx.compose.foundation.layout.Spacer
6 | import androidx.compose.runtime.Composable
7 | import androidx.compose.ui.Modifier
8 |
9 | @Composable
10 | fun Form(
11 | inputs: @Composable ColumnScope.() -> Unit,
12 | submitButton: @Composable () -> Unit,
13 | ) {
14 | Column {
15 | inputs()
16 | Spacer(modifier = Modifier.weight(1f))
17 | submitButton()
18 | }
19 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_contact_support.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_access_time.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/data_extraction_rules.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
12 |
13 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_attach_money.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/compose/designsystem/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.compose.designsystem
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("com.compose.designsystem", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/app/src/main/java/com/compose/designsystem/application/first/data/TransactionRepository.kt:
--------------------------------------------------------------------------------
1 | package com.compose.designsystem.application.first.data
2 |
3 | import com.compose.designsystem.application.first.domain.Transaction
4 | import com.compose.designsystem.application.first.domain.TransactionType
5 |
6 | private val transactionList: List = listOf(
7 | Transaction(TransactionType.Sale, 1.99),
8 | Transaction(TransactionType.Sale, 5.48),
9 | Transaction(TransactionType.Fund, 10.00),
10 | Transaction(TransactionType.Sale, 2.99),
11 | Transaction(TransactionType.Sale, 6.48),
12 | Transaction(TransactionType.Sale, 0.49),
13 | Transaction(TransactionType.Sale, 1.99),
14 | Transaction(TransactionType.Fund, 20.00),
15 | )
16 |
17 | object TransactionRepository {
18 |
19 | fun getAllTransactions(): List = transactionList
20 |
21 | fun getSales(): List =
22 | transactionList.filter { it.transactionType is TransactionType.Sale }
23 |
24 | fun getFunds(): List =
25 | transactionList.filter { it.transactionType is TransactionType.Fund }
26 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/compose/designsystem/space/theme/SpaceTheme.kt:
--------------------------------------------------------------------------------
1 | package com.compose.designsystem.space.theme
2 |
3 | import androidx.compose.runtime.Composable
4 | import androidx.compose.runtime.CompositionLocalProvider
5 | import androidx.compose.runtime.ReadOnlyComposable
6 |
7 | @Composable
8 | fun SpaceTheme(
9 | colors: SpaceColors = SpaceTheme.colors,
10 | typography: SpaceTypography = SpaceTheme.typography,
11 | shapes: SpaceShapes = SpaceTheme.shapes,
12 | content: @Composable () -> Unit
13 | ) {
14 |
15 | CompositionLocalProvider(
16 | LocalColors provides colors,
17 | LocalTypography provides typography,
18 | LocalShapes provides shapes
19 | ) {
20 | content()
21 | }
22 | }
23 |
24 | object SpaceTheme {
25 | val colors: SpaceColors
26 | @Composable
27 | @ReadOnlyComposable
28 | get() = LocalColors.current
29 |
30 | val typography: SpaceTypography
31 | @Composable
32 | @ReadOnlyComposable
33 | get() = LocalTypography.current
34 |
35 | val shapes: SpaceShapes
36 | @Composable
37 | @ReadOnlyComposable
38 | get() = LocalShapes.current
39 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/compose/designsystem/ui/theme/Theme.kt:
--------------------------------------------------------------------------------
1 | package com.compose.designsystem.ui.theme
2 |
3 | import androidx.compose.foundation.isSystemInDarkTheme
4 | import androidx.compose.runtime.Composable
5 | import com.compose.designsystem.space.theme.*
6 | import com.google.accompanist.systemuicontroller.rememberSystemUiController
7 |
8 | private val DarkColorPalette = darkSpaceColors()
9 |
10 | private val LightColorPalette = lightSpaceColors()
11 |
12 | @Composable
13 | fun ComposeDesignSystemTheme(
14 | darkTheme: Boolean = isSystemInDarkTheme(),
15 | content: @Composable () -> Unit
16 | ) {
17 | val colors = if (darkTheme) {
18 | DarkColorPalette
19 | } else {
20 | LightColorPalette
21 | }
22 |
23 | val systemUiController = rememberSystemUiController()
24 | systemUiController.setStatusBarColor(
25 | color = SpaceTheme.colors.shadesBlack,
26 | )
27 | systemUiController.setNavigationBarColor(
28 | color = SpaceTheme.colors.neutral_1
29 | )
30 |
31 | SpaceTheme(
32 | colors = colors,
33 | typography = SpaceTypography(),
34 | shapes = SpaceShapes(),
35 | content = content
36 | )
37 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
16 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/app/src/main/java/com/compose/designsystem/space/molecules/Tabs.kt:
--------------------------------------------------------------------------------
1 | package com.compose.designsystem.space.molecules
2 |
3 | import androidx.compose.foundation.layout.Arrangement
4 | import androidx.compose.foundation.layout.Row
5 | import androidx.compose.foundation.layout.RowScope
6 | import androidx.compose.foundation.selection.selectableGroup
7 | import androidx.compose.runtime.Composable
8 | import androidx.compose.ui.Modifier
9 | import androidx.compose.ui.graphics.Color
10 | import androidx.compose.ui.unit.dp
11 | import com.compose.designsystem.space.atoms.basic.Surface
12 | import com.compose.designsystem.space.theme.SpaceTheme
13 | import com.compose.designsystem.space.theme.contentColorFor
14 |
15 | @Composable
16 | fun Tabs(
17 | modifier: Modifier = Modifier,
18 | backgroundColor: Color = SpaceTheme.colors.shadesWhite,
19 | contentColor: Color = contentColorFor(backgroundColor = backgroundColor),
20 | content: @Composable RowScope.() -> Unit,
21 | ) {
22 | Surface(
23 | color = backgroundColor,
24 | contentColor = contentColor,
25 | modifier = modifier,
26 | ) {
27 | Row(
28 | modifier = Modifier.selectableGroup(),
29 | horizontalArrangement = Arrangement.spacedBy(8.dp),
30 | content = content,
31 | )
32 | }
33 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/compose/designsystem/space/atoms/basic/Divider.kt:
--------------------------------------------------------------------------------
1 | package com.compose.designsystem.space.atoms.basic
2 |
3 | import androidx.compose.foundation.background
4 | import androidx.compose.foundation.layout.Box
5 | import androidx.compose.foundation.layout.fillMaxWidth
6 | import androidx.compose.foundation.layout.height
7 | import androidx.compose.foundation.layout.padding
8 | import androidx.compose.runtime.Composable
9 | import androidx.compose.ui.Modifier
10 | import androidx.compose.ui.graphics.Color
11 | import androidx.compose.ui.platform.LocalDensity
12 | import androidx.compose.ui.unit.Dp
13 | import androidx.compose.ui.unit.dp
14 | import com.compose.designsystem.space.theme.LocalContentColor
15 |
16 | @Composable
17 | fun Divider(
18 | modifier: Modifier = Modifier,
19 | color: Color = LocalContentColor.current,
20 | thickness: Dp = 2.dp,
21 | startIndent: Dp = 0.dp
22 | ) {
23 | val indentMod = if (startIndent.value != 0f) {
24 | Modifier.padding(start = startIndent)
25 | } else {
26 | Modifier
27 | }
28 | val targetThickness = if (thickness == Dp.Hairline) {
29 | (1f / LocalDensity.current.density).dp
30 | } else {
31 | thickness
32 | }
33 | Box(
34 | modifier
35 | .then(indentMod)
36 | .fillMaxWidth()
37 | .height(targetThickness)
38 | .background(color = color)
39 | )
40 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app"s APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Kotlin code style for this project: "official" or "obsolete":
19 | kotlin.code.style=official
20 | # Enables namespacing of each library's R class so that its R class includes only the
21 | # resources declared in the library itself and none from the library's dependencies,
22 | # thereby reducing the size of the R class for that library
23 | android.nonTransitiveRClass=true
--------------------------------------------------------------------------------
/app/src/main/java/com/compose/designsystem/space/theme/SpaceShapes.kt:
--------------------------------------------------------------------------------
1 | package com.compose.designsystem.space.theme
2 |
3 | import androidx.compose.foundation.shape.CornerBasedShape
4 | import androidx.compose.foundation.shape.RoundedCornerShape
5 | import androidx.compose.runtime.staticCompositionLocalOf
6 | import androidx.compose.ui.unit.dp
7 |
8 | class SpaceShapes(
9 | val small: CornerBasedShape = RoundedCornerShape(8.dp),
10 | val medium: CornerBasedShape = RoundedCornerShape(16.dp),
11 | val large: CornerBasedShape = RoundedCornerShape(45.dp)
12 | ) {
13 |
14 | fun copy(
15 | small: CornerBasedShape = this.small,
16 | medium: CornerBasedShape = this.medium,
17 | large: CornerBasedShape = this.large
18 | ): SpaceShapes = SpaceShapes(
19 | small = small,
20 | medium = medium,
21 | large = large,
22 | )
23 |
24 | override fun equals(other: Any?): Boolean {
25 | if (this === other) return true
26 | if (other !is SpaceShapes) return false
27 | if (small != other.small) return false
28 | if (medium != other.medium) return false
29 | if (large != other.large) return false
30 | return true
31 | }
32 |
33 | override fun hashCode(): Int {
34 | var result = small.hashCode()
35 | result = 31 * result + medium.hashCode()
36 | result = 31 * result + large.hashCode()
37 | return result
38 | }
39 |
40 | override fun toString(): String {
41 | return "Space shapes(small=$small, medium=$medium, large=$large)"
42 | }
43 | }
44 |
45 | internal val LocalShapes = staticCompositionLocalOf { SpaceShapes() }
--------------------------------------------------------------------------------
/app/src/main/java/com/compose/designsystem/application/fifth/FifthSpaceScreen.kt:
--------------------------------------------------------------------------------
1 | package com.compose.designsystem.application.fifth
2 |
3 | import androidx.compose.foundation.layout.*
4 | import androidx.compose.foundation.rememberScrollState
5 | import androidx.compose.foundation.verticalScroll
6 | import androidx.compose.runtime.Composable
7 | import androidx.compose.runtime.getValue
8 | import androidx.compose.runtime.mutableStateOf
9 | import androidx.compose.runtime.remember
10 | import androidx.compose.ui.Modifier
11 | import androidx.compose.ui.unit.dp
12 | import com.compose.designsystem.R
13 | import com.compose.designsystem.space.atoms.basic.Text
14 | import com.compose.designsystem.space.organisms.Profile
15 | import com.compose.designsystem.space.theme.SpaceTheme
16 |
17 | private val profiles = listOf(
18 | Profile("John Smith", R.drawable.john, "Employee", true),
19 | Profile("Rose Taylor", R.drawable.rose, "Legendary Explorer", false),
20 | )
21 |
22 | @Composable
23 | fun FifthSpaceScreen() {
24 | val profiles by remember { mutableStateOf(profiles) }
25 |
26 | Column(
27 | modifier = Modifier
28 | .fillMaxSize()
29 | .verticalScroll(rememberScrollState())
30 | .padding(
31 | start = 16.dp,
32 | end = 16.dp,
33 | top = 32.dp
34 | )
35 | ) {
36 | Text(
37 | text = "Profiles",
38 | style = SpaceTheme.typography.h2,
39 | )
40 | Spacer(modifier = Modifier.height(16.dp))
41 | profiles.map { profile ->
42 | Profile(profile)
43 | Spacer(modifier = Modifier.height(16.dp))
44 | }
45 | }
46 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/compose/designsystem/application/third/ThirdSpaceScreen.kt:
--------------------------------------------------------------------------------
1 | package com.compose.designsystem.application.third
2 |
3 | import androidx.compose.foundation.layout.Box
4 | import androidx.compose.foundation.layout.fillMaxSize
5 | import androidx.compose.runtime.*
6 | import androidx.compose.ui.Modifier
7 | import com.compose.designsystem.space.atoms.Button
8 | import com.compose.designsystem.space.atoms.ButtonType
9 | import com.compose.designsystem.space.atoms.basic.Text
10 | import com.compose.designsystem.space.organisms.Prompt
11 | import com.compose.designsystem.space.theme.SpaceTheme
12 |
13 | @Composable
14 | fun ThirdSpaceScreen() {
15 |
16 | var showPrompt by remember {
17 | mutableStateOf(true)
18 | }
19 |
20 | if (showPrompt) {
21 | Prompt(
22 | title = "Reset Password",
23 | description = "Are you sure?",
24 | secondaryButton = {
25 | Button(onClick = { showPrompt = false }, type = ButtonType.Secondary) {
26 | Text(
27 | text = "No",
28 | style = SpaceTheme.typography.h4.copy(
29 | color = SpaceTheme.colors.neutral_5
30 | )
31 | )
32 | }
33 | },
34 | primaryButton = {
35 | Button(onClick = { showPrompt = false }, shape = SpaceTheme.shapes.small) {
36 | Text(text = "Yes")
37 | }
38 | },
39 | onDismiss = { showPrompt = false },
40 | )
41 | }
42 |
43 |
44 | Box(Modifier.fillMaxSize()) {
45 | Button(onClick = { showPrompt = true }) {
46 | Text(text = "Show prompt")
47 | }
48 | }
49 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.aar
4 | *.ap_
5 | *.aab
6 |
7 | # Files for the ART/Dalvik VM
8 | *.dex
9 |
10 | # Java class files
11 | *.class
12 |
13 | # Generated files
14 | bin/
15 | gen/
16 | out/
17 | # Uncomment the following line in case you need and you don't have the release build type files in your app
18 | # release/
19 |
20 | # Gradle files
21 | .gradle/
22 | build/
23 |
24 | # Local configuration file (sdk path, etc)
25 | local.properties
26 |
27 | # Proguard folder generated by Eclipse
28 | proguard/
29 |
30 | # Log Files
31 | *.log
32 |
33 | # Android Studio Navigation editor temp files
34 | .navigation/
35 |
36 | # Android Studio captures folder
37 | captures/
38 |
39 | # IntelliJ
40 | *.iml
41 | .idea/workspace.xml
42 | .idea/tasks.xml
43 | .idea/gradle.xml
44 | .idea/assetWizardSettings.xml
45 | .idea/dictionaries
46 | .idea/libraries
47 | # Android Studio 3 in .gitignore file.
48 | .idea/caches
49 | .idea/modules.xml
50 | # Comment next line if keeping position of elements in Navigation Editor is relevant for you
51 | .idea/navEditor.xml
52 |
53 | # Keystore files
54 | # Uncomment the following lines if you do not want to check your keystore files in.
55 | #*.jks
56 | #*.keystore
57 |
58 | # External native build folder generated in Android Studio 2.2 and later
59 | .externalNativeBuild
60 | .cxx/
61 |
62 | # Google Services (e.g. APIs or Firebase)
63 | # google-services.json
64 |
65 | # Freeline
66 | freeline.py
67 | freeline/
68 | freeline_project_description.json
69 |
70 | # fastlane
71 | fastlane/report.xml
72 | fastlane/Preview.html
73 | fastlane/screenshots
74 | fastlane/test_output
75 | fastlane/readme.md
76 |
77 | # Version control
78 | vcs.xml
79 |
80 | # lint
81 | lint/intermediates/
82 | lint/generated/
83 | lint/outputs/
84 | lint/tmp/
85 | # lint/reports/
86 |
--------------------------------------------------------------------------------
/app/src/main/java/com/compose/designsystem/space/molecules/SelectGroup.kt:
--------------------------------------------------------------------------------
1 | package com.compose.designsystem.space.molecules
2 |
3 | import androidx.compose.foundation.layout.Column
4 | import androidx.compose.foundation.layout.Spacer
5 | import androidx.compose.foundation.layout.fillMaxWidth
6 | import androidx.compose.foundation.layout.height
7 | import androidx.compose.runtime.Composable
8 | import androidx.compose.ui.Modifier
9 | import androidx.compose.ui.graphics.Shape
10 | import androidx.compose.ui.text.font.FontWeight
11 | import androidx.compose.ui.unit.dp
12 | import com.compose.designsystem.space.atoms.Select
13 | import com.compose.designsystem.space.atoms.basic.Text
14 | import com.compose.designsystem.space.theme.SpaceTheme
15 |
16 | @Composable
17 | fun SelectGroup(
18 | label: String,
19 | modifier: Modifier = Modifier,
20 | shape: Shape = SpaceTheme.shapes.large,
21 | input: String = "",
22 | sublabel: String? = null,
23 | ) {
24 | Column(modifier = modifier) {
25 | Text(
26 | text = label,
27 | style = SpaceTheme.typography.h4.copy(fontWeight = FontWeight.Normal)
28 | )
29 | Spacer(modifier = Modifier.height(8.dp))
30 | Select(
31 | modifier = Modifier.fillMaxWidth(),
32 | text = input,
33 | shape = shape,
34 | )
35 | Spacer(modifier = Modifier.height(4.dp))
36 | if (sublabel != null) {
37 | Text(
38 | text = sublabel,
39 | style = SpaceTheme.typography.h5.copy(
40 | fontWeight = FontWeight.Normal,
41 | color = SpaceTheme.colors.neutral_7,
42 | )
43 | )
44 | } else {
45 | Spacer(modifier = Modifier.height(20.dp))
46 | }
47 | }
48 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/compose/designsystem/space/atoms/basic/Text.kt:
--------------------------------------------------------------------------------
1 | package com.compose.designsystem.space.atoms.basic
2 |
3 | import androidx.compose.foundation.text.BasicText
4 | import androidx.compose.runtime.Composable
5 | import androidx.compose.runtime.CompositionLocalProvider
6 | import androidx.compose.runtime.compositionLocalOf
7 | import androidx.compose.runtime.structuralEqualityPolicy
8 | import androidx.compose.ui.Modifier
9 | import androidx.compose.ui.graphics.Color
10 | import androidx.compose.ui.graphics.takeOrElse
11 | import androidx.compose.ui.text.TextStyle
12 | import androidx.compose.ui.text.style.TextAlign
13 | import com.compose.designsystem.space.theme.LocalContentAlpha
14 | import com.compose.designsystem.space.theme.LocalContentColor
15 | import com.compose.designsystem.space.theme.SpaceTheme
16 |
17 | @Composable
18 | fun Text(
19 | text: String,
20 | modifier: Modifier = Modifier,
21 | color: Color = Color.Unspecified,
22 | style: TextStyle = SpaceTheme.typography.h4,
23 | textAlign: TextAlign = TextAlign.Center
24 | ) {
25 | val textColor = color.takeOrElse {
26 | style.color.takeOrElse {
27 | LocalContentColor.current.copy(alpha = LocalContentAlpha.current)
28 | }
29 | }
30 |
31 | val mergedStyle = style.copy(color = textColor, textAlign = textAlign)
32 |
33 | BasicText(
34 | text = text,
35 | modifier = modifier,
36 | style = mergedStyle,
37 | )
38 | }
39 |
40 | @Composable
41 | fun ProvideTextStyle(value: TextStyle, content: @Composable () -> Unit) {
42 | val mergedStyle = LocalTextStyle.current.merge(value)
43 | CompositionLocalProvider(LocalTextStyle provides mergedStyle, content = content)
44 | }
45 |
46 | val LocalTextStyle = compositionLocalOf(structuralEqualityPolicy()) { TextStyle.Default }
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/app/src/main/java/com/compose/designsystem/space/molecules/InputGroup.kt:
--------------------------------------------------------------------------------
1 | package com.compose.designsystem.space.molecules
2 |
3 | import androidx.compose.foundation.layout.Column
4 | import androidx.compose.foundation.layout.Spacer
5 | import androidx.compose.foundation.layout.fillMaxWidth
6 | import androidx.compose.foundation.layout.height
7 | import androidx.compose.runtime.Composable
8 | import androidx.compose.ui.Modifier
9 | import androidx.compose.ui.graphics.Shape
10 | import androidx.compose.ui.text.font.FontWeight
11 | import androidx.compose.ui.unit.dp
12 | import com.compose.designsystem.space.atoms.Input
13 | import com.compose.designsystem.space.atoms.basic.Text
14 | import com.compose.designsystem.space.theme.SpaceTheme
15 |
16 | @Composable
17 | fun InputGroup(
18 | label: String,
19 | onInputChange: (String) -> Unit,
20 | modifier: Modifier = Modifier,
21 | shape: Shape = SpaceTheme.shapes.large,
22 | input: String = "",
23 | sublabel: String? = null,
24 | ) {
25 | Column(modifier = modifier) {
26 | Text(
27 | text = label,
28 | style = SpaceTheme.typography.h4.copy(fontWeight = FontWeight.Normal)
29 | )
30 | Spacer(modifier = Modifier.height(8.dp))
31 | Input(
32 | modifier = Modifier.fillMaxWidth(),
33 | value = input,
34 | onValueChange = onInputChange,
35 | shape = shape,
36 | )
37 | Spacer(modifier = Modifier.height(4.dp))
38 | if (sublabel != null) {
39 | Text(
40 | text = sublabel,
41 | style = SpaceTheme.typography.h5.copy(
42 | fontWeight = FontWeight.Normal,
43 | color = SpaceTheme.colors.neutral_7,
44 | )
45 | )
46 | } else {
47 | Spacer(modifier = Modifier.height(20.dp))
48 | }
49 | }
50 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/compose/designsystem/space/molecules/NavBar.kt:
--------------------------------------------------------------------------------
1 | package com.compose.designsystem.space.molecules
2 |
3 | import androidx.compose.foundation.layout.*
4 | import androidx.compose.foundation.selection.selectableGroup
5 | import androidx.compose.runtime.Composable
6 | import androidx.compose.ui.Modifier
7 | import androidx.compose.ui.draw.drawWithCache
8 | import androidx.compose.ui.geometry.Offset
9 | import androidx.compose.ui.graphics.Color
10 | import androidx.compose.ui.unit.dp
11 | import com.compose.designsystem.space.atoms.basic.Surface
12 | import com.compose.designsystem.space.theme.SpaceTheme
13 | import com.compose.designsystem.space.theme.contentColorFor
14 |
15 | private val NavBarHeight = 64.dp
16 |
17 | @Composable
18 | fun NavBar(
19 | modifier: Modifier = Modifier,
20 | backgroundColor: Color = SpaceTheme.colors.neutral_1,
21 | contentColor: Color = contentColorFor(backgroundColor = backgroundColor),
22 | borderColor: Color = SpaceTheme.colors.neutral_3,
23 | content: @Composable RowScope.() -> Unit,
24 | ) {
25 |
26 | Surface(
27 | color = backgroundColor,
28 | contentColor = contentColor,
29 | modifier = modifier,
30 | ) {
31 | Row(
32 | modifier = Modifier
33 | .fillMaxWidth()
34 | .height(NavBarHeight)
35 | .selectableGroup()
36 | .drawWithCache {
37 | val strokeWidthPx = 1.dp.toPx()
38 |
39 | onDrawWithContent {
40 | drawContent()
41 | drawLine(
42 | borderColor,
43 | Offset(0f, 0f),
44 | Offset(this.size.width, 0f),
45 | strokeWidth = strokeWidthPx,
46 | )
47 | }
48 | },
49 | horizontalArrangement = Arrangement.SpaceBetween,
50 | content = content
51 | )
52 | }
53 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/compose/designsystem/space/organisms/BottomSheetScreen.kt:
--------------------------------------------------------------------------------
1 | package com.compose.designsystem.space.organisms
2 |
3 | import androidx.compose.foundation.layout.*
4 | import androidx.compose.runtime.Composable
5 | import androidx.compose.ui.Modifier
6 | import androidx.compose.ui.draw.clip
7 | import androidx.compose.ui.draw.shadow
8 | import androidx.compose.ui.graphics.Shape
9 | import androidx.compose.ui.layout.Layout
10 | import androidx.compose.ui.unit.Dp
11 |
12 | @Composable
13 | fun BottomSheetScreen(
14 | sheetContent: @Composable () -> Unit,
15 | sheetShape: Shape,
16 | sheetElevation: Dp,
17 | modifier: Modifier = Modifier,
18 | content: @Composable () -> Unit,
19 | ) {
20 | BoxWithConstraints(modifier) {
21 | BottomSheetScreenStack(body = {
22 | Column(Modifier.fillMaxSize()) {
23 | content()
24 | }
25 | }) {
26 | Box(
27 | modifier = Modifier
28 | .fillMaxWidth()
29 | .shadow(elevation = sheetElevation, sheetShape, clip = false)
30 | .clip(sheetShape)
31 | ) {
32 | sheetContent()
33 | }
34 | }
35 | }
36 | }
37 |
38 | @Composable
39 | private fun BottomSheetScreenStack(
40 | body: @Composable () -> Unit,
41 | bottomSheet: @Composable () -> Unit,
42 | ) {
43 | Layout(
44 | content = {
45 | body()
46 | bottomSheet()
47 | }
48 | ) { measurables, constraints ->
49 | val placeable = measurables.first().measure(constraints)
50 |
51 | layout(placeable.width, placeable.height) {
52 | placeable.placeRelative(0, 0)
53 |
54 | val (sheetPlaceable) = measurables.drop(1).map {
55 | it.measure(constraints.copy(minWidth = 0, minHeight = 0))
56 | }
57 |
58 | sheetPlaceable.placeRelative(0, constraints.maxHeight - sheetPlaceable.height)
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.application'
3 | id 'org.jetbrains.kotlin.android'
4 | }
5 |
6 | android {
7 | compileSdk 33
8 |
9 | defaultConfig {
10 | applicationId "com.compose.designsystem"
11 | minSdk 24
12 | targetSdk 33
13 | versionCode 1
14 | versionName "1.0"
15 |
16 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
17 | vectorDrawables {
18 | useSupportLibrary true
19 | }
20 | }
21 |
22 | buildTypes {
23 | release {
24 | minifyEnabled false
25 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
26 | }
27 | }
28 | compileOptions {
29 | sourceCompatibility JavaVersion.VERSION_1_8
30 | targetCompatibility JavaVersion.VERSION_1_8
31 | }
32 | kotlinOptions {
33 | jvmTarget = '1.8'
34 | }
35 | buildFeatures {
36 | compose true
37 | }
38 | composeOptions {
39 | kotlinCompilerExtensionVersion compose_version
40 | }
41 | packagingOptions {
42 | resources {
43 | excludes += '/META-INF/{AL2.0,LGPL2.1}'
44 | }
45 | }
46 | }
47 |
48 | dependencies {
49 |
50 | implementation 'androidx.core:core-ktx:1.8.0'
51 | implementation "androidx.compose.ui:ui:$compose_version"
52 | implementation "androidx.compose.foundation:foundation:$compose_version"
53 | implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
54 | implementation "androidx.navigation:navigation-compose:$nav_version"
55 | implementation "com.google.accompanist:accompanist-systemuicontroller:0.17.0"
56 | implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.5.1'
57 | implementation 'androidx.activity:activity-compose:1.5.1'
58 | testImplementation 'junit:junit:4.13.2'
59 | androidTestImplementation 'androidx.test.ext:junit:1.1.3'
60 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
61 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/compose/designsystem/space/organisms/Drawer.kt:
--------------------------------------------------------------------------------
1 | package com.compose.designsystem.space.organisms
2 |
3 | import androidx.compose.foundation.layout.*
4 | import androidx.compose.runtime.Composable
5 | import androidx.compose.ui.Alignment
6 | import androidx.compose.ui.Modifier
7 | import androidx.compose.ui.unit.dp
8 | import com.compose.designsystem.space.atoms.basic.Divider
9 | import com.compose.designsystem.space.atoms.basic.Surface
10 | import com.compose.designsystem.space.theme.SpaceTheme
11 |
12 | @Composable
13 | fun Drawer(
14 | title: @Composable () -> Unit,
15 | description: @Composable () -> Unit,
16 | labels: @Composable RowScope.() -> Unit,
17 | actionButton: @Composable () -> Unit,
18 | modifier: Modifier = Modifier,
19 | ) {
20 | Surface(
21 | modifier = modifier,
22 | color = SpaceTheme.colors.shadesWhite,
23 | ) {
24 | Column(
25 | modifier = Modifier.padding(
26 | start = 16.dp,
27 | end = 16.dp,
28 | bottom = 32.dp,
29 | top = 8.dp,
30 | ),
31 | ) {
32 | Box(modifier = Modifier.fillMaxWidth()) {
33 | Divider(
34 | modifier = Modifier
35 | .width(120.dp)
36 | .align(Alignment.Center),
37 | color = SpaceTheme.colors.neutral_2,
38 | thickness = 4.dp,
39 | )
40 | }
41 | Spacer(modifier = Modifier.height(20.dp))
42 | title()
43 | Spacer(modifier = Modifier.height(8.dp))
44 | description()
45 | Spacer(modifier = Modifier.height(16.dp))
46 | Row(
47 | modifier = Modifier.fillMaxWidth(),
48 | horizontalArrangement = Arrangement.spacedBy(8.dp)
49 | ) {
50 | labels()
51 | }
52 | Spacer(modifier = Modifier.height(16.dp))
53 | actionButton()
54 | }
55 | }
56 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/compose/designsystem/space/atoms/Button.kt:
--------------------------------------------------------------------------------
1 | package com.compose.designsystem.space.atoms
2 |
3 | import androidx.compose.foundation.layout.*
4 | import androidx.compose.runtime.Composable
5 | import androidx.compose.ui.Alignment
6 | import androidx.compose.ui.Modifier
7 | import androidx.compose.ui.graphics.RectangleShape
8 | import androidx.compose.ui.graphics.Shape
9 | import androidx.compose.ui.unit.dp
10 | import com.compose.designsystem.space.atoms.basic.ProvideTextStyle
11 | import com.compose.designsystem.space.atoms.basic.Surface
12 | import com.compose.designsystem.space.theme.SpaceTheme
13 |
14 | sealed interface ButtonType {
15 | object Primary : ButtonType
16 | object Secondary : ButtonType
17 | object Danger : ButtonType
18 | }
19 |
20 | @Composable
21 | fun Button(
22 | onClick: () -> Unit,
23 | modifier: Modifier = Modifier,
24 | enabled: Boolean = true,
25 | iconLeft: @Composable (() -> Unit)? = null,
26 | iconRight: @Composable (() -> Unit)? = null,
27 | shape: Shape = RectangleShape,
28 | type: ButtonType = ButtonType.Primary,
29 | content: @Composable RowScope.() -> Unit,
30 | ) {
31 | val color = when (type) {
32 | ButtonType.Primary -> SpaceTheme.colors.primary_4
33 | ButtonType.Secondary -> SpaceTheme.colors.neutral_2
34 | ButtonType.Danger -> SpaceTheme.colors.error_2
35 | }
36 |
37 | Surface(
38 | onClick = onClick,
39 | modifier = modifier,
40 | enabled = enabled,
41 | shape = shape,
42 | color = color,
43 | ) {
44 | ProvideTextStyle(value = SpaceTheme.typography.h4) {
45 | Row(
46 | modifier = Modifier.padding(
47 | horizontal = 16.dp,
48 | vertical = 8.dp,
49 | ),
50 | horizontalArrangement = Arrangement.Center,
51 | verticalAlignment = Alignment.CenterVertically,
52 | ) {
53 | iconLeft?.let {
54 | iconLeft()
55 | Spacer(modifier = Modifier.width(8.dp))
56 | }
57 | content()
58 | iconRight?.let {
59 | Spacer(modifier = Modifier.width(8.dp))
60 | iconRight()
61 | }
62 | }
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/app/src/main/java/com/compose/designsystem/space/atoms/Tab.kt:
--------------------------------------------------------------------------------
1 | package com.compose.designsystem.space.atoms
2 |
3 | import androidx.compose.foundation.interaction.MutableInteractionSource
4 | import androidx.compose.foundation.layout.*
5 | import androidx.compose.foundation.selection.selectable
6 | import androidx.compose.runtime.Composable
7 | import androidx.compose.runtime.CompositionLocalProvider
8 | import androidx.compose.runtime.remember
9 | import androidx.compose.ui.Modifier
10 | import androidx.compose.ui.semantics.Role
11 | import androidx.compose.ui.text.font.FontWeight
12 | import androidx.compose.ui.unit.dp
13 | import com.compose.designsystem.space.atoms.basic.Divider
14 | import com.compose.designsystem.space.atoms.basic.Text
15 | import com.compose.designsystem.space.theme.LocalContentColor
16 | import com.compose.designsystem.space.theme.SpaceTheme
17 |
18 | @Composable
19 | fun RowScope.Tab(
20 | text: String,
21 | selected: Boolean,
22 | onClick: () -> Unit,
23 | modifier: Modifier = Modifier,
24 | interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }
25 | ) {
26 | val contentColor = if (selected) {
27 | SpaceTheme.colors.primary_4
28 | } else {
29 | SpaceTheme.colors.neutral_9
30 | }
31 |
32 | val selectedStyle = SpaceTheme.typography.h4
33 |
34 | val unselectedStyle = SpaceTheme.typography.h4.copy(
35 | fontWeight = FontWeight.Normal
36 | )
37 |
38 | CompositionLocalProvider(
39 | LocalContentColor provides contentColor
40 | ) {
41 | Box(
42 | modifier = modifier
43 | .selectable(
44 | selected = selected,
45 | onClick = onClick,
46 | enabled = true,
47 | role = Role.Tab,
48 | interactionSource = interactionSource,
49 | indication = null,
50 | )
51 | ) {
52 | Column(modifier = Modifier.width(IntrinsicSize.Min)) {
53 | Text(
54 | modifier = Modifier.padding(vertical = 8.dp),
55 | text = text,
56 | style = if (selected) selectedStyle else unselectedStyle
57 | )
58 | if (selected) {
59 | Divider()
60 | }
61 | }
62 | }
63 | }
64 |
65 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/compose/designsystem/space/atoms/basic/Icon.kt:
--------------------------------------------------------------------------------
1 | package com.compose.designsystem.space.atoms.basic
2 |
3 | import androidx.compose.foundation.layout.Box
4 | import androidx.compose.foundation.layout.size
5 | import androidx.compose.runtime.Composable
6 | import androidx.compose.ui.Modifier
7 | import androidx.compose.ui.draw.paint
8 | import androidx.compose.ui.geometry.Size
9 | import androidx.compose.ui.graphics.Color
10 | import androidx.compose.ui.graphics.ColorFilter
11 | import androidx.compose.ui.graphics.painter.Painter
12 | import androidx.compose.ui.graphics.toolingGraphicsLayer
13 | import androidx.compose.ui.layout.ContentScale
14 | import androidx.compose.ui.semantics.Role
15 | import androidx.compose.ui.semantics.contentDescription
16 | import androidx.compose.ui.semantics.role
17 | import androidx.compose.ui.semantics.semantics
18 | import androidx.compose.ui.unit.dp
19 | import com.compose.designsystem.space.theme.LocalContentAlpha
20 | import com.compose.designsystem.space.theme.LocalContentColor
21 |
22 | @Composable
23 | fun Icon(
24 | painter: Painter,
25 | contentDescription: String?,
26 | modifier: Modifier = Modifier,
27 | tint: Color = LocalContentColor.current.copy(alpha = LocalContentAlpha.current)
28 | ) {
29 | val colorFilter = if (tint == Color.Unspecified) {
30 | ColorFilter.tint(LocalContentColor.current)
31 | } else {
32 | ColorFilter.tint(tint)
33 | }
34 | val semantics = if (contentDescription != null) {
35 | Modifier.semantics {
36 | this.contentDescription = contentDescription
37 | this.role = Role.Image
38 | }
39 | } else {
40 | Modifier
41 | }
42 |
43 | Box(
44 | modifier
45 | .toolingGraphicsLayer()
46 | .defaultSizeFor(painter)
47 | .paint(
48 | painter,
49 | colorFilter = colorFilter,
50 | contentScale = ContentScale.Fit
51 | )
52 | .then(semantics)
53 | )
54 | }
55 |
56 | private fun Modifier.defaultSizeFor(painter: Painter) =
57 | this.then(
58 | if (painter.intrinsicSize == Size.Unspecified || painter.intrinsicSize.isInfinite()) {
59 | Modifier.size(24.dp)
60 | } else {
61 | Modifier
62 | }
63 | )
64 |
65 | private fun Size.isInfinite() = width.isInfinite() && height.isInfinite()
--------------------------------------------------------------------------------
/app/src/main/java/com/compose/designsystem/space/organisms/Prompt.kt:
--------------------------------------------------------------------------------
1 | package com.compose.designsystem.space.organisms
2 |
3 | import androidx.compose.foundation.background
4 | import androidx.compose.foundation.border
5 | import androidx.compose.foundation.layout.*
6 | import androidx.compose.runtime.Composable
7 | import androidx.compose.ui.Modifier
8 | import androidx.compose.ui.text.font.FontWeight
9 | import androidx.compose.ui.unit.dp
10 | import androidx.compose.ui.window.Dialog
11 | import com.compose.designsystem.space.atoms.basic.Text
12 | import com.compose.designsystem.space.theme.SpaceTheme
13 |
14 | @Composable
15 | fun Prompt(
16 | title: String,
17 | primaryButton: @Composable () -> Unit,
18 | onDismiss: () -> Unit,
19 | modifier: Modifier = Modifier,
20 | description: String? = null,
21 | secondaryButton: @Composable (() -> Unit)? = null
22 | ) {
23 |
24 | Dialog(
25 | onDismissRequest = onDismiss,
26 | ) {
27 | Column(
28 | modifier = modifier
29 | .background(
30 | color = SpaceTheme.colors.neutral_2,
31 | shape = SpaceTheme.shapes.medium,
32 | )
33 | .border(
34 | width = 1.dp,
35 | color = SpaceTheme.colors.neutral_2,
36 | shape = SpaceTheme.shapes.medium,
37 | )
38 | .padding(
39 | top = 16.dp,
40 | start = 16.dp,
41 | end = 16.dp,
42 | bottom = 8.dp,
43 | ),
44 | ) {
45 | Text(text = title, style = SpaceTheme.typography.h3)
46 | description?.let {
47 | Text(
48 | text = description, style = SpaceTheme.typography.h4.copy(
49 | fontWeight = FontWeight.Normal,
50 | )
51 | )
52 | }
53 | Spacer(modifier = Modifier.height(8.dp))
54 | Row(
55 | modifier = Modifier.fillMaxWidth(),
56 | horizontalArrangement = Arrangement.End
57 | ) {
58 | secondaryButton?.let {
59 | secondaryButton()
60 | Spacer(modifier = Modifier.width(16.dp))
61 | }
62 |
63 | primaryButton()
64 | }
65 | }
66 | }
67 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/compose/designsystem/space/organisms/Profile.kt:
--------------------------------------------------------------------------------
1 | package com.compose.designsystem.space.organisms
2 |
3 | import androidx.compose.foundation.background
4 | import androidx.compose.foundation.layout.*
5 | import androidx.compose.runtime.Composable
6 | import androidx.compose.ui.Alignment
7 | import androidx.compose.ui.Modifier
8 | import androidx.compose.ui.graphics.Shape
9 | import androidx.compose.ui.res.painterResource
10 | import androidx.compose.ui.text.font.FontWeight
11 | import androidx.compose.ui.unit.dp
12 | import com.compose.designsystem.space.atoms.Avatar
13 | import com.compose.designsystem.space.atoms.AvatarStatus
14 | import com.compose.designsystem.space.atoms.Button
15 | import com.compose.designsystem.space.atoms.basic.Text
16 | import com.compose.designsystem.space.theme.IcCheck
17 | import com.compose.designsystem.space.theme.SpaceIcons
18 | import com.compose.designsystem.space.theme.SpaceTheme
19 |
20 | data class Profile(
21 | val name: String,
22 | val image: Int,
23 | val position: String,
24 | val subscribed: Boolean,
25 | )
26 |
27 | @Composable
28 | fun Profile(
29 | profile: Profile,
30 | modifier: Modifier = Modifier,
31 | shape: Shape = SpaceTheme.shapes.medium,
32 | ) {
33 | Column(
34 | modifier = modifier
35 | .background(SpaceTheme.colors.neutral_1, shape = shape)
36 | .padding(32.dp)
37 | .fillMaxWidth(),
38 | horizontalAlignment = Alignment.CenterHorizontally,
39 | ) {
40 | Avatar(
41 | size = 80.dp,
42 | status = AvatarStatus.Online,
43 | painter = painterResource(id = profile.image)
44 | )
45 | Spacer(modifier = Modifier.height(16.dp))
46 | Text(
47 | text = profile.name,
48 | style = SpaceTheme.typography.h2,
49 | )
50 | Text(
51 | text = profile.position,
52 | style = SpaceTheme.typography.h4.copy(
53 | fontWeight = FontWeight.Normal,
54 | ),
55 | )
56 | Spacer(modifier = Modifier.height(16.dp))
57 |
58 | Button(
59 | onClick = {},
60 | shape = SpaceTheme.shapes.large,
61 | iconRight = if (profile.subscribed) {
62 | { SpaceIcons.IcCheck(contentDescription = null) }
63 | } else null) {
64 | Text(text = if (profile.subscribed) "Subscribed" else "Subscribe")
65 | }
66 | }
67 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/compose/designsystem/space/atoms/Link.kt:
--------------------------------------------------------------------------------
1 | package com.compose.designsystem.space.atoms
2 |
3 | import androidx.compose.foundation.layout.*
4 | import androidx.compose.runtime.Composable
5 | import androidx.compose.ui.Alignment
6 | import androidx.compose.ui.Modifier
7 | import androidx.compose.ui.graphics.RectangleShape
8 | import androidx.compose.ui.unit.dp
9 | import com.compose.designsystem.space.atoms.basic.Divider
10 | import com.compose.designsystem.space.atoms.basic.ProvideTextStyle
11 | import com.compose.designsystem.space.atoms.basic.Surface
12 | import com.compose.designsystem.space.theme.SpaceTheme
13 |
14 | sealed interface LinkType {
15 | object Primary : LinkType
16 | object Secondary : LinkType
17 | object Danger : LinkType
18 | }
19 |
20 | @Composable
21 | fun Link(
22 | onClick: () -> Unit,
23 | modifier: Modifier = Modifier,
24 | enabled: Boolean = true,
25 | drawUnderline: Boolean = true,
26 | iconLeft: @Composable (() -> Unit)? = null,
27 | iconRight: @Composable (() -> Unit)? = null,
28 | type: LinkType = LinkType.Primary,
29 | content: @Composable RowScope.() -> Unit,
30 | ) {
31 | val color = when (type) {
32 | LinkType.Primary -> SpaceTheme.colors.primary_4
33 | LinkType.Secondary -> SpaceTheme.colors.neutral_2
34 | LinkType.Danger -> SpaceTheme.colors.error_2
35 | }
36 |
37 | Surface(
38 | onClick = onClick,
39 | modifier = modifier,
40 | enabled = enabled,
41 | shape = RectangleShape,
42 | contentColor = color
43 | ) {
44 | ProvideTextStyle(value = SpaceTheme.typography.h4) {
45 | Column(
46 | modifier = Modifier.width(IntrinsicSize.Max)
47 | ) {
48 | Row(
49 | modifier = Modifier.padding(
50 | vertical = 8.dp,
51 | ),
52 | horizontalArrangement = Arrangement.Center,
53 | verticalAlignment = Alignment.CenterVertically,
54 | ) {
55 | iconLeft?.let {
56 | iconLeft()
57 | Spacer(modifier = Modifier.width(8.dp))
58 | }
59 | content()
60 | iconRight?.let {
61 | Spacer(modifier = Modifier.width(8.dp))
62 | iconRight()
63 | }
64 | }
65 | if (drawUnderline) {
66 | Divider()
67 | }
68 | }
69 | }
70 | }
71 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/compose/designsystem/space/atoms/IconButton.kt:
--------------------------------------------------------------------------------
1 | package com.compose.designsystem.space.atoms
2 |
3 | import androidx.compose.foundation.background
4 | import androidx.compose.foundation.clickable
5 | import androidx.compose.foundation.interaction.MutableInteractionSource
6 | import androidx.compose.runtime.Composable
7 | import androidx.compose.runtime.CompositionLocalProvider
8 | import androidx.compose.runtime.remember
9 | import androidx.compose.ui.Modifier
10 | import androidx.compose.ui.layout.Layout
11 | import androidx.compose.ui.unit.dp
12 | import com.compose.designsystem.space.theme.LocalContentColor
13 | import com.compose.designsystem.space.theme.SpaceTheme
14 | import com.compose.designsystem.space.theme.contentColorFor
15 |
16 | private val IconButtonSize = 40.dp
17 |
18 | sealed interface IconButtonType {
19 | object Default : IconButtonType
20 | object Secondary : IconButtonType
21 | object Danger : IconButtonType
22 | }
23 |
24 | @Composable
25 | fun IconButton(
26 | icon: @Composable () -> Unit,
27 | onClick: () -> Unit,
28 | modifier: Modifier = Modifier,
29 | interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
30 | iconButtonType: IconButtonType = IconButtonType.Default,
31 | ) {
32 | val backgroundColor = when (iconButtonType) {
33 | IconButtonType.Danger -> SpaceTheme.colors.error_2
34 | IconButtonType.Default -> SpaceTheme.colors.primary_4
35 | IconButtonType.Secondary -> SpaceTheme.colors.neutral_2
36 | }
37 |
38 | val iconColor = contentColorFor(backgroundColor = backgroundColor)
39 |
40 | CompositionLocalProvider(
41 | LocalContentColor provides iconColor
42 | ) {
43 | Layout(
44 | modifier = modifier.then(
45 | Modifier
46 | .background(backgroundColor, SpaceTheme.shapes.large)
47 | .clickable(
48 | onClick = onClick,
49 | indication = null,
50 | interactionSource = interactionSource,
51 | )
52 | ),
53 | content = icon
54 | ) { measurables, constraints ->
55 | val placeables = measurables.map { measurable ->
56 | measurable.measure(constraints)
57 | }
58 |
59 | val boxWidth = IconButtonSize.toPx().toInt()
60 | val boxHeight = IconButtonSize.toPx().toInt()
61 |
62 | layout(boxWidth, boxWidth) {
63 | placeables.forEach { placeable ->
64 | val x = boxWidth / 2 - placeable.width / 2
65 | val y = boxHeight / 2 - placeable.height / 2
66 | placeable.placeRelative(x = x, y = y)
67 | }
68 | }
69 | }
70 | }
71 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/compose/designsystem/space/atoms/basic/Surface.kt:
--------------------------------------------------------------------------------
1 | package com.compose.designsystem.space.atoms.basic
2 |
3 | import androidx.compose.foundation.background
4 | import androidx.compose.foundation.clickable
5 | import androidx.compose.foundation.interaction.MutableInteractionSource
6 | import androidx.compose.foundation.layout.Box
7 | import androidx.compose.runtime.Composable
8 | import androidx.compose.runtime.CompositionLocalProvider
9 | import androidx.compose.runtime.remember
10 | import androidx.compose.ui.Modifier
11 | import androidx.compose.ui.draw.clip
12 | import androidx.compose.ui.graphics.Color
13 | import androidx.compose.ui.graphics.RectangleShape
14 | import androidx.compose.ui.graphics.Shape
15 | import androidx.compose.ui.input.pointer.pointerInput
16 | import androidx.compose.ui.semantics.Role
17 | import androidx.compose.ui.semantics.semantics
18 | import com.compose.designsystem.space.theme.LocalContentColor
19 | import com.compose.designsystem.space.theme.SpaceTheme
20 | import com.compose.designsystem.space.theme.contentColorFor
21 |
22 | @Composable
23 | fun Surface(
24 | onClick: () -> Unit,
25 | modifier: Modifier = Modifier,
26 | enabled: Boolean = true,
27 | shape: Shape = RectangleShape,
28 | color: Color = SpaceTheme.colors.shadesWhite,
29 | contentColor: Color = contentColorFor(color),
30 | interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
31 | content: @Composable () -> Unit,
32 | ) {
33 | CompositionLocalProvider(
34 | LocalContentColor provides contentColor
35 | ) {
36 | Box(
37 | modifier = modifier
38 | .surface(
39 | shape = shape,
40 | backgroundColor = color,
41 | )
42 | .clickable(
43 | interactionSource = interactionSource,
44 | indication = null,
45 | enabled = enabled,
46 | role = Role.Button,
47 | onClick = onClick
48 | ),
49 | ) {
50 | content()
51 | }
52 | }
53 | }
54 |
55 | @Composable
56 | fun Surface(
57 | modifier: Modifier = Modifier,
58 | shape: Shape = RectangleShape,
59 | color: Color = SpaceTheme.colors.shadesWhite,
60 | contentColor: Color = contentColorFor(color),
61 | content: @Composable () -> Unit
62 | ) {
63 | CompositionLocalProvider(
64 | LocalContentColor provides contentColor,
65 | ) {
66 | Box(
67 | modifier = modifier
68 | .surface(
69 | shape = shape,
70 | backgroundColor = color
71 | )
72 | .semantics(mergeDescendants = false) {}
73 | .pointerInput(Unit) {},
74 | propagateMinConstraints = true
75 | ) {
76 | content()
77 | }
78 | }
79 | }
80 |
81 | fun Modifier.surface(
82 | shape: Shape,
83 | backgroundColor: Color,
84 | ) = this
85 | .background(color = backgroundColor, shape = shape)
86 | .clip(shape)
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/app/src/main/java/com/compose/designsystem/space/atoms/Select.kt:
--------------------------------------------------------------------------------
1 | package com.compose.designsystem.space.atoms
2 |
3 | import androidx.compose.foundation.BorderStroke
4 | import androidx.compose.foundation.background
5 | import androidx.compose.foundation.border
6 | import androidx.compose.foundation.layout.*
7 | import androidx.compose.runtime.Composable
8 | import androidx.compose.ui.Alignment
9 | import androidx.compose.ui.Modifier
10 | import androidx.compose.ui.graphics.Shape
11 | import androidx.compose.ui.text.TextStyle
12 | import androidx.compose.ui.text.font.FontWeight
13 | import androidx.compose.ui.text.style.TextAlign
14 | import androidx.compose.ui.unit.dp
15 | import com.compose.designsystem.space.atoms.basic.Text
16 | import com.compose.designsystem.space.theme.IcKeyboardArrowDown
17 | import com.compose.designsystem.space.theme.SpaceIcons
18 | import com.compose.designsystem.space.theme.SpaceTheme
19 |
20 | sealed interface SelectType {
21 | object Default : SelectType
22 | object Success : SelectType
23 | object Error : SelectType
24 | }
25 |
26 | private val MinHeight = 40.dp
27 | private val MinWidth = 77.dp
28 |
29 | @Composable
30 | fun Select(
31 | text: String,
32 | modifier: Modifier = Modifier,
33 | inSelectionMode: Boolean = false,
34 | selectType: SelectType = SelectType.Default,
35 | shape: Shape = SpaceTheme.shapes.small,
36 | textStyle: TextStyle = SpaceTheme.typography.h4.copy(fontWeight = FontWeight.Normal),
37 | ) {
38 |
39 | val borderSize = when (selectType) {
40 | SelectType.Default -> 1.dp
41 | SelectType.Error -> 2.dp
42 | SelectType.Success -> 2.dp
43 | }
44 |
45 | val borderColor = when (selectType) {
46 | SelectType.Default -> SpaceTheme.colors.neutral_3
47 | SelectType.Error -> SpaceTheme.colors.error_4
48 | SelectType.Success -> SpaceTheme.colors.success_4
49 | }
50 |
51 | Box(
52 | modifier = modifier
53 | .defaultMinSize(
54 | minWidth = MinWidth,
55 | minHeight = MinHeight,
56 | )
57 | .background(SpaceTheme.colors.neutral_1, shape = shape)
58 | .border(
59 | border = BorderStroke(borderSize, borderColor),
60 | shape = shape
61 | )
62 |
63 | ) {
64 | Row(
65 | modifier = Modifier
66 | .padding(
67 | horizontal = 16.dp,
68 | vertical = 8.dp,
69 | ),
70 | verticalAlignment = Alignment.CenterVertically
71 | ) {
72 | Text(
73 | modifier = Modifier.weight(1f),
74 | text = text,
75 | style = textStyle,
76 | textAlign = TextAlign.Start,
77 | )
78 | Spacer(modifier = Modifier.width(4.dp))
79 | if (!inSelectionMode) {
80 | SpaceIcons.IcKeyboardArrowDown(contentDescription = null)
81 | } else {
82 | SpaceIcons.IcKeyboardArrowDown(
83 | contentDescription = null,
84 | rotate = true,
85 | )
86 | }
87 | }
88 | }
89 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/compose/designsystem/space/atoms/NavTab.kt:
--------------------------------------------------------------------------------
1 | package com.compose.designsystem.space.atoms
2 |
3 | import androidx.compose.foundation.interaction.MutableInteractionSource
4 | import androidx.compose.foundation.layout.Box
5 | import androidx.compose.foundation.layout.RowScope
6 | import androidx.compose.foundation.selection.selectable
7 | import androidx.compose.runtime.Composable
8 | import androidx.compose.runtime.CompositionLocalProvider
9 | import androidx.compose.runtime.remember
10 | import androidx.compose.ui.Alignment
11 | import androidx.compose.ui.Modifier
12 | import androidx.compose.ui.layout.LastBaseline
13 | import androidx.compose.ui.layout.Layout
14 | import androidx.compose.ui.layout.layoutId
15 | import androidx.compose.ui.semantics.Role
16 | import androidx.compose.ui.text.font.FontWeight
17 | import androidx.compose.ui.unit.dp
18 | import com.compose.designsystem.space.atoms.basic.Text
19 | import com.compose.designsystem.space.theme.LocalContentColor
20 | import com.compose.designsystem.space.theme.SpaceTheme
21 | import kotlin.math.max
22 |
23 | @Composable
24 | fun RowScope.NavTab(
25 | text: String,
26 | icon: @Composable () -> Unit,
27 | onClick: () -> Unit,
28 | selected: Boolean,
29 | modifier: Modifier = Modifier,
30 | interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }
31 | ) {
32 | val contentColor = if (selected) {
33 | SpaceTheme.colors.primary_4
34 | } else {
35 | SpaceTheme.colors.neutral_6
36 | }
37 |
38 | val style = if (selected) {
39 | SpaceTheme.typography.h4
40 | } else {
41 | SpaceTheme.typography.h4.copy(
42 | fontWeight = FontWeight.Normal,
43 | )
44 | }
45 | CompositionLocalProvider(
46 | LocalContentColor provides contentColor
47 | ) {
48 | Box(
49 | modifier = modifier
50 | .selectable(
51 | selected = selected,
52 | onClick = onClick,
53 | enabled = true,
54 | role = Role.Tab,
55 | interactionSource = interactionSource,
56 | indication = null,
57 | )
58 | .weight(1f),
59 | contentAlignment = Alignment.Center
60 | ) {
61 | Layout(
62 | {
63 | Box(Modifier.layoutId("icon")) { icon() }
64 | Box(Modifier.layoutId("text")) {
65 | Text(
66 | text = text,
67 | style = style,
68 | )
69 | }
70 | }
71 | ) { measurables, constraints ->
72 | val iconPlaceable = measurables.first { it.layoutId == "icon" }.measure(constraints)
73 | val textPlaceable = measurables.first { it.layoutId == "text" }.measure(
74 | constraints.copy(minHeight = 0)
75 | )
76 |
77 | val height = constraints.maxHeight
78 | val containerWidth = max(textPlaceable.width, iconPlaceable.width)
79 |
80 | val baseline = textPlaceable[LastBaseline]
81 | val baselineOffset = 10.dp.roundToPx()
82 |
83 | val textY = height - baseline - baselineOffset
84 |
85 | val iconY = baselineOffset
86 |
87 | val iconX = (containerWidth - iconPlaceable.width) / 2
88 |
89 | val textX = (containerWidth - textPlaceable.width) / 2
90 |
91 | layout(containerWidth, height) {
92 | textPlaceable.placeRelative(textX, textY)
93 | iconPlaceable.placeRelative(iconX, iconY)
94 | }
95 | }
96 | }
97 | }
98 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/compose/designsystem/application/forth/ForthSpaceScreen.kt:
--------------------------------------------------------------------------------
1 | package com.compose.designsystem.application.forth
2 |
3 | import androidx.compose.foundation.layout.*
4 | import androidx.compose.foundation.rememberScrollState
5 | import androidx.compose.foundation.verticalScroll
6 | import androidx.compose.runtime.Composable
7 | import androidx.compose.ui.Modifier
8 | import androidx.compose.ui.unit.dp
9 | import com.compose.designsystem.space.atoms.Button
10 | import com.compose.designsystem.space.atoms.basic.Text
11 | import com.compose.designsystem.space.molecules.InputGroup
12 | import com.compose.designsystem.space.molecules.SelectGroup
13 | import com.compose.designsystem.space.organisms.Form
14 | import com.compose.designsystem.space.theme.SpaceTheme
15 |
16 | @Composable
17 | fun ForthSpaceScreen() {
18 | Column(
19 | modifier = Modifier
20 | .fillMaxSize()
21 | .verticalScroll(rememberScrollState())
22 | .padding(
23 | top = 32.dp,
24 | start = 16.dp,
25 | end = 16.dp,
26 | bottom = 32.dp,
27 | )
28 | ) {
29 | Text(
30 | text = "Checkout",
31 | style = SpaceTheme.typography.h2,
32 | )
33 | Spacer(modifier = Modifier.height(16.dp))
34 | Form(
35 | inputs = {
36 | InputGroup(
37 | modifier = Modifier.fillMaxWidth(),
38 | label = "Name on card",
39 | onInputChange = {},
40 | )
41 | Spacer(modifier = Modifier.height(8.dp))
42 | InputGroup(
43 | modifier = Modifier.fillMaxWidth(),
44 | label = "Card Number",
45 | onInputChange = {},
46 | )
47 | Spacer(modifier = Modifier.height(8.dp))
48 | Row(
49 | modifier = Modifier.fillMaxWidth(),
50 | horizontalArrangement = Arrangement.SpaceEvenly,
51 | ) {
52 | SelectGroup(
53 | modifier = Modifier.weight(1f),
54 | label = "Month",
55 | input = "Jan",
56 | )
57 | Spacer(modifier = Modifier.width(12.dp))
58 | SelectGroup(
59 | modifier = Modifier.weight(1f),
60 | label = "Year",
61 | input = "2022",
62 | )
63 | }
64 | Spacer(modifier = Modifier.height(8.dp))
65 | Row(
66 | modifier = Modifier.fillMaxWidth(),
67 | horizontalArrangement = Arrangement.SpaceEvenly,
68 | ) {
69 | InputGroup(
70 | modifier = Modifier.weight(1f),
71 | label = "CVC",
72 | onInputChange = {},
73 | )
74 | Spacer(modifier = Modifier.width(12.dp))
75 | InputGroup(
76 | modifier = Modifier.weight(1f),
77 | label = "Zip Code",
78 | onInputChange = {},
79 | )
80 | }
81 | },
82 | submitButton = {
83 | Button(
84 | modifier = Modifier.height(48.dp),
85 | onClick = {},
86 | shape = SpaceTheme.shapes.large,
87 | ) {
88 | Text(
89 | text = "Submit",
90 | modifier = Modifier.fillMaxWidth(),
91 | )
92 | }
93 | }
94 | )
95 | }
96 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/compose/designsystem/space/atoms/Avatar.kt:
--------------------------------------------------------------------------------
1 | package com.compose.designsystem.space.atoms
2 |
3 | import androidx.compose.foundation.Image
4 | import androidx.compose.foundation.background
5 | import androidx.compose.foundation.border
6 | import androidx.compose.foundation.layout.Box
7 | import androidx.compose.foundation.layout.fillMaxSize
8 | import androidx.compose.foundation.layout.size
9 | import androidx.compose.foundation.shape.CircleShape
10 | import androidx.compose.runtime.Composable
11 | import androidx.compose.ui.Alignment
12 | import androidx.compose.ui.Modifier
13 | import androidx.compose.ui.draw.clip
14 | import androidx.compose.ui.graphics.Color
15 | import androidx.compose.ui.graphics.Shape
16 | import androidx.compose.ui.graphics.painter.Painter
17 | import androidx.compose.ui.text.font.FontWeight
18 | import androidx.compose.ui.unit.Dp
19 | import androidx.compose.ui.unit.dp
20 | import com.compose.designsystem.space.atoms.basic.Text
21 | import com.compose.designsystem.space.atoms.basic.surface
22 | import com.compose.designsystem.space.theme.SpaceTheme
23 |
24 | sealed interface AvatarStatus {
25 | object None : AvatarStatus
26 | object Online : AvatarStatus
27 | object Absent : AvatarStatus
28 | object Busy : AvatarStatus
29 | }
30 |
31 | @Composable
32 | fun Avatar(
33 | painter: Painter,
34 | status: AvatarStatus,
35 | modifier: Modifier = Modifier,
36 | shape: Shape = CircleShape,
37 | size: Dp = 40.dp,
38 | ) {
39 | Box(
40 | modifier = modifier
41 | .size(size)
42 | ) {
43 | Image(
44 | modifier = Modifier
45 | .clip(shape)
46 | .fillMaxSize(),
47 | painter = painter,
48 | contentDescription = null
49 | )
50 | if (status != AvatarStatus.None) {
51 | Indicator(
52 | avatarStatus = status,
53 | size = size / 3,
54 | modifier = Modifier.align(Alignment.TopEnd)
55 | )
56 | }
57 | }
58 |
59 | }
60 |
61 | @Composable
62 | fun Avatar(
63 | modifier: Modifier = Modifier,
64 | status: AvatarStatus,
65 | name: String? = null,
66 | shape: Shape = CircleShape,
67 | size: Dp = 40.dp
68 | ) {
69 | Box(
70 | modifier = modifier
71 | .size(size)
72 | .surface(shape, SpaceTheme.colors.neutral_9),
73 | ) {
74 | if (name != null) {
75 | Text(
76 | text = name.take(1),
77 | style = SpaceTheme.typography.h4.copy(
78 | fontWeight = FontWeight.Normal,
79 | color = SpaceTheme.colors.shadesWhite,
80 | )
81 | )
82 | }
83 | if (status != AvatarStatus.None) {
84 | Indicator(
85 | avatarStatus = status,
86 | size = size / 4,
87 | modifier = Modifier.align(Alignment.TopEnd)
88 | )
89 | }
90 | }
91 | }
92 |
93 | @Composable
94 | private fun Indicator(
95 | avatarStatus: AvatarStatus,
96 | size: Dp,
97 | modifier: Modifier = Modifier,
98 | shape: Shape = CircleShape,
99 | ) {
100 | val color = when (avatarStatus) {
101 | AvatarStatus.Online -> SpaceTheme.colors.success_4
102 | AvatarStatus.Absent -> SpaceTheme.colors.error_4
103 | AvatarStatus.Busy -> SpaceTheme.colors.warning_4
104 | else -> Color.Unspecified
105 | }
106 |
107 | Box(
108 | modifier = modifier
109 | .background(color, shape)
110 | .size(size)
111 | .border(
112 | width = 2.dp,
113 | color = SpaceTheme.colors.shadesWhite,
114 | shape = shape
115 | )
116 | )
117 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/compose/designsystem/application/second/SecondSpaceScreen.kt:
--------------------------------------------------------------------------------
1 | package com.compose.designsystem.application.second
2 |
3 | import androidx.compose.foundation.Image
4 | import androidx.compose.foundation.background
5 | import androidx.compose.foundation.layout.*
6 | import androidx.compose.foundation.shape.RoundedCornerShape
7 | import androidx.compose.runtime.Composable
8 | import androidx.compose.ui.Alignment
9 | import androidx.compose.ui.Modifier
10 | import androidx.compose.ui.graphics.Color
11 | import androidx.compose.ui.res.painterResource
12 | import androidx.compose.ui.text.font.FontWeight
13 | import androidx.compose.ui.text.style.TextAlign
14 | import androidx.compose.ui.unit.dp
15 | import com.compose.designsystem.R
16 | import com.compose.designsystem.space.atoms.Button
17 | import com.compose.designsystem.space.atoms.ButtonType
18 | import com.compose.designsystem.space.atoms.basic.Text
19 | import com.compose.designsystem.space.organisms.BottomSheetScreen
20 | import com.compose.designsystem.space.organisms.Drawer
21 | import com.compose.designsystem.space.theme.IcHeart
22 | import com.compose.designsystem.space.theme.SpaceIcons
23 | import com.compose.designsystem.space.theme.SpaceTheme
24 |
25 | @Composable
26 | fun SecondSpaceScreen() {
27 |
28 | BottomSheetScreen(
29 | sheetContent = { SecondScreenBottomSheet() },
30 | sheetShape = RoundedCornerShape(topStart = 45.dp, topEnd = 45.dp),
31 | sheetElevation = 16.dp,
32 | ) {
33 | Box(
34 | Modifier
35 | .fillMaxSize()
36 | .background(Color(0xFFCCCCF2))
37 | ) {
38 | Image(
39 | painter = painterResource(id = R.drawable.space),
40 | contentDescription = null,
41 | modifier = Modifier
42 | .align(Alignment.TopCenter)
43 | .padding(top = 90.dp)
44 | .size(240.dp)
45 | )
46 | }
47 | }
48 | }
49 |
50 | @Composable
51 | private fun SecondScreenBottomSheet() {
52 | Drawer(
53 | title = {
54 | Row {
55 | Text(
56 | text = "Title",
57 | style = SpaceTheme.typography.h3,
58 | )
59 | Spacer(modifier = Modifier.weight(1f))
60 | SpaceIcons.IcHeart(
61 | modifier = Modifier.size(32.dp),
62 | contentDescription = null,
63 | tint = SpaceTheme.colors.error_4
64 | )
65 | }
66 |
67 | },
68 | description = {
69 | Text(
70 | text = "Illustration by Andy Dao. Thank you for creating these beautiful illustrations. I’ve included several in this system. Credit for the illustrations goes to Andy.",
71 | style = SpaceTheme.typography.h4.copy(
72 | fontWeight = FontWeight.Normal,
73 | color = SpaceTheme.colors.neutral_7,
74 | ),
75 | textAlign = TextAlign.Left,
76 | )
77 | },
78 | labels = {
79 | Button(onClick = {}, type = ButtonType.Secondary, shape = SpaceTheme.shapes.large) {
80 | Text(
81 | "Illustrations",
82 | style = SpaceTheme.typography.h4.copy(fontWeight = FontWeight.Normal)
83 | )
84 | }
85 | Button(onClick = {}, type = ButtonType.Secondary, shape = SpaceTheme.shapes.large) {
86 | Text(
87 | text = "Cats",
88 | style = SpaceTheme.typography.h4.copy(fontWeight = FontWeight.Normal),
89 | )
90 | }
91 | },
92 | actionButton = {
93 | Button(onClick = {}, shape = SpaceTheme.shapes.large) {
94 | Text(
95 | text = "Download",
96 | style = SpaceTheme.typography.h3,
97 | modifier = Modifier.fillMaxWidth()
98 | )
99 | }
100 | }
101 | )
102 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/compose/designsystem/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.compose.designsystem
2 |
3 | import android.os.Bundle
4 | import androidx.activity.ComponentActivity
5 | import androidx.activity.compose.setContent
6 | import androidx.compose.foundation.layout.Column
7 | import androidx.compose.foundation.layout.Spacer
8 | import androidx.compose.foundation.layout.height
9 | import androidx.compose.runtime.Composable
10 | import androidx.compose.ui.Modifier
11 | import androidx.compose.ui.tooling.preview.Preview
12 | import androidx.compose.ui.unit.dp
13 | import androidx.navigation.NavController
14 | import androidx.navigation.compose.NavHost
15 | import androidx.navigation.compose.composable
16 | import androidx.navigation.compose.rememberNavController
17 | import com.compose.designsystem.application.fifth.FifthSpaceScreen
18 | import com.compose.designsystem.application.first.FirstSpaceScreen
19 | import com.compose.designsystem.application.forth.ForthSpaceScreen
20 | import com.compose.designsystem.application.second.SecondSpaceScreen
21 | import com.compose.designsystem.application.third.ThirdSpaceScreen
22 | import com.compose.designsystem.space.atoms.Button
23 | import com.compose.designsystem.space.atoms.basic.Text
24 | import com.compose.designsystem.ui.theme.ComposeDesignSystemTheme
25 |
26 | object Directions {
27 | const val Main = "main"
28 | const val FirstScreen = "first_screen"
29 | const val SecondScreen = "second_screen"
30 | const val ThirdScreen = "third_screen"
31 | const val ForthScreen = "forth_screen"
32 | const val FifthScreen = "fifth_screen"
33 | }
34 |
35 | class MainActivity : ComponentActivity() {
36 | override fun onCreate(savedInstanceState: Bundle?) {
37 | super.onCreate(savedInstanceState)
38 | setContent {
39 | ComposeDesignSystemTheme {
40 | val navController = rememberNavController()
41 | NavHost(navController = navController, startDestination = Directions.Main) {
42 | composable(Directions.Main) { MainScreen(navController = navController) }
43 | composable(Directions.FirstScreen) { FirstSpaceScreen() }
44 | composable(Directions.SecondScreen) { SecondSpaceScreen() }
45 | composable(Directions.ThirdScreen) { ThirdSpaceScreen() }
46 | composable(Directions.ForthScreen) { ForthSpaceScreen() }
47 | composable(Directions.FifthScreen) { FifthSpaceScreen() }
48 | }
49 | }
50 | }
51 | }
52 | }
53 |
54 | @Composable
55 | fun MainScreen(
56 | navController: NavController
57 | ) {
58 | Column {
59 | Button(onClick = { navController.navigate(Directions.FirstScreen) }) {
60 | Text("History screen")
61 | }
62 | Spacer(modifier = Modifier.height(8.dp))
63 | Button(onClick = { navController.navigate(Directions.SecondScreen) }) {
64 | Text("Drawer screen")
65 | }
66 | Spacer(modifier = Modifier.height(8.dp))
67 | Button(onClick = { navController.navigate(Directions.ThirdScreen) }) {
68 | Text("Prompt screen")
69 | }
70 | Spacer(modifier = Modifier.height(8.dp))
71 | Button(onClick = { navController.navigate(Directions.ForthScreen) }) {
72 | Text("Checkout screen")
73 | }
74 | Spacer(modifier = Modifier.height(8.dp))
75 | Button(onClick = { navController.navigate(Directions.FifthScreen) }) {
76 | Text("Profiles screen")
77 | }
78 | }
79 | }
80 |
81 | @Preview(showBackground = true)
82 | @Composable
83 | fun FirstScreenPreview() {
84 | ComposeDesignSystemTheme {
85 | FirstSpaceScreen()
86 | }
87 | }
88 |
89 | @Preview(showBackground = true)
90 | @Composable
91 | fun SecondScreenPreview() {
92 | ComposeDesignSystemTheme {
93 | SecondSpaceScreen()
94 | }
95 | }
96 |
97 | @Preview(showBackground = true)
98 | @Composable
99 | fun ThirdScreenPreview() {
100 | ComposeDesignSystemTheme {
101 | FirstSpaceScreen()
102 | }
103 | }
104 |
105 | @Preview(showBackground = true)
106 | @Composable
107 | fun ForthScreenPreview() {
108 | ComposeDesignSystemTheme {
109 | FirstSpaceScreen()
110 | }
111 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/compose/designsystem/space/theme/SpaceTypography.kt:
--------------------------------------------------------------------------------
1 | package com.compose.designsystem.space.theme
2 |
3 | import androidx.compose.runtime.staticCompositionLocalOf
4 | import androidx.compose.ui.text.TextStyle
5 | import androidx.compose.ui.text.font.Font
6 | import androidx.compose.ui.text.font.FontFamily
7 | import androidx.compose.ui.text.font.FontWeight
8 | import androidx.compose.ui.unit.sp
9 | import com.compose.designsystem.R
10 |
11 | val PlexSans = FontFamily(
12 | Font(R.font.plex_sans_regular, FontWeight.Normal),
13 | Font(R.font.plex_sans_bold, FontWeight.Bold)
14 | )
15 |
16 | class SpaceTypography internal constructor(
17 | val d1: TextStyle,
18 | val d2: TextStyle,
19 | val h1: TextStyle,
20 | val h2: TextStyle,
21 | val h3: TextStyle,
22 | val h4: TextStyle,
23 | val h5: TextStyle,
24 | val h6: TextStyle,
25 | val h7: TextStyle,
26 | ) {
27 |
28 | constructor(
29 | defaultFontFamily: FontFamily = PlexSans,
30 | d1: TextStyle = TextStyle(
31 | fontWeight = FontWeight.Bold,
32 | fontSize = 96.sp,
33 | lineHeight = 120.sp,
34 | ),
35 | d2: TextStyle = TextStyle(
36 | fontWeight = FontWeight.Bold,
37 | fontSize = 80.sp,
38 | lineHeight = 104.sp,
39 | ),
40 | h1: TextStyle = TextStyle(
41 | fontWeight = FontWeight.Bold,
42 | fontSize = 40.sp,
43 | lineHeight = 56.sp,
44 | ),
45 | h2: TextStyle = TextStyle(
46 | fontWeight = FontWeight.Bold,
47 | fontSize = 30.sp,
48 | lineHeight = 40.sp,
49 | ),
50 | h3: TextStyle = TextStyle(
51 | fontWeight = FontWeight.Bold,
52 | fontSize = 24.sp,
53 | lineHeight = 32.sp,
54 | ),
55 | h4: TextStyle = TextStyle(
56 | fontWeight = FontWeight.Bold,
57 | fontSize = 18.sp,
58 | lineHeight = 24.sp,
59 | ),
60 | h5: TextStyle = TextStyle(
61 | fontWeight = FontWeight.Bold,
62 | fontSize = 14.sp,
63 | lineHeight = 20.sp,
64 | ),
65 | h6: TextStyle = TextStyle(
66 | fontWeight = FontWeight.Bold,
67 | fontSize = 12.sp,
68 | lineHeight = 16.sp,
69 | ),
70 | h7: TextStyle = TextStyle(
71 | fontWeight = FontWeight.Bold,
72 | fontSize = 8.sp,
73 | lineHeight = 12.sp,
74 | ),
75 | ) : this(
76 | d1.withDefaultFontFamily(defaultFontFamily),
77 | d2.withDefaultFontFamily(defaultFontFamily),
78 | h1.withDefaultFontFamily(defaultFontFamily),
79 | h2.withDefaultFontFamily(defaultFontFamily),
80 | h3.withDefaultFontFamily(defaultFontFamily),
81 | h4.withDefaultFontFamily(defaultFontFamily),
82 | h5.withDefaultFontFamily(defaultFontFamily),
83 | h6.withDefaultFontFamily(defaultFontFamily),
84 | h7.withDefaultFontFamily(defaultFontFamily),
85 | )
86 |
87 | fun copy(
88 | d1: TextStyle = this.d1,
89 | d2: TextStyle = this.d2,
90 | h1: TextStyle = this.h1,
91 | h2: TextStyle = this.h2,
92 | h3: TextStyle = this.h3,
93 | h4: TextStyle = this.h4,
94 | h5: TextStyle = this.h5,
95 | h6: TextStyle = this.h6,
96 | h7: TextStyle = this.h7,
97 | ): SpaceTypography = SpaceTypography(
98 | d1, d2, h1, h2, h3, h4, h5, h6, h7
99 | )
100 |
101 | override fun equals(other: Any?): Boolean {
102 | if (this === other) return true
103 | if (other !is SpaceTypography) return false
104 |
105 | if (d1 != other.d1) return false
106 | if (d2 != other.d2) return false
107 | if (h1 != other.h1) return false
108 | if (h2 != other.h2) return false
109 | if (h3 != other.h3) return false
110 | if (h4 != other.h4) return false
111 | if (h5 != other.h5) return false
112 | if (h6 != other.h6) return false
113 | if (h7 != other.h7) return false
114 |
115 | return true
116 | }
117 |
118 | override fun hashCode(): Int {
119 | var result = d1.hashCode()
120 | result = 31 * result + d2.hashCode()
121 | result = 31 * result + h1.hashCode()
122 | result = 31 * result + h2.hashCode()
123 | result = 31 * result + h3.hashCode()
124 | result = 31 * result + h4.hashCode()
125 | result = 31 * result + h5.hashCode()
126 | result = 31 * result + h6.hashCode()
127 | result = 31 * result + h7.hashCode()
128 | return result
129 | }
130 | }
131 |
132 | private fun TextStyle.withDefaultFontFamily(default: FontFamily): TextStyle {
133 | return if (fontFamily != null) this else copy(fontFamily = default)
134 | }
135 |
136 | internal val LocalTypography = staticCompositionLocalOf { SpaceTypography() }
--------------------------------------------------------------------------------
/app/src/main/java/com/compose/designsystem/space/atoms/Input.kt:
--------------------------------------------------------------------------------
1 | package com.compose.designsystem.space.atoms
2 |
3 | import androidx.compose.foundation.BorderStroke
4 | import androidx.compose.foundation.background
5 | import androidx.compose.foundation.border
6 | import androidx.compose.foundation.interaction.MutableInteractionSource
7 | import androidx.compose.foundation.layout.*
8 | import androidx.compose.foundation.text.BasicTextField
9 | import androidx.compose.foundation.text.KeyboardActions
10 | import androidx.compose.foundation.text.KeyboardOptions
11 | import androidx.compose.runtime.Composable
12 | import androidx.compose.runtime.CompositionLocalProvider
13 | import androidx.compose.runtime.remember
14 | import androidx.compose.ui.Alignment
15 | import androidx.compose.ui.Modifier
16 | import androidx.compose.ui.graphics.Shape
17 | import androidx.compose.ui.graphics.SolidColor
18 | import androidx.compose.ui.text.TextStyle
19 | import androidx.compose.ui.text.font.FontWeight
20 | import androidx.compose.ui.text.input.VisualTransformation
21 | import androidx.compose.ui.unit.dp
22 | import com.compose.designsystem.space.theme.LocalContentColor
23 | import com.compose.designsystem.space.theme.SpaceTheme
24 |
25 | sealed interface InputType {
26 | object Default : InputType
27 | object Success : InputType
28 | object Error : InputType
29 | }
30 |
31 | private val MinHeight = 40.dp
32 | private val MinWidth = 77.dp
33 |
34 | @Composable
35 | fun Input(
36 | value: String,
37 | onValueChange: (String) -> Unit,
38 | modifier: Modifier = Modifier,
39 | enabled: Boolean = true,
40 | shape: Shape = SpaceTheme.shapes.small,
41 | textStyle: TextStyle = SpaceTheme.typography.h4.copy(fontWeight = FontWeight.Normal),
42 | inputType: InputType = InputType.Default,
43 | leadingIcon: @Composable (() -> Unit)? = null,
44 | trailingIcon: @Composable (() -> Unit)? = null,
45 | visualTransformation: VisualTransformation = VisualTransformation.None,
46 | keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
47 | keyboardActions: KeyboardActions = KeyboardActions(),
48 | interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
49 | ) {
50 |
51 | val textColor = textStyle.color
52 |
53 | val mergedTextStyle = textStyle.merge(TextStyle(color = textColor))
54 |
55 | val cursorColor = when (inputType) {
56 | InputType.Default -> SpaceTheme.colors.shadesBlack
57 | InputType.Error -> SpaceTheme.colors.error_4
58 | InputType.Success -> SpaceTheme.colors.success_4
59 | }
60 |
61 | BasicTextField(
62 | value = value,
63 | onValueChange = onValueChange,
64 | modifier = modifier
65 | .background(
66 | color = SpaceTheme.colors.neutral_1,
67 | shape = shape,
68 | )
69 | .defaultMinSize(
70 | minWidth = MinWidth,
71 | minHeight = MinHeight,
72 | ),
73 | enabled = enabled,
74 | textStyle = mergedTextStyle,
75 | cursorBrush = SolidColor(cursorColor),
76 | visualTransformation = visualTransformation,
77 | keyboardOptions = keyboardOptions,
78 | keyboardActions = keyboardActions,
79 | singleLine = true,
80 | maxLines = 1,
81 | decorationBox = @Composable { innerTextField ->
82 | InputDecoration(
83 | value = value,
84 | inputType = inputType,
85 | innerTextField = innerTextField,
86 | shape = shape,
87 | leadingIcon = leadingIcon,
88 | trailingIcon = trailingIcon,
89 | singleLine = false,
90 | interactionSource = interactionSource,
91 | )
92 | }
93 |
94 | )
95 | }
96 |
97 | @Composable
98 | private fun InputDecoration(
99 | value: String,
100 | inputType: InputType,
101 | interactionSource: MutableInteractionSource,
102 | shape: Shape,
103 | innerTextField: @Composable () -> Unit,
104 | leadingIcon: @Composable() (() -> Unit)? = null,
105 | trailingIcon: @Composable() (() -> Unit)? = null,
106 | singleLine: Boolean = false,
107 | ) {
108 | val borderSize = when (inputType) {
109 | InputType.Default -> 1.dp
110 | InputType.Error -> 2.dp
111 | InputType.Success -> 2.dp
112 | }
113 |
114 | val iconColor = when (inputType) {
115 | InputType.Default -> SpaceTheme.colors.shadesBlack
116 | InputType.Error -> SpaceTheme.colors.error_4
117 | InputType.Success -> SpaceTheme.colors.success_4
118 | }
119 |
120 | val borderColor = when (inputType) {
121 | InputType.Default -> SpaceTheme.colors.neutral_3
122 | InputType.Error -> SpaceTheme.colors.error_4
123 | InputType.Success -> SpaceTheme.colors.success_4
124 | }
125 |
126 | Box(
127 | modifier = Modifier.border(
128 | border = BorderStroke(borderSize, borderColor),
129 | shape = shape,
130 | )
131 | ) {
132 | Row(
133 | modifier = Modifier.padding(
134 | horizontal = 16.dp,
135 | vertical = 8.dp,
136 | ),
137 | verticalAlignment = Alignment.CenterVertically,
138 | ) {
139 | leadingIcon?.let {
140 | leadingIcon()
141 | Spacer(modifier = Modifier.width(8.dp))
142 | }
143 | innerTextField()
144 | trailingIcon?.let {
145 | Spacer(modifier = Modifier.width(8.dp))
146 | CompositionLocalProvider(
147 | LocalContentColor provides iconColor
148 | ) {
149 | trailingIcon()
150 | }
151 | }
152 | }
153 | }
154 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 |
86 | # Determine the Java command to use to start the JVM.
87 | if [ -n "$JAVA_HOME" ] ; then
88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
89 | # IBM's JDK on AIX uses strange locations for the executables
90 | JAVACMD="$JAVA_HOME/jre/sh/java"
91 | else
92 | JAVACMD="$JAVA_HOME/bin/java"
93 | fi
94 | if [ ! -x "$JAVACMD" ] ; then
95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
96 |
97 | Please set the JAVA_HOME variable in your environment to match the
98 | location of your Java installation."
99 | fi
100 | else
101 | JAVACMD="java"
102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
103 |
104 | Please set the JAVA_HOME variable in your environment to match the
105 | location of your Java installation."
106 | fi
107 |
108 | # Increase the maximum file descriptors if we can.
109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
110 | MAX_FD_LIMIT=`ulimit -H -n`
111 | if [ $? -eq 0 ] ; then
112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
113 | MAX_FD="$MAX_FD_LIMIT"
114 | fi
115 | ulimit -n $MAX_FD
116 | if [ $? -ne 0 ] ; then
117 | warn "Could not set maximum file descriptor limit: $MAX_FD"
118 | fi
119 | else
120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
121 | fi
122 | fi
123 |
124 | # For Darwin, add options to specify how the application appears in the dock
125 | if $darwin; then
126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
127 | fi
128 |
129 | # For Cygwin or MSYS, switch paths to Windows format before running java
130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
133 |
134 | JAVACMD=`cygpath --unix "$JAVACMD"`
135 |
136 | # We build the pattern for arguments to be converted via cygpath
137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
138 | SEP=""
139 | for dir in $ROOTDIRSRAW ; do
140 | ROOTDIRS="$ROOTDIRS$SEP$dir"
141 | SEP="|"
142 | done
143 | OURCYGPATTERN="(^($ROOTDIRS))"
144 | # Add a user-defined pattern to the cygpath arguments
145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
147 | fi
148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
149 | i=0
150 | for arg in "$@" ; do
151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
153 |
154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
156 | else
157 | eval `echo args$i`="\"$arg\""
158 | fi
159 | i=`expr $i + 1`
160 | done
161 | case $i in
162 | 0) set -- ;;
163 | 1) set -- "$args0" ;;
164 | 2) set -- "$args0" "$args1" ;;
165 | 3) set -- "$args0" "$args1" "$args2" ;;
166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
172 | esac
173 | fi
174 |
175 | # Escape application args
176 | save () {
177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
178 | echo " "
179 | }
180 | APP_ARGS=`save "$@"`
181 |
182 | # Collect all arguments for the java command, following the shell quoting and substitution rules
183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
184 |
185 | exec "$JAVACMD" "$@"
186 |
--------------------------------------------------------------------------------
/app/src/main/java/com/compose/designsystem/space/theme/SpaceIcons.kt:
--------------------------------------------------------------------------------
1 | package com.compose.designsystem.space.theme
2 |
3 | import androidx.compose.runtime.Composable
4 | import androidx.compose.ui.Modifier
5 | import androidx.compose.ui.draw.rotate
6 | import androidx.compose.ui.graphics.Color
7 | import androidx.compose.ui.res.painterResource
8 | import com.compose.designsystem.R
9 | import com.compose.designsystem.space.atoms.basic.Icon
10 |
11 | object SpaceIcons
12 |
13 | @Composable
14 | fun SpaceIcons.IcAccessTime(
15 | contentDescription: String?,
16 | modifier: Modifier = Modifier,
17 | tint: Color = Color.Unspecified,
18 | ) {
19 | Icon(
20 | painter = painterResource(id = R.drawable.ic_access_time),
21 | contentDescription = contentDescription,
22 | modifier = modifier,
23 | tint = tint,
24 | )
25 | }
26 |
27 | @Composable
28 | fun SpaceIcons.IcHeart(
29 | contentDescription: String?,
30 | modifier: Modifier = Modifier,
31 | tint: Color = Color.Unspecified,
32 | ) {
33 | Icon(
34 | painter = painterResource(id = R.drawable.ic_heart),
35 | contentDescription = contentDescription,
36 | modifier = modifier,
37 | tint = tint,
38 | )
39 | }
40 |
41 | @Composable
42 | fun SpaceIcons.IcKeyboardArrowDown(
43 | contentDescription: String?,
44 | modifier: Modifier = Modifier,
45 | rotate: Boolean = false,
46 | tint: Color = Color.Unspecified,
47 | ) {
48 | val rotation = if (rotate) {
49 | Modifier.rotate(180f)
50 | } else {
51 | Modifier
52 | }
53 |
54 | Icon(
55 | painter = painterResource(id = R.drawable.ic_keyboard_arrow_down),
56 | contentDescription = contentDescription,
57 | modifier = modifier.then(rotation),
58 | tint = tint,
59 | )
60 | }
61 |
62 | @Composable
63 | fun SpaceIcons.IcAdd(
64 | contentDescription: String?,
65 | modifier: Modifier = Modifier,
66 | tint: Color = Color.Unspecified,
67 | ) {
68 | Icon(
69 | painter = painterResource(id = R.drawable.ic_add),
70 | contentDescription = contentDescription,
71 | modifier = modifier,
72 | tint = tint,
73 | )
74 | }
75 |
76 | @Composable
77 | fun SpaceIcons.IcApps(
78 | contentDescription: String?,
79 | modifier: Modifier = Modifier,
80 | tint: Color = Color.Unspecified,
81 | ) {
82 | Icon(
83 | painter = painterResource(id = R.drawable.ic_apps),
84 | contentDescription = contentDescription,
85 | modifier = modifier,
86 | tint = tint,
87 | )
88 | }
89 |
90 | @Composable
91 | fun SpaceIcons.IcArrowDropDown(
92 | contentDescription: String?,
93 | modifier: Modifier = Modifier,
94 | tint: Color = Color.Unspecified,
95 | ) {
96 | Icon(
97 | painter = painterResource(id = R.drawable.ic_arrow_drop_down),
98 | contentDescription = contentDescription,
99 | modifier = modifier,
100 | tint = tint,
101 | )
102 | }
103 |
104 | @Composable
105 | fun SpaceIcons.IcAttachMoney(
106 | contentDescription: String?,
107 | modifier: Modifier = Modifier,
108 | tint: Color = Color.Unspecified,
109 | ) {
110 | Icon(
111 | painter = painterResource(id = R.drawable.ic_attach_money),
112 | contentDescription = contentDescription,
113 | modifier = modifier,
114 | tint = tint,
115 | )
116 | }
117 |
118 | @Composable
119 | fun SpaceIcons.IcCardTravel(
120 | contentDescription: String?,
121 | modifier: Modifier = Modifier,
122 | tint: Color = Color.Unspecified,
123 | ) {
124 | Icon(
125 | painter = painterResource(id = R.drawable.ic_card_travel),
126 | contentDescription = contentDescription,
127 | modifier = modifier,
128 | tint = tint,
129 | )
130 | }
131 |
132 | @Composable
133 | fun SpaceIcons.IcCheck(
134 | contentDescription: String?,
135 | modifier: Modifier = Modifier,
136 | tint: Color = Color.Unspecified,
137 | ) {
138 | Icon(
139 | painter = painterResource(id = R.drawable.ic_check),
140 | contentDescription = contentDescription,
141 | modifier = modifier,
142 | tint = tint,
143 | )
144 | }
145 |
146 | @Composable
147 | fun SpaceIcons.IcCheckCircle(
148 | contentDescription: String?,
149 | modifier: Modifier = Modifier,
150 | tint: Color = Color.Unspecified,
151 | ) {
152 | Icon(
153 | painter = painterResource(id = R.drawable.ic_check_circle),
154 | contentDescription = contentDescription,
155 | modifier = modifier,
156 | tint = tint,
157 | )
158 | }
159 |
160 | @Composable
161 | fun SpaceIcons.IcClose(
162 | contentDescription: String?,
163 | modifier: Modifier = Modifier,
164 | tint: Color = Color.Unspecified,
165 | ) {
166 | Icon(
167 | painter = painterResource(id = R.drawable.ic_close),
168 | contentDescription = contentDescription,
169 | modifier = modifier,
170 | tint = tint,
171 | )
172 | }
173 |
174 | @Composable
175 | fun SpaceIcons.IcContactSupport(
176 | contentDescription: String?,
177 | modifier: Modifier = Modifier,
178 | tint: Color = Color.Unspecified,
179 | ) {
180 | Icon(
181 | painter = painterResource(id = R.drawable.ic_contact_support),
182 | contentDescription = contentDescription,
183 | modifier = modifier,
184 | tint = tint,
185 | )
186 | }
187 |
188 | @Composable
189 | fun SpaceIcons.IcCreditCard(
190 | contentDescription: String?,
191 | modifier: Modifier = Modifier,
192 | tint: Color = Color.Unspecified,
193 | ) {
194 | Icon(
195 | painter = painterResource(id = R.drawable.ic_credit_card),
196 | contentDescription = contentDescription,
197 | modifier = modifier,
198 | tint = tint,
199 | )
200 | }
201 |
202 | @Composable
203 | fun SpaceIcons.IcHome(
204 | contentDescription: String?,
205 | modifier: Modifier = Modifier,
206 | tint: Color = Color.Unspecified,
207 | ) {
208 | Icon(
209 | painter = painterResource(id = R.drawable.ic_home),
210 | contentDescription = contentDescription,
211 | modifier = modifier,
212 | tint = tint,
213 | )
214 | }
215 |
216 | @Composable
217 | fun SpaceIcons.IcLibraryBooks(
218 | contentDescription: String?,
219 | modifier: Modifier = Modifier,
220 | tint: Color = Color.Unspecified,
221 | ) {
222 | Icon(
223 | painter = painterResource(id = R.drawable.ic_library_books),
224 | contentDescription = contentDescription,
225 | modifier = modifier,
226 | tint = tint,
227 | )
228 | }
229 |
230 | @Composable
231 | fun SpaceIcons.IcPerson(
232 | contentDescription: String?,
233 | modifier: Modifier = Modifier,
234 | tint: Color = Color.Unspecified,
235 | ) {
236 | Icon(
237 | painter = painterResource(id = R.drawable.ic_person),
238 | contentDescription = contentDescription,
239 | modifier = modifier,
240 | tint = tint,
241 | )
242 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/compose/designsystem/application/first/FirstSpaceScreen.kt:
--------------------------------------------------------------------------------
1 | package com.compose.designsystem.application.first
2 |
3 | import androidx.compose.foundation.background
4 | import androidx.compose.foundation.layout.*
5 | import androidx.compose.foundation.lazy.LazyColumn
6 | import androidx.compose.foundation.lazy.itemsIndexed
7 | import androidx.compose.runtime.*
8 | import androidx.compose.ui.Alignment
9 | import androidx.compose.ui.Modifier
10 | import androidx.compose.ui.text.font.FontWeight
11 | import androidx.compose.ui.unit.dp
12 | import com.compose.designsystem.application.first.data.TransactionRepository
13 | import com.compose.designsystem.application.first.domain.Transaction
14 | import com.compose.designsystem.application.first.domain.TransactionType
15 | import com.compose.designsystem.space.atoms.NavTab
16 | import com.compose.designsystem.space.atoms.Tab
17 | import com.compose.designsystem.space.atoms.basic.Divider
18 | import com.compose.designsystem.space.atoms.basic.Text
19 | import com.compose.designsystem.space.molecules.NavBar
20 | import com.compose.designsystem.space.molecules.Tabs
21 | import com.compose.designsystem.space.theme.*
22 |
23 | data class NavTabItem(
24 | val id: Int,
25 | val icon: @Composable () -> Unit,
26 | val text: String,
27 | )
28 |
29 | @Composable
30 | fun FirstSpaceScreen() {
31 |
32 | var selectedTab by remember {
33 | mutableStateOf(0)
34 | }
35 |
36 | val transaction by remember(selectedTab) {
37 | derivedStateOf {
38 | when (selectedTab) {
39 | 0 -> {
40 | TransactionRepository.getAllTransactions()
41 | }
42 | 1 -> {
43 | TransactionRepository.getSales()
44 | }
45 | else -> {
46 | TransactionRepository.getFunds()
47 | }
48 | }
49 | }
50 | }
51 |
52 | var selectedNavTab by remember {
53 | mutableStateOf(0)
54 | }
55 |
56 | Column(modifier = Modifier.background(SpaceTheme.colors.shadesWhite)) {
57 | Box(modifier = Modifier.weight(1f)) {
58 | ScreenContent(
59 | transactions = transaction,
60 | selectedTab = selectedTab,
61 | onTabChanged = { newTabIndex -> selectedTab = newTabIndex }
62 | )
63 | }
64 | Box {
65 | NavBar(
66 | modifier = Modifier.align(Alignment.BottomCenter)
67 | ) {
68 | NavTab(
69 | text = navItems[0].text,
70 | icon = navItems[0].icon,
71 | onClick = { selectedNavTab = 0 },
72 | selected = selectedNavTab == 0,
73 | )
74 | NavTab(
75 | text = navItems[1].text,
76 | icon = navItems[1].icon,
77 | onClick = { selectedNavTab = 1 },
78 | selected = selectedNavTab == 1,
79 | )
80 | NavTab(
81 | text = navItems[2].text,
82 | icon = navItems[2].icon,
83 | onClick = { selectedNavTab = 2 },
84 | selected = selectedNavTab == 2,
85 | )
86 | NavTab(
87 | text = navItems[3].text,
88 | icon = navItems[3].icon,
89 | onClick = { selectedNavTab = 3 },
90 | selected = selectedNavTab == 3,
91 | )
92 | }
93 | }
94 | }
95 | }
96 |
97 | @Composable
98 | fun ScreenContent(
99 | transactions: List,
100 | onTabChanged: (Int) -> Unit,
101 | selectedTab: Int
102 | ) {
103 |
104 | Column {
105 | Text(
106 | text = "History",
107 | modifier = Modifier.padding(
108 | top = 32.dp,
109 | start = 16.dp,
110 | end = 16.dp,
111 | ),
112 | style = SpaceTheme.typography.h2,
113 | )
114 | Spacer(modifier = Modifier.height(8.dp))
115 | Tabs(modifier = Modifier.padding(horizontal = 16.dp)) {
116 | Tab(text = "All", selected = selectedTab == 0, onClick = { onTabChanged(0) })
117 | Tab(text = "Purchases", selected = selectedTab == 1, onClick = { onTabChanged(1) })
118 | Tab(text = "Funding", selected = selectedTab == 2, onClick = { onTabChanged(2) })
119 | }
120 | Spacer(modifier = Modifier.height(16.dp))
121 | LazyColumn {
122 | itemsIndexed(transactions) { index, item ->
123 | TransactionItem(
124 | transaction = item,
125 | isGrayBackground = index % 2 != 0
126 | )
127 | }
128 | }
129 | }
130 | }
131 |
132 | @Composable
133 | private fun TransactionItem(
134 | transaction: Transaction,
135 | isGrayBackground: Boolean
136 | ) {
137 | val icon: @Composable () -> Unit = when (transaction.transactionType) {
138 | TransactionType.Fund -> {
139 | { SpaceIcons.IcPerson(contentDescription = null) }
140 | }
141 | TransactionType.Sale -> {
142 | { SpaceIcons.IcCreditCard(contentDescription = null) }
143 | }
144 | }
145 |
146 | val text = when (transaction.transactionType) {
147 | TransactionType.Fund -> "Fund"
148 | TransactionType.Sale -> "Sale"
149 | }
150 |
151 | Column {
152 | Row(
153 | modifier = Modifier
154 | .background(
155 | if (isGrayBackground) SpaceTheme.colors.neutral_1 else SpaceTheme.colors.shadesWhite
156 | )
157 | .padding(
158 | horizontal = 16.dp,
159 | vertical = 8.dp,
160 | ),
161 | verticalAlignment = Alignment.CenterVertically,
162 | ) {
163 | icon()
164 | Spacer(modifier = Modifier.width(8.dp))
165 | Text(
166 | text = text,
167 | style = SpaceTheme.typography.h4.copy(
168 | fontWeight = FontWeight.Normal,
169 | )
170 | )
171 | Spacer(modifier = Modifier.weight(1f))
172 | Text(
173 | text = "\$${transaction.amount}",
174 | style = SpaceTheme.typography.h4.copy(
175 | fontWeight = FontWeight.Normal,
176 | )
177 | )
178 | }
179 | Divider(
180 | color = SpaceTheme.colors.neutral_3,
181 | thickness = 1.dp,
182 | )
183 | }
184 |
185 | }
186 |
187 | private val navItems = listOf(
188 | NavTabItem(
189 | 1,
190 | { SpaceIcons.IcHome(contentDescription = null) },
191 | "Home"
192 | ),
193 | NavTabItem(
194 | 2,
195 | { SpaceIcons.IcCardTravel(contentDescription = null) },
196 | "Shop"
197 | ),
198 | NavTabItem(
199 | 3,
200 | { SpaceIcons.IcLibraryBooks(contentDescription = null) },
201 | "History"
202 | ),
203 | NavTabItem(
204 | 4,
205 | { SpaceIcons.IcPerson(contentDescription = null) },
206 | "Account"
207 | ),
208 | )
209 |
--------------------------------------------------------------------------------
/app/src/main/java/com/compose/designsystem/space/theme/SpaceColors.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress("PropertyName")
2 |
3 | package com.compose.designsystem.space.theme
4 |
5 | import androidx.compose.runtime.*
6 | import androidx.compose.ui.graphics.Color
7 | import androidx.compose.ui.graphics.takeOrElse
8 |
9 | @Stable
10 | class SpaceColors(
11 | neutral_1: Color,
12 | neutral_2: Color,
13 | neutral_3: Color,
14 | neutral_4: Color,
15 | neutral_5: Color,
16 | neutral_6: Color,
17 | neutral_7: Color,
18 | neutral_8: Color,
19 | neutral_9: Color,
20 | neutral_10: Color,
21 | primary_1: Color,
22 | primary_2: Color,
23 | primary_3: Color,
24 | primary_4: Color,
25 | primary_5: Color,
26 | success_1: Color,
27 | success_2: Color,
28 | success_3: Color,
29 | success_4: Color,
30 | success_5: Color,
31 | error_1: Color,
32 | error_2: Color,
33 | error_3: Color,
34 | error_4: Color,
35 | error_5: Color,
36 | warning_1: Color,
37 | warning_2: Color,
38 | warning_3: Color,
39 | warning_4: Color,
40 | warning_5: Color,
41 | shadesBlack: Color,
42 | shadesWhite: Color,
43 | isLight: Boolean,
44 | ) {
45 | var neutral_1 by mutableStateOf(neutral_1, structuralEqualityPolicy())
46 | internal set
47 | var neutral_2 by mutableStateOf(neutral_2, structuralEqualityPolicy())
48 | internal set
49 | var neutral_3 by mutableStateOf(neutral_3, structuralEqualityPolicy())
50 | internal set
51 | var neutral_4 by mutableStateOf(neutral_4, structuralEqualityPolicy())
52 | internal set
53 | var neutral_5 by mutableStateOf(neutral_5, structuralEqualityPolicy())
54 | internal set
55 | var neutral_6 by mutableStateOf(neutral_6, structuralEqualityPolicy())
56 | internal set
57 | var neutral_7 by mutableStateOf(neutral_7, structuralEqualityPolicy())
58 | internal set
59 | var neutral_8 by mutableStateOf(neutral_8, structuralEqualityPolicy())
60 | internal set
61 | var neutral_9 by mutableStateOf(neutral_9, structuralEqualityPolicy())
62 | internal set
63 | var neutral_10 by mutableStateOf(neutral_10, structuralEqualityPolicy())
64 | internal set
65 |
66 | var primary_1 by mutableStateOf(primary_1, structuralEqualityPolicy())
67 | internal set
68 | var primary_2 by mutableStateOf(primary_2, structuralEqualityPolicy())
69 | internal set
70 | var primary_3 by mutableStateOf(primary_3, structuralEqualityPolicy())
71 | internal set
72 | var primary_4 by mutableStateOf(primary_4, structuralEqualityPolicy())
73 | internal set
74 | var primary_5 by mutableStateOf(primary_5, structuralEqualityPolicy())
75 | internal set
76 |
77 | var success_1 by mutableStateOf(success_1, structuralEqualityPolicy())
78 | internal set
79 | var success_2 by mutableStateOf(success_2, structuralEqualityPolicy())
80 | internal set
81 | var success_3 by mutableStateOf(success_3, structuralEqualityPolicy())
82 | internal set
83 | var success_4 by mutableStateOf(success_4, structuralEqualityPolicy())
84 | internal set
85 | var success_5 by mutableStateOf(success_5, structuralEqualityPolicy())
86 | internal set
87 |
88 | var error_1 by mutableStateOf(error_1, structuralEqualityPolicy())
89 | internal set
90 | var error_2 by mutableStateOf(error_2, structuralEqualityPolicy())
91 | internal set
92 | var error_3 by mutableStateOf(error_3, structuralEqualityPolicy())
93 | internal set
94 | var error_4 by mutableStateOf(error_4, structuralEqualityPolicy())
95 | internal set
96 | var error_5 by mutableStateOf(error_5, structuralEqualityPolicy())
97 | internal set
98 |
99 | var warning_1 by mutableStateOf(warning_1, structuralEqualityPolicy())
100 | internal set
101 | var warning_2 by mutableStateOf(warning_2, structuralEqualityPolicy())
102 | internal set
103 | var warning_3 by mutableStateOf(warning_3, structuralEqualityPolicy())
104 | internal set
105 | var warning_4 by mutableStateOf(warning_4, structuralEqualityPolicy())
106 | internal set
107 | var warning_5 by mutableStateOf(warning_5, structuralEqualityPolicy())
108 | internal set
109 |
110 | var shadesBlack by mutableStateOf(shadesBlack, structuralEqualityPolicy())
111 | internal set
112 | var shadesWhite by mutableStateOf(shadesWhite, structuralEqualityPolicy())
113 | internal set
114 |
115 | var isLight by mutableStateOf(isLight, structuralEqualityPolicy())
116 | internal set
117 |
118 | fun copy(
119 | neutral_1: Color = this.neutral_1,
120 | neutral_2: Color = this.neutral_2,
121 | neutral_3: Color = this.neutral_3,
122 | neutral_4: Color = this.neutral_4,
123 | neutral_5: Color = this.neutral_5,
124 | neutral_6: Color = this.neutral_6,
125 | neutral_7: Color = this.neutral_7,
126 | neutral_8: Color = this.neutral_8,
127 | neutral_9: Color = this.neutral_9,
128 | neutral_10: Color = this.neutral_10,
129 | primary_1: Color = this.primary_1,
130 | primary_2: Color = this.primary_2,
131 | primary_3: Color = this.primary_3,
132 | primary_4: Color = this.primary_4,
133 | primary_5: Color = this.primary_5,
134 | success_1: Color = this.success_1,
135 | success_2: Color = this.success_2,
136 | success_3: Color = this.success_3,
137 | success_4: Color = this.success_4,
138 | success_5: Color = this.success_5,
139 | error_1: Color = this.error_1,
140 | error_2: Color = this.error_2,
141 | error_3: Color = this.error_3,
142 | error_4: Color = this.error_4,
143 | error_5: Color = this.error_5,
144 | warning_1: Color = this.warning_1,
145 | warning_2: Color = this.warning_2,
146 | warning_3: Color = this.warning_3,
147 | warning_4: Color = this.warning_4,
148 | warning_5: Color = this.warning_5,
149 | shadesBlack: Color = this.shadesBlack,
150 | shadesWhite: Color = this.shadesWhite,
151 | isLight: Boolean = this.isLight,
152 | ): SpaceColors = SpaceColors(
153 | neutral_1,
154 | neutral_2,
155 | neutral_3,
156 | neutral_4,
157 | neutral_5,
158 | neutral_6,
159 | neutral_7,
160 | neutral_8,
161 | neutral_9,
162 | neutral_10,
163 | primary_1,
164 | primary_2,
165 | primary_3,
166 | primary_4,
167 | primary_5,
168 | success_1,
169 | success_2,
170 | success_3,
171 | success_4,
172 | success_5,
173 | error_1,
174 | error_2,
175 | error_3,
176 | error_4,
177 | error_5,
178 | warning_1,
179 | warning_2,
180 | warning_3,
181 | warning_4,
182 | warning_5,
183 | shadesBlack,
184 | shadesWhite,
185 | isLight
186 | )
187 | }
188 |
189 |
190 | fun lightSpaceColors(
191 | neutral_1: Color = Color(0xFFF2F2F2),
192 | neutral_2: Color = Color(0xFFE5E5E5),
193 | neutral_3: Color = Color(0xFFCCCCCC),
194 | neutral_4: Color = Color(0xFFB2B2B2),
195 | neutral_5: Color = Color(0xFF999999),
196 | neutral_6: Color = Color(0xFF808080),
197 | neutral_7: Color = Color(0xFF666666),
198 | neutral_8: Color = Color(0xFF4D4D4D),
199 | neutral_9: Color = Color(0xFF333333),
200 | neutral_10: Color = Color(0xFF1A1A1A),
201 | primary_1: Color = Color(0xFFEBEBFA),
202 | primary_2: Color = Color(0xFFADADEB),
203 | primary_3: Color = Color(0xFF7070DB),
204 | primary_4: Color = Color(0xFF3333CC),
205 | primary_5: Color = Color(0xFF24248F),
206 | success_1: Color = Color(0xFFEBFAF2),
207 | success_2: Color = Color(0xFFADEBCA),
208 | success_3: Color = Color(0xFF70DBA2),
209 | success_4: Color = Color(0xFF33CC79),
210 | success_5: Color = Color(0xFF248F56),
211 | error_1: Color = Color(0xFFFBE9EB),
212 | error_2: Color = Color(0xFFF3BFC3),
213 | error_3: Color = Color(0xFFEB939B),
214 | error_4: Color = Color(0xFFDF535F),
215 | error_5: Color = Color(0xFFC12432),
216 | warning_1: Color = Color(0xFFFEFCE7),
217 | warning_2: Color = Color(0xFFFBF5B7),
218 | warning_3: Color = Color(0xFFF8EE87),
219 | warning_4: Color = Color(0xFFF3E43F),
220 | warning_5: Color = Color(0xFFD8C70D),
221 | shadesBlack: Color = Color.Black,
222 | shadesWhite: Color = Color.White,
223 | isLight: Boolean = true,
224 | ): SpaceColors = SpaceColors(
225 | neutral_1,
226 | neutral_2,
227 | neutral_3,
228 | neutral_4,
229 | neutral_5,
230 | neutral_6,
231 | neutral_7,
232 | neutral_8,
233 | neutral_9,
234 | neutral_10,
235 | primary_1,
236 | primary_2,
237 | primary_3,
238 | primary_4,
239 | primary_5,
240 | success_1,
241 | success_2,
242 | success_3,
243 | success_4,
244 | success_5,
245 | error_1,
246 | error_2,
247 | error_3,
248 | error_4,
249 | error_5,
250 | warning_1,
251 | warning_2,
252 | warning_3,
253 | warning_4,
254 | warning_5,
255 | shadesBlack,
256 | shadesWhite,
257 | isLight
258 | )
259 |
260 | fun darkSpaceColors() = lightSpaceColors(isLight = false)
261 |
262 | @Composable
263 | @ReadOnlyComposable
264 | fun contentColorFor(backgroundColor: Color) =
265 | SpaceTheme.colors.contentColorFor(backgroundColor).takeOrElse { LocalContentColor.current }
266 |
267 | private fun SpaceColors.contentColorFor(backgroundColor: Color): Color {
268 | return when (backgroundColor) {
269 | primary_4 -> shadesWhite
270 | neutral_2 -> shadesBlack
271 | error_2 -> error_4
272 | success_4 -> shadesWhite
273 | error_4 -> shadesWhite
274 | warning_4 -> shadesBlack
275 | shadesBlack -> shadesWhite
276 | shadesWhite -> shadesBlack
277 | else -> Color.Unspecified
278 | }
279 | }
280 |
281 | internal val LocalColors = staticCompositionLocalOf { lightSpaceColors() }
282 |
283 | internal val LocalContentColor = compositionLocalOf { Color.Black }
284 |
285 | internal val LocalContentAlpha = compositionLocalOf { 1f }
--------------------------------------------------------------------------------