mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-03-17 21:31:57 +01:00
Refactors chats into public, private and list views for tablets and phones
This commit is contained in:
parent
2b2b219536
commit
3942847d16
@ -81,7 +81,7 @@ import com.vitorpamplona.amethyst.ui.note.SearchIcon
|
||||
import com.vitorpamplona.amethyst.ui.note.UsernameDisplay
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.CloseButton
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist.ChannelName
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.list.ChannelName
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.search.SearchBarViewModel
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.ui.theme.DividerThickness
|
||||
|
@ -62,7 +62,7 @@ import com.vitorpamplona.amethyst.ui.note.UserCompose
|
||||
import com.vitorpamplona.amethyst.ui.note.timeAgo
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.CloseButton
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist.LoadUser
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.list.LoadUser
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.ui.theme.DoubleHorzSpacer
|
||||
import com.vitorpamplona.amethyst.ui.theme.DoubleVertSpacer
|
||||
|
@ -41,7 +41,7 @@ import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.ui.note.elements.TimeAgo
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist.NewItemsBubble
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.list.NewItemsBubble
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.ui.theme.DividerThickness
|
||||
import com.vitorpamplona.amethyst.ui.theme.DoubleHorzSpacer
|
||||
|
@ -60,10 +60,10 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.LoadRedirectScreen
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.NewPostScreen
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarks.BookmarkListScreen
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist.ChatroomListScreen
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist.private.ChatroomScreen
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist.private.ChatroomScreenByAuthor
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist.public.ChannelScreen
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.list.MessagesScreen
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.private.ChatroomScreen
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.private.ChatroomScreenByAuthor
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.public.ChannelScreen
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.communities.CommunityScreen
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.DiscoverScreen
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.drafts.DraftListScreen
|
||||
@ -120,7 +120,7 @@ fun AppNavigation(
|
||||
exitTransition = { fadeOut(animationSpec = tween(200)) },
|
||||
) {
|
||||
composable(Route.Home.route) { HomeScreen(accountViewModel, nav) }
|
||||
composable(Route.Message.route) { ChatroomListScreen(accountViewModel, nav) }
|
||||
composable(Route.Message.route) { MessagesScreen(accountViewModel, nav) }
|
||||
composable(Route.Video.route) { VideoScreen(accountViewModel, nav) }
|
||||
composable(Route.Discover.route) { DiscoverScreen(accountViewModel, nav) }
|
||||
composable(Route.Notification.route) { NotificationScreen(sharedPreferencesViewModel, accountViewModel, nav) }
|
||||
|
@ -78,11 +78,11 @@ import com.vitorpamplona.amethyst.ui.layouts.LeftPictureLayout
|
||||
import com.vitorpamplona.amethyst.ui.navigation.INav
|
||||
import com.vitorpamplona.amethyst.ui.note.elements.BannerImage
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist.public.ChannelHeader
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist.public.EndedFlag
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist.public.LiveFlag
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist.public.OfflineFlag
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist.public.ScheduledFlag
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.public.ChannelHeader
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.public.EndedFlag
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.public.LiveFlag
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.public.OfflineFlag
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.public.ScheduledFlag
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.dvms.observeAppDefinition
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.CheckIfVideoIsOnline
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.equalImmutableLists
|
||||
|
@ -123,7 +123,7 @@ import com.vitorpamplona.amethyst.ui.note.types.RenderTorrentComment
|
||||
import com.vitorpamplona.amethyst.ui.note.types.RenderWikiContent
|
||||
import com.vitorpamplona.amethyst.ui.note.types.VideoDisplay
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist.public.RenderChannelHeader
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.public.RenderChannelHeader
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.ui.theme.DoubleVertSpacer
|
||||
import com.vitorpamplona.amethyst.ui.theme.Font12SP
|
||||
|
@ -44,7 +44,7 @@ import com.vitorpamplona.amethyst.ui.components.RobohashAsyncImage
|
||||
import com.vitorpamplona.amethyst.ui.components.RobohashFallbackAsyncImage
|
||||
import com.vitorpamplona.amethyst.ui.navigation.INav
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist.LoadUser
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.list.LoadUser
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
||||
import com.vitorpamplona.quartz.nip17Dm.base.ChatroomKey
|
||||
|
||||
|
@ -33,7 +33,7 @@ import com.vitorpamplona.amethyst.model.Note
|
||||
import com.vitorpamplona.amethyst.ui.components.GenericLoadable
|
||||
import com.vitorpamplona.amethyst.ui.navigation.INav
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist.public.ChannelHeader
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.public.ChannelHeader
|
||||
import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer
|
||||
import com.vitorpamplona.amethyst.ui.theme.replyModifier
|
||||
import com.vitorpamplona.quartz.nip28PublicChat.message.ChannelMessageEvent
|
||||
|
@ -36,7 +36,7 @@ import com.vitorpamplona.amethyst.ui.components.GenericLoadable
|
||||
import com.vitorpamplona.amethyst.ui.navigation.INav
|
||||
import com.vitorpamplona.amethyst.ui.navigation.routeFor
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist.private.ChatroomHeader
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.private.ChatroomHeader
|
||||
import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer
|
||||
import com.vitorpamplona.amethyst.ui.theme.replyModifier
|
||||
import com.vitorpamplona.quartz.nip17Dm.base.ChatroomKeyable
|
||||
|
@ -49,7 +49,7 @@ import com.vitorpamplona.amethyst.ui.components.ZoomableContentView
|
||||
import com.vitorpamplona.amethyst.ui.navigation.INav
|
||||
import com.vitorpamplona.amethyst.ui.navigation.routeFor
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist.private.ChatroomHeader
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.private.ChatroomHeader
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.ui.theme.HalfVertPadding
|
||||
import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer
|
||||
|
@ -61,9 +61,9 @@ import com.vitorpamplona.amethyst.ui.note.ZapReaction
|
||||
import com.vitorpamplona.amethyst.ui.note.elements.DisplayUncitedHashtags
|
||||
import com.vitorpamplona.amethyst.ui.note.elements.MoreOptionsButton
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist.public.JoinCommunityButton
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist.public.LeaveCommunityButton
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist.public.NormalTimeAgo
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.public.JoinCommunityButton
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.public.LeaveCommunityButton
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.public.NormalTimeAgo
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.equalImmutableLists
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.ui.theme.DoubleHorzSpacer
|
||||
|
@ -58,8 +58,8 @@ import com.vitorpamplona.amethyst.ui.note.ClickableUserPicture
|
||||
import com.vitorpamplona.amethyst.ui.note.DisplayAuthorBanner
|
||||
import com.vitorpamplona.amethyst.ui.note.UsernameDisplay
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist.public.LiveFlag
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist.public.ScheduledFlag
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.public.LiveFlag
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.public.ScheduledFlag
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.CheckIfVideoIsOnline
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.CrossfadeCheckIfVideoIsOnline
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel
|
||||
|
@ -33,7 +33,7 @@ import com.vitorpamplona.amethyst.model.Note
|
||||
import com.vitorpamplona.amethyst.ui.components.GenericLoadable
|
||||
import com.vitorpamplona.amethyst.ui.navigation.INav
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist.public.ChannelHeader
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.public.ChannelHeader
|
||||
import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer
|
||||
import com.vitorpamplona.amethyst.ui.theme.replyModifier
|
||||
import com.vitorpamplona.quartz.nip53LiveActivities.chat.LiveActivitiesChatMessageEvent
|
||||
|
@ -43,7 +43,7 @@ import com.vitorpamplona.amethyst.ui.navigation.routeFor
|
||||
import com.vitorpamplona.amethyst.ui.note.LoadDecryptedContent
|
||||
import com.vitorpamplona.amethyst.ui.note.elements.DisplayUncitedHashtags
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist.private.ChatroomHeader
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.private.ChatroomHeader
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer
|
||||
import com.vitorpamplona.amethyst.ui.theme.placeholderText
|
||||
|
@ -1,515 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2024 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist
|
||||
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.consumeWindowInsets
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.systemBarsPadding
|
||||
import androidx.compose.foundation.pager.HorizontalPager
|
||||
import androidx.compose.foundation.pager.PagerState
|
||||
import androidx.compose.foundation.pager.rememberPagerState
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.MoreVert
|
||||
import androidx.compose.material3.DrawerState
|
||||
import androidx.compose.material3.DropdownMenu
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Tab
|
||||
import androidx.compose.material3.TabRow
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.MutableState
|
||||
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.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalLifecycleOwner
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleEventObserver
|
||||
import com.google.accompanist.adaptive.FoldAwareConfiguration
|
||||
import com.google.accompanist.adaptive.HorizontalTwoPaneStrategy
|
||||
import com.google.accompanist.adaptive.TwoPane
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.service.NostrChatroomListDataSource
|
||||
import com.vitorpamplona.amethyst.ui.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.ui.navigation.AppBottomBar
|
||||
import com.vitorpamplona.amethyst.ui.navigation.INav
|
||||
import com.vitorpamplona.amethyst.ui.navigation.MainTopBar
|
||||
import com.vitorpamplona.amethyst.ui.navigation.Route
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.DisappearingScaffold
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist.private.Chatroom
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist.public.Channel
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size20dp
|
||||
import com.vitorpamplona.amethyst.ui.theme.TabRowHeight
|
||||
import com.vitorpamplona.amethyst.ui.theme.placeholderText
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@Composable
|
||||
fun ChatroomListScreen(
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
val windowSizeClass by accountViewModel.settings.windowSizeClass
|
||||
|
||||
val twoPane by remember {
|
||||
derivedStateOf {
|
||||
when (windowSizeClass?.widthSizeClass) {
|
||||
WindowWidthSizeClass.Compact -> false
|
||||
WindowWidthSizeClass.Expanded,
|
||||
WindowWidthSizeClass.Medium,
|
||||
-> true
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (twoPane && windowSizeClass != null) {
|
||||
ChatroomListTwoPane(
|
||||
knownFeedContentState = accountViewModel.feedStates.dmKnown,
|
||||
newFeedContentState = accountViewModel.feedStates.dmNew,
|
||||
widthSizeClass = windowSizeClass!!.widthSizeClass,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
} else {
|
||||
ScaffoldChatroomListScreenOnlyList(
|
||||
knownFeedContentState = accountViewModel.feedStates.dmKnown,
|
||||
newFeedContentState = accountViewModel.feedStates.dmNew,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class TwoPaneNav(
|
||||
val nav: INav,
|
||||
val scope: CoroutineScope,
|
||||
) : INav {
|
||||
override val drawerState: DrawerState = nav.drawerState
|
||||
|
||||
val innerNav = mutableStateOf<RouteId?>(null)
|
||||
|
||||
override fun nav(route: String) {
|
||||
if (route.startsWith("Room/") || route.startsWith("Channel/")) {
|
||||
innerNav.value = RouteId(route.substringBefore("/"), route.substringAfter("/"))
|
||||
} else {
|
||||
nav.nav(route)
|
||||
}
|
||||
}
|
||||
|
||||
override fun nav(routeMaker: suspend () -> String) {
|
||||
scope.launch(Dispatchers.Default) {
|
||||
val route = routeMaker()
|
||||
if (route.startsWith("Room/") || route.startsWith("Channel/")) {
|
||||
innerNav.value = RouteId(route.substringBefore("/"), route.substringAfter("/"))
|
||||
} else {
|
||||
nav.nav(route)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun newStack(route: String) {
|
||||
nav.newStack(route)
|
||||
}
|
||||
|
||||
override fun popBack() {
|
||||
nav.popBack()
|
||||
}
|
||||
|
||||
override fun popUpTo(
|
||||
route: String,
|
||||
upTo: String,
|
||||
) {
|
||||
nav.popUpTo(route, upTo)
|
||||
}
|
||||
|
||||
override fun closeDrawer() {
|
||||
nav.closeDrawer()
|
||||
}
|
||||
|
||||
override fun openDrawer() {
|
||||
nav.openDrawer()
|
||||
}
|
||||
|
||||
data class RouteId(
|
||||
val route: String,
|
||||
val id: String,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ChatroomListTwoPane(
|
||||
knownFeedContentState: FeedContentState,
|
||||
newFeedContentState: FeedContentState,
|
||||
widthSizeClass: WindowWidthSizeClass,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
/** The index of the currently selected word, or `null` if none is selected */
|
||||
val scope = rememberCoroutineScope()
|
||||
val twoPaneNav = remember { TwoPaneNav(nav, scope) }
|
||||
|
||||
val strategy =
|
||||
remember {
|
||||
if (widthSizeClass == WindowWidthSizeClass.Expanded) {
|
||||
HorizontalTwoPaneStrategy(
|
||||
splitFraction = 1f / 3f,
|
||||
)
|
||||
} else {
|
||||
HorizontalTwoPaneStrategy(
|
||||
splitFraction = 1f / 2.5f,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
DisappearingScaffold(
|
||||
isInvertedLayout = false,
|
||||
topBar = {
|
||||
Column {
|
||||
MainTopBar(accountViewModel, nav)
|
||||
}
|
||||
},
|
||||
bottomBar = {
|
||||
AppBottomBar(Route.Message, accountViewModel) { route, _ ->
|
||||
nav.newStack(route.base)
|
||||
}
|
||||
},
|
||||
accountViewModel = accountViewModel,
|
||||
) {
|
||||
TwoPane(
|
||||
first = {
|
||||
Box(Modifier.fillMaxSize().systemBarsPadding(), contentAlignment = Alignment.BottomEnd) {
|
||||
ChatroomListScreenOnlyList(
|
||||
knownFeedContentState,
|
||||
newFeedContentState,
|
||||
accountViewModel,
|
||||
twoPaneNav,
|
||||
)
|
||||
|
||||
Box(Modifier.padding(Size20dp), contentAlignment = Alignment.Center) {
|
||||
ChannelFabColumn(accountViewModel, nav)
|
||||
}
|
||||
}
|
||||
},
|
||||
second = {
|
||||
Box(Modifier.fillMaxSize().systemBarsPadding()) {
|
||||
twoPaneNav.innerNav.value?.let {
|
||||
if (it.route == "Room") {
|
||||
Chatroom(
|
||||
roomId = it.id,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
}
|
||||
|
||||
if (it.route == "Channel") {
|
||||
Channel(
|
||||
channelId = it.id,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
strategy = strategy,
|
||||
displayFeatures = accountViewModel.settings.displayFeatures.value,
|
||||
foldAwareConfiguration = FoldAwareConfiguration.VerticalFoldsOnly,
|
||||
modifier = Modifier.padding(it).consumeWindowInsets(it).fillMaxSize(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun ChatroomListScreenOnlyList(
|
||||
knownFeedContentState: FeedContentState,
|
||||
newFeedContentState: FeedContentState,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
val pagerState = rememberPagerState { 2 }
|
||||
|
||||
val markKnownAsRead = remember { mutableStateOf(false) }
|
||||
val markNewAsRead = remember { mutableStateOf(false) }
|
||||
|
||||
WatchAccountForListScreen(knownFeedContentState, newFeedContentState, accountViewModel)
|
||||
WatchLifecycleAndRefreshDataSource(accountViewModel)
|
||||
|
||||
val tabs by
|
||||
remember(knownFeedContentState, markKnownAsRead) {
|
||||
derivedStateOf {
|
||||
listOf(
|
||||
ChatroomListTabItem(R.string.known, knownFeedContentState, markKnownAsRead),
|
||||
ChatroomListTabItem(R.string.new_requests, newFeedContentState, markNewAsRead),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
ChatroomListOnlyTabs(
|
||||
pagerState,
|
||||
tabs,
|
||||
{ markKnownAsRead.value = true },
|
||||
{ markNewAsRead.value = true },
|
||||
)
|
||||
|
||||
ChatroomListTabs(
|
||||
pagerState,
|
||||
tabs,
|
||||
PaddingValues(0.dp),
|
||||
accountViewModel,
|
||||
nav,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun ScaffoldChatroomListScreenOnlyList(
|
||||
knownFeedContentState: FeedContentState,
|
||||
newFeedContentState: FeedContentState,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
val pagerState = rememberPagerState { 2 }
|
||||
|
||||
val markKnownAsRead = remember { mutableStateOf(false) }
|
||||
val markNewAsRead = remember { mutableStateOf(false) }
|
||||
|
||||
WatchAccountForListScreen(knownFeedContentState, newFeedContentState, accountViewModel)
|
||||
WatchLifecycleAndRefreshDataSource(accountViewModel)
|
||||
|
||||
val tabs by
|
||||
remember(knownFeedContentState, markKnownAsRead) {
|
||||
derivedStateOf {
|
||||
listOf(
|
||||
ChatroomListTabItem(R.string.known, knownFeedContentState, markKnownAsRead),
|
||||
ChatroomListTabItem(R.string.new_requests, newFeedContentState, markNewAsRead),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
DisappearingScaffold(
|
||||
isInvertedLayout = false,
|
||||
topBar = {
|
||||
Column {
|
||||
MainTopBar(accountViewModel, nav)
|
||||
ChatroomListOnlyTabs(
|
||||
pagerState,
|
||||
tabs,
|
||||
{ markKnownAsRead.value = true },
|
||||
{ markNewAsRead.value = true },
|
||||
)
|
||||
}
|
||||
},
|
||||
bottomBar = {
|
||||
AppBottomBar(Route.Message, accountViewModel) { route, _ ->
|
||||
if (route == Route.Message) {
|
||||
tabs[pagerState.currentPage].feedContentState.sendToTop()
|
||||
} else {
|
||||
nav.newStack(route.base)
|
||||
}
|
||||
}
|
||||
},
|
||||
floatingButton = {
|
||||
ChannelFabColumn(accountViewModel, nav)
|
||||
},
|
||||
accountViewModel = accountViewModel,
|
||||
) {
|
||||
ChatroomListTabs(
|
||||
pagerState,
|
||||
tabs,
|
||||
it,
|
||||
accountViewModel,
|
||||
nav,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun WatchLifecycleAndRefreshDataSource(accountViewModel: AccountViewModel) {
|
||||
val lifeCycleOwner = LocalLifecycleOwner.current
|
||||
DisposableEffect(lifeCycleOwner) {
|
||||
val observer =
|
||||
LifecycleEventObserver { _, event ->
|
||||
if (event == Lifecycle.Event.ON_RESUME) {
|
||||
NostrChatroomListDataSource.account = accountViewModel.account
|
||||
NostrChatroomListDataSource.start()
|
||||
}
|
||||
}
|
||||
|
||||
lifeCycleOwner.lifecycle.addObserver(observer)
|
||||
onDispose { lifeCycleOwner.lifecycle.removeObserver(observer) }
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
private fun ChatroomListTabs(
|
||||
pagerState: PagerState,
|
||||
tabs: List<ChatroomListTabItem>,
|
||||
paddingValues: PaddingValues,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
HorizontalPager(
|
||||
contentPadding = paddingValues,
|
||||
state = pagerState,
|
||||
userScrollEnabled = false,
|
||||
) { page ->
|
||||
ChatroomListFeedView(
|
||||
feedContentState = tabs[page].feedContentState,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
markAsRead = tabs[page].markAsRead,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
private fun ChatroomListOnlyTabs(
|
||||
pagerState: PagerState,
|
||||
tabs: List<ChatroomListTabItem>,
|
||||
onMarkKnownAsRead: () -> Unit,
|
||||
onMarkNewAsRead: () -> Unit,
|
||||
) {
|
||||
var moreActionsExpanded by remember { mutableStateOf(false) }
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
|
||||
Box(Modifier.fillMaxWidth()) {
|
||||
TabRow(
|
||||
containerColor = Color.Transparent,
|
||||
contentColor = MaterialTheme.colorScheme.onBackground,
|
||||
selectedTabIndex = pagerState.currentPage,
|
||||
modifier = TabRowHeight,
|
||||
) {
|
||||
tabs.forEachIndexed { index, tab ->
|
||||
Tab(
|
||||
selected = pagerState.currentPage == index,
|
||||
text = { Text(text = stringRes(tab.resource)) },
|
||||
onClick = { coroutineScope.launch { pagerState.animateScrollToPage(index) } },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
IconButton(
|
||||
modifier =
|
||||
Modifier
|
||||
.size(40.dp)
|
||||
.align(Alignment.CenterEnd),
|
||||
onClick = { moreActionsExpanded = true },
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.MoreVert,
|
||||
contentDescription = stringRes(id = R.string.more_options),
|
||||
tint = MaterialTheme.colorScheme.placeholderText,
|
||||
)
|
||||
|
||||
ChatroomTabMenu(
|
||||
moreActionsExpanded,
|
||||
{ moreActionsExpanded = false },
|
||||
onMarkKnownAsRead,
|
||||
onMarkNewAsRead,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun WatchAccountForListScreen(
|
||||
knownFeedContentState: FeedContentState,
|
||||
newFeedContentState: FeedContentState,
|
||||
accountViewModel: AccountViewModel,
|
||||
) {
|
||||
LaunchedEffect(accountViewModel) {
|
||||
launch(Dispatchers.IO) {
|
||||
NostrChatroomListDataSource.account = accountViewModel.account
|
||||
NostrChatroomListDataSource.start()
|
||||
knownFeedContentState.invalidateData(true)
|
||||
newFeedContentState.invalidateData(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Immutable
|
||||
class ChatroomListTabItem(
|
||||
val resource: Int,
|
||||
val feedContentState: FeedContentState,
|
||||
val markAsRead: MutableState<Boolean>,
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun ChatroomTabMenu(
|
||||
expanded: Boolean,
|
||||
onDismiss: () -> Unit,
|
||||
onMarkKnownAsRead: () -> Unit,
|
||||
onMarkNewAsRead: () -> Unit,
|
||||
) {
|
||||
DropdownMenu(expanded = expanded, onDismissRequest = onDismiss) {
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringRes(R.string.mark_all_known_as_read)) },
|
||||
onClick = {
|
||||
onMarkKnownAsRead()
|
||||
onDismiss()
|
||||
},
|
||||
)
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringRes(R.string.mark_all_new_as_read)) },
|
||||
onClick = {
|
||||
onMarkNewAsRead()
|
||||
onDismiss()
|
||||
},
|
||||
)
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringRes(R.string.mark_all_as_read)) },
|
||||
onClick = {
|
||||
onMarkKnownAsRead()
|
||||
onMarkNewAsRead()
|
||||
onDismiss()
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
@ -18,7 +18,7 @@
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.list
|
||||
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
@ -18,7 +18,7 @@
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.list
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
@ -0,0 +1,68 @@
|
||||
/**
|
||||
* Copyright (c) 2024 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.list
|
||||
|
||||
import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import com.vitorpamplona.amethyst.ui.navigation.INav
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.list.singlepane.MessagesSinglePane
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.list.twopane.MessagesTwoPane
|
||||
|
||||
@Composable
|
||||
fun MessagesScreen(
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
val windowSizeClass by accountViewModel.settings.windowSizeClass
|
||||
|
||||
val twoPane by remember {
|
||||
derivedStateOf {
|
||||
when (windowSizeClass?.widthSizeClass) {
|
||||
WindowWidthSizeClass.Compact -> false
|
||||
WindowWidthSizeClass.Expanded,
|
||||
WindowWidthSizeClass.Medium,
|
||||
-> true
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (twoPane && windowSizeClass != null) {
|
||||
MessagesTwoPane(
|
||||
knownFeedContentState = accountViewModel.feedStates.dmKnown,
|
||||
newFeedContentState = accountViewModel.feedStates.dmNew,
|
||||
widthSizeClass = windowSizeClass!!.widthSizeClass,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
} else {
|
||||
MessagesSinglePane(
|
||||
knownFeedContentState = accountViewModel.feedStates.dmKnown,
|
||||
newFeedContentState = accountViewModel.feedStates.dmNew,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Copyright (c) 2024 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.list
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import com.vitorpamplona.amethyst.service.NostrChatroomListDataSource
|
||||
import com.vitorpamplona.amethyst.ui.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@Composable
|
||||
fun WatchAccountForListScreen(
|
||||
knownFeedContentState: FeedContentState,
|
||||
newFeedContentState: FeedContentState,
|
||||
accountViewModel: AccountViewModel,
|
||||
) {
|
||||
LaunchedEffect(accountViewModel) {
|
||||
launch(Dispatchers.IO) {
|
||||
NostrChatroomListDataSource.account = accountViewModel.account
|
||||
NostrChatroomListDataSource.start()
|
||||
knownFeedContentState.invalidateData(true)
|
||||
newFeedContentState.invalidateData(true)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Copyright (c) 2024 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.list
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleEventObserver
|
||||
import androidx.lifecycle.compose.LocalLifecycleOwner
|
||||
import com.vitorpamplona.amethyst.service.NostrChatroomListDataSource
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
|
||||
@Composable
|
||||
fun WatchLifecycleAndRefreshDataSource(accountViewModel: AccountViewModel) {
|
||||
val lifeCycleOwner = LocalLifecycleOwner.current
|
||||
DisposableEffect(lifeCycleOwner) {
|
||||
val observer =
|
||||
LifecycleEventObserver { _, event ->
|
||||
if (event == Lifecycle.Event.ON_RESUME) {
|
||||
NostrChatroomListDataSource.account = accountViewModel.account
|
||||
NostrChatroomListDataSource.start()
|
||||
}
|
||||
}
|
||||
|
||||
lifeCycleOwner.lifecycle.addObserver(observer)
|
||||
onDispose { lifeCycleOwner.lifecycle.removeObserver(observer) }
|
||||
}
|
||||
}
|
@ -18,7 +18,7 @@
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.list.feed
|
||||
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.foundation.layout.Row
|
||||
@ -42,6 +42,7 @@ import com.vitorpamplona.amethyst.ui.feeds.LoadingFeed
|
||||
import com.vitorpamplona.amethyst.ui.feeds.RefresheableBox
|
||||
import com.vitorpamplona.amethyst.ui.navigation.INav
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.list.ChatroomHeaderCompose
|
||||
import com.vitorpamplona.amethyst.ui.theme.DividerThickness
|
||||
import com.vitorpamplona.amethyst.ui.theme.FeedPadding
|
||||
|
||||
@ -52,7 +53,9 @@ fun ChatroomListFeedView(
|
||||
nav: INav,
|
||||
markAsRead: MutableState<Boolean>,
|
||||
) {
|
||||
RefresheableBox(feedContentState, true) { CrossFadeState(feedContentState, accountViewModel, nav, markAsRead) }
|
||||
RefresheableBox(feedContentState, true) {
|
||||
CrossFadeState(feedContentState, accountViewModel, nav, markAsRead)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
@ -0,0 +1,169 @@
|
||||
/**
|
||||
* Copyright (c) 2024 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.list.feed
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.pager.HorizontalPager
|
||||
import androidx.compose.foundation.pager.PagerState
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.MoreVert
|
||||
import androidx.compose.material3.DropdownMenu
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Tab
|
||||
import androidx.compose.material3.TabRow
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.ui.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.ui.navigation.INav
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.ui.theme.TabRowHeight
|
||||
import com.vitorpamplona.amethyst.ui.theme.placeholderText
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@Immutable
|
||||
class MessagesTabItem(
|
||||
val resource: Int,
|
||||
val feedContentState: FeedContentState,
|
||||
val markAsRead: MutableState<Boolean>,
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun MessagesTabHeader(
|
||||
pagerState: PagerState,
|
||||
tabs: List<MessagesTabItem>,
|
||||
onMarkKnownAsRead: () -> Unit,
|
||||
onMarkNewAsRead: () -> Unit,
|
||||
) {
|
||||
var moreActionsExpanded by remember { mutableStateOf(false) }
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
|
||||
Box(Modifier.fillMaxWidth()) {
|
||||
TabRow(
|
||||
containerColor = Color.Transparent,
|
||||
contentColor = MaterialTheme.colorScheme.onBackground,
|
||||
selectedTabIndex = pagerState.currentPage,
|
||||
modifier = TabRowHeight,
|
||||
) {
|
||||
tabs.forEachIndexed { index, tab ->
|
||||
Tab(
|
||||
selected = pagerState.currentPage == index,
|
||||
text = { Text(text = stringRes(tab.resource)) },
|
||||
onClick = { coroutineScope.launch { pagerState.animateScrollToPage(index) } },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
IconButton(
|
||||
modifier =
|
||||
Modifier
|
||||
.size(40.dp)
|
||||
.align(Alignment.CenterEnd),
|
||||
onClick = { moreActionsExpanded = true },
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.MoreVert,
|
||||
contentDescription = stringRes(id = R.string.more_options),
|
||||
tint = MaterialTheme.colorScheme.placeholderText,
|
||||
)
|
||||
|
||||
MessagesTabMenu(
|
||||
moreActionsExpanded,
|
||||
{ moreActionsExpanded = false },
|
||||
onMarkKnownAsRead,
|
||||
onMarkNewAsRead,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MessagesPager(
|
||||
pagerState: PagerState,
|
||||
tabs: List<MessagesTabItem>,
|
||||
paddingValues: PaddingValues,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
HorizontalPager(
|
||||
contentPadding = paddingValues,
|
||||
state = pagerState,
|
||||
userScrollEnabled = false,
|
||||
) { page ->
|
||||
ChatroomListFeedView(
|
||||
feedContentState = tabs[page].feedContentState,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
markAsRead = tabs[page].markAsRead,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MessagesTabMenu(
|
||||
expanded: Boolean,
|
||||
onDismiss: () -> Unit,
|
||||
onMarkKnownAsRead: () -> Unit,
|
||||
onMarkNewAsRead: () -> Unit,
|
||||
) {
|
||||
DropdownMenu(expanded = expanded, onDismissRequest = onDismiss) {
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringRes(R.string.mark_all_known_as_read)) },
|
||||
onClick = {
|
||||
onMarkKnownAsRead()
|
||||
onDismiss()
|
||||
},
|
||||
)
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringRes(R.string.mark_all_new_as_read)) },
|
||||
onClick = {
|
||||
onMarkNewAsRead()
|
||||
onDismiss()
|
||||
},
|
||||
)
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringRes(R.string.mark_all_as_read)) },
|
||||
onClick = {
|
||||
onMarkKnownAsRead()
|
||||
onMarkNewAsRead()
|
||||
onDismiss()
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,105 @@
|
||||
/**
|
||||
* Copyright (c) 2024 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.list.singlepane
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.pager.rememberPagerState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.ui.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.ui.navigation.AppBottomBar
|
||||
import com.vitorpamplona.amethyst.ui.navigation.INav
|
||||
import com.vitorpamplona.amethyst.ui.navigation.MainTopBar
|
||||
import com.vitorpamplona.amethyst.ui.navigation.Route
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.DisappearingScaffold
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.list.ChannelFabColumn
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.list.WatchAccountForListScreen
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.list.WatchLifecycleAndRefreshDataSource
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.list.feed.MessagesPager
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.list.feed.MessagesTabHeader
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.list.feed.MessagesTabItem
|
||||
|
||||
@Composable
|
||||
fun MessagesSinglePane(
|
||||
knownFeedContentState: FeedContentState,
|
||||
newFeedContentState: FeedContentState,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
val pagerState = rememberPagerState { 2 }
|
||||
|
||||
val markKnownAsRead = remember { mutableStateOf(false) }
|
||||
val markNewAsRead = remember { mutableStateOf(false) }
|
||||
|
||||
WatchAccountForListScreen(knownFeedContentState, newFeedContentState, accountViewModel)
|
||||
WatchLifecycleAndRefreshDataSource(accountViewModel)
|
||||
|
||||
val tabs by
|
||||
remember(knownFeedContentState, markKnownAsRead) {
|
||||
derivedStateOf {
|
||||
listOf(
|
||||
MessagesTabItem(R.string.known, knownFeedContentState, markKnownAsRead),
|
||||
MessagesTabItem(R.string.new_requests, newFeedContentState, markNewAsRead),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
DisappearingScaffold(
|
||||
isInvertedLayout = false,
|
||||
topBar = {
|
||||
Column {
|
||||
MainTopBar(accountViewModel, nav)
|
||||
MessagesTabHeader(
|
||||
pagerState,
|
||||
tabs,
|
||||
{ markKnownAsRead.value = true },
|
||||
{ markNewAsRead.value = true },
|
||||
)
|
||||
}
|
||||
},
|
||||
bottomBar = {
|
||||
AppBottomBar(Route.Message, accountViewModel) { route, _ ->
|
||||
if (route == Route.Message) {
|
||||
tabs[pagerState.currentPage].feedContentState.sendToTop()
|
||||
} else {
|
||||
nav.newStack(route.base)
|
||||
}
|
||||
}
|
||||
},
|
||||
floatingButton = {
|
||||
ChannelFabColumn(accountViewModel, nav)
|
||||
},
|
||||
accountViewModel = accountViewModel,
|
||||
) {
|
||||
MessagesPager(
|
||||
pagerState,
|
||||
tabs,
|
||||
it,
|
||||
accountViewModel,
|
||||
nav,
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
/**
|
||||
* Copyright (c) 2024 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.list.twopane
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.pager.rememberPagerState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.ui.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.ui.navigation.INav
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.list.WatchAccountForListScreen
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.list.WatchLifecycleAndRefreshDataSource
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.list.feed.MessagesPager
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.list.feed.MessagesTabHeader
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.list.feed.MessagesTabItem
|
||||
|
||||
@Composable
|
||||
fun ChatroomList(
|
||||
knownFeedContentState: FeedContentState,
|
||||
newFeedContentState: FeedContentState,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
val pagerState = rememberPagerState { 2 }
|
||||
|
||||
val markKnownAsRead = remember { mutableStateOf(false) }
|
||||
val markNewAsRead = remember { mutableStateOf(false) }
|
||||
|
||||
WatchAccountForListScreen(knownFeedContentState, newFeedContentState, accountViewModel)
|
||||
WatchLifecycleAndRefreshDataSource(accountViewModel)
|
||||
|
||||
val tabs by
|
||||
remember(knownFeedContentState, markKnownAsRead) {
|
||||
derivedStateOf {
|
||||
listOf(
|
||||
MessagesTabItem(R.string.known, knownFeedContentState, markKnownAsRead),
|
||||
MessagesTabItem(R.string.new_requests, newFeedContentState, markNewAsRead),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
MessagesTabHeader(
|
||||
pagerState,
|
||||
tabs,
|
||||
{ markKnownAsRead.value = true },
|
||||
{ markNewAsRead.value = true },
|
||||
)
|
||||
|
||||
MessagesPager(
|
||||
pagerState,
|
||||
tabs,
|
||||
PaddingValues(0.dp),
|
||||
accountViewModel,
|
||||
nav,
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,131 @@
|
||||
/**
|
||||
* Copyright (c) 2024 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.list.twopane
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.consumeWindowInsets
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.systemBarsPadding
|
||||
import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.google.accompanist.adaptive.FoldAwareConfiguration
|
||||
import com.google.accompanist.adaptive.HorizontalTwoPaneStrategy
|
||||
import com.google.accompanist.adaptive.TwoPane
|
||||
import com.vitorpamplona.amethyst.ui.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.ui.navigation.AppBottomBar
|
||||
import com.vitorpamplona.amethyst.ui.navigation.INav
|
||||
import com.vitorpamplona.amethyst.ui.navigation.MainTopBar
|
||||
import com.vitorpamplona.amethyst.ui.navigation.Route
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.DisappearingScaffold
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.list.ChannelFabColumn
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.private.Chatroom
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.public.Channel
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size20dp
|
||||
|
||||
@Composable
|
||||
fun MessagesTwoPane(
|
||||
knownFeedContentState: FeedContentState,
|
||||
newFeedContentState: FeedContentState,
|
||||
widthSizeClass: WindowWidthSizeClass,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
/** The index of the currently selected word, or `null` if none is selected */
|
||||
val scope = rememberCoroutineScope()
|
||||
val twoPaneNav = remember { TwoPaneNav(nav, scope) }
|
||||
|
||||
val strategy =
|
||||
remember {
|
||||
if (widthSizeClass == WindowWidthSizeClass.Expanded) {
|
||||
HorizontalTwoPaneStrategy(
|
||||
splitFraction = 1f / 3f,
|
||||
)
|
||||
} else {
|
||||
HorizontalTwoPaneStrategy(
|
||||
splitFraction = 1f / 2.5f,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
DisappearingScaffold(
|
||||
isInvertedLayout = false,
|
||||
topBar = {
|
||||
Column {
|
||||
MainTopBar(accountViewModel, nav)
|
||||
}
|
||||
},
|
||||
bottomBar = {
|
||||
AppBottomBar(Route.Message, accountViewModel) { route, _ ->
|
||||
nav.newStack(route.base)
|
||||
}
|
||||
},
|
||||
accountViewModel = accountViewModel,
|
||||
) { padding ->
|
||||
TwoPane(
|
||||
first = {
|
||||
Box(Modifier.fillMaxSize().systemBarsPadding(), contentAlignment = Alignment.BottomEnd) {
|
||||
ChatroomList(
|
||||
knownFeedContentState,
|
||||
newFeedContentState,
|
||||
accountViewModel,
|
||||
twoPaneNav,
|
||||
)
|
||||
|
||||
Box(Modifier.padding(Size20dp), contentAlignment = Alignment.Center) {
|
||||
ChannelFabColumn(accountViewModel, nav)
|
||||
}
|
||||
}
|
||||
},
|
||||
second = {
|
||||
Box(Modifier.fillMaxSize().systemBarsPadding()) {
|
||||
twoPaneNav.innerNav.value?.let {
|
||||
if (it.route == "Room") {
|
||||
Chatroom(
|
||||
roomId = it.id,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
}
|
||||
|
||||
if (it.route == "Channel") {
|
||||
Channel(
|
||||
channelId = it.id,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
strategy = strategy,
|
||||
displayFeatures = accountViewModel.settings.displayFeatures.value,
|
||||
foldAwareConfiguration = FoldAwareConfiguration.VerticalFoldsOnly,
|
||||
modifier = Modifier.padding(padding).consumeWindowInsets(padding).fillMaxSize(),
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
/**
|
||||
* Copyright (c) 2024 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.list.twopane
|
||||
|
||||
import androidx.compose.material3.DrawerState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import com.vitorpamplona.amethyst.ui.navigation.INav
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class TwoPaneNav(
|
||||
val nav: INav,
|
||||
val scope: CoroutineScope,
|
||||
) : INav {
|
||||
override val drawerState: DrawerState = nav.drawerState
|
||||
|
||||
val innerNav = mutableStateOf<RouteId?>(null)
|
||||
|
||||
override fun nav(route: String) {
|
||||
if (route.startsWith("Room/") || route.startsWith("Channel/")) {
|
||||
innerNav.value = RouteId(route.substringBefore("/"), route.substringAfter("/"))
|
||||
} else {
|
||||
nav.nav(route)
|
||||
}
|
||||
}
|
||||
|
||||
override fun nav(routeMaker: suspend () -> String) {
|
||||
scope.launch(Dispatchers.Default) {
|
||||
val route = routeMaker()
|
||||
if (route.startsWith("Room/") || route.startsWith("Channel/")) {
|
||||
innerNav.value = RouteId(route.substringBefore("/"), route.substringAfter("/"))
|
||||
} else {
|
||||
nav.nav(route)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun newStack(route: String) {
|
||||
nav.newStack(route)
|
||||
}
|
||||
|
||||
override fun popBack() {
|
||||
nav.popBack()
|
||||
}
|
||||
|
||||
override fun popUpTo(
|
||||
route: String,
|
||||
upTo: String,
|
||||
) {
|
||||
nav.popUpTo(route, upTo)
|
||||
}
|
||||
|
||||
override fun closeDrawer() {
|
||||
nav.closeDrawer()
|
||||
}
|
||||
|
||||
override fun openDrawer() {
|
||||
nav.openDrawer()
|
||||
}
|
||||
|
||||
data class RouteId(
|
||||
val route: String,
|
||||
val id: String,
|
||||
)
|
||||
}
|
@ -18,7 +18,7 @@
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist.private
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.private
|
||||
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.background
|
||||
@ -106,7 +106,7 @@ private fun BubblePreview() {
|
||||
|
||||
ChatBubbleLayout(
|
||||
isLoggedInUser = true,
|
||||
isDraft = true,
|
||||
isDraft = false,
|
||||
innerQuote = false,
|
||||
isComplete = true,
|
||||
hasDetailsToShow = true,
|
||||
@ -138,6 +138,40 @@ private fun BubblePreview() {
|
||||
Text("This is a very long long loong note")
|
||||
}
|
||||
|
||||
ChatBubbleLayout(
|
||||
isLoggedInUser = true,
|
||||
isDraft = true,
|
||||
innerQuote = false,
|
||||
isComplete = true,
|
||||
hasDetailsToShow = true,
|
||||
drawAuthorInfo = true,
|
||||
parentBackgroundColor = backgroundBubbleColor,
|
||||
onClick = { false },
|
||||
onAuthorClick = {},
|
||||
actionMenu = { onDismiss ->
|
||||
},
|
||||
drawAuthorLine = {
|
||||
UserDisplayNameLayout(
|
||||
picture = {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Person,
|
||||
contentDescription = null,
|
||||
modifier =
|
||||
Modifier
|
||||
.size(Size20dp)
|
||||
.clip(CircleShape),
|
||||
)
|
||||
},
|
||||
name = {
|
||||
Text("Me", fontWeight = FontWeight.Bold)
|
||||
},
|
||||
)
|
||||
},
|
||||
detailRow = { Text("Relays and Actions") },
|
||||
) { backgroundBubbleColor ->
|
||||
Text("This is a draft note")
|
||||
}
|
||||
|
||||
ChatBubbleLayout(
|
||||
isLoggedInUser = true,
|
||||
isDraft = false,
|
@ -18,7 +18,7 @@
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist.private
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.private
|
||||
|
||||
import android.content.Context
|
||||
import androidx.compose.runtime.Stable
|
||||
@ -40,11 +40,9 @@ import com.vitorpamplona.amethyst.ui.actions.mediaServers.ServerName
|
||||
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia
|
||||
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMediaProcessing
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.geohash.geohash
|
||||
import com.vitorpamplona.quartz.nip17Dm.base.ChatroomKey
|
||||
import com.vitorpamplona.quartz.nip17Dm.files.ChatMessageEncryptedFileHeaderEvent
|
||||
import com.vitorpamplona.quartz.nip17Dm.files.encryption.AESGCM
|
||||
import com.vitorpamplona.quartz.nip30CustomEmoji.emojis
|
||||
import com.vitorpamplona.quartz.nip31Alts.alt
|
||||
import com.vitorpamplona.quartz.nip36SensitiveContent.contentWarning
|
||||
import kotlinx.collections.immutable.ImmutableList
|
@ -18,7 +18,7 @@
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist.private
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.private
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
@ -18,7 +18,7 @@
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist.private
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.private
|
||||
|
||||
import android.content.Context
|
||||
import android.util.Log
|
@ -18,7 +18,7 @@
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist.private
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.private
|
||||
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.foundation.layout.Row
|
@ -18,14 +18,13 @@
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist.private
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.private
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
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.size
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
@ -18,7 +18,7 @@
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist.private
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.private
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
@ -103,11 +103,11 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.CloseButton
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.DisappearingScaffold
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.PostButton
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist.DisplayRoomSubject
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist.DisplayUserSetAsSubject
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist.LoadUser
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist.utils.DisplayReplyingToNote
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist.utils.MyTextField
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.list.DisplayRoomSubject
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.list.DisplayUserSetAsSubject
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.list.LoadUser
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.utils.DisplayReplyingToNote
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.utils.MyTextField
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.ui.theme.BottomTopHeight
|
||||
import com.vitorpamplona.amethyst.ui.theme.DividerThickness
|
@ -18,7 +18,7 @@
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist.private
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.private
|
||||
|
||||
import android.webkit.MimeTypeMap
|
||||
import androidx.compose.runtime.getValue
|
@ -18,7 +18,7 @@
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist.private
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.private
|
||||
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
@ -18,7 +18,7 @@
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist.public
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.public
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
@ -31,7 +31,6 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material.icons.Icons
|
||||
@ -120,10 +119,10 @@ import com.vitorpamplona.amethyst.ui.note.timeAgoShort
|
||||
import com.vitorpamplona.amethyst.ui.screen.NostrChannelFeedViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.DisappearingScaffold
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist.private.RefreshingChatroomFeedView
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist.private.ThinSendButton
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist.utils.DisplayReplyingToNote
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist.utils.MyTextField
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.private.RefreshingChatroomFeedView
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.private.ThinSendButton
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.utils.DisplayReplyingToNote
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.utils.MyTextField
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.CrossfadeCheckIfVideoIsOnline
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.equalImmutableLists
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
@ -18,7 +18,7 @@
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist.utils
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.utils
|
||||
|
||||
import androidx.compose.animation.animateContentSize
|
||||
import androidx.compose.foundation.layout.Column
|
||||
@ -39,7 +39,7 @@ import androidx.compose.ui.unit.dp
|
||||
import com.vitorpamplona.amethyst.model.Note
|
||||
import com.vitorpamplona.amethyst.ui.navigation.INav
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist.private.ChatroomMessageCompose
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.private.ChatroomMessageCompose
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size20Modifier
|
||||
import com.vitorpamplona.amethyst.ui.theme.placeholderText
|
||||
|
@ -18,7 +18,7 @@
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist.utils
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.utils
|
||||
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.interaction.collectIsFocusedAsState
|
@ -75,7 +75,7 @@ import com.vitorpamplona.amethyst.ui.note.UserCompose
|
||||
import com.vitorpamplona.amethyst.ui.note.elements.ObserveRelayListForSearchAndDisplayIfNotFound
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.DisappearingScaffold
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist.ChannelName
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.list.ChannelName
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.ui.theme.DividerThickness
|
||||
import com.vitorpamplona.amethyst.ui.theme.FeedPadding
|
||||
|
@ -147,8 +147,8 @@ import com.vitorpamplona.amethyst.ui.note.types.VideoDisplay
|
||||
import com.vitorpamplona.amethyst.ui.screen.LevelFeedViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.RenderFeedState
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist.private.ThinSendButton
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chatlist.public.ChannelHeader
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.private.ThinSendButton
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.public.ChannelHeader
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.ui.theme.DividerThickness
|
||||
|
Loading…
x
Reference in New Issue
Block a user