diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 00a45ba435..31c2466ae2 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -228,6 +228,10 @@
+
() {
+
+ 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
index 2cb1c5997d..851ae8e25a 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/settings/ConversationSettingsActivity.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/settings/ConversationSettingsActivity.kt
@@ -27,6 +27,18 @@ class ConversationSettingsActivity: PassphraseRequiredActionBarActivity(), View.
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 lokiThreadDb: LokiThreadDatabase
@Inject lateinit var viewModelFactory: ConversationSettingsViewModel.AssistedFactory
@@ -38,6 +50,10 @@ class ConversationSettingsActivity: PassphraseRequiredActionBarActivity(), View.
viewModelFactory.create(threadId)
}
+ private val notificationActivityCallback = registerForActivityResult(ConversationNotificationSettingsActivityContract()) {
+ updateRecipientDisplay()
+ }
+
override fun onCreate(savedInstanceState: Bundle?, ready: Boolean) {
super.onCreate(savedInstanceState, ready)
binding = ActivityConversationSettingsBinding.inflate(layoutInflater)
@@ -47,16 +63,12 @@ class ConversationSettingsActivity: PassphraseRequiredActionBarActivity(), View.
binding.searchConversation.setOnClickListener(this)
binding.allMedia.setOnClickListener(this)
binding.pinConversation.setOnClickListener(this)
- }
-
- override fun onResume() {
- super.onResume()
-
- }
-
- override fun onPause() {
- super.onPause()
-
+ binding.notificationSettings.setOnClickListener(this)
+ binding.back.setOnClickListener(this)
+ binding.autoDownloadMediaSwitch.setOnCheckedChangeListener { _, isChecked ->
+ viewModel.setTrusted(isChecked)
+ updateRecipientDisplay()
+ }
}
private fun updateRecipientDisplay() {
@@ -72,35 +84,66 @@ class ConversationSettingsActivity: PassphraseRequiredActionBarActivity(), View.
binding.conversationSubtitle.isVisible = recipient.isClosedGroupRecipient.apply {
binding.conversationSubtitle.text = "TODO: This is a test for group descriptions"
}
+
// Toggle group-specific settings
+ val areGroupOptionsVisible = recipient.isClosedGroupRecipient
+ groupOptions.forEach { v ->
+ v.isVisible = areGroupOptionsVisible
+ }
+
+ // Group admin settings
+ val isUserGroupAdmin = areGroupOptionsVisible && viewModel.isUserGroupAdmin()
+ with (binding) {
+ groupMembersDivider.root.isVisible = areGroupOptionsVisible && !isUserGroupAdmin
+ groupMembers.isVisible = areGroupOptionsVisible && !isUserGroupAdmin
+ adminControlsGroup.isVisible = isUserGroupAdmin
+ deleteGroup.isVisible = isUserGroupAdmin
+ clearMessagesDivider.root.isVisible = isUserGroupAdmin
+ }
// Set pinned state
binding.pinConversation.setText(
if (viewModel.isPinned()) R.string.conversation_settings_unpin_conversation
else R.string.conversation_settings_pin_conversation
)
+
// Set auto-download state
+ val trusted = viewModel.isTrusted()
+ 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?) {
- if (v === binding.searchConversation) {
- setResult(RESULT_SEARCH)
- finish()
- } else if (v === binding.allMedia) {
- val threadRecipient = viewModel.recipient ?: return
- val intent = Intent(this, MediaOverviewActivity::class.java).apply {
- putExtra(MediaOverviewActivity.ADDRESS_EXTRA, threadRecipient.address)
+ when {
+ v === binding.searchConversation -> {
+ setResult(RESULT_SEARCH)
+ finish()
}
- startActivity(intent)
- } else if (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.allMedia -> {
+ val threadRecipient = viewModel.recipient ?: return
+ val intent = Intent(this, MediaOverviewActivity::class.java).apply {
+ putExtra(MediaOverviewActivity.ADDRESS_EXTRA, threadRecipient.address)
}
+ startActivity(intent)
+ }
+ 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()
}
}
}
\ 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
index c7873ebe12..526826c2f1 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/settings/ConversationSettingsViewModel.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/settings/ConversationSettingsViewModel.kt
@@ -6,11 +6,15 @@ import androidx.lifecycle.viewModelScope
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import kotlinx.coroutines.launch
+import org.session.libsession.database.StorageProtocol
+import org.session.libsession.utilities.Address
+import org.session.libsession.utilities.TextSecurePreferences
import org.thoughtcrime.securesms.database.Storage
class ConversationSettingsViewModel(
val threadId: Long,
- private val storage: Storage
+ private val storage: StorageProtocol,
+ private val prefs: TextSecurePreferences
): ViewModel() {
val recipient get() = storage.getRecipientForThread(threadId)
@@ -22,6 +26,22 @@ class ConversationSettingsViewModel(
storage.setThreadPinned(threadId, !isPinned)
}
+ fun isTrusted() = recipient?.let { recipient ->
+ storage.isContactTrusted(recipient)
+ } ?: false
+
+ fun setTrusted(isTrusted: Boolean) {
+ val recipient = recipient ?: return
+ storage.setContactTrusted(recipient, isTrusted)
+ }
+
+ fun isUserGroupAdmin(): Boolean = recipient?.let { recipient ->
+ if (!recipient.isGroupRecipient) return@let false
+ 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
+ } ?: false
+
// DI-related
@dagger.assisted.AssistedFactory
interface AssistedFactory {
@@ -29,11 +49,12 @@ class ConversationSettingsViewModel(
}
class Factory @AssistedInject constructor(
@Assisted private val threadId: Long,
- private val storage: Storage
+ private val storage: Storage,
+ private val prefs: TextSecurePreferences
) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun create(modelClass: Class): T {
- return ConversationSettingsViewModel(threadId, storage) as T
+ return ConversationSettingsViewModel(threadId, storage, prefs) as T
}
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt
index d6052421be..4dd6764eff 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt
@@ -685,6 +685,21 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
}
}
+ override fun isContactTrusted(recipient: Recipient): Boolean {
+ val sessionID = recipient.address.toString()
+ val contactDb = DatabaseComponent.get(context).sessionContactDatabase()
+ val contact = contactDb.getContactWithSessionID(sessionID) ?: return false
+ return contact.isTrusted
+ }
+
+ override fun setContactTrusted(recipient: Recipient, isTrusted: Boolean) {
+ val sessionID = recipient.address.toString()
+ val contactDb = DatabaseComponent.get(context).sessionContactDatabase()
+ val contact = contactDb.getContactWithSessionID(sessionID) ?: return
+ val threadID = DatabaseComponent.get(context).threadDatabase().getThreadIdIfExistsFor(recipient)
+ contactDb.setContactIsTrusted(contact, isTrusted, threadID)
+ }
+
override fun getLastUpdated(threadID: Long): Long {
val threadDB = DatabaseComponent.get(context).threadDatabase()
return threadDB.getLastUpdated(threadID)
diff --git a/app/src/main/res/layout/activity_conversation_notification_settings.xml b/app/src/main/res/layout/activity_conversation_notification_settings.xml
new file mode 100644
index 0000000000..5482601caf
--- /dev/null
+++ b/app/src/main/res/layout/activity_conversation_notification_settings.xml
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+
+
+
\ 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
index 73f72b0970..c12a9857ee 100644
--- a/app/src/main/res/layout/activity_conversation_settings.xml
+++ b/app/src/main/res/layout/activity_conversation_settings.xml
@@ -9,6 +9,16 @@
android:layout_width="match_parent"
android:layout_height="wrap_content">
+
+
+
+
diff --git a/app/src/main/res/layout/view_large_profile_picture.xml b/app/src/main/res/layout/view_large_profile_picture.xml
index 559f6c5a1b..ac714f45b7 100644
--- a/app/src/main/res/layout/view_large_profile_picture.xml
+++ b/app/src/main/res/layout/view_large_profile_picture.xml
@@ -7,24 +7,26 @@
+ android:layout_width="@dimen/extra_large_profile_picture_size"
+ android:layout_height="@dimen/extra_large_profile_picture_size">
+ android:background="@drawable/profile_picture_view_large_background" />
+ android:background="@drawable/profile_picture_view_large_background" />
diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml
index 566ee7e36c..55a2a2d381 100644
--- a/app/src/main/res/values/arrays.xml
+++ b/app/src/main/res/values/arrays.xml
@@ -234,6 +234,7 @@
- @string/notify_type_all
- @string/notify_type_mentions
+ - @string/notify_type_mute
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index fe3191203d..97265c6760 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -748,8 +748,9 @@
Warning
This is your recovery phrase. If you send it to someone they\'ll have full access to your account.
Send
- All
- Mentions
+ All Messages
+ Mentions Only
+ Mute
This message has been deleted
Delete just for me
Delete for everyone
@@ -877,4 +878,6 @@
Add Admins
Clear Messages
Leave Group
+ Group Members
+ Delete Group
diff --git a/libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt b/libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt
index f8d000199c..7d529e7f25 100644
--- a/libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt
+++ b/libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt
@@ -163,6 +163,8 @@ interface StorageProtocol {
fun getRecipientForThread(threadId: Long): Recipient?
fun getRecipientSettings(address: Address): RecipientSettings?
fun addContacts(contacts: List)
+ fun isContactTrusted(recipient: Recipient): Boolean
+ fun setContactTrusted(recipient: Recipient, isTrusted: Boolean)
// Attachments
fun getAttachmentDataUri(attachmentId: AttachmentId): Uri