diff --git a/app/build.gradle b/app/build.gradle index 308ba655..c1a44316 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -65,7 +65,6 @@ dependencies { implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version" implementation "androidx.navigation:navigation-fragment-ktx:$navigation_version" implementation "androidx.navigation:navigation-ui-ktx:$navigation_version" - implementation "androidx.preference:preference-ktx:$preference_version" implementation "androidx.room:room-runtime:$room_version" implementation "androidx.room:room-ktx:$room_version" kapt "androidx.room:room-compiler:$room_version" diff --git a/app/src/main/java/com/rtbishop/look4sat/injection/AppModule.kt b/app/src/main/java/com/rtbishop/look4sat/injection/AppModule.kt index 0c2b4f40..a506035f 100644 --- a/app/src/main/java/com/rtbishop/look4sat/injection/AppModule.kt +++ b/app/src/main/java/com/rtbishop/look4sat/injection/AppModule.kt @@ -22,7 +22,6 @@ import android.content.Context import android.content.SharedPreferences import android.hardware.SensorManager import android.location.LocationManager -import androidx.preference.PreferenceManager import dagger.Module import dagger.Provides import dagger.hilt.InstallIn @@ -55,6 +54,6 @@ object AppModule { @Provides @Singleton fun provideSharedPreferences(@ApplicationContext context: Context): SharedPreferences { - return PreferenceManager.getDefaultSharedPreferences(context) + return context.getSharedPreferences("default", Context.MODE_PRIVATE) } } diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/infoScreen/InfoFragment.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/infoScreen/InfoFragment.kt deleted file mode 100644 index a3cc3434..00000000 --- a/app/src/main/java/com/rtbishop/look4sat/presentation/infoScreen/InfoFragment.kt +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Look4Sat. Amateur radio satellite tracker and pass predictor. - * Copyright (C) 2019-2021 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.infoScreen - -import android.content.Intent -import android.net.Uri -import android.os.Bundle -import android.text.method.LinkMovementMethod -import android.view.View -import androidx.fragment.app.Fragment -import com.rtbishop.look4sat.BuildConfig -import com.rtbishop.look4sat.R -import com.rtbishop.look4sat.databinding.FragmentInfoBinding - -class InfoFragment : Fragment(R.layout.fragment_info) { - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - FragmentInfoBinding.bind(view).apply { - infoVersion.text = - String.format(getString(R.string.info_version), BuildConfig.VERSION_NAME) - infoBtnGithub.setOnClickListener { - gotoUrl("https://github.com/rt-bishop/Look4Sat/") - } - infoBtnFdroid.setOnClickListener { - gotoUrl("https://f-droid.org/en/packages/com.rtbishop.look4sat/") - } - infoBtnDonate.setOnClickListener { - gotoUrl("https://www.buymeacoffee.com/rtbishop") - } - val moveMethod = LinkMovementMethod.getInstance() - infoThanks.movementMethod = moveMethod - infoWarranty.movementMethod = moveMethod - } - } - - private fun gotoUrl(url: String) { - startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(url))) - } -} diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/prefsScreen/PrefsFragment.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/prefsScreen/PrefsFragment.kt new file mode 100644 index 00000000..6e568d64 --- /dev/null +++ b/app/src/main/java/com/rtbishop/look4sat/presentation/prefsScreen/PrefsFragment.kt @@ -0,0 +1,187 @@ +/* + * Look4Sat. Amateur radio satellite tracker and pass predictor. + * Copyright (C) 2019-2021 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.prefsScreen + +import android.Manifest +import android.content.Intent +import android.content.pm.PackageManager +import android.net.Uri +import android.os.Bundle +import android.text.method.LinkMovementMethod +import android.view.View +import androidx.activity.result.contract.ActivityResultContracts +import androidx.core.content.ContextCompat +import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels +import androidx.navigation.fragment.findNavController +import com.google.android.material.snackbar.Snackbar +import com.rtbishop.look4sat.BuildConfig +import com.rtbishop.look4sat.R +import com.rtbishop.look4sat.databinding.FragmentPrefsBinding +import com.rtbishop.look4sat.framework.PreferencesSource +import com.rtbishop.look4sat.presentation.getNavResult +import com.rtbishop.look4sat.presentation.navigateSafe +import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject + +@AndroidEntryPoint +class PrefsFragment : Fragment(R.layout.fragment_prefs) { + + @Inject + lateinit var preferences: PreferencesSource + private val viewModel: PrefsViewModel by viewModels() + private val locPermFine = Manifest.permission.ACCESS_FINE_LOCATION + private val locPermCoarse = Manifest.permission.ACCESS_COARSE_LOCATION + private val contentContract = ActivityResultContracts.GetContent() + private val filePicker = registerForActivityResult(contentContract) { uri -> + uri?.let { viewModel.updateDataFromFile(uri) } + } + private val permReqContract = ActivityResultContracts.RequestMultiplePermissions() + private val locPermReq = registerForActivityResult(permReqContract) { permissions -> + when { + permissions[locPermFine] == true -> updatePositionFromGPS() + permissions[locPermCoarse] == true -> updatePositionFromGPS() + else -> showSnack(getString(R.string.pref_pos_gps_error)) + } + } + private var _binding: FragmentPrefsBinding? = null + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + _binding = FragmentPrefsBinding.bind(view) + setupInfoCard() + setupDataCard() + setupLocationCard() + setupWarrantyCard() + } + + private fun setupInfoCard() { + _binding?.prefsInfo?.let { binding -> + binding.aboutVersion.text = + String.format(getString(R.string.about_version), BuildConfig.VERSION_NAME) + binding.aboutBtnGithub.setOnClickListener { + gotoUrl("https://github.com/rt-bishop/Look4Sat/") + } + binding.aboutBtnDonate.setOnClickListener { + gotoUrl("https://www.buymeacoffee.com/rtbishop") + } + binding.aboutBtnFdroid.setOnClickListener { + gotoUrl("https://f-droid.org/en/packages/com.rtbishop.look4sat/") + } + } + } + + private fun setupDataCard() { + _binding?.prefsData?.let { binding -> + binding.updateBtnWeb.setOnClickListener { + findNavController().navigateSafe(R.id.action_prefs_to_sources) + } + binding.updateBtnFile.setOnClickListener { filePicker.launch("*/*") } + } + getNavResult>(R.id.nav_passes, "sources") { sources -> + viewModel.updateDataFromWeb(sources) + } + } + + private fun setupLocationCard() { + + } + + private fun setupWarrantyCard() { + _binding?.prefsWarranty?.let { binding -> + val moveMethod = LinkMovementMethod.getInstance() + binding.warrantyThanks.movementMethod = moveMethod + binding.warrantyLicense.movementMethod = moveMethod + } + } + + private fun updatePositionFromGPS() { + val locPermString = Manifest.permission.ACCESS_FINE_LOCATION + val locPermResult = ContextCompat.checkSelfPermission(requireContext(), locPermString) + if (locPermResult == PackageManager.PERMISSION_GRANTED) { + if (preferences.updatePositionFromGPS()) { + showSnack(getString(R.string.pref_pos_success)) + } else { + showSnack(getString(R.string.pref_pos_gps_null)) + } + } else locPermReq.launch(arrayOf(locPermFine, locPermCoarse)) + } + + private fun updatePositionFromQth(qthString: String): Boolean { + return if (preferences.updatePositionFromQTH(qthString)) { + showSnack(getString(R.string.pref_pos_success)) + true + } else { + showSnack(getString(R.string.pref_pos_qth_error)) + false + } + } + + private fun setupLater() { +// findPreference(PreferencesSource.keyPositionGPS)?.apply { +// setOnPreferenceClickListener { +// updatePositionFromGPS() +// return@setOnPreferenceClickListener true +// } +// } +// +// findPreference(PreferencesSource.keyPositionQTH)?.apply { +// setOnPreferenceChangeListener { _, newValue -> +// updatePositionFromQth(newValue.toString()) +// } +// } +// +// findPreference(PreferencesSource.keyRotatorAddress)?.apply { +// setOnPreferenceChangeListener { _, newValue -> +// val ip4 = "^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(\\.(?!\$)|\$)){4}\$" +// if (newValue.toString().matches(ip4.toRegex())) { +// return@setOnPreferenceChangeListener true +// } else { +// showSnack(getString(R.string.tracking_ip_invalid)) +// return@setOnPreferenceChangeListener false +// } +// } +// } +// +// findPreference(PreferencesSource.keyRotatorPort)?.apply { +// setOnBindEditTextListener { it.inputType = InputType.TYPE_CLASS_NUMBER } +// setOnPreferenceChangeListener { _, newValue -> +// val portValue = newValue.toString() +// if (portValue.isNotEmpty() && portValue.toInt() in 1024..65535) { +// return@setOnPreferenceChangeListener true +// } else { +// showSnack(getString(R.string.tracking_port_invalid)) +// return@setOnPreferenceChangeListener false +// } +// } +// } + } + + private fun showSnack(message: String) { + Snackbar.make(requireView(), message, Snackbar.LENGTH_SHORT).show() + } + + private fun gotoUrl(url: String) { + startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(url))) + } + + override fun onDestroyView() { + _binding = null + super.onDestroyView() + } +} diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/prefsScreen/PrefsViewModel.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/prefsScreen/PrefsViewModel.kt new file mode 100644 index 00000000..ec7f088f --- /dev/null +++ b/app/src/main/java/com/rtbishop/look4sat/presentation/prefsScreen/PrefsViewModel.kt @@ -0,0 +1,62 @@ +/* + * Look4Sat. Amateur radio satellite tracker and pass predictor. + * Copyright (C) 2019-2021 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.prefsScreen + +import android.content.ContentResolver +import android.net.Uri +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.rtbishop.look4sat.domain.DataRepository +import com.rtbishop.look4sat.framework.PreferencesSource +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.CoroutineExceptionHandler +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class PrefsViewModel @Inject constructor( + private val preferences: PreferencesSource, + private val resolver: ContentResolver, + private val dataRepository: DataRepository +) : ViewModel() { + + private val coroutineHandler = CoroutineExceptionHandler { _, throwable -> +// Timber.d(throwable) +// _satData.value = DataState.Error(throwable) + } + + fun updateDataFromFile(uri: Uri) { + viewModelScope.launch(coroutineHandler) { +// _satData.value = DataState.Loading + runCatching { + resolver.openInputStream(uri)?.use { stream -> + dataRepository.updateDataFromFile(stream) + } + }.onFailure { +// _satData.value = DataState.Error(it) + } + } + } + + fun updateDataFromWeb(sources: List) { + viewModelScope.launch(coroutineHandler) { +// _satData.value = DataState.Loading + dataRepository.updateDataFromWeb(sources) + } + } +} diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/settingsScreen/SettingsFragment.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/settingsScreen/SettingsFragment.kt deleted file mode 100644 index 5bb926ae..00000000 --- a/app/src/main/java/com/rtbishop/look4sat/presentation/settingsScreen/SettingsFragment.kt +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Look4Sat. Amateur radio satellite tracker and pass predictor. - * Copyright (C) 2019-2021 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.settingsScreen - -import android.Manifest -import android.content.pm.PackageManager -import android.os.Bundle -import android.text.InputType -import android.view.View -import androidx.activity.result.contract.ActivityResultContracts -import androidx.core.content.ContextCompat -import androidx.preference.EditTextPreference -import androidx.preference.Preference -import androidx.preference.PreferenceFragmentCompat -import com.google.android.material.snackbar.Snackbar -import com.rtbishop.look4sat.R -import com.rtbishop.look4sat.framework.PreferencesSource -import dagger.hilt.android.AndroidEntryPoint -import javax.inject.Inject - -@AndroidEntryPoint -class SettingsFragment : PreferenceFragmentCompat() { - - @Inject - lateinit var preferences: PreferencesSource - - private val permReqContract = ActivityResultContracts.RequestMultiplePermissions() - private val locPermFine = Manifest.permission.ACCESS_FINE_LOCATION - private val locPermCoarse = Manifest.permission.ACCESS_COARSE_LOCATION - private val locPermReq = registerForActivityResult(permReqContract) { permissions -> - when { - permissions[locPermFine] == true -> updatePositionFromGPS() - permissions[locPermCoarse] == true -> updatePositionFromGPS() - else -> showSnack(getString(R.string.pref_pos_gps_error)) - } - } - - override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { - setPreferencesFromResource(R.xml.preference, rootKey) - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - findPreference(PreferencesSource.keyPositionGPS)?.apply { - setOnPreferenceClickListener { - updatePositionFromGPS() - return@setOnPreferenceClickListener true - } - } - - findPreference(PreferencesSource.keyPositionQTH)?.apply { - setOnPreferenceChangeListener { _, newValue -> - updatePositionFromQth(newValue.toString()) - } - } - - findPreference(PreferencesSource.keyRotatorAddress)?.apply { - setOnPreferenceChangeListener { _, newValue -> - val ip4 = "^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(\\.(?!\$)|\$)){4}\$" - if (newValue.toString().matches(ip4.toRegex())) { - return@setOnPreferenceChangeListener true - } else { - showSnack(getString(R.string.tracking_rotator_address_invalid)) - return@setOnPreferenceChangeListener false - } - } - } - - findPreference(PreferencesSource.keyRotatorPort)?.apply { - setOnBindEditTextListener { it.inputType = InputType.TYPE_CLASS_NUMBER } - setOnPreferenceChangeListener { _, newValue -> - val portValue = newValue.toString() - if (portValue.isNotEmpty() && portValue.toInt() in 1024..65535) { - return@setOnPreferenceChangeListener true - } else { - showSnack(getString(R.string.tracking_rotator_port_invalid)) - return@setOnPreferenceChangeListener false - } - } - } - } - - private fun updatePositionFromQth(qthString: String): Boolean { - return if (preferences.updatePositionFromQTH(qthString)) { - showSnack(getString(R.string.pref_pos_success)) - true - } else { - showSnack(getString(R.string.pref_pos_qth_error)) - false - } - } - - private fun updatePositionFromGPS() { - val locPermString = Manifest.permission.ACCESS_FINE_LOCATION - val locPermResult = ContextCompat.checkSelfPermission(requireContext(), locPermString) - if (locPermResult == PackageManager.PERMISSION_GRANTED) { - if (preferences.updatePositionFromGPS()) { - showSnack(getString(R.string.pref_pos_success)) - } else { - showSnack(getString(R.string.pref_pos_gps_null)) - } - } else locPermReq.launch(arrayOf(locPermFine, locPermCoarse)) - } - - private fun showSnack(message: String) { - Snackbar.make(requireView(), message, Snackbar.LENGTH_SHORT).show() - } -} diff --git a/app/src/main/res/drawable/ic_gps.xml b/app/src/main/res/drawable/ic_gps.xml new file mode 100644 index 00000000..83dde279 --- /dev/null +++ b/app/src/main/res/drawable/ic_gps.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_nav_settings.xml b/app/src/main/res/drawable/ic_nav_prefs.xml similarity index 100% rename from app/src/main/res/drawable/ic_nav_settings.xml rename to app/src/main/res/drawable/ic_nav_prefs.xml diff --git a/app/src/main/res/drawable/ic_qth.xml b/app/src/main/res/drawable/ic_qth.xml new file mode 100644 index 00000000..27a095ca --- /dev/null +++ b/app/src/main/res/drawable/ic_qth.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/card_prefs_about.xml b/app/src/main/res/layout/card_prefs_about.xml new file mode 100644 index 00000000..407795b5 --- /dev/null +++ b/app/src/main/res/layout/card_prefs_about.xml @@ -0,0 +1,98 @@ + + + + + + + + + + + +