mirror of
https://github.com/bitwarden/android.git
synced 2026-03-21 22:00:42 -05:00
PM-19099: Centralize app metadata (#4847)
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
package com.x8bit.bitwarden.data.platform.util
|
package com.x8bit.bitwarden.data.platform.util
|
||||||
|
|
||||||
|
import android.os.Build
|
||||||
import com.x8bit.bitwarden.BuildConfig
|
import com.x8bit.bitwarden.BuildConfig
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -7,3 +8,55 @@ import com.x8bit.bitwarden.BuildConfig
|
|||||||
*/
|
*/
|
||||||
val isFdroid: Boolean
|
val isFdroid: Boolean
|
||||||
get() = BuildConfig.FLAVOR == "fdroid"
|
get() = BuildConfig.FLAVOR == "fdroid"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A string that represents a displayable app version.
|
||||||
|
*/
|
||||||
|
val versionData: String
|
||||||
|
get() = "${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A string that represents device data.
|
||||||
|
*/
|
||||||
|
val deviceData: String get() = "$deviceBrandModel $osInfo $buildInfo"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A string representing the CI information if available.
|
||||||
|
*/
|
||||||
|
val ciBuildInfo: String? get() = BuildConfig.CI_INFO.takeUnless { it.isBlank() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A string representing the build flavor or blank if it is the standard configuration.
|
||||||
|
*/
|
||||||
|
private val buildFlavorName: String
|
||||||
|
get() = when (BuildConfig.FLAVOR) {
|
||||||
|
"standard" -> ""
|
||||||
|
else -> "-${BuildConfig.FLAVOR}"
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A string representing the build type.
|
||||||
|
*/
|
||||||
|
private val buildTypeName: String
|
||||||
|
get() = when (BuildConfig.BUILD_TYPE) {
|
||||||
|
"debug" -> "dev"
|
||||||
|
"release" -> "prod"
|
||||||
|
else -> BuildConfig.BUILD_TYPE
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A string representing the device brand and model.
|
||||||
|
*/
|
||||||
|
private val deviceBrandModel: String get() = "\uD83D\uDCF1 ${Build.BRAND} ${Build.MODEL}"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A string representing the operating system information.
|
||||||
|
*/
|
||||||
|
private val osInfo: String get() = "\uD83E\uDD16 ${Build.VERSION.RELEASE}@${Build.VERSION.SDK_INT}"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A string representing the build information.
|
||||||
|
*/
|
||||||
|
private val buildInfo: String
|
||||||
|
get() = "\uD83D\uDCE6 $buildTypeName" +
|
||||||
|
buildFlavorName.takeUnless { it.isBlank() }?.let { " $it" }.orEmpty()
|
||||||
|
|||||||
@@ -1,16 +1,17 @@
|
|||||||
package com.x8bit.bitwarden.ui.platform.feature.settings.about
|
package com.x8bit.bitwarden.ui.platform.feature.settings.about
|
||||||
|
|
||||||
import android.os.Build
|
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import androidx.lifecycle.SavedStateHandle
|
import androidx.lifecycle.SavedStateHandle
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.x8bit.bitwarden.BuildConfig
|
|
||||||
import com.x8bit.bitwarden.R
|
import com.x8bit.bitwarden.R
|
||||||
import com.x8bit.bitwarden.data.platform.manager.LogsManager
|
import com.x8bit.bitwarden.data.platform.manager.LogsManager
|
||||||
import com.x8bit.bitwarden.data.platform.manager.clipboard.BitwardenClipboardManager
|
import com.x8bit.bitwarden.data.platform.manager.clipboard.BitwardenClipboardManager
|
||||||
import com.x8bit.bitwarden.data.platform.repository.EnvironmentRepository
|
import com.x8bit.bitwarden.data.platform.repository.EnvironmentRepository
|
||||||
import com.x8bit.bitwarden.data.platform.repository.util.baseWebVaultUrlOrDefault
|
import com.x8bit.bitwarden.data.platform.repository.util.baseWebVaultUrlOrDefault
|
||||||
|
import com.x8bit.bitwarden.data.platform.util.ciBuildInfo
|
||||||
|
import com.x8bit.bitwarden.data.platform.util.deviceData
|
||||||
import com.x8bit.bitwarden.data.platform.util.isFdroid
|
import com.x8bit.bitwarden.data.platform.util.isFdroid
|
||||||
|
import com.x8bit.bitwarden.data.platform.util.versionData
|
||||||
import com.x8bit.bitwarden.ui.platform.base.BaseViewModel
|
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.Text
|
||||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||||
@@ -37,10 +38,15 @@ class AboutViewModel @Inject constructor(
|
|||||||
private val logsManager: LogsManager,
|
private val logsManager: LogsManager,
|
||||||
private val environmentRepository: EnvironmentRepository,
|
private val environmentRepository: EnvironmentRepository,
|
||||||
) : BaseViewModel<AboutState, AboutEvent, AboutAction>(
|
) : BaseViewModel<AboutState, AboutEvent, AboutAction>(
|
||||||
initialState = savedStateHandle[KEY_STATE] ?: createInitialState(
|
initialState = savedStateHandle[KEY_STATE]
|
||||||
clock = clock,
|
?: AboutState(
|
||||||
isCrashLoggingEnabled = logsManager.isEnabled,
|
version = R.string.version.asText().concat(": $versionData".asText()),
|
||||||
),
|
deviceData = deviceData.asText(),
|
||||||
|
ciData = ciBuildInfo?.let { "\n$it" }.orEmpty().asText(),
|
||||||
|
isSubmitCrashLogsEnabled = logsManager.isEnabled,
|
||||||
|
shouldShowCrashLogsButton = !isFdroid,
|
||||||
|
copyrightInfo = "© Bitwarden Inc. 2015-${Year.now(clock).value}".asText(),
|
||||||
|
),
|
||||||
) {
|
) {
|
||||||
init {
|
init {
|
||||||
stateFlow
|
stateFlow
|
||||||
@@ -92,34 +98,13 @@ class AboutViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun handleVersionClick() {
|
private fun handleVersionClick() {
|
||||||
val buildFlavour = when (BuildConfig.FLAVOR) {
|
|
||||||
"standard" -> ""
|
|
||||||
else -> "-${BuildConfig.FLAVOR}"
|
|
||||||
}
|
|
||||||
|
|
||||||
val buildVariant = when (BuildConfig.BUILD_TYPE) {
|
|
||||||
"debug" -> "dev"
|
|
||||||
"release" -> "prod"
|
|
||||||
else -> BuildConfig.BUILD_TYPE
|
|
||||||
}
|
|
||||||
|
|
||||||
val deviceBrandModel = "\uD83D\uDCF1 ${Build.BRAND} ${Build.MODEL}"
|
|
||||||
val osInfo = "\uD83E\uDD16 ${Build.VERSION.RELEASE}@${Build.VERSION.SDK_INT}"
|
|
||||||
val buildInfo = "\uD83D\uDCE6 $buildVariant$buildFlavour"
|
|
||||||
val ciBuildInfoString = BuildConfig.CI_INFO
|
|
||||||
|
|
||||||
clipboardManager.setText(
|
clipboardManager.setText(
|
||||||
text = state.copyrightInfo
|
text = state.copyrightInfo
|
||||||
.concat("\n\n".asText())
|
.concat("\n\n".asText())
|
||||||
.concat(state.version)
|
.concat(state.version)
|
||||||
.concat("\n".asText())
|
.concat("\n".asText())
|
||||||
.concat("$deviceBrandModel $osInfo $buildInfo".asText())
|
.concat(state.deviceData)
|
||||||
.concat(
|
.concat(state.ciData),
|
||||||
"\n$ciBuildInfoString"
|
|
||||||
.takeUnless { ciBuildInfoString.isEmpty() }
|
|
||||||
.orEmpty()
|
|
||||||
.asText(),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,26 +115,6 @@ class AboutViewModel @Inject constructor(
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("UndocumentedPublicClass")
|
|
||||||
companion object {
|
|
||||||
/**
|
|
||||||
* Create initial state for the About View model.
|
|
||||||
*/
|
|
||||||
fun createInitialState(clock: Clock, isCrashLoggingEnabled: Boolean): AboutState {
|
|
||||||
val currentYear = Year.now(clock).value
|
|
||||||
val copyrightInfo = "© Bitwarden Inc. 2015-$currentYear".asText()
|
|
||||||
|
|
||||||
return AboutState(
|
|
||||||
version = R.string.version
|
|
||||||
.asText()
|
|
||||||
.concat(": ${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})".asText()),
|
|
||||||
isSubmitCrashLogsEnabled = isCrashLoggingEnabled,
|
|
||||||
shouldShowCrashLogsButton = !isFdroid,
|
|
||||||
copyrightInfo = copyrightInfo,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -158,6 +123,8 @@ class AboutViewModel @Inject constructor(
|
|||||||
@Parcelize
|
@Parcelize
|
||||||
data class AboutState(
|
data class AboutState(
|
||||||
val version: Text,
|
val version: Text,
|
||||||
|
val deviceData: Text,
|
||||||
|
val ciData: Text,
|
||||||
val isSubmitCrashLogsEnabled: Boolean,
|
val isSubmitCrashLogsEnabled: Boolean,
|
||||||
val shouldShowCrashLogsButton: Boolean,
|
val shouldShowCrashLogsButton: Boolean,
|
||||||
val copyrightInfo: Text,
|
val copyrightInfo: Text,
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ class AboutScreenTest : BaseComposeTest() {
|
|||||||
private val mutableStateFlow = MutableStateFlow(
|
private val mutableStateFlow = MutableStateFlow(
|
||||||
AboutState(
|
AboutState(
|
||||||
version = "Version: 1.0.0 (1)".asText(),
|
version = "Version: 1.0.0 (1)".asText(),
|
||||||
|
deviceData = "device_data".asText(),
|
||||||
|
ciData = "ci_data".asText(),
|
||||||
isSubmitCrashLogsEnabled = false,
|
isSubmitCrashLogsEnabled = false,
|
||||||
copyrightInfo = "".asText(),
|
copyrightInfo = "".asText(),
|
||||||
shouldShowCrashLogsButton = true,
|
shouldShowCrashLogsButton = true,
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
package com.x8bit.bitwarden.ui.platform.feature.settings.about
|
package com.x8bit.bitwarden.ui.platform.feature.settings.about
|
||||||
|
|
||||||
import android.os.Build
|
|
||||||
import androidx.lifecycle.SavedStateHandle
|
import androidx.lifecycle.SavedStateHandle
|
||||||
import app.cash.turbine.test
|
import app.cash.turbine.test
|
||||||
import com.x8bit.bitwarden.BuildConfig
|
|
||||||
import com.x8bit.bitwarden.data.platform.manager.LogsManager
|
import com.x8bit.bitwarden.data.platform.manager.LogsManager
|
||||||
import com.x8bit.bitwarden.data.platform.manager.clipboard.BitwardenClipboardManager
|
import com.x8bit.bitwarden.data.platform.manager.clipboard.BitwardenClipboardManager
|
||||||
import com.x8bit.bitwarden.data.platform.repository.util.FakeEnvironmentRepository
|
import com.x8bit.bitwarden.data.platform.repository.util.FakeEnvironmentRepository
|
||||||
@@ -110,31 +108,17 @@ class AboutViewModelTest : BaseViewModelTest() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `on VersionClick should call setText on the ClipboardManager with specific Text`() {
|
fun `on VersionClick should call setText on the ClipboardManager with specific Text`() {
|
||||||
val versionName = BuildConfig.VERSION_NAME
|
val state = DEFAULT_ABOUT_STATE
|
||||||
val versionCode = BuildConfig.VERSION_CODE
|
val expectedText = state.copyrightInfo
|
||||||
|
|
||||||
val deviceBrandModel = "\uD83D\uDCF1 ${Build.BRAND} ${Build.MODEL}"
|
|
||||||
val osInfo = "\uD83E\uDD16 ${Build.VERSION.RELEASE}@${Build.VERSION.SDK_INT}"
|
|
||||||
val buildInfo = "\uD83D\uDCE6 dev"
|
|
||||||
val ciInfo = BuildConfig.CI_INFO
|
|
||||||
|
|
||||||
val expectedText = "© Bitwarden Inc. 2015-"
|
|
||||||
.asText()
|
|
||||||
.concat(Year.now(fixedClock).value.toString().asText())
|
|
||||||
.concat("\n\n".asText())
|
.concat("\n\n".asText())
|
||||||
.concat("Version: $versionName ($versionCode)".asText())
|
.concat(state.version)
|
||||||
.concat("\n".asText())
|
.concat("\n".asText())
|
||||||
.concat("$deviceBrandModel $osInfo $buildInfo".asText())
|
.concat(state.deviceData)
|
||||||
.concat(
|
.concat(state.ciData)
|
||||||
"\n$ciInfo"
|
|
||||||
.takeUnless { ciInfo.isEmpty() }
|
|
||||||
.orEmpty()
|
|
||||||
.asText(),
|
|
||||||
)
|
|
||||||
|
|
||||||
every { clipboardManager.setText(expectedText, true, null) } just runs
|
every { clipboardManager.setText(expectedText, true, null) } just runs
|
||||||
|
|
||||||
val viewModel = createViewModel(DEFAULT_ABOUT_STATE)
|
val viewModel = createViewModel(state)
|
||||||
viewModel.trySendAction(AboutAction.VersionClick)
|
viewModel.trySendAction(AboutAction.VersionClick)
|
||||||
|
|
||||||
verify(exactly = 1) {
|
verify(exactly = 1) {
|
||||||
@@ -175,10 +159,10 @@ private val fixedClock = Clock.fixed(
|
|||||||
ZoneId.systemDefault(),
|
ZoneId.systemDefault(),
|
||||||
)
|
)
|
||||||
private val DEFAULT_ABOUT_STATE: AboutState = AboutState(
|
private val DEFAULT_ABOUT_STATE: AboutState = AboutState(
|
||||||
version = "Version: ${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})".asText(),
|
version = "Version: <version_name> (<version_code>)".asText(),
|
||||||
|
deviceData = "<device_data>".asText(),
|
||||||
|
ciData = "\n<ci_info>".asText(),
|
||||||
isSubmitCrashLogsEnabled = false,
|
isSubmitCrashLogsEnabled = false,
|
||||||
copyrightInfo = "© Bitwarden Inc. 2015-"
|
copyrightInfo = "© Bitwarden Inc. 2015-${Year.now(fixedClock).value}".asText(),
|
||||||
.asText()
|
|
||||||
.concat(Year.now(fixedClock).value.toString().asText()),
|
|
||||||
shouldShowCrashLogsButton = true,
|
shouldShowCrashLogsButton = true,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package com.x8bit.bitwarden.ui.platform.util
|
||||||
|
|
||||||
|
import android.os.Build
|
||||||
|
import com.x8bit.bitwarden.BuildConfig
|
||||||
|
import com.x8bit.bitwarden.data.platform.util.deviceData
|
||||||
|
import com.x8bit.bitwarden.data.platform.util.versionData
|
||||||
|
import org.junit.jupiter.api.Assertions.assertEquals
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
|
||||||
|
class BuildConfigTest {
|
||||||
|
@Test
|
||||||
|
fun `deviceData should be formatted correctly`() {
|
||||||
|
val deviceBrandModel = "\uD83D\uDCF1 ${Build.BRAND} ${Build.MODEL}"
|
||||||
|
val osInfo = "\uD83E\uDD16 ${Build.VERSION.RELEASE}@${Build.VERSION.SDK_INT}"
|
||||||
|
val buildInfo = "\uD83D\uDCE6 dev"
|
||||||
|
|
||||||
|
assertEquals("$deviceBrandModel $osInfo $buildInfo", deviceData)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `versionData should be formatted correctly`() {
|
||||||
|
val versionName = BuildConfig.VERSION_NAME
|
||||||
|
val versionCode = BuildConfig.VERSION_CODE
|
||||||
|
|
||||||
|
assertEquals("$versionName ($versionCode)", versionData)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user