mirror of
https://github.com/sudoxnym/habitica-android.git
synced 2026-07-08 05:26:10 +00:00
paginate party seeking
This commit is contained in:
parent
5249cb123b
commit
1ef2e901fc
7 changed files with 101 additions and 30 deletions
|
|
@ -108,6 +108,7 @@ dependencies {
|
|||
implementation "androidx.navigation:navigation-ui-ktx:$navigation_version"
|
||||
implementation "androidx.fragment:fragment-ktx:1.5.6"
|
||||
implementation "androidx.paging:paging-runtime-ktx:3.1.1"
|
||||
implementation "androidx.paging:paging-compose:1.0.0-alpha18"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
|
||||
implementation "com.google.accompanist:accompanist-themeadapter-material:$accompanist_version"
|
||||
|
|
|
|||
|
|
@ -465,5 +465,5 @@ interface ApiService {
|
|||
suspend fun markTaskNeedsWork(@Path("taskID") taskID: String, @Path("userID") userID: String): HabitResponse<Task>
|
||||
|
||||
@GET("looking-for-party")
|
||||
suspend fun retrievePartySeekingUsers(): HabitResponse<List<Member>>
|
||||
suspend fun retrievePartySeekingUsers(@Query("page") page: Int): HabitResponse<List<Member>>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -277,5 +277,5 @@ interface ApiClient {
|
|||
suspend fun updateMember(memberID: String, updateData: Map<String, Any?>): Member?
|
||||
suspend fun getHallMember(userId: String): Member?
|
||||
suspend fun markTaskNeedsWork(taskID: String, userID: String): Task?
|
||||
suspend fun retrievePartySeekingUsers() : List<Member>?
|
||||
suspend fun retrievePartySeekingUsers(page: Int) : List<Member>?
|
||||
}
|
||||
|
|
|
|||
|
|
@ -122,5 +122,5 @@ interface SocialRepository : BaseRepository {
|
|||
suspend fun blockMember(userID: String): List<String>?
|
||||
fun getMember(userID: String?): Flow<Member?>
|
||||
suspend fun updateMember(memberID: String, key: String, value: Any?): Member?
|
||||
suspend fun retrievePartySeekingUsers(): List<Member>?
|
||||
suspend fun retrievePartySeekingUsers(page: Int = 0): List<Member>?
|
||||
}
|
||||
|
|
|
|||
|
|
@ -622,8 +622,8 @@ class ApiClientImpl(
|
|||
return process { apiService.markTaskNeedsWork(taskID, userID) }
|
||||
}
|
||||
|
||||
override suspend fun retrievePartySeekingUsers() : List<Member>? {
|
||||
return process { apiService.retrievePartySeekingUsers() }
|
||||
override suspend fun retrievePartySeekingUsers(page: Int) : List<Member>? {
|
||||
return process { apiService.retrievePartySeekingUsers(page) }
|
||||
}
|
||||
|
||||
override suspend fun getMember(memberId: String) = processResponse(apiService.getMember(memberId))
|
||||
|
|
|
|||
|
|
@ -48,8 +48,8 @@ class SocialRepositoryImpl(
|
|||
return apiClient.updateMember(memberID, mapOf(key to value))
|
||||
}
|
||||
|
||||
override suspend fun retrievePartySeekingUsers() : List<Member>? {
|
||||
return apiClient.retrievePartySeekingUsers()
|
||||
override suspend fun retrievePartySeekingUsers(page: Int) : List<Member>? {
|
||||
return apiClient.retrievePartySeekingUsers(page)
|
||||
}
|
||||
|
||||
override fun getGroupMembership(id: String) = localRepository.getGroupMembership(userID, id)
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ import androidx.compose.foundation.background
|
|||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.IntrinsicSize
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
|
|
@ -17,7 +16,6 @@ import androidx.compose.foundation.layout.padding
|
|||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material.Divider
|
||||
import androidx.compose.material.ExperimentalMaterialApi
|
||||
import androidx.compose.material.Text
|
||||
|
|
@ -38,6 +36,15 @@ import androidx.compose.ui.unit.dp
|
|||
import androidx.compose.ui.unit.sp
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.paging.LoadState
|
||||
import androidx.paging.Pager
|
||||
import androidx.paging.PagingConfig
|
||||
import androidx.paging.PagingData
|
||||
import androidx.paging.PagingSource
|
||||
import androidx.paging.PagingState
|
||||
import androidx.paging.cachedIn
|
||||
import androidx.paging.compose.collectAsLazyPagingItems
|
||||
import androidx.paging.compose.items
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.data.SocialRepository
|
||||
import com.habitrpg.android.habitica.data.UserRepository
|
||||
|
|
@ -52,10 +59,12 @@ import com.habitrpg.android.habitica.ui.views.ClassText
|
|||
import com.habitrpg.android.habitica.ui.views.ComposableAvatarView
|
||||
import com.habitrpg.android.habitica.ui.views.LoadingButton
|
||||
import com.habitrpg.android.habitica.ui.views.LoadingButtonState
|
||||
import com.habitrpg.android.habitica.ui.views.progress.HabiticaCircularProgressView
|
||||
import com.habitrpg.android.habitica.ui.views.progress.HabiticaPullRefreshIndicator
|
||||
import com.habitrpg.common.habitica.helpers.launchCatching
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import java.util.Locale
|
||||
import javax.inject.Inject
|
||||
|
||||
|
|
@ -66,18 +75,17 @@ class PartySeekingViewModel @Inject constructor(
|
|||
val socialRepository : SocialRepository
|
||||
) : BaseViewModel(userRepository, userViewModel) {
|
||||
val isRefreshing = mutableStateOf(false)
|
||||
val seekingUsers = mutableStateOf<List<Member>>(emptyList())
|
||||
var seekingUsers: Flow<PagingData<Member>>
|
||||
|
||||
init {
|
||||
retrieveUsers()
|
||||
}
|
||||
|
||||
fun retrieveUsers() {
|
||||
isRefreshing.value = true
|
||||
viewModelScope.launchCatching {
|
||||
seekingUsers.value = socialRepository.retrievePartySeekingUsers() ?: emptyList()
|
||||
isRefreshing.value = false
|
||||
}
|
||||
seekingUsers = Pager(
|
||||
config = PagingConfig(
|
||||
pageSize = 30,
|
||||
),
|
||||
pagingSourceFactory = {
|
||||
PartySeekingPagingSource(socialRepository)
|
||||
}
|
||||
).flow.cachedIn(viewModelScope)
|
||||
}
|
||||
|
||||
suspend fun inviteUser(member : Member) : InviteResponse? {
|
||||
|
|
@ -114,11 +122,6 @@ class PartySeekingFragment : BaseFragment<FragmentComposeBinding>() {
|
|||
}
|
||||
return view
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
viewModel.retrieveUsers()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
|
@ -216,9 +219,9 @@ fun PartySeekingView(
|
|||
viewModel : PartySeekingViewModel,
|
||||
modifier : Modifier = Modifier
|
||||
) {
|
||||
val users : List<Member> by viewModel.seekingUsers
|
||||
val pageData = viewModel.seekingUsers.collectAsLazyPagingItems()
|
||||
val refreshing by viewModel.isRefreshing
|
||||
val pullRefreshState = rememberPullRefreshState(refreshing, { viewModel.retrieveUsers() })
|
||||
val pullRefreshState = rememberPullRefreshState(refreshing, { pageData.refresh() })
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
val inviteStates = remember { mutableMapOf<String, LoadingButtonState>() }
|
||||
|
|
@ -248,8 +251,11 @@ fun PartySeekingView(
|
|||
)
|
||||
}
|
||||
}
|
||||
items(users) {
|
||||
PartySeekingListItem(user = it, inviteState = inviteStates[it.id] ?: LoadingButtonState.CONTENT, modifier = Modifier.animateItemPlacement()) { member ->
|
||||
items(
|
||||
items = pageData
|
||||
) {
|
||||
if (it == null) return@items
|
||||
PartySeekingListItem(user = it, inviteState = inviteStates[it.id] ?: LoadingButtonState.CONTENT, modifier = Modifier.animateItemPlacement()) { member ->
|
||||
scope.launchCatching({
|
||||
inviteStates[member.id] = LoadingButtonState.FAILED
|
||||
}) {
|
||||
|
|
@ -261,9 +267,73 @@ fun PartySeekingView(
|
|||
LoadingButtonState.FAILED
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
when (pageData.loadState.refresh) {
|
||||
is LoadState.Error -> {
|
||||
}
|
||||
is LoadState.Loading -> {
|
||||
item {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillParentMaxSize(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center,
|
||||
) {
|
||||
|
||||
HabiticaCircularProgressView()
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
|
||||
when (pageData.loadState.append) {
|
||||
is LoadState.Error -> {
|
||||
}
|
||||
is LoadState.Loading -> {
|
||||
item {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(8.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
HabiticaCircularProgressView()
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
HabiticaPullRefreshIndicator(users.isEmpty(), refreshing, pullRefreshState, Modifier.align(Alignment.TopCenter))
|
||||
HabiticaPullRefreshIndicator(pageData.itemCount == 0, refreshing, pullRefreshState, Modifier.align(Alignment.TopCenter))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class PartySeekingPagingSource(
|
||||
private val repository: SocialRepository,
|
||||
): PagingSource<Int, Member>() {
|
||||
override fun getRefreshKey(state: PagingState<Int, Member>): Int? {
|
||||
return state.anchorPosition?.let { anchorPosition ->
|
||||
state.closestPageToPosition(anchorPosition)?.prevKey?.plus(1)
|
||||
?: state.closestPageToPosition(anchorPosition)?.nextKey?.minus(1)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Member> {
|
||||
return try {
|
||||
val page = params.key ?: 0
|
||||
val response = repository.retrievePartySeekingUsers(page)
|
||||
|
||||
LoadResult.Page(
|
||||
data = response ?: emptyList(),
|
||||
prevKey = if (page == 0) null else page.minus(1),
|
||||
nextKey = if (response?.isEmpty() != false) null else page.plus(1),
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
LoadResult.Error(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue