Skip to content

Commit

Permalink
Keep the last known location in the HomeScreenViewModel.
Browse files Browse the repository at this point in the history
Add more state to the viewmodel to keep track of the location.

Add a function to the viewmodel that binds a listener to the
`lastLocation` field of the location provider.

Modify the `EventListItem` to show the distance to the event when
the user position is not null.
  • Loading branch information
alejandrocalles committed May 24, 2024
1 parent ba30b1a commit 9a09fdc
Show file tree
Hide file tree
Showing 11 changed files with 107 additions and 78 deletions.
3 changes: 3 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ dependencies {
// Map Libre
implementation(libs.android.sdk)
implementation(libs.ramani.maplibre)

// Location
implementation(libs.play.services.location)

// Hilt
implementation(libs.hilt.android)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,5 +95,5 @@ fun AssociationDescription(association: Association) {

@Composable
fun AssociationEvents(events: List<Event>, isOnline: Boolean, refreshEvents: () -> Unit) {
ListDrawer(events, "", "", isOnline, refreshEvents)
ListDrawer(events, "", "", isOnline, null, refreshEvents)
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.unit.dp
import com.github.swent.echo.compose.components.searchmenu.SortByDisplayer
import com.github.swent.echo.compose.map.MapDrawer
import com.github.swent.echo.data.model.Location
import com.github.swent.echo.ui.navigation.NavigationActions
import com.github.swent.echo.ui.navigation.Routes
import com.github.swent.echo.viewmodels.HomeScreenViewModel
import com.github.swent.echo.viewmodels.MapOrListMode
import com.github.swent.echo.viewmodels.Overlay
import com.mapbox.mapboxsdk.geometry.LatLng
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json

Expand Down Expand Up @@ -77,7 +79,12 @@ fun HomeScreen(
SearchButton(onClick = { homeScreenViewModel.setOverlay(Overlay.SEARCH_SHEET) })
}
) { paddingValues ->
Content(paddingValues, navActions, homeScreenViewModel, hasLocationPermissions)
Content(
paddingValues,
navActions,
homeScreenViewModel,
hasLocationPermissions,
)
}
}
}
Expand Down Expand Up @@ -112,6 +119,12 @@ private fun Content(
Box(modifier = Modifier.padding(paddingValues)) {
if (mode == MapOrListMode.LIST) {
Column {
Box {
SortByDisplayer(
sortBy = homeScreenViewModel.sortBy.collectAsState().value,
homeScreenViewModel::onSortByChanged
)
}
if (tags.isNotEmpty() && !searchMode) {
TagUI(
tags = tags,
Expand All @@ -125,6 +138,9 @@ private fun Content(
section,
semester,
isOnline,
homeScreenViewModel.userLocation.collectAsState().value?.let {
LatLng(it.latitude, it.longitude)
},
homeScreenViewModel::refreshEvents
)
}
Expand Down Expand Up @@ -176,7 +192,6 @@ private fun Content(
pendingCallback = homeScreenViewModel::onPendingCheckedSwitch,
confirmedCallback = homeScreenViewModel::onConfirmedCheckedSwitch,
fullCallback = homeScreenViewModel::onFullCheckedSwitch,
sortByCallback = homeScreenViewModel::onSortByChanged,
resetFiltersCallback = homeScreenViewModel::resetFiltersContainer,
timeFilterCallback = homeScreenViewModel::onDateFilterChanged
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,18 @@ import androidx.compose.ui.unit.dp
import com.github.swent.echo.R
import com.github.swent.echo.data.model.Event
import com.github.swent.echo.viewmodels.STATUS_THRESHOLD
import com.mapbox.mapboxsdk.geometry.LatLng
import java.time.format.DateTimeFormatter
import java.util.Locale

@Composable
fun ListDrawer(
eventsList: List<Event>,
section: String,
semester: String,
isOnline: Boolean,
refreshEvents: () -> Unit
userPosition: LatLng?,
refreshEvents: () -> Unit,
) {
val selectedEvent = remember { mutableStateOf("") }
// Main column where every items will be displayed, scrollable
Expand All @@ -58,7 +61,8 @@ fun ListDrawer(
section,
semester,
isOnline,
refreshEvents
userPosition,
refreshEvents,
)
Spacer(modifier = Modifier.height(5.dp))
}
Expand All @@ -72,7 +76,8 @@ fun EventListItem(
section: String,
semester: String,
isOnline: Boolean,
refreshEvents: () -> Unit
userPosition: LatLng? = null,
refreshEvents: () -> Unit,
) {
// Colors for the background of the list item
val darkFractionMiddleCircle = 0.8f
Expand Down Expand Up @@ -165,18 +170,20 @@ fun EventListItem(
textAlign = TextAlign.Center,
color = textColor,
)
userPosition?.let {
val distance = it.distanceTo(event.location.toLatLng())
val formattedDistance = String.format(Locale.getDefault(), "%.0f", distance)
Text(
text = "${formattedDistance}km",
modifier =
Modifier.padding(horizontal = paddingItems)
.weight(1f)
.testTag("list_event_location_${event.eventId}"),
textAlign = TextAlign.Center
)
}
/*
// Display event distance from user
Text(
// TODO: Add a way to get the distance from the event (when we'll have the user's
// location)
text = "5km",
modifier =
Modifier.padding(horizontal = paddingItems)
.weight(1f)
.testTag("list_event_location_${event.eventId}"),
textAlign = TextAlign.Center
)
*/
// Display event status
Column(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ import com.github.swent.echo.R
import com.github.swent.echo.compose.components.searchmenu.FiltersContainer
import com.github.swent.echo.compose.components.searchmenu.SearchMenuDiscover
import com.github.swent.echo.compose.components.searchmenu.SearchMenuFilters
import com.github.swent.echo.compose.components.searchmenu.SortBy
import com.github.swent.echo.viewmodels.tag.TagViewModel

@OptIn(ExperimentalMaterial3Api::class)
Expand All @@ -52,7 +51,6 @@ fun SearchMenuSheet(
pendingCallback: () -> Unit,
confirmedCallback: () -> Unit,
fullCallback: () -> Unit,
sortByCallback: (SortBy) -> Unit,
resetFiltersCallback: () -> Unit,
timeFilterCallback: (Float, Float) -> Unit
) {
Expand Down Expand Up @@ -106,7 +104,6 @@ fun SearchMenuSheet(
pendingCallback,
confirmedCallback,
fullCallback,
sortByCallback,
timeFilterCallback
)
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,15 @@ data class FiltersContainer(
var fullChecked: Boolean,
var from: Float,
var to: Float,
var sortBy: SortBy,
)

// Enum class for the different states of the sort by filter
enum class SortBy(val stringKey: String) {
NONE("filters_container_sort_by_none"),
DATE_ASC("filters_container_sort_by_date_asc"),
DATE_DESC("filters_container_sort_by_date_desc"),
DISTANCE_ASC("filters_container_sort_by_distance_asc"),
DISTANCE_DESC("filters_container_sort_by_distance_desc"),
enum class SortBy(val stringKey: String, val ascending: Boolean) {
NONE("filters_container_sort_by_none", false),
DATE_ASC("filters_container_sort_by_date_asc", true),
DATE_DESC("filters_container_sort_by_date_desc", false),
DISTANCE_ASC("filters_container_sort_by_distance_asc", true),
DISTANCE_DESC("filters_container_sort_by_distance_desc", false),
}

// Function to get the string resource for the sort by filter
Expand All @@ -36,3 +35,5 @@ fun stringResourceSortBy(key: String): Int {
else -> throw IllegalArgumentException("Invalid string key")
}
}

class EventComparator(val keyType: SortBy) {}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.absoluteOffset
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.width
Expand Down Expand Up @@ -34,7 +33,6 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.zIndex
import com.github.swent.echo.R
import com.github.swent.echo.compose.components.colorClass
import com.github.swent.echo.compose.components.colorEpfl
Expand All @@ -54,7 +52,6 @@ fun SearchMenuFilters(
pendingCallback: () -> Unit,
confirmedCallback: () -> Unit,
fullCallback: () -> Unit,
sortByCallback: (SortBy) -> Unit,
timeFilterCallback: (Float, Float) -> Unit
) {
// Content of the Events for filters
Expand Down Expand Up @@ -116,16 +113,6 @@ fun SearchMenuFilters(
)

Box(modifier = Modifier.fillMaxSize().testTag("search_menu_filters_content")) {
// Sort by filter
Row(
modifier =
Modifier.align(Alignment.TopStart)
.fillMaxWidth()
.zIndex(1f)
.testTag("sort_by_displayer_container")
) {
SortByDisplayer(filters.sortBy, sortByCallback)
}
// Checkbox filters
Row(
modifier =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ fun MyEventsScreen(myEventsViewModel: MyEventsViewModel, navActions: NavigationA
"",
"",
isOnline,
null,
myEventsViewModel::refreshEvents
)
},
Expand All @@ -49,6 +50,7 @@ fun MyEventsScreen(myEventsViewModel: MyEventsViewModel, navActions: NavigationA
"",
"",
isOnline,
null,
myEventsViewModel::refreshEvents
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import android.Manifest
import android.app.Activity
import android.content.Context
import android.content.pm.PackageManager
import android.location.Location
import androidx.activity.compose.BackHandler
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
Expand Down Expand Up @@ -39,6 +40,8 @@ import com.github.swent.echo.data.repository.Repository
import com.github.swent.echo.ui.navigation.NavigationActions
import com.github.swent.echo.ui.navigation.Routes
import com.github.swent.echo.viewmodels.tag.TagViewModel
import com.github.swent.echo.viewmodels.HomeScreenViewModel
import com.google.android.gms.location.LocationServices
import kotlinx.coroutines.runBlocking

val LOCATION_PERMISSIONS =
Expand All @@ -49,6 +52,8 @@ fun locationPermissionsDenied(context: Context) =
ContextCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_DENIED
}

typealias OnLocationSuccessListener = (Location) -> Unit

/**
* Navigation composable, it display the relevant screen based on the route and pass an instance of
* navigationActions to the screens
Expand Down Expand Up @@ -90,11 +95,13 @@ fun AppNavigationHost(
var alreadyDeniedLocationPermissions by rememberSaveable { mutableStateOf(false) }
val scope = currentRecomposeScope
val launcher =
rememberLauncherForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { p
->
alreadyDeniedLocationPermissions = !p.values.any { it }
rememberLauncherForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) {
alreadyDeniedLocationPermissions = !it.values.any { granted -> granted }
scope.invalidate()
}
val localContext = LocalContext.current

val locationServices = LocationServices.getFusedLocationProviderClient(LocalContext.current)

NavHost(
navController = navController,
Expand All @@ -117,15 +124,32 @@ fun AppNavigationHost(

composable(Routes.MAP.name) {
QuitAppOnHardwareBackButtonPressPress()
// Run this if-else block on every Route that might need location permissions
val c = LocalContext.current
if (!alreadyDeniedLocationPermissions && runBlocking { locationPermissionsDenied(c) }) {
if (
!alreadyDeniedLocationPermissions &&
runBlocking { locationPermissionsDenied(localContext) }
) {
SideEffect { launcher.launch(LOCATION_PERMISSIONS) }
} else {
SideEffect { hasLocationPermissions = !alreadyDeniedLocationPermissions }
}
val homeScreenViewModel: HomeScreenViewModel = hiltViewModel()
homeScreenViewModel.bindOnLocationSuccessListener { onSuccess ->
if (
LOCATION_PERMISSIONS.any {
ContextCompat.checkSelfPermission(localContext, it) ==
PackageManager.PERMISSION_GRANTED
}
) {
locationServices.lastLocation
.addOnSuccessListener { location ->
// TODO if the location is null, try again with scope.invalidate()
location?.let(onSuccess)
}
.addOnFailureListener { scope.invalidate() }
}
}
HomeScreen(
homeScreenViewModel = hiltViewModel(),
homeScreenViewModel = homeScreenViewModel,
navActions = navActions,
hasLocationPermissions = hasLocationPermissions
)
Expand Down
Loading

0 comments on commit 9a09fdc

Please sign in to comment.