Skip to content

Commit

Permalink
feat(chat): use new popup model for chat info (#454)
Browse files Browse the repository at this point in the history
  • Loading branch information
outadoc authored Oct 4, 2024
1 parent c48c57b commit 385cda5
Show file tree
Hide file tree
Showing 16 changed files with 241 additions and 338 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import fr.outadoc.justchatting.feature.chat.domain.pubsub.PubSubPluginsProvider
import fr.outadoc.justchatting.feature.chat.presentation.ChatEventViewMapper
import fr.outadoc.justchatting.feature.chat.presentation.ChatViewModel
import fr.outadoc.justchatting.feature.chat.presentation.FilterAutocompleteItemsUseCase
import fr.outadoc.justchatting.feature.chat.presentation.StreamAndUserInfoViewModel
import fr.outadoc.justchatting.feature.chat.presentation.UserInfoViewModel
import fr.outadoc.justchatting.feature.deeplink.DeeplinkParser
import fr.outadoc.justchatting.feature.emotes.data.bttv.BttvEmotesApi
import fr.outadoc.justchatting.feature.emotes.data.bttv.BttvEmotesServer
Expand Down Expand Up @@ -106,7 +106,7 @@ public val sharedModule: Module
viewModel { FollowedChannelsViewModel(get()) }
viewModel { RecentChannelsViewModel(get()) }
viewModel { TimelineViewModel(get(), get()) }
viewModel { StreamAndUserInfoViewModel(get()) }
viewModel { UserInfoViewModel(get()) }
viewModel {
ChatViewModel(
get(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ internal class ChatViewModel(
data class UpdateChatterPronouns(val pronouns: Map<Chatter, Pronoun?>) : Action()
data class UpdateStreamDetails(val stream: Stream) : Action()
data class ShowUserInfo(val userId: String?) : Action()
data class UpdateStreamInfoVisibility(val isVisible: Boolean) : Action()
data class UpdateUser(val user: User) : Action()
}

Expand Down Expand Up @@ -162,6 +163,7 @@ internal class ChatViewModel(
val connectionStatus: ConnectionStatus = ConnectionStatus(),
val maxAdapterCount: Int,
val showInfoForUserId: String? = null,
val isStreamInfoVisible: Boolean = false,
) : State() {

val allEmotesMap: ImmutableMap<String, Emote>
Expand Down Expand Up @@ -504,6 +506,18 @@ internal class ChatViewModel(
}
}

fun onShowStreamInfo() {
defaultScope.launch {
actions.emit(Action.UpdateStreamInfoVisibility(isVisible = true))
}
}

fun onDismissStreamInfo() {
defaultScope.launch {
actions.emit(Action.UpdateStreamInfoVisibility(isVisible = false))
}
}

fun onReplyToMessage(entry: ChatListItem.Message?) {
inputScope.launch {
inputActions.emit(InputAction.ReplyToMessage(entry))
Expand Down Expand Up @@ -585,6 +599,7 @@ internal class ChatViewModel(
is Action.UpdateRaidAnnouncement -> reduce(state)
is Action.UpdatePinnedMessage -> reduce(state)
is Action.ShowUserInfo -> reduce(state)
is Action.UpdateStreamInfoVisibility -> reduce(state)
is Action.UpdateUser -> reduce(state)
}
}
Expand Down Expand Up @@ -877,6 +892,13 @@ internal class ChatViewModel(
)
}

private fun Action.UpdateStreamInfoVisibility.reduce(state: State): State {
if (state !is State.Chatting) return state
return state.copy(
isStreamInfoVisible = isVisible,
)
}

private fun Action.UpdateUser.reduce(state: State): State {
return when (state) {
is State.Initial,
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package fr.outadoc.justchatting.feature.chat.presentation

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import fr.outadoc.justchatting.feature.shared.domain.TwitchRepository
import fr.outadoc.justchatting.feature.shared.domain.model.User
import fr.outadoc.justchatting.utils.logging.logError
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.launch

internal class UserInfoViewModel(
private val twitchRepository: TwitchRepository,
) : ViewModel() {

sealed class State {
data object Loading : State()
data class Error(val throwable: Throwable) : State()
data class Loaded(val user: User) : State()
}

private val _state = MutableStateFlow<State>(State.Loading)
val state = _state.asStateFlow()

fun load(userId: String) {
viewModelScope.launch {
twitchRepository
.getUserById(userId)
.map { userResult ->
userResult.fold(
onSuccess = { user ->
State.Loaded(user)
},
onFailure = { exception ->
logError<UserInfoViewModel>(exception) {
"Error while loading user $userId: $exception"
}
State.Error(exception)
},
)
}
.onStart { emit(State.Loading) }
.collect(_state)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,11 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalUriHandler
import coil3.compose.LocalPlatformContext
import fr.outadoc.justchatting.feature.chat.presentation.ChatNotifier
import fr.outadoc.justchatting.feature.chat.presentation.ChatViewModel
import fr.outadoc.justchatting.feature.preferences.domain.PreferenceRepository
import fr.outadoc.justchatting.feature.preferences.domain.model.AppPreferences
import fr.outadoc.justchatting.utils.core.createChannelExternalLink
import fr.outadoc.justchatting.utils.http.toUri
import fr.outadoc.justchatting.utils.presentation.BackHandler
import fr.outadoc.justchatting.utils.presentation.OnLifecycleEvent
Expand Down Expand Up @@ -46,7 +44,6 @@ internal fun ChannelChatScreen(

val context = LocalPlatformContext.current
val density = LocalDensity.current.density
val uriHandler = LocalUriHandler.current

val user = (state as? ChatViewModel.State.Chatting)?.user

Expand Down Expand Up @@ -83,15 +80,10 @@ internal fun ChannelChatScreen(
modifier = modifier,
state = state,
inputState = inputState,
isEmotePickerOpen = isEmotePickerOpen,
showBackButton = !isStandalone && canNavigateUp,
showBubbleButton = canOpenInBubble,
isEmotePickerOpen = isEmotePickerOpen,
showTimestamps = prefs.showTimestamps,
onWatchLiveClicked = {
(state as? ChatViewModel.State.Chatting)?.user?.let { user ->
uriHandler.openUri(createChannelExternalLink(user))
}
},
onMessageChange = { textFieldValue ->
viewModel.onMessageInputChanged(
message = textFieldValue.text,
Expand All @@ -113,9 +105,6 @@ internal fun ChannelChatScreen(
onClearReplyingTo = {
viewModel.onReplyToMessage(null)
},
onReuseLastMessageClicked = {
viewModel.onReuseLastMessageClicked()
},
onOpenBubbleClicked = {
if (user != null) {
notifier.notify(
Expand All @@ -124,18 +113,19 @@ internal fun ChannelChatScreen(
)
}
},
onTriggerAutoComplete = {
viewModel.onTriggerAutoComplete()
},
onTriggerAutoComplete = viewModel::onTriggerAutoComplete,
onSubmit = {
viewModel.submit(
screenDensity = density,
isDarkTheme = isDarkTheme,
)
},
onReplyToMessage = viewModel::onReplyToMessage,
onDismissUserInfo = viewModel::onDismissUserInfo,
onShowInfoForUserId = viewModel::onShowUserInfo,
onDismissUserInfo = viewModel::onDismissUserInfo,
onShowStreamInfo = viewModel::onShowStreamInfo,
onDismissStreamInfo = viewModel::onDismissStreamInfo,
onReuseLastMessageClicked = viewModel::onReuseLastMessageClicked,
onNavigateUp = onNavigateUp,
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import androidx.compose.animation.expandVertically
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.shrinkVertically
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.asPaddingValues
Expand All @@ -17,7 +16,6 @@ import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarDuration
import androidx.compose.material3.SnackbarHost
Expand Down Expand Up @@ -55,6 +53,7 @@ import fr.outadoc.justchatting.feature.chat.domain.model.Chatter
import fr.outadoc.justchatting.feature.chat.presentation.ChatViewModel
import fr.outadoc.justchatting.feature.chat.presentation.MessagePostConstraint
import fr.outadoc.justchatting.feature.emotes.domain.model.Emote
import fr.outadoc.justchatting.feature.timeline.presentation.mobile.LiveDetailsDialog
import fr.outadoc.justchatting.shared.MR
import fr.outadoc.justchatting.utils.presentation.AppTheme
import kotlinx.coroutines.launch
Expand All @@ -70,7 +69,6 @@ internal fun ChannelChatScreenContent(
showBubbleButton: Boolean = true,
isEmotePickerOpen: Boolean = false,
showTimestamps: Boolean,
onWatchLiveClicked: () -> Unit = {},
onMessageChange: (TextFieldValue) -> Unit = {},
onToggleEmotePicker: () -> Unit = {},
onEmoteClick: (Emote) -> Unit = {},
Expand All @@ -80,8 +78,10 @@ internal fun ChannelChatScreenContent(
onTriggerAutoComplete: () -> Unit = {},
onSubmit: () -> Unit = {},
onReplyToMessage: (ChatListItem.Message) -> Unit = {},
onDismissUserInfo: () -> Unit = {},
onShowInfoForUserId: (String) -> Unit = {},
onDismissUserInfo: () -> Unit = {},
onShowStreamInfo: () -> Unit = {},
onDismissStreamInfo: () -> Unit = {},
onReuseLastMessageClicked: () -> Unit = {},
onNavigateUp: () -> Unit = {},
) {
Expand Down Expand Up @@ -115,15 +115,14 @@ internal fun ChannelChatScreenContent(
.hazeChild(
state = hazeState,
style = HazeMaterials.regular(),
)
.clickable(
onClick = { user?.id?.let(onShowInfoForUserId) },
onClickLabel = stringResource(MR.strings.stream_info),
),
colors = TopAppBarDefaults.topAppBarColors(Color.Transparent),
user = user,
stream = stream,
onWatchLiveClicked = onWatchLiveClicked,
onUserClicked = {
user?.id?.let(onShowInfoForUserId)
},
onStreamInfoClicked = onShowStreamInfo,
onOpenBubbleClicked = onOpenBubbleClicked,
showBackButton = showBackButton,
showBubbleButton = showBubbleButton,
Expand Down Expand Up @@ -261,24 +260,34 @@ internal fun ChannelChatScreenContent(
},
)

val showInfoForUserId: String? =
(state as? ChatViewModel.State.Chatting)?.showInfoForUserId
when (state) {
is ChatViewModel.State.Chatting -> {
if (state.showInfoForUserId != null) {
UserInfoDialog(
modifier = Modifier
.fillMaxWidth()
.padding(
start = 24.dp,
end = 24.dp,
bottom = 24.dp,
),
userId = state.showInfoForUserId,
onDismissRequest = onDismissUserInfo,
)
}

if (showInfoForUserId != null) {
ModalBottomSheet(
onDismissRequest = { onDismissUserInfo() },
) {
StreamAndUserInfoScreen(
modifier = Modifier
.fillMaxWidth()
.padding(
start = 24.dp,
end = 24.dp,
bottom = 24.dp,
),
userId = showInfoForUserId,
)
if (state.isStreamInfoVisible && state.stream != null) {
LiveDetailsDialog(
user = state.user,
stream = state.stream,
onDismissRequest = onDismissStreamInfo,
onOpenChat = null,
onOpenInBubble = onOpenBubbleClicked,
)
}
}

else -> {}
}
}

Expand Down
Loading

0 comments on commit 385cda5

Please sign in to comment.