diff --git a/app/build.gradle b/app/build.gradle index b469ce5b..ce889540 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -108,6 +108,10 @@ dependencies { implementation "com.kakao.sdk:v2-share:2.15.0" // 메시지(카카오톡 공유) //EncryptedSharedPreference implementation "androidx.security:security-crypto-ktx:1.1.0-alpha06" + // dataStore + implementation "androidx.datastore:datastore-preferences:1.0.0" + + } // hilt dependency와 함께 추가 kapt { diff --git a/app/src/main/java/com/puzzling/puzzlingaos/data/datasource/local/TokenDataSource.kt b/app/src/main/java/com/puzzling/puzzlingaos/data/datasource/local/TokenDataSource.kt new file mode 100644 index 00000000..e3f3db63 --- /dev/null +++ b/app/src/main/java/com/puzzling/puzzlingaos/data/datasource/local/TokenDataSource.kt @@ -0,0 +1,41 @@ +package com.puzzling.puzzlingaos.data.datasource.local + +import android.os.Build +import androidx.annotation.RequiresApi +import androidx.datastore.core.Serializer +import com.puzzling.puzzlingaos.data.entity.Token +import com.puzzling.puzzlingaos.data.service.CryptoService +import kotlinx.serialization.json.Json +import org.apache.commons.lang3.SerializationException +import java.io.InputStream +import java.io.OutputStream +import javax.inject.Inject + +@RequiresApi(Build.VERSION_CODES.M) +class TokenDataSource @Inject constructor(private val cryptoService: CryptoService) : Serializer { + override val defaultValue: Token + get() = Token() + + override suspend fun readFrom(input: InputStream): Token { + val decryptedBytes = cryptoService.decrypt(input) + return try { + Json.decodeFromString( + deserializer = Token.serializer(), + string = decryptedBytes.decodeToString(), + ) + } catch (e: SerializationException) { + e.printStackTrace() + defaultValue + } + } + + override suspend fun writeTo(t: Token, output: OutputStream) { + cryptoService.encrypt( + bytes = Json.encodeToString( + serializer = Token.serializer(), + value = t, + ).encodeToByteArray(), + outputStream = output, + ) + } +} diff --git a/app/src/main/java/com/puzzling/puzzlingaos/data/datasource/remote/ProjectDataSource.kt b/app/src/main/java/com/puzzling/puzzlingaos/data/datasource/remote/ProjectDataSource.kt index 413a3a83..d20e2529 100644 --- a/app/src/main/java/com/puzzling/puzzlingaos/data/datasource/remote/ProjectDataSource.kt +++ b/app/src/main/java/com/puzzling/puzzlingaos/data/datasource/remote/ProjectDataSource.kt @@ -1,6 +1,6 @@ package com.puzzling.puzzlingaos.data.datasource.remote -import com.puzzling.puzzlingaos.data.model.request.RequestInvitationCode +import com.puzzling.puzzlingaos.data.model.request.RequestJoinProject import com.puzzling.puzzlingaos.data.model.request.RequestProjectRegisterDto import com.puzzling.puzzlingaos.data.model.response.ResponseInvitationCodeDto import com.puzzling.puzzlingaos.data.model.response.ResponseJoinProjectDto @@ -15,7 +15,7 @@ interface ProjectDataSource { suspend fun joinProject( memberId: Int, - request: RequestInvitationCode, + request: RequestJoinProject, ): ResponseJoinProjectDto suspend fun isValidInvitationCode( diff --git a/app/src/main/java/com/puzzling/puzzlingaos/data/datasource/remote/impl/ProjectDataSourceImpl.kt b/app/src/main/java/com/puzzling/puzzlingaos/data/datasource/remote/impl/ProjectDataSourceImpl.kt index 93556380..d577e675 100644 --- a/app/src/main/java/com/puzzling/puzzlingaos/data/datasource/remote/impl/ProjectDataSourceImpl.kt +++ b/app/src/main/java/com/puzzling/puzzlingaos/data/datasource/remote/impl/ProjectDataSourceImpl.kt @@ -1,7 +1,7 @@ package com.puzzling.puzzlingaos.data.datasource.remote.impl import com.puzzling.puzzlingaos.data.datasource.remote.ProjectDataSource -import com.puzzling.puzzlingaos.data.model.request.RequestInvitationCode +import com.puzzling.puzzlingaos.data.model.request.RequestJoinProject import com.puzzling.puzzlingaos.data.model.request.RequestProjectRegisterDto import com.puzzling.puzzlingaos.data.model.response.ResponseInvitationCodeDto import com.puzzling.puzzlingaos.data.model.response.ResponseJoinProjectDto @@ -22,7 +22,7 @@ class ProjectDataSourceImpl @Inject constructor( override suspend fun joinProject( memberId: Int, - request: RequestInvitationCode, + request: RequestJoinProject, ): ResponseJoinProjectDto = apiService.joinProject(memberId, request) override suspend fun isValidInvitationCode(invitationCode: String): ResponseInvitationCodeDto = diff --git a/app/src/main/java/com/puzzling/puzzlingaos/data/entity/Token.kt b/app/src/main/java/com/puzzling/puzzlingaos/data/entity/Token.kt new file mode 100644 index 00000000..8e9e57fc --- /dev/null +++ b/app/src/main/java/com/puzzling/puzzlingaos/data/entity/Token.kt @@ -0,0 +1,8 @@ +package com.puzzling.puzzlingaos.data.entity + +import kotlinx.serialization.Serializable + +@Serializable +data class Token( + val accessToken: String? = null, +) diff --git a/app/src/main/java/com/puzzling/puzzlingaos/data/model/request/RequestInvitationCode.kt b/app/src/main/java/com/puzzling/puzzlingaos/data/model/request/RequestJoinProject.kt similarity index 60% rename from app/src/main/java/com/puzzling/puzzlingaos/data/model/request/RequestInvitationCode.kt rename to app/src/main/java/com/puzzling/puzzlingaos/data/model/request/RequestJoinProject.kt index 553d328f..f57b0aae 100644 --- a/app/src/main/java/com/puzzling/puzzlingaos/data/model/request/RequestInvitationCode.kt +++ b/app/src/main/java/com/puzzling/puzzlingaos/data/model/request/RequestJoinProject.kt @@ -1,10 +1,11 @@ package com.puzzling.puzzlingaos.data.model.request +import com.puzzling.puzzlingaos.domain.entity.JoinProjectInfo import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @Serializable -data class RequestInvitationCode( +data class RequestJoinProject( @SerialName("projectId") val projectId: Int, @SerialName("memberProjectNickname") @@ -12,3 +13,9 @@ data class RequestInvitationCode( @SerialName("memberProjectRole") val memberProjectRole: String, ) + +fun JoinProjectInfo.toRequestJoinProjectDto() = RequestJoinProject( + projectId, + memberProjectNickname, + memberProjectRole, +) diff --git a/app/src/main/java/com/puzzling/puzzlingaos/data/model/response/ResponseDetailRetroDto.kt b/app/src/main/java/com/puzzling/puzzlingaos/data/model/response/ResponseDetailRetroDto.kt index 34352f02..c2de2f4f 100644 --- a/app/src/main/java/com/puzzling/puzzlingaos/data/model/response/ResponseDetailRetroDto.kt +++ b/app/src/main/java/com/puzzling/puzzlingaos/data/model/response/ResponseDetailRetroDto.kt @@ -1,5 +1,6 @@ package com.puzzling.puzzlingaos.data.model.response +import com.puzzling.puzzlingaos.domain.entity.DetailRetro import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @@ -12,7 +13,7 @@ data class ResponseDetailRetroDto( @SerialName("message") val message: String, @SerialName("data") - val data: Data?, + val data: Data, ) { @Serializable data class Data( @@ -42,5 +43,18 @@ data class ResponseDetailRetroDto( val content: String, ) } + + fun toDetailRetro() = reviews.map { reviews -> + DetailRetro( + reviewId = reviews.reviewId, + reviewDay = reviews.reviewDay, + reviewDate = reviews.reviewDate, + reviewTemplateId = reviews.reviewTemplateId, + content = reviews.contents?.map { content -> + DetailRetro.Content(content.title, content.content) + }, + + ) + } } } diff --git a/app/src/main/java/com/puzzling/puzzlingaos/data/model/response/ResponseInvitationCodeDto.kt b/app/src/main/java/com/puzzling/puzzlingaos/data/model/response/ResponseInvitationCodeDto.kt index 78e4389f..cba18274 100644 --- a/app/src/main/java/com/puzzling/puzzlingaos/data/model/response/ResponseInvitationCodeDto.kt +++ b/app/src/main/java/com/puzzling/puzzlingaos/data/model/response/ResponseInvitationCodeDto.kt @@ -1,5 +1,6 @@ package com.puzzling.puzzlingaos.data.model.response +import com.puzzling.puzzlingaos.domain.entity.InvitationCode import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @@ -12,7 +13,7 @@ data class ResponseInvitationCodeDto( @SerialName("message") val message: String, @SerialName("data") - val data: InvitationCodeData?, + val data: InvitationCodeData, ) { @Serializable data class InvitationCodeData( @@ -20,5 +21,7 @@ data class ResponseInvitationCodeDto( val projectId: Int, @SerialName("projectName") val projectName: String, - ) + ) { + fun toInvitationCode() = InvitationCode(projectId, projectName) + } } diff --git a/app/src/main/java/com/puzzling/puzzlingaos/data/model/response/ResponseMyRetroListDto.kt b/app/src/main/java/com/puzzling/puzzlingaos/data/model/response/ResponseMyRetroListDto.kt index 16059fc1..01e97bb4 100644 --- a/app/src/main/java/com/puzzling/puzzlingaos/data/model/response/ResponseMyRetroListDto.kt +++ b/app/src/main/java/com/puzzling/puzzlingaos/data/model/response/ResponseMyRetroListDto.kt @@ -1,5 +1,6 @@ package com.puzzling.puzzlingaos.data.model.response +import com.puzzling.puzzlingaos.domain.entity.ProjectReview import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @@ -12,7 +13,7 @@ data class ResponseMyRetroListDto( @SerialName("message") val message: String, @SerialName("data") - val data: List?, + val data: List, ) { @Serializable data class ReviewData( @@ -23,5 +24,12 @@ data class ResponseMyRetroListDto( @SerialName("contents") val contents: String, ) -} + fun toProjectReview() = data.map { reviewData -> + ProjectReview( + reviewData.reviewId, + reviewData.reviewDate, + reviewData.contents, + ) + } +} diff --git a/app/src/main/java/com/puzzling/puzzlingaos/data/model/response/ResponseProjectRetroWeekDto.kt b/app/src/main/java/com/puzzling/puzzlingaos/data/model/response/ResponseProjectRetroWeekDto.kt index a251cc64..4d94cfc3 100644 --- a/app/src/main/java/com/puzzling/puzzlingaos/data/model/response/ResponseProjectRetroWeekDto.kt +++ b/app/src/main/java/com/puzzling/puzzlingaos/data/model/response/ResponseProjectRetroWeekDto.kt @@ -1,5 +1,6 @@ package com.puzzling.puzzlingaos.data.model.response +import com.puzzling.puzzlingaos.domain.entity.ReviewCycle import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @@ -12,7 +13,7 @@ data class ResponseProjectRetroWeekDto( @SerialName("message") val message: String, @SerialName("data") - val data: ProjectCycle?, + val data: ProjectCycle, ) { @Serializable data class ProjectCycle( @@ -20,5 +21,7 @@ data class ResponseProjectRetroWeekDto( val projectName: String, @SerialName("projectReviewCycle") val projectReviewCycle: String, - ) + ) { + fun toReviewCycle() = ReviewCycle(projectName, projectReviewCycle) + } } diff --git a/app/src/main/java/com/puzzling/puzzlingaos/data/repository/MyPageRepositoryImpl.kt b/app/src/main/java/com/puzzling/puzzlingaos/data/repository/MyPageRepositoryImpl.kt index a429e304..b3a35617 100644 --- a/app/src/main/java/com/puzzling/puzzlingaos/data/repository/MyPageRepositoryImpl.kt +++ b/app/src/main/java/com/puzzling/puzzlingaos/data/repository/MyPageRepositoryImpl.kt @@ -1,23 +1,32 @@ package com.puzzling.puzzlingaos.data.repository import com.puzzling.puzzlingaos.data.datasource.remote.MyPageDataSource -import com.puzzling.puzzlingaos.data.model.response.ResponseDetailRetroDto -import com.puzzling.puzzlingaos.data.model.response.ResponseMyRetroListDto +import com.puzzling.puzzlingaos.domain.entity.DetailRetro +import com.puzzling.puzzlingaos.domain.entity.ProjectReview import com.puzzling.puzzlingaos.domain.repository.MyPageRepository import javax.inject.Inject class MyPageRepositoryImpl @Inject constructor(private val myPageDataSource: MyPageDataSource) : MyPageRepository { - override suspend fun getMyProjectReview(memberId: Int, projectId: Int): ResponseMyRetroListDto { - return myPageDataSource.getMyProjectReview(memberId, projectId) - } + override suspend fun getMyProjectReview( + memberId: Int, + projectId: Int, + ): Result> = + runCatching { + myPageDataSource.getMyProjectReview(memberId, projectId).toProjectReview() + } override suspend fun getMyDetailReview( memberId: Int, projectId: Int, startDate: String, endDate: String, - ): ResponseDetailRetroDto { - return myPageDataSource.getMyDetailReview(memberId, projectId, startDate, endDate) + ): Result> = runCatching { + myPageDataSource.getMyDetailReview( + memberId, + projectId, + startDate, + endDate, + ).data.toDetailRetro() } } diff --git a/app/src/main/java/com/puzzling/puzzlingaos/data/repository/ProjectRepositoryImpl.kt b/app/src/main/java/com/puzzling/puzzlingaos/data/repository/ProjectRepositoryImpl.kt index 79e52d3c..ab637ca4 100644 --- a/app/src/main/java/com/puzzling/puzzlingaos/data/repository/ProjectRepositoryImpl.kt +++ b/app/src/main/java/com/puzzling/puzzlingaos/data/repository/ProjectRepositoryImpl.kt @@ -2,12 +2,13 @@ package com.puzzling.puzzlingaos.data.repository import android.util.Log import com.puzzling.puzzlingaos.data.datasource.remote.ProjectDataSource -import com.puzzling.puzzlingaos.data.model.request.RequestInvitationCode import com.puzzling.puzzlingaos.data.model.request.RequestProjectRegisterDto -import com.puzzling.puzzlingaos.data.model.response.ResponseInvitationCodeDto +import com.puzzling.puzzlingaos.data.model.request.toRequestJoinProjectDto import com.puzzling.puzzlingaos.data.model.response.ResponseJoinProjectDto import com.puzzling.puzzlingaos.data.model.response.ResponseProjectRegisterDto -import com.puzzling.puzzlingaos.data.model.response.ResponseProjectRetroWeekDto +import com.puzzling.puzzlingaos.domain.entity.InvitationCode +import com.puzzling.puzzlingaos.domain.entity.JoinProjectInfo +import com.puzzling.puzzlingaos.domain.entity.ReviewCycle import com.puzzling.puzzlingaos.domain.repository.ProjectRepository import javax.inject.Inject @@ -28,16 +29,17 @@ class ProjectRepositoryImpl @Inject constructor( override suspend fun joinProject( memberId: Int, - request: RequestInvitationCode, - ): ResponseJoinProjectDto { - return projectDataSource.joinProject(memberId, request) + request: JoinProjectInfo, + ): Result = runCatching { + projectDataSource.joinProject(memberId, request.toRequestJoinProjectDto()) } - override suspend fun isValidInvitationCode(invitationCode: String): ResponseInvitationCodeDto { - return projectDataSource.isValidInvitationCode(invitationCode) - } + override suspend fun isValidInvitationCode(invitationCode: String): Result = + runCatching { + projectDataSource.isValidInvitationCode(invitationCode).data.toInvitationCode() + } - override suspend fun getProjectWeekCycle(projectId: Int): ResponseProjectRetroWeekDto { - return projectDataSource.getProjectWeekCycle(projectId) + override suspend fun getProjectWeekCycle(projectId: Int): Result = runCatching { + projectDataSource.getProjectWeekCycle(projectId).data.toReviewCycle() } } diff --git a/app/src/main/java/com/puzzling/puzzlingaos/data/repository/TokenRepositoryImpl.kt b/app/src/main/java/com/puzzling/puzzlingaos/data/repository/TokenRepositoryImpl.kt new file mode 100644 index 00000000..e2f9412a --- /dev/null +++ b/app/src/main/java/com/puzzling/puzzlingaos/data/repository/TokenRepositoryImpl.kt @@ -0,0 +1,16 @@ +package com.puzzling.puzzlingaos.data.repository + +import androidx.datastore.core.DataStore +import com.puzzling.puzzlingaos.data.entity.Token +import com.puzzling.puzzlingaos.domain.repository.TokenRepository +import kotlinx.coroutines.flow.first +import javax.inject.Inject + +class TokenRepositoryImpl @Inject constructor(private val dataStore: DataStore) : + TokenRepository { + override suspend fun setToken(token: String) { + dataStore.updateData { Token(token) } + } + + override suspend fun getToken(): Token = dataStore.data.first() +} diff --git a/app/src/main/java/com/puzzling/puzzlingaos/data/service/CryptoService.kt b/app/src/main/java/com/puzzling/puzzlingaos/data/service/CryptoService.kt new file mode 100644 index 00000000..d052fb7a --- /dev/null +++ b/app/src/main/java/com/puzzling/puzzlingaos/data/service/CryptoService.kt @@ -0,0 +1,84 @@ +package com.puzzling.puzzlingaos.data.service + +import android.os.Build +import android.security.keystore.KeyGenParameterSpec +import android.security.keystore.KeyProperties +import androidx.annotation.RequiresApi +import java.io.InputStream +import java.io.OutputStream +import java.security.KeyStore +import javax.crypto.Cipher +import javax.crypto.KeyGenerator +import javax.crypto.SecretKey +import javax.crypto.spec.IvParameterSpec +import javax.inject.Inject + +@RequiresApi(Build.VERSION_CODES.M) +class CryptoService @Inject constructor() { + + private val keyStore = KeyStore.getInstance("AndroidKeyStore").apply { + load(null) + } + + private val encryptCipher = Cipher.getInstance(TRANSFORMATION).apply { + init(Cipher.ENCRYPT_MODE, getKey()) + } + + private fun getDecryptCipher(iv: ByteArray): Cipher { + return Cipher.getInstance(TRANSFORMATION).apply { + init(Cipher.DECRYPT_MODE, getKey(), IvParameterSpec(iv)) + } + } + + private fun getKey(): SecretKey { + val existingKey = keyStore.getEntry("secret", null) as? KeyStore.SecretKeyEntry + return existingKey?.secretKey ?: createKey() + } + + private fun createKey(): SecretKey { + return KeyGenerator.getInstance(ALGORITHM).apply { + init( + KeyGenParameterSpec.Builder( + "secret", + KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT, + ).setBlockModes(BLOCK_MODE).setEncryptionPaddings( + PADDING, + ).setUserAuthenticationRequired(false) // 지문인식 같은거 false + .setRandomizedEncryptionRequired(true).build(), + ) + }.generateKey() + } + + fun encrypt(bytes: ByteArray, outputStream: OutputStream): ByteArray { + val encryptedBytes = encryptCipher.doFinal(bytes) + outputStream.use { + it.write(encryptCipher.iv.size) + it.write(encryptCipher.iv) + it.write(encryptedBytes.size) + it.write(encryptedBytes) + } + + return encryptedBytes + } + + fun decrypt(inputStream: InputStream): ByteArray { + return inputStream.use { + val ivSize = it.read() + val iv = ByteArray(ivSize) + it.read(iv) + + val encryptedBytesSize = it.read() + val encryptedBytes = ByteArray(encryptedBytesSize) + it.read(encryptedBytes) + + getDecryptCipher(iv).doFinal(encryptedBytes) + } + } + + companion object { + private const val ALGORITHM = KeyProperties.KEY_ALGORITHM_AES + private const val BLOCK_MODE = KeyProperties.BLOCK_MODE_CBC + private const val PADDING = KeyProperties.ENCRYPTION_PADDING_PKCS7 + private const val TRANSFORMATION = "$ALGORITHM/$BLOCK_MODE/$PADDING" + } +} diff --git a/app/src/main/java/com/puzzling/puzzlingaos/data/service/KakaoLoginService.kt b/app/src/main/java/com/puzzling/puzzlingaos/data/service/KakaoAuthService.kt similarity index 88% rename from app/src/main/java/com/puzzling/puzzlingaos/data/service/KakaoLoginService.kt rename to app/src/main/java/com/puzzling/puzzlingaos/data/service/KakaoAuthService.kt index 335dee3c..4480d182 100644 --- a/app/src/main/java/com/puzzling/puzzlingaos/data/service/KakaoLoginService.kt +++ b/app/src/main/java/com/puzzling/puzzlingaos/data/service/KakaoAuthService.kt @@ -3,8 +3,10 @@ package com.puzzling.puzzlingaos.data.service import android.content.Context import com.kakao.sdk.auth.model.OAuthToken import com.kakao.sdk.user.UserApiClient +import dagger.hilt.android.qualifiers.ActivityContext +import javax.inject.Inject -class KakaoLoginService(private val context: Context) { +class KakaoAuthService @Inject constructor(@ActivityContext private val context: Context) { fun startKakaoLogin(kakaoLoginCallBack: (OAuthToken?, Throwable?) -> Unit) { val kakaoLoginState = if (UserApiClient.instance.isKakaoTalkLoginAvailable(context)) { @@ -20,6 +22,7 @@ class KakaoLoginService(private val context: Context) { callback = kakaoLoginCallBack, ) } + KAKAO_ACCOUNT_LOGIN -> { UserApiClient.instance.loginWithKakaoAccount( context, diff --git a/app/src/main/java/com/puzzling/puzzlingaos/data/service/ProjectService.kt b/app/src/main/java/com/puzzling/puzzlingaos/data/service/ProjectService.kt index 56b89f01..aa20b455 100644 --- a/app/src/main/java/com/puzzling/puzzlingaos/data/service/ProjectService.kt +++ b/app/src/main/java/com/puzzling/puzzlingaos/data/service/ProjectService.kt @@ -1,6 +1,6 @@ package com.puzzling.puzzlingaos.data.service -import com.puzzling.puzzlingaos.data.model.request.RequestInvitationCode +import com.puzzling.puzzlingaos.data.model.request.RequestJoinProject import com.puzzling.puzzlingaos.data.model.request.RequestProjectRegisterDto import com.puzzling.puzzlingaos.data.model.response.ResponseInvitationCodeDto import com.puzzling.puzzlingaos.data.model.response.ResponseJoinProjectDto @@ -23,7 +23,7 @@ interface ProjectService { @POST("api/v1/member/{memberId}/project/join") suspend fun joinProject( @Path("memberId") memberId: Int, - @Body request: RequestInvitationCode, + @Body request: RequestJoinProject, ): ResponseJoinProjectDto @GET("api/v1/project/verify?") diff --git a/app/src/main/java/com/puzzling/puzzlingaos/di/DataStoreModule.kt b/app/src/main/java/com/puzzling/puzzlingaos/di/DataStoreModule.kt new file mode 100644 index 00000000..22a0c10d --- /dev/null +++ b/app/src/main/java/com/puzzling/puzzlingaos/di/DataStoreModule.kt @@ -0,0 +1,35 @@ +package com.puzzling.puzzlingaos.di + +import android.content.Context +import androidx.datastore.core.DataStore +import androidx.datastore.core.DataStoreFactory +import androidx.datastore.dataStoreFile +import com.puzzling.puzzlingaos.data.datasource.local.TokenDataSource +import com.puzzling.puzzlingaos.data.entity.Token +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.qualifiers.ApplicationContext +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +object DataStoreModule { + private const val USER_PREFERENCES_NAME = "user_preferences" + private const val DATA_STORE_FILE_NAME = "user_prefs.pb" + + @Provides + @Singleton + fun providePreferencesDataStore( + @ApplicationContext appContext: Context, + tokenDataSource: TokenDataSource, + ): DataStore { + return DataStoreFactory.create( + serializer = tokenDataSource, + produceFile = { + appContext.dataStoreFile(DATA_STORE_FILE_NAME) + }, + ) + } +} diff --git a/app/src/main/java/com/puzzling/puzzlingaos/di/RepositoryModule.kt b/app/src/main/java/com/puzzling/puzzlingaos/di/RepositoryModule.kt index 84f96457..8f0f8594 100644 --- a/app/src/main/java/com/puzzling/puzzlingaos/di/RepositoryModule.kt +++ b/app/src/main/java/com/puzzling/puzzlingaos/di/RepositoryModule.kt @@ -1,15 +1,7 @@ package com.puzzling.puzzlingaos.di -import com.puzzling.puzzlingaos.data.repository.MyBoardRepositoryImpl -import com.puzzling.puzzlingaos.data.repository.MyPageRepositoryImpl -import com.puzzling.puzzlingaos.data.repository.ProjectRepositoryImpl -import com.puzzling.puzzlingaos.data.repository.TeamDashBoardRepositoryImpl -import com.puzzling.puzzlingaos.data.repository.WriteReviewRepositoryImpl -import com.puzzling.puzzlingaos.domain.repository.MyBoardRepository -import com.puzzling.puzzlingaos.domain.repository.MyPageRepository -import com.puzzling.puzzlingaos.domain.repository.ProjectRepository -import com.puzzling.puzzlingaos.domain.repository.TeamDashBoardRepository -import com.puzzling.puzzlingaos.domain.repository.WriteReviewRepository +import com.puzzling.puzzlingaos.data.repository.* +import com.puzzling.puzzlingaos.domain.repository.* import dagger.Binds import dagger.Module import dagger.hilt.InstallIn @@ -38,4 +30,8 @@ abstract class RepositoryModule { @Singleton @Binds abstract fun providesWriteReviewRepository(repoImpl: WriteReviewRepositoryImpl): WriteReviewRepository + + @Singleton + @Binds + abstract fun providesTokenRepository(repoImpl: TokenRepositoryImpl): TokenRepository } diff --git a/app/src/main/java/com/puzzling/puzzlingaos/domain/entity/DetailRetro.kt b/app/src/main/java/com/puzzling/puzzlingaos/domain/entity/DetailRetro.kt new file mode 100644 index 00000000..44e5d153 --- /dev/null +++ b/app/src/main/java/com/puzzling/puzzlingaos/domain/entity/DetailRetro.kt @@ -0,0 +1,14 @@ +package com.puzzling.puzzlingaos.domain.entity + +data class DetailRetro( + val reviewId: Int?, + val reviewDay: String, + val reviewDate: String, + val reviewTemplateId: Int?, + val content: List?, +) { + data class Content( + val title: String, + val content: String, + ) +} diff --git a/app/src/main/java/com/puzzling/puzzlingaos/domain/entity/InvitationCode.kt b/app/src/main/java/com/puzzling/puzzlingaos/domain/entity/InvitationCode.kt new file mode 100644 index 00000000..fce590b3 --- /dev/null +++ b/app/src/main/java/com/puzzling/puzzlingaos/domain/entity/InvitationCode.kt @@ -0,0 +1,6 @@ +package com.puzzling.puzzlingaos.domain.entity + +data class InvitationCode( + val projectId: Int, + val projectName: String, +) diff --git a/app/src/main/java/com/puzzling/puzzlingaos/domain/entity/JoinProjectInfo.kt b/app/src/main/java/com/puzzling/puzzlingaos/domain/entity/JoinProjectInfo.kt new file mode 100644 index 00000000..edbf0310 --- /dev/null +++ b/app/src/main/java/com/puzzling/puzzlingaos/domain/entity/JoinProjectInfo.kt @@ -0,0 +1,7 @@ +package com.puzzling.puzzlingaos.domain.entity + +data class JoinProjectInfo( + val projectId: Int, + val memberProjectNickname: String, + val memberProjectRole: String, +) diff --git a/app/src/main/java/com/puzzling/puzzlingaos/domain/entity/ProjectReview.kt b/app/src/main/java/com/puzzling/puzzlingaos/domain/entity/ProjectReview.kt new file mode 100644 index 00000000..91919d40 --- /dev/null +++ b/app/src/main/java/com/puzzling/puzzlingaos/domain/entity/ProjectReview.kt @@ -0,0 +1,7 @@ +package com.puzzling.puzzlingaos.domain.entity + +data class ProjectReview( + val reviewId: Int, + val reviewDate: String, + val contents: String, +) diff --git a/app/src/main/java/com/puzzling/puzzlingaos/domain/entity/ReviewCycle.kt b/app/src/main/java/com/puzzling/puzzlingaos/domain/entity/ReviewCycle.kt new file mode 100644 index 00000000..72849c1f --- /dev/null +++ b/app/src/main/java/com/puzzling/puzzlingaos/domain/entity/ReviewCycle.kt @@ -0,0 +1,6 @@ +package com.puzzling.puzzlingaos.domain.entity + +data class ReviewCycle( + val projectName: String, + val projectReviewCycle: String, +) diff --git a/app/src/main/java/com/puzzling/puzzlingaos/domain/repository/MyPageRepository.kt b/app/src/main/java/com/puzzling/puzzlingaos/domain/repository/MyPageRepository.kt index 678869c4..cc0873e0 100644 --- a/app/src/main/java/com/puzzling/puzzlingaos/domain/repository/MyPageRepository.kt +++ b/app/src/main/java/com/puzzling/puzzlingaos/domain/repository/MyPageRepository.kt @@ -1,19 +1,19 @@ package com.puzzling.puzzlingaos.domain.repository -import com.puzzling.puzzlingaos.data.model.response.ResponseDetailRetroDto -import com.puzzling.puzzlingaos.data.model.response.ResponseMyRetroListDto +import com.puzzling.puzzlingaos.domain.entity.DetailRetro +import com.puzzling.puzzlingaos.domain.entity.ProjectReview interface MyPageRepository { suspend fun getMyProjectReview( memberId: Int, projectId: Int, - ): ResponseMyRetroListDto + ): Result> suspend fun getMyDetailReview( memberId: Int, projectId: Int, startDate: String, endDate: String, - ): ResponseDetailRetroDto + ): Result> } diff --git a/app/src/main/java/com/puzzling/puzzlingaos/domain/repository/ProjectRepository.kt b/app/src/main/java/com/puzzling/puzzlingaos/domain/repository/ProjectRepository.kt index 3e48f6cb..65ed7e4f 100644 --- a/app/src/main/java/com/puzzling/puzzlingaos/domain/repository/ProjectRepository.kt +++ b/app/src/main/java/com/puzzling/puzzlingaos/domain/repository/ProjectRepository.kt @@ -1,11 +1,11 @@ package com.puzzling.puzzlingaos.domain.repository -import com.puzzling.puzzlingaos.data.model.request.RequestInvitationCode import com.puzzling.puzzlingaos.data.model.request.RequestProjectRegisterDto -import com.puzzling.puzzlingaos.data.model.response.ResponseInvitationCodeDto import com.puzzling.puzzlingaos.data.model.response.ResponseJoinProjectDto import com.puzzling.puzzlingaos.data.model.response.ResponseProjectRegisterDto -import com.puzzling.puzzlingaos.data.model.response.ResponseProjectRetroWeekDto +import com.puzzling.puzzlingaos.domain.entity.InvitationCode +import com.puzzling.puzzlingaos.domain.entity.JoinProjectInfo +import com.puzzling.puzzlingaos.domain.entity.ReviewCycle interface ProjectRepository { @@ -18,14 +18,14 @@ interface ProjectRepository { suspend fun joinProject( memberId: Int, - request: RequestInvitationCode, - ): ResponseJoinProjectDto + request: JoinProjectInfo, + ): Result suspend fun isValidInvitationCode( invitationCode: String, - ): ResponseInvitationCodeDto + ): Result suspend fun getProjectWeekCycle( projectId: Int, - ): ResponseProjectRetroWeekDto + ): Result } diff --git a/app/src/main/java/com/puzzling/puzzlingaos/domain/repository/TokenRepository.kt b/app/src/main/java/com/puzzling/puzzlingaos/domain/repository/TokenRepository.kt new file mode 100644 index 00000000..93f43adb --- /dev/null +++ b/app/src/main/java/com/puzzling/puzzlingaos/domain/repository/TokenRepository.kt @@ -0,0 +1,9 @@ +package com.puzzling.puzzlingaos.domain.repository + +import com.puzzling.puzzlingaos.data.entity.Token + +interface TokenRepository { + suspend fun setToken(token: String) + + suspend fun getToken(): Token +} diff --git a/app/src/main/java/com/puzzling/puzzlingaos/domain/usecase/onboarding/GetTokenUseCase.kt b/app/src/main/java/com/puzzling/puzzlingaos/domain/usecase/onboarding/GetTokenUseCase.kt new file mode 100644 index 00000000..36875199 --- /dev/null +++ b/app/src/main/java/com/puzzling/puzzlingaos/domain/usecase/onboarding/GetTokenUseCase.kt @@ -0,0 +1,13 @@ +package com.puzzling.puzzlingaos.domain.usecase.onboarding + +import com.puzzling.puzzlingaos.domain.repository.TokenRepository +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class GetTokenUseCase @Inject constructor( + private val tokenRepository: TokenRepository, +) { + + suspend operator fun invoke() = tokenRepository.getToken() +} diff --git a/app/src/main/java/com/puzzling/puzzlingaos/domain/usecase/onboarding/PostTokenUseCase.kt b/app/src/main/java/com/puzzling/puzzlingaos/domain/usecase/onboarding/PostTokenUseCase.kt new file mode 100644 index 00000000..dcf39d58 --- /dev/null +++ b/app/src/main/java/com/puzzling/puzzlingaos/domain/usecase/onboarding/PostTokenUseCase.kt @@ -0,0 +1,10 @@ +package com.puzzling.puzzlingaos.domain.usecase.onboarding + +import com.puzzling.puzzlingaos.domain.repository.TokenRepository +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class PostTokenUseCase @Inject constructor(private val tokenRepository: TokenRepository) { + suspend operator fun invoke(token: String) = tokenRepository.setToken(token) +} diff --git a/app/src/main/java/com/puzzling/puzzlingaos/presentation/detailRetrospect/DetailRetroAdapter.kt b/app/src/main/java/com/puzzling/puzzlingaos/presentation/detailRetrospect/DetailRetroAdapter.kt index 9f850c40..6a8f7d59 100644 --- a/app/src/main/java/com/puzzling/puzzlingaos/presentation/detailRetrospect/DetailRetroAdapter.kt +++ b/app/src/main/java/com/puzzling/puzzlingaos/presentation/detailRetrospect/DetailRetroAdapter.kt @@ -6,10 +6,11 @@ import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView import com.puzzling.puzzlingaos.data.model.response.ResponseDetailRetroDto import com.puzzling.puzzlingaos.databinding.ItemDetailRetroBinding +import com.puzzling.puzzlingaos.domain.entity.DetailRetro import com.puzzling.puzzlingaos.util.ItemDiffCallback class DetailRetroAdapter() : - ListAdapter( + ListAdapter( diffCallback, ) { @@ -25,7 +26,7 @@ class DetailRetroAdapter() : inner class DetailRetroViewHolder(private val binding: ItemDetailRetroBinding) : RecyclerView.ViewHolder(binding.root) { - fun onBind(item: ResponseDetailRetroDto.Data.DetailReviewData.Content) { + fun onBind(item: DetailRetro.Content) { binding.tvDetailRetroTitle.text = item.title binding.tvDetailRetroBody.text = item.content } @@ -33,7 +34,7 @@ class DetailRetroAdapter() : companion object { private val diffCallback = - ItemDiffCallback( + ItemDiffCallback( onContentsTheSame = { old, new -> old == new }, onItemsTheSame = { old, new -> old == new }, ) diff --git a/app/src/main/java/com/puzzling/puzzlingaos/presentation/detailRetrospect/DetailRetroFragment.kt b/app/src/main/java/com/puzzling/puzzlingaos/presentation/detailRetrospect/DetailRetroFragment.kt index 0656052b..cc67a567 100644 --- a/app/src/main/java/com/puzzling/puzzlingaos/presentation/detailRetrospect/DetailRetroFragment.kt +++ b/app/src/main/java/com/puzzling/puzzlingaos/presentation/detailRetrospect/DetailRetroFragment.kt @@ -2,6 +2,7 @@ package com.puzzling.puzzlingaos.presentation.detailRetrospect import android.os.Bundle import android.view.View +import androidx.fragment.app.activityViewModels import androidx.lifecycle.ViewModelProvider // import androidx.recyclerview.widget.DividerItemDecoration import com.puzzling.puzzlingaos.R @@ -15,16 +16,11 @@ class DetailRetroFragment( ) : BaseFragment(R.layout.fragment_detail_retro) { - private lateinit var viewModel: DetailRetroViewModel + private val viewModel by activityViewModels() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - viewModel = ViewModelProvider( - requireActivity(), - ViewModelFactory(requireContext()), - )[DetailRetroViewModel::class.java] - val day = viewModel.week[position] val dataList = viewModel.detailRetroList.value @@ -41,7 +37,7 @@ class DetailRetroFragment( for (data in dataList) { if (day == data.reviewDay) { binding.rcvDetailRetroMain.adapter = detailRetroAdapter - detailRetroAdapter.submitList(data.contents) + detailRetroAdapter.submitList(data.content) } } } diff --git a/app/src/main/java/com/puzzling/puzzlingaos/presentation/detailRetrospect/DetailRetroViewModel.kt b/app/src/main/java/com/puzzling/puzzlingaos/presentation/detailRetrospect/DetailRetroViewModel.kt index 4c785bcc..4d481bf3 100644 --- a/app/src/main/java/com/puzzling/puzzlingaos/presentation/detailRetrospect/DetailRetroViewModel.kt +++ b/app/src/main/java/com/puzzling/puzzlingaos/presentation/detailRetrospect/DetailRetroViewModel.kt @@ -5,7 +5,7 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.puzzling.puzzlingaos.data.model.response.ResponseDetailRetroDto +import com.puzzling.puzzlingaos.domain.entity.DetailRetro import com.puzzling.puzzlingaos.domain.repository.MyPageRepository import com.puzzling.puzzlingaos.util.UserInfo import dagger.hilt.android.lifecycle.HiltViewModel @@ -17,8 +17,8 @@ import javax.inject.Inject @HiltViewModel class DetailRetroViewModel @Inject constructor(private val repository: MyPageRepository) : ViewModel() { - private val _detailRetroList = MutableLiveData?>() - val detailRetroList: LiveData?> get() = _detailRetroList + private val _detailRetroList = MutableLiveData?>() + val detailRetroList: LiveData?> get() = _detailRetroList val week = listOf( "월", @@ -38,17 +38,13 @@ class DetailRetroViewModel @Inject constructor(private val repository: MyPageRep val projectName = MutableLiveData() fun getDetailRetro(projectId: Int) = viewModelScope.launch { - kotlin.runCatching { - Log.d("상세회고조회", "startOfWeek:: $startOfWeek") - Log.d("상세회고조회", "endOfWeek:: $endOfWeek") - repository.getMyDetailReview( - UserInfo.GET_MEMBER_ID, - projectId, - startOfWeek.toString(), - endOfWeek.toString(), - ) - }.onSuccess { response -> - _detailRetroList.value = response.data?.reviews + repository.getMyDetailReview( + UserInfo.GET_MEMBER_ID, + projectId, + startOfWeek.toString(), + endOfWeek.toString(), + ).onSuccess { response -> + _detailRetroList.value = response Log.d("상세회고조회", "response:: $response") }.onFailure { Log.d("상세회고조회", "fail:: $it") diff --git a/app/src/main/java/com/puzzling/puzzlingaos/presentation/home/HomeViewModel.kt b/app/src/main/java/com/puzzling/puzzlingaos/presentation/home/HomeViewModel.kt index c6440a34..55e8a771 100644 --- a/app/src/main/java/com/puzzling/puzzlingaos/presentation/home/HomeViewModel.kt +++ b/app/src/main/java/com/puzzling/puzzlingaos/presentation/home/HomeViewModel.kt @@ -6,8 +6,8 @@ import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.puzzling.puzzlingaos.data.model.response.ResponseMyPageProjectDto -import com.puzzling.puzzlingaos.data.model.response.ResponseProjectRetroWeekDto import com.puzzling.puzzlingaos.domain.entity.Project +import com.puzzling.puzzlingaos.domain.entity.ReviewCycle import com.puzzling.puzzlingaos.domain.repository.MyBoardRepository import com.puzzling.puzzlingaos.domain.repository.ProjectRepository import com.puzzling.puzzlingaos.domain.usecase.personaldashboard.GetProceedingProjectUseCase @@ -66,8 +66,8 @@ class HomeViewModel @Inject constructor( val projectName: LiveData> get() = _projectName - private val _retroWeek = MutableLiveData() - val retroWeek: LiveData get() = _retroWeek + private val _retroWeek = MutableLiveData() + val retroWeek: LiveData get() = _retroWeek val firstProjectName = MutableLiveData() @@ -112,12 +112,10 @@ class HomeViewModel @Inject constructor( } fun getProjectWeekCycle(projectId: Int) = viewModelScope.launch { - kotlin.runCatching { - projectRepository.getProjectWeekCycle(projectId) - }.onSuccess { response -> - _retroWeek.value = response.data + projectRepository.getProjectWeekCycle(projectId).onSuccess { response -> + _retroWeek.value = response Log.d("회고 주기", "$response") - Log.d("회고 주기", "${response.data?.projectReviewCycle}") + Log.d("회고 주기", "${response.projectReviewCycle}") }.onFailure { Log.d("회고 주기", "$it") } diff --git a/app/src/main/java/com/puzzling/puzzlingaos/presentation/invitationCode/InvitationCodeViewModel.kt b/app/src/main/java/com/puzzling/puzzlingaos/presentation/invitationCode/InvitationCodeViewModel.kt index bbdb7641..28570801 100644 --- a/app/src/main/java/com/puzzling/puzzlingaos/presentation/invitationCode/InvitationCodeViewModel.kt +++ b/app/src/main/java/com/puzzling/puzzlingaos/presentation/invitationCode/InvitationCodeViewModel.kt @@ -2,8 +2,8 @@ package com.puzzling.puzzlingaos.presentation.invitationCode import android.util.Log import androidx.lifecycle.* -import com.puzzling.puzzlingaos.data.model.request.RequestInvitationCode -import com.puzzling.puzzlingaos.data.model.response.ResponseInvitationCodeDto +import com.puzzling.puzzlingaos.domain.entity.InvitationCode +import com.puzzling.puzzlingaos.domain.entity.JoinProjectInfo import com.puzzling.puzzlingaos.domain.repository.ProjectRepository import com.puzzling.puzzlingaos.util.UserInfo import dagger.hilt.android.lifecycle.HiltViewModel @@ -43,7 +43,7 @@ class InvitationCodeViewModel @Inject constructor(private val repository: Projec }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), true) private val _codeResponse = - MutableStateFlow(null) + MutableStateFlow(null) val codeResponse = _codeResponse.asStateFlow() private val _isCodeSucces = MutableStateFlow(null) @@ -104,11 +104,9 @@ class InvitationCodeViewModel @Inject constructor(private val repository: Projec }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), true) fun isCodeValid() = viewModelScope.launch { - kotlin.runCatching { - repository.isValidInvitationCode(inputCode.value) - }.onSuccess { response -> + repository.isValidInvitationCode(inputCode.value).onSuccess { response -> _isCodeSucces.value = true - _codeResponse.value = response.data + _codeResponse.value = response Log.d("초대코드", "$response") }.onFailure { _isCodeSucces.value = false @@ -117,16 +115,14 @@ class InvitationCodeViewModel @Inject constructor(private val repository: Projec } fun joinProject() = viewModelScope.launch { - kotlin.runCatching { - repository.joinProject( - UserInfo.POST_MEMBER_ID, - RequestInvitationCode( - codeResponse.value!!.projectId, - inputNickName.value, - inputRole.value, - ), - ) - }.onSuccess { response -> + repository.joinProject( + UserInfo.POST_MEMBER_ID, + JoinProjectInfo( + codeResponse.value!!.projectId, + inputNickName.value, + inputRole.value, + ), + ).onSuccess { response -> _isProfileSucces.value = true Log.d("프로젝트 참여하기", "프로젝트 참여하기 $response") }.onFailure { diff --git a/app/src/main/java/com/puzzling/puzzlingaos/presentation/mypage/ChooseProjectBottomFragment.kt b/app/src/main/java/com/puzzling/puzzlingaos/presentation/mypage/ChooseProjectBottomFragment.kt index 859f7f28..89a9fd25 100644 --- a/app/src/main/java/com/puzzling/puzzlingaos/presentation/mypage/ChooseProjectBottomFragment.kt +++ b/app/src/main/java/com/puzzling/puzzlingaos/presentation/mypage/ChooseProjectBottomFragment.kt @@ -1,13 +1,11 @@ package com.puzzling.puzzlingaos.presentation.mypage import android.os.Bundle -import android.util.Log import android.view.View -import androidx.lifecycle.ViewModelProvider +import androidx.fragment.app.activityViewModels import androidx.lifecycle.lifecycleScope import com.puzzling.puzzlingaos.R import com.puzzling.puzzlingaos.base.BottomSheetDialogFragment -import com.puzzling.puzzlingaos.data.model.response.ResponseMyPageProjectDto import com.puzzling.puzzlingaos.databinding.FragmentBottomChooseProjectBinding import com.puzzling.puzzlingaos.domain.entity.Project import com.puzzling.puzzlingaos.presentation.mypage.adapter.ChooseProjectAdapter @@ -17,32 +15,10 @@ import kotlinx.coroutines.launch class ChooseProjectBottomFragment : BottomSheetDialogFragment(R.layout.fragment_bottom_choose_project) { - private lateinit var viewModel: MyRetrospectViewModel - - private val dummyItemList = mutableListOf( - ResponseMyPageProjectDto("Piickle", "2023-07-03", 2), - ResponseMyPageProjectDto("HARA", "2023-07-28", 3), - ResponseMyPageProjectDto("낫투두", "2023-07-12", 4), - ResponseMyPageProjectDto("PEEKABOOK", "2023-07-20", 5), - ResponseMyPageProjectDto("킵고잇", "2023-06-25", 8), - ResponseMyPageProjectDto("킵고잇", "2023-06-25", 8), - ResponseMyPageProjectDto("Piickle", "2023-07-03", 2), - ResponseMyPageProjectDto("HARA", "2023-07-28", 3), - ResponseMyPageProjectDto("낫투두", "2023-07-12", 4), - ResponseMyPageProjectDto("PEEKABOOK", "2023-07-20", 5), - ResponseMyPageProjectDto("킵고잇", "2023-06-25", 8), - ResponseMyPageProjectDto("킵고잇", "2023-06-25", 8), - ResponseMyPageProjectDto("Piickle", "2023-07-03", 2), - ResponseMyPageProjectDto("HARA", "2023-07-28", 3), - ResponseMyPageProjectDto("낫투두", "2023-07-12", 4), - ResponseMyPageProjectDto("PEEKABOOK", "2023-07-20", 5), - ResponseMyPageProjectDto("킵고잇", "2023-06-25", 8), - ResponseMyPageProjectDto("킵고잇", "2023-06-25", 8), - ) + private val viewModel by activityViewModels() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - viewModel = ViewModelProvider(requireActivity())[MyRetrospectViewModel::class.java] initAdapter() } diff --git a/app/src/main/java/com/puzzling/puzzlingaos/presentation/mypage/MyPageFragment.kt b/app/src/main/java/com/puzzling/puzzlingaos/presentation/mypage/MyPageFragment.kt index b30c3e45..8b7451e6 100644 --- a/app/src/main/java/com/puzzling/puzzlingaos/presentation/mypage/MyPageFragment.kt +++ b/app/src/main/java/com/puzzling/puzzlingaos/presentation/mypage/MyPageFragment.kt @@ -8,12 +8,10 @@ import android.view.View import androidx.core.content.ContextCompat import androidx.core.view.isVisible import androidx.fragment.app.activityViewModels -import androidx.lifecycle.ViewModelProvider import androidx.recyclerview.widget.ConcatAdapter import androidx.recyclerview.widget.LinearLayoutManager import com.puzzling.puzzlingaos.R import com.puzzling.puzzlingaos.base.BaseFragment -import com.puzzling.puzzlingaos.data.model.response.ResponseMyPageProjectDto import com.puzzling.puzzlingaos.databinding.FragmentMyPageBinding import com.puzzling.puzzlingaos.domain.entity.Project import com.puzzling.puzzlingaos.presentation.home.HomeFragment @@ -27,22 +25,12 @@ import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint class MyPageFragment : BaseFragment(R.layout.fragment_my_page) { - private lateinit var viewModel: MyRetrospectViewModel + private val viewModel by activityViewModels() private val personalViewModel by activityViewModels() private val homeViewModel by activityViewModels() - private val dummyItemList = mutableListOf( - ResponseMyPageProjectDto("Piickle", "2023-07-03", 2), - ResponseMyPageProjectDto("HARA", "2023-07-28", 3), - ResponseMyPageProjectDto("낫투두", "2023-07-12", 4), - ResponseMyPageProjectDto("PEEKABOOK", "2023-07-20", 5), - ResponseMyPageProjectDto("킵고잇", "2023-06-25", 8), - ResponseMyPageProjectDto("킵고잇", "2023-06-25", 8), - ) - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - viewModel = ViewModelProvider(requireActivity())[MyRetrospectViewModel::class.java] viewModel.getMyProjectList() homeViewModel.selectedProjectId.observe(this) { viewModel.getProjectWeekCycle(it) diff --git a/app/src/main/java/com/puzzling/puzzlingaos/presentation/mypage/MyRetrospectFragment.kt b/app/src/main/java/com/puzzling/puzzlingaos/presentation/mypage/MyRetrospectFragment.kt index 2f3e4020..93af2033 100644 --- a/app/src/main/java/com/puzzling/puzzlingaos/presentation/mypage/MyRetrospectFragment.kt +++ b/app/src/main/java/com/puzzling/puzzlingaos/presentation/mypage/MyRetrospectFragment.kt @@ -10,8 +10,8 @@ import androidx.recyclerview.widget.ConcatAdapter import androidx.recyclerview.widget.LinearLayoutManager import com.puzzling.puzzlingaos.R import com.puzzling.puzzlingaos.base.BaseFragment -import com.puzzling.puzzlingaos.data.model.response.ResponseMyRetroListDto import com.puzzling.puzzlingaos.databinding.FragmentMyRetrospectBinding +import com.puzzling.puzzlingaos.domain.entity.ProjectReview import com.puzzling.puzzlingaos.presentation.detailRetrospect.DetailRetroActivity import com.puzzling.puzzlingaos.presentation.mypage.adapter.MyRetroContentAdapter import com.puzzling.puzzlingaos.presentation.mypage.adapter.MyRetroTitleAdapter @@ -24,25 +24,12 @@ class MyRetrospectFragment : private lateinit var viewModel: MyRetrospectViewModel private var currentTitle = "piikle" - private val dummyItemList = mutableListOf( - ResponseMyRetroListDto.ReviewData(23, "2023-07-12", "여기는 20글자 정도 노출되고,,"), - ResponseMyRetroListDto.ReviewData( - 12, - "2023-07-24", - "유저가 회고 템플릿에서 가장 첫 번째 인풋창에 입력한 값 노출.. ", - ), - ResponseMyRetroListDto.ReviewData(5, "2023-07-27", "여기는18글자정도노출되고나머지부분..."), - ResponseMyRetroListDto.ReviewData(7, "2023-07-5", "여기는18글자정도노출되고나머지부분..."), - ResponseMyRetroListDto.ReviewData(8, "2023-08-02", "여기는18글자정도노출되고나머지부분..."), - ResponseMyRetroListDto.ReviewData(10, "2023-06-22", "여기는18글자정도노출되고나머지부분..."), - ) - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) viewModel = ViewModelProvider(requireActivity())[MyRetrospectViewModel::class.java] viewModel.currentProject.observe(this) { - Log.d("myPage 회고 뷰", "${it}") + Log.d("myPage 회고 뷰", "$it") viewModel.getMyProjectReview(it.projectId) } initToolbar() @@ -84,7 +71,7 @@ class MyRetrospectFragment : myRetroContentAdapter.setOnItemClickListener(object : MyRetroContentAdapter.OnItemClickListener { - override fun onItemClick(v: View, item: ResponseMyRetroListDto.ReviewData, pos: Int) { + override fun onItemClick(v: View, item: ProjectReview, pos: Int) { val intent = Intent(activity, DetailRetroActivity::class.java) intent.putExtra("Title", viewModel.currentProject.value?.projectName) intent.putExtra("homeProjectId", viewModel.currentProject.value?.projectId) diff --git a/app/src/main/java/com/puzzling/puzzlingaos/presentation/mypage/MyRetrospectViewModel.kt b/app/src/main/java/com/puzzling/puzzlingaos/presentation/mypage/MyRetrospectViewModel.kt index 4645a66e..f073de32 100644 --- a/app/src/main/java/com/puzzling/puzzlingaos/presentation/mypage/MyRetrospectViewModel.kt +++ b/app/src/main/java/com/puzzling/puzzlingaos/presentation/mypage/MyRetrospectViewModel.kt @@ -5,9 +5,9 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.puzzling.puzzlingaos.data.model.response.ResponseMyRetroListDto -import com.puzzling.puzzlingaos.data.model.response.ResponseProjectRetroWeekDto import com.puzzling.puzzlingaos.domain.entity.Project +import com.puzzling.puzzlingaos.domain.entity.ProjectReview +import com.puzzling.puzzlingaos.domain.entity.ReviewCycle import com.puzzling.puzzlingaos.domain.repository.MyBoardRepository import com.puzzling.puzzlingaos.domain.repository.MyPageRepository import com.puzzling.puzzlingaos.domain.repository.ProjectRepository @@ -23,8 +23,8 @@ class MyRetrospectViewModel @Inject constructor( ) : ViewModel() { - private val _responseReview = MutableLiveData?>() - val responseReveiew: LiveData?> get() = _responseReview + private val _responseReview = MutableLiveData?>() + val responseReveiew: LiveData?> get() = _responseReview private var _responseProjectList: MutableLiveData> = MutableLiveData() val responseProjectList: LiveData> @@ -33,14 +33,12 @@ class MyRetrospectViewModel @Inject constructor( private val _currentProject = MutableLiveData() val currentProject: LiveData get() = _currentProject - private val _retroWeek = MutableLiveData() - val retroWeek: LiveData get() = _retroWeek + private val _retroWeek = MutableLiveData() + val retroWeek: LiveData get() = _retroWeek fun getMyProjectReview(selectedProjectId: Int) = viewModelScope.launch { - kotlin.runCatching { - myPageRepository.getMyProjectReview(1, selectedProjectId) - }.onSuccess { response -> - _responseReview.value = response.data + myPageRepository.getMyProjectReview(1, selectedProjectId).onSuccess { response -> + _responseReview.value = response Log.d("MyProjectRetro", "$response") }.onFailure { Log.d("MyProjectRetro", "$it") @@ -64,12 +62,10 @@ class MyRetrospectViewModel @Inject constructor( // 2425350570 fun getProjectWeekCycle(projectId: Int) = viewModelScope.launch { - kotlin.runCatching { - projectRepository.getProjectWeekCycle(projectId) - }.onSuccess { response -> - _retroWeek.value = response.data + projectRepository.getProjectWeekCycle(projectId).onSuccess { response -> + _retroWeek.value = response Log.d("회고 주기", "$response") - Log.d("회고 주기", "${response.data?.projectReviewCycle}") + Log.d("회고 주기", "${response.projectReviewCycle}") }.onFailure { Log.d("회고 주기", "$it") } diff --git a/app/src/main/java/com/puzzling/puzzlingaos/presentation/mypage/adapter/MyRetroContentAdapter.kt b/app/src/main/java/com/puzzling/puzzlingaos/presentation/mypage/adapter/MyRetroContentAdapter.kt index 2f7ac65c..1e91dfcf 100644 --- a/app/src/main/java/com/puzzling/puzzlingaos/presentation/mypage/adapter/MyRetroContentAdapter.kt +++ b/app/src/main/java/com/puzzling/puzzlingaos/presentation/mypage/adapter/MyRetroContentAdapter.kt @@ -5,12 +5,12 @@ import android.view.View import android.view.ViewGroup import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView -import com.puzzling.puzzlingaos.data.model.response.ResponseMyRetroListDto import com.puzzling.puzzlingaos.databinding.ItemMyretroRetroBinding +import com.puzzling.puzzlingaos.domain.entity.ProjectReview import com.puzzling.puzzlingaos.util.ItemDiffCallback class MyRetroContentAdapter() : - ListAdapter( + ListAdapter( diffCallback, ) { @@ -28,7 +28,7 @@ class MyRetroContentAdapter() : inner class MyRetroContenViewHolder(private val binding: ItemMyretroRetroBinding) : RecyclerView.ViewHolder(binding.root) { - fun onBind(item: ResponseMyRetroListDto.ReviewData) { + fun onBind(item: ProjectReview) { binding.tvMyretroDate.text = item.reviewDate if (item.contents.length < 17) { @@ -40,14 +40,14 @@ class MyRetroContentAdapter() : if (bindingAdapterPosition != RecyclerView.NO_POSITION) { binding.clMyRetroContainer.setOnClickListener { - listener?.onItemClick(itemView,item, bindingAdapterPosition) + listener?.onItemClick(itemView, item, bindingAdapterPosition) } } } } interface OnItemClickListener { - fun onItemClick(v: View, item:ResponseMyRetroListDto.ReviewData, pos: Int) + fun onItemClick(v: View, item: ProjectReview, pos: Int) } fun setOnItemClickListener(listener: OnItemClickListener) { @@ -56,7 +56,7 @@ class MyRetroContentAdapter() : companion object { private val diffCallback = - ItemDiffCallback( + ItemDiffCallback( onContentsTheSame = { old, new -> old == new }, onItemsTheSame = { old, new -> old == new }, ) diff --git a/app/src/main/java/com/puzzling/puzzlingaos/presentation/onboarding/LoginActivity.kt b/app/src/main/java/com/puzzling/puzzlingaos/presentation/onboarding/LoginActivity.kt index 774d492d..bbfd50df 100644 --- a/app/src/main/java/com/puzzling/puzzlingaos/presentation/onboarding/LoginActivity.kt +++ b/app/src/main/java/com/puzzling/puzzlingaos/presentation/onboarding/LoginActivity.kt @@ -2,19 +2,27 @@ package com.puzzling.puzzlingaos.presentation.onboarding import android.content.Intent import android.os.Bundle +import android.util.Log import androidx.activity.viewModels import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle import com.puzzling.puzzlingaos.R import com.puzzling.puzzlingaos.base.BaseActivity +import com.puzzling.puzzlingaos.data.service.KakaoAuthService import com.puzzling.puzzlingaos.databinding.ActivityLoginBinding -import com.puzzling.puzzlingaos.util.ViewModelFactory +import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.launch +import javax.inject.Inject +@AndroidEntryPoint class LoginActivity : BaseActivity(R.layout.activity_login) { - private val viewModel: LoginViewModel by viewModels { ViewModelFactory(this) } + @Inject + lateinit var kakakoAuthService: KakaoAuthService + + private val viewModel: LoginViewModel by viewModels() + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -24,13 +32,13 @@ class LoginActivity : BaseActivity(R.layout.activity_login private fun startKakaoLogin() { binding.ibLoginKakao.setOnClickListener { - viewModel.kakaoLogin() + kakakoAuthService.startKakaoLogin(viewModel.kakaoLoginCallback) } } private fun isKakaoLoginSuccess() { lifecycleScope.launch { - repeatOnLifecycle(Lifecycle.State.RESUMED) { + repeatOnLifecycle(Lifecycle.State.STARTED) { viewModel.isKakaoLogin.collect { isLoginSuccess -> if (isLoginSuccess) { val intent = diff --git a/app/src/main/java/com/puzzling/puzzlingaos/presentation/onboarding/LoginViewModel.kt b/app/src/main/java/com/puzzling/puzzlingaos/presentation/onboarding/LoginViewModel.kt index 67a747c0..6b60acba 100644 --- a/app/src/main/java/com/puzzling/puzzlingaos/presentation/onboarding/LoginViewModel.kt +++ b/app/src/main/java/com/puzzling/puzzlingaos/presentation/onboarding/LoginViewModel.kt @@ -1,29 +1,37 @@ package com.puzzling.puzzlingaos.presentation.onboarding +import android.util.Log import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.kakao.sdk.auth.model.OAuthToken import com.puzzling.puzzlingaos.data.datasource.local.LocalDataSource -import com.puzzling.puzzlingaos.data.service.KakaoLoginService +import com.puzzling.puzzlingaos.domain.usecase.onboarding.GetTokenUseCase +import com.puzzling.puzzlingaos.domain.usecase.onboarding.PostTokenUseCase import com.puzzling.puzzlingaos.util.KakaoLoginCallback +import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch -import timber.log.Timber +import javax.inject.Inject -class LoginViewModel(private val kakaoLoginService: KakaoLoginService) : ViewModel() { +@HiltViewModel +class LoginViewModel @Inject constructor( + private val postTokenUseCase: PostTokenUseCase, + private val getTokenUseCase: GetTokenUseCase, +) : + ViewModel() { private val _isKakaoLogin = MutableStateFlow(false) val isKakaoLogin = _isKakaoLogin.asStateFlow() val kakaoLoginCallback: (OAuthToken?, Throwable?) -> Unit = { token, error -> KakaoLoginCallback { _isKakaoLogin.value = true - Timber.d("토큰!!!! $token") + Log.d("LoginViewModel", "토큰!! $token") LocalDataSource.setAccessToken("$token") + viewModelScope.launch { + postTokenUseCase.invoke(it) + Log.d("LoginViewModel", "토큰!! usecase ${getTokenUseCase.invoke()}") + } }.handleResult(token, error) } - - fun kakaoLogin() = viewModelScope.launch { - kakaoLoginService.startKakaoLogin(kakaoLoginCallback) - } } diff --git a/app/src/main/java/com/puzzling/puzzlingaos/util/ViewModelFactory.kt b/app/src/main/java/com/puzzling/puzzlingaos/util/ViewModelFactory.kt index 4fbe7331..bf6a5503 100644 --- a/app/src/main/java/com/puzzling/puzzlingaos/util/ViewModelFactory.kt +++ b/app/src/main/java/com/puzzling/puzzlingaos/util/ViewModelFactory.kt @@ -3,9 +3,6 @@ package com.puzzling.puzzlingaos.util import android.content.Context import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider -import com.puzzling.puzzlingaos.data.service.KakaoLoginService -import com.puzzling.puzzlingaos.presentation.invitationCode.InvitationCodeViewModel -import com.puzzling.puzzlingaos.presentation.onboarding.LoginViewModel class ViewModelFactory(private val context: Context) : ViewModelProvider.Factory { override fun create(modelClass: Class): T { @@ -14,10 +11,10 @@ class ViewModelFactory(private val context: Context) : ViewModelProvider.Factory // InvitationCodeViewModel(context) as T // } - modelClass.isAssignableFrom(LoginViewModel::class.java) -> { - val repository = KakaoLoginService(context) - LoginViewModel(repository) as T - } +// modelClass.isAssignableFrom(LoginViewModel::class.java) -> { +// val repository = KakaoAuthService(context) +// LoginViewModel(repository) as T +// } else -> { throw java.lang.IllegalArgumentException("Unknown ViewModel")