From ce4217fef4b175afd31bcb3cbcdd4f0a69218079 Mon Sep 17 00:00:00 2001 From: SYAAINN Date: Tue, 5 Nov 2024 14:28:29 +0900 Subject: [PATCH 01/19] =?UTF-8?q?[add/#8]=20=EC=84=9C=EB=B2=84=ED=86=B5?= =?UTF-8?q?=EC=8B=A0=20=EC=9D=98=EC=A1=B4=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 26 ++++++++++++++++++++------ app/src/main/AndroidManifest.xml | 3 +++ gradle/libs.versions.toml | 18 ++++++++++++++---- 3 files changed, 37 insertions(+), 10 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 5ea3ec0..a10ea06 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,3 +1,5 @@ +import java.util.Properties + plugins { alias(libs.plugins.android.application) alias(libs.plugins.kotlin.android) @@ -7,6 +9,10 @@ plugins { id("kotlin-kapt") // kapt 플러그인 추가 } +val properties = Properties().apply { + load(project.rootProject.file("local.properties").inputStream()) +} + android { namespace = "org.sopt.and" compileSdk = 34 @@ -18,6 +24,7 @@ android { versionCode = 1 versionName = "1.0" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + buildConfigField("String", "BASE_URL", properties["base.url"].toString()) } buildTypes { @@ -38,6 +45,7 @@ android { } buildFeatures { compose = true + buildConfig = true } } @@ -56,12 +64,6 @@ dependencies { implementation(libs.androidx.ui.tooling.preview) implementation(libs.androidx.material3) implementation(libs.androidx.compose.navigation) - implementation(libs.kotlinx.serialization.json) - // Hilt 관련 의존성 추가 - implementation(libs.hilt.android) - implementation(libs.hilt.navigation.compose) - implementation(libs.androidx.appcompat) - kapt(libs.hilt.compiler) testImplementation(libs.junit) androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.espresso.core) @@ -69,4 +71,16 @@ dependencies { androidTestImplementation(libs.androidx.ui.test.junit4) debugImplementation(libs.androidx.ui.tooling) debugImplementation(libs.androidx.ui.test.manifest) + // Hilt 관련 의존성 추가 + implementation(libs.hilt.android) + implementation(libs.hilt.navigation.compose) + implementation(libs.androidx.appcompat) + kapt(libs.hilt.compiler) + // Network + implementation(platform(libs.okhttp.bom)) + implementation(libs.okhttp) + implementation(libs.okhttp.logging.interceptor) + implementation(libs.retrofit) + implementation(libs.retrofit.kotlin.serialization.converter) + implementation(libs.kotlinx.serialization.json) } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e336060..acf3a2a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,6 +2,8 @@ + + Date: Fri, 15 Nov 2024 19:06:07 +0900 Subject: [PATCH 02/19] =?UTF-8?q?[del/#8]=20=EB=AF=B8=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=ED=95=98=EA=B2=8C=20=EB=90=9C=20data=20class=EB=A5=BC=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C=ED=95=A9=EB=8B=88=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/sopt/and/presentation/model/User.kt | 43 ------------------- 1 file changed, 43 deletions(-) delete mode 100644 app/src/main/java/org/sopt/and/presentation/model/User.kt diff --git a/app/src/main/java/org/sopt/and/presentation/model/User.kt b/app/src/main/java/org/sopt/and/presentation/model/User.kt deleted file mode 100644 index cd0abc2..0000000 --- a/app/src/main/java/org/sopt/and/presentation/model/User.kt +++ /dev/null @@ -1,43 +0,0 @@ -package org.sopt.and.presentation.model - -import org.sopt.and.presentation.ui.auth.screen.SignUpState - -data class User( - val email: String, - val password: String, -) { - companion object { - val EMAIL_VALIDATION_REGEX = "^[a-zA-Z0 -9]+@[a-zA-Z0-9.]+\\.[a-zA-Z]{2,}\$".toRegex() - - const val PW_MIN_LENGTH = 8 - const val PW_MAX_LENGTH = 20 - const val PW_MIN_TYPE_COUNT = 3 - val UPPER_CASE_REGEX = "[A-Z]".toRegex() - val LOWER_CASE_REGEX = "[a-z]".toRegex() - val DIGIT_REGEX = "[0-9]".toRegex() - val SPECIAL_CHAR_REGEX = "[!@#\$%^&*(),.?\":{}|<>]".toRegex() - } -} - -fun User.validateSignUp(): SignUpState { - return when { - !isSignUpEmailValidate() -> SignUpState.EmailInvalid - !isSignUpPasswordValidate() -> SignUpState.PasswordInvalid - else -> SignUpState.Success - } -} - -fun User.isSignUpEmailValidate(): Boolean { - return email.matches(User.EMAIL_VALIDATION_REGEX) -} - -fun User.isSignUpPasswordValidate(): Boolean { - val count = listOf( - User.UPPER_CASE_REGEX.containsMatchIn(password), - User.LOWER_CASE_REGEX.containsMatchIn(password), - User.DIGIT_REGEX.containsMatchIn(password), - User.SPECIAL_CHAR_REGEX.containsMatchIn(password) - ).count { it } - - return password.length in User.PW_MIN_LENGTH..User.PW_MAX_LENGTH && count >= User.PW_MIN_TYPE_COUNT -} From 8075f87186d8f3a1fede9e3ff15ea154a1a4197b Mon Sep 17 00:00:00 2001 From: SYAAINN Date: Fri, 15 Nov 2024 19:06:35 +0900 Subject: [PATCH 03/19] =?UTF-8?q?[chore/#8]=20=ED=8C=A8=ED=82=A4=EC=A7=80?= =?UTF-8?q?=20=EC=9D=B4=EB=A6=84=EC=9D=84=20utils=20->=20util=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=ED=95=A9=EB=8B=88=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/sopt/and/presentation/{utils => util}/ToastUtils.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename app/src/main/java/org/sopt/and/presentation/{utils => util}/ToastUtils.kt (88%) diff --git a/app/src/main/java/org/sopt/and/presentation/utils/ToastUtils.kt b/app/src/main/java/org/sopt/and/presentation/util/ToastUtils.kt similarity index 88% rename from app/src/main/java/org/sopt/and/presentation/utils/ToastUtils.kt rename to app/src/main/java/org/sopt/and/presentation/util/ToastUtils.kt index 920f9ad..92b958d 100644 --- a/app/src/main/java/org/sopt/and/presentation/utils/ToastUtils.kt +++ b/app/src/main/java/org/sopt/and/presentation/util/ToastUtils.kt @@ -1,4 +1,4 @@ -package org.sopt.and.presentation.utils +package org.sopt.and.presentation.util import android.content.Context import android.widget.Toast From 265bb4583301eecb747eb24a5050b44d22a8b2be Mon Sep 17 00:00:00 2001 From: SYAAINN Date: Fri, 15 Nov 2024 19:08:26 +0900 Subject: [PATCH 04/19] =?UTF-8?q?[feat/#8]=20=EC=84=9C=EB=B2=84=ED=86=B5?= =?UTF-8?q?=EC=8B=A0=EC=9D=84=20=EC=9C=84=ED=95=9C=20dto=EB=A5=BC=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=ED=95=A9=EB=8B=88=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../and/data/remote/dto/request/RequestLoginDto.kt | 10 ++++++++++ .../dto/request/RequestUserRegistrationDto.kt | 11 +++++++++++ .../remote/dto/response/ResponseGetMyHobbyDto.kt | 14 ++++++++++++++ .../data/remote/dto/response/ResponseLoginDto.kt | 14 ++++++++++++++ .../dto/response/ResponseUserRegistrationDto.kt | 14 ++++++++++++++ 5 files changed, 63 insertions(+) create mode 100644 app/src/main/java/org/sopt/and/data/remote/dto/request/RequestLoginDto.kt create mode 100644 app/src/main/java/org/sopt/and/data/remote/dto/request/RequestUserRegistrationDto.kt create mode 100644 app/src/main/java/org/sopt/and/data/remote/dto/response/ResponseGetMyHobbyDto.kt create mode 100644 app/src/main/java/org/sopt/and/data/remote/dto/response/ResponseLoginDto.kt create mode 100644 app/src/main/java/org/sopt/and/data/remote/dto/response/ResponseUserRegistrationDto.kt diff --git a/app/src/main/java/org/sopt/and/data/remote/dto/request/RequestLoginDto.kt b/app/src/main/java/org/sopt/and/data/remote/dto/request/RequestLoginDto.kt new file mode 100644 index 0000000..0f573d8 --- /dev/null +++ b/app/src/main/java/org/sopt/and/data/remote/dto/request/RequestLoginDto.kt @@ -0,0 +1,10 @@ +package org.sopt.and.data.remote.dto.request + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class RequestLoginDto( + @SerialName("username") val username: String, + @SerialName("password") val password: String, +) \ No newline at end of file diff --git a/app/src/main/java/org/sopt/and/data/remote/dto/request/RequestUserRegistrationDto.kt b/app/src/main/java/org/sopt/and/data/remote/dto/request/RequestUserRegistrationDto.kt new file mode 100644 index 0000000..186d6b4 --- /dev/null +++ b/app/src/main/java/org/sopt/and/data/remote/dto/request/RequestUserRegistrationDto.kt @@ -0,0 +1,11 @@ +package org.sopt.and.data.remote.dto.request + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class RequestUserRegistrationDto ( + @SerialName("username") val username: String, + @SerialName("password") val password: String, + @SerialName("hobby") val hobby: String, +) \ No newline at end of file diff --git a/app/src/main/java/org/sopt/and/data/remote/dto/response/ResponseGetMyHobbyDto.kt b/app/src/main/java/org/sopt/and/data/remote/dto/response/ResponseGetMyHobbyDto.kt new file mode 100644 index 0000000..77640db --- /dev/null +++ b/app/src/main/java/org/sopt/and/data/remote/dto/response/ResponseGetMyHobbyDto.kt @@ -0,0 +1,14 @@ +package org.sopt.and.data.remote.dto.response + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class ResponseGetMyHobbyDto( + @SerialName("result") val result: GetMyHobbyResult +) + +@Serializable +data class GetMyHobbyResult( + @SerialName("hobby") val hobby: String +) \ No newline at end of file diff --git a/app/src/main/java/org/sopt/and/data/remote/dto/response/ResponseLoginDto.kt b/app/src/main/java/org/sopt/and/data/remote/dto/response/ResponseLoginDto.kt new file mode 100644 index 0000000..8b31b8f --- /dev/null +++ b/app/src/main/java/org/sopt/and/data/remote/dto/response/ResponseLoginDto.kt @@ -0,0 +1,14 @@ +package org.sopt.and.data.remote.dto.response + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class ResponseLoginDto ( + @SerialName("result") val result: LoginResult +) + +@Serializable +data class LoginResult( + @SerialName("token") val token: String +) \ No newline at end of file diff --git a/app/src/main/java/org/sopt/and/data/remote/dto/response/ResponseUserRegistrationDto.kt b/app/src/main/java/org/sopt/and/data/remote/dto/response/ResponseUserRegistrationDto.kt new file mode 100644 index 0000000..66e8e9e --- /dev/null +++ b/app/src/main/java/org/sopt/and/data/remote/dto/response/ResponseUserRegistrationDto.kt @@ -0,0 +1,14 @@ +package org.sopt.and.data.remote.dto.response + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class ResponseUserRegistrationDto( + @SerialName("result") val result: UserRegistrationResult +) + +@Serializable +data class UserRegistrationResult( + @SerialName("no") val no: Int +) \ No newline at end of file From 7d6c91f27e7dff737cdb4ca8592e3cadf1ea0d31 Mon Sep 17 00:00:00 2001 From: SYAAINN Date: Fri, 15 Nov 2024 19:10:45 +0900 Subject: [PATCH 05/19] =?UTF-8?q?[chore/#8]=20localProperties=20=EB=B3=80?= =?UTF-8?q?=EC=88=98=EB=AA=85=EC=9D=84=20=EC=88=98=EC=A0=95=ED=95=A9?= =?UTF-8?q?=EB=8B=88=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index a10ea06..d995784 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -9,7 +9,7 @@ plugins { id("kotlin-kapt") // kapt 플러그인 추가 } -val properties = Properties().apply { +val localProperties = Properties().apply { load(project.rootProject.file("local.properties").inputStream()) } @@ -24,7 +24,7 @@ android { versionCode = 1 versionName = "1.0" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" - buildConfigField("String", "BASE_URL", properties["base.url"].toString()) + buildConfigField("String","BASE_URL", localProperties["base.url"].toString()) } buildTypes { From a99668b39fa9de0eb1d566fd2fb0d04fbcfb88cc Mon Sep 17 00:00:00 2001 From: SYAAINN Date: Fri, 15 Nov 2024 19:11:08 +0900 Subject: [PATCH 06/19] =?UTF-8?q?[del/#8]=20=EB=AF=B8=EC=82=AC=EC=9A=A9=20?= =?UTF-8?q?object=EB=A5=BC=20=EC=82=AD=EC=A0=9C=ED=95=A9=EB=8B=88=EB=8B=A4?= =?UTF-8?q?.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/sopt/and/presentation/ui/navigation/KeyStorage.kt | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 app/src/main/java/org/sopt/and/presentation/ui/navigation/KeyStorage.kt diff --git a/app/src/main/java/org/sopt/and/presentation/ui/navigation/KeyStorage.kt b/app/src/main/java/org/sopt/and/presentation/ui/navigation/KeyStorage.kt deleted file mode 100644 index d8f7567..0000000 --- a/app/src/main/java/org/sopt/and/presentation/ui/navigation/KeyStorage.kt +++ /dev/null @@ -1,5 +0,0 @@ -package org.sopt.and.presentation.ui.navigation - -object KeyStorage { - const val USER_EMAIL = "user_email" -} \ No newline at end of file From 75e5dc5b3180edac8cc1e1945a04321138a14556 Mon Sep 17 00:00:00 2001 From: SYAAINN Date: Fri, 15 Nov 2024 19:11:40 +0900 Subject: [PATCH 07/19] =?UTF-8?q?[feat/#8]=20=EC=84=9C=EB=B2=84=ED=86=B5?= =?UTF-8?q?=EC=8B=A0=20api=EB=A5=BC=20=EA=B5=AC=ED=98=84=ED=95=A9=EB=8B=88?= =?UTF-8?q?=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../and/data/remote/service/AuthService.kt | 21 +++++++++++++++++++ .../and/data/remote/service/UserService.kt | 13 ++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 app/src/main/java/org/sopt/and/data/remote/service/AuthService.kt create mode 100644 app/src/main/java/org/sopt/and/data/remote/service/UserService.kt diff --git a/app/src/main/java/org/sopt/and/data/remote/service/AuthService.kt b/app/src/main/java/org/sopt/and/data/remote/service/AuthService.kt new file mode 100644 index 0000000..5bc4f3b --- /dev/null +++ b/app/src/main/java/org/sopt/and/data/remote/service/AuthService.kt @@ -0,0 +1,21 @@ +package org.sopt.and.data.remote.service + +import org.sopt.and.data.remote.dto.request.RequestLoginDto +import org.sopt.and.data.remote.dto.request.RequestUserRegistrationDto +import org.sopt.and.data.remote.dto.response.ResponseLoginDto +import org.sopt.and.data.remote.dto.response.ResponseUserRegistrationDto +import retrofit2.Call +import retrofit2.http.Body +import retrofit2.http.POST + +interface AuthService { + @POST("user") + fun registerUser( + @Body requestUserRegistrationDto: RequestUserRegistrationDto + ): Call + + @POST("login") + fun login( + @Body requestLoginDto: RequestLoginDto + ): Call +} \ No newline at end of file diff --git a/app/src/main/java/org/sopt/and/data/remote/service/UserService.kt b/app/src/main/java/org/sopt/and/data/remote/service/UserService.kt new file mode 100644 index 0000000..833d780 --- /dev/null +++ b/app/src/main/java/org/sopt/and/data/remote/service/UserService.kt @@ -0,0 +1,13 @@ +package org.sopt.and.data.remote.service + +import org.sopt.and.data.remote.dto.response.ResponseGetMyHobbyDto +import retrofit2.Call +import retrofit2.http.GET +import retrofit2.http.Header + +interface UserService { + @GET("user/my-hobby") + fun getMyHobby( + @Header("token") token: String + ): Call +} \ No newline at end of file From 376f4584a19b9b952b0b0d457ebd64111051adef Mon Sep 17 00:00:00 2001 From: SYAAINN Date: Fri, 15 Nov 2024 19:12:32 +0900 Subject: [PATCH 08/19] =?UTF-8?q?[feat/#8]=20=EC=84=9C=EB=B2=84=ED=86=B5?= =?UTF-8?q?=EC=8B=A0=20response=EC=97=90=20=EB=8C=80=ED=95=9C=20=ED=85=9C?= =?UTF-8?q?=ED=94=8C=EB=A6=BF=EC=9D=84=20=EC=83=9D=EC=84=B1=ED=95=A9?= =?UTF-8?q?=EB=8B=88=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/sopt/and/data/remote/ApiResponse.kt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 app/src/main/java/org/sopt/and/data/remote/ApiResponse.kt diff --git a/app/src/main/java/org/sopt/and/data/remote/ApiResponse.kt b/app/src/main/java/org/sopt/and/data/remote/ApiResponse.kt new file mode 100644 index 0000000..6c69e95 --- /dev/null +++ b/app/src/main/java/org/sopt/and/data/remote/ApiResponse.kt @@ -0,0 +1,14 @@ +package org.sopt.and.data.remote + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class ApiResponse( + @SerialName("status") + val status: Int, + @SerialName("message") + val message: String, + @SerialName("result") + val result: T +) \ No newline at end of file From 135e9ff6cc67ef0fa4d39efa62a60450763c8c66 Mon Sep 17 00:00:00 2001 From: SYAAINN Date: Fri, 15 Nov 2024 19:14:21 +0900 Subject: [PATCH 09/19] =?UTF-8?q?[feat/#8]=20=EC=84=9C=EB=B2=84=ED=86=B5?= =?UTF-8?q?=EC=8B=A0=EC=9D=84=20=EC=9C=84=ED=95=9C=20retrofit=20=EA=B0=9D?= =?UTF-8?q?=EC=B2=B4=EB=A5=BC=20=EC=83=9D=EC=84=B1=ED=95=A9=EB=8B=88?= =?UTF-8?q?=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/org/sopt/and/di/ApiFactory.kt | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 app/src/main/java/org/sopt/and/di/ApiFactory.kt diff --git a/app/src/main/java/org/sopt/and/di/ApiFactory.kt b/app/src/main/java/org/sopt/and/di/ApiFactory.kt new file mode 100644 index 0000000..67532d3 --- /dev/null +++ b/app/src/main/java/org/sopt/and/di/ApiFactory.kt @@ -0,0 +1,38 @@ +package org.sopt.and.di + +import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory +import kotlinx.serialization.json.Json +import okhttp3.MediaType.Companion.toMediaType +import okhttp3.OkHttpClient +import okhttp3.logging.HttpLoggingInterceptor +import org.sopt.and.BuildConfig +import org.sopt.and.data.remote.service.AuthService +import org.sopt.and.data.remote.service.UserService +import retrofit2.Retrofit + +object ApiFactory { + private const val BASE_URL: String = BuildConfig.BASE_URL + + private val loggingInterceptor = HttpLoggingInterceptor().apply { + level = HttpLoggingInterceptor.Level.BODY + } + + private val client = OkHttpClient.Builder() + .addInterceptor(loggingInterceptor) + .build() + + val retrofit: Retrofit by lazy { + Retrofit.Builder() + .baseUrl(BASE_URL) + .client(client) + .addConverterFactory(Json.asConverterFactory("application/json".toMediaType())) + .build() + } + + inline fun create(): T = retrofit.create(T::class.java) +} + +object ServicePool { + val authService = ApiFactory.create() + val userService = ApiFactory.create() +} \ No newline at end of file From d16061b9151c1866a1c9b401215cc62685d7bb5e Mon Sep 17 00:00:00 2001 From: SYAAINN Date: Fri, 15 Nov 2024 19:15:01 +0900 Subject: [PATCH 10/19] =?UTF-8?q?[feat/#8]=20=EB=A1=9C=EA=B7=B8=EC=9D=B8?= =?UTF-8?q?=20=EC=8B=9C=20=EB=B0=9B=EC=9D=80=20token=20=EA=B0=92=EC=9D=84?= =?UTF-8?q?=20=EB=B6=88=EB=9F=AC=EC=98=A4=EB=8A=94=20dataSource=EB=A5=BC?= =?UTF-8?q?=20=EA=B5=AC=ED=98=84=ED=95=A9=EB=8B=88=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../and/data/local/TokenLocalDataSource.kt | 6 ++++++ .../data/local/TokenLocalDataSourceImpl.kt | 20 +++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 app/src/main/java/org/sopt/and/data/local/TokenLocalDataSource.kt create mode 100644 app/src/main/java/org/sopt/and/data/local/TokenLocalDataSourceImpl.kt diff --git a/app/src/main/java/org/sopt/and/data/local/TokenLocalDataSource.kt b/app/src/main/java/org/sopt/and/data/local/TokenLocalDataSource.kt new file mode 100644 index 0000000..34005e1 --- /dev/null +++ b/app/src/main/java/org/sopt/and/data/local/TokenLocalDataSource.kt @@ -0,0 +1,6 @@ +package org.sopt.and.data.local + +interface TokenLocalDataSource { + var token: String + fun clearInfo() +} \ No newline at end of file diff --git a/app/src/main/java/org/sopt/and/data/local/TokenLocalDataSourceImpl.kt b/app/src/main/java/org/sopt/and/data/local/TokenLocalDataSourceImpl.kt new file mode 100644 index 0000000..e8edb8d --- /dev/null +++ b/app/src/main/java/org/sopt/and/data/local/TokenLocalDataSourceImpl.kt @@ -0,0 +1,20 @@ +package org.sopt.and.data.local + +import android.content.SharedPreferences +import javax.inject.Inject + +class TokenLocalDataSourceImpl @Inject constructor( + private val sharedPreferences: SharedPreferences +): TokenLocalDataSource { + override var token: String + get() = sharedPreferences.getString(TOKEN, "") ?: "" + set(value) = sharedPreferences.edit().putString(TOKEN, value).apply() + + override fun clearInfo() { + sharedPreferences.edit().clear().apply() + } + + companion object { + private const val TOKEN = "TOKEN" + } +} \ No newline at end of file From 98f2445ce5d33ceca691170a62bbb519abee958a Mon Sep 17 00:00:00 2001 From: SYAAINN Date: Fri, 15 Nov 2024 19:17:18 +0900 Subject: [PATCH 11/19] =?UTF-8?q?[feat/#8]=20token=EC=9D=84=20=EC=9C=84?= =?UTF-8?q?=ED=95=9C=20repository=EB=A5=BC=20=EC=83=9D=EC=84=B1=ED=95=A9?= =?UTF-8?q?=EB=8B=88=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../and/data/repository/TokenRepository.kt | 7 +++++++ .../repositoryimpl/TokenRepositoryImpl.kt | 21 +++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 app/src/main/java/org/sopt/and/data/repository/TokenRepository.kt create mode 100644 app/src/main/java/org/sopt/and/data/repositoryimpl/TokenRepositoryImpl.kt diff --git a/app/src/main/java/org/sopt/and/data/repository/TokenRepository.kt b/app/src/main/java/org/sopt/and/data/repository/TokenRepository.kt new file mode 100644 index 0000000..54453d2 --- /dev/null +++ b/app/src/main/java/org/sopt/and/data/repository/TokenRepository.kt @@ -0,0 +1,7 @@ +package org.sopt.and.data.repository + +interface TokenRepository { + fun getToken(): String + fun setToken(token: String) + fun clearInfo() +} \ No newline at end of file diff --git a/app/src/main/java/org/sopt/and/data/repositoryimpl/TokenRepositoryImpl.kt b/app/src/main/java/org/sopt/and/data/repositoryimpl/TokenRepositoryImpl.kt new file mode 100644 index 0000000..2564cca --- /dev/null +++ b/app/src/main/java/org/sopt/and/data/repositoryimpl/TokenRepositoryImpl.kt @@ -0,0 +1,21 @@ +package org.sopt.and.data.repositoryimpl + +import android.util.Log +import org.sopt.and.data.local.TokenLocalDataSource +import org.sopt.and.data.repository.TokenRepository +import javax.inject.Inject + +class TokenRepositoryImpl @Inject constructor( + private val tokenLocalDataSource: TokenLocalDataSource +) : TokenRepository { + override fun getToken(): String = tokenLocalDataSource.token + + override fun setToken(token: String) { + tokenLocalDataSource.token = token + Log.d("TokenDataStore", "Token Saved: $token") + } + + override fun clearInfo() { + tokenLocalDataSource.clearInfo() + } +} \ No newline at end of file From e1323cadc0431f236b112de139fd5af0234edbf5 Mon Sep 17 00:00:00 2001 From: SYAAINN Date: Fri, 15 Nov 2024 19:17:37 +0900 Subject: [PATCH 12/19] =?UTF-8?q?[feat/#8]=20=EC=9D=98=EC=A1=B4=EC=84=B1?= =?UTF-8?q?=20=EC=A3=BC=EC=9E=85=EC=9D=84=20=EC=9C=84=ED=95=9C=20module?= =?UTF-8?q?=EC=9D=84=20=EC=83=9D=EC=84=B1=ED=95=A9=EB=8B=88=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/sopt/and/di/RepositoryModule.kt | 19 ++++++++++++++++++ .../sopt/and/di/SharedPreferencesModule.kt | 20 +++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 app/src/main/java/org/sopt/and/di/RepositoryModule.kt create mode 100644 app/src/main/java/org/sopt/and/di/SharedPreferencesModule.kt diff --git a/app/src/main/java/org/sopt/and/di/RepositoryModule.kt b/app/src/main/java/org/sopt/and/di/RepositoryModule.kt new file mode 100644 index 0000000..4bfe9aa --- /dev/null +++ b/app/src/main/java/org/sopt/and/di/RepositoryModule.kt @@ -0,0 +1,19 @@ +package org.sopt.and.di + +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import org.sopt.and.data.repository.TokenRepository +import org.sopt.and.data.repositoryimpl.TokenRepositoryImpl +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +abstract class RepositoryModule { + @Binds + @Singleton + abstract fun bindTokenRepository( + tokenRepositoryImpl: TokenRepositoryImpl + ): TokenRepository +} \ No newline at end of file diff --git a/app/src/main/java/org/sopt/and/di/SharedPreferencesModule.kt b/app/src/main/java/org/sopt/and/di/SharedPreferencesModule.kt new file mode 100644 index 0000000..01336f3 --- /dev/null +++ b/app/src/main/java/org/sopt/and/di/SharedPreferencesModule.kt @@ -0,0 +1,20 @@ +package org.sopt.and.di + +import android.content.Context +import android.content.SharedPreferences +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.qualifiers.ApplicationContext +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +object SharedPreferencesModule { + @Provides + @Singleton + fun provideSharedPreferences(@ApplicationContext context: Context): SharedPreferences { + return context.getSharedPreferences("token_prefs", Context.MODE_PRIVATE) + } +} \ No newline at end of file From e845e52322454f3e611bff7ba57a93d953dcc76b Mon Sep 17 00:00:00 2001 From: SYAAINN Date: Fri, 15 Nov 2024 19:17:41 +0900 Subject: [PATCH 13/19] =?UTF-8?q?[feat/#8]=20=EC=9D=98=EC=A1=B4=EC=84=B1?= =?UTF-8?q?=20=EC=A3=BC=EC=9E=85=EC=9D=84=20=EC=9C=84=ED=95=9C=20module?= =?UTF-8?q?=EC=9D=84=20=EC=83=9D=EC=84=B1=ED=95=A9=EB=8B=88=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/sopt/and/di/TokenDataStoreModule.kt | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 app/src/main/java/org/sopt/and/di/TokenDataStoreModule.kt diff --git a/app/src/main/java/org/sopt/and/di/TokenDataStoreModule.kt b/app/src/main/java/org/sopt/and/di/TokenDataStoreModule.kt new file mode 100644 index 0000000..3eb6c9a --- /dev/null +++ b/app/src/main/java/org/sopt/and/di/TokenDataStoreModule.kt @@ -0,0 +1,20 @@ +package org.sopt.and.di + +import android.content.SharedPreferences +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import org.sopt.and.data.local.TokenLocalDataSource +import org.sopt.and.data.local.TokenLocalDataSourceImpl +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +object TokenLocalDataSourceModule { + @Provides + @Singleton + fun provideTokenLocalDataSource(sharedPreferences: SharedPreferences): TokenLocalDataSource { + return TokenLocalDataSourceImpl(sharedPreferences) + } +} \ No newline at end of file From 3ba2ba57bf7197dedfa155c9529fd5cdff493384 Mon Sep 17 00:00:00 2001 From: SYAAINN Date: Fri, 15 Nov 2024 19:18:36 +0900 Subject: [PATCH 14/19] =?UTF-8?q?[add/#8]=20=EB=A7=88=EC=9D=B4=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20=EC=84=9C=EB=B2=84=ED=86=B5=EC=8B=A0=20?= =?UTF-8?q?=EC=83=81=ED=83=9C=EB=A5=BC=20=EC=A0=80=EC=9E=A5=ED=95=A0=20Sta?= =?UTF-8?q?te=EB=A5=BC=20=EC=83=9D=EC=84=B1=ED=95=A9=EB=8B=88=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sopt/and/presentation/ui/main/screen/UserHobbyState.kt | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 app/src/main/java/org/sopt/and/presentation/ui/main/screen/UserHobbyState.kt diff --git a/app/src/main/java/org/sopt/and/presentation/ui/main/screen/UserHobbyState.kt b/app/src/main/java/org/sopt/and/presentation/ui/main/screen/UserHobbyState.kt new file mode 100644 index 0000000..fa33bab --- /dev/null +++ b/app/src/main/java/org/sopt/and/presentation/ui/main/screen/UserHobbyState.kt @@ -0,0 +1,7 @@ +package org.sopt.and.presentation.ui.main.screen + +sealed class UserHobbyState { + data object Idle: UserHobbyState() + data class Success(val hobby: String): UserHobbyState() + data class Failure(val errorMessage: String): UserHobbyState() +} \ No newline at end of file From c08635f878c1dcc1dd30b0c1fd4ddc7606aa2284 Mon Sep 17 00:00:00 2001 From: SYAAINN Date: Fri, 15 Nov 2024 19:21:52 +0900 Subject: [PATCH 15/19] =?UTF-8?q?[chore/#8]=20=EC=84=9C=EB=B2=84=ED=86=B5?= =?UTF-8?q?=EC=8B=A0=EC=97=90=20=EB=A7=9E=EC=B6=94=EC=96=B4=20SignInState,?= =?UTF-8?q?=20SignUpState=EB=A5=BC=20=EC=88=98=EC=A0=95=ED=95=A9=EB=8B=88?= =?UTF-8?q?=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../and/presentation/ui/auth/screen/AuthState.kt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/org/sopt/and/presentation/ui/auth/screen/AuthState.kt b/app/src/main/java/org/sopt/and/presentation/ui/auth/screen/AuthState.kt index dbbe130..81ef43a 100644 --- a/app/src/main/java/org/sopt/and/presentation/ui/auth/screen/AuthState.kt +++ b/app/src/main/java/org/sopt/and/presentation/ui/auth/screen/AuthState.kt @@ -1,17 +1,17 @@ package org.sopt.and.presentation.ui.auth.screen +import org.sopt.and.data.remote.dto.response.ResponseUserRegistrationDto + sealed class SignInState { data object Idle : SignInState() data object EmailEmpty : SignInState() data object PasswordEmpty : SignInState() - data object EmailInvalid : SignInState() - data object PasswordInvalid : SignInState() data object Success : SignInState() + data class Failure(val errorMessage: String) : SignInState() } sealed class SignUpState { - data object Idle: SignUpState() - data object EmailInvalid: SignUpState() - data object PasswordInvalid: SignUpState() - data object Success: SignUpState() + data object Idle : SignUpState() + data class Success(val response: ResponseUserRegistrationDto?) : SignUpState() + data class Failure(val errorMessage: String) : SignUpState() } From bf155e75896f80584cd5ad242d618971c133d238 Mon Sep 17 00:00:00 2001 From: SYAAINN Date: Fri, 15 Nov 2024 19:22:49 +0900 Subject: [PATCH 16/19] =?UTF-8?q?[feat/#8]=20=EC=84=9C=EB=B2=84=ED=86=B5?= =?UTF-8?q?=EC=8B=A0=20=EB=A1=9C=EC=A7=81=EC=9D=84=20viewModel=EC=97=90=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9=ED=95=A9=EB=8B=88=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/auth/screen/AuthViewModel.kt | 86 +++++++++++++++---- .../ui/main/screen/MainViewModel.kt | 43 +++++++++- 2 files changed, 109 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/org/sopt/and/presentation/ui/auth/screen/AuthViewModel.kt b/app/src/main/java/org/sopt/and/presentation/ui/auth/screen/AuthViewModel.kt index 301fd42..4834a0b 100644 --- a/app/src/main/java/org/sopt/and/presentation/ui/auth/screen/AuthViewModel.kt +++ b/app/src/main/java/org/sopt/and/presentation/ui/auth/screen/AuthViewModel.kt @@ -1,39 +1,87 @@ package org.sopt.and.presentation.ui.auth.screen -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData +import android.util.Log import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow -import org.sopt.and.presentation.model.User -import org.sopt.and.presentation.model.validateSignUp +import kotlinx.coroutines.launch +import org.sopt.and.data.remote.dto.request.RequestLoginDto +import org.sopt.and.data.remote.dto.request.RequestUserRegistrationDto +import org.sopt.and.data.remote.dto.response.ResponseLoginDto +import org.sopt.and.data.remote.dto.response.ResponseUserRegistrationDto +import org.sopt.and.data.repository.TokenRepository +import org.sopt.and.di.ServicePool +import retrofit2.Call +import retrofit2.Callback +import retrofit2.Response import javax.inject.Inject @HiltViewModel -class AuthViewModel @Inject constructor() : ViewModel() { - private val _user = MutableLiveData() - val user: LiveData = _user +class AuthViewModel @Inject constructor( + private val tokenRepository: TokenRepository, +) : ViewModel() { + private val authService by lazy { ServicePool.authService } private val _signInState = MutableStateFlow(SignInState.Idle) - val signInState : StateFlow = _signInState + val signInState: StateFlow = _signInState private val _signUpState = MutableStateFlow(SignUpState.Idle) - val signUpState : StateFlow = _signUpState + val signUpState: StateFlow = _signUpState fun validateSignIn(inputEmail: String, inputPassword: String) { - _signInState.value = when { - inputEmail.isEmpty() -> SignInState.EmailEmpty - inputPassword.isEmpty() -> SignInState.PasswordEmpty - _user.value?.email != inputEmail -> SignInState.EmailInvalid - _user.value?.password != inputPassword -> SignInState.PasswordInvalid - else -> SignInState.Success + viewModelScope.launch { + authService.login(RequestLoginDto(inputEmail, inputPassword)).enqueue(object : + Callback { + override fun onResponse( + call: Call, + response: Response + ) { + if (response.isSuccessful) { + _signInState.value = SignInState.Success + tokenRepository.setToken(token = response.body()?.result!!.token) + Log.d("token", tokenRepository.getToken()) + } else { + _signInState.value = SignInState.Failure(response.message()) + } + } + + override fun onFailure( + call: Call, + t: Throwable + ) { + _signInState.value = SignInState.Failure(t.message.toString()) + } + } + ) } } - fun validateSignUp(email: String, password: String) { - val authInfo = User(email, password) - _signUpState.value = authInfo.validateSignUp() - if (_signUpState.value is SignUpState.Success) _user.value = authInfo + fun validateSignUp(email: String, password: String, hobby: String) { + viewModelScope.launch { + authService.registerUser(RequestUserRegistrationDto(email, password, hobby)) + .enqueue(object : + Callback { + override fun onResponse( + call: Call, + response: Response + ) { + if (response.isSuccessful) { + _signUpState.value = SignUpState.Success(response.body()) + } else { + _signUpState.value = SignUpState.Failure(response.message()) + } + } + + override fun onFailure( + call: Call, + t: Throwable + ) { + _signUpState.value = SignUpState.Failure(t.message.toString()) + } + } + ) + } } } \ No newline at end of file diff --git a/app/src/main/java/org/sopt/and/presentation/ui/main/screen/MainViewModel.kt b/app/src/main/java/org/sopt/and/presentation/ui/main/screen/MainViewModel.kt index 6c77450..5b29e56 100644 --- a/app/src/main/java/org/sopt/and/presentation/ui/main/screen/MainViewModel.kt +++ b/app/src/main/java/org/sopt/and/presentation/ui/main/screen/MainViewModel.kt @@ -1,11 +1,52 @@ package org.sopt.and.presentation.ui.main.screen import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.launch +import org.sopt.and.data.local.TokenLocalDataSource +import org.sopt.and.data.remote.dto.response.ResponseGetMyHobbyDto +import org.sopt.and.di.ServicePool +import retrofit2.Call +import retrofit2.Callback +import retrofit2.Response import javax.inject.Inject @HiltViewModel -class MainViewModel @Inject constructor() : ViewModel() { +class MainViewModel @Inject constructor( + private val tokenLocalDataSource: TokenLocalDataSource +) : ViewModel() { + private val userService by lazy { ServicePool.userService } + private val _userHobbyState = MutableStateFlow(UserHobbyState.Idle) + val userHobbyState: StateFlow = _userHobbyState + fun getUserHobby() { + viewModelScope.launch { + userService.getMyHobby(token = tokenLocalDataSource.token).enqueue(object : + Callback { + override fun onResponse( + call: Call, + response: Response + ) { + if (response.isSuccessful) { + _userHobbyState.value = + UserHobbyState.Success(response.body()?.result!!.hobby) + } else { + _userHobbyState.value = UserHobbyState.Failure(response.message()) + } + } + + override fun onFailure( + call: Call, + t: Throwable + ) { + _userHobbyState.value = UserHobbyState.Failure(t.message.toString()) + } + } + ) + } + } } \ No newline at end of file From 7e6b0c6a154147ac5f733a3634f4d95c6ba08160 Mon Sep 17 00:00:00 2001 From: SYAAINN Date: Fri, 15 Nov 2024 19:26:23 +0900 Subject: [PATCH 17/19] =?UTF-8?q?[refactor/#8]=20viewModel=20=EC=84=A0?= =?UTF-8?q?=EC=96=B8=20=EC=9C=84=EC=B9=98=EB=A5=BC=20navHost=20=EC=97=90?= =?UTF-8?q?=EC=84=9C=20Route=20=EB=8B=A8=EC=9C=BC=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=ED=95=A9=EB=8B=88=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sopt/and/presentation/ui/navigation/WavveNavHost.kt | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/org/sopt/and/presentation/ui/navigation/WavveNavHost.kt b/app/src/main/java/org/sopt/and/presentation/ui/navigation/WavveNavHost.kt index eb61c1b..508909f 100644 --- a/app/src/main/java/org/sopt/and/presentation/ui/navigation/WavveNavHost.kt +++ b/app/src/main/java/org/sopt/and/presentation/ui/navigation/WavveNavHost.kt @@ -4,21 +4,16 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavHostController import androidx.navigation.compose.NavHost import org.sopt.and.presentation.ui.auth.navigation.authNavGraph -import org.sopt.and.presentation.ui.auth.screen.AuthViewModel import org.sopt.and.presentation.ui.main.navigation.mainNavGraph -import org.sopt.and.presentation.ui.main.screen.MainViewModel @Composable fun WavveNavHost( navController: NavHostController, modifier: Modifier = Modifier, ) { - val authViewModel: AuthViewModel = hiltViewModel() - val mainViewModel: MainViewModel = hiltViewModel() Box( modifier = modifier.fillMaxSize() ) { @@ -26,8 +21,8 @@ fun WavveNavHost( navController = navController, startDestination = WavveRoute.AUTH, ) { - authNavGraph(navController, authViewModel) - mainNavGraph(navController, mainViewModel) + authNavGraph(navController) + mainNavGraph(navController) } } } \ No newline at end of file From c4f2044ddad0a5bca4f98b9653d7c4197f454f25 Mon Sep 17 00:00:00 2001 From: SYAAINN Date: Fri, 15 Nov 2024 19:29:28 +0900 Subject: [PATCH 18/19] =?UTF-8?q?[refactor/#8]=20navigate=20=ED=95=A8?= =?UTF-8?q?=EC=88=98=EB=A5=BC=20=EC=83=81=EC=9C=84=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EC=A0=80=EB=B8=94=EB=A1=9C=20=EC=9D=B4=EB=8F=99=ED=95=A9?= =?UTF-8?q?=EB=8B=88=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/auth/navigation/AuthNavGraph.kt | 12 ++- .../ui/auth/screen/SignInScreen.kt | 40 ++++------ .../ui/auth/screen/SignUpScreen.kt | 77 +++++++++++++------ 3 files changed, 71 insertions(+), 58 deletions(-) diff --git a/app/src/main/java/org/sopt/and/presentation/ui/auth/navigation/AuthNavGraph.kt b/app/src/main/java/org/sopt/and/presentation/ui/auth/navigation/AuthNavGraph.kt index 65b5223..7457aa4 100644 --- a/app/src/main/java/org/sopt/and/presentation/ui/auth/navigation/AuthNavGraph.kt +++ b/app/src/main/java/org/sopt/and/presentation/ui/auth/navigation/AuthNavGraph.kt @@ -4,15 +4,13 @@ import androidx.navigation.NavGraphBuilder import androidx.navigation.NavHostController import androidx.navigation.compose.composable import androidx.navigation.navigation -import kotlinx.serialization.Serializable -import org.sopt.and.presentation.ui.auth.screen.AuthViewModel import org.sopt.and.presentation.ui.auth.screen.SignInRoute import org.sopt.and.presentation.ui.auth.screen.SignUpRoute +import org.sopt.and.presentation.ui.main.navigation.navigateToMain import org.sopt.and.presentation.ui.navigation.WavveRoute fun NavGraphBuilder.authNavGraph( navController: NavHostController, - authViewModel: AuthViewModel, ) { navigation( startDestination = WavveRoute.SIGN_IN, @@ -20,15 +18,15 @@ fun NavGraphBuilder.authNavGraph( ) { composable(route = WavveRoute.SIGN_IN) { SignInRoute( - navController = navController, - authViewModel = authViewModel, + navigateToSignUp = { navController.navigateToSignUp() }, + navigateToMain = { navController.navigateToMain() }, ) } composable(route = WavveRoute.SIGN_UP) { SignUpRoute( - navController = navController, - authViewModel = authViewModel, + navigateToSignIn = { navController.navigateToSignIn() }, + navigateToBack = { navController.popBackStack() } ) } } diff --git a/app/src/main/java/org/sopt/and/presentation/ui/auth/screen/SignInScreen.kt b/app/src/main/java/org/sopt/and/presentation/ui/auth/screen/SignInScreen.kt index c4fdae4..2302604 100644 --- a/app/src/main/java/org/sopt/and/presentation/ui/auth/screen/SignInScreen.kt +++ b/app/src/main/java/org/sopt/and/presentation/ui/auth/screen/SignInScreen.kt @@ -18,7 +18,6 @@ import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.Text import androidx.compose.material3.VerticalDivider import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -36,42 +35,33 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import androidx.navigation.NavHostController +import androidx.hilt.navigation.compose.hiltViewModel import org.sopt.and.R import org.sopt.and.presentation.ui.auth.component.AuthTextField -import org.sopt.and.presentation.ui.auth.component.SocialPlatformList import org.sopt.and.presentation.ui.auth.component.SocialPlatformIconRow -import org.sopt.and.presentation.ui.auth.navigation.navigateToSignUp -import org.sopt.and.presentation.ui.main.navigation.navigateToMain -import org.sopt.and.presentation.utils.showToast +import org.sopt.and.presentation.ui.auth.component.SocialPlatformList +import org.sopt.and.presentation.util.showToast import org.sopt.and.ui.theme.ANDANDROIDTheme @Composable fun SignInRoute( - navController: NavHostController, - authViewModel: AuthViewModel, + authViewModel: AuthViewModel = hiltViewModel(), + navigateToSignUp: () -> Unit, + navigateToMain: () -> Unit, ) { val context = LocalContext.current val signInState by authViewModel.signInState.collectAsState() - val onSignUpClick = { navController.navigateToSignUp() } val onSignInClick: (String, String) -> Unit = { email, password -> authViewModel.validateSignIn(email, password) - } - - LaunchedEffect(signInState) { when (signInState) { - is SignInState.EmailEmpty -> showToast(context = context, message = "이메일을 입력하세요") - is SignInState.PasswordEmpty -> showToast(context = context, message = "비밀번호를 입력하세요") - is SignInState.EmailInvalid -> showToast(context = context, message = "이메일이 일치하지 않습니다") - is SignInState.PasswordInvalid -> showToast( - context = context, - message = "비밀번호가 일치하지 않습니다" - ) - is SignInState.Success -> { - showToast(context = context, message = "로그인에 성공했습니다") - navController.navigateToMain(authViewModel.user.value?.email.orEmpty()) + showToast(context = context, message = "로그인에 성공했습니다.") + navigateToMain() + } + + is SignInState.Failure -> { + showToast(context = context, message = "로그인에 실패했습니다.") } else -> {} @@ -79,7 +69,7 @@ fun SignInRoute( } SignInScreen( - onSignUpClick = onSignUpClick, + onSignUpClick = navigateToSignUp, onSignInClick = onSignInClick, ) } @@ -176,7 +166,7 @@ fun SignInScreen( ) SignInOption( text = "회원가입", - onClick = { onSignUpClick() } + onClick = onSignUpClick ) } @@ -255,8 +245,6 @@ fun SignInOption( ) } - - @Preview(showBackground = true) @Composable fun SignInPreview() { diff --git a/app/src/main/java/org/sopt/and/presentation/ui/auth/screen/SignUpScreen.kt b/app/src/main/java/org/sopt/and/presentation/ui/auth/screen/SignUpScreen.kt index 3f955b9..126d81b 100644 --- a/app/src/main/java/org/sopt/and/presentation/ui/auth/screen/SignUpScreen.kt +++ b/app/src/main/java/org/sopt/and/presentation/ui/auth/screen/SignUpScreen.kt @@ -33,60 +33,57 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import androidx.navigation.NavHostController +import androidx.hilt.navigation.compose.hiltViewModel import org.sopt.and.R import org.sopt.and.presentation.ui.auth.component.AuthTextField -import org.sopt.and.presentation.ui.auth.component.SocialPlatformList import org.sopt.and.presentation.ui.auth.component.SocialPlatformIconRow -import org.sopt.and.presentation.ui.auth.navigation.navigateToSignIn -import org.sopt.and.presentation.utils.showToast +import org.sopt.and.presentation.ui.auth.component.SocialPlatformList +import org.sopt.and.presentation.util.showToast import org.sopt.and.ui.theme.ANDANDROIDTheme @Composable fun SignUpRoute( - authViewModel: AuthViewModel, - navController: NavHostController, + authViewModel: AuthViewModel = hiltViewModel(), + navigateToSignIn: () -> Unit, + navigateToBack: () -> Unit, ) { val context = LocalContext.current val signUpState by authViewModel.signUpState.collectAsState() - val onSignUpClick: (String, String) -> Unit = { email, password -> - authViewModel.validateSignUp(email, password) + val onSignUpClick: (String, String, String) -> Unit = { username, password, hobby -> + authViewModel.validateSignUp(username, password, hobby) when (signUpState) { - is SignUpState.EmailInvalid -> showToast( - context = context, - message = "아이디가 잘못된 형식입니다" - ) - - is SignUpState.PasswordInvalid -> showToast( - context = context, - message = "비밀번호가 잘못된 형식입니다" - ) - is SignUpState.Success -> { - showToast(context = context, message = "회원가입에 성공했습니다.") - navController.navigateToSignIn() + showToast( + context = context, + message = "회원가입에 성공했습니다. 회원번호는 ${(signUpState as SignUpState.Success).response?.result?.no}입니다." + ) + navigateToSignIn() + } + + is SignUpState.Failure -> { + showToast(context = context, message = "회원가입에 실패하였습니다.") } else -> {} } } - val onCancelClick: () -> Unit = { navController.popBackStack() } SignUpScreen( onSignUpClick = onSignUpClick, - onCancelClick = onCancelClick, + onCancelClick = navigateToBack, ) } @Composable fun SignUpScreen( - onSignUpClick: (String, String) -> Unit, + onSignUpClick: (String, String, String) -> Unit, onCancelClick: () -> Unit, ) { var inputEmail by remember { mutableStateOf("") } var inputPassword by remember { mutableStateOf("") } + var inputHobby by remember { mutableStateOf("") } Column( modifier = Modifier @@ -157,7 +154,7 @@ fun SignUpScreen( .fillMaxWidth() .clip(shape = RoundedCornerShape(4.dp)) .background(color = Color(0xFF262626)), - hint = "wavve@example.com" + hint = "sonny" ) Spacer(modifier = Modifier.height(8.dp)) Row( @@ -213,6 +210,36 @@ fun SignUpScreen( ) } + AuthTextField( + value = inputHobby, + onValueChange = { newValue -> inputHobby = newValue }, + modifier = Modifier + .fillMaxWidth() + .clip(shape = RoundedCornerShape(4.dp)) + .background(color = Color(0xFF262626)), + hint = "basket" + ) + Spacer(modifier = Modifier.height(8.dp)) + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically + ) { + Image( + painter = painterResource(R.drawable.img_signup_caution), + contentDescription = "", + modifier = Modifier + .align(Alignment.Top) + .padding(2.dp) + .size(14.dp) + ) + Text( + text = "8자 미만으로 작성해주세요.", + fontSize = 12.sp, + lineHeight = 14.sp, + color = Color(0xFF848484) + ) + } + Spacer(modifier = Modifier.height(40.dp)) Row( @@ -282,7 +309,7 @@ fun SignUpScreen( .fillMaxWidth() .background(color = Color(0xFF0F42C7)) .clickable( - onClick = { onSignUpClick(inputEmail, inputPassword) } + onClick = { onSignUpClick(inputEmail, inputPassword, inputHobby) } ), contentAlignment = Alignment.Center ) { From 35bed354c6d1a883774a14431a572e2f9a830573 Mon Sep 17 00:00:00 2001 From: SYAAINN Date: Fri, 15 Nov 2024 19:30:02 +0900 Subject: [PATCH 19/19] =?UTF-8?q?[refactor/#8]=20=EB=B0=94=ED=85=80=20?= =?UTF-8?q?=EB=84=A4=EB=B9=84=EA=B2=8C=EC=9D=B4=EC=85=98=20=EA=B5=AC?= =?UTF-8?q?=EC=A1=B0=EB=A5=BC=20=EC=88=98=EC=A0=95=ED=95=A9=EB=8B=88?= =?UTF-8?q?=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/main/navigation/MainNavGraph.kt | 44 +++++++------ .../ui/main/navigation/MainNavigator.kt | 18 ++++-- .../presentation/ui/main/screen/HomeScreen.kt | 10 +-- .../presentation/ui/main/screen/MainScreen.kt | 61 +++++++++++++------ .../ui/main/screen/MyPageScreen.kt | 9 +-- .../ui/main/screen/SearchScreen.kt | 9 +-- .../presentation/ui/navigation/WavveRoute.kt | 4 ++ 7 files changed, 93 insertions(+), 62 deletions(-) diff --git a/app/src/main/java/org/sopt/and/presentation/ui/main/navigation/MainNavGraph.kt b/app/src/main/java/org/sopt/and/presentation/ui/main/navigation/MainNavGraph.kt index 8a7a6c2..cca39d2 100644 --- a/app/src/main/java/org/sopt/and/presentation/ui/main/navigation/MainNavGraph.kt +++ b/app/src/main/java/org/sopt/and/presentation/ui/main/navigation/MainNavGraph.kt @@ -2,30 +2,36 @@ package org.sopt.and.presentation.ui.main.navigation import androidx.navigation.NavGraphBuilder import androidx.navigation.NavHostController -import androidx.navigation.NavType import androidx.navigation.compose.composable -import androidx.navigation.navArgument +import androidx.navigation.navigation +import org.sopt.and.presentation.ui.main.screen.HomeScreen import org.sopt.and.presentation.ui.main.screen.MainRoute -import org.sopt.and.presentation.ui.main.screen.MainViewModel -import org.sopt.and.presentation.ui.navigation.KeyStorage +import org.sopt.and.presentation.ui.main.screen.MyPageScreen +import org.sopt.and.presentation.ui.main.screen.SearchScreen import org.sopt.and.presentation.ui.navigation.WavveRoute fun NavGraphBuilder.mainNavGraph( navController: NavHostController, - mainViewModel: MainViewModel, ) { - composable( - route = "${WavveRoute.MAIN}/{${KeyStorage.USER_EMAIL}}", - arguments = listOf( - navArgument(KeyStorage.USER_EMAIL) { type = NavType.StringType } - ) - ) { navBackStackEntry -> - val userEmail = - navBackStackEntry.arguments?.getString(KeyStorage.USER_EMAIL) ?: "unknown@example.com" - MainRoute( - navController = navController, - mainViewModel = mainViewModel, - userEmail = userEmail, - ) + navigation( + startDestination = WavveRoute.MAIN, + route = WavveRoute.WAVVE + ) { + composable(route = WavveRoute.MAIN) { + MainRoute( + navigateToHome = { navController.navigateToHome() }, + navigateToSearch = { navController.navigateToSearch() }, + navigateToMy = { navController.navigateToMy() } + ) + } + composable(route = WavveRoute.HOME) { + HomeScreen() + } + composable(route = WavveRoute.SEARCH) { + SearchScreen() + } + composable(route = WavveRoute.MY) { + MyPageScreen(userHobby = "") + } } -} +} \ No newline at end of file diff --git a/app/src/main/java/org/sopt/and/presentation/ui/main/navigation/MainNavigator.kt b/app/src/main/java/org/sopt/and/presentation/ui/main/navigation/MainNavigator.kt index d814e55..f4b2028 100644 --- a/app/src/main/java/org/sopt/and/presentation/ui/main/navigation/MainNavigator.kt +++ b/app/src/main/java/org/sopt/and/presentation/ui/main/navigation/MainNavigator.kt @@ -3,8 +3,18 @@ package org.sopt.and.presentation.ui.main.navigation import androidx.navigation.NavController import org.sopt.and.presentation.ui.navigation.WavveRoute -fun NavController.navigateToMain( - userEmail: String, -) { - navigate("${WavveRoute.MAIN}/$userEmail") +fun NavController.navigateToMain() { + navigate(WavveRoute.MAIN) +} + +fun NavController.navigateToHome() { + navigate(WavveRoute.HOME) +} + +fun NavController.navigateToSearch() { + navigate(WavveRoute.SEARCH) +} + +fun NavController.navigateToMy() { + navigate(WavveRoute.MY) } \ No newline at end of file diff --git a/app/src/main/java/org/sopt/and/presentation/ui/main/screen/HomeScreen.kt b/app/src/main/java/org/sopt/and/presentation/ui/main/screen/HomeScreen.kt index 98847cd..2d8b56e 100644 --- a/app/src/main/java/org/sopt/and/presentation/ui/main/screen/HomeScreen.kt +++ b/app/src/main/java/org/sopt/and/presentation/ui/main/screen/HomeScreen.kt @@ -4,7 +4,6 @@ import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize @@ -43,14 +42,11 @@ import org.sopt.and.presentation.ui.main.component.todayTop20Images import org.sopt.and.ui.theme.ANDANDROIDTheme @Composable -fun HomeScreen( - paddingValues: PaddingValues -) { +fun HomeScreen() { LazyColumn( modifier = Modifier .fillMaxSize() .background(color = Color(0xFF161616)) - .padding(paddingValues) .padding(10.dp), horizontalAlignment = Alignment.CenterHorizontally ) { @@ -194,8 +190,6 @@ fun HomeHorizontalBanner( @Composable fun ShowHomeScreen() { ANDANDROIDTheme { - HomeScreen( - paddingValues = PaddingValues(0.dp) - ) + } } \ No newline at end of file diff --git a/app/src/main/java/org/sopt/and/presentation/ui/main/screen/MainScreen.kt b/app/src/main/java/org/sopt/and/presentation/ui/main/screen/MainScreen.kt index 9982195..7bd8cfd 100644 --- a/app/src/main/java/org/sopt/and/presentation/ui/main/screen/MainScreen.kt +++ b/app/src/main/java/org/sopt/and/presentation/ui/main/screen/MainScreen.kt @@ -1,8 +1,10 @@ package org.sopt.and.presentation.ui.main.screen import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.CircleShape import androidx.compose.material3.NavigationBar @@ -11,6 +13,8 @@ import androidx.compose.material3.NavigationBarItemDefaults import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -24,24 +28,31 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.vectorResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import androidx.navigation.NavHostController +import androidx.hilt.navigation.compose.hiltViewModel import org.sopt.and.R import org.sopt.and.ui.theme.ANDANDROIDTheme @Composable fun MainRoute( - navController: NavHostController, - mainViewModel: MainViewModel, - userEmail: String, + mainViewModel: MainViewModel = hiltViewModel(), + navigateToHome: () -> Unit, + navigateToSearch: () -> Unit, + navigateToMy: () -> Unit, ) { + val userHobbyState by mainViewModel.userHobbyState.collectAsState() + + LaunchedEffect(Unit) { + mainViewModel.getUserHobby() + } + MainScreen( - userEmail = userEmail + userHobbyState = userHobbyState, ) } @Composable fun MainScreen( - userEmail: String + userHobbyState: UserHobbyState, ) { var selectedTab by remember { mutableStateOf(MainTabList.HOME) } val onTabSelected: (MainTabList) -> Unit = { tab -> @@ -127,23 +138,39 @@ fun MainScreen( containerColor = Color.Black, contentWindowInsets = WindowInsets(0.dp, 0.dp, 0.dp, 0.dp), content = { innerPadding -> - // selectedTab 값에 따라 표시되는 화면을 변경 - when (selectedTab) { - MainTabList.HOME -> HomeScreen(innerPadding) - MainTabList.SEARCH -> SearchScreen(innerPadding) - MainTabList.MY -> MyPageScreen( - paddingValues = innerPadding, - userEmail = userEmail - ) + Box( + modifier = Modifier + .fillMaxSize() + .padding(innerPadding) + ) { + when (selectedTab) { + MainTabList.HOME -> HomeScreen() + MainTabList.SEARCH -> SearchScreen() + MainTabList.MY -> { + when (userHobbyState) { + is UserHobbyState.Success -> { + val userHobby = userHobbyState.hobby + MyPageScreen(userHobby = userHobby) + } + + is UserHobbyState.Failure -> { + val errorMessage = userHobbyState.errorMessage + } + + else -> {} + } + } + } } + } ) } sealed class MainTabList { - data object HOME: MainTabList() - data object SEARCH: MainTabList() - data object MY: MainTabList() + data object HOME : MainTabList() + data object SEARCH : MainTabList() + data object MY : MainTabList() } diff --git a/app/src/main/java/org/sopt/and/presentation/ui/main/screen/MyPageScreen.kt b/app/src/main/java/org/sopt/and/presentation/ui/main/screen/MyPageScreen.kt index 431adb2..4ae120b 100644 --- a/app/src/main/java/org/sopt/and/presentation/ui/main/screen/MyPageScreen.kt +++ b/app/src/main/java/org/sopt/and/presentation/ui/main/screen/MyPageScreen.kt @@ -4,7 +4,6 @@ import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize @@ -28,15 +27,11 @@ import androidx.compose.ui.unit.sp import org.sopt.and.R @Composable -fun MyPageScreen( - paddingValues: PaddingValues, - userEmail: String -) { +fun MyPageScreen(userHobby: String) { Column( modifier = Modifier .fillMaxWidth() .background(color = Color(0xFF161616)) - .padding(paddingValues) ) { Row( modifier = Modifier @@ -55,7 +50,7 @@ fun MyPageScreen( ) Spacer(modifier = Modifier.width(12.dp)) Text( - text = "${userEmail}님", + text = "${userHobby}님", color = Color.White ) Spacer(modifier = Modifier.weight(1f)) diff --git a/app/src/main/java/org/sopt/and/presentation/ui/main/screen/SearchScreen.kt b/app/src/main/java/org/sopt/and/presentation/ui/main/screen/SearchScreen.kt index bdcc9e6..ce42cae 100644 --- a/app/src/main/java/org/sopt/and/presentation/ui/main/screen/SearchScreen.kt +++ b/app/src/main/java/org/sopt/and/presentation/ui/main/screen/SearchScreen.kt @@ -3,9 +3,7 @@ package org.sopt.and.presentation.ui.main.screen import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.padding import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment @@ -13,14 +11,11 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color @Composable -fun SearchScreen( - paddingValues: PaddingValues -) { +fun SearchScreen() { Column( modifier = Modifier .fillMaxSize() - .background(color = Color(0xFF161616)) - .padding(paddingValues), + .background(color = Color(0xFF161616)), verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally ) { diff --git a/app/src/main/java/org/sopt/and/presentation/ui/navigation/WavveRoute.kt b/app/src/main/java/org/sopt/and/presentation/ui/navigation/WavveRoute.kt index 29da919..79572bf 100644 --- a/app/src/main/java/org/sopt/and/presentation/ui/navigation/WavveRoute.kt +++ b/app/src/main/java/org/sopt/and/presentation/ui/navigation/WavveRoute.kt @@ -7,5 +7,9 @@ object WavveRoute { const val SIGN_UP = "sign_up" // mainNavGraph + const val WAVVE = "wavve" const val MAIN = "main" + const val HOME = "home" + const val SEARCH = "search" + const val MY = "my" } \ No newline at end of file