diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/entriesScreen/EntriesFragment.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/entriesScreen/EntriesFragment.kt index f70124e5..fc543e83 100644 --- a/app/src/main/java/com/rtbishop/look4sat/presentation/entriesScreen/EntriesFragment.kt +++ b/app/src/main/java/com/rtbishop/look4sat/presentation/entriesScreen/EntriesFragment.kt @@ -19,19 +19,20 @@ package com.rtbishop.look4sat.presentation.entriesScreen import android.os.Bundle import android.view.View -import androidx.appcompat.app.AlertDialog import androidx.core.widget.doOnTextChanged import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.SimpleItemAnimator import com.google.android.material.snackbar.Snackbar import com.rtbishop.look4sat.R import com.rtbishop.look4sat.databinding.FragmentEntriesBinding import com.rtbishop.look4sat.domain.model.DataState import com.rtbishop.look4sat.domain.model.SatItem +import com.rtbishop.look4sat.presentation.getNavResult import com.rtbishop.look4sat.presentation.setNavResult import dagger.hilt.android.AndroidEntryPoint @@ -59,13 +60,19 @@ class EntriesFragment : Fragment(R.layout.fragment_entries) { this.layoutManager = layoutManager addItemDecoration(itemDecoration) (itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false + addOnScrollListener(object : RecyclerView.OnScrollListener() { + override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { + if (dy > 0 && entriesFab.visibility == View.VISIBLE) entriesFab.hide() + else if (dy < 0 && entriesFab.visibility != View.VISIBLE) entriesFab.show() + } + }) } entriesBackBtn.setOnClickListener { findNavController().navigateUp() } entriesSearch.doOnTextChanged { text, _, _, _ -> viewModel.setQuery(text.toString()) } - entriesModesBtn.setOnClickListener { showModesDialog() } + entriesModesBtn.setOnClickListener { navigateToModesDialog() } entriesSelectBtn.setOnClickListener { viewModel.selectCurrentItems(true) } entriesClearBtn.setOnClickListener { viewModel.selectCurrentItems(false) } - entriesAcceptBtn.setOnClickListener { + entriesFab.setOnClickListener { setNavResult("selection", viewModel.saveSelection()) findNavController().popBackStack() } @@ -73,6 +80,9 @@ class EntriesFragment : Fragment(R.layout.fragment_entries) { viewModel.satData.observe(viewLifecycleOwner) { satData -> handleSatData(satData, binding, adapter) } + getNavResult>(R.id.nav_entries, "modes") { modes -> + viewModel.saveSelectedModes(modes) + } } private fun handleSatData( @@ -100,32 +110,8 @@ class EntriesFragment : Fragment(R.layout.fragment_entries) { } } - private fun showModesDialog() { - val modes = arrayOf( - "AFSK", "AFSK S-Net", "AFSK SALSAT", "AHRPT", "AM", "APT", "BPSK", "BPSK PMT-A3", - "CERTO", "CW", "DQPSK", "DSTAR", "DUV", "FFSK", "FM", "FMN", "FSK", "FSK AX.100 Mode 5", - "FSK AX.100 Mode 6", "FSK AX.25 G3RUH", "GFSK", "GFSK Rktr", "GMSK", "HRPT", "LoRa", - "LRPT", "LSB", "MFSK", "MSK", "MSK AX.100 Mode 5", "MSK AX.100 Mode 6", "OFDM", "OQPSK", - "PSK", "PSK31", "PSK63", "QPSK", "QPSK31", "QPSK63", "SSTV", "USB", "WSJT" - ) - val savedModes = BooleanArray(modes.size) - val selectedModes = viewModel.loadSelectedModes().toMutableList() - selectedModes.forEach { savedModes[modes.indexOf(it)] = true } - AlertDialog.Builder(requireContext()).apply { - setTitle(context.getString(R.string.modes_title)) - setMultiChoiceItems(modes, savedModes) { _, which, isChecked -> - when { - isChecked -> selectedModes.add(modes[which]) - selectedModes.contains(modes[which]) -> selectedModes.remove(modes[which]) - } - } - setPositiveButton(context.getString(android.R.string.ok)) { _, _ -> - viewModel.saveSelectedModes(selectedModes) - } - setNeutralButton(context.getString(android.R.string.cancel)) { dialog, _ -> - dialog.dismiss() - } - create().show() - } + private fun navigateToModesDialog() { + val direction = EntriesFragmentDirections.actionEntriesToModes() + findNavController().navigate(direction) } } diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/entriesScreen/EntriesViewModel.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/entriesScreen/EntriesViewModel.kt index 8e127f86..7285b5f8 100644 --- a/app/src/main/java/com/rtbishop/look4sat/presentation/entriesScreen/EntriesViewModel.kt +++ b/app/src/main/java/com/rtbishop/look4sat/presentation/entriesScreen/EntriesViewModel.kt @@ -41,35 +41,26 @@ class EntriesViewModel @Inject constructor( private val itemsWithQuery = currentQuery.switchMap { query -> itemsWithModes.map { items -> filterByQuery(items, query) } } -// private var shouldSelectAll = true val satData = itemsWithQuery.map { items -> DataState.Success(items) } fun selectCurrentItems(selectAll: Boolean) { itemsWithQuery.value?.let { itemsWithQuery -> updateSelection(itemsWithQuery.map { item -> item.catnum }, selectAll) -// shouldSelectAll = shouldSelectAll.not() } } - fun loadSelectedModes(): List { - return preferences.loadModesSelection() - } - fun saveSelectedModes(modes: List) { transModes.value = modes preferences.saveModesSelection(modes) } fun setQuery(query: String) { -// shouldSelectAll = true currentQuery.value = query } fun saveSelection(): List { return itemsFromRepo.value?.let { itemsAll -> - val filteredItems = itemsAll.filter { item -> item.isSelected } -// repository.setEntriesSelection(filteredItems.map { item -> item.catnum }) - filteredItems.map { item -> item.catnum } + itemsAll.filter { item -> item.isSelected }.map { item -> item.catnum } } ?: emptyList() } diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/entriesScreen/ModesAdapter.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/entriesScreen/ModesAdapter.kt new file mode 100644 index 00000000..b4c72dc4 --- /dev/null +++ b/app/src/main/java/com/rtbishop/look4sat/presentation/entriesScreen/ModesAdapter.kt @@ -0,0 +1,62 @@ +package com.rtbishop.look4sat.presentation.entriesScreen + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.AsyncListDiffer +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.RecyclerView +import com.rtbishop.look4sat.databinding.ItemModeBinding + +class ModesAdapter(private val clickListener: ModesClickListener) : + RecyclerView.Adapter() { + + private val diffCallback = object : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: String, newItem: String): Boolean { + return oldItem == newItem + } + + override fun areContentsTheSame(oldItem: String, newItem: String): Boolean { + return oldItem == newItem + } + } + private val differ = AsyncListDiffer(this, diffCallback) + private var selectedModes = listOf() + + fun submitModes(items: List, selected: List) { + differ.submitList(items) + selectedModes = selected + } + + override fun getItemCount(): Int = differ.currentList.size + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ModeHolder { + return ModeHolder.from(parent) + } + + override fun onBindViewHolder(holder: ModeHolder, position: Int) { + val currentItem = differ.currentList[position] + holder.bind(currentItem, selectedModes.contains(currentItem), clickListener) + } + + class ModeHolder(private val binding: ItemModeBinding) : RecyclerView.ViewHolder(binding.root) { + + fun bind(mode: String, isSelected: Boolean, listener: ModesClickListener) { + binding.modeCheckbox.text = mode + binding.modeCheckbox.isChecked = isSelected + binding.modeCheckbox.setOnClickListener { + listener.onModeClicked(mode, isSelected.not()) + } + } + + companion object { + fun from(parent: ViewGroup): ModeHolder { + val inflater = LayoutInflater.from(parent.context) + return ModeHolder(ItemModeBinding.inflate(inflater, parent, false)) + } + } + } + + interface ModesClickListener { + fun onModeClicked(mode: String, isSelected: Boolean) + } +} diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/entriesScreen/ModesDialog.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/entriesScreen/ModesDialog.kt new file mode 100644 index 00000000..436b3440 --- /dev/null +++ b/app/src/main/java/com/rtbishop/look4sat/presentation/entriesScreen/ModesDialog.kt @@ -0,0 +1,72 @@ +package com.rtbishop.look4sat.presentation.entriesScreen + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.appcompat.app.AppCompatDialogFragment +import androidx.recyclerview.widget.DividerItemDecoration +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.SimpleItemAnimator +import com.rtbishop.look4sat.R +import com.rtbishop.look4sat.data.ISettingsHandler +import com.rtbishop.look4sat.databinding.DialogModesBinding +import com.rtbishop.look4sat.presentation.setNavResult +import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject + +@AndroidEntryPoint +class ModesDialog : AppCompatDialogFragment(), ModesAdapter.ModesClickListener { + + @Inject + lateinit var preferences: ISettingsHandler + private lateinit var binding: DialogModesBinding + private val allModes = listOf( + "AFSK", "AFSK S-Net", "AFSK SALSAT", "AHRPT", "AM", "APT", "BPSK", "BPSK PMT-A3", + "CERTO", "CW", "DQPSK", "DSTAR", "DUV", "FFSK", "FM", "FMN", "FSK", "FSK AX.100 Mode 5", + "FSK AX.100 Mode 6", "FSK AX.25 G3RUH", "GFSK", "GFSK Rktr", "GMSK", "HRPT", "LoRa", + "LRPT", "LSB", "MFSK", "MSK", "MSK AX.100 Mode 5", "MSK AX.100 Mode 6", "OFDM", "OQPSK", + "PSK", "PSK31", "PSK63", "QPSK", "QPSK31", "QPSK63", "SSTV", "USB", "WSJT" + ) + private val selectedModes = mutableListOf() + + override fun onCreateView(inflater: LayoutInflater, group: ViewGroup?, state: Bundle?): View { + binding = DialogModesBinding.inflate(inflater, group, false) + return binding.root + } + + override fun onViewCreated(view: View, state: Bundle?) { + super.onViewCreated(view, state) + dialog?.window?.setBackgroundDrawableResource(R.color.transparent) + dialog?.window?.setLayout( + (resources.displayMetrics.widthPixels * 0.94).toInt(), + (resources.displayMetrics.heightPixels * 0.76).toInt() + ) + val modesAdapter = ModesAdapter(this@ModesDialog) + val layoutManager = GridLayoutManager(context, 2) + val itemDecoration = DividerItemDecoration(context, layoutManager.orientation) + selectedModes.addAll(preferences.loadModesSelection()) + modesAdapter.submitModes(allModes, selectedModes) + binding.run { + modesRecycler.apply { + setHasFixedSize(true) + this.adapter = modesAdapter + this.layoutManager = layoutManager + addItemDecoration(itemDecoration) + (itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false + } + modesBtnNeg.setOnClickListener { dismiss() } + modesBtnPos.setOnClickListener { + setNavResult("modes", selectedModes.toList()) + dismiss() + } + } + } + + override fun onModeClicked(mode: String, isSelected: Boolean) { + when { + isSelected -> selectedModes.add(mode) + selectedModes.contains(mode) -> selectedModes.remove(mode) + } + } +} diff --git a/app/src/main/res/layout/dialog_modes.xml b/app/src/main/res/layout/dialog_modes.xml new file mode 100644 index 00000000..7428fe2a --- /dev/null +++ b/app/src/main/res/layout/dialog_modes.xml @@ -0,0 +1,68 @@ + + + + + + + + + +