Improve live location UI with empty state
This commit is contained in:
parent
9ba8798175
commit
7c3b9523df
5 changed files with 56 additions and 33 deletions
|
|
@ -91,7 +91,7 @@ fun LocationShareRow(
|
|||
)
|
||||
}
|
||||
Text(
|
||||
text = item.formattedTimestamp,
|
||||
text = item.description,
|
||||
style = ElementTheme.typography.fontBodySmRegular,
|
||||
color = ElementTheme.colors.textSecondary,
|
||||
maxLines = 1,
|
||||
|
|
@ -123,7 +123,7 @@ internal fun LocationShareRowPreview() = ElementPreview {
|
|||
url = null,
|
||||
size = AvatarSize.UserListItem,
|
||||
),
|
||||
formattedTimestamp = "Shared 1 min ago",
|
||||
description = "Shared 1 min ago",
|
||||
isLive = true,
|
||||
assetType = AssetType.SENDER,
|
||||
location = Location(0.0, 0.0)
|
||||
|
|
@ -142,7 +142,7 @@ internal fun LocationShareRowPreview() = ElementPreview {
|
|||
),
|
||||
isLive = false,
|
||||
assetType = AssetType.PIN,
|
||||
formattedTimestamp = "Shared 5 hours ago",
|
||||
description = "Shared 5 hours ago",
|
||||
location = Location(0.0, 0.0)
|
||||
),
|
||||
onShareClick = {},
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@ import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
|||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||
import io.element.android.libraries.matrix.api.room.getBestName
|
||||
import io.element.android.libraries.matrix.api.room.joinedRoomMembers
|
||||
import io.element.android.libraries.matrix.api.room.location.AssetType
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
import io.element.android.services.toolbox.api.strings.StringProvider
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
|
@ -124,7 +123,7 @@ class ShowLocationPresenter(
|
|||
url = mode.senderAvatarUrl,
|
||||
size = AvatarSize.UserListItem,
|
||||
),
|
||||
formattedTimestamp = formattedTimestamp,
|
||||
description = formattedTimestamp,
|
||||
location = mode.location,
|
||||
isLive = false,
|
||||
assetType = mode.assetType,
|
||||
|
|
@ -152,7 +151,7 @@ class ShowLocationPresenter(
|
|||
url = avatarUrl,
|
||||
size = AvatarSize.UserListItem,
|
||||
),
|
||||
formattedTimestamp = "Sharing live location",
|
||||
description = "Sharing live location",
|
||||
location = location,
|
||||
isLive = true,
|
||||
assetType = lastLocation.assetType,
|
||||
|
|
@ -169,6 +168,7 @@ class ShowLocationPresenter(
|
|||
locationShares = locationShares,
|
||||
hasLocationPermission = permissionsState.isAnyGranted,
|
||||
isTrackMyLocation = isTrackMyLocation,
|
||||
isLive = mode is ShowLocationMode.Live,
|
||||
appName = appName,
|
||||
eventSink = ::handleEvent,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
package io.element.android.features.location.impl.show
|
||||
|
||||
import io.element.android.features.location.api.Location
|
||||
import io.element.android.features.location.api.ShowLocationMode
|
||||
import io.element.android.features.location.impl.common.ui.LocationConstraintsDialogState
|
||||
import io.element.android.features.location.impl.common.ui.LocationMarkerData
|
||||
import io.element.android.libraries.designsystem.components.PinVariant
|
||||
|
|
@ -18,6 +19,7 @@ import io.element.android.libraries.matrix.api.room.location.AssetType
|
|||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
data class ShowLocationState(
|
||||
val isLive: Boolean,
|
||||
val dialogState: LocationConstraintsDialogState,
|
||||
val locationShares: ImmutableList<LocationShareItem>,
|
||||
val hasLocationPermission: Boolean,
|
||||
|
|
@ -25,14 +27,14 @@ data class ShowLocationState(
|
|||
val appName: String,
|
||||
val eventSink: (ShowLocationEvent) -> Unit,
|
||||
) {
|
||||
val isSheetDraggable = locationShares.any { item -> item.isLive }
|
||||
val isSheetDraggable = isLive && locationShares.isNotEmpty()
|
||||
}
|
||||
|
||||
data class LocationShareItem(
|
||||
val userId: UserId,
|
||||
val displayName: String,
|
||||
val avatarData: AvatarData,
|
||||
val formattedTimestamp: String,
|
||||
val description: String,
|
||||
val location: Location,
|
||||
val isLive: Boolean,
|
||||
val assetType: AssetType?,
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ package io.element.android.features.location.impl.show
|
|||
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import io.element.android.features.location.api.Location
|
||||
import io.element.android.features.location.api.ShowLocationMode
|
||||
import io.element.android.features.location.impl.common.ui.LocationConstraintsDialogState
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
||||
|
|
@ -21,6 +22,8 @@ class ShowLocationStateProvider : PreviewParameterProvider<ShowLocationState> {
|
|||
override val values: Sequence<ShowLocationState>
|
||||
get() = sequenceOf(
|
||||
aShowLocationState(),
|
||||
aShowLocationState(isLive = true),
|
||||
aShowLocationState(isLive = true, locationShares = emptyList()),
|
||||
aShowLocationState(
|
||||
constraintsDialogState = LocationConstraintsDialogState.PermissionDenied,
|
||||
),
|
||||
|
|
@ -44,8 +47,9 @@ class ShowLocationStateProvider : PreviewParameterProvider<ShowLocationState> {
|
|||
private const val APP_NAME = "ApplicationName"
|
||||
|
||||
fun aShowLocationState(
|
||||
isLive: Boolean = false,
|
||||
constraintsDialogState: LocationConstraintsDialogState = LocationConstraintsDialogState.None,
|
||||
locationShares: List<LocationShareItem> = listOf(aLocationShareItem()),
|
||||
locationShares: List<LocationShareItem> = listOf(aLocationShareItem(isLive = isLive)),
|
||||
hasLocationPermission: Boolean = false,
|
||||
isTrackMyLocation: Boolean = false,
|
||||
appName: String = APP_NAME,
|
||||
|
|
@ -57,6 +61,7 @@ fun aShowLocationState(
|
|||
hasLocationPermission = hasLocationPermission,
|
||||
isTrackMyLocation = isTrackMyLocation,
|
||||
appName = appName,
|
||||
isLive = isLive,
|
||||
eventSink = eventSink,
|
||||
)
|
||||
}
|
||||
|
|
@ -78,7 +83,7 @@ fun aLocationShareItem(
|
|||
userId = userId,
|
||||
displayName = displayName,
|
||||
avatarData = avatarData,
|
||||
formattedTimestamp = formattedTimestamp,
|
||||
description = formattedTimestamp,
|
||||
location = location,
|
||||
isLive = isLive,
|
||||
assetType = assetType,
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ package io.element.android.features.location.impl.show
|
|||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.BottomSheetDefaults
|
||||
|
|
@ -26,6 +27,7 @@ import androidx.compose.runtime.rememberCoroutineScope
|
|||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.compound.theme.ElementTheme
|
||||
|
|
@ -88,7 +90,7 @@ fun ShowLocationView(
|
|||
bottomSheetState = rememberStandardBottomSheetState(
|
||||
initialValue =
|
||||
if (state.isSheetDraggable) {
|
||||
SheetValue.PartiallyExpanded
|
||||
SheetValue.Expanded
|
||||
} else {
|
||||
SheetValue.Expanded
|
||||
}
|
||||
|
|
@ -116,29 +118,43 @@ fun ShowLocationView(
|
|||
},
|
||||
sheetContent = { sheetPaddings ->
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
Spacer(Modifier.height(20.dp))
|
||||
Text(
|
||||
text = stringResource(CommonStrings.screen_static_location_sheet_title),
|
||||
style = ElementTheme.typography.fontBodyLgMedium,
|
||||
color = ElementTheme.colors.textPrimary,
|
||||
modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp),
|
||||
)
|
||||
state.locationShares.forEach { locationShare ->
|
||||
LocationShareRow(
|
||||
item = locationShare,
|
||||
onShareClick = { state.eventSink(ShowLocationEvent.Share(locationShare.location)) },
|
||||
modifier = Modifier.clickable {
|
||||
state.eventSink(ShowLocationEvent.TrackMyLocation(false))
|
||||
val position = CameraPosition(
|
||||
padding = sheetPaddings,
|
||||
target = Position(locationShare.location.lon, locationShare.location.lat),
|
||||
zoom = MapDefaults.DEFAULT_ZOOM
|
||||
)
|
||||
coroutineScope.launch {
|
||||
cameraState.animateTo(finalPosition = position)
|
||||
}
|
||||
}
|
||||
if (!state.isSheetDraggable) {
|
||||
Spacer(Modifier.height(20.dp))
|
||||
}
|
||||
if (state.locationShares.isEmpty()) {
|
||||
Spacer(Modifier.height(16.dp))
|
||||
Text(
|
||||
text = "Nobody is sharing their location",
|
||||
style = ElementTheme.typography.fontBodyLgMedium,
|
||||
color = ElementTheme.colors.textPrimary,
|
||||
modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp),
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
Spacer(Modifier.height(16.dp))
|
||||
} else {
|
||||
Text(
|
||||
text = stringResource(CommonStrings.screen_static_location_sheet_title),
|
||||
style = ElementTheme.typography.fontBodyLgMedium,
|
||||
color = ElementTheme.colors.textPrimary,
|
||||
modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp),
|
||||
)
|
||||
state.locationShares.forEach { locationShare ->
|
||||
LocationShareRow(
|
||||
item = locationShare,
|
||||
onShareClick = { state.eventSink(ShowLocationEvent.Share(locationShare.location)) },
|
||||
modifier = Modifier.clickable {
|
||||
state.eventSink(ShowLocationEvent.TrackMyLocation(false))
|
||||
val position = CameraPosition(
|
||||
padding = sheetPaddings,
|
||||
target = Position(locationShare.location.lon, locationShare.location.lat),
|
||||
zoom = MapDefaults.DEFAULT_ZOOM
|
||||
)
|
||||
coroutineScope.launch {
|
||||
cameraState.animateTo(finalPosition = position)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
mapContent = {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue