diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/TetheringFragment.kt b/mobile/src/main/java/be/mygod/vpnhotspot/TetheringFragment.kt index fe228eb3..707cc60e 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/TetheringFragment.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/TetheringFragment.kt @@ -1,5 +1,7 @@ package be.mygod.vpnhotspot +import android.animation.Animator +import android.animation.AnimatorListenerAdapter import android.content.Intent import android.content.res.Resources import android.databinding.BaseObservable @@ -11,6 +13,7 @@ import android.support.v7.util.SortedList import android.support.v7.widget.DefaultItemAnimator import android.support.v7.widget.LinearLayoutManager import android.support.v7.widget.RecyclerView +import android.text.Html import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -18,6 +21,7 @@ import be.mygod.vpnhotspot.App.Companion.app import be.mygod.vpnhotspot.NetUtils.tetheredIfaces import be.mygod.vpnhotspot.databinding.FragmentTetheringBinding import be.mygod.vpnhotspot.databinding.ListitemInterfaceBinding +import be.mygod.vpnhotspot.widget.TextViewLinkHandler class TetheringFragment : Fragment() { companion object { @@ -83,9 +87,13 @@ class TetheringFragment : Fragment() { private val tethered = SortedList(String::class.java, StringSorter) fun update(data: Set = VpnListener.connectivityManager.tetheredIfaces.toSet()) { + val oldEmpty = tethered.size() == 0 tethered.clear() tethered.addAll(data) notifyDataSetChanged() + if (oldEmpty != data.isEmpty()) + if (oldEmpty) crossFade(binding.empty, binding.interfaces) + else crossFade(binding.interfaces, binding.empty) } override fun getItemCount() = tethered.size() @@ -96,6 +104,7 @@ class TetheringFragment : Fragment() { } } + private lateinit var binding: FragmentTetheringBinding private val adapter = InterfaceAdapter() private val receiver = broadcastReceiver { _, intent -> when (intent.action) { @@ -107,8 +116,12 @@ class TetheringFragment : Fragment() { private var receiverRegistered = false override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - val binding = DataBindingUtil.inflate(inflater, R.layout.fragment_tethering, - container, false) + binding = DataBindingUtil.inflate(inflater, R.layout.fragment_tethering, container, false) + binding.empty.text = Html.fromHtml(getString(R.string.tethering_no_interfaces)) + binding.empty.movementMethod = TextViewLinkHandler.create { + startActivity(Intent().setClassName("com.android.settings", + "com.android.settings.Settings\$TetherSettingsActivity")) + } binding.interfaces.layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false) val animator = DefaultItemAnimator() animator.supportsChangeAnimations = false // prevent fading-in/out when rebinding @@ -138,4 +151,16 @@ class TetheringFragment : Fragment() { } super.onStop() } + + private fun crossFade(old: View, new: View) { + val shortAnimTime = resources.getInteger(android.R.integer.config_shortAnimTime).toLong() + old.animate().alpha(0F).setListener(object : AnimatorListenerAdapter() { + override fun onAnimationEnd(animation: Animator) { + old.visibility = View.GONE + } + }).duration = shortAnimTime + new.alpha = 0F + new.visibility = View.VISIBLE + new.animate().alpha(1F).setListener(null).duration = shortAnimTime + } } diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/widget/TextViewLinkHandler.kt b/mobile/src/main/java/be/mygod/vpnhotspot/widget/TextViewLinkHandler.kt new file mode 100644 index 00000000..24908aea --- /dev/null +++ b/mobile/src/main/java/be/mygod/vpnhotspot/widget/TextViewLinkHandler.kt @@ -0,0 +1,32 @@ +package be.mygod.vpnhotspot.widget + +import android.text.Spannable +import android.text.method.LinkMovementMethod +import android.text.style.URLSpan +import android.view.MotionEvent +import android.widget.TextView + +/** + * Based on: https://stackoverflow.com/a/32443884/2245107 + */ +abstract class TextViewLinkHandler : LinkMovementMethod() { + companion object { + fun create(handler: (String) -> Unit) = object : TextViewLinkHandler() { + override fun onLinkClick(url: String) = handler(url) + } + } + + override fun onTouchEvent(widget: TextView, buffer: Spannable, event: MotionEvent): Boolean { + if (event.action != MotionEvent.ACTION_UP) return super.onTouchEvent(widget, buffer, event) + val x = event.x - widget.totalPaddingLeft + widget.scrollX + val y = event.y.toInt() - widget.totalPaddingTop + widget.scrollY + val layout = widget.layout + val line = layout.getLineForVertical(y) + val off = layout.getOffsetForHorizontal(line, x) + val link = buffer.getSpans(off, off, URLSpan::class.java) + if (link.isNotEmpty()) onLinkClick(link[0].url) + return true + } + + abstract fun onLinkClick(url: String) +} diff --git a/mobile/src/main/res/layout/fragment_tethering.xml b/mobile/src/main/res/layout/fragment_tethering.xml index 6b669658..9ce4c9d9 100644 --- a/mobile/src/main/res/layout/fragment_tethering.xml +++ b/mobile/src/main/res/layout/fragment_tethering.xml @@ -16,13 +16,26 @@ android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" app:popupTheme="@style/ThemeOverlay.AppCompat.Light" android:id="@+id/toolbar"/> - + android:layout_weight="1"> + + + diff --git a/mobile/src/main/res/layout/listitem_interface.xml b/mobile/src/main/res/layout/listitem_interface.xml index cfdc4868..544548a8 100644 --- a/mobile/src/main/res/layout/listitem_interface.xml +++ b/mobile/src/main/res/layout/listitem_interface.xml @@ -21,6 +21,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@{data.icon}" + android:tint="?android:attr/textColorPrimary" tools:src="@drawable/ic_device_network_wifi"/> %d connected devices Fatal: Downstream interface not found + system + tethering first.]]>