diff --git a/core/designresource/src/main/res/drawable/ic_chat.xml b/core/designresource/src/main/res/drawable/ic_chat.xml index fca6a43ea..0ad34e910 100644 --- a/core/designresource/src/main/res/drawable/ic_chat.xml +++ b/core/designresource/src/main/res/drawable/ic_chat.xml @@ -1,9 +1,9 @@ - + android:width="32dp" + android:height="32dp" + android:viewportWidth="32" + android:viewportHeight="32"> + diff --git a/core/designresource/src/main/res/drawable/ic_chat_checked.xml b/core/designresource/src/main/res/drawable/ic_chat_checked.xml new file mode 100644 index 000000000..71e2dfc58 --- /dev/null +++ b/core/designresource/src/main/res/drawable/ic_chat_checked.xml @@ -0,0 +1,9 @@ + + + diff --git a/core/designresource/src/main/res/drawable/ic_home.xml b/core/designresource/src/main/res/drawable/ic_home.xml index 939c2e1d8..926c5fd22 100644 --- a/core/designresource/src/main/res/drawable/ic_home.xml +++ b/core/designresource/src/main/res/drawable/ic_home.xml @@ -4,6 +4,6 @@ android:viewportWidth="32" android:viewportHeight="32"> diff --git a/core/designresource/src/main/res/drawable/ic_job_posting.xml b/core/designresource/src/main/res/drawable/ic_job_posting.xml index 9b3b99cf0..8c0b7a35a 100644 --- a/core/designresource/src/main/res/drawable/ic_job_posting.xml +++ b/core/designresource/src/main/res/drawable/ic_job_posting.xml @@ -4,7 +4,7 @@ android:viewportWidth="32" android:viewportHeight="32"> diff --git a/core/domain/src/main/kotlin/com/idle/domain/usecase/chatting/GetChatRoomListUseCase.kt b/core/domain/src/main/kotlin/com/idle/domain/usecase/chatting/GetChatRoomListUseCase.kt index f94e7ce89..59c0c1cfa 100644 --- a/core/domain/src/main/kotlin/com/idle/domain/usecase/chatting/GetChatRoomListUseCase.kt +++ b/core/domain/src/main/kotlin/com/idle/domain/usecase/chatting/GetChatRoomListUseCase.kt @@ -15,7 +15,7 @@ class GetChatRoomListUseCase @Inject constructor( createdAt = LocalDateTime.now().minusDays(1), lastMessage = "안녕하세요!안녕하세요!안녕하세요!안녕하세요!안녕하세요!안녕하세요!", lastSentAt = LocalDateTime.now().minusHours(1), - unReadMessageCount = 3, + unReadMessageCount = 99, profileImageUrl = "", ), ChatRoom( @@ -25,7 +25,7 @@ class GetChatRoomListUseCase @Inject constructor( createdAt = LocalDateTime.now().minusDays(3), lastMessage = "오늘 만날 수 있을까요?", lastSentAt = LocalDateTime.now().minusHours(5), - unReadMessageCount = 2, + unReadMessageCount = 100, profileImageUrl = "", ), ChatRoom( diff --git a/core/domain/src/main/kotlin/com/idle/domain/util/NumberUtil.kt b/core/domain/src/main/kotlin/com/idle/domain/util/NumberUtil.kt index 3b9f67680..fb98ba0d7 100644 --- a/core/domain/src/main/kotlin/com/idle/domain/util/NumberUtil.kt +++ b/core/domain/src/main/kotlin/com/idle/domain/util/NumberUtil.kt @@ -39,4 +39,12 @@ fun formatBusinessRegistrationNumber(businessRegistrationNumber: String): String else -> throw IllegalArgumentException("사업자 등록번호 형식이 맞지 않습니다.") } +} + +fun Int.formatUnReadNumber(): String { + return when { + this < 0 -> "0" + this >= 100 -> "99+" + else -> this.toString() + } } \ No newline at end of file diff --git a/core/domain/src/test/kotlin/com/idle/domain/util/NumberUtilTest.kt b/core/domain/src/test/kotlin/com/idle/domain/util/NumberUtilTest.kt index fc376ab83..9caea9ed3 100644 --- a/core/domain/src/test/kotlin/com/idle/domain/util/NumberUtilTest.kt +++ b/core/domain/src/test/kotlin/com/idle/domain/util/NumberUtilTest.kt @@ -118,4 +118,40 @@ class NumberUtilTest { formatBusinessRegistrationNumber(businessRegistrationNumber) } } + + @Test + fun `음수일 경우 0으로 반환된다`() { + // Given + val number = -5 + + // When + val result = number.formatUnReadNumber() + + // Then + assertEquals("0", result) + } + + @Test + fun `99 이하의 숫자는 그대로 문자열로 반환된다`() { + // Given + val number = 99 + + // When + val result = number.formatUnReadNumber() + + // Then + assertEquals("99", result) + } + + @Test + fun `100 이상의 숫자는 '99+'로 반환된다`() { + // Given + val number = 100 + + // When + val result = number.formatUnReadNumber() + + // Then + assertEquals("99+", result) + } } \ No newline at end of file diff --git a/core/network/src/main/java/com/idle/network/source/auth/AuthDataSource.kt b/core/network/src/main/java/com/idle/network/source/auth/AuthDataSource.kt index 2bd63c271..a6607653c 100644 --- a/core/network/src/main/java/com/idle/network/source/auth/AuthDataSource.kt +++ b/core/network/src/main/java/com/idle/network/source/auth/AuthDataSource.kt @@ -16,9 +16,11 @@ import com.idle.network.model.token.TokenResponse import com.idle.network.util.safeApiCall import kotlinx.coroutines.suspendCancellableCoroutine import javax.inject.Inject +import javax.inject.Singleton import kotlin.coroutines.resume import kotlin.coroutines.resumeWithException +@Singleton class AuthDataSource @Inject constructor( private val authApi: AuthApi, private val firebaseMessaging: FirebaseMessaging, diff --git a/core/network/src/main/java/com/idle/network/source/jobposting/JobPostingDataSource.kt b/core/network/src/main/java/com/idle/network/source/jobposting/JobPostingDataSource.kt index 4ce235fa9..60f3ebe29 100644 --- a/core/network/src/main/java/com/idle/network/source/jobposting/JobPostingDataSource.kt +++ b/core/network/src/main/java/com/idle/network/source/jobposting/JobPostingDataSource.kt @@ -16,7 +16,9 @@ import com.idle.network.model.jobposting.GetWorkerJobPostingDetailResponse import com.idle.network.model.jobposting.JobPostingRequest import com.idle.network.util.safeApiCall import javax.inject.Inject +import javax.inject.Singleton +@Singleton class JobPostingDataSource @Inject constructor( private val jobPostingApi: JobPostingApi ) { diff --git a/core/network/src/main/java/com/idle/network/source/notification/NotificationDataSource.kt b/core/network/src/main/java/com/idle/network/source/notification/NotificationDataSource.kt index 579d92bd8..8f8c50a0e 100644 --- a/core/network/src/main/java/com/idle/network/source/notification/NotificationDataSource.kt +++ b/core/network/src/main/java/com/idle/network/source/notification/NotificationDataSource.kt @@ -6,7 +6,9 @@ import com.idle.network.model.notification.GetMyNotificationResponse import com.idle.network.model.notification.GetUnreadNotificationCountResponse import com.idle.network.util.safeApiCall import javax.inject.Inject +import javax.inject.Singleton +@Singleton class NotificationDataSource @Inject constructor( private val notificationApi: NotificationApi ) { diff --git a/core/network/src/main/java/com/idle/network/source/profile/ProfileDataSource.kt b/core/network/src/main/java/com/idle/network/source/profile/ProfileDataSource.kt index 6f9648f1b..55d9c8841 100644 --- a/core/network/src/main/java/com/idle/network/source/profile/ProfileDataSource.kt +++ b/core/network/src/main/java/com/idle/network/source/profile/ProfileDataSource.kt @@ -15,7 +15,9 @@ import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.RequestBody.Companion.toRequestBody import java.io.InputStream import javax.inject.Inject +import javax.inject.Singleton +@Singleton class ProfileDataSource @Inject constructor( private val userApi: UserApi, ) { diff --git a/core/network/src/main/java/com/idle/network/source/remoteconfig/ConfigDataSource.kt b/core/network/src/main/java/com/idle/network/source/remoteconfig/ConfigDataSource.kt index d1c0ae6c2..7c3e3a414 100644 --- a/core/network/src/main/java/com/idle/network/source/remoteconfig/ConfigDataSource.kt +++ b/core/network/src/main/java/com/idle/network/source/remoteconfig/ConfigDataSource.kt @@ -6,9 +6,11 @@ import com.google.firebase.remoteconfig.get import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.serialization.json.Json import javax.inject.Inject +import javax.inject.Singleton import kotlin.coroutines.resume import kotlin.coroutines.resumeWithException +@Singleton class ConfigDataSource @Inject constructor( private val remoteConfig: FirebaseRemoteConfig, ) { diff --git a/feature/center/chatting/src/main/java/com/idle/center/chatting/CenterChattingFragment.kt b/feature/center/chatting/src/main/java/com/idle/center/chatting/CenterChattingFragment.kt index 3f6581e0d..9dd675311 100644 --- a/feature/center/chatting/src/main/java/com/idle/center/chatting/CenterChattingFragment.kt +++ b/feature/center/chatting/src/main/java/com/idle/center/chatting/CenterChattingFragment.kt @@ -44,6 +44,7 @@ import com.idle.designsystem.compose.foundation.CareTheme import com.idle.domain.model.auth.UserType import com.idle.domain.model.chatting.ChatRoom import com.idle.domain.util.formatRelativeDateTime +import com.idle.domain.util.formatUnReadNumber import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint @@ -87,20 +88,47 @@ internal fun CenterChattingScreen( .fillMaxSize() ) { chatRoomList?.let { - LazyColumn( - modifier = Modifier - .fillMaxSize() - .padding(top = 20.dp, bottom = 36.dp), - ) { - items( - items = chatRoomList, - key = { it.id }, - ) { chatRoom -> - ChatRoomItem( - chatRoom = chatRoom, - navigateTo = navigateTo, + if (chatRoomList.isEmpty()) { + Column( + modifier = Modifier + .align(Alignment.Center) + .padding(bottom = 60.dp), + ) { + Text( + text = "아직 채팅 내역이 없어요", + style = CareTheme.typography.heading2, + color = CareTheme.colors.black, + textAlign = TextAlign.Center, + modifier = Modifier + .fillMaxWidth() + .padding(bottom = 8.dp), + ) + + Text( + text = "센터에 궁금한 점이 있다면 해당 공고에서\n" + + "‘채팅하기’ 버튼을 눌러 채팅을 시작할 수 있어요.", + style = CareTheme.typography.body3, + textAlign = TextAlign.Center, + color = CareTheme.colors.gray300, + modifier = Modifier.fillMaxWidth(), ) } + } else { + LazyColumn( + modifier = Modifier + .fillMaxSize() + .padding(top = 20.dp, bottom = 36.dp), + ) { + items( + items = chatRoomList, + key = { it.id }, + ) { chatRoom -> + ChatRoomItem( + chatRoom = chatRoom, + navigateTo = navigateTo, + ) + } + } } } ?: LoadingCircle(modifier = Modifier.align(Alignment.Center)) } @@ -207,7 +235,7 @@ internal fun ChatRoomItem( ) { Text( text = if (chatRoom.unReadMessageCount != 0) - chatRoom.unReadMessageCount.toString() else "", + chatRoom.unReadMessageCount.formatUnReadNumber() else "", style = CareTheme.typography.caption1.copy(fontWeight = FontWeight.Bold), color = CareTheme.colors.white000, textAlign = TextAlign.Center, diff --git a/feature/chatting-detail/src/main/java/com/idle/chatting_detail/component/CareChatTextBubble.kt b/feature/chatting-detail/src/main/java/com/idle/chatting_detail/component/CareChatTextBubble.kt index 1a3b83963..7548ed000 100644 --- a/feature/chatting-detail/src/main/java/com/idle/chatting_detail/component/CareChatTextBubble.kt +++ b/feature/chatting-detail/src/main/java/com/idle/chatting_detail/component/CareChatTextBubble.kt @@ -13,6 +13,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.wrapContentSize +import androidx.compose.foundation.layout.wrapContentWidth import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Text @@ -100,7 +101,7 @@ fun CareChatSenderTextBubbleWithImage( horizontalAlignment = Alignment.Start, modifier = Modifier .padding(start = 4.dp) - .width(35.dp) + .wrapContentWidth() .align(Alignment.Bottom), ) { if (isRead) { diff --git a/feature/worker/chatting/src/main/java/com/idle/worker/chatting/WorkerChattingFragment.kt b/feature/worker/chatting/src/main/java/com/idle/worker/chatting/WorkerChattingFragment.kt index 2f0c6535b..620668079 100644 --- a/feature/worker/chatting/src/main/java/com/idle/worker/chatting/WorkerChattingFragment.kt +++ b/feature/worker/chatting/src/main/java/com/idle/worker/chatting/WorkerChattingFragment.kt @@ -8,8 +8,11 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.widthIn +import androidx.compose.foundation.layout.wrapContentWidth import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.shape.CircleShape @@ -44,6 +47,7 @@ import com.idle.designsystem.compose.foundation.CareTheme import com.idle.domain.model.auth.UserType import com.idle.domain.model.chatting.ChatRoom import com.idle.domain.util.formatRelativeDateTime +import com.idle.domain.util.formatUnReadNumber import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint @@ -87,20 +91,47 @@ internal fun WorkerChattingScreen( .fillMaxSize() ) { chatRoomList?.let { - LazyColumn( - modifier = Modifier - .fillMaxSize() - .padding(top = 20.dp, bottom = 36.dp), - ) { - items( - items = chatRoomList, - key = { it.id }, - ) { chatRoom -> - ChatRoomItem( - chatRoom = chatRoom, - navigateTo = navigateTo, + if (chatRoomList.isEmpty()) { + Column( + modifier = Modifier + .align(Alignment.Center) + .padding(bottom = 60.dp), + ) { + Text( + text = "아직 채팅 내역이 없어요", + style = CareTheme.typography.heading2, + color = CareTheme.colors.black, + textAlign = TextAlign.Center, + modifier = Modifier + .fillMaxWidth() + .padding(bottom = 8.dp), + ) + + Text( + text = "센터에 궁금한 점이 있다면 해당 공고에서\n" + + "‘채팅하기’ 버튼을 눌러 채팅을 시작할 수 있어요.", + style = CareTheme.typography.body3, + textAlign = TextAlign.Center, + color = CareTheme.colors.gray300, + modifier = Modifier.fillMaxWidth(), ) } + } else { + LazyColumn( + modifier = Modifier + .fillMaxSize() + .padding(top = 20.dp, bottom = 36.dp), + ) { + items( + items = chatRoomList, + key = { it.id }, + ) { chatRoom -> + ChatRoomItem( + chatRoom = chatRoom, + navigateTo = navigateTo, + ) + } + } } } ?: LoadingCircle(modifier = Modifier.align(Alignment.Center)) } @@ -201,17 +232,21 @@ internal fun ChatRoomItem( Box( modifier = Modifier - .size(22.dp) + .height(22.dp) + .wrapContentWidth() + .widthIn(min = 22.dp) .clip(RoundedCornerShape(300.dp)) .background(unReadMessageColor), ) { Text( text = if (chatRoom.unReadMessageCount != 0) - chatRoom.unReadMessageCount.toString() else "", + chatRoom.unReadMessageCount.formatUnReadNumber() else "", style = CareTheme.typography.caption1.copy(fontWeight = FontWeight.Bold), color = CareTheme.colors.white000, textAlign = TextAlign.Center, - modifier = Modifier.align(Alignment.Center), + modifier = Modifier + .padding(horizontal = 6.dp) + .align(Alignment.Center), ) } } diff --git a/feature/worker/home/src/main/java/com/idle/worker/home/WorkerHomeFragment.kt b/feature/worker/home/src/main/java/com/idle/worker/home/WorkerHomeFragment.kt index 0676bed5a..10dd93b05 100644 --- a/feature/worker/home/src/main/java/com/idle/worker/home/WorkerHomeFragment.kt +++ b/feature/worker/home/src/main/java/com/idle/worker/home/WorkerHomeFragment.kt @@ -566,7 +566,7 @@ private fun WorkerWorkNetCard( ) Row( - verticalAlignment = Alignment.Top, + verticalAlignment = Alignment.CenterVertically, modifier = Modifier .fillMaxWidth() .padding(bottom = 2.dp) @@ -580,12 +580,11 @@ private fun WorkerWorkNetCard( text = "${jobPosting.workingSchedule} | ${jobPosting.workingTime}", style = CareTheme.typography.body3, color = CareTheme.colors.gray500, - modifier = Modifier.padding(top = 1.dp), ) } Row( - verticalAlignment = Alignment.Top, + verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth(), ) { Image( @@ -597,7 +596,6 @@ private fun WorkerWorkNetCard( text = jobPosting.payInfo, style = CareTheme.typography.body3, color = CareTheme.colors.gray500, - modifier = Modifier.padding(top = 1.dp), ) } } diff --git a/presentation/src/main/res/drawable/selector_menu_chat.xml b/presentation/src/main/res/drawable/selector_menu_chat.xml new file mode 100644 index 000000000..c7dbf9f24 --- /dev/null +++ b/presentation/src/main/res/drawable/selector_menu_chat.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/presentation/src/main/res/menu/menu_center.xml b/presentation/src/main/res/menu/menu_center.xml index e5c402ed9..6427f5c58 100644 --- a/presentation/src/main/res/menu/menu_center.xml +++ b/presentation/src/main/res/menu/menu_center.xml @@ -6,7 +6,7 @@ android:title="홈" />