Skip to content

Commit 4319e13

Browse files
committed
chore(fc): room name change tweaks
Signed-off-by: Brandon McAnsh <git@bmcreations.dev>
1 parent 6ad6b28 commit 4319e13

9 files changed

Lines changed: 134 additions & 37 deletions

File tree

flipchatApp/src/main/kotlin/xyz/flipchat/app/features/chat/conversation/ConversationMessages.kt

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@ import com.getcode.ui.components.chat.MessageListPointerResult
3333
import com.getcode.ui.components.chat.utils.ChatItem
3434
import com.getcode.ui.components.chat.utils.HandleMessageChanges
3535
import com.getcode.ui.components.text.markup.Markup
36+
import com.getcode.ui.utils.animateScrollToItemWithFullVisibility
3637
import com.getcode.ui.utils.keyboardAsState
38+
import com.getcode.ui.utils.scrollToItemWithFullVisibility
3739
import kotlinx.coroutines.delay
3840
import kotlinx.coroutines.launch
3941
import xyz.flipchat.app.R
@@ -118,18 +120,30 @@ internal fun ConversationMessages(
118120
is MessageListEvent.ViewOriginalMessage -> {
119121
composeScope.launch {
120122
val itemIndex = messages.itemSnapshotList
123+
.filterIsInstance<ChatItem.Message>()
124+
.indexOfFirst { it.chatMessageId == event.originalMessageId }
125+
126+
val currentItemIndex = messages.itemSnapshotList
121127
.filterIsInstance<ChatItem.Message>()
122128
.indexOfFirst { it.chatMessageId == event.messageId }
129+
130+
println("target item is @ $itemIndex")
123131
if (itemIndex >= 0) {
124-
val currentIndex = lazyListState.firstVisibleItemIndex
125-
val distance = abs(itemIndex - currentIndex)
132+
val distance = abs(itemIndex - currentItemIndex)
126133

134+
println("distance from current ($currentItemIndex) is $distance")
127135
if (distance <= 100) {
128-
lazyListState.animateScrollToItem(itemIndex)
136+
// Animate smoothly if within 100 items
137+
lazyListState.animateScrollToItemWithFullVisibility(
138+
to = itemIndex,
139+
from = currentItemIndex
140+
)
129141
} else {
130-
lazyListState.scrollToItem(itemIndex)
142+
// Jump directly if too far
143+
lazyListState.scrollToItemWithFullVisibility(
144+
index = itemIndex,
145+
)
131146
}
132-
133147
}
134148
}
135149
}

flipchatApp/src/main/kotlin/xyz/flipchat/app/features/chat/info/ChatInfoViewModel.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,15 +84,15 @@ class ChatInfoViewModel @Inject constructor(
8484

8585
eventFlow
8686
.filterIsInstance<Event.LeaveRoom>()
87-
.map { stateFlow.value.roomInfo.title }
88-
.onEach { roomTitle ->
87+
.map { stateFlow.value.roomInfo.number }
88+
.onEach { roomNumber ->
8989
BottomBarManager.showMessage(
9090
BottomBarManager.BottomBarMessage(
9191
title = resources.getString(R.string.title_leaveRoom),
9292
subtitle = resources.getString(R.string.subtitle_leaveRoom),
9393
positiveText = resources.getString(
9494
R.string.action_leaveRoomByName,
95-
roomTitle
95+
resources.getString(R.string.title_implicitRoomTitle, roomNumber)
9696
),
9797
negativeText = "",
9898
tertiaryText = resources.getString(R.string.action_cancel),

flipchatApp/src/main/kotlin/xyz/flipchat/app/features/chat/info/RoomInfoScreen.kt

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ class RoomInfoScreen(private val info: RoomInfoArgs) : Screen, Parcelable {
7979
viewModel.eventFlow
8080
.filterIsInstance<ChatInfoViewModel.Event.OnChangeName>()
8181
.onEach {
82-
navigator.show(ScreenRegistry.get(NavScreenProvider.Room.ChangeName(it.id, it.title)))
82+
navigator.push(ScreenRegistry.get(NavScreenProvider.Room.ChangeName(it.id, it.title)))
8383
}.launchIn(this)
8484
}
8585

@@ -180,15 +180,9 @@ private fun Actions(
180180
buttonState = ButtonState.Filled,
181181
text = stringResource(R.string.action_customize),
182182
) {
183-
val roomNameText = if (state.roomInfo.customTitle.isNotEmpty()) {
184-
context.getString(R.string.action_editRoomName)
185-
} else {
186-
context.getString(R.string.action_addRoomName)
187-
}
188-
189183
BottomBarManager.showMessage(
190184
BottomBarManager.BottomBarMessage(
191-
positiveText = roomNameText,
185+
positiveText = context.getString(R.string.action_changeRoomName),
192186
negativeText = context.getString(R.string.action_changeCoverCharge),
193187
negativeStyle = BottomBarManager.BottomBarButtonStyle.Filled,
194188
tertiaryText = context.getString(R.string.action_cancel),

flipchatApp/src/main/kotlin/xyz/flipchat/app/features/chat/name/RoomNameScreen.kt

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -65,33 +65,24 @@ data class RoomNameScreen(val roomId: ID, val customTitle: String) : Screen, Par
6565
val navigator = LocalCodeNavigator.current
6666
val keyboardIsVisible by keyboardAsState()
6767
val keyboard = LocalSoftwareKeyboardController.current
68-
val composeScope = rememberCoroutineScope()
6968

7069

7170
BackHandler {
7271
if (keyboardIsVisible) {
7372
keyboard?.hide()
7473
} else {
75-
navigator.hide()
74+
navigator.pop()
7675
}
7776
}
7877

7978
Column(
8079
modifier = Modifier
81-
.fillMaxWidth()
82-
.fillMaxHeight(CodeTheme.dimens.modalHeightRatio)
80+
.fillMaxSize()
8381
) {
8482
AppBarWithTitle(
85-
endContent = {
86-
AppBarDefaults.Close {
87-
composeScope.launch {
88-
if (keyboardIsVisible) {
89-
keyboard?.hide()
90-
}
91-
navigator.hide()
92-
}
93-
}
94-
}
83+
backButton = true,
84+
title = stringResource(R.string.action_changeRoomName),
85+
onBackIconClicked = { navigator.pop() },
9586
)
9687

9788
val viewModel = getViewModel<RoomNameScreenViewModel>()
@@ -110,7 +101,7 @@ data class RoomNameScreen(val roomId: ID, val customTitle: String) : Screen, Par
110101
.filterIsInstance<RoomNameScreenViewModel.Event.OnSuccess>()
111102
.onEach {
112103
delay(2.seconds)
113-
navigator.hide()
104+
navigator.pop()
114105
}
115106
.launchIn(this)
116107
}

flipchatApp/src/main/kotlin/xyz/flipchat/app/ui/room/RoomCard.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,10 +148,10 @@ fun RoomCard(
148148
) { textSize = it },
149149
text = roomInfo.title,
150150
style = CodeTheme.typography.displaySmall
151-
.copy(fontSize = textSize,)
151+
.copy(fontSize = textSize, lineHeight = 24.sp)
152152
.withDropShadow(),
153153
color = Color.White,
154-
maxLines = 1
154+
maxLines = 3
155155
)
156156
}
157157
Spacer(Modifier.requiredHeight(geometry.titleBottomPadding))

flipchatApp/src/main/res/values/strings.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@
194194
<string name="action_changeCoverCharge">Change Cover Charge</string>
195195
<string name="action_addRoomName">Add Room Name</string>
196196
<string name="action_editRoomName">Edit Room Name</string>
197+
<string name="action_changeRoomName">Change Room Name</string>
197198
<string name="action_customize">Customize</string>
198199
<string name="action_leaveRoom">Leave Room</string>
199200

ui/components/src/main/kotlin/com/getcode/ui/components/chat/MessageList.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.getcode.ui.components.chat
22

3+
import androidx.compose.foundation.ExperimentalFoundationApi
34
import androidx.compose.foundation.layout.Arrangement
45
import androidx.compose.foundation.layout.PaddingValues
56
import androidx.compose.foundation.layout.fillMaxWidth
@@ -42,7 +43,7 @@ sealed interface MessageListEvent {
4243
data class OpenMessageActions(val actions: List<MessageControlAction>) : MessageListEvent
4344
data class OnMarkupEvent(val markup: Markup.Interactive) : MessageListEvent
4445
data class ReplyToMessage(val message: ChatItem.Message) : MessageListEvent
45-
data class ViewOriginalMessage(val messageId: ID) : MessageListEvent
46+
data class ViewOriginalMessage(val messageId: ID, val originalMessageId: ID) : MessageListEvent
4647
}
4748

4849
data class MessageListPointer(
@@ -165,7 +166,7 @@ fun MessageList(
165166
onReply = { dispatch(MessageListEvent.ReplyToMessage(item)) },
166167
originalMessage = item.originalMessage,
167168
onViewOriginalMessage = {
168-
dispatch(MessageListEvent.ViewOriginalMessage(it))
169+
dispatch(MessageListEvent.ViewOriginalMessage(item.chatMessageId, it))
169170
}
170171
)
171172
}

ui/components/src/main/kotlin/com/getcode/ui/utils/LazyList.kt

Lines changed: 97 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ package com.getcode.ui.utils
44
import androidx.compose.animation.AnimatedVisibility
55
import androidx.compose.animation.EnterTransition
66
import androidx.compose.animation.ExitTransition
7+
import androidx.compose.foundation.gestures.animateScrollBy
8+
import androidx.compose.foundation.gestures.scrollBy
79
import androidx.compose.foundation.lazy.LazyItemScope
810
import androidx.compose.foundation.lazy.LazyListScope
911
import androidx.compose.foundation.lazy.LazyListState
@@ -41,4 +43,98 @@ fun LazyListState.isScrolledToTheEnd() =
4143
layoutInfo.visibleItemsInfo.lastOrNull()?.index == layoutInfo.totalItemsCount - 1
4244

4345
fun LazyListState.isScrolledToTheBeginning() =
44-
(layoutInfo.visibleItemsInfo.firstOrNull()?.index ?: 0) == 0
46+
(layoutInfo.visibleItemsInfo.firstOrNull()?.index ?: 0) == 0
47+
48+
suspend fun LazyListState.scrollToItemWithFullVisibility(index: Int) {
49+
// 1️⃣ Scroll to the item initially
50+
scrollToItem(index)
51+
52+
// 2️⃣ Fetch updated layout info
53+
val layoutInfo = layoutInfo
54+
val itemInfo = layoutInfo.visibleItemsInfo.find { it.index == index }
55+
56+
if (itemInfo != null) {
57+
val viewportStart = layoutInfo.viewportStartOffset
58+
val viewportEnd = layoutInfo.viewportEndOffset
59+
60+
val itemStart = itemInfo.offset
61+
val itemEnd = itemInfo.offset + itemInfo.size
62+
63+
println(
64+
"ItemStart: $itemStart, ItemEnd: $itemEnd, ViewportStart: $viewportStart, ViewportEnd: $viewportEnd"
65+
)
66+
67+
// 3️⃣ Determine if the item is partially clipped upwards
68+
if (itemStart < viewportStart) {
69+
val scrollAmount = (viewportStart - itemStart).coerceAtLeast(0)
70+
println("Item is clipped upwards, scrolling upwards by $scrollAmount")
71+
scrollBy(-scrollAmount.toFloat()) // Scroll upwards
72+
}
73+
74+
// 4️⃣ Determine if the item is partially clipped downwards
75+
if (itemEnd > viewportEnd) {
76+
val scrollAmount = (itemEnd - viewportEnd).coerceAtLeast(0)
77+
println("Item is clipped downwards, scrolling downwards by $scrollAmount")
78+
scrollBy(scrollAmount.toFloat()) // Scroll downwards
79+
}
80+
81+
// 5️⃣ If the item is still misaligned, enforce alignment manually
82+
val fullyVisible = itemStart >= viewportStart && itemEnd <= viewportEnd
83+
if (!fullyVisible) {
84+
println("Item is still misaligned, performing final alignment")
85+
scrollToItem(index, scrollOffset = 0)
86+
}
87+
} else {
88+
// 6️⃣ Fallback alignment
89+
println("Item not found in visibleItemsInfo, performing fallback alignment")
90+
scrollToItem(index, scrollOffset = 0)
91+
}
92+
}
93+
94+
suspend fun LazyListState.animateScrollToItemWithFullVisibility(to: Int, from: Int) {
95+
println("🔄 Ensuring full visibility for index: $to")
96+
97+
val firstIndex = firstVisibleItemIndex
98+
val firstOffset = firstVisibleItemScrollOffset
99+
100+
println("📊 FirstVisibleItemIndex: $firstIndex, FirstVisibleItemScrollOffset: $firstOffset")
101+
102+
val layoutInfo = layoutInfo
103+
val itemInfo = layoutInfo.visibleItemsInfo.find { it.index == to }
104+
105+
// Estimate item height if dynamic size is not available
106+
val averageItemHeight = itemInfo?.size ?: 200 // Default to 200px if not found
107+
108+
// Calculate the true item offset based on reverseLayout
109+
val indexDifference = to - firstIndex
110+
val estimatedItemStart = firstOffset
111+
112+
println(
113+
"📐 Calculated EstimatedItemStart: $estimatedItemStart (IndexDifference: $indexDifference, AverageItemHeight: $averageItemHeight)"
114+
)
115+
116+
val viewportStart = layoutInfo.viewportStartOffset
117+
val viewportEnd = layoutInfo.viewportEndOffset
118+
119+
println("ViewportStart: $viewportStart, ViewportEnd: $viewportEnd")
120+
121+
// Determine if adjustment is needed
122+
val scrollOffset = when {
123+
estimatedItemStart > viewportEnd -> {
124+
println("🔼 Item is clipped at the bottom in reverse layout, adjusting by ${estimatedItemStart - viewportEnd}")
125+
estimatedItemStart - viewportEnd // Scroll upwards in reverse
126+
}
127+
estimatedItemStart < viewportStart -> {
128+
println("🔽 Item is clipped at the top in reverse layout, adjusting by ${viewportStart - estimatedItemStart}")
129+
viewportStart - estimatedItemStart // Scroll downwards in reverse
130+
}
131+
else -> {
132+
println("✅ Item is fully visible in reverse layout, no adjustment needed.")
133+
0
134+
}
135+
}
136+
137+
// Perform the final scroll adjustment
138+
println("🎯 Performing final scroll with offset: $scrollOffset")
139+
animateScrollToItem(to, scrollOffset = scrollOffset)
140+
}

ui/components/src/main/kotlin/com/getcode/ui/utils/TextStyle.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import androidx.compose.ui.text.TextStyle
88
fun TextStyle.withDropShadow(
99
color: Color = Color.Black.copy(alpha = 0.5f),
1010
offset: Offset = Offset(4f, 4f),
11-
blurRadius: Float = 8f,
11+
blurRadius: Float = 4f,
1212
): TextStyle = copy(
1313
shadow = Shadow(
1414
color = color,

0 commit comments

Comments
 (0)