Make kotlin code use dialog dsl

This commit is contained in:
andrew 2023-05-30 21:39:03 +09:30
parent 4ee68cbbb1
commit 1d8d678047
12 changed files with 160 additions and 225 deletions

View File

@ -417,7 +417,7 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity im
MediaItem mediaItem = getCurrentMediaItem(); MediaItem mediaItem = getCurrentMediaItem();
if (mediaItem == null) return; if (mediaItem == null) return;
SaveAttachmentTask.showWarningDialog(this, () -> { SaveAttachmentTask.showWarningDialog(this, 1, () -> {
Permissions.with(this) Permissions.with(this)
.request(android.Manifest.permission.WRITE_EXTERNAL_STORAGE) .request(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
.maxSdkVersion(Build.VERSION_CODES.P) .maxSdkVersion(Build.VERSION_CODES.P)

View File

@ -1,6 +1,7 @@
package org.thoughtcrime.securesms package org.thoughtcrime.securesms
import android.content.Context import android.content.Context
import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup.LayoutParams.MATCH_PARENT import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
@ -18,7 +19,6 @@ import androidx.core.view.setPadding
import androidx.core.view.updateMargins import androidx.core.view.updateMargins
import network.loki.messenger.R import network.loki.messenger.R
import org.thoughtcrime.securesms.util.toPx import org.thoughtcrime.securesms.util.toPx
import java.lang.ref.Reference
@DslMarker @DslMarker
@ -35,9 +35,15 @@ class SessionDialogBuilder(val context: Context) {
private val topView = LinearLayout(context).apply { orientation = VERTICAL } private val topView = LinearLayout(context).apply { orientation = VERTICAL }
.also(dialogBuilder::setCustomTitle) .also(dialogBuilder::setCustomTitle)
private val contentView = LinearLayout(context).apply { orientation = VERTICAL }
private val buttonLayout = LinearLayout(context)
private val root = LinearLayout(context).apply { orientation = VERTICAL } private val root = LinearLayout(context).apply { orientation = VERTICAL }
.also(dialogBuilder::setView) .also(dialogBuilder::setView)
.apply {
addView(contentView)
addView(buttonLayout)
}
fun title(@StringRes id: Int) = title(context.getString(id)) fun title(@StringRes id: Int) = title(context.getString(id))
@ -65,52 +71,31 @@ class SessionDialogBuilder(val context: Context) {
}.let(topView::addView) }.let(topView::addView)
} }
fun view(view: View) { fun view(view: View) = contentView.addView(view)
dialogBuilder.setView(view)
}
fun view(@LayoutRes layout: Int) { fun view(@LayoutRes layout: Int) = contentView.addView(LayoutInflater.from(context).inflate(layout, contentView))
dialogBuilder.setView(layout)
}
fun setIconAttribute(@AttrRes icon: Int) { fun iconAttribute(@AttrRes icon: Int): AlertDialog.Builder = dialogBuilder.setIconAttribute(icon)
dialogBuilder.setIconAttribute(icon)
}
fun singleChoiceItems( fun singleChoiceItems(
options: Array<String>, options: Array<String>,
currentSelected: Int, currentSelected: Int,
onSelect: (Int) -> Unit onSelect: (Int) -> Unit
) { ): AlertDialog.Builder = dialogBuilder.setSingleChoiceItems(
dialogBuilder.setSingleChoiceItems(
options, options,
currentSelected currentSelected
) { dialog, it -> onSelect(it); dialog.dismiss() } ) { 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()
}
@DialogDsl
class ButtonsBuilder(val context: Context, val dismiss: () -> Unit) {
val root = LinearLayout(context)
fun destructiveButton( fun destructiveButton(
@StringRes text: Int, @StringRes text: Int,
@StringRes contentDescription: Int, @StringRes contentDescription: Int,
listener: () -> Unit = {} listener: () -> Unit = {}
) { ) = button(
button(
text, text,
contentDescription, contentDescription,
R.style.Widget_Session_Button_Dialog_DestructiveText, R.style.Widget_Session_Button_Dialog_DestructiveText,
listener listener
) )
}
fun cancelButton(listener: (() -> Unit) = {}) = button(android.R.string.cancel, R.string.AccessibilityId_cancel_button, listener = listener) fun cancelButton(listener: (() -> Unit) = {}) = button(android.R.string.cancel, R.string.AccessibilityId_cancel_button, listener = listener)
@ -119,9 +104,7 @@ class ButtonsBuilder(val context: Context, val dismiss: () -> Unit) {
@StringRes contentDescriptionRes: Int = 0, @StringRes contentDescriptionRes: Int = 0,
@StyleRes style: Int = R.style.Widget_Session_Button_Dialog_UnimportantText, @StyleRes style: Int = R.style.Widget_Session_Button_Dialog_UnimportantText,
listener: (() -> Unit) = {} listener: (() -> Unit) = {}
) { ) = Button(context, null, 0, style).apply {
Button(context, null, 0, style)
.apply {
setText(text) setText(text)
contentDescription = resources.getString(contentDescriptionRes) contentDescription = resources.getString(contentDescriptionRes)
layoutParams = LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT, 1f) layoutParams = LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT, 1f)
@ -130,14 +113,9 @@ class ButtonsBuilder(val context: Context, val dismiss: () -> Unit) {
listener.invoke() listener.invoke()
dismiss() dismiss()
} }
} }.let(buttonLayout::addView)
.let(root::addView)
}
internal fun build(build: ButtonsBuilder.() -> Unit): LinearLayout { fun show(): AlertDialog = dialogBuilder.show()
build()
return root
}
} }
fun Context.sessionDialog(build: SessionDialogBuilder.() -> Unit): AlertDialog = fun Context.sessionDialog(build: SessionDialogBuilder.() -> Unit): AlertDialog =

View File

@ -965,7 +965,6 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
sessionDialog { sessionDialog {
title(R.string.RecipientPreferenceActivity_block_this_contact_question) title(R.string.RecipientPreferenceActivity_block_this_contact_question)
text(R.string.RecipientPreferenceActivity_you_will_no_longer_receive_messages_and_calls_from_this_contact) text(R.string.RecipientPreferenceActivity_you_will_no_longer_receive_messages_and_calls_from_this_contact)
buttons {
destructiveButton(R.string.RecipientPreferenceActivity_block, R.string.AccessibilityId_block_confirm) { destructiveButton(R.string.RecipientPreferenceActivity_block, R.string.AccessibilityId_block_confirm) {
viewModel.block() viewModel.block()
if (deleteThread) { if (deleteThread) {
@ -976,7 +975,6 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
cancelButton() cancelButton()
} }
} }
}
override fun copySessionID(sessionId: String) { override fun copySessionID(sessionId: String) {
val clip = ClipData.newPlainText("Session ID", sessionId) val clip = ClipData.newPlainText("Session ID", sessionId)
@ -1018,7 +1016,6 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
sessionDialog { sessionDialog {
title(R.string.ConversationActivity_unblock_this_contact_question) title(R.string.ConversationActivity_unblock_this_contact_question)
text(R.string.ConversationActivity_you_will_once_again_be_able_to_receive_messages_and_calls_from_this_contact) text(R.string.ConversationActivity_you_will_once_again_be_able_to_receive_messages_and_calls_from_this_contact)
buttons {
destructiveButton( destructiveButton(
R.string.ConversationActivity_unblock, R.string.ConversationActivity_unblock,
R.string.AccessibilityId_block_confirm R.string.AccessibilityId_block_confirm
@ -1026,7 +1023,6 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
cancelButton() cancelButton()
} }
} }
}
// `position` is the adapter position; not the visual position // `position` is the adapter position; not the visual position
private fun handlePress(message: MessageRecord, position: Int, view: VisibleMessageView, event: MotionEvent) { private fun handlePress(message: MessageRecord, position: Int, view: VisibleMessageView, event: MotionEvent) {
@ -1464,14 +1460,12 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
sessionDialog { sessionDialog {
title(R.string.giphy_permission_title) title(R.string.giphy_permission_title)
text(R.string.giphy_permission_message) text(R.string.giphy_permission_message)
buttons {
button(R.string.continue_2) { button(R.string.continue_2) {
textSecurePreferences.setHasSeenGIFMetaDataWarning() textSecurePreferences.setHasSeenGIFMetaDataWarning()
selectGif() selectGif()
} }
cancelButton() cancelButton()
} }
}
} else { } else {
selectGif() selectGif()
} }
@ -1629,11 +1623,9 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
sessionDialog { sessionDialog {
title(resources.getQuantityString(R.plurals.ConversationFragment_delete_selected_messages, messageCount, messageCount)) 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)) 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() } button(R.string.delete) { messages.forEach(viewModel::deleteForEveryone); endActionMode() }
cancelButton { endActionMode() } cancelButton { endActionMode() }
} }
}
} else if (allSentByCurrentUser && allHasHash) { } else if (allSentByCurrentUser && allHasHash) {
val bottomSheet = DeleteOptionsBottomSheet() val bottomSheet = DeleteOptionsBottomSheet()
bottomSheet.recipient = recipient bottomSheet.recipient = recipient
@ -1658,35 +1650,29 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
sessionDialog { sessionDialog {
title(resources.getQuantityString(R.plurals.ConversationFragment_delete_selected_messages, messageCount, messageCount)) 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)) 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() } button(R.string.delete) { messages.forEach(viewModel::deleteLocally); endActionMode() }
cancelButton(::endActionMode) cancelButton(::endActionMode)
} }
} }
} }
}
override fun banUser(messages: Set<MessageRecord>) { override fun banUser(messages: Set<MessageRecord>) {
sessionDialog { sessionDialog {
title(R.string.ConversationFragment_ban_selected_user) 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.") 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() } button(R.string.ban) { viewModel.banUser(messages.first().individualRecipient); endActionMode() }
cancelButton(::endActionMode) cancelButton(::endActionMode)
} }
} }
}
override fun banAndDeleteAll(messages: Set<MessageRecord>) { override fun banAndDeleteAll(messages: Set<MessageRecord>) {
sessionDialog { sessionDialog {
title(R.string.ConversationFragment_ban_selected_user) 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.") 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() } button(R.string.ban) { viewModel.banAndDeleteAll(messages.first().individualRecipient); endActionMode() }
cancelButton(::endActionMode) cancelButton(::endActionMode)
} }
} }
}
override fun copyMessages(messages: Set<MessageRecord>) { override fun copyMessages(messages: Set<MessageRecord>) {
val sortedMessages = messages.sortedBy { it.dateSent } val sortedMessages = messages.sortedBy { it.dateSent }

View File

@ -150,7 +150,6 @@ class ConversationAdapter(
context.sessionDialog { context.sessionDialog {
title(R.string.CallNotificationBuilder_first_call_title) title(R.string.CallNotificationBuilder_first_call_title)
text(R.string.CallNotificationBuilder_first_call_message) text(R.string.CallNotificationBuilder_first_call_message)
buttons {
button(R.string.activity_settings_title) { button(R.string.activity_settings_title) {
Intent(context, PrivacySettingsActivity::class.java) Intent(context, PrivacySettingsActivity::class.java)
.let(context::startActivity) .let(context::startActivity)
@ -158,7 +157,6 @@ class ConversationAdapter(
cancelButton() cancelButton()
} }
} }
}
} else { } else {
viewHolder.view.setOnClickListener(null) viewHolder.view.setOnClickListener(null)
} }

View File

@ -190,13 +190,11 @@ object ConversationMenuHelper {
context.sessionDialog { context.sessionDialog {
title(R.string.ConversationActivity_call_title) title(R.string.ConversationActivity_call_title)
text(R.string.ConversationActivity_call_prompt) text(R.string.ConversationActivity_call_prompt)
buttons {
button(R.string.activity_settings_title, R.string.AccessibilityId_settings) { button(R.string.activity_settings_title, R.string.AccessibilityId_settings) {
Intent(context, PrivacySettingsActivity::class.java).let(context::startActivity) Intent(context, PrivacySettingsActivity::class.java).let(context::startActivity)
} }
cancelButton() cancelButton()
} }
}
return return
} }
@ -308,7 +306,6 @@ object ConversationMenuHelper {
context.sessionDialog { context.sessionDialog {
title(R.string.ConversationActivity_leave_group) title(R.string.ConversationActivity_leave_group)
text(message) text(message)
buttons {
button(R.string.yes) { button(R.string.yes) {
try { try {
val groupPublicKey = doubleDecodeGroupID(thread.address.toString()).toHexString() val groupPublicKey = doubleDecodeGroupID(thread.address.toString()).toHexString()
@ -323,7 +320,6 @@ object ConversationMenuHelper {
button(R.string.no) button(R.string.no)
} }
} }
}
private fun inviteContacts(context: Context, thread: Recipient) { private fun inviteContacts(context: Context, thread: Recipient) {
if (!thread.isOpenGroupRecipient) { return } if (!thread.isOpenGroupRecipient) { return }

View File

@ -492,7 +492,6 @@ class HomeActivity : PassphraseRequiredActionBarActivity(),
sessionDialog { sessionDialog {
title(R.string.RecipientPreferenceActivity_block_this_contact_question) title(R.string.RecipientPreferenceActivity_block_this_contact_question)
text(R.string.RecipientPreferenceActivity_you_will_no_longer_receive_messages_and_calls_from_this_contact) text(R.string.RecipientPreferenceActivity_you_will_no_longer_receive_messages_and_calls_from_this_contact)
buttons {
button(R.string.RecipientPreferenceActivity_block) { button(R.string.RecipientPreferenceActivity_block) {
lifecycleScope.launch(Dispatchers.IO) { lifecycleScope.launch(Dispatchers.IO) {
recipientDatabase.setBlocked(thread.recipient, true) recipientDatabase.setBlocked(thread.recipient, true)
@ -504,13 +503,11 @@ class HomeActivity : PassphraseRequiredActionBarActivity(),
cancelButton() cancelButton()
} }
} }
}
private fun unblockConversation(thread: ThreadRecord) { private fun unblockConversation(thread: ThreadRecord) {
sessionDialog { sessionDialog {
title(R.string.RecipientPreferenceActivity_unblock_this_contact_question) 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) text(R.string.RecipientPreferenceActivity_you_will_once_again_be_able_to_receive_messages_and_calls_from_this_contact)
buttons {
button(R.string.RecipientPreferenceActivity_unblock) { button(R.string.RecipientPreferenceActivity_unblock) {
lifecycleScope.launch(Dispatchers.IO) { lifecycleScope.launch(Dispatchers.IO) {
recipientDatabase.setBlocked(thread.recipient, false) recipientDatabase.setBlocked(thread.recipient, false)
@ -522,7 +519,6 @@ class HomeActivity : PassphraseRequiredActionBarActivity(),
cancelButton() cancelButton()
} }
} }
}
private fun setConversationMuted(thread: ThreadRecord, isMuted: Boolean) { private fun setConversationMuted(thread: ThreadRecord, isMuted: Boolean) {
if (isMuted) { if (isMuted) {
@ -582,7 +578,6 @@ class HomeActivity : PassphraseRequiredActionBarActivity(),
sessionDialog { sessionDialog {
text(message) text(message)
buttons {
button(R.string.yes) { button(R.string.yes) {
lifecycleScope.launch(Dispatchers.Main) { lifecycleScope.launch(Dispatchers.Main) {
val context = this@HomeActivity as Context val context = this@HomeActivity as Context
@ -637,7 +632,6 @@ class HomeActivity : PassphraseRequiredActionBarActivity(),
button(R.string.no) button(R.string.no)
} }
} }
}
private fun openSettings() { private fun openSettings() {
val intent = Intent(this, SettingsActivity::class.java) val intent = Intent(this, SettingsActivity::class.java)
@ -651,7 +645,6 @@ class HomeActivity : PassphraseRequiredActionBarActivity(),
private fun hideMessageRequests() { private fun hideMessageRequests() {
sessionDialog { sessionDialog {
text("Hide message requests?") text("Hide message requests?")
buttons {
button(R.string.yes) { button(R.string.yes) {
textSecurePreferences.setHasHiddenMessageRequests() textSecurePreferences.setHasHiddenMessageRequests()
setupMessageRequestsBanner() setupMessageRequestsBanner()
@ -660,7 +653,6 @@ class HomeActivity : PassphraseRequiredActionBarActivity(),
button(R.string.no) button(R.string.no)
} }
} }
}
private fun showNewConversation() { private fun showNewConversation() {
NewConversationFragment().show(supportFragmentManager, "NewConversationFragment") NewConversationFragment().show(supportFragmentManager, "NewConversationFragment")

View File

@ -86,12 +86,10 @@ class MessageRequestsActivity : PassphraseRequiredActionBarActivity(), Conversat
sessionDialog { sessionDialog {
title(R.string.RecipientPreferenceActivity_block_this_contact_question) title(R.string.RecipientPreferenceActivity_block_this_contact_question)
text(R.string.message_requests_block_message) text(R.string.message_requests_block_message)
buttons {
button(R.string.recipient_preferences__block) { doBlock() } button(R.string.recipient_preferences__block) { doBlock() }
button(R.string.no) button(R.string.no)
} }
} }
}
override fun onDeleteConversationClick(thread: ThreadRecord) { override fun onDeleteConversationClick(thread: ThreadRecord) {
fun doDecline() { fun doDecline() {
@ -105,12 +103,10 @@ class MessageRequestsActivity : PassphraseRequiredActionBarActivity(), Conversat
sessionDialog { sessionDialog {
title(R.string.decline) title(R.string.decline)
text(resources.getString(R.string.message_requests_decline_message)) text(resources.getString(R.string.message_requests_decline_message))
buttons {
button(R.string.decline) { doDecline() } button(R.string.decline) { doDecline() }
button(R.string.no) button(R.string.no)
} }
} }
}
private fun updateEmptyState() { private fun updateEmptyState() {
val threadCount = (binding.recyclerView.adapter as MessageRequestsAdapter).itemCount val threadCount = (binding.recyclerView.adapter as MessageRequestsAdapter).itemCount
@ -129,10 +125,8 @@ class MessageRequestsActivity : PassphraseRequiredActionBarActivity(), Conversat
sessionDialog { sessionDialog {
text(resources.getString(R.string.message_requests_clear_all_message)) text(resources.getString(R.string.message_requests_clear_all_message))
buttons {
button(R.string.yes) { doDeleteAllAndBlock() } button(R.string.yes) { doDeleteAllAndBlock() }
button(R.string.no) button(R.string.no)
} }
} }
} }
}

View File

@ -154,10 +154,8 @@ class PNModeActivity : BaseActionBarActivity() {
if (selectedOptionView == null) { if (selectedOptionView == null) {
sessionDialog { sessionDialog {
title(R.string.activity_pn_mode_no_option_picked_dialog_title) title(R.string.activity_pn_mode_no_option_picked_dialog_title)
buttons {
button(R.string.ok) button(R.string.ok)
} }
}
return return
} }

View File

@ -55,13 +55,11 @@ class BlockedContactsActivity: PassphraseRequiredActionBarActivity(), View.OnCli
sessionDialog { sessionDialog {
title(title) title(title)
text(message) text(message)
buttons {
button(R.string.continue_2) { viewModel.unblock(contactsToUnblock) } button(R.string.continue_2) { viewModel.unblock(contactsToUnblock) }
cancelButton() cancelButton()
} }
} }
} }
}
override fun onCreate(savedInstanceState: Bundle?, ready: Boolean) { override fun onCreate(savedInstanceState: Bundle?, ready: Boolean) {
super.onCreate(savedInstanceState, ready) super.onCreate(savedInstanceState, ready)

View File

@ -264,13 +264,11 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
sessionDialog { sessionDialog {
title(R.string.activity_settings_set_display_picture) title(R.string.activity_settings_set_display_picture)
view(R.layout.dialog_change_avatar) view(R.layout.dialog_change_avatar)
buttons {
button(R.string.activity_settings_upload) { startAvatarSelection() } button(R.string.activity_settings_upload) { startAvatarSelection() }
if (TextSecurePreferences.getProfileAvatarId(context) != 0) { if (TextSecurePreferences.getProfileAvatarId(context) != 0) {
button(R.string.activity_settings_remove) { removeAvatar() } button(R.string.activity_settings_remove) { removeAvatar() }
} }
cancelButton() cancelButton()
}
}.apply { }.apply {
findViewById<ProfilePictureView>(R.id.profile_picture_view)?.let(::setupProfilePictureView) findViewById<ProfilePictureView>(R.id.profile_picture_view)?.let(::setupProfilePictureView)
} }

View File

@ -3,7 +3,6 @@ package org.thoughtcrime.securesms.util
import android.content.ContentResolver import android.content.ContentResolver
import android.content.ContentValues import android.content.ContentValues
import android.content.Context import android.content.Context
import android.content.DialogInterface.OnClickListener
import android.media.MediaScannerConnection import android.media.MediaScannerConnection
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
@ -12,7 +11,6 @@ import android.provider.MediaStore
import android.text.TextUtils import android.text.TextUtils
import android.webkit.MimeTypeMap import android.webkit.MimeTypeMap
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import network.loki.messenger.R import network.loki.messenger.R
import org.session.libsession.utilities.task.ProgressDialogAsyncTask import org.session.libsession.utilities.task.ProgressDialogAsyncTask
import org.session.libsignal.utilities.ExternalStorageUtil import org.session.libsignal.utilities.ExternalStorageUtil
@ -31,7 +29,12 @@ import java.util.concurrent.TimeUnit
* Saves attachment files to an external storage using [MediaStore] API. * Saves attachment files to an external storage using [MediaStore] API.
* Requires [android.Manifest.permission.WRITE_EXTERNAL_STORAGE] on API 28 and below. * Requires [android.Manifest.permission.WRITE_EXTERNAL_STORAGE] on API 28 and below.
*/ */
class SaveAttachmentTask : ProgressDialogAsyncTask<SaveAttachmentTask.Attachment, Void, Pair<Int, String?>> { class SaveAttachmentTask @JvmOverloads constructor(context: Context, count: Int = 1) :
ProgressDialogAsyncTask<SaveAttachmentTask.Attachment, Void, Pair<Int, String?>>(
context,
context.resources.getQuantityString(R.plurals.ConversationFragment_saving_n_attachments, count, count),
context.resources.getQuantityString(R.plurals.ConversationFragment_saving_n_attachments_to_sd_card, count, count)
) {
companion object { companion object {
@JvmStatic @JvmStatic
@ -42,31 +45,25 @@ class SaveAttachmentTask : ProgressDialogAsyncTask<SaveAttachmentTask.Attachment
@JvmStatic @JvmStatic
@JvmOverloads @JvmOverloads
fun showWarningDialog(context: Context, count: Int = 1, onAcceptListener: () -> Unit) { fun showWarningDialog(context: Context, count: Int = 1, onAcceptListener: () -> Unit = {}) {
context.sessionDialog { context.sessionDialog {
title(R.string.ConversationFragment_save_to_sd_card) title(R.string.ConversationFragment_save_to_sd_card)
setIconAttribute(R.attr.dialog_alert_icon) iconAttribute(R.attr.dialog_alert_icon)
text(context.resources.getQuantityString( text(context.resources.getQuantityString(
R.plurals.ConversationFragment_saving_n_media_to_storage_warning, R.plurals.ConversationFragment_saving_n_media_to_storage_warning,
count, count,
count)) count))
buttons {
button(R.string.yes) { onAcceptListener() } button(R.string.yes) { onAcceptListener() }
button(R.string.no) button(R.string.no)
} }
} }
} }
}
private val contextReference: WeakReference<Context> private val contextReference: WeakReference<Context>
private val attachmentCount: Int private val attachmentCount: Int = count
@JvmOverloads init {
constructor(context: Context, count: Int = 1): super(context,
context.resources.getQuantityString(R.plurals.ConversationFragment_saving_n_attachments, count, count),
context.resources.getQuantityString(R.plurals.ConversationFragment_saving_n_attachments_to_sd_card, count, count)) {
this.contextReference = WeakReference(context) this.contextReference = WeakReference(context)
this.attachmentCount = count
} }
override fun doInBackground(vararg attachments: Attachment?): Pair<Int, String?> { override fun doInBackground(vararg attachments: Attachment?): Pair<Int, String?> {