diff --git a/app/src/main/ic_launcher-playstore.png b/app/src/main/ic_launcher-playstore.png new file mode 100644 index 00000000..1ed697a6 Binary files /dev/null and b/app/src/main/ic_launcher-playstore.png differ diff --git a/app/src/main/java/com/texthip/thip/data/model/feed/response/FeedMineInfoResponse.kt b/app/src/main/java/com/texthip/thip/data/model/feed/response/FeedMineInfoResponse.kt index 9a6777f4..5417e0d5 100644 --- a/app/src/main/java/com/texthip/thip/data/model/feed/response/FeedMineInfoResponse.kt +++ b/app/src/main/java/com/texthip/thip/data/model/feed/response/FeedMineInfoResponse.kt @@ -5,7 +5,7 @@ import kotlinx.serialization.Serializable @Serializable data class FeedMineInfoResponse( - @SerialName("creatorId") val creatorId: Int, + @SerialName("creatorId") val creatorId: Long, @SerialName("profileImageUrl") val profileImageUrl: String?, @SerialName("nickname") val nickname: String, @SerialName("aliasName") val aliasName: String, diff --git a/app/src/main/java/com/texthip/thip/data/model/feed/response/FeedUsersInfoResponse.kt b/app/src/main/java/com/texthip/thip/data/model/feed/response/FeedUsersInfoResponse.kt index ac5c5b06..a10cde7f 100644 --- a/app/src/main/java/com/texthip/thip/data/model/feed/response/FeedUsersInfoResponse.kt +++ b/app/src/main/java/com/texthip/thip/data/model/feed/response/FeedUsersInfoResponse.kt @@ -4,7 +4,7 @@ import kotlinx.serialization.Serializable @Serializable data class FeedUsersInfoResponse( - val creatorId: Int, + val creatorId: Long, val profileImageUrl: String, val nickname: String, val aliasName: String, diff --git a/app/src/main/java/com/texthip/thip/ui/common/forms/WarningTextField.kt b/app/src/main/java/com/texthip/thip/ui/common/forms/WarningTextField.kt index d5f433d2..bec351f1 100644 --- a/app/src/main/java/com/texthip/thip/ui/common/forms/WarningTextField.kt +++ b/app/src/main/java/com/texthip/thip/ui/common/forms/WarningTextField.kt @@ -73,6 +73,7 @@ fun WarningTextField( modifier = Modifier.fillMaxSize(), shape = RoundedCornerShape(12.dp), colors = TextFieldDefaults.colors( + unfocusedTextColor = colors.White, focusedTextColor = colors.White, focusedIndicatorColor = if (showWarning) colors.Red else Color.Transparent, unfocusedIndicatorColor = if (showWarning) colors.Red else Color.Transparent, diff --git a/app/src/main/java/com/texthip/thip/ui/common/header/AuthorHeader.kt b/app/src/main/java/com/texthip/thip/ui/common/header/AuthorHeader.kt index 7cd96399..ded4c777 100644 --- a/app/src/main/java/com/texthip/thip/ui/common/header/AuthorHeader.kt +++ b/app/src/main/java/com/texthip/thip/ui/common/header/AuthorHeader.kt @@ -45,12 +45,13 @@ fun AuthorHeader( thipNum: Int? = null, profileImageSize: Dp = 54.dp, onButtonClick: () -> Unit = {}, - onThipNumClick: () -> Unit = {} + onClick: () -> Unit = {} ) { Row( modifier = modifier .fillMaxWidth() - .padding(horizontal = 20.dp), + .padding(horizontal = 20.dp) + .clickable(onClick = onClick), verticalAlignment = Alignment.CenterVertically ) { if (profileImage != null) { @@ -98,7 +99,6 @@ fun AuthorHeader( } if (showThipNum && thipNum != null) { Row( - modifier = Modifier.clickable(onClick = onThipNumClick), verticalAlignment = Alignment.CenterVertically ) { Text( @@ -139,10 +139,7 @@ fun PreviewAuthorHeader() { badgeTextColor = colors.Yellow, showButton = false, showThipNum = true, - thipNum = 10, - onThipNumClick = { - - } + thipNum = 10 ) } } diff --git a/app/src/main/java/com/texthip/thip/ui/feed/component/LiveSearchPeopleResult.kt b/app/src/main/java/com/texthip/thip/ui/feed/component/LiveSearchPeopleResult.kt index 438aeb9c..07978b37 100644 --- a/app/src/main/java/com/texthip/thip/ui/feed/component/LiveSearchPeopleResult.kt +++ b/app/src/main/java/com/texthip/thip/ui/feed/component/LiveSearchPeopleResult.kt @@ -34,7 +34,7 @@ fun SearchPeopleResult( showButton = false, showThipNum = true, thipNum = user.subscriberCount, - onThipNumClick = { onThipNumClick(user) } + onClick = { onThipNumClick(user) } ) if (index < peopleList.size - 1) { Spacer( diff --git a/app/src/main/java/com/texthip/thip/ui/feed/component/OthersFeedCard.kt b/app/src/main/java/com/texthip/thip/ui/feed/component/OthersFeedCard.kt index d8aef755..41333397 100644 --- a/app/src/main/java/com/texthip/thip/ui/feed/component/OthersFeedCard.kt +++ b/app/src/main/java/com/texthip/thip/ui/feed/component/OthersFeedCard.kt @@ -8,10 +8,6 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.layout.ContentScale @@ -35,12 +31,11 @@ fun OthersFeedCard( val hasImages = images.isNotEmpty() val maxLines = if (hasImages) 3 else 8 - var isLiked by remember { mutableStateOf(false) } - Column( modifier = modifier .fillMaxWidth() .padding(horizontal = 20.dp) + .clickable { onContentClick() } ) { ActionBookButton( bookTitle = feedItem.bookTitle, @@ -56,7 +51,6 @@ fun OthersFeedCard( modifier = Modifier .fillMaxWidth() .padding(vertical = 16.dp) - .clickable { onContentClick() } ) if (hasImages) { @@ -86,9 +80,6 @@ fun OthersFeedCard( isSaveVisible = true, onLikeClick = { // onLikeClick(feedItem.feedId) - }, - onCommentClick = { -// onCommentClick() }, onBookmarkClick = { diff --git a/app/src/main/java/com/texthip/thip/ui/feed/screen/FeedCommentScreen.kt b/app/src/main/java/com/texthip/thip/ui/feed/screen/FeedCommentScreen.kt index 99fb656a..41177047 100644 --- a/app/src/main/java/com/texthip/thip/ui/feed/screen/FeedCommentScreen.kt +++ b/app/src/main/java/com/texthip/thip/ui/feed/screen/FeedCommentScreen.kt @@ -9,15 +9,18 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.ime import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Text @@ -31,8 +34,11 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.blur +import androidx.compose.ui.focus.FocusRequester +import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview @@ -147,6 +153,18 @@ fun FeedCommentScreen( var selectedCommentId by remember { mutableStateOf(null) } val focusManager = LocalFocusManager.current + val focusRequester = remember { FocusRequester() } + val listState = rememberLazyListState() + + val isKeyboardVisible = WindowInsets.ime.getBottom(LocalDensity.current) > 0 + + LaunchedEffect(isKeyboardVisible) { + if (!isKeyboardVisible) { + replyingToCommentId = null + replyingToNickname = null + focusManager.clearFocus() + } + } Box( modifier = Modifier @@ -179,6 +197,7 @@ fun FeedCommentScreen( ) LazyColumn( + state = listState, modifier = modifier .fillMaxWidth() .weight(1f), @@ -334,6 +353,7 @@ fun FeedCommentScreen( replyingToCommentId = commentId replyingToNickname = nickname selectedCommentId = null + focusRequester.requestFocus() }, onCommentLongPress = { comment -> selectedCommentId = comment.commentId @@ -353,7 +373,7 @@ fun FeedCommentScreen( // 댓글 입력창 CommentTextField( -// modifier = Modifier.align(Alignment.BottomCenter), + modifier = Modifier.focusRequester(focusRequester), input = commentInput, hint = stringResource(R.string.reply_to), onInputChange = { commentInput = it }, diff --git a/app/src/main/java/com/texthip/thip/ui/feed/screen/FeedOthersScreen.kt b/app/src/main/java/com/texthip/thip/ui/feed/screen/FeedOthersScreen.kt index 84d14767..f52d41a7 100644 --- a/app/src/main/java/com/texthip/thip/ui/feed/screen/FeedOthersScreen.kt +++ b/app/src/main/java/com/texthip/thip/ui/feed/screen/FeedOthersScreen.kt @@ -39,6 +39,8 @@ import com.texthip.thip.utils.color.hexToColor @Composable fun FeedOthersScreen( onNavigateBack: () -> Unit, + onNavigateToSubscriptionList: (userId: Long) -> Unit = {}, + onNavigateToFeedComment: (feedId: Long) -> Unit = {}, viewModel: FeedOthersViewModel = hiltViewModel() ) { val uiState by viewModel.uiState.collectAsState() @@ -46,7 +48,9 @@ fun FeedOthersScreen( FeedOthersContent( uiState = uiState, onNavigateBack = onNavigateBack, - onLikeClick = { feedId -> viewModel.changeFeedLike(feedId) } + onLikeClick = { feedId -> viewModel.changeFeedLike(feedId) }, + onNavigateToSubscriptionList = onNavigateToSubscriptionList, + onNavigateToFeedComment = onNavigateToFeedComment ) } @@ -54,7 +58,9 @@ fun FeedOthersScreen( fun FeedOthersContent( uiState: FeedOthersUiState, onNavigateBack: () -> Unit, - onLikeClick: (Long) -> Unit + onLikeClick: (Long) -> Unit, + onNavigateToSubscriptionList: (userId: Long) -> Unit, + onNavigateToFeedComment: (feedId: Long) -> Unit = {}, ) { val userInfo = uiState.userInfo @@ -96,7 +102,7 @@ fun FeedOthersContent( FeedSubscribeBarlist( modifier = Modifier.padding(horizontal = 20.dp), followerProfileImageUrls = userInfo.latestFollowerProfileImageUrls, - onClick = {} + onClick = { onNavigateToSubscriptionList(userInfo.creatorId) } ) Spacer(modifier = Modifier.height(40.dp)) Text( @@ -137,7 +143,7 @@ fun FeedOthersContent( OthersFeedCard( feedItem = feed, onLikeClick = { onLikeClick(feed.feedId) }, - onContentClick = { /* TODO: 피드 상세 댓글 화면으로 이동 */ } + onContentClick = { onNavigateToFeedComment(feed.feedId) } ) Spacer(modifier = Modifier.height(40.dp)) if (index < uiState.feeds.lastIndex) { @@ -187,7 +193,8 @@ private fun FeedOthersScreenPrev() { feeds = mockFeeds ), onNavigateBack = {}, - onLikeClick = {} + onLikeClick = {}, + onNavigateToSubscriptionList = {} ) } } \ No newline at end of file diff --git a/app/src/main/java/com/texthip/thip/ui/feed/screen/FeedScreen.kt b/app/src/main/java/com/texthip/thip/ui/feed/screen/FeedScreen.kt index 01f71cf4..6f18edc1 100644 --- a/app/src/main/java/com/texthip/thip/ui/feed/screen/FeedScreen.kt +++ b/app/src/main/java/com/texthip/thip/ui/feed/screen/FeedScreen.kt @@ -72,6 +72,7 @@ fun FeedScreen( onNavigateToBookDetail: (String) -> Unit = {}, resultFeedId: Long? = null, onNavigateToUserProfile: (userId: Long) -> Unit = {}, + onNavigateToOthersSubscription: (userId: Long) -> Unit = {}, onResultConsumed: () -> Unit = {}, navController: NavHostController, feedViewModel: FeedViewModel = hiltViewModel(), @@ -240,6 +241,9 @@ fun FeedScreen( modifier = Modifier.padding(horizontal = 20.dp), followerProfileImageUrls = myFeedInfo?.latestFollowerProfileImageUrls ?: emptyList(), onClick = { + myFeedInfo?.creatorId?.let { creatorId -> + onNavigateToOthersSubscription(creatorId) + } } ) Spacer(modifier = Modifier.height(40.dp)) diff --git a/app/src/main/java/com/texthip/thip/ui/feed/screen/MySubscriptionListScreen.kt b/app/src/main/java/com/texthip/thip/ui/feed/screen/MySubscriptionListScreen.kt index 6bbbdbe7..c1cea5d8 100644 --- a/app/src/main/java/com/texthip/thip/ui/feed/screen/MySubscriptionListScreen.kt +++ b/app/src/main/java/com/texthip/thip/ui/feed/screen/MySubscriptionListScreen.kt @@ -1,7 +1,6 @@ package com.texthip.thip.ui.feed.screen import androidx.compose.foundation.background -import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues @@ -152,7 +151,7 @@ fun MySubscriptionContent( items = uiState.followings, key = { _, user -> user.userId } ) { index, user -> - Column(modifier = Modifier.padding(horizontal = 20.dp).clickable { onUserClick(user.userId) }) { + Column(modifier = Modifier.padding(horizontal = 20.dp)) { AuthorHeader( profileImage = user.profileImageUrl, nickname = user.nickname, @@ -162,6 +161,7 @@ fun MySubscriptionContent( buttonWidth = 64.dp, profileImageSize = 36.dp, onButtonClick = { onToggleFollow(user.userId, user.nickname) }, + onClick = { onUserClick(user.userId) } ) if (index < uiState.followings.lastIndex) { diff --git a/app/src/main/java/com/texthip/thip/ui/feed/screen/OthersSubscriptionListScreen.kt b/app/src/main/java/com/texthip/thip/ui/feed/screen/OthersSubscriptionListScreen.kt index d34d19af..eed1ee27 100644 --- a/app/src/main/java/com/texthip/thip/ui/feed/screen/OthersSubscriptionListScreen.kt +++ b/app/src/main/java/com/texthip/thip/ui/feed/screen/OthersSubscriptionListScreen.kt @@ -29,7 +29,6 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel -import androidx.navigation.NavController import com.texthip.thip.R import com.texthip.thip.data.model.users.response.FollowerList import com.texthip.thip.ui.common.header.AuthorHeader @@ -42,8 +41,9 @@ import com.texthip.thip.ui.theme.ThipTheme.typography import com.texthip.thip.utils.color.hexToColor @Composable -fun OthersSubsciptionListScreen( - navController: NavController, +fun OthersSubscriptionListScreen( + onNavigateBack: () -> Unit, + onNavigateToUserProfile: (userId: Long) -> Unit = {}, viewModel: OthersSubscriptionViewModel = hiltViewModel() ) { val uiState by viewModel.uiState.collectAsState() @@ -64,17 +64,19 @@ fun OthersSubsciptionListScreen( } } - OthersSubsciptionContent( + OthersSubscriptionContent( uiState = uiState, lazyListState = lazyListState, - onNavigateBack = { navController.popBackStack() } + onNavigateBack = onNavigateBack, + onProfileClick = onNavigateToUserProfile ) } @Composable -fun OthersSubsciptionContent( +fun OthersSubscriptionContent( uiState: OthersSubscriptionUiState, lazyListState: LazyListState, - onNavigateBack: () -> Unit + onNavigateBack: () -> Unit, + onProfileClick: (userId: Long) -> Unit ) { Column( Modifier @@ -120,7 +122,7 @@ fun OthersSubsciptionContent( showThipNum = true, profileImageSize = 36.dp, thipNum = user.followerCount, - onThipNumClick = {} + onClick = { onProfileClick(user.userId) } ) if (index < uiState.followers.lastIndex) { @@ -154,7 +156,7 @@ fun OthersSubsciptionContent( } @Preview @Composable -private fun OthersSubsciptionListScreenPrev() { +private fun OthersSubscriptionListScreenPrev() { val mockUsers = (1..10).map { FollowerList( userId = it.toLong(), @@ -167,7 +169,7 @@ private fun OthersSubsciptionListScreenPrev() { } ThipTheme { - OthersSubsciptionContent( + OthersSubscriptionContent( uiState = OthersSubscriptionUiState( isLoading = false, followers = mockUsers, @@ -175,7 +177,8 @@ private fun OthersSubsciptionListScreenPrev() { isLastPage = false ), lazyListState = rememberLazyListState(), - onNavigateBack = {} + onNavigateBack = {}, + onProfileClick = {} ) } } \ No newline at end of file diff --git a/app/src/main/java/com/texthip/thip/ui/group/note/component/CommentBottomSheet.kt b/app/src/main/java/com/texthip/thip/ui/group/note/component/CommentBottomSheet.kt index eae22f65..91ca3229 100644 --- a/app/src/main/java/com/texthip/thip/ui/group/note/component/CommentBottomSheet.kt +++ b/app/src/main/java/com/texthip/thip/ui/group/note/component/CommentBottomSheet.kt @@ -3,11 +3,14 @@ package com.texthip.thip.ui.group.note.component import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.ime import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material3.CircularProgressIndicator @@ -22,9 +25,14 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.blur +import androidx.compose.ui.focus.FocusRequester +import androidx.compose.ui.focus.focusRequester +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel import com.texthip.thip.R import com.texthip.thip.data.model.comments.response.CommentList import com.texthip.thip.data.model.comments.response.ReplyList @@ -34,6 +42,7 @@ import com.texthip.thip.ui.common.bottomsheet.MenuBottomSheet import com.texthip.thip.ui.common.forms.CommentTextField import com.texthip.thip.ui.group.note.viewmodel.CommentsEvent import com.texthip.thip.ui.group.note.viewmodel.CommentsUiState +import com.texthip.thip.ui.group.note.viewmodel.CommentsViewModel import com.texthip.thip.ui.group.room.mock.MenuBottomSheetItem import com.texthip.thip.ui.theme.ThipTheme import com.texthip.thip.ui.theme.ThipTheme.colors @@ -43,10 +52,9 @@ import com.texthip.thip.utils.rooms.advancedImePadding @Composable fun CommentBottomSheet( uiState: CommentsUiState, - onEvent: (CommentsEvent) -> Unit, onDismiss: () -> Unit, - onSendReply: (text: String, parentCommentId: Int?, replyToNickname: String?) -> Unit, - onProfileClick: (userId: Long) -> Unit = {} + onProfileClick: (userId: Long) -> Unit = {}, + viewModel: CommentsViewModel = hiltViewModel(), ) { var inputText by remember { mutableStateOf("") } var replyingToCommentId by remember { mutableStateOf(null) } @@ -57,6 +65,21 @@ fun CommentBottomSheet( val isOverlayVisible = selectedCommentForMenu != null || selectedReplyForMenu != null + val focusRequester = remember { FocusRequester() } + val listState = rememberLazyListState() + + val focusManager = LocalFocusManager.current + + val isKeyboardVisible = WindowInsets.ime.getBottom(LocalDensity.current) > 0 + + LaunchedEffect(isKeyboardVisible) { + if (!isKeyboardVisible) { + replyingToCommentId = null + replyingToNickname = null + focusManager.clearFocus() + } + } + Box( if (isOverlayVisible) { Modifier @@ -98,15 +121,18 @@ fun CommentBottomSheet( EmptyCommentView() } else { CommentLazyList( + listState = listState, commentList = uiState.comments, isLoadingMore = uiState.isLoadingMore, isLastPage = uiState.isLast, - onLoadMore = { onEvent(CommentsEvent.LoadMoreComments) }, + onLoadMore = { viewModel.onEvent(CommentsEvent.LoadMoreComments) }, onReplyClick = { commentId, nickname -> replyingToCommentId = commentId replyingToNickname = nickname + + focusRequester.requestFocus() }, - onEvent = onEvent, + onEvent = viewModel::onEvent, onCommentLongPress = { comment -> selectedCommentForMenu = comment }, @@ -118,19 +144,23 @@ fun CommentBottomSheet( } CommentTextField( - modifier = Modifier.fillMaxWidth(), + modifier = Modifier + .fillMaxWidth() + .focusRequester(focusRequester), hint = stringResource(R.string.reply_to), input = inputText, onInputChange = { inputText = it }, onSendClick = { - onSendReply( - inputText, - replyingToCommentId, - replyingToNickname + viewModel.onEvent( + CommentsEvent.CreateComment( + content = inputText, + parentId = replyingToCommentId + ) ) inputText = "" replyingToCommentId = null replyingToNickname = null + focusManager.clearFocus() }, replyTo = replyingToNickname, onCancelReply = { @@ -162,7 +192,7 @@ fun CommentBottomSheet( is ReplyList -> item.commentId else -> null } - commentId?.let { onEvent(CommentsEvent.DeleteComment(it)) } + commentId?.let { viewModel.onEvent(CommentsEvent.DeleteComment(it)) } selectedCommentForMenu = null selectedReplyForMenu = null @@ -192,6 +222,7 @@ fun CommentBottomSheet( @Composable private fun CommentLazyList( + listState: LazyListState, commentList: List, isLoadingMore: Boolean, isLastPage: Boolean, @@ -202,11 +233,9 @@ private fun CommentLazyList( onReplyLongPress: (ReplyList) -> Unit, onProfileClick: (userId: Long) -> Unit ) { - val lazyListState = rememberLazyListState() - val isScrolledToEnd by remember { derivedStateOf { - val layoutInfo = lazyListState.layoutInfo + val layoutInfo = listState.layoutInfo if (layoutInfo.totalItemsCount == 0) return@derivedStateOf false val lastVisibleItemIndex = layoutInfo.visibleItemsInfo.lastOrNull()?.index ?: 0 lastVisibleItemIndex >= layoutInfo.totalItemsCount - 1 @@ -219,7 +248,7 @@ private fun CommentLazyList( } } - LazyColumn(state = lazyListState) { + LazyColumn(state = listState) { items( items = commentList, key = { comment -> @@ -310,9 +339,7 @@ private fun CommentBottomSheetPreview() { isLoadingMore = false, isLast = false ), - onEvent = {}, onDismiss = { showSheet = false }, - onSendReply = { _, _, _ -> } ) } } diff --git a/app/src/main/java/com/texthip/thip/ui/group/note/screen/GroupNoteScreen.kt b/app/src/main/java/com/texthip/thip/ui/group/note/screen/GroupNoteScreen.kt index 9b39a3f5..893ca1b5 100644 --- a/app/src/main/java/com/texthip/thip/ui/group/note/screen/GroupNoteScreen.kt +++ b/app/src/main/java/com/texthip/thip/ui/group/note/screen/GroupNoteScreen.kt @@ -57,7 +57,6 @@ import com.texthip.thip.ui.group.note.component.CommentBottomSheet import com.texthip.thip.ui.group.note.component.FilterHeaderSection import com.texthip.thip.ui.group.note.component.TextCommentCard import com.texthip.thip.ui.group.note.component.VoteCommentCard -import com.texthip.thip.ui.group.note.viewmodel.CommentsEvent import com.texthip.thip.ui.group.note.viewmodel.CommentsViewModel import com.texthip.thip.ui.group.note.viewmodel.GroupNoteEvent import com.texthip.thip.ui.group.note.viewmodel.GroupNoteSideEffect @@ -503,23 +502,13 @@ fun GroupNoteContent( } CommentBottomSheet( + viewModel = commentsViewModel, uiState = commentsUiState, - onEvent = commentsViewModel::onEvent, onDismiss = { isCommentBottomSheetVisible = false selectedPostForComment = null onEvent(GroupNoteEvent.RefreshPosts) }, - onSendReply = { text, parentId, _ -> - if (text.isNotBlank()) { - commentsViewModel.onEvent( - CommentsEvent.CreateComment( - content = text, - parentId = parentId - ) - ) - } - }, onProfileClick = onNavigateToUserProfile ) } diff --git a/app/src/main/java/com/texthip/thip/ui/group/note/viewmodel/CommentsViewModel.kt b/app/src/main/java/com/texthip/thip/ui/group/note/viewmodel/CommentsViewModel.kt index dc6cdd01..4d254c96 100644 --- a/app/src/main/java/com/texthip/thip/ui/group/note/viewmodel/CommentsViewModel.kt +++ b/app/src/main/java/com/texthip/thip/ui/group/note/viewmodel/CommentsViewModel.kt @@ -6,7 +6,9 @@ import com.texthip.thip.data.model.comments.response.CommentList import com.texthip.thip.data.model.comments.response.ReplyList import com.texthip.thip.data.repository.CommentsRepository import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch @@ -20,6 +22,10 @@ data class CommentsUiState( val comments: List = emptyList() ) +sealed interface CommentSideEffect { + data class ScrollToItem(val parentCommentId: Int?) : CommentSideEffect +} + sealed interface CommentsEvent { data object LoadMoreComments : CommentsEvent data class LikeComment(val commentId: Int) : CommentsEvent // 댓글 좋아요 이벤트 @@ -36,6 +42,9 @@ class CommentsViewModel @Inject constructor( private val _uiState = MutableStateFlow(CommentsUiState()) val uiState = _uiState.asStateFlow() + private val _sideEffect = MutableSharedFlow() + val sideEffect = _sideEffect.asSharedFlow() + private var nextCursor: String? = null private var currentPostId: Long = -1L private var currentPostType: String = "RECORD" @@ -137,20 +146,11 @@ class CommentsViewModel @Inject constructor( currentState.comments.indexOfFirst { it.commentId == parentId } if (parentCommentIndex != -1) { - val updatedParentComment = CommentList( - commentId = res.commentId, - creatorId = res.creatorId, - creatorProfileImageUrl = res.creatorProfileImageUrl, - creatorNickname = res.creatorNickname, - aliasName = res.aliasName, - aliasColor = res.aliasColor, - postDate = res.postDate, - content = res.content, - likeCount = res.likeCount, - isDeleted = res.isDeleted, - isWriter = res.isWriter, - isLike = res.isLike, - replyList = res.replyList + val originalParentComment = + currentState.comments[parentCommentIndex] + + val updatedParentComment = originalParentComment.copy( + replyList = originalParentComment.replyList + res.replyList ) val newCommentsList = currentState.comments.toMutableList().apply { @@ -162,6 +162,8 @@ class CommentsViewModel @Inject constructor( } } } + + _sideEffect.emit(CommentSideEffect.ScrollToItem(parentId)) } }.onFailure { throwable -> _uiState.update { it.copy(error = "댓글 작성 실패: ${throwable.message}") } diff --git a/app/src/main/java/com/texthip/thip/ui/navigator/extensions/FeedNavigationExtensions.kt b/app/src/main/java/com/texthip/thip/ui/navigator/extensions/FeedNavigationExtensions.kt index 88f892c1..8b4cad32 100644 --- a/app/src/main/java/com/texthip/thip/ui/navigator/extensions/FeedNavigationExtensions.kt +++ b/app/src/main/java/com/texthip/thip/ui/navigator/extensions/FeedNavigationExtensions.kt @@ -43,5 +43,9 @@ fun NavHostController.navigateToFeedWrite( // 유저 프로필(피드)로 fun NavHostController.navigateToUserProfile(userId: Long) { navigate(FeedRoutes.Others(userId)) +} +// 띱 목록으로 이동 +fun NavHostController.navigateToOthersSubscription(userId: Long) { + navigate(FeedRoutes.OthersSubscription(userId)) } \ No newline at end of file diff --git a/app/src/main/java/com/texthip/thip/ui/navigator/navigations/FeedNavigation.kt b/app/src/main/java/com/texthip/thip/ui/navigator/navigations/FeedNavigation.kt index df3bd6c2..e8121c84 100644 --- a/app/src/main/java/com/texthip/thip/ui/navigator/navigations/FeedNavigation.kt +++ b/app/src/main/java/com/texthip/thip/ui/navigator/navigations/FeedNavigation.kt @@ -11,11 +11,13 @@ import com.texthip.thip.ui.feed.screen.FeedOthersScreen import com.texthip.thip.ui.feed.screen.FeedScreen import com.texthip.thip.ui.feed.screen.FeedWriteScreen import com.texthip.thip.ui.feed.screen.MySubscriptionScreen +import com.texthip.thip.ui.feed.screen.OthersSubscriptionListScreen import com.texthip.thip.ui.feed.viewmodel.FeedWriteViewModel import com.texthip.thip.ui.navigator.extensions.navigateToBookDetail import com.texthip.thip.ui.navigator.extensions.navigateToFeedComment import com.texthip.thip.ui.navigator.extensions.navigateToFeedWrite import com.texthip.thip.ui.navigator.extensions.navigateToMySubscription +import com.texthip.thip.ui.navigator.extensions.navigateToOthersSubscription import com.texthip.thip.ui.navigator.extensions.navigateToUserProfile import com.texthip.thip.ui.navigator.routes.FeedRoutes import com.texthip.thip.ui.navigator.routes.MainTabRoutes @@ -45,6 +47,9 @@ fun NavGraphBuilder.feedNavigation(navController: NavHostController, navigateBac }, onNavigateToUserProfile = { userId -> navController.navigateToUserProfile(userId) + }, + onNavigateToOthersSubscription = { userId -> + navController.navigateToOthersSubscription(userId) } ) } @@ -116,6 +121,12 @@ fun NavGraphBuilder.feedNavigation(navController: NavHostController, navigateBac FeedOthersScreen( onNavigateBack = { navigateBack() + }, + onNavigateToSubscriptionList = { userId -> + navController.navigateToOthersSubscription(userId) + }, + onNavigateToFeedComment = { feedId -> + navController.navigateToFeedComment(feedId) } ) } @@ -139,4 +150,13 @@ fun NavGraphBuilder.feedNavigation(navController: NavHostController, navigateBac } ) } + + composable { + OthersSubscriptionListScreen( + onNavigateBack = navigateBack, + onNavigateToUserProfile = { userId -> + navController.navigateToUserProfile(userId) + } + ) + } } \ No newline at end of file diff --git a/app/src/main/java/com/texthip/thip/ui/navigator/routes/FeedRoutes.kt b/app/src/main/java/com/texthip/thip/ui/navigator/routes/FeedRoutes.kt index fd9037f5..5832ca95 100644 --- a/app/src/main/java/com/texthip/thip/ui/navigator/routes/FeedRoutes.kt +++ b/app/src/main/java/com/texthip/thip/ui/navigator/routes/FeedRoutes.kt @@ -25,4 +25,7 @@ sealed class FeedRoutes : Routes() { ) : FeedRoutes() @Serializable data class Others(val userId: Long) : FeedRoutes() + + @Serializable + data class OthersSubscription(val userId: Long) : FeedRoutes() } \ No newline at end of file diff --git a/app/src/main/java/com/texthip/thip/ui/signin/screen/SplashScreen.kt b/app/src/main/java/com/texthip/thip/ui/signin/screen/SplashScreen.kt index 318a5fa3..ad79335c 100644 --- a/app/src/main/java/com/texthip/thip/ui/signin/screen/SplashScreen.kt +++ b/app/src/main/java/com/texthip/thip/ui/signin/screen/SplashScreen.kt @@ -10,6 +10,7 @@ import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color.Companion.Unspecified @@ -20,23 +21,27 @@ import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.withStyle import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.texthip.thip.R +import com.texthip.thip.ui.signin.viewmodel.SplashViewModel import com.texthip.thip.ui.theme.Purple import com.texthip.thip.ui.theme.ThipTheme.colors import com.texthip.thip.ui.theme.ThipTheme.typography -import kotlinx.coroutines.delay @Composable fun SplashScreen( + viewModel: SplashViewModel = hiltViewModel(), onNavigateToLogin: () -> Unit = {} ) { - LaunchedEffect(key1 = Unit) { - //3초 delay - delay(3000L) + val navigateToLogin by viewModel.navigateToLogin.collectAsStateWithLifecycle() - // 로그인 화면으로 이동 - onNavigateToLogin() + LaunchedEffect(navigateToLogin) { + if (navigateToLogin) { + onNavigateToLogin() + } } + Column( Modifier .background(colors.Black) diff --git a/app/src/main/java/com/texthip/thip/ui/signin/viewmodel/SplashViewModel.kt b/app/src/main/java/com/texthip/thip/ui/signin/viewmodel/SplashViewModel.kt new file mode 100644 index 00000000..72b07245 --- /dev/null +++ b/app/src/main/java/com/texthip/thip/ui/signin/viewmodel/SplashViewModel.kt @@ -0,0 +1,23 @@ +package com.texthip.thip.ui.signin.viewmodel + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import dagger.hilt.android.lifecycle.HiltViewModel +import jakarta.inject.Inject +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.launch + +@HiltViewModel +class SplashViewModel @Inject constructor() : ViewModel() { + private val _navigateToLogin = MutableStateFlow(false) + val navigateToLogin = _navigateToLogin.asStateFlow() + + init { + viewModelScope.launch { + delay(3000) + _navigateToLogin.value = true + } + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml index 07d5da9c..ca3826a4 100644 --- a/app/src/main/res/drawable/ic_launcher_background.xml +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -1,170 +1,74 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + xmlns:android="http://schemas.android.com/apk/res/android"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/mipmap-anydpi/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml similarity index 56% rename from app/src/main/res/mipmap-anydpi/ic_launcher.xml rename to app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml index 6f3b755b..c4a603d4 100644 --- a/app/src/main/res/mipmap-anydpi/ic_launcher.xml +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -1,6 +1,5 @@ - - - + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml similarity index 56% rename from app/src/main/res/mipmap-anydpi/ic_launcher_round.xml rename to app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml index 6f3b755b..c4a603d4 100644 --- a/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -1,6 +1,5 @@ - - - + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/app/src/main/res/mipmap-hdpi/ic_launcher.webp index c209e78e..52323eb5 100644 Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher.webp and b/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp new file mode 100644 index 00000000..38e2f4cc Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp index b2dfe3d1..95e5d1e9 100644 Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/app/src/main/res/mipmap-mdpi/ic_launcher.webp index 4f0f1d64..f5ecfd18 100644 Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher.webp and b/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp new file mode 100644 index 00000000..c04927ff Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp index 62b611da..0c1ec6a1 100644 Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp index 948a3070..a6eef5ec 100644 Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp and b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp new file mode 100644 index 00000000..320763b6 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp index 1b9a6956..dd8083cf 100644 Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp index 28d4b77f..738c680f 100644 Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp new file mode 100644 index 00000000..997c1a82 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp index 9287f508..3db28c64 100644 Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp index aa7d6427..aa75ed64 100644 Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp new file mode 100644 index 00000000..12ed5206 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp index 9126ae37..d5507d6a 100644 Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index 7a737375..8fc4a58c 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -1,5 +1,9 @@ - \ No newline at end of file