Skip to content
Open
12 changes: 11 additions & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ plugins {
alias(libs.plugins.jetbrains.kotlin.android)
id ("kotlin-kapt")
id("kotlin-parcelize")
id("com.google.devtools.ksp")
id("com.google.dagger.hilt.android")
}

android {
Expand Down Expand Up @@ -100,4 +102,12 @@ dependencies {

// glide
implementation(libs.glide)
}

// hilt
implementation(libs.hilt.android)
ksp(libs.hilt.android.compiler)

implementation(libs.androidx.lifecycle.viewmodel.ktx.v291)
implementation(libs.androidx.lifecycle.livedata.ktx)
implementation(libs.androidx.fragment.ktx)
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@ import retrofit2.http.PUT
import retrofit2.http.Path
import retrofit2.http.Query

interface patApi {
// TODO 대문자, API보단 Service 라는 표현이 더 바람직해보임

// kotlin 공식 coding convention
// - 클래스와 객체의 이름은 대문자 카멜 표기법을 사용합니다.
interface PatPatService {

@POST("api/v1/login")
suspend fun postLogin(@Body loginRequest: LoginRequest): Response<LoginResponse>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,30 @@ package com.simply407.patpat.data.api
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory

// TODO object keyword로 선언하면 어떤일이 발생할까??
// TODO eager vs lazy

// object
// - 싱글톤 패턴을 구현할 때 사용
// - 해당 object가 처음 접근될 때 지연 초기화(lazy initialization)됩니다

// Eager Initialization (즉시 초기화)
// - 프로그램 시작 시 또는 클래스가 로드될 때 바로 인스턴스를 생성하는 방식
// - 장점: 인스턴스가 항상 준비되어 있어 접근 시 지연이 없습니다
// - 단점: 사용되지 않을 수도 있는 인스턴스에 대해 미리 자원을 할당하게 됩니다

object RetrofitInstance {
private const val BASE_URL = "https://oognuyh.asuscomm.com/"

private val client = Retrofit
val client: Retrofit = Retrofit
.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()

// TODO client의 선언을 val로 하면 되면 좋지 않을까??
fun getInstance(): Retrofit {
return client
}

}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
package com.simply407.patpat.data.model

data class CounselorMbtiInfo(val name: String, val mbtiList: List<String>)

object MBTIRepository {
val CounselorMbtiDataList = listOf(
CounselorMbtiInfo("복남이", listOf("INFJ", "INFP", "ENFJ", "ENFP")),
CounselorMbtiInfo("닥터 냉철한", listOf("INTJ", "INTP", "ENTJ", "ENTP")),
CounselorMbtiInfo("곽두팔", listOf("ISTJ", "ISTP", "ESTJ", "ESTP")),
CounselorMbtiInfo("코코", listOf("ISFJ", "ISFP", "ESFJ", "ESFP"))
)
}
data class CounselorMbtiInfo(
val name: String,
val mbtiList: List<String>
)
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,36 @@ package com.simply407.patpat.data.model
import android.os.Parcelable
import kotlinx.parcelize.Parcelize

// TODO API data class 와 UI data class는 분리하는게 좋다. isLiked는 api에서 처리?
// TODO isLiked 는 var로 해야하나? val로 선언하는 방법은? mutable vs immutable

// API data class 와 UI data class는 분리하는게 좋다
// - 관심사 분리
// - 유지보수 하기 좋다

// API 응답은 Immutable하게 val로 받는 것이 일반적

// CreateLetterResponse -> LetterResponse 이라는 이름이 더 좋음
@Parcelize
data class CreateLetterResponse(
val id: String,
val content: String,
val footer: String?,
val counselorId: String,
val userId: String,
var isLiked: Boolean,
val isLiked: Boolean,
val createdAt: String,
val updatedAt: String
) : Parcelable

// UI data class
// - API data 로 받아온 걸 UI data 형태로 데이터 변환(Mapping) 해서 표현되게 해줘야 함
data class LetterUiModel(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

data layer 의 폴더 안에 UI model이 있는 게 조금 이상한 것 같아요.
나중에는 멀티 모듈로 개선하면 좋을 것 같습니다.

val id: String,
val content: String,
val footer: String?,
val counselorName: String,
val userName: String,
var isLiked: Boolean,
val displayDate: String
)
Original file line number Diff line number Diff line change
@@ -1,8 +1,26 @@
package com.simply407.patpat.data.model

// TODO data 가 null이 되면 어떤일이 벌어질까? totalElements 이 null이 되면 어떤일이 벌어질까?
// TODO 원시타입 vs 참조타입

// JsonDataException 또는 JsonParseException) 가 발생합니다.
// - non nullable -> nullable 변경해주기
// ex) val data: List<CreateLetterResponse> -> val data: List<CreateLetterResponse>?

// 원시타입
// - 기본 데이터 타입으로, 메모리에 직접 값을 저장
// - ex) Int, Long, Float, Double, Boolean, Char, Byte, Short 등
// - null 값을 가질 수 없음

// 참조타입
// - 객체의 메모리 주소를 저장
// - ex) String, List, Map, Array, Class 등
// - null 값을 가질 수 있음
// - Int?, Boolean? → Kotlin에서 nullable한 원시 타입도 결국 참조 타입으로 처리됨

data class GetAllLettersResponse(
val data: List<CreateLetterResponse>,
val totalElements: Int,
val data: List<CreateLetterResponse>?,
val totalElements: Int?,
val currentPage: Int,
val totalPages: Int
)
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@ package com.simply407.patpat.data.model
import android.content.Context
import android.content.SharedPreferences

// TODO Preference는 MainThread? IOThread? WorkerThread?
// - MainThread 에서 SharedPreferences 작업을 요청하고, 실제 파일은 IOThread 에서 실행

// - MainThread : UI와 상호작용하는 메인 스레드
// - IOThread : 입출력 작업을 수행하는 스레드
// - WorkerThread : 일반적인 계산이나 비동기 작업을 수행하는 스레드
// ex) bit map 처리 같은 무거운 작업을 할 때, 사용 되면 좋음
object SharedPreferencesManager {

const val FILE_NAME = "user_info"
Expand Down Expand Up @@ -68,4 +75,4 @@ object SharedPreferencesManager {
return sharedPref.getString(KEY_COUNSELOR_RECOMMENDATION, null)
}

}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,49 @@
package com.simply407.patpat.data.repository

import com.simply407.patpat.data.api.PatPatService
import com.simply407.patpat.data.api.RetrofitInstance
import com.simply407.patpat.data.model.ChattingRoomInfo
import com.simply407.patpat.data.model.MessageInfo
import com.simply407.patpat.data.model.PostMessageRequest
import retrofit2.Response
import javax.inject.Inject
import javax.inject.Singleton

class ChattingRepository {
// TODO 의존성주입을 하면 더 좋을 것 같다. hilt를 사용해
// TODO create 의 내부 구현을 확인해보면 좋을듯
// TODO API return형은 Response data class 를 반환 할 수 있게 repository에서 구현로직 들어가야함
private val patPatService: PatPatService = RetrofitInstance.client.create(PatPatService::class.java)

val patApi = RetrofitInstance.getInstance().create(com.simply407.patpat.data.api.patApi::class.java)
suspend fun getAllChattingRoomInfo(accessToken: String, counselorId: String, page: Int, size: Int) = patPatService.getAllChattingRoomInfo(accessToken, counselorId, page, size)

suspend fun getAllChattingRoomInfo(accessToken: String, counselorId: String, page: Int, size: Int) = patApi.getAllChattingRoomInfo(accessToken, counselorId, page, size)
suspend fun postMessage(
accessToken: String,
counselorId: String,
postMessageRequest: PostMessageRequest
) = patPatService.postMessage(accessToken, counselorId, postMessageRequest)
}

// Hilt에 결합 정보를 제공하는 한 가지 방법은 생성자 삽입입니다
// 클래스의 생성자에서 @Inject 주석을 사용하여 클래스의 인스턴스를 제공하는 방법을 Hilt에 알려줍니다
@Singleton
class ChattingRepository @Inject constructor(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Repository에 Singleton annotation을 붙여야 할까요?

private val patPatService: PatPatService
) {
suspend fun getAllChattingRoomInfo(
accessToken: String,
counselorId: String,
page: Int,
size: Int
): Response<ChattingRoomInfo> {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Response 반환이 아닌 ChattingRoomInfo 로 반환 시켜보세요. Response로 반환하게 되면 해당 repository 에 대한 사용이 너무 어려울 것 같습니다.

return patPatService.getAllChattingRoomInfo(accessToken, counselorId, page, size)
}

suspend fun postMessage(
accessToken: String,
counselorId: String,
postMessageRequest: PostMessageRequest
) = patApi.postMessage(accessToken, counselorId, postMessageRequest)
}
): Response<MessageInfo> {
return patPatService.postMessage(accessToken, counselorId, postMessageRequest)
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package com.simply407.patpat.data.repository

import com.simply407.patpat.data.api.PatPatService
import com.simply407.patpat.data.api.RetrofitInstance

class CounselorRepository {

val patApi = RetrofitInstance.getInstance().create(com.simply407.patpat.data.api.patApi::class.java)
private val patPatService: PatPatService = RetrofitInstance.client.create(PatPatService::class.java)

suspend fun getCounselors(accessToken: String) = patApi.getCounselors(accessToken)
}
suspend fun getCounselors(accessToken: String) = patPatService.getCounselors(accessToken)
}
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
package com.simply407.patpat.data.repository

import com.simply407.patpat.data.api.PatPatService
import com.simply407.patpat.data.api.RetrofitInstance
import com.simply407.patpat.data.model.CreateLetterRequest
import com.simply407.patpat.data.model.LikeLetterRequest

class LetterRepository {

val patApi = RetrofitInstance.getInstance().create(com.simply407.patpat.data.api.patApi::class.java)
private val patPatService: PatPatService = RetrofitInstance.client.create(PatPatService::class.java)

suspend fun createLetter(accessToken: String, createLetterRequest: CreateLetterRequest) =
patApi.createLetter(accessToken, createLetterRequest)
patPatService.createLetter(accessToken, createLetterRequest)

suspend fun getAllLetters(accessToken: String, page: Int, size: Int, isLiked: Boolean) =
patApi.getAllLetters(accessToken, page, size, isLiked)
patPatService.getAllLetters(accessToken, page, size, isLiked)

suspend fun likeLetter(
accessToken: String,
letterId: String,
likeLetterRequest: LikeLetterRequest
) = patApi.likeLetter(accessToken, letterId, likeLetterRequest)
}
) = patPatService.likeLetter(accessToken, letterId, likeLetterRequest)
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
package com.simply407.patpat.data.repository


import com.simply407.patpat.data.api.PatPatService
import com.simply407.patpat.data.api.RetrofitInstance
import com.simply407.patpat.data.model.LoginRequest

class LoginRepository {

val patApi = RetrofitInstance.getInstance().create(com.simply407.patpat.data.api.patApi::class.java)
private val patPatService: PatPatService = RetrofitInstance.client.create(PatPatService::class.java)

suspend fun postLogin(loginRequest: LoginRequest) = patApi.postLogin(loginRequest)
suspend fun postLogin(loginRequest: LoginRequest) = patPatService.postLogin(loginRequest)

suspend fun userLogout(accessToken: String) = patApi.userLogout(accessToken)
suspend fun userLogout(accessToken: String) = patPatService.userLogout(accessToken)

suspend fun userWithdrawal(accessToken: String) = patApi.userWithdrawal(accessToken)
}
suspend fun userWithdrawal(accessToken: String) = patPatService.userWithdrawal(accessToken)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.simply407.patpat.data.repository

import android.content.Context
import com.simply407.patpat.R
import com.simply407.patpat.data.model.CounselorMbtiInfo

// TODO 샘플코드이긴 하지만... 만약 String을 객체로 담고 싶다면??
class MBTIRepository(context: Context) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

사실 이렇게 context를 넣어서 관리하는 것 보단 Resource만 보내고 이걸 사용하는 UI component쪽의 context를 사용해서 해당 Resource를 사용하는게 더 좋을 것 같습니다.

val counselorMbtiDataList = listOf(
CounselorMbtiInfo(
context.getString(R.string.counselor_boknam),
listOf(
context.getString(R.string.mbti_infj),
context.getString(R.string.mbti_infp),
context.getString(R.string.mbti_enfj),
context.getString(R.string.mbti_enfp)
)
), CounselorMbtiInfo(
context.getString(R.string.counselor_doctor),
listOf(
context.getString(R.string.mbti_intj),
context.getString(R.string.mbti_intp),
context.getString(R.string.mbti_entj),
context.getString(R.string.mbti_entp)
)
), CounselorMbtiInfo(
context.getString(R.string.counselor_kwak),
listOf(
context.getString(R.string.mbti_istj),
context.getString(R.string.mbti_istp),
context.getString(R.string.mbti_estj),
context.getString(R.string.mbti_estp)
)
), CounselorMbtiInfo(
context.getString(R.string.counselor_coco),
listOf(
context.getString(R.string.mbti_isfj),
context.getString(R.string.mbti_isfp),
context.getString(R.string.mbti_esfj),
context.getString(R.string.mbti_esfp)
)
)
)
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
package com.simply407.patpat.data.repository

import com.simply407.patpat.data.api.PatPatService
import com.simply407.patpat.data.api.RetrofitInstance
import com.simply407.patpat.data.model.NewUserInfo

class UserInfoRepository {

val patApi = RetrofitInstance.getInstance().create(com.simply407.patpat.data.api.patApi::class.java)
private val patPatService: PatPatService = RetrofitInstance.client.create(PatPatService::class.java)

suspend fun getUserInfo(accessToken: String) = patApi.getUserInfo(accessToken)
suspend fun getUserInfo(accessToken: String) = patPatService.getUserInfo(accessToken)

suspend fun putUserInfo(accessToken: String, newUserInfo: NewUserInfo) =
patApi.putUserInfo(accessToken, newUserInfo)
}
patPatService.putUserInfo(accessToken, newUserInfo)
}
Loading