Skip to content

Commit

Permalink
ThreadPreviewScreen: Implement paging support
Browse files Browse the repository at this point in the history
Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
  • Loading branch information
theimpulson committed Mar 25, 2024
1 parent 845e13f commit 1b6ef0f
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 111 deletions.
2 changes: 1 addition & 1 deletion app/src/main/java/io/aayush/relabs/network/XDAInterface.kt
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ interface XDAInterface {
): Response<Threads>

@GET("threads/audapp-watched/")
suspend fun getWatchedThreads(): Response<Threads>
suspend fun getWatchedThreads(@Query("page") page: Int? = null): Response<Threads>

@GET("forums/{id}/threads/")
suspend fun getThreadsByNode(
Expand Down
32 changes: 8 additions & 24 deletions app/src/main/java/io/aayush/relabs/network/XDARepository.kt
Original file line number Diff line number Diff line change
Expand Up @@ -45,32 +45,16 @@ class XDARepository @Inject constructor(
}.flow
}

suspend fun getThreads(
page: Int? = null,
prefix_id: Int? = null,
starter_id: Int? = null,
last_days: Int? = null,
unread: Boolean? = null,
thread_type: String? = null,
order: String? = null,
direction: String? = null
): Threads? {
return safeExecute {
xdaInterface.getThreads(
page,
prefix_id,
starter_id,
last_days,
unread,
thread_type,
order,
direction
)
}
fun getThreads(): Flow<PagingData<Thread>> {
return createPager { page ->
safeExecute { xdaInterface.getThreads(page) }?.threads.orEmpty()
}.flow
}

suspend fun getWatchedThreads(): Threads? {
return safeExecute { xdaInterface.getWatchedThreads() }
fun getWatchedThreads(): Flow<PagingData<Thread>> {
return createPager { page ->
safeExecute { xdaInterface.getWatchedThreads(page) }?.threads.orEmpty()
}.flow
}

fun getThreadsByNode(nodeID: Int): Flow<PagingData<Thread>> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,24 @@ import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Tab
import androidx.compose.material3.TabRow
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.util.fastForEachIndexed
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.NavHostController
import androidx.paging.LoadState
import androidx.paging.compose.collectAsLazyPagingItems
import androidx.paging.compose.itemContentType
import androidx.paging.compose.itemKey
import io.aayush.relabs.R
import io.aayush.relabs.network.data.thread.Thread
import io.aayush.relabs.ui.components.MainTopAppBar
Expand Down Expand Up @@ -58,65 +57,65 @@ fun ThreadPreviewScreen(
val tabIndex = pagerState.currentPage
val coroutineScope = rememberCoroutineScope()

val loading: Boolean by viewModel.loading.collectAsStateWithLifecycle()
val watchedThreads: List<Thread>? by viewModel.watchedThreads.collectAsStateWithLifecycle()
val trendingThreads: List<Thread>? by viewModel.trendingThreads.collectAsStateWithLifecycle()

LaunchedEffect(key1 = pagerState) {
snapshotFlow { pagerState.currentPage }.collect { page ->
when (page) {
0 -> viewModel.getWatchedThreads()
1 -> viewModel.getTrendingThreads()
}
}
}
val watchedThreads = viewModel.getWatchedThreads().collectAsLazyPagingItems()
val trendingThreads = viewModel.getTrendingThreads().collectAsLazyPagingItems()

Column(modifier = Modifier.padding(it)) {
TabRow(selectedTabIndex = tabIndex) {
tabData.fastForEachIndexed { index, _ ->
Tab(selected = tabIndex == index, onClick = {
coroutineScope.launch {
pagerState.animateScrollToPage(index)
}
}, text = {
Tab(
selected = tabIndex == index,
onClick = {
coroutineScope.launch {
pagerState.animateScrollToPage(index)
}
},
text = {
Text(text = stringResource(id = tabData[index]))
})
}
)
}
}
HorizontalPager(
state = pagerState
) {
if (loading) {
LazyColumn(modifier = Modifier.fillMaxHeight()) {
items(20) {
ThreadPreviewItem(modifier = Modifier.padding(10.dp), loading = true)
}
HorizontalPager(state = pagerState) {
LazyColumn(modifier = Modifier.fillMaxHeight()) {
val currentThreads = when (it) {
0 -> watchedThreads
else -> trendingThreads
}
return@HorizontalPager
}
when (currentThreads.loadState.refresh) {
is LoadState.Error -> {}
is LoadState.Loading -> {
items(20) {
ThreadPreviewItem(
modifier = Modifier.padding(10.dp),
loading = true
)
}
}

LazyColumn(modifier = Modifier.fillMaxHeight()) {
items(
items = when (it) {
0 -> watchedThreads ?: emptyList()
else -> trendingThreads ?: emptyList()
},
key = { t -> t.id }
) { thread ->
ThreadPreviewItem(
modifier = Modifier.padding(10.dp),
avatarURL = thread.user.avatar?.data?.medium ?: String(),
title = thread.title,
author = thread.user.username,
totalReplies = thread.reply_count,
views = thread.view_count,
lastReplyDate = thread.last_post_at.long,
forum = thread.node.title,
unread = thread.isUnread,
onClicked = {
navHostController.navigate(Screen.Thread.withID(thread.id))
else -> {
items(
count = currentThreads.itemCount,
key = currentThreads.itemKey { t -> t.id },
contentType = currentThreads.itemContentType { Thread::class.java },
) { index ->
val thread = currentThreads[index] ?: return@items
ThreadPreviewItem(
modifier = Modifier.padding(10.dp),
avatarURL = thread.user.avatar?.data?.medium ?: String(),
title = thread.title,
author = thread.user.username,
totalReplies = thread.reply_count,
views = thread.view_count,
lastReplyDate = thread.last_post_at.long,
forum = thread.node.title,
unread = thread.isUnread,
onClicked = {
navHostController.navigate(Screen.Thread.withID(thread.id))
}
)
}
)
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,49 +2,24 @@ package io.aayush.relabs.ui.screens.threadpreview

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.paging.PagingData
import androidx.paging.cachedIn
import dagger.hilt.android.lifecycle.HiltViewModel
import io.aayush.relabs.network.XDARepository
import io.aayush.relabs.network.data.thread.Thread
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.flow.Flow
import javax.inject.Inject

@HiltViewModel
class ThreadPreviewViewModel @Inject constructor(
private val xdaRepository: XDARepository
) : ViewModel() {

private val _loading = MutableStateFlow(false)
val loading = _loading.asStateFlow()

private val _trendingThreads = MutableStateFlow<List<Thread>?>(emptyList())
val trendingThreads = _trendingThreads.asStateFlow()

private val _watchedThreads = MutableStateFlow<List<Thread>?>(emptyList())
val watchedThreads = _watchedThreads.asStateFlow()

fun getTrendingThreads() {
if (!trendingThreads.value.isNullOrEmpty()) return
viewModelScope.launch(Dispatchers.IO) {
fetch { _trendingThreads.value = xdaRepository.getThreads()?.threads }
}
}

fun getWatchedThreads() {
if (!watchedThreads.value.isNullOrEmpty()) return
viewModelScope.launch(Dispatchers.IO) {
fetch { _watchedThreads.value = xdaRepository.getWatchedThreads()?.threads }
}
fun getTrendingThreads(): Flow<PagingData<Thread>> {
return xdaRepository.getThreads().cachedIn(viewModelScope)
}

private inline fun <T> fetch(block: () -> T): T? {
return try {
_loading.value = true
block()
} finally {
_loading.value = false
}
fun getWatchedThreads(): Flow<PagingData<Thread>> {
return xdaRepository.getWatchedThreads().cachedIn(viewModelScope)
}
}

0 comments on commit 1b6ef0f

Please sign in to comment.