diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/entriesScreen/EntriesAdapter.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/entriesScreen/EntriesAdapter.kt deleted file mode 100644 index 185a4c1d..00000000 --- a/app/src/main/java/com/rtbishop/look4sat/presentation/entriesScreen/EntriesAdapter.kt +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Look4Sat. Amateur radio satellite tracker and pass predictor. - * Copyright (C) 2019-2022 Arty Bishop (bishop.arty@gmail.com) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -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.ItemEntryBinding -import com.rtbishop.look4sat.domain.model.SatItem - -class EntriesAdapter(private val clickListener: EntriesClickListener) : - RecyclerView.Adapter() { - - private val diffCallback = object : DiffUtil.ItemCallback() { - override fun areItemsTheSame(oldItem: SatItem, newItem: SatItem): Boolean { - return oldItem.catnum == newItem.catnum - } - - override fun areContentsTheSame(oldItem: SatItem, newItem: SatItem): Boolean { - return oldItem.isSelected == newItem.isSelected - } - } - private val differ = AsyncListDiffer(this, diffCallback) - - fun submitList(items: List) { - differ.submitList(items) - } - - override fun getItemCount(): Int = differ.currentList.size - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SatItemHolder { - return SatItemHolder.from(parent) - } - - override fun onBindViewHolder(holder: SatItemHolder, position: Int) { - holder.bind(differ.currentList[position], clickListener) - } - - class SatItemHolder private constructor(private val binding: ItemEntryBinding) : - RecyclerView.ViewHolder(binding.root) { - - fun bind(item: SatItem, listener: EntriesClickListener) { - binding.entryCheckbox.text = item.name - binding.entryCheckbox.isChecked = item.isSelected - binding.entryCheckbox.setOnClickListener { - listener.updateSelection(listOf(item.catnum), item.isSelected.not()) - } - } - - companion object { - fun from(parent: ViewGroup): SatItemHolder { - val inflater = LayoutInflater.from(parent.context) - return SatItemHolder(ItemEntryBinding.inflate(inflater, parent, false)) - } - } - } - - interface EntriesClickListener { - fun updateSelection(catNums: List, isSelected: Boolean) - } -} 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 deleted file mode 100644 index 381b1740..00000000 --- a/app/src/main/java/com/rtbishop/look4sat/presentation/entriesScreen/EntriesFragment.kt +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Look4Sat. Amateur radio satellite tracker and pass predictor. - * Copyright (C) 2019-2022 Arty Bishop (bishop.arty@gmail.com) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -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.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.clickWithDebounce -import com.rtbishop.look4sat.presentation.getNavResult -import com.rtbishop.look4sat.presentation.setNavResult -import dagger.hilt.android.AndroidEntryPoint - -@AndroidEntryPoint -class EntriesFragment : Fragment(R.layout.fragment_entries) { - - private val viewModel: EntriesViewModel by viewModels() - private lateinit var binding: FragmentEntriesBinding - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - val entriesAdapter = EntriesAdapter(viewModel) - binding = FragmentEntriesBinding.bind(view).apply { - entriesRecycler.apply { - setHasFixedSize(true) - adapter = entriesAdapter - layoutManager = GridLayoutManager(requireContext(), 2) - (itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false - addItemDecoration(DividerItemDecoration(requireContext(), 1)) - 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() - } - }) - } - entriesBtnBack.clickWithDebounce { findNavController().navigateUp() } - entriesSearch.doOnTextChanged { text, _, _, _ -> viewModel.setQuery(text.toString()) } -// entriesBtnModes.clickWithDebounce { -// val direction = EntriesFragmentDirections.entriesToModes() -// findNavController().navigate(direction) -// } - entriesBtnSelect.clickWithDebounce { viewModel.selectCurrentItems(true) } - entriesBtnClear.clickWithDebounce { viewModel.selectCurrentItems(false) } - val typeMessageFormat = requireContext().getString(R.string.types_message) - val type = if (viewModel.getSatType().isNullOrBlank()) "All" else viewModel.getSatType() - entriesTypeMessage.text = String.format(typeMessageFormat, type) - entriesTypeCard.setOnClickListener { showSelectTypeDialog() } - } - viewModel.satData.observe(viewLifecycleOwner) { satData -> - handleSatData(satData, entriesAdapter) - binding.entriesFab.clickWithDebounce { - setNavResult("selection", viewModel.saveSelection()) - findNavController().popBackStack() - } - } -// getNavResult>(R.id.nav_entries, "modes") { modes -> -// viewModel.saveSelectedModes(modes) -// } - } - - private fun handleSatData(dataState: DataState>, entriesAdapter: EntriesAdapter) { - when (dataState) { - is DataState.Success -> { - entriesAdapter.submitList(dataState.data) - binding.entriesProgress.visibility = View.INVISIBLE - } - is DataState.Loading -> { - binding.entriesProgress.visibility = View.VISIBLE - } - else -> {} - } - } - - private fun showSelectTypeDialog() { - val satelliteTypes = viewModel.satTypes.toTypedArray() - val selectedValue = satelliteTypes.indexOf(viewModel.getSatType()) - val typeFormat = requireContext().getString(R.string.types_message) - AlertDialog.Builder(requireContext()).apply { - setTitle(R.string.types_title) - setSingleChoiceItems(satelliteTypes, selectedValue) { dialog, index -> - val selectedItem = satelliteTypes[index] - binding.entriesTypeMessage.text = String.format(typeFormat, selectedItem) - viewModel.setSatType(selectedItem) - dialog.dismiss() - } - create() - show() - } - } -} diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/entriesScreen/EntriesScreen.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/entriesScreen/EntriesScreen.kt index 56f59fe2..04803cff 100644 --- a/app/src/main/java/com/rtbishop/look4sat/presentation/entriesScreen/EntriesScreen.kt +++ b/app/src/main/java/com/rtbishop/look4sat/presentation/entriesScreen/EntriesScreen.kt @@ -2,6 +2,7 @@ package com.rtbishop.look4sat.presentation.entriesScreen import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items @@ -39,6 +40,15 @@ fun EntriesScreen( passesViewModel: PassesViewModel = hiltViewModel() ) { val state = viewModel.satData.observeAsState(DataState.Loading) + + val showDialog = rememberSaveable { mutableStateOf(false) } + val toggleDialog = { showDialog.value = showDialog.value.not() } + if (showDialog.value) { + TypesDialog(list = viewModel.satTypes, selected = viewModel.getSatType(), toggleDialog) { + viewModel.setSatType(it) + } + } + val unselectAll = { viewModel.selectCurrentItems(false) } val selectAll = { viewModel.selectCurrentItems(true) } Column(modifier = Modifier.padding(6.dp), verticalArrangement = Arrangement.spacedBy(6.dp)) { @@ -47,7 +57,12 @@ fun EntriesScreen( passesViewModel.calculatePasses(selection = entries) navToPasses() }) - MiddleBar(unselectAll = { unselectAll() }, selectAll = { selectAll() }) + Row(horizontalArrangement = Arrangement.spacedBy(6.dp), modifier = Modifier.height(48.dp)) { + EntryTypeCard( + type = viewModel.getSatType(), { toggleDialog() }, modifier = Modifier.weight(1f) + ) + SelectionCard(unselectAll = { unselectAll() }, selectAll = { selectAll() }) + } EntriesCard(state = state.value) { list, value -> viewModel.updateSelection(list, value) } } } @@ -125,19 +140,19 @@ private fun SaveButton(saveSelection: () -> Unit, modifier: Modifier = Modifier) @Composable private fun MiddleBar(unselectAll: () -> Unit, selectAll: () -> Unit) { Row(horizontalArrangement = Arrangement.spacedBy(6.dp), modifier = Modifier.height(48.dp)) { - EntryTypeCard(type = "Amateur", modifier = Modifier.weight(1f)) + EntryTypeCard(type = "Amateur", {}, modifier = Modifier.weight(1f)) SelectionCard(unselectAll = { unselectAll() }, selectAll = { selectAll() }) } } @Composable -private fun EntryTypeCard(type: String, modifier: Modifier = Modifier) { +private fun EntryTypeCard(type: String, onClick: () -> Unit, modifier: Modifier = Modifier) { ElevatedCard(modifier = modifier) { - Row( - horizontalArrangement = Arrangement.Start, + Row(horizontalArrangement = Arrangement.Start, verticalAlignment = Alignment.CenterVertically, - modifier = Modifier.height(48.dp) - ) { + modifier = Modifier + .height(48.dp) + .clickable { onClick() }) { Icon( imageVector = Icons.Outlined.PlayArrow, contentDescription = null, 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 52c27db8..ab2538ea 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 @@ -31,9 +31,9 @@ import javax.inject.Inject class EntriesViewModel @Inject constructor( private val repository: IDataRepository, private val settings: ISettingsManager -) : ViewModel(), EntriesAdapter.EntriesClickListener { +) : ViewModel() { - private val satType = MutableLiveData(String()) + private val satType = MutableLiveData("All") // private val transModes = MutableLiveData(settings.loadModesSelection()) private val currentQuery = MutableLiveData(String()) private val itemsFromRepo = liveData { @@ -52,7 +52,7 @@ class EntriesViewModel @Inject constructor( val satData = itemsWithQuery.map { items -> DataState.Success(items) } val satTypes: List = settings.sourcesMap.keys.sorted() - fun getSatType(): String? = satType.value + fun getSatType() = satType.value ?: "All" fun setSatType(type: String) { satType.value = type @@ -79,7 +79,7 @@ class EntriesViewModel @Inject constructor( } ?: emptyList() } - override fun updateSelection(catNums: List, isSelected: Boolean) { + fun updateSelection(catNums: List, isSelected: Boolean) { itemsFromRepo.value?.let { itemsAll -> val copiedList = itemsAll.map { item -> item.copy() } catNums.forEach { catnum -> diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/entriesScreen/TypesDialog.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/entriesScreen/TypesDialog.kt new file mode 100644 index 00000000..66d05400 --- /dev/null +++ b/app/src/main/java/com/rtbishop/look4sat/presentation/entriesScreen/TypesDialog.kt @@ -0,0 +1,59 @@ +package com.rtbishop.look4sat.presentation.entriesScreen + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material3.* +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.Dialog +import com.rtbishop.look4sat.presentation.MainTheme + +@Preview(showBackground = true) +@Composable +private fun TypeDialogPreview() { + val types = listOf("All", "Amateur", "Geostationary", "Military", "Weather") + MainTheme { TypesDialog(types, "All", {}) {} } +} + +@Composable +fun TypesDialog(list: List, selected: String, toggle: () -> Unit, click: (String) -> Unit) { + Dialog(onDismissRequest = { toggle() }) { + ElevatedCard(modifier = Modifier.fillMaxHeight(0.9f)) { + LazyColumn( + modifier = Modifier.background(MaterialTheme.colorScheme.background), + verticalArrangement = Arrangement.spacedBy(1.dp) + ) { + items(list) { type -> + Surface { + Row(verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .background(MaterialTheme.colorScheme.surface) + .clickable { + click(type) + toggle() + }) { + RadioButton(selected = type == selected, onClick = {}) + Text( + text = type, + modifier = Modifier + .padding(end = 6.dp) + .fillMaxWidth(), + fontWeight = FontWeight.Normal, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + } + } + } + } + } + } +} diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/passesScreen/PassesAdapter.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/passesScreen/PassesAdapter.kt index fd6ad9d5..67a4f4a1 100644 --- a/app/src/main/java/com/rtbishop/look4sat/presentation/passesScreen/PassesAdapter.kt +++ b/app/src/main/java/com/rtbishop/look4sat/presentation/passesScreen/PassesAdapter.kt @@ -71,7 +71,7 @@ class PassesAdapter(private val clickListener: PassesClickListener) : private val satIdFormat = itemView.context.getString(R.string.pass_satId) private val aosAzFormat = itemView.context.getString(R.string.pass_aosAz) private val altFormat = itemView.context.getString(R.string.pass_altitude) - private val losAzFormat = itemView.context.getString(R.string.pass_los) + private val losAzFormat = itemView.context.getString(R.string.pass_losAz) private val startTimeFormat = itemView.context.getString(R.string.pass_startTime) private val elevFormat = itemView.context.getString(R.string.pass_elevation) private val endTimeFormat = itemView.context.getString(R.string.pass_endTime) diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/passesScreen/PassesScreen.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/passesScreen/PassesScreen.kt index d2c89eb1..44a8e56f 100644 --- a/app/src/main/java/com/rtbishop/look4sat/presentation/passesScreen/PassesScreen.kt +++ b/app/src/main/java/com/rtbishop/look4sat/presentation/passesScreen/PassesScreen.kt @@ -11,6 +11,7 @@ import androidx.compose.runtime.livedata.observeAsState import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow @@ -23,6 +24,10 @@ import com.rtbishop.look4sat.domain.predict.NearEarthSat import com.rtbishop.look4sat.domain.predict.OrbitalData import com.rtbishop.look4sat.domain.predict.SatPass import com.rtbishop.look4sat.presentation.MainTheme +import java.text.SimpleDateFormat +import java.util.* + +private val sdf = SimpleDateFormat("HH:mm:ss", Locale.ENGLISH) @Composable fun PassesScreen(viewModel: PassesViewModel = hiltViewModel()) { @@ -86,24 +91,29 @@ private fun Pass(pass: SatPass, modifier: Modifier = Modifier) { horizontalArrangement = Arrangement.SpaceBetween, modifier = Modifier.fillMaxWidth() ) { - Text(text = "AOS - 90") - Text(text = "Altitude: 1800 km") - Text(text = "180 - LOS") + Text(text = stringResource(id = R.string.pass_aosAz, pass.aosAzimuth)) + Text( + text = stringResource(id = R.string.pass_altitude, pass.altitude), + textAlign = TextAlign.Center, + modifier = Modifier.weight(1f) + ) + Text(text = stringResource(id = R.string.pass_losAz, pass.losAzimuth)) } Row( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.SpaceBetween, modifier = Modifier.fillMaxWidth() ) { - Text(text = "16:02:28 - Sun") - Text(text = "Sun - 16:02:28") + val deepTime = stringResource(id = R.string.pass_placeholder) + Text(text = if (pass.isDeepSpace) deepTime else sdf.format(Date(pass.aosTime))) + LinearProgressIndicator( + progress = pass.progress, + modifier = modifier.weight(1f), + color = MaterialTheme.colorScheme.primary, + trackColor = MaterialTheme.colorScheme.inverseSurface + ) + Text(text = if (pass.isDeepSpace) deepTime else sdf.format(Date(pass.losTime))) } - LinearProgressIndicator( - progress = pass.progress, - modifier = modifier.fillMaxWidth(), - color = MaterialTheme.colorScheme.primary, - trackColor = MaterialTheme.colorScheme.inverseSurface - ) } } } diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/passesScreen/PassesViewModel.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/passesScreen/PassesViewModel.kt index ce70d51c..1eb0a77d 100644 --- a/app/src/main/java/com/rtbishop/look4sat/presentation/passesScreen/PassesViewModel.kt +++ b/app/src/main/java/com/rtbishop/look4sat/presentation/passesScreen/PassesViewModel.kt @@ -64,7 +64,7 @@ class PassesViewModel @Inject constructor( fun shouldUseUTC() = settings.getUseUTC() fun calculatePasses( - hoursAhead: Int = settings.getHoursAhead(), + hoursAhead: Int = 1, minElevation: Double = settings.getMinElevation(), timeRef: Long = System.currentTimeMillis(), selection: List? = null diff --git a/app/src/main/res/drawable/ic_delete.xml b/app/src/main/res/drawable/ic_delete.xml deleted file mode 100644 index 868b390b..00000000 --- a/app/src/main/res/drawable/ic_delete.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_support.xml b/app/src/main/res/drawable/ic_support.xml deleted file mode 100644 index 051f8ad9..00000000 --- a/app/src/main/res/drawable/ic_support.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml deleted file mode 100644 index e12c7ee3..00000000 --- a/app/src/main/res/layout/activity_main.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_entries.xml b/app/src/main/res/layout/fragment_entries.xml deleted file mode 100644 index c033bf66..00000000 --- a/app/src/main/res/layout/fragment_entries.xml +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -