diff --git a/app/src/main/java/org/session/libsession/messaging/sending_receiving/MessageParser.kt b/app/src/main/java/org/session/libsession/messaging/sending_receiving/MessageParser.kt index cbe29d8eda..f20f47912a 100644 --- a/app/src/main/java/org/session/libsession/messaging/sending_receiving/MessageParser.kt +++ b/app/src/main/java/org/session/libsession/messaging/sending_receiving/MessageParser.kt @@ -21,7 +21,6 @@ import org.session.libsession.messaging.open_groups.OpenGroupApi import org.session.libsession.network.SnodeClock import org.session.libsession.utilities.Address import org.session.libsession.utilities.ConfigFactoryProtocol -import org.session.libsession.utilities.TextSecurePreferences import org.session.libsession.utilities.withGroupConfigs import org.session.libsession.utilities.withUserConfigs import org.session.libsignal.exceptions.NonRetryableException @@ -42,7 +41,6 @@ class MessageParser @Inject constructor( private val configFactory: ConfigFactoryProtocol, private val storage: StorageProtocol, private val snodeClock: SnodeClock, - private val prefs: TextSecurePreferences, private val proBackendConfig: Provider, ) { @@ -142,13 +140,10 @@ class MessageParser @Inject constructor( message.receivedTimestamp = snodeClock.currentTimeMillis() message.isSenderSelf = isSenderSelf - // Only process pro features post pro launch - if (prefs.forcePostPro()) { - if (pro?.status == ProProof.STATUS_VALID) { - (message as? VisibleMessage)?.proFeatures = buildSet { - addAll(pro.proMessageFeatures.asSequence()) - addAll(pro.proProfileFeatures.asSequence()) - } + if (pro?.status == ProProof.STATUS_VALID) { + (message as? VisibleMessage)?.proFeatures = buildSet { + addAll(pro.proMessageFeatures.asSequence()) + addAll(pro.proProfileFeatures.asSequence()) } } diff --git a/app/src/main/java/org/session/libsession/utilities/TextSecurePreferences.kt b/app/src/main/java/org/session/libsession/utilities/TextSecurePreferences.kt index ae2dae46ec..d5251e5260 100644 --- a/app/src/main/java/org/session/libsession/utilities/TextSecurePreferences.kt +++ b/app/src/main/java/org/session/libsession/utilities/TextSecurePreferences.kt @@ -60,7 +60,6 @@ import org.session.libsession.utilities.TextSecurePreferences.Companion.SEND_WIT import org.session.libsession.utilities.TextSecurePreferences.Companion.SET_FORCE_CURRENT_USER_PRO import org.session.libsession.utilities.TextSecurePreferences.Companion.SET_FORCE_INCOMING_MESSAGE_PRO import org.session.libsession.utilities.TextSecurePreferences.Companion.SET_FORCE_OTHER_USERS_PRO -import org.session.libsession.utilities.TextSecurePreferences.Companion.SET_FORCE_POST_PRO import org.session.libsession.utilities.TextSecurePreferences.Companion.SHOWN_CALL_NOTIFICATION import org.session.libsession.utilities.TextSecurePreferences.Companion.SHOWN_CALL_WARNING import org.session.libsession.utilities.TextSecurePreferences.Companion.SHOW_DONATION_CTA_FROM_POSITIVE_REVIEW @@ -149,14 +148,11 @@ interface TextSecurePreferences { fun setForceOtherUsersAsPro(isPro: Boolean) fun forceIncomingMessagesAsPro(): Boolean fun setForceIncomingMessagesAsPro(isPro: Boolean) - fun forcePostPro(): Boolean - fun setForcePostPro(postPro: Boolean) fun hasSeenProExpiring(): Boolean fun setHasSeenProExpiring() fun hasSeenProExpired(): Boolean fun setHasSeenProExpired() fun clearProExpiryView() - fun watchPostProStatus(): StateFlow fun hasSeenSlowModeCallWarning(): Boolean fun setHasSeenSlowModeCallWarning(value: Boolean) fun setShownCallWarning(): Boolean @@ -304,7 +300,6 @@ interface TextSecurePreferences { const val SET_FORCE_CURRENT_USER_PRO = "pref_force_current_user_pro" const val SET_FORCE_OTHER_USERS_PRO = "pref_force_other_users_pro" const val SET_FORCE_INCOMING_MESSAGE_PRO = "pref_force_incoming_message_pro" - const val SET_FORCE_POST_PRO = "pref_force_post_pro" const val HAS_SEEN_PRO_EXPIRING = "has_seen_pro_expiring" const val HAS_SEEN_PRO_EXPIRED = "has_seen_pro_expired" const val SHOWN_SLOW_MODE_CALL_WARNING = "has_seen_slow_mode_call_warning" @@ -571,7 +566,6 @@ class AppTextSecurePreferences @Inject constructor( @param:ApplicationContext private val context: Context, private val json: Json, ): TextSecurePreferences { - private val postProLaunchState = MutableStateFlow(getBooleanPreference(SET_FORCE_POST_PRO, if (BuildConfig.BUILD_TYPE != "release") true else false)) private val hiddenPasswordState = MutableStateFlow(getBooleanPreference(HIDE_PASSWORD, false)) override var migratedToGroupV2Config: Boolean @@ -1010,16 +1004,6 @@ class AppTextSecurePreferences @Inject constructor( setBooleanPreference(SET_FORCE_INCOMING_MESSAGE_PRO, isPro) } - override fun forcePostPro(): Boolean { - return postProLaunchState.value - } - - override fun setForcePostPro(postPro: Boolean) { - setBooleanPreference(SET_FORCE_POST_PRO, postPro) - postProLaunchState.update { postPro } - _events.tryEmit(SET_FORCE_POST_PRO) - } - override fun hasSeenProExpiring(): Boolean { return getBooleanPreference(HAS_SEEN_PRO_EXPIRING, false) } @@ -1041,10 +1025,6 @@ class AppTextSecurePreferences @Inject constructor( setBooleanPreference(HAS_SEEN_PRO_EXPIRING, false) } - override fun watchPostProStatus(): StateFlow { - return postProLaunchState - } - override fun getFingerprintKeyGenerated(): Boolean { return getBooleanPreference(TextSecurePreferences.FINGERPRINT_KEY_GENERATED, false) } @@ -1148,7 +1128,6 @@ class AppTextSecurePreferences @Inject constructor( * Clear all prefs and reset our observables */ override fun clearAll() { - postProLaunchState.update { false } hiddenPasswordState.update { false } getDefaultSharedPreferences(context).edit(commit = true) { clear() } diff --git a/app/src/main/java/org/thoughtcrime/securesms/InputbarViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/InputbarViewModel.kt index a613132155..6df3180bda 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/InputbarViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/InputbarViewModel.kt @@ -42,7 +42,7 @@ abstract class InputbarViewModel( count = charsLeft, countFormatted = NumberUtil.getFormattedNumber(charsLeft.toLong()), danger = charsLeft < 0, - showProBadge = proStatusManager.isPostPro() && !currentUser.isPro // only show the badge for non pro users POST pro launch + showProBadge = !currentUser.isPro // only show the badge for non pro users ) } else { null @@ -56,9 +56,7 @@ abstract class InputbarViewModel( val charsLeft = _inputBarState.value.charLimitState?.count ?: 0 return if(charsLeft < 0){ // the user is trying to send a message that is too long - we should display a dialog - // we currently have different logic for PRE and POST Pro launch - // which we can remove once Pro is out - currently we can switch this fro the debug menu - if(!proStatusManager.isPostPro() || currentUser.isPro){ + if(currentUser.isPro){ showMessageTooLongSendDialog() } else { showSessionProCTA() @@ -71,9 +69,7 @@ abstract class InputbarViewModel( } fun onCharLimitTapped(){ - // we currently have different logic for PRE and POST Pro launch - // which we can remove once Pro is out - currently we can switch this fro the debug menu - if(!proStatusManager.isPostPro() || currentUser.isPro){ + if(currentUser.isPro){ handleCharLimitTappedForProUser() } else { handleCharLimitTappedForRegularUser() diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/RecipientRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/database/RecipientRepository.kt index dc10149c88..151a403aa0 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/RecipientRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/RecipientRepository.kt @@ -211,11 +211,7 @@ class RecipientRepository @Inject constructor( ): Pair?> { val now = snodeClock.get().currentTime() - val proDataContext = if (proStatusManager.get().postProLaunchStatus.value) { - ProDataContext() - } else { - null - } + val proDataContext = ProDataContext() // Fetch data from config first, this may contain partial information for some kind of recipient val configData = getDataFromConfig( @@ -482,8 +478,6 @@ class RecipientRepository @Inject constructor( } } - changeSources?.add(proStatusManager.get().postProLaunchStatus.drop(1)) - return updatedValue to changeSources?.let { merge(*it.toTypedArray()) } } @@ -554,11 +548,7 @@ class RecipientRepository @Inject constructor( settingsFetcher: (address: Address) -> RecipientSettings ): Recipient { // 1. Create a local context specifically for this member - val memberProDataContext = if (proStatusManager.get().postProLaunchStatus.value) { - ProDataContext() - } else { - null - } + val memberProDataContext = ProDataContext() // 2. Fetch the basic recipient data val rawRecipient = when (val configData = getDataFromConfig(member.address, memberProDataContext)) { @@ -603,11 +593,7 @@ class RecipientRepository @Inject constructor( settingsFetcher: (address: Address) -> RecipientSettings, ): Recipient { // 1. Create Local Context - val memberProDataContext = if (proStatusManager.get().postProLaunchStatus.value) { - ProDataContext() - } else { - null - } + val memberProDataContext = ProDataContext() // 2. Fetch Data val rawRecipient = when (val configData = getDataFromConfig(address, memberProDataContext)) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/debugmenu/DebugMenu.kt b/app/src/main/java/org/thoughtcrime/securesms/debugmenu/DebugMenu.kt index 8b04c5363f..84e96eb001 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/debugmenu/DebugMenu.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/debugmenu/DebugMenu.kt @@ -383,15 +383,6 @@ fun DebugMenu( } - Spacer(modifier = Modifier.height(LocalDimensions.current.xsSpacing)) - DebugSwitchRow( - text = "Set app as post Pro launch", - checked = uiState.forcePostPro, - onCheckedChange = { - sendCommand(DebugMenuViewModel.Commands.ForcePostPro(it)) - } - ) - Spacer(modifier = Modifier.height(LocalDimensions.current.xsSpacing)) DebugSwitchRow( text = "Set other users as Pro", @@ -963,7 +954,6 @@ fun PreviewDebugMenu() { forceCurrentUserAsPro = true, forceIncomingMessagesAsPro = true, forceOtherUsersAsPro = false, - forcePostPro = false, forceShortTTl = false, messageProFeature = setOf(ProMessageFeature.HIGHER_CHARACTER_LIMIT), dbInspectorState = DebugMenuViewModel.DatabaseInspectorState.STARTED, diff --git a/app/src/main/java/org/thoughtcrime/securesms/debugmenu/DebugMenuViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/debugmenu/DebugMenuViewModel.kt index 689e997412..536a120427 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/debugmenu/DebugMenuViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/debugmenu/DebugMenuViewModel.kt @@ -106,7 +106,6 @@ class DebugMenuViewModel @AssistedInject constructor( forceCurrentUserAsPro = textSecurePreferences.forceCurrentUserAsPro(), forceOtherUsersAsPro = textSecurePreferences.forceOtherUsersAsPro(), forceIncomingMessagesAsPro = textSecurePreferences.forceIncomingMessagesAsPro(), - forcePostPro = textSecurePreferences.forcePostPro(), forceShortTTl = textSecurePreferences.forcedShortTTL(), debugAvatarReupload = textSecurePreferences.debugAvatarReupload, messageProFeature = textSecurePreferences.getDebugMessageFeatures(), @@ -348,13 +347,6 @@ class DebugMenuViewModel @AssistedInject constructor( } } - is Commands.ForcePostPro -> { - textSecurePreferences.setForcePostPro(command.set) - _uiState.update { - it.copy(forcePostPro = command.set) - } - } - is Commands.ForceShortTTl -> { textSecurePreferences.setForcedShortTTL(command.set) _uiState.update { @@ -631,7 +623,6 @@ class DebugMenuViewModel @AssistedInject constructor( val forceOtherUsersAsPro: Boolean, val forceIncomingMessagesAsPro: Boolean, val messageProFeature: Set, - val forcePostPro: Boolean, val forceShortTTl: Boolean, val forceDeprecationState: LegacyGroupDeprecationManager.DeprecationState?, val debugAvatarReupload: Boolean, @@ -701,7 +692,6 @@ class DebugMenuViewModel @AssistedInject constructor( data class ForceIncomingMessagesAsPro(val set: Boolean) : Commands() data class ForceNoBilling(val set: Boolean) : Commands() data class WithinQuickRefund(val set: Boolean) : Commands() - data class ForcePostPro(val set: Boolean) : Commands() data class ForceShortTTl(val set: Boolean) : Commands() data class SetMessageProFeature(val feature: ProFeature, val set: Boolean) : Commands() data class ShowDeprecationChangeDialog(val state: LegacyGroupDeprecationManager.DeprecationState?) : Commands() diff --git a/app/src/main/java/org/thoughtcrime/securesms/preferences/SettingsScreen.kt b/app/src/main/java/org/thoughtcrime/securesms/preferences/SettingsScreen.kt index d0a0dd6d77..79c5c05a40 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/preferences/SettingsScreen.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/preferences/SettingsScreen.kt @@ -314,7 +314,6 @@ fun Settings( Buttons( recoveryHidden = uiState.recoveryHidden, pathStatus = uiState.pathStatus, - postPro = uiState.isPostPro, proDataState = uiState.proDataState, sendCommand = sendCommand ) @@ -398,7 +397,6 @@ fun Settings( AvatarDialog( state = uiState.avatarDialogState, isPro = uiState.proDataState.type is ProStatus.Active, - isPostPro = uiState.isPostPro, sendCommand = sendCommand, startAvatarSelection = startAvatarSelection ) @@ -537,7 +535,6 @@ fun Settings( fun Buttons( recoveryHidden: Boolean, pathStatus: PathStatus, - postPro: Boolean, proDataState: ProDataState, sendCommand: (SettingsViewModel.Commands) -> Unit, ) { @@ -580,10 +577,9 @@ fun Buttons( Cell { Column { - if(postPro){ - ItemButton( - text = annotatedStringResource( - when (proDataState.type) { + ItemButton( + text = annotatedStringResource( + when (proDataState.type) { is ProStatus.Active -> Phrase.from( LocalContext.current, R.string.sessionProBeta @@ -618,7 +614,6 @@ fun Buttons( } Divider() - } // Invite a friend ItemButton( @@ -921,7 +916,6 @@ fun AvatarOption( fun AvatarDialog( state: SettingsViewModel.AvatarDialogState, isPro: Boolean, - isPostPro: Boolean, sendCommand: (SettingsViewModel.Commands) -> Unit, startAvatarSelection: () -> Unit, ){ @@ -934,22 +928,20 @@ fun AvatarDialog( // custom content that has the displayed images // animated Pro title - if(isPostPro){ - ProBadgeText( - modifier = Modifier - .padding( - top = LocalDimensions.current.xxxsSpacing, - bottom = LocalDimensions.current.xsSpacing, - ) - .clickable { - sendCommand(ShowAnimatedProCTA) - }, - text = stringResource(if(isPro) R.string.proAnimatedDisplayPictureModalDescription - else R.string.proAnimatedDisplayPicturesNonProModalDescription), - textStyle = LocalType.current.base.copy(color = LocalColors.current.textSecondary), - badgeAtStart = isPro - ) - } + ProBadgeText( + modifier = Modifier + .padding( + top = LocalDimensions.current.xxxsSpacing, + bottom = LocalDimensions.current.xsSpacing, + ) + .clickable { + sendCommand(ShowAnimatedProCTA) + }, + text = stringResource(if(isPro) R.string.proAnimatedDisplayPictureModalDescription + else R.string.proAnimatedDisplayPicturesNonProModalDescription), + textStyle = LocalType.current.base.copy(color = LocalColors.current.textSecondary), + badgeAtStart = isPro + ) // main container that control the overall size and adds the rounded bg Box( @@ -1069,7 +1061,6 @@ private fun SettingsScreenPreview() { ) ) ), - isPostPro = true, proDataState = ProDataState( type = previewAutoRenewingApple, refreshState = State.Success(Unit), @@ -1099,7 +1090,6 @@ fun PreviewAvatarDialog( AvatarDialog( state = SettingsViewModel.AvatarDialogState.NoAvatar, isPro = false, - isPostPro = false, sendCommand = {}, startAvatarSelection = {} ) diff --git a/app/src/main/java/org/thoughtcrime/securesms/preferences/SettingsViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/preferences/SettingsViewModel.kt index 82342e4828..984fe48edf 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/preferences/SettingsViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/preferences/SettingsViewModel.kt @@ -114,7 +114,6 @@ class SettingsViewModel @Inject constructor( pathStatus = PathStatus.BUILDING, version = getVersionNumber(), recoveryHidden = prefs.getHidePassword(), - isPostPro = proStatusManager.isPostPro(), proDataState = getDefaultSubscriptionStateData(), )) val uiState: StateFlow @@ -145,12 +144,6 @@ class SettingsViewModel @Inject constructor( _uiState.update { it.copy(avatarDialogState = getDefaultAvatarDialogState()) } } - viewModelScope.launch { - proStatusManager.postProLaunchStatus.collect { postPro -> - _uiState.update { it.copy(isPostPro = postPro) } - } - } - viewModelScope.launch { prefs.watchHidePassword().collect { hidden -> _uiState.update { it.copy(recoveryHidden = hidden) } @@ -287,7 +280,7 @@ class SettingsViewModel @Inject constructor( ?: return Toast.makeText(context, R.string.profileErrorUpdate, Toast.LENGTH_LONG).show() // if the selected avatar is animated but the user isn't pro, show the animated pro CTA - if (tempAvatar.isAnimated && !selfRecipient.value.isPro && proStatusManager.isPostPro()) { + if (tempAvatar.isAnimated && !selfRecipient.value.isPro) { showAnimatedProCTA() return } @@ -381,11 +374,9 @@ class SettingsViewModel @Inject constructor( fun hasNetworkConnection(): Boolean = connectivity.networkAvailable.value - fun isAnimated(uri: Uri): Boolean = proStatusManager.isPostPro() // block animated avatars prior to pro - && AnimatedImageUtils.isAnimated(context, uri) + fun isAnimated(uri: Uri): Boolean = AnimatedImageUtils.isAnimated(context, uri) - fun isAnimated(rawImageData: ByteArray): Boolean = proStatusManager.isPostPro() // block animated avatars prior to pro - && AnimatedImageUtils.isAnimated(rawImageData) + fun isAnimated(rawImageData: ByteArray): Boolean = AnimatedImageUtils.isAnimated(rawImageData) private fun showAnimatedProCTA() { // show the right CTA based on pro state @@ -711,7 +702,6 @@ class SettingsViewModel @Inject constructor( val avatarCTAState: AvatarCTAState = AvatarCTAState.Hidden, val usernameDialog: UsernameDialogData? = null, val showSimpleDialog: SimpleDialogData? = null, - val isPostPro: Boolean, val proDataState: ProDataState, ) diff --git a/app/src/main/java/org/thoughtcrime/securesms/pro/FetchProStatusWorker.kt b/app/src/main/java/org/thoughtcrime/securesms/pro/FetchProStatusWorker.kt index 227e6be44e..ae81b2c296 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/pro/FetchProStatusWorker.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/pro/FetchProStatusWorker.kt @@ -20,7 +20,6 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.mapNotNull import org.session.libsession.network.SnodeClock import org.session.libsession.utilities.ConfigFactoryProtocol -import org.session.libsession.utilities.TextSecurePreferences import org.session.libsession.utilities.withMutableUserConfigs import org.session.libsession.utilities.withUserConfigs import org.session.libsignal.exceptions.NonRetryableException @@ -55,14 +54,8 @@ class FetchProStatusWorker @AssistedInject constructor( private val loginStateRepository: LoginStateRepository, private val snodeClock: SnodeClock, private val configFactory: ConfigFactoryProtocol, - private val prefs: TextSecurePreferences, ) : CoroutineWorker(context, params) { override suspend fun doWork(): Result { - if (!prefs.forcePostPro()) { - Log.d(TAG, "Pro status fetch skipped because pro is not enabled") - return Result.success() - } - val proMasterKey = requireNotNull(loginStateRepository.peekLoginState()?.seeded?.proMasterPrivateKey) { "User must be logged in to fetch pro status" diff --git a/app/src/main/java/org/thoughtcrime/securesms/pro/ProStatusManager.kt b/app/src/main/java/org/thoughtcrime/securesms/pro/ProStatusManager.kt index 455397ca39..4f22d1ec53 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/pro/ProStatusManager.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/pro/ProStatusManager.kt @@ -10,7 +10,6 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.collectLatest @@ -27,7 +26,6 @@ import kotlinx.coroutines.flow.merge import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.transformLatest -import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import kotlinx.coroutines.supervisorScope import kotlinx.coroutines.withTimeoutOrNull @@ -228,28 +226,9 @@ class ProStatusManager @Inject constructor( initialValue = getDefaultSubscriptionStateData() ) - private val _postProLaunchStatus = MutableStateFlow(isPostPro()) - val postProLaunchStatus: StateFlow = _postProLaunchStatus - - - init { - scope.launch { - prefs.watchPostProStatus().collect { - _postProLaunchStatus.update { isPostPro() } - } - } - } - override suspend fun doWhileLoggedIn(loggedInState: LoggedInState): Unit = supervisorScope { launch { - postProLaunchStatus - .collectLatest { postLaunch -> - if (postLaunch) { - RevocationListPollingWorker.schedule(application) - } else { - RevocationListPollingWorker.cancel(application) - } - } + RevocationListPollingWorker.schedule(application) } launch { manageOtherPeoplePro() } @@ -264,145 +243,128 @@ class ProStatusManager @Inject constructor( } private suspend fun manageOtherPeoplePro() { - postProLaunchStatus.collectLatest { postLaunch -> - if (postLaunch) { - merge( - configFactory.get().userConfigsChanged(EnumSet.of(UserConfigType.CONVO_INFO_VOLATILE)), - proDatabase.revocationChangeNotification, - ).onStart { emit(Unit) } - .collect { - // Go through all convo's pro proof and remove the ones that are revoked - val revokedConversations = configFactory.get() - .withUserConfigs { it.convoInfoVolatile.all() } - .asSequence() - .filterIsInstance() - .filter { convo -> - convo.proProofInfo?.revocationTag?.let { proDatabase.isRevoked(it.data.toHexString(), snodeClock.currentTime()) } == true - } - .onEach { convo -> - convo.proProofInfo = null + merge( + configFactory.get().userConfigsChanged(EnumSet.of(UserConfigType.CONVO_INFO_VOLATILE)), + proDatabase.revocationChangeNotification, + ).onStart { emit(Unit) } + .collect { + // Go through all convo's pro proof and remove the ones that are revoked + val revokedConversations = configFactory.get() + .withUserConfigs { it.convoInfoVolatile.all() } + .asSequence() + .filterIsInstance() + .filter { convo -> + convo.proProofInfo?.revocationTag?.let { proDatabase.isRevoked(it.data.toHexString(), snodeClock.currentTime()) } == true + } + .onEach { convo -> + convo.proProofInfo = null + } + .toList() + + if (revokedConversations.isNotEmpty()) { + Log.d( + DebugLogGroup.PRO_DATA.label, + "Clearing Pro proof info for ${revokedConversations.size} conversations due to revocation" + ) + + configFactory.get() + .withMutableUserConfigs { configs -> + for (convo in revokedConversations) { + configs.convoInfoVolatile.set(convo) } - .toList() - - if (revokedConversations.isNotEmpty()) { - Log.d( - DebugLogGroup.PRO_DATA.label, - "Clearing Pro proof info for ${revokedConversations.size} conversations due to revocation" - ) - - configFactory.get() - .withMutableUserConfigs { configs -> - for (convo in revokedConversations) { - configs.convoInfoVolatile.set(convo) - } - } } - } + } } - } - } @OptIn(FlowPreview::class) private suspend fun manageProStatusRefreshScheduling() { - postProLaunchStatus - .collectLatest { postLaunch -> - if (postLaunch) { - merge( - configFactory.get() - .userConfigsChanged(EnumSet.of(UserConfigType.USER_PROFILE)) - .map { - configFactory.get().withUserConfigs { configs -> - // Watch both the access expiry (E) and the prepaid marker (I): a - // synced prepaid from another device's purchase must kick the - // redemption poll here too, so any device can pull the entitlement - // through even if the purchasing device goes offline before redeeming. - configs.userProfile.getProAccessExpiry() to - configs.userProfile.getProPrepaid() - } - } - .distinctUntilChanged() - .map { "ProAccessExpiry/prepaid in config changes" }, - - proStatusRepository.get().loadState - .mapNotNull { it.lastUpdated?.first?.expiry } - .distinctUntilChanged() - .transformLatest { expiry -> - // Schedule a refresh for 30 seconds after access expiry - if (snodeClock.delayUntil(expiry.plusSeconds(30))) { - emit("30 seconds after Access expiry reached") - } - }, - - configFactory.get() - .watchUserProConfig() - .filterNotNull() - .distinctUntilChanged() - .mapLatest { proConfig -> - val expiry = Instant.ofEpochSecond(proConfig.proProof.expirySeconds) - // Wake ~1h before proof expiry so the renewal path runs. Deterministic - // (no client-side jitter): per-device random offsets leak device count - // via the landed-renewal order statistic; libsession owns the timing - // (renewal_target), and config resolution settles concurrent renewals. - val refreshTime = expiry.minus(Duration.ofMinutes(60)) - - snodeClock.delayUntil(refreshTime) - "Pro proof expiry reached" - }, - - flowOf("App starting up") - ).debounce(500.milliseconds) - .collect { refreshReason -> - Log.d( - DebugLogGroup.PRO_SUBSCRIPTION.label, - "Scheduling ProStatus fetch due to: $refreshReason" - ) - - proStatusRepository.get().requestRefresh(force = true) - } - } else { - FetchProStatusWorker.cancel(application) + merge( + configFactory.get() + .userConfigsChanged(EnumSet.of(UserConfigType.USER_PROFILE)) + .map { + configFactory.get().withUserConfigs { configs -> + // Watch both the access expiry (E) and the prepaid marker (I): a + // synced prepaid from another device's purchase must kick the + // redemption poll here too, so any device can pull the entitlement + // through even if the purchasing device goes offline before redeeming. + configs.userProfile.getProAccessExpiry() to + configs.userProfile.getProPrepaid() + } } + .distinctUntilChanged() + .map { "ProAccessExpiry/prepaid in config changes" }, + + proStatusRepository.get().loadState + .mapNotNull { it.lastUpdated?.first?.expiry } + .distinctUntilChanged() + .transformLatest { expiry -> + // Schedule a refresh for 30 seconds after access expiry + if (snodeClock.delayUntil(expiry.plusSeconds(30))) { + emit("30 seconds after Access expiry reached") + } + }, + + configFactory.get() + .watchUserProConfig() + .filterNotNull() + .distinctUntilChanged() + .mapLatest { proConfig -> + val expiry = Instant.ofEpochSecond(proConfig.proProof.expirySeconds) + // Wake ~1h before proof expiry so the renewal path runs. Deterministic + // (no client-side jitter): per-device random offsets leak device count + // via the landed-renewal order statistic; libsession owns the timing + // (renewal_target), and config resolution settles concurrent renewals. + val refreshTime = expiry.minus(Duration.ofMinutes(60)) + + snodeClock.delayUntil(refreshTime) + "Pro proof expiry reached" + }, + + flowOf("App starting up") + ).debounce(500.milliseconds) + .collect { refreshReason -> + Log.d( + DebugLogGroup.PRO_SUBSCRIPTION.label, + "Scheduling ProStatus fetch due to: $refreshReason" + ) + + proStatusRepository.get().requestRefresh(force = true) } } private suspend fun manageCurrentProProofRevocation() { - postProLaunchStatus.collectLatest { postLaunch -> - if (postLaunch) { - combine( - configFactory.get() - .watchUserProConfig() - .mapNotNull { it?.proProof?.revocationTagHex }, + combine( + configFactory.get() + .watchUserProConfig() + .mapNotNull { it?.proProof?.revocationTagHex }, - proDatabase.revocationChangeNotification - .onStart { emit(Unit) }, + proDatabase.revocationChangeNotification + .onStart { emit(Unit) }, - { proofRevocationTag, _ -> - proofRevocationTag.takeIf { proDatabase.isRevoked(it, snodeClock.currentTime()) } - } - ) - .filterNotNull() - .collectLatest { revokedHash -> - configFactory.get().withMutableUserConfigs { configs -> - if (configs.userProfile.getProConfig()?.proProof?.revocationTagHex == revokedHash) { - Log.w( - DebugLogGroup.PRO_SUBSCRIPTION.label, - "Current Pro proof has been revoked, clearing Pro config" - ) - configs.userProfile.removeProConfig() - } - } + { proofRevocationTag, _ -> + proofRevocationTag.takeIf { proDatabase.isRevoked(it, snodeClock.currentTime()) } + } + ) + .filterNotNull() + .collectLatest { revokedHash -> + configFactory.get().withMutableUserConfigs { configs -> + if (configs.userProfile.getProConfig()?.proProof?.revocationTagHex == revokedHash) { + Log.w( + DebugLogGroup.PRO_SUBSCRIPTION.label, + "Current Pro proof has been revoked, clearing Pro config" + ) + configs.userProfile.removeProConfig() } + } } - } - } /** * Logic to determine if we should animate the avatar for a user or freeze it on the first frame */ fun freezeFrameForUser(recipient: Recipient): Boolean{ - return if(!isPostPro() || recipient.isCommunityRecipient) false else !recipient.isPro + return if(recipient.isCommunityRecipient) false else !recipient.isPro } /** @@ -410,8 +372,7 @@ class ProStatusManager @Inject constructor( */ fun getIncomingMessageMaxLength(message: VisibleMessage): Int { // if the debug is set, return that - // of if we are in pre-pro world - if (prefs.forceIncomingMessagesAsPro() || !isPostPro()) return MAX_CHARACTER_PRO + if (prefs.forceIncomingMessagesAsPro()) return MAX_CHARACTER_PRO if (message.proFeatures.contains(ProMessageFeature.HIGHER_CHARACTER_LIMIT)) { return MAX_CHARACTER_PRO @@ -420,18 +381,11 @@ class ProStatusManager @Inject constructor( return MAX_CHARACTER_REGULAR } - // Temporary method and concept that we should remove once Pro is out - fun isPostPro(): Boolean { - return prefs.forcePostPro() - } - fun getCharacterLimit(isPro: Boolean): Int { return if (isPro) MAX_CHARACTER_PRO else MAX_CHARACTER_REGULAR } fun getPinnedConversationLimit(isPro: Boolean): Int { - if(!isPostPro()) return Int.MAX_VALUE // allow infinite pins while not in post Pro - return if (isPro) Int.MAX_VALUE else MAX_PIN_REGULAR } diff --git a/app/src/main/java/org/thoughtcrime/securesms/pro/ProStatusRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/pro/ProStatusRepository.kt index 88ee3987c4..f7d06dae71 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/pro/ProStatusRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/pro/ProStatusRepository.kt @@ -12,7 +12,6 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.stateIn import org.session.libsession.network.SnodeClock -import org.session.libsession.utilities.TextSecurePreferences import org.session.libsignal.utilities.Log import org.thoughtcrime.securesms.auth.LoginStateRepository import org.thoughtcrime.securesms.debugmenu.DebugLogGroup @@ -31,7 +30,6 @@ class ProStatusRepository @Inject constructor( private val snodeClock: SnodeClock, @ManagerScope scope: CoroutineScope, loginStateRepository: LoginStateRepository, - private val prefs: TextSecurePreferences, private val networkConnectivity: NetworkConnectivity, ) { sealed interface LoadState { @@ -89,11 +87,6 @@ class ProStatusRepository @Inject constructor( * made regardless of the freshness of the last update. */ fun requestRefresh(force: Boolean = false) { - if (!prefs.forcePostPro()) { - Log.d(DebugLogGroup.PRO_DATA.label, "Pro hasn't been enabled, skipping refresh") - return - } - val currentState = loadState.value if (!force && (currentState is LoadState.Loading || currentState is LoadState.Loaded) && currentState.lastUpdated?.second?.plusSeconds(MIN_UPDATE_INTERVAL_SECONDS) diff --git a/app/src/main/java/org/thoughtcrime/securesms/repository/DefaultConversationRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/repository/DefaultConversationRepository.kt index c2428adb94..a63776362a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/repository/DefaultConversationRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/repository/DefaultConversationRepository.kt @@ -185,7 +185,6 @@ class DefaultConversationRepository @Inject constructor( TextSecurePreferences.Companion.events.filter { it == TextSecurePreferences.Companion.SET_FORCE_OTHER_USERS_PRO || it == TextSecurePreferences.Companion.SET_FORCE_CURRENT_USER_PRO - it == TextSecurePreferences.Companion.SET_FORCE_POST_PRO } ).debounce(500) .onStart { emit(allAddresses) }