SmartSnackbars
This commit is contained in:
@@ -9,8 +9,6 @@ import android.net.wifi.WifiManager
|
||||
import android.os.Build
|
||||
import android.os.Handler
|
||||
import android.preference.PreferenceManager
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.core.content.getSystemService
|
||||
import be.mygod.vpnhotspot.util.DeviceStorageApp
|
||||
import be.mygod.vpnhotspot.util.Event0
|
||||
@@ -55,6 +53,4 @@ class App : Application() {
|
||||
val masquerade: Boolean get() = pref.getBoolean(KEY_MASQUERADE, true)
|
||||
|
||||
val cleanRoutings = Event0()
|
||||
|
||||
fun toast(@StringRes resId: Int) = handler.post { Toast.makeText(this, resId, Toast.LENGTH_SHORT).show() }
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package be.mygod.vpnhotspot
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.net.wifi.WifiManager
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.RequiresApi
|
||||
import be.mygod.vpnhotspot.App.Companion.app
|
||||
import be.mygod.vpnhotspot.manage.LocalOnlyHotspotManager
|
||||
@@ -11,6 +10,7 @@ import be.mygod.vpnhotspot.net.IpNeighbourMonitor
|
||||
import be.mygod.vpnhotspot.net.TetheringManager
|
||||
import be.mygod.vpnhotspot.util.broadcastReceiver
|
||||
import be.mygod.vpnhotspot.util.debugLog
|
||||
import be.mygod.vpnhotspot.widget.SmartSnackbar
|
||||
import com.crashlytics.android.Crashlytics
|
||||
|
||||
@RequiresApi(26)
|
||||
@@ -89,7 +89,7 @@ class LocalOnlyHotspotService : IpNeighbourMonitoringService() {
|
||||
getString(R.string.tethering_temp_hotspot_failure_tethering_disallowed)
|
||||
else -> getString(R.string.failure_reason_unknown, reason)
|
||||
})
|
||||
Toast.makeText(this@LocalOnlyHotspotService, message, Toast.LENGTH_SHORT).show()
|
||||
SmartSnackbar.make(message).show()
|
||||
startFailure(if (reason == WifiManager.LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE) null else
|
||||
StartFailure(message))
|
||||
}
|
||||
@@ -98,7 +98,7 @@ class LocalOnlyHotspotService : IpNeighbourMonitoringService() {
|
||||
e.printStackTrace()
|
||||
startFailure(e)
|
||||
} catch (e: SecurityException) {
|
||||
Toast.makeText(this, e.message, Toast.LENGTH_LONG).show()
|
||||
SmartSnackbar.make(e.localizedMessage).show()
|
||||
e.printStackTrace()
|
||||
startFailure(e)
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package be.mygod.vpnhotspot
|
||||
|
||||
import android.widget.Toast
|
||||
import be.mygod.vpnhotspot.App.Companion.app
|
||||
import be.mygod.vpnhotspot.net.Routing
|
||||
import be.mygod.vpnhotspot.net.UpstreamMonitor
|
||||
import be.mygod.vpnhotspot.widget.SmartSnackbar
|
||||
import com.crashlytics.android.Crashlytics
|
||||
import java.net.InetAddress
|
||||
import java.net.InterfaceAddress
|
||||
@@ -48,9 +48,9 @@ class LocalOnlyInterfaceManager(val downstream: String) : UpstreamMonitor.Callba
|
||||
routing.ipForward() // local only interfaces need not enable ip_forward
|
||||
.rule().forward(strict)
|
||||
if (app.masquerade) routing.masquerade(strict)
|
||||
if (!routing.dnsRedirect(dns).start()) app.toast(R.string.noisy_su_failure)
|
||||
if (!routing.dnsRedirect(dns).start()) SmartSnackbar.make(R.string.noisy_su_failure).show()
|
||||
} catch (e: SocketException) {
|
||||
Toast.makeText(app, e.message, Toast.LENGTH_SHORT).show()
|
||||
SmartSnackbar.make(e.localizedMessage).show()
|
||||
Crashlytics.logException(e)
|
||||
routing = null
|
||||
}
|
||||
|
||||
@@ -18,12 +18,17 @@ import be.mygod.vpnhotspot.client.ClientsFragment
|
||||
import be.mygod.vpnhotspot.databinding.ActivityMainBinding
|
||||
import be.mygod.vpnhotspot.manage.TetheringFragment
|
||||
import be.mygod.vpnhotspot.util.ServiceForegroundConnector
|
||||
import be.mygod.vpnhotspot.widget.SmartSnackbar
|
||||
import com.google.android.material.bottomnavigation.BottomNavigationMenuView
|
||||
import com.google.android.material.bottomnavigation.BottomNavigationView
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import q.rorbin.badgeview.QBadgeView
|
||||
|
||||
class MainActivity : AppCompatActivity(), BottomNavigationView.OnNavigationItemSelectedListener, ServiceConnection {
|
||||
companion object {
|
||||
var current: MainActivity? = null
|
||||
}
|
||||
|
||||
private lateinit var binding: ActivityMainBinding
|
||||
private lateinit var badge: QBadgeView
|
||||
private var clients: ClientMonitorService.Binder? = null
|
||||
@@ -33,7 +38,6 @@ class MainActivity : AppCompatActivity(), BottomNavigationView.OnNavigationItemS
|
||||
.build()
|
||||
}
|
||||
fun launchUrl(url: Uri) = customTabsIntent.launchUrl(this, url)
|
||||
fun snackbar(text: CharSequence = "") = Snackbar.make(binding.fragmentHolder, text, Snackbar.LENGTH_LONG)
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
@@ -47,6 +51,7 @@ class MainActivity : AppCompatActivity(), BottomNavigationView.OnNavigationItemS
|
||||
badge.badgeGravity = Gravity.TOP or Gravity.CENTER_HORIZONTAL
|
||||
badge.setGravityOffset(16f, 0f, true)
|
||||
ServiceForegroundConnector(this, this, ClientMonitorService::class)
|
||||
SmartSnackbar.Register(binding.fragmentHolder)
|
||||
}
|
||||
|
||||
override fun onNavigationItemSelected(item: MenuItem) = when (item.itemId) {
|
||||
|
||||
@@ -11,7 +11,6 @@ import android.net.wifi.p2p.WifiP2pInfo
|
||||
import android.net.wifi.p2p.WifiP2pManager
|
||||
import android.os.Looper
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.core.content.getSystemService
|
||||
import be.mygod.vpnhotspot.App.Companion.app
|
||||
@@ -22,6 +21,7 @@ import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper.requestPersistentGroupI
|
||||
import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper.setWifiP2pChannels
|
||||
import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper.startWps
|
||||
import be.mygod.vpnhotspot.util.*
|
||||
import be.mygod.vpnhotspot.widget.SmartSnackbar
|
||||
import com.crashlytics.android.Crashlytics
|
||||
import java.lang.reflect.InvocationTargetException
|
||||
|
||||
@@ -50,11 +50,11 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, SharedPrefere
|
||||
WpsInfo.KEYPAD
|
||||
}
|
||||
}, object : WifiP2pManager.ActionListener {
|
||||
override fun onSuccess() = Toast.makeText(this@RepeaterService,
|
||||
if (pin == null) R.string.repeater_wps_success_pbc else R.string.repeater_wps_success_keypad,
|
||||
Toast.LENGTH_SHORT).show()
|
||||
override fun onFailure(reason: Int) = Toast.makeText(this@RepeaterService,
|
||||
formatReason(R.string.repeater_wps_failure, reason), Toast.LENGTH_SHORT).show()
|
||||
override fun onSuccess() = SmartSnackbar.make(
|
||||
if (pin == null) R.string.repeater_wps_success_pbc else R.string.repeater_wps_success_keypad)
|
||||
.shortToast().show()
|
||||
override fun onFailure(reason: Int) = SmartSnackbar.make(
|
||||
formatReason(R.string.repeater_wps_failure, reason)).show()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -64,10 +64,10 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, SharedPrefere
|
||||
|
||||
fun resetCredentials() = (groups + group).filterNotNull().forEach {
|
||||
p2pManager.deletePersistentGroup(channel, it.netId, object : WifiP2pManager.ActionListener {
|
||||
override fun onSuccess() = Toast.makeText(this@RepeaterService,
|
||||
R.string.repeater_reset_credentials_success, Toast.LENGTH_SHORT).show()
|
||||
override fun onFailure(reason: Int) = Toast.makeText(this@RepeaterService,
|
||||
formatReason(R.string.repeater_reset_credentials_failure, reason), Toast.LENGTH_SHORT).show()
|
||||
override fun onSuccess() = SmartSnackbar.make(R.string.repeater_reset_credentials_success)
|
||||
.shortToast().show()
|
||||
override fun onFailure(reason: Int) = SmartSnackbar.make(
|
||||
formatReason(R.string.repeater_reset_credentials_failure, reason)).show()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, SharedPrefere
|
||||
} catch (e: ReflectiveOperationException) {
|
||||
e.printStackTrace()
|
||||
Crashlytics.logException(e)
|
||||
Toast.makeText(this@RepeaterService, e.message, Toast.LENGTH_LONG).show()
|
||||
SmartSnackbar.make(e.localizedMessage).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -115,7 +115,7 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, SharedPrefere
|
||||
binder.statusChanged()
|
||||
}
|
||||
|
||||
private fun formatReason(@StringRes resId: Int, reason: Int): String? {
|
||||
private fun formatReason(@StringRes resId: Int, reason: Int): String {
|
||||
val result = getString(resId, when (reason) {
|
||||
WifiP2pManager.ERROR -> getString(R.string.repeater_failure_reason_error)
|
||||
WifiP2pManager.P2P_UNSUPPORTED -> getString(R.string.repeater_failure_reason_p2p_unsupported)
|
||||
@@ -147,14 +147,13 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, SharedPrefere
|
||||
p2pManager.setWifiP2pChannels(channel, 0, oc, object : WifiP2pManager.ActionListener {
|
||||
override fun onSuccess() { }
|
||||
override fun onFailure(reason: Int) {
|
||||
Toast.makeText(this@RepeaterService, formatReason(R.string.repeater_set_oc_failure, reason),
|
||||
Toast.LENGTH_SHORT).show()
|
||||
SmartSnackbar.make(formatReason(R.string.repeater_set_oc_failure, reason)).show()
|
||||
}
|
||||
})
|
||||
} catch (e: InvocationTargetException) {
|
||||
if (oc != 0) {
|
||||
val message = getString(R.string.repeater_set_oc_failure, e.message)
|
||||
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
|
||||
SmartSnackbar.make(message).show()
|
||||
Crashlytics.logException(Failure(message))
|
||||
}
|
||||
e.printStackTrace()
|
||||
@@ -195,9 +194,8 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, SharedPrefere
|
||||
p2pManager.removeGroup(channel, object : WifiP2pManager.ActionListener {
|
||||
override fun onSuccess() = doStart()
|
||||
override fun onFailure(reason: Int) {
|
||||
Toast.makeText(this@RepeaterService,
|
||||
formatReason(R.string.repeater_remove_old_group_failure, reason),
|
||||
Toast.LENGTH_SHORT).show()
|
||||
SmartSnackbar.make(formatReason(R.string.repeater_remove_old_group_failure, reason))
|
||||
.show()
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -237,8 +235,8 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, SharedPrefere
|
||||
status = Status.ACTIVE
|
||||
showNotification(group)
|
||||
}
|
||||
private fun startFailure(msg: CharSequence?, group: WifiP2pGroup? = null) {
|
||||
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
|
||||
private fun startFailure(msg: CharSequence, group: WifiP2pGroup? = null) {
|
||||
SmartSnackbar.make(msg).show()
|
||||
showNotification()
|
||||
if (group != null) removeGroup() else clean()
|
||||
}
|
||||
@@ -251,8 +249,7 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, SharedPrefere
|
||||
override fun onSuccess() = clean()
|
||||
override fun onFailure(reason: Int) {
|
||||
if (reason == WifiP2pManager.BUSY) clean() else { // assuming it's already gone
|
||||
Toast.makeText(this@RepeaterService,
|
||||
formatReason(R.string.repeater_remove_group_failure, reason), Toast.LENGTH_SHORT).show()
|
||||
SmartSnackbar.make(formatReason(R.string.repeater_remove_group_failure, reason)).show()
|
||||
status = Status.ACTIVE
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import be.mygod.vpnhotspot.net.UpstreamMonitor
|
||||
import be.mygod.vpnhotspot.preference.AlwaysAutoCompleteEditTextPreferenceDialogFragmentCompat
|
||||
import be.mygod.vpnhotspot.preference.SharedPreferenceDataStore
|
||||
import be.mygod.vpnhotspot.util.loggerSuStream
|
||||
import be.mygod.vpnhotspot.widget.SmartSnackbar
|
||||
import com.crashlytics.android.Crashlytics
|
||||
import com.takisoft.preferencex.PreferenceFragmentCompat
|
||||
import java.io.File
|
||||
@@ -27,7 +28,6 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() {
|
||||
override fun onCreatePreferencesFix(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
preferenceManager.preferenceDataStore = SharedPreferenceDataStore(app.pref)
|
||||
addPreferencesFromResource(R.xml.pref_settings)
|
||||
val mainActivity = activity as MainActivity
|
||||
val boot = findPreference("service.repeater.startOnBoot") as SwitchPreference
|
||||
boot.setOnPreferenceChangeListener { _, value ->
|
||||
BootReceiver.enabled = value as Boolean
|
||||
@@ -35,7 +35,7 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() {
|
||||
}
|
||||
boot.isChecked = BootReceiver.enabled
|
||||
findPreference("service.clean").setOnPreferenceClickListener {
|
||||
if (Routing.clean() == null) mainActivity.snackbar().setText(R.string.root_unavailable).show()
|
||||
if (Routing.clean() == null) SmartSnackbar.make(R.string.root_unavailable).show()
|
||||
else app.cleanRoutings()
|
||||
true
|
||||
}
|
||||
@@ -96,7 +96,7 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() {
|
||||
true
|
||||
}
|
||||
findPreference("misc.source").setOnPreferenceClickListener {
|
||||
mainActivity.launchUrl("https://github.com/Mygod/VPNHotspot".toUri())
|
||||
(activity as MainActivity).launchUrl("https://github.com/Mygod/VPNHotspot".toUri())
|
||||
true
|
||||
}
|
||||
findPreference("misc.donate").setOnPreferenceClickListener {
|
||||
|
||||
@@ -9,6 +9,7 @@ import be.mygod.vpnhotspot.net.Routing
|
||||
import be.mygod.vpnhotspot.net.TetheringManager
|
||||
import be.mygod.vpnhotspot.net.UpstreamMonitor
|
||||
import be.mygod.vpnhotspot.util.broadcastReceiver
|
||||
import be.mygod.vpnhotspot.widget.SmartSnackbar
|
||||
import com.crashlytics.android.Crashlytics
|
||||
import java.net.InetAddress
|
||||
import java.net.SocketException
|
||||
@@ -32,7 +33,7 @@ class TetheringService : IpNeighbourMonitoringService(), UpstreamMonitor.Callbac
|
||||
private var receiverRegistered = false
|
||||
private val receiver = broadcastReceiver { _, intent ->
|
||||
synchronized(routings) {
|
||||
for (iface in routings.keys - TetheringManager.getTetheredIfaces(intent.extras))
|
||||
for (iface in routings.keys - TetheringManager.getTetheredIfaces(intent.extras!!))
|
||||
routings.remove(iface)?.stop()
|
||||
updateRoutingsLocked()
|
||||
}
|
||||
@@ -60,7 +61,7 @@ class TetheringService : IpNeighbourMonitoringService(), UpstreamMonitor.Callbac
|
||||
routings.remove(downstream)
|
||||
failed = true
|
||||
}
|
||||
if (failed) app.toast(R.string.noisy_su_failure)
|
||||
if (failed) SmartSnackbar.make(R.string.noisy_su_failure).show()
|
||||
} else if (!receiverRegistered) {
|
||||
registerReceiver(receiver, IntentFilter(TetheringManager.ACTION_TETHER_STATE_CHANGED))
|
||||
app.cleanRoutings[this] = {
|
||||
|
||||
@@ -22,6 +22,7 @@ import be.mygod.vpnhotspot.net.wifi.P2pSupplicantConfiguration
|
||||
import be.mygod.vpnhotspot.net.wifi.WifiP2pDialogFragment
|
||||
import be.mygod.vpnhotspot.util.ServiceForegroundConnector
|
||||
import be.mygod.vpnhotspot.util.formatAddresses
|
||||
import be.mygod.vpnhotspot.widget.SmartSnackbar
|
||||
import com.crashlytics.android.Crashlytics
|
||||
import java.net.NetworkInterface
|
||||
import java.net.SocketException
|
||||
@@ -100,14 +101,13 @@ class RepeaterManager(private val parent: TetheringFragment) : Manager(), Servic
|
||||
val binder = binder
|
||||
val group = binder?.service?.group
|
||||
val ssid = group?.networkName
|
||||
val mainActivity = parent.activity as MainActivity
|
||||
if (ssid != null) {
|
||||
val wifi = WifiConfiguration()
|
||||
val conf = P2pSupplicantConfiguration()
|
||||
wifi.SSID = ssid
|
||||
wifi.preSharedKey = group.passphrase
|
||||
if (wifi.preSharedKey == null) {
|
||||
wifi.preSharedKey = conf.readPsk { mainActivity.snackbar(it.message.toString()).show() }
|
||||
wifi.preSharedKey = conf.readPsk { SmartSnackbar.make(it.message.toString()).show() }
|
||||
}
|
||||
if (wifi.preSharedKey != null) {
|
||||
WifiP2pDialogFragment().apply {
|
||||
@@ -118,7 +118,7 @@ class RepeaterManager(private val parent: TetheringFragment) : Manager(), Servic
|
||||
return
|
||||
}
|
||||
}
|
||||
mainActivity.snackbar().setText(R.string.repeater_configure_failure).show()
|
||||
SmartSnackbar.make(R.string.repeater_configure_failure).show()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ import be.mygod.vpnhotspot.databinding.ListitemInterfaceBinding
|
||||
import be.mygod.vpnhotspot.net.TetherType
|
||||
import be.mygod.vpnhotspot.net.TetheringManager
|
||||
import be.mygod.vpnhotspot.net.wifi.WifiApManager
|
||||
import be.mygod.vpnhotspot.widget.SmartSnackbar
|
||||
import com.crashlytics.android.Crashlytics
|
||||
import java.lang.reflect.InvocationTargetException
|
||||
|
||||
@@ -92,7 +93,7 @@ sealed class TetherManager(protected val parent: TetheringFragment) : Manager(),
|
||||
|
||||
override fun onTetheringStarted() = data.notifyChange()
|
||||
override fun onTetheringFailed() =
|
||||
(parent.activity as MainActivity).snackbar().setText(R.string.tethering_manage_failed).show()
|
||||
SmartSnackbar.make(R.string.tethering_manage_failed).show()
|
||||
|
||||
override fun bindTo(viewHolder: RecyclerView.ViewHolder) {
|
||||
(viewHolder as ViewHolder).manager = this
|
||||
|
||||
@@ -4,6 +4,7 @@ import android.util.Log
|
||||
import be.mygod.vpnhotspot.App.Companion.app
|
||||
import be.mygod.vpnhotspot.R
|
||||
import be.mygod.vpnhotspot.util.thread
|
||||
import be.mygod.vpnhotspot.widget.SmartSnackbar
|
||||
import com.crashlytics.android.Crashlytics
|
||||
import java.io.IOException
|
||||
import java.io.InterruptedIOException
|
||||
@@ -67,7 +68,7 @@ abstract class IpMonitor : Runnable {
|
||||
if (err.isNotBlank()) {
|
||||
Crashlytics.log(Log.ERROR, javaClass.simpleName, err)
|
||||
Crashlytics.logException(FlushFailure())
|
||||
app.toast(R.string.noisy_su_failure)
|
||||
SmartSnackbar.make(R.string.noisy_su_failure).show()
|
||||
}
|
||||
}
|
||||
process.inputStream.bufferedReader().useLines(this::processLines)
|
||||
|
||||
@@ -12,9 +12,9 @@ import android.widget.TextView
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import be.mygod.vpnhotspot.App.Companion.app
|
||||
import be.mygod.vpnhotspot.MainActivity
|
||||
import be.mygod.vpnhotspot.R
|
||||
import be.mygod.vpnhotspot.manage.TetheringFragment
|
||||
import be.mygod.vpnhotspot.widget.SmartSnackbar
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
import java.nio.charset.Charset
|
||||
|
||||
@@ -90,8 +90,8 @@ class WifiP2pDialogFragment : DialogFragment(), TextWatcher, DialogInterface.OnC
|
||||
app.handler.postDelayed((targetFragment as TetheringFragment).adapter.repeaterManager
|
||||
.binder!!::requestGroupUpdate, 1000)
|
||||
}
|
||||
false -> (activity as MainActivity).snackbar().setText(R.string.noisy_su_failure).show()
|
||||
null -> (activity as MainActivity).snackbar().setText(R.string.root_unavailable).show()
|
||||
false -> SmartSnackbar.make(R.string.noisy_su_failure).show()
|
||||
null -> SmartSnackbar.make(R.string.root_unavailable).show()
|
||||
}
|
||||
DialogInterface.BUTTON_NEUTRAL ->
|
||||
(targetFragment as TetheringFragment).adapter.repeaterManager.binder!!.resetCredentials()
|
||||
|
||||
@@ -10,6 +10,7 @@ import androidx.databinding.BindingAdapter
|
||||
import be.mygod.vpnhotspot.App.Companion.app
|
||||
import be.mygod.vpnhotspot.BuildConfig
|
||||
import be.mygod.vpnhotspot.R
|
||||
import be.mygod.vpnhotspot.widget.SmartSnackbar
|
||||
import com.crashlytics.android.Crashlytics
|
||||
import java.net.NetworkInterface
|
||||
import java.net.SocketException
|
||||
@@ -57,7 +58,7 @@ fun thread(name: String? = null, start: Boolean = true, isDaemon: Boolean = fals
|
||||
contextClassLoader: ClassLoader? = null, priority: Int = -1, block: () -> Unit): Thread {
|
||||
val thread = kotlin.concurrent.thread(false, isDaemon, contextClassLoader, name, priority, block)
|
||||
thread.setUncaughtExceptionHandler { _, e ->
|
||||
app.toast(R.string.noisy_su_failure)
|
||||
SmartSnackbar.make(R.string.noisy_su_failure).show()
|
||||
Crashlytics.logException(e)
|
||||
}
|
||||
if (start) thread.start()
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
package be.mygod.vpnhotspot.widget
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleObserver
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.OnLifecycleEvent
|
||||
import be.mygod.vpnhotspot.App.Companion.app
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
|
||||
sealed class SmartSnackbar {
|
||||
companion object {
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
private var holder: View? = null
|
||||
|
||||
fun make(@StringRes text: Int): SmartSnackbar = make(app.getText(text))
|
||||
fun make(text: CharSequence = ""): SmartSnackbar {
|
||||
val holder = holder
|
||||
return if (holder == null) ToastWrapper(Toast.makeText(app, text, Toast.LENGTH_LONG)) else
|
||||
SnackbarWrapper(Snackbar.make(holder, text, Snackbar.LENGTH_LONG))
|
||||
}
|
||||
}
|
||||
|
||||
class Register(private val view: View) : LifecycleObserver {
|
||||
init {
|
||||
(view.context as LifecycleOwner).lifecycle.addObserver(this)
|
||||
}
|
||||
|
||||
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
|
||||
fun onResume() {
|
||||
holder = view
|
||||
}
|
||||
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
|
||||
fun onPause() {
|
||||
if (holder === view) holder = null
|
||||
}
|
||||
}
|
||||
|
||||
abstract fun show()
|
||||
open fun shortToast() = this
|
||||
}
|
||||
|
||||
private class SnackbarWrapper(private val snackbar: Snackbar) : SmartSnackbar() {
|
||||
override fun show() = snackbar.show()
|
||||
}
|
||||
|
||||
private class ToastWrapper(private val toast: Toast) : SmartSnackbar() {
|
||||
override fun show() {
|
||||
app.handler.post(toast::show)
|
||||
}
|
||||
|
||||
override fun shortToast() = apply { toast.duration = Toast.LENGTH_SHORT }
|
||||
}
|
||||
Reference in New Issue
Block a user