Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feat/#8] 4주차 과제 #9

Open
wants to merge 21 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
9edf84e
Add/#8: 서버 통신 기초 세팅
jm991014 Nov 7, 2024
1d4dadd
Mod/#8: 로그인 화면 로직 수정 (코드리뷰 반영)
jm991014 Nov 10, 2024
caf0714
Mod/#8: 회원가입 화면 로직 수정
jm991014 Nov 10, 2024
f555ec2
Add/#8: 로그인 및 회원가입 엔티티 추가
jm991014 Nov 10, 2024
f8164cc
Add/#8: string.xml 수정
jm991014 Nov 10, 2024
0e1b912
Mod/#8: 로그인/회원가입 usecase 및 Error타입 수정
jm991014 Nov 10, 2024
ba1f683
Feat/#8: AuthRepository 및 구현체 생성
jm991014 Nov 10, 2024
15bd300
Feat/#8 Local 및 AuthRemote data source 및 구현체 생성
jm991014 Nov 10, 2024
22c0c49
Feat/#8: DI 모듈 생성 및 일부 수정
jm991014 Nov 10, 2024
ae62069
Feat/#8: 로그인/회원가입 Service 및 request/response 데이터 클래스 추가
jm991014 Nov 10, 2024
51b5bac
Del/#8: 불필요 파일 제거
jm991014 Nov 10, 2024
0965335
Mod/#8: local datasource myhobby 제거
jm991014 Nov 13, 2024
5022e87
Feat/#8: Token Interceptor 구현
jm991014 Nov 13, 2024
755d7a4
Feat/#8: MyPage 관련 repository 및 datasource 구현, API 연동
jm991014 Nov 13, 2024
eca791d
Mod/#8: Mypage 취미 기능 기반 수정
jm991014 Nov 13, 2024
2d71803
Mod/#8: authrepository 수정
jm991014 Nov 13, 2024
38c5dc7
Mod/#8: 코드리뷰 반영
jm991014 Nov 13, 2024
3e8cc29
Chore/#8: import 제거 및 마이너 수정
jm991014 Nov 13, 2024
68012cf
Feat/#8: 사용자 정보 업데이트 기능 구현
jm991014 Nov 14, 2024
4988b03
Del/#8: 불필요 파일 삭제
jm991014 Nov 14, 2024
490077a
Feat/#8: 취미 검색 기능 구현
jm991014 Nov 14, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import java.util.Properties

plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
Expand All @@ -7,6 +9,10 @@ plugins {
alias(libs.plugins.hilt)
}

val properties = Properties().apply {
load(project.rootProject.file("local.properties").inputStream())
}

android {
namespace = "org.sopt.and"
compileSdk = 34
Expand All @@ -19,6 +25,7 @@ android {
versionName = "1.0"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
buildConfigField("String", "BASE_URL", properties["base.url"].toString())
}

buildTypes {
Expand All @@ -44,6 +51,7 @@ android {
}
buildFeatures {
compose = true
buildConfig = true
}
}

Expand All @@ -65,9 +73,6 @@ dependencies {
debugImplementation(libs.androidx.ui.tooling)
debugImplementation(libs.androidx.ui.test.manifest)

// serialization
implementation(libs.kotlinx.serialization.json)

// navigation
implementation(libs.androidx.compose.navigation)
implementation(libs.hilt.navigation.compose)
Expand All @@ -79,4 +84,12 @@ dependencies {
// coil3
implementation(libs.coil.compose)
implementation(libs.coil.network)

// Network
implementation(platform(libs.okhttp.bom))
implementation(libs.okhttp)
implementation(libs.okhttp.logging.interceptor)
implementation(libs.retrofit)
implementation(libs.retrofit.kotlin.serialization.converter)
implementation(libs.kotlinx.serialization.json)
}
1 change: 1 addition & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.ANDANDROID"
android:usesCleartextTraffic="true"
tools:targetApi="31">
<activity
android:name=".presentation.main.MainActivity"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.sopt.and.data.datasource.local


interface LocalDataSource {
var accessToken: String
fun clearInfo()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.sopt.and.data.datasource.remote

import org.sopt.and.data.service.model.BaseResponse
import org.sopt.and.data.service.model.request.SignInRequest
import org.sopt.and.data.service.model.request.SignUpRequest
import org.sopt.and.data.service.model.response.SignInResponse
import org.sopt.and.data.service.model.response.SignUpResponse


interface AuthRemoteDataSource {
suspend fun signIn(signInRequest: SignInRequest): BaseResponse<SignInResponse>

suspend fun signUp(signUpRequest: SignUpRequest): BaseResponse<SignUpResponse>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.sopt.and.data.datasource.remote

import org.sopt.and.data.service.model.BaseResponse
import org.sopt.and.data.service.model.request.HobbyModifyRequest
import org.sopt.and.data.service.model.response.HobbyResponse
import retrofit2.Response


interface MyPageRemoteDataSource {

suspend fun getMyHobby(): BaseResponse<HobbyResponse>

suspend fun getOtherHobby(
no: String
): BaseResponse<HobbyResponse>

suspend fun modifyMyHobby(
hobbyModifyRequest: HobbyModifyRequest
): Response<BaseResponse<String?>?>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package org.sopt.and.data.datasourceImpl.local

import android.content.SharedPreferences
import org.sopt.and.data.datasource.local.LocalDataSource
import javax.inject.Inject


class LocalDataSourceImpl @Inject constructor(

Choose a reason for hiding this comment

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

Localdl라는 이름으론 이 클래스가 어떤 저장소에 접근하는지 알기 어렵다고 생각해요.
로컬 데이터베이스의 경우 preference, datastore, room 등이 있으니까 이름에서 잘 구분해주면 좋을 것 같습니다!

private val sharedPreferences: SharedPreferences
) : LocalDataSource {

override var accessToken: String
get() = sharedPreferences.getString(ACCESS_TOKEN, DEFAULT).orEmpty()
set(value) = sharedPreferences.edit().putString(ACCESS_TOKEN, value).apply()

override fun clearInfo() = sharedPreferences.edit().clear().apply()

companion object {
private const val ACCESS_TOKEN = "access_token"
private const val DEFAULT = ""
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package org.sopt.and.data.datasourceImpl.remote

import org.sopt.and.data.datasource.remote.AuthRemoteDataSource
import org.sopt.and.data.service.AuthService
import org.sopt.and.data.service.model.BaseResponse
import org.sopt.and.data.service.model.request.SignInRequest
import org.sopt.and.data.service.model.request.SignUpRequest
import org.sopt.and.data.service.model.response.SignInResponse
import org.sopt.and.data.service.model.response.SignUpResponse
import javax.inject.Inject


class AuthRemoteDataSourceImpl @Inject constructor(
private val authService: AuthService
) : AuthRemoteDataSource {

override suspend fun signIn(
signInRequest: SignInRequest
): BaseResponse<SignInResponse> = authService.signIn(signInRequest)

override suspend fun signUp(
signUpRequest: SignUpRequest
): BaseResponse<SignUpResponse> = authService.signUp(signUpRequest)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package org.sopt.and.data.datasourceImpl.remote

import org.sopt.and.data.datasource.remote.MyPageRemoteDataSource
import org.sopt.and.data.service.MyPageService
import org.sopt.and.data.service.model.BaseResponse
import org.sopt.and.data.service.model.request.HobbyModifyRequest
import org.sopt.and.data.service.model.response.HobbyResponse
import retrofit2.Response
import javax.inject.Inject


class MyPageRemoteDataSourceImpl @Inject constructor(
private val myPageService: MyPageService
) : MyPageRemoteDataSource {

override suspend fun getMyHobby(): BaseResponse<HobbyResponse> = myPageService.getMyHobby()

override suspend fun getOtherHobby(
no: String
): BaseResponse<HobbyResponse> = myPageService.getOthersHobby(no)

override suspend fun modifyMyHobby(
hobbyModifyRequest: HobbyModifyRequest
): Response<BaseResponse<String?>?> = myPageService.modifyMyHobby(hobbyModifyRequest)
}
61 changes: 61 additions & 0 deletions app/src/main/java/org/sopt/and/data/di/ApiModule.kt

Choose a reason for hiding this comment

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

힐트 사용 너무 잘하시네요~

Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package org.sopt.and.data.di

import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import kotlinx.serialization.json.Json
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.ResponseBody
import okhttp3.logging.HttpLoggingInterceptor
import org.sopt.and.BuildConfig.BASE_URL
import org.sopt.and.data.interceptor.TokenInterceptor
import retrofit2.Converter
import retrofit2.Retrofit
import java.lang.reflect.Type
import javax.inject.Singleton


@Module
@InstallIn(SingletonComponent::class)
object ApiModule {

@Provides
@Singleton
fun provideLoggingInterceptor(): HttpLoggingInterceptor = HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY

Choose a reason for hiding this comment

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

HttpLoggingInterceptor 사용하는거 너무 좋은 것 같아요~!!

}

@Provides
@Singleton
fun provideOkHttpClient(
loggingInterceptor: HttpLoggingInterceptor,
tokenInterceptor: TokenInterceptor
): OkHttpClient = OkHttpClient.Builder()
.addInterceptor(loggingInterceptor)
.addInterceptor(tokenInterceptor)
.build()

@Provides
@Singleton
fun provideRetrofit(
client: OkHttpClient
): Retrofit {
val nullOnEmptyConverterFactory = object : Converter.Factory() {
fun converterFactory() = this
override fun responseBodyConverter(type: Type, annotations: Array<out Annotation>, retrofit: Retrofit) = object : Converter<ResponseBody, Any?> {
val nextResponseBodyConverter = retrofit.nextResponseBodyConverter<Any?>(converterFactory(), type, annotations)
override fun convert(value: ResponseBody) = if (value.contentLength() == 0L) null else nextResponseBodyConverter.convert(value)
}
}

return Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
.addConverterFactory(nullOnEmptyConverterFactory)
.addConverterFactory(Json.asConverterFactory("application/json".toMediaType()))
.build()
}
}
16 changes: 8 additions & 8 deletions app/src/main/java/org/sopt/and/data/di/AppModule.kt

Choose a reason for hiding this comment

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

이건 네이밍을 왜 앱 모듈로 하셨나요?
내용과 이름이 전혀 다르다고 생각되네요,,

Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import org.sopt.and.data.local.UserDataSource
import org.sopt.and.data.datasourceImpl.local.LocalDataSourceImpl
import javax.inject.Singleton

@Module
Expand All @@ -18,13 +18,13 @@ object AppModule {

@Provides
@Singleton
fun provideSharedPreferences(@ApplicationContext context: Context): SharedPreferences {
return context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE)
}
fun provideSharedPreferences(
@ApplicationContext context: Context
): SharedPreferences = context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE)

@Provides
@Singleton
fun provideUserDataSource(sharedPreferences: SharedPreferences): UserDataSource {
return UserDataSource(sharedPreferences)
}
}
fun provideUserDataSource(
sharedPreferences: SharedPreferences
): LocalDataSourceImpl = LocalDataSourceImpl(sharedPreferences)
}
37 changes: 37 additions & 0 deletions app/src/main/java/org/sopt/and/data/di/DataSourceModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package org.sopt.and.data.di

import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import org.sopt.and.data.datasource.local.LocalDataSource
import org.sopt.and.data.datasource.remote.AuthRemoteDataSource
import org.sopt.and.data.datasource.remote.MyPageRemoteDataSource
import org.sopt.and.data.datasourceImpl.local.LocalDataSourceImpl
import org.sopt.and.data.datasourceImpl.remote.AuthRemoteDataSourceImpl
import org.sopt.and.data.datasourceImpl.remote.MyPageRemoteDataSourceImpl
import javax.inject.Singleton


@Module
@InstallIn(SingletonComponent::class)
abstract class DataSourceModule {

@Binds
@Singleton
abstract fun bindAuthRemoteDataSource(
authRemoteDataSourceImpl: AuthRemoteDataSourceImpl
): AuthRemoteDataSource

@Binds
@Singleton
abstract fun bindMyPageRemoteDataSource(
myPageRemoteDataSourceImpl: MyPageRemoteDataSourceImpl
): MyPageRemoteDataSource

@Binds
@Singleton
abstract fun bindLocalDataSource(
localDataSourceImpl: LocalDataSourceImpl
): LocalDataSource
}
16 changes: 12 additions & 4 deletions app/src/main/java/org/sopt/and/data/di/RepositoryModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import org.sopt.and.data.repository.UserRepositoryImpl
import org.sopt.and.domain.repository.UserRepository
import org.sopt.and.data.repository.AuthRepositoryImpl
import org.sopt.and.data.repository.MyPageRepositoryImpl
import org.sopt.and.domain.repository.AuthRepository
import org.sopt.and.domain.repository.MyPageRepository
import javax.inject.Singleton

@Module
Expand All @@ -15,6 +17,12 @@ abstract class RepositoryModule {
@Binds
@Singleton
abstract fun bindUserRepository(
userRepositoryImpl: UserRepositoryImpl
): UserRepository
authRepositoryImpl: AuthRepositoryImpl
): AuthRepository

@Binds
@Singleton
abstract fun bindMyPageRepository(
myPageRepositoryImpl: MyPageRepositoryImpl
): MyPageRepository
}
28 changes: 28 additions & 0 deletions app/src/main/java/org/sopt/and/data/di/ServiceModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package org.sopt.and.data.di

import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import org.sopt.and.data.service.AuthService
import org.sopt.and.data.service.MyPageService
import retrofit2.Retrofit
import javax.inject.Singleton


@Module
@InstallIn(SingletonComponent::class)
object ServiceModule {

@Provides
@Singleton
fun provideAuthService(
retrofit: Retrofit
): AuthService = retrofit.create(AuthService::class.java)

@Provides
@Singleton
fun provideMyPageService(
retrofit: Retrofit
): MyPageService = retrofit.create(MyPageService::class.java)
}
Loading