mirror of
https://github.com/oxen-io/session-android.git
synced 2025-12-31 02:16:14 +00:00
feat: finish most wrappers and compile issues, start new closed group compose code
This commit is contained in:
@@ -19,7 +19,7 @@ object MentionManagerUtilities {
|
||||
}
|
||||
recipient.address.isClosedGroup -> {
|
||||
val members = storage.getMembers(recipient.address.serialize())
|
||||
TODO("Fix when compile errors are dealt with for recipient closed groups")
|
||||
result.addAll(members.map { it.sessionId })
|
||||
}
|
||||
recipient.address.isOpenGroup -> {
|
||||
val messageDatabase = DatabaseComponent.get(context).mmsSmsDatabase()
|
||||
|
||||
@@ -10,7 +10,7 @@ import network.loki.messenger.libsession_util.Contacts
|
||||
import network.loki.messenger.libsession_util.ConversationVolatileConfig
|
||||
import network.loki.messenger.libsession_util.GroupInfoConfig
|
||||
import network.loki.messenger.libsession_util.GroupKeysConfig
|
||||
import network.loki.messenger.libsession_util.GroupMemberConfig
|
||||
import network.loki.messenger.libsession_util.GroupMembersConfig
|
||||
import network.loki.messenger.libsession_util.UserGroupsConfig
|
||||
import network.loki.messenger.libsession_util.UserProfile
|
||||
import network.loki.messenger.libsession_util.util.BaseCommunityInfo
|
||||
@@ -94,6 +94,7 @@ import org.thoughtcrime.securesms.util.ConfigurationMessageUtilities
|
||||
import org.thoughtcrime.securesms.util.SessionMetaProtocol
|
||||
import java.security.MessageDigest
|
||||
import network.loki.messenger.libsession_util.util.Contact as LibSessionContact
|
||||
import network.loki.messenger.libsession_util.util.GroupMember as LibSessionGroupMember
|
||||
|
||||
open class Storage(context: Context, helper: SQLCipherOpenHelper, private val configFactory: ConfigFactory) : Database(context, helper), StorageProtocol,
|
||||
ThreadDatabase.ConversationThreadUpdateListener {
|
||||
@@ -460,9 +461,9 @@ open class Storage(context: Context, helper: SQLCipherOpenHelper, private val co
|
||||
is Contacts -> updateContacts(forConfigObject)
|
||||
is ConversationVolatileConfig -> updateConvoVolatile(forConfigObject)
|
||||
is UserGroupsConfig -> updateUserGroups(forConfigObject)
|
||||
is GroupInfoConfig -> TODO()
|
||||
is GroupKeysConfig -> TODO()
|
||||
is GroupMemberConfig -> TODO()
|
||||
is GroupInfoConfig -> updateGroupInfo(forConfigObject)
|
||||
is GroupKeysConfig -> updateGroupKeys(forConfigObject)
|
||||
is GroupMembersConfig -> updateGroupMembers(forConfigObject)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -499,6 +500,19 @@ open class Storage(context: Context, helper: SQLCipherOpenHelper, private val co
|
||||
|
||||
}
|
||||
|
||||
private fun updateGroupInfo(groupInfoConfig: GroupInfoConfig) {
|
||||
val threadId = getOrCreateThreadIdFor(Address.fromSerialized(groupInfoConfig.id().hexString()))
|
||||
// TODO: handle deleted group, handle delete attachment / message before a certain time
|
||||
}
|
||||
|
||||
private fun updateGroupKeys(groupKeys: GroupKeysConfig) {
|
||||
// TODO: update something here?
|
||||
}
|
||||
|
||||
private fun updateGroupMembers(groupMembers: GroupMembersConfig) {
|
||||
// TODO: maybe clear out some contacts or something?
|
||||
}
|
||||
|
||||
private fun updateContacts(contacts: Contacts) {
|
||||
val extracted = contacts.all().toList()
|
||||
addLibSessionContacts(extracted)
|
||||
@@ -1030,10 +1044,8 @@ open class Storage(context: Context, helper: SQLCipherOpenHelper, private val co
|
||||
}
|
||||
}
|
||||
|
||||
override fun getMembers(groupPublicKey: String): List<GroupMember> {
|
||||
val groups = configFactory.userGroups ?: return emptyList()
|
||||
TODO("Add group specific configs")
|
||||
}
|
||||
override fun getMembers(groupPublicKey: String): List<LibSessionGroupMember> =
|
||||
configFactory.groupMemberConfig(SessionId.from(groupPublicKey))?.all()?.toList() ?: emptyList()
|
||||
|
||||
override fun setServerCapabilities(server: String, capabilities: List<String>) {
|
||||
return DatabaseComponent.get(context).lokiAPIDatabase().setServerCapabilities(server, capabilities)
|
||||
@@ -1603,8 +1615,8 @@ open class Storage(context: Context, helper: SQLCipherOpenHelper, private val co
|
||||
}
|
||||
getAllContacts().forEach { contact ->
|
||||
val sessionId = SessionId(contact.sessionID)
|
||||
if (sessionId.prefix == IdPrefix.STANDARD && SodiumUtilities.sessionId(sessionId.hexString, blindedId, serverPublicKey)) {
|
||||
val contactMapping = mapping.copy(sessionId = sessionId.hexString)
|
||||
if (sessionId.prefix == IdPrefix.STANDARD && SodiumUtilities.sessionId(sessionId.hexString(), blindedId, serverPublicKey)) {
|
||||
val contactMapping = mapping.copy(sessionId = sessionId.hexString())
|
||||
db.addBlindedIdMapping(contactMapping)
|
||||
return contactMapping
|
||||
}
|
||||
|
||||
@@ -5,6 +5,9 @@ import android.os.Trace
|
||||
import network.loki.messenger.libsession_util.ConfigBase
|
||||
import network.loki.messenger.libsession_util.Contacts
|
||||
import network.loki.messenger.libsession_util.ConversationVolatileConfig
|
||||
import network.loki.messenger.libsession_util.GroupInfoConfig
|
||||
import network.loki.messenger.libsession_util.GroupKeysConfig
|
||||
import network.loki.messenger.libsession_util.GroupMembersConfig
|
||||
import network.loki.messenger.libsession_util.UserGroupsConfig
|
||||
import network.loki.messenger.libsession_util.UserProfile
|
||||
import org.session.libsession.snode.SnodeAPI
|
||||
@@ -12,7 +15,9 @@ import org.session.libsession.utilities.ConfigFactoryProtocol
|
||||
import org.session.libsession.utilities.ConfigFactoryUpdateListener
|
||||
import org.session.libsession.utilities.TextSecurePreferences
|
||||
import org.session.libsignal.protos.SignalServiceProtos.SharedConfigMessage
|
||||
import org.session.libsignal.utilities.Hex
|
||||
import org.session.libsignal.utilities.Log
|
||||
import org.session.libsignal.utilities.SessionId
|
||||
import org.thoughtcrime.securesms.database.ConfigDatabase
|
||||
import org.thoughtcrime.securesms.dependencies.DatabaseComponent.Companion.get
|
||||
import org.thoughtcrime.securesms.groups.GroupManager
|
||||
@@ -61,7 +66,7 @@ class ConfigFactory(
|
||||
listeners -= listener
|
||||
}
|
||||
|
||||
private inline fun <T> synchronizedWithLog(lock: Any, body: ()->T): T {
|
||||
private inline fun <T> synchronizedWithLog(lock: Any, body: () -> T): T {
|
||||
Trace.beginSection("synchronizedWithLog")
|
||||
val result = synchronized(lock) {
|
||||
body()
|
||||
@@ -72,7 +77,11 @@ class ConfigFactory(
|
||||
|
||||
override val user: UserProfile?
|
||||
get() = synchronizedWithLog(userLock) {
|
||||
if (!ConfigBase.isNewConfigEnabled(isConfigForcedOn, SnodeAPI.nowWithOffset)) return null
|
||||
if (!ConfigBase.isNewConfigEnabled(
|
||||
isConfigForcedOn,
|
||||
SnodeAPI.nowWithOffset
|
||||
)
|
||||
) return null
|
||||
if (_userConfig == null) {
|
||||
val (secretKey, publicKey) = maybeGetUserInfo() ?: return null
|
||||
val userDump = configDatabase.retrieveConfigAndHashes(
|
||||
@@ -92,7 +101,11 @@ class ConfigFactory(
|
||||
|
||||
override val contacts: Contacts?
|
||||
get() = synchronizedWithLog(contactsLock) {
|
||||
if (!ConfigBase.isNewConfigEnabled(isConfigForcedOn, SnodeAPI.nowWithOffset)) return null
|
||||
if (!ConfigBase.isNewConfigEnabled(
|
||||
isConfigForcedOn,
|
||||
SnodeAPI.nowWithOffset
|
||||
)
|
||||
) return null
|
||||
if (_contacts == null) {
|
||||
val (secretKey, publicKey) = maybeGetUserInfo() ?: return null
|
||||
val contactsDump = configDatabase.retrieveConfigAndHashes(
|
||||
@@ -112,7 +125,11 @@ class ConfigFactory(
|
||||
|
||||
override val convoVolatile: ConversationVolatileConfig?
|
||||
get() = synchronizedWithLog(convoVolatileLock) {
|
||||
if (!ConfigBase.isNewConfigEnabled(isConfigForcedOn, SnodeAPI.nowWithOffset)) return null
|
||||
if (!ConfigBase.isNewConfigEnabled(
|
||||
isConfigForcedOn,
|
||||
SnodeAPI.nowWithOffset
|
||||
)
|
||||
) return null
|
||||
if (_convoVolatileConfig == null) {
|
||||
val (secretKey, publicKey) = maybeGetUserInfo() ?: return null
|
||||
val convoDump = configDatabase.retrieveConfigAndHashes(
|
||||
@@ -133,7 +150,11 @@ class ConfigFactory(
|
||||
|
||||
override val userGroups: UserGroupsConfig?
|
||||
get() = synchronizedWithLog(userGroupsLock) {
|
||||
if (!ConfigBase.isNewConfigEnabled(isConfigForcedOn, SnodeAPI.nowWithOffset)) return null
|
||||
if (!ConfigBase.isNewConfigEnabled(
|
||||
isConfigForcedOn,
|
||||
SnodeAPI.nowWithOffset
|
||||
)
|
||||
) return null
|
||||
if (_userGroups == null) {
|
||||
val (secretKey, publicKey) = maybeGetUserInfo() ?: return null
|
||||
val userGroupsDump = configDatabase.retrieveConfigAndHashes(
|
||||
@@ -151,6 +172,61 @@ class ConfigFactory(
|
||||
_userGroups
|
||||
}
|
||||
|
||||
private fun getGroupAuthInfo(groupSessionId: SessionId) = userGroups?.getClosedGroup(groupSessionId.hexString())?.let {
|
||||
it.adminKey to it.authData
|
||||
}
|
||||
|
||||
override fun groupInfoConfig(groupSessionId: SessionId): GroupInfoConfig? = getGroupAuthInfo(groupSessionId)?.let { (sk, _) ->
|
||||
// get any potential initial dumps
|
||||
val dump = configDatabase.retrieveConfigAndHashes(
|
||||
SharedConfigMessage.Kind.CLOSED_GROUP_INFO.name,
|
||||
groupSessionId.hexString()
|
||||
) ?: byteArrayOf()
|
||||
|
||||
GroupInfoConfig.newInstance(Hex.fromStringCondensed(groupSessionId.publicKey), sk, dump)
|
||||
}
|
||||
|
||||
override fun groupKeysConfig(groupSessionId: SessionId): GroupKeysConfig? = getGroupAuthInfo(groupSessionId)?.let { (sk, _) ->
|
||||
// Get the user info or return early
|
||||
val (userSk, _) = maybeGetUserInfo() ?: return@let null
|
||||
|
||||
// Get the group info or return early
|
||||
val info = groupInfoConfig(groupSessionId) ?: return@let null
|
||||
|
||||
// Get the group members or return early
|
||||
val members = groupMemberConfig(groupSessionId) ?: return@let null
|
||||
|
||||
// Get the dump or empty
|
||||
val dump = configDatabase.retrieveConfigAndHashes(
|
||||
SharedConfigMessage.Kind.ENCRYPTION_KEYS.name,
|
||||
groupSessionId.hexString()
|
||||
) ?: byteArrayOf()
|
||||
|
||||
// Put it all together
|
||||
GroupKeysConfig.newInstance(
|
||||
userSk,
|
||||
Hex.fromStringCondensed(groupSessionId.publicKey),
|
||||
sk,
|
||||
dump,
|
||||
info,
|
||||
members
|
||||
)
|
||||
}
|
||||
|
||||
override fun groupMemberConfig(groupSessionId: SessionId): GroupMembersConfig? = getGroupAuthInfo(groupSessionId)?.let { (sk, auth) ->
|
||||
// Get initial dump if we have one
|
||||
val dump = configDatabase.retrieveConfigAndHashes(
|
||||
SharedConfigMessage.Kind.CLOSED_GROUP_MEMBERS.name,
|
||||
groupSessionId.hexString()
|
||||
) ?: byteArrayOf()
|
||||
|
||||
GroupMembersConfig.newInstance(
|
||||
Hex.fromStringCondensed(groupSessionId.publicKey),
|
||||
sk,
|
||||
dump
|
||||
)
|
||||
}
|
||||
|
||||
override fun getUserConfigs(): List<ConfigBase> =
|
||||
listOfNotNull(user, contacts, convoVolatile, userGroups)
|
||||
|
||||
@@ -158,13 +234,23 @@ class ConfigFactory(
|
||||
private fun persistUserConfigDump(timestamp: Long) = synchronized(userLock) {
|
||||
val dumped = user?.dump() ?: return
|
||||
val (_, publicKey) = maybeGetUserInfo() ?: return
|
||||
configDatabase.storeConfig(SharedConfigMessage.Kind.USER_PROFILE.name, publicKey, dumped, timestamp)
|
||||
configDatabase.storeConfig(
|
||||
SharedConfigMessage.Kind.USER_PROFILE.name,
|
||||
publicKey,
|
||||
dumped,
|
||||
timestamp
|
||||
)
|
||||
}
|
||||
|
||||
private fun persistContactsConfigDump(timestamp: Long) = synchronized(contactsLock) {
|
||||
val dumped = contacts?.dump() ?: return
|
||||
val (_, publicKey) = maybeGetUserInfo() ?: return
|
||||
configDatabase.storeConfig(SharedConfigMessage.Kind.CONTACTS.name, publicKey, dumped, timestamp)
|
||||
configDatabase.storeConfig(
|
||||
SharedConfigMessage.Kind.CONTACTS.name,
|
||||
publicKey,
|
||||
dumped,
|
||||
timestamp
|
||||
)
|
||||
}
|
||||
|
||||
private fun persistConvoVolatileConfigDump(timestamp: Long) = synchronized(convoVolatileLock) {
|
||||
@@ -181,7 +267,12 @@ class ConfigFactory(
|
||||
private fun persistUserGroupsConfigDump(timestamp: Long) = synchronized(userGroupsLock) {
|
||||
val dumped = userGroups?.dump() ?: return
|
||||
val (_, publicKey) = maybeGetUserInfo() ?: return
|
||||
configDatabase.storeConfig(SharedConfigMessage.Kind.GROUPS.name, publicKey, dumped, timestamp)
|
||||
configDatabase.storeConfig(
|
||||
SharedConfigMessage.Kind.GROUPS.name,
|
||||
publicKey,
|
||||
dumped,
|
||||
timestamp
|
||||
)
|
||||
}
|
||||
|
||||
override fun persist(forConfigObject: ConfigBase, timestamp: Long) {
|
||||
@@ -214,23 +305,21 @@ class ConfigFactory(
|
||||
if (openGroupId != null) {
|
||||
val userGroups = userGroups ?: return false
|
||||
val threadId = GroupManager.getOpenGroupThreadID(openGroupId, context)
|
||||
val openGroup = get(context).lokiThreadDatabase().getOpenGroupChat(threadId) ?: return false
|
||||
val openGroup =
|
||||
get(context).lokiThreadDatabase().getOpenGroupChat(threadId) ?: return false
|
||||
|
||||
// Not handling the `hidden` behaviour for communities so just indicate the existence
|
||||
return (userGroups.getCommunityInfo(openGroup.server, openGroup.room) != null)
|
||||
}
|
||||
else if (groupPublicKey != null) {
|
||||
} else if (groupPublicKey != null) {
|
||||
val userGroups = userGroups ?: return false
|
||||
|
||||
// Not handling the `hidden` behaviour for legacy groups so just indicate the existence
|
||||
return (userGroups.getLegacyGroupInfo(groupPublicKey) != null)
|
||||
}
|
||||
else if (publicKey == userPublicKey) {
|
||||
} else if (publicKey == userPublicKey) {
|
||||
val user = user ?: return false
|
||||
|
||||
return (!visibleOnly || user.getNtsPriority() != ConfigBase.PRIORITY_HIDDEN)
|
||||
}
|
||||
else if (publicKey != null) {
|
||||
} else if (publicKey != null) {
|
||||
val contacts = contacts ?: return false
|
||||
val targetContact = contacts.get(publicKey) ?: return false
|
||||
|
||||
@@ -240,12 +329,18 @@ class ConfigFactory(
|
||||
return false
|
||||
}
|
||||
|
||||
override fun canPerformChange(variant: String, publicKey: String, changeTimestampMs: Long): Boolean {
|
||||
override fun canPerformChange(
|
||||
variant: String,
|
||||
publicKey: String,
|
||||
changeTimestampMs: Long
|
||||
): Boolean {
|
||||
if (!ConfigBase.isNewConfigEnabled(isConfigForcedOn, SnodeAPI.nowWithOffset)) return true
|
||||
|
||||
val lastUpdateTimestampMs = configDatabase.retrieveConfigLastUpdateTimestamp(variant, publicKey)
|
||||
val lastUpdateTimestampMs =
|
||||
configDatabase.retrieveConfigLastUpdateTimestamp(variant, publicKey)
|
||||
|
||||
// Ensure the change occurred after the last config message was handled (minus the buffer period)
|
||||
return (changeTimestampMs >= (lastUpdateTimestampMs - ConfigFactory.configChangeBufferPeriod))
|
||||
}
|
||||
|
||||
}
|
||||
@@ -34,16 +34,9 @@ object ClosedGroupManager {
|
||||
}
|
||||
}
|
||||
|
||||
fun ConfigFactory.removeLegacyGroup(group: GroupRecord): Boolean {
|
||||
val groups = userGroups ?: return false
|
||||
if (!group.isClosedGroup) return false
|
||||
val groupPublicKey = GroupUtil.doubleEncodeGroupID(group.getId())
|
||||
return groups.eraseLegacyGroup(groupPublicKey)
|
||||
}
|
||||
|
||||
fun ConfigFactory.updateLegacyGroup(groupRecipientSettings: Recipient.RecipientSettings, group: GroupRecord) {
|
||||
val groups = userGroups ?: return
|
||||
if (!group.isClosedGroup) return
|
||||
if (!group.isLegacyClosedGroup) return
|
||||
val storage = MessagingModuleConfiguration.shared.storage
|
||||
val threadId = storage.getThreadId(group.encodedId) ?: return
|
||||
val groupPublicKey = GroupUtil.doubleEncodeGroupID(group.getId())
|
||||
|
||||
@@ -7,6 +7,13 @@ import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Toast
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.Fragment
|
||||
@@ -21,6 +28,7 @@ import nl.komponents.kovenant.ui.successUi
|
||||
import org.session.libsession.messaging.sending_receiving.MessageSender
|
||||
import org.session.libsession.messaging.sending_receiving.groupSizeLimit
|
||||
import org.session.libsession.utilities.Address
|
||||
import org.session.libsession.utilities.Contact
|
||||
import org.session.libsession.utilities.Device
|
||||
import org.session.libsession.utilities.TextSecurePreferences
|
||||
import org.session.libsession.utilities.recipients.Recipient
|
||||
@@ -49,8 +57,11 @@ class CreateGroupFragment : Fragment() {
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
binding = FragmentCreateGroupBinding.inflate(inflater)
|
||||
return binding.root
|
||||
return ComposeView(requireContext()).apply {
|
||||
setContent {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
@@ -121,4 +132,15 @@ class CreateGroupFragment : Fragment() {
|
||||
context.startActivity(intent)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MemberList(contacts: List<Contact>, modifier: Modifier = Modifier) {
|
||||
Avatar
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun ClosedGroupPreview() {
|
||||
MemberList(contacts = emptyList(), modifier = Modifier.fillMaxWidth())
|
||||
}
|
||||
@@ -144,7 +144,7 @@ class HomeActivity : PassphraseRequiredActionBarActivity(),
|
||||
intent.putExtra(ConversationActivityV2.ADDRESS, Address.fromSerialized(address))
|
||||
push(intent)
|
||||
}
|
||||
is GlobalSearchAdapter.Model.GroupConversation -> {
|
||||
is GlobalSearchAdapter.Model.LegacyGroupConversation -> {
|
||||
val groupAddress = Address.fromSerialized(model.groupRecord.encodedId)
|
||||
val threadId = threadDb.getThreadIdIfExistsFor(Recipient.from(this, groupAddress, false))
|
||||
if (threadId >= 0) {
|
||||
@@ -257,7 +257,7 @@ class HomeActivity : PassphraseRequiredActionBarActivity(),
|
||||
globalSearchViewModel.result.collect { result ->
|
||||
val currentUserPublicKey = publicKey
|
||||
val contactAndGroupList = result.contacts.map { GlobalSearchAdapter.Model.Contact(it) } +
|
||||
result.threads.map { GlobalSearchAdapter.Model.GroupConversation(it) }
|
||||
result.threads.map { GlobalSearchAdapter.Model.LegacyGroupConversation(it) }
|
||||
|
||||
val contactResults = contactAndGroupList.toMutableList()
|
||||
|
||||
@@ -642,14 +642,18 @@ class HomeActivity : PassphraseRequiredActionBarActivity(),
|
||||
// Cancel any outstanding jobs
|
||||
DatabaseComponent.get(context).sessionJobDatabase().cancelPendingMessageSendJobs(threadID)
|
||||
// Send a leave group message if this is an active closed group
|
||||
if (recipient.address.isClosedGroup && DatabaseComponent.get(context).groupDatabase().isActive(recipient.address.toGroupString())) {
|
||||
if (recipient.address.isLegacyClosedGroup && DatabaseComponent.get(context).groupDatabase().isActive(recipient.address.toGroupString())) {
|
||||
try {
|
||||
GroupUtil.doubleDecodeGroupID(recipient.address.toString()).toHexString()
|
||||
.takeIf(DatabaseComponent.get(context).lokiAPIDatabase()::isClosedGroup)
|
||||
?.let { MessageSender.explicitLeave(it, false) }
|
||||
} catch (_: IOException) {
|
||||
} catch (e: IOException) {
|
||||
Log.e("Loki", e)
|
||||
}
|
||||
}
|
||||
if (recipient.address.isClosedGroup) {
|
||||
TODO("Implement leaving / deleting a new closed group conversation")
|
||||
}
|
||||
// Delete the conversation
|
||||
val v2OpenGroup = DatabaseComponent.get(context).lokiThreadDatabase().getOpenGroupChat(threadID)
|
||||
if (v2OpenGroup != null) {
|
||||
|
||||
@@ -9,9 +9,10 @@ import androidx.recyclerview.widget.RecyclerView
|
||||
import network.loki.messenger.R
|
||||
import network.loki.messenger.databinding.ViewGlobalSearchHeaderBinding
|
||||
import network.loki.messenger.databinding.ViewGlobalSearchResultBinding
|
||||
import network.loki.messenger.libsession_util.util.GroupInfo
|
||||
import org.session.libsession.utilities.GroupRecord
|
||||
import org.session.libsession.utilities.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.mms.GlideApp
|
||||
import org.session.libsignal.utilities.SessionId
|
||||
import org.thoughtcrime.securesms.search.model.MessageResult
|
||||
import java.security.InvalidParameterException
|
||||
import org.session.libsession.messaging.contacts.Contact as ContactModel
|
||||
@@ -98,7 +99,7 @@ class GlobalSearchAdapter (private val modelCallback: (Model)->Unit): RecyclerVi
|
||||
fun bind(query: String, model: Model) {
|
||||
binding.searchResultProfilePicture.recycle()
|
||||
when (model) {
|
||||
is Model.GroupConversation -> bindModel(query, model)
|
||||
is Model.LegacyGroupConversation -> bindModel(query, model)
|
||||
is Model.Contact -> bindModel(query, model)
|
||||
is Model.Message -> bindModel(query, model)
|
||||
is Model.SavedMessages -> bindModel(model)
|
||||
@@ -119,7 +120,8 @@ class GlobalSearchAdapter (private val modelCallback: (Model)->Unit): RecyclerVi
|
||||
data class Header(@StringRes val title: Int) : Model()
|
||||
data class SavedMessages(val currentUserPublicKey: String): Model()
|
||||
data class Contact(val contact: ContactModel) : Model()
|
||||
data class GroupConversation(val groupRecord: GroupRecord) : Model()
|
||||
data class LegacyGroupConversation(val groupRecord: GroupRecord) : Model()
|
||||
data class ClosedGroupConversation(val sessionId: SessionId)
|
||||
data class Message(val messageResult: MessageResult, val unread: Int) : Model()
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import org.session.libsession.messaging.contacts.Contact
|
||||
import org.session.libsession.utilities.Address
|
||||
import org.session.libsession.utilities.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.home.search.GlobalSearchAdapter.ContentView
|
||||
import org.thoughtcrime.securesms.home.search.GlobalSearchAdapter.Model.GroupConversation
|
||||
import org.thoughtcrime.securesms.home.search.GlobalSearchAdapter.Model.LegacyGroupConversation
|
||||
import org.thoughtcrime.securesms.home.search.GlobalSearchAdapter.Model.Header
|
||||
import org.thoughtcrime.securesms.home.search.GlobalSearchAdapter.Model.Message
|
||||
import org.thoughtcrime.securesms.home.search.GlobalSearchAdapter.Model.SavedMessages
|
||||
@@ -65,7 +65,7 @@ fun ContentView.bindQuery(query: String, model: GlobalSearchAdapter.Model) {
|
||||
binding.searchResultSubtitle.isVisible = true
|
||||
binding.searchResultTitle.text = model.messageResult.conversationRecipient.toShortString()
|
||||
}
|
||||
is GroupConversation -> {
|
||||
is LegacyGroupConversation -> {
|
||||
binding.searchResultTitle.text = getHighlight(
|
||||
query,
|
||||
model.groupRecord.title
|
||||
@@ -86,10 +86,10 @@ private fun getHighlight(query: String?, toSearch: String): Spannable? {
|
||||
return SearchUtil.getHighlightedSpan(Locale.getDefault(), BoldStyleFactory, toSearch, query)
|
||||
}
|
||||
|
||||
fun ContentView.bindModel(query: String?, model: GroupConversation) {
|
||||
fun ContentView.bindModel(query: String?, model: LegacyGroupConversation) {
|
||||
binding.searchResultProfilePicture.isVisible = true
|
||||
binding.searchResultSavedMessages.isVisible = false
|
||||
binding.searchResultSubtitle.isVisible = model.groupRecord.isClosedGroup
|
||||
binding.searchResultSubtitle.isVisible = model.groupRecord.isLegacyClosedGroup
|
||||
binding.searchResultTimestamp.isVisible = false
|
||||
val threadRecipient = Recipient.from(binding.root.context, Address.fromSerialized(model.groupRecord.encodedId), false)
|
||||
binding.searchResultProfilePicture.update(threadRecipient)
|
||||
@@ -102,7 +102,7 @@ fun ContentView.bindModel(query: String?, model: GroupConversation) {
|
||||
val address = it.address.serialize()
|
||||
it.name ?: "${address.take(4)}...${address.takeLast(4)}"
|
||||
}
|
||||
if (model.groupRecord.isClosedGroup) {
|
||||
if (model.groupRecord.isLegacyClosedGroup) {
|
||||
binding.searchResultSubtitle.text = getHighlight(query, membersString)
|
||||
}
|
||||
}
|
||||
@@ -132,11 +132,6 @@ fun ContentView.bindModel(query: String?, model: Message) {
|
||||
binding.searchResultProfilePicture.isVisible = true
|
||||
binding.searchResultSavedMessages.isVisible = false
|
||||
binding.searchResultTimestamp.isVisible = true
|
||||
// val hasUnreads = model.unread > 0
|
||||
// binding.unreadCountIndicator.isVisible = hasUnreads
|
||||
// if (hasUnreads) {
|
||||
// binding.unreadCountTextView.text = model.unread.toString()
|
||||
// }
|
||||
binding.searchResultTimestamp.text = DateUtils.getDisplayFormattedTimeSpanString(binding.root.context, Locale.getDefault(), model.messageResult.sentTimestampMs)
|
||||
binding.searchResultProfilePicture.update(model.messageResult.conversationRecipient)
|
||||
val textSpannable = SpannableStringBuilder()
|
||||
|
||||
@@ -42,7 +42,6 @@ import com.goterl.lazysodium.utils.KeyPair;
|
||||
|
||||
import org.session.libsession.messaging.open_groups.OpenGroup;
|
||||
import org.session.libsession.messaging.sending_receiving.notifications.MessageNotifier;
|
||||
import org.session.libsession.messaging.utilities.SessionId;
|
||||
import org.session.libsession.messaging.utilities.SodiumUtilities;
|
||||
import org.session.libsession.snode.SnodeAPI;
|
||||
import org.session.libsession.utilities.Address;
|
||||
@@ -52,6 +51,7 @@ import org.session.libsession.utilities.TextSecurePreferences;
|
||||
import org.session.libsession.utilities.recipients.Recipient;
|
||||
import org.session.libsignal.utilities.IdPrefix;
|
||||
import org.session.libsignal.utilities.Log;
|
||||
import org.session.libsignal.utilities.SessionId;
|
||||
import org.session.libsignal.utilities.Util;
|
||||
import org.thoughtcrime.securesms.ApplicationContext;
|
||||
import org.thoughtcrime.securesms.contacts.ContactUtil;
|
||||
@@ -555,7 +555,7 @@ public class DefaultMessageNotifier implements MessageNotifier {
|
||||
if (openGroup != null && edKeyPair != null) {
|
||||
KeyPair blindedKeyPair = SodiumUtilities.blindedKeyPair(openGroup.getPublicKey(), edKeyPair);
|
||||
if (blindedKeyPair != null) {
|
||||
return new SessionId(IdPrefix.BLINDED, blindedKeyPair.getPublicKey().getAsBytes()).getHexString();
|
||||
return new SessionId(IdPrefix.BLINDED, blindedKeyPair.getPublicKey().getAsBytes()).hexString();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -9,11 +9,10 @@ import android.widget.TextView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import org.session.libsession.messaging.utilities.SessionId;
|
||||
import org.session.libsignal.utilities.SessionId;
|
||||
import org.thoughtcrime.securesms.components.ProfilePictureView;
|
||||
import org.thoughtcrime.securesms.components.emoji.EmojiImageView;
|
||||
import org.thoughtcrime.securesms.database.model.MessageId;
|
||||
import org.thoughtcrime.securesms.mms.GlideApp;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@@ -5,11 +5,11 @@ import network.loki.messenger.libsession_util.util.UserPic
|
||||
import org.session.libsession.messaging.contacts.Contact
|
||||
import org.session.libsession.messaging.jobs.JobQueue
|
||||
import org.session.libsession.messaging.jobs.RetrieveProfileAvatarJob
|
||||
import org.session.libsession.messaging.utilities.SessionId
|
||||
import org.session.libsession.utilities.SSKEnvironment
|
||||
import org.session.libsession.utilities.TextSecurePreferences
|
||||
import org.session.libsession.utilities.recipients.Recipient
|
||||
import org.session.libsignal.utilities.IdPrefix
|
||||
import org.session.libsignal.utilities.SessionId
|
||||
import org.thoughtcrime.securesms.dependencies.ConfigFactory
|
||||
import org.thoughtcrime.securesms.dependencies.DatabaseComponent
|
||||
import org.thoughtcrime.securesms.util.ConfigurationMessageUtilities
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.thoughtcrime.securesms.util
|
||||
|
||||
import android.content.Context
|
||||
import android.provider.Telephony.Sms.Conversations
|
||||
import network.loki.messenger.libsession_util.ConfigBase
|
||||
import network.loki.messenger.libsession_util.Contacts
|
||||
import network.loki.messenger.libsession_util.ConversationVolatileConfig
|
||||
@@ -26,6 +27,7 @@ import org.session.libsession.utilities.WindowDebouncer
|
||||
import org.session.libsignal.crypto.ecc.DjbECPublicKey
|
||||
import org.session.libsignal.utilities.Hex
|
||||
import org.session.libsignal.utilities.IdPrefix
|
||||
import org.session.libsignal.utilities.SessionId
|
||||
import org.session.libsignal.utilities.toHexString
|
||||
import org.thoughtcrime.securesms.database.GroupDatabase
|
||||
import org.thoughtcrime.securesms.database.ThreadDatabase
|
||||
@@ -199,6 +201,11 @@ object ConfigurationMessageUtilities {
|
||||
convoConfig.getOrConstructCommunity(base, room, pubKey)
|
||||
}
|
||||
recipient.isClosedGroupRecipient -> {
|
||||
// It's probably safe to assume there will never be a case where new closed groups will ever be there before a dump is created...
|
||||
// but just in case...
|
||||
convoConfig.getOrConstructClosedGroup(recipient.address.serialize())
|
||||
}
|
||||
recipient.isLegacyClosedGroupRecipient -> {
|
||||
val groupPublicKey = GroupUtil.doubleDecodeGroupId(recipient.address.serialize())
|
||||
convoConfig.getOrConstructLegacyGroup(groupPublicKey)
|
||||
}
|
||||
@@ -241,7 +248,7 @@ object ConfigurationMessageUtilities {
|
||||
}
|
||||
|
||||
val allLgc = storage.getAllGroups(includeInactive = false).filter {
|
||||
it.isClosedGroup && it.isActive && it.members.size > 1
|
||||
it.isLegacyClosedGroup && it.isActive && it.members.size > 1
|
||||
}.mapNotNull { group ->
|
||||
val groupAddress = Address.fromSerialized(group.encodedId)
|
||||
val groupPublicKey = GroupUtil.doubleDecodeGroupID(groupAddress.serialize()).toHexString()
|
||||
@@ -252,7 +259,7 @@ object ConfigurationMessageUtilities {
|
||||
val admins = group.admins.map { it.serialize() to true }.toMap()
|
||||
val members = group.members.filterNot { it.serialize() !in admins.keys }.map { it.serialize() to false }.toMap()
|
||||
GroupInfo.LegacyGroupInfo(
|
||||
sessionId = groupPublicKey,
|
||||
sessionId = SessionId.from(groupPublicKey),
|
||||
name = group.title,
|
||||
members = admins + members,
|
||||
priority = if (isPinned) ConfigBase.PRIORITY_PINNED else ConfigBase.PRIORITY_VISIBLE,
|
||||
|
||||
@@ -13,6 +13,8 @@ fun ConversationVolatileConfig.getConversationUnread(thread: ThreadRecord): Bool
|
||||
&& recipient.address.serialize().startsWith(IdPrefix.STANDARD.value)) {
|
||||
return getOneToOne(recipient.address.serialize())?.unread == true
|
||||
} else if (recipient.isClosedGroupRecipient) {
|
||||
return getClosedGroup(recipient.address.serialize())?.unread == true
|
||||
} else if (recipient.isLegacyClosedGroupRecipient) {
|
||||
return getLegacyClosedGroup(GroupUtil.doubleDecodeGroupId(recipient.address.toGroupString()))?.unread == true
|
||||
} else if (recipient.isOpenGroupRecipient) {
|
||||
val openGroup = MessagingModuleConfiguration.shared.storage.getOpenGroup(thread.threadId) ?: return false
|
||||
|
||||
Reference in New Issue
Block a user