diff --git a/app/build.gradle.kts b/app/build.gradle.kts index d07e678abf..8ec1aa7156 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -26,8 +26,8 @@ configurations.configureEach { exclude(module = "commons-logging") } -val canonicalVersionCode = 419 -val canonicalVersionName = "1.27.1" +val canonicalVersionCode = 420 +val canonicalVersionName = "1.28.0" val postFixSize = 10 val abiPostFix = mapOf( diff --git a/app/src/main/java/org/session/libsession/messaging/messages/ProfileUpdateHandler.kt b/app/src/main/java/org/session/libsession/messaging/messages/ProfileUpdateHandler.kt index b827c385c1..1ac62e171e 100644 --- a/app/src/main/java/org/session/libsession/messaging/messages/ProfileUpdateHandler.kt +++ b/app/src/main/java/org/session/libsession/messaging/messages/ProfileUpdateHandler.kt @@ -123,6 +123,9 @@ class ProfileUpdateHandler @Inject constructor( profilePic = updates.pic ?: r.profilePic, blocksCommunityMessagesRequests = updates.blocksCommunityMessageRequests ?: r.blocksCommunityMessagesRequests ) + } else if (updates.blocksCommunityMessageRequests != null && + r.blocksCommunityMessagesRequests != updates.blocksCommunityMessageRequests) { + r.copy(blocksCommunityMessagesRequests = updates.blocksCommunityMessageRequests) } else { r } @@ -140,8 +143,11 @@ class ProfileUpdateHandler @Inject constructor( lastUpdated: Instant?, newUpdateTime: Instant? ): Boolean { - return (lastUpdated == null && newUpdateTime == null) || - (newUpdateTime != null && lastUpdated != null && newUpdateTime > lastUpdated) + val lastUpdatedTimestamp = lastUpdated?.toEpochSeconds() ?: 0L + val newUpdateTimestamp = newUpdateTime?.toEpochSeconds() ?: 0L + + return (lastUpdatedTimestamp == 0L && newUpdateTimestamp == 0L) || + (newUpdateTimestamp > lastUpdatedTimestamp) } class Updates private constructor( diff --git a/app/src/main/java/org/session/libsession/messaging/sending_receiving/MessageRequestResponseHandler.kt b/app/src/main/java/org/session/libsession/messaging/sending_receiving/MessageRequestResponseHandler.kt index 43587724d2..c77b955891 100644 --- a/app/src/main/java/org/session/libsession/messaging/sending_receiving/MessageRequestResponseHandler.kt +++ b/app/src/main/java/org/session/libsession/messaging/sending_receiving/MessageRequestResponseHandler.kt @@ -60,6 +60,18 @@ class MessageRequestResponseHandler @Inject constructor( !messageSender.isSelf && messageReceiver.isSelf -> { // We received a request response from another user. + // Mark the sender as "approvedMe". + // This process MUST be done before trying to update the profile, + // as profile updating requires the contact to exist + val didApproveMe = configFactory.withMutableUserConfigs { configs -> + configs.contacts.upsertContact(messageSender.address) { + val oldApproveMe = approvedMe + approvedMe = true + oldApproveMe + } + } + + // Process the profile update if any message.profile?.toUpdates()?.let { updates -> profileUpdateHandler.get().handleProfileUpdate( @@ -69,14 +81,6 @@ class MessageRequestResponseHandler @Inject constructor( ) } - // Mark the sender as "approvedMe" - val didApproveMe = configFactory.withMutableUserConfigs { configs -> - configs.contacts.upsertContact(messageSender.address) { - val oldApproveMe = approvedMe - approvedMe = true - oldApproveMe - } - } val threadId by lazy { threadDatabase.getOrCreateThreadIdFor(messageSender.address) @@ -124,16 +128,24 @@ class MessageRequestResponseHandler @Inject constructor( moveConversation(fromThreadId = blindedThreadId, toThreadId = threadId) } - // If we ever have any blinded conversations with this sender, we should make - // sure we have set "approved" to true for them, because when we started the blinded - // conversation, we didn't know their real standard addresses, so we didn't say - // we have approved them, but now that we do, we need to approve them. - if (existingBlindedThreadIDs.isNotEmpty()) { - configFactory.withMutableUserConfigs { configs -> + configFactory.withMutableUserConfigs { configs -> + // If we ever have any blinded conversations with this sender, we should make + // sure we have set "approved" to true for them, because when we started the blinded + // conversation, we didn't know their real standard addresses, so we didn't say + // we have approved them, but now that we do, we need to approve them. + if (existingBlindedThreadIDs.isNotEmpty()) { configs.contacts.updateContact(messageSender.address) { approved = true } } + + // Also remove all blinded contacts + for (address in blindedConversationAddresses) { + configs.contacts.eraseBlinded( + communityServerUrl = address.serverUrl, + blindedId = address.blindedId.address + ) + } } } diff --git a/app/src/main/java/org/session/libsession/utilities/ViewUtils.kt b/app/src/main/java/org/session/libsession/utilities/ViewUtils.kt index 6f2379cd99..ba2bbb4c03 100644 --- a/app/src/main/java/org/session/libsession/utilities/ViewUtils.kt +++ b/app/src/main/java/org/session/libsession/utilities/ViewUtils.kt @@ -34,14 +34,7 @@ fun TextView.needsCollapsing( availableWidthPx: Int, maxLines: Int ): Boolean { - // Pick the width the TextView will actually respect before draw - val rawWidth = when { - measuredWidth > 0 -> measuredWidth - // if maxWidth is set, we check it - maxWidth in 1 until Int.MAX_VALUE -> minOf(availableWidthPx, maxWidth) - else -> availableWidthPx - } - val contentWidth = (rawWidth - paddingLeft - paddingRight).coerceAtLeast(0) + val contentWidth = (availableWidthPx - paddingLeft - paddingRight).coerceAtLeast(0) if (contentWidth <= 0 || text.isNullOrEmpty()) return false val textForLayout = transformationMethod?.getTransformation(text, this) ?: text @@ -67,7 +60,7 @@ fun TextView.needsCollapsing( .setAlignment(alignment) .setTextDirection(direction) .setMaxLines(maxLines) // cap at maxLines - .setEllipsize(ellipsize ?: TextUtils.TruncateAt.END) // compute ellipsis + .setEllipsize(ellipsize) // compute ellipsis builder.setJustificationMode(justificationMode) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageContentView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageContentView.kt index d65001d297..aa066227b0 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageContentView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageContentView.kt @@ -356,13 +356,9 @@ class VisibleMessageContentView : ConstraintLayout { } } - val widthCap = binding.bodyTextView.maxWidth - .takeIf { it > 0 && it < Int.MAX_VALUE } - ?: resources.getDimensionPixelSize(R.dimen.max_bubble_width) - // if the text was already manually expanded, we can skip this logic if(!isTextExpanded && binding.bodyTextView.needsCollapsing( - availableWidthPx = widthCap, + availableWidthPx = binding.bodyTextView.maxWidth, maxLines = MAX_COLLAPSED_LINE_COUNT) ){ // show the "Read mode" button diff --git a/app/src/main/java/org/thoughtcrime/securesms/home/startconversation/community/JoinCommunityScreen.kt b/app/src/main/java/org/thoughtcrime/securesms/home/startconversation/community/JoinCommunityScreen.kt index adbdfe7570..34caae50a9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/home/startconversation/community/JoinCommunityScreen.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/home/startconversation/community/JoinCommunityScreen.kt @@ -183,6 +183,7 @@ private fun CommunityScreen( .fillMaxWidth() .qaTag(R.string.AccessibilityId_communityJoin), enabled = state.isJoinButtonEnabled, + disabledColor = LocalColors.current.textSecondary, onClick = { sendCommand(JoinCommunityViewModel.Commands.JoinCommunity( state.communityUrl diff --git a/app/src/main/java/org/thoughtcrime/securesms/home/startconversation/home/StartConversation.kt b/app/src/main/java/org/thoughtcrime/securesms/home/startconversation/home/StartConversation.kt index 5fe2aaba9c..06b0e89c2d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/home/startconversation/home/StartConversation.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/home/startconversation/home/StartConversation.kt @@ -74,6 +74,7 @@ internal fun StartConversationScreen( text = annotatedStringResource(newMessageTitleTxt), textStyle = LocalType.current.xl, iconRes = R.drawable.ic_message_square, + iconSize = LocalDimensions.current.iconMedium2, modifier = Modifier.qaTag(R.string.AccessibilityId_messageNew), onClick = { navigateTo(StartConversationDestination.NewMessage) @@ -89,6 +90,7 @@ internal fun StartConversationScreen( text = annotatedStringResource(R.string.groupCreate), textStyle = LocalType.current.xl, iconRes = R.drawable.ic_users_group_custom, + iconSize = LocalDimensions.current.iconMedium2, modifier = Modifier.qaTag(R.string.AccessibilityId_groupCreate), onClick = { navigateTo(StartConversationDestination.CreateGroup) @@ -104,6 +106,7 @@ internal fun StartConversationScreen( text = annotatedStringResource(R.string.communityJoin), textStyle = LocalType.current.xl, iconRes = R.drawable.ic_globe, + iconSize = LocalDimensions.current.iconMedium2, modifier = Modifier.qaTag(R.string.AccessibilityId_communityJoin), onClick = { navigateTo(StartConversationDestination.JoinCommunity) @@ -119,6 +122,7 @@ internal fun StartConversationScreen( text = annotatedStringResource(R.string.sessionInviteAFriend), textStyle = LocalType.current.xl, iconRes = R.drawable.ic_user_round_plus, + iconSize = LocalDimensions.current.iconMedium2, modifier = Modifier.qaTag(R.string.AccessibilityId_sessionInviteAFriendButton), onClick = { navigateTo(StartConversationDestination.InviteFriend) diff --git a/app/src/main/java/org/thoughtcrime/securesms/home/startconversation/newmessage/NewMessage.kt b/app/src/main/java/org/thoughtcrime/securesms/home/startconversation/newmessage/NewMessage.kt index d4f7d604c3..cf0cff108b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/home/startconversation/newmessage/NewMessage.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/home/startconversation/newmessage/NewMessage.kt @@ -139,6 +139,7 @@ private fun EnterAccountId( .fillMaxWidth() .qaTag(R.string.next), enabled = state.isNextButtonEnabled, + disabledColor = LocalColors.current.textSecondary, onClick = callbacks::onContinue ) { LoadingArcOr(state.loading) { 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 7e6057cd7a..34f97504f5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/preferences/SettingsScreen.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/preferences/SettingsScreen.kt @@ -59,6 +59,7 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp import com.bumptech.glide.integration.compose.ExperimentalGlideComposeApi import com.bumptech.glide.integration.compose.GlideImage import network.loki.messenger.BuildConfig @@ -107,6 +108,7 @@ import org.thoughtcrime.securesms.ui.ProBadgeText import org.thoughtcrime.securesms.ui.RadioOption import org.thoughtcrime.securesms.ui.components.AcccentOutlineCopyButton import org.thoughtcrime.securesms.ui.components.AccentOutlineButton +import org.thoughtcrime.securesms.ui.components.AnnotatedTextWithIcon import org.thoughtcrime.securesms.ui.components.AppBarCloseIcon import org.thoughtcrime.securesms.ui.components.Avatar import org.thoughtcrime.securesms.ui.components.BaseBottomSheet @@ -116,6 +118,7 @@ import org.thoughtcrime.securesms.ui.components.SessionOutlinedTextField import org.thoughtcrime.securesms.ui.components.SmallCircularProgressIndicator import org.thoughtcrime.securesms.ui.components.annotatedStringResource import org.thoughtcrime.securesms.ui.qaTag +import org.thoughtcrime.securesms.ui.safeContentWidth import org.thoughtcrime.securesms.ui.theme.LocalColors import org.thoughtcrime.securesms.ui.theme.LocalDimensions import org.thoughtcrime.securesms.ui.theme.LocalType @@ -252,8 +255,10 @@ fun Settings( Spacer(modifier = Modifier.height(LocalDimensions.current.spacing)) // name - ProBadgeText( + AnnotatedTextWithIcon( modifier = Modifier.qaTag(R.string.AccessibilityId_displayName) + .fillMaxWidth() + .safeContentWidth() .clickable( interactionSource = remember { MutableInteractionSource() }, indication = null @@ -261,7 +266,10 @@ fun Settings( sendCommand(ShowUsernameDialog) }, text = uiState.username, - showBadge = uiState.showProBadge, + iconRes = if(uiState.showProBadge) R.drawable.ic_pro_badge else null, + onIconClick = null, + iconSize = 53.sp to 24.sp, + style = LocalType.current.h5, ) Spacer(modifier = Modifier.height(LocalDimensions.current.smallSpacing)) diff --git a/app/src/main/java/org/thoughtcrime/securesms/preferences/prosettings/ProSettingsHomeScreen.kt b/app/src/main/java/org/thoughtcrime/securesms/preferences/prosettings/ProSettingsHomeScreen.kt index 1e10196db4..3ab41a0cc2 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/preferences/prosettings/ProSettingsHomeScreen.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/preferences/prosettings/ProSettingsHomeScreen.kt @@ -254,6 +254,7 @@ fun ProStats( verticalArrangement = Arrangement.spacedBy(LocalDimensions.current.smallSpacing) ){ Row( + verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(LocalDimensions.current.xsSpacing) ) { // groups updated @@ -281,6 +282,7 @@ fun ProStats( } Row( + verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(LocalDimensions.current.xsSpacing) ) { // Pro Badges @@ -325,7 +327,7 @@ fun ProStatItem( Image( painter = painterResource(id = icon), contentDescription = null, - modifier = Modifier.size(LocalDimensions.current.iconRowItem), + modifier = Modifier.size(LocalDimensions.current.iconMedium2), colorFilter = ColorFilter.tint(LocalColors.current.accent) ) diff --git a/app/src/main/java/org/thoughtcrime/securesms/ui/Components.kt b/app/src/main/java/org/thoughtcrime/securesms/ui/Components.kt index 5088037aa9..6829dc7ef4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/ui/Components.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/ui/Components.kt @@ -264,7 +264,7 @@ fun ItemButton( modifier: Modifier = Modifier, textStyle: TextStyle = LocalType.current.h8, iconTint: Color? = null, - iconSize: Dp = LocalDimensions.current.iconRowItem, + iconSize: Dp = LocalDimensions.current.iconMedium, subtitle: String? = null, @StringRes subtitleQaTag: Int? = null, enabled: Boolean = true, @@ -1058,7 +1058,7 @@ fun IconActionRowItem( textStyle: TextStyle = LocalType.current.h8, subtitleStyle: TextStyle = LocalType.current.small, iconColor: Color = LocalColors.current.text, - iconSize: Dp = LocalDimensions.current.iconRowItem, + iconSize: Dp = LocalDimensions.current.iconMedium, minHeight: Dp = LocalDimensions.current.minItemButtonHeight, paddingValues: PaddingValues = PaddingValues(horizontal = LocalDimensions.current.smallSpacing), ){ diff --git a/app/src/main/java/org/thoughtcrime/securesms/ui/components/BottomSheets.kt b/app/src/main/java/org/thoughtcrime/securesms/ui/components/BottomSheets.kt index ee08945b9e..1cfb7701cb 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/ui/components/BottomSheets.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/ui/components/BottomSheets.kt @@ -1,5 +1,8 @@ package org.thoughtcrime.securesms.ui.components +import android.app.Activity +import android.graphics.Color +import android.os.Build import androidx.annotation.DrawableRes import androidx.annotation.StringRes import androidx.compose.foundation.clickable @@ -20,13 +23,18 @@ import androidx.compose.material3.Text import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.material3.rememberStandardBottomSheetState import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect +import androidx.compose.runtime.SideEffect import androidx.compose.ui.Alignment.Companion.CenterVertically import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalView 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.tooling.preview.PreviewParameter +import androidx.compose.ui.window.DialogWindowProvider +import androidx.core.view.WindowCompat import network.loki.messenger.R import org.thoughtcrime.securesms.ui.qaTag import org.thoughtcrime.securesms.ui.theme.LocalColors @@ -58,9 +66,30 @@ fun BaseBottomSheet( topEnd = LocalDimensions.current.xsSpacing ), dragHandle = dragHandle, - containerColor = LocalColors.current.backgroundSecondary, - content = content - ) + containerColor = LocalColors.current.backgroundSecondary + ){ + // make sure the status and navigation bars follow our theme color's light vs dark + val view = LocalView.current + val isLight = LocalColors.current.isLight + + DisposableEffect(Unit) { + val window = (view.parent as? DialogWindowProvider)?.window + if (window != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + val prev = window.isNavigationBarContrastEnforced + window.isNavigationBarContrastEnforced = false + // Set status bar color + WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = isLight + // Set navigation bar color + WindowCompat.getInsetsController(window, view).isAppearanceLightNavigationBars = isLight + + onDispose { window.isNavigationBarContrastEnforced = prev } + } else { + onDispose { } + } + } + + content() + } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/ui/components/Button.kt b/app/src/main/java/org/thoughtcrime/securesms/ui/components/Button.kt index 1b9f8863a6..2929b24e1b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/ui/components/Button.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/ui/components/Button.kt @@ -162,8 +162,13 @@ fun Button( Button(text, onClick, ButtonType.Outline(LocalColors.current.accentText), modifier, enabled, minWidth = minWidth) } -@Composable fun AccentOutlineButton(modifier: Modifier = Modifier, enabled: Boolean = true, onClick: () -> Unit, content: @Composable RowScope.() -> Unit) { - Button(onClick, ButtonType.Outline(LocalColors.current.accentText), modifier, enabled, content = content) +@Composable fun AccentOutlineButton(modifier: Modifier = Modifier, enabled: Boolean = true, + disabledColor: Color = LocalColors.current.disabled, + onClick: () -> Unit, content: @Composable RowScope.() -> Unit) { + Button(onClick, ButtonType.Outline( + contentColor = LocalColors.current.accentText, + disabledColor = disabledColor + ), modifier, enabled, content = content) } @Composable fun SlimOutlineButton(modifier: Modifier = Modifier, color: Color = LocalColors.current.text, enabled: Boolean = true, onClick: () -> Unit, content: @Composable RowScope.() -> Unit) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/ui/components/ButtonType.kt b/app/src/main/java/org/thoughtcrime/securesms/ui/components/ButtonType.kt index 532cd45994..3306511ce5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/ui/components/ButtonType.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/ui/components/ButtonType.kt @@ -26,18 +26,19 @@ interface ButtonType { class Outline( private val contentColor: Color, - private val borderColor: Color = contentColor + private val borderColor: Color = contentColor, + private val disabledColor: Color? = null ): ButtonType { @Composable override fun border(enabled: Boolean) = BorderStroke( width = LocalDimensions.current.borderStroke, - color = if (enabled) borderColor else LocalColors.current.disabled + color = if (enabled) borderColor else disabledColor ?: LocalColors.current.disabled ) @Composable override fun buttonColors() = ButtonDefaults.buttonColors( contentColor = contentColor, containerColor = Color.Transparent, - disabledContentColor = LocalColors.current.disabled, + disabledContentColor = disabledColor ?: LocalColors.current.disabled, disabledContainerColor = Color.Transparent ) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/ui/components/Text.kt b/app/src/main/java/org/thoughtcrime/securesms/ui/components/Text.kt index 45d8bfa897..d72b704dc9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/ui/components/Text.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/ui/components/Text.kt @@ -259,7 +259,7 @@ fun AnnotatedTextWithIcon( style: TextStyle = LocalType.current.base, color: Color = Color.Unspecified, iconSize: Pair = 12.sp to 12.sp, - iconPaddingValues: PaddingValues = PaddingValues(1.dp), + iconPaddingValues: PaddingValues = PaddingValues(start = style.lineHeight.value.dp * 0.2f), onIconClick: (() -> Unit)? = null ) { var inlineContent: Map = mapOf() diff --git a/app/src/main/java/org/thoughtcrime/securesms/ui/theme/Dimensions.kt b/app/src/main/java/org/thoughtcrime/securesms/ui/theme/Dimensions.kt index feca5bc890..745c8aff84 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/ui/theme/Dimensions.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/ui/theme/Dimensions.kt @@ -32,7 +32,7 @@ data class Dimensions( val iconSmall: Dp = 20.dp, val iconMedium: Dp = 24.dp, val iconMediumAvatar: Dp = 26.dp, - val iconRowItem: Dp = 24.dp, + val iconMedium2: Dp = 32.dp, val iconLargeAvatar: Dp = 36.dp, val iconLarge: Dp = 46.dp, val iconXLarge: Dp = 60.dp, diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index f2911f726b..0985e4898f 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -16,8 +16,8 @@ @color/gray50 ?colorPrimary @style/Theme.Session.BottomSheet - true - 0.6 + false + 0 @dimen/dialog_corner_radius @style/ThemeOverlay.Session.AlertDialog @style/ThemeOverlay.Session.AlertDialog