diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 4fdda6a..487f2d2 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -2,6 +2,8 @@ plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
kotlin("plugin.serialization") version "2.0.10"
+ id("com.google.devtools.ksp")
+ id("com.google.dagger.hilt.android")
}
android {
@@ -54,6 +56,9 @@ android {
dependencies {
+ implementation("com.google.dagger:hilt-android:2.51.1")
+ ksp("com.google.dagger:hilt-android-compiler:2.51.1")
+
implementation("androidx.core:core-ktx:1.13.1")
implementation("androidx.appcompat:appcompat:1.7.0")
implementation("com.google.android.material:material:1.12.0")
@@ -64,12 +69,12 @@ dependencies {
implementation("androidx.navigation:navigation-ui-ktx:2.7.7")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.4")
implementation("androidx.activity:activity-compose:1.9.1")
- implementation(platform("androidx.compose:compose-bom:2023.08.00"))
+ implementation(platform("androidx.compose:compose-bom:2024.11.00"))
implementation("androidx.compose.ui:ui-graphics")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.2.1")
androidTestImplementation("androidx.test.espresso:espresso-core:3.6.1")
- androidTestImplementation(platform("androidx.compose:compose-bom:2023.08.00"))
+ androidTestImplementation(platform("androidx.compose:compose-bom:2024.11.00"))
val composeBom = platform("androidx.compose:compose-bom:2024.06.00")
implementation(composeBom)
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 2ab164d..bbd44e1 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -5,6 +5,7 @@
+
+
+
-
+
+
diff --git a/app/src/main/java/com/example/com_us/MainActivity.kt b/app/src/main/java/com/example/com_us/MainActivity.kt
index 92d94ef..ac4f7eb 100644
--- a/app/src/main/java/com/example/com_us/MainActivity.kt
+++ b/app/src/main/java/com/example/com_us/MainActivity.kt
@@ -9,7 +9,9 @@ import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.setupActionBarWithNavController
import androidx.navigation.ui.setupWithNavController
import com.example.com_us.databinding.ActivityMainBinding
+import dagger.hilt.android.AndroidEntryPoint
+@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
diff --git a/app/src/main/java/com/example/com_us/base/AppInterceptor.kt b/app/src/main/java/com/example/com_us/base/AppInterceptor.kt
new file mode 100644
index 0000000..05b496f
--- /dev/null
+++ b/app/src/main/java/com/example/com_us/base/AppInterceptor.kt
@@ -0,0 +1,28 @@
+package com.example.com_us.base
+
+import android.util.Log
+import okhttp3.Interceptor
+import okhttp3.Response
+import java.io.IOException
+
+ class AppInterceptor(private val accessToken: String) : Interceptor {
+ private val contentType = "application/json"
+ @Throws(IOException::class)
+ override fun intercept(chain: Interceptor.Chain) : Response = with(chain) {
+ val newRequest = request().newBuilder()
+ .addHeader("Content-Type", contentType)
+ .addHeader("Authorization", accessToken)
+ .build()
+
+ val response = proceed(newRequest)
+ when (response.code) {
+ 401, 404 -> {
+ Log.d("API FAILURE", response.toString())
+ }
+ 500 -> {
+ Log.d("API FAILURE 500", response.toString())
+ }
+ }
+ response
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/com_us/base/Application.kt b/app/src/main/java/com/example/com_us/base/Application.kt
new file mode 100644
index 0000000..209fd62
--- /dev/null
+++ b/app/src/main/java/com/example/com_us/base/Application.kt
@@ -0,0 +1,8 @@
+package com.example.com_us.base
+
+import android.app.Application
+import dagger.hilt.android.HiltAndroidApp
+
+@HiltAndroidApp
+class Application : Application() {
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/com_us/base/data/BaseResponse.kt b/app/src/main/java/com/example/com_us/base/data/BaseResponse.kt
new file mode 100644
index 0000000..a2c6fac
--- /dev/null
+++ b/app/src/main/java/com/example/com_us/base/data/BaseResponse.kt
@@ -0,0 +1,26 @@
+package com.example.com_us.base.data
+
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class BaseResponse(
+ val status: Int,
+ val message: String,
+ val data: T? = null,
+)
+
+@Serializable
+data class BaseResponseNoData(
+ val status: Int,
+ val message: String,
+)
+
+fun BaseResponse.toResult(): Result {
+ return when{
+ status == 200 && data != null -> Result.success(data)
+ status == 200 && data == null -> Result.failure(NetworkError.NullDataError())
+ status == 400 or 401 -> Result.failure(NetworkError.ApiError(status, message))
+ status == 500 -> Result.failure(NetworkError.ApiError(status, message))
+ else -> Result.failure(NetworkError.ApiError(status, message))
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/com_us/base/data/NetworkError.kt b/app/src/main/java/com/example/com_us/base/data/NetworkError.kt
new file mode 100644
index 0000000..9d3a18b
--- /dev/null
+++ b/app/src/main/java/com/example/com_us/base/data/NetworkError.kt
@@ -0,0 +1,17 @@
+package com.example.com_us.base.data
+
+sealed class NetworkError : Exception(){
+ data class ApiError(
+ val statusCode : Int,
+ override val message : String
+ ) : NetworkError()
+
+ data class NetworkException(
+ override val cause : Throwable,
+ ) : NetworkError()
+
+ data class NullDataError(
+ override val message : String = "Data is null"
+ ) : NetworkError()
+
+}
diff --git a/app/src/main/java/com/example/com_us/base/di/ServiceModule.kt b/app/src/main/java/com/example/com_us/base/di/ServiceModule.kt
new file mode 100644
index 0000000..ad5b670
--- /dev/null
+++ b/app/src/main/java/com/example/com_us/base/di/ServiceModule.kt
@@ -0,0 +1,22 @@
+package com.example.com_us.base.di
+
+import android.content.Context
+import com.example.com_us.R
+import com.example.com_us.data.di.BaseUrl
+import dagger.Module
+import dagger.hilt.InstallIn
+import dagger.hilt.components.SingletonComponent
+import javax.inject.Singleton
+import dagger.Provides
+import dagger.hilt.android.qualifiers.ApplicationContext
+
+@Module
+@InstallIn(SingletonComponent::class)
+object ServiceModule {
+
+ @Provides
+ @BaseUrl
+ fun provideBaseUrl(
+ @ApplicationContext context: Context
+ ) : String = context.getString(R.string.baseUrl)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/com_us/data/datasource/HomeDataSource.kt b/app/src/main/java/com/example/com_us/data/datasource/HomeDataSource.kt
deleted file mode 100644
index 75cada0..0000000
--- a/app/src/main/java/com/example/com_us/data/datasource/HomeDataSource.kt
+++ /dev/null
@@ -1,8 +0,0 @@
-package com.example.com_us.data.datasource
-
-import com.example.com_us.data.response.BaseResponse
-import com.example.com_us.data.response.home.ResponseHomeDataDto
-
-interface HomeDataSource {
- suspend fun getHomeData() : BaseResponse
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/com_us/data/datasource/HomeRemoteDataSource.kt b/app/src/main/java/com/example/com_us/data/datasource/HomeRemoteDataSource.kt
deleted file mode 100644
index c43f617..0000000
--- a/app/src/main/java/com/example/com_us/data/datasource/HomeRemoteDataSource.kt
+++ /dev/null
@@ -1,11 +0,0 @@
-package com.example.com_us.data.datasource
-
-import com.example.com_us.data.response.BaseResponse
-import com.example.com_us.data.response.home.ResponseHomeDataDto
-import com.example.com_us.data.service.HomeService
-
-class HomeRemoteDataSource(private val homeService : HomeService) : HomeDataSource {
- override suspend fun getHomeData(): BaseResponse {
- return homeService.getHomeData()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/com_us/data/datasource/ProfileDataSource.kt b/app/src/main/java/com/example/com_us/data/datasource/ProfileDataSource.kt
deleted file mode 100644
index 536c81a..0000000
--- a/app/src/main/java/com/example/com_us/data/datasource/ProfileDataSource.kt
+++ /dev/null
@@ -1,8 +0,0 @@
-package com.example.com_us.data.datasource
-
-import com.example.com_us.data.response.BaseResponse
-import com.example.com_us.data.response.question.ResponseProfileDto
-
-interface ProfileDataSource {
- suspend fun getProfileData() : BaseResponse
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/com_us/data/datasource/ProfileRemoteDataSource.kt b/app/src/main/java/com/example/com_us/data/datasource/ProfileRemoteDataSource.kt
deleted file mode 100644
index f993e79..0000000
--- a/app/src/main/java/com/example/com_us/data/datasource/ProfileRemoteDataSource.kt
+++ /dev/null
@@ -1,11 +0,0 @@
-package com.example.com_us.data.datasource
-
-import com.example.com_us.data.response.BaseResponse
-import com.example.com_us.data.response.question.ResponseProfileDto
-import com.example.com_us.data.service.ProfileService
-
-class ProfileRemoteDataSource(private val profileService: ProfileService) : ProfileDataSource {
- override suspend fun getProfileData(): BaseResponse {
- return profileService.getProfileData()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/com_us/data/datasource/QuestionDataSource.kt b/app/src/main/java/com/example/com_us/data/datasource/QuestionDataSource.kt
deleted file mode 100644
index 91096a3..0000000
--- a/app/src/main/java/com/example/com_us/data/datasource/QuestionDataSource.kt
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.example.com_us.data.datasource
-
-import com.example.com_us.data.request.question.RequestAnswerDto
-import com.example.com_us.data.response.BaseResponse
-import com.example.com_us.data.response.BaseResponseNoData
-import com.example.com_us.data.response.question.ResponseAnswerDetailDto
-import com.example.com_us.data.response.question.ResponseAnswerDetailWithDateDto
-import com.example.com_us.data.response.question.ResponsePreviousAnswerDto
-import com.example.com_us.data.response.question.ResponseQuestionDetailDto
-import com.example.com_us.data.response.question.ResponseQuestionDto
-
-interface QuestionDataSource {
- suspend fun getQuestionListByCate(category: String) : BaseResponse>
- suspend fun getQuestionDetail(questionId: Long) : BaseResponse
- suspend fun getAnswerDetail(answer: String) : BaseResponse>
- suspend fun postAnswer(body: RequestAnswerDto) : BaseResponse
- suspend fun getPreviousAnswer(questionId: Long) : BaseResponse
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/com_us/data/datasource/QuestionRemoteDataSource.kt b/app/src/main/java/com/example/com_us/data/datasource/QuestionRemoteDataSource.kt
deleted file mode 100644
index ba0f669..0000000
--- a/app/src/main/java/com/example/com_us/data/datasource/QuestionRemoteDataSource.kt
+++ /dev/null
@@ -1,29 +0,0 @@
-package com.example.com_us.data.datasource
-
-import com.example.com_us.data.request.question.RequestAnswerDto
-import com.example.com_us.data.response.BaseResponse
-import com.example.com_us.data.response.BaseResponseNoData
-import com.example.com_us.data.response.question.ResponseAnswerDetailDto
-import com.example.com_us.data.response.question.ResponseAnswerDetailWithDateDto
-import com.example.com_us.data.response.question.ResponsePreviousAnswerDto
-import com.example.com_us.data.response.question.ResponseQuestionDetailDto
-import com.example.com_us.data.response.question.ResponseQuestionDto
-import com.example.com_us.data.service.QuestionService
-
-class QuestionRemoteDataSource(private val questionService : QuestionService) : QuestionDataSource {
- override suspend fun getQuestionListByCate(category: String): BaseResponse> {
- return questionService.getQuestionListByCate(category)
- }
- override suspend fun getQuestionDetail(questionId: Long): BaseResponse {
- return questionService.getQuestionDetail(questionId)
- }
- override suspend fun getAnswerDetail(answer: String): BaseResponse> {
- return questionService.getAnswerDetail(answer)
- }
- override suspend fun postAnswer(body: RequestAnswerDto): BaseResponse {
- return questionService.postAnswer(body)
- }
- override suspend fun getPreviousAnswer(questionId: Long): BaseResponse {
- return questionService.getPreviousAnswer(questionId)
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/com_us/data/default_repository/DefaultHomeRepository.kt b/app/src/main/java/com/example/com_us/data/default_repository/DefaultHomeRepository.kt
new file mode 100644
index 0000000..3b9d165
--- /dev/null
+++ b/app/src/main/java/com/example/com_us/data/default_repository/DefaultHomeRepository.kt
@@ -0,0 +1,22 @@
+package com.example.com_us.data.default_repository
+
+import com.example.com_us.base.data.NetworkError
+import com.example.com_us.data.model.home.ResponseHomeDataDto
+import com.example.com_us.data.repository.HomeRepository
+import com.example.com_us.data.default_source.DefaultHomeDataSource
+import com.example.com_us.base.data.toResult
+import javax.inject.Inject
+
+
+
+class DefaultHomeRepository @Inject constructor(
+ private val defaultHomeDataSource: DefaultHomeDataSource
+) : HomeRepository {
+ override suspend fun getHomeData(): Result {
+ return try {
+ defaultHomeDataSource.getHomeData().toResult()
+ } catch (e: Exception) {
+ Result.failure(NetworkError.NetworkException(e))
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/com_us/data/default_repository/DefaultProfileRepository.kt b/app/src/main/java/com/example/com_us/data/default_repository/DefaultProfileRepository.kt
new file mode 100644
index 0000000..0c2ac71
--- /dev/null
+++ b/app/src/main/java/com/example/com_us/data/default_repository/DefaultProfileRepository.kt
@@ -0,0 +1,20 @@
+package com.example.com_us.data.default_repository
+
+import com.example.com_us.base.data.NetworkError
+import com.example.com_us.data.model.question.response.question.ResponseProfileDto
+import com.example.com_us.data.repository.ProfileRepository
+import com.example.com_us.data.default_source.DefaultProfileDataSource
+import com.example.com_us.base.data.toResult
+import javax.inject.Inject
+
+class DefaultProfileRepository @Inject constructor(
+ private val profileRemoteDataSource: DefaultProfileDataSource
+) : ProfileRepository {
+ override suspend fun getProfileData(): Result {
+ return try {
+ profileRemoteDataSource.getProfileData().toResult()
+ }catch (e: Exception){
+ Result.failure(NetworkError.NetworkException(e))
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/com_us/data/default_repository/DefaultQuestionRepository.kt b/app/src/main/java/com/example/com_us/data/default_repository/DefaultQuestionRepository.kt
new file mode 100644
index 0000000..7b5a0fd
--- /dev/null
+++ b/app/src/main/java/com/example/com_us/data/default_repository/DefaultQuestionRepository.kt
@@ -0,0 +1,53 @@
+package com.example.com_us.data.default_repository
+
+import com.example.com_us.base.data.NetworkError
+import com.example.com_us.data.model.question.request.RequestAnswerRequest
+import com.example.com_us.data.model.question.response.question.ResponseAnswerDetailDto
+import com.example.com_us.data.model.question.response.question.ResponseAnswerDetailWithDateDto
+import com.example.com_us.data.model.question.response.question.ResponsePreviousAnswerDto
+import com.example.com_us.data.model.question.response.question.ResponseQuestionDetailDto
+import com.example.com_us.data.model.question.response.question.ResponseQuestionDto
+import com.example.com_us.data.repository.QuestionRepository
+import com.example.com_us.data.default_source.DefaultQuestionDataSource
+import com.example.com_us.base.data.toResult
+import javax.inject.Inject
+
+class DefaultQuestionRepository @Inject constructor(
+ private val defaultQuestionDataSource: DefaultQuestionDataSource
+) : QuestionRepository {
+ override suspend fun getQuestionListByCate(category: String): Result> {
+ return try{
+ defaultQuestionDataSource.getQuestionListByCate(category).toResult()
+ } catch (e: Exception) {
+ Result.failure(NetworkError.NetworkException(e))
+ }
+ }
+ override suspend fun getQuestionDetail(questionId: Long): Result {
+ return try{
+ defaultQuestionDataSource.getQuestionDetail(questionId).toResult()
+ } catch (e: Exception) {
+ Result.failure(NetworkError.NetworkException(e))
+ }
+ }
+ override suspend fun getAnswerDetail(answer: String): Result> {
+ return try{
+ defaultQuestionDataSource.getAnswerDetail(answer).toResult()
+ } catch (e: Exception) {
+ Result.failure(NetworkError.NetworkException(e))
+ }
+ }
+ override suspend fun postAnswer(body: RequestAnswerRequest): Result {
+ return try{
+ defaultQuestionDataSource.postAnswer(body).toResult()
+ } catch (e: Exception) {
+ Result.failure(NetworkError.NetworkException(e))
+ }
+ }
+ override suspend fun getPreviousAnswer(questionId: Long ): Result {
+ return try{
+ defaultQuestionDataSource.getPreviousAnswer(questionId).toResult()
+ } catch (e: Exception) {
+ Result.failure(NetworkError.NetworkException(e))
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/com_us/data/default_source/DefaultHomeDataSource.kt b/app/src/main/java/com/example/com_us/data/default_source/DefaultHomeDataSource.kt
new file mode 100644
index 0000000..ec2154b
--- /dev/null
+++ b/app/src/main/java/com/example/com_us/data/default_source/DefaultHomeDataSource.kt
@@ -0,0 +1,13 @@
+package com.example.com_us.data.default_source
+
+import com.example.com_us.base.data.BaseResponse
+import com.example.com_us.data.model.home.ResponseHomeDataDto
+import com.example.com_us.data.service.HomeService
+import com.example.com_us.data.source.HomeDataSource
+import javax.inject.Inject
+
+class DefaultHomeDataSource @Inject constructor(private val homeService : HomeService) : HomeDataSource {
+ override suspend fun getHomeData(): BaseResponse {
+ return homeService.getHomeData()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/com_us/data/default_source/DefaultProfileDataSource.kt b/app/src/main/java/com/example/com_us/data/default_source/DefaultProfileDataSource.kt
new file mode 100644
index 0000000..0c45041
--- /dev/null
+++ b/app/src/main/java/com/example/com_us/data/default_source/DefaultProfileDataSource.kt
@@ -0,0 +1,13 @@
+package com.example.com_us.data.default_source
+
+import com.example.com_us.base.data.BaseResponse
+import com.example.com_us.data.model.question.response.question.ResponseProfileDto
+import com.example.com_us.data.service.ProfileService
+import com.example.com_us.data.source.ProfileDataSource
+import javax.inject.Inject
+
+class DefaultProfileDataSource @Inject constructor(private val profileService: ProfileService) : ProfileDataSource {
+ override suspend fun getProfileData(): BaseResponse {
+ return profileService.getProfileData()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/com_us/data/default_source/DefaultQuestionDataSource.kt b/app/src/main/java/com/example/com_us/data/default_source/DefaultQuestionDataSource.kt
new file mode 100644
index 0000000..676b120
--- /dev/null
+++ b/app/src/main/java/com/example/com_us/data/default_source/DefaultQuestionDataSource.kt
@@ -0,0 +1,31 @@
+package com.example.com_us.data.default_source
+
+import com.example.com_us.data.model.question.request.RequestAnswerRequest
+import com.example.com_us.base.data.BaseResponse
+import com.example.com_us.data.model.question.response.question.ResponseAnswerDetailDto
+import com.example.com_us.data.model.question.response.question.ResponseAnswerDetailWithDateDto
+import com.example.com_us.data.model.question.response.question.ResponsePreviousAnswerDto
+import com.example.com_us.data.model.question.response.question.ResponseQuestionDetailDto
+import com.example.com_us.data.model.question.response.question.ResponseQuestionDto
+import com.example.com_us.data.service.QuestionService
+import com.example.com_us.data.source.QuestionDataSource
+import javax.inject.Inject
+
+class DefaultQuestionDataSource @Inject constructor(private val questionService : QuestionService) :
+ QuestionDataSource {
+ override suspend fun getQuestionListByCate(category: String): BaseResponse> {
+ return questionService.getQuestionListByCate(category)
+ }
+ override suspend fun getQuestionDetail(questionId: Long): BaseResponse {
+ return questionService.getQuestionDetail(questionId)
+ }
+ override suspend fun getAnswerDetail(answer: String): BaseResponse> {
+ return questionService.getAnswerDetail(answer)
+ }
+ override suspend fun postAnswer(body: RequestAnswerRequest): BaseResponse {
+ return questionService.postAnswer(body)
+ }
+ override suspend fun getPreviousAnswer(questionId: Long): BaseResponse {
+ return questionService.getPreviousAnswer(questionId)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/com_us/data/di/DatasourceModule.kt b/app/src/main/java/com/example/com_us/data/di/DatasourceModule.kt
new file mode 100644
index 0000000..bf43aa8
--- /dev/null
+++ b/app/src/main/java/com/example/com_us/data/di/DatasourceModule.kt
@@ -0,0 +1,28 @@
+package com.example.com_us.data.di
+
+import com.example.com_us.data.default_source.DefaultHomeDataSource
+import com.example.com_us.data.default_source.DefaultProfileDataSource
+import com.example.com_us.data.default_source.DefaultQuestionDataSource
+import com.example.com_us.data.source.HomeDataSource
+import com.example.com_us.data.source.ProfileDataSource
+import com.example.com_us.data.source.QuestionDataSource
+import dagger.Binds
+import dagger.Module
+import dagger.hilt.InstallIn
+import dagger.hilt.components.SingletonComponent
+
+@InstallIn(SingletonComponent::class)
+@Module
+interface DatasourceModule {
+
+ @Binds
+ fun provideHomeDataSource(defaultDataSource : DefaultHomeDataSource) : HomeDataSource
+
+ @Binds
+ fun provideProfileDataSource(defaultDataSource : DefaultProfileDataSource) : ProfileDataSource
+
+ @Binds
+ fun provideQuestionDataSource(defaultDataSource : DefaultQuestionDataSource) : QuestionDataSource
+
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/com_us/data/ApiClient.kt b/app/src/main/java/com/example/com_us/data/di/NetworkModule.kt
similarity index 57%
rename from app/src/main/java/com/example/com_us/data/ApiClient.kt
rename to app/src/main/java/com/example/com_us/data/di/NetworkModule.kt
index 9d70897..f2c287e 100644
--- a/app/src/main/java/com/example/com_us/data/ApiClient.kt
+++ b/app/src/main/java/com/example/com_us/data/di/NetworkModule.kt
@@ -1,47 +1,49 @@
-package com.example.com_us.data
+package com.example.com_us.data.di
import android.content.Context
import android.util.Log
-import okhttp3.Interceptor
+import com.example.com_us.base.AppInterceptor
+import dagger.Module
+import dagger.Provides
+import dagger.hilt.InstallIn
+import dagger.hilt.android.qualifiers.ApplicationContext
+import dagger.hilt.components.SingletonComponent
import okhttp3.OkHttpClient
-import okhttp3.Response
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
-import java.io.IOException
import java.security.KeyStore
import java.security.cert.Certificate
import java.security.cert.CertificateException
import java.security.cert.CertificateFactory
import java.security.cert.X509Certificate
import java.util.concurrent.TimeUnit
+import javax.inject.Singleton
import javax.net.ssl.SSLContext
import javax.net.ssl.TrustManagerFactory
import javax.net.ssl.X509TrustManager
-object ApiClient {
- private const val baseUrl = "http://15.165.140.141:8080"
- private const val contentType = "application/json"
- private const val sampleToken = "Bearer " + "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI1IiwiaWF0IjoxNzIzNjY5NTQxLCJleHAiOjE3MjYyNjE1NDF9.x2KM7idtqLN4EQwjuw3zqPWhp01KpmCxHLweYu1Gqvo"
+// 모듈을 통해 객체 제공방법을 hilt에게 알려줄 수 있다.
+// 생성자 삽입할 수 없는 결합
+@Module
+@InstallIn(SingletonComponent::class)
+object NetworkModule {
- fun getApiClient(context: Context): Retrofit {
- val accessToken = "Bearer " + "";
- return Retrofit.Builder()
- .baseUrl(baseUrl)
- .client(sslOkHttpClient(context, AppInterceptor(context, sampleToken)))
- .addConverterFactory(GsonConverterFactory.create())
- .build()
- }
-
- private fun okHttpClient(interceptor: AppInterceptor): OkHttpClient {
- return OkHttpClient.Builder()
- .addInterceptor(interceptor)
- .addInterceptor(HttpLoggingInterceptor().apply {
- level = HttpLoggingInterceptor.Level.BODY
- }).build()
+ @Provides
+ @Singleton
+ fun provideInterceptor(
+ ) : AppInterceptor {
+ return AppInterceptor(
+ accessToken = "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI0IiwiaWF0IjoxNzMxOTI3NDI0LCJleHAiOjE3MzQ1MTk0MjR9.jU6s6drHXR09SBvFMbd5w_rbkxG3wYHYHwTzy403ifY"
+ )
}
- private fun sslOkHttpClient(context: Context, interceptor: Interceptor): OkHttpClient {
+ @Provides
+ @Singleton
+ fun provideOkHttpClient(
+ @ApplicationContext context: Context,
+ interceptor: AppInterceptor
+ ) : OkHttpClient {
val okHttpClient = OkHttpClient.Builder()
try {
val cf = CertificateFactory.getInstance("X.509")
@@ -56,8 +58,7 @@ object ApiClient {
} finally {
caInput.close()
}
-
- if (ca != null) {
+ if(ca != null) {
val keyStoreType = KeyStore.getDefaultType()
val keyStore = KeyStore.getInstance(keyStoreType)
keyStore.load(null, null)
@@ -78,35 +79,26 @@ object ApiClient {
} catch (e: Exception) {
e.printStackTrace()
}
-
return okHttpClient.addInterceptor(interceptor)
.addInterceptor(HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
})
.connectTimeout(200, TimeUnit.SECONDS)
- .readTimeout(200,TimeUnit.SECONDS)
- .writeTimeout(200,TimeUnit.SECONDS)
+ .readTimeout(200, TimeUnit.SECONDS)
+ .writeTimeout(200, TimeUnit.SECONDS)
.build()
}
- class AppInterceptor(private val context: Context, private val accessToken: String) : Interceptor {
- @Throws(IOException::class)
- override fun intercept(chain: Interceptor.Chain) : Response = with(chain) {
- val newRequest = request().newBuilder()
- .addHeader("Content-Type", contentType)
- .addHeader("Authorization", accessToken)
- .build()
-
- val response = proceed(newRequest)
- when (response.code) {
- 401, 404 -> {
- Log.d("API FAILURE", response.toString())
- }
- 500 -> {
- Log.d("API FAILURE 500", response.toString())
- }
- }
- response
- }
+ @Provides
+ @Singleton
+ fun provideRetrofit(
+ @BaseUrl baseUrl : String,
+ okHttpClient: OkHttpClient) : Retrofit {
+ return Retrofit.Builder()
+ .baseUrl(baseUrl)
+ .client(okHttpClient)
+ .addConverterFactory(GsonConverterFactory.create())
+ .build()
}
+
}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/com_us/data/di/RepositoryModule.kt b/app/src/main/java/com/example/com_us/data/di/RepositoryModule.kt
new file mode 100644
index 0000000..5d48549
--- /dev/null
+++ b/app/src/main/java/com/example/com_us/data/di/RepositoryModule.kt
@@ -0,0 +1,29 @@
+package com.example.com_us.data.di
+
+import com.example.com_us.data.default_repository.DefaultHomeRepository
+import com.example.com_us.data.default_repository.DefaultProfileRepository
+import com.example.com_us.data.default_repository.DefaultQuestionRepository
+import com.example.com_us.data.repository.HomeRepository
+import com.example.com_us.data.repository.ProfileRepository
+import com.example.com_us.data.repository.QuestionRepository
+import dagger.Binds
+import dagger.Module
+import dagger.Provides
+import dagger.hilt.InstallIn
+import dagger.hilt.components.SingletonComponent
+import javax.inject.Singleton
+
+@InstallIn(SingletonComponent::class)
+@Module
+interface RepositoryModule {
+ @Binds
+ @Singleton
+ fun provideHomeRepository(defaultRepository : DefaultHomeRepository) :HomeRepository
+
+ @Binds
+ fun provideProfileRepository(defaultRepository : DefaultProfileRepository) : ProfileRepository
+
+ @Binds
+ fun provideQuestionRepository(defaultRepository : DefaultQuestionRepository) : QuestionRepository
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/com_us/data/di/ServiceModule.kt b/app/src/main/java/com/example/com_us/data/di/ServiceModule.kt
new file mode 100644
index 0000000..fd44e6f
--- /dev/null
+++ b/app/src/main/java/com/example/com_us/data/di/ServiceModule.kt
@@ -0,0 +1,32 @@
+package com.example.com_us.data.di
+
+import com.example.com_us.data.service.HomeService
+import com.example.com_us.data.service.ProfileService
+import com.example.com_us.data.service.QuestionService
+import dagger.Module
+import dagger.Provides
+import dagger.hilt.InstallIn
+import dagger.hilt.components.SingletonComponent
+import retrofit2.Retrofit
+import javax.inject.Singleton
+
+
+@InstallIn(SingletonComponent::class)
+@Module
+object ServiceModule {
+ @Provides
+ @Singleton
+ fun provideHomeService(retrofit: Retrofit): HomeService =
+ retrofit.create(HomeService::class.java)
+
+ @Provides
+ @Singleton
+ fun provideProfileService(retrofit: Retrofit): ProfileService =
+ retrofit.create(ProfileService::class.java)
+
+ @Provides
+ @Singleton
+ fun provideQuestionService(retrofit: Retrofit): QuestionService =
+ retrofit.create(QuestionService::class.java)
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/com_us/data/di/quarlifier.kt b/app/src/main/java/com/example/com_us/data/di/quarlifier.kt
new file mode 100644
index 0000000..b2ef289
--- /dev/null
+++ b/app/src/main/java/com/example/com_us/data/di/quarlifier.kt
@@ -0,0 +1,7 @@
+package com.example.com_us.data.di
+
+import javax.inject.Qualifier
+
+ @Qualifier
+ @Retention(AnnotationRetention.BINARY)
+ annotation class BaseUrl
diff --git a/app/src/main/java/com/example/com_us/data/response/home/ResponseHomeDataDto.kt b/app/src/main/java/com/example/com_us/data/model/home/ResponseHomeDataDto.kt
similarity index 97%
rename from app/src/main/java/com/example/com_us/data/response/home/ResponseHomeDataDto.kt
rename to app/src/main/java/com/example/com_us/data/model/home/ResponseHomeDataDto.kt
index 3e815da..d129951 100644
--- a/app/src/main/java/com/example/com_us/data/response/home/ResponseHomeDataDto.kt
+++ b/app/src/main/java/com/example/com_us/data/model/home/ResponseHomeDataDto.kt
@@ -1,4 +1,4 @@
-package com.example.com_us.data.response.home
+package com.example.com_us.data.model.home
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
diff --git a/app/src/main/java/com/example/com_us/data/request/question/RequestAnswerDto.kt b/app/src/main/java/com/example/com_us/data/model/question/request/RequestAnswerRequest.kt
similarity index 71%
rename from app/src/main/java/com/example/com_us/data/request/question/RequestAnswerDto.kt
rename to app/src/main/java/com/example/com_us/data/model/question/request/RequestAnswerRequest.kt
index 3fa7af7..499bf68 100644
--- a/app/src/main/java/com/example/com_us/data/request/question/RequestAnswerDto.kt
+++ b/app/src/main/java/com/example/com_us/data/model/question/request/RequestAnswerRequest.kt
@@ -1,10 +1,10 @@
-package com.example.com_us.data.request.question
+package com.example.com_us.data.model.question.request
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
-data class RequestAnswerDto(
+data class RequestAnswerRequest(
@SerialName("questionId")
val questionId: Long,
@SerialName("answerContent")
diff --git a/app/src/main/java/com/example/com_us/data/response/question/ResponseAnswerDetailDto.kt b/app/src/main/java/com/example/com_us/data/model/question/response/question/ResponseAnswerDetailDto.kt
similarity index 56%
rename from app/src/main/java/com/example/com_us/data/response/question/ResponseAnswerDetailDto.kt
rename to app/src/main/java/com/example/com_us/data/model/question/response/question/ResponseAnswerDetailDto.kt
index e8140ef..f3f1bd3 100644
--- a/app/src/main/java/com/example/com_us/data/response/question/ResponseAnswerDetailDto.kt
+++ b/app/src/main/java/com/example/com_us/data/model/question/response/question/ResponseAnswerDetailDto.kt
@@ -1,15 +1,15 @@
-package com.example.com_us.data.response.question
+package com.example.com_us.data.model.question.response.question
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
data class ResponseAnswerDetailDto(
@SerialName("id")
- val id: Long,
+ val id: Long=0L,
@SerialName("signLanguageName")
- val signLanguageName: String,
+ val signLanguageName: String = "",
@SerialName("signLanguageVideoUrl")
- val signLanguageVideoUrl: String,
+ val signLanguageVideoUrl: String = "",
@SerialName("signLanguageDescription")
- val signLanguageDescription: String,
+ val signLanguageDescription: String = "",
)
diff --git a/app/src/main/java/com/example/com_us/data/response/question/ResponseAnswerDetailWithDateDto.kt b/app/src/main/java/com/example/com_us/data/model/question/response/question/ResponseAnswerDetailWithDateDto.kt
similarity index 81%
rename from app/src/main/java/com/example/com_us/data/response/question/ResponseAnswerDetailWithDateDto.kt
rename to app/src/main/java/com/example/com_us/data/model/question/response/question/ResponseAnswerDetailWithDateDto.kt
index 1bc5f09..6e1b909 100644
--- a/app/src/main/java/com/example/com_us/data/response/question/ResponseAnswerDetailWithDateDto.kt
+++ b/app/src/main/java/com/example/com_us/data/model/question/response/question/ResponseAnswerDetailWithDateDto.kt
@@ -1,4 +1,4 @@
-package com.example.com_us.data.response.question
+package com.example.com_us.data.model.question.response.question
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
diff --git a/app/src/main/java/com/example/com_us/data/response/question/ResponsePreviousAnswerDto.kt b/app/src/main/java/com/example/com_us/data/model/question/response/question/ResponsePreviousAnswerDto.kt
similarity index 92%
rename from app/src/main/java/com/example/com_us/data/response/question/ResponsePreviousAnswerDto.kt
rename to app/src/main/java/com/example/com_us/data/model/question/response/question/ResponsePreviousAnswerDto.kt
index 6bb4465..5a2bbfc 100644
--- a/app/src/main/java/com/example/com_us/data/response/question/ResponsePreviousAnswerDto.kt
+++ b/app/src/main/java/com/example/com_us/data/model/question/response/question/ResponsePreviousAnswerDto.kt
@@ -1,4 +1,4 @@
-package com.example.com_us.data.response.question
+package com.example.com_us.data.model.question.response.question
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
diff --git a/app/src/main/java/com/example/com_us/data/response/question/ResponseProfileDto.kt b/app/src/main/java/com/example/com_us/data/model/question/response/question/ResponseProfileDto.kt
similarity index 95%
rename from app/src/main/java/com/example/com_us/data/response/question/ResponseProfileDto.kt
rename to app/src/main/java/com/example/com_us/data/model/question/response/question/ResponseProfileDto.kt
index aa19812..d30dde9 100644
--- a/app/src/main/java/com/example/com_us/data/response/question/ResponseProfileDto.kt
+++ b/app/src/main/java/com/example/com_us/data/model/question/response/question/ResponseProfileDto.kt
@@ -1,4 +1,4 @@
-package com.example.com_us.data.response.question
+package com.example.com_us.data.model.question.response.question
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
diff --git a/app/src/main/java/com/example/com_us/data/response/question/ResponseQuestionDetailDto.kt b/app/src/main/java/com/example/com_us/data/model/question/response/question/ResponseQuestionDetailDto.kt
similarity index 88%
rename from app/src/main/java/com/example/com_us/data/response/question/ResponseQuestionDetailDto.kt
rename to app/src/main/java/com/example/com_us/data/model/question/response/question/ResponseQuestionDetailDto.kt
index 339f1f6..4d515f6 100644
--- a/app/src/main/java/com/example/com_us/data/response/question/ResponseQuestionDetailDto.kt
+++ b/app/src/main/java/com/example/com_us/data/model/question/response/question/ResponseQuestionDetailDto.kt
@@ -1,4 +1,4 @@
-package com.example.com_us.data.response.question
+package com.example.com_us.data.model.question.response.question
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
diff --git a/app/src/main/java/com/example/com_us/data/response/question/ResponseQuestionListDto.kt b/app/src/main/java/com/example/com_us/data/model/question/response/question/ResponseQuestionListDto.kt
similarity index 86%
rename from app/src/main/java/com/example/com_us/data/response/question/ResponseQuestionListDto.kt
rename to app/src/main/java/com/example/com_us/data/model/question/response/question/ResponseQuestionListDto.kt
index b158eea..ef3a750 100644
--- a/app/src/main/java/com/example/com_us/data/response/question/ResponseQuestionListDto.kt
+++ b/app/src/main/java/com/example/com_us/data/model/question/response/question/ResponseQuestionListDto.kt
@@ -1,4 +1,4 @@
-package com.example.com_us.data.response.question
+package com.example.com_us.data.model.question.response.question
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
diff --git a/app/src/main/java/com/example/com_us/data/repository/HomeRepository.kt b/app/src/main/java/com/example/com_us/data/repository/HomeRepository.kt
index c1b3eda..a616187 100644
--- a/app/src/main/java/com/example/com_us/data/repository/HomeRepository.kt
+++ b/app/src/main/java/com/example/com_us/data/repository/HomeRepository.kt
@@ -1,12 +1,7 @@
package com.example.com_us.data.repository
-import com.example.com_us.data.datasource.HomeRemoteDataSource
-import com.example.com_us.data.response.home.ResponseHomeDataDto
+import com.example.com_us.data.model.home.ResponseHomeDataDto
-class HomeRepository(
- private val homeRemoteDataSource: HomeRemoteDataSource
-) {
- suspend fun getHomeData(): Result {
- return runCatching { homeRemoteDataSource.getHomeData().data!! }
- }
+interface HomeRepository{
+ suspend fun getHomeData(): Result
}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/com_us/data/repository/ProfileRepository.kt b/app/src/main/java/com/example/com_us/data/repository/ProfileRepository.kt
index 7f1ed87..56f4407 100644
--- a/app/src/main/java/com/example/com_us/data/repository/ProfileRepository.kt
+++ b/app/src/main/java/com/example/com_us/data/repository/ProfileRepository.kt
@@ -1,12 +1,7 @@
package com.example.com_us.data.repository
-import com.example.com_us.data.datasource.ProfileRemoteDataSource
-import com.example.com_us.data.response.question.ResponseProfileDto
+import com.example.com_us.data.model.question.response.question.ResponseProfileDto
-class ProfileRepository(
- private val profileRemoteDataSource: ProfileRemoteDataSource
-) {
- suspend fun getProfileData(): Result {
- return runCatching { profileRemoteDataSource.getProfileData().data!! }
- }
+interface ProfileRepository {
+ suspend fun getProfileData(): Result
}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/com_us/data/repository/QuestionRepository.kt b/app/src/main/java/com/example/com_us/data/repository/QuestionRepository.kt
index 2a6f067..0aa1343 100644
--- a/app/src/main/java/com/example/com_us/data/repository/QuestionRepository.kt
+++ b/app/src/main/java/com/example/com_us/data/repository/QuestionRepository.kt
@@ -1,29 +1,16 @@
package com.example.com_us.data.repository
-import com.example.com_us.data.datasource.QuestionRemoteDataSource
-import com.example.com_us.data.request.question.RequestAnswerDto
-import com.example.com_us.data.response.question.ResponseAnswerDetailDto
-import com.example.com_us.data.response.question.ResponseAnswerDetailWithDateDto
-import com.example.com_us.data.response.question.ResponsePreviousAnswerDto
-import com.example.com_us.data.response.question.ResponseQuestionDetailDto
-import com.example.com_us.data.response.question.ResponseQuestionDto
+import com.example.com_us.data.model.question.request.RequestAnswerRequest
+import com.example.com_us.data.model.question.response.question.ResponseAnswerDetailDto
+import com.example.com_us.data.model.question.response.question.ResponseAnswerDetailWithDateDto
+import com.example.com_us.data.model.question.response.question.ResponsePreviousAnswerDto
+import com.example.com_us.data.model.question.response.question.ResponseQuestionDetailDto
+import com.example.com_us.data.model.question.response.question.ResponseQuestionDto
-class QuestionRepository(
- private val questionRemoteDataSource: QuestionRemoteDataSource
-) {
- suspend fun getQuestionListByCate(category: String): Result> {
- return runCatching { questionRemoteDataSource.getQuestionListByCate(category).data!! }
- }
- suspend fun getQuestionDetail(questionId: Long): Result {
- return runCatching { questionRemoteDataSource.getQuestionDetail(questionId).data!! }
- }
- suspend fun getAnswerDetail(answer: String): Result> {
- return runCatching { questionRemoteDataSource.getAnswerDetail(answer).data!! }
- }
- suspend fun postAnswer(body: RequestAnswerDto): Result {
- return runCatching { questionRemoteDataSource.postAnswer(body).data!! }
- }
- suspend fun getPreviousAnswer(questionId: Long ): Result {
- return runCatching { questionRemoteDataSource.getPreviousAnswer(questionId).data!! }
- }
+interface QuestionRepository {
+ suspend fun getQuestionListByCate(category: String): Result>
+ suspend fun getQuestionDetail(questionId: Long): Result
+ suspend fun getAnswerDetail(answer: String): Result>
+ suspend fun postAnswer(body: RequestAnswerRequest): Result
+ suspend fun getPreviousAnswer(questionId: Long ): Result
}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/com_us/data/response/BaseResponse.kt b/app/src/main/java/com/example/com_us/data/response/BaseResponse.kt
deleted file mode 100644
index fd26f1d..0000000
--- a/app/src/main/java/com/example/com_us/data/response/BaseResponse.kt
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.example.com_us.data.response
-
-import kotlinx.serialization.Serializable
-
-@Serializable
-data class BaseResponse(
- val status: Int,
- val message: String,
- val data: T? = null,
-)
-
-@Serializable
-data class BaseResponseNoData(
- val status: Int,
- val message: String,
-)
diff --git a/app/src/main/java/com/example/com_us/data/service/HomeService.kt b/app/src/main/java/com/example/com_us/data/service/HomeService.kt
index 62a0228..d8f4d78 100644
--- a/app/src/main/java/com/example/com_us/data/service/HomeService.kt
+++ b/app/src/main/java/com/example/com_us/data/service/HomeService.kt
@@ -1,7 +1,7 @@
package com.example.com_us.data.service
-import com.example.com_us.data.response.BaseResponse
-import com.example.com_us.data.response.home.ResponseHomeDataDto
+import com.example.com_us.base.data.BaseResponse
+import com.example.com_us.data.model.home.ResponseHomeDataDto
import retrofit2.http.GET
interface HomeService {
diff --git a/app/src/main/java/com/example/com_us/data/service/ProfileService.kt b/app/src/main/java/com/example/com_us/data/service/ProfileService.kt
index 327f2e0..9f47180 100644
--- a/app/src/main/java/com/example/com_us/data/service/ProfileService.kt
+++ b/app/src/main/java/com/example/com_us/data/service/ProfileService.kt
@@ -1,8 +1,7 @@
package com.example.com_us.data.service
-import com.example.com_us.data.response.BaseResponse
-import com.example.com_us.data.response.home.ResponseHomeDataDto
-import com.example.com_us.data.response.question.ResponseProfileDto
+import com.example.com_us.base.data.BaseResponse
+import com.example.com_us.data.model.question.response.question.ResponseProfileDto
import retrofit2.http.GET
interface ProfileService {
diff --git a/app/src/main/java/com/example/com_us/data/service/QuestionService.kt b/app/src/main/java/com/example/com_us/data/service/QuestionService.kt
index 5d9b67d..1670133 100644
--- a/app/src/main/java/com/example/com_us/data/service/QuestionService.kt
+++ b/app/src/main/java/com/example/com_us/data/service/QuestionService.kt
@@ -1,12 +1,12 @@
package com.example.com_us.data.service
-import com.example.com_us.data.request.question.RequestAnswerDto
-import com.example.com_us.data.response.BaseResponse
-import com.example.com_us.data.response.question.ResponseAnswerDetailDto
-import com.example.com_us.data.response.question.ResponseAnswerDetailWithDateDto
-import com.example.com_us.data.response.question.ResponsePreviousAnswerDto
-import com.example.com_us.data.response.question.ResponseQuestionDetailDto
-import com.example.com_us.data.response.question.ResponseQuestionDto
+import com.example.com_us.data.model.question.request.RequestAnswerRequest
+import com.example.com_us.base.data.BaseResponse
+import com.example.com_us.data.model.question.response.question.ResponseAnswerDetailDto
+import com.example.com_us.data.model.question.response.question.ResponseAnswerDetailWithDateDto
+import com.example.com_us.data.model.question.response.question.ResponsePreviousAnswerDto
+import com.example.com_us.data.model.question.response.question.ResponseQuestionDetailDto
+import com.example.com_us.data.model.question.response.question.ResponseQuestionDto
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.POST
@@ -31,7 +31,7 @@ interface QuestionService {
@POST("/api/answer")
suspend fun postAnswer(
- @Body body: RequestAnswerDto,
+ @Body body: RequestAnswerRequest,
): BaseResponse
@GET("/api/answer/{questionId}")
diff --git a/app/src/main/java/com/example/com_us/data/source/HomeDataSource.kt b/app/src/main/java/com/example/com_us/data/source/HomeDataSource.kt
new file mode 100644
index 0000000..30727e5
--- /dev/null
+++ b/app/src/main/java/com/example/com_us/data/source/HomeDataSource.kt
@@ -0,0 +1,8 @@
+package com.example.com_us.data.source
+
+import com.example.com_us.base.data.BaseResponse
+import com.example.com_us.data.model.home.ResponseHomeDataDto
+
+interface HomeDataSource {
+ suspend fun getHomeData() : BaseResponse
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/com_us/data/source/ProfileDataSource.kt b/app/src/main/java/com/example/com_us/data/source/ProfileDataSource.kt
new file mode 100644
index 0000000..387c696
--- /dev/null
+++ b/app/src/main/java/com/example/com_us/data/source/ProfileDataSource.kt
@@ -0,0 +1,8 @@
+package com.example.com_us.data.source
+
+import com.example.com_us.base.data.BaseResponse
+import com.example.com_us.data.model.question.response.question.ResponseProfileDto
+
+interface ProfileDataSource {
+ suspend fun getProfileData() : BaseResponse
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/com_us/data/source/QuestionDataSource.kt b/app/src/main/java/com/example/com_us/data/source/QuestionDataSource.kt
new file mode 100644
index 0000000..d9fb8cc
--- /dev/null
+++ b/app/src/main/java/com/example/com_us/data/source/QuestionDataSource.kt
@@ -0,0 +1,17 @@
+package com.example.com_us.data.source
+
+import com.example.com_us.data.model.question.request.RequestAnswerRequest
+import com.example.com_us.base.data.BaseResponse
+import com.example.com_us.data.model.question.response.question.ResponseAnswerDetailDto
+import com.example.com_us.data.model.question.response.question.ResponseAnswerDetailWithDateDto
+import com.example.com_us.data.model.question.response.question.ResponsePreviousAnswerDto
+import com.example.com_us.data.model.question.response.question.ResponseQuestionDetailDto
+import com.example.com_us.data.model.question.response.question.ResponseQuestionDto
+
+interface QuestionDataSource {
+ suspend fun getQuestionListByCate(category: String) : BaseResponse>
+ suspend fun getQuestionDetail(questionId: Long) : BaseResponse
+ suspend fun getAnswerDetail(answer: String) : BaseResponse>
+ suspend fun postAnswer(body: RequestAnswerRequest) : BaseResponse
+ suspend fun getPreviousAnswer(questionId: Long) : BaseResponse
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/com_us/ui/base/UiState.kt b/app/src/main/java/com/example/com_us/ui/base/UiState.kt
new file mode 100644
index 0000000..4d6e9fc
--- /dev/null
+++ b/app/src/main/java/com/example/com_us/ui/base/UiState.kt
@@ -0,0 +1,9 @@
+package com.example.com_us.ui.base
+
+
+// 성공 / 실패에 따른 UI 처리
+sealed class UiState {
+ data object Initial : UiState()
+ data class Success(val data : T) : UiState()
+ data class Error(val message : String) : UiState()
+}
diff --git a/app/src/main/java/com/example/com_us/ui/compose/AnswerOptionList.kt b/app/src/main/java/com/example/com_us/ui/compose/AnswerOptionList.kt
index 3b421fd..f93f18f 100644
--- a/app/src/main/java/com/example/com_us/ui/compose/AnswerOptionList.kt
+++ b/app/src/main/java/com/example/com_us/ui/compose/AnswerOptionList.kt
@@ -7,10 +7,10 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
-import com.example.com_us.ui.question.QuestionViewModel
+import com.example.com_us.ui.question.select.SelectAnswerViewModel
@Composable
-fun AnswerOptionList(answerList: List, questionViewModel: QuestionViewModel) {
+fun AnswerOptionList(answerList: List, questionViewModel: SelectAnswerViewModel) {
var columCount = 2
var selectedOption by remember { mutableIntStateOf(-1) } // 선택된 아이템의 ID를 저장하는 상태
diff --git a/app/src/main/java/com/example/com_us/ui/compose/QuestionListItem.kt b/app/src/main/java/com/example/com_us/ui/compose/QuestionListItem.kt
index e5dfd72..cf67bd2 100644
--- a/app/src/main/java/com/example/com_us/ui/compose/QuestionListItem.kt
+++ b/app/src/main/java/com/example/com_us/ui/compose/QuestionListItem.kt
@@ -16,7 +16,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
-import com.example.com_us.data.response.question.ResponseQuestionDto
+import com.example.com_us.data.model.question.response.question.ResponseQuestionDto
import com.example.com_us.util.ColorMatch
import com.example.com_us.util.ColorType
import com.example.com_us.ui.compose.theme.Gray200
@@ -27,7 +27,7 @@ import com.example.com_us.ui.compose.theme.Typography
@Composable
fun QuestionListItem(data: ResponseQuestionDto, onClick: () -> Unit) {
- var color = ColorMatch.fromKor(data.answerType)?.colorType ?: ColorType.GRAY
+ val color = ColorMatch.fromKor(data.answerType)?.colorType ?: ColorType.GRAY
Surface(
diff --git a/app/src/main/java/com/example/com_us/ui/home/HomeFragment.kt b/app/src/main/java/com/example/com_us/ui/home/HomeFragment.kt
index f46f835..1bacfda 100644
--- a/app/src/main/java/com/example/com_us/ui/home/HomeFragment.kt
+++ b/app/src/main/java/com/example/com_us/ui/home/HomeFragment.kt
@@ -6,21 +6,29 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.ViewTreeObserver
+import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
+import androidx.lifecycle.Lifecycle
import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
import com.bumptech.glide.Glide
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
import com.bumptech.glide.request.RequestOptions
import com.example.com_us.R
-import com.example.com_us.data.response.home.Block
-import com.example.com_us.data.response.home.Category
+import com.example.com_us.data.model.home.Block
+import com.example.com_us.data.model.home.Category
import com.example.com_us.databinding.FragmentHomeBinding
+import com.example.com_us.ui.base.UiState
+import com.example.com_us.ui.question.theme.ThemeQuestionListActivity
import com.example.com_us.util.ColorMatch
-import com.example.com_us.util.ServerResponseHandler
import com.example.com_us.util.ThemeType
+import dagger.hilt.android.AndroidEntryPoint
+import kotlinx.coroutines.launch
-class HomeFragment : Fragment(), View.OnClickListener, ServerResponseHandler {
+@AndroidEntryPoint
+class HomeFragment : Fragment(), View.OnClickListener {
private lateinit var blockList: List>
@@ -28,7 +36,7 @@ class HomeFragment : Fragment(), View.OnClickListener, ServerResponseHandler {
private var isReload: MutableLiveData = MutableLiveData(false)
private val binding get() = _binding!!
- private val homeViewModel: HomeViewModel by viewModels { HomeViewModelFactory(requireContext()) }
+ private val homeViewModel: HomeViewModel by viewModels()
private val scrollChangedListener = ViewTreeObserver.OnScrollChangedListener {
_binding?.let {
@@ -52,9 +60,6 @@ class HomeFragment : Fragment(), View.OnClickListener, ServerResponseHandler {
listOf(binding.viewHomeBlock30, binding.viewHomeBlock31, binding.viewHomeBlock32, binding.viewHomeBlock33),
)
- homeViewModel.serverResponseHandler = this
- homeViewModel.loadHomeData()
-
setSwipeRefresh()
setThemeClickListener()
setHomeData()
@@ -88,19 +93,41 @@ class HomeFragment : Fragment(), View.OnClickListener, ServerResponseHandler {
private fun setHomeData() {
val emojiText = String(Character.toChars(resources.getInteger(R.integer.waving_hand_sign)))
- homeViewModel.homeData.observe(viewLifecycleOwner) {
- val chatMinute = it.user.todayChatTime.substring(3, 5).toInt()
- binding.textviewHomeGreeting.text = String.format(resources.getString(R.string.home_title_greeting_user_hi), it.user.name, emojiText)
- binding.textviewHomeMinute.text = String.format(resources.getString(R.string.home_sub_today_conversation_minute), chatMinute)
- Glide.with(this)
- .load(it.user.imageUrl)
- .apply(RequestOptions().transform(RoundedCorners(300)))
- .into(binding.imageviewHomeUsericon)
-
- setThemeProgress(it.category)
- setBlock(it.block)
- isReload.value = true
+ viewLifecycleOwner.lifecycleScope.launch {
+ repeatOnLifecycle(Lifecycle.State.STARTED) {
+ homeViewModel.homeUiState.collect {
+ when (it) {
+ is UiState.Success -> {
+ binding.constraintHome.visibility = View.VISIBLE
+ val chatMinute = it.data.user.todayChatTime.substring(3, 5).toInt()
+ binding.textviewHomeGreeting.text = String.format(
+ resources.getString(R.string.home_title_greeting_user_hi),
+ it.data.user.name,
+ emojiText
+ )
+ binding.textviewHomeMinute.text = String.format(
+ resources.getString(R.string.home_sub_today_conversation_minute),
+ chatMinute
+ )
+ Glide.with(this@HomeFragment)
+ .load(it.data.user.imageUrl)
+ .apply(RequestOptions().transform(RoundedCorners(300)))
+ .into(binding.imageviewHomeUsericon)
+
+ setThemeProgress(it.data.category)
+ setBlock(it.data.block)
+ isReload.value = true
+
+ }
+ is UiState.Error -> {
+ Toast.makeText(context,"잠시 후에 다시 시도해주세요!",Toast.LENGTH_SHORT).show()
+ }
+ else -> {}
+ }
+ }
+ }
}
+
}
override fun onClick(view: View) {
@@ -155,6 +182,7 @@ class HomeFragment : Fragment(), View.OnClickListener, ServerResponseHandler {
color = ColorMatch.findColorFromKor(data.category)
if(color != null){
blockList[data.blockRow][data.blockColumn].setBackgroundResource(color)
+
}
}
}
@@ -164,7 +192,7 @@ class HomeFragment : Fragment(), View.OnClickListener, ServerResponseHandler {
binding.textviewHomeNoblock.visibility = visibility
}
private fun moveToQuestionList(theme: String, themeKor: String) {
- val intent = Intent(context, HomeThemeQuestionListActivity::class.java)
+ val intent = Intent(context, ThemeQuestionListActivity::class.java)
intent.putExtra("theme", theme)
intent.putExtra("themeKor", themeKor)
startActivity(intent)
@@ -186,10 +214,4 @@ class HomeFragment : Fragment(), View.OnClickListener, ServerResponseHandler {
_binding = null
}
- override fun onServerSuccess() {
- binding.constraintHome.visibility = View.VISIBLE
- }
-
- override fun onServerFailure() {
- }
}
diff --git a/app/src/main/java/com/example/com_us/ui/home/HomeViewModel.kt b/app/src/main/java/com/example/com_us/ui/home/HomeViewModel.kt
index 76978ac..d6d7d91 100644
--- a/app/src/main/java/com/example/com_us/ui/home/HomeViewModel.kt
+++ b/app/src/main/java/com/example/com_us/ui/home/HomeViewModel.kt
@@ -1,32 +1,47 @@
package com.example.com_us.ui.home
-import android.util.Log
-import androidx.lifecycle.LiveData
-import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
+import com.example.com_us.base.data.NetworkError
import com.example.com_us.data.repository.HomeRepository
-import com.example.com_us.data.response.home.ResponseHomeDataDto
+import com.example.com_us.data.model.home.ResponseHomeDataDto
+import com.example.com_us.ui.base.UiState
import com.example.com_us.util.ServerResponseHandler
+import dagger.hilt.android.lifecycle.HiltViewModel
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
+import okhttp3.Response
+import javax.inject.Inject
-class HomeViewModel(private val homeRepository: HomeRepository) : ViewModel() {
- private val _homeData = MutableLiveData()
- val homeData: LiveData = _homeData
+@HiltViewModel
+class HomeViewModel @Inject constructor(private val homeRepository: HomeRepository) : ViewModel() {
+ private val _homeUiState= MutableStateFlow>(UiState.Initial)
+ val homeUiState = _homeUiState.asStateFlow()
var serverResponseHandler: ServerResponseHandler? = null
+ init {
+ loadHomeData()
+ }
+
fun loadHomeData(){
viewModelScope.launch {
homeRepository.getHomeData()
.onSuccess {
- _homeData.value = it
- serverResponseHandler?.onServerSuccess()
+ _homeUiState.value = UiState.Success(it)
}
.onFailure {
- Log.d("GET: [HOME DATA] DATA FAILURE", it.toString())
- serverResponseHandler?.onServerFailure()
+ val errorMessage = when(it) {
+ is NetworkError.NetworkException -> { it.message }
+ is NetworkError.NullDataError -> { "데이터가 준비중이에요!" }
+ else -> "알 수 없는 에러가 발생했습니다. 다시 시도해주세요!"
+ }
+ if (errorMessage!= null ) _homeUiState.value = UiState.Error(errorMessage)
}
}
}
+
+
+
}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/com_us/ui/home/HomeViewModelFactory.kt b/app/src/main/java/com/example/com_us/ui/home/HomeViewModelFactory.kt
deleted file mode 100644
index 9440efc..0000000
--- a/app/src/main/java/com/example/com_us/ui/home/HomeViewModelFactory.kt
+++ /dev/null
@@ -1,25 +0,0 @@
-package com.example.com_us.ui.home
-
-import android.content.Context
-import androidx.lifecycle.ViewModel
-import androidx.lifecycle.ViewModelProvider
-import com.example.com_us.data.ApiClient
-import com.example.com_us.data.datasource.HomeRemoteDataSource
-import com.example.com_us.data.datasource.QuestionRemoteDataSource
-import com.example.com_us.data.repository.HomeRepository
-import com.example.com_us.data.repository.QuestionRepository
-import retrofit2.create
-class HomeViewModelFactory(private val context: Context): ViewModelProvider.Factory {
-
- override fun create(modelClass: Class): T {
- return when {
- modelClass.isAssignableFrom(HomeViewModel::class.java) -> {
- val repository = HomeRepository(HomeRemoteDataSource(ApiClient.getApiClient(context).create()))
- HomeViewModel(repository) as T
- }
- else -> {
- throw IllegalArgumentException("Failed to create ViewModel : ${modelClass.name}")
- }
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/com_us/ui/login/LoginActivity.kt b/app/src/main/java/com/example/com_us/ui/login/LoginActivity.kt
new file mode 100644
index 0000000..1cf1f4b
--- /dev/null
+++ b/app/src/main/java/com/example/com_us/ui/login/LoginActivity.kt
@@ -0,0 +1,19 @@
+package com.example.com_us.ui.login
+
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+import com.example.com_us.databinding.ActivityLoginBinding
+import com.example.com_us.databinding.ActivityQuestionCheckAnswerBinding
+import dagger.hilt.android.AndroidEntryPoint
+
+@AndroidEntryPoint
+class LoginActivity : AppCompatActivity() {
+
+ private lateinit var binding: ActivityLoginBinding
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = ActivityLoginBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/com_us/ui/profile/ProfileFragment.kt b/app/src/main/java/com/example/com_us/ui/profile/ProfileFragment.kt
index 8b0931e..556b0b2 100644
--- a/app/src/main/java/com/example/com_us/ui/profile/ProfileFragment.kt
+++ b/app/src/main/java/com/example/com_us/ui/profile/ProfileFragment.kt
@@ -3,28 +3,35 @@ package com.example.com_us.ui.profile
import android.graphics.drawable.GradientDrawable
import android.os.Build
import android.os.Bundle
+import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout.LayoutParams
+import android.widget.Toast
import androidx.annotation.RequiresApi
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
+import androidx.lifecycle.lifecycleScope
import com.bumptech.glide.Glide
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
import com.bumptech.glide.request.RequestOptions
import com.example.com_us.R
import com.example.com_us.databinding.FragmentProfileBinding
+import com.example.com_us.ui.base.UiState
import com.example.com_us.util.ServerResponseHandler
+import dagger.hilt.android.AndroidEntryPoint
+import kotlinx.coroutines.launch
import java.time.LocalTime
import java.time.format.DateTimeFormatter
-class ProfileFragment : Fragment(), ServerResponseHandler {
+@AndroidEntryPoint
+class ProfileFragment : Fragment() ,ServerResponseHandler{
private var _binding: FragmentProfileBinding? = null
- private val profileViewModel: ProfileViewModel by viewModels { ProfileViewModelFactory(requireContext()) }
+ private val profileViewModel: ProfileViewModel by viewModels()
private val binding get() = _binding!!
@RequiresApi(Build.VERSION_CODES.O)
@@ -36,31 +43,53 @@ class ProfileFragment : Fragment(), ServerResponseHandler {
_binding = FragmentProfileBinding.inflate(inflater, container, false)
profileViewModel.loadProfileData()
- profileViewModel.serverResponseHandler = this
-
- setProfile()
return binding.root
}
+ @RequiresApi(Build.VERSION_CODES.O)
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ setProfile()
+ super.onViewCreated(view, savedInstanceState)
+ }
+
@RequiresApi(Build.VERSION_CODES.O)
private fun setProfile() {
- profileViewModel.profileData.observe(viewLifecycleOwner) {
- val themeGraphRatioList: List = listOf(
- it.answerStatistic.dailyQuestionRatio.toFloat(),
- it.answerStatistic.schoolQuestionRatio.toFloat(),
- it.answerStatistic.friendQuestionRatio.toFloat(),
- it.answerStatistic.familyQuestionRatio.toFloat(),
- it.answerStatistic.hobbyQuestionRatio.toFloat(),
- )
- setProfile(it.userInfo.name, it.userInfo.imageUrl)
- setStatic(it.userInfo.totalChatTime, it.userInfo.totalChatCount)
- changeTypeGraph(it.answerStatistic.multipleChoiceRatio.toFloat(), it.answerStatistic.sentenceRatio.toFloat())
- changeThemeGraph(themeGraphRatioList)
+ lifecycleScope.launch {
+ profileViewModel.profileUiState.collect {
+ when (it) {
+ is UiState.Success -> {
+ binding.constraintProfile.visibility = View.VISIBLE
+ val themeGraphRatioList: List = listOf(
+ it.data.answerStatistic.dailyQuestionRatio.toFloat(),
+ it.data.answerStatistic.schoolQuestionRatio.toFloat(),
+ it.data.answerStatistic.friendQuestionRatio.toFloat(),
+ it.data.answerStatistic.familyQuestionRatio.toFloat(),
+ it.data.answerStatistic.hobbyQuestionRatio.toFloat(),
+ )
+
+ setProfile(it.data.userInfo.name, it.data.userInfo.imageUrl)
+ setStatic(it.data.userInfo.totalChatTime, it.data.userInfo.totalChatCount)
+ changeTypeGraph(
+ it.data.answerStatistic.multipleChoiceRatio.toFloat(),
+ it.data.answerStatistic.sentenceRatio.toFloat()
+ )
+ changeThemeGraph(themeGraphRatioList)
+ }
+
+ is UiState.Error -> {
+ Toast.makeText(context,"잠시 후에 다시 시도해주세요!",Toast.LENGTH_SHORT).show()
+ }
+
+ else -> {}
+ }
+
+ }
}
}
private fun setProfile(username: String, profileImgUrl: String) {
+ Log.d("profile","setProfile")
binding.textviewProfileNickname.text = String.format(resources.getString(R.string.profile_username), username)
Glide.with(this)
.load(profileImgUrl)
@@ -70,12 +99,14 @@ class ProfileFragment : Fragment(), ServerResponseHandler {
@RequiresApi(Build.VERSION_CODES.O)
private fun setStatic(totalChatTime: String, totalChatCount: Int) {
+ Log.d("profile","setStatic")
val totalChatTime = stringToLocalTime(totalChatTime)
binding.textviewTimeTaken.text = String.format(resources.getString(R.string.profile_time_taken_minute), totalChatTime.toSecondOfDay() / 60)
binding.textviewConvCount.text = String.format(resources.getString(R.string.profile_conv_count_count), totalChatCount)
}
private fun changeTypeGraph(choiceRatio: Float, interactionRatio: Float) {
+ Log.d("profile","changeTypeGraph")
changeGraphShape(R.drawable.shape_type_graph_fill_stroke_rect34_blue, choiceRatio, GraphPosition.LEFT)
changeGraphShape(R.drawable.shape_type_graph_fill_stroke_rect34_pink, interactionRatio, GraphPosition.RIGHT)
@@ -87,6 +118,7 @@ class ProfileFragment : Fragment(), ServerResponseHandler {
}
private fun changeThemeGraph(themeGraphRatioList: List) {
+ Log.d("profile","changeThemeGraph")
val themeGraphBg: List = listOf(
R.drawable.shape_theme_graph_fill_rect_orange700,
R.drawable.shape_theme_graph_fill_rect_blue700,
@@ -121,6 +153,7 @@ class ProfileFragment : Fragment(), ServerResponseHandler {
changeGraphLayoutWeight(binding.viewProfileThemeGraphFamily, themeGraphRatioList[3])
changeGraphLayoutWeight(binding.viewProfileThemeGraphInterest, themeGraphRatioList[4])
+ print(binding)
binding.includeProfileGraphThemeDaily.textviewGraphPercent.text = String.format(resources.getString(R.string.percent), themeGraphRatioList[0].toInt())
binding.includeProfileGraphThemeSchool.textviewGraphPercent.text = String.format(resources.getString(R.string.percent), themeGraphRatioList[1].toInt())
binding.includeProfileGraphThemeFriend.textviewGraphPercent.text = String.format(resources.getString(R.string.percent), themeGraphRatioList[2].toInt())
@@ -129,6 +162,7 @@ class ProfileFragment : Fragment(), ServerResponseHandler {
}
private fun changeGraphLayoutWeight(view: View, ratio: Float) {
+ Log.d("profile","changeGraphLayoutWeight")
val marginInDp = resources.getDimensionPixelSize(R.dimen.profile_graph_margin)
view.layoutParams = LayoutParams(
LayoutParams.WRAP_CONTENT,
@@ -140,6 +174,7 @@ class ProfileFragment : Fragment(), ServerResponseHandler {
}
private fun changeGraphShape(graphDrawableId: Int, ratio: Float, position: GraphPosition) {
+ Log.d("profile","changeGraphShape")
val drawable = context?.let { ContextCompat.getDrawable(it, graphDrawableId) } as? GradientDrawable
if(ratio >= 100.0) {
drawable?.cornerRadius = 40f
@@ -158,6 +193,7 @@ class ProfileFragment : Fragment(), ServerResponseHandler {
@RequiresApi(Build.VERSION_CODES.O)
fun stringToLocalTime(timeString: String): LocalTime {
+ Log.d("profile","stringToLocalTime")
val formatter = DateTimeFormatter.ofPattern("HH:mm:ss")
return LocalTime.parse(timeString, formatter)
@@ -172,10 +208,11 @@ class ProfileFragment : Fragment(), ServerResponseHandler {
RIGHT, MIDDLE, LEFT
}
+ @RequiresApi(Build.VERSION_CODES.O)
override fun onServerSuccess() {
- binding.constraintProfile.visibility = View.VISIBLE
}
override fun onServerFailure() {
+ TODO("Not yet implemented")
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/com_us/ui/profile/ProfileViewModel.kt b/app/src/main/java/com/example/com_us/ui/profile/ProfileViewModel.kt
index c231e7e..9aec7d5 100644
--- a/app/src/main/java/com/example/com_us/ui/profile/ProfileViewModel.kt
+++ b/app/src/main/java/com/example/com_us/ui/profile/ProfileViewModel.kt
@@ -1,32 +1,41 @@
package com.example.com_us.ui.profile
-import android.util.Log
-import androidx.lifecycle.LiveData
-import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
+import com.example.com_us.base.data.NetworkError
import com.example.com_us.data.repository.ProfileRepository
-import com.example.com_us.data.response.question.ResponseProfileDto
-import com.example.com_us.util.ServerResponseHandler
+import com.example.com_us.data.model.question.response.question.ResponseProfileDto
+import com.example.com_us.ui.base.UiState
+import dagger.hilt.android.lifecycle.HiltViewModel
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
+import javax.inject.Inject
-class ProfileViewModel(private val profileRepository: ProfileRepository) : ViewModel() {
+@HiltViewModel
+class ProfileViewModel @Inject constructor(private val profileRepository: ProfileRepository) : ViewModel() {
- var serverResponseHandler: ServerResponseHandler? = null
+ private val _profileUiState = MutableStateFlow>(UiState.Initial)
+ val profileUiState = _profileUiState.asStateFlow()
- private val _profileData = MutableLiveData()
- val profileData: LiveData = _profileData
- fun loadProfileData(){
+
+
+ fun loadProfileData() {
viewModelScope.launch {
profileRepository.getProfileData()
.onSuccess {
- _profileData.value = it
- serverResponseHandler?.onServerSuccess()
+ _profileUiState.value = UiState.Success(it)
}
.onFailure {
- Log.d("GET: [PROFILE DATA]", it.toString())
- serverResponseHandler?.onServerFailure()
+ val errorMessage = when (it) {
+ is NetworkError.NetworkException -> { it.message }
+ is NetworkError.NullDataError -> { "데이터가 준비중이에요!" }
+ else -> "알 수 없는 에러가 발생했습니다. 다시 시도해주세요!"
+ }
+ if (errorMessage != null) {
+ _profileUiState.value = UiState.Error(errorMessage)
+ }
}
}
}
diff --git a/app/src/main/java/com/example/com_us/ui/profile/ProfileViewModelFactory.kt b/app/src/main/java/com/example/com_us/ui/profile/ProfileViewModelFactory.kt
deleted file mode 100644
index 155ce63..0000000
--- a/app/src/main/java/com/example/com_us/ui/profile/ProfileViewModelFactory.kt
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.example.com_us.ui.profile
-
-import android.content.Context
-import androidx.lifecycle.ViewModel
-import androidx.lifecycle.ViewModelProvider
-import com.example.com_us.data.ApiClient
-import com.example.com_us.data.datasource.ProfileRemoteDataSource
-import com.example.com_us.data.repository.ProfileRepository
-import retrofit2.create
-class ProfileViewModelFactory(private val context: Context): ViewModelProvider.Factory {
-
- override fun create(modelClass: Class): T {
- return when {
- modelClass.isAssignableFrom(ProfileViewModel::class.java) -> {
- val repository = ProfileRepository(ProfileRemoteDataSource(ApiClient.getApiClient(context).create()))
- ProfileViewModel(repository) as T
- }
- else -> {
- throw IllegalArgumentException("Failed to create ViewModel : ${modelClass.name}")
- }
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/com_us/ui/question/QuestionFollowAlongDialog.kt b/app/src/main/java/com/example/com_us/ui/question/QuestionFollowAlongDialog.kt
deleted file mode 100644
index 0235fc4..0000000
--- a/app/src/main/java/com/example/com_us/ui/question/QuestionFollowAlongDialog.kt
+++ /dev/null
@@ -1,143 +0,0 @@
-package com.example.com_us.ui.question
-
-import android.content.Intent
-import android.graphics.Color
-import android.graphics.drawable.ColorDrawable
-import android.net.Uri
-import android.os.Bundle
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import android.widget.Toast
-import androidx.fragment.app.DialogFragment
-import androidx.fragment.app.viewModels
-import androidx.lifecycle.MutableLiveData
-import com.example.com_us.R
-import com.example.com_us.data.response.question.ResponseAnswerDetailDto
-import com.example.com_us.databinding.DialogQuestionFollowAlongBinding
-import com.example.com_us.util.QuestionManager
-import com.example.com_us.util.ServerResponseHandler
-
-private const val ARG_PARAM_QUESTION = "paramQuestion"
-private const val ARG_PARAM_ANSWER = "paramAnswer"
-private const val ARG_PARAM_CATEGORY = "paramCategory"
-private const val ARG_PARAM_SIGNDATA = "paramSignData"
-
-class QuestionFollowAlongDialog : DialogFragment(), ServerResponseHandler {
- // TODO: Rename and change types of parameters
- private lateinit var paramQuestion: String
- private lateinit var paramAnswer: String
- private lateinit var paramCategory: String
-
- private lateinit var signData: List
-
- private var videoPlayCount: MutableLiveData = MutableLiveData(0)
-
- private var _binding: DialogQuestionFollowAlongBinding? = null
- private val binding get() = _binding!!
-
- private val questionViewModel: QuestionViewModel by viewModels { QuestionViewModelFactory(requireContext()) }
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- questionViewModel.serverResponseHandler = this
- arguments?.let {
- paramQuestion = it.getString(ARG_PARAM_QUESTION)!!
- paramAnswer = it.getString(ARG_PARAM_ANSWER)!!
- paramCategory = it.getString(ARG_PARAM_CATEGORY)!!
- //paramSignData = it.getSerializable(ARG_PARAM_SIGNDATA) as List
- }
- }
-
- override fun onCreateView(
- inflater: LayoutInflater, container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View? {
- _binding = DialogQuestionFollowAlongBinding.inflate(inflater, container, false)
- val view = binding.root
- dialog?.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
- signData = QuestionManager.signLanguageInfo
-
- setAnswerDetail()
- getAnswerDate()
-
- binding.buttonAnswerComplete.setOnClickListener {
- val questionId = QuestionManager.questionId
- if(questionId > 0 && paramAnswer.isNotEmpty()) questionViewModel.postAnswer(questionId, paramAnswer)
- }
-
- // Inflate the layout for this fragment
- return view
- }
-
- override fun onStart() {
- super.onStart()
-
- dialog?.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
- }
-
- companion object {
- @JvmStatic
- fun newInstance(paramQuestion: String, paramAnswer: String, paramCategory: String) =
- QuestionFollowAlongDialog().apply {
- arguments = Bundle().apply {
- putString(ARG_PARAM_QUESTION, paramQuestion)
- putString(ARG_PARAM_ANSWER, paramAnswer)
- putString(ARG_PARAM_CATEGORY, paramCategory)
- //putSerializable(ARG_PARAM_SIGNDATA, ArrayList(paramSignData))
- }
- }
- }
-
- override fun onDestroyView() {
- super.onDestroyView()
- _binding = null
- }
-
- private fun setAnswerDetail() {
- binding.textviewFollowdialogQuestion.text = paramQuestion
- var repeatCount = 0
-
- videoPlayCount.observe(this) {
- if(it >= 0) setSignDetail(it)
- }
-
- if(signData.size > 1) {
- binding.videoviewFollowdialogSign.setOnCompletionListener {
- if(videoPlayCount.value!! >= signData.size-1){
- if(++repeatCount > 3) {
- videoPlayCount.value = -1
- repeatCount = 0
- } else {
- videoPlayCount.value = 0
- }
- } else
- videoPlayCount.value = videoPlayCount.value?.plus(1)
-
- }
- }
- }
-
- private fun getAnswerDate() {
- questionViewModel.resultData.observe(this) {
- if(it != null) QuestionManager.answerDate = it.answerDate
- }
- }
-
- private fun setSignDetail(signIdx: Int) {
- binding.textviewFollowdialogAnswer.text = signData[signIdx].signLanguageName
- binding.videoviewFollowdialogSign.setVideoURI(Uri.parse(signData[signIdx].signLanguageVideoUrl))
- binding.videoviewFollowdialogSign.start()
- binding.textviewFollodialogDescrp.text = signData[signIdx].signLanguageDescription
- }
-
- override fun onServerSuccess() {
- val intent = Intent(activity, QuestionCollectBlockActivity::class.java)
- intent.putExtra("category", paramCategory)
- startActivity(intent)
- activity?.finish()
- }
-
- override fun onServerFailure() {
- Toast.makeText(context, getString(R.string.question_follow_along_server_failure), Toast.LENGTH_SHORT).show()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/com_us/ui/question/QuestionViewModel.kt b/app/src/main/java/com/example/com_us/ui/question/QuestionViewModel.kt
deleted file mode 100644
index 73e2b72..0000000
--- a/app/src/main/java/com/example/com_us/ui/question/QuestionViewModel.kt
+++ /dev/null
@@ -1,122 +0,0 @@
-package com.example.com_us.ui.question
-
-import android.util.Log
-import androidx.lifecycle.LiveData
-import androidx.lifecycle.MutableLiveData
-import androidx.lifecycle.ViewModel
-import androidx.lifecycle.viewModelScope
-import com.example.com_us.R
-import com.example.com_us.data.repository.QuestionRepository
-import com.example.com_us.data.request.question.RequestAnswerDto
-import com.example.com_us.data.response.question.ResponseAnswerDetailDto
-import com.example.com_us.data.response.question.ResponseAnswerDetailWithDateDto
-import com.example.com_us.data.response.question.ResponsePreviousAnswerDto
-import com.example.com_us.data.response.question.ResponseQuestionDetailDto
-import com.example.com_us.data.response.question.ResponseQuestionDto
-import com.example.com_us.util.ServerResponseHandler
-import kotlinx.coroutines.launch
-
-class QuestionViewModel(private val questionRepository: QuestionRepository) : ViewModel() {
-
- var serverResponseHandler: ServerResponseHandler? = null
-
- private val _selectedThemeId = MutableLiveData().apply {
- value = R.id.include_theme_all
- }
- val selectedThemeId: LiveData = _selectedThemeId
-
- private val _selectedAnswerOptionId = MutableLiveData(-1)
- val selectedAnswerOptionId: LiveData = _selectedAnswerOptionId
-
- private val _questionListByCate = MutableLiveData>()
- val questionListByCate: LiveData> = _questionListByCate
-
- private val _questionDetail = MutableLiveData()
- val questionDetail: LiveData = _questionDetail
-
- private val _answerDetail = MutableLiveData>()
- val answerDetail: LiveData> = _answerDetail
-
- private val _answerPrevious = MutableLiveData()
- val answerPrevious: LiveData = _answerPrevious
-
- private val _resultData = MutableLiveData()
- val resultData: LiveData = _resultData
-
- fun updateSelectedThemeId(newId: Int) {
- _selectedThemeId.value = newId
- }
- fun updateSelectedAnswerOptionId(newOptionId: Int) {
- _selectedAnswerOptionId.value = newOptionId
- }
- fun loadQuestionListByCate(category: String){
- viewModelScope.launch {
- questionRepository.getQuestionListByCate(category)
- .onSuccess {
- serverResponseHandler?.onServerSuccess()
- _questionListByCate.value = it
- }
- .onFailure {
- serverResponseHandler?.onServerFailure()
- Log.d("GET: [QUESTION LIST BY CATE]", it.toString())
- }
- }
- }
-
- fun loadQuestionDetail(questionId: Long){
- viewModelScope.launch {
- questionRepository.getQuestionDetail(questionId)
- .onSuccess {
- _questionDetail.value = it
- serverResponseHandler?.onServerSuccess()
- }
- .onFailure {
- serverResponseHandler?.onServerFailure()
- Log.d("GET: [QUESTION DETAIL]", it.toString())
- }
- }
- }
-
- fun loadAnswerDetail(answer: String){
- viewModelScope.launch {
- questionRepository.getAnswerDetail(answer)
- .onSuccess {
- _answerDetail.value = it
- serverResponseHandler?.onServerSuccess()
- }
- .onFailure {
- serverResponseHandler?.onServerFailure()
- Log.d("GET: [ANSWER DETAIL]", it.toString())
- }
- }
- }
-
- fun postAnswer(questionId: Long, answerContent: String){
- var body = RequestAnswerDto(questionId, answerContent)
- viewModelScope.launch {
- questionRepository.postAnswer(body)
- .onSuccess {
- _resultData.value = it
- serverResponseHandler?.onServerSuccess()
- }
- .onFailure {
- serverResponseHandler?.onServerFailure()
- Log.d("POST: [ANSWER]", it.toString())
- }
- }
- }
-
- fun loadPreviousAnswer(questionId: Long) {
- viewModelScope.launch {
- questionRepository.getPreviousAnswer(questionId)
- .onSuccess {
- _answerPrevious.value = it
- serverResponseHandler?.onServerSuccess()
- }
- .onFailure {
- serverResponseHandler?.onServerFailure()
- Log.d("GET: [ANSWER DETAIL]", it.toString())
- }
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/com_us/ui/question/QuestionViewModelFactory.kt b/app/src/main/java/com/example/com_us/ui/question/QuestionViewModelFactory.kt
deleted file mode 100644
index 93c31cb..0000000
--- a/app/src/main/java/com/example/com_us/ui/question/QuestionViewModelFactory.kt
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.example.com_us.ui.question
-
-import android.content.Context
-import androidx.lifecycle.ViewModel
-import androidx.lifecycle.ViewModelProvider
-import com.example.com_us.data.ApiClient
-import com.example.com_us.data.datasource.QuestionRemoteDataSource
-import com.example.com_us.data.repository.QuestionRepository
-import retrofit2.create
-class QuestionViewModelFactory(private val context: Context): ViewModelProvider.Factory {
-
- override fun create(modelClass: Class): T {
- return when {
- modelClass.isAssignableFrom(QuestionViewModel::class.java) -> {
- val repository = QuestionRepository(QuestionRemoteDataSource(ApiClient.getApiClient(context).create()))
- QuestionViewModel(repository) as T
- }
- else -> {
- throw IllegalArgumentException("Failed to create ViewModel : ${modelClass.name}")
- }
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/com_us/ui/question/QuestionCollectBlockActivity.kt b/app/src/main/java/com/example/com_us/ui/question/block/CollectBlockActivity.kt
similarity index 73%
rename from app/src/main/java/com/example/com_us/ui/question/QuestionCollectBlockActivity.kt
rename to app/src/main/java/com/example/com_us/ui/question/block/CollectBlockActivity.kt
index 013bced..fe7a211 100644
--- a/app/src/main/java/com/example/com_us/ui/question/QuestionCollectBlockActivity.kt
+++ b/app/src/main/java/com/example/com_us/ui/question/block/CollectBlockActivity.kt
@@ -1,15 +1,19 @@
-package com.example.com_us.ui.question
+package com.example.com_us.ui.question.block
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.Handler
import androidx.activity.OnBackPressedCallback
-import com.example.com_us.R
+import com.example.com_us.MainActivity
import com.example.com_us.databinding.ActivityQuestionCollectBlockBinding
+import com.example.com_us.ui.question.result.ResultAfterSignActivity
import com.example.com_us.util.ThemeType
+import dagger.hilt.android.AndroidEntryPoint
-class QuestionCollectBlockActivity : AppCompatActivity() {
+// 대화 블럭 획득 화면
+@AndroidEntryPoint
+class CollectBlockActivity : AppCompatActivity() {
private lateinit var binding: ActivityQuestionCollectBlockBinding
private lateinit var category: String
@@ -17,20 +21,20 @@ class QuestionCollectBlockActivity : AppCompatActivity() {
super.onCreate(savedInstanceState)
binding = ActivityQuestionCollectBlockBinding.inflate(layoutInflater)
setContentView(binding.root)
-
category = intent.getStringExtra("category").toString()
- if(!category.isNullOrEmpty()){
+ if(category.isNotEmpty()){
setTheme()
}
controlBackButton()
Handler().postDelayed({
- val intent = Intent(this, QuestionResultActivity::class.java)
+ val intent = Intent(this, ResultAfterSignActivity::class.java)
+ intent.putExtra("category",category)
startActivity(intent)
finish()
- }, 1500) // 3초
+ }, 3000) // 3초
}
private fun setTheme() {
diff --git a/app/src/main/java/com/example/com_us/ui/question/QuestionFragment.kt b/app/src/main/java/com/example/com_us/ui/question/list/AllQuestionListFragment.kt
similarity index 52%
rename from app/src/main/java/com/example/com_us/ui/question/QuestionFragment.kt
rename to app/src/main/java/com/example/com_us/ui/question/list/AllQuestionListFragment.kt
index 1edd595..2a7634a 100644
--- a/app/src/main/java/com/example/com_us/ui/question/QuestionFragment.kt
+++ b/app/src/main/java/com/example/com_us/ui/question/list/AllQuestionListFragment.kt
@@ -1,4 +1,4 @@
-package com.example.com_us.ui.question
+package com.example.com_us.ui.question.list
import android.content.Intent
import android.os.Bundle
@@ -6,6 +6,7 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
+import android.widget.Toast
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.ui.Modifier
@@ -13,24 +14,26 @@ import androidx.compose.ui.platform.ViewCompositionStrategy
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
import com.example.com_us.R
import com.example.com_us.databinding.FragmentQuestionBinding
+import com.example.com_us.ui.base.UiState
import com.example.com_us.ui.compose.QuestionListItem
-import com.example.com_us.util.ServerResponseHandler
+import com.example.com_us.ui.question.select.SelectAnswerActivity
import com.example.com_us.util.ThemeType
+import dagger.hilt.android.AndroidEntryPoint
+import kotlinx.coroutines.launch
-class QuestionFragment : Fragment(), View.OnClickListener, ServerResponseHandler {
+// 바텀 네비게이션바에서 햄버거 버튼 클릭 시 이동하는 질문 리스트 화면
+@AndroidEntryPoint
+class AllQuestionListFragment : Fragment(), View.OnClickListener {
private var _binding: FragmentQuestionBinding? = null
-
- // This property is only valid between onCreateView and
- // onDestroyView.
private val binding get() = _binding!!
-
- private val questionViewModel: QuestionViewModel by viewModels { QuestionViewModelFactory(requireContext()) }
-
+ private val viewModel: AllQuestionListViewModel by viewModels()
private var lastSelectedView: TextView? = null
-
private lateinit var selectedView:TextView
private lateinit var themeKor:String
@@ -39,50 +42,71 @@ class QuestionFragment : Fragment(), View.OnClickListener, ServerResponseHandler
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
-
_binding = FragmentQuestionBinding.inflate(inflater, container, false)
val root: View = binding.root
+ return root
+ }
- questionViewModel.serverResponseHandler = this
- questionViewModel.loadQuestionListByCate("")
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ val themeAllView = binding.includeThemeAll
+ viewModel.updateSelectedThemeId(themeAllView.textviewTheme.id)
setThemeList()
setComposeList()
setThemeClickListener()
- return root
- }
-
- override fun onResume() {
- super.onResume()
- val themeAllView = binding.includeThemeAll
- questionViewModel.updateSelectedThemeId(themeAllView.textviewTheme.id)
}
+ // 선택한 카테고리에 맞는 질문 리스트 얻기
private fun setThemeList() {
- questionViewModel.selectedThemeId.observe(viewLifecycleOwner) {
+ viewModel.selectedThemeId.observe(viewLifecycleOwner) {
selectedView = binding.root.findViewById(it)
themeKor = selectedView.text.toString()
var category = ThemeType.fromKor(themeKor).toString()
if(category == ThemeType.ALL.toString()) category = ""
- questionViewModel.loadQuestionListByCate(category)
+ viewModel.loadQuestionListByCate(category)
}
}
+ // 각 질문을 담을 아이템
private fun setComposeList() {
- questionViewModel.questionListByCate.observe(viewLifecycleOwner) {
- binding.textviewQuestionCount.text = String.format(resources.getString(R.string.question_title_question_count), it.size)
- binding.composeviewQuestion.apply {
- setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
- setContent {
- LazyColumn(modifier = Modifier.fillMaxSize()) {
- items(it.size) { idx ->
- QuestionListItem(data = it[idx], onClick = { moveToQuestionDetail(it[idx].id) })
+ // 데이터 리스트
+ lifecycleScope.launch {
+ repeatOnLifecycle(Lifecycle.State.STARTED){
+ viewModel.apiResult.collect {
+ when(it) {
+ is UiState.Success -> {
+ if (it.data.isNotEmpty()) {
+ setThemeSelected()
+ binding.constraintQuestion.visibility = View.VISIBLE
+ binding.textviewQuestionCount.text = String.format(
+ resources.getString(R.string.question_title_question_count),
+ it.data.size
+ )
+ binding.composeviewQuestion.apply {
+ setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
+ setContent {
+ LazyColumn(modifier = Modifier.fillMaxSize()) {
+ items(it.data.size) { idx ->
+ QuestionListItem(
+ data = it.data[idx],
+ onClick = { movieToSelectAnswer(it.data[idx].id) })
+ }
+ }
+ }
+ }
+ }
+ }
+ is UiState.Error -> {
+ binding.constraintQuestion.visibility = View.GONE
+ Toast.makeText(context, it.toString(), Toast.LENGTH_SHORT).show()
}
+ else -> {}
}
}
}
}
+
}
private fun setThemeClickListener(){
@@ -111,14 +135,14 @@ class QuestionFragment : Fragment(), View.OnClickListener, ServerResponseHandler
lastSelectedView = selectedView
}
- private fun moveToQuestionDetail(questionId: Long) {
- val intent = Intent(activity, QuestionDetailActivity::class.java)
+ private fun movieToSelectAnswer(questionId: Long) {
+ val intent = Intent(activity, SelectAnswerActivity::class.java)
intent.putExtra("questionId", questionId)
startActivity(intent)
}
override fun onClick(view: View) {
- questionViewModel.updateSelectedThemeId(view.id)
+ viewModel.updateSelectedThemeId(view.id)
}
override fun onDestroyView() {
@@ -126,11 +150,4 @@ class QuestionFragment : Fragment(), View.OnClickListener, ServerResponseHandler
_binding = null
}
- override fun onServerSuccess() {
- setThemeSelected()
- binding.constraintQuestion.visibility = View.VISIBLE
- }
-
- override fun onServerFailure() {
- }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/com_us/ui/question/list/AllQuestionListViewModel.kt b/app/src/main/java/com/example/com_us/ui/question/list/AllQuestionListViewModel.kt
new file mode 100644
index 0000000..5588761
--- /dev/null
+++ b/app/src/main/java/com/example/com_us/ui/question/list/AllQuestionListViewModel.kt
@@ -0,0 +1,71 @@
+package com.example.com_us.ui.question.list
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import com.example.com_us.R
+import com.example.com_us.base.data.NetworkError
+import com.example.com_us.data.model.question.response.question.ResponseQuestionDto
+import com.example.com_us.data.repository.QuestionRepository
+import com.example.com_us.ui.base.UiState
+import dagger.hilt.android.lifecycle.HiltViewModel
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.launch
+import javax.inject.Inject
+
+
+@HiltViewModel
+class AllQuestionListViewModel @Inject constructor(
+ private val questionRepository: QuestionRepository
+) : ViewModel() {
+
+ init {
+ loadQuestionListByCate("")
+ }
+
+ // 질문 리스트
+ private val _questionListByCate = MutableLiveData>()
+ val questionListByCate: LiveData> = _questionListByCate
+
+
+ // ui 상태 변수
+ private val _uiState = MutableStateFlow>>(UiState.Initial)
+ val apiResult = _uiState.asStateFlow()
+
+
+ // 선택한 테마의 id
+ private val _selectedThemeId = MutableLiveData().apply {
+ value = R.id.include_theme_all
+ }
+ val selectedThemeId: LiveData = _selectedThemeId
+
+
+
+ fun updateSelectedThemeId(newId: Int) {
+ _selectedThemeId.value = newId
+ }
+
+
+ // 클릭한 카테고리의 질문 리스트를 가져오는 함수
+ fun loadQuestionListByCate(category: String){
+ viewModelScope.launch {
+ questionRepository.getQuestionListByCate(category)
+ .onSuccess {
+ _uiState.value = UiState.Success(it)
+ }
+ .onFailure {
+ val errorMessage = when(it){
+ is NetworkError.NetworkException -> {it.message}
+ is NetworkError.NullDataError -> {"아직 데이터를 준비중이에요!"}
+ else -> "알 수 없는 에러가 발생했습니다. 다시 시도해주세요!"
+ }
+ if (errorMessage != null) {
+ _uiState.value = UiState.Error(errorMessage)
+ } }
+ }
+ }
+
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/com_us/ui/question/QuestionPreviousAnswerActivity.kt b/app/src/main/java/com/example/com_us/ui/question/previous/PreviousAnswerActivity.kt
similarity index 70%
rename from app/src/main/java/com/example/com_us/ui/question/QuestionPreviousAnswerActivity.kt
rename to app/src/main/java/com/example/com_us/ui/question/previous/PreviousAnswerActivity.kt
index 1f6e84f..d73636f 100644
--- a/app/src/main/java/com/example/com_us/ui/question/QuestionPreviousAnswerActivity.kt
+++ b/app/src/main/java/com/example/com_us/ui/question/previous/PreviousAnswerActivity.kt
@@ -1,25 +1,34 @@
-package com.example.com_us.ui.question
+package com.example.com_us.ui.question.previous
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.MenuItem
+import android.widget.Toast
import androidx.activity.viewModels
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.ui.platform.ViewCompositionStrategy
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
import com.example.com_us.R
-import com.example.com_us.data.response.question.Answer
+import com.example.com_us.data.model.question.response.question.Answer
import com.example.com_us.databinding.ActivityQuestionPreviousAnswerBinding
+import com.example.com_us.ui.base.UiState
import com.example.com_us.ui.compose.AnswerHistoryItem
import com.example.com_us.ui.compose.AnswerTypeTag
import com.example.com_us.util.ColorMatch
+import dagger.hilt.android.AndroidEntryPoint
+import kotlinx.coroutines.launch
-class QuestionPreviousAnswerActivity : AppCompatActivity() {
+// 이전 답변을 보여주는 화면
+@AndroidEntryPoint
+class PreviousAnswerActivity : AppCompatActivity() {
private lateinit var binding: ActivityQuestionPreviousAnswerBinding
- private val questionViewModel: QuestionViewModel by viewModels { QuestionViewModelFactory(applicationContext) }
+ private val viewModel: PreviousAnswerViewModel by viewModels()
private var questionId: Long = -1
override fun onCreate(savedInstanceState: Bundle?) {
@@ -33,13 +42,25 @@ class QuestionPreviousAnswerActivity : AppCompatActivity() {
questionId = intent.getLongExtra("questionId", -1)
println(questionId)
- if(questionId > -1) questionViewModel.loadPreviousAnswer(questionId)
+ if(questionId > -1) viewModel.loadPreviousAnswer(questionId)
+
+ lifecycleScope.launch {
+ repeatOnLifecycle(Lifecycle.State.STARTED){
+ viewModel.uiState.collect{
+ when(it){
+ is UiState.Success -> {
+ setQuestion(it.data.question.questionCount, it.data.question.questionContent)
+ setQuestionTypeCompose(it.data.question.category, it.data.question.answerType)
+ setComposeList(it.data.answerList)
+ }
+ else ->
+ Toast.makeText(this@PreviousAnswerActivity, it.toString(), Toast.LENGTH_SHORT).show()
+
+ }
+ }
- questionViewModel.answerPrevious.observe(this) {
- setQuestion(it.question.questionCount, it.question.questionContent)
- setQuestionTypeCompose(it.question.category, it.question.answerType)
- setComposeList(it.answerList)
- }
+ }
+ }
}
private fun setActionBar() {
diff --git a/app/src/main/java/com/example/com_us/ui/question/previous/PreviousAnswerViewModel.kt b/app/src/main/java/com/example/com_us/ui/question/previous/PreviousAnswerViewModel.kt
new file mode 100644
index 0000000..8543d21
--- /dev/null
+++ b/app/src/main/java/com/example/com_us/ui/question/previous/PreviousAnswerViewModel.kt
@@ -0,0 +1,49 @@
+package com.example.com_us.ui.question.previous
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import com.example.com_us.base.data.NetworkError
+import com.example.com_us.data.model.question.response.question.ResponsePreviousAnswerDto
+import com.example.com_us.data.repository.QuestionRepository
+import com.example.com_us.ui.base.UiState
+import dagger.hilt.android.lifecycle.HiltViewModel
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.launch
+import javax.inject.Inject
+
+
+
+@HiltViewModel
+class PreviousAnswerViewModel @Inject constructor(
+ private val questionRepository: QuestionRepository
+) : ViewModel(){
+
+ // ui 상태 변수
+ private val _uiState = MutableStateFlow>(UiState.Initial)
+ val uiState= _uiState.asStateFlow()
+
+ private val _answerPrevious = MutableLiveData()
+ val answerPrevious: LiveData = _answerPrevious
+
+ fun loadPreviousAnswer(questionId: Long) {
+ viewModelScope.launch {
+ questionRepository.getPreviousAnswer(questionId)
+ .onSuccess {
+ _uiState.value = UiState.Success(it)
+ }
+ .onFailure {
+ val errorMessage = when(it){
+ is NetworkError.NetworkException -> {it.message}
+ is NetworkError.NullDataError -> "데이터가 없어요"
+ else -> "알 수 없는 에러가 발생했어요. 다시 시도해주세요!"
+ }
+ if (errorMessage != null) {
+ _uiState.value = UiState.Error(errorMessage)
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/com_us/ui/question/QuestionResultActivity.kt b/app/src/main/java/com/example/com_us/ui/question/result/ResultAfterSignActivity.kt
similarity index 83%
rename from app/src/main/java/com/example/com_us/ui/question/QuestionResultActivity.kt
rename to app/src/main/java/com/example/com_us/ui/question/result/ResultAfterSignActivity.kt
index 4827018..1ecfb7c 100644
--- a/app/src/main/java/com/example/com_us/ui/question/QuestionResultActivity.kt
+++ b/app/src/main/java/com/example/com_us/ui/question/result/ResultAfterSignActivity.kt
@@ -1,4 +1,4 @@
-package com.example.com_us.ui.question
+package com.example.com_us.ui.question.result
import android.content.Intent
import android.net.Uri
@@ -8,13 +8,18 @@ import android.view.MenuItem
import androidx.lifecycle.MutableLiveData
import com.example.com_us.MainActivity
import com.example.com_us.R
-import com.example.com_us.data.response.question.ResponseAnswerDetailDto
+import com.example.com_us.data.model.question.response.question.ResponseAnswerDetailDto
import com.example.com_us.databinding.ActivityQuestionResultBinding
+import com.example.com_us.ui.question.block.CollectBlockActivity
import com.example.com_us.util.QuestionManager
+import dagger.hilt.android.AndroidEntryPoint
-class QuestionResultActivity : AppCompatActivity() {
+// 수형 따라해보기 완료 후 대화 블럭 얻기 전 답변 완료 화면
+@AndroidEntryPoint
+class ResultAfterSignActivity : AppCompatActivity() {
private lateinit var binding: ActivityQuestionResultBinding
+ private lateinit var category : String
private var videoPlayCount: MutableLiveData = MutableLiveData(0)
@@ -32,6 +37,7 @@ class QuestionResultActivity : AppCompatActivity() {
if(!QuestionManager.answerDate.isNullOrEmpty()) {
binding.textviewResultDate.text = QuestionManager.answerDate
}
+ category = intent.getStringExtra("category").toString()
setActionBar()
setCompleteButton()
@@ -88,7 +94,8 @@ class QuestionResultActivity : AppCompatActivity() {
private fun setCompleteButton() {
binding.buttonResultComplete.setOnClickListener{
QuestionManager.reset()
- val intent = Intent(this, MainActivity::class.java)
+ // 메인 화면으로 이동
+ val intent = Intent(this,MainActivity::class.java)
startActivity(intent)
finish()
}
diff --git a/app/src/main/java/com/example/com_us/ui/question/QuestionCheckAnswerActivity.kt b/app/src/main/java/com/example/com_us/ui/question/result/ResultBeforeSignActivity.kt
similarity index 50%
rename from app/src/main/java/com/example/com_us/ui/question/QuestionCheckAnswerActivity.kt
rename to app/src/main/java/com/example/com_us/ui/question/result/ResultBeforeSignActivity.kt
index c38cab1..1219258 100644
--- a/app/src/main/java/com/example/com_us/ui/question/QuestionCheckAnswerActivity.kt
+++ b/app/src/main/java/com/example/com_us/ui/question/result/ResultBeforeSignActivity.kt
@@ -1,23 +1,31 @@
-package com.example.com_us.ui.question
+package com.example.com_us.ui.question.result
import android.net.Uri
import android.os.Bundle
import android.view.MenuItem
+import android.view.View
import android.widget.Toast
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
+import androidx.lifecycle.Lifecycle
import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
import com.example.com_us.R
-import com.example.com_us.data.response.question.ResponseAnswerDetailDto
+import com.example.com_us.data.model.question.response.question.ResponseAnswerDetailDto
import com.example.com_us.databinding.ActivityQuestionCheckAnswerBinding
+import com.example.com_us.ui.base.UiState
+import com.example.com_us.ui.question.sign.SignAnswerDialog
import com.example.com_us.util.QuestionManager
-import com.example.com_us.util.ServerResponseHandler
+import dagger.hilt.android.AndroidEntryPoint
+import kotlinx.coroutines.launch
-
-class QuestionCheckAnswerActivity : AppCompatActivity(), ServerResponseHandler {
+// 답변 선택 시 처음으로 이동하는 화면 (질문, 답변 , 수형 영상, 따라해보기 버튼)
+@AndroidEntryPoint
+class ResultBeforeSignActivity : AppCompatActivity(){
private lateinit var binding: ActivityQuestionCheckAnswerBinding
- private val questionViewModel: QuestionViewModel by viewModels { QuestionViewModelFactory(this) }
+ private val viewModel: ResultViewModel by viewModels()
private lateinit var answer: String
private lateinit var question: String
@@ -29,31 +37,43 @@ class QuestionCheckAnswerActivity : AppCompatActivity(), ServerResponseHandler {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- questionViewModel.serverResponseHandler = this
answer = intent.getStringExtra("answer").toString()
question = intent.getStringExtra("question").toString()
category = intent.getStringExtra("category").toString()
- if(!answer.isNullOrEmpty()){
+ if (answer.isNotEmpty()) {
QuestionManager.question = question
- questionViewModel.loadAnswerDetail(answer)
+ viewModel.loadAnswerDetail(answer)
}
binding = ActivityQuestionCheckAnswerBinding.inflate(layoutInflater)
setContentView(binding.root)
setActionBar()
- questionViewModel.answerDetail.observe(this) {
- if(!it.isNullOrEmpty()){
- QuestionManager.signLanguageInfo = it
- signData = it
- setAnswerDetail()
- binding.buttonAnswerFollowalong.setOnClickListener {
- moveToFollowAlongDialog()
+
+ lifecycleScope.launch {
+ repeatOnLifecycle(Lifecycle.State.STARTED) {
+ viewModel.answerDetail.collect {
+ when (it) {
+ is UiState.Success -> {
+ QuestionManager.signLanguageInfo = it.data
+ signData = it.data
+ setAnswerDetail()
+ binding.buttonAnswerFollowalong.setOnClickListener {
+ moveToFollowAlongDialog()
+ }
+ }
+
+ is UiState.Error -> {
+ Toast.makeText(this@ResultBeforeSignActivity, it.toString(), Toast.LENGTH_SHORT).show()
+ }
+ else -> {}
+ }
}
}
}
+
}
private fun setActionBar() {
@@ -105,15 +125,43 @@ class QuestionCheckAnswerActivity : AppCompatActivity(), ServerResponseHandler {
}
private fun moveToFollowAlongDialog() {
videoPlayCount.value = -1
- val dialog = QuestionFollowAlongDialog.newInstance(question, answer, category)
- dialog.show(supportFragmentManager, "FollowAlongDialog")
- }
- override fun onServerSuccess() {
- }
+ viewModel.answerDetail.value
+ viewModel.answerDetail.value.let {
+ when(it) {
+ is UiState.Success -> {
+ val dialog =
+ SignAnswerDialog.newInstance(question, answer, category,
+ it.data
+ )
+ dialog.isCancelable = false
+ dialog.show(supportFragmentManager, "FollowAlongDialog")
+
+ }
+ else -> {
+ Toast.makeText(this , "잠시 후에 다시 시도해주세요",Toast.LENGTH_SHORT).show()
+ }
+ }
+ }
+
+ print(viewModel.answerDetail.value)
+
+ // 다이얼로그가 뜨면 아래 내용 질문만 희미하게 보이게 하기
+ binding.textView8.visibility = View.GONE
+ binding.textviewAnswerAnswer.visibility = View.GONE
+ binding.textView13.visibility = View.GONE
+ binding.textviewAnswerDescrp.visibility = View.GONE
+ binding.buttonAnswerFollowalong.visibility = View.GONE
+ binding.videoviewAnswerSign.visibility = View.GONE
- override fun onServerFailure() {
- Toast.makeText(this, getString(R.string.server_data_error), Toast.LENGTH_SHORT).show()
- finish()
}
+
+
+// override fun onServerSuccess() {
+// }
+//
+// override fun onServerFailure() {
+// Toast.makeText(this, getString(R.string.server_data_error), Toast.LENGTH_SHORT).show()
+// finish()
+// }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/com_us/ui/question/result/ResultViewModel.kt b/app/src/main/java/com/example/com_us/ui/question/result/ResultViewModel.kt
new file mode 100644
index 0000000..4d09d90
--- /dev/null
+++ b/app/src/main/java/com/example/com_us/ui/question/result/ResultViewModel.kt
@@ -0,0 +1,37 @@
+package com.example.com_us.ui.question.result
+
+import android.util.Log
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import com.example.com_us.data.model.question.response.question.ResponseAnswerDetailDto
+import com.example.com_us.data.repository.QuestionRepository
+import com.example.com_us.ui.base.UiState
+import dagger.hilt.android.lifecycle.HiltViewModel
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.launch
+import javax.inject.Inject
+
+@HiltViewModel
+class ResultViewModel @Inject constructor(
+ private val questionRepository : QuestionRepository
+) : ViewModel() {
+
+ private val _answerDetail = MutableStateFlow>>(UiState.Initial)
+ val answerDetail =_answerDetail.asStateFlow()
+
+
+ fun loadAnswerDetail(answer: String){
+ viewModelScope.launch {
+ questionRepository.getAnswerDetail(answer)
+ .onSuccess {
+ _answerDetail.value = UiState.Success(it)
+ }
+ .onFailure {
+ Log.d("GET: [ANSWER DETAIL]", it.toString())
+ }
+ }
+ }
+
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/com_us/ui/question/QuestionDetailActivity.kt b/app/src/main/java/com/example/com_us/ui/question/select/SelectAnswerActivity.kt
similarity index 60%
rename from app/src/main/java/com/example/com_us/ui/question/QuestionDetailActivity.kt
rename to app/src/main/java/com/example/com_us/ui/question/select/SelectAnswerActivity.kt
index 1488f1d..c7d2f89 100644
--- a/app/src/main/java/com/example/com_us/ui/question/QuestionDetailActivity.kt
+++ b/app/src/main/java/com/example/com_us/ui/question/select/SelectAnswerActivity.kt
@@ -1,4 +1,4 @@
-package com.example.com_us.ui.question
+package com.example.com_us.ui.question.select
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
@@ -9,15 +9,22 @@ import androidx.activity.viewModels
import androidx.compose.foundation.layout.Row
import androidx.compose.ui.platform.ViewCompositionStrategy
import androidx.core.content.ContextCompat
+import androidx.lifecycle.lifecycleScope
import com.example.com_us.R
import com.example.com_us.databinding.ActivityQuestionDetailBinding
+import com.example.com_us.ui.base.UiState
import com.example.com_us.util.ColorMatch
import com.example.com_us.ui.compose.AnswerOptionList
import com.example.com_us.ui.compose.AnswerTypeTag
+import com.example.com_us.ui.question.result.ResultBeforeSignActivity
+import com.example.com_us.ui.question.previous.PreviousAnswerActivity
import com.example.com_us.util.QuestionManager
-import com.example.com_us.util.ServerResponseHandler
+import dagger.hilt.android.AndroidEntryPoint
+import kotlinx.coroutines.launch
-class QuestionDetailActivity : AppCompatActivity(), ServerResponseHandler {
+// 질문에 대한 답변을 선택하는 화면
+@AndroidEntryPoint
+class SelectAnswerActivity : AppCompatActivity() {
private lateinit var binding: ActivityQuestionDetailBinding
private lateinit var answerList: List
@@ -26,26 +33,25 @@ class QuestionDetailActivity : AppCompatActivity(), ServerResponseHandler {
private var questionId: Long = -1
private var answerOptionId: Int = -1
- private val questionViewModel: QuestionViewModel by viewModels { QuestionViewModelFactory(this) }
+ private val viewModel: SelectAnswerViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityQuestionDetailBinding.inflate(layoutInflater)
setContentView(binding.root)
- questionViewModel.serverResponseHandler = this
questionId = intent.getLongExtra("questionId", 0L)
if(questionId > 0) {
QuestionManager.questionId = questionId
- questionViewModel.loadQuestionDetail(questionId)
+ viewModel.loadQuestionDetail(questionId)
setPreviousAnswerButton()
}
setQuestionDetail()
- questionViewModel.selectedAnswerOptionId.observe(this) {
+ viewModel.selectedAnswerOptionId.observe(this) {
if (it > -1) {
setCompleteButton()
answerOptionId = it
@@ -54,13 +60,29 @@ class QuestionDetailActivity : AppCompatActivity(), ServerResponseHandler {
}
private fun setQuestionDetail() {
- questionViewModel.questionDetail.observe(this) {
- binding.textviewDetailQuestion.text = it.question.questionContent
- question = it.question.questionContent
- category = it.question.category
- setQuestionTypeCompose(it.question.answerType)
- setQuestionAnswerOptionCompose(it.answerList)
- }
+ lifecycleScope.launch {
+ viewModel.uiState.collect {
+ if (it is UiState.Success) {
+ binding.constraintQuestionDetail.visibility = View.VISIBLE
+ binding.textviewDetailQuestion.text = it.data.question.questionContent
+ question = it.data.question.questionContent
+ category = it.data.question.category
+ setQuestionTypeCompose(it.data.question.answerType)
+ setQuestionAnswerOptionCompose(it.data.answerList)
+ }
+
+ if (it is UiState.Error) {
+ Toast.makeText(
+ this@SelectAnswerActivity,
+ it.message,
+ Toast.LENGTH_SHORT
+ ).show()
+ finish()
+ }
+ }
+
+ }
+
}
private fun setQuestionTypeCompose(answerType: String) {
@@ -80,7 +102,7 @@ class QuestionDetailActivity : AppCompatActivity(), ServerResponseHandler {
binding.composeDetailAnsweroption.apply {
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setContent {
- AnswerOptionList(answerList, questionViewModel)
+ AnswerOptionList(answerList, viewModel)
}
}
}
@@ -103,14 +125,14 @@ class QuestionDetailActivity : AppCompatActivity(), ServerResponseHandler {
private fun setPreviousAnswerButton() {
binding.buttonDetailAnswerbefore.setOnClickListener {
- val intent = Intent(this, QuestionPreviousAnswerActivity::class.java)
+ val intent = Intent(this, PreviousAnswerActivity::class.java)
intent.putExtra("questionId", questionId)
startActivity(intent)
}
}
private fun moveToQuestionAnswer(answerOptionId: Int) {
- val intent = Intent(this, QuestionCheckAnswerActivity::class.java)
+ val intent = Intent(this, ResultBeforeSignActivity::class.java)
intent.putExtra("question", question)
intent.putExtra("category", category)
intent.putExtra("answer", answerList[answerOptionId])
@@ -118,12 +140,12 @@ class QuestionDetailActivity : AppCompatActivity(), ServerResponseHandler {
finish()
}
- override fun onServerSuccess() {
- binding.constraintQuestionDetail.visibility = View.VISIBLE
- }
-
- override fun onServerFailure() {
- Toast.makeText(this, getString(R.string.question_detail_msg_when_server_failure), Toast.LENGTH_SHORT).show()
- finish()
- }
+// override fun onServerSuccess() {
+// binding.constraintQuestionDetail.visibility = View.VISIBLE
+// }
+//
+// override fun onServerFailure() {
+// Toast.makeText(this, getString(R.string.question_detail_msg_when_server_failure), Toast.LENGTH_SHORT).show()
+// finish()
+// }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/com_us/ui/question/select/SelectAnswerViewModel.kt b/app/src/main/java/com/example/com_us/ui/question/select/SelectAnswerViewModel.kt
new file mode 100644
index 0000000..ac8ab07
--- /dev/null
+++ b/app/src/main/java/com/example/com_us/ui/question/select/SelectAnswerViewModel.kt
@@ -0,0 +1,56 @@
+package com.example.com_us.ui.question.select
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import com.example.com_us.base.data.NetworkError
+import com.example.com_us.data.model.question.response.question.ResponseQuestionDetailDto
+import com.example.com_us.data.repository.QuestionRepository
+import com.example.com_us.ui.base.UiState
+import dagger.hilt.android.lifecycle.HiltViewModel
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.launch
+import javax.inject.Inject
+
+@HiltViewModel
+class SelectAnswerViewModel @Inject constructor(
+ private val questionRepository: QuestionRepository
+): ViewModel() {
+
+ // ui 상태 변수
+ private val _uiState = MutableStateFlow>(UiState.Initial)
+ val uiState: StateFlow> = _uiState
+
+ private val _questionDetail = MutableLiveData()
+ val questionDetail: LiveData = _questionDetail
+
+ private val _selectedAnswerOptionId = MutableLiveData(-1)
+ val selectedAnswerOptionId: LiveData = _selectedAnswerOptionId
+
+ fun updateSelectedAnswerOptionId(newOptionId: Int) {
+ _selectedAnswerOptionId.value = newOptionId
+ }
+
+ // 질문 클릭 시 상세 내용 가져오는 함수
+ fun loadQuestionDetail(questionId: Long){
+ viewModelScope.launch {
+ questionRepository.getQuestionDetail(questionId)
+ .onSuccess {
+ _uiState.value = UiState.Success(it)
+ }
+ .onFailure {
+ println(it)
+ val errorMessage = when(it) {
+ is NetworkError.ApiError -> { it.message }
+ is NetworkError.NullDataError -> { "데이터가 없어요" }
+ is NetworkError.NetworkException -> { "잠시 후에 다시 시도해주세요" }
+ else -> "알 수 없는 에러가 발생했어요. 다시 시도해주세요!"
+ }
+ _uiState.value = UiState.Error(errorMessage)
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/com_us/ui/question/sign/SignAnswerDialog.kt b/app/src/main/java/com/example/com_us/ui/question/sign/SignAnswerDialog.kt
new file mode 100644
index 0000000..3a31e19
--- /dev/null
+++ b/app/src/main/java/com/example/com_us/ui/question/sign/SignAnswerDialog.kt
@@ -0,0 +1,120 @@
+package com.example.com_us.ui.question.sign
+
+import android.content.Context
+import android.content.Intent
+import android.graphics.Color
+import android.graphics.drawable.ColorDrawable
+import android.net.Uri
+import android.os.Bundle
+import android.util.Printer
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.Toast
+import androidx.fragment.app.DialogFragment
+import androidx.fragment.app.viewModels
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.viewModelScope
+import com.example.com_us.data.model.question.response.question.ResponseAnswerDetailDto
+import com.example.com_us.databinding.DialogQuestionFollowAlongBinding
+import com.example.com_us.ui.question.block.CollectBlockActivity
+import com.example.com_us.ui.question.result.ResultAfterSignActivity
+import com.example.com_us.util.QuestionManager
+import dagger.hilt.android.AndroidEntryPoint
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
+import kotlin.math.sign
+
+// 수형 따라해보기 화면
+@AndroidEntryPoint
+class SignAnswerDialog(
+ private val question : String,
+ private val answer : String,
+ private val category : String,
+ private val signDescription: List,
+) : DialogFragment() {
+ private lateinit var signData: List
+ private var index = 0
+
+ private var _binding: DialogQuestionFollowAlongBinding? = null
+ private val binding get() = _binding!!
+
+ private val viewModel: SignAnswerViewModel by viewModels()
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View {
+ _binding = DialogQuestionFollowAlongBinding.inflate(inflater, container, false)
+ val view = binding.root
+ dialog?.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
+ signData = signDescription
+ return view
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ setSignDetail(0)
+
+ binding.btnCompleteWithoutBlock.setOnClickListener {
+ val intent = Intent(context,ResultAfterSignActivity::class.java)
+ startActivity(intent)
+ }
+ binding.buttonNextStep.setOnClickListener {
+ if (viewModel.signIndex.value == signData.lastIndex) {
+ val intent = Intent(context,CollectBlockActivity::class.java)
+ intent.putExtra("category",category)
+ startActivity(intent)
+ }
+ else {
+ index +=1
+ viewModel.setSignIndex(index)
+ setSignDetail(index)
+ }
+
+ }
+ binding.linearProgressIndicator.progress = 50
+ binding.textviewFollowdialogQuestion.text = question
+ }
+
+ override fun onStart() {
+ super.onStart()
+ dialog?.window?.setLayout(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT
+ )
+ }
+
+ companion object {
+ fun newInstance(paramQuestion: String, paramAnswer: String, paramCategory: String,signDescription: List) =
+ SignAnswerDialog(paramQuestion,paramAnswer,paramCategory, signDescription).apply {
+ arguments = Bundle()
+ }
+ }
+
+ override fun onDestroyView() {
+ super.onDestroyView()
+ _binding = null
+ }
+
+
+
+ // todo: 역할이 뭐지?
+ private fun getAnswerDate() {
+ viewModel.resultData.observe(this) {
+ if(it != null) QuestionManager.answerDate = it.answerDate
+ }
+ }
+
+ private fun setSignDetail(signIdx: Int) {
+ if (signIdx > signData.lastIndex) return
+ if (viewModel.signIndex.value == signData.lastIndex) {
+ binding.buttonNextStep.text = "완료하기"
+ binding.btnCompleteWithoutBlock.visibility = View.GONE
+ }
+ binding.textviewFollowdialogAnswer.text = signData[signIdx].signLanguageName
+ binding.videoviewFollowdialogSign.setVideoURI(Uri.parse(signData[signIdx].signLanguageVideoUrl))
+ binding.videoviewFollowdialogSign.start()
+ binding.textviewFollodialogDescrp.text = signData[signIdx].signLanguageDescription
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/com_us/ui/question/sign/SignAnswerViewModel.kt b/app/src/main/java/com/example/com_us/ui/question/sign/SignAnswerViewModel.kt
new file mode 100644
index 0000000..5babe3a
--- /dev/null
+++ b/app/src/main/java/com/example/com_us/ui/question/sign/SignAnswerViewModel.kt
@@ -0,0 +1,57 @@
+package com.example.com_us.ui.question.sign
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import com.example.com_us.base.data.NetworkError
+import com.example.com_us.data.repository.QuestionRepository
+import com.example.com_us.data.model.question.request.RequestAnswerRequest
+import com.example.com_us.data.model.question.response.question.ResponseAnswerDetailWithDateDto
+import com.example.com_us.ui.base.UiState
+import dagger.hilt.android.lifecycle.HiltViewModel
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.launch
+import javax.inject.Inject
+
+
+@HiltViewModel
+class SignAnswerViewModel @Inject constructor(
+ private val questionRepository: QuestionRepository,
+) : ViewModel() {
+
+
+ private val _signIndex = MutableStateFlow(0)
+ val signIndex = _signIndex.asStateFlow()
+
+ private val _uiState = MutableStateFlow>(UiState.Initial)
+ val uiState= _uiState.asStateFlow()
+ private val _resultData = MutableLiveData()
+ val resultData: LiveData = _resultData
+
+ fun setSignIndex(index : Int ) {
+ _signIndex.value = index
+ }
+// todo : 이 함수의 역할은 뭐야?
+ fun postAnswer(questionId: Long, answerContent: String){
+ val body = RequestAnswerRequest(questionId, answerContent)
+ viewModelScope.launch {
+ questionRepository.postAnswer(body)
+ .onSuccess {
+ _uiState.value = UiState.Success(it)
+ }
+ .onFailure {
+ val errorMessage = when(it) {
+ is NetworkError.NetworkException -> { "네트워크 에러가 발생했어요! 잠시 후에 다시 시도해주세에요"}
+ is NetworkError.ApiError ->{it.message}
+ is NetworkError.NullDataError -> {"데이터를 준비하고 있어요!"}
+ else -> { "잠시 후에 다시 시도해주세요"}
+ }
+ _uiState.value = UiState.Error(errorMessage)
+ }
+ }
+ }
+
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/com_us/ui/home/HomeThemeQuestionListActivity.kt b/app/src/main/java/com/example/com_us/ui/question/theme/ThemeQuestionListActivity.kt
similarity index 51%
rename from app/src/main/java/com/example/com_us/ui/home/HomeThemeQuestionListActivity.kt
rename to app/src/main/java/com/example/com_us/ui/question/theme/ThemeQuestionListActivity.kt
index 320d466..6cf58d5 100644
--- a/app/src/main/java/com/example/com_us/ui/home/HomeThemeQuestionListActivity.kt
+++ b/app/src/main/java/com/example/com_us/ui/question/theme/ThemeQuestionListActivity.kt
@@ -1,66 +1,83 @@
-package com.example.com_us.ui.home
+package com.example.com_us.ui.question.theme
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.MenuItem
+import android.widget.Toast
import androidx.activity.viewModels
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.ui.platform.ViewCompositionStrategy
+import androidx.lifecycle.lifecycleScope
import com.example.com_us.R
import com.example.com_us.databinding.ActivityThemeQuestionListBinding
-import com.example.com_us.ui.question.QuestionDetailActivity
+import com.example.com_us.ui.base.UiState
+import com.example.com_us.ui.question.select.SelectAnswerActivity
import com.example.com_us.ui.compose.QuestionListItem
-import com.example.com_us.ui.question.QuestionViewModel
-import com.example.com_us.ui.question.QuestionViewModelFactory
+import dagger.hilt.android.AndroidEntryPoint
+import kotlinx.coroutines.launch
-class HomeThemeQuestionListActivity : AppCompatActivity() {
+@AndroidEntryPoint
+class ThemeQuestionListActivity : AppCompatActivity() {
private lateinit var binding: ActivityThemeQuestionListBinding
- private val questionViewModel: QuestionViewModel by viewModels { QuestionViewModelFactory(applicationContext) }
+ private val viewModel: ThemeQuestionListViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityThemeQuestionListBinding.inflate(layoutInflater)
+ val theme = intent.getStringExtra("theme").toString()
+ viewModel.loadQuestionListByCate(theme)
+
setContentView(binding.root)
+ }
- val theme = intent.getStringExtra("theme").toString()
+ override fun onStart() {
+ super.onStart()
val themeKor = intent.getStringExtra("themeKor")
binding.textviewTitle.text = String.format(resources.getString(R.string.theme_question_list_title), themeKor)
-
- questionViewModel.loadQuestionListByCate(theme)
-
setActionBar()
setComposeList()
}
private fun setComposeList() {
- questionViewModel.questionListByCate.observe(this) {
- binding.composeviewTheme.apply {
- setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
- setContent {
- LazyColumn {
- items(it.size) { idx ->
- QuestionListItem(data = it[idx], onClick = { moveToQuestionDetail(it[idx].id) })
+ lifecycleScope.launch {
+ viewModel.uiState.collect {
+ when (it) {
+ is UiState.Success -> {
+ binding.composeviewTheme.apply {
+ setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
+ setContent {
+ LazyColumn {
+ println(it.data)
+ items(it.data.size) { idx ->
+ QuestionListItem(
+ data = it.data[idx],
+ onClick = { moveToQuestionDetail(it.data[idx].id) })
+ }
+ }
+ }
}
}
+ is UiState.Error -> {
+ Toast.makeText(this@ThemeQuestionListActivity,it.toString(),Toast.LENGTH_SHORT).show()
+ }
+ else -> {}
}
}
}
}
-
private fun setActionBar() {
setSupportActionBar(binding.includeToolbar.toolbar)
-
val actionBar = supportActionBar
actionBar?.setDisplayHomeAsUpEnabled(true)
actionBar?.setHomeAsUpIndicator(R.drawable.ic_arrow_left)
}
private fun moveToQuestionDetail(questionId: Long) {
- val intent = Intent(this, QuestionDetailActivity::class.java)
+ val intent = Intent(this, SelectAnswerActivity::class.java)
intent.putExtra("questionId", questionId)
startActivity(intent)
}
diff --git a/app/src/main/java/com/example/com_us/ui/question/theme/ThemeQuestionListViewModel.kt b/app/src/main/java/com/example/com_us/ui/question/theme/ThemeQuestionListViewModel.kt
new file mode 100644
index 0000000..1e72890
--- /dev/null
+++ b/app/src/main/java/com/example/com_us/ui/question/theme/ThemeQuestionListViewModel.kt
@@ -0,0 +1,60 @@
+package com.example.com_us.ui.question.theme
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import com.example.com_us.R
+import com.example.com_us.base.data.NetworkError
+import com.example.com_us.data.model.question.response.question.ResponseQuestionDto
+import com.example.com_us.data.repository.QuestionRepository
+import com.example.com_us.ui.base.UiState
+import dagger.hilt.android.lifecycle.HiltViewModel
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.launch
+import javax.inject.Inject
+
+
+
+@HiltViewModel
+class ThemeQuestionListViewModel @Inject constructor(
+ private val questionRepository: QuestionRepository
+) : ViewModel() {
+ // 질문 리스트
+ private val _questionListByCate = MutableLiveData>()
+ val questionListByCate: LiveData> = _questionListByCate
+
+
+ // ui 상태 변수
+ private val _uiState = MutableStateFlow>>(UiState.Initial)
+ val uiState = _uiState.asStateFlow()
+
+ // 선택한 테마의 id
+ private val _selectedThemeId = MutableLiveData().apply {
+ value = R.id.include_theme_all
+ }
+ val selectedThemeId: LiveData = _selectedThemeId
+
+
+
+ // 클릭한 카테고리의 질문 리스트를 가져오는 함수
+ fun loadQuestionListByCate(category: String){
+ viewModelScope.launch {
+ questionRepository.getQuestionListByCate(category)
+ .onSuccess {
+ _uiState.value = UiState.Success(it)
+ }
+ .onFailure {
+ val errorMessage = when(it){
+ is NetworkError.NetworkException -> {it.message}
+ is NetworkError.NullDataError -> {"아직 데이터를 준비중이에요!"}
+ else -> "알 수 없는 에러가 발생했습니다. 다시 시도해주세요!"
+ }
+ if (errorMessage != null) {
+ _uiState.value = UiState.Error(errorMessage)
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/com_us/util/ColorMatch.kt b/app/src/main/java/com/example/com_us/util/ColorMatch.kt
index aca09f3..150f50a 100644
--- a/app/src/main/java/com/example/com_us/util/ColorMatch.kt
+++ b/app/src/main/java/com/example/com_us/util/ColorMatch.kt
@@ -1,5 +1,6 @@
package com.example.com_us.util
+import android.content.Context
import androidx.compose.ui.graphics.Color
import com.example.com_us.R
import com.example.com_us.ui.compose.theme.Blue700
@@ -9,7 +10,8 @@ import com.example.com_us.ui.compose.theme.Pink700
import com.example.com_us.ui.compose.theme.Purple700
import com.example.com_us.ui.compose.theme.Salmon700
-enum class ColorMatch(val kor: String, val colorType: ColorType, val color: Color, val colorRes: Int) {
+enum class ColorMatch(
+ val kor: String, val colorType: ColorType, val color: Color, val colorRes: Int) {
DAILY("일상", ColorType.ORANGE, Orange700, R.color.orange_700),
SCHOOL("학교", ColorType.BLUE, Blue700, R.color.blue_700),
FRIEND("친구", ColorType.GREEN, Green700, R.color.green_700),
diff --git a/app/src/main/java/com/example/com_us/util/QuestionManager.kt b/app/src/main/java/com/example/com_us/util/QuestionManager.kt
index 069a081..f59b649 100644
--- a/app/src/main/java/com/example/com_us/util/QuestionManager.kt
+++ b/app/src/main/java/com/example/com_us/util/QuestionManager.kt
@@ -1,6 +1,6 @@
package com.example.com_us.util
-import com.example.com_us.data.response.question.ResponseAnswerDetailDto
+import com.example.com_us.data.model.question.response.question.ResponseAnswerDetailDto
object QuestionManager {
var questionId: Long = -1
diff --git a/app/src/main/res/drawable/btn_complete_selected.xml b/app/src/main/res/drawable/btn_complete_selected.xml
new file mode 100644
index 0000000..ee6dee1
--- /dev/null
+++ b/app/src/main/res/drawable/btn_complete_selected.xml
@@ -0,0 +1,12 @@
+
+
+
+
diff --git a/app/src/main/res/drawable/btn_complete_unselected.xml b/app/src/main/res/drawable/btn_complete_unselected.xml
new file mode 100644
index 0000000..135dff9
--- /dev/null
+++ b/app/src/main/res/drawable/btn_complete_unselected.xml
@@ -0,0 +1,12 @@
+
+
+
+
diff --git a/app/src/main/res/drawable/btn_google_login.png b/app/src/main/res/drawable/btn_google_login.png
new file mode 100644
index 0000000..4f15111
Binary files /dev/null and b/app/src/main/res/drawable/btn_google_login.png differ
diff --git a/app/src/main/res/drawable/ic_block_family_purple.xml b/app/src/main/res/drawable/ic_block_family_purple.xml
new file mode 100644
index 0000000..f415548
--- /dev/null
+++ b/app/src/main/res/drawable/ic_block_family_purple.xml
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_block_friend_green.xml b/app/src/main/res/drawable/ic_block_friend_green.xml
new file mode 100644
index 0000000..443c270
--- /dev/null
+++ b/app/src/main/res/drawable/ic_block_friend_green.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_block_interest_pink.xml b/app/src/main/res/drawable/ic_block_interest_pink.xml
new file mode 100644
index 0000000..6858838
--- /dev/null
+++ b/app/src/main/res/drawable/ic_block_interest_pink.xml
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_block_school_blue.xml b/app/src/main/res/drawable/ic_block_school_blue.xml
new file mode 100644
index 0000000..0646f99
--- /dev/null
+++ b/app/src/main/res/drawable/ic_block_school_blue.xml
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_block_school_orange.xml b/app/src/main/res/drawable/ic_block_school_orange.xml
new file mode 100644
index 0000000..e197fa8
--- /dev/null
+++ b/app/src/main/res/drawable/ic_block_school_orange.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_daily.xml b/app/src/main/res/drawable/ic_daily.xml
new file mode 100644
index 0000000..33ae60e
--- /dev/null
+++ b/app/src/main/res/drawable/ic_daily.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_entire.xml b/app/src/main/res/drawable/ic_entire.xml
new file mode 100644
index 0000000..a0287a7
--- /dev/null
+++ b/app/src/main/res/drawable/ic_entire.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_hamburger.xml b/app/src/main/res/drawable/ic_hamburger.xml
new file mode 100644
index 0000000..72b7e27
--- /dev/null
+++ b/app/src/main/res/drawable/ic_hamburger.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_home_blue.xml b/app/src/main/res/drawable/ic_home_blue.xml
new file mode 100644
index 0000000..0ca7da8
--- /dev/null
+++ b/app/src/main/res/drawable/ic_home_blue.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_logo.xml b/app/src/main/res/drawable/ic_logo.xml
new file mode 100644
index 0000000..862d47d
--- /dev/null
+++ b/app/src/main/res/drawable/ic_logo.xml
@@ -0,0 +1,12 @@
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_speech_bubble.xml b/app/src/main/res/drawable/ic_speech_bubble.xml
new file mode 100644
index 0000000..fbf31b4
--- /dev/null
+++ b/app/src/main/res/drawable/ic_speech_bubble.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_tag_conversation.xml b/app/src/main/res/drawable/ic_tag_conversation.xml
new file mode 100644
index 0000000..b39a328
--- /dev/null
+++ b/app/src/main/res/drawable/ic_tag_conversation.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_tag_select.xml b/app/src/main/res/drawable/ic_tag_select.xml
new file mode 100644
index 0000000..d5cd735
--- /dev/null
+++ b/app/src/main/res/drawable/ic_tag_select.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_timer.xml b/app/src/main/res/drawable/ic_timer.xml
new file mode 100644
index 0000000..489540c
--- /dev/null
+++ b/app/src/main/res/drawable/ic_timer.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_user_blue.xml b/app/src/main/res/drawable/ic_user_blue.xml
new file mode 100644
index 0000000..3276d94
--- /dev/null
+++ b/app/src/main/res/drawable/ic_user_blue.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_user_green.xml b/app/src/main/res/drawable/ic_user_green.xml
new file mode 100644
index 0000000..bacb8a8
--- /dev/null
+++ b/app/src/main/res/drawable/ic_user_green.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_user_orange.xml b/app/src/main/res/drawable/ic_user_orange.xml
new file mode 100644
index 0000000..da13bbd
--- /dev/null
+++ b/app/src/main/res/drawable/ic_user_orange.xml
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_user_pink.xml b/app/src/main/res/drawable/ic_user_pink.xml
new file mode 100644
index 0000000..a2fc8fc
--- /dev/null
+++ b/app/src/main/res/drawable/ic_user_pink.xml
@@ -0,0 +1,69 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_user_purple.xml b/app/src/main/res/drawable/ic_user_purple.xml
new file mode 100644
index 0000000..4785ecc
--- /dev/null
+++ b/app/src/main/res/drawable/ic_user_purple.xml
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/layout_table.xml b/app/src/main/res/drawable/layout_table.xml
new file mode 100644
index 0000000..bbbcfb0
--- /dev/null
+++ b/app/src/main/res/drawable/layout_table.xml
@@ -0,0 +1,18 @@
+
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/shape_stroke_rect_bottomleft10_gray200.xml b/app/src/main/res/drawable/shape_stroke_rect_bottomleft10_gray200.xml
index 8ff971d..33ce8e7 100644
--- a/app/src/main/res/drawable/shape_stroke_rect_bottomleft10_gray200.xml
+++ b/app/src/main/res/drawable/shape_stroke_rect_bottomleft10_gray200.xml
@@ -3,4 +3,4 @@
android:shape="rectangle">
-
\ No newline at end of file
+
diff --git a/app/src/main/res/drawable/shape_stroke_rect_gray200.xml b/app/src/main/res/drawable/shape_stroke_rect_gray200.xml
index 73ddd04..45b8859 100644
--- a/app/src/main/res/drawable/shape_stroke_rect_gray200.xml
+++ b/app/src/main/res/drawable/shape_stroke_rect_gray200.xml
@@ -2,4 +2,5 @@
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml
new file mode 100644
index 0000000..281f59d
--- /dev/null
+++ b/app/src/main/res/layout/activity_login.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 2e6249e..60f59f2 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -4,7 +4,7 @@
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent">
-/
+
@@ -24,11 +24,11 @@
app:menu="@menu/bottom_nav_menu" />
+ tools:context=".ui.question.result.ResultBeforeSignActivity">
+ tools:context=".ui.question.block.CollectBlockActivity">
+ tools:context=".ui.question.select.SelectAnswerActivity">
+ tools:context=".ui.question.previous.PreviousAnswerActivity">
+ tools:context=".ui.question.result.ResultAfterSignActivity">
+ tools:context=".ui.question.theme.ThemeQuestionListActivity">
+ tools:context=".ui.question.sign.SignAnswerDialog">
+
+
+
+ app:layout_constraintTop_toBottomOf="@+id/linearProgressIndicator" />
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml
index 1158c01..d76a617 100644
--- a/app/src/main/res/layout/fragment_home.xml
+++ b/app/src/main/res/layout/fragment_home.xml
@@ -297,10 +297,11 @@
android:layout_weight="1">
+ android:background="@drawable/shape_stroke_rect_gray200" />
+ android:background="@drawable/shape_stroke_rect_gray200" />
diff --git a/app/src/main/res/layout/fragment_question.xml b/app/src/main/res/layout/fragment_question.xml
index e3856f3..f9dc4e7 100644
--- a/app/src/main/res/layout/fragment_question.xml
+++ b/app/src/main/res/layout/fragment_question.xml
@@ -9,7 +9,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
- tools:context=".ui.question.QuestionFragment">
+ tools:context=".ui.question.list.AllQuestionListFragment">
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index cd74fba..05c48de 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1,4 +1,5 @@
+ "http://15.165.140.141:8080"
com-us
Home
홈
diff --git a/build.gradle.kts b/build.gradle.kts
index 0da18c4..48af700 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -2,4 +2,6 @@
plugins {
id("com.android.application") version "8.2.2" apply false
id("org.jetbrains.kotlin.android") version "1.9.10" apply false
+ id("com.google.devtools.ksp") version "1.9.0-1.0.12" apply false
+ id("com.google.dagger.hilt.android") version "2.51.1" apply false
}
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 12624c2..f2f6f5d 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Sun Aug 11 21:39:17 KST 2024
+#Tue Nov 19 11:13:40 KST 2024
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists