Commit aaf1e7bd authored by Mygod's avatar Mygod Committed by Max Lv

Migrate AlertDialogFragment to fragment result API

parent f0b6ee48
......@@ -71,7 +71,6 @@ dependencies {
api("androidx.appcompat:appcompat:1.2.0")
api("androidx.core:core-ktx:1.5.0-rc01")
api("androidx.fragment:fragment-ktx:1.3.2")
api("androidx.lifecycle:lifecycle-common-java8:$lifecycleVersion")
api("androidx.lifecycle:lifecycle-livedata-core-ktx:$lifecycleVersion")
api("androidx.preference:preference:1.1.1")
......
......@@ -29,9 +29,9 @@ import androidx.appcompat.app.AppCompatActivity
import com.github.shadowsocks.core.R
import com.github.shadowsocks.database.Profile
import com.github.shadowsocks.database.ProfileManager
import com.github.shadowsocks.plugin.AlertDialogFragment
import com.github.shadowsocks.plugin.Empty
import com.github.shadowsocks.plugin.showAllowingStateLoss
import com.github.shadowsocks.plugin.fragment.AlertDialogFragment
import com.github.shadowsocks.plugin.fragment.Empty
import com.github.shadowsocks.plugin.fragment.showAllowingStateLoss
import kotlinx.parcelize.Parcelize
class UrlImportActivity : AppCompatActivity() {
......@@ -68,6 +68,9 @@ class UrlImportActivity : AppCompatActivity() {
private fun handleShareIntent() = intent.data?.toString()?.let { sharedStr ->
val profiles = Profile.findAllUrls(sharedStr, Core.currentProfile?.main).toList()
if (profiles.isEmpty()) null else ImportProfilesDialogFragment().withArg(ProfilesArg(profiles))
if (profiles.isEmpty()) null else ImportProfilesDialogFragment().apply {
arg(ProfilesArg(profiles))
key()
}
}
}
......@@ -30,9 +30,9 @@ import androidx.activity.result.component2
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import com.github.shadowsocks.plugin.AlertDialogFragment
import com.github.shadowsocks.plugin.Empty
import com.github.shadowsocks.plugin.PluginContract
import com.github.shadowsocks.plugin.fragment.AlertDialogFragment
import com.github.shadowsocks.plugin.fragment.Empty
import com.github.shadowsocks.preference.DataStore
import com.github.shadowsocks.widget.ListHolderListener
......@@ -71,8 +71,9 @@ class ProfileConfigActivity : AppCompatActivity() {
override fun onOptionsItemSelected(item: MenuItem) = child.onOptionsItemSelected(item)
override fun onBackPressed() {
if (DataStore.dirty) UnsavedChangesDialogFragment().show(child, ProfileConfigFragment.REQUEST_UNSAVED_CHANGES)
else super.onBackPressed()
if (DataStore.dirty) UnsavedChangesDialogFragment().apply {
key()
}.show(supportFragmentManager, null) else super.onBackPressed()
}
val pluginHelp = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
......
......@@ -41,6 +41,9 @@ import androidx.preference.*
import com.github.shadowsocks.database.Profile
import com.github.shadowsocks.database.ProfileManager
import com.github.shadowsocks.plugin.*
import com.github.shadowsocks.plugin.fragment.AlertDialogFragment
import com.github.shadowsocks.plugin.fragment.Empty
import com.github.shadowsocks.plugin.fragment.showAllowingStateLoss
import com.github.shadowsocks.preference.*
import com.github.shadowsocks.utils.*
import com.github.shadowsocks.widget.ListListener
......@@ -54,7 +57,6 @@ class ProfileConfigFragment : PreferenceFragmentCompat(),
companion object PasswordSummaryProvider : Preference.SummaryProvider<EditTextPreference> {
override fun provideSummary(preference: EditTextPreference?) = "\u2022".repeat(preference?.text?.length ?: 0)
const val REQUEST_UNSAVED_CHANGES = 2
private const val REQUEST_PICK_PLUGIN = 3
}
......@@ -127,6 +129,12 @@ class ProfileConfigFragment : PreferenceFragmentCompat(),
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
ViewCompat.setOnApplyWindowInsetsListener(listView, ListListener)
AlertDialogFragment.setResultListener<ProfileConfigActivity.UnsavedChangesDialogFragment, Empty>(this) { which, ret ->
when (which) {
DialogInterface.BUTTON_POSITIVE -> saveAndExit()
DialogInterface.BUTTON_NEGATIVE -> requireActivity().finish()
}
}
}
private fun initPlugins() {
......@@ -216,34 +224,31 @@ class ProfileConfigFragment : PreferenceFragmentCompat(),
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
when (requestCode) {
REQUEST_PICK_PLUGIN -> if (resultCode == Activity.RESULT_OK) {
val selected = plugin.plugins.lookup.getValue(
data?.getStringExtra(PluginPreferenceDialogFragment.KEY_SELECTED_ID)!!)
val override = pluginConfiguration.pluginsOptions.keys.firstOrNull {
plugin.plugins.lookup[it] == selected
}
pluginConfiguration = PluginConfiguration(pluginConfiguration.pluginsOptions, override ?: selected.id)
DataStore.plugin = pluginConfiguration.toString()
DataStore.dirty = true
plugin.value = pluginConfiguration.selected
pluginConfigure.isEnabled = selected !is NoPlugin
pluginConfigure.text = pluginConfiguration.getOptions().toString()
if (!selected.trusted) {
Snackbar.make(requireView(), R.string.plugin_untrusted, Snackbar.LENGTH_LONG).show()
}
if (requestCode != REQUEST_PICK_PLUGIN) super.onActivityResult(requestCode, resultCode, data)
else if (resultCode == Activity.RESULT_OK) {
val selected = plugin.plugins.lookup.getValue(
data?.getStringExtra(PluginPreferenceDialogFragment.KEY_SELECTED_ID)!!)
val override = pluginConfiguration.pluginsOptions.keys.firstOrNull {
plugin.plugins.lookup[it] == selected
}
REQUEST_UNSAVED_CHANGES -> when (resultCode) {
DialogInterface.BUTTON_POSITIVE -> saveAndExit()
DialogInterface.BUTTON_NEGATIVE -> requireActivity().finish()
pluginConfiguration = PluginConfiguration(pluginConfiguration.pluginsOptions, override ?: selected.id)
DataStore.plugin = pluginConfiguration.toString()
DataStore.dirty = true
plugin.value = pluginConfiguration.selected
pluginConfigure.isEnabled = selected !is NoPlugin
pluginConfigure.text = pluginConfiguration.getOptions().toString()
if (!selected.trusted) {
Snackbar.make(requireView(), R.string.plugin_untrusted, Snackbar.LENGTH_LONG).show()
}
else -> super.onActivityResult(requestCode, resultCode, data)
}
}
override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
R.id.action_delete -> {
DeleteConfirmationDialogFragment().withArg(ProfileIdArg(profileId)).show(this)
DeleteConfirmationDialogFragment().apply {
arg(ProfileIdArg(profileId))
key()
}.show(parentFragmentManager, null)
true
}
R.id.action_apply -> {
......
......@@ -22,7 +22,6 @@ package com.github.shadowsocks.acl
import android.annotation.SuppressLint
import android.content.DialogInterface
import android.content.Intent
import android.os.Bundle
import android.os.Parcelable
import android.text.Editable
......@@ -46,7 +45,7 @@ import com.github.shadowsocks.R
import com.github.shadowsocks.ToolbarFragment
import com.github.shadowsocks.bg.BaseService
import com.github.shadowsocks.net.Subnet
import com.github.shadowsocks.plugin.AlertDialogFragment
import com.github.shadowsocks.plugin.fragment.AlertDialogFragment
import com.github.shadowsocks.utils.asIterable
import com.github.shadowsocks.utils.readableMessage
import com.github.shadowsocks.utils.resolveResourceId
......@@ -65,9 +64,6 @@ import java.util.regex.PatternSyntaxException
class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener, ActionMode.Callback {
companion object {
private const val REQUEST_CODE_ADD = 1
private const val REQUEST_CODE_EDIT = 2
private const val SELECTED_SUBNETS = "com.github.shadowsocks.acl.CustomRulesFragment.SELECTED_SUBNETS"
private const val SELECTED_HOSTNAMES = "com.github.shadowsocks.acl.CustomRulesFragment.SELECTED_HOSTNAMES"
private const val SELECTED_URLS = "com.github.shadowsocks.acl.CustomRulesFragment.SELECTED_URLS"
......@@ -95,8 +91,10 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener,
fun toAny() = if (isUrl) URL(item) else Subnet.fromString(item) ?: item
}
@Parcelize
data class AclEditResult(val edited: AclItem, val replacing: AclItem) : Parcelable
class AclRuleDialogFragment : AlertDialogFragment<AclItem, AclEditResult>(),
data class AclArg(val item: AclItem? = null) : Parcelable
@Parcelize
data class AclEditResult(val edited: AclItem?, val replacing: AclItem?) : Parcelable
class AclRuleDialogFragment : AlertDialogFragment<AclArg, AclEditResult>(),
TextWatcher, AdapterView.OnItemSelectedListener {
private lateinit var templateSelector: Spinner
private lateinit var editText: EditText
......@@ -111,8 +109,10 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener,
editText = view.findViewById(R.id.content)
inputLayout = view.findViewById(R.id.content_layout)
templateSelector.setSelection(Template.Generic.ordinal)
editText.setText(arg.item)
val arg = arg.item
editText.setText(arg?.item)
when {
arg == null -> { }
arg.isUrl -> templateSelector.setSelection(Template.Url.ordinal)
Subnet.fromString(arg.item) == null -> {
val match = domainPattern.find(arg.item)
......@@ -128,7 +128,7 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener,
setTitle(R.string.edit_rule)
setPositiveButton(android.R.string.ok, listener)
setNegativeButton(android.R.string.cancel, null)
if (arg.item.isNotEmpty()) setNeutralButton(R.string.delete, listener)
if (!arg?.item.isNullOrEmpty()) setNeutralButton(R.string.delete, listener)
setView(view)
}
......@@ -183,9 +183,9 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener,
.replace(".", "\\.").let { "(?:^|\\.)$it\$" })
Template.Url -> AclItem(text, true)
}
}, arg)
}, arg.item)
}
DialogInterface.BUTTON_NEUTRAL -> AclEditResult(arg, arg)
DialogInterface.BUTTON_NEUTRAL -> AclEditResult(null, arg.item)
else -> null
}
......@@ -223,8 +223,10 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener,
}
override fun onClick(v: View?) {
if (selectedItems.isNotEmpty()) onLongClick(v)
else AclRuleDialogFragment().withArg(AclItem(item)).show(this@CustomRulesFragment, REQUEST_CODE_EDIT)
if (selectedItems.isNotEmpty()) onLongClick(v) else AclRuleDialogFragment().apply {
arg(AclArg(AclItem(item)))
key()
}.show(parentFragmentManager, null)
}
override fun onLongClick(v: View?): Boolean {
if (!selectedItems.add(item)) selectedItems.remove(item) // toggle
......@@ -379,6 +381,14 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener,
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
ViewCompat.setOnApplyWindowInsetsListener(view, ListHolderListener)
AlertDialogFragment.setResultListener<AclRuleDialogFragment, AclEditResult>(this) { which, ret ->
val (edited, replacing) = ret ?: return@setResultListener
replacing?.toAny()?.let { item ->
adapter.remove(item)
if (which == DialogInterface.BUTTON_NEUTRAL) undoManager.remove(Pair(-1, item))
}
if (edited != null) adapter.add(edited.toAny())?.also { list.post { list.scrollToPosition(it) } }
}
if (savedInstanceState != null) {
selectedItems.addAll(savedInstanceState.getStringArray(SELECTED_SUBNETS)
?.mapNotNull { Subnet.fromString(it) } ?: listOf())
......@@ -442,7 +452,10 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener,
override fun onMenuItemClick(item: MenuItem): Boolean = when (item.itemId) {
R.id.action_manual_settings -> {
AclRuleDialogFragment().withArg(AclItem()).show(this, REQUEST_CODE_ADD)
AclRuleDialogFragment().apply {
arg(AclArg(AclItem()))
key()
}.show(parentFragmentManager, null)
true
}
R.id.action_import_clipboard -> {
......@@ -464,25 +477,6 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener,
else -> false
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
val editing = when (requestCode) {
REQUEST_CODE_ADD -> false
REQUEST_CODE_EDIT -> true
else -> return super.onActivityResult(requestCode, resultCode, data)
}
val ret by lazy { AlertDialogFragment.getRet<AclEditResult>(data!!) }
when (resultCode) {
DialogInterface.BUTTON_POSITIVE -> {
if (editing) adapter.remove(ret.replacing.toAny())
adapter.add(ret.edited.toAny())?.also { list.post { list.scrollToPosition(it) } }
}
DialogInterface.BUTTON_NEUTRAL -> ret.replacing.toAny().let { item ->
adapter.remove(item)
undoManager.remove(Pair(-1, item))
}
}
}
override fun onDetach() {
undoManager.flush()
mode?.finish()
......
......@@ -41,7 +41,7 @@ import androidx.recyclerview.widget.RecyclerView
import com.github.shadowsocks.MainActivity
import com.github.shadowsocks.R
import com.github.shadowsocks.ToolbarFragment
import com.github.shadowsocks.plugin.AlertDialogFragment
import com.github.shadowsocks.plugin.fragment.AlertDialogFragment
import com.github.shadowsocks.utils.readableMessage
import com.github.shadowsocks.widget.ListHolderListener
import com.github.shadowsocks.widget.MainListListener
......@@ -53,18 +53,11 @@ import java.net.MalformedURLException
import java.net.URL
class SubscriptionFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener {
companion object {
private const val REQUEST_CODE_ADD = 1
private const val REQUEST_CODE_EDIT = 2
}
@Parcelize
data class SubItem(val item: String = "") : Parcelable {
fun toURL() = URL(item)
}
data class SubItem(val item: String? = null) : Parcelable
@Parcelize
data class SubEditResult(val edited: SubItem, val replacing: SubItem) : Parcelable
data class SubEditResult(val edited: String?, val replacing: String?) : Parcelable
class SubDialogFragment : AlertDialogFragment<SubItem, SubEditResult>(),
TextWatcher, AdapterView.OnItemSelectedListener {
......@@ -83,7 +76,7 @@ class SubscriptionFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener
setTitle(R.string.edit_subscription)
setPositiveButton(android.R.string.ok, listener)
setNegativeButton(android.R.string.cancel, null)
if (arg.item.isNotEmpty()) setNeutralButton(R.string.delete, listener)
if (!arg.item.isNullOrEmpty()) setNeutralButton(R.string.delete, listener)
setView(view)
}
......@@ -112,10 +105,8 @@ class SubscriptionFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener
}
override fun ret(which: Int) = when (which) {
DialogInterface.BUTTON_POSITIVE -> {
SubEditResult(editText.text.toString().let { text -> SubItem(text) }, arg)
}
DialogInterface.BUTTON_NEUTRAL -> SubEditResult(arg, arg)
DialogInterface.BUTTON_POSITIVE -> SubEditResult(editText.text.toString(), arg.item)
DialogInterface.BUTTON_NEUTRAL -> SubEditResult(null, arg.item)
else -> null
}
......@@ -141,8 +132,10 @@ class SubscriptionFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener
}
override fun onClick(v: View?) {
SubDialogFragment().withArg(SubItem(item.toString()))
.show(this@SubscriptionFragment, REQUEST_CODE_EDIT)
SubDialogFragment().apply {
arg(SubItem(item.toString()))
key()
}.show(parentFragmentManager, null)
}
}
......@@ -186,14 +179,10 @@ class SubscriptionFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener
apply()
}
fun remove(item: Any) {
when (item) {
is URL -> {
notifyItemRemoved(subscription.urls.indexOf(item))
subscription.urls.remove(item)
apply()
}
}
fun remove(item: URL) {
notifyItemRemoved(subscription.urls.indexOf(item))
subscription.urls.remove(item)
apply()
}
fun undo(actions: List<Pair<Int, Any>>) {
......@@ -217,6 +206,15 @@ class SubscriptionFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
ViewCompat.setOnApplyWindowInsetsListener(view, ListHolderListener)
AlertDialogFragment.setResultListener<SubDialogFragment, SubEditResult>(this) { which, ret ->
val (edited, replacing) = ret ?: return@setResultListener
replacing?.let { item ->
val url = URL(item)
adapter.remove(url)
if (which == DialogInterface.BUTTON_NEUTRAL) undoManager.remove(-1 to url)
}
if (edited != null) adapter.add(URL(edited)).also { list.post { list.scrollToPosition(it) } }
}
toolbar.setTitle(R.string.subscriptions)
toolbar.inflateMenu(R.menu.subscription_menu)
toolbar.setOnMenuItemClickListener(this)
......@@ -250,7 +248,10 @@ class SubscriptionFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener
override fun onMenuItemClick(item: MenuItem): Boolean = when (item.itemId) {
R.id.action_manual_settings -> {
SubDialogFragment().withArg(SubItem()).show(this, REQUEST_CODE_ADD)
SubDialogFragment().apply {
arg(SubItem())
key()
}.show(parentFragmentManager, null)
true
}
R.id.action_update_subscription -> {
......@@ -261,25 +262,6 @@ class SubscriptionFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener
else -> false
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
val editing = when (requestCode) {
REQUEST_CODE_ADD -> false
REQUEST_CODE_EDIT -> true
else -> return super.onActivityResult(requestCode, resultCode, data)
}
val ret by lazy { AlertDialogFragment.getRet<SubEditResult>(data!!) }
when (resultCode) {
DialogInterface.BUTTON_POSITIVE -> {
if (editing) adapter.remove(ret.replacing.toURL())
adapter.add(ret.edited.toURL()).also { list.post { list.scrollToPosition(it) } }
}
DialogInterface.BUTTON_NEUTRAL -> ret.replacing.toURL().let { item ->
adapter.remove(item)
undoManager.remove(Pair(-1, item))
}
}
}
override fun onDetach() {
undoManager.flush()
mode?.finish()
......
* 2.0.1:
* Moved `AlertDialogFragment` and related utilities to `fragment` package, with support for Fragment Result API from AndroidX Fragment 1.3.
* Dependency updates:
- `androidx.fragment:fragment-ktx:1.3.2`;
- `com.google.android.material:material:1.3.0`;
- `org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.4.32`.
* 2.0.0:
* Deprecated passing `-V` and `--fast-open` to plugin.
Please find `__android_vpn` option passed via plugin options.
......
......@@ -26,5 +26,6 @@ dependencies {
api("androidx.core:core-ktx:1.3.2")
// https://android-developers.googleblog.com/2019/07/android-q-beta-5-update.html
api("androidx.drawerlayout:drawerlayout:1.1.1")
api("androidx.fragment:fragment-ktx:1.3.2")
api("com.google.android.material:material:1.3.0")
}
......@@ -32,6 +32,8 @@ import androidx.fragment.app.Fragment
/**
* Based on: https://android.googlesource.com/platform/packages/apps/ExactCalculator/+/8c43f06/src/com/android/calculator2/AlertDialogFragment.java
*/
@Suppress("DEPRECATION")
@Deprecated("Related APIs are deprecated in AndroidX", ReplaceWith("fragment.AlertDialogFragment"))
abstract class AlertDialogFragment<Arg : Parcelable, Ret : Parcelable> :
AppCompatDialogFragment(), DialogInterface.OnClickListener {
companion object {
......
......@@ -31,6 +31,7 @@ import kotlinx.parcelize.Parcelize
class Empty : Parcelable
@JvmOverloads
@Deprecated("Moved to fragment package", ReplaceWith("fragment.showAllowingStateLoss"))
fun DialogFragment.showAllowingStateLoss(fragmentManager: FragmentManager, tag: String? = null) {
if (!fragmentManager.isStateSaved) show(fragmentManager, tag)
}
/*******************************************************************************
* *
* Copyright (C) 2020 by Max Lv <max.c.lv@gmail.com> *
* Copyright (C) 2020 by Mygod Studio <contact-shadowsocks-android@mygod.be> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
package com.github.shadowsocks.plugin.fragment
import android.app.Activity
import android.content.DialogInterface
import android.os.Bundle
import android.os.Parcelable
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatDialogFragment
import androidx.fragment.app.Fragment
import androidx.fragment.app.setFragmentResult
import androidx.fragment.app.setFragmentResultListener
/**
* Based on: https://android.googlesource.com/platform/packages/apps/ExactCalculator/+/8c43f06/src/com/android/calculator2/AlertDialogFragment.java
*/
abstract class AlertDialogFragment<Arg : Parcelable, Ret : Parcelable?> :
AppCompatDialogFragment(), DialogInterface.OnClickListener {
companion object {
private const val KEY_RESULT = "result"
private const val KEY_ARG = "arg"
private const val KEY_RET = "ret"
private const val KEY_WHICH = "which"
fun <Ret : Parcelable> setResultListener(fragment: Fragment, requestKey: String,
listener: (Int, Ret?) -> Unit) {
fragment.setFragmentResultListener(requestKey) { _, bundle ->
listener(bundle.getInt(KEY_WHICH, Activity.RESULT_CANCELED), bundle.getParcelable(KEY_RET))
}
}
inline fun <reified T : AlertDialogFragment<*, Ret>, Ret : Parcelable?> setResultListener(
fragment: Fragment, noinline listener: (Int, Ret?) -> Unit) =
setResultListener(fragment, T::class.java.name, listener)
}
protected abstract fun AlertDialog.Builder.prepare(listener: DialogInterface.OnClickListener)
private val resultKey get() = requireArguments().getString(KEY_RESULT)
protected val arg by lazy { requireArguments().getParcelable<Arg>(KEY_ARG)!! }
protected open fun ret(which: Int): Ret? = null
private fun args() = arguments ?: Bundle().also { arguments = it }
fun arg(arg: Arg) = args().putParcelable(KEY_ARG, arg)
fun key(resultKey: String = javaClass.name) = args().putString(KEY_RESULT, resultKey)
override fun onCreateDialog(savedInstanceState: Bundle?): AlertDialog =
AlertDialog.Builder(requireContext()).also { it.prepare(this) }.create()
override fun onClick(dialog: DialogInterface?, which: Int) {
setFragmentResult(resultKey ?: return, Bundle().apply {
putInt(KEY_WHICH, which)
putParcelable(KEY_RET, ret(which) ?: return@apply)
})
}
override fun onDismiss(dialog: DialogInterface) {
super.onDismiss(dialog)
onClick(null, Activity.RESULT_CANCELED)
}
}
/*******************************************************************************
* *
* Copyright (C) 2020 by Max Lv <max.c.lv@gmail.com> *
* Copyright (C) 2020 by Mygod Studio <contact-shadowsocks-android@mygod.be> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
@file:JvmName("Utils")
package com.github.shadowsocks.plugin.fragment
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.FragmentManager
typealias Empty = com.github.shadowsocks.plugin.Empty
@JvmOverloads
fun DialogFragment.showAllowingStateLoss(fragmentManager: FragmentManager, tag: String? = null) {
if (!fragmentManager.isStateSaved) show(fragmentManager, tag)
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment