Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import kotlinx.coroutines.withTimeout
import org.session.libsession.network.snode.SnodeDirectory
import org.session.libsignal.utilities.Log
import org.thoughtcrime.securesms.dependencies.ManagerScope
import org.thoughtcrime.securesms.dependencies.OnAppStartupComponent
import java.util.Date
import javax.inject.Inject
import javax.inject.Singleton
Expand All @@ -32,7 +33,7 @@ class SnodeClock @Inject constructor(
@param:ManagerScope private val scope: CoroutineScope,
private val snodeDirectory: SnodeDirectory,
private val snodeClient: Lazy<SnodeClient>,
) {
): OnAppStartupComponent {

private val instantState = MutableStateFlow<Instant?>(null)

Expand All @@ -46,6 +47,12 @@ class SnodeClock @Inject constructor(
// 10 Minutes in milliseconds
private val minSyncIntervalMs = 10 * 60 * 1000L

override fun onPostAppStarted() {
scope.launch {
resyncClock()
}
}

/**
* Resync by querying 3 random snodes and setting time to the median of their adjusted times.
* * Rules:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,6 @@ sealed interface RecipientData {
val expiryMode: ExpiryMode,
val members: List<GroupMemberInfo>,
val description: String?,
override val proData: ProData?,
override val firstMember: Recipient?, // Used primarily to assemble the profile picture for the group.
override val secondMember: Recipient?, // Used primarily to assemble the profile picture for the group.
) : RecipientData, GroupLike {
Expand All @@ -186,6 +185,7 @@ sealed interface RecipientData {
val kicked: Boolean get() = groupInfo.kicked
val destroyed: Boolean get() = groupInfo.destroyed
val shouldPoll: Boolean get() = groupInfo.shouldPoll
override val proData: ProData? get() = null //todo LARGE GROUP hiding group pro status until we enable large groups

override val profileUpdatedAt: Instant?
get() = null
Expand All @@ -198,7 +198,8 @@ sealed interface RecipientData {
return hasAdmin(user)
}

override fun setProData(proData: ProData): Group = copy(proData = proData)
//todo LARGE GROUP hiding group pro status until we enable large groups
override fun setProData(proData: ProData): Group = this //copy(proData = proData)
}

data class LegacyGroup(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,10 @@ package org.thoughtcrime.securesms

import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import com.squareup.phrase.Phrase
import network.loki.messenger.R
import org.session.libsession.utilities.NonTranslatableStringConstants
import org.session.libsession.utilities.StringSubstitutionConstants.APP_PRO_KEY
import org.thoughtcrime.securesms.ui.AlertDialog
import org.thoughtcrime.securesms.ui.CTAFeature
import org.thoughtcrime.securesms.ui.DialogButtonData
import org.thoughtcrime.securesms.ui.GetString
import org.thoughtcrime.securesms.ui.LongMessageProCTA
import org.thoughtcrime.securesms.ui.SimpleSessionProCTA
import org.thoughtcrime.securesms.ui.components.annotatedStringResource
import org.thoughtcrime.securesms.ui.theme.LocalColors
import org.thoughtcrime.securesms.ui.theme.SessionMaterialTheme
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ import org.thoughtcrime.securesms.MediaPreviewActivity
import org.thoughtcrime.securesms.ScreenLockActionBarActivity
import org.thoughtcrime.securesms.database.model.MessageId
import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader
import org.thoughtcrime.securesms.pro.ProStatus
import org.thoughtcrime.securesms.pro.ProStatusManager
import org.thoughtcrime.securesms.ui.AnimatedProfilePicProCTA
import org.thoughtcrime.securesms.ui.CTAFeature
Expand Down Expand Up @@ -720,7 +721,7 @@ fun MessageDetailDialogs(

is ProBadgeCTA.AnimatedProfile ->
AnimatedProfilePicProCTA(
proSubscription = state.proBadgeCTA.proSubscription,
expired = state.proBadgeCTA.proSubscription is ProStatus.Expired,
onDismissRequest = {sendCommand(Commands.HideProBadgeCTA)}
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -660,7 +660,8 @@ class RecipientRepository @Inject constructor(
avatar = configs.groupInfo.getProfilePic().toRemoteFile(),
expiryMode = configs.groupInfo.expiryMode,
name = configs.groupInfo.getName() ?: groupInfo.name,
proData = null, // final ProData will be calculated later
//todo LARGE GROUP hiding group pro status until we enable large groups
//proData = null, // final ProData will be calculated later
description = configs.groupInfo.getDescription(),
members = configs.groupMembers.all()
.asSequence()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.dependencies

import org.session.libsession.messaging.notifications.TokenFetcher
import org.session.libsession.messaging.sending_receiving.pollers.OpenGroupPollerManager
import org.session.libsession.network.SnodeClock
import org.thoughtcrime.securesms.auth.AuthAwareComponentsHandler
import org.thoughtcrime.securesms.database.ThreadDatabase
import org.thoughtcrime.securesms.disguise.AppDisguiseManager
Expand Down Expand Up @@ -43,6 +44,7 @@ class OnAppStartupComponents private constructor(
emojiIndexLoader: EmojiIndexLoader,
subscriptionCoordinator: SubscriptionCoordinator,
authAwareHandler: AuthAwareComponentsHandler,
snodeClock: SnodeClock,
subscriptionManagers: Set<@JvmSuppressWildcards SubscriptionManager>,
): this(
components = listOf(
Expand All @@ -62,6 +64,7 @@ class OnAppStartupComponents private constructor(
emojiIndexLoader,
subscriptionCoordinator,
authAwareHandler,
snodeClock
) + subscriptionManagers
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -408,11 +408,52 @@ fun Settings(
}

// Animated avatar CTA
if(uiState.showAnimatedProCTA){
AnimatedProCTA(
proSubscription = uiState.proDataState.type,
sendCommand = sendCommand
)
when(uiState.avatarCTAState){
is SettingsViewModel.AvatarCTAState.Pro -> {
SessionProCTA (
title = stringResource(R.string.proActivated),
badgeAtStart = true,
textContent = {
ProBadgeText(
modifier = Modifier.align(Alignment.CenterHorizontally),
text = stringResource(R.string.proAlreadyPurchased),
textStyle = LocalType.current.base.copy(color = LocalColors.current.textSecondary)
)

Spacer(Modifier.height(2.dp))

// main message
Text(
modifier = Modifier
.qaTag(R.string.qa_cta_body)
.align(Alignment.CenterHorizontally),
text = stringResource(R.string.proAnimatedDisplayPicture),
textAlign = TextAlign.Center,
style = LocalType.current.base.copy(
color = LocalColors.current.textSecondary
)
)
},
content = {
CTAAnimatedImages(
heroImageBg = R.drawable.cta_hero_animated_bg,
heroImageAnimatedFg = R.drawable.cta_hero_animated_fg,
)
},
positiveButtonText = null,
negativeButtonText = stringResource(R.string.close),
onCancel = { sendCommand(HideAnimatedProCTA) }
)
}

is SettingsViewModel.AvatarCTAState.NonPro -> {
AnimatedProfilePicProCTA(
expired = uiState.avatarCTAState.expired,
onDismissRequest = { sendCommand(HideAnimatedProCTA) },
)
}

else -> {}
}

// donate confirmation
Expand Down Expand Up @@ -1014,54 +1055,6 @@ fun AvatarDialog(
)
}

@Composable
fun AnimatedProCTA(
proSubscription: ProStatus,
sendCommand: (SettingsViewModel.Commands) -> Unit,
){
if(proSubscription is ProStatus.Active) {
SessionProCTA (
title = stringResource(R.string.proActivated),
badgeAtStart = true,
textContent = {
ProBadgeText(
modifier = Modifier.align(Alignment.CenterHorizontally),
text = stringResource(R.string.proAlreadyPurchased),
textStyle = LocalType.current.base.copy(color = LocalColors.current.textSecondary)
)

Spacer(Modifier.height(2.dp))

// main message
Text(
modifier = Modifier
.qaTag(R.string.qa_cta_body)
.align(Alignment.CenterHorizontally),
text = stringResource(R.string.proAnimatedDisplayPicture),
textAlign = TextAlign.Center,
style = LocalType.current.base.copy(
color = LocalColors.current.textSecondary
)
)
},
content = {
CTAAnimatedImages(
heroImageBg = R.drawable.cta_hero_animated_bg,
heroImageAnimatedFg = R.drawable.cta_hero_animated_fg,
)
},
positiveButtonText = null,
negativeButtonText = stringResource(R.string.close),
onCancel = { sendCommand(HideAnimatedProCTA) }
)
} else {
AnimatedProfilePicProCTA(
proSubscription = proSubscription,
onDismissRequest = { sendCommand(HideAnimatedProCTA) },
)
}
}

@OptIn(ExperimentalSharedTransitionApi::class)
@SuppressLint("UnusedContentLambdaTargetStateParameter")
@Preview
Expand All @@ -1077,7 +1070,7 @@ private fun SettingsScreenPreview() {
showAvatarDialog = false,
showAvatarPickerOptionCamera = false,
showAvatarPickerOptions = false,
showAnimatedProCTA = false,
avatarCTAState = SettingsViewModel.AvatarCTAState.Hidden,
avatarData = AvatarUIData(
listOf(
AvatarUIElement(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ import org.thoughtcrime.securesms.dependencies.ConfigFactory
import org.thoughtcrime.securesms.mms.MediaConstraints
import org.thoughtcrime.securesms.pro.ProDataState
import org.thoughtcrime.securesms.pro.ProDetailsRepository
import org.thoughtcrime.securesms.pro.ProStatus
import org.thoughtcrime.securesms.pro.ProStatusManager
import org.thoughtcrime.securesms.pro.getDefaultSubscriptionStateData
import org.thoughtcrime.securesms.reviews.InAppReviewManager
Expand Down Expand Up @@ -375,11 +376,21 @@ class SettingsViewModel @Inject constructor(
&& AnimatedImageUtils.isAnimated(rawImageData)

private fun showAnimatedProCTA() {
_uiState.update { it.copy(showAnimatedProCTA = true) }
// show the right CTA based on pro state
_uiState.update {
it.copy(
avatarCTAState =
if(it.proDataState.type is ProStatus.Active) AvatarCTAState.Pro
else AvatarCTAState.NonPro(
expired = it.proDataState.type is ProStatus.Expired
))
}
}

private fun hideAnimatedProCTA() {
_uiState.update { it.copy(showAnimatedProCTA = false) }
_uiState.update { it.copy(
avatarCTAState = AvatarCTAState.Hidden
) }
}

fun showAvatarDialog() {
Expand Down Expand Up @@ -672,13 +683,19 @@ class SettingsViewModel @Inject constructor(
val showAvatarDialog: Boolean = false,
val showAvatarPickerOptionCamera: Boolean = false,
val showAvatarPickerOptions: Boolean = false,
val showAnimatedProCTA: Boolean = false,
val avatarCTAState: AvatarCTAState = AvatarCTAState.Hidden,
val usernameDialog: UsernameDialogData? = null,
val showSimpleDialog: SimpleDialogData? = null,
val isPostPro: Boolean,
val proDataState: ProDataState,
)

sealed interface AvatarCTAState {
data object Hidden : AvatarCTAState
data object Pro : AvatarCTAState
data class NonPro(val expired: Boolean) : AvatarCTAState
}

sealed interface Commands {
data object ShowClearDataDialog: Commands
data object HideClearDataDialog: Commands
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ fun ProSettingsNavHost(
// handle the custom case of dealing with the post "choose plan confirmation"screen
ProNavHostCustomActions.ON_POST_PLAN_CONFIRMATION,
ProNavHostCustomActions.ON_POST_CANCELLATION -> {
// we get here where we either hit back or hit the "ok" button on the plan confirmation screen
// we get here when we either hit back or hit the "ok" button on the plan confirmation screen
// if we are in a sheet we need to close it
if (inSheet) {
onBack()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ import org.thoughtcrime.securesms.pro.isFromAnotherPlatform
import org.thoughtcrime.securesms.pro.subscription.ProSubscriptionDuration
import org.thoughtcrime.securesms.pro.subscription.SubscriptionCoordinator
import org.thoughtcrime.securesms.pro.subscription.SubscriptionManager
import org.thoughtcrime.securesms.pro.subscription.expiryFromNow
import org.thoughtcrime.securesms.ui.SimpleDialogData
import org.thoughtcrime.securesms.ui.UINavigator
import org.thoughtcrime.securesms.util.CurrencyFormatter
Expand Down Expand Up @@ -227,7 +226,7 @@ class ProSettingsViewModel @AssistedInject constructor(
else -> ""
},
subscriptionExpiryDate = when(subType){
is ProStatus.Active -> subType.duration.expiryFromNow(now)
is ProStatus.Active -> subType.validUntilFormatted()
else -> ""
},
)
Expand Down Expand Up @@ -526,7 +525,7 @@ class ProSettingsViewModel @AssistedInject constructor(
val selectedPlan = getSelectedPlan() ?: return

if(currentSubscription is ProStatus.Active){
val newSubscriptionExpiryString = selectedPlan.durationType.expiryFromNow()
val newSubscriptionExpiryString = currentSubscription.validUntilFormatted()

val currentSubscriptionDuration = DateUtils.getLocalisedTimeDuration(
context = context,
Expand All @@ -551,14 +550,14 @@ class ProSettingsViewModel @AssistedInject constructor(
.put(PRO_KEY, NonTranslatableStringConstants.PRO)
.put(DATE_KEY, newSubscriptionExpiryString)
.put(CURRENT_PLAN_LENGTH_KEY, currentSubscriptionDuration)
.put(SELECTED_PLAN_LENGTH_KEY, selectedSubscriptionDuration)
.put(SELECTED_PLAN_LENGTH_KEY, selectedSubscriptionDuration.lowercase())
// for this string below, we want to remove the 's' at the end if there is one: 12 Months becomes 12 Month
.put(SELECTED_PLAN_LENGTH_SINGULAR_KEY, selectedSubscriptionDuration.removeSuffix("s"))
.format()
else Phrase.from(context.getText(R.string.proUpdateAccessExpireDescription))
.put(PRO_KEY, NonTranslatableStringConstants.PRO)
.put(DATE_KEY, newSubscriptionExpiryString)
.put(SELECTED_PLAN_LENGTH_KEY, selectedSubscriptionDuration)
.put(SELECTED_PLAN_LENGTH_KEY, selectedSubscriptionDuration.lowercase())
.format(),
positiveText = context.getString(R.string.update),
negativeText = context.getString(R.string.cancel),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ import org.thoughtcrime.securesms.preferences.prosettings.ProSettingsViewModel.P
import org.thoughtcrime.securesms.preferences.prosettings.ProSettingsViewModel.ProPlanBadge
import org.thoughtcrime.securesms.pro.ProStatus
import org.thoughtcrime.securesms.pro.subscription.ProSubscriptionDuration
import org.thoughtcrime.securesms.pro.subscription.expiryFromNow
import org.thoughtcrime.securesms.ui.LoadingArcOr
import org.thoughtcrime.securesms.ui.SpeechBubbleTooltip
import org.thoughtcrime.securesms.ui.components.AccentFillButtonRect
Expand Down Expand Up @@ -111,7 +110,7 @@ fun ChoosePlan(
val title = when (planData.proStatus) {
is ProStatus.Active.Expiring -> Phrase.from(context.getText(R.string.proAccessActivatedNotAuto))
.put(PRO_KEY, NonTranslatableStringConstants.PRO)
.put(DATE_KEY, planData.proStatus.duration.expiryFromNow())
.put(DATE_KEY, planData.proStatus.validUntilFormatted())
.format()

is ProStatus.Active.AutoRenewing -> Phrase.from(context.getText(R.string.proAccessActivatesAuto))
Expand All @@ -123,7 +122,7 @@ fun ChoosePlan(
unit = MeasureUnit.MONTH
)
)
.put(DATE_KEY, planData.proStatus.duration.expiryFromNow())
.put(DATE_KEY, planData.proStatus.validUntilFormatted())
.format()

else ->
Expand Down
Loading