diff --git a/app/build.gradle.kts b/app/build.gradle.kts index da8c6ecf..78ad2798 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -66,9 +66,8 @@ dependencies { implementation(libs.androidx.lifecycle.viewmodel.compose) implementation(libs.androidx.navigation.runtime.android) implementation(libs.kotlinx.serialization.json) - implementation(libs.accompanist.pager) - implementation(libs.accompanist.pager.indicators) implementation(libs.coil.compose) + implementation(libs.foundation) testImplementation(libs.junit) androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.espresso.core) @@ -76,6 +75,7 @@ dependencies { androidTestImplementation(libs.androidx.ui.test.junit4) debugImplementation(libs.androidx.ui.tooling) debugImplementation(libs.androidx.ui.test.manifest) + implementation("androidx.compose.foundation:foundation:1.5.0") // Hilt implementation(libs.hilt.android) diff --git a/app/src/main/java/com/texthip/thip/ui/common/buttons/ActionBarButton.kt b/app/src/main/java/com/texthip/thip/ui/common/buttons/ActionBarButton.kt index 60a64898..5af726aa 100644 --- a/app/src/main/java/com/texthip/thip/ui/common/buttons/ActionBarButton.kt +++ b/app/src/main/java/com/texthip/thip/ui/common/buttons/ActionBarButton.kt @@ -82,7 +82,7 @@ fun ActionBarButton( modifier = Modifier.clickable { onPinClick() }, painter = painterResource(R.drawable.ic_pin), contentDescription = null, - tint = Color.White + tint = colors.White ) } } diff --git a/app/src/main/java/com/texthip/thip/ui/common/cards/CardItemRoom.kt b/app/src/main/java/com/texthip/thip/ui/common/cards/CardItemRoom.kt index c319d0d1..33a02afb 100644 --- a/app/src/main/java/com/texthip/thip/ui/common/cards/CardItemRoom.kt +++ b/app/src/main/java/com/texthip/thip/ui/common/cards/CardItemRoom.kt @@ -109,7 +109,7 @@ fun CardItemRoom( modifier = Modifier.size(20.dp), painter = painterResource(id = R.drawable.ic_group), contentDescription = "그룹 아이콘", - tint = Color.White + tint = colors.White ) Spacer(modifier = Modifier.width(4.dp)) diff --git a/app/src/main/java/com/texthip/thip/ui/common/cards/CardItemRoomSmall.kt b/app/src/main/java/com/texthip/thip/ui/common/cards/CardItemRoomSmall.kt index e4599b5e..9859ce13 100644 --- a/app/src/main/java/com/texthip/thip/ui/common/cards/CardItemRoomSmall.kt +++ b/app/src/main/java/com/texthip/thip/ui/common/cards/CardItemRoomSmall.kt @@ -116,7 +116,7 @@ fun CardItemRoomSmall( modifier = Modifier.size(20.dp), painter = painterResource(id = R.drawable.ic_group), contentDescription = "그룹 아이콘", - tint = Color.White + tint = colors.White ) Spacer(modifier = Modifier.width(4.dp)) diff --git a/app/src/main/java/com/texthip/thip/ui/common/cards/CardRoomBook.kt b/app/src/main/java/com/texthip/thip/ui/common/cards/CardRoomBook.kt index b298e218..eab849c6 100644 --- a/app/src/main/java/com/texthip/thip/ui/common/cards/CardRoomBook.kt +++ b/app/src/main/java/com/texthip/thip/ui/common/cards/CardRoomBook.kt @@ -68,7 +68,7 @@ fun CardRoomBook( Text( text = title, style = typography.menu_m500_s16_h24, - color = Color.White, + color = colors.White, maxLines = 1, modifier = Modifier.weight(1f), ) @@ -77,7 +77,7 @@ fun CardRoomBook( Icon( imageVector = ImageVector.vectorResource(R.drawable.ic_chevron_right), contentDescription = "더보기", - tint = Color.White, + tint = colors.White, ) } 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 14d694d5..f8731155 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 @@ -11,15 +11,19 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material3.Icon import androidx.compose.material3.Text 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.res.painterResource +import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import coil.compose.AsyncImage +import com.texthip.thip.R import com.texthip.thip.ui.common.buttons.OutlinedButton import com.texthip.thip.ui.theme.ThipTheme import com.texthip.thip.ui.theme.ThipTheme.colors @@ -34,6 +38,8 @@ fun AuthorHeader( buttonText: String = "", buttonWidth: Dp = 60.dp, showButton: Boolean = true, + showThipNum: Boolean = false, + thipNum: Int? = null, profileImageSize: Dp = 54.dp, onButtonClick: () -> Unit = {} ) { @@ -91,6 +97,19 @@ fun AuthorHeader( onClick = onButtonClick ) } + if(showThipNum && thipNum!=null){ + Text( + text = stringResource(R.string.thip_num,thipNum), + style = typography.view_r400_s11_h20, + color = colors.White + ) + Spacer(modifier = Modifier.width(18.dp)) + Icon( + painter = painterResource(R.drawable.ic_chevron), + contentDescription = null, + tint = colors.White, + ) + } } } @@ -110,8 +129,9 @@ fun PreviewAuthorHeader() { profileImage = null, nickname = "열자자제한열열자제한", badgeText = "칭호칭호칭호", - buttonWidth = 60.dp, - showButton = false + showButton = false, + showThipNum = true, + thipNum = 10 ) } } diff --git a/app/src/main/java/com/texthip/thip/ui/common/header/HeaderMenuBarTab.kt b/app/src/main/java/com/texthip/thip/ui/common/header/HeaderMenuBarTab.kt index 0e090e39..fc1bf53e 100644 --- a/app/src/main/java/com/texthip/thip/ui/common/header/HeaderMenuBarTab.kt +++ b/app/src/main/java/com/texthip/thip/ui/common/header/HeaderMenuBarTab.kt @@ -26,7 +26,7 @@ fun HeaderMenuBarTab( titles: List, selectedTabIndex: Int, onTabSelected: (Int) -> Unit, - indicatorColor: Color = Color.White, + indicatorColor: Color = colors.White, ) { ScrollableTabRow( selectedTabIndex = selectedTabIndex, diff --git a/app/src/main/java/com/texthip/thip/ui/common/modal/ScrollbarUtil.kt b/app/src/main/java/com/texthip/thip/ui/common/modal/ScrollbarUtil.kt index 6689e4eb..40a7978a 100644 --- a/app/src/main/java/com/texthip/thip/ui/common/modal/ScrollbarUtil.kt +++ b/app/src/main/java/com/texthip/thip/ui/common/modal/ScrollbarUtil.kt @@ -1,12 +1,14 @@ package com.texthip.thip.ui.common.modal import androidx.compose.foundation.ScrollState +import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.draw.drawBehind import androidx.compose.ui.geometry.CornerRadius import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Size import androidx.compose.ui.graphics.Color +import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp diff --git a/app/src/main/java/com/texthip/thip/ui/feed/component/FeedSubscribelistBar.kt b/app/src/main/java/com/texthip/thip/ui/feed/component/FeedSubscribelistBar.kt index 77e7fab9..30e5022f 100644 --- a/app/src/main/java/com/texthip/thip/ui/feed/component/FeedSubscribelistBar.kt +++ b/app/src/main/java/com/texthip/thip/ui/feed/component/FeedSubscribelistBar.kt @@ -11,8 +11,8 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.CircleShape -import androidx.compose.material.Icon -import androidx.compose.material.Text +import androidx.compose.material3.Icon +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -47,7 +47,7 @@ fun FeedSubscribeBarlist( Icon( painter = painterResource(id = R.drawable.ic_group), contentDescription = null, - tint = Color.Unspecified + tint = colors.White ) Text( text = buildAnnotatedString { diff --git a/app/src/main/java/com/texthip/thip/ui/feed/component/ImageViewerModal.kt b/app/src/main/java/com/texthip/thip/ui/feed/component/ImageViewerModal.kt new file mode 100644 index 00000000..0fed4b94 --- /dev/null +++ b/app/src/main/java/com/texthip/thip/ui/feed/component/ImageViewerModal.kt @@ -0,0 +1,158 @@ +package com.texthip.thip.ui.feed.component + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.pager.HorizontalPager +import androidx.compose.foundation.pager.rememberPagerState +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material3.Icon +import androidx.compose.material3.Text +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.graphics.painter.Painter +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.zIndex +import com.texthip.thip.R +import com.texthip.thip.ui.theme.ThipTheme +import com.texthip.thip.ui.theme.ThipTheme.colors +import com.texthip.thip.ui.theme.ThipTheme.typography + +@Composable +fun ImageViewerModal( + images: List, + initialIndex: Int = 0, + onDismiss: () -> Unit +) { + val pagerState = rememberPagerState( + initialPage = initialIndex, + pageCount = { images.size } + ) + + Box( + modifier = Modifier + .fillMaxSize() + .background(colors.Black) + .clickable { onDismiss() } + ) { + // 닫기 버튼 + Icon( + painter = painterResource(R.drawable.ic_x), + contentDescription = "닫기", + tint = colors.White, + modifier = Modifier + .align(Alignment.TopEnd) + .padding(20.dp) + .size(24.dp) + .clickable { onDismiss() } + .zIndex(1f) + ) + + // 이미지 페이저 + HorizontalPager( + state = pagerState, + modifier = Modifier + .fillMaxSize() + .clickable { /* HorizontalPager 내부 클릭 시 모달 닫기 방지 */ } + ) { page -> + Box( + modifier = Modifier.fillMaxSize(), + contentAlignment = Alignment.Center + ) { + Image( + painter = images[page], + contentDescription = null, + contentScale = ContentScale.Fit, // 원본 비율 유지하면서 화면에 맞춤 + modifier = Modifier.fillMaxSize() + ) + } + } + + // 페이지 인디케이터 (이미지가 2개 이상일 때만 표시) + if (images.size > 1) { + Row( + modifier = Modifier + .align(Alignment.BottomCenter) + .padding(20.dp), + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + repeat(images.size) { index -> + Box( + modifier = Modifier + .size(8.dp) + .clip(CircleShape) + .background( + if (index == pagerState.currentPage) colors.White + else colors.White.copy(alpha = 0.4f) + ) + ) + } + } + } + + // 이미지 카운터 (예: 1/3) + if (images.size > 1) { + Text( + text = stringResource(id = R.string.tag_count, images.size, 3), + style = typography.copy_r400_s14, + color = colors.White, + modifier = Modifier + .align(Alignment.TopCenter) + .padding(20.dp) + .background( + colors.Black.copy(alpha = 0.5f), + shape = androidx.compose.foundation.shape.RoundedCornerShape(12.dp) + ) + .padding(horizontal = 12.dp, vertical = 6.dp) + ) + } + } +} + + +@Preview +@Composable +private fun ImageViewerModalSingleImagePreview() { + ThipTheme { + val mockImages = listOf( + painterResource(R.drawable.bookcover_sample) + ) + + ImageViewerModal( + images = mockImages, + initialIndex = 0, + onDismiss = {} + ) + } +} + +@Preview +@Composable +private fun ImageViewerModalMultipleImagesPreview() { + ThipTheme { + val mockImages = listOf( + painterResource(R.drawable.character_art), + painterResource(R.drawable.character_literature), + painterResource(R.drawable.character_sociology) + ) + + ImageViewerModal( + images = mockImages, + initialIndex = 1, + onDismiss = { } + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/texthip/thip/ui/feed/component/MyFeedCard.kt b/app/src/main/java/com/texthip/thip/ui/feed/component/MyFeedCard.kt index e7646f43..447372ae 100644 --- a/app/src/main/java/com/texthip/thip/ui/feed/component/MyFeedCard.kt +++ b/app/src/main/java/com/texthip/thip/ui/feed/component/MyFeedCard.kt @@ -6,15 +6,14 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer 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.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource @@ -30,45 +29,55 @@ import com.texthip.thip.ui.theme.ThipTheme.typography fun MyFeedCard( modifier: Modifier = Modifier, feedItem: FeedItem, - bookImage: Painter? = null, - onLikeClick: () -> Unit = {} + onLikeClick: () -> Unit = {}, + onContentClick: () -> Unit = {} ) { + val images = feedItem.imageUrls.orEmpty().map { painterResource(id = it) } + val hasImages = images.isNotEmpty() + val maxLines = if (hasImages) 3 else 8 + Column( modifier = modifier .fillMaxWidth() .padding(horizontal = 20.dp) ) { - Column( - modifier = modifier - .fillMaxWidth() - .padding(top = 16.dp, bottom = 16.dp) - ) { - ActionBookButton( - bookTitle = feedItem.bookTitle, - bookAuthor = feedItem.authName, - - onClick = {} - ) - } - if (bookImage != null) { - Image( - painter = bookImage , - contentDescription = null, - modifier = Modifier - .fillMaxWidth() - .height(480.dp), - contentScale = ContentScale.Crop - ) - } + ActionBookButton( + bookTitle = feedItem.bookTitle, + bookAuthor = feedItem.authName, + onClick = {} + ) Text( text = feedItem.content, style = typography.feedcopy_r400_s14_h20, color = colors.White, + maxLines = maxLines, modifier = Modifier .fillMaxWidth() - .padding(bottom = 16.dp) + .padding(vertical = 16.dp) + .clickable { onContentClick() } ) + + if (hasImages) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(bottom = 16.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + images.take(3).forEach { image -> + Image( + painter = image, + contentDescription = null, + modifier = Modifier + .padding(end = 10.dp) + .size(100.dp), + contentScale = ContentScale.Crop + ) + } + } + } + Row( verticalAlignment = Alignment.CenterVertically ) { @@ -104,7 +113,6 @@ fun MyFeedCard( ) } } - } } @@ -119,15 +127,14 @@ private fun MyFeedCardPrev() { bookTitle = "책 제목", authName = "한강", timeAgo = "3시간 전", - content = "무한대로입력가능합니닷무한대로입력가능합니닷무한대로입력가능합니닷무한대로입력가능합니닷무한대로입력가능합니닷무한대로입력가능합니닷무한대로입력가능합니닷무한대로입력가능합니닷", + content = "무한대로입력가능합니닷무한대로입력가능합니닷무한대로입력가능합니닷무한대로입력가능합니닷무한대로입력가능합니닷무한대로입력가능합니닷무한대로입력가능합니닷무한대로입력가능합니닷무한대로입력가능합니닷무한대로입력가능합니닷무한대로입력가능합니닷무한대로입력가능합니닷무한대로입력가능합니닷무한대로입력가능합니닷무한대로입력가능합니닷무한대로입력가능합니닷무한대로입력가능합니닷무한대로입력가능합니닷무한대로입력가능합니닷무한대로입력가능합니닷무한대로입력가능합니닷무한대로입력가능합니닷무한대로입력가능합니닷무한대로입력가능합니닷", likeCount = 10, commentCount = 5, isLiked = false, isSaved = true, isLocked = true, - imageUrl = null + imageUrls = null ) - val feed2 = FeedItem( id = 2, userProfileImage = R.drawable.character_art, @@ -136,23 +143,21 @@ private fun MyFeedCardPrev() { bookTitle = "책 제목", authName = "한강", timeAgo = "3시간 전", - content = "한줄만 입력 가능", + content = "세 줄만 보여줄거임!!세 줄만 보여줄거임!!세 줄만 보여줄거임!!세 줄만 보여줄거임!!세 줄만 보여줄거임!!세 줄만 보여줄거임!!세 줄만 보여줄거임!!세 줄만 보여줄거임!!세 줄만 보여줄거임!!세 줄만 보여줄거임!!세 줄만 보여줄거임!!", likeCount = 10, commentCount = 5, isLiked = false, isSaved = true, isLocked = false, - imageUrl = R.drawable.bookcover_sample + imageUrls = listOf(R.drawable.bookcover_sample,R.drawable.bookcover_sample) ) Column { MyFeedCard( - feedItem = feed1, - bookImage = null + feedItem = feed1 ) MyFeedCard( - feedItem = feed2, - bookImage = painterResource(feed2.imageUrl!!) + feedItem = feed2 ) } diff --git a/app/src/main/java/com/texthip/thip/ui/feed/component/MySubscribelistBar.kt b/app/src/main/java/com/texthip/thip/ui/feed/component/MySubscribelistBar.kt index 5915c6ca..d8b4125e 100644 --- a/app/src/main/java/com/texthip/thip/ui/feed/component/MySubscribelistBar.kt +++ b/app/src/main/java/com/texthip/thip/ui/feed/component/MySubscribelistBar.kt @@ -12,8 +12,8 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.CircleShape -import androidx.compose.material.Icon -import androidx.compose.material.Text +import androidx.compose.material3.Icon +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -62,12 +62,12 @@ fun MySubscribeBarlist( modifier = Modifier.size(20.dp), painter = painterResource(id = R.drawable.ic_group), contentDescription = null, - tint = Color.Unspecified + tint = colors.White ) Text( text = stringResource(R.string.my_subscription), style = typography.smalltitle_sb600_s14_h20, - color = Color.White, + color = colors.White, modifier = Modifier.padding(start = 2.dp) ) } @@ -99,7 +99,7 @@ fun MySubscribeBarlist( maxLines = 1, overflow = TextOverflow.Ellipsis, style = typography.view_r400_s11_h20, - color = Color.White, + color = colors.White, modifier = Modifier.width(36.dp) ) } @@ -125,7 +125,7 @@ private fun MySubscribeBarlistPrev() { profileImageUrl = "https://example.com/profile$it.jpg", nickname = "닉네임$it", role = "문학가", - roleColor = Color.Red, + roleColor = colors.Red, subscriberCount = 100 + it ) } diff --git a/app/src/main/java/com/texthip/thip/ui/feed/component/MySubscriptionList.kt b/app/src/main/java/com/texthip/thip/ui/feed/component/MySubscriptionList.kt index 88219fe7..5e1e2999 100644 --- a/app/src/main/java/com/texthip/thip/ui/feed/component/MySubscriptionList.kt +++ b/app/src/main/java/com/texthip/thip/ui/feed/component/MySubscriptionList.kt @@ -2,7 +2,9 @@ package com.texthip.thip.ui.feed.component import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.material3.HorizontalDivider import androidx.compose.runtime.Composable @@ -18,6 +20,7 @@ import com.texthip.thip.ui.theme.ThipTheme.colors @Composable fun MySubscriptionList( members: List, + isMine: Boolean=true, onUnsubscribe: (String) -> Unit ) { Column( @@ -34,6 +37,9 @@ fun MySubscriptionList( buttonText = stringResource(if(member.isSubscribed) R.string.thip_cancel else R.string.thip), buttonWidth = 64.dp, profileImageSize = 36.dp, + showButton = isMine, + showThipNum = !isMine, + thipNum = member.subscriberCount, onButtonClick = { onUnsubscribe(member.nickname) } @@ -44,6 +50,8 @@ fun MySubscriptionList( color = colors.DarkGrey02, thickness = 1.dp ) + }else{ + Spacer(modifier = Modifier.height(76.dp)) } } } @@ -85,4 +93,43 @@ private fun MySubscriptionListPrev() { ), onUnsubscribe = {} ) +} + +@Preview +@Composable +private fun MySubscriptionListPrev2() { + MySubscriptionList( + members = listOf( + MySubscriptionData( + profileImageUrl = null, + nickname = "Thiper", + role = "칭호칭호", + roleColor = colors.Yellow, + subscriberCount = 100, + ), + MySubscriptionData( + profileImageUrl = null, + nickname = "thipthip", + role = "공식 인플루언서", + roleColor = colors.NeonGreen, + subscriberCount = 50 + ), + MySubscriptionData( + profileImageUrl = null, + nickname = "Thiper", + role = "칭호칭호", + roleColor = colors.Yellow, + subscriberCount = 100 + ), + MySubscriptionData( + profileImageUrl = null, + nickname = "thip01", + role = "작가", + roleColor = colors.NeonGreen, + subscriberCount = 100 + ), + ), + isMine = false, + onUnsubscribe = {} + ) } \ No newline at end of file diff --git a/app/src/main/java/com/texthip/thip/ui/feed/mock/FeedData.kt b/app/src/main/java/com/texthip/thip/ui/feed/mock/FeedData.kt new file mode 100644 index 00000000..40ecf8ae --- /dev/null +++ b/app/src/main/java/com/texthip/thip/ui/feed/mock/FeedData.kt @@ -0,0 +1,21 @@ +package com.texthip.thip.ui.feed.mock + +import android.net.Uri +import androidx.compose.runtime.mutableStateListOf +import androidx.compose.runtime.snapshots.SnapshotStateList +import com.texthip.thip.ui.group.makeroom.mock.BookData + +data class FeedData( + val selectedBook: BookData? = null, + val feedContent: String = "", + val isPrivate: Boolean = false, + val selectedGenreIndex: Int = -1, + val selectedSubGenres: List = emptyList(), + val imageUris: SnapshotStateList = mutableStateListOf() +) { + val isReadyToSubmit: Boolean + get() = selectedBook != null && + feedContent.isNotBlank() && + selectedGenreIndex != -1 && + selectedSubGenres.isNotEmpty() +} diff --git a/app/src/main/java/com/texthip/thip/ui/feed/mock/FeedItemType.java b/app/src/main/java/com/texthip/thip/ui/feed/mock/FeedItemType.java new file mode 100644 index 00000000..8a8c2785 --- /dev/null +++ b/app/src/main/java/com/texthip/thip/ui/feed/mock/FeedItemType.java @@ -0,0 +1,5 @@ +package com.texthip.thip.ui.feed.mock; + +public enum FeedItemType { + LOCKED, SAVABLE +} 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 9a587288..0ff1b2b3 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 @@ -1,11 +1,26 @@ package com.texthip.thip.ui.feed.screen import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.border import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.* +import androidx.compose.foundation.gestures.detectTapGestures +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +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.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.lazy.LazyColumn +import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.HorizontalDivider -import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue @@ -13,11 +28,13 @@ import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue +import androidx.compose.runtime.snapshots.SnapshotStateList import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.blur import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource @@ -31,7 +48,11 @@ import com.texthip.thip.ui.common.forms.CommentTextField import com.texthip.thip.ui.common.header.ProfileBar import com.texthip.thip.ui.common.modal.DialogPopup import com.texthip.thip.ui.common.topappbar.DefaultTopAppBar -import com.texthip.thip.ui.group.note.component.* +import com.texthip.thip.ui.feed.component.ImageViewerModal +import com.texthip.thip.ui.feed.mock.FeedItemType +import com.texthip.thip.ui.group.note.component.CommentItem +import com.texthip.thip.ui.group.note.component.ReplyItem +import com.texthip.thip.ui.group.note.mock.mockCommentList import com.texthip.thip.ui.group.room.mock.MenuBottomSheetItem import com.texthip.thip.ui.mypage.mock.FeedItem import com.texthip.thip.ui.theme.ThipTheme @@ -44,7 +65,7 @@ import com.texthip.thip.ui.group.note.mock.ReplyItem as FeedReplyItem fun FeedCommentScreen( modifier: Modifier = Modifier, feedItem: FeedItem, - bookImage: Painter? = null, + feedType: FeedItemType, profileImage: Painter? = null, currentUserId: Int, currentUserName: String, @@ -52,8 +73,10 @@ fun FeedCommentScreen( currentUserProfileImageUrl: String, onLikeClick: () -> Unit = {}, onCommentInputChange: (String) -> Unit = {}, - onSendClick: () -> Unit = {} + onSendClick: () -> Unit = {}, + commentList: SnapshotStateList? = null ) { + val CommentList = commentList ?: remember { mutableStateListOf() } var isBottomSheetVisible by remember { mutableStateOf(false) } var showDialog by remember { mutableStateOf(false) } @@ -61,41 +84,29 @@ fun FeedCommentScreen( val replyTo = remember { mutableStateOf(null) } val feed = remember { mutableStateOf(feedItem) } val justNow = stringResource(R.string.just_a_moment_ago) - val commentList = remember { - mutableStateListOf( - FeedCommentItem( - commentId = 1, - userId = 1, - nickName = "사용자1", - genreName = "문학", - profileImageUrl = "", - content = "너무 공감돼요!", - postDate = "1시간 전", - isWriter = false, - isLiked = false, - likeCount = 3, - replyList = listOf( - FeedReplyItem( - replyId = 2, - userId = 2, - nickName = "사용자2", - parentNickname = "사용자1", - genreName = "문학", - profileImageUrl = "", - content = "저도 그렇게 느꼈어요.", - postDate = "30분 전", - isWriter = false, - isLiked = false, - likeCount = 1 - ) - ) - ) - ) - } + + val images = feedItem.imageUrls.orEmpty().map { painterResource(id = it) } + var showImageViewer by remember { mutableStateOf(false) } + var selectedImageIndex by remember { mutableStateOf(0) } + + var selectedComment by remember { mutableStateOf(null) } + var selectedReply by remember { mutableStateOf(null) } + Box( - modifier = Modifier - .fillMaxSize() - .blur(if (showDialog) 10.dp else 0.dp) + modifier = if (isBottomSheetVisible || showDialog) { + Modifier + .fillMaxSize() + .blur(5.dp) + } else { + Modifier.fillMaxSize() + } + //바깥 터치 시 선택 해제 되도록 + .pointerInput(Unit) { + detectTapGestures(onTap = { + selectedComment = null + selectedReply = null + }) + } ) { DefaultTopAppBar( isRightIconVisible = true, @@ -103,19 +114,18 @@ fun FeedCommentScreen( onLeftClick = {}, onRightClick = { isBottomSheetVisible = true }, ) + LazyColumn( modifier = modifier .fillMaxWidth() .padding(top = 56.dp), contentPadding = PaddingValues(bottom = 20.dp) ) { + // 상단 피드 item { - Column( - modifier = Modifier - .fillMaxWidth() - .padding(20.dp) - ) { + Column { ProfileBar( + modifier = Modifier.padding(20.dp), profileImage = profileImage, topText = feedItem.userName, bottomText = feedItem.userRole, @@ -123,9 +133,9 @@ fun FeedCommentScreen( hoursAgo = feedItem.timeAgo ) Column( - modifier = Modifier + Modifier .fillMaxWidth() - .padding(top = 16.dp, bottom = 16.dp) + .padding(vertical = 16.dp, horizontal = 20.dp) ) { ActionBookButton( bookTitle = feedItem.bookTitle, @@ -139,23 +149,36 @@ fun FeedCommentScreen( color = colors.White, modifier = Modifier .fillMaxWidth() - .padding(bottom = 16.dp) + .padding(bottom = 16.dp, start = 20.dp, end = 20.dp) ) - if (bookImage != null) { - Image( - painter = bookImage, - contentDescription = null, - modifier = Modifier + if (images.isNotEmpty()) { + LazyRow( + Modifier .fillMaxWidth() - .height(480.dp), - contentScale = ContentScale.Crop - ) + .padding(start = 20.dp, bottom = 16.dp), + verticalAlignment = Alignment.CenterVertically + ) { + itemsIndexed(images.take(3)) { index, image -> + Image( + painter = image, + contentDescription = null, + modifier = Modifier + .padding(end = 16.dp) + .size(200.dp) + .clickable { + selectedImageIndex = index + showImageViewer = true + }, + contentScale = ContentScale.Crop + ) + } + } } if (feedItem.tags.isNotEmpty()) { Row( - modifier = Modifier + Modifier .fillMaxWidth() - .padding(vertical = 16.dp), + .padding(bottom = 16.dp, start = 20.dp, end = 20.dp), horizontalArrangement = Arrangement.spacedBy(8.dp) ) { feedItem.tags.forEach { tag -> @@ -163,93 +186,176 @@ fun FeedCommentScreen( text = tag, isFilled = false, isSelected = false, - onClick = {} - ) + onClick = {}) } } } - HorizontalDivider( - color = colors.DarkGrey02, - thickness = 1.dp, - ) - Row( - modifier = Modifier.padding(top = 16.dp, bottom = 30.dp), - verticalAlignment = Alignment.CenterVertically - ) { - Icon( - modifier = Modifier.clickable { - feed.value = feed.value.copy( - isLiked = !feed.value.isLiked, - likeCount = if (feed.value.isLiked) feed.value.likeCount - 1 else feed.value.likeCount + 1 - ) - onLikeClick() - }, - painter = painterResource(if (feedItem.isLiked) R.drawable.ic_heart_filled else R.drawable.ic_heart), - contentDescription = null, - tint = Color.Unspecified - ) - Text( - text = feedItem.likeCount.toString(), - style = typography.feedcopy_r400_s14_h20, - color = colors.White, - modifier = Modifier.padding(start = 5.dp, end = 12.dp) - ) - Icon( - painter = painterResource(R.drawable.ic_comment), - contentDescription = null, - tint = colors.White - ) - Text( - text = feedItem.commentCount.toString(), - style = typography.feedcopy_r400_s14_h20, - color = colors.White, - modifier = Modifier.padding(start = 5.dp, end = 12.dp) - ) - Spacer(modifier = Modifier.weight(1f)) - if (feedItem.isLocked) { - Icon( - painter = painterResource(R.drawable.ic_lock), - contentDescription = null, - tint = Color.Unspecified - ) - } - } + HorizontalDivider(color = colors.DarkGrey02, thickness = 10.dp) } - HorizontalDivider( - color = colors.DarkGrey02, - thickness = 10.dp - ) - Spacer(modifier = Modifier.height(40.dp)) } - commentList.forEach { commentItem -> + //댓글이 없는 경우 + if (CommentList.isEmpty()) { item { Column( modifier = Modifier .fillMaxWidth() - .padding(horizontal = 20.dp, vertical = 24.dp) + .height(400.dp), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally ) { - CommentItem( - data = commentItem, - onReplyClick = { replyTo.value = it }, - + Text( + text = stringResource(R.string.no_comments_yet), + style = typography.smalltitle_sb600_s18_h24, + color = colors.White ) + Spacer(modifier = Modifier.height(8.dp)) + Text( + text = stringResource(R.string.no_comment_subtext), + style = typography.copy_r400_s14, + color = colors.Grey + ) + } + } + } else { + CommentList.forEachIndexed { index, commentItem -> + item { + Spacer(modifier = Modifier.height(40.dp)) + Column( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 20.dp) + ) { + // 댓글 아이템 + Box( + modifier = Modifier + .fillMaxWidth() + .pointerInput(Unit) { + detectTapGestures( + onLongPress = { + selectedComment = commentItem + selectedReply = null + } + ) + } + ) { + CommentItem( + data = commentItem, + onReplyClick = { replyTo.value = it } + ) + } + if (selectedComment == commentItem) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.End + ) { + val isMyComment = commentItem.userId == currentUserId + Box( + modifier = Modifier + .background( + Color.Transparent, + RoundedCornerShape(12.dp) + ) + .border( + width = 1.dp, + color = colors.White, + shape = RoundedCornerShape(12.dp) + ) + .clickable { + if (isMyComment) { + //TODO 삭제 로직 + } else { + //TODO 신고 로직 + } + selectedComment = null + } + .padding(horizontal = 20.dp, vertical = 12.dp) + ) { + Text( + text = stringResource(if (isMyComment) R.string.delete else R.string.report), + color = if (isMyComment) colors.White else colors.Red, + style = typography.feedcopy_r400_s14_h20 + ) + } + } + } + } + + // 대댓글들 Spacer(modifier = Modifier.height(24.dp)) commentItem.replyList.forEach { reply -> - ReplyItem( - data = reply, - onReplyClick = { replyTo.value = it } - ) + Column( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 20.dp) + ) { + // 대댓글 아이템 + Box( + modifier = Modifier + .fillMaxWidth() + .pointerInput(Unit) { + detectTapGestures( + onLongPress = { + selectedReply = reply + selectedComment = null + } + ) + } + ) { + ReplyItem(data = reply, onReplyClick = { replyTo.value = it }) + } + + if (selectedReply == reply) { + Row( + modifier = Modifier + .fillMaxWidth(), + horizontalArrangement = Arrangement.End + ) { + val isMyReply = reply.userId == currentUserId + Box( + modifier = Modifier + .background( + Color.Transparent, + RoundedCornerShape(12.dp) + ) + .border( + width = 1.dp, + color = colors.White, + shape = RoundedCornerShape(12.dp) + ) + .clickable { + if (isMyReply) { + //TODO 삭제 로직 + } else { + //TODO 신고 로직 + } + selectedReply = null + } + .padding(horizontal = 20.dp, vertical = 12.dp) + ) { + Text( + text = stringResource(if (isMyReply) R.string.delete else R.string.report), + color = if (isMyReply) colors.White else colors.Red, + style = typography.feedcopy_r400_s14_h20 + ) + } + } + } + Spacer(modifier = Modifier.height(24.dp)) + } + } + + + if (index == CommentList.lastIndex) { + Spacer(modifier = Modifier.height(40.dp)) } } } } - item { - Spacer(modifier = Modifier.height(40.dp)) - } } + + // 댓글 입력창 CommentTextField( - modifier = Modifier - .align(Alignment.BottomCenter), + modifier = Modifier.align(Alignment.BottomCenter), input = commentInput.value, hint = stringResource(R.string.feed_reply_to, feedItem.userName), onInputChange = { @@ -260,10 +366,9 @@ fun FeedCommentScreen( if (commentInput.value.isNotBlank()) { val replyTargetNickname = replyTo.value if (replyTargetNickname == null) { - - commentList.add( + CommentList.add( FeedCommentItem( - commentId = commentList.size + 1, + commentId = CommentList.size + 1, userId = currentUserId, nickName = currentUserName, genreName = currentUserGenre, @@ -277,11 +382,10 @@ fun FeedCommentScreen( ) ) } else { - // 대댓글 val parentIndex = - commentList.indexOfFirst { it.nickName == replyTargetNickname } + CommentList.indexOfFirst { it.nickName == replyTargetNickname } if (parentIndex != -1) { - val parentComment = commentList[parentIndex] + val parentComment = CommentList[parentIndex] val newReply = FeedReplyItem( replyId = parentComment.replyList.size + 1, userId = currentUserId, @@ -295,9 +399,8 @@ fun FeedCommentScreen( isLiked = false, likeCount = 0 ) - val updatedReplies = parentComment.replyList + newReply - commentList[parentIndex] = - parentComment.copy(replyList = updatedReplies) + CommentList[parentIndex] = + parentComment.copy(replyList = parentComment.replyList + newReply) } } commentInput.value = "" @@ -308,15 +411,15 @@ fun FeedCommentScreen( replyTo = replyTo.value, onCancelReply = { replyTo.value = null } ) - } + if (isBottomSheetVisible) { MenuBottomSheet( items = listOf( MenuBottomSheetItem( text = stringResource(R.string.edit_feed), color = colors.White, - onClick = { } + onClick = {} ), MenuBottomSheetItem( text = stringResource(R.string.delete_feed), @@ -327,20 +430,16 @@ fun FeedCommentScreen( } ) ), - onDismiss = { - isBottomSheetVisible = false - } + onDismiss = { isBottomSheetVisible = false } ) } + if (showDialog) { Box( - modifier = Modifier + Modifier .fillMaxSize() - .clickable(enabled = true, onClick = { showDialog = false }) - ) { - Box( - modifier = Modifier.align(Alignment.Center) - ) { + .clickable { showDialog = false }) { + Box(Modifier.align(Alignment.Center)) { DialogPopup( title = stringResource(R.string.delete_feed_dialog_title), description = stringResource(R.string.delete_feed_dialog_description), @@ -356,39 +455,95 @@ fun FeedCommentScreen( } } } + + if (showImageViewer && images.isNotEmpty()) { + ImageViewerModal( + images = images.take(3), + initialIndex = selectedImageIndex, + onDismiss = { showImageViewer = false } + ) + } +} + +@Preview +@Composable +private fun FeedCommentScreenWithMockComments() { + ThipTheme { + val mockFeedItem = FeedItem( + id = 1, + userProfileImage = R.drawable.character_literature, + userName = "문학소녀", + userRole = "문학 칭호", + bookTitle = "채식주의자", + authName = "한강", + timeAgo = "1시간 전", + content = "이 책은 인간의 본성과 억압에 대한 깊은 성찰을 담고 있어요.", + likeCount = 12, + commentCount = 3, + isLiked = true, + isSaved = true, + isLocked = true, + imageUrls = listOf( + R.drawable.bookcover_sample, + R.drawable.bookcover_sample, + R.drawable.bookcover_sample + ), + tags = listOf("에세이", "문학", "힐링") + ) + val commentList = remember { + mutableStateListOf().apply { + addAll(mockCommentList.commentData) + } + } + FeedCommentScreen( + feedItem = mockFeedItem, + feedType = FeedItemType.SAVABLE, + profileImage = painterResource(R.drawable.character_literature), + currentUserId = 999, + currentUserName = "나", + currentUserGenre = "문학", + currentUserProfileImageUrl = "", + commentList = commentList + ) + } } @Preview @Composable private fun FeedCommentScreenPrev() { ThipTheme { - FeedCommentScreen( - feedItem = FeedItem( - id = 1, - userProfileImage = R.drawable.character_literature, - userName = "문학소녀", - userRole = "문학 칭호", - bookTitle = "채식주의자", - authName = "한강", - timeAgo = "1시간 전", - content = "이 책은 인간의 본성과 억압에 대한 깊은 성찰을 담고 있어요. 인상 깊은 문장이 많았어요.", - likeCount = 12, - commentCount = 3, - isLiked = true, - isSaved = false, - isLocked = true, - imageUrl = R.drawable.bookcover_sample, - tags = listOf("에세이", "문학", "힐링") + val mockFeedItem = FeedItem( + id = 1, + userProfileImage = R.drawable.character_literature, + userName = "문학소녀", + userRole = "문학 칭호", + bookTitle = "채식주의자", + authName = "한강", + timeAgo = "1시간 전", + content = "이 책은 인간의 본성과 억압에 대한 깊은 성찰을 담고 있어요.", + likeCount = 12, + commentCount = 3, + isLiked = true, + isSaved = true, + isLocked = false, + imageUrls = listOf( + R.drawable.bookcover_sample, + R.drawable.bookcover_sample, + R.drawable.bookcover_sample ), - bookImage = painterResource(R.drawable.bookcover_sample), + tags = listOf("에세이", "문학", "힐링") + ) + val commentList = remember { mutableStateListOf() } + + FeedCommentScreen( + feedItem = mockFeedItem, + feedType = FeedItemType.SAVABLE, profileImage = painterResource(R.drawable.character_literature), - onLikeClick = {}, - onCommentInputChange = {}, - onSendClick = {}, currentUserId = 999, currentUserName = "나", - currentUserGenre = "장르", - currentUserProfileImageUrl = "" + currentUserGenre = "문학", + currentUserProfileImageUrl = "", + commentList = commentList ) } -} \ 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 131da9d6..d896e9b9 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 @@ -2,6 +2,7 @@ package com.texthip.thip.ui.feed.screen import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth @@ -106,87 +107,121 @@ fun FeedScreen( ) ) Box(modifier = Modifier.fillMaxSize()) { - LogoTopAppBar( - leftIcon = painterResource(R.drawable.ic_plusfriend), - hasNotification = false, - onLeftClick = {}, - onRightClick = {}, - modifier = Modifier.align(Alignment.TopStart) - ) - - // 스크롤 영역 전체 - LazyColumn( - modifier = Modifier - .fillMaxSize() - .padding(top = 40.dp), - verticalArrangement = Arrangement.spacedBy(12.dp) + Column( + modifier = Modifier.fillMaxSize() ) { - item { - Spacer(modifier = Modifier.height(40.dp)) - HeaderMenuBarTab( - titles = listOf("피드", "내 피드"), - selectedTabIndex = selectedIndex.value, - onTabSelected = { selectedIndex.value = it } - ) - } - - if (selectedIndex.value == 1) { - // 내 피드 - item { - Spacer(modifier = Modifier.height(32.dp)) - AuthorHeader( - profileImage = null, - nickname = nickname, - badgeText = userRole, - buttonText = "", - buttonWidth = 60.dp, - showButton = false - ) - Spacer(modifier = Modifier.height(16.dp)) - FeedSubscribeBarlist( - modifier = Modifier.padding(horizontal = 20.dp), - followerProfileImageUrls = followerProfileImageUrls, - onClick = { - } - ) - Spacer(modifier = Modifier.height(40.dp)) - Text( - text = stringResource(R.string.whole_num, totalFeedCount), - style = typography.menu_m500_s14_h24, - color = colors.Grey, - modifier = Modifier - .fillMaxWidth() - .padding(bottom = 12.dp, start = 20.dp) - ) - HorizontalDivider( - color = colors.DarkGrey02, - thickness = 1.dp, - modifier = Modifier.padding(horizontal = 20.dp) - ) - } + LogoTopAppBar( + leftIcon = painterResource(R.drawable.ic_plusfriend), + hasNotification = false, + onLeftClick = {}, + onRightClick = {}, + ) + Spacer(modifier = Modifier.height(32.dp)) + HeaderMenuBarTab( + titles = listOf("피드", "내 피드"), + selectedTabIndex = selectedIndex.value, + onTabSelected = { selectedIndex.value = it } + ) - if (totalFeedCount == 0) { + // 스크롤 영역 전체 + LazyColumn( + modifier = Modifier.weight(1f), + verticalArrangement = Arrangement.spacedBy(12.dp) + ) { + if (selectedIndex.value == 1) { + // 내 피드 item { - Box( + Spacer(modifier = Modifier.height(32.dp)) + AuthorHeader( + profileImage = null, + nickname = nickname, + badgeText = userRole, + buttonText = "", + buttonWidth = 60.dp, + showButton = false + ) + Spacer(modifier = Modifier.height(16.dp)) + FeedSubscribeBarlist( + modifier = Modifier.padding(horizontal = 20.dp), + followerProfileImageUrls = followerProfileImageUrls, + onClick = { + } + ) + Spacer(modifier = Modifier.height(40.dp)) + Text( + text = stringResource(R.string.whole_num, totalFeedCount), + style = typography.menu_m500_s14_h24, + color = colors.Grey, modifier = Modifier .fillMaxWidth() - .padding(top = 110.dp), - contentAlignment = Alignment.TopCenter - ) { - Text( - text = stringResource(R.string.create_feed), - style = typography.smalltitle_sb600_s18_h24, - color = colors.Grey + .padding(bottom = 12.dp, start = 20.dp) + ) + HorizontalDivider( + color = colors.DarkGrey02, + thickness = 1.dp, + modifier = Modifier.padding(horizontal = 20.dp) + ) + } + + if (totalFeedCount == 0) { + item { + Box( + modifier = Modifier + .fillMaxWidth() + .padding(top = 110.dp), + contentAlignment = Alignment.TopCenter + ) { + Text( + text = stringResource(R.string.create_feed), + style = typography.smalltitle_sb600_s18_h24, + color = colors.Grey + ) + } + } + } else { + itemsIndexed(feedStateList, key = { _, item -> item.id }) { index, feed -> + Spacer(modifier = Modifier.height(if (index == 0) 20.dp else 40.dp)) + MyFeedCard( + feedItem = feed, + onLikeClick = { + val updated = feed.copy( + isLiked = !feed.isLiked, + likeCount = if (feed.isLiked) feed.likeCount - 1 else feed.likeCount + 1 + ) + feedStateList[index] = updated + }, + onContentClick = {} //FeedCommentScreen으로 ) + Spacer(modifier = Modifier.height(40.dp)) + if (index != feeds.lastIndex) { + HorizontalDivider( + color = colors.DarkGrey02, + thickness = 10.dp + ) + } } } } else { + //피드 + item { + Spacer(modifier = Modifier.height(20.dp)) + MySubscribeBarlist( + modifier = Modifier.padding(horizontal = 20.dp), + subscriptions = mySubscriptions, + onClick = { + } + ) + } itemsIndexed(feedStateList, key = { _, item -> item.id }) { index, feed -> - val bookImage = feed.imageUrl?.let { painterResource(it) } - Spacer(modifier = Modifier.height(if (index == 0) 20.dp else 40.dp)) - MyFeedCard( + val profileImage = feed.userProfileImage?.let { painterResource(it) } + + SavedFeedCard( feedItem = feed, - bookImage = bookImage, + profileImage = profileImage, + onBookmarkClick = { + val updated = feed.copy(isSaved = !feed.isSaved) + feedStateList[index] = updated + }, onLikeClick = { val updated = feed.copy( isLiked = !feed.isLiked, @@ -194,8 +229,9 @@ fun FeedScreen( ) feedStateList[index] = updated }, + onContentClick = {} //FeedCommentScreen으로 + ) - Spacer(modifier = Modifier.height(40.dp)) if (index != feeds.lastIndex) { HorizontalDivider( color = colors.DarkGrey02, @@ -204,49 +240,11 @@ fun FeedScreen( } } } - } else { - //피드 - item { - Spacer(modifier = Modifier.height(20.dp)) - MySubscribeBarlist( - modifier = Modifier.padding(horizontal = 20.dp), - subscriptions = mySubscriptions, - onClick = { - } - ) - } - itemsIndexed(feedStateList, key = { _, item -> item.id }) { index, feed -> - val profileImage = feed.userProfileImage?.let { painterResource(it) } - val bookImage = feed.imageUrl?.let { painterResource(it) } - - SavedFeedCard( - feedItem = feed, - profileImage = profileImage, - bookImage = bookImage, - onBookmarkClick = { - val updated = feed.copy(isSaved = !feed.isSaved) - feedStateList[index] = updated - }, - onLikeClick = { - val updated = feed.copy( - isLiked = !feed.isLiked, - likeCount = if (feed.isLiked) feed.likeCount - 1 else feed.likeCount + 1 - ) - feedStateList[index] = updated - } - ) - if (index != feeds.lastIndex) { - HorizontalDivider( - color = colors.DarkGrey02, - thickness = 10.dp - ) - } - } } } FloatingButton( icon = painterResource(id = R.drawable.ic_write), - onClick = { } + onClick = { } ) } } @@ -254,40 +252,42 @@ fun FeedScreen( @Preview(showBackground = true) @Composable private fun FeedScreenPreview() { - val mockFeeds = List(5) { - FeedItem( - id = it + 1, - userProfileImage = R.drawable.character_literature, - userName = "user.$it", - userRole = "문학 칭호", - bookTitle = "책 제목 ", - authName = "한강", - timeAgo = "1시간 전", - content = "내용내용내용 입니다.", - likeCount = it, - commentCount = it, - isLiked = false, - isSaved = false, - isLocked = it % 2 == 0, - imageUrl = R.drawable.bookcover_sample - ) - } - val mockFollowerImages = listOf( - "https://example.com/image1.jpg", - "https://example.com/image2.jpg", - "https://example.com/image3.jpg", - "https://example.com/image4.jpg", - "https://example.com/image5.jpg" - ) - ThipTheme { - FeedScreen( - nickname = "ThipUser01", - userRole = "문학 칭호", - selectedTabIndex = 0, - feeds = mockFeeds, - totalFeedCount = mockFeeds.size, - followerProfileImageUrls = mockFollowerImages + val mockFeeds = List(5) { + FeedItem( + id = it + 1, + userProfileImage = R.drawable.character_literature, + userName = "user.$it", + userRole = "문학 칭호", + bookTitle = "책 제목 ", + authName = "한강", + timeAgo = "1시간 전", + content = "내용내용내용 입니다. 내용내용내용 입니다.내용내용내용 입니다.내용내용내용 입니다.내용내용내용 입니다.내용내용내용 입니다.내용내용내용 입니다.내용내용내용 입니다.내용내용내용 입니다.내용내용내용 입니다.내용내용내용 입니다.내용내용내용 입니다.내용내용내용 입니다.내용내용내용 입니다.내용내용내용 입니다.내용내용내용 입니다.내용내용내용 입니다.내용내용내용 입니다.내용내용내용 입니다.내용내용내용 입니다.내용내용내용 입니다.내용내용내용 입니다.내용내용내용 입니다.내용내용내용 입니다.내용내용내용 입니다.", + likeCount = it, + commentCount = it, + isLiked = false, + isSaved = false, + isLocked = it % 2 == 0, + imageUrls = listOf(R.drawable.bookcover_sample) + ) + } + val mockFollowerImages = listOf( + "https://example.com/image1.jpg", + "https://example.com/image2.jpg", + "https://example.com/image3.jpg", + "https://example.com/image4.jpg", + "https://example.com/image5.jpg" ) + + ThipTheme { + FeedScreen( + nickname = "ThipUser01", + userRole = "문학 칭호", + selectedTabIndex = 0, + feeds = mockFeeds, + totalFeedCount = mockFeeds.size, + followerProfileImageUrls = mockFollowerImages + ) + } } } diff --git a/app/src/main/java/com/texthip/thip/ui/feed/screen/FeedWriteScreen.kt b/app/src/main/java/com/texthip/thip/ui/feed/screen/FeedWriteScreen.kt index 279a6a8f..b0bac9dc 100644 --- a/app/src/main/java/com/texthip/thip/ui/feed/screen/FeedWriteScreen.kt +++ b/app/src/main/java/com/texthip/thip/ui/feed/screen/FeedWriteScreen.kt @@ -27,11 +27,8 @@ import androidx.compose.material3.IconButton import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableIntStateOf -import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -50,11 +47,11 @@ import com.texthip.thip.ui.common.buttons.GenreChipRow import com.texthip.thip.ui.common.buttons.SubGenreChipGrid import com.texthip.thip.ui.common.buttons.ToggleSwitchButton import com.texthip.thip.ui.common.topappbar.InputTopAppBar +import com.texthip.thip.ui.feed.mock.FeedData import com.texthip.thip.ui.group.makeroom.component.GroupBookSearchBottomSheet import com.texthip.thip.ui.group.makeroom.component.GroupInputField import com.texthip.thip.ui.group.makeroom.component.GroupSelectBook import com.texthip.thip.ui.group.makeroom.component.SectionDivider -import com.texthip.thip.ui.group.makeroom.mock.BookData import com.texthip.thip.ui.group.makeroom.mock.dummyGroupBooks import com.texthip.thip.ui.group.makeroom.mock.dummySavedBooks import com.texthip.thip.ui.theme.ThipTheme @@ -66,10 +63,9 @@ fun FeedWriteScreen( onNavigateBack: () -> Unit, modifier: Modifier = Modifier ) { + var feedData by remember { mutableStateOf(FeedData()) } val scrollState = rememberScrollState() - var selectedGenreIndex by rememberSaveable { mutableIntStateOf(-1) } val genres = listOf("문학", "과학·IT", "사회과학", "인문학", "예술") - var selectedSubGenres by remember { mutableStateOf>(emptyList()) } val subGenreMap = mapOf( 0 to listOf("소설", "에세이", "시", "고전", "추리", "판타지", "로맨스", "SF", "공포", "역사"), 1 to listOf("AI", "프로그래밍", "로봇", "IT 일반", "수학", "물리", "화학"), @@ -77,21 +73,17 @@ fun FeedWriteScreen( 3 to listOf("철학", "역사", "심리", "종교", "윤리"), 4 to listOf("음악", "미술", "공예", "무용", "연극") ) - var feed_content by remember { mutableStateOf("") } - var isPrivate by remember { mutableStateOf(false) } val showBookSearchSheet = remember { mutableStateOf(false) } - val selectedBook = remember { mutableStateOf(null) } - val imageUris = remember { mutableStateListOf() } val imagePickerLauncher = rememberLauncherForActivityResult( contract = ActivityResultContracts.GetMultipleContents() ) { uris: List -> if (uris.isNotEmpty()) { - val availableSlots = 3 - imageUris.size + val availableSlots = 3 - feedData.imageUris.size val imagesToAdd = uris.take(availableSlots) // 3장까지만 유지 - imageUris.addAll(imagesToAdd) + feedData.imageUris.addAll(imagesToAdd) } } - val isImageLimitReached = imageUris.size >= 3 + val isImageLimitReached = feedData.imageUris.size >= 3 val focusManager = LocalFocusManager.current Box { @@ -101,7 +93,7 @@ fun FeedWriteScreen( .then(if (showBookSearchSheet.value) Modifier.blur(5.dp) else Modifier), horizontalAlignment = Alignment.CenterHorizontally ) { - val isRightButtonEnabled = selectedBook.value != null && feed_content.isNotBlank() && selectedGenreIndex != -1 && selectedSubGenres.isNotEmpty() + val isRightButtonEnabled = feedData.selectedBook != null && feedData.feedContent.isNotBlank() && feedData.selectedGenreIndex != -1 && feedData.selectedSubGenres.isNotEmpty() InputTopAppBar( title = stringResource(R.string.new_feed), rightButtonName = stringResource(R.string.registration), @@ -124,7 +116,7 @@ fun FeedWriteScreen( Spacer(modifier = Modifier.height(20.dp)) GroupSelectBook( - selectedBook = selectedBook.value, + selectedBook = feedData.selectedBook, onChangeBookClick = { showBookSearchSheet.value = true }, onSelectBookClick = { showBookSearchSheet.value = true } ) @@ -134,9 +126,11 @@ fun FeedWriteScreen( GroupInputField( title = stringResource(R.string.write_feed), hint = stringResource(R.string.write_feed_hint), - value = feed_content, + value = feedData.feedContent, maxLength = 2000, - onValueChange = { feed_content = it } + onValueChange = { newText -> + feedData = feedData.copy(feedContent = newText) + } ) SectionDivider() @@ -174,16 +168,16 @@ fun FeedWriteScreen( ) } } - items(imageUris.size) { index -> + items(feedData.imageUris.size) { index -> Box(modifier = Modifier.size(80.dp)) { AsyncImage( - model = imageUris[index], + model = feedData.imageUris[index], contentDescription = null, modifier = Modifier.fillMaxSize(), contentScale = ContentScale.Crop ) IconButton( - onClick = { imageUris.removeAt(index) }, + onClick = { feedData.imageUris.removeAt(index) }, modifier = Modifier .align(Alignment.TopEnd) .size(24.dp) @@ -202,7 +196,7 @@ fun FeedWriteScreen( horizontalArrangement = Arrangement.End ) { Text( - text = stringResource(id = R.string.photo_count, imageUris.size, 3), + text = stringResource(id = R.string.photo_count, feedData.imageUris.size, 3), style = typography.info_r400_s12, color = colors.NeonGreen, ) @@ -225,8 +219,10 @@ fun FeedWriteScreen( color = colors.White ) ToggleSwitchButton( - isChecked = isPrivate, - onToggleChange = { isPrivate = it } + isChecked = feedData.isPrivate, + onToggleChange = { isChecked -> + feedData = feedData.copy(isPrivate = isChecked) + } ) } SectionDivider() @@ -240,26 +236,31 @@ fun FeedWriteScreen( GenreChipRow( modifier = Modifier.width(18.dp), genres = genres, - selectedIndex = selectedGenreIndex, + selectedIndex = feedData.selectedGenreIndex, onSelect = { - selectedGenreIndex = it - selectedSubGenres = emptyList() + feedData = feedData.copy(selectedGenreIndex = it, selectedSubGenres = emptyList()) } ) Spacer(modifier = Modifier.height(12.dp)) - if (selectedGenreIndex != -1) { - val subGenres = subGenreMap[selectedGenreIndex].orEmpty() + if (feedData.selectedGenreIndex != -1) { + val subGenres = subGenreMap[feedData.selectedGenreIndex].orEmpty() Spacer(modifier = Modifier.height(8.dp)) SubGenreChipGrid( subGenres = subGenres, - selectedGenres = selectedSubGenres, + selectedGenres = feedData.selectedSubGenres, onGenreToggle = { genre -> - selectedSubGenres = if (selectedSubGenres.contains(genre)) { - selectedSubGenres - genre + val newSelected = if (feedData.selectedSubGenres.contains(genre)) { + feedData.selectedSubGenres - genre } else { - if (selectedSubGenres.size < 5) selectedSubGenres + genre else selectedSubGenres + if (feedData.selectedSubGenres.size < 5) { + feedData.selectedSubGenres + genre + } else { + feedData.selectedSubGenres + } } + + feedData = feedData.copy(selectedSubGenres = newSelected) } ) Row( @@ -267,7 +268,7 @@ fun FeedWriteScreen( horizontalArrangement = Arrangement.End ) { Text( - text = stringResource(id = R.string.tag_count, selectedSubGenres.size, 5), + text = stringResource(id = R.string.tag_count, feedData.selectedSubGenres.size, 5), style = typography.info_r400_s12, color = colors.NeonGreen, ) @@ -280,21 +281,25 @@ fun FeedWriteScreen( color = colors.White ) Spacer(modifier = Modifier.height(12.dp)) - if (selectedSubGenres.isNotEmpty()) { + if (feedData.selectedSubGenres.isNotEmpty()) { LazyRow( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(8.dp) ) { - items(selectedSubGenres) { subGenre -> + items(feedData.selectedSubGenres) { subGenre -> GenreChipButton( text = subGenre, onClick = { //해당 칩 눌렀을 때도 서브장르 삭제 - selectedSubGenres = selectedSubGenres - subGenre + feedData = feedData.copy( + selectedSubGenres =feedData.selectedSubGenres - subGenre + ) }, onCloseClick = { //x버튼 누르면 서브장르 삭제 - selectedSubGenres = selectedSubGenres - subGenre + feedData = feedData.copy( + selectedSubGenres = feedData.selectedSubGenres - subGenre + ) } ) } @@ -308,7 +313,7 @@ fun FeedWriteScreen( GroupBookSearchBottomSheet( onDismiss = { showBookSearchSheet.value = false }, onBookSelect = { book -> - selectedBook.value = book + feedData = feedData.copy(selectedBook= book) showBookSearchSheet.value = false }, onRequestBook = { 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 0ba930af..1eed1583 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 @@ -9,7 +9,7 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.material.Text +import androidx.compose.material3.Text import androidx.compose.material3.HorizontalDivider import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -38,7 +38,8 @@ import kotlinx.coroutines.delay @Composable fun MySubscriptionScreen( - navController: NavController? = null + navController: NavController? = null, + titleText: String = stringResource(R.string.my_thip_list) ) { val initialmembers = listOf( MySubscriptionData( @@ -160,7 +161,7 @@ fun MySubscriptionScreen( ) { DefaultTopAppBar( onLeftClick = {}, - title = stringResource(R.string.my_thip_list) + title = titleText ) Column( modifier = Modifier diff --git a/app/src/main/java/com/texthip/thip/ui/feed/screen/SubscriptionListScreen.kt b/app/src/main/java/com/texthip/thip/ui/feed/screen/SubscriptionListScreen.kt new file mode 100644 index 00000000..76d355a4 --- /dev/null +++ b/app/src/main/java/com/texthip/thip/ui/feed/screen/SubscriptionListScreen.kt @@ -0,0 +1,176 @@ +package com.texthip.thip.ui.feed.screen + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +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.lazy.LazyColumn +import androidx.compose.material3.HorizontalDivider +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.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.navigation.NavController +import com.texthip.thip.R +import com.texthip.thip.ui.common.topappbar.DefaultTopAppBar +import com.texthip.thip.ui.feed.component.MySubscriptionList +import com.texthip.thip.ui.feed.mock.MySubscriptionData +import com.texthip.thip.ui.theme.ThipTheme +import com.texthip.thip.ui.theme.ThipTheme.colors +import com.texthip.thip.ui.theme.ThipTheme.typography + +@Composable +fun SubscriptionScreen( + navController: NavController? = null, + titleText: String = stringResource(R.string.thip_list) +) { + val initialmembers = listOf( + MySubscriptionData( + profileImageUrl = null, + nickname = "Thiper", + role = "칭호칭호", + roleColor = colors.Yellow, + subscriberCount = 100 + ), + MySubscriptionData( + profileImageUrl = null, + nickname = "thipthip", + role = "공식 인플루언서", + roleColor = colors.NeonGreen, + subscriberCount = 50 + ), + MySubscriptionData( + profileImageUrl = null, + nickname = "Thiper", + role = "칭호칭호", + roleColor = colors.Yellow, + subscriberCount = 0 + ), + MySubscriptionData( + profileImageUrl = null, + nickname = "thip01", + role = "작가", + roleColor = colors.NeonGreen, + subscriberCount = 1000 + ), + MySubscriptionData( + profileImageUrl = null, + nickname = "Thiper", + role = "칭호칭호", + roleColor = colors.Yellow, + subscriberCount = 500 + ), + + MySubscriptionData( + profileImageUrl = null, + nickname = "thipthip", + role = "공식 인플루언서", + roleColor = colors.NeonGreen, + subscriberCount = 105 + ), + MySubscriptionData( + profileImageUrl = null, + nickname = "Thiper", + role = "칭호칭호", + roleColor = colors.Yellow, + subscriberCount = 8 + ), + MySubscriptionData( + profileImageUrl = null, + nickname = "thip01", + role = "작가", + roleColor = colors.NeonGreen, + subscriberCount = 100 + ), + MySubscriptionData( + profileImageUrl = null, + nickname = "Thiper", + role = "칭호칭호", + roleColor = colors.Yellow, + subscriberCount = 88 + ), + MySubscriptionData( + profileImageUrl = null, + nickname = "thipthip", + role = "공식 인플루언서", + roleColor = colors.NeonGreen, + subscriberCount = 50 + ), + MySubscriptionData( + profileImageUrl = null, + nickname = "Thiper", + role = "칭호칭호", + roleColor = colors.Yellow, + subscriberCount = 100 + ), + MySubscriptionData( + profileImageUrl = null, + nickname = "thip01", + role = "작가", + roleColor = colors.NeonGreen, + subscriberCount = 1 + ), + ) + + var members by remember { mutableStateOf(initialmembers) } + + Column( + Modifier + .fillMaxSize() + ) { + DefaultTopAppBar( + onLeftClick = {}, + title = titleText + ) + Column( + modifier = Modifier + .fillMaxWidth() + + ) { + Spacer(modifier = Modifier.height(40.dp)) + Text( + text = stringResource(R.string.whole_num, members.size), + style = typography.menu_m500_s14_h24, + color = colors.Grey, + modifier = Modifier + .fillMaxWidth() + .padding(start = 20.dp, bottom = 4.dp) + ) + HorizontalDivider( + modifier = Modifier.padding(horizontal = 20.dp), + color = colors.DarkGrey02, + thickness = 1.dp + ) + LazyColumn( + modifier = Modifier + .fillMaxSize() + ) { + item { + MySubscriptionList( + members = members, + isMine = false, + onUnsubscribe = { } + ) + } + } + } + } + +} + +@Preview +@Composable +private fun SubscriptionListScreenPrev() { + ThipTheme { + SubscriptionScreen() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/texthip/thip/ui/group/makeroom/component/GroupWheelPicker.kt b/app/src/main/java/com/texthip/thip/ui/group/makeroom/component/GroupWheelPicker.kt index cca7af26..fdf71339 100644 --- a/app/src/main/java/com/texthip/thip/ui/group/makeroom/component/GroupWheelPicker.kt +++ b/app/src/main/java/com/texthip/thip/ui/group/makeroom/component/GroupWheelPicker.kt @@ -266,7 +266,7 @@ fun WheelPickerPreview() { Box( modifier = Modifier - .background(Color.Black), + .background(colors.Black), contentAlignment = Alignment.Center ) { Row( diff --git a/app/src/main/java/com/texthip/thip/ui/group/myroom/component/GroupEmptyCard.kt b/app/src/main/java/com/texthip/thip/ui/group/myroom/component/GroupEmptyCard.kt index 1b11017b..05d398e4 100644 --- a/app/src/main/java/com/texthip/thip/ui/group/myroom/component/GroupEmptyCard.kt +++ b/app/src/main/java/com/texthip/thip/ui/group/myroom/component/GroupEmptyCard.kt @@ -33,7 +33,7 @@ import com.texthip.thip.ui.theme.ThipTheme.typography @Composable fun GroupEmptyCard( modifier: Modifier = Modifier, - backgroundColor: Color = Color.White, + backgroundColor: Color = colors.White, onClick: () -> Unit = {} ) { // 그라데이션 diff --git a/app/src/main/java/com/texthip/thip/ui/group/myroom/component/GroupMainCard.kt b/app/src/main/java/com/texthip/thip/ui/group/myroom/component/GroupMainCard.kt index 2feb3c94..3fc92203 100644 --- a/app/src/main/java/com/texthip/thip/ui/group/myroom/component/GroupMainCard.kt +++ b/app/src/main/java/com/texthip/thip/ui/group/myroom/component/GroupMainCard.kt @@ -40,7 +40,7 @@ import com.texthip.thip.ui.theme.ThipTheme.typography @Composable fun GroupMainCard( data: GroupCardData, - backgroundColor: Color = Color.White, + backgroundColor: Color = colors.White, onClick: () -> Unit = {} ) { // 그라데이션 diff --git a/app/src/main/java/com/texthip/thip/ui/group/note/component/ReplyItem.kt b/app/src/main/java/com/texthip/thip/ui/group/note/component/ReplyItem.kt index 16353fee..3849a853 100644 --- a/app/src/main/java/com/texthip/thip/ui/group/note/component/ReplyItem.kt +++ b/app/src/main/java/com/texthip/thip/ui/group/note/component/ReplyItem.kt @@ -42,7 +42,7 @@ fun ReplyItem( Icon( painter = painterResource(R.drawable.ic_reply), contentDescription = null, - tint = Color.White + tint = colors.White ) Column( diff --git a/app/src/main/java/com/texthip/thip/ui/mypage/component/MypageSaveFeed.kt b/app/src/main/java/com/texthip/thip/ui/mypage/component/MypageSaveFeed.kt index eeab2b6d..970a7539 100644 --- a/app/src/main/java/com/texthip/thip/ui/mypage/component/MypageSaveFeed.kt +++ b/app/src/main/java/com/texthip/thip/ui/mypage/component/MypageSaveFeed.kt @@ -15,12 +15,10 @@ fun FeedContent(viewModel: SavedFeedViewModel = viewModel()) { LazyColumn { items(feedList, key = { it.id }) { feed -> - val bookImagePainter = feed.imageUrl?.let { painterResource(it) } val profileImagePainter = feed.userProfileImage?.let { painterResource(it) } SavedFeedCard( feedItem = feed, - bookImage = bookImagePainter, profileImage = profileImagePainter, onBookmarkClick = { viewModel.toggleBookmark(feed.id) }, onLikeClick = { viewModel.toggleLike(feed.id) } diff --git a/app/src/main/java/com/texthip/thip/ui/mypage/component/RoleCard.kt b/app/src/main/java/com/texthip/thip/ui/mypage/component/RoleCard.kt index 27157d30..4779eb62 100644 --- a/app/src/main/java/com/texthip/thip/ui/mypage/component/RoleCard.kt +++ b/app/src/main/java/com/texthip/thip/ui/mypage/component/RoleCard.kt @@ -52,21 +52,17 @@ fun RoleCard( val borderColor = if (selected) White else DarkGrey val bgAlpha = if (selected) 1f else 0.3f val backgroundBrush = if (selected) { - Brush.verticalGradient( - colors = listOf( - colors.Black.copy(alpha = 0.7f), //상단은 어둡게 - colors.White.copy(alpha = 0.2f) //하단은 밝게 - ) - ) + colors.Black800 } else { - SolidColor(colors.Black.copy(alpha = 0.3f)) + colors.Black700 } + val actualGenreColor = if (selected) genreColor else colors.Grey01 Box( modifier = modifier .width(162.dp) .height(100.dp) .clip(RoundedCornerShape(12.dp)) - .background(brush = backgroundBrush, shape = RoundedCornerShape(12.dp)) + .background(color = backgroundBrush, shape = RoundedCornerShape(12.dp)) .border( width = 1.dp, color = borderColor, @@ -92,7 +88,7 @@ fun RoleCard( Text( text = genre, style = typography.smalltitle_m500_s18_h24, - color = genreColor + color = actualGenreColor ) Text( text = role, diff --git a/app/src/main/java/com/texthip/thip/ui/mypage/component/SavedFeedCard.kt b/app/src/main/java/com/texthip/thip/ui/mypage/component/SavedFeedCard.kt index 5d82f201..21324213 100644 --- a/app/src/main/java/com/texthip/thip/ui/mypage/component/SavedFeedCard.kt +++ b/app/src/main/java/com/texthip/thip/ui/mypage/component/SavedFeedCard.kt @@ -6,8 +6,10 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer 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.rememberScrollState +import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -24,6 +26,7 @@ import com.texthip.thip.R import com.texthip.thip.ui.common.buttons.ActionBookButton import com.texthip.thip.ui.common.header.ProfileBar import com.texthip.thip.ui.mypage.mock.FeedItem +import com.texthip.thip.ui.theme.ThipTheme import com.texthip.thip.ui.theme.ThipTheme.colors import com.texthip.thip.ui.theme.ThipTheme.typography @@ -31,11 +34,16 @@ import com.texthip.thip.ui.theme.ThipTheme.typography fun SavedFeedCard( modifier: Modifier = Modifier, feedItem: FeedItem, - bookImage: Painter? = null, profileImage: Painter? = null, onBookmarkClick: () -> Unit = {}, - onLikeClick: () -> Unit = {} + onLikeClick: () -> Unit = {}, + onContentClick: () -> Unit = {} ) { + val images = feedItem.imageUrls.orEmpty().map { painterResource(id = it) } + val imagePainters = feedItem.imageUrls.orEmpty().map { painterResource(it) } + val hasImages = imagePainters.isNotEmpty() + val maxLines = if (hasImages) 3 else 8 + Column( modifier = modifier .fillMaxWidth() @@ -51,7 +59,7 @@ fun SavedFeedCard( Column( modifier = Modifier .fillMaxWidth() - .padding(top = 16.dp, bottom = 16.dp) + .padding(top = 16.dp) ) { ActionBookButton( bookTitle = feedItem.bookTitle, @@ -59,25 +67,35 @@ fun SavedFeedCard( onClick = {} ) } - if (bookImage != null) { - Image( - painter = bookImage , - contentDescription = null, - modifier = Modifier - .fillMaxWidth() - .height(480.dp), - contentScale = ContentScale.Crop - ) - } - Text( text = feedItem.content, style = typography.feedcopy_r400_s14_h20, color = colors.White, + maxLines = maxLines, modifier = Modifier .fillMaxWidth() - .padding(bottom = 16.dp) + .padding(vertical = 16.dp) + .clickable { onContentClick() } ) + if (images.isNotEmpty()) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(bottom = 16.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + images.take(3).forEach { image -> + Image( + painter = image, + contentDescription = null, + modifier = Modifier + .padding(end = 10.dp) + .size(100.dp), + contentScale = ContentScale.Crop + ) + } + } + } Row( verticalAlignment = Alignment.CenterVertically ) { @@ -112,7 +130,6 @@ fun SavedFeedCard( tint = Color.Unspecified ) } - } } @@ -127,12 +144,12 @@ private fun SavedFeedCardPrev() { bookTitle = "책 제목", authName = "한강", timeAgo = "3시간 전", - content = "무한대로입력가능합니닷무한대로입력가능합니닷무한대로입력가능합니닷무한대로입력가능합니닷무한대로입력가능합니닷무한대로입력가능합니닷무한대로입력가능합니닷무한대로입력가능합니닷", + content = "무한대로입력가능합니닷무한대로입력가능합니닷무한대로입력가능합니닷무한대로입력가능합니닷무한대로입력가능합니닷무한대로입력가능합니닷무한대로입력가능합니닷무한대로입력가능합니닷무한대로입력가능합니닷", likeCount = 10, commentCount = 5, isLiked = false, isSaved = true, - imageUrl = null + imageUrls = null ) val feed2 = FeedItem( @@ -143,26 +160,30 @@ private fun SavedFeedCardPrev() { bookTitle = "책 제목", authName = "한강", timeAgo = "3시간 전", - content = "한줄만 입력 가능", + content = "한줄만 입력 가능한줄만 입력 가능한줄만 입력 가능한줄만 입력 가능한줄만 입력 가능한줄만 " + + "한줄만 입력 가능한줄만 입력 가능한줄만 입력 가능한줄만 입력 가능한줄만 입력 가능한줄만한줄만 입력 가능한줄만 입력 가능한줄만 입력 가능한줄만 입력 가능한줄만 입력 가능한줄만입력 가능한줄만 입력 가능한줄만 입력 가능한줄만 입력 가능한줄만 입력 가능", likeCount = 10, commentCount = 5, isLiked = false, isSaved = true, - imageUrl = R.drawable.bookcover_sample + imageUrls = listOf(R.drawable.bookcover_sample,R.drawable.bookcover_sample,R.drawable.bookcover_sample) ) + val scrollState = rememberScrollState() - Column { - SavedFeedCard( - feedItem = feed1, - profileImage = painterResource(feed1.userProfileImage!!), - bookImage = null - ) - SavedFeedCard( - feedItem = feed2, - profileImage = painterResource(feed2.userProfileImage!!), - bookImage = painterResource(feed2.imageUrl!!) - ) + ThipTheme { + Column( + modifier = Modifier + .fillMaxWidth() + .verticalScroll(scrollState) + ) { + SavedFeedCard( + feedItem = feed1, + profileImage = painterResource(feed1.userProfileImage!!) + ) + SavedFeedCard( + feedItem = feed2, + profileImage = painterResource(feed2.userProfileImage!!) + ) + } } - - } \ No newline at end of file diff --git a/app/src/main/java/com/texthip/thip/ui/mypage/mock/FeedItem.kt b/app/src/main/java/com/texthip/thip/ui/mypage/mock/FeedItem.kt index 3dab91cc..99009098 100644 --- a/app/src/main/java/com/texthip/thip/ui/mypage/mock/FeedItem.kt +++ b/app/src/main/java/com/texthip/thip/ui/mypage/mock/FeedItem.kt @@ -15,6 +15,6 @@ data class FeedItem( val isSaved: Boolean, val isLocked: Boolean = false, val tags: List = emptyList(), - val imageUrl: Int? = null + val imageUrls: List? = emptyList() ) diff --git a/app/src/main/java/com/texthip/thip/ui/mypage/screen/MypageNotificationEditScreen.kt b/app/src/main/java/com/texthip/thip/ui/mypage/screen/MypageNotificationEditScreen.kt index feb41106..af5b4fe8 100644 --- a/app/src/main/java/com/texthip/thip/ui/mypage/screen/MypageNotificationEditScreen.kt +++ b/app/src/main/java/com/texthip/thip/ui/mypage/screen/MypageNotificationEditScreen.kt @@ -25,6 +25,7 @@ import androidx.compose.ui.zIndex import com.texthip.thip.R import com.texthip.thip.ui.common.buttons.ToggleSwitchButton import com.texthip.thip.ui.common.modal.ToastWithDate +import com.texthip.thip.ui.common.topappbar.DefaultTopAppBar import com.texthip.thip.ui.common.topappbar.InputTopAppBar import com.texthip.thip.ui.theme.ThipTheme.colors import com.texthip.thip.ui.theme.ThipTheme.typography @@ -65,11 +66,9 @@ fun NotificationScreen() { .background(colors.Black) .fillMaxSize() ) { - InputTopAppBar( + DefaultTopAppBar( title = stringResource(R.string.notification_settings), - isRightButtonEnabled = true, onLeftClick = {}, - onRightClick = {} ) Spacer(modifier = Modifier.height(40.dp)) Column( diff --git a/app/src/main/java/com/texthip/thip/ui/mypage/screen/MypageReactionScreen.kt b/app/src/main/java/com/texthip/thip/ui/mypage/screen/MypageReactionScreen.kt index 28396257..70c2324b 100644 --- a/app/src/main/java/com/texthip/thip/ui/mypage/screen/MypageReactionScreen.kt +++ b/app/src/main/java/com/texthip/thip/ui/mypage/screen/MypageReactionScreen.kt @@ -10,7 +10,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items -import androidx.compose.material3.Scaffold +import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -25,7 +25,6 @@ import com.texthip.thip.ui.common.buttons.OptionChipButton import com.texthip.thip.ui.common.cards.CardAlarm import com.texthip.thip.ui.common.topappbar.DefaultTopAppBar import com.texthip.thip.ui.mypage.mock.ReactionItem -import com.texthip.thip.ui.theme.Black import com.texthip.thip.ui.theme.ThipTheme.colors @Composable @@ -72,13 +71,13 @@ fun ReactionsScreen() { Row(modifier = Modifier.padding(start = 20.dp, top = 20.dp, bottom = 20.dp)) { OptionChipButton( text = stringResource(R.string.likes), - isFilled = isLikesSelected, + isFilled = true, onClick = {isLikesSelected = !isLikesSelected} ) Spacer(modifier = Modifier.width(12.dp)) OptionChipButton( text = stringResource(R.string.comments), - isFilled = isCommentsSelected, + isFilled = true, onClick = {isCommentsSelected = !isCommentsSelected} ) @@ -89,14 +88,20 @@ fun ReactionsScreen() { .padding(horizontal = 20.dp), verticalArrangement = Arrangement.spacedBy(20.dp) ) { - items(filteredReactions) { item -> + itemsIndexed (filteredReactions) { index, item -> + val isLastItem = index == filteredReactions.lastIndex CardAlarm( title = item.title, message = item.message, timeAgo = item.timeAgo, isRead = true, badgeText = item.type, - onClick = {} + onClick = {}, + modifier = if (isLastItem) { + Modifier.padding(bottom = 20.dp) + } else { + Modifier + } ) } } diff --git a/app/src/main/java/com/texthip/thip/ui/mypage/screen/MypageScreen.kt b/app/src/main/java/com/texthip/thip/ui/mypage/screen/MypageScreen.kt index f8467f32..4797ea41 100644 --- a/app/src/main/java/com/texthip/thip/ui/mypage/screen/MypageScreen.kt +++ b/app/src/main/java/com/texthip/thip/ui/mypage/screen/MypageScreen.kt @@ -1,19 +1,25 @@ package com.texthip.thip.ui.mypage.screen import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer 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.material3.Scaffold +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll 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.res.painterResource import androidx.compose.ui.res.stringResource @@ -26,7 +32,7 @@ import com.texthip.thip.ui.common.buttons.MenuItemButton import com.texthip.thip.ui.common.header.AuthorHeader import com.texthip.thip.ui.common.modal.DialogPopup import com.texthip.thip.ui.common.topappbar.LeftNameTopAppBar -import com.texthip.thip.ui.theme.Black +import com.texthip.thip.ui.theme.ThipTheme import com.texthip.thip.ui.theme.ThipTheme.colors import com.texthip.thip.ui.theme.ThipTheme.typography @@ -37,6 +43,7 @@ fun MyPageScreen( badgeText: String ) { var showLogoutDialog by remember { mutableStateOf(false) } + Column( Modifier .background(colors.Black) @@ -47,142 +54,164 @@ fun MyPageScreen( leftIcon = painterResource(R.drawable.ic_search), rightIcon = painterResource(R.drawable.ic_plus) ) - Column( - modifier = Modifier - .fillMaxSize() + LazyColumn( + modifier = Modifier.weight(1f), + verticalArrangement = Arrangement.spacedBy(0.dp) ) { - Spacer(modifier = Modifier.height(40.dp)) - AuthorHeader( - profileImage = null, - nickname = nickname, - badgeText = badgeText, - buttonText = stringResource(R.string.edit) - ) - Spacer(modifier = Modifier.height(40.dp)) - - Column( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 20.dp) - ) { - Text( - text = stringResource(R.string.my_activity), - style = typography.smalltitle_sb600_s18_h24, - color = colors.White, - modifier = Modifier - .fillMaxWidth() - .padding(bottom = 12.dp) - ) - MenuItemButton( - text = stringResource(R.string.saved), - icon = painterResource(R.drawable.ic_save), - contentColor = colors.White, - backgroundColor = colors.DarkGrey02, - hasRightIcon = true, - modifier = Modifier.fillMaxWidth(), - onClick = {} - ) - Spacer(modifier = Modifier.height(16.dp)) - MenuItemButton( - text = stringResource(R.string.reactions), - icon = painterResource(R.drawable.ic_heart), - contentColor = colors.White, - backgroundColor = colors.DarkGrey02, - hasRightIcon = true, - modifier = Modifier.fillMaxWidth(), - onClick = {} + item { + Spacer(modifier = Modifier.height(20.dp)) + AuthorHeader( + profileImage = null, + nickname = nickname, + badgeText = badgeText, + buttonText = stringResource(R.string.edit) ) + Spacer(modifier = Modifier.height(40.dp)) } - Spacer(modifier = Modifier.height(40.dp)) - Column( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 20.dp) - ) { - Text( - text = stringResource(R.string.menu), - style = typography.smalltitle_sb600_s18_h24, - color = colors.White, + item { + Column( modifier = Modifier .fillMaxWidth() - .padding(bottom = 12.dp) - ) - MenuItemButton( - text = stringResource(R.string.notification_settings), - icon = painterResource(R.drawable.ic_notice), - contentColor = colors.White, - backgroundColor = colors.DarkGrey02, - hasRightIcon = true, - modifier = Modifier.fillMaxWidth(), - onClick = {} - ) - Spacer(modifier = Modifier.height(16.dp)) - MenuItemButton( - text = stringResource(R.string.guide), - icon = painterResource(R.drawable.ic_guide), - contentColor = colors.White, - backgroundColor = colors.DarkGrey02, - hasRightIcon = true, - modifier = Modifier.fillMaxWidth(), - onClick = {} - ) - Spacer(modifier = Modifier.height(16.dp)) - MenuItemButton( - text = stringResource(R.string.customer_service), - icon = painterResource(R.drawable.ic_center), - contentColor = colors.White, - backgroundColor = colors.DarkGrey02, - hasRightIcon = true, - modifier = Modifier.fillMaxWidth(), - onClick = {} - ) - Spacer(modifier = Modifier.height(16.dp)) - MenuItemButton( - text = stringResource(R.string.delete_account), - icon = painterResource(R.drawable.ic_bye), - contentColor = colors.White, - backgroundColor = colors.DarkGrey02, - hasRightIcon = true, - modifier = Modifier.fillMaxWidth(), - onClick = {} - ) - Spacer(modifier = Modifier.height(16.dp)) - MenuItemButton( - text = stringResource(R.string.log_out), - icon = painterResource(R.drawable.ic_logout), - contentColor = colors.Red, - backgroundColor = colors.DarkGrey02, - hasRightIcon = false, - modifier = Modifier.fillMaxWidth(), - onClick = { - showLogoutDialog = true - } - ) + .padding(horizontal = 20.dp) + ) { + Text( + text = stringResource(R.string.my_activity), + style = typography.smalltitle_sb600_s18_h24, + color = colors.White, + modifier = Modifier + .fillMaxWidth() + .padding(bottom = 12.dp) + ) + MenuItemButton( + text = stringResource(R.string.saved), + icon = painterResource(R.drawable.ic_save), + contentColor = colors.White, + backgroundColor = colors.DarkGrey02, + hasRightIcon = true, + modifier = Modifier.fillMaxWidth(), + onClick = {} + ) + } + Spacer(modifier = Modifier.height(40.dp)) } - if (showLogoutDialog) { - Dialog(onDismissRequest = { showLogoutDialog = false }) { - DialogPopup( + item { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 20.dp) + ) { + Text( + text = stringResource(R.string.etc), + style = typography.smalltitle_sb600_s18_h24, + color = colors.White, modifier = Modifier - .fillMaxWidth(), - title = stringResource(R.string.log_out), - description = stringResource(R.string.logout_description), - onCancel = { showLogoutDialog = false }, - onConfirm = { - showLogoutDialog = false - // TODO: 로그아웃 로직 + .fillMaxWidth() + .padding(bottom = 12.dp) + ) + MenuItemButton( + text = stringResource(R.string.notification_settings), + icon = painterResource(R.drawable.ic_notice), + contentColor = colors.White, + backgroundColor = colors.DarkGrey02, + hasRightIcon = true, + modifier = Modifier.fillMaxWidth(), + onClick = {} + ) + Spacer(modifier = Modifier.height(16.dp)) + MenuItemButton( + text = stringResource(R.string.customer_service), + icon = painterResource(R.drawable.ic_center), + contentColor = colors.White, + backgroundColor = colors.DarkGrey02, + hasRightIcon = true, + modifier = Modifier.fillMaxWidth(), + onClick = {} + ) + Spacer(modifier = Modifier.height(16.dp)) + MenuItemButton( + text = stringResource(R.string.terms_of_use), + icon = painterResource(R.drawable.ic_doc), + contentColor = colors.White, + backgroundColor = colors.DarkGrey02, + hasRightIcon = true, + modifier = Modifier.fillMaxWidth(), + onClick = {} + ) + Spacer(modifier = Modifier.height(16.dp)) + MenuItemButton( + text = stringResource(R.string.guide), + icon = painterResource(R.drawable.ic_guide), + contentColor = colors.White, + backgroundColor = colors.DarkGrey02, + hasRightIcon = true, + modifier = Modifier.fillMaxWidth(), + onClick = {} + ) + Spacer(modifier = Modifier.height(16.dp)) + MenuItemButton( + text = stringResource(R.string.version_1_0), + icon = painterResource(R.drawable.ic_version), + contentColor = colors.White, + backgroundColor = colors.DarkGrey02, + hasRightIcon = true, + modifier = Modifier.fillMaxWidth(), + onClick = {} + ) + } + Spacer(modifier = Modifier.height(184.dp)) + } + item { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(bottom = 40.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text( + text = stringResource(R.string.log_out), + style = typography.feedcopy_r400_s14_h20, + color = colors.Grey01, + modifier = Modifier.clickable { showLogoutDialog = true } + ) + Spacer(modifier = Modifier.height(24.dp)) + Text( + text = stringResource(R.string.delete_account), + style = typography.feedcopy_r400_s14_h20, + color = colors.Grey01, + modifier = Modifier.clickable { + // TODO: 탈퇴 로직 } ) } } } + + if (showLogoutDialog) { + Dialog(onDismissRequest = { showLogoutDialog = false }) { + DialogPopup( + modifier = Modifier + .fillMaxWidth(), + title = stringResource(R.string.log_out), + description = stringResource(R.string.logout_description), + onCancel = { showLogoutDialog = false }, + onConfirm = { + showLogoutDialog = false + // TODO: 로그아웃 로직 + } + ) + } + } } } + @Preview @Composable private fun MyPagePrev() { - MyPageScreen( - nickname = "ThipUser01", - badgeText = "문학가" - ) + ThipTheme { + MyPageScreen( + nickname = "ThipUser01", + badgeText = "문학가" + ) + } } \ No newline at end of file diff --git a/app/src/main/java/com/texthip/thip/ui/mypage/viewmodel/SavedFeedViewModel.kt b/app/src/main/java/com/texthip/thip/ui/mypage/viewmodel/SavedFeedViewModel.kt index 1eefdc48..ff0756d4 100644 --- a/app/src/main/java/com/texthip/thip/ui/mypage/viewmodel/SavedFeedViewModel.kt +++ b/app/src/main/java/com/texthip/thip/ui/mypage/viewmodel/SavedFeedViewModel.kt @@ -36,7 +36,7 @@ class SavedFeedViewModel: ViewModel() { commentCount = 4, isLiked = false, isSaved = true, - imageUrl = R.drawable.bookcover_sample + imageUrls = null ), FeedItem( id = 3, @@ -51,7 +51,7 @@ class SavedFeedViewModel: ViewModel() { commentCount = 4, isLiked = false, isSaved = true, - imageUrl = R.drawable.bookcover_sample + imageUrls = listOf(R.drawable.bookcover_sample) ), FeedItem( id = 4, @@ -66,7 +66,7 @@ class SavedFeedViewModel: ViewModel() { commentCount = 4, isLiked = false, isSaved = true, - imageUrl = R.drawable.bookcover_sample + imageUrls = listOf(R.drawable.bookcover_sample) ), FeedItem( id = 5, 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 d6868bbd..e7e3a8b9 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 @@ -9,6 +9,15 @@ import com.texthip.thip.ui.navigator.routes.MainTabRoutes // Feed fun NavGraphBuilder.feedNavigation(navController: NavHostController) { composable { - FeedScreen(navController) + //TODO 추후 view model 적용 예정 + FeedScreen( + navController = navController, + nickname = "ThipUser01", + userRole = "문학가", + feeds = emptyList(), + totalFeedCount = 0, + selectedTabIndex = 0, + followerProfileImageUrls = emptyList() + ) } } \ No newline at end of file diff --git a/app/src/main/java/com/texthip/thip/ui/signin/screen/LoginScreen.kt b/app/src/main/java/com/texthip/thip/ui/signin/screen/LoginScreen.kt index 3f150f75..9a88c9e7 100644 --- a/app/src/main/java/com/texthip/thip/ui/signin/screen/LoginScreen.kt +++ b/app/src/main/java/com/texthip/thip/ui/signin/screen/LoginScreen.kt @@ -48,7 +48,7 @@ fun LoginScreen() { Text( text = buildAnnotatedString { withStyle(style = SpanStyle(color = Purple)) { - append(stringResource(R.string.thip)) + append(stringResource(R.string.splash_thip)) } append(stringResource(R.string.splash_ment)) }, diff --git a/app/src/main/java/com/texthip/thip/ui/signin/screen/SignupGenreScreen.kt b/app/src/main/java/com/texthip/thip/ui/signin/screen/SignupGenreScreen.kt index 369e6b7a..7b1233bf 100644 --- a/app/src/main/java/com/texthip/thip/ui/signin/screen/SignupGenreScreen.kt +++ b/app/src/main/java/com/texthip/thip/ui/signin/screen/SignupGenreScreen.kt @@ -1,10 +1,6 @@ package com.texthip.thip.ui.signin.screen import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.FlowRow -import com.texthip.thip.ui.mypage.component.RoleCard -import com.texthip.thip.ui.mypage.mock.RoleItem -import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize @@ -19,7 +15,6 @@ import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier @@ -27,13 +22,12 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.texthip.thip.R -import com.texthip.thip.ui.common.forms.WarningTextField import com.texthip.thip.ui.common.topappbar.InputTopAppBar +import com.texthip.thip.ui.mypage.component.RoleCard +import com.texthip.thip.ui.mypage.mock.RoleItem import com.texthip.thip.ui.theme.ThipTheme import com.texthip.thip.ui.theme.ThipTheme.colors import com.texthip.thip.ui.theme.ThipTheme.typography -import kotlinx.coroutines.delay -import kotlinx.coroutines.launch @Composable diff --git a/app/src/main/java/com/texthip/thip/ui/theme/Color.kt b/app/src/main/java/com/texthip/thip/ui/theme/Color.kt index 6306b18d..1fe1ebe9 100644 --- a/app/src/main/java/com/texthip/thip/ui/theme/Color.kt +++ b/app/src/main/java/com/texthip/thip/ui/theme/Color.kt @@ -43,6 +43,10 @@ val Black = Color(0xFF121212) val Black50 = Color(0x80121212) val Black10 = Color(0x1A121212) val Black00 = Color(0x00121212) +val Black700 = Color(0xFF090909) +val Black800 = Color(0xFF040404) + + @Immutable data class ThipColors( @@ -80,6 +84,8 @@ data class ThipColors( val Black50: Color, val Black10: Color, val Black00: Color, + val Black800: Color, + val Black700: Color ) val defaultThipColors = ThipColors( @@ -116,7 +122,9 @@ val defaultThipColors = ThipColors( Black = Black, Black50 = Black50, Black10 = Black10, - Black00 = Black00 + Black00 = Black00, + Black700 = Black700, + Black800 = Black800 ) val LocalThipColorsProvider = staticCompositionLocalOf { defaultThipColors } \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_doc.xml b/app/src/main/res/drawable/ic_doc.xml new file mode 100644 index 00000000..32879e60 --- /dev/null +++ b/app/src/main/res/drawable/ic_doc.xml @@ -0,0 +1,41 @@ + + + + + + + diff --git a/app/src/main/res/drawable/ic_version.xml b/app/src/main/res/drawable/ic_version.xml new file mode 100644 index 00000000..717d60f2 --- /dev/null +++ b/app/src/main/res/drawable/ic_version.xml @@ -0,0 +1,15 @@ + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b9f0fc1e..4f70ba19 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -66,12 +66,15 @@ 마이페이지 + 기타 편집 내 활동 저장 반응 알림설정 가이드 + 버전 1.0 + 이용약관 고객센터 회원탈퇴 로그아웃 @@ -282,12 +285,14 @@ 이후 내 정보에서 변경이 가능해요. - 내 띱 리스트 + 내 띱 목록 + 띱 목록 전체 %d %1$s 님을 띱 했어요 %1$s 님을 띱 취소했어요 띱 하기 띱 취소 + %d명이 띱 하는 중 피드에 글을 작성해 보세요 모집을 마감하시겠습니까? @@ -301,7 +306,7 @@ 첫번째 모임방에 참여해보세요 %1$s 님에게 댓글을 남겨보세요. 방금 전 - 내 구독 + 내 띱 새 글 등록 글 작성 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f34d7d9e..821d4cca 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -20,6 +20,7 @@ accompanistPager = "0.36.0" accompanistPagerIndicators = "0.36.0" coilCompose = "2.7.0" kotlinxSerializationJson = "1.9.0" +foundationVersion = "1.9.0-rc01" okhttp = "5.1.0" retrofit = "3.0.0" retrofitKotlinSerializationConverter = "1.0.0" @@ -52,6 +53,7 @@ accompanist-pager = { group = "com.google.accompanist", name = "accompanist-page accompanist-pager-indicators = { group = "com.google.accompanist", name = "accompanist-pager-indicators", version.ref = "accompanistPagerIndicators" } coil-compose = { group = "io.coil-kt", name = "coil-compose", version.ref = "coilCompose" } kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" } +foundation = { group = "androidx.compose.foundation", name = "foundation", version.ref = "foundationVersion" } logging-interceptor = { module = "com.squareup.okhttp3:logging-interceptor", version.ref = "loggingInterceptor" } okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" } retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" }