Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
278ca75
[CHORE/#394] version update 1.3.3 -> 1.3.4
leeeyubin May 16, 2025
b9d7155
[FEAT/#396] 푸시알림 상태변경 API
leeeyubin May 16, 2025
df03763
[FEAT/#396] 프로필 정보 API 응답값 수정
leeeyubin May 16, 2025
7bfd4c5
[FEAT/#396] AlarmType 작성
leeeyubin May 16, 2025
0e09c28
[FEAT/#396] Home 화면에 알림 상태 서버통신 구현
leeeyubin May 16, 2025
fce4cfb
[FEAT/#396] Mypage 화면에 알림 상태 서버통신 구현
leeeyubin May 16, 2025
e95fb65
[FEAT/#396] FirebaseMessaging 로컬 -> 서버DB 로직으로 변경
leeeyubin May 17, 2025
ea565ff
[FEAT/#396] FirebaseMessaging 코드 복구
leeeyubin May 17, 2025
f641f5a
[FEAT/#396] Home에서 로컬로도 통신하도록 구현
leeeyubin May 17, 2025
5eb3c08
[FEAT/#396] Mypage Optimistic UI 적용
leeeyubin May 17, 2025
0310185
[FEAT/#396] groupBy 확장함수 작성
leeeyubin May 17, 2025
3332ac3
[FEAT/#396] AlarmInfo 작성
leeeyubin May 17, 2025
defb28c
[FEAT/#396] debounceFlow 적용
leeeyubin May 17, 2025
97c5c7a
[FEAT/#396] 디바운스 상수화
leeeyubin May 17, 2025
c134828
[CHORE/#396] currentState 네이밍 변경
leeeyubin May 17, 2025
8a86ca7
[CHORE/#396] AlarmInfo 접근제어자 수정 및 파일 위치 이동
leeeyubin May 17, 2025
ab37251
[CHORE/#396] alarmStatus 변수명 변경
leeeyubin May 17, 2025
d6d9275
[CHORE/#396] onSuccess / onFailure 수정
leeeyubin May 17, 2025
fa9dde3
[CHORE/#396] 예외처리 구현
leeeyubin May 17, 2025
8bfb7aa
[CHORE/#396] DisposableEffect 통합
leeeyubin May 17, 2025
a42ed2a
[CHORE/#396] 안쓰이는 코드 삭제
leeeyubin May 17, 2025
93e4e37
[CHORE/#396] groupBy 확장함수 없이 구현
leeeyubin May 17, 2025
b81f23f
[CHORE/#396] 탈퇴 두 번 한 유저는 자동 disabled 되게 수정
leeeyubin May 17, 2025
05886e7
[FIX/#396] 기존 유저의 알림 활성화 되지 않는 문제 해결
leeeyubin May 17, 2025
da0c921
[FIX/#396] 코드 원상 복구 및 큐에이 해결
leeeyubin May 17, 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.terning.core.designsystem.extension

import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.channels.SendChannel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.consumeAsFlow
import kotlinx.coroutines.flow.flow

fun <T, K> Flow<T>.groupBy(getKey: (T) -> K): Flow<Pair<K, Flow<T>>> = flow {
val storage = mutableMapOf<K, SendChannel<T>>()
try {
collect { t ->
val key = getKey(t)
val channel = storage.getOrPut(key) {
Channel<T>(capacity = Channel.BUFFERED).also {
emit(key to it.consumeAsFlow())
}
}
channel.send(t)
}
} finally {
storage.values.forEach { it.close() }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.terning.core.designsystem.type

enum class AlarmType(val value: String) {
ENABLED("ENABLED"),
DISABLED("DISABLED")
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.terning.data.mypage.datasource

import com.terning.core.network.BaseResponse
import com.terning.core.network.NonDataBaseResponse
import com.terning.data.mypage.dto.request.AlarmStatusRequestDto
import com.terning.data.mypage.dto.request.MyPageProfileEditRequestDto
import com.terning.data.mypage.dto.response.MyPageResponseDto

Expand All @@ -15,4 +16,8 @@ interface MyPageDataSource {
suspend fun editProfile(
request: MyPageProfileEditRequestDto
): NonDataBaseResponse
}

suspend fun updateAlarmState(
request : AlarmStatusRequestDto
) : NonDataBaseResponse
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.terning.data.mypage.datasourceimpl
import com.terning.core.network.BaseResponse
import com.terning.core.network.NonDataBaseResponse
import com.terning.data.mypage.datasource.MyPageDataSource
import com.terning.data.mypage.dto.request.AlarmStatusRequestDto
import com.terning.data.mypage.dto.request.MyPageProfileEditRequestDto
import com.terning.data.mypage.dto.response.MyPageResponseDto
import com.terning.data.mypage.service.MyPageService
Expand All @@ -20,4 +21,7 @@ class MyPageDataSourceImpl @Inject constructor(
override suspend fun editProfile(
request: MyPageProfileEditRequestDto
): NonDataBaseResponse = myPageService.editProfile(request)
}

override suspend fun updateAlarmState(request: AlarmStatusRequestDto): NonDataBaseResponse =
myPageService.patchAlarmStatus(request)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.terning.data.mypage.dto.request

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class AlarmStatusRequestDto(
@SerialName("newStatus")
val newStatus: String
)
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,7 @@ data class MyPageResponseDto(
@SerialName("profileImage")
val profileImage: String,
@SerialName("authType")
val authType: String
)
val authType: String,
@SerialName("pushStatus")
val pushStatus: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.terning.data.mypage.mapper

import com.terning.data.mypage.dto.request.AlarmStatusRequestDto
import com.terning.domain.mypage.entity.AlarmStatus

fun AlarmStatus.toAlarmStatusRequestDto(): AlarmStatusRequestDto =
AlarmStatusRequestDto(
newStatus = newStatus
)
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ fun MyPageResponseDto.toMyPageProfile() =
MyPageProfile(
name = name,
profileImage = profileImage,
authType = authType
authType = authType,
alarmStatus = pushStatus
)
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package com.terning.data.mypage.repositoryimpl

import com.terning.data.mypage.datasource.MyPageDataSource
import com.terning.data.mypage.mapper.toAlarmStatusRequestDto
import com.terning.data.mypage.mapper.toMyPageProfile
import com.terning.data.mypage.mapper.toMyPageProfileEditRequestDto
import com.terning.domain.mypage.entity.AlarmStatus
import com.terning.domain.mypage.entity.MyPageProfile
import com.terning.domain.mypage.entity.MyPageProfileEdit
import com.terning.domain.mypage.repository.MyPageRepository
Expand Down Expand Up @@ -34,4 +36,9 @@ class MyPageRepositoryImpl @Inject constructor(
request.toMyPageProfileEditRequestDto()
)
}
}

override suspend fun updateAlarmState(request: AlarmStatus): Result<Unit> =
runCatching {
myPageDataSource.updateAlarmState(request.toAlarmStatusRequestDto())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.terning.data.mypage.service

import com.terning.core.network.BaseResponse
import com.terning.core.network.NonDataBaseResponse
import com.terning.data.mypage.dto.request.AlarmStatusRequestDto
import com.terning.data.mypage.dto.request.MyPageProfileEditRequestDto
import com.terning.data.mypage.dto.response.MyPageResponseDto
import retrofit2.http.Body
Expand All @@ -24,4 +25,9 @@ interface MyPageService {
suspend fun editProfile(
@Body body: MyPageProfileEditRequestDto
): NonDataBaseResponse

@PATCH("api/v1/push-status")
suspend fun patchAlarmStatus(
@Body body: AlarmStatusRequestDto
): NonDataBaseResponse
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.terning.domain.mypage.entity

data class AlarmStatus(
val newStatus: String
)
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ package com.terning.domain.mypage.entity
data class MyPageProfile(
val name: String,
val profileImage: String,
val authType: String
)
val authType: String,
val alarmStatus: String
)
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.terning.domain.mypage.repository

import com.terning.domain.mypage.entity.AlarmStatus
import com.terning.domain.mypage.entity.MyPageProfile
import com.terning.domain.mypage.entity.MyPageProfileEdit

Expand All @@ -13,4 +14,8 @@ interface MyPageRepository {
suspend fun editProfile(
request: MyPageProfileEdit
): Result<Unit>
}

suspend fun updateAlarmState(
request: AlarmStatus
): Result<Unit>
}
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ fun HomeRoute(
viewModel.updatePermissionRequested(true)
}
}
else {
val isAlarmAvailable = viewModel.getAlarmAvailability()
viewModel.updateAlarmAvailability(isAlarmAvailable)
}
}

var hasHandledInternDeeplink by rememberSaveable { mutableStateOf(false) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@ import androidx.paging.PagingData
import androidx.paging.cachedIn
import androidx.paging.map
import com.terning.core.designsystem.state.UiState
import com.terning.core.designsystem.type.AlarmType.DISABLED
import com.terning.core.designsystem.type.AlarmType.ENABLED
import com.terning.core.designsystem.type.SortBy
import com.terning.domain.home.entity.ChangeFilteringRequestModel
import com.terning.domain.home.entity.FcmToken
import com.terning.domain.home.entity.HomeRecommendIntern
import com.terning.domain.home.entity.HomeRecommendedIntern
import com.terning.domain.home.repository.HomeRepository
import com.terning.domain.mypage.entity.AlarmStatus
import com.terning.domain.mypage.repository.MyPageRepository
import com.terning.domain.user.repository.UserRepository
import dagger.hilt.android.lifecycle.HiltViewModel
Expand Down Expand Up @@ -220,6 +223,11 @@ class HomeViewModel @Inject constructor(

fun updateAlarmAvailability(availability: Boolean) {
userRepository.setAlarmAvailable(availability)

viewModelScope.launch {
if (availability) myPageRepository.updateAlarmState(AlarmStatus(ENABLED.value))
else myPageRepository.updateAlarmState(AlarmStatus(DISABLED.value))
}
}

fun updatePermissionRequested(requested: Boolean) {
Expand All @@ -244,4 +252,6 @@ class HomeViewModel @Inject constructor(
).onFailure(Timber::e)
}
}

fun getAlarmAvailability(): Boolean = userRepository.getAlarmAvailable()
}
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,12 @@ fun MyPageRoute(
rememberPermissionState(permission = notificationPermission)
var isChecked by remember {
Copy link
Member

Choose a reason for hiding this comment

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

이 변수는 상태 객체 자체가 바뀌지 않고, 내부 값만 변경되는 구조라서 val로 선언해도 괜찮을 것 같아요!

Suggested change
var isChecked by remember {
val isChecked = remember {

Copy link
Member Author

Choose a reason for hiding this comment

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

말씀해주신 부분 보고 저도 생각을 해 보았는데요..!

사실 저는 by를 써주면 isChecked 변수를 사용할 때 .value를 같이 사용하지 않아도 돼서 가독성이 좋아진다고 생각했었어요..!
그런데 이렇게 by를 써주게 되면 get/set에 대한 위임이 이루어지면서 값이 바뀔 수 있는 var로 사용되어야 하더라구요
val로 선언하고 .value를 같이 사용해주는 것이 좋을까요?

다른 분들의 의견도 궁금하네요!!

Copy link
Member

Choose a reason for hiding this comment

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

var의 경우 상태 객체 자체를 바꿀 수 있어서 조금의 실수라도 방지하기 위해 val을 사용하는게 좋다고 생각했습니다!

Copy link
Member

@Hyobeen-Park Hyobeen-Park May 17, 2025

Choose a reason for hiding this comment

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

저는 by에 한표 드립니당!! 가독성이 더 좋아지고 더 직관적인 것 같아서요!! 그리고 by 사용하면 var이어도 상태 객체 자체를 바꾸지는 못할걸요.....?(아마도... 그치만 아닐 수 있음 주의)

Copy link
Member

Choose a reason for hiding this comment

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

조금 더 찾아보니까 by를 사용하면 상태 값 자체에 접근할 수 있고 효빈이 말처럼 객체 자체를 바꾸진 못한다고 하네요!
이 상황에선 간결성을 위해 var을 유지하는게 맞는 것 같아요!
덕분에 하나 배워갑니다~

mutableStateOf(
if (!permissionState.status.isGranted) false
else viewModel.getAlarmAvailability()
if (!permissionState.status.isGranted) {
viewModel.updateAlarmAvailability(false)
false
} else {
viewModel.getAlarmAvailability()
}
)
}
val notificationSettingsLauncher =
Expand All @@ -106,17 +110,15 @@ fun MyPageRoute(
viewModel.updateAlarmAvailability(isGranted)
}

LaunchedEffect(Unit) {
DisposableEffect(lifecycleOwner) {
systemUiController.setStatusBarColor(color = Back)
}

DisposableEffect(lifecycleOwner) {
onDispose {
systemUiController.setStatusBarColor(color = White)
}
Copy link
Member

Choose a reason for hiding this comment

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

113부터 119가 예전 코드라 태그가 안되네요;;
LaunchedEffect와 DisposableEffect를 합쳐도 되지 않을까 싶네요!

Suggested change
}
DisposableEffect(lifecycleOwner) {
systemUiController.setStatusBarColor(color = Back)
onDispose {
systemUiController.setStatusBarColor(color = White)
}
}

Copy link
Member Author

Choose a reason for hiding this comment

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

오호 혹시 어떻게 합친다는 의미인지 여쭤봐도 될까용...??

LaunchedEffect는 컴포지션이 생성될 때, DisposableEffect는 컴포지션이 사라질 때 적용된다고 생각해서 마이페이지 전용 상태바 색인 Back을 넣구 다른 화면으로 갈 때는 원래 상태바 색인 White로 돌아가게 했었어요..!

Copy link
Member Author

Choose a reason for hiding this comment

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

아! 코드를 제시해주셨군요!! 😅😅 반영해놓겠습니다~ 공부해올게요.

}

LaunchedEffect(key1 = true) {
LaunchedEffect(Unit) {
viewModel.getProfile()
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.terning.feature.mypage.mypage

import com.terning.core.designsystem.state.UiState
import com.terning.core.designsystem.type.AlarmType.DISABLED

data class MyPageState(
val isGetSuccess: UiState<Boolean> = UiState.Loading,
Expand All @@ -13,5 +14,6 @@ data class MyPageState(
val showPersonal: Boolean = false,
val showLogoutBottomSheet: Boolean = false,
val showQuitBottomSheet: Boolean = false,
val showAlarmDialog: Boolean = false
)
val showAlarmDialog: Boolean = false,
val alarmStatus: String = DISABLED.value,
)
Loading