Element config (#4471)
* Add handy extension "VariantDimension.buildConfigFieldStr" * Update configuration for MapTiler. * Update configuration for Sentry. * Build AnalyticsConfig depending on analytics configuration. * Configure analytics policy url. * Add handy extension "VariantDimension.buildConfigFieldBoolean" * Configure legal urls. * Add a way to disable rageshake / reporting bugs. * Update screenshots * Quality * Fix test * Use `ifBlank` extension * Add missing configuration for PostHog * Update configuration for Rageshake. * Add build log. * Disable crash detection if rageshake feature is not available. Disabled twice. * Hide link to analytics policy if the link is missing. * Fix test when run in enterprise context. * Use RageshakeFeatureAvailability where appropriate. * Rename file. * Move some classes to their correct module. * Update screenshots --------- Co-authored-by: ElementBot <android@element.io>
This commit is contained in:
parent
0838f4259a
commit
87fd1372a9
95 changed files with 613 additions and 273 deletions
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright 2025 New Vector 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.features.rageshake.impl
|
||||
|
||||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import io.element.android.appconfig.RageshakeConfig
|
||||
import io.element.android.appconfig.isEnabled
|
||||
import io.element.android.features.rageshake.api.RageshakeFeatureAvailability
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import javax.inject.Inject
|
||||
|
||||
@ContributesBinding(AppScope::class)
|
||||
class DefaultRageshakeFeatureAvailability @Inject constructor() : RageshakeFeatureAvailability {
|
||||
override fun isAvailable(): Boolean {
|
||||
return RageshakeConfig.isEnabled
|
||||
}
|
||||
}
|
||||
|
|
@ -16,10 +16,10 @@ import androidx.compose.runtime.mutableFloatStateOf
|
|||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import io.element.android.features.rageshake.api.crash.CrashDataStore
|
||||
import io.element.android.features.rageshake.api.reporter.BugReporter
|
||||
import io.element.android.features.rageshake.api.reporter.BugReporterListener
|
||||
import io.element.android.features.rageshake.api.screenshot.ScreenshotHolder
|
||||
import io.element.android.features.rageshake.impl.crash.CrashDataStore
|
||||
import io.element.android.features.rageshake.impl.screenshot.ScreenshotHolder
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
import io.element.android.libraries.architecture.Presenter
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Copyright 2023, 2024 New Vector 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.features.rageshake.impl.crash
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface CrashDataStore {
|
||||
fun setCrashData(crashData: String)
|
||||
|
||||
suspend fun resetAppHasCrashed()
|
||||
fun appHasCrashed(): Flow<Boolean>
|
||||
fun crashInfo(): Flow<String>
|
||||
|
||||
suspend fun reset()
|
||||
}
|
||||
|
|
@ -9,15 +9,17 @@ package io.element.android.features.rageshake.impl.crash
|
|||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import io.element.android.features.rageshake.api.crash.CrashDataStore
|
||||
import io.element.android.features.rageshake.api.RageshakeFeatureAvailability
|
||||
import io.element.android.features.rageshake.api.crash.CrashDetectionEvents
|
||||
import io.element.android.features.rageshake.api.crash.CrashDetectionPresenter
|
||||
import io.element.android.features.rageshake.api.crash.CrashDetectionState
|
||||
import io.element.android.libraries.core.meta.BuildMeta
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
|
|
@ -25,12 +27,18 @@ import javax.inject.Inject
|
|||
class DefaultCrashDetectionPresenter @Inject constructor(
|
||||
private val buildMeta: BuildMeta,
|
||||
private val crashDataStore: CrashDataStore,
|
||||
) :
|
||||
CrashDetectionPresenter {
|
||||
private val rageshakeFeatureAvailability: RageshakeFeatureAvailability,
|
||||
) : CrashDetectionPresenter {
|
||||
@Composable
|
||||
override fun present(): CrashDetectionState {
|
||||
val localCoroutineScope = rememberCoroutineScope()
|
||||
val crashDetected = crashDataStore.appHasCrashed().collectAsState(initial = false)
|
||||
val crashDetected = remember {
|
||||
if (rageshakeFeatureAvailability.isAvailable()) {
|
||||
crashDataStore.appHasCrashed()
|
||||
} else {
|
||||
flowOf(false)
|
||||
}
|
||||
}.collectAsState(false)
|
||||
|
||||
fun handleEvents(event: CrashDetectionEvents) {
|
||||
when (event) {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ import androidx.datastore.preferences.core.edit
|
|||
import androidx.datastore.preferences.core.stringPreferencesKey
|
||||
import androidx.datastore.preferences.preferencesDataStore
|
||||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import io.element.android.features.rageshake.api.crash.CrashDataStore
|
||||
import io.element.android.libraries.core.bool.orFalse
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.di.ApplicationContext
|
||||
|
|
|
|||
|
|
@ -20,9 +20,9 @@ import io.element.android.features.rageshake.api.detection.RageshakeDetectionPre
|
|||
import io.element.android.features.rageshake.api.detection.RageshakeDetectionState
|
||||
import io.element.android.features.rageshake.api.preferences.RageshakePreferencesEvents
|
||||
import io.element.android.features.rageshake.api.preferences.RageshakePreferencesPresenter
|
||||
import io.element.android.features.rageshake.api.rageshake.RageShake
|
||||
import io.element.android.features.rageshake.api.screenshot.ImageResult
|
||||
import io.element.android.features.rageshake.api.screenshot.ScreenshotHolder
|
||||
import io.element.android.features.rageshake.impl.rageshake.RageShake
|
||||
import io.element.android.features.rageshake.impl.screenshot.ScreenshotHolder
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
|
|
@ -75,7 +75,8 @@ class DefaultRageshakeDetectionPresenter @Inject constructor(
|
|||
LaunchedEffect(preferencesState.sensitivity) {
|
||||
rageShake.setSensitivity(preferencesState.sensitivity)
|
||||
}
|
||||
val shouldStart = preferencesState.isEnabled &&
|
||||
val shouldStart = preferencesState.isFeatureEnabled &&
|
||||
preferencesState.isEnabled &&
|
||||
preferencesState.isSupported &&
|
||||
isStarted.value &&
|
||||
!takeScreenshot.value &&
|
||||
|
|
|
|||
|
|
@ -11,14 +11,16 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import io.element.android.features.rageshake.api.RageshakeFeatureAvailability
|
||||
import io.element.android.features.rageshake.api.preferences.RageshakePreferencesEvents
|
||||
import io.element.android.features.rageshake.api.preferences.RageshakePreferencesPresenter
|
||||
import io.element.android.features.rageshake.api.preferences.RageshakePreferencesState
|
||||
import io.element.android.features.rageshake.api.rageshake.RageShake
|
||||
import io.element.android.features.rageshake.api.rageshake.RageshakeDataStore
|
||||
import io.element.android.features.rageshake.impl.rageshake.RageShake
|
||||
import io.element.android.features.rageshake.impl.rageshake.RageshakeDataStore
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
|
|
@ -28,6 +30,7 @@ import javax.inject.Inject
|
|||
class DefaultRageshakePreferencesPresenter @Inject constructor(
|
||||
private val rageshake: RageShake,
|
||||
private val rageshakeDataStore: RageshakeDataStore,
|
||||
private val rageshakeFeatureAvailability: RageshakeFeatureAvailability,
|
||||
) : RageshakePreferencesPresenter {
|
||||
@Composable
|
||||
override fun present(): RageshakePreferencesState {
|
||||
|
|
@ -35,6 +38,7 @@ class DefaultRageshakePreferencesPresenter @Inject constructor(
|
|||
val isSupported: MutableState<Boolean> = rememberSaveable {
|
||||
mutableStateOf(rageshake.isAvailable())
|
||||
}
|
||||
val isFeatureAvailable = remember { rageshakeFeatureAvailability.isAvailable() }
|
||||
val isEnabled = rageshakeDataStore
|
||||
.isEnabled()
|
||||
.collectAsState(initial = false)
|
||||
|
|
@ -51,6 +55,7 @@ class DefaultRageshakePreferencesPresenter @Inject constructor(
|
|||
}
|
||||
|
||||
return RageshakePreferencesState(
|
||||
isFeatureEnabled = isFeatureAvailable,
|
||||
isEnabled = isEnabled.value,
|
||||
isSupported = isSupported.value,
|
||||
sensitivity = sensitivity.value,
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ import android.hardware.SensorManager
|
|||
import androidx.core.content.getSystemService
|
||||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import com.squareup.seismic.ShakeDetector
|
||||
import io.element.android.features.rageshake.api.rageshake.RageShake
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.di.ApplicationContext
|
||||
import io.element.android.libraries.di.SingleIn
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ import androidx.datastore.preferences.core.edit
|
|||
import androidx.datastore.preferences.core.floatPreferencesKey
|
||||
import androidx.datastore.preferences.preferencesDataStore
|
||||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import io.element.android.features.rageshake.api.rageshake.RageshakeDataStore
|
||||
import io.element.android.libraries.core.bool.orFalse
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.di.ApplicationContext
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright 2023, 2024 New Vector 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.features.rageshake.impl.rageshake
|
||||
|
||||
interface RageShake {
|
||||
/**
|
||||
* Check if the feature is available on this device.
|
||||
*/
|
||||
fun isAvailable(): Boolean
|
||||
|
||||
fun start(sensitivity: Float)
|
||||
|
||||
fun stop()
|
||||
|
||||
/**
|
||||
* sensitivity will be {0, O.25, 0.5, 0.75, 1} and converted to
|
||||
* [ShakeDetector.SENSITIVITY_LIGHT (=11), ShakeDetector.SENSITIVITY_HARD (=15)].
|
||||
*/
|
||||
fun setSensitivity(sensitivity: Float)
|
||||
|
||||
fun setInterceptor(interceptor: (() -> Unit)?)
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright 2023, 2024 New Vector 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.features.rageshake.impl.rageshake
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface RageshakeDataStore {
|
||||
fun isEnabled(): Flow<Boolean>
|
||||
|
||||
suspend fun setIsEnabled(isEnabled: Boolean)
|
||||
|
||||
fun sensitivity(): Flow<Float>
|
||||
|
||||
suspend fun setSensitivity(sensitivity: Float)
|
||||
|
||||
suspend fun reset()
|
||||
}
|
||||
|
|
@ -13,10 +13,10 @@ import androidx.core.net.toFile
|
|||
import androidx.core.net.toUri
|
||||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import io.element.android.appconfig.RageshakeConfig
|
||||
import io.element.android.features.rageshake.api.crash.CrashDataStore
|
||||
import io.element.android.features.rageshake.api.reporter.BugReporter
|
||||
import io.element.android.features.rageshake.api.reporter.BugReporterListener
|
||||
import io.element.android.features.rageshake.api.screenshot.ScreenshotHolder
|
||||
import io.element.android.features.rageshake.impl.crash.CrashDataStore
|
||||
import io.element.android.features.rageshake.impl.screenshot.ScreenshotHolder
|
||||
import io.element.android.libraries.androidutils.file.compressFile
|
||||
import io.element.android.libraries.androidutils.file.safeDelete
|
||||
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ import android.content.Context
|
|||
import android.graphics.Bitmap
|
||||
import androidx.core.net.toUri
|
||||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import io.element.android.features.rageshake.api.screenshot.ScreenshotHolder
|
||||
import io.element.android.libraries.androidutils.bitmap.writeBitmap
|
||||
import io.element.android.libraries.androidutils.file.safeDelete
|
||||
import io.element.android.libraries.di.AppScope
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* Copyright 2023, 2024 New Vector 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.features.rageshake.impl.screenshot
|
||||
|
||||
import android.graphics.Bitmap
|
||||
|
||||
interface ScreenshotHolder {
|
||||
fun writeBitmap(data: Bitmap)
|
||||
fun getFileUri(): String?
|
||||
fun reset()
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue