diff --git a/app/src/main/java/com/gaurav/avnc/Architecture.kt b/app/src/main/java/com/gaurav/avnc/Architecture.kt index 7f12a9c..61983f0 100644 --- a/app/src/main/java/com/gaurav/avnc/Architecture.kt +++ b/app/src/main/java/com/gaurav/avnc/Architecture.kt @@ -11,7 +11,10 @@ package com.gaurav.avnc import com.gaurav.avnc.model.ServerProfile import com.gaurav.avnc.model.db.MainDb import com.gaurav.avnc.ui.about.AboutActivity -import com.gaurav.avnc.ui.home.* +import com.gaurav.avnc.ui.home.HomeActivity +import com.gaurav.avnc.ui.home.ProfileEditorFragment +import com.gaurav.avnc.ui.home.ServerTabs +import com.gaurav.avnc.ui.home.UrlBarActivity import com.gaurav.avnc.ui.prefs.PrefsActivity import com.gaurav.avnc.ui.vnc.* import com.gaurav.avnc.viewmodel.HomeViewModel @@ -68,8 +71,8 @@ import com.gaurav.avnc.vnc.VncClient * - A urlbar, which launches [UrlBarActivity], allowing user to quickly connect * to a server without creating a profile for it. * - * - List of saved servers, shown by [ServersFragment]. - * - List of servers found by [Discovery], shown by [DiscoveryFragment]. + * - Lists of saved & discovered servers, in [ServerTabs]. + * * - [ProfileEditorFragment], used for creating/editing [ServerProfile]. * * diff --git a/app/src/main/java/com/gaurav/avnc/ui/home/DiscoveryFragment.kt b/app/src/main/java/com/gaurav/avnc/ui/home/DiscoveryFragment.kt deleted file mode 100644 index e20cb65..0000000 --- a/app/src/main/java/com/gaurav/avnc/ui/home/DiscoveryFragment.kt +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2020 Gaurav Ujjwal. - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - * See COPYING.txt for more details. - */ - -package com.gaurav.avnc.ui.home - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.fragment.app.Fragment -import androidx.fragment.app.activityViewModels -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.lifecycleScope -import androidx.recyclerview.widget.LinearLayoutManager -import com.gaurav.avnc.databinding.FragmentDiscoveryBinding -import com.gaurav.avnc.ui.home.adapter.DiscoveryAdapter -import com.gaurav.avnc.viewmodel.HomeViewModel -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.delay -import kotlinx.coroutines.launch - -/** - * Fragment for displaying VNC servers found by Discovery. - */ -class DiscoveryFragment : Fragment() { - - val viewModel by activityViewModels() - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { - val binding = FragmentDiscoveryBinding.inflate(inflater, container, false) - binding.lifecycleOwner = viewLifecycleOwner - binding.viewModel = viewModel - - val adapter = DiscoveryAdapter(viewModel) - binding.discoveredRv.layoutManager = LinearLayoutManager(requireContext()) - binding.discoveredRv.adapter = adapter - binding.discoveredRv.setHasFixedSize(true) - - viewModel.discovery.servers.observe(viewLifecycleOwner) { adapter.submitList(it) } - - launchRestarter() - return binding.root - } - - private fun launchRestarter() = lifecycleScope.launch(Dispatchers.Main) { - - while (true) { - delay(viewModel.pref.server.discoveryTimeout + viewModel.pref.server.discoveryRestartDelay) - - if (activity?.lifecycle?.currentState == Lifecycle.State.RESUMED && - viewModel.pref.server.discoveryAutoStart && - viewModel.pref.server.discoveryRestart) { - viewModel.startDiscovery() - } - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/gaurav/avnc/ui/home/HomeActivity.kt b/app/src/main/java/com/gaurav/avnc/ui/home/HomeActivity.kt index 9873cc1..8422635 100644 --- a/app/src/main/java/com/gaurav/avnc/ui/home/HomeActivity.kt +++ b/app/src/main/java/com/gaurav/avnc/ui/home/HomeActivity.kt @@ -34,7 +34,7 @@ import com.google.android.material.snackbar.Snackbar class HomeActivity : AppCompatActivity() { val viewModel by viewModels() private lateinit var binding: ActivityHomeBinding - private lateinit var tabController: TabController + private val tabs = ServerTabs(this) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -44,7 +44,8 @@ class HomeActivity : AppCompatActivity() { binding = DataBindingUtil.setContentView(this, R.layout.activity_home) binding.lifecycleOwner = this - tabController = TabController(this, binding.pager, binding.tabLayout) + tabs.create(binding.tabLayout, binding.pager) + binding.drawerNav.setNavigationItemSelectedListener { onMenuItemSelected(it.itemId) } binding.navigationBtn.setOnClickListener { binding.drawerLayout.open() } binding.settingsBtn.setOnClickListener { showSettings() } @@ -107,7 +108,7 @@ class HomeActivity : AppCompatActivity() { } private fun onProfileInserted(profile: ServerProfile) { - tabController.showSavedServers() + tabs.showSavedServers() // Show snackbar for new servers if (profile.ID == 0L) @@ -124,6 +125,6 @@ class HomeActivity : AppCompatActivity() { } private fun updateDiscoveryBadge(list: List) { - tabController.updateDiscoveryBadge(list.size) + tabs.updateDiscoveryBadge(list.size) } } \ No newline at end of file diff --git a/app/src/main/java/com/gaurav/avnc/ui/home/ServerTabs.kt b/app/src/main/java/com/gaurav/avnc/ui/home/ServerTabs.kt new file mode 100644 index 0000000..b6f94e6 --- /dev/null +++ b/app/src/main/java/com/gaurav/avnc/ui/home/ServerTabs.kt @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2021 Gaurav Ujjwal. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + * See COPYING.txt for more details. + */ + +package com.gaurav.avnc.ui.home + +import android.view.* +import androidx.core.view.forEach +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.ListAdapter +import androidx.recyclerview.widget.RecyclerView +import androidx.viewpager2.widget.ViewPager2 +import com.gaurav.avnc.R +import com.gaurav.avnc.databinding.ServerDiscoveryBinding +import com.gaurav.avnc.databinding.ServerDiscoveryItemBinding +import com.gaurav.avnc.databinding.ServerSavedBinding +import com.gaurav.avnc.databinding.ServerSavedItemBinding +import com.gaurav.avnc.model.ServerProfile +import com.gaurav.avnc.ui.home.ServerTabs.PagerAdapter.ViewHolder +import com.gaurav.avnc.util.Experimental +import com.gaurav.avnc.viewmodel.HomeViewModel +import com.google.android.material.snackbar.Snackbar +import com.google.android.material.tabs.TabLayout +import com.google.android.material.tabs.TabLayoutMediator + +/** + * This class creates and manages tabs in [HomeActivity]. + * Tabs: + * 1. Saved servers + * 2. Discovered servers + */ +class ServerTabs(val activity: HomeActivity) { + + lateinit var savedServersTab: TabLayout.Tab + lateinit var discoveredServersTab: TabLayout.Tab + + /** + * Creates and initializes tabs + * + * [tabLayout] Hosts tabs + * [pager] Hosts actual content views + */ + fun create(tabLayout: TabLayout, pager: ViewPager2) { + pager.adapter = PagerAdapter() + pager.offscreenPageLimit = 1 // Tell pager to initialize & keep both tabs in memory + + TabLayoutMediator(tabLayout, pager) { _, _ -> } + .attach() + + savedServersTab = tabLayout.getTabAt(0)!! + savedServersTab.setIcon(R.drawable.ic_computer) + savedServersTab.setContentDescription(R.string.desc_saved_servers_tab) + + discoveredServersTab = tabLayout.getTabAt(1)!! + discoveredServersTab.setIcon(R.drawable.ic_search) + discoveredServersTab.setContentDescription(R.string.desc_discovered_servers_tab) + } + + fun showSavedServers() { + savedServersTab.select() + } + + fun updateDiscoveryBadge(count: Int) { + //Currently, we are not showing the actual count in the badge. + //But maybe we could implement a preference??? + discoveredServersTab.getOrCreateBadge().isVisible = (count != 0) + } + + + /** + * Adapter for our pager. + * + * We have fixed number of static views so our implementation is really simple. + * We override [getItemViewType] to use the given position itself as view type. + * Then, in [onCreateViewHolder], that view type (i.e. position) is used to + * generate corresponding view. + * + * As a result, nothing else needs to be done by [ViewHolder] & [bindViewHolder]. + */ + private inner class PagerAdapter : RecyclerView.Adapter() { + + private inner class ViewHolder(v: View) : RecyclerView.ViewHolder(v) + + override fun getItemCount() = 2 + override fun getItemViewType(position: Int) = position + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return when (viewType) { + 0 -> ViewHolder(createSavedServersView(parent)) + 1 -> ViewHolder(createDiscoveredServersView(parent)) + else -> throw IllegalStateException("Unexpected view type: [$viewType]") + } + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) {} + } + + + /********************************************************************************************** + * Saved servers + **********************************************************************************************/ + + private fun createSavedServersView(parent: ViewGroup): View { + val binding = ServerSavedBinding.inflate(activity.layoutInflater, parent, false) + binding.lifecycleOwner = activity + binding.viewModel = activity.viewModel + + val adapter = SavedServerAdapter(activity.viewModel) + binding.serversRv.layoutManager = LinearLayoutManager(activity) + binding.serversRv.adapter = adapter + binding.serversRv.setHasFixedSize(true) + + activity.viewModel.serverProfiles.observe(activity) { adapter.submitList(it) } + + if (activity.viewModel.pref.experimental.indicator) { + Experimental.Indicator().setup(binding, adapter) + } + + return binding.root + } + + + /** + * Adapter for saved servers + */ + class SavedServerAdapter(val viewModel: HomeViewModel) + : ListAdapter(Differ) { + + //Experimental feature + var bindListener: ((ViewHolder, ServerProfile) -> Unit)? = null + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + val inflater = LayoutInflater.from(parent.context) + val binding = ServerSavedItemBinding.inflate(inflater, parent, false) + return ViewHolder(binding) + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val profile = getItem(position) + holder.profile = profile + holder.binding.viewModel = profile + bindListener?.invoke(holder, profile) + } + + inner class ViewHolder(val binding: ServerSavedItemBinding) + : ProfileViewHolder(viewModel, binding.root, R.menu.saved_server) + + object Differ : DiffUtil.ItemCallback() { + override fun areItemsTheSame(old: ServerProfile, new: ServerProfile) = (old.ID == new.ID) + override fun areContentsTheSame(old: ServerProfile, new: ServerProfile) = (old == new) + } + } + + + /********************************************************************************************** + * Discovered servers + **********************************************************************************************/ + + private fun createDiscoveredServersView(parent: ViewGroup): View { + val binding = ServerDiscoveryBinding.inflate(activity.layoutInflater, parent, false) + binding.lifecycleOwner = activity + binding.viewModel = activity.viewModel + + val adapter = DiscoveredServerAdapter(activity.viewModel) + binding.discoveredRv.layoutManager = LinearLayoutManager(activity) + binding.discoveredRv.adapter = adapter + binding.discoveredRv.setHasFixedSize(true) + + activity.viewModel.discovery.servers.observe(activity) { adapter.submitList(it) } + + return binding.root + } + + + class DiscoveredServerAdapter(val viewModel: HomeViewModel) + : ListAdapter(Differ) { + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + val inflater = LayoutInflater.from(parent.context) + val binding = ServerDiscoveryItemBinding.inflate(inflater, parent, false) + return ViewHolder(binding) + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val profile = getItem(position) + holder.profile = profile + holder.binding.viewModel = profile + } + + inner class ViewHolder(val binding: ServerDiscoveryItemBinding) : + ProfileViewHolder(viewModel, binding.root, R.menu.discovered_server) { + + init { + binding.saveBtn.setOnClickListener { viewModel.onNewProfile(profile) } + } + } + + /** + * Profiles generated by discovery don't have unique IDs, so we compare the whole profile. + */ + object Differ : DiffUtil.ItemCallback() { + override fun areItemsTheSame(old: ServerProfile, new: ServerProfile) = (old == new) + override fun areContentsTheSame(old: ServerProfile, new: ServerProfile) = (old == new) + } + } + + + /** + * Base ViewHolder for [ServerProfile], used by both adapters. + */ + open class ProfileViewHolder( + private val homeViewModel: HomeViewModel, + private val rootView: View, + private val contextMenuId: Int) + : RecyclerView.ViewHolder(rootView) { + + /** + * Points to the profile being rendered by this view holder. + * Updated by adapters during onBindViewHolder(). + */ + var profile = ServerProfile() + + init { + rootView.setOnClickListener { homeViewModel.startConnection(profile) } + + rootView.setOnCreateContextMenuListener { contextMenu, view, _ -> + MenuInflater(view.context).inflate(contextMenuId, contextMenu) + contextMenu.forEach { item -> + item.setOnMenuItemClickListener { onContextMenuItemClick(it) } + } + } + } + + private fun onContextMenuItemClick(item: MenuItem): Boolean { + when (item.itemId) { + R.id.edit -> homeViewModel.onEditProfile(profile) + R.id.duplicate -> homeViewModel.onDuplicateProfile(profile) + R.id.delete -> homeViewModel.deleteProfile(profile) + R.id.copy_host -> copyToClipboard(profile.host) + R.id.copy_name -> copyToClipboard(profile.name) + } + return true + } + + private fun copyToClipboard(text: String) { + homeViewModel.setClipboardText(text) + Snackbar.make(rootView, R.string.msg_copied_to_clipboard, Snackbar.LENGTH_SHORT).show() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gaurav/avnc/ui/home/ServersFragment.kt b/app/src/main/java/com/gaurav/avnc/ui/home/ServersFragment.kt deleted file mode 100644 index 8fd7ec4..0000000 --- a/app/src/main/java/com/gaurav/avnc/ui/home/ServersFragment.kt +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2020 Gaurav Ujjwal. - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - * See COPYING.txt for more details. - */ - -package com.gaurav.avnc.ui.home - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.fragment.app.Fragment -import androidx.fragment.app.activityViewModels -import androidx.recyclerview.widget.LinearLayoutManager -import com.gaurav.avnc.databinding.FragmentServersBinding -import com.gaurav.avnc.ui.home.adapter.ServersAdapter -import com.gaurav.avnc.util.Experimental -import com.gaurav.avnc.viewmodel.HomeViewModel - -/** - * Fragment for displaying list of known servers. - */ -class ServersFragment : Fragment() { - - val viewModel by activityViewModels() - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { - val binding = FragmentServersBinding.inflate(inflater, container, false) - binding.lifecycleOwner = viewLifecycleOwner - binding.viewModel = viewModel - - val adapter = ServersAdapter(viewModel) - binding.serversRv.layoutManager = LinearLayoutManager(context) - binding.serversRv.adapter = adapter - binding.serversRv.setHasFixedSize(true) - - viewModel.serverProfiles.observe(viewLifecycleOwner) { adapter.submitList(it) } - - if (viewModel.pref.experimental.indicator) { - Experimental.Indicator().setup(binding, adapter) - } - - return binding.root - } -} \ No newline at end of file diff --git a/app/src/main/java/com/gaurav/avnc/ui/home/TabController.kt b/app/src/main/java/com/gaurav/avnc/ui/home/TabController.kt deleted file mode 100644 index 7f5e7b2..0000000 --- a/app/src/main/java/com/gaurav/avnc/ui/home/TabController.kt +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2021 Gaurav Ujjwal. - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - * See COPYING.txt for more details. - */ - -package com.gaurav.avnc.ui.home - -import androidx.annotation.DrawableRes -import androidx.annotation.StringRes -import androidx.fragment.app.Fragment -import androidx.viewpager2.adapter.FragmentStateAdapter -import androidx.viewpager2.widget.ViewPager2 -import com.gaurav.avnc.R -import com.google.android.material.tabs.TabLayout -import com.google.android.material.tabs.TabLayoutMediator - -/** - * Controls tab layout and associated pager in home activity. - */ -class TabController(val activity: HomeActivity, private val pager: ViewPager2, tabLayout: TabLayout) { - - private data class PageInfo( - val fragment: Fragment, - @DrawableRes val iconId: Int, - @StringRes val descriptionId: Int - ) - - private val pageList = listOf( - PageInfo(ServersFragment(), R.drawable.ic_computer, R.string.desc_saved_servers_tab), - PageInfo(DiscoveryFragment(), R.drawable.ic_search, R.string.desc_discovered_servers_tab), - ) - - private inner class PagerAdapter : FragmentStateAdapter(activity) { - override fun getItemCount() = pageList.size - override fun createFragment(position: Int) = pageList[position].fragment - } - - - private val discoveryTab: TabLayout.Tab - - init { - pager.adapter = PagerAdapter() - - // Ask the the pager to keep both fragments in memory - // This allows smoother transition between fragments - pager.offscreenPageLimit = 1 - - val mediator = TabLayoutMediator(tabLayout, pager) { tab, position -> - tab.setIcon(pageList[position].iconId) - tab.setContentDescription(pageList[position].descriptionId) - } - - mediator.attach() - discoveryTab = tabLayout.getTabAt(1)!! - } - - fun showSavedServers() { - pager.setCurrentItem(0, true) - } - - fun updateDiscoveryBadge(count: Int) { - //Currently, we are not showing the actual count in the badge. - //But maybe we could implement a preference??? - discoveryTab.getOrCreateBadge().isVisible = (count != 0) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/gaurav/avnc/ui/home/adapter/DiscoveryAdapter.kt b/app/src/main/java/com/gaurav/avnc/ui/home/adapter/DiscoveryAdapter.kt deleted file mode 100644 index faec566..0000000 --- a/app/src/main/java/com/gaurav/avnc/ui/home/adapter/DiscoveryAdapter.kt +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2020 Gaurav Ujjwal. - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - * See COPYING.txt for more details. - */ - -package com.gaurav.avnc.ui.home.adapter - -import android.view.LayoutInflater -import android.view.ViewGroup -import androidx.recyclerview.widget.DiffUtil -import androidx.recyclerview.widget.ListAdapter -import com.gaurav.avnc.R -import com.gaurav.avnc.databinding.ItemDiscoveryBinding -import com.gaurav.avnc.model.ServerProfile -import com.gaurav.avnc.viewmodel.HomeViewModel - -class DiscoveryAdapter(val viewModel: HomeViewModel) : ListAdapter(Differ) { - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { - val inflater = LayoutInflater.from(parent.context) - val binding = ItemDiscoveryBinding.inflate(inflater, parent, false) - return ViewHolder(binding) - } - - override fun onBindViewHolder(holder: ViewHolder, position: Int) { - holder.bind(getItem(position)) - } - - /** - * View holder for discovered servers. - */ - inner class ViewHolder(binding: ItemDiscoveryBinding) : - ProfileViewHolder(viewModel, binding, R.menu.discovered_server) { - - init { - binding.saveBtn.setOnClickListener { viewModel.onNewProfile(profile) } - } - } - - /** - * This is slightly different from [ServersAdapter.Differ] because all profiles generated - * by service discovery have same ID (0) & all discovered servers are unique. So we - * compare the whole profile instead of a particular field. - */ - object Differ : DiffUtil.ItemCallback() { - override fun areItemsTheSame(old: ServerProfile, new: ServerProfile) = (old == new) - override fun areContentsTheSame(old: ServerProfile, new: ServerProfile) = (old == new) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/gaurav/avnc/ui/home/adapter/ProfileViewHolder.kt b/app/src/main/java/com/gaurav/avnc/ui/home/adapter/ProfileViewHolder.kt deleted file mode 100644 index 6a5ba1a..0000000 --- a/app/src/main/java/com/gaurav/avnc/ui/home/adapter/ProfileViewHolder.kt +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (c) 2020 Gaurav Ujjwal. - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - * See COPYING.txt for more details. - */ - -package com.gaurav.avnc.ui.home.adapter - -import android.view.MenuInflater -import android.view.MenuItem -import androidx.core.view.forEach -import androidx.databinding.ViewDataBinding -import androidx.recyclerview.widget.RecyclerView -import com.gaurav.avnc.BR -import com.gaurav.avnc.R -import com.gaurav.avnc.model.ServerProfile -import com.gaurav.avnc.viewmodel.HomeViewModel -import com.google.android.material.snackbar.Snackbar - -/** - * ViewHolder for [ServerProfile]. - */ -open class ProfileViewHolder( - private val homeViewModel: HomeViewModel, - val binding: ViewDataBinding, - private val menuId: Int) - : RecyclerView.ViewHolder(binding.root) { - - /** - * Points to the profile being rendered by this view holder. - * See [bind]. - */ - var profile = ServerProfile() - - init { - val root = binding.root - - root.setOnClickListener { - homeViewModel.startConnection(profile) - } - - root.setOnCreateContextMenuListener { contextMenu, view, _ -> - MenuInflater(view.context).inflate(menuId, contextMenu) - contextMenu.forEach { item -> - item.setOnMenuItemClickListener { onContextOptionClick(it) } - } - } - } - - /** - * Handle context menu events - */ - private fun onContextOptionClick(item: MenuItem): Boolean { - - when (item.itemId) { - R.id.edit -> homeViewModel.onEditProfile(profile) - R.id.duplicate -> homeViewModel.onDuplicateProfile(profile) - R.id.delete -> homeViewModel.deleteProfile(profile) - - R.id.copy_host -> { - homeViewModel.setClipboardText(profile.host) - showCopiedMsg() - } - R.id.copy_name -> { - homeViewModel.setClipboardText(profile.name) - showCopiedMsg() - } - } - - return true - } - - private fun showCopiedMsg() { - Snackbar.make(binding.root, R.string.msg_copied_to_clipboard, Snackbar.LENGTH_SHORT).show() - } - - /** - * Binds given profile to this view holder. - */ - fun bind(profile: ServerProfile) { - this.profile = profile - binding.setVariable(BR.viewModel, profile) - binding.executePendingBindings() - } -} - diff --git a/app/src/main/java/com/gaurav/avnc/ui/home/adapter/ServersAdapter.kt b/app/src/main/java/com/gaurav/avnc/ui/home/adapter/ServersAdapter.kt deleted file mode 100644 index 54def84..0000000 --- a/app/src/main/java/com/gaurav/avnc/ui/home/adapter/ServersAdapter.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2020 Gaurav Ujjwal. - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - * See COPYING.txt for more details. - */ - -package com.gaurav.avnc.ui.home.adapter - -import android.view.LayoutInflater -import android.view.ViewGroup -import androidx.recyclerview.widget.DiffUtil -import androidx.recyclerview.widget.ListAdapter -import com.gaurav.avnc.R -import com.gaurav.avnc.databinding.ItemServerBinding -import com.gaurav.avnc.model.ServerProfile -import com.gaurav.avnc.viewmodel.HomeViewModel - -/** - * Adapter for known servers - */ -class ServersAdapter(val viewModel: HomeViewModel) - : ListAdapter(Differ) { - - //Experimental feature - var bindListener: ((ProfileViewHolder, ServerProfile) -> Unit)? = null - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ProfileViewHolder { - val inflater = LayoutInflater.from(parent.context) - val binding = ItemServerBinding.inflate(inflater, parent, false) - return ProfileViewHolder(viewModel, binding, R.menu.server_profile) - } - - override fun onBindViewHolder(holder: ProfileViewHolder, position: Int) { - val profile = getItem(position) - holder.bind(profile) - bindListener?.invoke(holder, profile) - } - - object Differ : DiffUtil.ItemCallback() { - override fun areItemsTheSame(old: ServerProfile, new: ServerProfile) = (old.ID == new.ID) - override fun areContentsTheSame(old: ServerProfile, new: ServerProfile) = (old == new) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/gaurav/avnc/util/Experimental.kt b/app/src/main/java/com/gaurav/avnc/util/Experimental.kt index f2cbfb4..8949748 100644 --- a/app/src/main/java/com/gaurav/avnc/util/Experimental.kt +++ b/app/src/main/java/com/gaurav/avnc/util/Experimental.kt @@ -21,10 +21,9 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleObserver import androidx.lifecycle.OnLifecycleEvent import androidx.recyclerview.widget.RecyclerView -import com.gaurav.avnc.databinding.FragmentServersBinding -import com.gaurav.avnc.databinding.ItemServerBinding +import com.gaurav.avnc.databinding.ServerSavedBinding import com.gaurav.avnc.model.ServerProfile -import com.gaurav.avnc.ui.home.adapter.ServersAdapter +import com.gaurav.avnc.ui.home.ServerTabs.SavedServerAdapter /** * All the experimental stuff is dumped here. @@ -83,7 +82,7 @@ object Experimental { * * Note: Viewmodel & lifecycle must have been assigned to [binding]. */ - fun setup(binding: FragmentServersBinding, adapter: ServersAdapter) { + fun setup(binding: ServerSavedBinding, adapter: SavedServerAdapter) { Log.i(javaClass.simpleName, "Setting up Experimental Indicator") // There are 4 event sources which we are interested in: @@ -100,11 +99,9 @@ object Experimental { // 2 - RV Binding: We need to know which RV Item View is rendering which profile. adapter.bindListener = { holder, profile -> - if (holder.binding is ItemServerBinding) { - val view = holder.binding.indicator - profileMap[view] = profile - animatorMap[view] = isServerDiscovered(profile) - } + val view = holder.binding.indicator + profileMap[view] = profile + animatorMap[view] = isServerDiscovered(profile) } // 3 - RV Views: We need to clear Views which are no longer used by RecyclerView. diff --git a/app/src/main/res/layout/fragment_discovery.xml b/app/src/main/res/layout/server_discovery.xml similarity index 97% rename from app/src/main/res/layout/fragment_discovery.xml rename to app/src/main/res/layout/server_discovery.xml index 5489d08..9ea3afb 100644 --- a/app/src/main/res/layout/fragment_discovery.xml +++ b/app/src/main/res/layout/server_discovery.xml @@ -28,7 +28,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:contentDescription="@string/desc_discovered_list" - tools:listitem="@layout/item_discovery" /> + tools:listitem="@layout/server_discovery_item" /> + diff --git a/app/src/main/res/layout/fragment_servers.xml b/app/src/main/res/layout/server_saved.xml similarity index 96% rename from app/src/main/res/layout/fragment_servers.xml rename to app/src/main/res/layout/server_saved.xml index c4a7339..422aa5e 100644 --- a/app/src/main/res/layout/fragment_servers.xml +++ b/app/src/main/res/layout/server_saved.xml @@ -28,7 +28,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:contentDescription="@string/desc_saved_servers_list" - tools:listitem="@layout/item_server" /> + tools:listitem="@layout/server_saved_item" /> diff --git a/app/src/main/res/menu/server_profile.xml b/app/src/main/res/menu/saved_server.xml similarity index 100% rename from app/src/main/res/menu/server_profile.xml rename to app/src/main/res/menu/saved_server.xml