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
4 changes: 2 additions & 2 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ configurations.configureEach {
exclude(module = "commons-logging")
}

val canonicalVersionCode = 444
val canonicalVersionName = "1.32.1"
val canonicalVersionCode = 445
val canonicalVersionName = "1.32.2"

val postFixSize = 10
val abiPostFix = mapOf(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ class InviteContactsJob @AssistedInject constructor(
override var failureCount: Int = 0
override val maxFailureCount: Int = 1

private fun handleSuccess(dispatcherName: String) {
delegate?.handleJobSucceeded(this, dispatcherName)
}

override suspend fun execute(dispatcherName: String) {
val group = requireNotNull(configFactory.getGroup(AccountId(groupSessionId))) {
"Group must exist to invite"
Expand Down Expand Up @@ -118,8 +122,10 @@ class InviteContactsJob @AssistedInject constructor(
result.exceptionOrNull()?.let { err -> id to err }
}

// if there are failed invites, display a message
// assume job "success" even if we fail, the state of invites is tracked outside of this job
handleSuccess(dispatcherName)

// if there are failed invites, display a message
if (failures.isNotEmpty()) {
// show the failure toast
val (_, firstError) = failures.first()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,6 @@ object NonTranslatableStringConstants {
const val PRO = "Pro"
const val ENTITY_RANGEPROOF = "Rangeproof PTY LTD"
const val ENTITY_STF = "The Session Technology Foundation"
const val DONATE_APPEAL_NAME = "Cofounder of Session Chris McCabe"
}

Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,5 @@ object StringSubstitutionConstants {
const val ACTION_TYPE_KEY: StringSubKey = "action_type"
const val ACTIVATION_TYPE_KEY: StringSubKey = "activation_type"
const val ENTITY_KEY: StringSubKey = "entity"
const val DONATE_APPEAL_KEY: StringSubKey = "donate_appeal_name"
}
Original file line number Diff line number Diff line change
Expand Up @@ -406,11 +406,11 @@ interface TextSecurePreferences {
const val HAS_CHECKED_DOZE_WHITELIST = "has_checked_doze_whitelist"

// Donation
const val HAS_DONATED = "has_donated"
const val HAS_COPIED_DONATION_URL = "has_copied_donation_url"
const val SEEN_DONATION_CTA_AMOUNT = "seen_donation_cta_amount"
const val LAST_SEEN_DONATION_CTA = "last_seen_donation_cta"
const val SHOW_DONATION_CTA_FROM_POSITIVE_REVIEW = "show_donation_cta_from_positive_review"
const val HAS_DONATED = "has_donated_v2"
const val HAS_COPIED_DONATION_URL = "has_copied_donation_url_v2"
const val SEEN_DONATION_CTA_AMOUNT = "seen_donation_cta_amount_v2"
const val LAST_SEEN_DONATION_CTA = "last_seen_donation_cta_v2"
const val SHOW_DONATION_CTA_FROM_POSITIVE_REVIEW = "show_donation_cta_from_positive_review_v2"

const val DEBUG_HAS_DONATED = "debug_has_donated"
const val DEBUG_HAS_COPIED_DONATION_URL = "debug_has_copied_donation_url"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,11 @@ class ConversationReactionOverlay : FrameLayout {
updateBoundsOnLayoutChanged()
revealAnimatorSet.start()

val maxMenuY = maxOf(
systemInsets.top.toFloat(),
(height - systemInsets.bottom - actualMenuHeight).toFloat()
)

if (isWideLayout) {
val menuXInOverlay = if (isMessageOnLeft) {
// Menu to the RIGHT of the scrubber
Expand All @@ -359,8 +364,7 @@ class ConversationReactionOverlay : FrameLayout {
scrubberX - contextMenu.getMaxWidth() - menuPadding
}

val maxMenuYInOverlay = (height - systemInsets.bottom - actualMenuHeight).toFloat()
val menuYInOverlay = minOf(backgroundView.y, maxMenuYInOverlay)
val menuYInOverlay = minOf(backgroundView.y, maxMenuY)

// Convert overlay-local to anchor relative as expected by ConversationContextMenu.show()
val (xOffset, yOffset) = toAnchorOffsets(menuXInOverlay, menuYInOverlay)
Expand All @@ -377,7 +381,7 @@ class ConversationReactionOverlay : FrameLayout {
val menuYInOverlay = (menuTop + menuPadding)
.coerceIn(
systemInsets.top.toFloat(),
(height - systemInsets.bottom - actualMenuHeight).toFloat()
maxMenuY
)

val (xOffset, yOffset) = toAnchorOffsets(menuXInOverlay, menuYInOverlay)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import org.session.libsession.utilities.getGroup
import org.session.libsession.utilities.recipients.Recipient
import org.session.libsession.utilities.withUserConfigs
import org.session.libsignal.utilities.AccountId
import org.session.libsignal.utilities.Log
import org.thoughtcrime.securesms.auth.LoginStateRepository
import org.thoughtcrime.securesms.database.GroupDatabase
import org.thoughtcrime.securesms.database.ThreadDatabase
Expand Down Expand Up @@ -93,9 +94,15 @@ class ConversationOptionsBottomSheet() : BottomSheetDialogFragment(), View.OnCli
requireNotNull(args.getLong(ARG_THREAD_ID))
val addressString = requireNotNull(args.getString(ARG_ADDRESS))
val address = Address.fromSerialized(addressString)
thread = requireNotNull(
threadDatabase.getThreads(listOf(address)).firstOrNull()
) { "Thread not found for address: $addressString" }
val threadFromDb = threadDatabase.getThreads(listOf(address)).firstOrNull()

if(threadFromDb == null){
Log.w("", "Home conversation bottom sheet: Thread not found for address: $addressString" )
dismiss()
return
}

thread = threadFromDb
group = groupDatabase.getGroup(thread.recipient.address.toString())
}

Expand Down
192 changes: 169 additions & 23 deletions app/src/main/java/org/thoughtcrime/securesms/home/HomeDialogs.kt
Original file line number Diff line number Diff line change
@@ -1,13 +1,39 @@
package org.thoughtcrime.securesms.home

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.retain.retain
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.squareup.phrase.Phrase
import kotlinx.coroutines.delay
import network.loki.messenger.R
Expand All @@ -26,21 +52,32 @@ import org.thoughtcrime.securesms.home.HomeViewModel.Commands.HideUrlDialog
import org.thoughtcrime.securesms.home.HomeViewModel.Commands.HideUserProfileModal
import org.thoughtcrime.securesms.home.HomeViewModel.Commands.OnLinkCopied
import org.thoughtcrime.securesms.home.HomeViewModel.Commands.OnLinkOpened
import org.thoughtcrime.securesms.home.HomeViewModel.Commands.ShowDonationConfirmation
import org.thoughtcrime.securesms.home.startconversation.StartConversationSheet
import org.thoughtcrime.securesms.preferences.prosettings.ProSettingsDestination
import org.thoughtcrime.securesms.ui.AlertDialog
import org.thoughtcrime.securesms.ui.AnimatedSessionProCTA
import org.thoughtcrime.securesms.ui.BasicSessionAlertDialog
import org.thoughtcrime.securesms.ui.BottomFadingEdgeBox
import org.thoughtcrime.securesms.ui.CTAFeature
import org.thoughtcrime.securesms.ui.DialogButtonData
import org.thoughtcrime.securesms.ui.CTAImage
import org.thoughtcrime.securesms.ui.DialogBg
import org.thoughtcrime.securesms.ui.GetString
import org.thoughtcrime.securesms.ui.OpenURLAlertDialog
import org.thoughtcrime.securesms.ui.PinProCTA
import org.thoughtcrime.securesms.ui.SimpleSessionProCTA
import org.thoughtcrime.securesms.ui.UserProfileModal
import org.thoughtcrime.securesms.ui.components.AccentFillButtonRect
import org.thoughtcrime.securesms.ui.components.annotatedStringResource
import org.thoughtcrime.securesms.ui.openUrl
import org.thoughtcrime.securesms.ui.qaTag
import org.thoughtcrime.securesms.ui.shimmerOverlay
import org.thoughtcrime.securesms.ui.theme.LocalColors
import org.thoughtcrime.securesms.ui.theme.LocalDimensions
import org.thoughtcrime.securesms.ui.theme.LocalType
import org.thoughtcrime.securesms.ui.theme.PreviewTheme
import org.thoughtcrime.securesms.ui.theme.SessionMaterialTheme
import org.thoughtcrime.securesms.ui.theme.blackAlpha40
import org.thoughtcrime.securesms.util.DonationManager.Companion.URL_DONATE

@Composable
fun HomeDialogs(
Expand Down Expand Up @@ -210,27 +247,8 @@ fun HomeDialogs(
}

if (showDonation && dialogsState.donationCTA) {
val context = LocalContext.current
SimpleSessionProCTA(
heroImage = R.drawable.cta_hero_flower,
title = Phrase.from(context,R.string.donateSessionHelp)
.put(StringSubstitutionConstants.APP_NAME_KEY, NonTranslatableStringConstants.APP_NAME)
.format()
.toString(),
showProBadge = false,
text = Phrase.from(context,R.string.donateSessionDescription)
.put(StringSubstitutionConstants.APP_NAME_KEY, NonTranslatableStringConstants.APP_NAME)
.format()
.toString(),
positiveButtonText = stringResource(R.string.donate),
negativeButtonText = stringResource(R.string.maybeLater),
onUpgrade = {
sendCommand(HideDonationCTADialog)
sendCommand(ShowDonationConfirmation)
},
onCancel = {
sendCommand(HideDonationCTADialog)
}
DonationDialog(
sendCommand = sendCommand
)
}

Expand All @@ -245,3 +263,131 @@ fun HomeDialogs(
}
}

@Composable
fun DonationDialog(
sendCommand: (HomeViewModel.Commands) -> Unit
) {
val context = LocalContext.current
val onCancel = {
sendCommand(HideDonationCTADialog)
}

val title = Phrase.from(context,R.string.donateSessionAppealTitle)
.put(StringSubstitutionConstants.DONATE_APPEAL_KEY, NonTranslatableStringConstants.DONATE_APPEAL_NAME)
.format()

val text = Phrase.from(context,R.string.donateSessionAppealDescription)
.put(StringSubstitutionConstants.APP_NAME_KEY, NonTranslatableStringConstants.APP_NAME)
.format()

val titleColor: Color = LocalColors.current.text

BasicSessionAlertDialog(
onDismissRequest = onCancel,
content = {
DialogBg {
BoxWithConstraints(Modifier.fillMaxWidth()) {
val heroMaxHeight = maxHeight * 0.4f
Column(
modifier = Modifier.fillMaxWidth()
.verticalScroll(rememberScrollState())
) {
// hero image
BottomFadingEdgeBox(
modifier = Modifier.heightIn(max = heroMaxHeight),
fadingEdgeHeight = 70.dp,
fadingColor = LocalColors.current.backgroundSecondary,
content = { _ ->
CTAImage(heroImage = R.drawable.cta_hero_donation)
},
)

// content
Column(
modifier = Modifier
.fillMaxWidth()
.padding(LocalDimensions.current.smallSpacing)
) {
// title
Text(
modifier = Modifier
.align(Alignment.CenterHorizontally),
text = annotatedStringResource(title),
textAlign = TextAlign.Center,
style = LocalType.current.h5.copy(color = titleColor),
)

Spacer(Modifier.height(LocalDimensions.current.contentSpacing))

// main message
Text(
modifier = Modifier
.qaTag(R.string.qa_cta_body)
.align(Alignment.CenterHorizontally),
text = annotatedStringResource(text),
textAlign = TextAlign.Center,
style = LocalType.current.base.copy(
color = LocalColors.current.textSecondary
)
)

Spacer(Modifier.height(LocalDimensions.current.contentSpacing))

// buttons
Row(
Modifier.height(IntrinsicSize.Min)
.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(
LocalDimensions.current.xsSpacing,
Alignment.CenterHorizontally
),
) {
AccentFillButtonRect(
modifier = Modifier
.qaTag(R.string.qa_cta_button_positive)
.shimmerOverlay(),
text = stringResource(R.string.donateSessionAppealReadMore),
onClick = {
context.openUrl(URL_DONATE)
sendCommand(HomeViewModel.Commands.OnDonationLinkClicked)
}
)
}
}
}

IconButton(
onClick = onCancel,
modifier = Modifier
.align(Alignment.TopEnd)
.padding(LocalDimensions.current.xxsSpacing)
.background(
color = blackAlpha40,
shape = CircleShape,
).size(34.dp),
) {
Icon(
painter = painterResource(id = R.drawable.ic_x),
tint = Color.White,
contentDescription = stringResource(R.string.close)
)
}
}
}
}
)
}


@Preview
@Composable
fun PreviewDonationDialog() {
PreviewTheme {
Column(
modifier = Modifier.fillMaxSize()
) {
DonationDialog {}
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -406,8 +406,9 @@ class HomeViewModel @Inject constructor(
_dialogsState.update { it.copy(donationCTA = false) }
}

is Commands.ShowDonationConfirmation -> {
showUrlDialog(URL_DONATE)
is Commands.OnDonationLinkClicked -> {
donationManager.onDonationSeen()
_dialogsState.update { it.copy(donationCTA = false) }
}

is Commands.HideUrlDialog -> {
Expand Down Expand Up @@ -533,7 +534,7 @@ class HomeViewModel @Inject constructor(
data object HidePinCTADialog : Commands
data object HideExpiringCTADialog : Commands
data object HideExpiredCTADialog : Commands
data object ShowDonationConfirmation : Commands
data object OnDonationLinkClicked : Commands
data object HideDonationCTADialog : Commands
data object HideUserProfileModal : Commands
data object HideUrlDialog : Commands
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,11 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
new Data(outState).writeModel(imageEditorView.getModel());
if (imageEditorView != null) {
new Data(outState).writeModel(imageEditorView.getModel());
} else if (restoredModel != null) {
new Data(outState).writeModel(restoredModel);
}
}

@Override
Expand Down
Loading