mirror of
https://github.com/bitwarden/android.git
synced 2025-03-15 18:58:59 +03:00
BIT-478: Implementation for crash logging switch in settings screen (#864)
This commit is contained in:
parent
085fa0153d
commit
2de2ade7a6
11 changed files with 135 additions and 13 deletions
|
@ -0,0 +1,12 @@
|
|||
package com.x8bit.bitwarden.data.platform.manager
|
||||
|
||||
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
|
||||
|
||||
/**
|
||||
* CrashLogsManager implementation for F-droid flavor builds.
|
||||
*/
|
||||
class CrashLogsManagerImpl(
|
||||
settingsRepository: SettingsRepository,
|
||||
) : CrashLogsManager {
|
||||
override var isEnabled: Boolean = true
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
package com.x8bit.bitwarden
|
||||
|
||||
import android.app.Application
|
||||
import com.x8bit.bitwarden.data.platform.manager.CrashLogsManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.NetworkConfigManager
|
||||
import dagger.hilt.android.HiltAndroidApp
|
||||
import javax.inject.Inject
|
||||
|
@ -14,4 +15,7 @@ class BitwardenApplication : Application() {
|
|||
// other callers.
|
||||
@Inject
|
||||
lateinit var networkConfigManager: NetworkConfigManager
|
||||
|
||||
@Inject
|
||||
lateinit var crashLogsManager: CrashLogsManager
|
||||
}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
package com.x8bit.bitwarden.data.platform.manager
|
||||
|
||||
/**
|
||||
* Implementations of this interface provide a way to enable or disable the collection of crash
|
||||
* logs, giving control over whether crash logs are generated and stored.
|
||||
*/
|
||||
interface CrashLogsManager {
|
||||
/**
|
||||
* Gets or sets whether the collection of crash logs is enabled.
|
||||
*/
|
||||
var isEnabled: Boolean
|
||||
}
|
|
@ -14,6 +14,8 @@ import com.x8bit.bitwarden.data.platform.manager.AppForegroundManager
|
|||
import com.x8bit.bitwarden.data.platform.manager.AppForegroundManagerImpl
|
||||
import com.x8bit.bitwarden.data.platform.manager.BiometricsEncryptionManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.BiometricsEncryptionManagerImpl
|
||||
import com.x8bit.bitwarden.data.platform.manager.CrashLogsManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.CrashLogsManagerImpl
|
||||
import com.x8bit.bitwarden.data.platform.manager.NetworkConfigManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.NetworkConfigManagerImpl
|
||||
import com.x8bit.bitwarden.data.platform.manager.NetworkConnectionManager
|
||||
|
@ -135,4 +137,12 @@ object PlatformManagerModule {
|
|||
clock = clock,
|
||||
json = json,
|
||||
)
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideCrashLogsManager(
|
||||
settingsRepository: SettingsRepository,
|
||||
): CrashLogsManager = CrashLogsManagerImpl(
|
||||
settingsRepository = settingsRepository,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
package com.x8bit.bitwarden.data.platform.util
|
||||
|
||||
import com.x8bit.bitwarden.BuildConfig
|
||||
|
||||
/**
|
||||
* A boolean property that indicates whether the current build flavor is "fdroid".
|
||||
*/
|
||||
val isFdroid: Boolean
|
||||
get() = BuildConfig.FLAVOR == "fdroid"
|
|
@ -150,16 +150,18 @@ private fun ContentColumn(
|
|||
.verticalScroll(rememberScrollState()),
|
||||
) {
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
BitwardenWideSwitch(
|
||||
label = stringResource(id = R.string.submit_crash_logs),
|
||||
isChecked = state.isSubmitCrashLogsEnabled,
|
||||
onCheckedChange = onSubmitCrashLogsCheckedChange,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
contentDescription = stringResource(id = R.string.submit_crash_logs),
|
||||
)
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
if (state.shouldShowCrashLogsButton) {
|
||||
BitwardenWideSwitch(
|
||||
label = stringResource(id = R.string.submit_crash_logs),
|
||||
isChecked = state.isSubmitCrashLogsEnabled,
|
||||
onCheckedChange = onSubmitCrashLogsCheckedChange,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
contentDescription = stringResource(id = R.string.submit_crash_logs),
|
||||
)
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
}
|
||||
BitwardenExternalLinkRow(
|
||||
text = stringResource(id = R.string.bitwarden_help_center),
|
||||
onConfirmClick = onHelpCenterClick,
|
||||
|
|
|
@ -5,7 +5,10 @@ import androidx.lifecycle.SavedStateHandle
|
|||
import androidx.lifecycle.viewModelScope
|
||||
import com.x8bit.bitwarden.BuildConfig
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.data.platform.manager.CrashLogsManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.clipboard.BitwardenClipboardManager
|
||||
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
|
||||
import com.x8bit.bitwarden.data.platform.util.isFdroid
|
||||
import com.x8bit.bitwarden.ui.platform.base.BaseViewModel
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.Text
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||
|
@ -29,8 +32,13 @@ class AboutViewModel @Inject constructor(
|
|||
private val savedStateHandle: SavedStateHandle,
|
||||
private val clipboardManager: BitwardenClipboardManager,
|
||||
private val clock: Clock,
|
||||
private val settingsRepository: SettingsRepository,
|
||||
private val crashLogsManager: CrashLogsManager,
|
||||
) : BaseViewModel<AboutState, AboutEvent, AboutAction>(
|
||||
initialState = savedStateHandle[KEY_STATE] ?: createInitialState(clock = clock),
|
||||
initialState = savedStateHandle[KEY_STATE] ?: createInitialState(
|
||||
clock = clock,
|
||||
isCrashLoggingEnabled = crashLogsManager.isEnabled,
|
||||
),
|
||||
) {
|
||||
init {
|
||||
stateFlow
|
||||
|
@ -65,6 +73,7 @@ class AboutViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun handleSubmitCrashLogsClick(action: AboutAction.SubmitCrashLogsClick) {
|
||||
crashLogsManager.isEnabled = action.enabled
|
||||
mutableStateFlow.update { currentState ->
|
||||
currentState.copy(isSubmitCrashLogsEnabled = action.enabled)
|
||||
}
|
||||
|
@ -84,7 +93,7 @@ class AboutViewModel @Inject constructor(
|
|||
/**
|
||||
* Create initial state for the About View model.
|
||||
*/
|
||||
fun createInitialState(clock: Clock): AboutState {
|
||||
fun createInitialState(clock: Clock, isCrashLoggingEnabled: Boolean): AboutState {
|
||||
val currentYear = Year.now(clock).value
|
||||
val copyrightInfo = "© Bitwarden Inc. 2015-$currentYear".asText()
|
||||
|
||||
|
@ -92,7 +101,8 @@ class AboutViewModel @Inject constructor(
|
|||
version = R.string.version
|
||||
.asText()
|
||||
.concat(": ${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})".asText()),
|
||||
isSubmitCrashLogsEnabled = false,
|
||||
isSubmitCrashLogsEnabled = isCrashLoggingEnabled,
|
||||
shouldShowCrashLogsButton = !isFdroid,
|
||||
copyrightInfo = copyrightInfo,
|
||||
)
|
||||
}
|
||||
|
@ -106,6 +116,7 @@ class AboutViewModel @Inject constructor(
|
|||
data class AboutState(
|
||||
val version: Text,
|
||||
val isSubmitCrashLogsEnabled: Boolean,
|
||||
val shouldShowCrashLogsButton: Boolean,
|
||||
val copyrightInfo: Text,
|
||||
) : Parcelable
|
||||
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
package com.x8bit.bitwarden.data.platform.manager
|
||||
|
||||
import com.google.firebase.crashlytics.ktx.crashlytics
|
||||
import com.google.firebase.ktx.Firebase
|
||||
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
|
||||
|
||||
/**
|
||||
* CrashLogsManager implementation for standard flavor builds.
|
||||
*/
|
||||
class CrashLogsManagerImpl(
|
||||
private val settingsRepository: SettingsRepository,
|
||||
) : CrashLogsManager {
|
||||
|
||||
override var isEnabled: Boolean
|
||||
get() = settingsRepository.isCrashLoggingEnabled
|
||||
set(value) {
|
||||
settingsRepository.isCrashLoggingEnabled = value
|
||||
Firebase.crashlytics.setCrashlyticsCollectionEnabled(value)
|
||||
}
|
||||
|
||||
init {
|
||||
isEnabled = settingsRepository.isCrashLoggingEnabled
|
||||
}
|
||||
}
|
|
@ -32,6 +32,7 @@ class MainViewModelTest : BaseViewModelTest() {
|
|||
private val mutableAppThemeFlow = MutableStateFlow(AppTheme.DEFAULT)
|
||||
private val mutableUserStateFlow = MutableStateFlow<UserState?>(DEFAULT_USER_STATE)
|
||||
private val mutableScreenCaptureAllowedFlow = MutableStateFlow(true)
|
||||
private val mutableCrashLoggingEnabledFlow = MutableStateFlow(true)
|
||||
val authRepository = mockk<AuthRepository> {
|
||||
every { userStateFlow } returns mutableUserStateFlow
|
||||
every { activeUserId } returns USER_ID
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.x8bit.bitwarden.ui.platform.feature.settings.about
|
||||
|
||||
import androidx.compose.ui.test.assertIsDisplayed
|
||||
import androidx.compose.ui.test.assertIsNotDisplayed
|
||||
import androidx.compose.ui.test.assertIsOff
|
||||
import androidx.compose.ui.test.assertIsOn
|
||||
import androidx.compose.ui.test.filterToOne
|
||||
|
@ -40,6 +41,7 @@ class AboutScreenTest : BaseComposeTest() {
|
|||
version = "Version: 1.0.0 (1)".asText(),
|
||||
isSubmitCrashLogsEnabled = false,
|
||||
copyrightInfo = "".asText(),
|
||||
shouldShowCrashLogsButton = true,
|
||||
),
|
||||
)
|
||||
private val mutableEventFlow = bufferedMutableSharedFlow<AboutEvent>()
|
||||
|
@ -174,6 +176,21 @@ class AboutScreenTest : BaseComposeTest() {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `submit crash logs switch should be displayed according to state`() {
|
||||
mutableStateFlow.update { it.copy(shouldShowCrashLogsButton = true) }
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText("Submit crash logs")
|
||||
.assertIsDisplayed()
|
||||
|
||||
mutableStateFlow.update { it.copy(shouldShowCrashLogsButton = false) }
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText("Submit crash logs")
|
||||
.assertIsNotDisplayed()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `on submit crash logs toggle should send SubmitCrashLogsClick`() {
|
||||
val enabled = true
|
||||
|
|
|
@ -3,10 +3,13 @@ package com.x8bit.bitwarden.ui.platform.feature.settings.about
|
|||
import androidx.lifecycle.SavedStateHandle
|
||||
import app.cash.turbine.test
|
||||
import com.x8bit.bitwarden.BuildConfig
|
||||
import com.x8bit.bitwarden.data.platform.manager.CrashLogsManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.clipboard.BitwardenClipboardManager
|
||||
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
|
||||
import com.x8bit.bitwarden.ui.platform.base.BaseViewModelTest
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.concat
|
||||
import io.mockk.coVerify
|
||||
import io.mockk.every
|
||||
import io.mockk.just
|
||||
import io.mockk.mockk
|
||||
|
@ -25,6 +28,11 @@ import java.time.ZoneId
|
|||
class AboutViewModelTest : BaseViewModelTest() {
|
||||
|
||||
private val clipboardManager: BitwardenClipboardManager = mockk()
|
||||
private val settingsRepository: SettingsRepository = mockk()
|
||||
private val crashLogsManager: CrashLogsManager = mockk {
|
||||
every { isEnabled } returns false
|
||||
every { isEnabled = any() } just runs
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `on BackClick should emit NavigateBack`() = runTest {
|
||||
|
@ -71,6 +79,15 @@ class AboutViewModelTest : BaseViewModelTest() {
|
|||
assertTrue(viewModel.stateFlow.value.isSubmitCrashLogsEnabled)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `on SubmitCrashLogsClick should update crashLogsManager isEnabled`() = runTest {
|
||||
val viewModel = createViewModel(DEFAULT_ABOUT_STATE)
|
||||
|
||||
viewModel.trySendAction(AboutAction.SubmitCrashLogsClick(true))
|
||||
|
||||
coVerify(exactly = 1) { crashLogsManager.isEnabled = true }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `on VersionClick should call setText on the ClipboardManager with specific Text`() {
|
||||
val versionName = BuildConfig.VERSION_NAME
|
||||
|
@ -108,6 +125,8 @@ class AboutViewModelTest : BaseViewModelTest() {
|
|||
savedStateHandle = SavedStateHandle().apply { set("state", state) },
|
||||
clipboardManager = clipboardManager,
|
||||
clock = fixedClock,
|
||||
settingsRepository = settingsRepository,
|
||||
crashLogsManager = crashLogsManager,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -121,4 +140,5 @@ private val DEFAULT_ABOUT_STATE: AboutState = AboutState(
|
|||
copyrightInfo = "© Bitwarden Inc. 2015-"
|
||||
.asText()
|
||||
.concat(Year.now(fixedClock).value.toString().asText()),
|
||||
shouldShowCrashLogsButton = true,
|
||||
)
|
||||
|
|
Loading…
Add table
Reference in a new issue