diff --git a/.coderabbit.yaml b/.coderabbit.yaml
new file mode 100644
index 0000000..459c6c2
--- /dev/null
+++ b/.coderabbit.yaml
@@ -0,0 +1,42 @@
+language: ko-KR
+
+reviews:
+ profile: chill
+ request_changes_workflow: false
+ high_level_summary: true
+ poem: false
+ review_status: true
+ auto_review:
+ enabled: true
+ drafts: false
+ base_branches:
+ - develop
+ - main
+
+ path_filters:
+ - "!**/*.lock"
+ - "!**/build/**"
+ - "!**/.gradle/**"
+ - "!**/generated/**"
+ - "!**/*.png"
+ - "!**/*.jpg"
+ - "!**/*.webp"
+
+ path_instructions:
+ - path: "**/*.kt"
+ instructions: |
+ Kotlin 코드는 다음 기준으로 리뷰해줘:
+ - Compose 모범 사례 (remember, derivedStateOf, Stable/Immutable)
+ - Hilt 의존성 주입 패턴
+ - 코루틴 사용 (Dispatcher, scope, exception handling)
+ - 네이밍 컨벤션 (PascalCase 클래스, camelCase 함수)
+ - 매직 넘버나 하드코딩된 문자열 지적
+
+ - path: "**/build.gradle.kts"
+ instructions: |
+ Gradle 설정은 다음을 확인해줘:
+ - 의존성 버전이 libs.versions.toml에서 관리되는지
+ - 불필요한 의존성이 없는지
+
+chat:
+ auto_reply: true
diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml
index b268ef3..03429f8 100644
--- a/.idea/deploymentTargetSelector.xml
+++ b/.idea/deploymentTargetSelector.xml
@@ -7,4 +7,4 @@
-
\ No newline at end of file
+
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
index 6e65b66..e469ef8 100644
--- a/.idea/gradle.xml
+++ b/.idea/gradle.xml
@@ -27,6 +27,7 @@
+
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
index 7061a0d..82d900e 100644
--- a/.idea/inspectionProfiles/Project_Default.xml
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -57,5 +57,6 @@
+
\ No newline at end of file
diff --git a/core/coroutine/.gitignore b/core/coroutine/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/core/coroutine/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/core/coroutine/build.gradle.kts b/core/coroutine/build.gradle.kts
new file mode 100644
index 0000000..3aec9aa
--- /dev/null
+++ b/core/coroutine/build.gradle.kts
@@ -0,0 +1,10 @@
+import com.kindl.buildlogic.setNamespace
+
+plugins {
+ alias(libs.plugins.kindl.android.library)
+ alias(libs.plugins.kindl.hilt)
+}
+
+android {
+ setNamespace("core.coroutine")
+}
diff --git a/core/coroutine/src/main/java/com/kindl/coroutine/di/DispatcherModule.kt b/core/coroutine/src/main/java/com/kindl/coroutine/di/DispatcherModule.kt
new file mode 100644
index 0000000..c78e431
--- /dev/null
+++ b/core/coroutine/src/main/java/com/kindl/coroutine/di/DispatcherModule.kt
@@ -0,0 +1,18 @@
+package com.kindl.coroutine.di
+
+import com.kindl.coroutine.qualifier.IoDispatcher
+import dagger.Module
+import dagger.Provides
+import dagger.hilt.InstallIn
+import dagger.hilt.components.SingletonComponent
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.Dispatchers
+
+@Module
+@InstallIn(SingletonComponent::class)
+object DispatcherModule {
+
+ @IoDispatcher
+ @Provides
+ fun providesIoDispatcher(): CoroutineDispatcher = Dispatchers.IO
+}
diff --git a/core/coroutine/src/main/java/com/kindl/coroutine/qualifier/IoDispatcher.kt b/core/coroutine/src/main/java/com/kindl/coroutine/qualifier/IoDispatcher.kt
new file mode 100644
index 0000000..b1a9d02
--- /dev/null
+++ b/core/coroutine/src/main/java/com/kindl/coroutine/qualifier/IoDispatcher.kt
@@ -0,0 +1,7 @@
+package com.kindl.coroutine.qualifier
+
+import javax.inject.Qualifier
+
+@Retention(AnnotationRetention.BINARY)
+@Qualifier
+annotation class IoDispatcher
diff --git a/core/designsystem/src/main/java/com/kindl/core/designsystem/component/UrlImage.kt b/core/designsystem/src/main/java/com/kindl/core/designsystem/component/UrlImage.kt
index df30678..37b2f9b 100644
--- a/core/designsystem/src/main/java/com/kindl/core/designsystem/component/UrlImage.kt
+++ b/core/designsystem/src/main/java/com/kindl/core/designsystem/component/UrlImage.kt
@@ -15,7 +15,7 @@ import com.kindl.core.designsystem.R
@Composable
fun UrlImage(
- url: Any?,
+ url: String?,
modifier: Modifier = Modifier,
contentScale: ContentScale = ContentScale.Fit,
contentDescription: String? = null,
diff --git a/core/designsystem/src/main/java/com/kindl/core/designsystem/theme/Color.kt b/core/designsystem/src/main/java/com/kindl/core/designsystem/theme/Color.kt
index e8ac748..bca004c 100644
--- a/core/designsystem/src/main/java/com/kindl/core/designsystem/theme/Color.kt
+++ b/core/designsystem/src/main/java/com/kindl/core/designsystem/theme/Color.kt
@@ -1,11 +1,210 @@
package com.kindl.core.designsystem.theme
+import androidx.compose.runtime.Immutable
+import androidx.compose.runtime.staticCompositionLocalOf
import androidx.compose.ui.graphics.Color
-val Purple80 = Color(0xFFD0BCFF)
-val PurpleGrey80 = Color(0xFFCCC2DC)
-val Pink80 = Color(0xFFEFB8C8)
+// Main Color - Slate
+val KindlSlate50 = Color(0xFFF8F9FA)
+val KindlSlate100 = Color(0xFFE9ECEF)
+val KindlSlate200 = Color(0xFFD3D7DC)
+val KindlSlate300 = Color(0xFFB0B7C0)
+val KindlSlate400 = Color(0xFF7D8794)
+val KindlSlate500 = Color(0xFF4A5568)
+val KindlSlate600 = Color(0xFF2D3748)
+val KindlSlate700 = Color(0xFF1E2530)
+val KindlSlate800 = Color(0xFF151A23)
+val KindlSlate900 = Color(0xFF0D1117)
-val Purple40 = Color(0xFF6650a4)
-val PurpleGrey40 = Color(0xFF625b71)
-val Pink40 = Color(0xFF7D5260)
+// Point Color - Coral
+val KindlCoral50 = Color(0xFFFFF5F5)
+val KindlCoral100 = Color(0xFFFFE3E3)
+val KindlCoral200 = Color(0xFFFFC9C9)
+val KindlCoral300 = Color(0xFFFFA8A8)
+val KindlCoral400 = Color(0xFFFF8787)
+val KindlCoral500 = Color(0xFFFF6B6B)
+val KindlCoral600 = Color(0xFFFA5252)
+val KindlCoral700 = Color(0xFFF03E3E)
+val KindlCoral800 = Color(0xFFE03131)
+val KindlCoral900 = Color(0xFFC92A2A)
+
+// Supporting Colors
+val KindlBlue500 = Color(0xFF339AF0)
+val KindlTeal500 = Color(0xFF20C997)
+val KindlAmber500 = Color(0xFFFCC419)
+
+val White = Color(0xFFFFFFFF)
+
+@Immutable
+data class KindlColors(
+ // Surface
+ val background: Color,
+ val foreground: Color,
+ val card: Color,
+ val cardForeground: Color,
+ val popover: Color,
+ val popoverForeground: Color,
+
+ // Interactive
+ val primary: Color,
+ val primaryForeground: Color,
+ val secondary: Color,
+ val secondaryForeground: Color,
+
+ // State
+ val muted: Color,
+ val mutedForeground: Color,
+ val accent: Color,
+ val accentForeground: Color,
+ val destructive: Color,
+ val destructiveForeground: Color,
+ val success: Color,
+ val successForeground: Color,
+
+ // Form
+ val border: Color,
+ val input: Color,
+ val inputBackground: Color,
+ val switchBackground: Color,
+ val ring: Color,
+
+ // Chart
+ val chart1: Color,
+ val chart2: Color,
+ val chart3: Color,
+ val chart4: Color,
+ val chart5: Color,
+
+ // Sidebar
+ val sidebar: Color,
+ val sidebarForeground: Color,
+ val sidebarPrimary: Color,
+ val sidebarPrimaryForeground: Color,
+ val sidebarAccent: Color,
+ val sidebarAccentForeground: Color,
+ val sidebarBorder: Color,
+ val sidebarRing: Color,
+
+ // Raw palette (필요 시 직접 참조)
+ val slate50: Color = KindlSlate50,
+ val slate100: Color = KindlSlate100,
+ val slate200: Color = KindlSlate200,
+ val slate300: Color = KindlSlate300,
+ val slate400: Color = KindlSlate400,
+ val slate500: Color = KindlSlate500,
+ val slate600: Color = KindlSlate600,
+ val slate700: Color = KindlSlate700,
+ val slate800: Color = KindlSlate800,
+ val slate900: Color = KindlSlate900,
+
+ val coral50: Color = KindlCoral50,
+ val coral100: Color = KindlCoral100,
+ val coral200: Color = KindlCoral200,
+ val coral300: Color = KindlCoral300,
+ val coral400: Color = KindlCoral400,
+ val coral500: Color = KindlCoral500,
+ val coral600: Color = KindlCoral600,
+ val coral700: Color = KindlCoral700,
+ val coral800: Color = KindlCoral800,
+ val coral900: Color = KindlCoral900,
+
+ val blue500: Color = KindlBlue500,
+ val teal500: Color = KindlTeal500,
+ val amber500: Color = KindlAmber500,
+
+ val isDark: Boolean,
+)
+
+val lightKindlColors = KindlColors(
+ background = White,
+ foreground = KindlSlate700,
+ card = White,
+ cardForeground = KindlSlate700,
+ popover = White,
+ popoverForeground = KindlSlate700,
+
+ primary = KindlSlate700,
+ primaryForeground = White,
+ secondary = KindlCoral500,
+ secondaryForeground = White,
+
+ muted = KindlSlate50,
+ mutedForeground = KindlSlate400,
+ accent = KindlCoral500,
+ accentForeground = White,
+ destructive = KindlCoral700,
+ destructiveForeground= White,
+ success = KindlTeal500,
+ successForeground = White,
+
+ border = KindlSlate700.copy(alpha = 0.10f),
+ input = Color.Transparent,
+ inputBackground = KindlSlate50,
+ switchBackground = KindlSlate200,
+ ring = KindlCoral500,
+
+ chart1 = KindlCoral500,
+ chart2 = KindlSlate700,
+ chart3 = KindlBlue500,
+ chart4 = KindlTeal500,
+ chart5 = KindlAmber500,
+
+ sidebar = KindlSlate50,
+ sidebarForeground = KindlSlate700,
+ sidebarPrimary = KindlSlate700,
+ sidebarPrimaryForeground = White,
+ sidebarAccent = KindlSlate100,
+ sidebarAccentForeground = KindlSlate700,
+ sidebarBorder = KindlSlate700.copy(alpha = 0.10f),
+ sidebarRing = KindlCoral500,
+
+ isDark = false,
+)
+
+val darkKindlColors = KindlColors(
+ background = KindlSlate900,
+ foreground = KindlSlate50,
+ card = KindlSlate800,
+ cardForeground = KindlSlate50,
+ popover = KindlSlate800,
+ popoverForeground = KindlSlate50,
+
+ primary = KindlCoral500,
+ primaryForeground = White,
+ secondary = KindlSlate700,
+ secondaryForeground = White,
+
+ muted = KindlSlate600,
+ mutedForeground = KindlSlate300,
+ accent = KindlCoral500,
+ accentForeground = White,
+ destructive = KindlCoral700,
+ destructiveForeground= White,
+ success = KindlTeal500,
+ successForeground = KindlSlate900,
+
+ border = KindlCoral500.copy(alpha = 0.20f),
+ input = KindlCoral500.copy(alpha = 0.10f),
+ inputBackground = KindlSlate800,
+ switchBackground = KindlSlate600,
+ ring = KindlCoral500,
+
+ chart1 = KindlCoral500,
+ chart2 = KindlBlue500,
+ chart3 = KindlTeal500,
+ chart4 = KindlAmber500,
+ chart5 = KindlCoral400,
+
+ sidebar = KindlSlate800,
+ sidebarForeground = KindlSlate50,
+ sidebarPrimary = KindlCoral500,
+ sidebarPrimaryForeground = White,
+ sidebarAccent = KindlSlate600,
+ sidebarAccentForeground = KindlSlate50,
+ sidebarBorder = KindlCoral500.copy(alpha = 0.20f),
+ sidebarRing = KindlCoral500,
+
+ isDark = true,
+)
+
+val localKindlColors = staticCompositionLocalOf { darkKindlColors }
diff --git a/core/designsystem/src/main/java/com/kindl/core/designsystem/theme/Theme.kt b/core/designsystem/src/main/java/com/kindl/core/designsystem/theme/Theme.kt
index c3665f6..6db7b97 100644
--- a/core/designsystem/src/main/java/com/kindl/core/designsystem/theme/Theme.kt
+++ b/core/designsystem/src/main/java/com/kindl/core/designsystem/theme/Theme.kt
@@ -1,57 +1,92 @@
package com.kindl.core.designsystem.theme
-import android.os.Build
-import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.darkColorScheme
-import androidx.compose.material3.dynamicDarkColorScheme
-import androidx.compose.material3.dynamicLightColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
-import androidx.compose.ui.platform.LocalContext
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.ReadOnlyComposable
-private val DarkColorScheme = darkColorScheme(
- primary = Purple80,
- secondary = PurpleGrey80,
- tertiary = Pink80
+private val KindlDarkColorScheme = darkColorScheme(
+ primary = KindlCoral500,
+ onPrimary = White,
+ primaryContainer = KindlSlate700,
+ onPrimaryContainer = KindlSlate50,
+ secondary = KindlSlate700,
+ onSecondary = White,
+ secondaryContainer = KindlSlate600,
+ onSecondaryContainer = KindlSlate100,
+ background = KindlSlate900,
+ onBackground = KindlSlate50,
+ surface = KindlSlate800,
+ onSurface = KindlSlate50,
+ surfaceVariant = KindlSlate700,
+ onSurfaceVariant = KindlSlate300,
+ outline = KindlCoral500,
+ error = KindlCoral700,
+ onError = White,
)
-private val LightColorScheme = lightColorScheme(
- primary = Purple40,
- secondary = PurpleGrey40,
- tertiary = Pink40
-
- /* Other default colors to override
- background = Color(0xFFFFFBFE),
- surface = Color(0xFFFFFBFE),
- onPrimary = Color.White,
- onSecondary = Color.White,
- onTertiary = Color.White,
- onBackground = Color(0xFF1C1B1F),
- onSurface = Color(0xFF1C1B1F),
- */
+private val KindlLightColorScheme = lightColorScheme(
+ primary = KindlSlate700,
+ onPrimary = White,
+ primaryContainer = KindlSlate100,
+ onPrimaryContainer = KindlSlate700,
+ secondary = KindlCoral500,
+ onSecondary = White,
+ secondaryContainer = KindlCoral100,
+ onSecondaryContainer = KindlCoral700,
+ background = White,
+ onBackground = KindlSlate700,
+ surface = White,
+ onSurface = KindlSlate700,
+ surfaceVariant = KindlSlate50,
+ onSurfaceVariant = KindlSlate500,
+ outline = KindlSlate700,
+ error = KindlCoral700,
+ onError = White,
)
@Composable
-fun KindlTheme(
- darkTheme: Boolean = isSystemInDarkTheme(),
- // Dynamic color is available on Android 12+
- dynamicColor: Boolean = true,
+fun ProvideKindlColorsAndTypography(
+ colors: KindlColors,
+ typography: KindlTypography,
content: @Composable () -> Unit
) {
- val colorScheme = when {
- dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
- val context = LocalContext.current
- if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
- }
-
- darkTheme -> DarkColorScheme
- else -> LightColorScheme
- }
-
- MaterialTheme(
- colorScheme = colorScheme,
- typography = Typography,
+ CompositionLocalProvider(
+ localKindlColors provides colors,
+ localKindlTypography provides typography,
content = content
)
}
+
+@Composable
+fun KindlTheme(
+ darkTheme: Boolean = true,
+ content: @Composable () -> Unit,
+) {
+ val kindlColors = if (darkTheme) darkKindlColors else lightKindlColors
+ val colorScheme = if (darkTheme) KindlDarkColorScheme else KindlLightColorScheme
+
+ ProvideKindlColorsAndTypography(
+ colors = kindlColors,
+ typography = defaultKindlTypography,
+ ) {
+ MaterialTheme(
+ colorScheme = colorScheme,
+ content = content,
+ )
+ }
+}
+
+object KindlTheme {
+ val colors: KindlColors
+ @Composable
+ @ReadOnlyComposable
+ get() = localKindlColors.current
+
+ val typography: KindlTypography
+ @Composable
+ @ReadOnlyComposable
+ get() = localKindlTypography.current
+}
diff --git a/core/designsystem/src/main/java/com/kindl/core/designsystem/theme/Type.kt b/core/designsystem/src/main/java/com/kindl/core/designsystem/theme/Type.kt
index 1a81b63..f5e7606 100644
--- a/core/designsystem/src/main/java/com/kindl/core/designsystem/theme/Type.kt
+++ b/core/designsystem/src/main/java/com/kindl/core/designsystem/theme/Type.kt
@@ -1,34 +1,187 @@
package com.kindl.core.designsystem.theme
-import androidx.compose.material3.Typography
+import androidx.compose.runtime.Immutable
+import androidx.compose.runtime.staticCompositionLocalOf
+import androidx.compose.ui.text.PlatformTextStyle
import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
-import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.em
import androidx.compose.ui.unit.sp
+import com.kindl.core.designsystem.R
-// Set of Material typography styles to start with
-val Typography = Typography(
- bodyLarge = TextStyle(
- fontFamily = FontFamily.Default,
- fontWeight = FontWeight.Normal,
- fontSize = 16.sp,
- lineHeight = 24.sp,
- letterSpacing = 0.5.sp
+object KindlFont {
+ val semiBold = FontFamily(Font(R.font.pretendard_semibold))
+ val bold = FontFamily(Font(R.font.pretendard_bold))
+ val regular = FontFamily(Font(R.font.pretendard_regular))
+ val medium = FontFamily(Font(R.font.pretendard_medium))
+}
+
+private object TypographyDefaults {
+ val RegularLetterSpacing = (-0.005).em
+ val RegularLineHeight = 1.5.em
+
+ val SemiBoldLetterSpacing = (-0.01).em
+ val SemiBoldLineHeight = 1.5.em
+
+ val BoldLetterSpacing = (-0.01).em
+ val BoldLineHeight = 1.5.em
+
+ val PlatformStyle = PlatformTextStyle(includeFontPadding = false)
+}
+
+sealed interface TypographyTokens {
+
+ /**
+ * Regular weight body 텍스트
+ * CSS base 16px 기준 스케일 유지
+ */
+ @Immutable
+ data class Regular(
+ val body1: TextStyle, // 18sp
+ val body2: TextStyle, // 16sp
+ val body3: TextStyle, // 14sp
+ val body4: TextStyle, // 12sp
+ val body5: TextStyle, // 11sp
+ val body6: TextStyle, // 10sp
)
- /* Other default text styles to override
- titleLarge = TextStyle(
- fontFamily = FontFamily.Default,
- fontWeight = FontWeight.Normal,
- fontSize = 22.sp,
- lineHeight = 28.sp,
- letterSpacing = 0.sp
- ),
- labelSmall = TextStyle(
- fontFamily = FontFamily.Default,
- fontWeight = FontWeight.Medium,
- fontSize = 11.sp,
- lineHeight = 16.sp,
- letterSpacing = 0.5.sp
+
+ /**
+ * SemiBold weight title 텍스트
+ * CSS h1~h4 에서 font-weight: medium(500) 대응
+ */
+ @Immutable
+ data class SemiBold(
+ val title1: TextStyle, // 22sp
+ val title2: TextStyle, // 20sp
+ val title3: TextStyle, // 16sp
+ val title4: TextStyle, // 14sp
)
- */
+
+ /**
+ * Bold weight headline 텍스트
+ */
+ @Immutable
+ data class Bold(
+ val headLine1: TextStyle, // 22sp
+ val headLine2: TextStyle, // 20sp
+ val headLine3: TextStyle, // 16sp
+ val headLine4: TextStyle, // 14sp
+ )
+}
+
+@Immutable
+data class KindlTypography(
+ val regular: TypographyTokens.Regular,
+ val semiBold: TypographyTokens.SemiBold,
+ val bold: TypographyTokens.Bold,
+)
+
+val defaultKindlTypography = KindlTypography(
+ regular = TypographyTokens.Regular(
+ body1 = TextStyle(
+ fontFamily = KindlFont.regular,
+ fontSize = 18.sp,
+ letterSpacing = TypographyDefaults.RegularLetterSpacing,
+ lineHeight = TypographyDefaults.RegularLineHeight,
+ platformStyle = TypographyDefaults.PlatformStyle,
+ ),
+ body2 = TextStyle(
+ fontFamily = KindlFont.regular,
+ fontSize = 16.sp,
+ letterSpacing = TypographyDefaults.RegularLetterSpacing,
+ lineHeight = TypographyDefaults.RegularLineHeight,
+ platformStyle = TypographyDefaults.PlatformStyle,
+ ),
+ body3 = TextStyle(
+ fontFamily = KindlFont.regular,
+ fontSize = 14.sp,
+ letterSpacing = TypographyDefaults.RegularLetterSpacing,
+ lineHeight = TypographyDefaults.RegularLineHeight,
+ platformStyle = TypographyDefaults.PlatformStyle,
+ ),
+ body4 = TextStyle(
+ fontFamily = KindlFont.regular,
+ fontSize = 12.sp,
+ letterSpacing = TypographyDefaults.RegularLetterSpacing,
+ lineHeight = TypographyDefaults.RegularLineHeight,
+ platformStyle = TypographyDefaults.PlatformStyle,
+ ),
+ body5 = TextStyle(
+ fontFamily = KindlFont.regular,
+ fontSize = 11.sp,
+ letterSpacing = TypographyDefaults.RegularLetterSpacing,
+ lineHeight = TypographyDefaults.RegularLineHeight,
+ platformStyle = TypographyDefaults.PlatformStyle,
+ ),
+ body6 = TextStyle(
+ fontFamily = KindlFont.regular,
+ fontSize = 10.sp,
+ letterSpacing = TypographyDefaults.RegularLetterSpacing,
+ lineHeight = TypographyDefaults.RegularLineHeight,
+ platformStyle = TypographyDefaults.PlatformStyle,
+ ),
+ ),
+ semiBold = TypographyTokens.SemiBold(
+ title1 = TextStyle(
+ fontFamily = KindlFont.semiBold,
+ fontSize = 22.sp,
+ letterSpacing = TypographyDefaults.SemiBoldLetterSpacing,
+ lineHeight = TypographyDefaults.SemiBoldLineHeight,
+ platformStyle = TypographyDefaults.PlatformStyle,
+ ),
+ title2 = TextStyle(
+ fontFamily = KindlFont.semiBold,
+ fontSize = 20.sp,
+ letterSpacing = TypographyDefaults.SemiBoldLetterSpacing,
+ lineHeight = TypographyDefaults.SemiBoldLineHeight,
+ platformStyle = TypographyDefaults.PlatformStyle,
+ ),
+ title3 = TextStyle(
+ fontFamily = KindlFont.semiBold,
+ fontSize = 16.sp,
+ letterSpacing = TypographyDefaults.SemiBoldLetterSpacing,
+ lineHeight = TypographyDefaults.SemiBoldLineHeight,
+ platformStyle = TypographyDefaults.PlatformStyle,
+ ),
+ title4 = TextStyle(
+ fontFamily = KindlFont.semiBold,
+ fontSize = 14.sp,
+ letterSpacing = TypographyDefaults.SemiBoldLetterSpacing,
+ lineHeight = TypographyDefaults.SemiBoldLineHeight,
+ platformStyle = TypographyDefaults.PlatformStyle,
+ ),
+ ),
+ bold = TypographyTokens.Bold(
+ headLine1 = TextStyle(
+ fontFamily = KindlFont.bold,
+ fontSize = 22.sp,
+ letterSpacing = TypographyDefaults.BoldLetterSpacing,
+ lineHeight = TypographyDefaults.BoldLineHeight,
+ platformStyle = TypographyDefaults.PlatformStyle,
+ ),
+ headLine2 = TextStyle(
+ fontFamily = KindlFont.bold,
+ fontSize = 20.sp,
+ letterSpacing = TypographyDefaults.BoldLetterSpacing,
+ lineHeight = TypographyDefaults.BoldLineHeight,
+ platformStyle = TypographyDefaults.PlatformStyle,
+ ),
+ headLine3 = TextStyle(
+ fontFamily = KindlFont.bold,
+ fontSize = 16.sp,
+ letterSpacing = TypographyDefaults.BoldLetterSpacing,
+ lineHeight = TypographyDefaults.BoldLineHeight,
+ platformStyle = TypographyDefaults.PlatformStyle,
+ ),
+ headLine4 = TextStyle(
+ fontFamily = KindlFont.bold,
+ fontSize = 14.sp,
+ letterSpacing = TypographyDefaults.BoldLetterSpacing,
+ lineHeight = TypographyDefaults.BoldLineHeight,
+ platformStyle = TypographyDefaults.PlatformStyle,
+ ),
+ ),
)
+
+val localKindlTypography = staticCompositionLocalOf { defaultKindlTypography }
diff --git a/core/permission/src/main/kotlin/com/kindl/core/permission/PermissionType.kt b/core/permission/src/main/kotlin/com/kindl/core/permission/PermissionType.kt
index ac69d3d..3ea04eb 100644
--- a/core/permission/src/main/kotlin/com/kindl/core/permission/PermissionType.kt
+++ b/core/permission/src/main/kotlin/com/kindl/core/permission/PermissionType.kt
@@ -5,5 +5,5 @@ enum class PermissionType(val isFocusRequired: Boolean) {
OVERLAY(isFocusRequired = true),
BATTERY_OPTIMIZATION(isFocusRequired = true),
POST_NOTIFICATIONS(isFocusRequired = false),
- ACCESSIBILITY(isFocusRequired = true),
+ ACCESSIBILITY(isFocusRequired = false),
}
diff --git a/data/forbidden/build.gradle.kts b/data/forbidden/build.gradle.kts
index eedf00b..760f3b1 100644
--- a/data/forbidden/build.gradle.kts
+++ b/data/forbidden/build.gradle.kts
@@ -9,5 +9,9 @@ android {
}
dependencies {
+ // core
+ implementation(projects.core.coroutine)
+
+ // domain
implementation(projects.domain.forbidden)
}
diff --git a/data/forbidden/src/main/java/com/kindl/data/forbidden/repositoryimpl/ForbiddenAppRepositoryImpl.kt b/data/forbidden/src/main/java/com/kindl/data/forbidden/repositoryimpl/ForbiddenAppRepositoryImpl.kt
index a329a9d..e740b8c 100644
--- a/data/forbidden/src/main/java/com/kindl/data/forbidden/repositoryimpl/ForbiddenAppRepositoryImpl.kt
+++ b/data/forbidden/src/main/java/com/kindl/data/forbidden/repositoryimpl/ForbiddenAppRepositoryImpl.kt
@@ -2,28 +2,32 @@ package com.kindl.data.forbidden.repositoryimpl
import android.content.Context
import android.content.Intent
+import com.kindl.coroutine.qualifier.IoDispatcher
import com.kindl.domain.forbidden.model.InstalledAppModel
import com.kindl.domain.forbidden.repository.ForbiddenAppRepository
import dagger.hilt.android.qualifiers.ApplicationContext
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.withContext
import javax.inject.Inject
internal class ForbiddenAppRepositoryImpl @Inject constructor(
@param:ApplicationContext private val context: Context,
+ @param:IoDispatcher private val ioDispatcher: CoroutineDispatcher
) : ForbiddenAppRepository {
- override fun getInstalledUserApps(): List {
+ override suspend fun getInstalledUserApps(): List = withContext(ioDispatcher) {
val pm = context.packageManager
val intent = Intent(Intent.ACTION_MAIN).apply {
addCategory(Intent.CATEGORY_LAUNCHER)
}
- return pm.queryIntentActivities(intent, 0)
+ pm.queryIntentActivities(intent, 0)
.filter { it.activityInfo.packageName != context.packageName }
.map { resolveInfo ->
InstalledAppModel(
packageName = resolveInfo.activityInfo.packageName,
appName = resolveInfo.loadLabel(pm).toString(),
- //icon = resolveInfo.loadIcon(pm),
+ // icon = resolveInfo.loadIcon(pm),
)
}
.sortedBy { it.appName }
diff --git a/domain/forbidden/src/main/java/com/kindl/domain/forbidden/repository/ForbiddenAppRepository.kt b/domain/forbidden/src/main/java/com/kindl/domain/forbidden/repository/ForbiddenAppRepository.kt
index c7159c4..cdec5d5 100644
--- a/domain/forbidden/src/main/java/com/kindl/domain/forbidden/repository/ForbiddenAppRepository.kt
+++ b/domain/forbidden/src/main/java/com/kindl/domain/forbidden/repository/ForbiddenAppRepository.kt
@@ -3,5 +3,5 @@ package com.kindl.domain.forbidden.repository
import com.kindl.domain.forbidden.model.InstalledAppModel
interface ForbiddenAppRepository {
- fun getInstalledUserApps(): List
+ suspend fun getInstalledUserApps(): List
}
diff --git a/domain/forbidden/src/main/java/com/kindl/domain/forbidden/usecase/GetInstalledAppsUseCase.kt b/domain/forbidden/src/main/java/com/kindl/domain/forbidden/usecase/GetInstalledAppsUseCase.kt
index 92d69e4..6debe39 100644
--- a/domain/forbidden/src/main/java/com/kindl/domain/forbidden/usecase/GetInstalledAppsUseCase.kt
+++ b/domain/forbidden/src/main/java/com/kindl/domain/forbidden/usecase/GetInstalledAppsUseCase.kt
@@ -9,6 +9,6 @@ import javax.inject.Inject
class GetInstalledAppsUseCase @Inject constructor(
private val appRepository: ForbiddenAppRepository,
) {
- operator fun invoke(): ImmutableList =
+ suspend operator fun invoke(): ImmutableList =
appRepository.getInstalledUserApps().toImmutableList()
}
diff --git a/presentation/home/src/main/java/com/kindl/presentation/home/HomeViewModel.kt b/presentation/home/src/main/java/com/kindl/presentation/home/HomeViewModel.kt
index 2c0cc20..1babca3 100644
--- a/presentation/home/src/main/java/com/kindl/presentation/home/HomeViewModel.kt
+++ b/presentation/home/src/main/java/com/kindl/presentation/home/HomeViewModel.kt
@@ -13,6 +13,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
+import timber.log.Timber
import javax.inject.Inject
@HiltViewModel
diff --git a/presentation/home/src/main/java/com/kindl/presentation/home/component/ForbiddenAppItem.kt b/presentation/home/src/main/java/com/kindl/presentation/home/component/ForbiddenAppItem.kt
index 1298f7f..ff6a110 100644
--- a/presentation/home/src/main/java/com/kindl/presentation/home/component/ForbiddenAppItem.kt
+++ b/presentation/home/src/main/java/com/kindl/presentation/home/component/ForbiddenAppItem.kt
@@ -1,17 +1,21 @@
package com.kindl.presentation.home.component
+import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.asImageBitmap
+import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
-import com.kindl.core.designsystem.component.UrlImage
+import androidx.core.graphics.drawable.toBitmap
import com.kindl.core.designsystem.theme.KindlTheme
import com.kindl.presentation.home.model.ForbiddenAppUiModel
@@ -20,20 +24,35 @@ internal fun ForbiddenAppItem(
item: ForbiddenAppUiModel,
modifier: Modifier = Modifier
) {
+ val iconBitmap = remember(item.icon) {
+ item.icon?.toBitmap()?.asImageBitmap()
+ }
+
Row(
modifier = modifier,
verticalAlignment = Alignment.CenterVertically
) {
- UrlImage(
- url = item.icon,
- modifier = Modifier
- .size(36.dp)
- .clip(RoundedCornerShape(16.dp))
- )
+ val iconModifier = Modifier
+ .size(36.dp)
+ .clip(RoundedCornerShape(16.dp))
+
+
+ iconBitmap?.let {
+ Image(
+ bitmap = it,
+ contentDescription = null,
+ contentScale = ContentScale.Crop,
+ modifier = iconModifier
+ )
+ }
Spacer(modifier = Modifier.weight(1f))
- Text(text = item.appName)
+ Text(
+ text = item.appName,
+ style = KindlTheme.typography.semiBold.title3,
+ color = KindlTheme.colors.primary
+ )
}
}
diff --git a/settings.gradle.kts b/settings.gradle.kts
index bdf0fbc..2ec2a67 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -33,7 +33,8 @@ include(
":core:localstorage",
":core:permission",
":core:service",
- ":core:work"
+ ":core:work",
+ ":core:coroutine"
)
// data