kopia lustrzana https://github.com/rt-bishop/Look4Sat
rodzic
fb2008b07a
commit
a0a95ce372
|
@ -13,8 +13,8 @@ android {
|
|||
applicationId "com.rtbishop.look4sat"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 30
|
||||
versionCode 250
|
||||
versionName "2.5.0"
|
||||
versionCode 251
|
||||
versionName "2.5.1"
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
|
|
|
@ -25,15 +25,49 @@ import com.rtbishop.look4sat.data.PreferencesSource
|
|||
import com.rtbishop.look4sat.domain.predict4kotlin.QthConverter
|
||||
import com.rtbishop.look4sat.domain.predict4kotlin.StationPosition
|
||||
import com.rtbishop.look4sat.utility.round
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.squareup.moshi.Types
|
||||
import javax.inject.Inject
|
||||
|
||||
class PreferencesProvider @Inject constructor(
|
||||
moshi: Moshi,
|
||||
private val qthConverter: QthConverter,
|
||||
private val locationManager: LocationManager,
|
||||
private val preferences: SharedPreferences
|
||||
) : PreferencesSource {
|
||||
|
||||
private val sourcesType = Types.newParameterizedType(List::class.java, String::class.java)
|
||||
private val sourcesAdapter = moshi.adapter<List<String>>(sourcesType)
|
||||
|
||||
override fun loadTleSources(): List<String> {
|
||||
return try {
|
||||
val sourcesString = preferences.getString(keySources, String())
|
||||
if (sourcesString.isNullOrEmpty()) {
|
||||
loadDefaultSources()
|
||||
} else {
|
||||
sourcesAdapter.fromJson(sourcesString) ?: loadDefaultSources()
|
||||
}
|
||||
} catch (exception: ClassCastException) {
|
||||
loadDefaultSources()
|
||||
}
|
||||
}
|
||||
|
||||
override fun saveTleSources(sources: List<String>) {
|
||||
val sourcesJson = sourcesAdapter.toJson(sources)
|
||||
preferences.edit { putString(keySources, sourcesJson) }
|
||||
}
|
||||
|
||||
override fun loadDefaultSources(): List<String> {
|
||||
return listOf(
|
||||
"https://celestrak.com/NORAD/elements/active.txt",
|
||||
"https://amsat.org/tle/current/nasabare.txt",
|
||||
"https://www.prismnet.com/~mmccants/tles/classfd.zip",
|
||||
"https://www.prismnet.com/~mmccants/tles/inttles.zip"
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val keySources = "sourcesListJson"
|
||||
const val keyModes = "satModes"
|
||||
const val keyCompass = "compass"
|
||||
const val keyTextLabels = "shouldUseTextLabels"
|
||||
|
|
|
@ -27,9 +27,9 @@ import com.rtbishop.look4sat.framework.PreferencesProvider
|
|||
import com.rtbishop.look4sat.framework.api.SatDataRemote
|
||||
import com.rtbishop.look4sat.framework.api.SatDataService
|
||||
import com.rtbishop.look4sat.framework.db.RoomConverters
|
||||
import com.rtbishop.look4sat.framework.db.SatDataLocal
|
||||
import com.rtbishop.look4sat.framework.db.SatDataDao
|
||||
import com.rtbishop.look4sat.framework.db.SatDataDb
|
||||
import com.rtbishop.look4sat.framework.db.SatDataLocal
|
||||
import com.squareup.moshi.Moshi
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
|
@ -58,11 +58,12 @@ object SatDataModule {
|
|||
@Provides
|
||||
@Singleton
|
||||
fun providePreferenceSource(
|
||||
moshi: Moshi,
|
||||
qthConverter: QthConverter,
|
||||
locationManager: LocationManager,
|
||||
preferences: SharedPreferences
|
||||
): PreferencesSource {
|
||||
return PreferencesProvider(qthConverter, locationManager, preferences)
|
||||
return PreferencesProvider(moshi, qthConverter, locationManager, preferences)
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
|
|
@ -28,10 +28,10 @@ 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.data.PreferencesSource
|
||||
import com.rtbishop.look4sat.framework.PreferencesProvider
|
||||
import com.rtbishop.look4sat.utility.showSnack
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -46,7 +46,7 @@ class AppSettingsFragment : PreferenceFragmentCompat() {
|
|||
if (isGranted) {
|
||||
updatePositionFromGPS()
|
||||
} else {
|
||||
requireView().showSnack(getString(R.string.pref_pos_gps_error))
|
||||
showSnack(getString(R.string.pref_pos_gps_error))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,7 +75,7 @@ class AppSettingsFragment : PreferenceFragmentCompat() {
|
|||
if (Patterns.IP_ADDRESS.matcher(newValue.toString()).matches()) {
|
||||
return@setOnPreferenceChangeListener true
|
||||
} else {
|
||||
requireView().showSnack(getString(R.string.tracking_rotator_address_invalid))
|
||||
showSnack(getString(R.string.tracking_rotator_address_invalid))
|
||||
return@setOnPreferenceChangeListener false
|
||||
}
|
||||
}
|
||||
|
@ -88,7 +88,7 @@ class AppSettingsFragment : PreferenceFragmentCompat() {
|
|||
if (portValue.isNotEmpty() && portValue.toInt() in 1024..65535) {
|
||||
return@setOnPreferenceChangeListener true
|
||||
} else {
|
||||
requireView().showSnack(getString(R.string.tracking_rotator_port_invalid))
|
||||
showSnack(getString(R.string.tracking_rotator_port_invalid))
|
||||
return@setOnPreferenceChangeListener false
|
||||
}
|
||||
}
|
||||
|
@ -97,10 +97,10 @@ class AppSettingsFragment : PreferenceFragmentCompat() {
|
|||
|
||||
private fun updatePositionFromQth(qthString: String): Boolean {
|
||||
return if (preferencesSource.updatePositionFromQTH(qthString)) {
|
||||
requireView().showSnack(getString(R.string.pref_pos_success))
|
||||
showSnack(getString(R.string.pref_pos_success))
|
||||
true
|
||||
} else {
|
||||
requireView().showSnack(getString(R.string.pref_pos_qth_error))
|
||||
showSnack(getString(R.string.pref_pos_qth_error))
|
||||
false
|
||||
}
|
||||
}
|
||||
|
@ -110,10 +110,16 @@ class AppSettingsFragment : PreferenceFragmentCompat() {
|
|||
val locPermResult = ContextCompat.checkSelfPermission(requireContext(), locPermString)
|
||||
if (locPermResult == PackageManager.PERMISSION_GRANTED) {
|
||||
if (preferencesSource.updatePositionFromGPS()) {
|
||||
requireView().showSnack(getString(R.string.pref_pos_success))
|
||||
showSnack(getString(R.string.pref_pos_success))
|
||||
} else {
|
||||
requireView().showSnack(getString(R.string.pref_pos_gps_null))
|
||||
showSnack(getString(R.string.pref_pos_gps_null))
|
||||
}
|
||||
} else requestPermissionLauncher.launch(locPermString)
|
||||
}
|
||||
|
||||
private fun showSnack(message: String) {
|
||||
Snackbar.make(requireView(), message, Snackbar.LENGTH_SHORT).apply {
|
||||
setAnchorView(R.id.nav_bottom)
|
||||
}.show()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import androidx.activity.result.contract.ActivityResultContracts
|
|||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.SimpleItemAnimator
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
|
@ -33,6 +34,8 @@ import com.rtbishop.look4sat.databinding.FragmentEntriesBinding
|
|||
import com.rtbishop.look4sat.domain.model.SatItem
|
||||
import com.rtbishop.look4sat.framework.model.Result
|
||||
import com.rtbishop.look4sat.utility.RecyclerDivider
|
||||
import com.rtbishop.look4sat.utility.getNavResult
|
||||
import com.rtbishop.look4sat.utility.navigateSafe
|
||||
import com.rtbishop.look4sat.utility.showSnack
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
||||
|
@ -62,8 +65,11 @@ class SatItemFragment : Fragment(R.layout.fragment_entries) {
|
|||
(itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false
|
||||
addItemDecoration(RecyclerDivider(R.drawable.rec_divider_light))
|
||||
}
|
||||
importWeb.setOnClickListener { viewModel.updateEntriesFromWeb(null) }
|
||||
importSource.setOnClickListener { showSourceDialog() }
|
||||
importWeb.setOnClickListener {
|
||||
// viewModel.updateEntriesFromWeb(null)
|
||||
findNavController().navigateSafe(R.id.action_entries_to_sources)
|
||||
}
|
||||
// importSource.setOnClickListener { showSourceDialog() }
|
||||
importFile.setOnClickListener { filePicker.launch("*/*") }
|
||||
selectMode.setOnClickListener { showModesDialog() }
|
||||
selectAll.setOnClickListener { viewModel.selectCurrentItems() }
|
||||
|
@ -72,6 +78,9 @@ class SatItemFragment : Fragment(R.layout.fragment_entries) {
|
|||
viewModel.satData.observe(viewLifecycleOwner, { satData ->
|
||||
handleSatData(satData, binding, entriesAdapter)
|
||||
})
|
||||
getNavResult<List<String>>(R.id.nav_entries, "sources") { sources ->
|
||||
viewModel.updateEntriesFromWeb(sources)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleSatData(
|
||||
|
|
|
@ -21,6 +21,7 @@ import android.content.ContentResolver
|
|||
import android.net.Uri
|
||||
import android.widget.SearchView
|
||||
import androidx.lifecycle.*
|
||||
import com.rtbishop.look4sat.data.PreferencesSource
|
||||
import com.rtbishop.look4sat.data.SatDataRepository
|
||||
import com.rtbishop.look4sat.domain.model.SatItem
|
||||
import com.rtbishop.look4sat.framework.model.Result
|
||||
|
@ -32,6 +33,7 @@ import javax.inject.Inject
|
|||
|
||||
@HiltViewModel
|
||||
class SatItemViewModel @Inject constructor(
|
||||
private val preferencesSource: PreferencesSource,
|
||||
private val resolver: ContentResolver,
|
||||
private val satDataRepository: SatDataRepository,
|
||||
) : ViewModel(), SatItemAdapter.EntriesClickListener, SearchView.OnQueryTextListener {
|
||||
|
@ -61,12 +63,12 @@ class SatItemViewModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
fun updateEntriesFromWeb(sources: List<String>?) {
|
||||
fun updateEntriesFromWeb(sources: List<String>) {
|
||||
viewModelScope.launch {
|
||||
_satData.value = Result.InProgress
|
||||
runCatching {
|
||||
if (sources == null) satDataRepository.updateEntriesFromWeb()
|
||||
else satDataRepository.updateEntriesFromWeb(sources)
|
||||
preferencesSource.saveTleSources(sources)
|
||||
satDataRepository.updateEntriesFromWeb(sources)
|
||||
}.onFailure { _satData.value = Result.Error(it) }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,8 +65,8 @@ class SatPassViewModel @Inject constructor(
|
|||
preferencesSource.updatePositionFromGPS()
|
||||
viewModelScope.launch {
|
||||
_passes.postValue(Result.InProgress)
|
||||
satDataRepository.updateEntriesFromWeb()
|
||||
val defaultCatNums = listOf(43700, 25544, 25338, 28654, 33591, 40069, 27607, 24278)
|
||||
satDataRepository.updateEntriesFromWeb(preferencesSource.loadDefaultSources())
|
||||
satDataRepository.updateEntriesSelection(defaultCatNums, true)
|
||||
satPassRepository.forceCalculation(satDataRepository.getSelectedSatellites())
|
||||
preferencesSource.setSetupDone()
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.rtbishop.look4sat.presentation.satSourcesScreen
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.widget.doOnTextChanged
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.rtbishop.look4sat.databinding.ItemTleSourceBinding
|
||||
|
||||
class SourcesAdapter(private val sources: MutableList<TleSource> = mutableListOf()) :
|
||||
RecyclerView.Adapter<SourcesAdapter.TleSourceHolder>() {
|
||||
|
||||
fun getSources(): List<TleSource> {
|
||||
return sources.filter { it.url.contains("https://") }
|
||||
}
|
||||
|
||||
fun setSources(list: List<TleSource>) {
|
||||
sources.clear()
|
||||
sources.addAll(list)
|
||||
}
|
||||
|
||||
fun addSource() {
|
||||
sources.add(TleSource())
|
||||
notifyItemInserted(itemCount - 1)
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TleSourceHolder {
|
||||
val binding = ItemTleSourceBinding
|
||||
.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
return TleSourceHolder(binding)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: TleSourceHolder, position: Int) {
|
||||
holder.bind(sources[position])
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return sources.size
|
||||
}
|
||||
|
||||
inner class TleSourceHolder(private val binding: ItemTleSourceBinding) :
|
||||
RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
fun bind(source: TleSource) {
|
||||
binding.tleSourceUrl.setText(source.url)
|
||||
binding.tleSourceUrl.doOnTextChanged { text, _, _, _ -> source.url = text.toString() }
|
||||
binding.tleSourceInputLayout.setEndIconOnClickListener {
|
||||
sources.remove(source)
|
||||
notifyItemRemoved(adapterPosition)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.rtbishop.look4sat.presentation.satSourcesScreen
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.WindowManager
|
||||
import androidx.appcompat.app.AppCompatDialogFragment
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.rtbishop.look4sat.R
|
||||
import com.rtbishop.look4sat.data.PreferencesSource
|
||||
import com.rtbishop.look4sat.databinding.DialogSourcesBinding
|
||||
import com.rtbishop.look4sat.utility.setNavResult
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
class SourcesDialog : AppCompatDialogFragment() {
|
||||
|
||||
@Inject
|
||||
lateinit var prefsManager: PreferencesSource
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, group: ViewGroup?, state: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.dialog_sources, group, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, state: Bundle?) {
|
||||
super.onViewCreated(view, state)
|
||||
val sources = prefsManager.loadTleSources().map { TleSource(it) }
|
||||
val sourcesAdapter = SourcesAdapter().apply { setSources(sources) }
|
||||
DialogSourcesBinding.bind(view).apply {
|
||||
dialog?.window?.setLayout(
|
||||
WindowManager.LayoutParams.MATCH_PARENT,
|
||||
WindowManager.LayoutParams.WRAP_CONTENT
|
||||
)
|
||||
sourcesRecycler.apply {
|
||||
adapter = sourcesAdapter
|
||||
layoutManager = LinearLayoutManager(requireContext())
|
||||
}
|
||||
sourceBtnAdd.setOnClickListener {
|
||||
sourcesAdapter.addSource()
|
||||
}
|
||||
sourcesBtnPos.setOnClickListener {
|
||||
setNavResult("sources", sourcesAdapter.getSources().map { it.url })
|
||||
dismiss()
|
||||
}
|
||||
sourcesBtnNeg.setOnClickListener { dismiss() }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.rtbishop.look4sat.presentation.satSourcesScreen
|
||||
|
||||
class TleSource(var url: String = String())
|
|
@ -20,9 +20,13 @@ package com.rtbishop.look4sat.utility
|
|||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.annotation.IdRes
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleEventObserver
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.NavOptions
|
||||
import androidx.navigation.Navigator
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.rtbishop.look4sat.R
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
@ -58,3 +62,26 @@ fun NavController.navigateSafe(
|
|||
navigate(resId, args, navOptions, navExtras)
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> Fragment.setNavResult(key: String, value: T) {
|
||||
findNavController().previousBackStackEntry?.savedStateHandle?.set(key, value)
|
||||
}
|
||||
|
||||
fun <T> Fragment.getNavResult(@IdRes id: Int, key: String, onResult: (result: T) -> Unit) {
|
||||
val navBackStackEntry = findNavController().getBackStackEntry(id)
|
||||
val observer = LifecycleEventObserver { _, event ->
|
||||
if (event == Lifecycle.Event.ON_RESUME
|
||||
&& navBackStackEntry.savedStateHandle.contains(key)
|
||||
) {
|
||||
val result = navBackStackEntry.savedStateHandle.get<T>(key)
|
||||
result?.let(onResult)
|
||||
navBackStackEntry.savedStateHandle.remove<T>(key)
|
||||
}
|
||||
}
|
||||
navBackStackEntry.lifecycle.addObserver(observer)
|
||||
viewLifecycleOwner.lifecycle.addObserver(LifecycleEventObserver { _, event ->
|
||||
if (event == Lifecycle.Event.ON_DESTROY) {
|
||||
navBackStackEntry.lifecycle.removeObserver(observer)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@color/themeLight"
|
||||
android:pathData="M19,8l-4,4h3c0,3.31 -2.69,6 -6,6 -1.01,0 -1.97,-0.25 -2.8,-0.7l-1.46,1.46C8.97,19.54 10.43,20 12,20c4.42,0 8,-3.58 8,-8h3l-4,-4zM6,12c0,-3.31 2.69,-6 6,-6 1.01,0 1.97,0.25 2.8,0.7l1.46,-1.46C15.03,4.46 13.57,4 12,4c-4.42,0 -8,3.58 -8,8H1l4,4 4,-4H6z" />
|
||||
</vector>
|
|
@ -1,9 +0,0 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@color/themeLight"
|
||||
android:pathData="M3.9,12c0,-1.71 1.39,-3.1 3.1,-3.1h4L11,7L7,7c-2.76,0 -5,2.24 -5,5s2.24,5 5,5h4v-1.9L7,15.1c-1.71,0 -3.1,-1.39 -3.1,-3.1zM8,13h8v-2L8,11v2zM17,7h-4v1.9h4c1.71,0 3.1,1.39 3.1,3.1s-1.39,3.1 -3.1,3.1h-4L13,17h4c2.76,0 5,-2.24 5,-5s-2.24,-5 -5,-5z" />
|
||||
</vector>
|
|
@ -1,9 +0,0 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@color/themeLight"
|
||||
android:pathData="M12,4L12,1L8,5l4,4L12,6c3.31,0 6,2.69 6,6 0,1.01 -0.25,1.97 -0.7,2.8l1.46,1.46C19.54,15.03 20,13.57 20,12c0,-4.42 -3.58,-8 -8,-8zM12,18c-3.31,0 -6,-2.69 -6,-6 0,-1.01 0.25,-1.97 0.7,-2.8L5.24,7.74C4.46,8.97 4,10.43 4,12c0,4.42 3.58,8 8,8v3l4,-4 -4,-4v3z" />
|
||||
</vector>
|
|
@ -1,9 +0,0 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@color/themeLight"
|
||||
android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z" />
|
||||
</vector>
|
|
@ -5,5 +5,5 @@
|
|||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@color/themeLight"
|
||||
android:pathData="M19,9h-4V3H9v6H5l7,7 7,-7zM5,18v2h14v-2H5z" />
|
||||
android:pathData="M19,8l-4,4h3c0,3.31 -2.69,6 -6,6 -1.01,0 -1.97,-0.25 -2.8,-0.7l-1.46,1.46C8.97,19.54 10.43,20 12,20c4.42,0 8,-3.58 8,-8h3l-4,-4zM6,12c0,-3.31 2.69,-6 6,-6 1.01,0 1.97,0.25 2.8,0.7l1.46,-1.46C15.03,4.46 13.57,4 12,4c-4.42,0 -8,3.58 -8,8H1l4,4 4,-4H6z" />
|
||||
</vector>
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/tleSourcesDialog"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/greyDark"
|
||||
android:padding="4dp">
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/sourcesTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="6dp"
|
||||
android:text="@string/sources_title"
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintHorizontal_chainStyle="spread_inside"
|
||||
app:layout_constraintStart_toStartOf="@+id/sourcesRecycler"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/sourcesWarning"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/sources_https"
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintStart_toStartOf="@+id/sourcesRecycler"
|
||||
app:layout_constraintTop_toBottomOf="@+id/sourcesTitle" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/sourceBtnAdd"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:backgroundTint="@color/greySurface"
|
||||
android:contentDescription="@string/placeholder"
|
||||
android:src="@drawable/ic_add"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/sourcesWarning"
|
||||
app:layout_constraintDimensionRatio="h,1:1"
|
||||
app:layout_constraintEnd_toEndOf="@+id/sourcesRecycler"
|
||||
app:layout_constraintTop_toTopOf="@+id/sourcesTitle" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/sourcesRecycler"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/sourcesWarning">
|
||||
|
||||
</androidx.recyclerview.widget.RecyclerView>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/sourcesBtnNeg"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:backgroundTint="@color/greySurface"
|
||||
android:text="@string/btn_cancel"
|
||||
android:textAllCaps="false"
|
||||
android:textColor="@color/themeLight"
|
||||
app:layout_constraintBaseline_toBaselineOf="@+id/sourcesBtnPos"
|
||||
app:layout_constraintHorizontal_chainStyle="spread_inside"
|
||||
app:layout_constraintStart_toStartOf="@+id/sourcesRecycler" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/sourcesBtnPos"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:backgroundTint="@color/greySurface"
|
||||
android:text="@string/btn_update"
|
||||
android:textAllCaps="false"
|
||||
android:textColor="@color/themeLight"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="@+id/sourcesRecycler"
|
||||
app:layout_constraintTop_toBottomOf="@+id/sourcesRecycler" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -30,19 +30,7 @@
|
|||
android:backgroundTint="@color/greyDark"
|
||||
android:contentDescription="@string/placeholder"
|
||||
android:elevation="4dp"
|
||||
android:src="@drawable/ic_baseline_cached_24"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/import_file"
|
||||
app:layout_constraintEnd_toStartOf="@+id/import_source"
|
||||
app:layout_constraintTop_toTopOf="@+id/import_file" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/import_source"
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="48dp"
|
||||
android:backgroundTint="@color/greyDark"
|
||||
android:contentDescription="@string/placeholder"
|
||||
android:elevation="4dp"
|
||||
android:src="@drawable/ic_baseline_link_24"
|
||||
android:src="@drawable/ic_update_web"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/import_file"
|
||||
app:layout_constraintEnd_toStartOf="@+id/import_file"
|
||||
app:layout_constraintTop_toTopOf="@+id/import_file" />
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/tleSourceItem"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="4dp"
|
||||
android:paddingBottom="4dp">
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/tleSourceInputLayout"
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/sources_hint"
|
||||
app:endIconDrawable="@drawable/ic_map_sat"
|
||||
app:endIconMode="custom"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_chainStyle="packed"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/tleSourceUrl"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:inputType="textUri" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -16,6 +16,13 @@
|
|||
app:exitAnim="@anim/nav_default_exit_anim"
|
||||
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@anim/nav_default_pop_exit_anim" />
|
||||
<action
|
||||
android:id="@+id/action_entries_to_sources"
|
||||
app:destination="@id/nav_dialog_sources"
|
||||
app:enterAnim="@anim/nav_default_enter_anim"
|
||||
app:exitAnim="@anim/nav_default_exit_anim"
|
||||
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@anim/nav_default_pop_exit_anim" />
|
||||
</fragment>
|
||||
|
||||
<fragment
|
||||
|
@ -59,5 +66,9 @@
|
|||
android:id="@+id/nav_info"
|
||||
android:name="com.rtbishop.look4sat.presentation.appInfoScreen.AppInfoFragment"
|
||||
tools:layout="@layout/fragment_info" />
|
||||
<dialog
|
||||
android:id="@+id/nav_dialog_sources"
|
||||
android:name="com.rtbishop.look4sat.presentation.satSourcesScreen.SourcesDialog"
|
||||
tools:layout="@layout/dialog_sources" />
|
||||
|
||||
</navigation>
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
<resources>
|
||||
<string name="yes">Да</string>
|
||||
<string name="no">Нет</string>
|
||||
<string name="btn_cancel">Отмена</string>
|
||||
<string name="btn_update">Обновить</string>
|
||||
|
||||
<string name="menu_entries">Спутники</string>
|
||||
<string name="menu_passes">Пролеты</string>
|
||||
|
@ -9,8 +11,9 @@
|
|||
<string name="menu_prefs">Настройки</string>
|
||||
<string name="menu_about">Инфо</string>
|
||||
|
||||
<string name="sources_title">Введите HTTPS адрес источника</string>
|
||||
<string name="sources_title">Управление TLE</string>
|
||||
<string name="sources_hint">URL источника</string>
|
||||
<string name="sources_https">Только протокол HTTPS</string>
|
||||
<string name="sources_error">Пожалуйста, проверьте URL</string>
|
||||
|
||||
<string name="entries_update">Обновить спутники:</string>
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
<string name="no">No</string>
|
||||
<string name="yes">Yes</string>
|
||||
<string name="btn_cancel">Cancel</string>
|
||||
<string name="btn_update">Update</string>
|
||||
|
||||
<string name="menu_entries">Satellites</string>
|
||||
<string name="menu_passes">Passes</string>
|
||||
|
@ -12,8 +14,9 @@
|
|||
<string name="menu_prefs">Settings</string>
|
||||
<string name="menu_about">Info</string>
|
||||
|
||||
<string name="sources_title">Enter HTTPS source address</string>
|
||||
<string name="sources_title">Manage TLE sources</string>
|
||||
<string name="sources_hint">Source URL</string>
|
||||
<string name="sources_https">Protocol HTTPS only</string>
|
||||
<string name="sources_error">Please check the entered URL</string>
|
||||
|
||||
<string name="entries_update">TLE data update:</string>
|
||||
|
|
|
@ -52,4 +52,10 @@ interface PreferencesSource {
|
|||
fun loadModesSelection(): List<String>
|
||||
|
||||
fun getRotatorServer(): Pair<String, Int>?
|
||||
|
||||
fun loadTleSources(): List<String>
|
||||
|
||||
fun saveTleSources(sources: List<String>)
|
||||
|
||||
fun loadDefaultSources(): List<String>
|
||||
}
|
||||
|
|
|
@ -35,12 +35,6 @@ class SatDataRepository(
|
|||
private val satRemoteSource: SatDataRemoteSource,
|
||||
private val ioDispatcher: CoroutineDispatcher
|
||||
) {
|
||||
private val defaultSources = listOf(
|
||||
"https://celestrak.com/NORAD/elements/active.txt",
|
||||
"https://amsat.org/tle/current/nasabare.txt",
|
||||
"https://www.prismnet.com/~mmccants/tles/classfd.zip",
|
||||
"https://www.prismnet.com/~mmccants/tles/inttles.zip"
|
||||
)
|
||||
|
||||
fun saveSelectedModes(modes: List<String>) {
|
||||
preferencesSource.saveModesSelection(modes)
|
||||
|
@ -66,7 +60,7 @@ class SatDataRepository(
|
|||
satLocalSource.updateEntries(importSatEntries(stream))
|
||||
}
|
||||
|
||||
suspend fun updateEntriesFromWeb(sources: List<String> = defaultSources) {
|
||||
suspend fun updateEntriesFromWeb(sources: List<String>) {
|
||||
coroutineScope {
|
||||
launch(ioDispatcher) {
|
||||
val streams = mutableListOf<InputStream>()
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
Added immediate initial setup
|
||||
Added pass direction arrow to radar view #52
|
||||
Added orientation pointer to radar view
|
||||
Fixed radar view update bug #51
|
||||
Fixed tle update issue #53
|
||||
Fixed location update bug #54
|
||||
Switched to modular architecture
|
|
@ -1,6 +1,7 @@
|
|||
Added simple custom source TLE update dialog
|
||||
Added immediate initial setup
|
||||
Added pass direction arrow to radar view #52
|
||||
Added orientation pointer to radar view
|
||||
Fixed radar view update bug #51
|
||||
Fixed tle update issue #53
|
||||
Fixed location update bug #54
|
||||
Switched to modular architecture
|
Ładowanie…
Reference in New Issue