diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountStateViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountStateViewModel.kt index 7223d2654b..80d4d75c91 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountStateViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountStateViewModel.kt @@ -6,7 +6,6 @@ import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.DefaultChannels import com.vitorpamplona.amethyst.model.toByteArray import com.vitorpamplona.amethyst.service.NostrAccountDataSource -import com.vitorpamplona.amethyst.service.NostrChannelDataSource import com.vitorpamplona.amethyst.service.NostrChatroomListDataSource import com.vitorpamplona.amethyst.service.NostrGlobalDataSource import com.vitorpamplona.amethyst.service.NostrHomeDataSource diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedViewModel.kt index 045de36042..2e0ff936fc 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedViewModel.kt @@ -1,7 +1,5 @@ package com.vitorpamplona.amethyst.ui.screen -import android.os.Handler -import android.os.Looper import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.vitorpamplona.amethyst.model.LocalCache @@ -15,10 +13,6 @@ import com.vitorpamplona.amethyst.service.NostrGlobalDataSource import com.vitorpamplona.amethyst.service.NostrHomeDataSource import com.vitorpamplona.amethyst.service.NostrThreadDataSource import com.vitorpamplona.amethyst.service.NostrUserProfileDataSource -import com.vitorpamplona.amethyst.service.NostrUserProfileFollowersDataSource -import com.vitorpamplona.amethyst.service.NostrUserProfileFollowsDataSource -import kotlin.time.ExperimentalTime -import kotlin.time.measureTimedValue import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job @@ -31,21 +25,42 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.withContext class NostrChannelFeedViewModel: FeedViewModel(NostrChannelDataSource) -class NostrChatroomListFeedViewModel: FeedViewModel(NostrChatroomListDataSource) class NostrChatRoomFeedViewModel: FeedViewModel(NostrChatRoomDataSource) class NostrHomeFeedViewModel: FeedViewModel(NostrHomeDataSource) class NostrGlobalFeedViewModel: FeedViewModel(NostrGlobalDataSource) class NostrThreadFeedViewModel: FeedViewModel(NostrThreadDataSource) class NostrUserProfileFeedViewModel: FeedViewModel(NostrUserProfileDataSource) +class NostrChatroomListKnownFeedViewModel: FeedViewModel(NostrChatroomListDataSource) { + override fun newListFromDataSource(): List { + // Filter: all channels + PMs the account has replied to + return super.newListFromDataSource().filter { + val me = NostrChatroomListDataSource.account.userProfile() + it.channel != null || me.messages[it.author]?.firstOrNull { me == it.author } != null + } + } +} +class NostrChatroomListNewFeedViewModel: FeedViewModel(NostrChatroomListDataSource) { + override fun newListFromDataSource(): List { + // Filter: no channels + PMs the account has never replied to + return super.newListFromDataSource().filter { + val me = NostrChatroomListDataSource.account.userProfile() + it.channel == null && me.messages[it.author]?.firstOrNull { me == it.author } == null + } + } +} abstract class FeedViewModel(val dataSource: NostrDataSource): ViewModel() { private val _feedContent = MutableStateFlow(FeedState.Loading) val feedContent = _feedContent.asStateFlow() + open fun newListFromDataSource(): List { + return dataSource.loadTop() + } + fun refresh() { viewModelScope.launch(Dispatchers.IO) { - val notes = dataSource.loadTop() + val notes = newListFromDataSource() val oldNotesState = feedContent.value if (oldNotesState is FeedState.Loaded) { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomListScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomListScreen.kt index 935493aa71..b61e0f6007 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomListScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomListScreen.kt @@ -3,35 +3,100 @@ package com.vitorpamplona.amethyst.ui.screen import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.padding +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Tab +import androidx.compose.material.TabRow +import androidx.compose.material.TabRowDefaults +import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.livedata.observeAsState +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.NavController -import com.vitorpamplona.amethyst.service.NostrChatroomListDataSource +import com.google.accompanist.pager.ExperimentalPagerApi +import com.google.accompanist.pager.HorizontalPager +import com.google.accompanist.pager.pagerTabIndicatorOffset +import com.google.accompanist.pager.rememberPagerState +import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import kotlinx.coroutines.launch +@OptIn(ExperimentalPagerApi::class) @Composable fun ChatroomListScreen(accountViewModel: AccountViewModel, navController: NavController) { val account by accountViewModel.accountLiveData.observeAsState() if (account != null) { - val feedViewModel: NostrChatroomListFeedViewModel = viewModel() - - LaunchedEffect(Unit) { - feedViewModel.refresh() - } + val pagerState = rememberPagerState() + val coroutineScope = rememberCoroutineScope() Column(Modifier.fillMaxHeight()) { Column( modifier = Modifier.padding(vertical = 0.dp) ) { - ChatroomListFeedView(feedViewModel, accountViewModel, navController) + TabRow( + selectedTabIndex = pagerState.currentPage, + indicator = { tabPositions -> + TabRowDefaults.Indicator( + Modifier.pagerTabIndicatorOffset(pagerState, tabPositions), + color = MaterialTheme.colors.primary + ) + }, + ) { + Tab( + selected = pagerState.currentPage == 0, + onClick = { coroutineScope.launch { pagerState.animateScrollToPage(0) } }, + text = { + Text(text = "Known") + } + ) + + Tab( + selected = pagerState.currentPage == 1, + onClick = { coroutineScope.launch { pagerState.animateScrollToPage(1) } }, + text = { + Text(text = "New Requests") + } + ) + } + HorizontalPager(count = 2, state = pagerState) { + when (pagerState.currentPage) { + 0 -> TabKnown(accountViewModel, navController) + 1 -> TabNew(accountViewModel, navController) + } + } } } } } +@Composable +fun TabKnown(accountViewModel: AccountViewModel, navController: NavController) { + val feedViewModel: NostrChatroomListKnownFeedViewModel = viewModel() + + + Column(Modifier.fillMaxHeight()) { + Column( + modifier = Modifier.padding(vertical = 0.dp) + ) { + ChatroomListFeedView(feedViewModel, accountViewModel, navController) + } + } +} + +@Composable +fun TabNew(accountViewModel: AccountViewModel, navController: NavController) { + val feedViewModel: NostrChatroomListNewFeedViewModel = viewModel() + + Column(Modifier.fillMaxHeight()) { + Column( + modifier = Modifier.padding(vertical = 0.dp) + ) { + ChatroomListFeedView(feedViewModel, accountViewModel, navController) + } + } +} \ No newline at end of file