From de7c6c5d8cb3802c7bb57f7cc0b79853f91a5513 Mon Sep 17 00:00:00 2001 From: Mygod Date: Sun, 21 Jan 2018 13:16:21 -0800 Subject: [PATCH] Mimic Android Wi-Fi setting design in tethering --- .../be/mygod/vpnhotspot/TetheringFragment.kt | 72 +++++++++---------- .../src/main/res/drawable/ic_content_add.xml | 9 +++ .../main/res/layout/fragment_tethering.xml | 25 ++----- .../src/main/res/layout/listitem_client.xml | 4 +- .../main/res/layout/listitem_interface.xml | 9 ++- .../src/main/res/layout/listitem_manage.xml | 29 ++++++++ mobile/src/main/res/menu/tethering.xml | 10 --- mobile/src/main/res/values/strings.xml | 3 - 8 files changed, 82 insertions(+), 79 deletions(-) create mode 100644 mobile/src/main/res/drawable/ic_content_add.xml create mode 100644 mobile/src/main/res/layout/listitem_manage.xml delete mode 100644 mobile/src/main/res/menu/tethering.xml diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/TetheringFragment.kt b/mobile/src/main/java/be/mygod/vpnhotspot/TetheringFragment.kt index b56c2ab7..de59112c 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/TetheringFragment.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/TetheringFragment.kt @@ -1,7 +1,5 @@ package be.mygod.vpnhotspot -import android.animation.Animator -import android.animation.AnimatorListenerAdapter import android.content.ComponentName import android.content.Context import android.content.Intent @@ -16,9 +14,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.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 @@ -26,7 +22,12 @@ import be.mygod.vpnhotspot.databinding.ListitemInterfaceBinding import be.mygod.vpnhotspot.net.ConnectivityManagerHelper import be.mygod.vpnhotspot.net.TetherType -class TetheringFragment : Fragment(), ServiceConnection, Toolbar.OnMenuItemClickListener { +class TetheringFragment : Fragment(), ServiceConnection { + companion object { + private const val VIEW_TYPE_INTERFACE = 0 + private const val VIEW_TYPE_MANAGE = 1 + } + private abstract class BaseSorter : SortedList.Callback() { override fun onInserted(position: Int, count: Int) { } override fun areContentsTheSame(oldItem: T?, newItem: T?): Boolean = oldItem == newItem @@ -48,7 +49,7 @@ class TetheringFragment : Fragment(), ServiceConnection, Toolbar.OnMenuItemClick var active = binder?.active?.contains(iface) == true } - class InterfaceViewHolder(val binding: ListitemInterfaceBinding) : RecyclerView.ViewHolder(binding.root), + private class InterfaceViewHolder(val binding: ListitemInterfaceBinding) : RecyclerView.ViewHolder(binding.root), View.OnClickListener { init { itemView.setOnClickListener(this) @@ -64,38 +65,50 @@ class TetheringFragment : Fragment(), ServiceConnection, Toolbar.OnMenuItemClick data.active = !data.active } } - inner class InterfaceAdapter : RecyclerView.Adapter() { + private class ManageViewHolder(view: View) : RecyclerView.ViewHolder(view), View.OnClickListener { + init { + view.setOnClickListener(this) + } + + override fun onClick(v: View?) = itemView.context.startActivity(Intent() + .setClassName("com.android.settings", "com.android.settings.Settings\$TetherSettingsActivity")) + } + inner class TetheringAdapter : 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]) + override fun getItemCount() = tethered.size() + 1 + override fun getItemViewType(position: Int) = + if (position == tethered.size()) VIEW_TYPE_MANAGE else VIEW_TYPE_INTERFACE + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { + val inflater = LayoutInflater.from(parent.context) + return when (viewType) { + VIEW_TYPE_INTERFACE -> InterfaceViewHolder(ListitemInterfaceBinding.inflate(inflater, parent, false)) + VIEW_TYPE_MANAGE -> ManageViewHolder(inflater.inflate(R.layout.listitem_manage, parent, false)) + else -> throw IllegalArgumentException() + } + } + override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { + when (holder) { + is InterfaceViewHolder -> holder.binding.data = Data(tethered[position]) + } } } private lateinit var binding: FragmentTetheringBinding private var binder: TetheringService.TetheringBinder? = null - val adapter = InterfaceAdapter() + val adapter = TetheringAdapter() private val receiver = broadcastReceiver { _, intent -> adapter.update(ConnectivityManagerHelper.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 @@ -128,25 +141,4 @@ class TetheringFragment : Fragment(), ServiceConnection, Toolbar.OnMenuItemClick binder?.fragment = null binder = null } - - 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 - } } diff --git a/mobile/src/main/res/drawable/ic_content_add.xml b/mobile/src/main/res/drawable/ic_content_add.xml new file mode 100644 index 00000000..0258249c --- /dev/null +++ b/mobile/src/main/res/drawable/ic_content_add.xml @@ -0,0 +1,9 @@ + + + diff --git a/mobile/src/main/res/layout/fragment_tethering.xml b/mobile/src/main/res/layout/fragment_tethering.xml index 4fa72e97..2f0b4e44 100644 --- a/mobile/src/main/res/layout/fragment_tethering.xml +++ b/mobile/src/main/res/layout/fragment_tethering.xml @@ -12,28 +12,15 @@ android:layout_width="match_parent" android:background="?attr/colorPrimary" android:elevation="4dp" - android:touchscreenBlocksFocus="false" app:title="@string/app_name" android:id="@+id/toolbar"/> - - - - + android:layout_weight="1" + android:clipToPadding="false" + android:scrollbars="vertical" + tools:listitem="@layout/listitem_interface"/> diff --git a/mobile/src/main/res/layout/listitem_client.xml b/mobile/src/main/res/layout/listitem_client.xml index 0e28e724..81d2a4a2 100644 --- a/mobile/src/main/res/layout/listitem_client.xml +++ b/mobile/src/main/res/layout/listitem_client.xml @@ -11,10 +11,10 @@ + android:paddingTop="8dp"> + android:padding="16dp"> @@ -32,13 +30,14 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" + android:layout_gravity="center_vertical" + android:checked="@{data.active}" android:clickable="false" android:ellipsize="end" android:focusable="false" android:focusableInTouchMode="false" android:gravity="center_vertical" android:text="@{data.iface}" - android:checked="@{data.active}" tools:text="wlan0"/> diff --git a/mobile/src/main/res/layout/listitem_manage.xml b/mobile/src/main/res/layout/listitem_manage.xml new file mode 100644 index 00000000..6f5bd253 --- /dev/null +++ b/mobile/src/main/res/layout/listitem_manage.xml @@ -0,0 +1,29 @@ + + + + + + + + + + diff --git a/mobile/src/main/res/menu/tethering.xml b/mobile/src/main/res/menu/tethering.xml deleted file mode 100644 index 76094581..00000000 --- a/mobile/src/main/res/menu/tethering.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - \ No newline at end of file diff --git a/mobile/src/main/res/values/strings.xml b/mobile/src/main/res/values/strings.xml index 15c7b69a..c93878a8 100644 --- a/mobile/src/main/res/values/strings.xml +++ b/mobile/src/main/res/values/strings.xml @@ -37,9 +37,6 @@ no service requests added unknown #%d - System tethering - To use this feature, turn on any system tethering first. - Service Downstream DNS server:port Clean/reapply routing rules