139 lines
6.1 KiB
Kotlin
139 lines
6.1 KiB
Kotlin
package be.mygod.vpnhotspot
|
|
|
|
import android.animation.Animator
|
|
import android.animation.AnimatorListenerAdapter
|
|
import android.content.Intent
|
|
import android.databinding.BaseObservable
|
|
import android.databinding.DataBindingUtil
|
|
import android.os.Bundle
|
|
import android.support.v4.app.Fragment
|
|
import android.support.v4.content.LocalBroadcastManager
|
|
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.support.v7.widget.Toolbar
|
|
import android.view.LayoutInflater
|
|
import android.view.MenuItem
|
|
import android.view.View
|
|
import android.view.ViewGroup
|
|
import be.mygod.vpnhotspot.databinding.FragmentTetheringBinding
|
|
import be.mygod.vpnhotspot.databinding.ListitemInterfaceBinding
|
|
import be.mygod.vpnhotspot.net.NetUtils
|
|
import be.mygod.vpnhotspot.net.TetherType
|
|
|
|
class TetheringFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|
private abstract class BaseSorter<T> : SortedList.Callback<T>() {
|
|
override fun onInserted(position: Int, count: Int) { }
|
|
override fun areContentsTheSame(oldItem: T?, newItem: T?): Boolean = oldItem == newItem
|
|
override fun onMoved(fromPosition: Int, toPosition: Int) { }
|
|
override fun onChanged(position: Int, count: Int) { }
|
|
override fun onRemoved(position: Int, count: Int) { }
|
|
override fun areItemsTheSame(item1: T?, item2: T?): Boolean = item1 == item2
|
|
override fun compare(o1: T?, o2: T?): Int =
|
|
if (o1 == null) if (o2 == null) 0 else 1 else if (o2 == null) -1 else compareNonNull(o1, o2)
|
|
abstract fun compareNonNull(o1: T, o2: T): Int
|
|
}
|
|
private open class DefaultSorter<T : Comparable<T>> : BaseSorter<T>() {
|
|
override fun compareNonNull(o1: T, o2: T): Int = o1.compareTo(o2)
|
|
}
|
|
private object StringSorter : DefaultSorter<String>()
|
|
|
|
class Data(val iface: String) : BaseObservable() {
|
|
val icon: Int get() = TetherType.ofInterface(iface).icon
|
|
var active = TetheringService.active.contains(iface)
|
|
}
|
|
|
|
class InterfaceViewHolder(val binding: ListitemInterfaceBinding) : RecyclerView.ViewHolder(binding.root),
|
|
View.OnClickListener {
|
|
init {
|
|
itemView.setOnClickListener(this)
|
|
}
|
|
|
|
override fun onClick(view: View) {
|
|
val context = itemView.context
|
|
val data = binding.data!!
|
|
context.startService(Intent(context, TetheringService::class.java).putExtra(if (data.active)
|
|
TetheringService.EXTRA_REMOVE_INTERFACE else TetheringService.EXTRA_ADD_INTERFACE, data.iface))
|
|
data.active = !data.active
|
|
}
|
|
}
|
|
inner class InterfaceAdapter : RecyclerView.Adapter<InterfaceViewHolder>() {
|
|
private val tethered = SortedList(String::class.java, StringSorter)
|
|
|
|
fun update(data: Set<String>) {
|
|
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()
|
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = InterfaceViewHolder(
|
|
ListitemInterfaceBinding.inflate(LayoutInflater.from(parent.context), parent, false))
|
|
override fun onBindViewHolder(holder: InterfaceViewHolder, position: Int) {
|
|
holder.binding.data = Data(tethered[position])
|
|
}
|
|
}
|
|
|
|
private lateinit var binding: FragmentTetheringBinding
|
|
private val adapter = InterfaceAdapter()
|
|
private val receiver = broadcastReceiver { _, intent ->
|
|
when (intent.action) {
|
|
TetheringService.ACTION_ACTIVE_INTERFACES_CHANGED -> adapter.notifyDataSetChanged()
|
|
NetUtils.ACTION_TETHER_STATE_CHANGED -> adapter.update(NetUtils.getTetheredIfaces(intent.extras).toSet())
|
|
}
|
|
}
|
|
|
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
|
binding = DataBindingUtil.inflate(inflater, R.layout.fragment_tethering, container, false)
|
|
binding.toolbar.inflateMenu(R.menu.tethering)
|
|
binding.toolbar.setOnMenuItemClickListener(this)
|
|
binding.interfaces.layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
|
|
val animator = DefaultItemAnimator()
|
|
animator.supportsChangeAnimations = false // prevent fading-in/out when rebinding
|
|
binding.interfaces.itemAnimator = animator
|
|
binding.interfaces.adapter = adapter
|
|
return binding.root
|
|
}
|
|
|
|
override fun onStart() {
|
|
super.onStart()
|
|
val context = context!!
|
|
context.registerReceiver(receiver, intentFilter(NetUtils.ACTION_TETHER_STATE_CHANGED))
|
|
LocalBroadcastManager.getInstance(context)
|
|
.registerReceiver(receiver, intentFilter(TetheringService.ACTION_ACTIVE_INTERFACES_CHANGED))
|
|
}
|
|
|
|
override fun onStop() {
|
|
val context = context!!
|
|
context.unregisterReceiver(receiver)
|
|
LocalBroadcastManager.getInstance(context).unregisterReceiver(receiver)
|
|
super.onStop()
|
|
}
|
|
|
|
override fun onMenuItemClick(item: MenuItem) = when (item.itemId) {
|
|
R.id.systemTethering -> {
|
|
startActivity(Intent().setClassName("com.android.settings",
|
|
"com.android.settings.Settings\$TetherSettingsActivity"))
|
|
true
|
|
}
|
|
else -> false
|
|
}
|
|
|
|
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
|
|
}
|
|
}
|