diff --git a/app-compose/build.gradle.kts b/app-compose/build.gradle.kts
index fa34d3bc3..be3fc11b6 100644
--- a/app-compose/build.gradle.kts
+++ b/app-compose/build.gradle.kts
@@ -3,6 +3,8 @@ plugins {
alias(libs.plugins.suwiki.android.application)
alias(libs.plugins.suwiki.android.application.compose)
alias(libs.plugins.suwiki.android.hilt)
+ alias(libs.plugins.google.services)
+ alias(libs.plugins.firebase.crashlytics)
}
android {
@@ -16,15 +18,7 @@ android {
}
dependencies {
- implementation(projects.presentation)
-
- implementation(projects.core.android)
- implementation(projects.core.model)
- implementation(projects.core.common)
- implementation(projects.core.network)
- implementation(projects.core.security)
- implementation(projects.core.database)
- implementation(projects.core.ui)
+ implementation(projects.feature.navigator)
implementation(projects.remote.openmajor)
implementation(projects.remote.timetable)
@@ -48,14 +42,9 @@ dependencies {
implementation(projects.data.notice)
implementation(projects.data.signup)
- implementation(projects.domain.openmajor)
- implementation(projects.domain.user)
- implementation(projects.domain.signup)
- implementation(projects.domain.lectureevaluation.viewerreporter)
- implementation(projects.domain.lectureevaluation.my)
- implementation(projects.domain.lectureevaluation.editor)
- implementation(projects.domain.timetable)
- implementation(projects.domain.notice)
+ implementation(platform(libs.firebase.bom))
+ implementation(libs.firebase.crashlytics)
+ implementation(libs.firebase.analytics)
implementation(libs.timber)
}
diff --git a/app-compose/src/main/AndroidManifest.xml b/app-compose/src/main/AndroidManifest.xml
index b81d7d3e4..94776ba9c 100644
--- a/app-compose/src/main/AndroidManifest.xml
+++ b/app-compose/src/main/AndroidManifest.xml
@@ -1,14 +1,18 @@
-
+
-
-
+
-
\ No newline at end of file
+
diff --git a/app-compose/src/main/res/values/strings.xml b/app-compose/src/main/res/values/strings.xml
index 0537dd83f..e84d9b034 100644
--- a/app-compose/src/main/res/values/strings.xml
+++ b/app-compose/src/main/res/values/strings.xml
@@ -1,3 +1,3 @@
- Suwiki-Compose
-
\ No newline at end of file
+ SUWIKI
+
diff --git a/app-compose/src/main/res/xml/data_extraction_rules.xml b/app-compose/src/main/res/xml/data_extraction_rules.xml
new file mode 100644
index 000000000..7da4b02dc
--- /dev/null
+++ b/app-compose/src/main/res/xml/data_extraction_rules.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build-logic/convention/src/main/java/FeatureComposeConventionPlugin.kt b/build-logic/convention/src/main/java/FeatureComposeConventionPlugin.kt
index eaf5459d8..2e1478705 100644
--- a/build-logic/convention/src/main/java/FeatureComposeConventionPlugin.kt
+++ b/build-logic/convention/src/main/java/FeatureComposeConventionPlugin.kt
@@ -2,6 +2,7 @@ import com.kunize.convention.libs
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.dependencies
+import org.gradle.kotlin.dsl.project
internal class FeatureComposeConventionPlugin : Plugin {
@@ -14,6 +15,14 @@ internal class FeatureComposeConventionPlugin : Plugin {
}
dependencies {
+ "implementation"(project(":core:model"))
+ "implementation"(project(":core:android"))
+ "implementation"(project(":core:ui"))
+ "implementation"(project(":core:designsystem"))
+
+ "implementation"(libs.findBundle("orbit").get())
+
+ "implementation"(libs.findLibrary("kotlinx.immutable").get())
"implementation"(libs.findLibrary("kotlinx.coroutines.android").get())
"implementation"(libs.findLibrary("kotlinx.coroutines.core").get())
diff --git a/build.gradle.kts b/build.gradle.kts
index e96ab67e3..8e2b147ed 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,8 +1,11 @@
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+
// Top-level build file where you can add configuration options common to all sub-projects/modules.
@Suppress("DSL_SCOPE_VIOLATION")
plugins {
alias(libs.plugins.detekt)
alias(libs.plugins.ktlint)
+ alias(libs.plugins.firebase.crashlytics) apply false
alias(libs.plugins.android.application) apply false
alias(libs.plugins.android.library) apply false
alias(libs.plugins.kotlin.android) apply false
@@ -15,6 +18,8 @@ plugins {
}
allprojects {
+ val projectPath = rootProject.file(".").absolutePath
+
apply {
plugin(rootProject.libs.plugins.detekt.get().pluginId)
plugin(rootProject.libs.plugins.ktlint.get().pluginId)
@@ -28,6 +33,23 @@ allprojects {
config.setFrom(files("$rootDir/detekt-config.yml"))
}
}
+
+ tasks.withType {
+ kotlinOptions {
+ freeCompilerArgs = freeCompilerArgs + listOf(
+ "-opt-in=kotlin.OptIn",
+ "-opt-in=kotlin.RequiresOptIn",
+ )
+ freeCompilerArgs = freeCompilerArgs + listOf(
+ "-P",
+ "plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=$projectPath/report/compose-metrics",
+ )
+ freeCompilerArgs = freeCompilerArgs + listOf(
+ "-P",
+ "plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=$projectPath/report/compose-reports",
+ )
+ }
+ }
}
buildscript {
diff --git a/core/android/build.gradle.kts b/core/android/build.gradle.kts
index 86f84904d..46ce5d669 100644
--- a/core/android/build.gradle.kts
+++ b/core/android/build.gradle.kts
@@ -7,3 +7,10 @@ plugins {
android {
namespace = "com.suwiki.core.android"
}
+
+dependencies {
+ implementation(projects.core.model)
+
+ implementation(platform(libs.firebase.bom))
+ implementation(libs.firebase.crashlytics)
+}
diff --git a/core/android/src/main/java/com/suwiki/core/android/ThrowUnknownException.kt b/core/android/src/main/java/com/suwiki/core/android/ThrowUnknownException.kt
new file mode 100644
index 000000000..1bf96c61a
--- /dev/null
+++ b/core/android/src/main/java/com/suwiki/core/android/ThrowUnknownException.kt
@@ -0,0 +1,12 @@
+package com.suwiki.core.android
+
+import com.google.firebase.crashlytics.ktx.crashlytics
+import com.google.firebase.ktx.Firebase
+import com.suwiki.core.model.exception.UnknownException
+
+fun throwUnknownException(
+ e: Throwable,
+) {
+ Firebase.crashlytics.recordException(e)
+ throw e.message?.let { UnknownException(it) } ?: UnknownException()
+}
diff --git a/core/designsystem/src/main/java/com/suwiki/core/designsystem/component/bottomnavigation/SuwikiBottomNavigation.kt b/core/designsystem/src/main/java/com/suwiki/core/designsystem/component/bottomnavigation/SuwikiBottomNavigation.kt
deleted file mode 100644
index 0518b01b9..000000000
--- a/core/designsystem/src/main/java/com/suwiki/core/designsystem/component/bottomnavigation/SuwikiBottomNavigation.kt
+++ /dev/null
@@ -1,87 +0,0 @@
-package com.suwiki.core.designsystem.component.bottomnavigation
-
-import androidx.compose.foundation.background
-import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.wrapContentHeight
-import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.setValue
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.draw.clip
-import androidx.compose.ui.draw.shadow
-import androidx.compose.ui.tooling.preview.Preview
-import androidx.compose.ui.unit.dp
-import com.suwiki.core.designsystem.R
-import com.suwiki.core.designsystem.theme.SuwikiTheme
-import com.suwiki.core.designsystem.theme.White
-
-@Composable
-fun SuwikiBottomNavigation(
- modifier: Modifier = Modifier,
- isTimeTableChecked: Boolean,
- isEvaluationChecked: Boolean,
- isMyInfoChecked: Boolean,
- onClickTimeTableItem: () -> Unit = {},
- onClickEvaluationItem: () -> Unit = {},
- onClickMyInfoItem: () -> Unit = {},
-) {
- Box(
- modifier = modifier
- .shadow(elevation = 4.dp)
- .clip(RoundedCornerShape(10.dp, 10.dp, 0.dp, 0.dp))
- .background(White)
- .fillMaxWidth()
- .wrapContentHeight(),
- ) {
- Row(
- horizontalArrangement = Arrangement.SpaceBetween,
- ) {
- SuwikiBottomNavigationItem(
- modifier = Modifier.weight(1f),
- isChecked = isTimeTableChecked,
- iconId = R.drawable.ic_bottom_navigation_evaluation,
- onClickItem = onClickTimeTableItem,
- )
- SuwikiBottomNavigationItem(
- modifier = Modifier.weight(1f),
- isChecked = isEvaluationChecked,
- iconId = R.drawable.ic_bottom_navigation_evaluation,
- onClickItem = onClickEvaluationItem,
- )
- SuwikiBottomNavigationItem(
- modifier = Modifier.weight(1f),
- isChecked = isMyInfoChecked,
- iconId = R.drawable.ic_bottom_navigation_evaluation,
- onClickItem = onClickMyInfoItem,
- )
- }
- }
-}
-
-@Preview(showSystemUi = true)
-@Composable
-fun SuwikiBottomNavigationPreview() {
- var isTimeTableChecked by remember { mutableStateOf(true) }
- var isEvaluationChecked by remember { mutableStateOf(false) }
- var isMyInfoChecked by remember { mutableStateOf(false) }
-
- SuwikiTheme {
- Column {
- SuwikiBottomNavigation(
- isTimeTableChecked = isTimeTableChecked,
- isEvaluationChecked = isEvaluationChecked,
- isMyInfoChecked = isMyInfoChecked,
- onClickTimeTableItem = { isTimeTableChecked = !isTimeTableChecked },
- onClickEvaluationItem = { isEvaluationChecked = !isEvaluationChecked },
- onClickMyInfoItem = { isMyInfoChecked = !isMyInfoChecked },
- )
- }
- }
-}
diff --git a/core/designsystem/src/main/java/com/suwiki/core/designsystem/component/bottomnavigation/SuwikiBottomNavigationItem.kt b/core/designsystem/src/main/java/com/suwiki/core/designsystem/component/bottomnavigation/SuwikiBottomNavigationItem.kt
deleted file mode 100644
index d7c784f1a..000000000
--- a/core/designsystem/src/main/java/com/suwiki/core/designsystem/component/bottomnavigation/SuwikiBottomNavigationItem.kt
+++ /dev/null
@@ -1,50 +0,0 @@
-package com.suwiki.core.designsystem.component.bottomnavigation
-
-import androidx.compose.foundation.layout.padding
-import androidx.compose.material3.Icon
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.setValue
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.res.painterResource
-import androidx.compose.ui.tooling.preview.Preview
-import androidx.compose.ui.unit.dp
-import com.suwiki.core.designsystem.R
-import com.suwiki.core.designsystem.theme.GrayDA
-import com.suwiki.core.designsystem.theme.Primary
-import com.suwiki.core.designsystem.theme.SuwikiTheme
-import com.suwiki.core.ui.extension.suwikiClickable
-
-@Composable
-fun SuwikiBottomNavigationItem(
- modifier: Modifier = Modifier,
- isChecked: Boolean,
- iconId: Int,
- onClickItem: () -> Unit = {},
-) {
- val iconColor = if (isChecked) Primary else GrayDA
- Icon(
- painter = painterResource(id = iconId),
- contentDescription = "",
- tint = iconColor,
- modifier = modifier
- .suwikiClickable(onClick = onClickItem)
- .padding(vertical = 16.dp, horizontal = 48.dp),
- )
-}
-
-@Preview
-@Composable
-fun SuwikiBottomNavigationItemPreview() {
- var isChecked by remember { mutableStateOf(false) }
-
- SuwikiTheme {
- SuwikiBottomNavigationItem(
- isChecked = isChecked,
- iconId = R.drawable.ic_bottom_navigation_evaluation,
- onClickItem = { isChecked = !isChecked },
- )
- }
-}
diff --git a/core/designsystem/src/main/java/com/suwiki/core/designsystem/component/toast/SuwikiToast.kt b/core/designsystem/src/main/java/com/suwiki/core/designsystem/component/toast/SuwikiToast.kt
new file mode 100644
index 000000000..dd6d74cec
--- /dev/null
+++ b/core/designsystem/src/main/java/com/suwiki/core/designsystem/component/toast/SuwikiToast.kt
@@ -0,0 +1,82 @@
+package com.suwiki.core.designsystem.component.toast
+
+import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.animation.fadeIn
+import androidx.compose.animation.fadeOut
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.imePadding
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.wrapContentSize
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.Surface
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import com.suwiki.core.designsystem.theme.Gray95
+import com.suwiki.core.designsystem.theme.SuwikiTheme
+import com.suwiki.core.designsystem.theme.White
+
+@Composable
+fun SuwikiToast(
+ visible: Boolean,
+ message: String,
+) {
+ AnimatedVisibility(
+ visible = visible,
+ enter = fadeIn(),
+ exit = fadeOut(),
+ ) {
+ Box(
+ modifier = Modifier
+ .fillMaxSize()
+ .padding(bottom = 70.dp),
+ contentAlignment = Alignment.BottomCenter,
+ ) {
+ SuwikiToastContent(
+ modifier = Modifier.imePadding(),
+ message = message,
+ )
+ }
+ }
+}
+
+@Composable
+private fun SuwikiToastContent(
+ modifier: Modifier = Modifier,
+ message: String,
+) {
+ Surface(
+ modifier = modifier
+ .wrapContentSize()
+ .background(
+ color = Gray95,
+ shape = RoundedCornerShape(25.dp),
+ ),
+ color = Color.Transparent,
+ ) {
+ Text(
+ text = message,
+ textAlign = TextAlign.Center,
+ style = SuwikiTheme.typography.body5,
+ color = White,
+ modifier = Modifier.padding(16.dp, 10.dp),
+ )
+ }
+}
+
+@Preview
+@Composable
+fun SuwikiToastPreview() {
+ SuwikiTheme {
+ SuwikiToastContent(
+ message = "text",
+ )
+ }
+}
diff --git a/core/designsystem/src/main/java/com/suwiki/core/designsystem/component/toast/SuwikiToastView.kt b/core/designsystem/src/main/java/com/suwiki/core/designsystem/component/toast/SuwikiToastView.kt
deleted file mode 100644
index 85fe45bc7..000000000
--- a/core/designsystem/src/main/java/com/suwiki/core/designsystem/component/toast/SuwikiToastView.kt
+++ /dev/null
@@ -1,59 +0,0 @@
-package com.suwiki.core.designsystem.component.toast
-
-import androidx.compose.foundation.background
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.wrapContentSize
-import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.material3.Surface
-import androidx.compose.material3.Text
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.text.style.TextAlign
-import androidx.compose.ui.tooling.preview.Preview
-import androidx.compose.ui.unit.dp
-import com.suwiki.core.designsystem.theme.Gray95
-import com.suwiki.core.designsystem.theme.SuwikiTheme
-import com.suwiki.core.designsystem.theme.White
-
-@Composable
-fun SuwikiToastView(
- messageText: String,
-) {
- Box(
- modifier = Modifier
- .fillMaxSize(),
- contentAlignment = Alignment.Center,
- ) {
- Surface(
- modifier = Modifier
- .wrapContentSize()
- .background(
- color = Gray95,
- shape = RoundedCornerShape(25.dp),
- ),
- color = Color.Transparent,
- ) {
- Text(
- text = messageText,
- textAlign = TextAlign.Center,
- style = SuwikiTheme.typography.body5,
- color = White,
- modifier = Modifier.padding(16.dp, 10.dp),
- )
- }
- }
-}
-
-@Preview
-@Composable
-fun SetViewPreview() {
- SuwikiTheme {
- SuwikiToastView(
- messageText = "text",
- )
- }
-}
diff --git a/core/designsystem/src/main/res/values/themes.xml b/core/designsystem/src/main/res/values/themes.xml
new file mode 100644
index 000000000..785c47862
--- /dev/null
+++ b/core/designsystem/src/main/res/values/themes.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/presentation/.gitignore b/data/login/.gitignore
similarity index 100%
rename from presentation/.gitignore
rename to data/login/.gitignore
diff --git a/data/login/build.gradle.kts b/data/login/build.gradle.kts
new file mode 100644
index 000000000..aac137b04
--- /dev/null
+++ b/data/login/build.gradle.kts
@@ -0,0 +1,13 @@
+@Suppress("DSL_SCOPE_VIOLATION") // TODO: Remove once KTIJ-19369 is fixed
+plugins {
+ alias(libs.plugins.suwiki.android.data)
+}
+
+android {
+ namespace = "com.suwiki.data.login"
+}
+
+dependencies {
+ implementation(projects.core.security)
+ implementation(projects.domain.login)
+}
diff --git a/presentation/consumer-rules.pro b/data/login/consumer-rules.pro
similarity index 100%
rename from presentation/consumer-rules.pro
rename to data/login/consumer-rules.pro
diff --git a/presentation/proguard-rules.pro b/data/login/proguard-rules.pro
similarity index 100%
rename from presentation/proguard-rules.pro
rename to data/login/proguard-rules.pro
diff --git a/data/login/src/main/AndroidManifest.xml b/data/login/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..8bdb7e14b
--- /dev/null
+++ b/data/login/src/main/AndroidManifest.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/data/login/src/main/java/com/suwiki/data/login/datasource/LocalLoginDataSource.kt b/data/login/src/main/java/com/suwiki/data/login/datasource/LocalLoginDataSource.kt
new file mode 100644
index 000000000..8140bbe9e
--- /dev/null
+++ b/data/login/src/main/java/com/suwiki/data/login/datasource/LocalLoginDataSource.kt
@@ -0,0 +1,9 @@
+package com.suwiki.data.login.datasource
+
+import com.suwiki.core.model.user.Token
+
+interface LocalLoginDataSource {
+ suspend fun setToken(
+ token: Token,
+ )
+}
diff --git a/data/login/src/main/java/com/suwiki/data/login/datasource/RemoteLoginDataSource.kt b/data/login/src/main/java/com/suwiki/data/login/datasource/RemoteLoginDataSource.kt
new file mode 100644
index 000000000..4fdb1fe8d
--- /dev/null
+++ b/data/login/src/main/java/com/suwiki/data/login/datasource/RemoteLoginDataSource.kt
@@ -0,0 +1,17 @@
+package com.suwiki.data.login.datasource
+
+import com.suwiki.core.model.user.Token
+
+interface RemoteLoginDataSource {
+ suspend fun findId(email: String)
+
+ suspend fun findPassword(
+ loginId: String,
+ email: String,
+ )
+
+ suspend fun login(
+ loginId: String,
+ password: String,
+ ): Token
+}
diff --git a/data/login/src/main/java/com/suwiki/data/login/di/RepositoryModule.kt b/data/login/src/main/java/com/suwiki/data/login/di/RepositoryModule.kt
new file mode 100644
index 000000000..43423c999
--- /dev/null
+++ b/data/login/src/main/java/com/suwiki/data/login/di/RepositoryModule.kt
@@ -0,0 +1,20 @@
+package com.suwiki.data.login.di
+
+import com.suwiki.data.login.repository.LoginRepositoryImpl
+import com.suwiki.domain.login.repository.LoginRepository
+import dagger.Binds
+import dagger.Module
+import dagger.hilt.InstallIn
+import dagger.hilt.components.SingletonComponent
+import javax.inject.Singleton
+
+@Module
+@InstallIn(SingletonComponent::class)
+abstract class RepositoryModule {
+
+ @Singleton
+ @Binds
+ abstract fun bindLoginRepository(
+ loginRepositoryImpl: LoginRepositoryImpl,
+ ): LoginRepository
+}
diff --git a/data/login/src/main/java/com/suwiki/data/login/repository/LoginRepositoryImpl.kt b/data/login/src/main/java/com/suwiki/data/login/repository/LoginRepositoryImpl.kt
new file mode 100644
index 000000000..c47ddfbc0
--- /dev/null
+++ b/data/login/src/main/java/com/suwiki/data/login/repository/LoginRepositoryImpl.kt
@@ -0,0 +1,32 @@
+package com.suwiki.data.login.repository
+
+import com.suwiki.data.login.datasource.LocalLoginDataSource
+import com.suwiki.data.login.datasource.RemoteLoginDataSource
+import com.suwiki.domain.login.repository.LoginRepository
+import javax.inject.Inject
+
+class LoginRepositoryImpl @Inject constructor(
+ private val remoteLoginDataSource: RemoteLoginDataSource,
+ private val localLoginDataSource: LocalLoginDataSource,
+) : LoginRepository {
+
+ override suspend fun findId(email: String) {
+ remoteLoginDataSource.findId(email = email)
+ }
+
+ override suspend fun findPassword(loginId: String, email: String) {
+ remoteLoginDataSource.findPassword(
+ loginId = loginId,
+ email = email,
+ )
+ }
+
+ override suspend fun login(loginId: String, password: String) {
+ val token = remoteLoginDataSource.login(
+ loginId = loginId,
+ password = password,
+ )
+
+ localLoginDataSource.setToken(token)
+ }
+}
diff --git a/data/user/build.gradle.kts b/data/user/build.gradle.kts
index 13aa5fb02..abf0c4854 100644
--- a/data/user/build.gradle.kts
+++ b/data/user/build.gradle.kts
@@ -8,5 +8,6 @@ android {
}
dependencies {
+ implementation(projects.core.security)
implementation(projects.domain.user)
}
diff --git a/data/user/src/main/java/com/suwiki/data/user/datasource/LocalUserProviderDataSource.kt b/data/user/src/main/java/com/suwiki/data/user/datasource/LocalUserDataSource.kt
similarity index 56%
rename from data/user/src/main/java/com/suwiki/data/user/datasource/LocalUserProviderDataSource.kt
rename to data/user/src/main/java/com/suwiki/data/user/datasource/LocalUserDataSource.kt
index 46bba0dc6..81f0b14db 100644
--- a/data/user/src/main/java/com/suwiki/data/user/datasource/LocalUserProviderDataSource.kt
+++ b/data/user/src/main/java/com/suwiki/data/user/datasource/LocalUserDataSource.kt
@@ -3,6 +3,12 @@ package com.suwiki.data.user.datasource
import com.suwiki.core.model.user.User
import kotlinx.coroutines.flow.Flow
-interface LocalUserProviderDataSource {
+interface LocalUserDataSource {
val user: Flow
+
+ suspend fun setUserInfo(
+ user: User,
+ )
+
+ suspend fun clearUserInfo()
}
diff --git a/data/user/src/main/java/com/suwiki/data/user/datasource/LocalUserStorageDataSource.kt b/data/user/src/main/java/com/suwiki/data/user/datasource/LocalUserStorageDataSource.kt
deleted file mode 100644
index de9abe3ea..000000000
--- a/data/user/src/main/java/com/suwiki/data/user/datasource/LocalUserStorageDataSource.kt
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.suwiki.data.user.datasource
-
-import com.suwiki.core.model.user.Token
-import com.suwiki.core.model.user.User
-
-interface LocalUserStorageDataSource {
- suspend fun setUserInfo(
- user: User,
- )
-
- suspend fun setToken(
- token: Token,
- )
-
- suspend fun clearUserInfoAndToken()
-}
diff --git a/data/user/src/main/java/com/suwiki/data/user/datasource/RemoteUserDataSource.kt b/data/user/src/main/java/com/suwiki/data/user/datasource/RemoteUserDataSource.kt
index 380bbb395..13b5743aa 100644
--- a/data/user/src/main/java/com/suwiki/data/user/datasource/RemoteUserDataSource.kt
+++ b/data/user/src/main/java/com/suwiki/data/user/datasource/RemoteUserDataSource.kt
@@ -1,26 +1,14 @@
package com.suwiki.data.user.datasource
-import com.suwiki.core.model.user.Token
import com.suwiki.core.model.user.User
interface RemoteUserDataSource {
- suspend fun findId(email: String)
-
- suspend fun findPassword(
- loginId: String,
- email: String,
- )
suspend fun resetPassword(
currentPassword: String,
newPassword: String,
)
- suspend fun login(
- loginId: String,
- password: String,
- ): Token
-
suspend fun quit(
id: String,
password: String,
diff --git a/data/user/src/main/java/com/suwiki/data/user/repository/UserRepositoryImpl.kt b/data/user/src/main/java/com/suwiki/data/user/repository/UserRepositoryImpl.kt
index 252a1ba2c..8f51c78ee 100644
--- a/data/user/src/main/java/com/suwiki/data/user/repository/UserRepositoryImpl.kt
+++ b/data/user/src/main/java/com/suwiki/data/user/repository/UserRepositoryImpl.kt
@@ -1,8 +1,8 @@
package com.suwiki.data.user.repository
import com.suwiki.core.model.user.User
-import com.suwiki.data.user.datasource.LocalUserProviderDataSource
-import com.suwiki.data.user.datasource.LocalUserStorageDataSource
+import com.suwiki.core.security.SecurityPreferences
+import com.suwiki.data.user.datasource.LocalUserDataSource
import com.suwiki.data.user.datasource.RemoteUserDataSource
import com.suwiki.domain.user.repository.UserRepository
import kotlinx.coroutines.flow.Flow
@@ -11,23 +11,13 @@ import kotlinx.coroutines.flow.flow
import javax.inject.Inject
class UserRepositoryImpl @Inject constructor(
- private val localUserProviderDataSource: LocalUserProviderDataSource,
- private val localUserStorageDataSource: LocalUserStorageDataSource,
+ private val localUserDataSource: LocalUserDataSource,
private val remoteUserDataSource: RemoteUserDataSource,
+ private val securityPreferences: SecurityPreferences,
) : UserRepository {
override suspend fun logout() {
- localUserStorageDataSource.clearUserInfoAndToken()
- }
-
- override suspend fun findId(email: String) {
- remoteUserDataSource.findId(email = email)
- }
-
- override suspend fun findPassword(loginId: String, email: String) {
- remoteUserDataSource.findPassword(
- loginId = loginId,
- email = email,
- )
+ localUserDataSource.clearUserInfo()
+ securityPreferences.clearAll()
}
override suspend fun resetPassword(currentPassword: String, newPassword: String) {
@@ -37,15 +27,6 @@ class UserRepositoryImpl @Inject constructor(
)
}
- override suspend fun login(loginId: String, password: String) {
- val token = remoteUserDataSource.login(
- loginId = loginId,
- password = password,
- )
-
- localUserStorageDataSource.setToken(token)
- }
-
override suspend fun quit(id: String, password: String) {
remoteUserDataSource.quit(
id = id,
@@ -54,12 +35,12 @@ class UserRepositoryImpl @Inject constructor(
}
override suspend fun getUserInfo(): Flow = flow {
- val localUserInfo = localUserProviderDataSource.user.first()
+ val localUserInfo = localUserDataSource.user.first()
emit(localUserInfo)
val remoteUserInfo = remoteUserDataSource.getUserInfo()
emit(remoteUserInfo)
- localUserStorageDataSource.setUserInfo(remoteUserInfo)
+ localUserDataSource.setUserInfo(remoteUserInfo)
}
}
diff --git a/domain/login/.gitignore b/domain/login/.gitignore
new file mode 100644
index 000000000..42afabfd2
--- /dev/null
+++ b/domain/login/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/domain/login/build.gradle.kts b/domain/login/build.gradle.kts
new file mode 100644
index 000000000..a401e2cb5
--- /dev/null
+++ b/domain/login/build.gradle.kts
@@ -0,0 +1,13 @@
+@file:Suppress("DSL_SCOPE_VIOLATION") // @file:을 붙인 이유 -> https://github.com/gradle/gradle/issues/20131
+
+plugins {
+ alias(libs.plugins.suwiki.java.library)
+}
+
+dependencies {
+ implementation(projects.core.model)
+ implementation(projects.core.common)
+
+ implementation(libs.kotlinx.coroutines.core)
+ implementation(libs.hilt.core)
+}
diff --git a/domain/login/src/main/java/com/suwiki/domain/login/repository/LoginRepository.kt b/domain/login/src/main/java/com/suwiki/domain/login/repository/LoginRepository.kt
new file mode 100644
index 000000000..f6a1450c2
--- /dev/null
+++ b/domain/login/src/main/java/com/suwiki/domain/login/repository/LoginRepository.kt
@@ -0,0 +1,16 @@
+package com.suwiki.domain.login.repository
+
+interface LoginRepository {
+
+ suspend fun findId(email: String)
+
+ suspend fun findPassword(
+ loginId: String,
+ email: String,
+ )
+
+ suspend fun login(
+ loginId: String,
+ password: String,
+ )
+}
diff --git a/domain/user/src/main/java/com/suwiki/domain/user/usecase/FindIdUseCase.kt b/domain/login/src/main/java/com/suwiki/domain/login/usecase/FindIdUseCase.kt
similarity index 55%
rename from domain/user/src/main/java/com/suwiki/domain/user/usecase/FindIdUseCase.kt
rename to domain/login/src/main/java/com/suwiki/domain/login/usecase/FindIdUseCase.kt
index f2213aaa6..5ad7d571d 100644
--- a/domain/user/src/main/java/com/suwiki/domain/user/usecase/FindIdUseCase.kt
+++ b/domain/login/src/main/java/com/suwiki/domain/login/usecase/FindIdUseCase.kt
@@ -1,13 +1,13 @@
-package com.suwiki.domain.user.usecase
+package com.suwiki.domain.login.usecase
import com.suwiki.core.common.runCatchingIgnoreCancelled
-import com.suwiki.domain.user.repository.UserRepository
+import com.suwiki.domain.login.repository.LoginRepository
import javax.inject.Inject
class FindIdUseCase @Inject constructor(
- private val userRepository: UserRepository,
+ private val loginRepository: LoginRepository,
) {
suspend operator fun invoke(email: String): Result = runCatchingIgnoreCancelled {
- userRepository.findId(email)
+ loginRepository.findId(email)
}
}
diff --git a/domain/user/src/main/java/com/suwiki/domain/user/usecase/FindPasswordUseCase.kt b/domain/login/src/main/java/com/suwiki/domain/login/usecase/FindPasswordUseCase.kt
similarity index 63%
rename from domain/user/src/main/java/com/suwiki/domain/user/usecase/FindPasswordUseCase.kt
rename to domain/login/src/main/java/com/suwiki/domain/login/usecase/FindPasswordUseCase.kt
index 8ab222605..035bdc92d 100644
--- a/domain/user/src/main/java/com/suwiki/domain/user/usecase/FindPasswordUseCase.kt
+++ b/domain/login/src/main/java/com/suwiki/domain/login/usecase/FindPasswordUseCase.kt
@@ -1,17 +1,17 @@
-package com.suwiki.domain.user.usecase
+package com.suwiki.domain.login.usecase
import com.suwiki.core.common.runCatchingIgnoreCancelled
-import com.suwiki.domain.user.repository.UserRepository
+import com.suwiki.domain.login.repository.LoginRepository
import javax.inject.Inject
class FindPasswordUseCase @Inject constructor(
- private val userRepository: UserRepository,
+ private val loginRepository: LoginRepository,
) {
suspend operator fun invoke(
loginId: String,
email: String,
): Result = runCatchingIgnoreCancelled {
- userRepository.findPassword(
+ loginRepository.findPassword(
loginId = loginId,
email = email,
)
diff --git a/domain/user/src/main/java/com/suwiki/domain/user/usecase/LoginUseCase.kt b/domain/login/src/main/java/com/suwiki/domain/login/usecase/LoginUseCase.kt
similarity index 64%
rename from domain/user/src/main/java/com/suwiki/domain/user/usecase/LoginUseCase.kt
rename to domain/login/src/main/java/com/suwiki/domain/login/usecase/LoginUseCase.kt
index f48863080..cf85139ed 100644
--- a/domain/user/src/main/java/com/suwiki/domain/user/usecase/LoginUseCase.kt
+++ b/domain/login/src/main/java/com/suwiki/domain/login/usecase/LoginUseCase.kt
@@ -1,17 +1,17 @@
-package com.suwiki.domain.user.usecase
+package com.suwiki.domain.login.usecase
import com.suwiki.core.common.runCatchingIgnoreCancelled
-import com.suwiki.domain.user.repository.UserRepository
+import com.suwiki.domain.login.repository.LoginRepository
import javax.inject.Inject
class LoginUseCase @Inject constructor(
- private val userRepository: UserRepository,
+ private val loginRepository: LoginRepository,
) {
suspend operator fun invoke(
loginId: String,
password: String,
): Result = runCatchingIgnoreCancelled {
- userRepository.login(
+ loginRepository.login(
loginId = loginId,
password = password,
)
diff --git a/domain/user/src/main/java/com/suwiki/domain/user/repository/UserRepository.kt b/domain/user/src/main/java/com/suwiki/domain/user/repository/UserRepository.kt
index fd8113967..2e7b4769e 100644
--- a/domain/user/src/main/java/com/suwiki/domain/user/repository/UserRepository.kt
+++ b/domain/user/src/main/java/com/suwiki/domain/user/repository/UserRepository.kt
@@ -7,23 +7,11 @@ interface UserRepository {
suspend fun logout()
- suspend fun findId(email: String)
-
- suspend fun findPassword(
- loginId: String,
- email: String,
- )
-
suspend fun resetPassword(
currentPassword: String,
newPassword: String,
)
- suspend fun login(
- loginId: String,
- password: String,
- )
-
suspend fun quit(
id: String,
password: String,
diff --git a/feature/lectureevaluation/editor/.gitignore b/feature/lectureevaluation/editor/.gitignore
new file mode 100644
index 000000000..42afabfd2
--- /dev/null
+++ b/feature/lectureevaluation/editor/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/feature/lectureevaluation/editor/build.gradle.kts b/feature/lectureevaluation/editor/build.gradle.kts
new file mode 100644
index 000000000..8b6d18373
--- /dev/null
+++ b/feature/lectureevaluation/editor/build.gradle.kts
@@ -0,0 +1,12 @@
+@Suppress("DSL_SCOPE_VIOLATION") // TODO: Remove once KTIJ-19369 is fixed
+plugins {
+ alias(libs.plugins.suwiki.android.feature.compose)
+}
+
+android {
+ namespace = "com.suwiki.feature.lectureevaluation.editor"
+}
+
+dependencies {
+ implementation(projects.domain.lectureevaluation.editor)
+}
diff --git a/feature/lectureevaluation/editor/consumer-rules.pro b/feature/lectureevaluation/editor/consumer-rules.pro
new file mode 100644
index 000000000..e69de29bb
diff --git a/feature/lectureevaluation/editor/proguard-rules.pro b/feature/lectureevaluation/editor/proguard-rules.pro
new file mode 100644
index 000000000..481bb4348
--- /dev/null
+++ b/feature/lectureevaluation/editor/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/feature/lectureevaluation/editor/src/main/AndroidManifest.xml b/feature/lectureevaluation/editor/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..8bdb7e14b
--- /dev/null
+++ b/feature/lectureevaluation/editor/src/main/AndroidManifest.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/feature/lectureevaluation/my/.gitignore b/feature/lectureevaluation/my/.gitignore
new file mode 100644
index 000000000..42afabfd2
--- /dev/null
+++ b/feature/lectureevaluation/my/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/feature/lectureevaluation/my/build.gradle.kts b/feature/lectureevaluation/my/build.gradle.kts
new file mode 100644
index 000000000..b311392a8
--- /dev/null
+++ b/feature/lectureevaluation/my/build.gradle.kts
@@ -0,0 +1,12 @@
+@Suppress("DSL_SCOPE_VIOLATION") // TODO: Remove once KTIJ-19369 is fixed
+plugins {
+ alias(libs.plugins.suwiki.android.feature.compose)
+}
+
+android {
+ namespace = "com.suwiki.feature.lectureevaluation.my"
+}
+
+dependencies {
+ implementation(projects.domain.lectureevaluation.my)
+}
diff --git a/feature/lectureevaluation/my/consumer-rules.pro b/feature/lectureevaluation/my/consumer-rules.pro
new file mode 100644
index 000000000..e69de29bb
diff --git a/feature/lectureevaluation/my/proguard-rules.pro b/feature/lectureevaluation/my/proguard-rules.pro
new file mode 100644
index 000000000..481bb4348
--- /dev/null
+++ b/feature/lectureevaluation/my/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/feature/lectureevaluation/my/src/main/AndroidManifest.xml b/feature/lectureevaluation/my/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..8bdb7e14b
--- /dev/null
+++ b/feature/lectureevaluation/my/src/main/AndroidManifest.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/feature/lectureevaluation/viewerreporter/.gitignore b/feature/lectureevaluation/viewerreporter/.gitignore
new file mode 100644
index 000000000..42afabfd2
--- /dev/null
+++ b/feature/lectureevaluation/viewerreporter/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/feature/lectureevaluation/viewerreporter/build.gradle.kts b/feature/lectureevaluation/viewerreporter/build.gradle.kts
new file mode 100644
index 000000000..f0e430ad2
--- /dev/null
+++ b/feature/lectureevaluation/viewerreporter/build.gradle.kts
@@ -0,0 +1,12 @@
+@Suppress("DSL_SCOPE_VIOLATION") // TODO: Remove once KTIJ-19369 is fixed
+plugins {
+ alias(libs.plugins.suwiki.android.feature.compose)
+}
+
+android {
+ namespace = "com.suwiki.feature.lectureevaluation.viewerreporter"
+}
+
+dependencies {
+ implementation(projects.domain.lectureevaluation.viewerreporter)
+}
diff --git a/feature/lectureevaluation/viewerreporter/consumer-rules.pro b/feature/lectureevaluation/viewerreporter/consumer-rules.pro
new file mode 100644
index 000000000..e69de29bb
diff --git a/feature/lectureevaluation/viewerreporter/proguard-rules.pro b/feature/lectureevaluation/viewerreporter/proguard-rules.pro
new file mode 100644
index 000000000..481bb4348
--- /dev/null
+++ b/feature/lectureevaluation/viewerreporter/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/feature/lectureevaluation/viewerreporter/src/main/AndroidManifest.xml b/feature/lectureevaluation/viewerreporter/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..8bdb7e14b
--- /dev/null
+++ b/feature/lectureevaluation/viewerreporter/src/main/AndroidManifest.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/feature/lectureevaluation/viewerreporter/src/main/java/com/suwiki/feature/lectureevaluation/viewerreporter/LectureEvaluationScreen.kt b/feature/lectureevaluation/viewerreporter/src/main/java/com/suwiki/feature/lectureevaluation/viewerreporter/LectureEvaluationScreen.kt
new file mode 100644
index 000000000..57d4c189b
--- /dev/null
+++ b/feature/lectureevaluation/viewerreporter/src/main/java/com/suwiki/feature/lectureevaluation/viewerreporter/LectureEvaluationScreen.kt
@@ -0,0 +1,28 @@
+package com.suwiki.feature.lectureevaluation.viewerreporter
+
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import com.suwiki.core.designsystem.theme.SuwikiTheme
+
+@Composable
+fun LectureEvaluationScreen(
+ padding: PaddingValues,
+) {
+ Text(
+ modifier = Modifier.padding(padding),
+ text = "강의평가",
+ )
+}
+
+@Preview
+@Composable
+fun LectureEvaluationScreenPreview() {
+ SuwikiTheme {
+ LectureEvaluationScreen(padding = PaddingValues(0.dp))
+ }
+}
diff --git a/feature/lectureevaluation/viewerreporter/src/main/java/com/suwiki/feature/lectureevaluation/viewerreporter/navigation/LectureEvaluationNavigation.kt b/feature/lectureevaluation/viewerreporter/src/main/java/com/suwiki/feature/lectureevaluation/viewerreporter/navigation/LectureEvaluationNavigation.kt
new file mode 100644
index 000000000..28d1bf054
--- /dev/null
+++ b/feature/lectureevaluation/viewerreporter/src/main/java/com/suwiki/feature/lectureevaluation/viewerreporter/navigation/LectureEvaluationNavigation.kt
@@ -0,0 +1,24 @@
+package com.suwiki.feature.lectureevaluation.viewerreporter.navigation
+
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.navigation.NavController
+import androidx.navigation.NavGraphBuilder
+import androidx.navigation.NavOptions
+import androidx.navigation.compose.composable
+import com.suwiki.feature.lectureevaluation.viewerreporter.LectureEvaluationScreen
+
+fun NavController.navigateLectureEvaluation(navOptions: NavOptions) {
+ navigate(LectureEvaluationRoute.route, navOptions)
+}
+
+fun NavGraphBuilder.lectureEvaluationNavGraph(
+ padding: PaddingValues,
+) {
+ composable(route = LectureEvaluationRoute.route) {
+ LectureEvaluationScreen(padding)
+ }
+}
+
+object LectureEvaluationRoute {
+ const val route = "lecture-evaluation"
+}
diff --git a/feature/login/.gitignore b/feature/login/.gitignore
new file mode 100644
index 000000000..42afabfd2
--- /dev/null
+++ b/feature/login/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/feature/login/build.gradle.kts b/feature/login/build.gradle.kts
new file mode 100644
index 000000000..1f2f94825
--- /dev/null
+++ b/feature/login/build.gradle.kts
@@ -0,0 +1,12 @@
+@Suppress("DSL_SCOPE_VIOLATION") // TODO: Remove once KTIJ-19369 is fixed
+plugins {
+ alias(libs.plugins.suwiki.android.feature.compose)
+}
+
+android {
+ namespace = "com.suwiki.feature.login"
+}
+
+dependencies {
+ implementation(projects.domain.login)
+}
diff --git a/feature/login/consumer-rules.pro b/feature/login/consumer-rules.pro
new file mode 100644
index 000000000..e69de29bb
diff --git a/feature/login/proguard-rules.pro b/feature/login/proguard-rules.pro
new file mode 100644
index 000000000..481bb4348
--- /dev/null
+++ b/feature/login/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/feature/login/src/main/AndroidManifest.xml b/feature/login/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..8bdb7e14b
--- /dev/null
+++ b/feature/login/src/main/AndroidManifest.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/feature/myinfo/.gitignore b/feature/myinfo/.gitignore
new file mode 100644
index 000000000..42afabfd2
--- /dev/null
+++ b/feature/myinfo/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/feature/myinfo/build.gradle.kts b/feature/myinfo/build.gradle.kts
new file mode 100644
index 000000000..d8b3ece32
--- /dev/null
+++ b/feature/myinfo/build.gradle.kts
@@ -0,0 +1,12 @@
+@Suppress("DSL_SCOPE_VIOLATION") // TODO: Remove once KTIJ-19369 is fixed
+plugins {
+ alias(libs.plugins.suwiki.android.feature.compose)
+}
+
+android {
+ namespace = "com.suwiki.feature.myinfo"
+}
+
+dependencies {
+ implementation(projects.domain.user)
+}
diff --git a/feature/myinfo/consumer-rules.pro b/feature/myinfo/consumer-rules.pro
new file mode 100644
index 000000000..e69de29bb
diff --git a/feature/myinfo/proguard-rules.pro b/feature/myinfo/proguard-rules.pro
new file mode 100644
index 000000000..481bb4348
--- /dev/null
+++ b/feature/myinfo/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/feature/myinfo/src/main/AndroidManifest.xml b/feature/myinfo/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..8bdb7e14b
--- /dev/null
+++ b/feature/myinfo/src/main/AndroidManifest.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoScreen.kt b/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoScreen.kt
new file mode 100644
index 000000000..33409b651
--- /dev/null
+++ b/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoScreen.kt
@@ -0,0 +1,28 @@
+package com.suwiki.feature.myinfo
+
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import com.suwiki.core.designsystem.theme.SuwikiTheme
+
+@Composable
+fun MyInfoScreen(
+ padding: PaddingValues,
+) {
+ Text(
+ modifier = Modifier.padding(padding),
+ text = "내 정보",
+ )
+}
+
+@Preview
+@Composable
+fun MyInfoScreenScreenPreview() {
+ SuwikiTheme {
+ MyInfoScreen(padding = PaddingValues(0.dp))
+ }
+}
diff --git a/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/navigation/LectureEvaluationNavigation.kt b/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/navigation/LectureEvaluationNavigation.kt
new file mode 100644
index 000000000..16d59ce58
--- /dev/null
+++ b/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/navigation/LectureEvaluationNavigation.kt
@@ -0,0 +1,24 @@
+package com.suwiki.feature.myinfo.navigation
+
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.navigation.NavController
+import androidx.navigation.NavGraphBuilder
+import androidx.navigation.NavOptions
+import androidx.navigation.compose.composable
+import com.suwiki.feature.myinfo.MyInfoScreen
+
+fun NavController.navigateMyInfo(navOptions: NavOptions) {
+ navigate(MyInfoRoute.route, navOptions)
+}
+
+fun NavGraphBuilder.myInfoNavGraph(
+ padding: PaddingValues,
+) {
+ composable(route = MyInfoRoute.route) {
+ MyInfoScreen(padding)
+ }
+}
+
+object MyInfoRoute {
+ const val route = "my-info"
+}
diff --git a/feature/navigator/.gitignore b/feature/navigator/.gitignore
new file mode 100644
index 000000000..42afabfd2
--- /dev/null
+++ b/feature/navigator/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/feature/navigator/build.gradle.kts b/feature/navigator/build.gradle.kts
new file mode 100644
index 000000000..255dbe957
--- /dev/null
+++ b/feature/navigator/build.gradle.kts
@@ -0,0 +1,21 @@
+@Suppress("DSL_SCOPE_VIOLATION") // TODO: Remove once KTIJ-19369 is fixed
+plugins {
+ alias(libs.plugins.suwiki.android.feature.compose)
+}
+
+android {
+ namespace = "com.suwiki.feature.navigator"
+}
+
+dependencies {
+ implementation(projects.feature.lectureevaluation.editor)
+ implementation(projects.feature.lectureevaluation.my)
+ implementation(projects.feature.lectureevaluation.viewerreporter)
+
+ implementation(projects.feature.login)
+ implementation(projects.feature.myinfo)
+ implementation(projects.feature.notice)
+ implementation(projects.feature.openmajor)
+ implementation(projects.feature.signup)
+ implementation(projects.feature.timetable)
+}
diff --git a/feature/navigator/consumer-rules.pro b/feature/navigator/consumer-rules.pro
new file mode 100644
index 000000000..e69de29bb
diff --git a/feature/navigator/proguard-rules.pro b/feature/navigator/proguard-rules.pro
new file mode 100644
index 000000000..481bb4348
--- /dev/null
+++ b/feature/navigator/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/feature/navigator/src/main/AndroidManifest.xml b/feature/navigator/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..ed5ceb6eb
--- /dev/null
+++ b/feature/navigator/src/main/AndroidManifest.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/feature/navigator/src/main/java/com/suwiki/feature/navigator/MainActivity.kt b/feature/navigator/src/main/java/com/suwiki/feature/navigator/MainActivity.kt
new file mode 100644
index 000000000..37526476e
--- /dev/null
+++ b/feature/navigator/src/main/java/com/suwiki/feature/navigator/MainActivity.kt
@@ -0,0 +1,49 @@
+package com.suwiki.feature.navigator
+
+import android.os.Bundle
+import androidx.activity.ComponentActivity
+import androidx.activity.compose.setContent
+import androidx.compose.foundation.layout.WindowInsets
+import androidx.compose.foundation.layout.WindowInsetsSides
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.only
+import androidx.compose.foundation.layout.systemBars
+import androidx.compose.foundation.layout.windowInsetsPadding
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.core.view.WindowCompat
+import com.suwiki.core.designsystem.theme.SuwikiTheme
+import dagger.hilt.android.AndroidEntryPoint
+
+@AndroidEntryPoint
+class MainActivity : ComponentActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ WindowCompat.setDecorFitsSystemWindows(window, false)
+
+ setContent {
+ SuwikiTheme {
+ MainScreen(
+ modifier = Modifier
+ .fillMaxSize()
+ .windowInsetsPadding(
+ WindowInsets.systemBars.only(
+ WindowInsetsSides.Vertical,
+ ),
+ ),
+ )
+ }
+ }
+ }
+}
+
+@Preview(showBackground = true)
+@Composable
+fun GreetingPreview() {
+ SuwikiTheme {
+ MainScreen()
+ }
+}
diff --git a/feature/navigator/src/main/java/com/suwiki/feature/navigator/MainNavigator.kt b/feature/navigator/src/main/java/com/suwiki/feature/navigator/MainNavigator.kt
new file mode 100644
index 000000000..291833e9d
--- /dev/null
+++ b/feature/navigator/src/main/java/com/suwiki/feature/navigator/MainNavigator.kt
@@ -0,0 +1,67 @@
+package com.suwiki.feature.navigator
+
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
+import androidx.navigation.NavDestination
+import androidx.navigation.NavGraph.Companion.findStartDestination
+import androidx.navigation.NavHostController
+import androidx.navigation.compose.currentBackStackEntryAsState
+import androidx.navigation.compose.rememberNavController
+import androidx.navigation.navOptions
+import com.suwiki.feature.lectureevaluation.viewerreporter.navigation.navigateLectureEvaluation
+import com.suwiki.feature.myinfo.navigation.navigateMyInfo
+import com.suwiki.feature.timetable.navigation.TimetableRoute
+import com.suwiki.feature.timetable.navigation.navigateTimetable
+
+internal class MainNavigator(
+ val navController: NavHostController,
+) {
+ private val currentDestination: NavDestination?
+ @Composable get() = navController
+ .currentBackStackEntryAsState().value?.destination
+
+ val startDestination = MainTab.TIMETABLE.route
+
+ val currentTab: MainTab?
+ @Composable get() = currentDestination
+ ?.route
+ ?.let(MainTab::find)
+
+ fun navigate(tab: MainTab) {
+ val navOptions = navOptions {
+ popUpTo(navController.graph.findStartDestination().id) {
+ saveState = true
+ }
+ launchSingleTop = true
+ restoreState = true
+ }
+
+ when (tab) {
+ MainTab.TIMETABLE -> navController.navigateTimetable(navOptions)
+ MainTab.LECTURE_EVALUATION -> navController.navigateLectureEvaluation(navOptions)
+ MainTab.MY_INFO -> navController.navigateMyInfo(navOptions)
+ }
+ }
+
+ fun popBackStackIfNotHome() {
+ if (!isSameCurrentDestination(TimetableRoute.route)) {
+ navController.popBackStack()
+ }
+ }
+
+ private fun isSameCurrentDestination(route: String) =
+ navController.currentDestination?.route == route
+
+ @Composable
+ fun shouldShowBottomBar(): Boolean {
+ val currentRoute = currentDestination?.route ?: return false
+ return currentRoute in MainTab
+ }
+}
+
+@Composable
+internal fun rememberMainNavigator(
+ navController: NavHostController = rememberNavController(),
+): MainNavigator = remember(navController) {
+ MainNavigator(navController)
+}
diff --git a/feature/navigator/src/main/java/com/suwiki/feature/navigator/MainScreen.kt b/feature/navigator/src/main/java/com/suwiki/feature/navigator/MainScreen.kt
new file mode 100644
index 000000000..189ba451a
--- /dev/null
+++ b/feature/navigator/src/main/java/com/suwiki/feature/navigator/MainScreen.kt
@@ -0,0 +1,187 @@
+package com.suwiki.feature.navigator
+
+import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.animation.fadeIn
+import androidx.compose.animation.fadeOut
+import androidx.compose.animation.slideIn
+import androidx.compose.animation.slideOut
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.RowScope
+import androidx.compose.foundation.layout.fillMaxHeight
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.Icon
+import androidx.compose.material3.Scaffold
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.IntOffset
+import androidx.compose.ui.unit.dp
+import androidx.navigation.compose.NavHost
+import com.suwiki.core.designsystem.component.toast.SuwikiToast
+import com.suwiki.core.designsystem.shadow.bottomNavigationShadow
+import com.suwiki.core.designsystem.theme.GrayDA
+import com.suwiki.core.designsystem.theme.Primary
+import com.suwiki.core.designsystem.theme.SuwikiTheme
+import com.suwiki.core.designsystem.theme.White
+import com.suwiki.core.ui.extension.suwikiClickable
+import com.suwiki.feature.lectureevaluation.viewerreporter.navigation.lectureEvaluationNavGraph
+import com.suwiki.feature.myinfo.navigation.myInfoNavGraph
+import com.suwiki.feature.timetable.navigation.timetableNavGraph
+import kotlinx.collections.immutable.ImmutableList
+import kotlinx.collections.immutable.toImmutableList
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.sync.Mutex
+
+private const val SHOW_TOAST_LENGTH = 2000L
+val mutex = Mutex()
+
+@Composable
+internal fun MainScreen(
+ modifier: Modifier = Modifier,
+ navigator: MainNavigator = rememberMainNavigator(),
+) {
+ val coroutineScope = rememberCoroutineScope()
+
+ var toastMessage: String? by remember { mutableStateOf(null) }
+ var toastVisible by remember { mutableStateOf(false) }
+
+ // TODO REMOVE
+ @Suppress("detekt:UnusedPrivateProperty")
+ val onShowToast: (message: String) -> Unit = { message ->
+ coroutineScope.launch {
+ mutex.lock()
+ toastMessage = message
+ }
+ }
+
+ LaunchedEffect(key1 = toastMessage) {
+ if (toastMessage == null) return@LaunchedEffect
+
+ toastVisible = true
+ delay(SHOW_TOAST_LENGTH)
+ toastVisible = false
+ if (mutex.isLocked) mutex.unlock()
+ }
+
+ Scaffold(
+ modifier = modifier,
+ content = { innerPadding ->
+ NavHost(
+ navController = navigator.navController,
+ startDestination = navigator.startDestination,
+ ) {
+ timetableNavGraph(
+ padding = innerPadding,
+ )
+
+ lectureEvaluationNavGraph(
+ padding = innerPadding,
+ )
+
+ myInfoNavGraph(
+ padding = innerPadding,
+ )
+ }
+
+ SuwikiToast(
+ visible = toastVisible,
+ message = toastMessage ?: "",
+ )
+ },
+ bottomBar = {
+ MainBottomBar(
+ visible = navigator.shouldShowBottomBar(),
+ tabs = MainTab.entries.toImmutableList(),
+ currentTab = navigator.currentTab,
+ onTabSelected = navigator::navigate,
+ )
+ },
+ )
+}
+
+@Preview
+@Composable
+fun MainScreenPreview() {
+ SuwikiTheme {
+ MainScreen()
+ }
+}
+
+@Composable
+private fun MainBottomBar(
+ visible: Boolean,
+ tabs: ImmutableList,
+ currentTab: MainTab?,
+ onTabSelected: (MainTab) -> Unit,
+) {
+ AnimatedVisibility(
+ visible = visible,
+ enter = fadeIn() + slideIn { IntOffset(0, it.height) },
+ exit = fadeOut() + slideOut { IntOffset(0, it.height) },
+ ) {
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .height(56.dp)
+ .bottomNavigationShadow()
+ .background(
+ color = White,
+ shape = RoundedCornerShape(topStart = 10.dp, topEnd = 10.dp),
+ ),
+ horizontalArrangement = Arrangement.spacedBy(8.dp),
+ ) {
+ tabs.forEach { tab ->
+ MainBottomBarItem(
+ tab = tab,
+ selected = tab == currentTab,
+ onClick = { onTabSelected(tab) },
+ )
+ }
+ }
+ }
+}
+
+@Composable
+private fun RowScope.MainBottomBarItem(
+ tab: MainTab,
+ selected: Boolean,
+ onClick: () -> Unit,
+) {
+ Box(
+ modifier = Modifier
+ .weight(1f)
+ .fillMaxHeight()
+ .suwikiClickable(
+ rippleEnabled = false,
+ onClick = onClick,
+ ),
+ contentAlignment = Alignment.Center,
+ ) {
+ Icon(
+ painter = painterResource(tab.iconResId),
+ contentDescription = tab.contentDescription,
+ tint = if (selected) {
+ Primary
+ } else {
+ GrayDA
+ },
+ modifier = Modifier.size(24.dp),
+ )
+ }
+}
diff --git a/feature/navigator/src/main/java/com/suwiki/feature/navigator/MainTab.kt b/feature/navigator/src/main/java/com/suwiki/feature/navigator/MainTab.kt
new file mode 100644
index 000000000..2c04134bf
--- /dev/null
+++ b/feature/navigator/src/main/java/com/suwiki/feature/navigator/MainTab.kt
@@ -0,0 +1,38 @@
+package com.suwiki.feature.navigator
+
+import com.suwiki.feature.lectureevaluation.viewerreporter.navigation.LectureEvaluationRoute
+import com.suwiki.feature.myinfo.navigation.MyInfoRoute
+import com.suwiki.feature.timetable.navigation.TimetableRoute
+
+internal enum class MainTab(
+ val iconResId: Int,
+ internal val contentDescription: String,
+ val route: String,
+) {
+ TIMETABLE(
+ iconResId = R.drawable.ic_bottom_navigation_timetable,
+ contentDescription = "시간표",
+ route = TimetableRoute.route,
+ ),
+ LECTURE_EVALUATION(
+ iconResId = R.drawable.ic_bottom_navigation_evaluation,
+ contentDescription = "강의평가",
+ route = LectureEvaluationRoute.route,
+ ),
+ MY_INFO(
+ iconResId = R.drawable.ic_bottom_navigation_myinfo,
+ contentDescription = "내 정보",
+ route = MyInfoRoute.route,
+ ),
+ ;
+
+ companion object {
+ operator fun contains(route: String): Boolean {
+ return entries.map { it.route }.contains(route)
+ }
+
+ fun find(route: String): MainTab? {
+ return entries.find { it.route == route }
+ }
+ }
+}
diff --git a/core/designsystem/src/main/res/drawable/ic_bottom_navigation_evaluation.xml b/feature/navigator/src/main/res/drawable/ic_bottom_navigation_evaluation.xml
similarity index 100%
rename from core/designsystem/src/main/res/drawable/ic_bottom_navigation_evaluation.xml
rename to feature/navigator/src/main/res/drawable/ic_bottom_navigation_evaluation.xml
diff --git a/feature/navigator/src/main/res/drawable/ic_bottom_navigation_myinfo.xml b/feature/navigator/src/main/res/drawable/ic_bottom_navigation_myinfo.xml
new file mode 100644
index 000000000..f0fe1db0f
--- /dev/null
+++ b/feature/navigator/src/main/res/drawable/ic_bottom_navigation_myinfo.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/feature/navigator/src/main/res/drawable/ic_bottom_navigation_timetable.xml b/feature/navigator/src/main/res/drawable/ic_bottom_navigation_timetable.xml
new file mode 100644
index 000000000..8c28ef9fb
--- /dev/null
+++ b/feature/navigator/src/main/res/drawable/ic_bottom_navigation_timetable.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/feature/navigator/src/main/res/values/strings.xml b/feature/navigator/src/main/res/values/strings.xml
new file mode 100644
index 000000000..b4075cad7
--- /dev/null
+++ b/feature/navigator/src/main/res/values/strings.xml
@@ -0,0 +1,4 @@
+
+
+ SUWIKI
+
diff --git a/feature/notice/.gitignore b/feature/notice/.gitignore
new file mode 100644
index 000000000..42afabfd2
--- /dev/null
+++ b/feature/notice/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/feature/notice/build.gradle.kts b/feature/notice/build.gradle.kts
new file mode 100644
index 000000000..879e134d7
--- /dev/null
+++ b/feature/notice/build.gradle.kts
@@ -0,0 +1,12 @@
+@Suppress("DSL_SCOPE_VIOLATION") // TODO: Remove once KTIJ-19369 is fixed
+plugins {
+ alias(libs.plugins.suwiki.android.feature.compose)
+}
+
+android {
+ namespace = "com.suwiki.feature.notice"
+}
+
+dependencies {
+ implementation(projects.domain.notice)
+}
diff --git a/feature/notice/consumer-rules.pro b/feature/notice/consumer-rules.pro
new file mode 100644
index 000000000..e69de29bb
diff --git a/feature/notice/proguard-rules.pro b/feature/notice/proguard-rules.pro
new file mode 100644
index 000000000..481bb4348
--- /dev/null
+++ b/feature/notice/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/feature/notice/src/main/AndroidManifest.xml b/feature/notice/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..8bdb7e14b
--- /dev/null
+++ b/feature/notice/src/main/AndroidManifest.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/feature/openmajor/.gitignore b/feature/openmajor/.gitignore
new file mode 100644
index 000000000..42afabfd2
--- /dev/null
+++ b/feature/openmajor/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/feature/openmajor/build.gradle.kts b/feature/openmajor/build.gradle.kts
new file mode 100644
index 000000000..a959563bb
--- /dev/null
+++ b/feature/openmajor/build.gradle.kts
@@ -0,0 +1,12 @@
+@Suppress("DSL_SCOPE_VIOLATION") // TODO: Remove once KTIJ-19369 is fixed
+plugins {
+ alias(libs.plugins.suwiki.android.feature.compose)
+}
+
+android {
+ namespace = "com.suwiki.feature.openmajor"
+}
+
+dependencies {
+ implementation(projects.domain.openmajor)
+}
diff --git a/feature/openmajor/consumer-rules.pro b/feature/openmajor/consumer-rules.pro
new file mode 100644
index 000000000..e69de29bb
diff --git a/feature/openmajor/proguard-rules.pro b/feature/openmajor/proguard-rules.pro
new file mode 100644
index 000000000..481bb4348
--- /dev/null
+++ b/feature/openmajor/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/feature/openmajor/src/main/AndroidManifest.xml b/feature/openmajor/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..8bdb7e14b
--- /dev/null
+++ b/feature/openmajor/src/main/AndroidManifest.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/feature/signup/.gitignore b/feature/signup/.gitignore
new file mode 100644
index 000000000..42afabfd2
--- /dev/null
+++ b/feature/signup/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/feature/signup/build.gradle.kts b/feature/signup/build.gradle.kts
new file mode 100644
index 000000000..f312e223f
--- /dev/null
+++ b/feature/signup/build.gradle.kts
@@ -0,0 +1,12 @@
+@Suppress("DSL_SCOPE_VIOLATION") // TODO: Remove once KTIJ-19369 is fixed
+plugins {
+ alias(libs.plugins.suwiki.android.feature.compose)
+}
+
+android {
+ namespace = "com.suwiki.feature.signup"
+}
+
+dependencies {
+ implementation(projects.domain.signup)
+}
diff --git a/feature/signup/consumer-rules.pro b/feature/signup/consumer-rules.pro
new file mode 100644
index 000000000..e69de29bb
diff --git a/feature/signup/proguard-rules.pro b/feature/signup/proguard-rules.pro
new file mode 100644
index 000000000..481bb4348
--- /dev/null
+++ b/feature/signup/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/feature/signup/src/main/AndroidManifest.xml b/feature/signup/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..8bdb7e14b
--- /dev/null
+++ b/feature/signup/src/main/AndroidManifest.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/feature/timetable/.gitignore b/feature/timetable/.gitignore
new file mode 100644
index 000000000..42afabfd2
--- /dev/null
+++ b/feature/timetable/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/feature/timetable/build.gradle.kts b/feature/timetable/build.gradle.kts
new file mode 100644
index 000000000..1b4afcff3
--- /dev/null
+++ b/feature/timetable/build.gradle.kts
@@ -0,0 +1,12 @@
+@Suppress("DSL_SCOPE_VIOLATION") // TODO: Remove once KTIJ-19369 is fixed
+plugins {
+ alias(libs.plugins.suwiki.android.feature.compose)
+}
+
+android {
+ namespace = "com.suwiki.feature.timetable"
+}
+
+dependencies {
+ implementation(projects.domain.timetable)
+}
diff --git a/feature/timetable/consumer-rules.pro b/feature/timetable/consumer-rules.pro
new file mode 100644
index 000000000..e69de29bb
diff --git a/feature/timetable/proguard-rules.pro b/feature/timetable/proguard-rules.pro
new file mode 100644
index 000000000..481bb4348
--- /dev/null
+++ b/feature/timetable/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/feature/timetable/src/main/AndroidManifest.xml b/feature/timetable/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..8bdb7e14b
--- /dev/null
+++ b/feature/timetable/src/main/AndroidManifest.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/feature/timetable/src/main/java/com/suwiki/feature/timetable/TimetableScreen.kt b/feature/timetable/src/main/java/com/suwiki/feature/timetable/TimetableScreen.kt
new file mode 100644
index 000000000..5b5064cb1
--- /dev/null
+++ b/feature/timetable/src/main/java/com/suwiki/feature/timetable/TimetableScreen.kt
@@ -0,0 +1,28 @@
+package com.suwiki.feature.timetable
+
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import com.suwiki.core.designsystem.theme.SuwikiTheme
+
+@Composable
+fun TimetableScreen(
+ padding: PaddingValues,
+) {
+ Text(
+ modifier = Modifier.padding(padding),
+ text = "시간표",
+ )
+}
+
+@Preview
+@Composable
+fun TimetableScreenPreview() {
+ SuwikiTheme {
+ TimetableScreen(padding = PaddingValues(0.dp))
+ }
+}
diff --git a/feature/timetable/src/main/java/com/suwiki/feature/timetable/navigation/TimetableNavigation.kt b/feature/timetable/src/main/java/com/suwiki/feature/timetable/navigation/TimetableNavigation.kt
new file mode 100644
index 000000000..8d6f1b591
--- /dev/null
+++ b/feature/timetable/src/main/java/com/suwiki/feature/timetable/navigation/TimetableNavigation.kt
@@ -0,0 +1,24 @@
+package com.suwiki.feature.timetable.navigation
+
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.navigation.NavController
+import androidx.navigation.NavGraphBuilder
+import androidx.navigation.NavOptions
+import androidx.navigation.compose.composable
+import com.suwiki.feature.timetable.TimetableScreen
+
+fun NavController.navigateTimetable(navOptions: NavOptions) {
+ navigate(TimetableRoute.route, navOptions)
+}
+
+fun NavGraphBuilder.timetableNavGraph(
+ padding: PaddingValues,
+) {
+ composable(route = TimetableRoute.route) {
+ TimetableScreen(padding)
+ }
+}
+
+object TimetableRoute {
+ const val route = "timetable"
+}
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 8893710bf..033290c34 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -5,7 +5,8 @@ junit4 = "4.13.2"
espresso = "3.4.0"
ksp = "1.9.10-1.0.13"
google-service = "4.3.15"
-firebase-bom = "32.3.1"
+firebase-bom = "32.7.0"
+firebase-crashlytics = "2.9.9"
compose-compiler = "1.5.3"
# compose-bom = "2023.09.00"
@@ -15,6 +16,8 @@ activity-compose = "1.7.2"
compose-stable-marker = "1.0.3"
androidx-hilt-navigation-compose = "1.0.0"
+orbit = "6.1.0"
+
androidx-app-compat = "1.6.1"
androidx-core = "1.12.0"
androidx-lifecycle = "2.6.2"
@@ -30,6 +33,8 @@ kotlin = "1.9.10"
kotlinx-coroutines = "1.7.3"
kotlinx-serialization-json = "1.5.1"
kotlinx-datetime = "0.4.0"
+kotlinx-immutable = "0.3.6"
+
ktlint = "11.5.1"
detekt = "1.23.1"
@@ -71,6 +76,7 @@ android-library = { id = "com.android.library", version.ref = "android-gradle-pl
hilt = { id = "com.google.dagger.hilt.android", version.ref = "hilt" }
google-services = { id = "com.google.gms.google-services", version.ref = "google-service" }
protobuf = { id = "com.google.protobuf", version.ref = "protobuf-plugin" }
+firebase-crashlytics = { id = "com.google.firebase.crashlytics", version.ref = "firebase-crashlytics" }
# Plugins defined by this project
suwiki-android-application = { id = "suwiki.android.application", version = "unspecified" }
@@ -114,6 +120,11 @@ navigation-compose = { group = "androidx.navigation", name = "navigation-compose
hilt-navigation-compose = { group = "androidx.hilt", name = "hilt-navigation-compose", version.ref = "androidx-hilt-navigation-compose" }
compose-stable-marker = { group = "com.github.skydoves", name = "compose-stable-marker", version.ref = "compose-stable-marker" }
+orbit-core = { group = "org.orbit-mvi", name = "orbit-core", version.ref = "orbit" }
+orbit-viewmodel = { group = "org.orbit-mvi", name = "orbit-viewmodel", version.ref = "orbit" }
+orbit-compose = { group = "org.orbit-mvi", name = "orbit-compose", version.ref = "orbit" }
+orbit-test = { group = "org.orbit-mvi", name = "orbit-test", version.ref = "orbit" }
+
hilt-android = { group = "com.google.dagger", name = "hilt-android", version.ref = "hilt" }
hilt-compiler = { group = "com.google.dagger", name = "hilt-android-compiler", version.ref = "hilt" }
hilt-core = { group = "com.google.dagger", name = "hilt-core", version.ref = "hilt" }
@@ -124,6 +135,7 @@ kotlinx-coroutines-android = { group = "org.jetbrains.kotlinx", name = "kotlinx-
kotlinx-coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" }
kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinx-serialization-json" }
kotlinx-datetime = { group = "org.jetbrains.kotlinx", name = "kotlinx-datetime", version.ref = "kotlinx-datetime" }
+kotlinx-immutable = { group = "org.jetbrains.kotlinx", name = "kotlinx-collections-immutable", version.ref = "kotlinx-immutable" }
retrofit-core = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "retrofit" }
retrofit-kotlin-serialization = { group = "com.jakewharton.retrofit", name = "retrofit2-kotlinx-serialization-converter", version.ref = "retrofit-kotlinx-serialization-json" }
@@ -153,6 +165,7 @@ encrypted-datastore-preference-security = { group = "tech.thdev", name = "useful
firebase-bom = { group = "com.google.firebase", name = "firebase-bom", version.ref = "firebase-bom" }
firebase-analytics = { group = "com.google.firebase", name = "firebase-analytics-ktx" }
+firebase-crashlytics = { group = "com.google.firebase", name = "firebase-crashlytics-ktx" }
firebase-database = { group = "com.google.firebase", name = "firebase-database-ktx" }
ted-permission = { group = "io.github.ParkSangGwon", name = "tedpermission-normal", version.ref = "ted-permission" }
@@ -179,4 +192,6 @@ androidx-lifecycle = ["androidx-lifecycle-runtime-ktx", "androidx-lifecycle-view
androidx-navigation = ["navigation-fragment-ktx", "navigation-ui-ktx"]
coroutine = ["kotlinx-coroutines-android", "kotlinx-coroutines-core"]
compose = ["ui", "ui-graphics", "ui-tooling-preview", "material3-compose", "coil-compose", "ui-foundation", "activity-compose", "lifecycle-compose", "navigation-compose"]
-compose-debug = ["ui-tooling", "ui-test-manifest" ]
+compose-debug = ["ui-tooling", "ui-test-manifest"]
+
+orbit = ["orbit-core", "orbit-viewmodel", "orbit-compose"]
diff --git a/gradlew b/gradlew
old mode 100644
new mode 100755
diff --git a/local/login/.gitignore b/local/login/.gitignore
new file mode 100644
index 000000000..42afabfd2
--- /dev/null
+++ b/local/login/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/local/login/build.gradle.kts b/local/login/build.gradle.kts
new file mode 100644
index 000000000..02b7e06a9
--- /dev/null
+++ b/local/login/build.gradle.kts
@@ -0,0 +1,20 @@
+@Suppress("DSL_SCOPE_VIOLATION") // TODO: Remove once KTIJ-19369 is fixed
+plugins {
+ alias(libs.plugins.suwiki.android.library)
+ alias(libs.plugins.suwiki.android.hilt)
+}
+
+android {
+ namespace = "com.suwiki.local.login"
+}
+
+dependencies {
+ implementation(projects.core.model)
+ implementation(projects.data.login)
+ implementation(projects.core.security)
+
+ implementation(libs.bundles.coroutine)
+
+ testImplementation(libs.junit4)
+ androidTestImplementation(libs.junit)
+}
diff --git a/local/login/consumer-rules.pro b/local/login/consumer-rules.pro
new file mode 100644
index 000000000..e69de29bb
diff --git a/local/login/proguard-rules.pro b/local/login/proguard-rules.pro
new file mode 100644
index 000000000..481bb4348
--- /dev/null
+++ b/local/login/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/local/login/src/main/AndroidManifest.xml b/local/login/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..8bdb7e14b
--- /dev/null
+++ b/local/login/src/main/AndroidManifest.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/local/login/src/main/java/com/suwiki/local/login/datasource/LocalLoginDataSourceImpl.kt b/local/login/src/main/java/com/suwiki/local/login/datasource/LocalLoginDataSourceImpl.kt
new file mode 100644
index 000000000..a575aefaa
--- /dev/null
+++ b/local/login/src/main/java/com/suwiki/local/login/datasource/LocalLoginDataSourceImpl.kt
@@ -0,0 +1,18 @@
+package com.suwiki.local.login.datasource
+
+import com.suwiki.core.model.user.Token
+import com.suwiki.core.security.SecurityPreferences
+import com.suwiki.data.login.datasource.LocalLoginDataSource
+import javax.inject.Inject
+
+class LocalLoginDataSourceImpl @Inject constructor(
+ private val securityPreferences: SecurityPreferences,
+) : LocalLoginDataSource {
+
+ override suspend fun setToken(token: Token) {
+ token.run {
+ securityPreferences.setAccessToken(accessToken)
+ securityPreferences.setRefreshToken(refreshToken)
+ }
+ }
+}
diff --git a/local/login/src/main/java/com/suwiki/local/login/di/LocalDataSourceModule.kt b/local/login/src/main/java/com/suwiki/local/login/di/LocalDataSourceModule.kt
new file mode 100644
index 000000000..9287a674f
--- /dev/null
+++ b/local/login/src/main/java/com/suwiki/local/login/di/LocalDataSourceModule.kt
@@ -0,0 +1,20 @@
+package com.suwiki.local.login.di
+
+import com.suwiki.data.login.datasource.LocalLoginDataSource
+import com.suwiki.local.login.datasource.LocalLoginDataSourceImpl
+import dagger.Binds
+import dagger.Module
+import dagger.hilt.InstallIn
+import dagger.hilt.components.SingletonComponent
+import javax.inject.Singleton
+
+@Module
+@InstallIn(SingletonComponent::class)
+abstract class LocalDataSourceModule {
+
+ @Singleton
+ @Binds
+ abstract fun bindLocalLoginDataSource(
+ localLoginDataSourceImpl: LocalLoginDataSourceImpl,
+ ): LocalLoginDataSource
+}
diff --git a/local/user/src/main/java/com/suwiki/local/user/datasource/LocalUserStorageDataSourceImpl.kt b/local/user/src/main/java/com/suwiki/local/user/datasource/LocalUserDataSourceImpl.kt
similarity index 70%
rename from local/user/src/main/java/com/suwiki/local/user/datasource/LocalUserStorageDataSourceImpl.kt
rename to local/user/src/main/java/com/suwiki/local/user/datasource/LocalUserDataSourceImpl.kt
index 5937e9e79..abed5497b 100644
--- a/local/user/src/main/java/com/suwiki/local/user/datasource/LocalUserStorageDataSourceImpl.kt
+++ b/local/user/src/main/java/com/suwiki/local/user/datasource/LocalUserDataSourceImpl.kt
@@ -8,16 +8,27 @@ import com.suwiki.core.model.user.DEFAULT_USER_POINT
import com.suwiki.core.model.user.DEFAULT_USER_VIEW_EXAM
import com.suwiki.core.model.user.DEFAULT_USER_WRITTEN_EVALUATION
import com.suwiki.core.model.user.DEFAULT_USER_WRITTEN_EXAM
-import com.suwiki.core.model.user.Token
import com.suwiki.core.model.user.User
-import com.suwiki.core.security.SecurityPreferences
-import com.suwiki.data.user.datasource.LocalUserStorageDataSource
+import com.suwiki.data.user.datasource.LocalUserDataSource
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.map
import javax.inject.Inject
-class LocalUserStorageDataSourceImpl @Inject constructor(
+class LocalUserDataSourceImpl @Inject constructor(
private val dataStore: DataStore,
- private val securityPreferences: SecurityPreferences,
-) : LocalUserStorageDataSource {
+) : LocalUserDataSource {
+
+ override val user: Flow
+ get() = dataStore.data.map {
+ User(
+ userId = it.userId,
+ email = it.email,
+ point = it.point,
+ writtenEvaluation = it.writtenEvaluation,
+ writtenExam = it.writtenExam,
+ viewExam = it.viewExam,
+ )
+ }
override suspend fun setUserInfo(user: User) {
user.run {
@@ -35,15 +46,7 @@ class LocalUserStorageDataSourceImpl @Inject constructor(
}
}
- override suspend fun setToken(token: Token) {
- token.run {
- securityPreferences.setAccessToken(accessToken)
- securityPreferences.setRefreshToken(refreshToken)
- }
- }
-
- override suspend fun clearUserInfoAndToken() {
- securityPreferences.clearAll()
+ override suspend fun clearUserInfo() {
dataStore.updateData { userPref ->
userPref
.toBuilder()
diff --git a/local/user/src/main/java/com/suwiki/local/user/datasource/LocalUserProviderDataSourceImpl.kt b/local/user/src/main/java/com/suwiki/local/user/datasource/LocalUserProviderDataSourceImpl.kt
deleted file mode 100644
index b947ce00f..000000000
--- a/local/user/src/main/java/com/suwiki/local/user/datasource/LocalUserProviderDataSourceImpl.kt
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.suwiki.local.user.datasource
-
-import androidx.datastore.core.DataStore
-import com.suwiki.core.database.UserPreference
-import com.suwiki.core.model.user.User
-import com.suwiki.data.user.datasource.LocalUserProviderDataSource
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.map
-import javax.inject.Inject
-
-class LocalUserProviderDataSourceImpl @Inject constructor(
- private val dataStore: DataStore,
-) : LocalUserProviderDataSource {
-
- override val user: Flow
- get() = dataStore.data.map {
- User(
- userId = it.userId,
- email = it.email,
- point = it.point,
- writtenEvaluation = it.writtenEvaluation,
- writtenExam = it.writtenExam,
- viewExam = it.viewExam,
- )
- }
-}
diff --git a/local/user/src/main/java/com/suwiki/local/user/di/LocalDataSourceModule.kt b/local/user/src/main/java/com/suwiki/local/user/di/LocalDataSourceModule.kt
index 50d35e87b..05d9daf07 100644
--- a/local/user/src/main/java/com/suwiki/local/user/di/LocalDataSourceModule.kt
+++ b/local/user/src/main/java/com/suwiki/local/user/di/LocalDataSourceModule.kt
@@ -1,9 +1,7 @@
package com.suwiki.local.user.di
-import com.suwiki.data.user.datasource.LocalUserProviderDataSource
-import com.suwiki.data.user.datasource.LocalUserStorageDataSource
-import com.suwiki.local.user.datasource.LocalUserProviderDataSourceImpl
-import com.suwiki.local.user.datasource.LocalUserStorageDataSourceImpl
+import com.suwiki.data.user.datasource.LocalUserDataSource
+import com.suwiki.local.user.datasource.LocalUserDataSourceImpl
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
@@ -17,12 +15,6 @@ abstract class LocalDataSourceModule {
@Singleton
@Binds
abstract fun bindLocalUserProviderDataSource(
- localUserProviderDataSourceImpl: LocalUserProviderDataSourceImpl,
- ): LocalUserProviderDataSource
-
- @Singleton
- @Binds
- abstract fun bindLocalUserStorageDataSource(
- localUserStorageDataSourceImpl: LocalUserStorageDataSourceImpl,
- ): LocalUserStorageDataSource
+ localUserProviderDataSourceImpl: LocalUserDataSourceImpl,
+ ): LocalUserDataSource
}
diff --git a/presentation/build.gradle.kts b/presentation/build.gradle.kts
deleted file mode 100644
index 0970e4e9e..000000000
--- a/presentation/build.gradle.kts
+++ /dev/null
@@ -1,15 +0,0 @@
-plugins {
- id("suwiki.android.feature.compose")
-}
-
-android {
- namespace = "com.mangbaam.presentation"
-}
-
-dependencies {
- implementation(projects.core.model)
-
- implementation(projects.domain.openmajor)
- implementation(projects.domain.signup)
- implementation(projects.domain.user)
-}
diff --git a/presentation/src/androidTest/java/com/mangbaam/presentation/ExampleInstrumentedTest.kt b/presentation/src/androidTest/java/com/mangbaam/presentation/ExampleInstrumentedTest.kt
deleted file mode 100644
index 8c59cc8e9..000000000
--- a/presentation/src/androidTest/java/com/mangbaam/presentation/ExampleInstrumentedTest.kt
+++ /dev/null
@@ -1,22 +0,0 @@
-package com.mangbaam.presentation
-
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.platform.app.InstrumentationRegistry
-import junit.framework.TestCase.assertEquals
-import org.junit.Test
-import org.junit.runner.RunWith
-
-/**
- * Instrumented test, which will execute on an Android device.
- *
- * See [testing documentation](http://d.android.com/tools/testing).
- */
-@RunWith(AndroidJUnit4::class)
-class ExampleInstrumentedTest {
- @Test
- fun useAppContext() {
- // Context of the app under test.
- val appContext = InstrumentationRegistry.getInstrumentation().targetContext
- assertEquals("com.mangbaam.presentation.test", appContext.packageName)
- }
-}
diff --git a/presentation/src/main/AndroidManifest.xml b/presentation/src/main/AndroidManifest.xml
deleted file mode 100644
index bd42ef156..000000000
--- a/presentation/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/presentation/src/main/java/com/mangbaam/presentation/MainActivity.kt b/presentation/src/main/java/com/mangbaam/presentation/MainActivity.kt
deleted file mode 100644
index ad2c2fc69..000000000
--- a/presentation/src/main/java/com/mangbaam/presentation/MainActivity.kt
+++ /dev/null
@@ -1,64 +0,0 @@
-package com.mangbaam.presentation
-
-import android.os.Bundle
-import androidx.activity.ComponentActivity
-import androidx.activity.compose.setContent
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Surface
-import androidx.compose.material3.Text
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.tooling.preview.Preview
-import com.mangbaam.presentation.ui.theme.UswtimetableTheme
-import com.suwiki.domain.openmajor.usecase.GetOpenMajorListUseCase
-import dagger.hilt.android.AndroidEntryPoint
-import kotlinx.coroutines.flow.collect
-import timber.log.Timber
-import javax.inject.Inject
-
-@AndroidEntryPoint
-class MainActivity : ComponentActivity() {
-
- @Inject
- lateinit var useCase1: GetOpenMajorListUseCase
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContent {
- UswtimetableTheme {
- // A surface container using the 'background' color from the theme
- Surface(
- modifier = Modifier.fillMaxSize(),
- color = MaterialTheme.colorScheme.background,
- ) {
- Greeting(name = "Suwiki", useCase1 = useCase1)
- }
- }
- }
- }
-}
-
-@Composable
-fun Greeting(
- name: String,
- modifier: Modifier = Modifier,
- useCase1: GetOpenMajorListUseCase,
-) {
- LaunchedEffect(key1 = Unit) {
- useCase1().collect { Timber.d("$it") }
- }
-
- Text(
- text = "Hello $name!",
- modifier = modifier,
- )
-}
-
-@Preview(showBackground = true)
-@Composable
-fun GreetingPreview() {
- UswtimetableTheme {
- }
-}
diff --git a/presentation/src/main/java/com/mangbaam/presentation/common/CommonRecyclerViewState.kt b/presentation/src/main/java/com/mangbaam/presentation/common/CommonRecyclerViewState.kt
deleted file mode 100644
index 321e957c6..000000000
--- a/presentation/src/main/java/com/mangbaam/presentation/common/CommonRecyclerViewState.kt
+++ /dev/null
@@ -1,34 +0,0 @@
-package com.mangbaam.presentation.common
-
-class CommonRecyclerViewState {
- private val _items = mutableListOf()
- val items: List
- get() = _items.toList()
-
- var loading: Boolean = false
- set(value) = run {
- when (value) {
- true -> {
- if (items.isEmpty() || items.last() != null) {
- _items.add(null)
- }
- }
-
- false -> {
- if (items.isNotEmpty() && items.last() == null) {
- _items.removeLast()
- }
- }
- }
- field = value
- }
-
- fun setItems(items: List) {
- _items.removeAll { true }
- _items.addAll(items)
- }
-
- fun addItems(items: List) {
- _items.addAll(items)
- }
-}
diff --git a/presentation/src/main/java/com/mangbaam/presentation/extension/Activity.kt b/presentation/src/main/java/com/mangbaam/presentation/extension/Activity.kt
deleted file mode 100644
index ec16769a3..000000000
--- a/presentation/src/main/java/com/mangbaam/presentation/extension/Activity.kt
+++ /dev/null
@@ -1,33 +0,0 @@
-package com.mangbaam.presentation.extension
-
-import android.app.Activity
-import android.content.Intent
-import android.view.View
-import android.view.inputmethod.InputMethodManager
-import android.widget.Toast
-import androidx.annotation.StringRes
-import androidx.core.content.ContextCompat
-
-inline fun Activity.startActivity(
- finishCallingActivity: Boolean = false,
- noinline block: (Intent.() -> Unit)? = null,
-) {
- val intent = Intent(this, T::class.java)
- block?.let { it(intent) }
- startActivity(intent)
- if (finishCallingActivity) finish()
-}
-
-fun Activity.toast(message: String, duration: Int = Toast.LENGTH_SHORT) {
- Toast.makeText(this, message, duration).show()
-}
-
-fun Activity.toast(@StringRes message: Int, duration: Int = Toast.LENGTH_SHORT) {
- Toast.makeText(this, message, duration).show()
-}
-
-fun Activity.hideKeyboard() {
- val imm = ContextCompat.getSystemService(this, InputMethodManager::class.java) ?: return
- val view = currentFocus ?: View(this)
- imm.hideSoftInputFromWindow(view.windowToken, InputMethodManager.HIDE_NOT_ALWAYS)
-}
diff --git a/presentation/src/main/java/com/mangbaam/presentation/extension/Fragment.kt b/presentation/src/main/java/com/mangbaam/presentation/extension/Fragment.kt
deleted file mode 100644
index c1e386131..000000000
--- a/presentation/src/main/java/com/mangbaam/presentation/extension/Fragment.kt
+++ /dev/null
@@ -1,25 +0,0 @@
-package com.mangbaam.presentation.extension
-
-import android.app.Activity
-import android.content.Intent
-import android.widget.Toast
-import androidx.annotation.StringRes
-import androidx.fragment.app.Fragment
-
-inline fun Fragment.startActivity(
- finishCallingActivity: Boolean = false,
- noinline block: (Intent.() -> Unit)? = null,
-) {
- val intent = Intent(requireContext(), T::class.java)
- block?.let { it(intent) }
- startActivity(intent)
- if (finishCallingActivity) requireActivity().finish()
-}
-
-fun Fragment.toast(message: String, duration: Int = Toast.LENGTH_SHORT) {
- Toast.makeText(requireContext(), message, duration).show()
-}
-
-fun Fragment.toast(@StringRes message: Int, duration: Int = Toast.LENGTH_SHORT) {
- Toast.makeText(requireContext(), message, duration).show()
-}
diff --git a/presentation/src/main/java/com/mangbaam/presentation/ui/theme/Color.kt b/presentation/src/main/java/com/mangbaam/presentation/ui/theme/Color.kt
deleted file mode 100644
index db8dac3ad..000000000
--- a/presentation/src/main/java/com/mangbaam/presentation/ui/theme/Color.kt
+++ /dev/null
@@ -1,11 +0,0 @@
-package com.mangbaam.presentation.ui.theme
-
-import androidx.compose.ui.graphics.Color
-
-val Purple80 = Color(0xFFD0BCFF)
-val PurpleGrey80 = Color(0xFFCCC2DC)
-val Pink80 = Color(0xFFEFB8C8)
-
-val Purple40 = Color(0xFF6650a4)
-val PurpleGrey40 = Color(0xFF625b71)
-val Pink40 = Color(0xFF7D5260)
diff --git a/presentation/src/main/java/com/mangbaam/presentation/ui/theme/Theme.kt b/presentation/src/main/java/com/mangbaam/presentation/ui/theme/Theme.kt
deleted file mode 100644
index 382d69711..000000000
--- a/presentation/src/main/java/com/mangbaam/presentation/ui/theme/Theme.kt
+++ /dev/null
@@ -1,60 +0,0 @@
-package com.mangbaam.presentation.ui.theme
-
-import android.app.Activity
-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.runtime.SideEffect
-import androidx.compose.ui.graphics.toArgb
-import androidx.compose.ui.platform.LocalContext
-import androidx.compose.ui.platform.LocalView
-import androidx.core.view.WindowCompat
-
-private val DarkColorScheme = darkColorScheme(
- primary = Purple80,
- secondary = PurpleGrey80,
- tertiary = Pink80,
-)
-
-private val LightColorScheme = lightColorScheme(
- primary = Purple40,
- secondary = PurpleGrey40,
- tertiary = Pink40,
-)
-
-@Composable
-fun UswtimetableTheme(
- darkTheme: Boolean = isSystemInDarkTheme(),
- // Dynamic color is available on Android 12+
- dynamicColor: Boolean = true,
- 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
- }
- val view = LocalView.current
- if (!view.isInEditMode) {
- SideEffect {
- val window = (view.context as Activity).window
- window.statusBarColor = colorScheme.primary.toArgb()
- WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = darkTheme
- }
- }
-
- MaterialTheme(
- colorScheme = colorScheme,
- typography = Typography,
- content = content,
- )
-}
diff --git a/presentation/src/main/java/com/mangbaam/presentation/ui/theme/Type.kt b/presentation/src/main/java/com/mangbaam/presentation/ui/theme/Type.kt
deleted file mode 100644
index 015c0a843..000000000
--- a/presentation/src/main/java/com/mangbaam/presentation/ui/theme/Type.kt
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.mangbaam.presentation.ui.theme
-
-import androidx.compose.material3.Typography
-import androidx.compose.ui.text.TextStyle
-import androidx.compose.ui.text.font.FontFamily
-import androidx.compose.ui.text.font.FontWeight
-import androidx.compose.ui.unit.sp
-
-// 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,
- ),
-)
diff --git a/presentation/src/main/res/values/strings.xml b/presentation/src/main/res/values/strings.xml
deleted file mode 100644
index 0de1544ac..000000000
--- a/presentation/src/main/res/values/strings.xml
+++ /dev/null
@@ -1,3 +0,0 @@
-
- MainActivity
-
diff --git a/presentation/src/main/res/values/themes.xml b/presentation/src/main/res/values/themes.xml
deleted file mode 100644
index af139c76f..000000000
--- a/presentation/src/main/res/values/themes.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/presentation/src/test/java/com/mangbaam/presentation/ExampleUnitTest.kt b/presentation/src/test/java/com/mangbaam/presentation/ExampleUnitTest.kt
deleted file mode 100644
index 010658d60..000000000
--- a/presentation/src/test/java/com/mangbaam/presentation/ExampleUnitTest.kt
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.mangbaam.presentation
-
-import junit.framework.TestCase.assertEquals
-import org.junit.Test
-
-/**
- * Example local unit test, which will execute on the development machine (host).
- *
- * See [testing documentation](http://d.android.com/tools/testing).
- */
-class ExampleUnitTest {
- @Test
- fun addition_isCorrect() {
- assertEquals(4, 2 + 2)
- }
-}
diff --git a/remote/login/.gitignore b/remote/login/.gitignore
new file mode 100644
index 000000000..42afabfd2
--- /dev/null
+++ b/remote/login/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/remote/login/build.gradle.kts b/remote/login/build.gradle.kts
new file mode 100644
index 000000000..162ff78ca
--- /dev/null
+++ b/remote/login/build.gradle.kts
@@ -0,0 +1,17 @@
+@Suppress("DSL_SCOPE_VIOLATION") // TODO: Remove once KTIJ-19369 is fixed
+plugins {
+ alias(libs.plugins.suwiki.android.remote)
+ alias(libs.plugins.kotlin.serialization)
+}
+
+android {
+ namespace = "com.suwiki.remote.login"
+}
+
+dependencies {
+ implementation(projects.data.login)
+
+ implementation(libs.retrofit.core)
+ implementation(libs.kotlinx.serialization.json)
+ implementation(libs.kotlinx.datetime)
+}
diff --git a/remote/login/consumer-rules.pro b/remote/login/consumer-rules.pro
new file mode 100644
index 000000000..e69de29bb
diff --git a/remote/login/proguard-rules.pro b/remote/login/proguard-rules.pro
new file mode 100644
index 000000000..481bb4348
--- /dev/null
+++ b/remote/login/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/remote/login/src/main/AndroidManifest.xml b/remote/login/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..8bdb7e14b
--- /dev/null
+++ b/remote/login/src/main/AndroidManifest.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/remote/login/src/main/java/com/suwiki/remote/login/api/LoginApi.kt b/remote/login/src/main/java/com/suwiki/remote/login/api/LoginApi.kt
new file mode 100644
index 000000000..08449c9ee
--- /dev/null
+++ b/remote/login/src/main/java/com/suwiki/remote/login/api/LoginApi.kt
@@ -0,0 +1,35 @@
+package com.suwiki.remote.login.api
+
+import com.suwiki.core.network.retrofit.ApiResult
+import com.suwiki.remote.login.request.FindIdRequest
+import com.suwiki.remote.login.request.FindPasswordRequest
+import com.suwiki.remote.login.request.LoginRequest
+import com.suwiki.remote.login.response.SuccessCheckResponse
+import com.suwiki.remote.login.response.TokenResponse
+import retrofit2.http.Body
+import retrofit2.http.POST
+
+// TODO : v2 api로 업그레이드 필요.
+interface LoginApi {
+ companion object {
+ const val USER = "/user"
+ }
+
+ // 아이디 찾기 API
+ @POST("$USER/find-id")
+ suspend fun findId(
+ @Body findIdRequest: FindIdRequest,
+ ): ApiResult
+
+ // 비밀번호 찾기(임시 비밀번호 전송) API
+ @POST("$USER/find-pw")
+ suspend fun findPassword(
+ @Body findPasswordRequest: FindPasswordRequest,
+ ): ApiResult
+
+ // 로그인 요청 API
+ @POST("$USER/login")
+ suspend fun login(
+ @Body loginRequest: LoginRequest,
+ ): ApiResult
+}
diff --git a/remote/login/src/main/java/com/suwiki/remote/login/datasource/RemoteLoginDataSourceImpl.kt b/remote/login/src/main/java/com/suwiki/remote/login/datasource/RemoteLoginDataSourceImpl.kt
new file mode 100644
index 000000000..acd0aed31
--- /dev/null
+++ b/remote/login/src/main/java/com/suwiki/remote/login/datasource/RemoteLoginDataSourceImpl.kt
@@ -0,0 +1,45 @@
+package com.suwiki.remote.login.datasource
+
+import com.suwiki.core.model.exception.RequestFailException
+import com.suwiki.core.model.user.Token
+import com.suwiki.data.login.datasource.RemoteLoginDataSource
+import com.suwiki.remote.login.api.LoginApi
+import com.suwiki.remote.login.request.FindIdRequest
+import com.suwiki.remote.login.request.FindPasswordRequest
+import com.suwiki.remote.login.request.LoginRequest
+import com.suwiki.remote.login.response.toModel
+import javax.inject.Inject
+
+class RemoteLoginDataSourceImpl @Inject constructor(
+ private val loginApi: LoginApi,
+) : RemoteLoginDataSource {
+
+ override suspend fun findId(email: String) {
+ loginApi
+ .findId(FindIdRequest(email))
+ .getOrThrow()
+ .run {
+ if (!success) throw RequestFailException()
+ }
+ }
+
+ override suspend fun findPassword(loginId: String, email: String) {
+ loginApi
+ .findPassword(
+ FindPasswordRequest(loginId, email),
+ )
+ .getOrThrow()
+ .run {
+ if (!success) throw RequestFailException()
+ }
+ }
+
+ override suspend fun login(loginId: String, password: String): Token {
+ return loginApi.login(
+ LoginRequest(
+ loginId = loginId,
+ password = password,
+ ),
+ ).getOrThrow().toModel()
+ }
+}
diff --git a/remote/login/src/main/java/com/suwiki/remote/login/di/ApiModule.kt b/remote/login/src/main/java/com/suwiki/remote/login/di/ApiModule.kt
new file mode 100644
index 000000000..49c99f7bb
--- /dev/null
+++ b/remote/login/src/main/java/com/suwiki/remote/login/di/ApiModule.kt
@@ -0,0 +1,21 @@
+package com.suwiki.remote.login.di
+
+import com.suwiki.core.network.di.AuthRetrofit
+import com.suwiki.remote.login.api.LoginApi
+import dagger.Module
+import dagger.Provides
+import dagger.hilt.InstallIn
+import dagger.hilt.components.SingletonComponent
+import retrofit2.Retrofit
+import javax.inject.Singleton
+
+@Module
+@InstallIn(SingletonComponent::class)
+object ApiModule {
+
+ @Singleton
+ @Provides
+ fun provideUserApi(@AuthRetrofit retrofit: Retrofit): LoginApi {
+ return retrofit.create(LoginApi::class.java)
+ }
+}
diff --git a/remote/login/src/main/java/com/suwiki/remote/login/di/RemoteDataSourceModule.kt b/remote/login/src/main/java/com/suwiki/remote/login/di/RemoteDataSourceModule.kt
new file mode 100644
index 000000000..ebe86dbd6
--- /dev/null
+++ b/remote/login/src/main/java/com/suwiki/remote/login/di/RemoteDataSourceModule.kt
@@ -0,0 +1,20 @@
+package com.suwiki.remote.login.di
+
+import com.suwiki.data.login.datasource.RemoteLoginDataSource
+import com.suwiki.remote.login.datasource.RemoteLoginDataSourceImpl
+import dagger.Binds
+import dagger.Module
+import dagger.hilt.InstallIn
+import dagger.hilt.components.SingletonComponent
+import javax.inject.Singleton
+
+@Module
+@InstallIn(SingletonComponent::class)
+abstract class RemoteDataSourceModule {
+
+ @Singleton
+ @Binds
+ abstract fun bindRemoteLoginDatasource(
+ remoteLoginDataSourceImpl: RemoteLoginDataSourceImpl,
+ ): RemoteLoginDataSource
+}
diff --git a/remote/user/src/main/java/com/suwiki/remote/user/request/FindIdRequest.kt b/remote/login/src/main/java/com/suwiki/remote/login/request/FindIdRequest.kt
similarity index 71%
rename from remote/user/src/main/java/com/suwiki/remote/user/request/FindIdRequest.kt
rename to remote/login/src/main/java/com/suwiki/remote/login/request/FindIdRequest.kt
index 93fe7b793..bc5366068 100644
--- a/remote/user/src/main/java/com/suwiki/remote/user/request/FindIdRequest.kt
+++ b/remote/login/src/main/java/com/suwiki/remote/login/request/FindIdRequest.kt
@@ -1,4 +1,4 @@
-package com.suwiki.remote.user.request
+package com.suwiki.remote.login.request
import kotlinx.serialization.Serializable
diff --git a/remote/user/src/main/java/com/suwiki/remote/user/request/FindPasswordRequest.kt b/remote/login/src/main/java/com/suwiki/remote/login/request/FindPasswordRequest.kt
similarity index 77%
rename from remote/user/src/main/java/com/suwiki/remote/user/request/FindPasswordRequest.kt
rename to remote/login/src/main/java/com/suwiki/remote/login/request/FindPasswordRequest.kt
index 49f6bcf4f..47a0c4c2e 100644
--- a/remote/user/src/main/java/com/suwiki/remote/user/request/FindPasswordRequest.kt
+++ b/remote/login/src/main/java/com/suwiki/remote/login/request/FindPasswordRequest.kt
@@ -1,4 +1,4 @@
-package com.suwiki.remote.user.request
+package com.suwiki.remote.login.request
import kotlinx.serialization.Serializable
diff --git a/remote/user/src/main/java/com/suwiki/remote/user/request/LoginRequest.kt b/remote/login/src/main/java/com/suwiki/remote/login/request/LoginRequest.kt
similarity index 76%
rename from remote/user/src/main/java/com/suwiki/remote/user/request/LoginRequest.kt
rename to remote/login/src/main/java/com/suwiki/remote/login/request/LoginRequest.kt
index b1e0260af..9b4a84b36 100644
--- a/remote/user/src/main/java/com/suwiki/remote/user/request/LoginRequest.kt
+++ b/remote/login/src/main/java/com/suwiki/remote/login/request/LoginRequest.kt
@@ -1,4 +1,4 @@
-package com.suwiki.remote.user.request
+package com.suwiki.remote.login.request
import kotlinx.serialization.Serializable
diff --git a/remote/login/src/main/java/com/suwiki/remote/login/response/SuccessCheckResponse.kt b/remote/login/src/main/java/com/suwiki/remote/login/response/SuccessCheckResponse.kt
new file mode 100644
index 000000000..b7bc7f9f2
--- /dev/null
+++ b/remote/login/src/main/java/com/suwiki/remote/login/response/SuccessCheckResponse.kt
@@ -0,0 +1,8 @@
+package com.suwiki.remote.login.response
+
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class SuccessCheckResponse(
+ val success: Boolean,
+)
diff --git a/remote/login/src/main/java/com/suwiki/remote/login/response/TokenResponse.kt b/remote/login/src/main/java/com/suwiki/remote/login/response/TokenResponse.kt
new file mode 100644
index 000000000..c1f9c1900
--- /dev/null
+++ b/remote/login/src/main/java/com/suwiki/remote/login/response/TokenResponse.kt
@@ -0,0 +1,16 @@
+package com.suwiki.remote.login.response
+
+import com.suwiki.core.model.user.Token
+import kotlinx.serialization.SerialName
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class TokenResponse(
+ @SerialName("AccessToken") val accessToken: String,
+ @SerialName("RefreshToken") val refreshToken: String,
+)
+
+internal fun TokenResponse.toModel() = Token(
+ accessToken = accessToken,
+ refreshToken = refreshToken,
+)
diff --git a/remote/user/src/main/java/com/suwiki/remote/user/api/UserApi.kt b/remote/user/src/main/java/com/suwiki/remote/user/api/UserApi.kt
index 471b09faf..acbcb67f8 100644
--- a/remote/user/src/main/java/com/suwiki/remote/user/api/UserApi.kt
+++ b/remote/user/src/main/java/com/suwiki/remote/user/api/UserApi.kt
@@ -1,13 +1,9 @@
package com.suwiki.remote.user.api
import com.suwiki.core.network.retrofit.ApiResult
-import com.suwiki.remote.user.request.FindIdRequest
-import com.suwiki.remote.user.request.FindPasswordRequest
-import com.suwiki.remote.user.request.LoginRequest
import com.suwiki.remote.user.request.QuitRequest
import com.suwiki.remote.user.request.ResetPasswordRequest
import com.suwiki.remote.user.response.SuccessCheckResponse
-import com.suwiki.remote.user.response.TokenResponse
import com.suwiki.remote.user.response.UserResponse
import retrofit2.http.Body
import retrofit2.http.GET
@@ -19,24 +15,6 @@ interface UserApi {
const val USER = "/user"
}
- // 아이디 찾기 API
- @POST("$USER/find-id")
- suspend fun findId(
- @Body findIdRequest: FindIdRequest,
- ): ApiResult
-
- // 비밀번호 찾기(임시 비밀번호 전송) API
- @POST("$USER/find-pw")
- suspend fun findPassword(
- @Body findPasswordRequest: FindPasswordRequest,
- ): ApiResult
-
- // 로그인 요청 API
- @POST("$USER/login")
- suspend fun login(
- @Body loginRequest: LoginRequest,
- ): ApiResult
-
// 비밀번호 재설정 API
@POST("$USER/reset-pw")
suspend fun resetPassword(
diff --git a/remote/user/src/main/java/com/suwiki/remote/user/datasource/RemoteUserDataSourceImpl.kt b/remote/user/src/main/java/com/suwiki/remote/user/datasource/RemoteUserDataSourceImpl.kt
index f6b69797f..3022ac844 100644
--- a/remote/user/src/main/java/com/suwiki/remote/user/datasource/RemoteUserDataSourceImpl.kt
+++ b/remote/user/src/main/java/com/suwiki/remote/user/datasource/RemoteUserDataSourceImpl.kt
@@ -1,13 +1,9 @@
package com.suwiki.remote.user.datasource
import com.suwiki.core.model.exception.RequestFailException
-import com.suwiki.core.model.user.Token
import com.suwiki.core.model.user.User
import com.suwiki.data.user.datasource.RemoteUserDataSource
import com.suwiki.remote.user.api.UserApi
-import com.suwiki.remote.user.request.FindIdRequest
-import com.suwiki.remote.user.request.FindPasswordRequest
-import com.suwiki.remote.user.request.LoginRequest
import com.suwiki.remote.user.request.QuitRequest
import com.suwiki.remote.user.request.ResetPasswordRequest
import com.suwiki.remote.user.response.toModel
@@ -17,26 +13,6 @@ class RemoteUserDataSourceImpl @Inject constructor(
private val userApi: UserApi,
) : RemoteUserDataSource {
- override suspend fun findId(email: String) {
- userApi
- .findId(FindIdRequest(email))
- .getOrThrow()
- .run {
- if (!success) throw RequestFailException()
- }
- }
-
- override suspend fun findPassword(loginId: String, email: String) {
- userApi
- .findPassword(
- FindPasswordRequest(loginId, email),
- )
- .getOrThrow()
- .run {
- if (!success) throw RequestFailException()
- }
- }
-
override suspend fun resetPassword(
currentPassword: String,
newPassword: String,
@@ -51,15 +27,6 @@ class RemoteUserDataSourceImpl @Inject constructor(
}
}
- override suspend fun login(loginId: String, password: String): Token {
- return userApi.login(
- LoginRequest(
- loginId = loginId,
- password = password,
- ),
- ).getOrThrow().toModel()
- }
-
override suspend fun quit(id: String, password: String) {
userApi.quit(
QuitRequest(
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 98936914e..ee74764f9 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -19,7 +19,6 @@ dependencyResolutionManagement {
}
rootProject.name = "uswtimetable"
-include(":presentation")
include(":app-compose")
include(":core:android")
@@ -39,10 +38,12 @@ include(":remote:lectureevaluation:editor")
include(":remote:signup")
include(":remote:notice")
include(":remote:user")
+include(":remote:login")
include(":local:openmajor")
include(":local:timetable")
include(":local:user")
+include(":local:login")
include(":data:openmajor")
include(":data:timetable")
@@ -52,6 +53,7 @@ include(":data:lectureevaluation:my")
include(":data:user")
include(":data:notice")
include(":data:signup")
+include(":data:login")
include(":domain:openmajor")
include(":domain:user")
@@ -61,3 +63,15 @@ include(":domain:lectureevaluation:my")
include(":domain:lectureevaluation:editor")
include(":domain:timetable")
include(":domain:notice")
+include(":domain:login")
+
+include(":feature:navigator")
+include(":feature:openmajor")
+include(":feature:timetable")
+include(":feature:lectureevaluation:viewerreporter")
+include(":feature:lectureevaluation:editor")
+include(":feature:lectureevaluation:my")
+include(":feature:myinfo")
+include(":feature:notice")
+include(":feature:signup")
+include(":feature:login")