From 841bc69c3c150c30aa03839f2eff98a77b4b9556 Mon Sep 17 00:00:00 2001
From: SessionHero01 <180888785+SessionHero01@users.noreply.github.com>
Date: Thu, 12 Sep 2024 16:40:19 +1000
Subject: [PATCH] Remove conversation settings and added back group operation
---
app/src/main/AndroidManifest.xml | 7 -
...onversationNotificationSettingsActivity.kt | 59 ---
...ionNotificationSettingsActivityContract.kt | 16 -
.../settings/ConversationSettingsActivity.kt | 269 -------------
.../ConversationSettingsActivityContract.kt | 24 --
.../settings/ConversationSettingsViewModel.kt | 104 -----
.../conversation/v2/ConversationActivityV2.kt | 32 +-
.../v2/menus/ConversationMenuHelper.kt | 100 ++++-
...ity_conversation_notification_settings.xml | 73 ----
.../layout/activity_conversation_settings.xml | 375 ------------------
.../res/menu/menu_conversation_groups_v2.xml | 12 +
.../menu_conversation_groups_v2_admin.xml | 12 +
...xml => menu_conversation_legacy_group.xml} | 0
13 files changed, 111 insertions(+), 972 deletions(-)
delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/conversation/settings/ConversationNotificationSettingsActivity.kt
delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/conversation/settings/ConversationNotificationSettingsActivityContract.kt
delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/conversation/settings/ConversationSettingsActivity.kt
delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/conversation/settings/ConversationSettingsActivityContract.kt
delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/conversation/settings/ConversationSettingsViewModel.kt
delete mode 100644 app/src/main/res/layout/activity_conversation_notification_settings.xml
delete mode 100644 app/src/main/res/layout/activity_conversation_settings.xml
create mode 100644 app/src/main/res/menu/menu_conversation_groups_v2.xml
create mode 100644 app/src/main/res/menu/menu_conversation_groups_v2_admin.xml
rename app/src/main/res/menu/{menu_conversation_closed_group.xml => menu_conversation_legacy_group.xml} (100%)
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 9687c01143..eeead1c3ce 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -243,13 +243,6 @@
android:name="android.support.PARENT_ACTIVITY"
android:value="org.thoughtcrime.securesms.home.HomeActivity" />
-
-
() {
-
- override fun createIntent(context: Context, input: Long): Intent =
- Intent(context, ConversationNotificationSettingsActivity::class.java).apply {
- putExtra(ConversationActivityV2.THREAD_ID, input)
- }
-
- override fun parseResult(resultCode: Int, intent: Intent?) { /* do nothing */ }
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/settings/ConversationSettingsActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/settings/ConversationSettingsActivity.kt
deleted file mode 100644
index a44b3fc55d..0000000000
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/settings/ConversationSettingsActivity.kt
+++ /dev/null
@@ -1,269 +0,0 @@
-package org.thoughtcrime.securesms.conversation.settings
-
-import android.content.Intent
-import android.os.Bundle
-import android.view.View
-import androidx.activity.viewModels
-import androidx.core.view.isVisible
-import androidx.lifecycle.lifecycleScope
-import com.squareup.phrase.Phrase
-import dagger.hilt.android.AndroidEntryPoint
-import kotlinx.coroutines.launch
-import network.loki.messenger.R
-import network.loki.messenger.databinding.ActivityConversationSettingsBinding
-import org.session.libsession.messaging.sending_receiving.MessageSender
-import org.session.libsession.utilities.Address
-import org.session.libsession.utilities.GroupUtil
-import org.session.libsession.utilities.StringSubstitutionConstants.GROUP_NAME_KEY
-import org.session.libsession.utilities.StringSubstitutionConstants.NAME_KEY
-import org.session.libsession.utilities.TextSecurePreferences
-import org.session.libsignal.utilities.Log
-import org.session.libsignal.utilities.toHexString
-import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
-import org.thoughtcrime.securesms.conversation.v2.ConversationActivityV2
-import org.thoughtcrime.securesms.database.GroupDatabase
-import org.thoughtcrime.securesms.database.LokiThreadDatabase
-import org.thoughtcrime.securesms.database.ThreadDatabase
-import org.thoughtcrime.securesms.groups.EditGroupActivity
-import org.thoughtcrime.securesms.groups.EditLegacyGroupActivity
-import org.thoughtcrime.securesms.media.MediaOverviewActivity
-import org.thoughtcrime.securesms.showSessionDialog
-import java.io.IOException
-import javax.inject.Inject
-
-@AndroidEntryPoint
-class ConversationSettingsActivity: PassphraseRequiredActionBarActivity(), View.OnClickListener {
-
- companion object {
- // used to trigger displaying conversation search in calling parent activity
- const val RESULT_SEARCH = 22
- }
-
- lateinit var binding: ActivityConversationSettingsBinding
-
- private val groupOptions: List
- get() = with(binding) {
- listOf(
- groupMembers,
- groupMembersDivider.root,
- editGroup,
- editGroupDivider.root,
- leaveGroup,
- leaveGroupDivider.root
- )
- }
-
- @Inject lateinit var threadDb: ThreadDatabase
- @Inject lateinit var groupDb: GroupDatabase
- @Inject lateinit var lokiThreadDb: LokiThreadDatabase
- @Inject lateinit var viewModelFactory: ConversationSettingsViewModel.AssistedFactory
- val viewModel: ConversationSettingsViewModel by viewModels {
- val threadId = intent.getLongExtra(ConversationActivityV2.THREAD_ID, -1L)
- if (threadId == -1L) {
- finish()
- }
- viewModelFactory.create(threadId)
- }
-
- private val notificationActivityCallback = registerForActivityResult(ConversationNotificationSettingsActivityContract()) {
- updateRecipientDisplay()
- }
-
- override fun onCreate(savedInstanceState: Bundle?, ready: Boolean) {
- super.onCreate(savedInstanceState, ready)
- binding = ActivityConversationSettingsBinding.inflate(layoutInflater)
- setContentView(binding.root)
- updateRecipientDisplay()
- binding.searchConversation.setOnClickListener(this)
- binding.clearMessages.setOnClickListener(this)
- binding.allMedia.setOnClickListener(this)
- binding.pinConversation.setOnClickListener(this)
- binding.notificationSettings.setOnClickListener(this)
- binding.editGroup.setOnClickListener(this)
- binding.leaveGroup.setOnClickListener(this)
- binding.back.setOnClickListener(this)
- binding.autoDownloadMediaSwitch.setOnCheckedChangeListener { _, isChecked ->
- viewModel.setAutoDownloadAttachments(isChecked)
- updateRecipientDisplay()
- }
- }
-
- private fun updateRecipientDisplay() {
- val recipient = viewModel.recipient ?: return
- // Setup profile image
- binding.profilePictureView.root.update(recipient)
- // Setup name
- binding.conversationName.text = when {
- recipient.isLocalNumber -> getString(R.string.noteToSelf)
- else -> recipient.toShortString()
- }
- // Setup group description (if group)
- binding.conversationSubtitle.isVisible = recipient.isClosedGroupV2Recipient.apply {
- binding.conversationSubtitle.text = viewModel.closedGroupInfo()?.description
- }
-
- // Toggle group-specific settings
- val areGroupOptionsVisible = recipient.isClosedGroupV2Recipient || recipient.isLegacyClosedGroupRecipient
- groupOptions.forEach { v ->
- v.isVisible = areGroupOptionsVisible
- }
-
- // Group admin settings
- val isUserGroupAdmin = areGroupOptionsVisible && viewModel.isUserGroupAdmin()
- with (binding) {
- groupMembersDivider.root.isVisible = areGroupOptionsVisible && !isUserGroupAdmin
- groupMembers.isVisible = !isUserGroupAdmin
- adminControlsGroup.isVisible = isUserGroupAdmin
- deleteGroup.isVisible = isUserGroupAdmin
- clearMessages.isVisible = isUserGroupAdmin
- clearMessagesDivider.root.isVisible = isUserGroupAdmin
- leaveGroupDivider.root.isVisible = isUserGroupAdmin
- }
-
- // Set pinned state
- binding.pinConversation.setText(
- if (viewModel.isPinned()) R.string.pinUnpinConversation
- else R.string.pinConversation
- )
-
- // Set auto-download state
- val trusted = viewModel.autoDownloadAttachments()
- binding.autoDownloadMediaSwitch.isChecked = trusted
-
- // Set notification type
- val notifyTypes = resources.getStringArray(R.array.notify_types)
- val summary = notifyTypes.getOrNull(recipient.notifyType)
- binding.notificationsValue.text = summary
- }
-
- override fun onClick(v: View?) {
- val threadRecipient = viewModel.recipient ?: return
- when {
- v === binding.searchConversation -> {
- setResult(RESULT_SEARCH)
- finish()
- }
- v === binding.allMedia -> {
- startActivity(MediaOverviewActivity.createIntent(this, threadRecipient.address))
- }
- v === binding.pinConversation -> {
- viewModel.togglePin().invokeOnCompletion { e ->
- if (e != null) {
- // something happened
- Log.e("ConversationSettings", "Failed to toggle pin on thread", e)
- } else {
- updateRecipientDisplay()
- }
- }
- }
- v === binding.notificationSettings -> {
- notificationActivityCallback.launch(viewModel.threadId)
- }
- v === binding.back -> onBackPressed()
- v === binding.clearMessages -> {
-
- showSessionDialog {
- title(R.string.clearMessages)
- text(Phrase.from(this@ConversationSettingsActivity, R.string.clearMessagesChatDescription)
- .put(NAME_KEY, threadRecipient.name)
- .format())
- dangerButton(
- R.string.clear,
- R.string.clear) {
- viewModel.clearMessages(false)
- }
- cancelButton()
- }
- }
- v === binding.leaveGroup -> {
-
- if (threadRecipient.isLegacyClosedGroupRecipient) {
- // Send a leave group message if this is an active closed group
- val groupString = threadRecipient.address.toGroupString()
- val ourId = TextSecurePreferences.getLocalNumber(this)!!
- if (groupDb.isActive(groupString)) {
- showSessionDialog {
-
- title(R.string.groupLeave)
-
- val name = viewModel.recipient!!.name!!
- val textWithArgs = if (groupDb.getGroup(groupString).get().admins.map(Address::serialize).contains(ourId)) {
- Phrase.from(context, R.string.groupLeaveDescriptionAdmin)
- .put(GROUP_NAME_KEY, name)
- .format()
- } else {
- Phrase.from(context, R.string.groupLeaveDescription)
- .put(GROUP_NAME_KEY, name)
- .format()
- }
- text(textWithArgs)
- dangerButton(
- R.string.groupLeave,
- R.string.groupLeave
- ) {
- lifecycleScope.launch {
- GroupUtil.doubleDecodeGroupID(threadRecipient.address.toString())
- .toHexString()
- .let { MessageSender.explicitLeave(it, true, deleteThread = true) }
- finish()
- }
- }
- cancelButton()
- }
- try {
-
- } catch (e: IOException) {
- Log.e("Loki", e)
- }
- }
- } else if (threadRecipient.isClosedGroupV2Recipient) {
- val groupInfo = viewModel.closedGroupInfo()
- showSessionDialog {
-
- title(R.string.groupLeave)
-
- val name = viewModel.recipient!!.name!!
- val textWithArgs = if (groupInfo?.isUserAdmin == true) {
- Phrase.from(context, R.string.groupLeaveDescription)
- .put(GROUP_NAME_KEY, name)
- .format()
- } else {
- Phrase.from(context, R.string.groupLeaveDescription)
- .put(GROUP_NAME_KEY, name)
- .format()
- }
- text(textWithArgs)
- dangerButton(
- R.string.groupLeave,
- R.string.groupLeave
- ) {
- lifecycleScope.launch {
- viewModel.leaveGroup()
- finish()
- }
- }
- cancelButton()
- }
- }
- }
- v === binding.editGroup -> {
- val recipient = viewModel.recipient ?: return
-
- val intent = when {
- recipient.isLegacyClosedGroupRecipient -> Intent(this, EditLegacyGroupActivity::class.java).apply {
- val groupID: String = recipient.address.toGroupString()
- putExtra(EditLegacyGroupActivity.groupIDKey, groupID)
- }
-
- recipient.isClosedGroupV2Recipient -> EditGroupActivity.createIntent(
- context = this,
- groupSessionId = recipient.address.serialize()
- )
-
- else -> return
- }
- startActivity(intent)
- }
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/settings/ConversationSettingsActivityContract.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/settings/ConversationSettingsActivityContract.kt
deleted file mode 100644
index a79d94b3ae..0000000000
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/settings/ConversationSettingsActivityContract.kt
+++ /dev/null
@@ -1,24 +0,0 @@
-package org.thoughtcrime.securesms.conversation.settings
-
-import android.content.Context
-import android.content.Intent
-import androidx.activity.result.contract.ActivityResultContract
-import org.thoughtcrime.securesms.conversation.v2.ConversationActivityV2
-
-sealed class ConversationSettingsActivityResult {
- object Finished: ConversationSettingsActivityResult()
- object SearchConversation: ConversationSettingsActivityResult()
-}
-
-class ConversationSettingsActivityContract: ActivityResultContract() {
-
- override fun createIntent(context: Context, input: Long) = Intent(context, ConversationSettingsActivity::class.java).apply {
- putExtra(ConversationActivityV2.THREAD_ID, input ?: -1L)
- }
-
- override fun parseResult(resultCode: Int, intent: Intent?): ConversationSettingsActivityResult =
- when (resultCode) {
- ConversationSettingsActivity.RESULT_SEARCH -> ConversationSettingsActivityResult.SearchConversation
- else -> ConversationSettingsActivityResult.Finished
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/settings/ConversationSettingsViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/settings/ConversationSettingsViewModel.kt
deleted file mode 100644
index 17411b2211..0000000000
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/settings/ConversationSettingsViewModel.kt
+++ /dev/null
@@ -1,104 +0,0 @@
-package org.thoughtcrime.securesms.conversation.settings
-
-import androidx.lifecycle.ViewModel
-import androidx.lifecycle.ViewModelProvider
-import androidx.lifecycle.viewModelScope
-import dagger.assisted.Assisted
-import dagger.assisted.AssistedInject
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
-import network.loki.messenger.libsession_util.util.GroupDisplayInfo
-import org.session.libsession.database.StorageProtocol
-import org.session.libsession.messaging.jobs.JobQueue
-import org.session.libsession.messaging.jobs.LibSessionGroupLeavingJob
-import org.session.libsession.utilities.Address
-import org.session.libsession.utilities.TextSecurePreferences
-import org.session.libsignal.utilities.AccountId
-
-class ConversationSettingsViewModel(
- val threadId: Long,
- private val storage: StorageProtocol,
- private val prefs: TextSecurePreferences
-): ViewModel() {
-
- val recipient get() = storage.getRecipientForThread(threadId)
-
- fun isPinned() = storage.isPinned(threadId)
-
- fun togglePin() = viewModelScope.launch {
- val isPinned = storage.isPinned(threadId)
- storage.setPinned(threadId, !isPinned)
- }
-
- fun autoDownloadAttachments() = recipient?.let { recipient -> storage.shouldAutoDownloadAttachments(recipient) } ?: false
-
- fun setAutoDownloadAttachments(shouldDownload: Boolean) {
- recipient?.let { recipient -> storage.setAutoDownloadAttachments(recipient, shouldDownload) }
- }
-
- fun isUserGroupAdmin(): Boolean = recipient?.let { recipient ->
- when {
- recipient.isLegacyClosedGroupRecipient -> {
- val localUserAddress = prefs.getLocalNumber() ?: return@let false
- val group = storage.getGroup(recipient.address.toGroupString())
- group?.admins?.contains(Address.fromSerialized(localUserAddress)) ?: false // this will have to be replaced for new closed groups
- }
- recipient.isClosedGroupV2Recipient -> {
- val group = storage.getLibSessionClosedGroup(recipient.address.serialize()) ?: return@let false
- group.adminKey != null
- }
- else -> false
- }
- } ?: false
-
- fun clearMessages(forAll: Boolean) {
- if (forAll && !isUserGroupAdmin()) return
-
- if (!forAll) {
- viewModelScope.launch {
- storage.clearMessages(threadId)
- }
- } else {
- // do a send message here and on success do a clear messages
- viewModelScope.launch {
- storage.clearMessages(threadId)
- }
- }
- }
-
- fun closedGroupInfo(): GroupDisplayInfo? = recipient
- ?.address
- ?.takeIf { it.isClosedGroupV2 }
- ?.serialize()
- ?.let(storage::getClosedGroupDisplayInfo)
-
- // Assume that user has verified they don't want to add a new admin etc
- suspend fun leaveGroup() {
- val recipient = recipient ?: return
- return withContext(Dispatchers.IO) {
- val groupLeave = LibSessionGroupLeavingJob(
- AccountId(recipient.address.serialize()),
- true
- )
- JobQueue.shared.add(groupLeave)
- }
- }
-
- // DI-related
- @dagger.assisted.AssistedFactory
- interface AssistedFactory {
- fun create(threadId: Long): Factory
- }
- class Factory @AssistedInject constructor(
- @Assisted private val threadId: Long,
- private val storage: StorageProtocol,
- private val prefs: TextSecurePreferences
- ) : ViewModelProvider.Factory {
- @Suppress("UNCHECKED_CAST")
- override fun create(modelClass: Class): T {
- return ConversationSettingsViewModel(threadId, storage, prefs) as T
- }
- }
-
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt
index 345253bda1..7f526c518d 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt
@@ -119,8 +119,6 @@ import org.thoughtcrime.securesms.components.emoji.RecentEmojiPageModel
import org.thoughtcrime.securesms.contacts.SelectContactsActivity.Companion.selectedContactsKey
import org.thoughtcrime.securesms.conversation.ConversationActionBarDelegate
import org.thoughtcrime.securesms.conversation.disappearingmessages.DisappearingMessagesActivity
-import org.thoughtcrime.securesms.conversation.settings.ConversationSettingsActivityContract
-import org.thoughtcrime.securesms.conversation.settings.ConversationSettingsActivityResult
import org.thoughtcrime.securesms.conversation.v2.ConversationReactionOverlay.OnActionSelectedListener
import org.thoughtcrime.securesms.conversation.v2.ConversationReactionOverlay.OnReactionSelectedListener
import org.thoughtcrime.securesms.conversation.v2.MessageDetailActivity.Companion.MESSAGE_TIMESTAMP
@@ -164,6 +162,7 @@ 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.database.model.ReactionRecord
+import org.thoughtcrime.securesms.dependencies.ConfigFactory
import org.thoughtcrime.securesms.giph.ui.GiphyActivity
import org.thoughtcrime.securesms.groups.OpenGroupManager
import org.thoughtcrime.securesms.home.search.getSearchName
@@ -222,7 +221,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
ConversationActionModeCallbackDelegate, VisibleMessageViewDelegate, RecipientModifiedListener,
SearchBottomBar.EventListener, LoaderManager.LoaderCallbacks, ConversationActionBarDelegate,
OnReactionSelectedListener, ReactWithAnyEmojiDialogFragment.Callback, ReactionsDialogFragment.Callback,
- ConversationMenuHelper.ConversationMenuListener, View.OnClickListener {
+ ConversationMenuHelper.ConversationMenuListener {
private lateinit var binding: ActivityConversationV2Binding
@@ -239,6 +238,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
@Inject lateinit var reactionDb: ReactionDatabase
@Inject lateinit var viewModelFactory: ConversationViewModel.AssistedFactory
@Inject lateinit var mentionViewModelFactory: MentionViewModel.AssistedFactory
+ @Inject lateinit var configFactory: ConfigFactory
private val screenshotObserver by lazy {
ScreenshotObserver(this, Handler(Looper.getMainLooper())) {
@@ -247,13 +247,6 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
}
}
- private val conversationSettingsCallback = registerForActivityResult(ConversationSettingsActivityContract()) { result ->
- if (result is ConversationSettingsActivityResult.SearchConversation) {
- // open search
- binding?.toolbar?.menu?.findItem(R.id.menu_search)?.expandActionView()
- }
- }
-
private val screenWidth = Resources.getSystem().displayMetrics.widthPixels
private val linkPreviewViewModel: LinkPreviewViewModel by lazy {
ViewModelProvider(this, LinkPreviewViewModel.Factory(LinkPreviewRepository()))
@@ -497,7 +490,6 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
updatePlaceholder()
setUpBlockedBanner()
binding.searchBottomBar.setEventListener(this)
- binding.toolbarContent.profilePictureView.setOnClickListener(this)
updateSendAfterApprovalText()
setUpMessageRequests()
@@ -949,10 +941,11 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
val recipient = viewModel.recipient ?: return false
if (!viewModel.isMessageRequestThread) {
ConversationMenuHelper.onPrepareOptionsMenu(
- menu,
- menuInflater,
- recipient,
- this
+ menu = menu,
+ inflater = menuInflater,
+ thread = recipient,
+ context = this,
+ configFactory = configFactory,
)
}
maybeUpdateToolbar(recipient)
@@ -1219,17 +1212,10 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
return false
}
return viewModel.recipient?.let { recipient ->
- ConversationMenuHelper.onOptionItemSelected(this, item, recipient)
+ ConversationMenuHelper.onOptionItemSelected(this, item, recipient, configFactory, storage)
} ?: false
}
- override fun onClick(v: View?) {
- if (v === binding?.toolbarContent?.profilePictureView) {
- // open conversation settings
- conversationSettingsCallback.launch(viewModel.threadId)
- }
- }
-
override fun block(deleteThread: Boolean) {
val recipient = viewModel.recipient ?: return Log.w("Loki", "Recipient was null for block action")
val invitingAdmin = viewModel.invitingAdmin
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt
index d16c46946b..4a0cf31d00 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt
@@ -5,7 +5,6 @@ import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.graphics.BitmapFactory
-import android.net.Uri
import android.os.AsyncTask
import android.view.Menu
import android.view.MenuInflater
@@ -21,13 +20,14 @@ import androidx.core.graphics.drawable.IconCompat
import com.squareup.phrase.Phrase
import java.io.IOException
import network.loki.messenger.R
+import org.session.libsession.database.StorageProtocol
import org.session.libsession.messaging.sending_receiving.MessageSender
import org.session.libsession.messaging.sending_receiving.leave
import org.session.libsession.utilities.GroupUtil.doubleDecodeGroupID
-import org.session.libsession.utilities.StringSubstitutionConstants.APP_NAME_KEY
import org.session.libsession.utilities.StringSubstitutionConstants.GROUP_NAME_KEY
import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsession.utilities.recipients.Recipient
+import org.session.libsignal.utilities.AccountId
import org.session.libsignal.utilities.Log
import org.session.libsignal.utilities.guava.Optional
import org.session.libsignal.utilities.toHexString
@@ -38,6 +38,8 @@ import org.thoughtcrime.securesms.calls.WebRtcCallActivity
import org.thoughtcrime.securesms.contacts.SelectContactsActivity
import org.thoughtcrime.securesms.conversation.v2.ConversationActivityV2
import org.thoughtcrime.securesms.conversation.v2.utilities.NotificationUtils
+import org.thoughtcrime.securesms.database.Storage
+import org.thoughtcrime.securesms.dependencies.ConfigFactory
import org.thoughtcrime.securesms.dependencies.DatabaseComponent
import org.thoughtcrime.securesms.groups.EditLegacyGroupActivity
import org.thoughtcrime.securesms.groups.EditLegacyGroupActivity.Companion.groupIDKey
@@ -54,7 +56,8 @@ object ConversationMenuHelper {
menu: Menu,
inflater: MenuInflater,
thread: Recipient,
- context: Context
+ context: Context,
+ configFactory: ConfigFactory,
) {
// Prepare
menu.clear()
@@ -77,10 +80,20 @@ object ConversationMenuHelper {
inflater.inflate(R.menu.menu_conversation_block, menu)
}
}
- // Closed group menu (options that should only be present in closed groups)
+ // (Legacy) Closed group menu (options that should only be present in closed groups)
if (thread.isLegacyClosedGroupRecipient) {
- inflater.inflate(R.menu.menu_conversation_closed_group, menu)
+ inflater.inflate(R.menu.menu_conversation_legacy_group, menu)
}
+
+ // Groups v2 menu
+ if (thread.isClosedGroupV2Recipient) {
+ if (configFactory.userGroups?.getClosedGroup(thread.address.serialize())?.hasAdminKey() == true) {
+ inflater.inflate(R.menu.menu_conversation_groups_v2_admin, menu)
+ }
+
+ inflater.inflate(R.menu.menu_conversation_groups_v2, menu)
+ }
+
// Open group menu
if (isCommunity) {
inflater.inflate(R.menu.menu_conversation_open_group, menu)
@@ -134,7 +147,13 @@ object ConversationMenuHelper {
})
}
- fun onOptionItemSelected(context: Context, item: MenuItem, thread: Recipient): Boolean {
+ fun onOptionItemSelected(
+ context: Context,
+ item: MenuItem,
+ thread: Recipient,
+ factory: ConfigFactory,
+ storage: StorageProtocol
+ ): Boolean {
when (item.itemId) {
R.id.menu_view_all_media -> { showAllMedia(context, thread) }
R.id.menu_search -> { search(context) }
@@ -146,7 +165,7 @@ object ConversationMenuHelper {
R.id.menu_copy_account_id -> { copyAccountID(context, thread) }
R.id.menu_copy_open_group_url -> { copyOpenGroupUrl(context, thread) }
R.id.menu_edit_group -> { editClosedGroup(context, thread) }
- R.id.menu_leave_group -> { leaveClosedGroup(context, thread) }
+ R.id.menu_leave_group -> { leaveClosedGroup(context, thread, factory, storage) }
R.id.menu_invite_to_open_group -> { inviteContacts(context, thread) }
R.id.menu_unmute_notifications -> { unmute(context, thread) }
R.id.menu_mute_notifications -> { mute(context, thread) }
@@ -278,26 +297,67 @@ object ConversationMenuHelper {
context.startActivity(intent)
}
- private fun leaveClosedGroup(context: Context, thread: Recipient) {
- if (!thread.isLegacyClosedGroupRecipient) { return }
+ private fun leaveClosedGroup(
+ context: Context,
+ thread: Recipient,
+ configFactory: ConfigFactory,
+ storage: StorageProtocol
+ ) {
+ when {
+ thread.isLegacyClosedGroupRecipient -> {
+ val group = DatabaseComponent.get(context).groupDatabase().getGroup(thread.address.toGroupString()).orNull()
+ val admins = group.admins
+ val accountID = TextSecurePreferences.getLocalNumber(context)
+ val isCurrentUserAdmin = admins.any { it.toString() == accountID }
- val group = DatabaseComponent.get(context).groupDatabase().getGroup(thread.address.toGroupString()).orNull()
- val admins = group.admins
- val accountID = TextSecurePreferences.getLocalNumber(context)
- val isCurrentUserAdmin = admins.any { it.toString() == accountID }
- val message = if (isCurrentUserAdmin) {
+ confirmAndLeaveClosedGroup(context, group.title, isCurrentUserAdmin, doLeave = {
+ val groupPublicKey = doubleDecodeGroupID(thread.address.toString()).toHexString()
+
+ check(DatabaseComponent.get(context).lokiAPIDatabase().isClosedGroup(groupPublicKey)) {
+ "Invalid group public key"
+ }
+ MessageSender.leave(groupPublicKey, notifyUser = false)
+ })
+ }
+
+ thread.isClosedGroupV2Recipient -> {
+ val accountId = AccountId(thread.address.serialize())
+ val group = configFactory.userGroups?.getClosedGroup(accountId.hexString) ?: return
+ val (name, isAdmin) = configFactory.getGroupInfoConfig(accountId)?.use {
+ it.getName() to group.hasAdminKey()
+ } ?: return
+
+ confirmAndLeaveClosedGroup(
+ context = context,
+ groupName = name,
+ isAdmin = isAdmin,
+ doLeave = {
+ check(storage.leaveGroup(accountId.hexString, true))
+ }
+ )
+ }
+ }
+ }
+
+ private fun confirmAndLeaveClosedGroup(
+ context: Context,
+ groupName: String,
+ isAdmin: Boolean,
+ doLeave: () -> Unit,
+ ) {
+ val message = if (isAdmin) {
Phrase.from(context, R.string.groupDeleteDescription)
- .put(GROUP_NAME_KEY, group.title)
+ .put(GROUP_NAME_KEY, groupName)
.format()
} else {
Phrase.from(context, R.string.groupLeaveDescription)
- .put(GROUP_NAME_KEY, group.title)
+ .put(GROUP_NAME_KEY, groupName)
.format()
}
fun onLeaveFailed() {
val txt = Phrase.from(context, R.string.groupLeaveErrorFailed)
- .put(GROUP_NAME_KEY, group.title)
+ .put(GROUP_NAME_KEY, groupName)
.format().toString()
Toast.makeText(context, txt, Toast.LENGTH_LONG).show()
}
@@ -307,11 +367,7 @@ object ConversationMenuHelper {
text(message)
dangerButton(R.string.leave) {
try {
- val groupPublicKey = doubleDecodeGroupID(thread.address.toString()).toHexString()
- val isClosedGroup = DatabaseComponent.get(context).lokiAPIDatabase().isClosedGroup(groupPublicKey)
-
- if (isClosedGroup) MessageSender.leave(groupPublicKey, notifyUser = false)
- else onLeaveFailed()
+ doLeave()
} catch (e: Exception) {
onLeaveFailed()
}
diff --git a/app/src/main/res/layout/activity_conversation_notification_settings.xml b/app/src/main/res/layout/activity_conversation_notification_settings.xml
deleted file mode 100644
index 74ba7632e1..0000000000
--- a/app/src/main/res/layout/activity_conversation_notification_settings.xml
+++ /dev/null
@@ -1,73 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_conversation_settings.xml b/app/src/main/res/layout/activity_conversation_settings.xml
deleted file mode 100644
index d5f810d2cb..0000000000
--- a/app/src/main/res/layout/activity_conversation_settings.xml
+++ /dev/null
@@ -1,375 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/menu/menu_conversation_groups_v2.xml b/app/src/main/res/menu/menu_conversation_groups_v2.xml
new file mode 100644
index 0000000000..e519278931
--- /dev/null
+++ b/app/src/main/res/menu/menu_conversation_groups_v2.xml
@@ -0,0 +1,12 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/menu_conversation_groups_v2_admin.xml b/app/src/main/res/menu/menu_conversation_groups_v2_admin.xml
new file mode 100644
index 0000000000..2cab0f9c5b
--- /dev/null
+++ b/app/src/main/res/menu/menu_conversation_groups_v2_admin.xml
@@ -0,0 +1,12 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/menu_conversation_closed_group.xml b/app/src/main/res/menu/menu_conversation_legacy_group.xml
similarity index 100%
rename from app/src/main/res/menu/menu_conversation_closed_group.xml
rename to app/src/main/res/menu/menu_conversation_legacy_group.xml