Reverted TLE source update screen, fixed location setting bug #53 #54

pull/65/head
Arty Bishop 2021-05-18 10:02:18 +01:00
rodzic fb2008b07a
commit a0a95ce372
26 zmienionych plików z 404 dodań i 78 usunięć

Wyświetl plik

@ -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 {

Wyświetl plik

@ -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"

Wyświetl plik

@ -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

Wyświetl plik

@ -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()
}
}

Wyświetl plik

@ -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(

Wyświetl plik

@ -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) }
}
}

Wyświetl plik

@ -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()

Wyświetl plik

@ -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)
}
}
}
}

Wyświetl plik

@ -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() }
}
}
}

Wyświetl plik

@ -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())

Wyświetl plik

@ -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)
}
})
}

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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" />

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>
}

Wyświetl plik

@ -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>()

Wyświetl plik

@ -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

Wyświetl plik

@ -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