Add Banners to all reminder usages behind remote config.

This commit is contained in:
Nicholas Tinsley
2024-08-09 17:41:02 -04:00
committed by mtang-signal
parent f296fcd716
commit e2e6a73e8d
18 changed files with 253 additions and 62 deletions

View File

@@ -46,8 +46,8 @@ class CdsPermanentErrorBanner(private val fragmentManager: FragmentManager) : Ba
val PERMANENT_TIME_CUTOFF = 30.days.inWholeMilliseconds
@JvmStatic
fun createFlow(fragmentManager: FragmentManager): Flow<CdsPermanentErrorBanner> = createAndEmit {
CdsPermanentErrorBanner(fragmentManager)
fun createFlow(childFragmentManager: FragmentManager): Flow<CdsPermanentErrorBanner> = createAndEmit {
CdsPermanentErrorBanner(childFragmentManager)
}
}
}

View File

@@ -39,8 +39,8 @@ class CdsTemporaryErrorBanner(private val fragmentManager: FragmentManager) : Ba
companion object {
@JvmStatic
fun createFlow(fragmentManager: FragmentManager): Flow<CdsTemporaryErrorBanner> = createAndEmit {
CdsTemporaryErrorBanner(fragmentManager)
fun createFlow(childFragmentManager: FragmentManager): Flow<CdsTemporaryErrorBanner> = createAndEmit {
CdsTemporaryErrorBanner(childFragmentManager)
}
}
}

View File

@@ -7,7 +7,6 @@ package org.thoughtcrime.securesms.banner.banners
import android.content.Context
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import kotlinx.coroutines.flow.Flow
@@ -20,12 +19,15 @@ import org.thoughtcrime.securesms.util.PowerManagerCompat
import org.thoughtcrime.securesms.util.ServiceUtil
import org.thoughtcrime.securesms.util.TextSecurePreferences
@RequiresApi(23)
class DozeBanner(private val context: Context) : Banner() {
override val enabled: Boolean = !SignalStore.account.fcmEnabled && !TextSecurePreferences.hasPromptedOptimizeDoze(context) && Build.VERSION.SDK_INT >= 23 && !ServiceUtil.getPowerManager(context).isIgnoringBatteryOptimizations(context.packageName)
override val enabled: Boolean =
Build.VERSION.SDK_INT >= 23 && !SignalStore.account.fcmEnabled && !TextSecurePreferences.hasPromptedOptimizeDoze(context) && !ServiceUtil.getPowerManager(context).isIgnoringBatteryOptimizations(context.packageName)
@Composable
override fun DisplayBanner() {
if (Build.VERSION.SDK_INT < 23) {
throw IllegalStateException("Showing a Doze banner for an OS prior to Android 6.0")
}
DefaultBanner(
title = stringResource(id = R.string.DozeReminder_optimize_for_missing_play_services),
body = stringResource(id = R.string.DozeReminder_this_device_does_not_support_play_services_tap_to_disable_system_battery),
@@ -45,11 +47,7 @@ class DozeBanner(private val context: Context) : Banner() {
@JvmStatic
fun createFlow(context: Context): Flow<DozeBanner> = createAndEmit {
if (Build.VERSION.SDK_INT >= 23) {
DozeBanner(context)
} else {
null
}
DozeBanner(context)
}
}
}

View File

@@ -12,7 +12,7 @@ import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@@ -40,7 +40,9 @@ class MediaRestoreProgressBanner(private val data: MediaRestoreEvent) : Banner()
lifecycleOwner.lifecycle.addObserver(observer)
return observer.flow
} else {
return emptyFlow()
return flow {
emit(MediaRestoreProgressBanner(MediaRestoreEvent(0L, 0L)))
}
}
}
}

View File

@@ -22,22 +22,38 @@ import kotlin.time.Duration.Companion.milliseconds
/**
* Banner to let the user know their build is about to expire or has expired.
*
* @param status can be used to filter which conditions are shown.
*/
class OutdatedBuildBanner(val context: Context, private val daysUntilExpiry: Int) : Banner() {
class OutdatedBuildBanner(val context: Context, private val daysUntilExpiry: Int, private val status: ExpiryStatus) : Banner() {
override val enabled = SignalStore.misc.isClientDeprecated || daysUntilExpiry <= MAX_DAYS_UNTIL_EXPIRE
override val enabled = when (status) {
ExpiryStatus.OUTDATED_ONLY -> SignalStore.misc.isClientDeprecated
ExpiryStatus.EXPIRED_ONLY -> daysUntilExpiry <= MAX_DAYS_UNTIL_EXPIRE
ExpiryStatus.OUTDATED_OR_EXPIRED -> SignalStore.misc.isClientDeprecated || daysUntilExpiry <= MAX_DAYS_UNTIL_EXPIRE
}
@Composable
override fun DisplayBanner() {
DefaultBanner(
title = null,
body = if (SignalStore.misc.isClientDeprecated) {
val bodyText = when (status) {
ExpiryStatus.OUTDATED_ONLY -> if (daysUntilExpiry == 0) {
stringResource(id = R.string.OutdatedBuildReminder_your_version_of_signal_will_expire_today)
} else {
pluralStringResource(id = R.plurals.OutdatedBuildReminder_your_version_of_signal_will_expire_in_n_days, count = daysUntilExpiry, daysUntilExpiry)
}
ExpiryStatus.EXPIRED_ONLY -> stringResource(id = R.string.OutdatedBuildReminder_your_version_of_signal_will_expire_today)
ExpiryStatus.OUTDATED_OR_EXPIRED -> if (SignalStore.misc.isClientDeprecated) {
stringResource(id = R.string.OutdatedBuildReminder_your_version_of_signal_will_expire_today)
} else if (daysUntilExpiry == 0) {
stringResource(id = R.string.OutdatedBuildReminder_your_version_of_signal_will_expire_today)
} else {
pluralStringResource(id = R.plurals.OutdatedBuildReminder_your_version_of_signal_will_expire_in_n_days, count = daysUntilExpiry, daysUntilExpiry)
},
}
}
DefaultBanner(
title = null,
body = bodyText,
importance = if (SignalStore.misc.isClientDeprecated) {
Importance.ERROR
} else {
@@ -51,13 +67,25 @@ class OutdatedBuildBanner(val context: Context, private val daysUntilExpiry: Int
)
}
/**
* A enumeration for [OutdatedBuildBanner] to limit it to showing either [OUTDATED_ONLY] status, [EXPIRED_ONLY] status, or both.
*
* [OUTDATED_ONLY] refers to builds that are still valid but need to be updated.
* [EXPIRED_ONLY] refers to builds that are no longer allowed to connect to the service.
*/
enum class ExpiryStatus {
OUTDATED_ONLY,
EXPIRED_ONLY,
OUTDATED_OR_EXPIRED
}
companion object {
private const val MAX_DAYS_UNTIL_EXPIRE = 10
@JvmStatic
fun createFlow(context: Context): Flow<OutdatedBuildBanner> = createAndEmit {
fun createFlow(context: Context, status: ExpiryStatus): Flow<OutdatedBuildBanner> = createAndEmit {
val daysUntilExpiry = Util.getTimeUntilBuildExpiry(SignalStore.misc.estimatedServerTime).milliseconds.inWholeDays.toInt()
OutdatedBuildBanner(context, daysUntilExpiry)
OutdatedBuildBanner(context, daysUntilExpiry, status)
}
}
}

View File

@@ -9,7 +9,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.res.pluralStringResource
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.flow
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.banner.Banner
import org.thoughtcrime.securesms.banner.ui.compose.Action
@@ -33,14 +32,8 @@ class PendingGroupJoinRequestsBanner(override val enabled: Boolean, private val
)
}
companion object {
@JvmStatic
fun createFlow(suggestionsSize: Int, onViewClicked: () -> Unit): Flow<PendingGroupJoinRequestsBanner> = Producer(suggestionsSize, onViewClicked).flow
}
private class Producer(suggestionsSize: Int, onViewClicked: () -> Unit) {
val dismissListener: () -> Unit = {
class Producer(suggestionsSize: Int, onViewClicked: () -> Unit) {
private val dismissListener: () -> Unit = {
mutableStateFlow.tryEmit(PendingGroupJoinRequestsBanner(false, suggestionsSize, onViewClicked, null))
}
private val mutableStateFlow: MutableStateFlow<PendingGroupJoinRequestsBanner> = MutableStateFlow(PendingGroupJoinRequestsBanner(true, suggestionsSize, onViewClicked, dismissListener))

View File

@@ -46,6 +46,9 @@ class UsernameOutOfSyncBanner(private val context: Context, private val username
companion object {
/**
* @param onActionClick input is true if both the username and the link are corrupted, false if only the link is corrupted
*/
@JvmStatic
fun createFlow(context: Context, onActionClick: (Boolean) -> Unit): Flow<UsernameOutOfSyncBanner> = createAndEmit {
UsernameOutOfSyncBanner(context, SignalStore.account.usernameSyncState, onActionClick)