From ab89e9391a822e1ec5841e512799b8b36cb99057 Mon Sep 17 00:00:00 2001 From: Mygod Date: Wed, 23 Jan 2019 15:02:15 +0800 Subject: [PATCH] Enhanced AlertDialogFragment --- .../java/be/mygod/vpnhotspot/EBegFragment.kt | 24 +++---- .../mygod/vpnhotspot/AlertDialogFragment.kt | 24 ++++++- .../vpnhotspot/client/ClientsFragment.kt | 67 +++++++------------ .../vpnhotspot/manage/RepeaterManager.kt | 29 +++----- .../net/wifi/WifiP2pDialogFragment.kt | 24 +++---- 5 files changed, 74 insertions(+), 94 deletions(-) diff --git a/mobile/src/base/java/be/mygod/vpnhotspot/EBegFragment.kt b/mobile/src/base/java/be/mygod/vpnhotspot/EBegFragment.kt index fffd85f0..396e62fb 100644 --- a/mobile/src/base/java/be/mygod/vpnhotspot/EBegFragment.kt +++ b/mobile/src/base/java/be/mygod/vpnhotspot/EBegFragment.kt @@ -1,5 +1,6 @@ package be.mygod.vpnhotspot +import android.content.DialogInterface import android.os.Bundle import android.view.LayoutInflater import android.view.View @@ -11,8 +12,8 @@ import android.widget.Spinner import androidx.annotation.StringRes import androidx.appcompat.app.AlertDialog import androidx.core.net.toUri -import androidx.core.os.bundleOf import androidx.fragment.app.DialogFragment +import androidx.versionedparcelable.VersionedParcelable import be.mygod.vpnhotspot.widget.SmartSnackbar import com.android.billingclient.api.* import timber.log.Timber @@ -22,18 +23,13 @@ import timber.log.Timber */ class EBegFragment : DialogFragment(), PurchasesUpdatedListener, BillingClientStateListener, SkuDetailsResponseListener, ConsumeResponseListener { - companion object { - private const val KEY_TITLE = "title" - private const val KEY_MESSAGE = "message" - } - - class MessageDialogFragment : DialogFragment() { - override fun onCreateDialog(savedInstanceState: Bundle?) = AlertDialog.Builder(requireContext()).apply { - val arguments = arguments!! - setTitle(arguments.getInt(KEY_TITLE, 0)) - setMessage(arguments.getInt(KEY_MESSAGE, 0)) + data class MessageArg(@StringRes val title: Int, @StringRes val message: Int) : VersionedParcelable + class MessageDialogFragment : AlertDialogFragment() { + override fun AlertDialog.Builder.prepare(listener: DialogInterface.OnClickListener) { + setTitle(arg.title) + setMessage(arg.message) setNeutralButton(R.string.donations__button_close, null) - }.create() + } } private lateinit var billingClient: BillingClient @@ -74,9 +70,7 @@ class EBegFragment : DialogFragment(), PurchasesUpdatedListener, BillingClientSt private fun openDialog(@StringRes title: Int, @StringRes message: Int) { val fragmentManager = fragmentManager if (fragmentManager == null) SmartSnackbar.make(message).show() else try { - MessageDialogFragment().apply { - arguments = bundleOf(KEY_TITLE to title, KEY_MESSAGE to message) - }.show(fragmentManager, "MessageDialogFragment") + MessageDialogFragment().withArg(MessageArg(title, message)).show(fragmentManager, "MessageDialogFragment") } catch (e: IllegalStateException) { SmartSnackbar.make(message).show() } diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/AlertDialogFragment.kt b/mobile/src/main/java/be/mygod/vpnhotspot/AlertDialogFragment.kt index 21de5769..d3f318e6 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/AlertDialogFragment.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/AlertDialogFragment.kt @@ -6,19 +6,35 @@ import android.content.Intent import android.os.Bundle import androidx.appcompat.app.AlertDialog import androidx.fragment.app.DialogFragment +import androidx.versionedparcelable.ParcelUtils +import androidx.versionedparcelable.VersionedParcelable /** * Based on: https://android.googlesource.com/platform/packages/apps/ExactCalculator/+/8c43f06/src/com/android/calculator2/AlertDialogFragment.java */ -abstract class AlertDialogFragment : DialogFragment(), DialogInterface.OnClickListener { +abstract class AlertDialogFragment : + DialogFragment(), DialogInterface.OnClickListener { + companion object { + private const val KEY_ARG = "arg" + private const val KEY_RET = "ret" + fun getRet(data: Intent) = + ParcelUtils.getVersionedParcelable(data.extras, KEY_RET)!! + } protected abstract fun AlertDialog.Builder.prepare(listener: DialogInterface.OnClickListener) - open val data: Intent? get() = null + + protected val arg by lazy { ParcelUtils.getVersionedParcelable(arguments, KEY_ARG)!! } + protected open val ret: Ret? get() = null + fun withArg(arg: Arg) = apply { + arguments = Bundle().also { ParcelUtils.putVersionedParcelable(it, KEY_ARG, arg) } + } override fun onCreateDialog(savedInstanceState: Bundle?): AlertDialog = AlertDialog.Builder(requireContext()).also { it.prepare(this) }.create() override fun onClick(dialog: DialogInterface?, which: Int) { - targetFragment?.onActivityResult(targetRequestCode, which, data) + targetFragment?.onActivityResult(targetRequestCode, which, ret?.let { + Intent().replaceExtras(Bundle().apply { ParcelUtils.putVersionedParcelable(this, KEY_RET, it) }) + }) } override fun onDismiss(dialog: DialogInterface) { @@ -26,3 +42,5 @@ abstract class AlertDialogFragment : DialogFragment(), DialogInterface.OnClickLi targetFragment?.onActivityResult(targetRequestCode, Activity.RESULT_CANCELED, null) } } + +class Empty : VersionedParcelable diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/client/ClientsFragment.kt b/mobile/src/main/java/be/mygod/vpnhotspot/client/ClientsFragment.kt index d9c1899a..7486945a 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/client/ClientsFragment.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/client/ClientsFragment.kt @@ -12,7 +12,6 @@ import android.view.ViewGroup import android.widget.EditText import androidx.appcompat.app.AlertDialog import androidx.appcompat.widget.PopupMenu -import androidx.core.os.bundleOf import androidx.databinding.BaseObservable import androidx.databinding.DataBindingUtil import androidx.fragment.app.Fragment @@ -23,10 +22,11 @@ import androidx.recyclerview.widget.DefaultItemAnimator import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView -import androidx.versionedparcelable.ParcelUtils +import androidx.versionedparcelable.VersionedParcelable import be.mygod.vpnhotspot.AlertDialogFragment import be.mygod.vpnhotspot.App.Companion.app import be.mygod.vpnhotspot.R +import be.mygod.vpnhotspot.Empty import be.mygod.vpnhotspot.databinding.FragmentClientsBinding import be.mygod.vpnhotspot.databinding.ListitemClientBinding import be.mygod.vpnhotspot.net.monitor.IpNeighbourMonitor @@ -38,58 +38,46 @@ import be.mygod.vpnhotspot.widget.SmartSnackbar import java.text.NumberFormat class ClientsFragment : Fragment() { - class NicknameDialogFragment : AlertDialogFragment() { - companion object { - const val KEY_MAC = "mac" - const val KEY_NICKNAME = "nickname" - } - - private val mac by lazy { arguments!!.getString(KEY_MAC)!! } - + data class NicknameArg(val mac: String, val nickname: CharSequence) : VersionedParcelable + class NicknameDialogFragment : AlertDialogFragment() { override fun AlertDialog.Builder.prepare(listener: DialogInterface.OnClickListener) { setView(R.layout.dialog_nickname) - setTitle(getString(R.string.clients_nickname_title, mac)) + setTitle(getString(R.string.clients_nickname_title, arg.mac)) setPositiveButton(android.R.string.ok, listener) setNegativeButton(android.R.string.cancel, null) } override fun onCreateDialog(savedInstanceState: Bundle?) = super.onCreateDialog(savedInstanceState).apply { create() - findViewById(android.R.id.edit)!!.setText(arguments!!.getCharSequence(KEY_NICKNAME)) + findViewById(android.R.id.edit)!!.setText(arg.nickname) } - override fun onClick(di: DialogInterface?, which: Int) { - AppDatabase.instance.clientRecordDao.lookup(mac.macToLong()).apply { - nickname = dialog!!.findViewById(android.R.id.edit).text + override fun onClick(dialog: DialogInterface?, which: Int) { + AppDatabase.instance.clientRecordDao.lookup(arg.mac.macToLong()).apply { + nickname = this@NicknameDialogFragment.dialog!!.findViewById(android.R.id.edit).text AppDatabase.instance.clientRecordDao.update(this) } IpNeighbourMonitor.instance?.flush() } } - class StatsDialogFragment : AlertDialogFragment() { - companion object { - const val KEY_TITLE = "title" - const val KEY_STATS = "stats" - } - - private val title by lazy { arguments!!.getCharSequence(KEY_TITLE)!! } - private val stats by lazy { ParcelUtils.getVersionedParcelable(arguments, KEY_STATS)!! } - + data class StatsArg(val title: CharSequence, val stats: ClientStats) : VersionedParcelable + class StatsDialogFragment : AlertDialogFragment() { override fun AlertDialog.Builder.prepare(listener: DialogInterface.OnClickListener) { - setTitle(getString(R.string.clients_stats_title, title)) + setTitle(getString(R.string.clients_stats_title, arg.title)) val context = context val resources = resources val format = NumberFormat.getIntegerInstance(resources.configuration.locale) setMessage("%s\n%s\n%s".format( - resources.getQuantityString(R.plurals.clients_stats_message_1, stats.count.toPluralInt(), - format.format(stats.count), DateUtils.formatDateTime(context, stats.timestamp, + resources.getQuantityString(R.plurals.clients_stats_message_1, arg.stats.count.toPluralInt(), + format.format(arg.stats.count), DateUtils.formatDateTime(context, arg.stats.timestamp, DateUtils.FORMAT_SHOW_TIME or DateUtils.FORMAT_SHOW_YEAR or DateUtils.FORMAT_SHOW_DATE)), - resources.getQuantityString(R.plurals.clients_stats_message_2, stats.sentPackets.toPluralInt(), - format.format(stats.sentPackets), Formatter.formatFileSize(context, stats.sentBytes)), - resources.getQuantityString(R.plurals.clients_stats_message_3, stats.sentPackets.toPluralInt(), - format.format(stats.receivedPackets), - Formatter.formatFileSize(context, stats.receivedBytes)))) + resources.getQuantityString(R.plurals.clients_stats_message_2, arg.stats.sentPackets.toPluralInt(), + format.format(arg.stats.sentPackets), + Formatter.formatFileSize(context, arg.stats.sentBytes)), + resources.getQuantityString(R.plurals.clients_stats_message_3, arg.stats.sentPackets.toPluralInt(), + format.format(arg.stats.receivedPackets), + Formatter.formatFileSize(context, arg.stats.receivedBytes)))) setPositiveButton(android.R.string.ok, null) } } @@ -123,10 +111,8 @@ class ClientsFragment : Fragment() { return when (item?.itemId) { R.id.nickname -> { val client = binding.client ?: return false - NicknameDialogFragment().apply { - arguments = bundleOf(Pair(NicknameDialogFragment.KEY_MAC, client.mac), - Pair(NicknameDialogFragment.KEY_NICKNAME, client.record.nickname)) - }.show(fragmentManager ?: return false, "NicknameDialogFragment") + NicknameDialogFragment().withArg(NicknameArg(client.mac, client.record.nickname)) + .show(fragmentManager ?: return false, "NicknameDialogFragment") true } R.id.block, R.id.unblock -> { @@ -143,12 +129,9 @@ class ClientsFragment : Fragment() { } R.id.stats -> { val client = binding.client ?: return false - StatsDialogFragment().apply { - arguments = bundleOf(StatsDialogFragment.KEY_TITLE to client.title).apply { - ParcelUtils.putVersionedParcelable(this, StatsDialogFragment.KEY_STATS, - AppDatabase.instance.trafficRecordDao.queryStats(client.mac.macToLong())) - } - }.show(fragmentManager ?: return false, "StatsDialogFragment") + StatsDialogFragment().withArg(StatsArg(client.title, + AppDatabase.instance.trafficRecordDao.queryStats(client.mac.macToLong()))) + .show(fragmentManager ?: return false, "StatsDialogFragment") true } else -> false diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/manage/RepeaterManager.kt b/mobile/src/main/java/be/mygod/vpnhotspot/manage/RepeaterManager.kt index fbc1504a..ad6de7ed 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/manage/RepeaterManager.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/manage/RepeaterManager.kt @@ -12,13 +12,13 @@ import android.view.WindowManager import android.widget.EditText import androidx.appcompat.app.AlertDialog import androidx.core.content.ContextCompat -import androidx.core.os.bundleOf import androidx.databinding.BaseObservable import androidx.databinding.Bindable import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProviders import androidx.lifecycle.get import androidx.recyclerview.widget.RecyclerView +import androidx.versionedparcelable.VersionedParcelable import be.mygod.vpnhotspot.* import be.mygod.vpnhotspot.App.Companion.app import be.mygod.vpnhotspot.databinding.ListitemRepeaterBinding @@ -28,7 +28,6 @@ import be.mygod.vpnhotspot.util.ServiceForegroundConnector import be.mygod.vpnhotspot.util.formatAddresses import be.mygod.vpnhotspot.widget.SmartSnackbar import timber.log.Timber -import java.lang.RuntimeException import java.net.NetworkInterface import java.net.SocketException @@ -96,13 +95,10 @@ class RepeaterManager(private val parent: TetheringFragment) : Manager(), Servic if (group != null) try { val config = P2pSupplicantConfiguration(group, binder?.thisDevice?.deviceAddress) holder.config = config - WifiP2pDialogFragment().apply { - arguments = bundleOf(Pair(WifiP2pDialogFragment.KEY_CONFIGURATION, WifiConfiguration().apply { - SSID = group.networkName - preSharedKey = config.psk - })) - setTargetFragment(parent, TetheringFragment.REPEATER_EDIT_CONFIGURATION) - }.show(parent.fragmentManager ?: return, WifiP2pDialogFragment.TAG) + WifiP2pDialogFragment().withArg(WifiP2pDialogFragment.Arg(WifiConfiguration().apply { + SSID = group.networkName + preSharedKey = config.psk + })).show(parent.fragmentManager ?: return, "WifiP2pDialogFragment") return } catch (e: RuntimeException) { Timber.w(e) @@ -111,11 +107,8 @@ class RepeaterManager(private val parent: TetheringFragment) : Manager(), Servic } } - class WpsDialogFragment : AlertDialogFragment() { - companion object { - const val KEY_PIN = "pin" - } - + data class WpsRet(val pin: String?) : VersionedParcelable + class WpsDialogFragment : AlertDialogFragment() { override fun AlertDialog.Builder.prepare(listener: DialogInterface.OnClickListener) { setTitle(R.string.repeater_wps_dialog_title) setView(R.layout.dialog_wps) @@ -123,8 +116,8 @@ class RepeaterManager(private val parent: TetheringFragment) : Manager(), Servic setNegativeButton(android.R.string.cancel, null) setNeutralButton(R.string.repeater_wps_dialog_pbc, listener) } - override val data: Intent get() = Intent() - .putExtra(KEY_PIN, dialog!!.findViewById(android.R.id.edit)?.text?.toString()) + + override val ret get() = WpsRet(dialog!!.findViewById(android.R.id.edit)?.text?.toString()) override fun onCreateDialog(savedInstanceState: Bundle?) = super.onCreateDialog(savedInstanceState).apply { window!!.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE) @@ -166,7 +159,7 @@ class RepeaterManager(private val parent: TetheringFragment) : Manager(), Servic fun onWpsResult(which: Int, data: Intent?) { when (which) { - DialogInterface.BUTTON_POSITIVE -> binder?.startWps(data!!.getStringExtra(WpsDialogFragment.KEY_PIN)) + DialogInterface.BUTTON_POSITIVE -> binder?.startWps(AlertDialogFragment.getRet(data!!).pin) DialogInterface.BUTTON_NEUTRAL -> binder?.startWps(null) } } @@ -175,7 +168,7 @@ class RepeaterManager(private val parent: TetheringFragment) : Manager(), Servic when (which) { DialogInterface.BUTTON_POSITIVE -> try { val master = holder.config ?: return - val config = data!!.getParcelableExtra(WifiP2pDialogFragment.KEY_CONFIGURATION) + val config = AlertDialogFragment.getRet(data!!).configuration master.update(config.SSID, config.preSharedKey) binder!!.group = null } catch (e: Exception) { diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/WifiP2pDialogFragment.kt b/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/WifiP2pDialogFragment.kt index 07fa1831..f99d15dd 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/WifiP2pDialogFragment.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/WifiP2pDialogFragment.kt @@ -1,7 +1,6 @@ package be.mygod.vpnhotspot.net.wifi import android.content.DialogInterface -import android.content.Intent import android.net.wifi.WifiConfiguration import android.net.wifi.WifiConfiguration.AuthAlgorithm import android.text.Editable @@ -10,6 +9,7 @@ import android.view.View import android.widget.EditText import android.widget.TextView import androidx.appcompat.app.AlertDialog +import androidx.versionedparcelable.VersionedParcelable import be.mygod.vpnhotspot.AlertDialogFragment import be.mygod.vpnhotspot.R import com.google.android.material.textfield.TextInputLayout @@ -21,16 +21,14 @@ import java.nio.charset.Charset * This dialog has been deprecated in API 28, but we are still using it since it works better for our purposes. * Related: https://android.googlesource.com/platform/packages/apps/Settings/+/defb1183ecb00d6231bac7d934d07f58f90261ea */ -class WifiP2pDialogFragment : AlertDialogFragment(), TextWatcher, DialogInterface.OnClickListener { - companion object { - const val TAG = "WifiP2pDialogFragment" - const val KEY_CONFIGURATION = "configuration" - } +class WifiP2pDialogFragment : AlertDialogFragment(), + TextWatcher, DialogInterface.OnClickListener { + data class Arg(val configuration: WifiConfiguration) : VersionedParcelable private lateinit var mView: View private lateinit var mSsid: TextView private lateinit var mPassword: EditText - private val config: WifiConfiguration? + override val ret: Arg? get() { val config = WifiConfiguration() config.SSID = mSsid.text.toString() @@ -39,7 +37,7 @@ class WifiP2pDialogFragment : AlertDialogFragment(), TextWatcher, DialogInterfac val password = mPassword.text.toString() config.preSharedKey = password } - return config + return Arg(config) } override fun AlertDialog.Builder.prepare(listener: DialogInterface.OnClickListener) { @@ -51,18 +49,12 @@ class WifiP2pDialogFragment : AlertDialogFragment(), TextWatcher, DialogInterfac setPositiveButton(context.getString(R.string.wifi_save), listener) setNegativeButton(context.getString(R.string.wifi_cancel), null) setNeutralButton(context.getString(R.string.repeater_reset_credentials), listener) - val arguments = arguments!! - val mWifiConfig = arguments.getParcelable(KEY_CONFIGURATION) - if (mWifiConfig != null) { - mSsid.text = mWifiConfig.SSID - mPassword.setText(mWifiConfig.preSharedKey) - } + mSsid.text = arg.configuration.SSID mSsid.addTextChangedListener(this@WifiP2pDialogFragment) + mPassword.setText(arg.configuration.preSharedKey) mPassword.addTextChangedListener(this@WifiP2pDialogFragment) } - override val data get() = Intent().putExtra(KEY_CONFIGURATION, config) - override fun onStart() { super.onStart() validate()