Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added app/src/main/ic_launcher-playstore.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import kotlinx.serialization.Serializable

@Serializable
data class FeedUsersInfoResponse(
val creatorId: Int,
val creatorId: Long,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Int 가정 잔존 여부 점검 필요 (NavType/Bundle/매퍼/DB).

모델은 Long으로 바뀌었지만, 다음 지점에서 Int 전제가 남아 있으면 런타임/네비게이션 버그가 납니다:

  • Compose Navigation: NavType.IntType, getInt/putInt, route 인코딩 시 toInt()
  • Bundle/Intent extras: putInt/getInt
  • 매핑 확장함수: toInt() 캐스팅
  • Room/DB 엔티티/DAO 시그니처: creatorId: Int

아래 스크립트로 잔존 사용을 한 번에 확인해 주세요.


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "[1] creatorId: Int 선언 검색"
rg -n --type=kt -C2 '\bcreatorId\s*:\s*Int\b' || true

echo
echo "[2] NavType/Bundle Int 사용 검색"
rg -n --type=kt -C2 'NavType\.IntType|\bgetInt\(\s*"creatorId"\s*\)|\bputInt\(\s*"creatorId"\s*,' || true

echo
echo "[3] creatorId 관련 toInt() 캐스팅 검색"
rg -n --type=kt -C2 'creatorId[^;\n]*\.toInt\(\)|\.toInt\(\)[^;\n]*creatorId' || true

echo
echo "[4] getLong 사용 현황(전환 여부)"
rg -n --type=kt -C2 '\bgetLong\(\s*"creatorId"' || true

Length of output: 715


NavType/Bundle Int용 검사를 위해 .kt 파일만 지정하여 다시 검색해 보겠습니다.


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "[1] `creatorId: Int` 선언 검색 (.kt 파일 대상)"
rg -n -C2 '\bcreatorId\s*:\s*Int\b' -g '*.kt' || true

echo
echo "[2] NavType.IntType / getInt·putInt 사용 검색"
rg -n -C2 'NavType\.IntType|\bgetInt\(\s*"creatorId"\s*\)|\bputInt\(\s*"creatorId"\s*,' -g '*.kt' || true

echo
echo "[3] `creatorId.toInt()` 캐스팅 검색"
rg -n -C2 'creatorId[^;\n]*\.toInt\(\)|\.toInt\(\)[^;\n]*creatorId' -g '*.kt' || true

echo
echo "[4] getLong으로 전환된 호출 검색"
rg -n -C2 '\bgetLong\(\s*"creatorId"\s*\)' -g '*.kt' || true

Length of output: 2136


creatorId 타입 일관성 유지 필요
모델에서 Long으로 변경된 creatorId가 여전히 Int로 선언된 곳이 발견되었습니다. 런타임/네비게이션 버그를 방지하려면 아래 파일들을 모두 Long으로 변경하고, 매퍼·NavType·Bundle·DB 시그니처도 함께 검토해 주세요.

• app/src/main/java/com/texthip/thip/data/model/rooms/response/RoomsDailyGreetingResponse.kt (15줄)
• app/src/main/java/com/texthip/thip/data/model/feed/response/RelatedBooksResponse.kt (16줄)

예시 변경:

-    val creatorId: Int,
+    val creatorId: Long,

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In
app/src/main/java/com/texthip/thip/data/model/feed/response/FeedUsersInfoResponse.kt
around line 7 (creatorId), change the creatorId declaration from Int to Long and
propagate that change to all related code: update the two other occurrences at
app/src/main/java/com/texthip/thip/data/model/rooms/response/RoomsDailyGreetingResponse.kt
(line 15) and
app/src/main/java/com/texthip/thip/data/model/feed/response/RelatedBooksResponse.kt
(line 16) to use Long; then update any mappers (DTO↔domain), NavType
implementations/argument parsing, Bundle put/get calls to use putLong/getLong,
and DB schema/DAO signatures and entity fields to Long so types remain
consistent end-to-end.

val profileImageUrl: String,
val nickname: String,
val aliasName: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -98,7 +99,6 @@ fun AuthorHeader(
}
if (showThipNum && thipNum != null) {
Row(
modifier = Modifier.clickable(onClick = onThipNumClick),
verticalAlignment = Alignment.CenterVertically
) {
Text(
Expand Down Expand Up @@ -139,10 +139,7 @@ fun PreviewAuthorHeader() {
badgeTextColor = colors.Yellow,
showButton = false,
showThipNum = true,
thipNum = 10,
onThipNumClick = {

}
thipNum = 10
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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,
Expand All @@ -56,7 +51,6 @@ fun OthersFeedCard(
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 16.dp)
.clickable { onContentClick() }
)

if (hasImages) {
Expand Down Expand Up @@ -86,9 +80,6 @@ fun OthersFeedCard(
isSaveVisible = true,
onLikeClick = {
// onLikeClick(feedItem.feedId)
},
onCommentClick = {
// onCommentClick()
},
onBookmarkClick = {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -147,6 +153,18 @@ fun FeedCommentScreen(
var selectedCommentId by remember { mutableStateOf<Int?>(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()
}
}

Comment on lines +157 to 168

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

VM SideEffect(ScrollToItem) 수신 누락: 답글 작성 후 해당 부모 위치로 스크롤 연동 필요

CommentsViewModel이 ScrollToItem 사이드이펙트를 발행하지만, 이 화면에서는 수집하지 않아 스크롤이 동작하지 않습니다. 또, 수집자가 없으면 ViewModel 쪽 emit이 서스펜드되는 리스크가 있어 UI 일관성을 위해 반드시 수집을 권장합니다.

다음 코드를 val listState 선언 인근에 추가해 주세요:

LaunchedEffect(commentsViewModel.sideEffect, commentsUiState.comments) {
    commentsViewModel.sideEffect.collect { effect ->
        when (effect) {
            is CommentSideEffect.ScrollToItem -> {
                val targetIndex = effect.parentCommentId?.let { id ->
                    commentsUiState.comments.indexOfFirst { it.commentId == id }
                } ?: 0
                if (targetIndex >= 0) {
                    listState.animateScrollToItem(targetIndex)
                }
            }
        }
    }
}

또는, 답글 시작(onReplyClick) 시에도 입력창 포커스와 함께 해당 항목까지 스크롤하도록 보강할 수 있습니다.

🤖 Prompt for AI Agents
In app/src/main/java/com/texthip/thip/ui/feed/screen/FeedCommentScreen.kt around
lines 157 to 168, the screen currently creates listState but does not collect
CommentsViewModel sideEffect(s) so CommentSideEffect.ScrollToItem is ignored
(and the ViewModel emit may suspend); add a LaunchedEffect that collects
commentsViewModel.sideEffect and when receiving CommentSideEffect.ScrollToItem
compute the target index with commentsUiState.comments.indexOfFirst {
it.commentId == effect.parentCommentId } (use 0 or skip if index < 0), then call
listState.animateScrollToItem(targetIndex); ensure this LaunchedEffect depends
on commentsViewModel.sideEffect and commentsUiState.comments so it runs when
data updates; optionally also trigger the same scroll when handling onReplyClick
alongside focusing the input.

Box(
modifier = Modifier
Expand Down Expand Up @@ -179,6 +197,7 @@ fun FeedCommentScreen(
)

LazyColumn(
state = listState,
modifier = modifier
.fillMaxWidth()
.weight(1f),
Expand Down Expand Up @@ -334,6 +353,7 @@ fun FeedCommentScreen(
replyingToCommentId = commentId
replyingToNickname = nickname
selectedCommentId = null
focusRequester.requestFocus()
},
onCommentLongPress = { comment ->
selectedCommentId = comment.commentId
Expand All @@ -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 },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,22 +39,28 @@ 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()

FeedOthersContent(
uiState = uiState,
onNavigateBack = onNavigateBack,
onLikeClick = { feedId -> viewModel.changeFeedLike(feedId) }
onLikeClick = { feedId -> viewModel.changeFeedLike(feedId) },
onNavigateToSubscriptionList = onNavigateToSubscriptionList,
onNavigateToFeedComment = onNavigateToFeedComment
)
}

@Composable
fun FeedOthersContent(
uiState: FeedOthersUiState,
onNavigateBack: () -> Unit,
onLikeClick: (Long) -> Unit
onLikeClick: (Long) -> Unit,
onNavigateToSubscriptionList: (userId: Long) -> Unit,
onNavigateToFeedComment: (feedId: Long) -> Unit = {},
) {
val userInfo = uiState.userInfo

Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -187,7 +193,8 @@ private fun FeedOthersScreenPrev() {
feeds = mockFeeds
),
onNavigateBack = {},
onLikeClick = {}
onLikeClick = {},
onNavigateToSubscriptionList = {}
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down Expand Up @@ -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))
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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,
Expand All @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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()
Expand All @@ -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
Expand Down Expand Up @@ -120,7 +122,7 @@ fun OthersSubsciptionContent(
showThipNum = true,
profileImageSize = 36.dp,
thipNum = user.followerCount,
onThipNumClick = {}
onClick = { onProfileClick(user.userId) }
)

if (index < uiState.followers.lastIndex) {
Expand Down Expand Up @@ -154,7 +156,7 @@ fun OthersSubsciptionContent(
}
@Preview
@Composable
private fun OthersSubsciptionListScreenPrev() {
private fun OthersSubscriptionListScreenPrev() {
val mockUsers = (1..10).map {
FollowerList(
userId = it.toLong(),
Expand All @@ -167,15 +169,16 @@ private fun OthersSubsciptionListScreenPrev() {
}

ThipTheme {
OthersSubsciptionContent(
OthersSubscriptionContent(
uiState = OthersSubscriptionUiState(
isLoading = false,
followers = mockUsers,
totalCount = mockUsers.size,
isLastPage = false
),
lazyListState = rememberLazyListState(),
onNavigateBack = {}
onNavigateBack = {},
onProfileClick = {}
)
}
}
Loading