Refine UI for tethering

This commit is contained in:
Mygod
2018-01-13 11:30:52 +08:00
parent 48b17f087e
commit 7b2166af61
5 changed files with 81 additions and 8 deletions

View File

@@ -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<String> = 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<FragmentTetheringBinding>(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
}
}

View File

@@ -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)
}

View File

@@ -16,13 +16,26 @@
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
android:id="@+id/toolbar"/>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<TextView
android:id="@+id/empty"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:linksClickable="true"
android:padding="16dp"
tools:text="@string/tethering_no_interfaces"/>
<android.support.v7.widget.RecyclerView
android:id="@+id/interfaces"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
android:clipToPadding="false"
android:scrollbars="vertical"
tools:listitem="@layout/listitem_interface"/>
android:visibility="gone"
tools:listitem="@layout/listitem_interface"
tools:visibility="visible"/>
</FrameLayout>
</LinearLayout>
</layout>

View File

@@ -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"/>
<Space

View File

@@ -6,4 +6,6 @@
<item quantity="other">%d connected devices</item>
</plurals>
<string name="exception_interface_not_found">Fatal: Downstream interface not found</string>
<string name="tethering_no_interfaces"><![CDATA[To use this feature, turn on any <a href=&quot;#&quot;>system
tethering</a> first.]]></string>
</resources>