Skip to content

Commit

Permalink
채팅 구조 변경
Browse files Browse the repository at this point in the history
  • Loading branch information
taewooyo committed Apr 21, 2024
1 parent d39590b commit 423ff4c
Show file tree
Hide file tree
Showing 26 changed files with 327 additions and 189 deletions.
2 changes: 1 addition & 1 deletion app/src/main/java/com/tht/tht/HomeActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import tht.core.ui.base.BaseActivity
import tht.core.ui.base.FragmentNavigator
import tht.core.ui.delegate.viewBinding
import tht.core.ui.extension.hideSoftInput
import tht.feature.chat.ChatFragment
import tht.feature.chat.chat.fragment.ChatFragment
import tht.feature.like.like.LikeFragment
import tht.feature.setting.MyPageFragment
import tht.feature.tohot.tohot.fragment.ToHotFragment
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package tht.core.navigation

import androidx.fragment.app.FragmentManager

interface ChatNavigation {
fun navigateChat(
fragmentManager: FragmentManager,
fragmentContainerResourceId: Int
)
}
9 changes: 2 additions & 7 deletions feature/chat/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<manifest>

<application>
<activity
android:name=".screen.detail.ChatDetailActivity"
android:exported="false" />
</application>

</manifest>
</manifest>
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package tht.feature.chat
package tht.feature.chat.chat.fragment

import android.os.Bundle
import android.view.LayoutInflater
Expand All @@ -8,8 +8,7 @@ import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.ViewCompositionStrategy
import androidx.fragment.app.Fragment
import dagger.hilt.android.AndroidEntryPoint
import tht.feature.chat.screen.ChatScreen
import tht.feature.chat.screen.detail.ChatDetailActivity
import tht.feature.chat.navigation.ChatNavigation

@AndroidEntryPoint
class ChatFragment : Fragment() {
Expand All @@ -25,9 +24,7 @@ class ChatFragment : Fragment() {
return ComposeView(requireContext()).apply {
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setContent {
ChatScreen {
startActivity(ChatDetailActivity.newIntent(requireContext()))
}
ChatNavigation()
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package tht.feature.chat.screen.detail.screen
package tht.feature.chat.chat.screen

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
Expand All @@ -11,11 +11,11 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.hilt.navigation.compose.hiltViewModel
import com.example.compose_ui.common.viewmodel.collectAsState
import tht.feature.chat.chat.state.ChatDetailState
import tht.feature.chat.chat.viewmodel.ChatDetailViewModel
import tht.feature.chat.component.detail.ChatDetailList
import tht.feature.chat.component.detail.ChatDetailTopAppBar
import tht.feature.chat.component.detail.ChatEditTextContainer
import tht.feature.chat.viewmodel.detail.ChatDetailViewModel
import tht.feature.chat.viewmodel.detail.state.ChatDetailState

@Composable
internal fun ChatDetailScreen(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package tht.feature.chat.chat.screen

import androidx.compose.foundation.Image
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import com.example.compose_ui.component.button.ThtButton
import com.example.compose_ui.component.text.headline.ThtHeadline4
import com.example.compose_ui.component.text.headline.ThtHeadline5
import com.example.compose_ui.component.text.p.ThtP1
import tht.feature.chat.R

@Composable
internal fun ChatEmptyScreen(
onClickChangeTitle: () -> Unit
) {
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Image(
painter = painterResource(id = R.drawable.ic_empty),
contentDescription = null
)
Spacer(modifier = Modifier.height(16.dp))
ThtHeadline4(
text = "아직 매칭된 무디가 없어요",
fontWeight = FontWeight.W600,
color = Color.White
)
Spacer(modifier = Modifier.height(6.dp))
ThtP1(
text = "대화가 잘 통하는 무디를 찾아볼까요?",
fontWeight = FontWeight.W400,
color = Color(0xFF8D8D8D)
)
}
Spacer(modifier = Modifier.height(64.dp))
ThtButton(
modifier = Modifier
.clip(RoundedCornerShape(16.dp))
.border(1.dp, Color.White, RoundedCornerShape(16.dp))
.padding(horizontal = 70.dp),
backgroundColor = Color.Transparent,
contentColor = Color.White,
onClick = onClickChangeTitle,
content = {
ThtHeadline5(
text = "무디들 만나러 가기",
fontWeight = FontWeight.W700,
color = Color.White
)
}
)
Spacer(modifier = Modifier.height(56.dp))
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package tht.feature.chat.screen.chatlist
package tht.feature.chat.chat.screen

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import tht.feature.chat.component.LazyColumnChatItem
import tht.feature.chat.viewmodel.state.ChatState
import tht.feature.chat.chat.state.ChatState

@Composable
internal fun ChatListScreen(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package tht.feature.chat.screen
package tht.feature.chat.chat.screen

import androidx.compose.animation.Crossfade
import androidx.compose.animation.core.tween
Expand All @@ -15,17 +15,16 @@ import androidx.hilt.navigation.compose.hiltViewModel
import com.example.compose_ui.R
import com.example.compose_ui.common.viewmodel.collectAsState
import tht.feature.chat.component.ChatTopAppBar
import tht.feature.chat.screen.chatlist.ChatListScreen
import tht.feature.chat.viewmodel.chatlist.ChatViewModel
import tht.feature.chat.viewmodel.state.ChatState
import tht.feature.chat.chat.viewmodel.ChatViewModel
import tht.feature.chat.chat.state.ChatState

@Composable
internal fun ChatScreen(
viewModel: ChatViewModel = hiltViewModel(),
navigateChatDetail: () -> Unit = { }
) {
LaunchedEffect(key1 = Unit) {
viewModel.getChatList()
viewModel.getFakeChatList()
}

val state = viewModel.collectAsState().value
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package tht.feature.chat.chat.screen

import android.os.Build
import androidx.annotation.RequiresApi
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.LifecycleOwner
import java.time.Instant
import java.time.LocalDateTime
import java.time.ZoneOffset
import java.time.format.DateTimeFormatter

@Composable
fun OnLifecycleEvent(
onEvent: (
owner: LifecycleOwner,
event: Lifecycle.Event,
) -> Unit
) {
val eventHandler = rememberUpdatedState(onEvent)
val lifecycleOwner = rememberUpdatedState(LocalLifecycleOwner.current)

DisposableEffect(lifecycleOwner.value) {
val lifecycle = lifecycleOwner.value.lifecycle
val observer = LifecycleEventObserver { owner, event ->
eventHandler.value(owner, event)
}

lifecycle.addObserver(observer)
onDispose {
lifecycle.removeObserver(observer)
}
}
}

@RequiresApi(Build.VERSION_CODES.O)
fun format(milliseconds: Long): String {
return LocalDateTime.ofInstant(
Instant.ofEpochMilli(milliseconds),
ZoneOffset.systemDefault()
).format(DateTimeFormatter.ISO_DATE)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package tht.feature.chat.chat.state

sealed class ChatDetailSideEffect
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package tht.feature.chat.viewmodel.detail.state
package tht.feature.chat.chat.state

import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package tht.feature.chat.chat.state

sealed class ChatSideEffect
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package tht.feature.chat.viewmodel.state
package tht.feature.chat.chat.state

import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package tht.feature.chat.viewmodel.detail
package tht.feature.chat.chat.viewmodel

import androidx.lifecycle.ViewModel
import com.example.compose_ui.common.viewmodel.Container
Expand All @@ -10,21 +10,19 @@ import kotlinx.collections.immutable.persistentListOf
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import tht.feature.chat.chat.state.ChatDetailSideEffect
import tht.feature.chat.chat.state.ChatDetailState
import tht.feature.chat.model.ChatListUiModel
import tht.feature.chat.viewmodel.detail.sideeffect.ChatDetailSideEffect
import tht.feature.chat.viewmodel.detail.state.ChatDetailState
import tht.feature.chat.viewmodel.state.skeletonChatList
import javax.inject.Inject

@HiltViewModel
internal class ChatDetailViewModel @Inject constructor() :
ViewModel(),
Container<ChatDetailState, ChatDetailSideEffect> {
internal class ChatDetailViewModel @Inject constructor(
) : ViewModel(), Container<ChatDetailState, ChatDetailSideEffect> {
override val store: Store<ChatDetailState, ChatDetailSideEffect> =
store(
initialState = ChatDetailState.ChatList(
isLoading = true,
chatList = skeletonChatList
chatList = persistentListOf()
)
)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package tht.feature.chat.chat.viewmodel

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.compose_ui.common.viewmodel.Container
import com.example.compose_ui.common.viewmodel.Store
import com.example.compose_ui.common.viewmodel.intent
import com.example.compose_ui.common.viewmodel.store
import com.tht.tht.domain.chat.model.ChatListModel
import com.tht.tht.domain.chat.usecase.GetChatListUseCase
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.launch
import tht.feature.chat.chat.state.ChatSideEffect
import tht.feature.chat.chat.state.ChatState
import tht.feature.chat.mapper.toModel
import javax.inject.Inject

@HiltViewModel
internal class ChatViewModel @Inject constructor(
private val getChatListUseCase: GetChatListUseCase
) : ViewModel(), Container<ChatState, ChatSideEffect> {
override val store: Store<ChatState, ChatSideEffect> =
store(initialState = ChatState.ChatList(isLoading = true, chatList = persistentListOf()))

fun getChatList() {
viewModelScope.launch {
val chatList = getChatListUseCase().getOrNull() ?: listOf()
intent {
reduce {
if (chatList.isEmpty()) {
ChatState.Empty
} else {
ChatState.ChatList(
isLoading = false,
chatList = chatList.map { it.toModel() }.toImmutableList()
)
}
}
}
}
}

fun getFakeChatList() {
viewModelScope.launch {
intent {
reduce {
ChatState.ChatList(
isLoading = false,
chatList = listOf(
ChatListModel(
chatRoomIdx = 1L,
partnerName = "최웅재",
partnerProfileUrl = "",
currentMessage = "안녕",
messageTime = "2020.08.08"
),
ChatListModel(
chatRoomIdx = 2L,
partnerName = "최웅재",
partnerProfileUrl = "",
currentMessage = "안녕",
messageTime = "2020.08.08"
),
ChatListModel(
chatRoomIdx = 3L,
partnerName = "최웅재",
partnerProfileUrl = "",
currentMessage = "안녕",
messageTime = "2020.08.08"
), ChatListModel(
chatRoomIdx = 4L,
partnerName = "최웅재",
partnerProfileUrl = "",
currentMessage = "안녕",
messageTime = "2020.08.08"
)
).map { it.toModel() }.toImmutableList()
)
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package tht.feature.chat.navigation

interface ChatDestination {
val route: String
}

object Chat : ChatDestination {
override val route: String = "chat"
}

object ChatDetail : ChatDestination {
override val route: String = "chat-detail"
}
Loading

0 comments on commit 423ff4c

Please sign in to comment.