Skip to content

Commit

Permalink
Remove paging3 from member detail bottom sheet (#38)
Browse files Browse the repository at this point in the history
* Remove paging 3 from member detail bottom sheet

* Remove dependency and related file

* Minor refactoring

---------

Co-authored-by: Radhika Canopas <[email protected]>
  • Loading branch information
cp-megh-l and cp-radhika-s authored Apr 16, 2024
1 parent ff4a8b0 commit d5757d0
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 86 deletions.
3 changes: 0 additions & 3 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -180,9 +180,6 @@ dependencies {

implementation("com.google.maps.android:maps-compose:4.3.0")

// Paging
implementation("androidx.paging:paging-compose:3.2.1")

// Image cropper
implementation("com.vanniktech:android-image-cropper:4.5.0")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,16 @@ package com.canopas.yourspace.ui.component
import androidx.compose.foundation.lazy.LazyListState

internal fun LazyListState.reachedBottom(): Boolean {
val isScrollEnd =
layoutInfo.visibleItemsInfo.lastOrNull()?.index == layoutInfo.totalItemsCount - 1
val visibleItemsInfo = layoutInfo.visibleItemsInfo
return if (layoutInfo.totalItemsCount == 0) {
false
} else {
val lastVisibleItem = visibleItemsInfo.last()
val viewportHeight = layoutInfo.viewportEndOffset + layoutInfo.viewportStartOffset

val totalItemsNumber = layoutInfo.totalItemsCount
val lastVisibleItemIndex = layoutInfo.visibleItemsInfo.lastOrNull()?.index ?: 0

return isScrollEnd && lastVisibleItemIndex >= totalItemsNumber - 1
(
lastVisibleItem.index + 1 == layoutInfo.totalItemsCount &&
lastVisibleItem.offset + lastVisibleItem.size <= viewportHeight
)
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
Expand All @@ -38,6 +39,7 @@ import androidx.compose.material3.rememberDatePickerState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
Expand All @@ -56,16 +58,14 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.paging.LoadState
import androidx.paging.compose.LazyPagingItems
import androidx.paging.compose.collectAsLazyPagingItems
import com.canopas.yourspace.R
import com.canopas.yourspace.data.models.location.LocationJourney
import com.canopas.yourspace.data.models.location.isSteadyLocation
import com.canopas.yourspace.data.models.user.UserInfo
import com.canopas.yourspace.domain.utils.getAddress
import com.canopas.yourspace.ui.component.AppProgressIndicator
import com.canopas.yourspace.ui.component.UserProfile
import com.canopas.yourspace.ui.component.reachedBottom
import com.canopas.yourspace.ui.theme.AppTheme
import com.google.android.gms.maps.model.LatLng
import kotlinx.coroutines.Dispatchers
Expand All @@ -82,7 +82,6 @@ fun MemberDetailBottomSheetContent(
) {
val viewModel = hiltViewModel<MemberDetailViewModel>()
val state by viewModel.state.collectAsState()
val locations = viewModel.location.collectAsLazyPagingItems()

LaunchedEffect(userInfo) {
val calendar = Calendar.getInstance()
Expand Down Expand Up @@ -112,42 +111,56 @@ fun MemberDetailBottomSheetContent(
calendar.set(Calendar.HOUR_OF_DAY, 23)
viewModel.fetchUserLocationHistory(from = timestamp, to = calendar.timeInMillis)
}
LocationHistory(locations)
LocationHistory()
}
}

@Composable
fun LocationHistory(
locations: LazyPagingItems<LocationJourney>
) {
fun LocationHistory() {
val viewModel = hiltViewModel<MemberDetailViewModel>()
val state by viewModel.state.collectAsState()

val locations = state.locations
val lazyListState = rememberLazyListState()

val reachedBottom by remember {
derivedStateOf { lazyListState.reachedBottom() }
}

LaunchedEffect(reachedBottom) {
if (reachedBottom) viewModel.loadMoreLocations()
}

Box {
when {
locations.loadState.refresh == LoadState.Loading -> {
locations.isEmpty() && state.isLoading -> {
Box(
modifier = Modifier.fillMaxWidth(),
contentAlignment = Alignment.Center
) { AppProgressIndicator() }
}

locations.itemCount == 0 -> {
locations.isEmpty() -> {
EmptyHistory()
}

else -> {
LazyColumn {
items(locations.itemCount) { index ->
LazyColumn(
state = lazyListState
) {
items(locations.size) { index ->
val location = locations[index]
val previousLocationJourney = locations.itemSnapshotList.getOrNull(index - 1)
val previousLocationJourney = locations.getOrNull(index - 1)

LocationHistoryItem(
location!!,
location,
previousLocationJourney,
index,
isLastItem = index == locations.itemCount - 1
isLastItem = index == locations.lastIndex
)
}

if (locations.loadState.append == LoadState.Loading) {
if (locations.isNotEmpty() && state.isLoading) {
item {
Box(
modifier = Modifier.fillMaxWidth(),
Expand Down Expand Up @@ -314,7 +327,10 @@ private fun LocationHistoryItem(
)

Text(
text = getFormattedLocationTime(location.created_at!!, previousLocationJourney?.created_at ?: System.currentTimeMillis()),
text = getFormattedLocationTime(
location.created_at!!,
previousLocationJourney?.created_at ?: System.currentTimeMillis()
),
style = AppTheme.appTypography.label2.copy(color = AppTheme.colorScheme.textSecondary)
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@ package com.canopas.yourspace.ui.flow.home.map.member

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.cachedIn
import com.canopas.yourspace.data.models.location.LocationJourney
import com.canopas.yourspace.data.models.user.UserInfo
import com.canopas.yourspace.data.service.location.LocationJourneyService
import com.canopas.yourspace.data.utils.AppDispatcher
Expand All @@ -24,24 +22,6 @@ class MemberDetailViewModel @Inject constructor(
private val _state = MutableStateFlow(MemberDetailState())
var state = _state.asStateFlow()

private var _dataPagingSource: LocationHistoryPagingSource? = null

val location = Pager(
config = PagingConfig(
pageSize = 2
)
) {
LocationHistoryPagingSource(
query = journeyService.getJourneyHistoryQuery(
_state.value.selectedUser?.user?.id ?: "",
_state.value.selectedTimeFrom ?: 0,
_state.value.selectedTimeTo ?: 0
)
).also {
_dataPagingSource = it
}
}.flow.cachedIn(viewModelScope)

fun fetchUserLocationHistory(
from: Long,
to: Long,
Expand All @@ -51,14 +31,45 @@ class MemberDetailViewModel @Inject constructor(
_state.value.copy(
selectedUser = userInfo,
selectedTimeFrom = from,
selectedTimeTo = to
selectedTimeTo = to,
locations = listOf()
)
)
loadLocations()
}

private fun loadLocations() = viewModelScope.launch {
if (state.value.selectedUser == null) return@launch

_state.value = _state.value.copy(isLoading = true)

try {
_dataPagingSource?.invalidate()
val locations = journeyService.getJourneyHistory(
_state.value.selectedUser?.user?.id ?: "",
_state.value.selectedTimeFrom ?: 0,
_state.value.locations.lastOrNull()?.created_at ?: _state.value.selectedTimeTo
?: 0
)

val locationJourneys = (state.value.locations + locations).distinctBy { it.id }
val hasMoreItems = !state.value.locations.map { it.id }.containsAll(locations.map { it.id })

_state.value = _state.value.copy(
locations = locationJourneys,
hasMoreLocations = hasMoreItems,
isLoading = false
)
} catch (e: Exception) {
Timber.e(e, "Failed to fetch location history")
_state.emit(_state.value.copy(error = e))
_state.value = _state.value.copy(error = e, isLoading = false)
}
}

fun loadMoreLocations() {
state.value.let {
if (it.hasMoreLocations && !it.isLoading) {
loadLocations()
}
}
}
}
Expand All @@ -67,5 +78,8 @@ data class MemberDetailState(
val selectedUser: UserInfo? = null,
val selectedTimeFrom: Long? = null,
val selectedTimeTo: Long? = null,
val locations: List<LocationJourney> = listOf(),
val hasMoreLocations: Boolean = true,
val isLoading: Boolean = false,
val error: Exception? = null
)
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@ class ApiLocationService @Inject constructor(
.whereGreaterThanOrEqualTo("created_at", endTime)
.whereLessThan("created_at", startTime)
.orderBy("created_at", Query.Direction.DESCENDING).limit(1)
.get().await().documents.random()?.toObject(ApiLocation::class.java)
.get().await().documents
.randomOrNull()?.toObject(ApiLocation::class.java)

apiLocation?.let {
locations.add(it)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ class LocationJourneyService @Inject constructor(
) {
private val userRef = db.collection(Config.FIRESTORE_COLLECTION_USERS)
private fun journeyRef(userId: String) =
userRef.document(userId.replace('/', '_')).collection(Config.FIRESTORE_COLLECTION_USER_JOURNEYS)
userRef.document(userId.replace('/', '_'))
.collection(Config.FIRESTORE_COLLECTION_USER_JOURNEYS)

suspend fun saveLastKnownJourney(
userId: String
Expand Down Expand Up @@ -101,11 +102,14 @@ class LocationJourneyService @Inject constructor(
null
}

fun getJourneyHistoryQuery(userId: String, from: Long, to: Long) =
suspend fun getJourneyHistory(userId: String, from: Long, to: Long) =
journeyRef(userId).whereEqualTo("user_id", userId)
.whereGreaterThanOrEqualTo("created_at", from)
.whereLessThan("created_at", to)
.orderBy("created_at", Query.Direction.DESCENDING).limit(50)
.orderBy("created_at", Query.Direction.DESCENDING)
.limit(10)
.get().await()
.documents.mapNotNull { it.toObject(LocationJourney::class.java) }

fun updateLastMovingLocation(userId: String, newJourney: LocationJourney) {
journeyRef(userId).document(newJourney.id).set(newJourney)
Expand Down

0 comments on commit d5757d0

Please sign in to comment.