Feature : share live location (#6741)

* First live location sharing sending implementation

* Simplify logic around canStop sharing

* Add some debug logs around LiveLocationSharingService

* Add LiveLocationException

* Expose beaconId to identify the current share

* Throttle live location instead of debouncing

* Keep sync alive when sharing live location

* Improve LiveLocation sharing

* Show LiveLocationDisclaimer

* Read minDistanceUpdate in LiveLocationSharingService

* Set minDistanceUpdate in AdvancedSettings

* Display banner in room when sharing live location

* Fix tests around LiveLocationSharing

* Ensure shares are properly restarted/stopped when app is re-launched

* Ensure LLS data is cleared when session is removed

* Update and fix LLS tests

* Handle Start LLS in ui

* Add check LLS permissions

* Remove hardcoded strings

* Fix quality and format

* Create DeviceLocationProvider so we can share location data between sources (presenter/live location service)

* Update screenshots

* Fix warning

* Do not try to stop if it was not sharing

* Revert "Create DeviceLocationProvider so we can share location data between sources (presenter/live location service)"

This reverts commit ba12bd968e82941cc231bdbb449310b24c97c5b8.

* Tweak location provider config values

* Address PR review remarks

* Fix ktlint

* Update screenshots

* Fix some tests after merging develop

* Adjust TimelineItemLocationView ui to match figma

* Update screenshots

* Documentation and cleanup

* Remove temporary resource

---------

Co-authored-by: ElementBot <android@element.io>
Co-authored-by: Benoit Marty <benoit@matrix.org>
Co-authored-by: Benoit Marty <benoitm@matrix.org>
This commit is contained in:
ganfra 2026-05-11 10:19:28 +02:00 committed by GitHub
parent 0c657c258a
commit e49e183178
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
145 changed files with 2913 additions and 278 deletions

View file

@ -10,6 +10,7 @@ package io.element.android.libraries.preferences.impl.store
import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.intPreferencesKey
import androidx.datastore.preferences.core.stringPreferencesKey
import dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.ContributesBinding
@ -28,6 +29,7 @@ private val customElementCallBaseUrlKey = stringPreferencesKey("elementCallBaseU
private val themeKey = stringPreferencesKey("theme")
private val hideInviteAvatarsKey = booleanPreferencesKey("hideInviteAvatars")
private val timelineMediaPreviewValueKey = stringPreferencesKey("timelineMediaPreviewValue")
private val liveLocationMinimumDistanceUpdateKey = intPreferencesKey("liveLocationMinimumDistanceUpdate")
private val logLevelKey = stringPreferencesKey("logLevel")
private val traceLogPacksKey = stringPreferencesKey("traceLogPacks")
@ -79,6 +81,18 @@ class DefaultAppPreferencesStore(
}
}
override suspend fun setLiveLocationMinimumDistanceInMetersUpdate(value: Int) {
store.edit { prefs ->
prefs[liveLocationMinimumDistanceUpdateKey] = value
}
}
override fun getLiveLocationMinimumDistanceInMetersUpdateFlow(): Flow<Int> {
return store.data.map { prefs ->
prefs[liveLocationMinimumDistanceUpdateKey] ?: 10
}
}
@Deprecated("Use MediaPreviewService instead. Kept only for migration.")
override fun getHideInviteAvatarsFlow(): Flow<Boolean?> {
return store.data.map { prefs ->

View file

@ -0,0 +1,57 @@
/*
* Copyright (c) 2026 Element Creations Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.libraries.preferences.impl.store
import com.google.common.truth.Truth.assertThat
import io.element.android.libraries.core.meta.BuildMeta
import io.element.android.libraries.core.meta.BuildType
import io.element.android.libraries.preferences.test.FakePreferenceDataStoreFactory
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.test.runTest
import org.junit.Test
class DefaultAppPreferencesStoreTest {
private val buildMeta = BuildMeta(
buildType = BuildType.DEBUG,
isDebuggable = true,
applicationName = "Element X",
productionApplicationName = "Element",
desktopApplicationName = "Element Desktop",
applicationId = "io.element.android",
isEnterpriseBuild = false,
lowPrivacyLoggingEnabled = false,
versionName = "1.0.0",
versionCode = 1,
gitRevision = "test",
gitBranchName = "test",
flavorDescription = "test",
flavorShortDescription = "test",
)
@Test
fun `live location minimum distance defaults to 10`() = runTest {
val store = DefaultAppPreferencesStore(
buildMeta = buildMeta,
preferenceDataStoreFactory = FakePreferenceDataStoreFactory(),
)
assertThat(store.getLiveLocationMinimumDistanceInMetersUpdateFlow().first()).isEqualTo(10)
}
@Test
fun `live location minimum distance persists updates`() = runTest {
val store = DefaultAppPreferencesStore(
buildMeta = buildMeta,
preferenceDataStoreFactory = FakePreferenceDataStoreFactory(),
)
store.setLiveLocationMinimumDistanceInMetersUpdate(25)
assertThat(store.getLiveLocationMinimumDistanceInMetersUpdateFlow().first()).isEqualTo(25)
}
}