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 : SortedList.Callback() { 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> : BaseSorter() { override fun compareNonNull(o1: T, o2: T): Int = o1.compareTo(o2) } private object StringSorter : DefaultSorter() 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() { private val tethered = SortedList(String::class.java, StringSorter) fun update(data: Set) { 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 } }