Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,4 @@ build/
app/.idea/
/composeApp/google-services.json
/iosApp/iosApp/GoogleService-Info.plist
/iosApp/Configuration/Config.xcconfig
125 changes: 61 additions & 64 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,88 +1,85 @@
### ๐Ÿšง Suwiki๋Š” ํ˜„์žฌ ๋ฆฌํŒฉํ† ๋ง ์ž‘์—… ์ค‘์ž…๋‹ˆ๋‹ค.
# ChukChukHaksa (์ฒ™์ฒ™ํ•™์‚ฌ)

# Suwiki
์ˆ˜์›๋Œ€ํ•™๊ต ์žฌํ•™์ƒ์„ ์œ„ํ•œ ์‹œ๊ฐ„ํ‘œ & ๊ฐ•์˜ํ‰๊ฐ€ ์„œ๋น„์Šค์ž…๋‹ˆ๋‹ค.
Kotlin Multiplatform (Android + iOS) ๊ธฐ๋ฐ˜์œผ๋กœ ๊ฐœ๋ฐœ๋˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

# Introduce
## Tech Stack

**Suwiki(์ˆ˜์œ„ํ‚ค)** ๋Š” ์ˆ˜์›๋Œ€ํ•™๊ต ์žฌํ•™์ƒ๋“ค์˜ ๋ถˆํŽธํ•จ์„ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋งŒ๋“ค์–ด์ง„ ์‹œ๊ฐ„ํ‘œ & ๊ฐ•์˜ํ‰๊ฐ€ ์„œ๋น„์Šค์ž…๋‹ˆ๋‹ค. ๋Œ€๋žต **43**๊ฐœ์˜ ๋ชจ๋“ˆ๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ์œผ๋ฉฐ Clean Architecture, Mvi, Hilt, Coroutine, Flow, Jetpack
Compose ๋“ฑ์˜ ๊ธฐ์ˆ ์ด ์ ์šฉ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.
| Category | Stack |
|----------|-------|
| Language | Kotlin 2.2, Swift |
| UI | Compose Multiplatform 1.10 |
| Architecture | MVI + Clean Architecture |
| DI | Koin 4.1 |
| Database | Room 2.7 (KMP) |
| Remote | Firebase (GitLive KMP) |
| Widget | Glance (Android), WidgetKit (iOS) |

2023๋…„ 12์›” 13์ผ ๊ธฐ์ค€ **2039**๋ช…์˜ ์œ ์ €๊ฐ€ ์‚ฌ์šฉ ์ค‘์ž…๋‹ˆ๋‹ค.
## Project Structure

# Architecture
๋‹จ์ผ `composeApp` ๋ชจ๋“ˆ ๊ตฌ์กฐ:

Suwiki๋Š” Mvi ๊ธฐ๋ฐ˜์˜ Clean Architecture ๊ตฌ์กฐ๋กœ ์„ค๊ณ„๋˜์–ด ์žˆ์œผ๋ฉฐ ํฌ๊ฒŒ core, data, domain, feature ๋ชจ๋“ˆ๋กœ ๊ตฌ์„ฑ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.
presentation layer์—์„œ๋Š” UDF(๋‹จ๋ฐฉํ–ฅ ๋ฐ์ดํ„ฐ ํ๋ฆ„) ํŒจํ„ด์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
```
com.chukchukhaksa.mobile/
โ”œโ”€โ”€ common/ # ๋””์ž์ธ์‹œ์Šคํ…œ, ํ™•์žฅํ•จ์ˆ˜, KMP ํ”Œ๋žซํผ ์ฝ”๋“œ
โ”œโ”€โ”€ data/ # Repository ๊ตฌํ˜„
โ”œโ”€โ”€ di/ # Koin DI ๋ชจ๋“ˆ
โ”œโ”€โ”€ domain/ # UseCase, Repository ์ธํ„ฐํŽ˜์ด์Šค
โ”œโ”€โ”€ local/ # Room DB, DataStore
โ”œโ”€โ”€ presentation/ # ํ™”๋ฉด (MVI ํŒจํ„ด)
โ”œโ”€โ”€ remote/ # Firebase ๋ฐ์ดํ„ฐ์†Œ์Šค
โ””โ”€โ”€ widget/ # ์œ„์ ฏ (Android Glance / iOS WidgetKit)
```

> ์œ ์ง€ ๋ณด์ˆ˜๋ฅผ ํ•ด๊ฐ€๋ฉฐ ๋ชจ๋“ˆ์ด ๊ณผํ•˜๊ฒŒ ๋‚˜๋ˆ„์–ด์ ธ ์žˆ๋‹ค๋ฉด ํ†ตํ•ฉ์„, ์ถ”๊ฐ€๋กœ ๋‚˜๋ˆ ์•ผํ•œ๋‹ค๋ฉด ๋ถ„๋ฆฌํ•  ์ƒ๊ฐ์ž…๋‹ˆ๋‹ค. Suwiki Architecture๋Š” ๊ณ„์† ๋ณ€๊ฒฝ๋  ์˜ˆ์ •์ด๋ฉฐ ํ”ผ๋“œ๋ฐฑ์ด๋‚˜ ์งˆ๋ฌธ์ด ์žˆ๋‹ค๋ฉด koownij@kakao.com์œผ๋กœ ์–ธ์ œ๋“ ์ง€ ์—ฐ๋ฝ ์ฃผ์„ธ์š” :)
## Setup

## Module
### 1. ํ”„๋กœ์ ํŠธ ํด๋ก 

### 40๊ฐœ๊ฐ€ ๋„˜๋Š” ๋ชจ๋“ˆ๋กœ ๋‚˜๋ˆˆ ์ด์œ 
```bash
git clone https://github.com/your-org/cchaksa-kmp.git
cd cchaksa-kmp
```

#### 1. Suwiki๋Š” ์ตœ์†Œ 5๋…„ ์ด์ƒ์˜ ์„œ๋น„์Šค๋ฅผ ๋ชฉํ‘œ๋กœ ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
### 2. API Key ์„ค์ •

์˜ค๋žœ ์‹œ๊ฐ„์ด ์ง€๋‚œ ํ›„ ์ฝ”๋“œ๋ฅผ ๋‹ค์‹œ ๋ณด์•˜์„ ๋•Œ, ๊ด€์‹ฌ์‚ฌ๋ณ„๋กœ ๋ชจ๋“ˆ์ด ๋ถ„๋ฆฌ๋˜์–ด ์žˆ๋‹ค๋ฉด ์œ ์ง€ ๋ณด์ˆ˜๊ฐ€ ์‰ฌ์šธ๊ฑฐ๋ผ ํŒ๋‹จํ–ˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.
ํ‚ค ๊ฐ’์€ [Notion](https://www.notion.so/30a1a2480da180408962e123dc1482ca?source=copy_link)์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

#### 2. ์ธ์›์ด ๊ณ„์† ๋ณ€๊ฒฝ๋ฉ๋‹ˆ๋‹ค.
#### Android

๊ณ ์ •๋œ ์ธ์›์ด ๊ฐœ๋ฐœ์„ ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ฉฐ ์ˆ˜์›๋Œ€ํ•™๊ต ํ›„๋ฐฐ๋“ค์—๊ฒŒ ํ”„๋กœ์ ํŠธ๋ฅผ ๋„˜๊ฒจ์ฃผ๋ฉฐ ์ด์–ด๋‚˜๊ฐˆ ์ƒ๊ฐ์ž…๋‹ˆ๋‹ค. ๋ชจ๋“ˆ ๋ถ„๋ฆฌ๊ฐ€ ๋ช…ํ™•ํ•˜๋‹ค๋ฉด ์ƒˆ๋กœ์šด ์ธ์›์ด ์ฝ”๋“œ๋ฅผ ๋ณ€๊ฒฝํ•ด๋„ ์•ˆ์ „ํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.
`local.properties`์— ์ถ”๊ฐ€ (gitignore ๋จ):

#### 3. ์ƒˆ๋กœ์šด Feature๊ฐ€ ์ถ”๊ฐ€๋  ๊ฐ€๋Šฅ์„ฑ์ด ํฝ๋‹ˆ๋‹ค.
```properties
KAKAO_NATIVE_APP_KEY=๋…ธ์…˜์—์„œ_ํ™•์ธํ•œ_ํ‚ค_๊ฐ’
```

์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์ด ์ถ”๊ฐ€๋˜๋”๋ผ๋„ ๋ชจ๋“ˆ ๋ถ„๋ฆฌ๊ฐ€ ๋˜์–ด์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ธฐ์กด ์ฝ”๋“œ์— ์˜ํ–ฅ์„ ์ฃผ๊ธฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค.
#### iOS

#### 4. ๋ฉ€ํ‹ฐ ๋ชจ๋“ˆ ๋‹จ์  ๊ทน๋ณต
`iosApp/Configuration/Config.xcconfig`์— ์ถ”๊ฐ€ (gitignore ๋จ):

40๊ฐœ์˜ ๋ชจ๋“ˆ๋กœ ๋ถ„๋ฆฌํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ์˜คํžˆ๋ ค ๋ณต์žกํ•ด๋ณด์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋ฌธ์„œํ™”๋ฅผ ํ†ตํ•ด ๋ชจ๋“ˆ๊ฐ„์˜ ์˜์กด์„ฑ๊ณผ ๋ชจ๋“ˆ์ด ์–ด๋–ค ์—ญํ• ์„ ํ•˜๋Š”์ง€ ์ž์„ธํžˆ ์ ์–ด๋†“๋Š”๋‹ค๋ฉด ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค.
```
KAKAO_NATIVE_APP_KEY=๋…ธ์…˜์—์„œ_ํ™•์ธํ•œ_ํ‚ค_๊ฐ’
```

### ๋ชจ๋“ˆํ™” ๊ธฐ์ค€
### 3. Build

#### 1. Clean Architecture์˜ Layer์™€ ์•ฑ์˜ Feature ๋‹จ์œ„๋กœ ๋ถ„๋ฆฌ
```bash
# Android
./gradlew assembleDebug

ex) ์‹œ๊ฐ„ํ‘œ, ๊ฐ•์˜ํ‰๊ฐ€
# iOS (Simulator)
./gradlew linkDebugFrameworkIosSimulatorArm64
# ์ดํ›„ Xcode์—์„œ iosApp.xcworkspace ์—ด๊ณ  ๋นŒ๋“œ
```

`domain:timetable`, `data:timetable`, `feature:timetable`
`domain:lectureevaluation`, `data:lectureevaluation`, `feature:lectureevaluatioin`
## Architecture

#### 2. ๋ชจ๋“ˆ์˜ ํŠน์ • ๋ถ€๋ถ„์ด ์—ฌ๋Ÿฌ ๊ณณ์—์„œ ์‚ฌ์šฉ๋œ๋‹ค๋ฉด ๋ถ„๋ฆฌ
MVI + Clean Architecture ํŒจํ„ด์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

ex) ๊ฐ•์˜ํ‰๊ฐ€ Create/Read/Update/Delete ๊ธฐ๋Šฅ ์ค‘ Create/Update/Delete ๋ถ€๋ถ„์ด `feature:myinfo`, `feature:lectureevaluation`์—์„œ ์‚ฌ์šฉ๋˜๋Š” ๊ฒฝ์šฐ
```
Presentation (MVI) โ†’ Domain (UseCase) โ†’ Data (Repository)
โ†“ โ†“
ViewModel + State/SideEffect Local (Room/DataStore)
Remote (Firebase)
```

๊ฐ•์˜ํ‰๊ฐ€ Read ๊ธฐ๋Šฅ๊ณผ Create/Update/Delete ๊ธฐ๋Šฅ์„ ๋ถ„๋ฆฌํ•ฉ๋‹ˆ๋‹ค. -> `feature:lectureevaluation:viewer`, `feature:lectureevaluation:editor`

### ๋ชจ๋“ˆ ์„ค๋ช…

feature, data, domain, local, remote ๋ชจ๋“ˆ์ด ๊ฐ€์ง€๋Š” ์˜์กด์„ฑ์€ ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค. (core ๋ชจ๋“ˆ ๋“ฑ ์ผ๋ถ€ ๋ชจ๋“ˆ์˜ ์˜์กด์„ฑ์€ ์‚ฌ์ง„์—์„œ ์ œ์™ธํ•จ)
![entire_module_graph.png](docs/entire_module_graph.png)

#### core

์ด๋ฆ„์—์„œ ์œ ์ถ”ํ•  ์ˆ˜ ์žˆ๋“ฏ ๋งŽ์€ ๋ชจ๋“ˆ์—์„œ ์žฌ์‚ฌ์šฉํ•˜๋Š” ํ•ต์‹ฌ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค. core ๋ชจ๋“ˆ๊ฐ„์˜ ์˜์กด์„ฑ์€ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์œผ๋‚˜ core ๋ชจ๋“ˆ์ด ๋‹ค๋ฅธ ๋ชจ๋“ˆ(feature, data, domain, local, remote)์˜ ์˜์กด์„ฑ์„ ๊ฐ€์ง€๋ฉด ์•ˆ๋ฉ๋‹ˆ๋‹ค.

![core_module.png](docs/core_module.png)

| ์ด๋ฆ„ | ์—ญํ•  |
|:-----------------:|:-----------------------------------------------------:|
| core:android | ์•ˆ๋“œ๋กœ์ด๋“œ ์˜์กด์„ฑ์„ ๊ฐ€์ง€๋Š” ๋ชจ๋“ˆ๋“ค์ด ๊ณตํ†ต์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ฝ”๋“œ๊ฐ€ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. |
| core:common | ๋ชจ๋“  ๋ชจ๋“ˆ์—์„œ ๊ณตํ†ต์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ฝ”๋“œ๊ฐ€ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. |
| core:database | Local Database(Room), Jetpack - DataStore |
| core:designsystem | Component, Theme, Color, Typography |
| core:network | Retrofit2 ๊ด€๋ จ ์ฝ”๋“œ๊ฐ€ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. |
| core:ui | ui์—์„œ ๊ณตํ†ต์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ์ฝ”๋“œ๊ฐ€ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค๋ฉด Modifier์˜ ํ™•์žฅํ•จ์ˆ˜๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. |
| core:security | ํŠน์ • ๊ฐ’์„ ์•”ํ˜ธํ™”ํ•ด์ฃผ๋Š” ๋ชจ๋“ˆ์ž…๋‹ˆ๋‹ค. Jwt๋ฅผ ์•”ํ˜ธํ™”ํ•ฉ๋‹ˆ๋‹ค. |
| core:model | ๊ณตํ†ต์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” Model์ด ์ •์˜๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. |

#### feature

๋ชจ๋“  feature ๋ชจ๋“ˆ์€ `feature:navigation` ๋ชจ๋“ˆ์— ์˜์กดํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

#### ๊ทธ ์™ธ

| ์ด๋ฆ„ | ์—ญํ•  |
|:-------------------:|:----------------------------------------:|
| app | ๋ ˆ๊ฑฐ์‹œ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค. |
| app:compose | ์ƒˆ๋กญ๊ฒŒ ๋ฆฌํŒฉํ† ๋ง ์ค‘์ธ ๋ชจ๋“ˆ์ž…๋‹ˆ๋‹ค. |
| data, local, remote | Clean Architecture์—์„œ์˜ data Layer |
| domain | Clean Architecture์—์„œ์˜ domain Layer |
| feature | Clean Architecture์—์„œ์˜ presentation Layer |
๊ฐ ํ™”๋ฉด์€ `[Feature]State`, `[Feature]SideEffect`, `[Feature]ViewModel` ๊ตฌ์กฐ๋ฅผ ๋”ฐ๋ฆ…๋‹ˆ๋‹ค.
13 changes: 13 additions & 0 deletions composeApp/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import java.util.Properties

val localProperties = Properties().apply {
val localPropertiesFile = rootProject.file("local.properties")
if (localPropertiesFile.exists()) {
load(localPropertiesFile.inputStream())
}
}

plugins {
alias(libs.plugins.kotlinMultiplatform)
Expand Down Expand Up @@ -49,6 +57,7 @@ kotlin {
implementation(libs.glance.appwidget)
implementation(libs.glance.material3)
implementation(libs.compose.runtime)
implementation(libs.kakao.sdk.v2.user)
}
iosMain.dependencies {
}
Expand Down Expand Up @@ -82,6 +91,7 @@ kotlin {
implementation(libs.kmp.firebase.crashlytics)
implementation(libs.kmp.firebase.analytics)
implementation(libs.napier)
implementation(libs.kinappbrowser)
}
commonTest.dependencies {
implementation(libs.kotlin.test)
Expand All @@ -104,6 +114,9 @@ android {
targetSdk = libs.versions.android.targetSdk.get().toInt()
versionCode = 51
versionName = "3.0.1"

buildConfigField("String", "KAKAO_NATIVE_APP_KEY", "\"${localProperties["KAKAO_NATIVE_APP_KEY"] ?: ""}\"")
manifestPlaceholders["KAKAO_NATIVE_APP_KEY"] = localProperties["KAKAO_NATIVE_APP_KEY"] ?: ""
}
packaging {
resources {
Expand Down
12 changes: 12 additions & 0 deletions composeApp/src/androidMain/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,18 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.kakao.sdk.auth.AuthCodeHandlerActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="oauth"
android:scheme="kakao${KAKAO_NATIVE_APP_KEY}" />
</intent-filter>
</activity>
<receiver android:name=".widget.TimetableWidgetReceiver" android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.chukchukhaksa.mobile
import android.app.Application
import com.chukchukhaksa.mobile.common.kmp.isDebug
import com.chukchukhaksa.mobile.di.initKoin
import com.kakao.sdk.common.KakaoSdk
import com.google.firebase.Firebase
import com.google.firebase.initialize
import io.github.aakira.napier.DebugAntilog
Expand All @@ -22,5 +23,6 @@ class ChukChukHaksaApplication : Application() {
}

Firebase.initialize(this)
KakaoSdk.init(this, BuildConfig.KAKAO_NATIVE_APP_KEY)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package com.chukchukhaksa.mobile.common.kmp

import android.content.Context
import com.kakao.sdk.auth.model.OAuthToken
import com.kakao.sdk.common.model.ClientError
import com.kakao.sdk.common.model.ClientErrorCause
import com.kakao.sdk.user.UserApiClient
import kotlinx.coroutines.suspendCancellableCoroutine
import java.util.UUID
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException

actual class KakaoSignInClient {

actual suspend fun signIn(context: Any?): KakaoSignInResult {
val androidContext = context as? Context
?: throw IllegalStateException("Android Context is required for Kakao Login")

val nonce = UUID.randomUUID().toString()

return suspendCancellableCoroutine { continuation ->
val callback: (OAuthToken?, Throwable?) -> Unit = callback@{ token, error ->
if (error != null) {
continuation.resumeWithException(error)
return@callback
}
val idToken = token?.idToken
if (idToken == null) {
continuation.resumeWithException(
IllegalStateException("id_token์ด null์ž…๋‹ˆ๋‹ค. ์นด์นด์˜ค ์ฝ˜์†”์—์„œ OpenID Connect๋ฅผ ํ™œ์„ฑํ™”ํ•˜์„ธ์š”.")
)
return@callback
}
continuation.resume(KakaoSignInResult(idToken = idToken, nonce = nonce))
}

if (UserApiClient.instance.isKakaoTalkLoginAvailable(androidContext)) {
UserApiClient.instance.loginWithKakaoTalk(
context = androidContext,
nonce = nonce,
) { token, error ->
if (error != null) {
if (error is ClientError && error.reason == ClientErrorCause.Cancelled) {
UserApiClient.instance.loginWithKakaoAccount(
context = androidContext,
nonce = nonce,
callback = callback,
)
return@loginWithKakaoTalk
}
callback(null, error)
return@loginWithKakaoTalk
}
callback(token, null)
}
} else {
UserApiClient.instance.loginWithKakaoAccount(
context = androidContext,
nonce = nonce,
callback = callback,
)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.chukchukhaksa.mobile.di

import com.chukchukhaksa.mobile.common.kmp.KakaoSignInClient
import com.chukchukhaksa.mobile.local.database.openlecture.database.OpenLectureDatabaseFactory
import com.chukchukhaksa.mobile.local.database.openmajor.database.OpenMajorDatabaseFactory
import com.chukchukhaksa.mobile.local.database.timetable.database.TimetableDatabaseFactory
Expand All @@ -12,4 +13,5 @@ actual val platformModule = module {
single { OpenMajorDatabaseFactory(androidApplication()) }
single { OpenLectureDatabaseFactory(androidApplication()) }
single { ChukChukHaksaDataStoreFactory(androidApplication()) }
factory { KakaoSignInClient() }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.chukchukhaksa.mobile.common.kmp

data class KakaoSignInResult(
val idToken: String,
val nonce: String,
)

expect class KakaoSignInClient {
suspend fun signIn(context: Any? = null): KakaoSignInResult
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.chukchukhaksa.mobile.di

import com.chukchukhaksa.mobile.domain.auth.usecase.AppleLoginUseCase
import com.chukchukhaksa.mobile.domain.auth.usecase.KakaoLoginUseCase
import com.chukchukhaksa.mobile.domain.config.usecase.CheckNeedForceUpdateUseCase
import com.chukchukhaksa.mobile.domain.timetable.usecase.DeleteTimetableCellUseCase
import com.chukchukhaksa.mobile.domain.timetable.usecase.DeleteTimetableUseCase
Expand Down Expand Up @@ -44,4 +45,5 @@ val domainModule = module {

// Auth use cases
factory { AppleLoginUseCase(get()) }
factory { KakaoLoginUseCase(get()) }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.chukchukhaksa.mobile.domain.auth.usecase

import com.chukchukhaksa.mobile.common.kmp.KakaoSignInClient
import com.chukchukhaksa.mobile.common.kmp.KakaoSignInResult
import com.chukchukhaksa.mobile.domain.common.runCatchingIgnoreCancelled

class KakaoLoginUseCase(
private val kakaoSignInClient: KakaoSignInClient,
) {
suspend operator fun invoke(context: Any? = null): Result<KakaoSignInResult> =
runCatchingIgnoreCancelled {
kakaoSignInClient.signIn(context)
}
}
Loading
Loading