Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
103 commits
Select commit Hold shift + click to select a range
55aeb58
feat: 친구 프로필 Service 세팅
rhkrwngud445 Aug 24, 2025
783ba62
refactor: ContactFrequency -> ContactFrequencyLevel 수정
rhkrwngud445 Aug 24, 2025
83815a3
feat: repository API 호출 로직 구성
rhkrwngud445 Aug 24, 2025
061043f
refactor: friendSummary 모델 세부 패키지 구성
rhkrwngud445 Aug 24, 2025
7492ab0
feat: friendProfileScreen 상단 상태바 패딩 적용
rhkrwngud445 Aug 24, 2025
d2cc816
chore: string res 정리
rhkrwngud445 Aug 24, 2025
4979f35
feat: dropdown 구성
rhkrwngud445 Aug 24, 2025
6d55bbb
feat: 프로필 정보 조회 API 연동
rhkrwngud445 Aug 24, 2025
3dfd47d
feat: 전화 및 문자 화면 이동 로직 구성
rhkrwngud445 Aug 24, 2025
e69e043
docs: res 사용하는 model TODO 작성
rhkrwngud445 Aug 25, 2025
7502dae
refactor: remindInterval 서버와 네이밍을 똑같이 수정
rhkrwngud445 Aug 25, 2025
f76e95c
refactor: relation 타입을 enum으로 변경
rhkrwngud445 Aug 25, 2025
19df3f3
feat: 프로필 정보 데이터 연동
rhkrwngud445 Aug 26, 2025
3d793b5
feat: 챙김 기록 데이터 연동
rhkrwngud445 Aug 26, 2025
7933609
fix: 챙김 기록 Entity 직렬화 적용
rhkrwngud445 Aug 26, 2025
7e718b6
feat: 챙김 및 친구 삭제 데이터 연동
rhkrwngud445 Aug 26, 2025
5263fb3
feat: Friend Navigation 인자 전달을 위한 Serializable 적용
rhkrwngud445 Aug 27, 2025
2c03a14
feat: 로그인 화면 UI 구현
stopstone Aug 28, 2025
bd6ac87
feat: DataStore 라이브러리 추가
stopstone Aug 28, 2025
6114ae3
feat: 카카오 SDK 연동
stopstone Aug 28, 2025
22e4d3a
feat: 로그인 화면 수정 및 네비게이션 적용
stopstone Aug 28, 2025
0d70567
feat: 카카오 소셜 로그인 서버 API 요청
stopstone Aug 28, 2025
b92b913
feat: 카카오 로그인 서버 API 연동
stopstone Aug 28, 2025
e410519
feat: 카카오 로그인 datasource 계층 분리 및 확장 가능한 코드로 변경
stopstone Aug 29, 2025
8836162
refactor: 소셜 로그인 데이터 소스 파일 경로 변경
stopstone Aug 29, 2025
78237ca
Refactor: DataStoreModule 분리
stopstone Aug 29, 2025
fb89c57
feat: 토큰 관리 및 인증 로직 구현
stopstone Aug 29, 2025
431ccc2
feat: parcelize 의존성 추가
rhkrwngud445 Aug 30, 2025
04d6d36
feat: Route 인자 전달을 위한 serializable, pacelable 적용
rhkrwngud445 Aug 30, 2025
c25a8eb
feat: friend 파라미터 전달 적용
rhkrwngud445 Aug 30, 2025
e066210
feat: 정보 수정 이벤트 적용
rhkrwngud445 Aug 30, 2025
0074695
feat: 정보 수정 API 연동
rhkrwngud445 Aug 31, 2025
85a40ee
feat: 이전 화면 데이터 적용
rhkrwngud445 Aug 31, 2025
e5fd302
fix: navigation imageUrl 인코딩 적용
rhkrwngud445 Aug 31, 2025
83465cb
feat: 화면이 길어질 경우 스크롤 적용
rhkrwngud445 Aug 31, 2025
acdd13a
feat: 수정시 다이얼로그 추가
rhkrwngud445 Aug 31, 2025
9819c4c
fix: 친구 관계 버튼 클릭 포인트 수정
rhkrwngud445 Aug 31, 2025
79b504f
fix: 챔김순서 최신순으로 수정
rhkrwngud445 Aug 31, 2025
0c08868
feat: 토큰 갱신 및 만료 처리 로직 개선
stopstone Sep 1, 2025
737b9c3
refactor: 토큰 갱신 로직 삭제
stopstone Sep 1, 2025
9f03d40
refactor: 로그인 백그라운드 색상 변경
stopstone Sep 1, 2025
123091c
refactor: string res 분리
rhkrwngud445 Sep 1, 2025
0f844a8
chore: 카카오 네이티브키 CI 설정
stopstone Sep 1, 2025
877388d
feat: 토큰 갱신 로직 추가
stopstone Sep 1, 2025
131cb47
feat: TokenManager 추가 및 토큰 관리 로직 개선
stopstone Sep 1, 2025
0800e55
refactor: 카카오 로그인 로직 수정
stopstone Sep 1, 2025
cc27edc
refactor: 토큰 유효성 검사 로직 수정
stopstone Sep 1, 2025
c3edc18
refactor: logout 로직 수정
stopstone Sep 1, 2025
75855d3
refactor: 토큰 만료 시간 계산 로직 변경
stopstone Sep 1, 2025
6ffe949
feat: 로그 유틸리티 추가
stopstone Sep 2, 2025
c6102a7
refactor: 로깅 시 호출자 정보 찾는 로직 개선
stopstone Sep 2, 2025
7bcd976
refactor: 소셜 로그인 결과 처리 방식 변경
stopstone Sep 2, 2025
2d3062d
Refactor: TokenInterceptor에서 AuthEndpoint 분리
stopstone Sep 2, 2025
9f3475a
refactor: KakaoDataSource 바인딩 DI 모듈 뷰ㅜㄴ리
stopstone Sep 2, 2025
e2fa26f
refactor: 로깅 유틸리티 `NearLog` 개선
stopstone Sep 2, 2025
f8b09cf
Merge pull request #22 from near-Contact-Reminder/feat/login-form
stopstone Sep 2, 2025
bbc5704
Merge pull request #25 from near-Contact-Reminder/feat/logger-extension
stopstone Sep 2, 2025
39d462b
fix: delete 엔드포인트 수정
rhkrwngud445 Sep 6, 2025
7e3f7b3
refactor: string res 적용
rhkrwngud445 Sep 7, 2025
a42d27a
refactor: 연락 빈도 매직넘버 처리
rhkrwngud445 Sep 7, 2025
90ed514
fix: context -> stringres 수정
rhkrwngud445 Sep 7, 2025
9bfdb65
refactor: dayOfWeek enum 적용
rhkrwngud445 Sep 7, 2025
ea1c634
fix: 네비게이션바 패딩 적용
rhkrwngud445 Sep 7, 2025
ea1bdae
fix: records isEmpty 상태를 통한 화면 상태 관리하도록 수정
rhkrwngud445 Sep 7, 2025
5b0a186
feat: 친구 프로필 Service 세팅
rhkrwngud445 Aug 24, 2025
369fd4d
refactor: ContactFrequency -> ContactFrequencyLevel 수정
rhkrwngud445 Aug 24, 2025
9a66d1a
feat: repository API 호출 로직 구성
rhkrwngud445 Aug 24, 2025
2891d1d
refactor: friendSummary 모델 세부 패키지 구성
rhkrwngud445 Aug 24, 2025
5119ed8
feat: friendProfileScreen 상단 상태바 패딩 적용
rhkrwngud445 Aug 24, 2025
77ced7c
chore: string res 정리
rhkrwngud445 Aug 24, 2025
7bfb1a8
feat: dropdown 구성
rhkrwngud445 Aug 24, 2025
4f5e7af
feat: 프로필 정보 조회 API 연동
rhkrwngud445 Aug 24, 2025
ccd2f94
refactor: conflict 수정
rhkrwngud445 Sep 7, 2025
bf10b44
docs: res 사용하는 model TODO 작성
rhkrwngud445 Aug 25, 2025
9e6673f
refactor: remindInterval 서버와 네이밍을 똑같이 수정
rhkrwngud445 Aug 25, 2025
22997cd
refactor: relation 타입을 enum으로 변경
rhkrwngud445 Aug 25, 2025
1c337d2
feat: 프로필 정보 데이터 연동
rhkrwngud445 Aug 26, 2025
46fd87f
feat: 챙김 기록 데이터 연동
rhkrwngud445 Aug 26, 2025
3367602
fix: 챙김 기록 Entity 직렬화 적용
rhkrwngud445 Aug 26, 2025
6056356
feat: 챙김 및 친구 삭제 데이터 연동
rhkrwngud445 Aug 26, 2025
d81ed8c
feat: Friend Navigation 인자 전달을 위한 Serializable 적용
rhkrwngud445 Aug 27, 2025
b802953
feat: parcelize 의존성 추가
rhkrwngud445 Aug 30, 2025
0127f09
feat: Route 인자 전달을 위한 serializable, pacelable 적용
rhkrwngud445 Aug 30, 2025
817ec40
feat: friend 파라미터 전달 적용
rhkrwngud445 Aug 30, 2025
010d395
feat: 정보 수정 이벤트 적용
rhkrwngud445 Aug 30, 2025
6eb87dd
feat: 정보 수정 API 연동
rhkrwngud445 Aug 31, 2025
77a1c65
feat: 이전 화면 데이터 적용
rhkrwngud445 Aug 31, 2025
b6dfdff
fix: navigation imageUrl 인코딩 적용
rhkrwngud445 Aug 31, 2025
5a0a84c
feat: 화면이 길어질 경우 스크롤 적용
rhkrwngud445 Aug 31, 2025
078384b
feat: 수정시 다이얼로그 추가
rhkrwngud445 Aug 31, 2025
7046065
fix: 친구 관계 버튼 클릭 포인트 수정
rhkrwngud445 Aug 31, 2025
f2807ab
fix: 챔김순서 최신순으로 수정
rhkrwngud445 Aug 31, 2025
80a0b87
refactor: string res 분리
rhkrwngud445 Sep 1, 2025
6e07d8e
fix: delete 엔드포인트 수정
rhkrwngud445 Sep 6, 2025
66c1ddd
refactor: string res 적용
rhkrwngud445 Sep 7, 2025
adfd5f4
refactor: 연락 빈도 매직넘버 처리
rhkrwngud445 Sep 7, 2025
258fa45
fix: context -> stringres 수정
rhkrwngud445 Sep 7, 2025
867511c
refactor: dayOfWeek enum 적용
rhkrwngud445 Sep 7, 2025
a77678d
fix: 네비게이션바 패딩 적용
rhkrwngud445 Sep 7, 2025
72acb6a
fix: records isEmpty 상태를 통한 화면 상태 관리하도록 수정
rhkrwngud445 Sep 7, 2025
c290de7
Merge remote-tracking branch 'origin/feat/#21-feat_친구_프로필_api_연동' int…
rhkrwngud445 Sep 7, 2025
eb93e25
feat: NearFrame 적용
rhkrwngud445 Sep 7, 2025
307da48
feat: NearDropdown 적용
rhkrwngud445 Sep 7, 2025
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
6 changes: 6 additions & 0 deletions .github/workflows/android-pull-request-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ jobs:
run: |
echo "TEMP_TOKEN=\"TEMP_TOKEN\"" >> local.properties

- name: Access Kakao KAKAO_NATIVE_APP_KEY
env:
KAKAO_NATIVE_APP_KEY: ${{ secrets.KAKAO_NATIVE_APP_KEY }}
run: |
echo "KAKAO_NATIVE_APP_KEY=\"$KAKAO_NATIVE_APP_KEY\"" >> local.properties

- name: Grant execute permission for gradlew
run: chmod +x gradlew

Expand Down
11 changes: 11 additions & 0 deletions Near/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ plugins {
alias(libs.plugins.hilt.application)
alias(libs.plugins.kotlin.kapt)
alias(libs.plugins.kotlin.serialization)
alias(libs.plugins.kotlin.parcelize)
}

android {
Expand All @@ -32,10 +33,14 @@ android {
)
buildConfigField("String", "NEAR_URL", getProperty("NEAR_PROD_URL"))
buildConfigField("String", "TEMP_TOKEN", getProperty("TEMP_TOKEN")) // TODO 추후 삭제 필요
buildConfigField("String", "KAKAO_NATIVE_APP_KEY", getProperty("KAKAO_NATIVE_APP_KEY"))
manifestPlaceholders["kakaoAppKey"] = getProperty("KAKAO_NATIVE_APP_KEY").replace("\"", "")
}
debug {
buildConfigField("String", "NEAR_URL", getProperty("NEAR_DEV_URL"))
buildConfigField("String", "TEMP_TOKEN", getProperty("TEMP_TOKEN")) // TODO 추후 삭제 필요
buildConfigField("String", "KAKAO_NATIVE_APP_KEY", getProperty("KAKAO_NATIVE_APP_KEY"))
manifestPlaceholders["kakaoAppKey"] = getProperty("KAKAO_NATIVE_APP_KEY").replace("\"", "")
}
}
compileOptions {
Expand Down Expand Up @@ -88,6 +93,12 @@ dependencies {
implementation(libs.navigation.compose)
// Serialization
implementation(libs.kotlin.serialization.json)
// DataStore
implementation(libs.androidx.datastore.preferences)
implementation(libs.androidx.datastore.core)

// Kakao Module
implementation(libs.v2.all)
}

fun getProperty(propertyKey: String): String = gradleLocalProperties(rootDir, providers).getProperty(propertyKey)
19 changes: 19 additions & 0 deletions Near/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,25 @@
android:supportsRtl="true"
android:theme="@style/Theme.Near"
tools:targetApi="31">

<!-- Kakao SDK -->
<meta-data
android:name="com.kakao.sdk.AppKey"
android:value="${kakaoAppKey}" />

<!-- 카카오톡 로그인 콜백을 위한 Activity -->
<activity
android:name="com.kakao.sdk.auth.AuthCodeHandlerActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:host="oauth"
android:scheme="kakao${kakaoAppKey}" />
</intent-filter>
</activity>

<activity
android:name=".presentation.feature.main.MainActivity"
android:exported="true"
Expand Down
11 changes: 10 additions & 1 deletion Near/app/src/main/java/com/alarmy/near/NearApplication.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
package com.alarmy.near

import android.app.Application
import com.kakao.sdk.common.KakaoSdk
import dagger.hilt.android.HiltAndroidApp

@HiltAndroidApp
class NearApplication : Application()
class NearApplication : Application() {

override fun onCreate() {
super.onCreate()

// 카카오 SDK 초기화
KakaoSdk.init(this, BuildConfig.KAKAO_NATIVE_APP_KEY)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package com.alarmy.near.data.datasource

import android.content.Context
import com.alarmy.near.model.ProviderType
import com.kakao.sdk.auth.model.OAuthToken
import com.kakao.sdk.common.model.ClientError
import com.kakao.sdk.common.model.ClientErrorCause
import com.kakao.sdk.user.UserApiClient
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.CancellableContinuation
import kotlinx.coroutines.suspendCancellableCoroutine
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.coroutines.resume

/**
* 카카오 로그인 데이터 소스
* 단일 책임: 카카오 SDK만 처리
*/
@Singleton
class KakaoDataSource
@Inject
constructor(
@ApplicationContext private val context: Context,
) : SocialLoginDataSource {
override val supportedType: ProviderType = ProviderType.KAKAO

override suspend fun login(): Result<String> =
try {
val token =
if (UserApiClient.instance.isKakaoTalkLoginAvailable(context)) {
loginWithKakaoTalk()
} else {
loginWithKakaoAccount()
}

if (token.isNotEmpty()) {
Result.success(token)
} else {
Result.failure(Exception("사용자가 로그인을 취소했습니다"))
}
} catch (exception: Exception) {
Result.failure(exception)
}

private suspend fun loginWithKakaoTalk(): String =
suspendCancellableCoroutine { continuation ->
UserApiClient.instance.loginWithKakaoTalk(context) { token, error ->
when {
error != null -> {
if (error is ClientError && error.reason == ClientErrorCause.Cancelled) {
continuation.resume("")
} else {
UserApiClient.instance.loginWithKakaoAccount(context) { retryToken, retryError ->
handleLoginResult(retryToken, retryError, continuation)
}
}
}
token != null -> continuation.resume(token.accessToken)
else -> continuation.resume("")
}
}
}

private suspend fun loginWithKakaoAccount(): String =
suspendCancellableCoroutine { continuation ->
UserApiClient.instance.loginWithKakaoAccount(context) { token, error ->
handleLoginResult(token, error, continuation)
}
}

private fun handleLoginResult(
token: OAuthToken?,
error: Throwable?,
continuation: CancellableContinuation<String>,
) {
when {
error != null -> {
if (error is ClientError && error.reason == ClientErrorCause.Cancelled) {
continuation.resume("")
} else {
continuation.resumeWith(Result.failure(error))
}
}
token != null -> continuation.resume(token.accessToken)
else -> continuation.resume("")
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.alarmy.near.data.datasource

import com.alarmy.near.model.ProviderType

/**
* 소셜 로그인 데이터 소스 인터페이스
* Strategy 패턴으로 각 소셜 플랫폼별로 구현
*/
interface SocialLoginDataSource {
/**
* 지원하는 소셜 로그인 타입
*/
val supportedType: ProviderType

/**
* 소셜 로그인 수행
* Context는 생성자에서 주입받아 사용
*/
suspend fun login(): Result<String>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.alarmy.near.data.datasource


import com.alarmy.near.model.ProviderType
import javax.inject.Inject
import javax.inject.Singleton

/**
* 소셜 로그인 프로세서
* Strategy 패턴으로 동적으로 로그인 방식 선택
*/
@Singleton
class SocialLoginProcessor
@Inject
constructor(
private val socialLoginDataSources: Set<@JvmSuppressWildcards SocialLoginDataSource>,
) {
/**
* 소셜 로그인 처리
* @param providerType 로그인 제공자 타입
* @return 로그인 결과
*/
suspend fun processLogin(
providerType: ProviderType,
): Result<String> {
val dataSource =
socialLoginDataSources.find { it.supportedType == providerType }
?: return Result.failure(Exception("지원하지 않는 로그인 타입입니다: ${providerType.name}"))

return dataSource.login()
}
}
17 changes: 17 additions & 0 deletions Near/app/src/main/java/com/alarmy/near/data/di/DataSourceModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.alarmy.near.data.di

import com.alarmy.near.data.datasource.KakaoDataSource
import com.alarmy.near.data.datasource.SocialLoginDataSource
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import dagger.multibindings.IntoSet

@Module
@InstallIn(SingletonComponent::class)
interface DataSourceModule {
@Binds
@IntoSet
abstract fun bindKakaoDataSource(kakaoDataSource: KakaoDataSource): SocialLoginDataSource
}
25 changes: 25 additions & 0 deletions Near/app/src/main/java/com/alarmy/near/data/di/DataStoreModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.alarmy.near.data.di

import android.content.Context
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.preferencesDataStore
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton

// DataStore 확장 프로퍼티
private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "auth_preferences")

@Module
@InstallIn(SingletonComponent::class)
object DataStoreModule {
@Provides
@Singleton
fun provideDataStore(
@ApplicationContext context: Context,
): DataStore<Preferences> = context.dataStore
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.alarmy.near.data.di

import com.alarmy.near.data.repository.AuthRepository
import com.alarmy.near.data.repository.AuthRepositoryImpl
import com.alarmy.near.data.repository.DefaultFriendRepository
import com.alarmy.near.data.repository.ExampleRepository
import com.alarmy.near.data.repository.ExampleRepositoryImpl
Expand All @@ -20,4 +22,8 @@ interface RepositoryModule {
@Binds
@Singleton
abstract fun bindFriendRepository(friendRepository: DefaultFriendRepository): FriendRepository

@Binds
@Singleton
abstract fun bindAuthRepository(authRepositoryImpl: AuthRepositoryImpl): AuthRepository
}
Loading