Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
c8e8b39
Moved AlertDialog
ThomasSession Mar 11, 2026
bed4708
New way to handle links
ThomasSession Mar 11, 2026
0124ea6
v3 dialog update
ThomasSession Mar 11, 2026
1879b16
Hooking up the community join message
ThomasSession Mar 11, 2026
390c098
Linking open/join community actions
ThomasSession Mar 11, 2026
4e9febb
Making sure we can format the text
ThomasSession Mar 11, 2026
18d814e
Moved address ownership to permit navigation from convo to convo
ThomasSession Mar 11, 2026
7e5b3d8
Cleaning up accountId validation and adding community link handling
ThomasSession Mar 13, 2026
1b047d9
simplified logic
ThomasSession Mar 13, 2026
b280a11
Open or join community with confirmation in "New Message"
ThomasSession Mar 13, 2026
c8af9e2
Merge branch 'dev' into feature/community-link-handling
ThomasSession Mar 13, 2026
a72d89a
Community link handling in create group
ThomasSession Mar 15, 2026
75e2d0f
Join community "already joined" confirmation
ThomasSession Mar 15, 2026
647bfb2
Merge branch 'dev' into feature/community-link-handling
ThomasSession Mar 15, 2026
945e2eb
Proper strings
ThomasSession Mar 15, 2026
25d29cc
Community link handling in search
ThomasSession Mar 16, 2026
ec6d6aa
Can now search users by their ID and start convo when not yet contact…
ThomasSession Mar 16, 2026
94a69a7
Merge branch 'dev' into feature/community-link-handling
ThomasSession Mar 16, 2026
6cc4f5b
Potential fix for pull request finding
ThomasSession Mar 16, 2026
1d76ede
PR feedback: moving ui events derived from search query
ThomasSession Mar 17, 2026
c91c63b
Making the check suspend
ThomasSession Mar 17, 2026
a3bc814
Merge branch 'dev' into feature/community-link-handling
ThomasSession Mar 17, 2026
f07769b
Fixed tests
ThomasSession Mar 17, 2026
efaa3fa
Merge branch 'feature/community-link-handling' of https://github.com/…
ThomasSession Mar 17, 2026
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 @@ -112,7 +112,6 @@ interface StorageProtocol {
fun addClosedGroupEncryptionKeyPair(encryptionKeyPair: ECKeyPair, groupPublicKey: String, timestamp: Long)
fun removeAllClosedGroupEncryptionKeyPairs(groupPublicKey: String)

fun isLegacyClosedGroup(publicKey: String): Boolean
fun getClosedGroupEncryptionKeyPairs(groupPublicKey: String): MutableList<ECKeyPair>
fun getLatestClosedGroupEncryptionKeyPair(groupPublicKey: String): ECKeyPair?
fun updateFormationTimestamp(groupID: String, formationTimestamp: Long)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ interface LokiAPIDatabaseProtocol {
fun setOpenGroupPublicKey(server: String, newValue: String)
fun getClosedGroupEncryptionKeyPairs(groupPublicKey: String): List<ECKeyPair>
fun getLatestClosedGroupEncryptionKeyPair(groupPublicKey: String): ECKeyPair?
fun isClosedGroup(groupPublicKey: String): Boolean
fun getForkInfo(): ForkInfo
fun setForkInfo(forkInfo: ForkInfo)
fun migrateLegacyOpenGroup(legacyServerId: String, newServerId: String)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,7 @@ data class AccountId(
null
}
}

fun hasValidLength(candidate: String) = candidate.length == 66
}
}
27 changes: 0 additions & 27 deletions app/src/main/java/org/session/libsignal/utilities/Validation.kt

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ package org.thoughtcrime.securesms

import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.runtime.Composable
import org.thoughtcrime.securesms.ui.AlertDialog
import org.thoughtcrime.securesms.ui.DialogButtonData
import org.thoughtcrime.securesms.ui.dialog.AlertDialog
import org.thoughtcrime.securesms.ui.dialog.DialogButtonData
import org.thoughtcrime.securesms.ui.GetString
import org.thoughtcrime.securesms.ui.LongMessageProCTA
import org.thoughtcrime.securesms.ui.components.annotatedStringResource
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import org.session.libsession.utilities.StringSubstitutionConstants.LIMIT_KEY
import org.thoughtcrime.securesms.database.RecipientRepository
import org.thoughtcrime.securesms.pro.ProStatus
import org.thoughtcrime.securesms.pro.ProStatusManager
import org.thoughtcrime.securesms.ui.SimpleDialogData
import org.thoughtcrime.securesms.ui.dialog.SimpleDialogData
import org.thoughtcrime.securesms.util.NumberUtil

// the amount of character left at which point we should show an indicator
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ import org.thoughtcrime.securesms.components.TypingStatusSender
import org.thoughtcrime.securesms.components.emoji.RecentEmojiPageModel
import org.thoughtcrime.securesms.conversation.v2.ConversationReactionOverlay.OnActionSelectedListener
import org.thoughtcrime.securesms.conversation.v2.ConversationReactionOverlay.OnReactionSelectedListener
import org.thoughtcrime.securesms.conversation.v2.ConversationViewModel.Commands.ShowOpenUrlDialog
import org.thoughtcrime.securesms.conversation.v2.ConversationViewModel.Commands.HandleLink
import org.thoughtcrime.securesms.conversation.v2.MessageDetailActivity.Companion.ON_COPY
import org.thoughtcrime.securesms.conversation.v2.MessageDetailActivity.Companion.ON_DELETE
import org.thoughtcrime.securesms.conversation.v2.MessageDetailActivity.Companion.ON_REPLY
Expand Down Expand Up @@ -562,7 +562,7 @@ class ConversationActivityV2 : ScreenLockActionBarActivity(), InputBarDelegate,
}
// endregion

fun showOpenUrlDialog(url: String) = viewModel.onCommand(ShowOpenUrlDialog(url))
fun handleLink(url: String) = viewModel.onCommand(HandleLink(url))

// region Lifecycle
override fun onCreate(savedInstanceState: Bundle?) {
Expand Down Expand Up @@ -837,7 +837,7 @@ class ConversationActivityV2 : ScreenLockActionBarActivity(), InputBarDelegate,
val intent = ConversationSettingsActivity.createIntent(
context = this@ConversationActivityV2,
address = event.address,
startDestination = ConversationV3Destination.RouteDisappearingMessages
startDestination = ConversationV3Destination.RouteDisappearingMessages(event.address)
)
startActivity(intent)
}
Expand Down Expand Up @@ -1264,7 +1264,7 @@ class ConversationActivityV2 : ScreenLockActionBarActivity(), InputBarDelegate,
}

binding.conversationHeader.outdatedGroupBanner.setOnClickListener {
showOpenUrlDialog("https://getsession.org/groups")
handleLink("https://getsession.org/groups")
}
}
}
Expand Down Expand Up @@ -3194,4 +3194,4 @@ class ConversationActivityV2 : ScreenLockActionBarActivity(), InputBarDelegate,
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,28 +18,26 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import com.squareup.phrase.Phrase
import network.loki.messenger.R
import org.session.libsession.utilities.StringSubstitutionConstants.COMMUNITY_NAME_KEY
import org.session.libsession.utilities.StringSubstitutionConstants.CONVERSATION_NAME_KEY
import org.session.libsession.utilities.StringSubstitutionConstants.EMOJI_KEY
import org.session.libsession.utilities.recipients.displayName
import org.thoughtcrime.securesms.InputBarDialogs
import org.thoughtcrime.securesms.InputbarViewModel
import org.thoughtcrime.securesms.conversation.v2.ConversationViewModel.Commands.*
import org.thoughtcrime.securesms.home.startconversation.group.CreateGroupScreen
import org.thoughtcrime.securesms.ui.AlertDialog
import org.thoughtcrime.securesms.ui.DialogButtonData
import org.thoughtcrime.securesms.links.LinkType
import org.thoughtcrime.securesms.ui.dialog.AlertDialog
import org.thoughtcrime.securesms.ui.dialog.DialogButtonData
import org.thoughtcrime.securesms.ui.GetString
import org.thoughtcrime.securesms.ui.OpenURLAlertDialog
import org.thoughtcrime.securesms.ui.RadioOption
import org.thoughtcrime.securesms.ui.UserProfileModal
import org.thoughtcrime.securesms.ui.components.DialogTitledRadioButton
import org.thoughtcrime.securesms.ui.components.annotatedStringResource
import org.thoughtcrime.securesms.ui.dialog.LinkAlertDialog
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 kotlin.text.format

@OptIn(ExperimentalMaterial3Api::class)
@Composable
Expand Down Expand Up @@ -93,13 +91,16 @@ fun ConversationV2Dialogs(
sendCommand = sendInputBarCommand
)

// open link confirmation
if(!dialogsState.openLinkDialogUrl.isNullOrEmpty()){
OpenURLAlertDialog(
url = dialogsState.openLinkDialogUrl,
// Link dialogs
if(dialogsState.urlDialog != null){
LinkAlertDialog(
data = dialogsState.urlDialog,
onDismissRequest = {
// hide dialog
sendCommand(ShowOpenUrlDialog(null))
sendCommand(HideOpenUrlDialog)
},
openOrJoinCommunity = {
sendCommand(OpenOrJoinCommunity(it))
}
)
}
Expand Down Expand Up @@ -273,30 +274,6 @@ fun ConversationV2Dialogs(
)
}

// Join community
if(dialogsState.joinCommunity != null){
AlertDialog(
onDismissRequest = {
// hide dialog
sendCommand(HideJoinCommunityDialog)
},
title = stringResource(R.string.communityJoin),
text = Phrase.from(LocalContext.current, R.string.communityJoinDescription)
.put(COMMUNITY_NAME_KEY, dialogsState.joinCommunity.communityName).format().toString(),
buttons = listOf(
DialogButtonData(
text = GetString(stringResource(id = R.string.join)),
onClick = {
sendCommand(JoinCommunity(dialogsState.joinCommunity.communityUrl))
}
),
DialogButtonData(
GetString(stringResource(R.string.cancel))
)
)
)
}

// Attachment downloads
if(dialogsState.attachmentDownload != null){
AlertDialog(
Expand Down Expand Up @@ -333,7 +310,7 @@ fun PreviewURLDialog(){
PreviewTheme {
ConversationV2Dialogs(
dialogsState = ConversationViewModel.DialogsState(
openLinkDialogUrl = "https://google.com"
urlDialog = LinkType.GenericLink("https://google.com")
),
inputBarDialogsState = InputbarViewModel.InputBarDialogsState(),
sendCommand = {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,13 +108,15 @@ import org.thoughtcrime.securesms.database.model.GroupThreadStatus
import org.thoughtcrime.securesms.database.model.MessageId
import org.thoughtcrime.securesms.database.model.MessageRecord
import org.thoughtcrime.securesms.database.model.MmsMessageRecord
import org.thoughtcrime.securesms.links.LinkChecker
import org.thoughtcrime.securesms.links.LinkType
import org.thoughtcrime.securesms.database.model.NotifyType
import org.thoughtcrime.securesms.dependencies.ConfigFactory
import org.thoughtcrime.securesms.groups.ExpiredGroupManager
import org.thoughtcrime.securesms.groups.OpenGroupManager
import org.thoughtcrime.securesms.pro.ProStatusManager
import org.thoughtcrime.securesms.repository.ConversationRepository
import org.thoughtcrime.securesms.ui.SimpleDialogData
import org.thoughtcrime.securesms.ui.dialog.SimpleDialogData
import org.thoughtcrime.securesms.ui.components.ConversationAppBarData
import org.thoughtcrime.securesms.ui.components.ConversationAppBarPagerData
import org.thoughtcrime.securesms.ui.getSubbedString
Expand Down Expand Up @@ -163,6 +165,7 @@ class ConversationViewModel @AssistedInject constructor(
private val upmFactory: UserProfileUtils.UserProfileUtilsFactory,
attachmentDownloadHandlerFactory: AttachmentDownloadHandler.Factory,
private val openGroupManager: OpenGroupManager,
private val linkChecker: LinkChecker,
private val attachmentDownloadJobFactory: AttachmentDownloadJob.Factory,
private val communityApiExecutor: CommunityApiExecutor,
private val deleteAllReactionsApiFactory: DeleteAllReactionsApi.Factory,
Expand Down Expand Up @@ -1209,18 +1212,36 @@ class ConversationViewModel @AssistedInject constructor(
}

fun confirmCommunityJoin(communityName: String, communityUrl: String){
_dialogsState.update {
it.copy(
joinCommunity = JoinCommunityDialogData(
communityName = communityName,
communityUrl = communityUrl
)
viewModelScope.launch {
val detectedLink = linkChecker.check(communityUrl) as? LinkType.CommunityLink
val resolvedName = communityName.takeIf { it.isNotBlank() } ?: detectedLink?.name ?: communityUrl
val link = detectedLink?.copy(
name = resolvedName,
) ?: LinkType.CommunityLink(
url = communityUrl,
name = resolvedName,
joined = false,
displayType = LinkType.CommunityLink.DisplayType.CONVERSATION
)

_dialogsState.update {
it.copy(
urlDialog = link,
)
}
}
}

private fun joinCommunity(url: String){
val openGroup = OpenGroupUrlParser.parseUrl(url)
private fun openOrJoinCommunity(url: String){
val openGroup = try {
OpenGroupUrlParser.parseUrl(url)
} catch (_: OpenGroupUrlParser.Error) {
Toast.makeText(application, R.string.communityEnterUrlErrorInvalidDescription, Toast.LENGTH_SHORT)
.show()
return
}

_dialogsState.update { it.copy(urlDialog = null) }

viewModelScope.launch {
try {
Expand All @@ -1229,6 +1250,11 @@ class ConversationViewModel @AssistedInject constructor(
room = openGroup.room,
publicKey = openGroup.serverPublicKey,
)

// after joining or if already joined, open the conversation
_uiEvents.tryEmit(ConversationUiEvent.NavigateToConversation(
address = Address.Community(openGroup.server, openGroup.room),
))
} catch (e: Exception) {
Log.e("", "Error joining community", e)
withContext(Dispatchers.Main) {
Expand All @@ -1239,6 +1265,16 @@ class ConversationViewModel @AssistedInject constructor(
}
}

private fun handleLink(url: String) {
viewModelScope.launch {
_dialogsState.update {
it.copy(
urlDialog = linkChecker.check(url),
)
}
}
}

/**
* Implicitly approve the recipient.
*
Expand All @@ -1258,9 +1294,13 @@ class ConversationViewModel @AssistedInject constructor(

fun onCommand(command: Commands) {
when (command) {
is Commands.ShowOpenUrlDialog -> {
is Commands.HandleLink -> {
handleLink(command.url)
}

Commands.HideOpenUrlDialog -> {
_dialogsState.update {
it.copy(openLinkDialogUrl = command.url)
it.copy(urlDialog = null)
}
}

Expand Down Expand Up @@ -1332,14 +1372,14 @@ class ConversationViewModel @AssistedInject constructor(
userProfileModalUtils?.onCommand(command.upmCommand)
}

is Commands.JoinCommunity -> {
joinCommunity(command.url)
is Commands.OpenOrJoinCommunity -> {
openOrJoinCommunity(command.url)
}

is Commands.HideJoinCommunityDialog -> {
_dialogsState.update {
it.copy(
joinCommunity = null
urlDialog = null
)
}
}
Expand Down Expand Up @@ -1565,21 +1605,15 @@ class ConversationViewModel @AssistedInject constructor(

data class DialogsState(
val showSimpleDialog: SimpleDialogData? = null,
val openLinkDialogUrl: String? = null,
val clearAllEmoji: ClearAllEmoji? = null,
val deleteEveryone: DeleteForEveryoneDialogData? = null,
val recreateGroupConfirm: Boolean = false,
val recreateGroupData: RecreateGroupDialogData? = null,
val userProfileModal: UserProfileModalData? = null,
val joinCommunity: JoinCommunityDialogData? = null,
val urlDialog: LinkType? = null,
val attachmentDownload: ConfirmAttachmentDownloadDialogData? = null
)

data class JoinCommunityDialogData(
val communityName: String,
val communityUrl: String
)

data class ConfirmAttachmentDownloadDialogData(
val attachment: DatabaseAttachment,
val conversationName: String
Expand All @@ -1604,7 +1638,8 @@ class ConversationViewModel @AssistedInject constructor(
)

sealed interface Commands {
data class ShowOpenUrlDialog(val url: String?) : Commands
data class HandleLink(val url: String) : Commands
data object HideOpenUrlDialog : Commands

data class ClearEmoji(val emoji:String, val messageId: MessageId) : Commands

Expand All @@ -1625,7 +1660,7 @@ class ConversationViewModel @AssistedInject constructor(
val upmCommand: UserProfileModalCommands
): Commands

data class JoinCommunity(val url: String): Commands
data class OpenOrJoinCommunity(val url: String): Commands
data object HideJoinCommunityDialog: Commands

data class DownloadAttachments(val attachment: DatabaseAttachment): Commands
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ class LinkPreviewView : LinearLayout {
private fun openURL() {
val url = this.url ?: return Log.w("LinkPreviewView", "Cannot open a null URL")
val activity = context as? ConversationActivityV2
activity?.showOpenUrlDialog(url)
activity?.handleLink(url)
}
// endregion
}
}
Loading