Dodaj aktualizacje aplikacji kierowcy przez Google Play
This commit is contained in:
@@ -130,6 +130,8 @@ dependencies {
|
||||
implementation(libs.okhttp.logging)
|
||||
implementation(libs.play.services.auth)
|
||||
implementation(libs.play.services.auth.api.phone)
|
||||
implementation(libs.play.app.update)
|
||||
implementation(libs.play.app.update.ktx)
|
||||
implementation(libs.retrofit)
|
||||
implementation(libs.retrofit.gson)
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package pl.firmatpp.kierowca
|
||||
import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
@@ -11,17 +12,33 @@ import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import pl.firmatpp.kierowca.ui.DriverApp
|
||||
import pl.firmatpp.kierowca.ui.DriverViewModel
|
||||
import pl.firmatpp.kierowca.ui.theme.TppKierowcaTheme
|
||||
import pl.firmatpp.kierowca.update.PlayAppUpdateState
|
||||
import pl.firmatpp.kierowca.update.PlayInAppUpdateController
|
||||
|
||||
class MainActivity : ComponentActivity() {
|
||||
private var notificationRouteId by mutableStateOf<String?>(null)
|
||||
private var notificationRouteTarget by mutableStateOf<String?>(null)
|
||||
private var notificationLeaveRequestId by mutableStateOf<String?>(null)
|
||||
private var playAppUpdateState by mutableStateOf(PlayAppUpdateState())
|
||||
private lateinit var playInAppUpdates: PlayInAppUpdateController
|
||||
private val appUpdateLauncher = registerForActivityResult(
|
||||
ActivityResultContracts.StartIntentSenderForResult(),
|
||||
) { result ->
|
||||
if (::playInAppUpdates.isInitialized) {
|
||||
playInAppUpdates.onUpdateFlowResult(result.resultCode)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
notificationRouteId = intent.getStringExtra(EXTRA_ROUTE_ID)
|
||||
notificationRouteTarget = intent.getStringExtra(EXTRA_ROUTE_TARGET)
|
||||
notificationLeaveRequestId = intent.getStringExtra(EXTRA_LEAVE_REQUEST_ID)
|
||||
playInAppUpdates = PlayInAppUpdateController(
|
||||
activity = this,
|
||||
launcher = appUpdateLauncher,
|
||||
onStateChanged = { playAppUpdateState = it },
|
||||
)
|
||||
setContent {
|
||||
val viewModel: DriverViewModel = viewModel()
|
||||
val state by viewModel.state.collectAsStateWithLifecycle()
|
||||
@@ -32,9 +49,27 @@ class MainActivity : ComponentActivity() {
|
||||
initialRouteId = notificationRouteId,
|
||||
initialRouteTarget = notificationRouteTarget,
|
||||
initialLeaveRequestId = notificationLeaveRequestId,
|
||||
playAppUpdateState = playAppUpdateState,
|
||||
onStartAppUpdate = playInAppUpdates::startUpdate,
|
||||
onCompleteAppUpdate = playInAppUpdates::completeDownloadedUpdate,
|
||||
)
|
||||
}
|
||||
}
|
||||
playInAppUpdates.checkForUpdate()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
if (::playInAppUpdates.isInitialized) {
|
||||
playInAppUpdates.checkForUpdate()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
if (::playInAppUpdates.isInitialized) {
|
||||
playInAppUpdates.dispose()
|
||||
}
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
override fun onNewIntent(intent: android.content.Intent) {
|
||||
|
||||
@@ -50,6 +50,16 @@ data class BootstrapResponse(
|
||||
val notificationPreferences: NotificationPreferencesDto? = null,
|
||||
val realtime: RealtimeConfigDto? = null,
|
||||
val syncState: SyncStateResponse? = null,
|
||||
val appUpdate: AppUpdateDto? = null,
|
||||
)
|
||||
|
||||
data class AppUpdateDto(
|
||||
val latestVersionCode: Int? = null,
|
||||
val latestVersionName: String? = null,
|
||||
val minimumSupportedVersionCode: Int = 0,
|
||||
val playStoreUrl: String? = null,
|
||||
val track: String? = null,
|
||||
val checkedAt: String? = null,
|
||||
)
|
||||
|
||||
data class DriverAppSettingsDto(
|
||||
|
||||
@@ -74,6 +74,7 @@ import androidx.compose.material.icons.outlined.Navigation
|
||||
import androidx.compose.material.icons.outlined.Person
|
||||
import androidx.compose.material.icons.outlined.Phone
|
||||
import androidx.compose.material.icons.outlined.Refresh
|
||||
import androidx.compose.material.icons.outlined.SystemUpdate
|
||||
import androidx.compose.material.ExperimentalMaterialApi
|
||||
import androidx.compose.material.pullrefresh.PullRefreshIndicator
|
||||
import androidx.compose.material.pullrefresh.pullRefresh
|
||||
@@ -149,6 +150,7 @@ import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import java.util.Locale
|
||||
import pl.firmatpp.kierowca.R
|
||||
import pl.firmatpp.kierowca.BuildConfig
|
||||
import pl.firmatpp.kierowca.data.PhotoUploadMetadata
|
||||
import pl.firmatpp.kierowca.data.model.DispatchSheetReminderDto
|
||||
import pl.firmatpp.kierowca.data.model.DriverLeaveCalendarEntryDto
|
||||
@@ -169,6 +171,7 @@ import pl.firmatpp.kierowca.domain.RouteDisplayMapper
|
||||
import pl.firmatpp.kierowca.domain.StartupSessionPolicy
|
||||
import pl.firmatpp.kierowca.ui.theme.AppThemeMode
|
||||
import pl.firmatpp.kierowca.ui.theme.TppTheme
|
||||
import pl.firmatpp.kierowca.update.PlayAppUpdateState
|
||||
|
||||
@Composable
|
||||
fun DriverApp(
|
||||
@@ -176,8 +179,27 @@ fun DriverApp(
|
||||
initialRouteId: String? = null,
|
||||
initialRouteTarget: String? = null,
|
||||
initialLeaveRequestId: String? = null,
|
||||
playAppUpdateState: PlayAppUpdateState = PlayAppUpdateState(),
|
||||
onStartAppUpdate: (required: Boolean, playStoreUrl: String?) -> Unit = { _, _ -> },
|
||||
onCompleteAppUpdate: () -> Unit = {},
|
||||
) {
|
||||
val state by viewModel.state.collectAsState()
|
||||
val updateUi = appUpdateBannerUi(
|
||||
currentVersionCode = BuildConfig.VERSION_CODE,
|
||||
latestVersionCode = state.appUpdate?.latestVersionCode,
|
||||
latestVersionName = state.appUpdate?.latestVersionName,
|
||||
minimumSupportedVersionCode = state.appUpdate?.minimumSupportedVersionCode ?: 0,
|
||||
playUpdateAvailable = playAppUpdateState.updateAvailable,
|
||||
playAvailableVersionCode = playAppUpdateState.availableVersionCode,
|
||||
updateDownloaded = playAppUpdateState.downloaded,
|
||||
)
|
||||
val runUpdate = {
|
||||
if (updateUi?.downloaded == true) {
|
||||
onCompleteAppUpdate()
|
||||
} else {
|
||||
onStartAppUpdate(updateUi?.required == true, state.appUpdate?.playStoreUrl)
|
||||
}
|
||||
}
|
||||
val lifecycleOwner = LocalLifecycleOwner.current
|
||||
val context = LocalContext.current
|
||||
var appInForeground by remember { mutableStateOf(true) }
|
||||
@@ -399,6 +421,80 @@ fun DriverApp(
|
||||
CircularProgressIndicator(color = TppTheme.colors.forest)
|
||||
}
|
||||
}
|
||||
|
||||
if (updateUi != null && !updateUi.required) {
|
||||
AppUpdateBanner(
|
||||
update = updateUi,
|
||||
onUpdate = runUpdate,
|
||||
modifier = Modifier
|
||||
.align(Alignment.TopCenter)
|
||||
.statusBarsPadding()
|
||||
.padding(horizontal = 12.dp, vertical = 8.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (updateUi?.required == true) {
|
||||
AlertDialog(
|
||||
onDismissRequest = {},
|
||||
title = {
|
||||
Text(
|
||||
"Wymagana aktualizacja",
|
||||
color = TppTheme.colors.ink,
|
||||
fontWeight = FontWeight.Bold,
|
||||
)
|
||||
},
|
||||
text = { Text(updateUi.message, color = TppTheme.colors.muted) },
|
||||
confirmButton = {
|
||||
Button(
|
||||
onClick = runUpdate,
|
||||
colors = ButtonDefaults.buttonColors(containerColor = TppTheme.colors.forest),
|
||||
) {
|
||||
Text(updateUi.actionLabel, color = Color.White, fontWeight = FontWeight.Bold)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun AppUpdateBanner(
|
||||
update: AppUpdateBannerUi,
|
||||
onUpdate: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Card(
|
||||
colors = CardDefaults.cardColors(containerColor = TppTheme.colors.warningContainer),
|
||||
border = BorderStroke(1.dp, TppTheme.colors.warningOutline),
|
||||
shape = MaterialTheme.shapes.medium,
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
) {
|
||||
Row(
|
||||
Modifier.fillMaxWidth().padding(14.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(12.dp),
|
||||
) {
|
||||
Box(
|
||||
Modifier.size(40.dp).background(Color.White, RoundedCornerShape(6.dp)),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Icon(Icons.Outlined.SystemUpdate, contentDescription = null, tint = TppTheme.colors.forest)
|
||||
}
|
||||
Text(
|
||||
update.message,
|
||||
color = Color(0xFF5F4200),
|
||||
fontWeight = FontWeight.Bold,
|
||||
modifier = Modifier.weight(1f),
|
||||
)
|
||||
Button(
|
||||
onClick = onUpdate,
|
||||
colors = ButtonDefaults.buttonColors(containerColor = TppTheme.colors.forest),
|
||||
shape = MaterialTheme.shapes.small,
|
||||
contentPadding = PaddingValues(horizontal = 14.dp, vertical = 10.dp),
|
||||
) {
|
||||
Text(update.actionLabel, color = Color.White, fontWeight = FontWeight.Bold)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,48 @@ data class NavigationIntentCandidate(
|
||||
val packageName: String? = null,
|
||||
)
|
||||
|
||||
data class AppUpdateBannerUi(
|
||||
val message: String,
|
||||
val actionLabel: String,
|
||||
val required: Boolean,
|
||||
val downloaded: Boolean,
|
||||
)
|
||||
|
||||
fun appUpdateBannerUi(
|
||||
currentVersionCode: Int,
|
||||
latestVersionCode: Int?,
|
||||
latestVersionName: String?,
|
||||
minimumSupportedVersionCode: Int,
|
||||
playUpdateAvailable: Boolean,
|
||||
playAvailableVersionCode: Int?,
|
||||
updateDownloaded: Boolean,
|
||||
): AppUpdateBannerUi? {
|
||||
val highestAvailableVersion = listOfNotNull(latestVersionCode, playAvailableVersionCode).maxOrNull()
|
||||
val required = minimumSupportedVersionCode > 0 && currentVersionCode < minimumSupportedVersionCode
|
||||
val available = updateDownloaded ||
|
||||
playUpdateAvailable ||
|
||||
highestAvailableVersion?.let { it > currentVersionCode } == true ||
|
||||
required
|
||||
if (!available) return null
|
||||
|
||||
val versionLabel = latestVersionName
|
||||
?.takeIf { it.isNotBlank() }
|
||||
?.let { " $it" }
|
||||
.orEmpty()
|
||||
val message = when {
|
||||
updateDownloaded -> "Aktualizacja$versionLabel jest pobrana i gotowa do instalacji."
|
||||
required -> "Ta wersja aplikacji nie jest już obsługiwana. Zaktualizuj ją, aby kontynuować."
|
||||
else -> "Dostępna jest nowa wersja aplikacji$versionLabel."
|
||||
}
|
||||
|
||||
return AppUpdateBannerUi(
|
||||
message = message,
|
||||
actionLabel = if (updateDownloaded) "Zainstaluj" else "Aktualizuj",
|
||||
required = required,
|
||||
downloaded = updateDownloaded,
|
||||
)
|
||||
}
|
||||
|
||||
fun hasValidNavigationCoordinates(latitude: Double?, longitude: Double?): Boolean =
|
||||
latitude != null &&
|
||||
longitude != null &&
|
||||
|
||||
@@ -24,6 +24,7 @@ import pl.firmatpp.kierowca.data.sync.DriverSyncRepository
|
||||
import pl.firmatpp.kierowca.data.sync.NetworkMonitor
|
||||
import pl.firmatpp.kierowca.data.sync.StartupOfflineFallbackLoader
|
||||
import pl.firmatpp.kierowca.data.model.DispatchSheetReminderDto
|
||||
import pl.firmatpp.kierowca.data.model.AppUpdateDto
|
||||
import pl.firmatpp.kierowca.data.model.DriverDto
|
||||
import pl.firmatpp.kierowca.data.model.DriverLeaveCalendarEntryDto
|
||||
import pl.firmatpp.kierowca.data.model.DriverLeaveRequestDto
|
||||
@@ -92,6 +93,7 @@ data class DriverUiState(
|
||||
val photoUploads: List<PhotoUploadEntity> = emptyList(),
|
||||
val queuedPhotoUploads: List<PhotoUploadEntity> = emptyList(),
|
||||
val dispatchSheetReminder: DispatchSheetReminderDto? = null,
|
||||
val appUpdate: AppUpdateDto? = null,
|
||||
val dispatchSheetUploads: List<DispatchSheetUploadEntity> = emptyList(),
|
||||
val leaveRequestsConfig: LeaveRequestsConfig? = null,
|
||||
val leaveRequests: List<DriverLeaveRequestDto> = emptyList(),
|
||||
@@ -422,6 +424,7 @@ class DriverViewModel(application: Application) : AndroidViewModel(application)
|
||||
driver = response.session.driver,
|
||||
routes = response.routes.today,
|
||||
dispatchSheetReminder = response.dispatchSheetReminder,
|
||||
appUpdate = response.appUpdate ?: it.appUpdate,
|
||||
selectedDate = settings?.selectedDate ?: date ?: it.selectedDate,
|
||||
minRouteDate = settings?.minDate ?: it.minRouteDate,
|
||||
maxRouteDate = settings?.maxDate ?: it.maxRouteDate,
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
package pl.firmatpp.kierowca.update
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.activity.result.IntentSenderRequest
|
||||
import com.google.android.play.core.appupdate.AppUpdateInfo
|
||||
import com.google.android.play.core.appupdate.AppUpdateManager
|
||||
import com.google.android.play.core.appupdate.AppUpdateManagerFactory
|
||||
import com.google.android.play.core.appupdate.AppUpdateOptions
|
||||
import com.google.android.play.core.install.InstallStateUpdatedListener
|
||||
import com.google.android.play.core.install.model.AppUpdateType
|
||||
import com.google.android.play.core.install.model.InstallStatus
|
||||
import com.google.android.play.core.install.model.UpdateAvailability
|
||||
|
||||
data class PlayAppUpdateState(
|
||||
val updateAvailable: Boolean = false,
|
||||
val availableVersionCode: Int? = null,
|
||||
val downloaded: Boolean = false,
|
||||
val checking: Boolean = false,
|
||||
)
|
||||
|
||||
class PlayInAppUpdateController(
|
||||
private val activity: ComponentActivity,
|
||||
private val launcher: ActivityResultLauncher<IntentSenderRequest>,
|
||||
private val onStateChanged: (PlayAppUpdateState) -> Unit,
|
||||
private val appUpdateManager: AppUpdateManager = AppUpdateManagerFactory.create(activity),
|
||||
) {
|
||||
private var state = PlayAppUpdateState()
|
||||
private val installStateListener = InstallStateUpdatedListener { installState ->
|
||||
when (installState.installStatus()) {
|
||||
InstallStatus.DOWNLOADED -> updateState(state.copy(downloaded = true, updateAvailable = true))
|
||||
InstallStatus.INSTALLED -> updateState(PlayAppUpdateState())
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
appUpdateManager.registerListener(installStateListener)
|
||||
}
|
||||
|
||||
fun checkForUpdate() {
|
||||
updateState(state.copy(checking = true))
|
||||
appUpdateManager.appUpdateInfo
|
||||
.addOnSuccessListener(::handleUpdateInfo)
|
||||
.addOnFailureListener { updateState(state.copy(checking = false)) }
|
||||
}
|
||||
|
||||
fun startUpdate(required: Boolean, playStoreUrl: String?) {
|
||||
appUpdateManager.appUpdateInfo
|
||||
.addOnSuccessListener { info ->
|
||||
if (info.updateAvailability() != UpdateAvailability.UPDATE_AVAILABLE) {
|
||||
openPlayStore(playStoreUrl)
|
||||
return@addOnSuccessListener
|
||||
}
|
||||
|
||||
val preferredType = if (required) AppUpdateType.IMMEDIATE else AppUpdateType.FLEXIBLE
|
||||
val updateType = when {
|
||||
info.isUpdateTypeAllowed(preferredType) -> preferredType
|
||||
info.isUpdateTypeAllowed(AppUpdateType.FLEXIBLE) -> AppUpdateType.FLEXIBLE
|
||||
info.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE) -> AppUpdateType.IMMEDIATE
|
||||
else -> null
|
||||
}
|
||||
|
||||
if (updateType == null || !launchUpdate(info, updateType)) {
|
||||
openPlayStore(playStoreUrl)
|
||||
}
|
||||
}
|
||||
.addOnFailureListener { openPlayStore(playStoreUrl) }
|
||||
}
|
||||
|
||||
fun completeDownloadedUpdate() {
|
||||
appUpdateManager.completeUpdate()
|
||||
}
|
||||
|
||||
fun onUpdateFlowResult(resultCode: Int) {
|
||||
if (resultCode != Activity.RESULT_OK) {
|
||||
checkForUpdate()
|
||||
}
|
||||
}
|
||||
|
||||
fun dispose() {
|
||||
appUpdateManager.unregisterListener(installStateListener)
|
||||
}
|
||||
|
||||
private fun handleUpdateInfo(info: AppUpdateInfo) {
|
||||
val downloaded = info.installStatus() == InstallStatus.DOWNLOADED
|
||||
val available = info.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE ||
|
||||
info.updateAvailability() == UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS ||
|
||||
downloaded
|
||||
|
||||
updateState(
|
||||
PlayAppUpdateState(
|
||||
updateAvailable = available,
|
||||
availableVersionCode = info.availableVersionCode().takeIf { it > 0 },
|
||||
downloaded = downloaded,
|
||||
checking = false,
|
||||
),
|
||||
)
|
||||
|
||||
if (
|
||||
info.updateAvailability() == UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS &&
|
||||
info.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)
|
||||
) {
|
||||
launchUpdate(info, AppUpdateType.IMMEDIATE)
|
||||
}
|
||||
}
|
||||
|
||||
private fun launchUpdate(info: AppUpdateInfo, updateType: Int): Boolean =
|
||||
appUpdateManager.startUpdateFlowForResult(
|
||||
info,
|
||||
launcher,
|
||||
AppUpdateOptions.newBuilder(updateType).build(),
|
||||
)
|
||||
|
||||
private fun openPlayStore(playStoreUrl: String?) {
|
||||
val packageName = activity.packageName
|
||||
val candidates = listOf(
|
||||
Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=$packageName")).setPackage("com.android.vending"),
|
||||
Intent(
|
||||
Intent.ACTION_VIEW,
|
||||
Uri.parse(playStoreUrl?.takeIf { it.isNotBlank() }
|
||||
?: "https://play.google.com/store/apps/details?id=$packageName"),
|
||||
),
|
||||
)
|
||||
|
||||
for (intent in candidates) {
|
||||
try {
|
||||
activity.startActivity(intent)
|
||||
return
|
||||
} catch (_: ActivityNotFoundException) {
|
||||
// Try the browser fallback.
|
||||
} catch (_: SecurityException) {
|
||||
// Try the browser fallback.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateState(next: PlayAppUpdateState) {
|
||||
state = next
|
||||
onStateChanged(next)
|
||||
}
|
||||
}
|
||||
@@ -115,6 +115,75 @@ class DriverUiRulesTest {
|
||||
assertTrue(navigationIntentCandidates(null, null, "Cel").isEmpty())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun showsAnOptionalUpdateWhenGooglePlayOrBackendHasANewerVersion() {
|
||||
val fromPlay = appUpdateBannerUi(
|
||||
currentVersionCode = 113,
|
||||
latestVersionCode = null,
|
||||
latestVersionName = null,
|
||||
minimumSupportedVersionCode = 0,
|
||||
playUpdateAvailable = true,
|
||||
playAvailableVersionCode = 114,
|
||||
updateDownloaded = false,
|
||||
)
|
||||
val fromBackend = appUpdateBannerUi(
|
||||
currentVersionCode = 113,
|
||||
latestVersionCode = 114,
|
||||
latestVersionName = "1.0.61",
|
||||
minimumSupportedVersionCode = 0,
|
||||
playUpdateAvailable = false,
|
||||
playAvailableVersionCode = null,
|
||||
updateDownloaded = false,
|
||||
)
|
||||
|
||||
assertEquals(false, fromPlay?.required)
|
||||
assertEquals("Aktualizuj", fromPlay?.actionLabel)
|
||||
assertEquals("Dostępna jest nowa wersja aplikacji 1.0.61.", fromBackend?.message)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun requiresAnUpdateOnlyBelowTheConfiguredMinimumVersion() {
|
||||
val required = appUpdateBannerUi(
|
||||
currentVersionCode = 111,
|
||||
latestVersionCode = 114,
|
||||
latestVersionName = "1.0.61",
|
||||
minimumSupportedVersionCode = 112,
|
||||
playUpdateAvailable = true,
|
||||
playAvailableVersionCode = 114,
|
||||
updateDownloaded = false,
|
||||
)
|
||||
val current = appUpdateBannerUi(
|
||||
currentVersionCode = 114,
|
||||
latestVersionCode = 114,
|
||||
latestVersionName = "1.0.61",
|
||||
minimumSupportedVersionCode = 112,
|
||||
playUpdateAvailable = false,
|
||||
playAvailableVersionCode = null,
|
||||
updateDownloaded = false,
|
||||
)
|
||||
|
||||
assertEquals(true, required?.required)
|
||||
assertTrue(required?.message?.contains("nie jest już obsługiwana") == true)
|
||||
assertEquals(null, current)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun downloadedUpdateUsesInstallAction() {
|
||||
val update = appUpdateBannerUi(
|
||||
currentVersionCode = 113,
|
||||
latestVersionCode = 114,
|
||||
latestVersionName = "1.0.61",
|
||||
minimumSupportedVersionCode = 0,
|
||||
playUpdateAvailable = true,
|
||||
playAvailableVersionCode = 114,
|
||||
updateDownloaded = true,
|
||||
)
|
||||
|
||||
assertEquals("Zainstaluj", update?.actionLabel)
|
||||
assertEquals(true, update?.downloaded)
|
||||
assertTrue(update?.message?.contains("gotowa do instalacji") == true)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun calculatesPhotoGridRowsForTwoColumnInlineGallery() {
|
||||
assertEquals(0, inlinePhotoGridRows(0))
|
||||
|
||||
Reference in New Issue
Block a user