diff --git a/app/src/main/java/com/runnect/runnect/data/dto/LocationData.kt b/app/src/main/java/com/runnect/runnect/data/dto/LocationData.kt deleted file mode 100644 index 95b566cce..000000000 --- a/app/src/main/java/com/runnect/runnect/data/dto/LocationData.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.runnect.runnect.data.dto - - -import android.os.Parcelable -import kotlinx.android.parcel.Parcelize - -@Parcelize -data class LocationData( - val buildingName: String, - val fullAddress: String, -) : Parcelable \ No newline at end of file diff --git a/app/src/main/java/com/runnect/runnect/data/dto/LoginDTO.kt b/app/src/main/java/com/runnect/runnect/data/dto/LoginDTO.kt index cbb86236d..dde86aee4 100644 --- a/app/src/main/java/com/runnect/runnect/data/dto/LoginDTO.kt +++ b/app/src/main/java/com/runnect/runnect/data/dto/LoginDTO.kt @@ -1,7 +1,6 @@ package com.runnect.runnect.data.dto data class LoginDTO( - val status: Int, val accessToken: String, val refreshToken: String, val email: String, diff --git a/app/src/main/java/com/runnect/runnect/data/dto/response/ResponseGetMyDrawCourse.kt b/app/src/main/java/com/runnect/runnect/data/dto/response/ResponseGetMyDrawCourse.kt index 7d9776e6d..7d528ac2d 100644 --- a/app/src/main/java/com/runnect/runnect/data/dto/response/ResponseGetMyDrawCourse.kt +++ b/app/src/main/java/com/runnect/runnect/data/dto/response/ResponseGetMyDrawCourse.kt @@ -7,29 +7,29 @@ import kotlinx.serialization.Serializable @Serializable data class ResponseGetMyDrawCourse( @SerialName("courses") - val courses: List, + val courses: List?, @SerialName("user") - val user: User, + val user: User?, ) { @Serializable data class Course( @SerialName("createdAt") - val createdAt: String, + val createdAt: String?, @SerialName("departure") - val departure: Departure, + val departure: Departure?, @SerialName("id") - val id: Int, + val id: Int?, @SerialName("image") - val image: String, + val image: String?, @SerialName("title") - val title: String + val title: String? ) { @Serializable data class Departure( @SerialName("city") - val city: String, + val city: String?, @SerialName("region") - val region: String, + val region: String?, ) } @@ -41,13 +41,17 @@ data class ResponseGetMyDrawCourse( } fun ResponseGetMyDrawCourse.toMyDrawCourse(): List { - return this.courses.map { - MyDrawCourse( - courseId = it.id, - image = it.image, - city = it.departure.city, - region = it.departure.region, - title = it.title - ) + + return if (this.courses.isNullOrEmpty()) emptyList() + else { + this.courses.map { + MyDrawCourse( + courseId = it.id, + image = it.image, + city = it.departure?.city ?: "", //todo - 예외 처리 논의 + region = it.departure?.region ?: "", + title = it.title ?: "" + ) + } } } \ No newline at end of file diff --git a/app/src/main/java/com/runnect/runnect/data/dto/response/ResponseGetMyHistory.kt b/app/src/main/java/com/runnect/runnect/data/dto/response/ResponseGetMyHistory.kt index b537842ac..d65f1e2e8 100644 --- a/app/src/main/java/com/runnect/runnect/data/dto/response/ResponseGetMyHistory.kt +++ b/app/src/main/java/com/runnect/runnect/data/dto/response/ResponseGetMyHistory.kt @@ -1,44 +1,72 @@ package com.runnect.runnect.data.dto.response +import com.runnect.runnect.data.dto.HistoryInfoDTO import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @Serializable data class ResponseGetMyHistory( - val `data`: HistoryData, - val message: String, - val status: Int, - val success: Boolean -) + val user: RecordUser, + val records: List, +) { + @Serializable + data class RecordUser( + @SerialName("userId") val id: Int + ) -@Serializable -data class Record( - val courseId: Int, - val createdAt: String, - val departure: Departure, - val distance: Double, - val id: Int, - val image: String, - val pace: String, - val publicCourseId: Int?, - val time: String, - val title: String -) + @Serializable + data class Record( + val courseId: Int, + val createdAt: String, + val departure: Departure, + val distance: Double, + val id: Int, + val image: String, + val pace: String, + val publicCourseId: Int?, + val time: String, + val title: String + ) { + @Serializable + data class Departure( + val city: String, + val region: String + ) + } -@Serializable -data class Departure( - val city: String, - val region: String -) + fun toHistoryInfoList(): List { + return records.map { + HistoryInfoDTO( + id = it.id, + img = it.image, + title = it.title, + location = "${it.departure.region} ${it.departure.city}", + date = (it.createdAt.split(" ")[0]).replace("-", "."), + distance = it.distance.toString(), + time = timeConvert(it.time), + pace = paceConvert(it.pace) + ) + } + } -@Serializable -data class RecordUser( - @SerialName("userId") val id: Int -) - -@Serializable -data class HistoryData( - val records: List, - val user: RecordUser -) + private fun timeConvert(time: String): String { + val hms = time.split(":").toMutableList() + if (hms[0] == "00") { + hms[0] = "0" + } + return "${hms[0]}:${hms[1]}:${hms[2]}" + } + private fun paceConvert(p: String): String { + val pace = p.split(":").toMutableList() + return if (pace[0] == "00") { + pace.removeAt(0) + if (pace[0][0] == '0') { + pace[0] = pace[0][1].toString() + } + "${pace[0]}’${pace[1]}”" + } else { + "${pace[0]}’${pace[1]}”${pace[2]}”" + } + } +} diff --git a/app/src/main/java/com/runnect/runnect/data/dto/response/ResponseGetMyStamp.kt b/app/src/main/java/com/runnect/runnect/data/dto/response/ResponseGetMyStamp.kt index 165938664..75a2ff1cc 100644 --- a/app/src/main/java/com/runnect/runnect/data/dto/response/ResponseGetMyStamp.kt +++ b/app/src/main/java/com/runnect/runnect/data/dto/response/ResponseGetMyStamp.kt @@ -1,26 +1,21 @@ package com.runnect.runnect.data.dto.response + import kotlinx.serialization.Serializable @Serializable data class ResponseGetMyStamp( - val `data`: StampData, - val message: String, - val status: Int, - val success: Boolean -) - -@Serializable -data class StampData( + val user: StampUser, val stamps: List, - val user: StampUser -) +) { + @Serializable + data class StampUser( + val id: Int + ) -@Serializable -data class Stamp( - val id: String -) + @Serializable + data class Stamp( + val id: String + ) -@Serializable -data class StampUser( - val id: Int -) \ No newline at end of file + fun toStampList() = stamps.map { it.id } +} \ No newline at end of file diff --git a/app/src/main/java/com/runnect/runnect/data/dto/response/ResponseGetUser.kt b/app/src/main/java/com/runnect/runnect/data/dto/response/ResponseGetUser.kt index f23b5be85..5ea1dd002 100644 --- a/app/src/main/java/com/runnect/runnect/data/dto/response/ResponseGetUser.kt +++ b/app/src/main/java/com/runnect/runnect/data/dto/response/ResponseGetUser.kt @@ -1,25 +1,29 @@ package com.runnect.runnect.data.dto.response +import com.runnect.runnect.domain.entity.User import kotlinx.serialization.Serializable @Serializable data class ResponseGetUser( - val data: Data, - val message: String, - val status: Int, - val success: Boolean -) + val user: UserResponse, +) { -@Serializable -data class Data( - val user: User -) + @Serializable + data class UserResponse( + val email: String, + val latestStamp: String, + val level: Int, + val levelPercent: Int, + val nickname: String + ) -@Serializable -data class User( - val email:String, - val latestStamp: String, - val level: Int, - val levelPercent: Int, - val nickname: String -) \ No newline at end of file + fun toUser(): User { + return User( + email = user.email, + latestStamp = user.latestStamp, + level = user.level, + levelPercent = user.levelPercent, + nickname = user.nickname + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/runnect/runnect/data/dto/response/ResponseGetUserUploadCourse.kt b/app/src/main/java/com/runnect/runnect/data/dto/response/ResponseGetUserUploadCourse.kt index 2246a8480..9d853bbb6 100644 --- a/app/src/main/java/com/runnect/runnect/data/dto/response/ResponseGetUserUploadCourse.kt +++ b/app/src/main/java/com/runnect/runnect/data/dto/response/ResponseGetUserUploadCourse.kt @@ -1,49 +1,53 @@ package com.runnect.runnect.data.dto.response import com.google.gson.annotations.SerializedName +import com.runnect.runnect.domain.entity.UserUploadCourse import kotlinx.serialization.Serializable @Serializable data class ResponseGetUserUploadCourse( - @SerializedName("data") - val `data`: DataUpload, - @SerializedName("message") - val message: String, - @SerializedName("status") - val status: Int, - @SerializedName("success") - val success: Boolean -) -@Serializable -data class UserUpload( - @SerializedName("id") - val id: Int -) -@Serializable -data class PublicCourseUpload( - @SerializedName("courseId") - val courseId: Int, - @SerializedName("departure") - val departure: DepartureUpload, - @SerializedName("id") - val id: Int, - @SerializedName("image") - val image: String, - @SerializedName("title") - val title: String -) - -@Serializable -data class DepartureUpload( - @SerializedName("city") - val city: String, - @SerializedName("region") - val region: String -) -@Serializable -data class DataUpload( - @SerializedName("publicCourse") - val publicCourses: List, @SerializedName("user") - val user: UserUpload -) \ No newline at end of file + val user: UserId, + @SerializedName("publicCourses") + val publicCourses: List, +) { + + @Serializable + data class UserId( + @SerializedName("id") + val id: Int, + ) + + @Serializable + data class PublicCourseUpload( + @SerializedName("id") + val id: Int, + @SerializedName("courseId") + val courseId: Int, + @SerializedName("title") + val title: String, + @SerializedName("scrap") + val scrap: Boolean, + @SerializedName("image") + val image: String, + @SerializedName("departure") + val departure: DepartureUpload, + ) + + @Serializable + data class DepartureUpload( + @SerializedName("region") + val region: String, + @SerializedName("city") + val city: String, + ) + + fun toUserUploadCourse(): List = publicCourses.map { + UserUploadCourse( + id = it.id, + title = it.title, + img = it.image, + departure = "${it.departure.region} ${it.departure.city}" + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/runnect/runnect/data/dto/response/ResponsePostLogin.kt b/app/src/main/java/com/runnect/runnect/data/dto/response/ResponsePostLogin.kt index a11b969d4..77f45b84b 100644 --- a/app/src/main/java/com/runnect/runnect/data/dto/response/ResponsePostLogin.kt +++ b/app/src/main/java/com/runnect/runnect/data/dto/response/ResponsePostLogin.kt @@ -1,31 +1,28 @@ package com.runnect.runnect.data.dto.response - +import com.runnect.runnect.data.dto.LoginDTO import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @Serializable data class ResponsePostLogin( - @SerialName("data") - val `data`: Data, - @SerialName("message") - val message: String, - @SerialName("status") - val status: Int, - @SerialName("success") - val success: Boolean, + @SerialName("accessToken") + val accessToken: String, + @SerialName("email") + val email: String, + @SerialName("nickname") + val nickName: String = "", + @SerialName("refreshToken") + val refreshToken: String, + @SerialName("type") + val type: String, ) { - @Serializable - data class Data( - @SerialName("accessToken") - val accessToken: String, - @SerialName("email") - val email: String, - @SerialName("nickname") - val nickName: String = "", - @SerialName("refreshToken") - val refreshToken: String, - @SerialName("type") - val type: String, - ) + fun toData(): LoginDTO { + return LoginDTO( + accessToken = accessToken, + refreshToken = refreshToken, + email = email, + type = type + ) + } } \ No newline at end of file diff --git a/app/src/main/java/com/runnect/runnect/data/dto/response/ResponsePostMyDrawCourse.kt b/app/src/main/java/com/runnect/runnect/data/dto/response/ResponsePostMyDrawCourse.kt index 8b18758ed..2cc953674 100644 --- a/app/src/main/java/com/runnect/runnect/data/dto/response/ResponsePostMyDrawCourse.kt +++ b/app/src/main/java/com/runnect/runnect/data/dto/response/ResponsePostMyDrawCourse.kt @@ -5,20 +5,14 @@ import kotlinx.serialization.Serializable @Serializable data class ResponsePostMyDrawCourse( - @SerialName("status") - val status: Int, - @SerialName("success") - val success: Boolean, - @SerialName("message") - val message: String, @SerialName("data") - val data: Data, + val data: Data ) { @Serializable data class Data( @SerialName("id") val id: Int, @SerialName("createdAt") - val createdAt: String, + val createdAt: String ) } \ No newline at end of file diff --git a/app/src/main/java/com/runnect/runnect/data/dto/response/ResponsePostScrap.kt b/app/src/main/java/com/runnect/runnect/data/dto/response/ResponsePostScrap.kt index cd5d3b0ae..e73ec736b 100644 --- a/app/src/main/java/com/runnect/runnect/data/dto/response/ResponsePostScrap.kt +++ b/app/src/main/java/com/runnect/runnect/data/dto/response/ResponsePostScrap.kt @@ -1,5 +1,6 @@ package com.runnect.runnect.data.dto.response +import com.runnect.runnect.domain.entity.PostScrap import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @@ -11,4 +12,12 @@ data class ResponsePostScrap( val scrapCount: Long, @SerialName("scrapTF") val scrapTF: Boolean -) \ No newline at end of file +) { + fun toPostScrap(): PostScrap { + return PostScrap( + publicCourseId = publicCourseId, + scrapCount = scrapCount, + scrapTF = scrapTF + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/runnect/runnect/data/dto/response/ResponsePutMyDrawCourse.kt b/app/src/main/java/com/runnect/runnect/data/dto/response/ResponsePutMyDrawCourse.kt index 705e6ab05..5fe703f3c 100644 --- a/app/src/main/java/com/runnect/runnect/data/dto/response/ResponsePutMyDrawCourse.kt +++ b/app/src/main/java/com/runnect/runnect/data/dto/response/ResponsePutMyDrawCourse.kt @@ -1,23 +1,10 @@ package com.runnect.runnect.data.dto.response - import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @Serializable data class ResponsePutMyDrawCourse( - @SerialName("data") - val data: Data, - @SerialName("message") - val message: String, - @SerialName("status") - val status: Int, - @SerialName("success") - val success: Boolean -) { - @Serializable - data class Data( - @SerialName("deletedCourseCount") - val deletedCourseCount: Int - ) -} \ No newline at end of file + @SerialName("deletedCourseCount") + val deletedCourseCount: Int +) \ No newline at end of file diff --git a/app/src/main/java/com/runnect/runnect/data/dto/tmap/geocoding/ResponseReverseGeocodingDto.kt b/app/src/main/java/com/runnect/runnect/data/dto/response/ResponseReverseGeocodingDto.kt similarity index 89% rename from app/src/main/java/com/runnect/runnect/data/dto/tmap/geocoding/ResponseReverseGeocodingDto.kt rename to app/src/main/java/com/runnect/runnect/data/dto/response/ResponseReverseGeocodingDto.kt index 928e1d5f8..a23d80e47 100644 --- a/app/src/main/java/com/runnect/runnect/data/dto/tmap/geocoding/ResponseReverseGeocodingDto.kt +++ b/app/src/main/java/com/runnect/runnect/data/dto/response/ResponseReverseGeocodingDto.kt @@ -1,6 +1,6 @@ -package com.runnect.runnect.data.dto.tmap.geocoding - +package com.runnect.runnect.data.dto.response +import com.runnect.runnect.domain.entity.LocationData import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @@ -91,4 +91,10 @@ data class ResponseReverseGeocodingDto( val lonEntr: String ) } + + fun toLocationData(): LocationData = + LocationData( + buildingName = addressInfo.buildingName ?: "buildingName fail", + fullAddress = addressInfo.fullAddress ?: "fullAddress fail" + ) } \ No newline at end of file diff --git a/app/src/main/java/com/runnect/runnect/data/network/interceptor/ResponseInterceptor.kt b/app/src/main/java/com/runnect/runnect/data/network/interceptor/ResponseInterceptor.kt index 256e2ec72..5b39ebec5 100644 --- a/app/src/main/java/com/runnect/runnect/data/network/interceptor/ResponseInterceptor.kt +++ b/app/src/main/java/com/runnect/runnect/data/network/interceptor/ResponseInterceptor.kt @@ -1,6 +1,8 @@ package com.runnect.runnect.data.network.interceptor import com.google.gson.Gson +import com.google.gson.JsonElement +import com.google.gson.JsonObject import com.google.gson.JsonParseException import com.google.gson.JsonSyntaxException import com.runnect.runnect.data.dto.response.base.BaseResponse @@ -42,6 +44,11 @@ class ResponseInterceptor : Interceptor { private fun jsonToBaseResponse(body: String): String? { return try { + val jsonElement: JsonElement = gson.fromJson(body, JsonElement::class.java) + if (!isBaseResponse(jsonElement.asJsonObject)) { + return null + } + val baseResponse = gson.fromJson(body, BaseResponse::class.java) gson.toJson(baseResponse.data) } catch (e: JsonSyntaxException) { @@ -52,4 +59,9 @@ class ResponseInterceptor : Interceptor { null // 기타 예외 발생 시 원래 형식을 반환 } } + + private fun isBaseResponse(jsonObject: JsonObject): Boolean { + val requiredFields = listOf("status", "success", "message", "data") + return requiredFields.all { jsonObject.has(it) } + } } \ No newline at end of file diff --git a/app/src/main/java/com/runnect/runnect/data/repository/CourseRepositoryImpl.kt b/app/src/main/java/com/runnect/runnect/data/repository/CourseRepositoryImpl.kt index 614777fc9..0155cd8aa 100644 --- a/app/src/main/java/com/runnect/runnect/data/repository/CourseRepositoryImpl.kt +++ b/app/src/main/java/com/runnect/runnect/data/repository/CourseRepositoryImpl.kt @@ -1,30 +1,29 @@ package com.runnect.runnect.data.repository import com.runnect.runnect.data.dto.request.RequestPatchMyDrawCourseTitle -import com.runnect.runnect.domain.entity.CourseDetail +import com.runnect.runnect.data.dto.request.RequestPatchPublicCourse import com.runnect.runnect.data.dto.request.RequestPostCourseScrap +import com.runnect.runnect.data.dto.request.RequestPostPublicCourse import com.runnect.runnect.data.dto.request.RequestPostRunningHistory import com.runnect.runnect.data.dto.request.RequestPutMyDrawCourse -import com.runnect.runnect.data.dto.request.RequestPatchPublicCourse -import com.runnect.runnect.data.dto.request.RequestPostPublicCourse import com.runnect.runnect.data.dto.response.ResponseGetMyDrawDetail +import com.runnect.runnect.data.dto.response.ResponsePostDiscoverUpload import com.runnect.runnect.data.dto.response.ResponsePostMyDrawCourse import com.runnect.runnect.data.dto.response.ResponsePostMyHistory import com.runnect.runnect.data.dto.response.ResponsePutMyDrawCourse -import com.runnect.runnect.data.dto.response.ResponsePostDiscoverUpload -import com.runnect.runnect.data.dto.response.ResponsePostScrap import com.runnect.runnect.data.network.mapToFlowResult import com.runnect.runnect.data.source.remote.RemoteCourseDataSource +import com.runnect.runnect.domain.entity.CourseDetail +import com.runnect.runnect.domain.entity.DiscoverMultiViewItem.MarathonCourse import com.runnect.runnect.domain.entity.DiscoverSearchCourse -import com.runnect.runnect.domain.entity.DiscoverMultiViewItem.* import com.runnect.runnect.domain.entity.DiscoverUploadCourse import com.runnect.runnect.domain.entity.EditableCourseDetail +import com.runnect.runnect.domain.entity.PostScrap import com.runnect.runnect.domain.entity.RecommendCoursePagingData import com.runnect.runnect.domain.repository.CourseRepository import kotlinx.coroutines.flow.Flow import okhttp3.MultipartBody import okhttp3.RequestBody -import retrofit2.Response import javax.inject.Inject class CourseRepositoryImpl @Inject constructor(private val remoteCourseDataSource: RemoteCourseDataSource) : @@ -39,37 +38,45 @@ class CourseRepositoryImpl @Inject constructor(private val remoteCourseDataSourc override suspend fun getRecommendCourse( pageNo: String, sort: String - ): Result = runCatching { - val response = remoteCourseDataSource.getRecommendCourse( + ): Flow> { + return remoteCourseDataSource.getRecommendCourse( pageNo = pageNo, sort = sort - ).data - - response?.let { - RecommendCoursePagingData(response.isEnd, response.toRecommendCourses()) + ).mapToFlowResult { + RecommendCoursePagingData(it.isEnd, it.toRecommendCourses()) } } - override suspend fun getCourseSearch(keyword: String): Result?> = - runCatching { - remoteCourseDataSource.getCourseSearch(keyword = keyword).data?.toDiscoverSearchCourses() + override suspend fun getCourseSearch(keyword: String): Flow>> = + remoteCourseDataSource.getCourseSearch(keyword = keyword).mapToFlowResult { + it.toDiscoverSearchCourses() + } + + override suspend fun getCourseDetail(publicCourseId: Int): Flow> = + remoteCourseDataSource.getCourseDetail(publicCourseId = publicCourseId).mapToFlowResult { + it.toCourseDetail() } - override suspend fun getMyCourseLoad(): Result?> = - runCatching { - remoteCourseDataSource.getMyCourseLoad().data?.toUploadCourses() + override suspend fun getMyCourseLoad(): Flow>> { + return remoteCourseDataSource.getMyCourseLoad().mapToFlowResult { + it.toUploadCourses() } + } - override suspend fun postUploadMyCourse(requestPostPublicCourse: RequestPostPublicCourse): ResponsePostDiscoverUpload { - return remoteCourseDataSource.postUploadMyCourse(requestPostPublicCourse = requestPostPublicCourse) + override suspend fun getMyDrawDetail(courseId: Int): Flow> { + return remoteCourseDataSource.getMyDrawDetail(courseId = courseId).mapToFlowResult { it } } - override suspend fun deleteMyDrawCourse(deleteCourseList: RequestPutMyDrawCourse): Response { - return remoteCourseDataSource.deleteMyDrawCourse(deleteCourseList = deleteCourseList) + override suspend fun deleteMyDrawCourse(deleteCourseList: RequestPutMyDrawCourse): Flow> { + return remoteCourseDataSource.deleteMyDrawCourse(deleteCourseList = deleteCourseList).mapToFlowResult { it } } - override suspend fun getMyDrawDetail(courseId: Int) = runCatching { - remoteCourseDataSource.getMyDrawDetail(courseId).data?.toMyDrawCourseDetail() + override suspend fun postCourseScrap( + requestPostCourseScrap: RequestPostCourseScrap + ): Flow> { + return remoteCourseDataSource.postCourseScrap(requestPostCourseScrap = requestPostCourseScrap).mapToFlowResult { + it.toPostScrap() + } } override suspend fun patchMyDrawCourseTitle( @@ -79,39 +86,29 @@ class CourseRepositoryImpl @Inject constructor(private val remoteCourseDataSourc remoteCourseDataSource.patchMyDrawCourseTitle(courseId, requestPatchMyDrawCourseTitle).data?.toEditableMyDrawCourseDetail() } - override suspend fun postRecord(request: RequestPostRunningHistory): Response { - return remoteCourseDataSource.postRecord(request = request) - } - - override suspend fun uploadCourse( - image: MultipartBody.Part, - data: RequestBody - ): Response { - return remoteCourseDataSource.uploadCourse( - image = image, - data = data - ) - } - - override suspend fun getCourseDetail( - publicCourseId: Int - ): Result = runCatching { - remoteCourseDataSource.getCourseDetail(publicCourseId = publicCourseId).data?.toCourseDetail() + override suspend fun postUploadMyCourse(requestPostPublicCourse: RequestPostPublicCourse): Flow> { + return remoteCourseDataSource.postUploadMyCourse(requestPostPublicCourse = requestPostPublicCourse).mapToFlowResult { it } } override suspend fun patchPublicCourse( publicCourseId: Int, requestPatchPublicCourse: RequestPatchPublicCourse - ): Result = runCatching { + ): Flow> = remoteCourseDataSource.patchPublicCourse( publicCourseId = publicCourseId, requestPatchPublicCourse = requestPatchPublicCourse - ).data?.toEditableCourseDetail() + ).mapToFlowResult { + it.toEditableCourseDetail() + } + + override suspend fun postRecord(request: RequestPostRunningHistory): Flow> { + return remoteCourseDataSource.postRecord(request = request).mapToFlowResult { it } } - override suspend fun postCourseScrap( - requestPostCourseScrap: RequestPostCourseScrap - ): Result = runCatching { - remoteCourseDataSource.postCourseScrap(requestPostCourseScrap = requestPostCourseScrap).data + override suspend fun uploadCourse( + image: MultipartBody.Part, + data: RequestBody + ): Flow> { + return remoteCourseDataSource.uploadCourse(image = image, data = data).mapToFlowResult { it } } } \ No newline at end of file diff --git a/app/src/main/java/com/runnect/runnect/data/repository/DepartureSearchRepositoryImpl.kt b/app/src/main/java/com/runnect/runnect/data/repository/DepartureSearchRepositoryImpl.kt index f1ff7c7e9..001ba51ce 100644 --- a/app/src/main/java/com/runnect/runnect/data/repository/DepartureSearchRepositoryImpl.kt +++ b/app/src/main/java/com/runnect/runnect/data/repository/DepartureSearchRepositoryImpl.kt @@ -3,17 +3,20 @@ package com.runnect.runnect.data.repository import com.naver.maps.geometry.LatLng import com.runnect.runnect.data.dto.SearchResultEntity import com.runnect.runnect.data.dto.response.ResponseGetSearchTmap +import com.runnect.runnect.data.network.mapToFlowResult import com.runnect.runnect.data.source.remote.RemoteDepartureSearchDataSource import com.runnect.runnect.domain.repository.DepartureSearchRepository +import kotlinx.coroutines.flow.Flow import javax.inject.Inject class DepartureSearchRepositoryImpl @Inject constructor(private val departureSourceDataSource: RemoteDepartureSearchDataSource) : DepartureSearchRepository { - override suspend fun getSearchList(keyword: String): List? { - return changeData( - departureSourceDataSource.getSearchList(searchKeyword = keyword) - .body()?.searchPoiInfo?.pois ?: return null - ) + override suspend fun getSearchList(keyword: String): Flow>> { + return departureSourceDataSource + .getSearchList(searchKeyword = keyword) + .mapToFlowResult { + changeData(it.searchPoiInfo.pois) + } } private fun changeData(pois: ResponseGetSearchTmap.SearchPoiInfo.Pois): List { diff --git a/app/src/main/java/com/runnect/runnect/data/repository/LoginRepositoryImpl.kt b/app/src/main/java/com/runnect/runnect/data/repository/LoginRepositoryImpl.kt index 680428ca0..f711e4dc4 100644 --- a/app/src/main/java/com/runnect/runnect/data/repository/LoginRepositoryImpl.kt +++ b/app/src/main/java/com/runnect/runnect/data/repository/LoginRepositoryImpl.kt @@ -2,14 +2,18 @@ package com.runnect.runnect.data.repository import com.runnect.runnect.data.dto.request.RequestPostLogin import com.runnect.runnect.data.dto.LoginDTO +import com.runnect.runnect.data.network.mapToFlowResult import com.runnect.runnect.data.source.remote.RemoteLoginDataSource import com.runnect.runnect.domain.repository.LoginRepository -import com.runnect.runnect.util.extension.toData +import kotlinx.coroutines.flow.Flow import javax.inject.Inject class LoginRepositoryImpl @Inject constructor(private val remoteLoginDataSource: RemoteLoginDataSource) : LoginRepository { - override suspend fun postLogin(requestPostLogin: RequestPostLogin): LoginDTO { - return remoteLoginDataSource.postLogin(requestPostLogin).toData() + + override suspend fun postLogin(requestPostLogin: RequestPostLogin): Flow> { + return remoteLoginDataSource.postLogin(requestPostLogin).mapToFlowResult { + it.toData() + } } } \ No newline at end of file diff --git a/app/src/main/java/com/runnect/runnect/data/repository/ReverseGeocodingRepositoryImpl.kt b/app/src/main/java/com/runnect/runnect/data/repository/ReverseGeocodingRepositoryImpl.kt index 011eb33d7..3f074d0bd 100644 --- a/app/src/main/java/com/runnect/runnect/data/repository/ReverseGeocodingRepositoryImpl.kt +++ b/app/src/main/java/com/runnect/runnect/data/repository/ReverseGeocodingRepositoryImpl.kt @@ -1,8 +1,10 @@ package com.runnect.runnect.data.repository -import com.runnect.runnect.data.dto.LocationData +import com.runnect.runnect.data.network.mapToFlowResult import com.runnect.runnect.data.source.remote.RemoteReverseGeocodingDataSource +import com.runnect.runnect.domain.entity.LocationData import com.runnect.runnect.domain.repository.ReverseGeocodingRepository +import kotlinx.coroutines.flow.Flow import javax.inject.Inject class ReverseGeocodingRepositoryImpl @Inject constructor(private val reverseGeocodingDataSource: RemoteReverseGeocodingDataSource) : @@ -10,12 +12,9 @@ class ReverseGeocodingRepositoryImpl @Inject constructor(private val reverseGeoc override suspend fun getLocationInfoUsingLatLng( lat: Double, lon: Double - ): LocationData { - val response = - reverseGeocodingDataSource.getLocationInfoUsingLatLng(lat = lat, lon = lon).body() - return LocationData( - buildingName = response?.addressInfo?.buildingName ?: "buildingName fail", - fullAddress = response?.addressInfo?.fullAddress ?: "fullAddress fail" - ) - } + ): Flow> = + reverseGeocodingDataSource.getLocationInfoUsingLatLng(lat = lat, lon = lon) + .mapToFlowResult { + it.toLocationData() + } } \ No newline at end of file diff --git a/app/src/main/java/com/runnect/runnect/data/repository/StorageRepositoryImpl.kt b/app/src/main/java/com/runnect/runnect/data/repository/StorageRepositoryImpl.kt index a786e2e40..94fb3a28a 100644 --- a/app/src/main/java/com/runnect/runnect/data/repository/StorageRepositoryImpl.kt +++ b/app/src/main/java/com/runnect/runnect/data/repository/StorageRepositoryImpl.kt @@ -1,27 +1,27 @@ package com.runnect.runnect.data.repository import com.runnect.runnect.data.dto.request.RequestPutMyDrawCourse -import com.runnect.runnect.domain.entity.MyScrapCourse import com.runnect.runnect.data.dto.response.ResponsePutMyDrawCourse import com.runnect.runnect.data.dto.response.toMyDrawCourse +import com.runnect.runnect.data.network.mapToFlowResult import com.runnect.runnect.data.source.remote.RemoteStorageDataSource import com.runnect.runnect.domain.entity.MyDrawCourse +import com.runnect.runnect.domain.entity.MyScrapCourse import com.runnect.runnect.domain.repository.StorageRepository -import retrofit2.Response +import kotlinx.coroutines.flow.Flow import javax.inject.Inject -class StorageRepositoryImpl @Inject constructor(private val remoteStorageDataSource: RemoteStorageDataSource) : - StorageRepository { - override suspend fun getMyDrawCourse(): Result?> = runCatching{ - remoteStorageDataSource.getMyDrawCourse().data?.toMyDrawCourse() - } +class StorageRepositoryImpl @Inject constructor( + private val remoteStorageDataSource: RemoteStorageDataSource +) : StorageRepository { + + override suspend fun getMyDrawCourse(): Flow>> = + remoteStorageDataSource.getMyDrawCourse().mapToFlowResult { it.toMyDrawCourse() } - override suspend fun deleteMyDrawCourse(deleteCourseList: RequestPutMyDrawCourse): Response { - return remoteStorageDataSource.deleteMyDrawCourse(deleteCourseList = deleteCourseList) + override suspend fun deleteMyDrawCourse(deleteCourseList: RequestPutMyDrawCourse): Flow> { + return remoteStorageDataSource.deleteMyDrawCourse(deleteCourseList = deleteCourseList).mapToFlowResult { it } } - override suspend fun getMyScrapCourse(): Result?> = - runCatching { - remoteStorageDataSource.getMyScrapCourse().data?.toMyScrapCourses() - } + override suspend fun getMyScrapCourse(): Flow>> = + remoteStorageDataSource.getMyScrapCourse().mapToFlowResult { it.toMyScrapCourses() } } \ No newline at end of file diff --git a/app/src/main/java/com/runnect/runnect/data/repository/UserRepositoryImpl.kt b/app/src/main/java/com/runnect/runnect/data/repository/UserRepositoryImpl.kt index 8c0bf1081..045cc4bc8 100644 --- a/app/src/main/java/com/runnect/runnect/data/repository/UserRepositoryImpl.kt +++ b/app/src/main/java/com/runnect/runnect/data/repository/UserRepositoryImpl.kt @@ -2,7 +2,6 @@ package com.runnect.runnect.data.repository import com.runnect.runnect.data.dto.HistoryInfoDTO import com.runnect.runnect.domain.entity.UserProfile -import com.runnect.runnect.data.dto.UserUploadCourseDTO import com.runnect.runnect.data.dto.request.RequestDeleteHistory import com.runnect.runnect.data.dto.request.RequestDeleteUploadCourse import com.runnect.runnect.data.dto.request.RequestPatchHistoryTitle @@ -10,57 +9,68 @@ import com.runnect.runnect.data.dto.request.RequestPatchNickName import com.runnect.runnect.data.dto.response.ResponseDeleteHistory import com.runnect.runnect.data.dto.response.ResponseDeleteUploadCourse import com.runnect.runnect.data.dto.response.ResponseDeleteUser -import com.runnect.runnect.data.dto.response.ResponseGetUser import com.runnect.runnect.data.dto.response.ResponsePatchHistoryTitle import com.runnect.runnect.data.dto.response.ResponsePatchUserNickName +import com.runnect.runnect.data.network.mapToFlowResult import com.runnect.runnect.data.source.remote.RemoteUserDataSource +import com.runnect.runnect.domain.entity.User +import com.runnect.runnect.domain.entity.UserUploadCourse import com.runnect.runnect.domain.repository.UserRepository -import com.runnect.runnect.util.extension.toData +import kotlinx.coroutines.flow.Flow import javax.inject.Inject class UserRepositoryImpl @Inject constructor(private val remoteUserDataSource: RemoteUserDataSource) : UserRepository { - override suspend fun getUserInfo(): ResponseGetUser = remoteUserDataSource.getUserInfo() - override suspend fun updateNickName(requestPatchNickName: RequestPatchNickName): ResponsePatchUserNickName = - remoteUserDataSource.updateNickName(requestPatchNickName) - override suspend fun getMyStamp(): MutableList { - return remoteUserDataSource.getMyStamp().data.stamps.map { it.id }.toMutableList() - } - - override suspend fun getRecord(): MutableList { - return remoteUserDataSource.getRecord().data.records.map { it.toData() }.toMutableList() - } + override suspend fun getUserInfo(): Flow> = remoteUserDataSource.getUserInfo() + .mapToFlowResult { it.toUser() } - override suspend fun getUserUploadCourse(): MutableList { - return remoteUserDataSource.getUserUploadCourse().data.publicCourses.map { it.toData() } - .toMutableList() - } - - override suspend fun getUserProfile(userId: Int): Result = - runCatching { - remoteUserDataSource.getUserProfile(userId).data?.toUserProfile() + override suspend fun getUserUploadCourse(): Flow>> { + return remoteUserDataSource.getUserUploadCourse().mapToFlowResult { + it.toUserUploadCourse() } + } override suspend fun putDeleteUploadCourse( requestDeleteUploadCourse: RequestDeleteUploadCourse - ): Result = runCatching { - remoteUserDataSource.putDeleteUploadCourse(requestDeleteUploadCourse).data + ): Flow> { + return remoteUserDataSource.putDeleteUploadCourse(requestDeleteUploadCourse).mapToFlowResult { it } } override suspend fun putDeleteHistory( requestDeleteHistory: RequestDeleteHistory - ): Result = runCatching { - remoteUserDataSource.putDeleteHistory(requestDeleteHistory).data + ): Flow> { + return remoteUserDataSource.putDeleteHistory(requestDeleteHistory).mapToFlowResult { it } } override suspend fun patchHistoryTitle( historyId: Int, requestPatchHistoryTitle: RequestPatchHistoryTitle - ): Result = runCatching { - remoteUserDataSource.patchHistoryTitle(historyId, requestPatchHistoryTitle).data + ): Flow> = + remoteUserDataSource.patchHistoryTitle(historyId, requestPatchHistoryTitle).mapToFlowResult { it } + + override suspend fun deleteUser(): Flow> { + return remoteUserDataSource.deleteUser().mapToFlowResult { it } } - override suspend fun deleteUser(): ResponseDeleteUser { - return remoteUserDataSource.deleteUser() + override suspend fun updateNickName( + requestPatchNickName: RequestPatchNickName + ): Flow> = + remoteUserDataSource.updateNickName(requestPatchNickName).mapToFlowResult { it } + + override suspend fun getRecord(): Flow>> { + return remoteUserDataSource.getRecord().mapToFlowResult { + it.toHistoryInfoList() + } } + + override suspend fun getMyStamp(): Flow>> { + return remoteUserDataSource.getMyStamp().mapToFlowResult { + it.toStampList() + } + } + + override suspend fun getUserProfile(userId: Int): Flow> = + remoteUserDataSource.getUserProfile(userId).mapToFlowResult { + it.toUserProfile() + } } \ No newline at end of file diff --git a/app/src/main/java/com/runnect/runnect/data/service/CourseService.kt b/app/src/main/java/com/runnect/runnect/data/service/CourseService.kt index 1a450447e..fb24cc1fa 100644 --- a/app/src/main/java/com/runnect/runnect/data/service/CourseService.kt +++ b/app/src/main/java/com/runnect/runnect/data/service/CourseService.kt @@ -7,6 +7,7 @@ import com.runnect.runnect.data.dto.request.RequestPostPublicCourse import com.runnect.runnect.data.dto.request.RequestPostRunningHistory import com.runnect.runnect.data.dto.request.RequestPutMyDrawCourse import com.runnect.runnect.data.dto.response.ResponseGetCourseDetail +import com.runnect.runnect.data.dto.response.ResponseGetDiscoverMarathon import com.runnect.runnect.data.dto.response.ResponseGetDiscoverRecommend import com.runnect.runnect.data.dto.response.ResponseGetDiscoverSearch import com.runnect.runnect.data.dto.response.ResponseGetDiscoverUploadCourse @@ -23,77 +24,69 @@ import com.runnect.runnect.data.dto.response.ResponsePutMyDrawCourse import com.runnect.runnect.data.dto.response.base.BaseResponse import okhttp3.MultipartBody import okhttp3.RequestBody -import retrofit2.Response -import retrofit2.http.* +import retrofit2.http.Body +import retrofit2.http.GET +import retrofit2.http.Multipart +import retrofit2.http.PATCH +import retrofit2.http.POST +import retrofit2.http.PUT +import retrofit2.http.Part +import retrofit2.http.Path +import retrofit2.http.Query interface CourseService { - @GET("/api/public-course") - suspend fun getRecommendCourse( - @Query("pageNo") pageNo: String, - @Query("sort") sort: String - ): BaseResponse - - @POST("/api/scrap") - suspend fun postCourseScrap( - @Body requestPostCourseScrap: RequestPostCourseScrap, - ): BaseResponse - @GET("/api/public-course/search?") suspend fun getCourseSearch( @Query("keyword") keyword: String, - ): BaseResponse + ): Result @GET("/api/public-course/detail/{publicCourseId}") suspend fun getCourseDetail( @Path("publicCourseId") publicCourseId: Int, - ): BaseResponse + ): Result - @GET("/api/course/private/user") - suspend fun getMyCourseLoad(): BaseResponse + @GET("/api/public-course/marathon") + suspend fun getMarathonCourse(): Result - @POST("/api/public-course") - suspend fun postUploadMyCourse( - @Body requestPostPublicCourse: RequestPostPublicCourse, - ): ResponsePostDiscoverUpload + @GET("/api/public-course") + suspend fun getRecommendCourse( + @Query("pageNo") pageNo: String, + @Query("sort") sort: String + ): Result - @PATCH("/api/public-course/{publicCourseId}") - suspend fun patchPublicCourse( - @Path("publicCourseId") publicCourseId: Int, - @Body requestPatchPublicCourse: RequestPatchPublicCourse - ): BaseResponse + @GET("/api/course/private/user") + suspend fun getMyCourseLoad(): Result - @PUT("/api/course") - suspend fun deleteMyDrawCourse( - @Body deleteCourseList: RequestPutMyDrawCourse - ): Response + //내가 그린 코스 Detail 가져오기 + @GET("/api/course/detail/{courseId}") + suspend fun getMyDrawDetail( + @Path("courseId") courseId: Int, + ): Result - // 보관함 내가 그린 코스 가져오기 + //보관함 내가 그린 코스 가져오기 @GET("/api/course/user") - suspend fun getDrawCourseList(): BaseResponse + suspend fun getDrawCourseList(): Result - // 보관함 스크랩 코스 가져오기 + //보관함 스크랩 코스 가져오기 @GET("/api/scrap/user") - suspend fun getScrapCourseList(): BaseResponse + suspend fun getScrapCourseList(): Result - // 내가 그린 코스 Detail 가져오기 - @GET("/api/course/detail/{courseId}") - suspend fun getMyDrawDetail( - @Path("courseId") courseId: Int, - ): BaseResponse + @POST("/api/public-course") + suspend fun postUploadMyCourse( + @Body requestPostPublicCourse: RequestPostPublicCourse, + ): Result - // 내가 그린 코스 제목 수정 - @PATCH("/api/course/{courseId}") - suspend fun patchMyDrawCourseTitle( - @Path("courseId") courseId: Int, - @Body requestPatchMyDrawCourseTitle: RequestPatchMyDrawCourseTitle - ): BaseResponse + @POST("/api/scrap") + suspend fun postCourseScrap( + @Body requestPostCourseScrap: RequestPostCourseScrap, + ): Result // 기록 업로드 @POST("/api/record") suspend fun postRecord( @Body request: RequestPostRunningHistory - ): Response + ): Result // 코스 업로드 @Multipart @@ -101,5 +94,24 @@ interface CourseService { suspend fun uploadCourse( @Part image: MultipartBody.Part, @Part("data") data: RequestBody, - ): Response + ): Result + + @PATCH("/api/public-course/{publicCourseId}") + suspend fun patchPublicCourse( + @Path("publicCourseId") publicCourseId: Int, + @Body requestPatchPublicCourse: RequestPatchPublicCourse + ): Result + + // 내가 그린 코스 제목 수정 + @PATCH("/api/course/{courseId}") + suspend fun patchMyDrawCourseTitle( + @Path("courseId") courseId: Int, + @Body requestPatchMyDrawCourseTitle: RequestPatchMyDrawCourseTitle + ): BaseResponse + + // 내가 그린 코스 삭제 + @PUT("/api/course") + suspend fun deleteMyDrawCourse( + @Body deleteCourseList: RequestPutMyDrawCourse + ): Result } \ No newline at end of file diff --git a/app/src/main/java/com/runnect/runnect/data/service/CourseV2Service.kt b/app/src/main/java/com/runnect/runnect/data/service/CourseV2Service.kt deleted file mode 100644 index 75d7198b5..000000000 --- a/app/src/main/java/com/runnect/runnect/data/service/CourseV2Service.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.runnect.runnect.data.service - -import com.runnect.runnect.data.dto.response.ResponseGetDiscoverMarathon -import retrofit2.http.GET - -interface CourseV2Service { - @GET("/api/public-course/marathon") - suspend fun getMarathonCourse(): Result -} \ No newline at end of file diff --git a/app/src/main/java/com/runnect/runnect/data/service/LoginService.kt b/app/src/main/java/com/runnect/runnect/data/service/LoginService.kt index 6c8af82e7..7615b06b8 100644 --- a/app/src/main/java/com/runnect/runnect/data/service/LoginService.kt +++ b/app/src/main/java/com/runnect/runnect/data/service/LoginService.kt @@ -1,21 +1,15 @@ package com.runnect.runnect.data.service - import com.runnect.runnect.data.dto.request.RequestPostLogin import com.runnect.runnect.data.dto.response.ResponsePostLogin -import com.runnect.runnect.data.dto.response.ResponseGetRefreshToken -import retrofit2.http.* +import retrofit2.http.Body +import retrofit2.http.POST interface LoginService { + //로그인 @POST("/api/auth") suspend fun postLogin( @Body request: RequestPostLogin - ): ResponsePostLogin - - //토큰 재발급 - @GET("/api/auth/getNewToken") - suspend fun getNewToken( - - ): ResponseGetRefreshToken + ): Result } \ No newline at end of file diff --git a/app/src/main/java/com/runnect/runnect/data/service/ReverseGeocodingService.kt b/app/src/main/java/com/runnect/runnect/data/service/ReverseGeocodingService.kt index 8de14589e..0397c40e6 100644 --- a/app/src/main/java/com/runnect/runnect/data/service/ReverseGeocodingService.kt +++ b/app/src/main/java/com/runnect/runnect/data/service/ReverseGeocodingService.kt @@ -1,8 +1,7 @@ package com.runnect.runnect.data.service import com.runnect.runnect.BuildConfig -import com.runnect.runnect.data.dto.tmap.geocoding.ResponseReverseGeocodingDto -import retrofit2.Response +import com.runnect.runnect.data.dto.response.ResponseReverseGeocodingDto import retrofit2.http.GET import retrofit2.http.Header import retrofit2.http.Query @@ -18,5 +17,5 @@ interface ReverseGeocodingService { @Query("lon") lon: Double, @Query("coordType") coordType: String? = "WGS84GEO", @Query("addressType") addresstType: String? = "A04", - ): Response + ): Result } diff --git a/app/src/main/java/com/runnect/runnect/data/service/SearchService.kt b/app/src/main/java/com/runnect/runnect/data/service/SearchService.kt index 6803df9dd..f8ac7e1c9 100644 --- a/app/src/main/java/com/runnect/runnect/data/service/SearchService.kt +++ b/app/src/main/java/com/runnect/runnect/data/service/SearchService.kt @@ -25,5 +25,5 @@ interface SearchService { @Query("reqCoordType") reqCoordType: String? = null, @Query("centerLon") centerLon: String? = null, @Query("centerLat") centerLat: String? = null, - ): Response + ): Result } diff --git a/app/src/main/java/com/runnect/runnect/data/service/TokenService.kt b/app/src/main/java/com/runnect/runnect/data/service/TokenService.kt new file mode 100644 index 000000000..2a0648942 --- /dev/null +++ b/app/src/main/java/com/runnect/runnect/data/service/TokenService.kt @@ -0,0 +1,11 @@ +package com.runnect.runnect.data.service + +import com.runnect.runnect.data.dto.response.ResponseGetRefreshToken +import retrofit2.http.* + +interface TokenService { + + //토큰 재발급 + @GET("/api/auth/getNewToken") + suspend fun getNewToken(): ResponseGetRefreshToken +} \ No newline at end of file diff --git a/app/src/main/java/com/runnect/runnect/data/service/UserService.kt b/app/src/main/java/com/runnect/runnect/data/service/UserService.kt index 780a22bf9..8578110f9 100644 --- a/app/src/main/java/com/runnect/runnect/data/service/UserService.kt +++ b/app/src/main/java/com/runnect/runnect/data/service/UserService.kt @@ -4,54 +4,64 @@ import com.runnect.runnect.data.dto.request.RequestDeleteHistory import com.runnect.runnect.data.dto.request.RequestDeleteUploadCourse import com.runnect.runnect.data.dto.request.RequestPatchHistoryTitle import com.runnect.runnect.data.dto.request.RequestPatchNickName -import com.runnect.runnect.data.dto.response.* -import com.runnect.runnect.data.dto.response.base.BaseResponse -import retrofit2.http.* +import com.runnect.runnect.data.dto.response.ResponseDeleteHistory +import com.runnect.runnect.data.dto.response.ResponseDeleteUploadCourse +import com.runnect.runnect.data.dto.response.ResponseDeleteUser +import com.runnect.runnect.data.dto.response.ResponseGetMyHistory +import com.runnect.runnect.data.dto.response.ResponseGetMyStamp +import com.runnect.runnect.data.dto.response.ResponseGetUser +import com.runnect.runnect.data.dto.response.ResponseGetUserProfile +import com.runnect.runnect.data.dto.response.ResponseGetUserUploadCourse +import com.runnect.runnect.data.dto.response.ResponsePatchHistoryTitle +import com.runnect.runnect.data.dto.response.ResponsePatchUserNickName +import retrofit2.http.Body +import retrofit2.http.DELETE +import retrofit2.http.GET +import retrofit2.http.PATCH +import retrofit2.http.PUT +import retrofit2.http.Path interface UserService { - @GET("api/user") - suspend fun getUserInfo( - ): ResponseGetUser - @PATCH("api/user") - suspend fun updateNickName( - @Body requestPatchNickName: RequestPatchNickName, - ): ResponsePatchUserNickName + @GET("api/user") + suspend fun getUserInfo(): Result - @GET("api/stamp/user") - suspend fun getMyStamp( - ): ResponseGetMyStamp + @GET("api/public-course/user") + suspend fun getUserUploadCourse(): Result @GET("api/record/user") - suspend fun getRecord( - ): ResponseGetMyHistory + suspend fun getRecord(): Result - @GET("api/public-course/user") - suspend fun getUserUploadCourse( - ): ResponseGetUserUploadCourse + @GET("api/stamp/user") + suspend fun getMyStamp(): Result + + // 유저 프로필 조회 + @GET("/api/user/{profileUserId}") + suspend fun getUserProfile( + @Path("profileUserId") userId: Int, + ): Result @PUT("api/public-course") suspend fun putDeleteUploadCourse( @Body requestDeleteUploadCourse: RequestDeleteUploadCourse - ): BaseResponse + ): Result @PUT("api/record") suspend fun putDeleteHistory( @Body requestDeleteHistory: RequestDeleteHistory - ): BaseResponse + ): Result @PATCH("api/record/{recordId}") suspend fun patchHistoryTitle( @Path("recordId") historyId: Int, @Body requestPatchHistoryTitle: RequestPatchHistoryTitle - ): BaseResponse + ): Result - @DELETE("api/user") - suspend fun deleteUser(): ResponseDeleteUser + @PATCH("api/user") + suspend fun updateNickName( + @Body requestPatchNickName: RequestPatchNickName, + ): Result - // 유저 프로필 조회 - @GET("/api/user/{profileUserId}") - suspend fun getUserProfile( - @Path("profileUserId") userId: Int, - ): BaseResponse + @DELETE("api/user") + suspend fun deleteUser(): Result } \ No newline at end of file diff --git a/app/src/main/java/com/runnect/runnect/data/source/remote/RemoteCourseDataSource.kt b/app/src/main/java/com/runnect/runnect/data/source/remote/RemoteCourseDataSource.kt index 33f67348c..b6ebc9e8d 100644 --- a/app/src/main/java/com/runnect/runnect/data/source/remote/RemoteCourseDataSource.kt +++ b/app/src/main/java/com/runnect/runnect/data/source/remote/RemoteCourseDataSource.kt @@ -11,32 +11,29 @@ import com.runnect.runnect.data.dto.response.ResponseGetDiscoverMarathon import com.runnect.runnect.data.dto.response.ResponseGetDiscoverRecommend import com.runnect.runnect.data.dto.response.ResponsePatchPublicCourse import com.runnect.runnect.data.dto.response.ResponsePostScrap -import com.runnect.runnect.data.dto.response.base.BaseResponse import com.runnect.runnect.data.service.CourseService -import com.runnect.runnect.data.service.CourseV2Service import okhttp3.MultipartBody import okhttp3.RequestBody import javax.inject.Inject class RemoteCourseDataSource @Inject constructor( - private var courseV2Service: CourseV2Service, - private val courseService: CourseService + private var courseService: CourseService, ) { suspend fun getMarathonCourse(): Result = - courseV2Service.getMarathonCourse() + courseService.getMarathonCourse() suspend fun getRecommendCourse( pageNo: String, sort: String - ): BaseResponse = + ): Result = courseService.getRecommendCourse(pageNo = pageNo, sort = sort) - suspend fun postCourseScrap(requestPostCourseScrap: RequestPostCourseScrap): BaseResponse = + suspend fun postCourseScrap(requestPostCourseScrap: RequestPostCourseScrap): Result = courseService.postCourseScrap(requestPostCourseScrap) suspend fun getCourseSearch(keyword: String) = courseService.getCourseSearch(keyword) - suspend fun getCourseDetail(publicCourseId: Int): BaseResponse = + suspend fun getCourseDetail(publicCourseId: Int): Result = courseService.getCourseDetail(publicCourseId) suspend fun getMyCourseLoad() = courseService.getMyCourseLoad() @@ -47,7 +44,7 @@ class RemoteCourseDataSource @Inject constructor( suspend fun patchPublicCourse( publicCourseId: Int, requestPatchPublicCourse: RequestPatchPublicCourse - ): BaseResponse = + ): Result = courseService.patchPublicCourse(publicCourseId, requestPatchPublicCourse) suspend fun deleteMyDrawCourse(deleteCourseList: RequestPutMyDrawCourse) = diff --git a/app/src/main/java/com/runnect/runnect/data/source/remote/RemoteDepartureSearchDataSource.kt b/app/src/main/java/com/runnect/runnect/data/source/remote/RemoteDepartureSearchDataSource.kt index efd91856a..a83588d07 100644 --- a/app/src/main/java/com/runnect/runnect/data/source/remote/RemoteDepartureSearchDataSource.kt +++ b/app/src/main/java/com/runnect/runnect/data/source/remote/RemoteDepartureSearchDataSource.kt @@ -2,11 +2,10 @@ package com.runnect.runnect.data.source.remote import com.runnect.runnect.data.dto.response.ResponseGetSearchTmap import com.runnect.runnect.data.service.SearchService -import retrofit2.Response import javax.inject.Inject class RemoteDepartureSearchDataSource @Inject constructor(private val searchService: SearchService) { - suspend fun getSearchList(searchKeyword: String): Response = + suspend fun getSearchList(searchKeyword: String): Result = searchService.getSearchLocation(keyword = searchKeyword) } \ No newline at end of file diff --git a/app/src/main/java/com/runnect/runnect/data/source/remote/RemoteLoginDataSource.kt b/app/src/main/java/com/runnect/runnect/data/source/remote/RemoteLoginDataSource.kt index 8e1853d02..4c8f67214 100644 --- a/app/src/main/java/com/runnect/runnect/data/source/remote/RemoteLoginDataSource.kt +++ b/app/src/main/java/com/runnect/runnect/data/source/remote/RemoteLoginDataSource.kt @@ -1,10 +1,14 @@ package com.runnect.runnect.data.source.remote -import com.runnect.runnect.data.service.LoginService import com.runnect.runnect.data.dto.request.RequestPostLogin import com.runnect.runnect.data.dto.response.ResponsePostLogin +import com.runnect.runnect.data.service.LoginService import javax.inject.Inject -class RemoteLoginDataSource @Inject constructor(private val loginService: LoginService) { - suspend fun postLogin(requestPostLogin: RequestPostLogin):ResponsePostLogin=loginService.postLogin(requestPostLogin) +class RemoteLoginDataSource @Inject constructor( + private val loginService: LoginService +) { + suspend fun postLogin( + requestPostLogin: RequestPostLogin + ): Result = loginService.postLogin(requestPostLogin) } \ No newline at end of file diff --git a/app/src/main/java/com/runnect/runnect/data/source/remote/RemoteReverseGeocodingDataSource.kt b/app/src/main/java/com/runnect/runnect/data/source/remote/RemoteReverseGeocodingDataSource.kt index a4f29514a..fc04bd583 100644 --- a/app/src/main/java/com/runnect/runnect/data/source/remote/RemoteReverseGeocodingDataSource.kt +++ b/app/src/main/java/com/runnect/runnect/data/source/remote/RemoteReverseGeocodingDataSource.kt @@ -1,14 +1,15 @@ package com.runnect.runnect.data.source.remote -import com.runnect.runnect.data.dto.tmap.geocoding.ResponseReverseGeocodingDto +import com.runnect.runnect.data.dto.response.ResponseReverseGeocodingDto import com.runnect.runnect.data.service.ReverseGeocodingService -import retrofit2.Response import javax.inject.Inject -class RemoteReverseGeocodingDataSource @Inject constructor(private val reverseGeocodingService: ReverseGeocodingService) { +class RemoteReverseGeocodingDataSource @Inject constructor( + private val reverseGeocodingService: ReverseGeocodingService +) { suspend fun getLocationInfoUsingLatLng( lat: Double, lon: Double - ): Response = + ): Result = reverseGeocodingService.getLocationUsingLatLng(lat = lat, lon = lon) } \ No newline at end of file diff --git a/app/src/main/java/com/runnect/runnect/data/source/remote/RemoteStorageDataSource.kt b/app/src/main/java/com/runnect/runnect/data/source/remote/RemoteStorageDataSource.kt index beb4e36ed..a9dc29707 100644 --- a/app/src/main/java/com/runnect/runnect/data/source/remote/RemoteStorageDataSource.kt +++ b/app/src/main/java/com/runnect/runnect/data/source/remote/RemoteStorageDataSource.kt @@ -1,21 +1,21 @@ package com.runnect.runnect.data.source.remote -import com.runnect.runnect.data.service.CourseService import com.runnect.runnect.data.dto.request.RequestPutMyDrawCourse import com.runnect.runnect.data.dto.response.ResponseGetMyDrawCourse import com.runnect.runnect.data.dto.response.ResponseGetMyScrapCourse import com.runnect.runnect.data.dto.response.ResponsePutMyDrawCourse -import com.runnect.runnect.data.dto.response.base.BaseResponse -import retrofit2.Response +import com.runnect.runnect.data.service.CourseService import javax.inject.Inject -class RemoteStorageDataSource @Inject constructor(private val courseService: CourseService) { - suspend fun getMyDrawCourse(): BaseResponse = +class RemoteStorageDataSource @Inject constructor( + private val courseService: CourseService, +) { + suspend fun getMyDrawCourse(): Result = courseService.getDrawCourseList() - suspend fun deleteMyDrawCourse(deleteCourseList: RequestPutMyDrawCourse): Response = - courseService.deleteMyDrawCourse(deleteCourseList) - - suspend fun getMyScrapCourse(): BaseResponse = + suspend fun getMyScrapCourse(): Result = courseService.getScrapCourseList() + + suspend fun deleteMyDrawCourse(deleteCourseList: RequestPutMyDrawCourse): Result = + courseService.deleteMyDrawCourse(deleteCourseList) } \ No newline at end of file diff --git a/app/src/main/java/com/runnect/runnect/data/source/remote/RemoteUserDataSource.kt b/app/src/main/java/com/runnect/runnect/data/source/remote/RemoteUserDataSource.kt index 19d9b64e0..be5ce7bcf 100644 --- a/app/src/main/java/com/runnect/runnect/data/source/remote/RemoteUserDataSource.kt +++ b/app/src/main/java/com/runnect/runnect/data/source/remote/RemoteUserDataSource.kt @@ -14,36 +14,42 @@ import com.runnect.runnect.data.dto.response.ResponseGetUserProfile import com.runnect.runnect.data.dto.response.ResponseGetUserUploadCourse import com.runnect.runnect.data.dto.response.ResponsePatchHistoryTitle import com.runnect.runnect.data.dto.response.ResponsePatchUserNickName -import com.runnect.runnect.data.dto.response.base.BaseResponse import com.runnect.runnect.data.service.UserService import javax.inject.Inject -class RemoteUserDataSource @Inject constructor(private val userService: UserService) { - suspend fun getUserInfo(): ResponseGetUser = userService.getUserInfo() - suspend fun updateNickName(requestPatchNickName: RequestPatchNickName): ResponsePatchUserNickName = - userService.updateNickName(requestPatchNickName) +class RemoteUserDataSource @Inject constructor( + private val userService: UserService, +) { + suspend fun getUserInfo(): Result = userService.getUserInfo() - suspend fun getMyStamp(): ResponseGetMyStamp = userService.getMyStamp() - suspend fun getRecord(): ResponseGetMyHistory = userService.getRecord() - suspend fun getUserUploadCourse(): ResponseGetUserUploadCourse = + suspend fun getUserUploadCourse(): Result = userService.getUserUploadCourse() - suspend fun getUserProfile(userId: Int): BaseResponse = - userService.getUserProfile(userId) + suspend fun deleteUser(): Result = userService.deleteUser() + + suspend fun getRecord(): Result = userService.getRecord() + + suspend fun getMyStamp(): Result = userService.getMyStamp() suspend fun putDeleteUploadCourse( requestDeleteUploadCourse: RequestDeleteUploadCourse - ): BaseResponse = + ): Result = userService.putDeleteUploadCourse(requestDeleteUploadCourse) - suspend fun putDeleteHistory(requestDeleteHistory: RequestDeleteHistory): BaseResponse = + suspend fun putDeleteHistory(requestDeleteHistory: RequestDeleteHistory): Result = userService.putDeleteHistory(requestDeleteHistory) suspend fun patchHistoryTitle( historyId: Int, requestPatchHistoryTitle: RequestPatchHistoryTitle - ): BaseResponse = + ): Result = userService.patchHistoryTitle(historyId, requestPatchHistoryTitle) - suspend fun deleteUser(): ResponseDeleteUser = userService.deleteUser() + suspend fun updateNickName( + requestPatchNickName: RequestPatchNickName + ): Result = + userService.updateNickName(requestPatchNickName) + + suspend fun getUserProfile(userId: Int): Result = + userService.getUserProfile(userId) } \ No newline at end of file diff --git a/app/src/main/java/com/runnect/runnect/di/RetrofitModule.kt b/app/src/main/java/com/runnect/runnect/di/RetrofitModule.kt index 391caa408..b1d61a8c5 100644 --- a/app/src/main/java/com/runnect/runnect/di/RetrofitModule.kt +++ b/app/src/main/java/com/runnect/runnect/di/RetrofitModule.kt @@ -135,10 +135,13 @@ object RetrofitModule { @Provides @Singleton @Tmap - fun provideTmapRetrofit(json: Json, @HttpClient client: OkHttpClient): Retrofit { + fun provideTmapRetrofit(json: Json, @HttpClientV2 client: OkHttpClient): Retrofit { kotlinx.coroutines.internal.synchronized(this) { - val retrofit = Retrofit.Builder().baseUrl(BuildConfig.TMAP_BASE_URL).client(client) - .addConverterFactory(json.asConverterFactory("application/json".toMediaType())) + val retrofit = Retrofit.Builder() + .baseUrl(BuildConfig.TMAP_BASE_URL) + .client(client) + .addConverterFactory(GsonConverterFactory.create()) + .addCallAdapterFactory(ResultCallAdapterFactory.create()) .build() return retrofit ?: throw RuntimeException("Retrofit creation failed.") } diff --git a/app/src/main/java/com/runnect/runnect/di/ServiceModule.kt b/app/src/main/java/com/runnect/runnect/di/ServiceModule.kt index 01ea70b55..d83a93bb9 100644 --- a/app/src/main/java/com/runnect/runnect/di/ServiceModule.kt +++ b/app/src/main/java/com/runnect/runnect/di/ServiceModule.kt @@ -4,6 +4,8 @@ import com.google.firebase.firestore.ktx.firestore import com.google.firebase.ktx.Firebase import com.runnect.runnect.data.repository.* import com.runnect.runnect.data.service.* +import com.runnect.runnect.data.service.LoginService +import com.runnect.runnect.data.service.UserService import com.runnect.runnect.data.source.remote.* import com.runnect.runnect.domain.* import dagger.Module @@ -19,23 +21,18 @@ object ServiceModule { @Singleton @Provides - fun providePCourseV2Service(@RetrofitModule.RetrofitV2 retrofitV2: Retrofit) = - retrofitV2.create(CourseV2Service::class.java) + fun providePUserService(@RetrofitModule.RetrofitV2 retrofitV2: Retrofit) = + retrofitV2.create(UserService::class.java) @Singleton @Provides - fun providePCourseService(@RetrofitModule.Runnect runnectRetrofit: Retrofit) = - runnectRetrofit.create(CourseService::class.java) + fun providePLoginService(@RetrofitModule.RetrofitV2 retrofitV2: Retrofit) = + retrofitV2.create(LoginService::class.java) @Singleton @Provides - fun providePUserService(@RetrofitModule.Runnect runnectRetrofit: Retrofit) = - runnectRetrofit.create(UserService::class.java) - - @Singleton - @Provides - fun provideLoginService(@RetrofitModule.Runnect runnectRetrofit: Retrofit) = - runnectRetrofit.create(LoginService::class.java) + fun providePCourseService(@RetrofitModule.RetrofitV2 retrofitV2: Retrofit) = + retrofitV2.create(CourseService::class.java) @Singleton @Provides diff --git a/app/src/main/java/com/runnect/runnect/domain/common/RunnectException.kt b/app/src/main/java/com/runnect/runnect/domain/common/RunnectException.kt index aadbdce7f..e84f5b1c8 100644 --- a/app/src/main/java/com/runnect/runnect/domain/common/RunnectException.kt +++ b/app/src/main/java/com/runnect/runnect/domain/common/RunnectException.kt @@ -9,6 +9,10 @@ class RunnectException( fun toLog() = "$message (${code})" } +fun Throwable.getCode(): Int { + return if (this is RunnectException) code else -1 +} + fun Throwable.toLog(): String { return if(this is RunnectException) { this.toLog() diff --git a/app/src/main/java/com/runnect/runnect/domain/entity/LocationData.kt b/app/src/main/java/com/runnect/runnect/domain/entity/LocationData.kt new file mode 100644 index 000000000..3108e1dd6 --- /dev/null +++ b/app/src/main/java/com/runnect/runnect/domain/entity/LocationData.kt @@ -0,0 +1,6 @@ +package com.runnect.runnect.domain.entity + +data class LocationData( + val buildingName: String, + val fullAddress: String, +) \ No newline at end of file diff --git a/app/src/main/java/com/runnect/runnect/domain/entity/PostScrap.kt b/app/src/main/java/com/runnect/runnect/domain/entity/PostScrap.kt new file mode 100644 index 000000000..b2ee69be5 --- /dev/null +++ b/app/src/main/java/com/runnect/runnect/domain/entity/PostScrap.kt @@ -0,0 +1,7 @@ +package com.runnect.runnect.domain.entity + +data class PostScrap( + val publicCourseId: Long, + val scrapCount: Long, + val scrapTF: Boolean, +) \ No newline at end of file diff --git a/app/src/main/java/com/runnect/runnect/domain/entity/User.kt b/app/src/main/java/com/runnect/runnect/domain/entity/User.kt new file mode 100644 index 000000000..9c2d6079a --- /dev/null +++ b/app/src/main/java/com/runnect/runnect/domain/entity/User.kt @@ -0,0 +1,9 @@ +package com.runnect.runnect.domain.entity + +data class User( + val email: String, + val latestStamp: String, + val level: Int, + val levelPercent: Int, + val nickname: String +) \ No newline at end of file diff --git a/app/src/main/java/com/runnect/runnect/data/dto/UserUploadCourseDTO.kt b/app/src/main/java/com/runnect/runnect/domain/entity/UserUploadCourse.kt similarity index 54% rename from app/src/main/java/com/runnect/runnect/data/dto/UserUploadCourseDTO.kt rename to app/src/main/java/com/runnect/runnect/domain/entity/UserUploadCourse.kt index 5608c4d7f..00e367f10 100644 --- a/app/src/main/java/com/runnect/runnect/data/dto/UserUploadCourseDTO.kt +++ b/app/src/main/java/com/runnect/runnect/domain/entity/UserUploadCourse.kt @@ -1,6 +1,6 @@ -package com.runnect.runnect.data.dto +package com.runnect.runnect.domain.entity -data class UserUploadCourseDTO( +data class UserUploadCourse( val id:Int, val img:String, var title:String, diff --git a/app/src/main/java/com/runnect/runnect/domain/repository/CourseRepository.kt b/app/src/main/java/com/runnect/runnect/domain/repository/CourseRepository.kt index 16194689c..b9cbbf1a3 100644 --- a/app/src/main/java/com/runnect/runnect/domain/repository/CourseRepository.kt +++ b/app/src/main/java/com/runnect/runnect/domain/repository/CourseRepository.kt @@ -7,11 +7,9 @@ import com.runnect.runnect.data.dto.request.RequestPostPublicCourse import com.runnect.runnect.data.dto.request.RequestPostRunningHistory import com.runnect.runnect.data.dto.request.RequestPutMyDrawCourse import com.runnect.runnect.data.dto.response.ResponseGetMyDrawDetail -import com.runnect.runnect.data.dto.response.ResponsePatchMyDrawCourseTitle import com.runnect.runnect.data.dto.response.ResponsePostDiscoverUpload import com.runnect.runnect.data.dto.response.ResponsePostMyDrawCourse import com.runnect.runnect.data.dto.response.ResponsePostMyHistory -import com.runnect.runnect.data.dto.response.ResponsePostScrap import com.runnect.runnect.data.dto.response.ResponsePutMyDrawCourse import com.runnect.runnect.domain.entity.CourseDetail import com.runnect.runnect.domain.entity.DiscoverMultiViewItem.MarathonCourse @@ -19,12 +17,11 @@ import com.runnect.runnect.domain.entity.DiscoverSearchCourse import com.runnect.runnect.domain.entity.DiscoverUploadCourse import com.runnect.runnect.domain.entity.EditableCourseDetail import com.runnect.runnect.domain.entity.EditableMyDrawCourseDetail -import com.runnect.runnect.domain.entity.MyDrawCourseDetail +import com.runnect.runnect.domain.entity.PostScrap import com.runnect.runnect.domain.entity.RecommendCoursePagingData import kotlinx.coroutines.flow.Flow import okhttp3.MultipartBody import okhttp3.RequestBody -import retrofit2.Response interface CourseRepository { suspend fun getMarathonCourse(): Flow>> @@ -32,35 +29,35 @@ interface CourseRepository { suspend fun getRecommendCourse( pageNo: String, sort: String - ): Result + ): Flow> - suspend fun getCourseSearch(keyword: String): Result?> + suspend fun getCourseSearch(keyword: String): Flow>> - suspend fun getMyCourseLoad(): Result?> + suspend fun getCourseDetail(publicCourseId: Int): Flow> - suspend fun postUploadMyCourse(requestPostPublicCourse: RequestPostPublicCourse): ResponsePostDiscoverUpload + suspend fun getMyCourseLoad(): Flow>> - suspend fun deleteMyDrawCourse(deleteCourseList: RequestPutMyDrawCourse): Response + suspend fun getMyDrawDetail(courseId: Int): Flow> - suspend fun getMyDrawDetail(courseId: Int): Result + suspend fun deleteMyDrawCourse(deleteCourseList: RequestPutMyDrawCourse): Flow> + + suspend fun postCourseScrap(requestPostCourseScrap: RequestPostCourseScrap): Flow> suspend fun patchMyDrawCourseTitle( courseId: Int, requestPatchMyDrawCourseTitle: RequestPatchMyDrawCourseTitle ): Result - suspend fun postRecord(request: RequestPostRunningHistory): Response - - suspend fun uploadCourse( - image: MultipartBody.Part, data: RequestBody - ): Response - - suspend fun getCourseDetail(publicCourseId: Int): Result + suspend fun postUploadMyCourse(requestPostPublicCourse: RequestPostPublicCourse): Flow> suspend fun patchPublicCourse( publicCourseId: Int, requestPatchPublicCourse: RequestPatchPublicCourse - ): Result + ): Flow> + + suspend fun postRecord(request: RequestPostRunningHistory): Flow> - suspend fun postCourseScrap(requestPostCourseScrap: RequestPostCourseScrap): Result + suspend fun uploadCourse( + image: MultipartBody.Part, data: RequestBody + ): Flow> } \ No newline at end of file diff --git a/app/src/main/java/com/runnect/runnect/domain/repository/DepartureSearchRepository.kt b/app/src/main/java/com/runnect/runnect/domain/repository/DepartureSearchRepository.kt index 4b6933a2f..2c54da290 100644 --- a/app/src/main/java/com/runnect/runnect/domain/repository/DepartureSearchRepository.kt +++ b/app/src/main/java/com/runnect/runnect/domain/repository/DepartureSearchRepository.kt @@ -1,7 +1,8 @@ package com.runnect.runnect.domain.repository import com.runnect.runnect.data.dto.SearchResultEntity +import kotlinx.coroutines.flow.Flow interface DepartureSearchRepository { - suspend fun getSearchList(keyword: String): List? + suspend fun getSearchList(keyword: String): Flow>> } \ No newline at end of file diff --git a/app/src/main/java/com/runnect/runnect/domain/repository/LoginRepository.kt b/app/src/main/java/com/runnect/runnect/domain/repository/LoginRepository.kt index bc484cbc1..132c4778c 100644 --- a/app/src/main/java/com/runnect/runnect/domain/repository/LoginRepository.kt +++ b/app/src/main/java/com/runnect/runnect/domain/repository/LoginRepository.kt @@ -2,7 +2,8 @@ package com.runnect.runnect.domain.repository import com.runnect.runnect.data.dto.request.RequestPostLogin import com.runnect.runnect.data.dto.LoginDTO +import kotlinx.coroutines.flow.Flow interface LoginRepository { - suspend fun postLogin(requestPostLogin: RequestPostLogin): LoginDTO + suspend fun postLogin(requestPostLogin: RequestPostLogin): Flow> } \ No newline at end of file diff --git a/app/src/main/java/com/runnect/runnect/domain/repository/ReverseGeocodingRepository.kt b/app/src/main/java/com/runnect/runnect/domain/repository/ReverseGeocodingRepository.kt index 62eb51038..927a7ba8e 100644 --- a/app/src/main/java/com/runnect/runnect/domain/repository/ReverseGeocodingRepository.kt +++ b/app/src/main/java/com/runnect/runnect/domain/repository/ReverseGeocodingRepository.kt @@ -1,7 +1,8 @@ package com.runnect.runnect.domain.repository -import com.runnect.runnect.data.dto.LocationData +import com.runnect.runnect.domain.entity.LocationData +import kotlinx.coroutines.flow.Flow interface ReverseGeocodingRepository { - suspend fun getLocationInfoUsingLatLng(lat: Double, lon: Double): LocationData + suspend fun getLocationInfoUsingLatLng(lat: Double, lon: Double): Flow> } \ No newline at end of file diff --git a/app/src/main/java/com/runnect/runnect/domain/repository/StorageRepository.kt b/app/src/main/java/com/runnect/runnect/domain/repository/StorageRepository.kt index 75e1fe0e2..258841be9 100644 --- a/app/src/main/java/com/runnect/runnect/domain/repository/StorageRepository.kt +++ b/app/src/main/java/com/runnect/runnect/domain/repository/StorageRepository.kt @@ -4,10 +4,10 @@ import com.runnect.runnect.domain.entity.MyScrapCourse import com.runnect.runnect.data.dto.request.RequestPutMyDrawCourse import com.runnect.runnect.data.dto.response.ResponsePutMyDrawCourse import com.runnect.runnect.domain.entity.MyDrawCourse -import retrofit2.Response +import kotlinx.coroutines.flow.Flow interface StorageRepository { - suspend fun getMyDrawCourse(): Result?> - suspend fun deleteMyDrawCourse(deleteCourseList: RequestPutMyDrawCourse) : Response - suspend fun getMyScrapCourse(): Result?> + suspend fun getMyDrawCourse(): Flow>> + suspend fun getMyScrapCourse(): Flow>> + suspend fun deleteMyDrawCourse(deleteCourseList: RequestPutMyDrawCourse) : Flow> } \ No newline at end of file diff --git a/app/src/main/java/com/runnect/runnect/domain/repository/UserRepository.kt b/app/src/main/java/com/runnect/runnect/domain/repository/UserRepository.kt index bb2713628..45fb41834 100644 --- a/app/src/main/java/com/runnect/runnect/domain/repository/UserRepository.kt +++ b/app/src/main/java/com/runnect/runnect/domain/repository/UserRepository.kt @@ -2,7 +2,6 @@ package com.runnect.runnect.domain.repository import com.runnect.runnect.data.dto.HistoryInfoDTO import com.runnect.runnect.domain.entity.UserProfile -import com.runnect.runnect.data.dto.UserUploadCourseDTO import com.runnect.runnect.data.dto.request.RequestDeleteHistory import com.runnect.runnect.data.dto.request.RequestDeleteUploadCourse import com.runnect.runnect.data.dto.request.RequestPatchHistoryTitle @@ -10,33 +9,37 @@ import com.runnect.runnect.data.dto.request.RequestPatchNickName import com.runnect.runnect.data.dto.response.ResponseDeleteHistory import com.runnect.runnect.data.dto.response.ResponseDeleteUploadCourse import com.runnect.runnect.data.dto.response.ResponseDeleteUser -import com.runnect.runnect.data.dto.response.ResponseGetUser import com.runnect.runnect.data.dto.response.ResponsePatchHistoryTitle import com.runnect.runnect.data.dto.response.ResponsePatchUserNickName +import com.runnect.runnect.domain.entity.User +import com.runnect.runnect.domain.entity.UserUploadCourse +import kotlinx.coroutines.flow.Flow interface UserRepository { - suspend fun getUserInfo(): ResponseGetUser + suspend fun getUserInfo(): Flow> - suspend fun updateNickName(requestPatchNickName: RequestPatchNickName): ResponsePatchUserNickName + suspend fun getUserUploadCourse(): Flow>> - suspend fun getMyStamp(): MutableList - - suspend fun getRecord(): MutableList + suspend fun putDeleteUploadCourse( + requestDeleteUploadCourse: RequestDeleteUploadCourse + ): Flow> - suspend fun getUserUploadCourse(): MutableList + suspend fun putDeleteHistory(requestDeleteHistory: RequestDeleteHistory): Flow> - suspend fun getUserProfile(userId: Int): Result + suspend fun deleteUser(): Flow> - suspend fun putDeleteUploadCourse( - requestDeleteUploadCourse: RequestDeleteUploadCourse - ): Result + suspend fun getRecord(): Flow>> - suspend fun putDeleteHistory(requestDeleteHistory: RequestDeleteHistory): Result + suspend fun getMyStamp(): Flow>> suspend fun patchHistoryTitle( historyId: Int, requestPatchHistoryTitle: RequestPatchHistoryTitle - ): Result + ): Flow> + + suspend fun updateNickName( + requestPatchNickName: RequestPatchNickName + ): Flow> - suspend fun deleteUser(): ResponseDeleteUser + suspend fun getUserProfile(userId: Int): Flow> } \ No newline at end of file diff --git a/app/src/main/java/com/runnect/runnect/presentation/detail/CourseDetailActivity.kt b/app/src/main/java/com/runnect/runnect/presentation/detail/CourseDetailActivity.kt index 4fde8a3e4..f2928c1a1 100644 --- a/app/src/main/java/com/runnect/runnect/presentation/detail/CourseDetailActivity.kt +++ b/app/src/main/java/com/runnect/runnect/presentation/detail/CourseDetailActivity.kt @@ -417,11 +417,17 @@ class CourseDetailActivity : applyScreenExitAnimation() } - private fun navigateToUserProfile() { - Intent(this@CourseDetailActivity, ProfileActivity::class.java).apply { - putExtra(EXTRA_COURSE_USER_ID, courseDetail.userId) - addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) - startActivity(this) + private fun setupFromDeepLinkObserver() { + viewModel.isDeepLinkLogin.observe(this) { result -> + // 딥링크로 진입했는데 로그인이 안 되어있는 경우 + if (!result) { + // CHECK 로그인 액티비티 이동시 Task 모두 제거하도록 수정 (확인 필요) + Intent(this, LoginActivity::class.java).apply { + addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK) + }.let(::startActivity) + + viewModel.isDeepLinkLogin.value = true + } } applyScreenEnterAnimation() Analytics.logClickedItemEvent(EVENT_CLICK_USER_PROFILE) @@ -528,7 +534,7 @@ class CourseDetailActivity : viewModel.courseScrapState.observe(this) { state -> when (state) { is UiStateV2.Success -> { - val response = state.data ?: return@observe + val response = state.data binding.tvCourseDetailScrapCount.text = response.scrapCount.toString() binding.ivCourseDetailScrap.isSelected = response.scrapTF } diff --git a/app/src/main/java/com/runnect/runnect/presentation/detail/CourseDetailViewModel.kt b/app/src/main/java/com/runnect/runnect/presentation/detail/CourseDetailViewModel.kt index 87636411e..c91ddfb39 100644 --- a/app/src/main/java/com/runnect/runnect/presentation/detail/CourseDetailViewModel.kt +++ b/app/src/main/java/com/runnect/runnect/presentation/detail/CourseDetailViewModel.kt @@ -2,29 +2,29 @@ package com.runnect.runnect.presentation.detail import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel import androidx.lifecycle.map -import androidx.lifecycle.viewModelScope import com.runnect.runnect.data.dto.request.RequestDeleteUploadCourse import com.runnect.runnect.data.dto.request.RequestPatchPublicCourse import com.runnect.runnect.data.dto.request.RequestPostCourseScrap import com.runnect.runnect.data.dto.response.ResponseDeleteUploadCourse -import com.runnect.runnect.data.dto.response.ResponsePostScrap +import com.runnect.runnect.domain.common.toLog import com.runnect.runnect.domain.entity.CourseDetail import com.runnect.runnect.domain.entity.EditableCourseDetail +import com.runnect.runnect.domain.entity.PostScrap import com.runnect.runnect.domain.repository.CourseRepository import com.runnect.runnect.domain.repository.UserRepository +import com.runnect.runnect.presentation.base.BaseViewModel import com.runnect.runnect.presentation.state.UiStateV2 +import com.runnect.runnect.util.extension.collectResult import com.runnect.runnect.util.mode.ScreenMode import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.launch -import retrofit2.HttpException +import kotlinx.coroutines.flow.onStart import javax.inject.Inject @HiltViewModel class CourseDetailViewModel @Inject constructor( private val courseRepository: CourseRepository, private val userRepository: UserRepository -) : ViewModel() { +) : BaseViewModel() { // 서버통신 코드 private val _courseGetState = MutableLiveData>() val courseGetState: LiveData> @@ -38,8 +38,8 @@ class CourseDetailViewModel @Inject constructor( val courseDeleteState: LiveData> get() = _courseDeleteState - private val _courseScrapState = MutableLiveData>() - val courseScrapState: LiveData> + private val _courseScrapState = MutableLiveData>() + val courseScrapState: LiveData> get() = _courseScrapState // 사용자가 수정할 수 있는 부분 (제목, 내용) @@ -75,66 +75,69 @@ class CourseDetailViewModel @Inject constructor( _currentScreenMode = mode } - fun getCourseDetail(courseId: Int) { - viewModelScope.launch { - _courseGetState.value = UiStateV2.Loading - - courseRepository.getCourseDetail( - publicCourseId = courseId - ).onSuccess { response -> - _courseGetState.value = UiStateV2.Success(response) - }.onFailure { exception -> - _courseGetState.value = UiStateV2.Failure(exception.message.toString()) + fun getCourseDetail(courseId: Int) = launchWithHandler { + courseRepository.getCourseDetail( + publicCourseId = courseId + ).collectResult( + onSuccess = { + _courseGetState.value = UiStateV2.Success(it) + }, + onFailure = { + _courseGetState.value = UiStateV2.Failure(it.toLog()) } - } + ) } - fun patchPublicCourse(id: Int) { - viewModelScope.launch { - _coursePatchState.value = UiStateV2.Loading - - val requestDto = RequestPatchPublicCourse( - title = title, - description = description - ) - - courseRepository.patchPublicCourse(id, requestDto) - .onSuccess { response -> - _coursePatchState.value = UiStateV2.Success(response) - }.onFailure { exception -> - _coursePatchState.value = UiStateV2.Failure(exception.message.toString()) + fun patchPublicCourse(id: Int) = launchWithHandler { + val requestDto = RequestPatchPublicCourse( + title = title, + description = description + ) + + courseRepository.patchPublicCourse(id, requestDto) + .onStart { + _coursePatchState.value = UiStateV2.Loading + }.collectResult( + onSuccess = { + _coursePatchState.value = UiStateV2.Success(it) + }, + onFailure = { + _coursePatchState.value = UiStateV2.Failure(it.toLog()) } - } + ) } - fun deleteUploadCourse(id: Int) { - viewModelScope.launch { + fun deleteUploadCourse(id: Int) = launchWithHandler { + userRepository.putDeleteUploadCourse( + RequestDeleteUploadCourse(publicCourseIdList = listOf(id)) + ).onStart { _courseDeleteState.value = UiStateV2.Loading - - userRepository.putDeleteUploadCourse( - RequestDeleteUploadCourse(publicCourseIdList = listOf(id)) - ).onSuccess { response -> - _courseDeleteState.value = UiStateV2.Success(response) - }.onFailure { exception -> - _courseDeleteState.value = UiStateV2.Failure(exception.message.toString()) + }.collectResult( + onSuccess = { + _courseDeleteState.value = UiStateV2.Success(it) + }, + onFailure = { + _courseDeleteState.value = UiStateV2.Failure(it.toLog()) } - } + ) } - fun postCourseScrap(id: Int, scrapTF: Boolean) { - viewModelScope.launch { - _courseScrapState.value = UiStateV2.Loading - - courseRepository.postCourseScrap( - RequestPostCourseScrap( - publicCourseId = id, scrapTF = scrapTF.toString() - ) - ).onSuccess { response -> - _courseScrapState.value = UiStateV2.Success(response) - }.onFailure { exception -> - _courseScrapState.value = UiStateV2.Failure(exception.message.toString()) - } - } + fun postCourseScrap(id: Int, scrapTF: Boolean) = launchWithHandler { + val requestPostCourseScrap = RequestPostCourseScrap( + publicCourseId = id, scrapTF = scrapTF.toString() + ) + + courseRepository.postCourseScrap(requestPostCourseScrap) + .onStart { + _courseScrapState.value = UiStateV2.Loading + }.collectResult( + onSuccess = { + _courseScrapState.value = UiStateV2.Success(it) + }, + onFailure = { + _courseScrapState.value = UiStateV2.Failure(it.toLog()) + } + ) } companion object { diff --git a/app/src/main/java/com/runnect/runnect/presentation/discover/DiscoverFragment.kt b/app/src/main/java/com/runnect/runnect/presentation/discover/DiscoverFragment.kt index fe7f0c749..ccfdf6edb 100644 --- a/app/src/main/java/com/runnect/runnect/presentation/discover/DiscoverFragment.kt +++ b/app/src/main/java/com/runnect/runnect/presentation/discover/DiscoverFragment.kt @@ -460,7 +460,7 @@ class DiscoverFragment : BindingFragment(R.layout.fragm viewModel.courseScrapState.observe(viewLifecycleOwner) { state -> when (state) { is UiStateV2.Success -> { - val response = state.data ?: return@observe + val response = state.data multiViewAdapter.updateCourseScrap( publicCourseId = response.publicCourseId.toInt(), scrap = response.scrapTF diff --git a/app/src/main/java/com/runnect/runnect/presentation/discover/DiscoverViewModel.kt b/app/src/main/java/com/runnect/runnect/presentation/discover/DiscoverViewModel.kt index 36f2f80e2..e53123701 100644 --- a/app/src/main/java/com/runnect/runnect/presentation/discover/DiscoverViewModel.kt +++ b/app/src/main/java/com/runnect/runnect/presentation/discover/DiscoverViewModel.kt @@ -4,14 +4,16 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope import com.runnect.runnect.data.dto.request.RequestPostCourseScrap -import com.runnect.runnect.data.dto.response.ResponsePostScrap import com.runnect.runnect.domain.common.toLog -import com.runnect.runnect.domain.entity.DiscoverMultiViewItem.* import com.runnect.runnect.domain.entity.DiscoverBanner +import com.runnect.runnect.domain.entity.PostScrap +import com.runnect.runnect.domain.entity.DiscoverMultiViewItem.MarathonCourse +import com.runnect.runnect.domain.entity.DiscoverMultiViewItem.RecommendCourse import com.runnect.runnect.domain.repository.BannerRepository import com.runnect.runnect.domain.repository.CourseRepository import com.runnect.runnect.presentation.base.BaseViewModel import com.runnect.runnect.presentation.state.UiStateV2 +import com.runnect.runnect.util.extension.collectResult import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.onStart @@ -44,8 +46,8 @@ class DiscoverViewModel @Inject constructor( val recommendCourseSortState: LiveData>> get() = _recommendCourseSortState - private val _courseScrapState = MutableLiveData>() - val courseScrapState: LiveData> + private val _courseScrapState = MutableLiveData>() + val courseScrapState: LiveData> get() = _courseScrapState private var _clickedCourseId = -1 @@ -98,35 +100,28 @@ class DiscoverViewModel @Inject constructor( } } - private fun getMarathonCourses() { - launchWithHandler { - courseRepository.getMarathonCourse() - .onStart { - _marathonCourseGetState.value = UiStateV2.Loading - }.collect { result -> - result.onSuccess { - _marathonCourseGetState.value = UiStateV2.Success(it) - }.onFailure { - _marathonCourseGetState.value = UiStateV2.Failure(it.toLog()) - } + private fun getMarathonCourses() = launchWithHandler { + courseRepository.getMarathonCourse() + .onStart { + _marathonCourseGetState.value = UiStateV2.Loading + }.collectResult( + onSuccess = { + _marathonCourseGetState.value = UiStateV2.Success(it) + }, + onFailure = { + _marathonCourseGetState.value = UiStateV2.Failure(it.toLog()) } - } + ) } - private fun getRecommendCourses() { - viewModelScope.launch { + private fun getRecommendCourses() = launchWithHandler { + courseRepository.getRecommendCourse( + pageNo = FIRST_PAGE_NUM.toString(), + sort = currentSortCriteria + ).onStart { _recommendCourseGetState.value = UiStateV2.Loading - - courseRepository.getRecommendCourse( - pageNo = FIRST_PAGE_NUM.toString(), - sort = currentSortCriteria - ).onSuccess { pagingData -> - if (pagingData == null) { - _recommendCourseGetState.value = - UiStateV2.Failure("RECOMMEND COURSE DATA IS NULL") - return@onSuccess - } - + }.collectResult( + onSuccess = { pagingData -> updateRecommendCoursePagingData( isEnd = pagingData.isEnd, pageNo = FIRST_PAGE_NUM @@ -134,94 +129,88 @@ class DiscoverViewModel @Inject constructor( _recommendCourseGetState.value = UiStateV2.Success(pagingData.recommendCourses) Timber.d("RECOMMEND COURSE GET SUCCESS") - - }.onFailure { exception -> - _recommendCourseGetState.value = UiStateV2.Failure(exception.message.toString()) + }, + onFailure = { + _recommendCourseGetState.value = UiStateV2.Failure(it.toLog()) Timber.e("RECOMMEND COURSE GET FAIL") } - } + ) } fun isNextPageLoading() = recommendCourseNextPageState.value is UiStateV2.Loading fun getRecommendCourseNextPage() { - viewModelScope.launch { - // 다음 페이지가 없으면 요청하지 않는다. - if (isRecommendCoursePageEnd) return@launch - - _recommendCourseNextPageState.value = UiStateV2.Loading + // 다음 페이지가 없으면 요청하지 않는다. + if (isRecommendCoursePageEnd) return + launchWithHandler { courseRepository.getRecommendCourse( pageNo = (currentPageNumber + 1).toString(), sort = currentSortCriteria - ) - .onSuccess { pagingData -> - if (pagingData == null) { - _recommendCourseNextPageState.value = - UiStateV2.Failure("RECOMMEND COURSE NEXT PAGE DATA IS NULL") - return@onSuccess - } - + ).onStart { + _recommendCourseNextPageState.value = UiStateV2.Loading + }.collectResult( + onSuccess = { pagingData -> updateRecommendCoursePagingData( isEnd = pagingData.isEnd, pageNo = currentPageNumber + 1 ) - _recommendCourseNextPageState.value = UiStateV2.Success(pagingData.recommendCourses) - Timber.d("RECOMMEND COURSE NEXT PAGE GET SUCCESS") - } - .onFailure { exception -> _recommendCourseNextPageState.value = - UiStateV2.Failure(exception.message.toString()) + UiStateV2.Success(pagingData.recommendCourses) + Timber.d("RECOMMEND COURSE NEXT PAGE GET SUCCESS") + }, + onFailure = { + _recommendCourseNextPageState.value = UiStateV2.Failure(it.toLog()) Timber.e("RECOMMEND COURSE NEXT PAGE GET FAIL") } + ) } } fun sortRecommendCourses(criteria: String) { updateRecommendCourseSortCriteria(criteria) - viewModelScope.launch { - _recommendCourseSortState.value = UiStateV2.Loading - + launchWithHandler { courseRepository.getRecommendCourse( pageNo = FIRST_PAGE_NUM.toString(), sort = currentSortCriteria - ).onSuccess { pagingData -> - if (pagingData == null) { - _recommendCourseSortState.value = - UiStateV2.Failure("RECOMMEND COURSE DATA IS NULL") - return@onSuccess - } - - updateRecommendCoursePagingData( - isEnd = pagingData.isEnd, - pageNo = FIRST_PAGE_NUM - ) + ).onStart { + _recommendCourseSortState.value = UiStateV2.Loading + }.collectResult( + onSuccess = { pagingData -> + updateRecommendCoursePagingData( + isEnd = pagingData.isEnd, + pageNo = FIRST_PAGE_NUM + ) - _recommendCourseSortState.value = UiStateV2.Success(pagingData.recommendCourses) - Timber.d("RECOMMEND COURSE SORT SUCCESS") - }.onFailure { exception -> - _recommendCourseSortState.value = UiStateV2.Failure(exception.message.toString()) - Timber.e("RECOMMEND COURSE SORT FAIL") - } + _recommendCourseSortState.value = UiStateV2.Success(pagingData.recommendCourses) + Timber.d("RECOMMEND COURSE SORT SUCCESS") + }, + onFailure = { + _recommendCourseSortState.value = UiStateV2.Failure(it.toLog()) + Timber.e("RECOMMEND COURSE SORT FAIL") + } + ) } } - fun postCourseScrap(id: Int, scrapTF: Boolean) { - viewModelScope.launch { - _courseScrapState.value = UiStateV2.Loading + fun postCourseScrap(id: Int, scrapTF: Boolean) = launchWithHandler { + val requestPostCourseScrap = RequestPostCourseScrap( + publicCourseId = id, scrapTF = scrapTF.toString() + ) - courseRepository.postCourseScrap( - RequestPostCourseScrap( - publicCourseId = id, scrapTF = scrapTF.toString() - ) - ).onSuccess { response -> - _courseScrapState.value = UiStateV2.Success(response) - }.onFailure { exception -> - _courseScrapState.value = UiStateV2.Failure(exception.message.toString()) - } - } + courseRepository.postCourseScrap(requestPostCourseScrap) + .onStart { + _courseScrapState.value = UiStateV2.Loading + }.collectResult( + onSuccess = { + _courseScrapState.value = UiStateV2.Success(it) + }, + onFailure = { + _courseScrapState.value = UiStateV2.Failure(it.toLog()) + } + ) } companion object { diff --git a/app/src/main/java/com/runnect/runnect/presentation/discover/adapter/multiview/DiscoverMultiViewAdapter.kt b/app/src/main/java/com/runnect/runnect/presentation/discover/adapter/multiview/DiscoverMultiViewAdapter.kt index 74c85b515..d4e52e6ff 100644 --- a/app/src/main/java/com/runnect/runnect/presentation/discover/adapter/multiview/DiscoverMultiViewAdapter.kt +++ b/app/src/main/java/com/runnect/runnect/presentation/discover/adapter/multiview/DiscoverMultiViewAdapter.kt @@ -72,6 +72,11 @@ class DiscoverMultiViewAdapter( val startPosition = getViewTypeStartPosition(viewType) if (startPosition >= 0) { notifyItemChanged(startPosition) + } else { + // Refresh 했을 때 코스 데이터를 비우는데 + // 빈데이터는 initItemViewTypes에서 사라지게 되므로 notify가 되지 않음 + // notify 되지 않은채로 데이터를 갱신하려고 하면 Inconsistency detected 예외 발생하여 추가 + notifyDataSetChanged() } } diff --git a/app/src/main/java/com/runnect/runnect/presentation/discover/pick/DiscoverPickViewModel.kt b/app/src/main/java/com/runnect/runnect/presentation/discover/pick/DiscoverPickViewModel.kt index 42217588b..f77938497 100644 --- a/app/src/main/java/com/runnect/runnect/presentation/discover/pick/DiscoverPickViewModel.kt +++ b/app/src/main/java/com/runnect/runnect/presentation/discover/pick/DiscoverPickViewModel.kt @@ -2,20 +2,21 @@ package com.runnect.runnect.presentation.discover.pick import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope +import com.runnect.runnect.domain.common.toLog import com.runnect.runnect.domain.entity.DiscoverUploadCourse import com.runnect.runnect.domain.repository.CourseRepository +import com.runnect.runnect.presentation.base.BaseViewModel import com.runnect.runnect.presentation.state.UiStateV2 +import com.runnect.runnect.util.extension.collectResult import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.launch +import kotlinx.coroutines.flow.onStart import timber.log.Timber import javax.inject.Inject @HiltViewModel class DiscoverPickViewModel @Inject constructor( private val courseRepository: CourseRepository -) : ViewModel() { +) : BaseViewModel() { private val _courseGetState = MutableLiveData?>>() val courseGetState: LiveData?>> get() = _courseGetState @@ -31,28 +32,23 @@ class DiscoverPickViewModel @Inject constructor( getMyCourseLoad() } - private fun getMyCourseLoad() { - viewModelScope.launch { - _courseGetState.value = UiStateV2.Loading - - courseRepository.getMyCourseLoad() - .onSuccess { response -> - if (response == null) { - _courseGetState.value = - UiStateV2.Failure("DISCOVER UPLOAD COURSE DATA IS NULL") - return@launch - } + private fun getMyCourseLoad() = launchWithHandler { + _courseGetState.value = UiStateV2.Loading + courseRepository.getMyCourseLoad() + .onStart { + _courseGetState.value = UiStateV2.Loading + }.collectResult( + onSuccess = { Timber.d("DISCOVER UPLOAD COURSE GET SUCCESS") - if (response.isEmpty()) _courseGetState.value = UiStateV2.Empty - else _courseGetState.value = UiStateV2.Success(response) - - }.onFailure { t -> + _courseGetState.value = if (it.isEmpty()) UiStateV2.Empty else UiStateV2.Success(it) + }, + onFailure = { Timber.e("DISCOVER UPLOAD COURSE GET FAIL") - Timber.e("${t.message}") - _courseGetState.value = UiStateV2.Failure(t.message.toString()) + Timber.e(it.toLog()) + _courseGetState.value = UiStateV2.Failure(it.toLog()) } - } + ) } fun updateCourseSelectState(isSelected: Boolean) { diff --git a/app/src/main/java/com/runnect/runnect/presentation/discover/search/DiscoverSearchActivity.kt b/app/src/main/java/com/runnect/runnect/presentation/discover/search/DiscoverSearchActivity.kt index 2df40aad2..be912d41a 100644 --- a/app/src/main/java/com/runnect/runnect/presentation/discover/search/DiscoverSearchActivity.kt +++ b/app/src/main/java/com/runnect/runnect/presentation/discover/search/DiscoverSearchActivity.kt @@ -207,7 +207,7 @@ class DiscoverSearchActivity : viewModel.courseScrapState.observe(this) { state -> when (state) { is UiStateV2.Success -> { - val response = state.data ?: return@observe + val response = state.data searchAdapter.updateCourseScrap( publicCourseId = response.publicCourseId.toInt(), scrap = response.scrapTF diff --git a/app/src/main/java/com/runnect/runnect/presentation/discover/search/DiscoverSearchViewModel.kt b/app/src/main/java/com/runnect/runnect/presentation/discover/search/DiscoverSearchViewModel.kt index 434cd670a..913edcdb4 100644 --- a/app/src/main/java/com/runnect/runnect/presentation/discover/search/DiscoverSearchViewModel.kt +++ b/app/src/main/java/com/runnect/runnect/presentation/discover/search/DiscoverSearchViewModel.kt @@ -2,27 +2,28 @@ package com.runnect.runnect.presentation.discover.search import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope import com.runnect.runnect.data.dto.request.RequestPostCourseScrap -import com.runnect.runnect.data.dto.response.ResponsePostScrap +import com.runnect.runnect.domain.common.toLog import com.runnect.runnect.domain.entity.DiscoverSearchCourse +import com.runnect.runnect.domain.entity.PostScrap import com.runnect.runnect.domain.repository.CourseRepository +import com.runnect.runnect.presentation.base.BaseViewModel import com.runnect.runnect.presentation.state.UiStateV2 +import com.runnect.runnect.util.extension.collectResult import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.launch +import kotlinx.coroutines.flow.onStart import javax.inject.Inject @HiltViewModel class DiscoverSearchViewModel @Inject constructor( private val courseRepository: CourseRepository -) : ViewModel() { +) : BaseViewModel() { private var _courseSearchState = MutableLiveData?>>() val courseSearchState: LiveData?>> get() = _courseSearchState - private val _courseScrapState = MutableLiveData>() - val courseScrapState: LiveData> + private val _courseScrapState = MutableLiveData>() + val courseScrapState: LiveData> get() = _courseScrapState private var _clickedCourseId = -1 @@ -32,41 +33,41 @@ class DiscoverSearchViewModel @Inject constructor( _clickedCourseId = id } - fun getCourseSearch(keyword: String) { - viewModelScope.launch { + fun getCourseSearch(keyword: String) = launchWithHandler { + courseRepository.getCourseSearch( + keyword = keyword + ).onStart { _courseSearchState.value = UiStateV2.Loading - - courseRepository.getCourseSearch( - keyword = keyword - ).onSuccess { response -> - if (response == null) return@launch - - if (response.isEmpty()) { + }.collectResult( + onSuccess = { + if (it.isEmpty()) { _courseSearchState.value = UiStateV2.Empty - return@launch + return@collectResult } - _courseSearchState.value = UiStateV2.Success(response) - }.onFailure { exception -> - _courseSearchState.value = UiStateV2.Failure(exception.message.toString()) + _courseSearchState.value = UiStateV2.Success(it) + }, + onFailure = { + _courseSearchState.value = UiStateV2.Failure(it.toLog()) } - } + ) } - fun postCourseScrap(id: Int, scrapTF: Boolean) { - viewModelScope.launch { - _courseScrapState.value = UiStateV2.Loading + fun postCourseScrap(id: Int, scrapTF: Boolean) = launchWithHandler { + val requestPostCourseScrap = RequestPostCourseScrap( + publicCourseId = id, scrapTF = scrapTF.toString() + ) - courseRepository.postCourseScrap( - RequestPostCourseScrap( - publicCourseId = id, scrapTF = scrapTF.toString() - ) - ).onSuccess { response -> - _courseScrapState.value = UiStateV2.Success(response) - } - .onFailure { exception -> - _courseScrapState.value = UiStateV2.Failure(exception.message.toString()) - } - } + courseRepository.postCourseScrap(requestPostCourseScrap) + .onStart { + _courseScrapState.value = UiStateV2.Loading + }.collectResult( + onSuccess = { + _courseScrapState.value = UiStateV2.Success(it) + }, + onFailure = { + _courseScrapState.value = UiStateV2.Failure(it.toLog()) + } + ) } } \ No newline at end of file diff --git a/app/src/main/java/com/runnect/runnect/presentation/discover/upload/DiscoverUploadViewModel.kt b/app/src/main/java/com/runnect/runnect/presentation/discover/upload/DiscoverUploadViewModel.kt index 32f4c6c44..3d218f072 100644 --- a/app/src/main/java/com/runnect/runnect/presentation/discover/upload/DiscoverUploadViewModel.kt +++ b/app/src/main/java/com/runnect/runnect/presentation/discover/upload/DiscoverUploadViewModel.kt @@ -3,20 +3,22 @@ package com.runnect.runnect.presentation.discover.upload import androidx.lifecycle.LiveData import androidx.lifecycle.MediatorLiveData import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope import com.runnect.runnect.data.dto.request.RequestPostPublicCourse +import com.runnect.runnect.domain.common.toLog import com.runnect.runnect.domain.repository.CourseRepository +import com.runnect.runnect.presentation.base.BaseViewModel import com.runnect.runnect.presentation.state.UiState import com.runnect.runnect.util.extension.addSourceList +import com.runnect.runnect.util.extension.collectResult import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.launch -import timber.log.Timber +import kotlinx.coroutines.flow.onStart import javax.inject.Inject @HiltViewModel -class DiscoverUploadViewModel @Inject constructor(private val courseRepository: CourseRepository) : - ViewModel() { +class DiscoverUploadViewModel @Inject constructor( + private val courseRepository: CourseRepository +) : BaseViewModel() { + var id = 0 val title = MutableLiveData() val desc = MutableLiveData() @@ -39,26 +41,24 @@ class DiscoverUploadViewModel @Inject constructor(private val courseRepository: return !(title.value.isNullOrEmpty() or desc.value.isNullOrEmpty()) } - fun postUploadMyCourse() { - viewModelScope.launch { - Timber.d("업로드 호출") - runCatching { + fun postUploadMyCourse() = launchWithHandler { + val requestPostPublicCourse = RequestPostPublicCourse( + courseId = id, + description = desc.value.toString(), + title = title.value.toString() + ) + + courseRepository.postUploadMyCourse(requestPostPublicCourse) + .onStart { _courseUpLoadState.value = UiState.Loading - courseRepository.postUploadMyCourse( - RequestPostPublicCourse( - courseId = id, - description = desc.value.toString(), - title = title.value.toString() - ) - ) - }.onSuccess { - Timber.d("업로드 성공") - _courseUpLoadState.value = UiState.Success - }.onFailure { - Timber.d("업로드 실패") - errorMessage.value = it.message - _courseUpLoadState.value = UiState.Failure - } - } + }.collectResult( + onSuccess = { + _courseUpLoadState.value = UiState.Success + }, + onFailure = { + errorMessage.value = it.toLog() + _courseUpLoadState.value = UiState.Failure + } + ) } } diff --git a/app/src/main/java/com/runnect/runnect/presentation/draw/DrawViewModel.kt b/app/src/main/java/com/runnect/runnect/presentation/draw/DrawViewModel.kt index c4fe4d421..149bb7869 100644 --- a/app/src/main/java/com/runnect/runnect/presentation/draw/DrawViewModel.kt +++ b/app/src/main/java/com/runnect/runnect/presentation/draw/DrawViewModel.kt @@ -1,28 +1,28 @@ package com.runnect.runnect.presentation.draw -import android.content.ContentValues import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import com.runnect.runnect.data.dto.LocationData import com.runnect.runnect.data.dto.SearchResultEntity import com.runnect.runnect.data.dto.UploadLatLng import com.runnect.runnect.data.dto.response.ResponsePostMyDrawCourse +import com.runnect.runnect.domain.common.toLog +import com.runnect.runnect.domain.entity.LocationData import com.runnect.runnect.domain.repository.CourseRepository import com.runnect.runnect.domain.repository.ReverseGeocodingRepository +import com.runnect.runnect.presentation.base.BaseViewModel import com.runnect.runnect.presentation.state.UiState +import com.runnect.runnect.util.extension.collectResult import com.runnect.runnect.util.multipart.ContentUriRequestBody import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.launch -import timber.log.Timber +import kotlinx.coroutines.flow.onStart import javax.inject.Inject +import kotlin.math.acos @HiltViewModel class DrawViewModel @Inject constructor( val courseRepository: CourseRepository, val reverseGeocodingRepository: ReverseGeocodingRepository -) : ViewModel() { +) : BaseViewModel() { private var _drawState = MutableLiveData(UiState.Empty) val drawState: LiveData @@ -60,82 +60,70 @@ class DrawViewModel @Inject constructor( deg2rad(lat2) ) * Math.cos(deg2rad(theta)) - dist = Math.acos(dist) + dist = acos(dist) dist = rad2deg(dist) - dist = dist * 60 * 1.1515 + dist *= 60 * 1.1515 if (unit === "kilometer") { - dist = dist * 1.609344 + dist *= 1.609344 } else if (unit === "meter") { - dist = dist * 1609.344 + dist *= 1609.344 } return dist } // This function converts decimal degrees to radians - fun deg2rad(deg: Double): Double { + private fun deg2rad(deg: Double): Double { return (deg * Math.PI / 180.0) } // This function converts radians to decimal degrees - fun rad2deg(rad: Double): Double { + private fun rad2deg(rad: Double): Double { return (rad * 180 / Math.PI) } - fun uploadCourse() { - viewModelScope.launch { - runCatching { + launchWithHandler { + courseRepository.uploadCourse( + image = _image.value!!.toFormData(), + data = CourseCreateRequestDto( + path = path.value ?: listOf( + UploadLatLng( + 37.52901832956373, + 126.9136196847032 + ) + ), + title = courseTitle, + distance = distanceSum.value!!, + departureAddress = departureAddress.value!!, + departureName = departureName.value!! + ).toRequestBody() + ).onStart { _drawState.value = UiState.Loading - courseRepository.uploadCourse( - image = _image.value!!.toFormData(), - data = CourseCreateRequestDto( - path = path.value ?: listOf( - UploadLatLng( - 37.52901832956373, - 126.9136196847032 - ) - ), - title = courseTitle, - distance = distanceSum.value!!, - departureAddress = departureAddress.value!!, - departureName = departureName.value!! - ).toRequestBody() - ) - }.onSuccess { - if (it.body() == null) { + }.collectResult( + onSuccess = { + uploadResult.value = it + _drawState.value = UiState.Success + }, + onFailure = { + errorMessage.value = it.message _drawState.value = UiState.Failure - return@onSuccess //추가 조치 필요 } - Timber.tag(ContentValues.TAG).d("통신success") - uploadResult.value = it.body() - _drawState.value = UiState.Success - }.onFailure { - Timber.tag(ContentValues.TAG).d("통신failure : ${it}") - errorMessage.value = it.message - _drawState.value = UiState.Failure - } + ) } + } - fun getLocationInfoUsingLatLng(lat: Double, lon: Double) { - viewModelScope.launch { - runCatching { - reverseGeocodingRepository.getLocationInfoUsingLatLng( - lat = lat, lon = lon - ) - }.onSuccess { - Timber.tag(ContentValues.TAG).d("통신success") + fun getLocationInfoUsingLatLng(lat: Double, lon: Double) = launchWithHandler { + reverseGeocodingRepository.getLocationInfoUsingLatLng( + lat = lat, lon = lon + ).collectResult( + onSuccess = { reverseGeocodingResult.value = it - }.onFailure { - Timber.tag(ContentValues.TAG).d("통신failure : ${it}") - errorMessage.value = it.message + }, + onFailure = { + errorMessage.value = it.toLog() } - } + ) } -} - - - - - +} \ No newline at end of file diff --git a/app/src/main/java/com/runnect/runnect/presentation/endrun/EndRunViewModel.kt b/app/src/main/java/com/runnect/runnect/presentation/endrun/EndRunViewModel.kt index a2ec89bb9..03ca0c344 100644 --- a/app/src/main/java/com/runnect/runnect/presentation/endrun/EndRunViewModel.kt +++ b/app/src/main/java/com/runnect/runnect/presentation/endrun/EndRunViewModel.kt @@ -3,19 +3,19 @@ package com.runnect.runnect.presentation.endrun import android.net.Uri import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope import com.runnect.runnect.data.dto.request.RequestPostRunningHistory import com.runnect.runnect.data.dto.response.ResponsePostMyHistory import com.runnect.runnect.domain.repository.CourseRepository +import com.runnect.runnect.presentation.base.BaseViewModel import com.runnect.runnect.presentation.state.UiState +import com.runnect.runnect.util.extension.collectResult import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.launch +import kotlinx.coroutines.flow.onStart import javax.inject.Inject @HiltViewModel class EndRunViewModel @Inject constructor(private val courseRepository: CourseRepository) : - ViewModel() { + BaseViewModel() { val distanceSum = MutableLiveData() val captureUri = MutableLiveData() @@ -34,29 +34,29 @@ class EndRunViewModel @Inject constructor(private val courseRepository: CourseRe val endRunState: LiveData get() = _endRunState - fun postRecord(request: RequestPostRunningHistory) { - viewModelScope.launch { - runCatching { - _endRunState.value = UiState.Loading - courseRepository.postRecord( - RequestPostRunningHistory( - courseId = request.courseId, - publicCourseId = request.publicCourseId, - title = request.title, - time = request.time, - pace = request.pace + launchWithHandler { + courseRepository.postRecord( + RequestPostRunningHistory( + courseId = request.courseId, + publicCourseId = request.publicCourseId, + title = request.title, + time = request.time, + pace = request.pace - ) ) - }.onSuccess { - uploadResult.value = it.body() - _endRunState.value = UiState.Success - }.onFailure { - errorMessage.value = it.message - _endRunState.value = UiState.Failure - } + ).onStart { + _endRunState.value = UiState.Loading + }.collectResult( + onSuccess = { + uploadResult.value = it + _endRunState.value = UiState.Success + }, + onFailure = { + errorMessage.value = it.message + _endRunState.value = UiState.Failure + } + ) } } - } \ No newline at end of file diff --git a/app/src/main/java/com/runnect/runnect/presentation/login/GiveNickNameViewModel.kt b/app/src/main/java/com/runnect/runnect/presentation/login/GiveNickNameViewModel.kt index 7d10d2fbb..4bc3915eb 100644 --- a/app/src/main/java/com/runnect/runnect/presentation/login/GiveNickNameViewModel.kt +++ b/app/src/main/java/com/runnect/runnect/presentation/login/GiveNickNameViewModel.kt @@ -2,18 +2,20 @@ package com.runnect.runnect.presentation.login import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope import com.runnect.runnect.data.dto.request.RequestPatchNickName import com.runnect.runnect.domain.repository.UserRepository +import com.runnect.runnect.presentation.base.BaseViewModel import com.runnect.runnect.presentation.state.UiState +import com.runnect.runnect.util.extension.collectResult import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.launch +import kotlinx.coroutines.flow.onStart import javax.inject.Inject @HiltViewModel -class GiveNickNameViewModel @Inject constructor(private val userRepository: UserRepository) : - ViewModel() { +class GiveNickNameViewModel @Inject constructor( + private val userRepository: UserRepository +) : BaseViewModel() { + val nickName = MutableLiveData() val uiState: LiveData get() = _uiState @@ -22,18 +24,21 @@ class GiveNickNameViewModel @Inject constructor(private val userRepository: User get() = _statusCode private val _statusCode = MutableLiveData() - fun updateNickName() { - viewModelScope.launch { - runCatching { + fun updateNickName() = launchWithHandler { + val requestPatchNickName = RequestPatchNickName(nickName.value.toString()) + + userRepository.updateNickName(requestPatchNickName) + .onStart { _uiState.value = UiState.Loading - userRepository.updateNickName(RequestPatchNickName(nickName.value.toString())) - }.onSuccess { - _uiState.value = UiState.Success - }.onFailure { - _statusCode.value = REDUNDANT_NICKNAME_ERROR - _uiState.value = UiState.Failure - } - } + }.collectResult( + onSuccess = { + _uiState.value = UiState.Success + }, + onFailure = { + _statusCode.value = REDUNDANT_NICKNAME_ERROR + _uiState.value = UiState.Failure + } + ) } companion object { diff --git a/app/src/main/java/com/runnect/runnect/presentation/login/LoginActivity.kt b/app/src/main/java/com/runnect/runnect/presentation/login/LoginActivity.kt index 210b29d8c..b72efcc02 100644 --- a/app/src/main/java/com/runnect/runnect/presentation/login/LoginActivity.kt +++ b/app/src/main/java/com/runnect/runnect/presentation/login/LoginActivity.kt @@ -15,6 +15,7 @@ import com.runnect.runnect.presentation.state.UiState import com.runnect.runnect.util.analytics.Analytics import com.runnect.runnect.util.analytics.EventName.EVENT_CLICK_VISITOR import com.runnect.runnect.util.analytics.EventName.EVENT_VIEW_SOCIAL_LOGIN +import com.runnect.runnect.util.extension.showSnackbar import com.runnect.runnect.util.extension.showToast import com.runnect.runnect.util.preference.AuthUtil.getAccessToken import com.runnect.runnect.util.preference.AuthUtil.saveToken @@ -105,6 +106,7 @@ class LoginActivity : } } viewModel.errorMessage.observe(this) { + showSnackbar(binding.root, it) Timber.tag(ContentValues.TAG).d("로그인 통신 실패: $it") } } diff --git a/app/src/main/java/com/runnect/runnect/presentation/login/LoginViewModel.kt b/app/src/main/java/com/runnect/runnect/presentation/login/LoginViewModel.kt index 986360b1a..020672f21 100644 --- a/app/src/main/java/com/runnect/runnect/presentation/login/LoginViewModel.kt +++ b/app/src/main/java/com/runnect/runnect/presentation/login/LoginViewModel.kt @@ -2,20 +2,21 @@ package com.runnect.runnect.presentation.login import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import com.runnect.runnect.data.dto.request.RequestPostLogin import com.runnect.runnect.data.dto.LoginDTO +import com.runnect.runnect.data.dto.request.RequestPostLogin +import com.runnect.runnect.domain.common.toLog import com.runnect.runnect.domain.repository.LoginRepository +import com.runnect.runnect.presentation.base.BaseViewModel import com.runnect.runnect.presentation.state.UiState +import com.runnect.runnect.util.extension.collectResult import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.launch +import kotlinx.coroutines.flow.onStart import javax.inject.Inject @HiltViewModel -class LoginViewModel @Inject constructor(private val loginRepository: LoginRepository) : - ViewModel() { - +class LoginViewModel @Inject constructor( + private val loginRepository: LoginRepository +) : BaseViewModel() { val loginResult = MutableLiveData() val errorMessage = MutableLiveData() @@ -24,25 +25,25 @@ class LoginViewModel @Inject constructor(private val loginRepository: LoginRepos val loginState: LiveData get() = _loginState + fun postLogin(request: RequestPostLogin, logEvent: (() -> Unit)? = null) = launchWithHandler { + val requestPostLogin = RequestPostLogin( + token = request.token, + provider = request.provider + ) - fun postLogin(request: RequestPostLogin, logEvent: (() -> Unit)? = null) { - viewModelScope.launch { - runCatching { + loginRepository.postLogin(requestPostLogin) + .onStart { _loginState.value = UiState.Loading - loginRepository.postLogin( - RequestPostLogin( - token = request.token, provider = request.provider - ) - ) - }.onSuccess { - loginResult.value = it - _loginState.value = UiState.Success - logEvent?.invoke() - }.onFailure { - errorMessage.value = it.message - _loginState.value = UiState.Failure - } - } + }.collectResult( + onSuccess = { + loginResult.value = it + _loginState.value = UiState.Success + logEvent?.invoke() + }, + onFailure = { + errorMessage.value = it.toLog() + _loginState.value = UiState.Failure + } + ) } - } \ No newline at end of file diff --git a/app/src/main/java/com/runnect/runnect/presentation/mypage/MyPageViewModel.kt b/app/src/main/java/com/runnect/runnect/presentation/mypage/MyPageViewModel.kt index 67ee11627..59b479761 100644 --- a/app/src/main/java/com/runnect/runnect/presentation/mypage/MyPageViewModel.kt +++ b/app/src/main/java/com/runnect/runnect/presentation/mypage/MyPageViewModel.kt @@ -2,18 +2,21 @@ package com.runnect.runnect.presentation.mypage import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope import com.runnect.runnect.R +import com.runnect.runnect.domain.common.toLog import com.runnect.runnect.domain.repository.UserRepository +import com.runnect.runnect.presentation.base.BaseViewModel import com.runnect.runnect.presentation.state.UiState +import com.runnect.runnect.util.extension.collectResult import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.launch +import kotlinx.coroutines.flow.onStart import javax.inject.Inject @HiltViewModel -class MyPageViewModel @Inject constructor(private val userRepository: UserRepository) : - ViewModel() { +class MyPageViewModel @Inject constructor( + private val userRepository: UserRepository +) : BaseViewModel() { + val nickName: MutableLiveData = MutableLiveData() val stampId: MutableLiveData = MutableLiveData(STAMP_LOCK) val profileImgResId: MutableLiveData = MutableLiveData(R.drawable.user_profile_basic) @@ -34,23 +37,27 @@ class MyPageViewModel @Inject constructor(private val userRepository: UserReposi this.profileImgResId.value = profileImgResId } - fun getUserInfo() { - viewModelScope.launch { - runCatching { + fun getUserInfo() = launchWithHandler { + userRepository.getUserInfo() + .onStart { _userInfoState.value = UiState.Loading - userRepository.getUserInfo() - }.onSuccess { - level.value = it.data.user.level.toString() - nickName.value = it.data.user.nickname - stampId.value = it.data.user.latestStamp - levelPercent.value = it.data.user.levelPercent - email.value = it.data.user.email - _userInfoState.value = UiState.Success - }.onFailure { - errorMessage.value = it.message - _userInfoState.value = UiState.Failure - } - } + }.collectResult( + onSuccess = { user -> + user.let { + level.value = it.level.toString() + nickName.value = it.nickname + stampId.value = it.latestStamp + levelPercent.value = it.levelPercent + email.value = it.email + } + + _userInfoState.value = UiState.Success + }, + onFailure = { + errorMessage.value = it.toLog() + _userInfoState.value = UiState.Failure + } + ) } companion object { diff --git a/app/src/main/java/com/runnect/runnect/presentation/mypage/editname/MyPageEditNameViewModel.kt b/app/src/main/java/com/runnect/runnect/presentation/mypage/editname/MyPageEditNameViewModel.kt index ce4a70edb..aa45685fa 100644 --- a/app/src/main/java/com/runnect/runnect/presentation/mypage/editname/MyPageEditNameViewModel.kt +++ b/app/src/main/java/com/runnect/runnect/presentation/mypage/editname/MyPageEditNameViewModel.kt @@ -2,19 +2,20 @@ package com.runnect.runnect.presentation.mypage.editname import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope import com.runnect.runnect.R import com.runnect.runnect.data.dto.request.RequestPatchNickName import com.runnect.runnect.domain.repository.UserRepository +import com.runnect.runnect.presentation.base.BaseViewModel import com.runnect.runnect.presentation.state.UiState +import com.runnect.runnect.util.extension.collectResult import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.launch +import kotlinx.coroutines.flow.onStart import javax.inject.Inject @HiltViewModel -class MyPageEditNameViewModel @Inject constructor(private val userRepository: UserRepository) : - ViewModel() { +class MyPageEditNameViewModel @Inject constructor( + private val userRepository: UserRepository +) : BaseViewModel() { val nickName = MutableLiveData() private val _uiState = MutableLiveData() @@ -35,22 +36,23 @@ class MyPageEditNameViewModel @Inject constructor(private val userRepository: Us this.profileImgResId.value = profileImgResId } - fun updateNickName() { - viewModelScope.launch { - runCatching { + fun updateNickName() = launchWithHandler { + val requestPatchNickName = RequestPatchNickName( + nickname = nickName.value.toString() + ) + + userRepository.updateNickName(requestPatchNickName) + .onStart { _uiState.value = UiState.Loading - userRepository.updateNickName( - RequestPatchNickName( - nickname = nickName.value.toString() - ) - ) - }.onSuccess { - _uiState.value = UiState.Success - }.onFailure { - _statusCode.value = REDUNDANT_NICKNAME_ERROR - _uiState.value = UiState.Failure - } - } + }.collectResult( + onSuccess = { + _uiState.value = UiState.Success + }, + onFailure = { + _uiState.value = UiState.Failure + _statusCode.value = REDUNDANT_NICKNAME_ERROR + } + ) } companion object { diff --git a/app/src/main/java/com/runnect/runnect/presentation/mypage/history/MyHistoryViewModel.kt b/app/src/main/java/com/runnect/runnect/presentation/mypage/history/MyHistoryViewModel.kt index 2cd098d51..cc6754904 100644 --- a/app/src/main/java/com/runnect/runnect/presentation/mypage/history/MyHistoryViewModel.kt +++ b/app/src/main/java/com/runnect/runnect/presentation/mypage/history/MyHistoryViewModel.kt @@ -2,19 +2,22 @@ package com.runnect.runnect.presentation.mypage.history import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope import com.runnect.runnect.data.dto.HistoryInfoDTO import com.runnect.runnect.data.dto.request.RequestDeleteHistory +import com.runnect.runnect.domain.common.toLog import com.runnect.runnect.domain.repository.UserRepository +import com.runnect.runnect.presentation.base.BaseViewModel import com.runnect.runnect.presentation.state.UiState +import com.runnect.runnect.util.extension.collectResult import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.launch +import kotlinx.coroutines.flow.onStart import javax.inject.Inject @HiltViewModel -class MyHistoryViewModel @Inject constructor(private val userRepository: UserRepository) : - ViewModel() { +class MyHistoryViewModel @Inject constructor( + private val userRepository: UserRepository +) : BaseViewModel() { + private var _historyState = MutableLiveData() val historyState: LiveData get() = _historyState @@ -63,51 +66,49 @@ class MyHistoryViewModel @Inject constructor(private val userRepository: UserRep _editMode.value = !_editMode.value!! } - fun getRecord() { - _historyState.value = UiState.Loading - _historyItems = mutableListOf() - viewModelScope.launch { - runCatching { + fun getRecord() = launchWithHandler { + userRepository.getRecord() + .onStart { + _historyItems.clear() _historyState.value = UiState.Loading - userRepository.getRecord() - }.onSuccess { - if (it.isEmpty()) { - _historyState.value = UiState.Empty - } else { - _historyItems = it - _historyState.value = UiState.Success + }.collectResult( + onSuccess = { + _historyItems = it.toMutableList() + _historyState.value = if (it.isEmpty()) UiState.Empty else UiState.Success + }, + onFailure = { + errorMessage.value = it.toLog() + _historyState.value = UiState.Failure } - }.onFailure { - errorMessage.value = it.message - _historyState.value = UiState.Failure - } - } + ) } - fun deleteHistory() { - viewModelScope.launch { - runCatching { - _historyDeleteState.value = UiState.Loading + fun deleteHistory() = launchWithHandler { + val requestDeleteHistory = RequestDeleteHistory( + recordIdList = _itemsToDelete + ) - userRepository.putDeleteHistory( - RequestDeleteHistory( - recordIdList = _itemsToDelete - ) - ) - }.onSuccess { - _historyItems = - _historyItems.filter { !itemsToDelete.contains(it.id) }.toMutableList() - _historyDeleteState.value = UiState.Success - //모든 기록 삭제 시, 편집 모드 취소 - if (_historyItems.isEmpty()) { - _historyState.value = UiState.Empty - convertMode() + userRepository.putDeleteHistory(requestDeleteHistory) + .onStart { + _historyDeleteState.value = UiState.Loading + }.collectResult( + onSuccess = { + _historyItems = _historyItems.filterNot { item -> + itemsToDelete.contains(item.id) + }.toMutableList() + _historyDeleteState.value = UiState.Success + + //모든 기록 삭제 시, 편집 모드 취소 + if (_historyItems.isEmpty()) { + _historyState.value = UiState.Empty + convertMode() + } + }, + onFailure = { + errorMessage.value = it.toLog() + _historyDeleteState.value = UiState.Failure } - }.onFailure { - errorMessage.value = it.message - _historyDeleteState.value = UiState.Failure - } - } + ) } companion object { diff --git a/app/src/main/java/com/runnect/runnect/presentation/mypage/history/detail/MyHistoryDetailViewModel.kt b/app/src/main/java/com/runnect/runnect/presentation/mypage/history/detail/MyHistoryDetailViewModel.kt index 583e77c7d..d2a13284c 100644 --- a/app/src/main/java/com/runnect/runnect/presentation/mypage/history/detail/MyHistoryDetailViewModel.kt +++ b/app/src/main/java/com/runnect/runnect/presentation/mypage/history/detail/MyHistoryDetailViewModel.kt @@ -2,23 +2,26 @@ package com.runnect.runnect.presentation.mypage.history.detail import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel import androidx.lifecycle.map -import androidx.lifecycle.viewModelScope import com.runnect.runnect.data.dto.request.RequestDeleteHistory import com.runnect.runnect.data.dto.request.RequestPatchHistoryTitle import com.runnect.runnect.data.dto.response.ResponseDeleteHistory import com.runnect.runnect.data.dto.response.ResponsePatchHistoryTitle +import com.runnect.runnect.domain.common.toLog import com.runnect.runnect.domain.repository.UserRepository +import com.runnect.runnect.presentation.base.BaseViewModel import com.runnect.runnect.presentation.state.UiStateV2 +import com.runnect.runnect.util.extension.collectResult import com.runnect.runnect.util.mode.ScreenMode import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.launch +import kotlinx.coroutines.flow.onStart import javax.inject.Inject @HiltViewModel -class MyHistoryDetailViewModel @Inject constructor(private val userRepository: UserRepository) : - ViewModel() { +class MyHistoryDetailViewModel @Inject constructor( + private val userRepository: UserRepository +) : BaseViewModel() { + private val _historyDeleteState = MutableLiveData>() val historyDeleteState: LiveData> @@ -59,32 +62,35 @@ class MyHistoryDetailViewModel @Inject constructor(private val userRepository: U _currentScreenMode = mode } - fun deleteHistory() { - viewModelScope.launch { - _historyDeleteState.value = UiStateV2.Loading - - val deleteItems = listOf(historyId) - userRepository.putDeleteHistory(RequestDeleteHistory(deleteItems)) - .onSuccess { response -> - _historyDeleteState.value = UiStateV2.Success(response) - }.onFailure { t -> - _historyDeleteState.value = UiStateV2.Failure(t.message.toString()) + fun deleteHistory() = launchWithHandler { + val requestDeleteHistory = RequestDeleteHistory(listOf(historyId)) + + userRepository.putDeleteHistory(requestDeleteHistory) + .onStart { + _historyDeleteState.value = UiStateV2.Loading + }.collectResult( + onSuccess = { + _historyDeleteState.value = UiStateV2.Success(it) + }, + onFailure = { + _historyDeleteState.value = UiStateV2.Failure(it.toLog()) } - } + ) } - fun patchHistoryTitle() { - viewModelScope.launch { + fun patchHistoryTitle() = launchWithHandler { + userRepository.patchHistoryTitle( + historyId = historyId, + requestPatchHistoryTitle = RequestPatchHistoryTitle(title) + ).onStart { _titlePatchState.value = UiStateV2.Loading - - userRepository.patchHistoryTitle( - historyId = historyId, - requestPatchHistoryTitle = RequestPatchHistoryTitle(title) - ).onSuccess { response -> - _titlePatchState.value = UiStateV2.Success(response) - }.onFailure { t -> - _titlePatchState.value = UiStateV2.Failure(t.message.toString()) + }.collectResult( + onSuccess = { + _titlePatchState.value = UiStateV2.Success(it) + }, + onFailure = { + _titlePatchState.value = UiStateV2.Failure(it.toLog()) } - } + ) } } diff --git a/app/src/main/java/com/runnect/runnect/presentation/mypage/reward/MyRewardViewModel.kt b/app/src/main/java/com/runnect/runnect/presentation/mypage/reward/MyRewardViewModel.kt index 2d86618ec..101a8d4b0 100644 --- a/app/src/main/java/com/runnect/runnect/presentation/mypage/reward/MyRewardViewModel.kt +++ b/app/src/main/java/com/runnect/runnect/presentation/mypage/reward/MyRewardViewModel.kt @@ -2,17 +2,19 @@ package com.runnect.runnect.presentation.mypage.reward import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope +import com.runnect.runnect.domain.common.toLog import com.runnect.runnect.domain.repository.UserRepository +import com.runnect.runnect.presentation.base.BaseViewModel import com.runnect.runnect.presentation.state.UiState +import com.runnect.runnect.util.extension.collectResult import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.launch +import kotlinx.coroutines.flow.onStart import javax.inject.Inject @HiltViewModel -class MyRewardViewModel @Inject constructor(private val userRepository: UserRepository) : - ViewModel() { +class MyRewardViewModel @Inject constructor( + private val userRepository: UserRepository +) : BaseViewModel() { private val _getStampListState = MutableLiveData(UiState.Loading) val getStampListState: LiveData @@ -22,18 +24,19 @@ class MyRewardViewModel @Inject constructor(private val userRepository: UserRepo val errorMessage = MutableLiveData() - fun getStampList() { - viewModelScope.launch { - runCatching { + fun getStampList() = launchWithHandler { + userRepository.getMyStamp() + .onStart { _getStampListState.value = UiState.Loading - userRepository.getMyStamp() - }.onSuccess { - stampList = it - _getStampListState.value = UiState.Success - }.onFailure { - errorMessage.value = it.message - _getStampListState.value = UiState.Failure - } - } + }.collectResult( + onSuccess = { + stampList = it.toMutableList() + _getStampListState.value = UiState.Success + }, + onFailure = { + errorMessage.value = it.toLog() + _getStampListState.value = UiState.Failure + } + ) } } \ No newline at end of file diff --git a/app/src/main/java/com/runnect/runnect/presentation/mypage/setting/accountinfo/MySettingAccountInfoFragment.kt b/app/src/main/java/com/runnect/runnect/presentation/mypage/setting/accountinfo/MySettingAccountInfoFragment.kt index 3996a1a10..12f8d7d94 100644 --- a/app/src/main/java/com/runnect/runnect/presentation/mypage/setting/accountinfo/MySettingAccountInfoFragment.kt +++ b/app/src/main/java/com/runnect/runnect/presentation/mypage/setting/accountinfo/MySettingAccountInfoFragment.kt @@ -169,7 +169,7 @@ class MySettingAccountInfoFragment : const val DESCRIPTION_LOGOUT = "로그아웃 하시겠어요?" const val DESCRIPTION_LOGOUT_YES = "네" const val DESCRIPTION_LOGOUT_NO = "아니오" - const val DESCRIPTION_WITHDRAWAL = "정말로 탈퇴하시겟어요?" + const val DESCRIPTION_WITHDRAWAL = "정말로 탈퇴하시겠어요?" const val DESCRIPTION_WITHDRAWAL_YES = "네" const val DESCRIPTION_WITHDRAWAL_NO = "아니오" } diff --git a/app/src/main/java/com/runnect/runnect/presentation/mypage/setting/accountinfo/MySettingAccountInfoViewModel.kt b/app/src/main/java/com/runnect/runnect/presentation/mypage/setting/accountinfo/MySettingAccountInfoViewModel.kt index ef6706e1a..bb1102bd6 100644 --- a/app/src/main/java/com/runnect/runnect/presentation/mypage/setting/accountinfo/MySettingAccountInfoViewModel.kt +++ b/app/src/main/java/com/runnect/runnect/presentation/mypage/setting/accountinfo/MySettingAccountInfoViewModel.kt @@ -2,33 +2,38 @@ package com.runnect.runnect.presentation.mypage.setting.accountinfo import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope +import com.runnect.runnect.domain.common.toLog import com.runnect.runnect.domain.repository.UserRepository +import com.runnect.runnect.presentation.base.BaseViewModel import com.runnect.runnect.presentation.state.UiState +import com.runnect.runnect.util.extension.collectResult import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.launch +import kotlinx.coroutines.flow.onStart import javax.inject.Inject @HiltViewModel -class MySettingAccountInfoViewModel @Inject constructor(private val userRepository: UserRepository) : - ViewModel() { +class MySettingAccountInfoViewModel @Inject constructor( + private val userRepository: UserRepository +) : BaseViewModel() { + private val _withdrawalState = MutableLiveData() val withdrawalState: LiveData get() = _withdrawalState + val errorMessage = MutableLiveData() - fun deleteUser() { - viewModelScope.launch { - runCatching { + fun deleteUser() = launchWithHandler { + userRepository.deleteUser() + .onStart { _withdrawalState.value = UiState.Loading - userRepository.deleteUser() - }.onSuccess { - _withdrawalState.value = UiState.Success - }.onFailure { - errorMessage.value = it.message - _withdrawalState.value = UiState.Failure - } - } + }.collectResult( + onSuccess = { + _withdrawalState.value = UiState.Success + }, + onFailure = { + errorMessage.value = it.toLog() + _withdrawalState.value = UiState.Failure + } + ) } } \ No newline at end of file diff --git a/app/src/main/java/com/runnect/runnect/presentation/mypage/upload/MyUploadActivity.kt b/app/src/main/java/com/runnect/runnect/presentation/mypage/upload/MyUploadActivity.kt index c6fe4e7c0..911a88bf3 100644 --- a/app/src/main/java/com/runnect/runnect/presentation/mypage/upload/MyUploadActivity.kt +++ b/app/src/main/java/com/runnect/runnect/presentation/mypage/upload/MyUploadActivity.kt @@ -29,6 +29,7 @@ import com.runnect.runnect.util.extension.getCompatibleParcelableExtra import com.runnect.runnect.util.extension.navigateToPreviousScreenWithAnimation import com.runnect.runnect.util.extension.setCustomDialog import com.runnect.runnect.util.extension.setDialogButtonClickListener +import com.runnect.runnect.util.extension.showSnackbar import dagger.hilt.android.AndroidEntryPoint import kotlinx.android.synthetic.main.custom_dialog_delete.btn_delete_no import kotlinx.android.synthetic.main.custom_dialog_delete.btn_delete_yes @@ -280,6 +281,14 @@ class MyUploadActivity : BindingActivity(R.layout.activ private fun handleUnsuccessfulUploadCall() { binding.indeterminateBar.isVisible = false + + // CHECK 에러시 동작 임의로 지정 (확인 필요) + binding.constMyPageUploadEditBar.isVisible = true + binding.svMyPageUpload.isVisible = true + viewModel.errorMessage.value?.let { + showSnackbar(binding.root, it) + } + Timber.tag(ContentValues.TAG).d("Failure : ${viewModel.errorMessage.value}") } diff --git a/app/src/main/java/com/runnect/runnect/presentation/mypage/upload/MyUploadViewModel.kt b/app/src/main/java/com/runnect/runnect/presentation/mypage/upload/MyUploadViewModel.kt index 4235d3192..6ce9ecb0c 100644 --- a/app/src/main/java/com/runnect/runnect/presentation/mypage/upload/MyUploadViewModel.kt +++ b/app/src/main/java/com/runnect/runnect/presentation/mypage/upload/MyUploadViewModel.kt @@ -3,19 +3,22 @@ package com.runnect.runnect.presentation.mypage.upload import androidx.lifecycle.LiveData import androidx.lifecycle.MediatorLiveData import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import com.runnect.runnect.data.dto.UserUploadCourseDTO import com.runnect.runnect.data.dto.request.RequestDeleteUploadCourse +import com.runnect.runnect.domain.common.toLog +import com.runnect.runnect.domain.entity.UserUploadCourse import com.runnect.runnect.domain.repository.UserRepository +import com.runnect.runnect.presentation.base.BaseViewModel import com.runnect.runnect.presentation.state.UiState +import com.runnect.runnect.util.extension.collectResult import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.launch +import kotlinx.coroutines.flow.onStart import javax.inject.Inject @HiltViewModel -class MyUploadViewModel @Inject constructor(private val userRepository: UserRepository) : - ViewModel() { +class MyUploadViewModel @Inject constructor( + private val userRepository: UserRepository +) : BaseViewModel() { + private var _myUploadCourseState = MutableLiveData() val myUploadCourseState: LiveData get() = _myUploadCourseState @@ -24,8 +27,8 @@ class MyUploadViewModel @Inject constructor(private val userRepository: UserRepo val myUploadDeleteState: LiveData get() = _myUploadDeleteState - private var _myUploadCourses = mutableListOf() - val myUploadCourses: List + private var _myUploadCourses = mutableListOf() + val myUploadCourses: List get() = _myUploadCourses val errorMessage = MutableLiveData() @@ -63,45 +66,45 @@ class MyUploadViewModel @Inject constructor(private val userRepository: UserRepo _selectedItemsCount.value = count } - fun getUserUploadCourse() { - viewModelScope.launch { - runCatching { + fun getUserUploadCourse() = launchWithHandler { + userRepository.getUserUploadCourse() + .onStart { _myUploadCourseState.value = UiState.Loading - userRepository.getUserUploadCourse() - }.onSuccess { - _myUploadCourses = it - if (_myUploadCourses.isEmpty()) { - _myUploadCourseState.value = UiState.Empty - } else { - _myUploadCourseState.value = UiState.Success + }.collectResult( + onSuccess = { + _myUploadCourses = it.toMutableList() + _myUploadCourseState.value = if (it.isEmpty()) UiState.Empty else UiState.Success + }, + onFailure = { + errorMessage.value = it.toLog() + _myUploadCourseState.value = UiState.Failure } - }.onFailure { - errorMessage.value = it.message - _myUploadCourseState.value = UiState.Failure - } - } + ) } - fun deleteUploadCourse() { - viewModelScope.launch { - runCatching { + fun deleteUploadCourse() = launchWithHandler { + val requestDeleteUploadCourse = RequestDeleteUploadCourse(_itemsToDelete) + + userRepository.putDeleteUploadCourse(requestDeleteUploadCourse) + .onStart { _myUploadDeleteState.value = UiState.Loading setSelectedItemsCount(DEFAULT_SELECTED_COUNT) - userRepository.putDeleteUploadCourse(RequestDeleteUploadCourse(_itemsToDelete)) - }.onSuccess { - _myUploadCourses = - _myUploadCourses.filter { !itemsToDelete.contains(it.id) }.toMutableList() - _myUploadDeleteState.value = UiState.Success - //모든 기록 삭제 시, 편집 모드 -> 읽기 모드 - if (_myUploadCourses.isEmpty()) { - _myUploadCourseState.value = UiState.Empty - convertMode() + }.collectResult( + onSuccess = { + _myUploadCourses.removeAll { it.id in itemsToDelete } + _myUploadDeleteState.value = UiState.Success + + //모든 기록 삭제 시, 편집 모드 -> 읽기 모드 + if (_myUploadCourses.isEmpty()) { + _myUploadCourseState.value = UiState.Empty + convertMode() + } + }, + onFailure = { + errorMessage.value = it.toLog() + _myUploadDeleteState.value = UiState.Failure } - }.onFailure { - errorMessage.value = it.message - _myUploadDeleteState.value = UiState.Failure - } - } + ) } diff --git a/app/src/main/java/com/runnect/runnect/presentation/mypage/upload/adapter/MyUploadAdapter.kt b/app/src/main/java/com/runnect/runnect/presentation/mypage/upload/adapter/MyUploadAdapter.kt index 65e4b141b..d9441f41b 100644 --- a/app/src/main/java/com/runnect/runnect/presentation/mypage/upload/adapter/MyUploadAdapter.kt +++ b/app/src/main/java/com/runnect/runnect/presentation/mypage/upload/adapter/MyUploadAdapter.kt @@ -8,15 +8,15 @@ import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView import com.bumptech.glide.Glide import com.bumptech.glide.load.DecodeFormat -import com.runnect.runnect.data.dto.UserUploadCourseDTO import com.runnect.runnect.databinding.ItemMypageUploadBinding +import com.runnect.runnect.domain.entity.UserUploadCourse import com.runnect.runnect.presentation.discover.model.EditableDiscoverCourse import com.runnect.runnect.util.callback.diff.ItemDiffCallback import com.runnect.runnect.util.callback.listener.OnMyUploadItemClick class MyUploadAdapter( private val onMyUploadItemClick: OnMyUploadItemClick -) : ListAdapter(diffUtil) { +) : ListAdapter(diffUtil) { private var selectedItems: MutableList? = mutableListOf() private var selectedBoxes: MutableList? = mutableListOf() @@ -60,7 +60,7 @@ class MyUploadAdapter( inner class MyUploadViewHolder(private val binding: ItemMypageUploadBinding) : RecyclerView.ViewHolder(binding.root) { - fun onBind(data: UserUploadCourseDTO) { + fun onBind(data: UserUploadCourse) { with(binding) { selectedBoxes?.add(ivCheckbox) @@ -104,7 +104,7 @@ class MyUploadAdapter( } companion object { - private val diffUtil = ItemDiffCallback( + private val diffUtil = ItemDiffCallback( onItemsTheSame = { old, new -> old.id == new.id }, onContentsTheSame = { old, new -> old == new } ) diff --git a/app/src/main/java/com/runnect/runnect/presentation/profile/ProfileActivity.kt b/app/src/main/java/com/runnect/runnect/presentation/profile/ProfileActivity.kt index ff8546b7b..035ecc883 100644 --- a/app/src/main/java/com/runnect/runnect/presentation/profile/ProfileActivity.kt +++ b/app/src/main/java/com/runnect/runnect/presentation/profile/ProfileActivity.kt @@ -113,12 +113,11 @@ class ProfileActivity : BindingActivity(R.layout.activit } is UiStateV2.Success -> { - state.data?.let { it -> - adapter.updateCourseItem( - courseId = it.publicCourseId.toInt(), - scrapTF = it.scrapTF - ) - } + val postScrap = state.data + adapter.updateCourseItem( + courseId = postScrap.publicCourseId.toInt(), + scrapTF = postScrap.scrapTF + ) } is UiStateV2.Failure -> { diff --git a/app/src/main/java/com/runnect/runnect/presentation/profile/ProfileViewModel.kt b/app/src/main/java/com/runnect/runnect/presentation/profile/ProfileViewModel.kt index b518cc418..65a9e8d23 100644 --- a/app/src/main/java/com/runnect/runnect/presentation/profile/ProfileViewModel.kt +++ b/app/src/main/java/com/runnect/runnect/presentation/profile/ProfileViewModel.kt @@ -2,16 +2,17 @@ package com.runnect.runnect.presentation.profile import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope import com.runnect.runnect.data.dto.request.RequestPostCourseScrap -import com.runnect.runnect.data.dto.response.ResponsePostScrap +import com.runnect.runnect.domain.common.toLog +import com.runnect.runnect.domain.entity.PostScrap import com.runnect.runnect.domain.entity.UserProfile import com.runnect.runnect.domain.repository.CourseRepository import com.runnect.runnect.domain.repository.UserRepository +import com.runnect.runnect.presentation.base.BaseViewModel import com.runnect.runnect.presentation.state.UiStateV2 +import com.runnect.runnect.util.extension.collectResult import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.launch +import kotlinx.coroutines.flow.onStart import timber.log.Timber import javax.inject.Inject @@ -19,11 +20,10 @@ import javax.inject.Inject class ProfileViewModel @Inject constructor( private val userRepository: UserRepository, private val courseRepository: CourseRepository -) : - ViewModel() { +) : BaseViewModel() { - private val _courseScrapState = MutableLiveData>() - val courseScrapState: LiveData> + private val _courseScrapState = MutableLiveData>() + val courseScrapState: LiveData> get() = _courseScrapState private val _userProfileState = MutableLiveData>() @@ -31,42 +31,39 @@ class ProfileViewModel @Inject constructor( get() = _userProfileState - fun getUserProfile(userId: Int) { - viewModelScope.launch { - _userProfileState.value = UiStateV2.Loading - - userRepository.getUserProfile(userId = userId) - .onSuccess { profileData -> - if (profileData == null) { - _userProfileState.value = UiStateV2.Failure("PROFILE DATA IS NULL") - Timber.d("PROFILE DATA IS NULL") - return@launch - } - _userProfileState.value = UiStateV2.Success(profileData) - Timber.d("GET PROFILE DATA SUCCESS") - } - .onFailure { error -> - _userProfileState.value = UiStateV2.Failure(error.message.toString()) - Timber.e("GET PROFILE DATA FAILURE") + fun getUserProfile(userId: Int) = launchWithHandler { + userRepository.getUserProfile(userId) + .onStart { + _userProfileState.value = UiStateV2.Loading + }.collectResult( + onSuccess = { + _userProfileState.value = UiStateV2.Success(it) + }, + onFailure = { + _userProfileState.value = UiStateV2.Failure(it.toLog()) } - } + ) } - fun postCourseScrap(courseId: Int, scrapTF: Boolean) { - viewModelScope.launch { - _courseScrapState.value = UiStateV2.Loading - courseRepository.postCourseScrap( - RequestPostCourseScrap( - publicCourseId = courseId, scrapTF = scrapTF.toString() - ) - ).onSuccess { response -> - Timber.d("POST COURSE SCRAP SUCCESS") - _courseScrapState.value = UiStateV2.Success(response) - }.onFailure { exception -> - Timber.e("POST COURSE SCRAP FAILURE") - _courseScrapState.value = UiStateV2.Failure(exception.message.toString()) - } - } + fun postCourseScrap(courseId: Int, scrapTF: Boolean) = launchWithHandler { + val requestPostCourseScrap = RequestPostCourseScrap( + publicCourseId = courseId, + scrapTF = scrapTF.toString() + ) + + courseRepository.postCourseScrap(requestPostCourseScrap) + .onStart { + _courseScrapState.value = UiStateV2.Loading + }.collectResult( + onSuccess = { + Timber.d("POST COURSE SCRAP SUCCESS") + _courseScrapState.value = UiStateV2.Success(it) + }, + onFailure = { + Timber.e("POST COURSE SCRAP FAILURE") + _courseScrapState.value = UiStateV2.Failure(it.toLog()) + } + ) } } diff --git a/app/src/main/java/com/runnect/runnect/presentation/search/SearchViewModel.kt b/app/src/main/java/com/runnect/runnect/presentation/search/SearchViewModel.kt index 4477de9dd..8f65511c7 100644 --- a/app/src/main/java/com/runnect/runnect/presentation/search/SearchViewModel.kt +++ b/app/src/main/java/com/runnect/runnect/presentation/search/SearchViewModel.kt @@ -1,21 +1,20 @@ package com.runnect.runnect.presentation.search -import android.content.ContentValues import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope import com.runnect.runnect.data.dto.SearchResultEntity import com.runnect.runnect.domain.repository.DepartureSearchRepository +import com.runnect.runnect.presentation.base.BaseViewModel import com.runnect.runnect.presentation.state.UiState +import com.runnect.runnect.util.extension.collectResult import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.launch -import timber.log.Timber +import kotlinx.coroutines.flow.onStart import javax.inject.Inject @HiltViewModel -class SearchViewModel @Inject constructor(private val departureSearchRepository: DepartureSearchRepository) : - ViewModel() { +class SearchViewModel @Inject constructor( + private val departureSearchRepository: DepartureSearchRepository +) : BaseViewModel() { val searchError = MutableLiveData() @@ -25,26 +24,20 @@ class SearchViewModel @Inject constructor(private val departureSearchRepository: val searchState: LiveData get() = _searchState - - fun getSearchList(searchKeyword: String) { - viewModelScope.launch { - runCatching { - _searchState.value = UiState.Loading - departureSearchRepository.getSearchList(keyword = searchKeyword) - }.onSuccess { - if (it != null) { - dataList.value = it - Timber.tag(ContentValues.TAG) - .d("SuccessNotNull : getSearchList body is not null") - } else { - dataList.value = null - Timber.tag(ContentValues.TAG).d("SuccessButNull : getSearchList body is null") - } + fun getSearchList(searchKeyword: String) = launchWithHandler { + departureSearchRepository.getSearchList( + keyword = searchKeyword + ).onStart { + _searchState.value = UiState.Loading + }.collectResult( + onSuccess = { + dataList.value = it _searchState.value = UiState.Success - }.onFailure { + }, + onFailure = { searchError.value = it.message _searchState.value = UiState.Failure } - } + ) } } \ No newline at end of file diff --git a/app/src/main/java/com/runnect/runnect/presentation/search/adapter/SearchAdapter.kt b/app/src/main/java/com/runnect/runnect/presentation/search/adapter/SearchAdapter.kt index 3609b27f5..7054d0bc2 100644 --- a/app/src/main/java/com/runnect/runnect/presentation/search/adapter/SearchAdapter.kt +++ b/app/src/main/java/com/runnect/runnect/presentation/search/adapter/SearchAdapter.kt @@ -2,11 +2,9 @@ package com.runnect.runnect.presentation.search.adapter import android.view.LayoutInflater import android.view.ViewGroup -import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView import com.runnect.runnect.data.dto.SearchResultEntity -import com.runnect.runnect.data.dto.UserUploadCourseDTO import com.runnect.runnect.databinding.ItemSearchBinding import com.runnect.runnect.util.callback.diff.ItemDiffCallback import com.runnect.runnect.util.callback.listener.OnSearchItemClick diff --git a/app/src/main/java/com/runnect/runnect/presentation/storage/StorageViewModel.kt b/app/src/main/java/com/runnect/runnect/presentation/storage/StorageViewModel.kt index 7032e9363..3e8d425b2 100644 --- a/app/src/main/java/com/runnect/runnect/presentation/storage/StorageViewModel.kt +++ b/app/src/main/java/com/runnect/runnect/presentation/storage/StorageViewModel.kt @@ -1,22 +1,21 @@ package com.runnect.runnect.presentation.storage -import android.content.ContentValues import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import com.runnect.runnect.domain.entity.MyScrapCourse import com.runnect.runnect.data.dto.request.RequestPostCourseScrap import com.runnect.runnect.data.dto.request.RequestPutMyDrawCourse -import com.runnect.runnect.data.dto.response.ResponsePostScrap +import com.runnect.runnect.domain.common.toLog import com.runnect.runnect.domain.entity.MyDrawCourse -import com.runnect.runnect.domain.entity.MyDrawCourseDetail +import com.runnect.runnect.domain.entity.MyScrapCourse +import com.runnect.runnect.domain.entity.PostScrap import com.runnect.runnect.domain.repository.CourseRepository import com.runnect.runnect.domain.repository.StorageRepository +import com.runnect.runnect.presentation.base.BaseViewModel import com.runnect.runnect.presentation.state.UiState import com.runnect.runnect.presentation.state.UiStateV2 +import com.runnect.runnect.util.extension.collectResult import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.launch +import kotlinx.coroutines.flow.onStart import timber.log.Timber import javax.inject.Inject @@ -24,7 +23,8 @@ import javax.inject.Inject class StorageViewModel @Inject constructor( private val storageRepository: StorageRepository, private val courseRepository: CourseRepository -) : ViewModel() { +) : BaseViewModel() { + private val _myDrawCourseGetState = MutableLiveData(UiState.Empty) val myDrawCourseGetState: LiveData get() = _myDrawCourseGetState @@ -41,8 +41,8 @@ class StorageViewModel @Inject constructor( val myScrapCourseGetState: LiveData>?> get() = _myScrapCourseGetState - private val _courseScrapState = MutableLiveData>() - val courseScrapState: LiveData> + private val _courseScrapState = MutableLiveData>() + val courseScrapState: LiveData> get() = _courseScrapState val errorMessage = MutableLiveData() @@ -55,86 +55,73 @@ class StorageViewModel @Inject constructor( private var _clickedCourseId = -1 val clickedCourseId get() = _clickedCourseId - fun getMyDrawList() { - viewModelScope.launch { - runCatching { - _myDrawCourseGetState.value = UiState.Loading - storageRepository.getMyDrawCourse() - }.onSuccess { - _myDrawCourses = (it.getOrNull() ?: emptyList()).toMutableList() - Timber.tag(ContentValues.TAG).d("데이터 수신 완료") + fun getMyDrawList() = launchWithHandler { + storageRepository.getMyDrawCourse().onStart { + _myDrawCourseGetState.value = UiState.Loading + }.collectResult( + onSuccess = { + _myDrawCourses = it.toMutableList() _myDrawCourseGetState.value = UiState.Success - }.onFailure { - Timber.tag(ContentValues.TAG).d("onFailure 메세지 : $it") + }, + onFailure = { errorMessage.value = it.message _myDrawCourseGetState.value = UiState.Failure } - } + ) } - fun deleteMyDrawCourse() { - viewModelScope.launch { - runCatching { - _myDrawCourseDeleteState.value = UiState.Loading - storageRepository.deleteMyDrawCourse( - RequestPutMyDrawCourse( - courseIdList = itemsToDelete - ) - ) - }.onSuccess { - Timber.tag(ContentValues.TAG).d("삭제 성공입니다") - _myDrawCourses = - _myDrawCourses.filter { !itemsToDelete.contains(it.courseId) }.toMutableList() + fun deleteMyDrawCourse() = launchWithHandler { + storageRepository.deleteMyDrawCourse( + RequestPutMyDrawCourse( + courseIdList = itemsToDelete + ) + ).onStart { + _myDrawCourseDeleteState.value = UiState.Loading + }.collectResult( + onSuccess = { + _myDrawCourses = _myDrawCourses.filter { + !itemsToDelete.contains(it.courseId) + }.toMutableList() _myDrawCourseDeleteState.value = UiState.Success - - }.onFailure { - Timber.tag(ContentValues.TAG).d("실패했고 문제는 다음과 같습니다 $it") + }, + onFailure = { _myDrawCourseDeleteState.value = UiState.Failure } - } + ) } - fun getMyScrapCourses() { - viewModelScope.launch { + fun getMyScrapCourses() = launchWithHandler { + storageRepository.getMyScrapCourse().onStart { _myScrapCourseGetState.value = UiStateV2.Loading - - storageRepository.getMyScrapCourse() - .onSuccess { response -> - if (response == null) { - _myScrapCourseGetState.value = - UiStateV2.Failure("MY SCRAP COURSE DATA IS NULL") - return@launch - } - - Timber.d("MY SCRAP COURSE GET SUCCESS") - _myScrapCourseGetState.value = UiStateV2.Success(response) - itemSize.value = response.size - } - .onFailure { t -> - Timber.e("MY SCRAP COURSE GET FAIL") - Timber.e("${t.message}") - _myScrapCourseGetState.value = UiStateV2.Failure(t.message.toString()) - } - } + }.collectResult( + onSuccess = { + _myScrapCourseGetState.value = UiStateV2.Success(it) + itemSize.value = it.size + }, + onFailure = { + Timber.e("${it.message}") + _myScrapCourseGetState.value = UiStateV2.Failure(it.message.toString()) + } + ) } - fun postCourseScrap(id: Int, scrapTF: Boolean) { - viewModelScope.launch { - _courseScrapState.value = UiStateV2.Loading - - courseRepository.postCourseScrap( - RequestPostCourseScrap( - publicCourseId = id, scrapTF = scrapTF.toString() - ) - ) - .onSuccess { response -> - _courseScrapState.value = UiStateV2.Success(response) - } - .onFailure { t -> - Timber.e("${t.message}") - _courseScrapState.value = UiStateV2.Failure(t.message.toString()) + fun postCourseScrap(id: Int, scrapTF: Boolean) = launchWithHandler { + val requestPostCourseScrap = RequestPostCourseScrap( + publicCourseId = id, scrapTF = scrapTF.toString() + ) + + courseRepository.postCourseScrap(requestPostCourseScrap) + .onStart { + _courseScrapState.value = UiStateV2.Loading + }.collectResult( + onSuccess = { + _courseScrapState.value = UiStateV2.Success(it) + }, + onFailure = { + Timber.e(it.toLog()) + _courseScrapState.value = UiStateV2.Failure(it.toLog()) } - } + ) } fun modifyItemsToDelete(id: Int) { diff --git a/app/src/main/java/com/runnect/runnect/util/extension/ResponseExt.kt b/app/src/main/java/com/runnect/runnect/util/extension/ResponseExt.kt deleted file mode 100644 index 322069114..000000000 --- a/app/src/main/java/com/runnect/runnect/util/extension/ResponseExt.kt +++ /dev/null @@ -1,57 +0,0 @@ -package com.runnect.runnect.util.extension - -import com.runnect.runnect.data.dto.* -import com.runnect.runnect.data.dto.response.* - -fun Record.toData(): HistoryInfoDTO { - return HistoryInfoDTO( - id = id, - img = image, - title = title, - location = departure.region + ' ' + departure.city, - date = (createdAt.split(" ")[0]).replace("-", "."), - distance = distance.toString(), - time = timeConvert(time), - pace = paceConvert(pace) - ) -} - -fun PublicCourseUpload.toData(): UserUploadCourseDTO { - return UserUploadCourseDTO( - id = id, title = title, img = image, departure = departure.region + ' ' + departure.city - ) -} - -fun ResponsePostLogin.toData(): LoginDTO { - with(this.data) { - return LoginDTO( - status = status, - accessToken = accessToken, - refreshToken = refreshToken, - email = email, - type = type - ) - } - -} - -private fun timeConvert(time: String): String { - val hms = time.split(":").toMutableList() - if (hms[0] == "00") { - hms[0] = "0" - } - return "${hms[0]}:${hms[1]}:${hms[2]}" -} - -private fun paceConvert(p: String): String { - val pace = p.split(":").toMutableList() - return if (pace[0] == "00") { - pace.removeAt(0) - if (pace[0][0] == '0') { - pace[0] = pace[0][1].toString() - } - "${pace[0]}’${pace[1]}”" - } else { - "${pace[0]}’${pace[1]}”${pace[2]}”" - } -} \ No newline at end of file