Utilise dialog dsl

This commit is contained in:
andrew 2023-05-30 16:49:07 +09:30
parent 1b88d4f950
commit 4ee68cbbb1
14 changed files with 375 additions and 334 deletions

View File

@ -76,6 +76,7 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import kotlin.Unit;
import network.loki.messenger.R;
/**
@ -318,9 +319,9 @@ public class MediaOverviewActivity extends PassphraseRequiredActionBarActivity {
@SuppressWarnings("CodeBlock2Expr")
@SuppressLint({"InlinedApi", "StaticFieldLeak"})
private void handleSaveMedia(@NonNull Collection<MediaDatabase.MediaRecord> mediaRecords) {
final Context context = getContext();
final Context context = requireContext();
SaveAttachmentTask.showWarningDialog(context, (dialogInterface, which) -> {
SaveAttachmentTask.showWarningDialog(context, mediaRecords.size(), () -> {
Permissions.with(this)
.request(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
.maxSdkVersion(Build.VERSION_CODES.P)
@ -362,7 +363,8 @@ public class MediaOverviewActivity extends PassphraseRequiredActionBarActivity {
}.execute();
})
.execute();
}, mediaRecords.size());
return Unit.INSTANCE;
});
}
private void sendMediaSavedNotificationIfNeeded() {

View File

@ -85,6 +85,7 @@ import java.io.IOException;
import java.util.Locale;
import java.util.WeakHashMap;
import kotlin.Unit;
import network.loki.messenger.R;
/**
@ -416,7 +417,7 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity im
MediaItem mediaItem = getCurrentMediaItem();
if (mediaItem == null) return;
SaveAttachmentTask.showWarningDialog(this, (dialogInterface, i) -> {
SaveAttachmentTask.showWarningDialog(this, () -> {
Permissions.with(this)
.request(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
.maxSdkVersion(Build.VERSION_CODES.P)
@ -433,6 +434,7 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity im
}
})
.execute();
return Unit.INSTANCE;
});
}

View File

@ -8,70 +8,128 @@ import android.widget.Button
import android.widget.LinearLayout
import android.widget.LinearLayout.VERTICAL
import android.widget.TextView
import androidx.annotation.AttrRes
import androidx.annotation.LayoutRes
import androidx.annotation.StringRes
import androidx.annotation.StyleRes
import androidx.appcompat.app.AlertDialog
import androidx.core.view.setMargins
import androidx.core.view.setPadding
import androidx.core.view.updateMargins
import network.loki.messenger.R
import org.thoughtcrime.securesms.util.toPx
import java.lang.ref.Reference
@DslMarker
@Target(AnnotationTarget.CLASS, AnnotationTarget.TYPE)
annotation class DialogDsl
@DialogDsl
class SessionDialogBuilder(val context: Context) {
private val dialog: AlertDialog = AlertDialog.Builder(context).create()
private val dialogBuilder: AlertDialog.Builder = AlertDialog.Builder(context)
private var dialog: AlertDialog? = null
private fun dismiss() = dialog?.dismiss()
private val topView = LinearLayout(context).apply { orientation = VERTICAL }
.also(dialogBuilder::setCustomTitle)
private val root = LinearLayout(context).apply { orientation = VERTICAL }
.also(dialog::setView)
.also(dialogBuilder::setView)
fun title(@StringRes id: Int) {
TextView(context, null, 0, R.style.TextAppearance_AppCompat_Title)
.apply { textAlignment = View.TEXT_ALIGNMENT_CENTER }
.apply { setText(id) }
.apply { layoutParams = LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT)
.apply { setMargins(toPx(20, resources)) }
}.let(root::addView)
fun title(@StringRes id: Int) = title(context.getString(id))
fun title(text: CharSequence?) = title(text?.toString())
fun title(text: String?) {
text(text, R.style.TextAppearance_AppCompat_Title) { setPadding(toPx(20, resources)) }
}
fun text(@StringRes id: Int, style: Int = 0) {
TextView(context, null, 0, style)
.apply { textAlignment = View.TEXT_ALIGNMENT_CENTER }
.apply { setText(id) }
.apply { layoutParams = LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT)
fun text(@StringRes id: Int, style: Int = 0) = text(context.getString(id), style)
fun text(text: CharSequence?) = text(text?.toString())
fun text(text: String?, @StyleRes style: Int = 0) {
text(text, style) {
layoutParams = LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT)
.apply { toPx(40, resources).let { updateMargins(it, 0, it, 0) } }
}.let(root::addView)
}
}
fun buttons(build: ButtonsBuilder.() -> Unit) {
ButtonsBuilder(context, dialog).build(build).let(root::addView)
private fun text(text: String?, @StyleRes style: Int, modify: TextView.() -> Unit) {
text ?: return
TextView(context, null, 0, style)
.apply {
setText(text)
textAlignment = View.TEXT_ALIGNMENT_CENTER
modify()
}.let(topView::addView)
}
fun show(): AlertDialog = dialog.apply { show() }
fun view(view: View) {
dialogBuilder.setView(view)
}
fun view(@LayoutRes layout: Int) {
dialogBuilder.setView(layout)
}
fun setIconAttribute(@AttrRes icon: Int) {
dialogBuilder.setIconAttribute(icon)
}
fun singleChoiceItems(
options: Array<String>,
currentSelected: Int,
onSelect: (Int) -> Unit
) {
dialogBuilder.setSingleChoiceItems(
options,
currentSelected
) { dialog, it -> onSelect(it); dialog.dismiss() }
}
fun buttons(build: (@DialogDsl ButtonsBuilder).() -> Unit) {
ButtonsBuilder(context, ::dismiss).build(build).let(root::addView)
}
fun show(): AlertDialog = dialogBuilder.show()
}
class ButtonsBuilder(val context: Context, val dialog: AlertDialog) {
@DialogDsl
class ButtonsBuilder(val context: Context, val dismiss: () -> Unit) {
val root = LinearLayout(context)
fun destructiveButton(@StringRes text: Int, @StringRes contentDescription: Int, listener: () -> Unit = {}) {
button(text, contentDescription, R.style.Widget_Session_Button_Dialog_DestructiveText, listener)
fun destructiveButton(
@StringRes text: Int,
@StringRes contentDescription: Int,
listener: () -> Unit = {}
) {
button(
text,
contentDescription,
R.style.Widget_Session_Button_Dialog_DestructiveText,
listener
)
}
fun cancelButton() = button(android.R.string.cancel)
fun cancelButton(listener: (() -> Unit) = {}) = button(android.R.string.cancel, R.string.AccessibilityId_cancel_button, listener = listener)
fun button(
@StringRes text: Int,
@StringRes contentDescriptionRes: Int = 0,
@StyleRes style: Int = R.style.Widget_Session_Button_Dialog_UnimportantText,
listener: (() -> Unit) = {}) {
listener: (() -> Unit) = {}
) {
Button(context, null, 0, style)
.apply { setText(text) }
.apply { setOnClickListener {
listener.invoke()
dialog.dismiss()
contentDescription = resources.getString(contentDescriptionRes)
} }
.apply {
setText(text)
contentDescription = resources.getString(contentDescriptionRes)
layoutParams = LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT, 1f)
.apply { setMargins(toPx(20, resources)) }
setOnClickListener {
listener.invoke()
dismiss()
}
}
.let(root::addView)
}

View File

@ -1461,23 +1461,24 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
private fun showGIFPicker() {
val hasSeenGIFMetaDataWarning: Boolean = textSecurePreferences.hasSeenGIFMetaDataWarning()
if (!hasSeenGIFMetaDataWarning) {
val builder = AlertDialog.Builder(this)
builder.setTitle(R.string.giphy_permission_title)
builder.setMessage(R.string.giphy_permission_message)
builder.setPositiveButton(R.string.continue_2) { dialog: DialogInterface, _: Int ->
textSecurePreferences.setHasSeenGIFMetaDataWarning()
AttachmentManager.selectGif(this, PICK_GIF)
dialog.dismiss()
sessionDialog {
title(R.string.giphy_permission_title)
text(R.string.giphy_permission_message)
buttons {
button(R.string.continue_2) {
textSecurePreferences.setHasSeenGIFMetaDataWarning()
selectGif()
}
cancelButton()
}
}
builder.setNegativeButton(R.string.cancel) { dialog: DialogInterface, _: Int ->
dialog.dismiss()
}
builder.create().show()
} else {
AttachmentManager.selectGif(this, PICK_GIF)
selectGif()
}
}
private fun selectGif() = AttachmentManager.selectGif(this, PICK_GIF)
private fun showDocumentPicker() {
AttachmentManager.selectDocument(this, PICK_DOCUMENT)
}
@ -1624,35 +1625,25 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
val allHasHash = messages.all { lokiMessageDb.getMessageServerHash(it.id) != null }
if (recipient.isOpenGroupRecipient) {
val messageCount = 1
val builder = AlertDialog.Builder(this)
builder.setTitle(resources.getQuantityString(R.plurals.ConversationFragment_delete_selected_messages, messageCount, messageCount))
builder.setMessage(resources.getQuantityString(R.plurals.ConversationFragment_this_will_permanently_delete_all_n_selected_messages, messageCount, messageCount))
builder.setCancelable(true)
builder.setPositiveButton(R.string.delete) { _, _ ->
for (message in messages) {
viewModel.deleteForEveryone(message)
sessionDialog {
title(resources.getQuantityString(R.plurals.ConversationFragment_delete_selected_messages, messageCount, messageCount))
text(resources.getQuantityString(R.plurals.ConversationFragment_this_will_permanently_delete_all_n_selected_messages, messageCount, messageCount))
buttons {
button(R.string.delete) { messages.forEach(viewModel::deleteForEveryone); endActionMode() }
cancelButton { endActionMode() }
}
endActionMode()
}
builder.setNegativeButton(android.R.string.cancel) { dialog, _ ->
dialog.dismiss()
endActionMode()
}
builder.show()
} else if (allSentByCurrentUser && allHasHash) {
val bottomSheet = DeleteOptionsBottomSheet()
bottomSheet.recipient = recipient
bottomSheet.onDeleteForMeTapped = {
for (message in messages) {
viewModel.deleteLocally(message)
}
messages.forEach(viewModel::deleteLocally)
bottomSheet.dismiss()
endActionMode()
}
bottomSheet.onDeleteForEveryoneTapped = {
for (message in messages) {
viewModel.deleteForEveryone(message)
}
messages.forEach(viewModel::deleteForEveryone)
bottomSheet.dismiss()
endActionMode()
}
@ -1663,54 +1654,38 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
bottomSheet.show(supportFragmentManager, bottomSheet.tag)
} else {
val messageCount = 1
val builder = AlertDialog.Builder(this)
builder.setTitle(resources.getQuantityString(R.plurals.ConversationFragment_delete_selected_messages, messageCount, messageCount))
builder.setMessage(resources.getQuantityString(R.plurals.ConversationFragment_this_will_permanently_delete_all_n_selected_messages, messageCount, messageCount))
builder.setCancelable(true)
builder.setPositiveButton(R.string.delete) { _, _ ->
for (message in messages) {
viewModel.deleteLocally(message)
sessionDialog {
title(resources.getQuantityString(R.plurals.ConversationFragment_delete_selected_messages, messageCount, messageCount))
text(resources.getQuantityString(R.plurals.ConversationFragment_this_will_permanently_delete_all_n_selected_messages, messageCount, messageCount))
buttons {
button(R.string.delete) { messages.forEach(viewModel::deleteLocally); endActionMode() }
cancelButton(::endActionMode)
}
endActionMode()
}
builder.setNegativeButton(android.R.string.cancel) { dialog, _ ->
dialog.dismiss()
endActionMode()
}
builder.show()
}
}
override fun banUser(messages: Set<MessageRecord>) {
val builder = AlertDialog.Builder(this)
builder.setTitle(R.string.ConversationFragment_ban_selected_user)
builder.setMessage("This will ban the selected user from this room. It won't ban them from other rooms.")
builder.setCancelable(true)
builder.setPositiveButton(R.string.ban) { _, _ ->
viewModel.banUser(messages.first().individualRecipient)
endActionMode()
sessionDialog {
title(R.string.ConversationFragment_ban_selected_user)
text("This will ban the selected user from this room. It won't ban them from other rooms.")
buttons {
button(R.string.ban) { viewModel.banUser(messages.first().individualRecipient); endActionMode() }
cancelButton(::endActionMode)
}
}
builder.setNegativeButton(android.R.string.cancel) { dialog, _ ->
dialog.dismiss()
endActionMode()
}
builder.show()
}
override fun banAndDeleteAll(messages: Set<MessageRecord>) {
val builder = AlertDialog.Builder(this)
builder.setTitle(R.string.ConversationFragment_ban_selected_user)
builder.setMessage("This will ban the selected user from this room and delete all messages sent by them. It won't ban them from other rooms or delete the messages they sent there.")
builder.setCancelable(true)
builder.setPositiveButton(R.string.ban) { _, _ ->
viewModel.banAndDeleteAll(messages.first().individualRecipient)
endActionMode()
sessionDialog {
title(R.string.ConversationFragment_ban_selected_user)
text("This will ban the selected user from this room and delete all messages sent by them. It won't ban them from other rooms or delete the messages they sent there.")
buttons {
button(R.string.ban) { viewModel.banAndDeleteAll(messages.first().individualRecipient); endActionMode() }
cancelButton(::endActionMode)
}
}
builder.setNegativeButton(android.R.string.cancel) { dialog, _ ->
dialog.dismiss()
endActionMode()
}
builder.show()
}
override fun copyMessages(messages: Set<MessageRecord>) {
@ -1774,7 +1749,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
override fun saveAttachment(messages: Set<MessageRecord>) {
val message = messages.first() as MmsMessageRecord
SaveAttachmentTask.showWarningDialog(this, { _, _ ->
SaveAttachmentTask.showWarningDialog(this) {
Permissions.with(this)
.request(Manifest.permission.WRITE_EXTERNAL_STORAGE)
.maxSdkVersion(Build.VERSION_CODES.P)
@ -1802,7 +1777,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
Toast.LENGTH_LONG).show()
}
.execute()
})
}
}
override fun reply(messages: Set<MessageRecord>) {

View File

@ -31,6 +31,7 @@ import org.thoughtcrime.securesms.database.model.MessageRecord
import org.thoughtcrime.securesms.dependencies.DatabaseComponent
import org.thoughtcrime.securesms.mms.GlideRequests
import org.thoughtcrime.securesms.preferences.PrivacySettingsActivity
import org.thoughtcrime.securesms.sessionDialog
class ConversationAdapter(
context: Context,
@ -146,17 +147,17 @@ class ConversationAdapter(
viewHolder.view.bind(message, messageBefore)
if (message.isCallLog && message.isFirstMissedCall) {
viewHolder.view.setOnClickListener {
AlertDialog.Builder(context)
.setTitle(R.string.CallNotificationBuilder_first_call_title)
.setMessage(R.string.CallNotificationBuilder_first_call_message)
.setPositiveButton(R.string.activity_settings_title) { _, _ ->
val intent = Intent(context, PrivacySettingsActivity::class.java)
context.startActivity(intent)
context.sessionDialog {
title(R.string.CallNotificationBuilder_first_call_title)
text(R.string.CallNotificationBuilder_first_call_message)
buttons {
button(R.string.activity_settings_title) {
Intent(context, PrivacySettingsActivity::class.java)
.let(context::startActivity)
}
cancelButton()
}
.setNeutralButton(R.string.cancel) { d, _ ->
d.dismiss()
}
.show()
}
}
} else {
viewHolder.view.setOnClickListener(null)

View File

@ -45,6 +45,7 @@ import org.thoughtcrime.securesms.groups.EditClosedGroupActivity
import org.thoughtcrime.securesms.groups.EditClosedGroupActivity.Companion.groupIDKey
import org.thoughtcrime.securesms.preferences.PrivacySettingsActivity
import org.thoughtcrime.securesms.service.WebRtcCallService
import org.thoughtcrime.securesms.sessionDialog
import org.thoughtcrime.securesms.util.BitmapUtil
import java.io.IOException
@ -186,29 +187,25 @@ object ConversationMenuHelper {
private fun call(context: Context, thread: Recipient) {
if (!TextSecurePreferences.isCallNotificationsEnabled(context)) {
val dialog = AlertDialog.Builder(context)
.setTitle(R.string.ConversationActivity_call_title)
.setMessage(R.string.ConversationActivity_call_prompt)
.setPositiveButton(R.string.activity_settings_title) { _, _ ->
val intent = Intent(context, PrivacySettingsActivity::class.java)
context.startActivity(intent)
context.sessionDialog {
title(R.string.ConversationActivity_call_title)
text(R.string.ConversationActivity_call_prompt)
buttons {
button(R.string.activity_settings_title, R.string.AccessibilityId_settings) {
Intent(context, PrivacySettingsActivity::class.java).let(context::startActivity)
}
cancelButton()
}
.setNeutralButton(R.string.cancel) { d, _ ->
d.dismiss()
}.create()
dialog.getButton(DialogInterface.BUTTON_POSITIVE)?.contentDescription = context.getString(R.string.AccessibilityId_settings)
dialog.getButton(DialogInterface.BUTTON_NEGATIVE)?.contentDescription = context.getString(R.string.AccessibilityId_cancel_button)
dialog.show()
}
return
}
val service = WebRtcCallService.createCall(context, thread)
context.startService(service)
WebRtcCallService.createCall(context, thread)
.let(context::startService)
val activity = Intent(context, WebRtcCallActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK
}
context.startActivity(activity)
Intent(context, WebRtcCallActivity::class.java)
.apply { flags = Intent.FLAG_ACTIVITY_NEW_TASK }
.let(context::startActivity)
}
@ -295,9 +292,7 @@ object ConversationMenuHelper {
private fun leaveClosedGroup(context: Context, thread: Recipient) {
if (!thread.isClosedGroupRecipient) { return }
val builder = AlertDialog.Builder(context)
builder.setTitle(context.resources.getString(R.string.ConversationActivity_leave_group))
builder.setCancelable(true)
val group = DatabaseComponent.get(context).groupDatabase().getGroup(thread.address.toGroupString()).orNull()
val admins = group.admins
val sessionID = TextSecurePreferences.getLocalNumber(context)
@ -307,29 +302,27 @@ object ConversationMenuHelper {
} else {
context.resources.getString(R.string.ConversationActivity_are_you_sure_you_want_to_leave_this_group)
}
builder.setMessage(message)
builder.setPositiveButton(R.string.yes) { _, _ ->
var groupPublicKey: String?
var isClosedGroup: Boolean
try {
groupPublicKey = doubleDecodeGroupID(thread.address.toString()).toHexString()
isClosedGroup = DatabaseComponent.get(context).lokiAPIDatabase().isClosedGroup(groupPublicKey)
} catch (e: IOException) {
groupPublicKey = null
isClosedGroup = false
}
try {
if (isClosedGroup) {
MessageSender.leave(groupPublicKey!!, true)
} else {
Toast.makeText(context, R.string.ConversationActivity_error_leaving_group, Toast.LENGTH_LONG).show()
fun onLeaveFailed() = Toast.makeText(context, R.string.ConversationActivity_error_leaving_group, Toast.LENGTH_LONG).show()
context.sessionDialog {
title(R.string.ConversationActivity_leave_group)
text(message)
buttons {
button(R.string.yes) {
try {
val groupPublicKey = doubleDecodeGroupID(thread.address.toString()).toHexString()
val isClosedGroup = DatabaseComponent.get(context).lokiAPIDatabase().isClosedGroup(groupPublicKey)
if (isClosedGroup) MessageSender.leave(groupPublicKey, true)
else onLeaveFailed()
} catch (e: Exception) {
onLeaveFailed()
}
}
} catch (e: Exception) {
Toast.makeText(context, R.string.ConversationActivity_error_leaving_group, Toast.LENGTH_LONG).show()
button(R.string.no)
}
}
builder.setNegativeButton(R.string.no, null)
builder.show()
}
private fun inviteContacts(context: Context, thread: Recipient) {

View File

@ -1,21 +1,18 @@
package org.thoughtcrime.securesms.conversation.v2.utilities
import android.content.Context
import androidx.appcompat.app.AlertDialog
import network.loki.messenger.R
import org.session.libsession.utilities.recipients.Recipient
import org.thoughtcrime.securesms.sessionDialog
object NotificationUtils {
fun showNotifyDialog(context: Context, thread: Recipient, notifyTypeHandler: (Int)->Unit) {
val notifyTypes = context.resources.getStringArray(R.array.notify_types)
val currentSelected = thread.notifyType
AlertDialog.Builder(context)
.setSingleChoiceItems(notifyTypes,currentSelected) { d, newSelection ->
notifyTypeHandler(newSelection)
d.dismiss()
}
.setTitle(R.string.RecipientPreferenceActivity_notification_settings)
.show()
context.sessionDialog {
title(R.string.RecipientPreferenceActivity_notification_settings)
singleChoiceItems(
context.resources.getStringArray(R.array.notify_types),
thread.notifyType
) { notifyTypeHandler(it) }
}
}
}
}

View File

@ -63,6 +63,7 @@ import org.thoughtcrime.securesms.mms.GlideRequests
import org.thoughtcrime.securesms.onboarding.SeedActivity
import org.thoughtcrime.securesms.onboarding.SeedReminderViewDelegate
import org.thoughtcrime.securesms.preferences.SettingsActivity
import org.thoughtcrime.securesms.sessionDialog
import org.thoughtcrime.securesms.util.ConfigurationMessageUtilities
import org.thoughtcrime.securesms.util.DateUtils
import org.thoughtcrime.securesms.util.IP2Country
@ -488,46 +489,43 @@ class HomeActivity : PassphraseRequiredActionBarActivity(),
}
private fun blockConversation(thread: ThreadRecord) {
AlertDialog.Builder(this)
.setTitle(R.string.RecipientPreferenceActivity_block_this_contact_question)
.setMessage(R.string.RecipientPreferenceActivity_you_will_no_longer_receive_messages_and_calls_from_this_contact)
.setNegativeButton(android.R.string.cancel, null)
.setPositiveButton(R.string.RecipientPreferenceActivity_block) { dialog, _ ->
sessionDialog {
title(R.string.RecipientPreferenceActivity_block_this_contact_question)
text(R.string.RecipientPreferenceActivity_you_will_no_longer_receive_messages_and_calls_from_this_contact)
buttons {
button(R.string.RecipientPreferenceActivity_block) {
lifecycleScope.launch(Dispatchers.IO) {
recipientDatabase.setBlocked(thread.recipient, true)
withContext(Dispatchers.Main) {
binding.recyclerView.adapter!!.notifyDataSetChanged()
dialog.dismiss()
binding.recyclerView.adapter?.notifyDataSetChanged()
}
}
}.show()
}
cancelButton()
}
}
}
private fun unblockConversation(thread: ThreadRecord) {
AlertDialog.Builder(this)
.setTitle(R.string.RecipientPreferenceActivity_unblock_this_contact_question)
.setMessage(R.string.RecipientPreferenceActivity_you_will_once_again_be_able_to_receive_messages_and_calls_from_this_contact)
.setNegativeButton(android.R.string.cancel, null)
.setPositiveButton(R.string.RecipientPreferenceActivity_unblock) { dialog, _ ->
sessionDialog {
title(R.string.RecipientPreferenceActivity_unblock_this_contact_question)
text(R.string.RecipientPreferenceActivity_you_will_once_again_be_able_to_receive_messages_and_calls_from_this_contact)
buttons {
button(R.string.RecipientPreferenceActivity_unblock) {
lifecycleScope.launch(Dispatchers.IO) {
recipientDatabase.setBlocked(thread.recipient, false)
withContext(Dispatchers.Main) {
binding.recyclerView.adapter!!.notifyDataSetChanged()
dialog.dismiss()
binding.recyclerView.adapter?.notifyDataSetChanged()
}
}
}.show()
}
cancelButton()
}
}
}
private fun setConversationMuted(thread: ThreadRecord, isMuted: Boolean) {
if (!isMuted) {
lifecycleScope.launch(Dispatchers.IO) {
recipientDatabase.setMuted(thread.recipient, 0)
withContext(Dispatchers.Main) {
binding.recyclerView.adapter!!.notifyDataSetChanged()
}
}
} else {
if (isMuted) {
MuteDialog.show(this) { until: Long ->
lifecycleScope.launch(Dispatchers.IO) {
recipientDatabase.setMuted(thread.recipient, until)
@ -536,6 +534,13 @@ class HomeActivity : PassphraseRequiredActionBarActivity(),
}
}
}
} else {
lifecycleScope.launch(Dispatchers.IO) {
recipientDatabase.setMuted(thread.recipient, 0)
withContext(Dispatchers.Main) {
binding.recyclerView.adapter!!.notifyDataSetChanged()
}
}
}
}
@ -574,48 +579,64 @@ class HomeActivity : PassphraseRequiredActionBarActivity(),
} else {
resources.getString(R.string.activity_home_delete_conversation_dialog_message)
}
val dialog = AlertDialog.Builder(this)
dialog.setMessage(message)
dialog.setPositiveButton(R.string.yes) { _, _ ->
lifecycleScope.launch(Dispatchers.Main) {
val context = this@HomeActivity as Context
// 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())) {
var isClosedGroup: Boolean
var groupPublicKey: String?
try {
groupPublicKey = GroupUtil.doubleDecodeGroupID(recipient.address.toString()).toHexString()
isClosedGroup = DatabaseComponent.get(context).lokiAPIDatabase().isClosedGroup(groupPublicKey)
} catch (e: IOException) {
groupPublicKey = null
isClosedGroup = false
}
if (isClosedGroup) {
MessageSender.explicitLeave(groupPublicKey!!, false)
sessionDialog {
text(message)
buttons {
button(R.string.yes) {
lifecycleScope.launch(Dispatchers.Main) {
val context = this@HomeActivity as Context
// 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())
) {
var isClosedGroup: Boolean
var groupPublicKey: String?
try {
groupPublicKey =
GroupUtil.doubleDecodeGroupID(recipient.address.toString())
.toHexString()
isClosedGroup = DatabaseComponent.get(context).lokiAPIDatabase()
.isClosedGroup(groupPublicKey)
} catch (e: IOException) {
groupPublicKey = null
isClosedGroup = false
}
if (isClosedGroup) {
MessageSender.explicitLeave(groupPublicKey!!, false)
}
}
// Delete the conversation
val v2OpenGroup =
DatabaseComponent.get(this@HomeActivity).lokiThreadDatabase()
.getOpenGroupChat(threadID)
if (v2OpenGroup != null) {
OpenGroupManager.delete(
v2OpenGroup.server,
v2OpenGroup.room,
this@HomeActivity
)
} else {
lifecycleScope.launch(Dispatchers.IO) {
threadDb.deleteConversation(threadID)
}
}
// Update the badge count
ApplicationContext.getInstance(context).messageNotifier.updateNotification(
context
)
// Notify the user
val toastMessage =
if (recipient.isGroupRecipient) R.string.MessageRecord_left_group else R.string.activity_home_conversation_deleted_message
Toast.makeText(context, toastMessage, Toast.LENGTH_LONG).show()
}
}
// Delete the conversation
val v2OpenGroup = DatabaseComponent.get(this@HomeActivity).lokiThreadDatabase().getOpenGroupChat(threadID)
if (v2OpenGroup != null) {
OpenGroupManager.delete(v2OpenGroup.server, v2OpenGroup.room, this@HomeActivity)
} else {
lifecycleScope.launch(Dispatchers.IO) {
threadDb.deleteConversation(threadID)
}
}
// Update the badge count
ApplicationContext.getInstance(context).messageNotifier.updateNotification(context)
// Notify the user
val toastMessage = if (recipient.isGroupRecipient) R.string.MessageRecord_left_group else R.string.activity_home_conversation_deleted_message
Toast.makeText(context, toastMessage, Toast.LENGTH_LONG).show()
button(R.string.no)
}
}
dialog.setNegativeButton(R.string.no) { _, _ ->
// Do nothing
}
dialog.create().show()
}
private fun openSettings() {
@ -624,22 +645,21 @@ class HomeActivity : PassphraseRequiredActionBarActivity(),
}
private fun showMessageRequests() {
val intent = Intent(this, MessageRequestsActivity::class.java)
push(intent)
Intent(this, MessageRequestsActivity::class.java).let(::push)
}
private fun hideMessageRequests() {
AlertDialog.Builder(this)
.setMessage("Hide message requests?")
.setPositiveButton(R.string.yes) { _, _ ->
textSecurePreferences.setHasHiddenMessageRequests()
setupMessageRequestsBanner()
homeViewModel.tryUpdateChannel()
sessionDialog {
text("Hide message requests?")
buttons {
button(R.string.yes) {
textSecurePreferences.setHasHiddenMessageRequests()
setupMessageRequestsBanner()
homeViewModel.tryUpdateChannel()
}
button(R.string.no)
}
.setNegativeButton(R.string.no) { _, _ ->
// Do nothing
}
.create().show()
}
}
private fun showNewConversation() {

View File

@ -20,6 +20,7 @@ import org.thoughtcrime.securesms.database.ThreadDatabase
import org.thoughtcrime.securesms.database.model.ThreadRecord
import org.thoughtcrime.securesms.mms.GlideApp
import org.thoughtcrime.securesms.mms.GlideRequests
import org.thoughtcrime.securesms.sessionDialog
import org.thoughtcrime.securesms.util.ConfigurationMessageUtilities
import org.thoughtcrime.securesms.util.push
import javax.inject.Inject
@ -77,34 +78,38 @@ class MessageRequestsActivity : PassphraseRequiredActionBarActivity(), Conversat
}
override fun onBlockConversationClick(thread: ThreadRecord) {
val dialog = AlertDialog.Builder(this)
dialog.setTitle(R.string.RecipientPreferenceActivity_block_this_contact_question)
.setMessage(R.string.message_requests_block_message)
.setPositiveButton(R.string.recipient_preferences__block) { _, _ ->
viewModel.blockMessageRequest(thread)
LoaderManager.getInstance(this).restartLoader(0, null, this)
}
.setNegativeButton(R.string.no) { _, _ ->
// Do nothing
}
dialog.create().show()
fun doBlock() {
viewModel.blockMessageRequest(thread)
LoaderManager.getInstance(this).restartLoader(0, null, this)
}
sessionDialog {
title(R.string.RecipientPreferenceActivity_block_this_contact_question)
text(R.string.message_requests_block_message)
buttons {
button(R.string.recipient_preferences__block) { doBlock() }
button(R.string.no)
}
}
}
override fun onDeleteConversationClick(thread: ThreadRecord) {
val dialog = AlertDialog.Builder(this)
dialog.setTitle(R.string.decline)
.setMessage(resources.getString(R.string.message_requests_decline_message))
.setPositiveButton(R.string.decline) { _,_ ->
viewModel.deleteMessageRequest(thread)
LoaderManager.getInstance(this).restartLoader(0, null, this)
lifecycleScope.launch(Dispatchers.IO) {
ConfigurationMessageUtilities.forceSyncConfigurationNowIfNeeded(this@MessageRequestsActivity)
}
fun doDecline() {
viewModel.deleteMessageRequest(thread)
LoaderManager.getInstance(this).restartLoader(0, null, this)
lifecycleScope.launch(Dispatchers.IO) {
ConfigurationMessageUtilities.forceSyncConfigurationNowIfNeeded(this@MessageRequestsActivity)
}
.setNegativeButton(R.string.no) { _, _ ->
// Do nothing
}
sessionDialog {
title(R.string.decline)
text(resources.getString(R.string.message_requests_decline_message))
buttons {
button(R.string.decline) { doDecline() }
button(R.string.no)
}
dialog.create().show()
}
}
private fun updateEmptyState() {
@ -114,18 +119,20 @@ class MessageRequestsActivity : PassphraseRequiredActionBarActivity(), Conversat
}
private fun deleteAllAndBlock() {
val dialog = AlertDialog.Builder(this)
dialog.setMessage(resources.getString(R.string.message_requests_clear_all_message))
dialog.setPositiveButton(R.string.yes) { _, _ ->
fun doDeleteAllAndBlock() {
viewModel.clearAllMessageRequests()
LoaderManager.getInstance(this).restartLoader(0, null, this)
lifecycleScope.launch(Dispatchers.IO) {
ConfigurationMessageUtilities.forceSyncConfigurationNowIfNeeded(this@MessageRequestsActivity)
}
}
dialog.setNegativeButton(R.string.no) { _, _ ->
// Do nothing
sessionDialog {
text(resources.getString(R.string.message_requests_clear_all_message))
buttons {
button(R.string.yes) { doDeleteAllAndBlock() }
button(R.string.no)
}
}
dialog.create().show()
}
}
}

View File

@ -20,6 +20,7 @@ import org.session.libsession.utilities.ThemeUtil
import org.thoughtcrime.securesms.ApplicationContext
import org.thoughtcrime.securesms.BaseActionBarActivity
import org.thoughtcrime.securesms.home.HomeActivity
import org.thoughtcrime.securesms.sessionDialog
import org.thoughtcrime.securesms.util.GlowViewUtilities
import org.thoughtcrime.securesms.util.PNModeView
import org.thoughtcrime.securesms.util.disableClipping
@ -151,12 +152,15 @@ class PNModeActivity : BaseActionBarActivity() {
private fun register() {
if (selectedOptionView == null) {
val dialog = AlertDialog.Builder(this)
dialog.setTitle(R.string.activity_pn_mode_no_option_picked_dialog_title)
dialog.setPositiveButton(R.string.ok) { _, _ -> }
dialog.create().show()
sessionDialog {
title(R.string.activity_pn_mode_no_option_picked_dialog_title)
buttons {
button(R.string.ok)
}
}
return
}
TextSecurePreferences.setIsUsingFCM(this, (selectedOptionView == binding.fcmOptionView))
val application = ApplicationContext.getInstance(this)
application.startPollingIfNeeded()

View File

@ -9,6 +9,7 @@ import dagger.hilt.android.AndroidEntryPoint
import network.loki.messenger.R
import network.loki.messenger.databinding.ActivityBlockedContactsBinding
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
import org.thoughtcrime.securesms.sessionDialog
@AndroidEntryPoint
class BlockedContactsActivity: PassphraseRequiredActionBarActivity(), View.OnClickListener {
@ -51,17 +52,14 @@ class BlockedContactsActivity: PassphraseRequiredActionBarActivity(), View.OnCli
getString(R.string.Unblock_dialog__message, stringBuilder.toString())
}
AlertDialog.Builder(this)
.setTitle(title)
.setMessage(message)
.setPositiveButton(R.string.continue_2) { d, _ ->
viewModel.unblock(contactsToUnblock)
d.dismiss()
sessionDialog {
title(title)
text(message)
buttons {
button(R.string.continue_2) { viewModel.unblock(contactsToUnblock) }
cancelButton()
}
.setNegativeButton(R.string.cancel) { d, _ ->
d.dismiss()
}
.show()
}
}
}

View File

@ -1,41 +1,24 @@
package org.thoughtcrime.securesms.preferences
import android.content.Context
import android.view.LayoutInflater
import androidx.appcompat.app.AlertDialog
import androidx.preference.ListPreference
import network.loki.messenger.databinding.DialogListPreferenceBinding
import org.thoughtcrime.securesms.sessionDialog
fun listPreferenceDialog(
context: Context,
listPreference: ListPreference,
dialogListener: () -> Unit
) : AlertDialog {
onChange: () -> Unit
) : AlertDialog = listPreference.run {
context.sessionDialog {
val index = entryValues.indexOf(value)
val options = entries.map(CharSequence::toString).toTypedArray()
val builder = AlertDialog.Builder(context)
val binding = DialogListPreferenceBinding.inflate(LayoutInflater.from(context))
binding.titleTextView.text = listPreference.dialogTitle
binding.messageTextView.text = listPreference.dialogMessage
builder.setView(binding.root)
val dialog = builder.show()
val valueIndex = listPreference.findIndexOfValue(listPreference.value)
RadioOptionAdapter(valueIndex) {
listPreference.value = it.value
dialog.dismiss()
dialogListener()
}
.apply {
listPreference.entryValues.zip(listPreference.entries) { value, title ->
RadioOption(value.toString(), title.toString())
}.let(this::submitList)
title(dialogTitle)
text(dialogMessage)
singleChoiceItems(options, index) {
listPreference.setValueIndex(it)
onChange()
}
.let { binding.recyclerView.adapter = it }
binding.closeButton.setOnClickListener { dialog.dismiss() }
return dialog
}
}

View File

@ -38,6 +38,7 @@ import org.thoughtcrime.securesms.mms.GlideRequests
import org.thoughtcrime.securesms.permissions.Permissions
import org.thoughtcrime.securesms.preferences.appearance.AppearanceSettingsActivity
import org.thoughtcrime.securesms.profiles.ProfileMediaConstraints
import org.thoughtcrime.securesms.sessionDialog
import org.thoughtcrime.securesms.util.BitmapDecodingException
import org.thoughtcrime.securesms.util.BitmapUtil
import org.thoughtcrime.securesms.util.ConfigurationMessageUtilities
@ -260,21 +261,19 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
}
private fun showEditProfilePictureUI() {
AlertDialog.Builder(this)
.setTitle(R.string.activity_settings_set_display_picture)
.setView(R.layout.dialog_change_avatar)
.setPositiveButton(R.string.activity_settings_upload) { _, _ ->
startAvatarSelection()
}
.setNegativeButton(R.string.cancel) { _, _ -> }
.apply {
sessionDialog {
title(R.string.activity_settings_set_display_picture)
view(R.layout.dialog_change_avatar)
buttons {
button(R.string.activity_settings_upload) { startAvatarSelection() }
if (TextSecurePreferences.getProfileAvatarId(context) != 0) {
setNeutralButton(R.string.activity_settings_remove) { _, _ -> removeAvatar() }
button(R.string.activity_settings_remove) { removeAvatar() }
}
cancelButton()
}
.show().apply {
findViewById<ProfilePictureView>(R.id.profile_picture_view)?.let(::setupProfilePictureView)
}
}.apply {
findViewById<ProfilePictureView>(R.id.profile_picture_view)?.let(::setupProfilePictureView)
}
}
private fun removeAvatar() {

View File

@ -18,6 +18,7 @@ import org.session.libsession.utilities.task.ProgressDialogAsyncTask
import org.session.libsignal.utilities.ExternalStorageUtil
import org.session.libsignal.utilities.Log
import org.thoughtcrime.securesms.mms.PartAuthority
import org.thoughtcrime.securesms.sessionDialog
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
@ -41,18 +42,19 @@ class SaveAttachmentTask : ProgressDialogAsyncTask<SaveAttachmentTask.Attachment
@JvmStatic
@JvmOverloads
fun showWarningDialog(context: Context, onAcceptListener: OnClickListener, count: Int = 1) {
val builder = AlertDialog.Builder(context)
builder.setTitle(R.string.ConversationFragment_save_to_sd_card)
builder.setIconAttribute(R.attr.dialog_alert_icon)
builder.setCancelable(true)
builder.setMessage(context.resources.getQuantityString(
fun showWarningDialog(context: Context, count: Int = 1, onAcceptListener: () -> Unit) {
context.sessionDialog {
title(R.string.ConversationFragment_save_to_sd_card)
setIconAttribute(R.attr.dialog_alert_icon)
text(context.resources.getQuantityString(
R.plurals.ConversationFragment_saving_n_media_to_storage_warning,
count,
count))
builder.setPositiveButton(R.string.yes, onAcceptListener)
builder.setNegativeButton(R.string.no, null)
builder.show()
buttons {
button(R.string.yes) { onAcceptListener() }
button(R.string.no)
}
}
}
}