Refine UI for tethering
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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="#">system
|
||||
tethering</a> first.]]></string>
|
||||
</resources>
|
||||
|
||||
Reference in New Issue
Block a user