Merge pull request #5565 from vector-im/feature/mna/PSF-664-5536-permissions
Live Location Sharing - Background permission
This commit is contained in:
commit
3547c5acba
1
changelog.d/5536.feature
Normal file
1
changelog.d/5536.feature
Normal file
@ -0,0 +1 @@
|
|||||||
|
Live location sharing: adding build config field and show permission dialog
|
@ -230,6 +230,7 @@ android {
|
|||||||
buildConfigField "boolean", "LOW_PRIVACY_LOG_ENABLE", "false"
|
buildConfigField "boolean", "LOW_PRIVACY_LOG_ENABLE", "false"
|
||||||
// Set to true if you want to enable strict mode in debug
|
// Set to true if you want to enable strict mode in debug
|
||||||
buildConfigField "boolean", "ENABLE_STRICT_MODE_LOGS", "false"
|
buildConfigField "boolean", "ENABLE_STRICT_MODE_LOGS", "false"
|
||||||
|
buildConfigField "Boolean", "ENABLE_LIVE_LOCATION_SHARING", "true"
|
||||||
|
|
||||||
signingConfig signingConfigs.debug
|
signingConfig signingConfigs.debug
|
||||||
}
|
}
|
||||||
@ -239,6 +240,7 @@ android {
|
|||||||
|
|
||||||
buildConfigField "boolean", "LOW_PRIVACY_LOG_ENABLE", "false"
|
buildConfigField "boolean", "LOW_PRIVACY_LOG_ENABLE", "false"
|
||||||
buildConfigField "boolean", "ENABLE_STRICT_MODE_LOGS", "false"
|
buildConfigField "boolean", "ENABLE_STRICT_MODE_LOGS", "false"
|
||||||
|
buildConfigField "Boolean", "ENABLE_LIVE_LOCATION_SHARING", "false"
|
||||||
|
|
||||||
postprocessing {
|
postprocessing {
|
||||||
removeUnusedCode true
|
removeUnusedCode true
|
||||||
|
@ -45,6 +45,7 @@
|
|||||||
<!-- Location Sharing -->
|
<!-- Location Sharing -->
|
||||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
|
||||||
|
|
||||||
<!-- Jitsi SDK is now API23+ -->
|
<!-- Jitsi SDK is now API23+ -->
|
||||||
<uses-sdk tools:overrideLibrary="org.jitsi.meet.sdk,com.oney.WebRTCModule,com.learnium.RNDeviceInfo,com.reactnativecommunity.asyncstorage,com.ocetnik.timer,com.calendarevents,com.reactnativecommunity.netinfo,com.kevinresol.react_native_default_preference,com.rnimmersive,com.corbt.keepawake,com.BV.LinearGradient,com.horcrux.svg,com.oblador.performance,com.reactnativecommunity.slider,com.brentvatne.react" />
|
<uses-sdk tools:overrideLibrary="org.jitsi.meet.sdk,com.oney.WebRTCModule,com.learnium.RNDeviceInfo,com.reactnativecommunity.asyncstorage,com.ocetnik.timer,com.calendarevents,com.reactnativecommunity.netinfo,com.kevinresol.react_native_default_preference,com.rnimmersive,com.corbt.keepawake,com.BV.LinearGradient,com.horcrux.svg,com.oblador.performance,com.reactnativecommunity.slider,com.brentvatne.react" />
|
||||||
|
@ -19,6 +19,7 @@ package im.vector.app.core.utils
|
|||||||
import android.Manifest
|
import android.Manifest
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
|
import android.os.Build
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.activity.result.ActivityResultLauncher
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
@ -32,6 +33,7 @@ import im.vector.app.R
|
|||||||
import im.vector.app.core.platform.VectorBaseActivity
|
import im.vector.app.core.platform.VectorBaseActivity
|
||||||
|
|
||||||
// Permissions sets
|
// Permissions sets
|
||||||
|
val PERMISSIONS_EMPTY = emptyList<String>()
|
||||||
val PERMISSIONS_FOR_AUDIO_IP_CALL = listOf(Manifest.permission.RECORD_AUDIO)
|
val PERMISSIONS_FOR_AUDIO_IP_CALL = listOf(Manifest.permission.RECORD_AUDIO)
|
||||||
val PERMISSIONS_FOR_VIDEO_IP_CALL = listOf(Manifest.permission.RECORD_AUDIO, Manifest.permission.CAMERA)
|
val PERMISSIONS_FOR_VIDEO_IP_CALL = listOf(Manifest.permission.RECORD_AUDIO, Manifest.permission.CAMERA)
|
||||||
val PERMISSIONS_FOR_VOICE_MESSAGE = listOf(Manifest.permission.RECORD_AUDIO)
|
val PERMISSIONS_FOR_VOICE_MESSAGE = listOf(Manifest.permission.RECORD_AUDIO)
|
||||||
@ -40,9 +42,12 @@ val PERMISSIONS_FOR_MEMBERS_SEARCH = listOf(Manifest.permission.READ_CONTACTS)
|
|||||||
val PERMISSIONS_FOR_ROOM_AVATAR = listOf(Manifest.permission.CAMERA)
|
val PERMISSIONS_FOR_ROOM_AVATAR = listOf(Manifest.permission.CAMERA)
|
||||||
val PERMISSIONS_FOR_WRITING_FILES = listOf(Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
val PERMISSIONS_FOR_WRITING_FILES = listOf(Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||||
val PERMISSIONS_FOR_PICKING_CONTACT = listOf(Manifest.permission.READ_CONTACTS)
|
val PERMISSIONS_FOR_PICKING_CONTACT = listOf(Manifest.permission.READ_CONTACTS)
|
||||||
val PERMISSIONS_FOR_LOCATION_SHARING = listOf(Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION)
|
val PERMISSIONS_FOR_FOREGROUND_LOCATION_SHARING = listOf(Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION)
|
||||||
|
val PERMISSIONS_FOR_BACKGROUND_LOCATION_SHARING = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||||
val PERMISSIONS_EMPTY = emptyList<String>()
|
listOf(Manifest.permission.ACCESS_BACKGROUND_LOCATION)
|
||||||
|
} else {
|
||||||
|
PERMISSIONS_EMPTY
|
||||||
|
}
|
||||||
|
|
||||||
// This is not ideal to store the value like that, but it works
|
// This is not ideal to store the value like that, but it works
|
||||||
private var permissionDialogDisplayed = false
|
private var permissionDialogDisplayed = false
|
||||||
@ -123,6 +128,7 @@ fun checkPermissions(permissionsToBeGranted: List<String>,
|
|||||||
.setPositiveButton(R.string.ok) { _, _ ->
|
.setPositiveButton(R.string.ok) { _, _ ->
|
||||||
activityResultLauncher.launch(missingPermissions.toTypedArray())
|
activityResultLauncher.launch(missingPermissions.toTypedArray())
|
||||||
}
|
}
|
||||||
|
.setNegativeButton(R.string.action_not_now, null)
|
||||||
.show()
|
.show()
|
||||||
} else {
|
} else {
|
||||||
// some permissions are not granted, ask permissions
|
// some permissions are not granted, ask permissions
|
||||||
|
@ -37,7 +37,7 @@ import androidx.core.view.isVisible
|
|||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.epoxy.onClick
|
import im.vector.app.core.epoxy.onClick
|
||||||
import im.vector.app.core.utils.PERMISSIONS_EMPTY
|
import im.vector.app.core.utils.PERMISSIONS_EMPTY
|
||||||
import im.vector.app.core.utils.PERMISSIONS_FOR_LOCATION_SHARING
|
import im.vector.app.core.utils.PERMISSIONS_FOR_FOREGROUND_LOCATION_SHARING
|
||||||
import im.vector.app.core.utils.PERMISSIONS_FOR_PICKING_CONTACT
|
import im.vector.app.core.utils.PERMISSIONS_FOR_PICKING_CONTACT
|
||||||
import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO
|
import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO
|
||||||
import im.vector.app.databinding.ViewAttachmentTypeSelectorBinding
|
import im.vector.app.databinding.ViewAttachmentTypeSelectorBinding
|
||||||
@ -215,6 +215,6 @@ class AttachmentTypeSelectorView(context: Context,
|
|||||||
STICKER(PERMISSIONS_EMPTY, R.string.tooltip_attachment_sticker),
|
STICKER(PERMISSIONS_EMPTY, R.string.tooltip_attachment_sticker),
|
||||||
CONTACT(PERMISSIONS_FOR_PICKING_CONTACT, R.string.tooltip_attachment_contact),
|
CONTACT(PERMISSIONS_FOR_PICKING_CONTACT, R.string.tooltip_attachment_contact),
|
||||||
POLL(PERMISSIONS_EMPTY, R.string.tooltip_attachment_poll),
|
POLL(PERMISSIONS_EMPTY, R.string.tooltip_attachment_poll),
|
||||||
LOCATION(PERMISSIONS_FOR_LOCATION_SHARING, R.string.tooltip_attachment_location)
|
LOCATION(PERMISSIONS_FOR_FOREGROUND_LOCATION_SHARING, R.string.tooltip_attachment_location)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.app.features.location
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import im.vector.app.core.utils.openAppSettingsPage
|
||||||
|
|
||||||
|
class DefaultLocationSharingNavigator constructor(val activity: Activity?) : LocationSharingNavigator {
|
||||||
|
|
||||||
|
override var goingToAppSettings: Boolean = false
|
||||||
|
|
||||||
|
override fun quit() {
|
||||||
|
activity?.finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun goToAppSettings() {
|
||||||
|
activity?.let {
|
||||||
|
goingToAppSettings = true
|
||||||
|
openAppSettingsPage(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -23,4 +23,5 @@ sealed class LocationSharingAction : VectorViewModelAction {
|
|||||||
data class PinnedLocationSharing(val locationData: LocationData?) : LocationSharingAction()
|
data class PinnedLocationSharing(val locationData: LocationData?) : LocationSharingAction()
|
||||||
data class LocationTargetChange(val locationData: LocationData) : LocationSharingAction()
|
data class LocationTargetChange(val locationData: LocationData) : LocationSharingAction()
|
||||||
object ZoomToUserLocation : LocationSharingAction()
|
object ZoomToUserLocation : LocationSharingAction()
|
||||||
|
object StartLiveLocationSharing : LocationSharingAction()
|
||||||
}
|
}
|
||||||
|
@ -27,9 +27,14 @@ import com.airbnb.mvrx.fragmentViewModel
|
|||||||
import com.airbnb.mvrx.withState
|
import com.airbnb.mvrx.withState
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.mapbox.mapboxsdk.maps.MapView
|
import com.mapbox.mapboxsdk.maps.MapView
|
||||||
|
import im.vector.app.BuildConfig
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.extensions.exhaustive
|
import im.vector.app.core.extensions.exhaustive
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
import im.vector.app.core.platform.VectorBaseFragment
|
||||||
|
import im.vector.app.core.utils.PERMISSIONS_FOR_BACKGROUND_LOCATION_SHARING
|
||||||
|
import im.vector.app.core.utils.PERMISSIONS_FOR_FOREGROUND_LOCATION_SHARING
|
||||||
|
import im.vector.app.core.utils.checkPermissions
|
||||||
|
import im.vector.app.core.utils.registerForPermissionsResult
|
||||||
import im.vector.app.databinding.FragmentLocationSharingBinding
|
import im.vector.app.databinding.FragmentLocationSharingBinding
|
||||||
import im.vector.app.features.home.AvatarRenderer
|
import im.vector.app.features.home.AvatarRenderer
|
||||||
import im.vector.app.features.home.room.detail.timeline.helper.MatrixItemColorProvider
|
import im.vector.app.features.home.room.detail.timeline.helper.MatrixItemColorProvider
|
||||||
@ -49,6 +54,8 @@ class LocationSharingFragment @Inject constructor(
|
|||||||
|
|
||||||
private val viewModel: LocationSharingViewModel by fragmentViewModel()
|
private val viewModel: LocationSharingViewModel by fragmentViewModel()
|
||||||
|
|
||||||
|
private val locationSharingNavigator: LocationSharingNavigator by lazy { DefaultLocationSharingNavigator(activity) }
|
||||||
|
|
||||||
// Keep a ref to handle properly the onDestroy callback
|
// Keep a ref to handle properly the onDestroy callback
|
||||||
private var mapView: WeakReference<MapView>? = null
|
private var mapView: WeakReference<MapView>? = null
|
||||||
|
|
||||||
@ -76,8 +83,8 @@ class LocationSharingFragment @Inject constructor(
|
|||||||
|
|
||||||
viewModel.observeViewEvents {
|
viewModel.observeViewEvents {
|
||||||
when (it) {
|
when (it) {
|
||||||
|
LocationSharingViewEvents.Close -> locationSharingNavigator.quit()
|
||||||
LocationSharingViewEvents.LocationNotAvailableError -> handleLocationNotAvailableError()
|
LocationSharingViewEvents.LocationNotAvailableError -> handleLocationNotAvailableError()
|
||||||
LocationSharingViewEvents.Close -> activity?.finish()
|
|
||||||
is LocationSharingViewEvents.ZoomToUserLocation -> handleZoomToUserLocationEvent(it)
|
is LocationSharingViewEvents.ZoomToUserLocation -> handleZoomToUserLocationEvent(it)
|
||||||
}.exhaustive
|
}.exhaustive
|
||||||
}
|
}
|
||||||
@ -86,6 +93,11 @@ class LocationSharingFragment @Inject constructor(
|
|||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
views.mapView.onResume()
|
views.mapView.onResume()
|
||||||
|
if (locationSharingNavigator.goingToAppSettings) {
|
||||||
|
locationSharingNavigator.goingToAppSettings = false
|
||||||
|
// retry to start live location
|
||||||
|
tryStartLiveLocationSharing()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
@ -137,12 +149,24 @@ class LocationSharingFragment @Inject constructor(
|
|||||||
.setTitle(R.string.location_not_available_dialog_title)
|
.setTitle(R.string.location_not_available_dialog_title)
|
||||||
.setMessage(R.string.location_not_available_dialog_content)
|
.setMessage(R.string.location_not_available_dialog_content)
|
||||||
.setPositiveButton(R.string.ok) { _, _ ->
|
.setPositiveButton(R.string.ok) { _, _ ->
|
||||||
activity?.finish()
|
locationSharingNavigator.quit()
|
||||||
}
|
}
|
||||||
.setCancelable(false)
|
.setCancelable(false)
|
||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun handleMissingBackgroundLocationPermission() {
|
||||||
|
MaterialAlertDialogBuilder(requireActivity())
|
||||||
|
.setTitle(R.string.location_in_background_missing_permission_dialog_title)
|
||||||
|
.setMessage(R.string.location_in_background_missing_permission_dialog_content)
|
||||||
|
.setPositiveButton(R.string.settings) { _, _ ->
|
||||||
|
locationSharingNavigator.goToAppSettings()
|
||||||
|
}
|
||||||
|
.setNegativeButton(R.string.action_not_now, null)
|
||||||
|
.setCancelable(false)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
|
||||||
private fun initLocateButton() {
|
private fun initLocateButton() {
|
||||||
views.mapView.locateButton.setOnClickListener {
|
views.mapView.locateButton.setOnClickListener {
|
||||||
viewModel.handle(LocationSharingAction.ZoomToUserLocation)
|
viewModel.handle(LocationSharingAction.ZoomToUserLocation)
|
||||||
@ -164,22 +188,58 @@ class LocationSharingFragment @Inject constructor(
|
|||||||
viewModel.handle(LocationSharingAction.CurrentUserLocationSharing)
|
viewModel.handle(LocationSharingAction.CurrentUserLocationSharing)
|
||||||
}
|
}
|
||||||
views.shareLocationOptionsPicker.optionUserLive.debouncedClicks {
|
views.shareLocationOptionsPicker.optionUserLive.debouncedClicks {
|
||||||
// TODO
|
tryStartLiveLocationSharing()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val foregroundLocationResultLauncher = registerForPermissionsResult { allGranted, deniedPermanently ->
|
||||||
|
if (allGranted && checkPermissions(PERMISSIONS_FOR_BACKGROUND_LOCATION_SHARING, requireActivity(), backgroundLocationResultLauncher)) {
|
||||||
|
startLiveLocationSharing()
|
||||||
|
} else if (deniedPermanently) {
|
||||||
|
handleMissingBackgroundLocationPermission()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val backgroundLocationResultLauncher = registerForPermissionsResult { allGranted, deniedPermanently ->
|
||||||
|
if (allGranted) {
|
||||||
|
startLiveLocationSharing()
|
||||||
|
} else if (deniedPermanently) {
|
||||||
|
handleMissingBackgroundLocationPermission()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun tryStartLiveLocationSharing() {
|
||||||
|
// we need to re-check foreground location to be sure it has not changed after landing on this screen
|
||||||
|
if (checkPermissions(PERMISSIONS_FOR_FOREGROUND_LOCATION_SHARING, requireActivity(), foregroundLocationResultLauncher) &&
|
||||||
|
checkPermissions(
|
||||||
|
PERMISSIONS_FOR_BACKGROUND_LOCATION_SHARING,
|
||||||
|
requireActivity(),
|
||||||
|
backgroundLocationResultLauncher,
|
||||||
|
R.string.location_in_background_missing_permission_dialog_content
|
||||||
|
)) {
|
||||||
|
startLiveLocationSharing()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun startLiveLocationSharing() {
|
||||||
|
viewModel.handle(LocationSharingAction.StartLiveLocationSharing)
|
||||||
|
}
|
||||||
|
|
||||||
private fun updateMap(state: LocationSharingViewState) {
|
private fun updateMap(state: LocationSharingViewState) {
|
||||||
// first, update the options view
|
// first, update the options view
|
||||||
when (state.areTargetAndUserLocationEqual) {
|
val options: Set<LocationSharingOption> = when (state.areTargetAndUserLocationEqual) {
|
||||||
// TODO activate USER_LIVE option when implemented
|
true -> {
|
||||||
true -> views.shareLocationOptionsPicker.render(
|
if (BuildConfig.ENABLE_LIVE_LOCATION_SHARING) {
|
||||||
LocationSharingOption.USER_CURRENT
|
setOf(LocationSharingOption.USER_CURRENT, LocationSharingOption.USER_LIVE)
|
||||||
)
|
} else {
|
||||||
false -> views.shareLocationOptionsPicker.render(
|
setOf(LocationSharingOption.USER_CURRENT)
|
||||||
LocationSharingOption.PINNED
|
}
|
||||||
)
|
}
|
||||||
else -> views.shareLocationOptionsPicker.render()
|
false -> setOf(LocationSharingOption.PINNED)
|
||||||
|
else -> emptySet()
|
||||||
}
|
}
|
||||||
|
views.shareLocationOptionsPicker.render(options)
|
||||||
|
|
||||||
// then, update the map using the height of the options view after it has been rendered
|
// then, update the map using the height of the options view after it has been rendered
|
||||||
views.shareLocationOptionsPicker.post {
|
views.shareLocationOptionsPicker.post {
|
||||||
val mapState = state
|
val mapState = state
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.app.features.location
|
||||||
|
|
||||||
|
interface LocationSharingNavigator {
|
||||||
|
var goingToAppSettings: Boolean
|
||||||
|
fun quit()
|
||||||
|
fun goToAppSettings()
|
||||||
|
}
|
@ -38,6 +38,7 @@ import kotlinx.coroutines.launch
|
|||||||
import org.matrix.android.sdk.api.extensions.orFalse
|
import org.matrix.android.sdk.api.extensions.orFalse
|
||||||
import org.matrix.android.sdk.api.session.Session
|
import org.matrix.android.sdk.api.session.Session
|
||||||
import org.matrix.android.sdk.api.util.toMatrixItem
|
import org.matrix.android.sdk.api.util.toMatrixItem
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sampling period to compare target location and user location.
|
* Sampling period to compare target location and user location.
|
||||||
@ -120,6 +121,7 @@ class LocationSharingViewModel @AssistedInject constructor(
|
|||||||
is LocationSharingAction.PinnedLocationSharing -> handlePinnedLocationSharingAction(action)
|
is LocationSharingAction.PinnedLocationSharing -> handlePinnedLocationSharingAction(action)
|
||||||
is LocationSharingAction.LocationTargetChange -> handleLocationTargetChangeAction(action)
|
is LocationSharingAction.LocationTargetChange -> handleLocationTargetChangeAction(action)
|
||||||
LocationSharingAction.ZoomToUserLocation -> handleZoomToUserLocationAction()
|
LocationSharingAction.ZoomToUserLocation -> handleZoomToUserLocationAction()
|
||||||
|
LocationSharingAction.StartLiveLocationSharing -> handleStartLiveLocationSharingAction()
|
||||||
}.exhaustive
|
}.exhaustive
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,6 +159,11 @@ class LocationSharingViewModel @AssistedInject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun handleStartLiveLocationSharingAction() {
|
||||||
|
// TODO start sharing live location and update view state
|
||||||
|
Timber.d("live location sharing started")
|
||||||
|
}
|
||||||
|
|
||||||
override fun onLocationUpdate(locationData: LocationData) {
|
override fun onLocationUpdate(locationData: LocationData) {
|
||||||
setState {
|
setState {
|
||||||
copy(lastKnownUserLocation = locationData)
|
copy(lastKnownUserLocation = locationData)
|
||||||
|
@ -58,7 +58,7 @@ class LocationSharingOptionPickerView @JvmOverloads constructor(
|
|||||||
applyBackground()
|
applyBackground()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun render(vararg options: LocationSharingOption) {
|
fun render(options: Set<LocationSharingOption> = emptySet()) {
|
||||||
val optionsNumber = options.toSet().size
|
val optionsNumber = options.toSet().size
|
||||||
val isPinnedVisible = options.contains(LocationSharingOption.PINNED)
|
val isPinnedVisible = options.contains(LocationSharingOption.PINNED)
|
||||||
val isUserCurrentVisible = options.contains(LocationSharingOption.USER_CURRENT)
|
val isUserCurrentVisible = options.contains(LocationSharingOption.USER_CURRENT)
|
||||||
|
@ -2937,6 +2937,8 @@
|
|||||||
<string name="a11y_location_share_option_user_live_icon">Share live location</string>
|
<string name="a11y_location_share_option_user_live_icon">Share live location</string>
|
||||||
<string name="location_share_option_pinned">Share this location</string>
|
<string name="location_share_option_pinned">Share this location</string>
|
||||||
<string name="a11y_location_share_option_pinned_icon">Share this location</string>
|
<string name="a11y_location_share_option_pinned_icon">Share this location</string>
|
||||||
|
<string name="location_in_background_missing_permission_dialog_title">Allow access</string>
|
||||||
|
<string name="location_in_background_missing_permission_dialog_content">If you’d like to share your Live location, ${app_name} needs location access all the time when the app is in the background.\nWe will only access your location for the duration that you choose.</string>
|
||||||
<string name="location_not_available_dialog_title">${app_name} could not access your location</string>
|
<string name="location_not_available_dialog_title">${app_name} could not access your location</string>
|
||||||
<string name="location_not_available_dialog_content">${app_name} could not access your location. Please try again later.</string>
|
<string name="location_not_available_dialog_content">${app_name} could not access your location. Please try again later.</string>
|
||||||
<string name="location_share_external">Open with</string>
|
<string name="location_share_external">Open with</string>
|
||||||
|
Loading…
Reference in New Issue
Block a user