mirror of
https://github.com/atsunatsu/Look4Sat.git
synced 2026-10-02 03:15:37 +00:00
Added Api 21 support. Fixed the bug with geostationary satellites calculations. Showing them on top of the list in separate ViewHolders.
This commit is contained in:
1 parent
94e4b5fb31
commit
6ead302634
16 files changed
+209
-59
No files matched your search
+3
-3
@@ -28,10 +28,10 @@ android {
|
||||
buildToolsVersion "29.0.2"
|
||||
defaultConfig {
|
||||
applicationId "com.rtbishop.look4sat"
|
||||
minSdkVersion 24
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 29
|
||||
versionCode 2
|
||||
versionName '1.1'
|
||||
versionCode 3
|
||||
versionName '1.2'
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
|
||||
@@ -103,18 +103,49 @@ class PassPredictor(private val tle: TLE, private val qth: GroundStationPosition
|
||||
var lastAOS: Date
|
||||
var count = 0
|
||||
|
||||
do {
|
||||
if (count > 0) windBackTime = false
|
||||
val pass = nextSatPass(trackStartDate, windBackTime)
|
||||
lastAOS = pass.startTime
|
||||
passes.add(pass)
|
||||
trackStartDate = Date(pass.endTime.time + threeQuarterOrbitMinutes() * 60L * 1000L)
|
||||
count++
|
||||
} while (lastAOS < trackEndDate)
|
||||
if (tle.isDeepspace) {
|
||||
passes.add(nextGeoSatPass(start))
|
||||
} else {
|
||||
do {
|
||||
if (count > 0) windBackTime = false
|
||||
val pass = nextSatPass(trackStartDate, windBackTime)
|
||||
lastAOS = pass.startTime
|
||||
passes.add(pass)
|
||||
trackStartDate = Date(pass.endTime.time + threeQuarterOrbitMinutes() * 60L * 1000L)
|
||||
count++
|
||||
} while (lastAOS < trackEndDate)
|
||||
}
|
||||
|
||||
return passes
|
||||
}
|
||||
|
||||
private fun nextGeoSatPass(date: Date): SatPassTime {
|
||||
val aosAzimuth: Int
|
||||
val losAzimuth: Int
|
||||
val tca: Date
|
||||
val polePassed: String
|
||||
val cal = Calendar.getInstance(timeZone).apply {
|
||||
clear()
|
||||
timeInMillis = date.time
|
||||
}
|
||||
val satPos = getSatPos(cal.time)
|
||||
|
||||
aosAzimuth = (satPos.azimuth / (2.0 * Math.PI) * 360.0).toInt()
|
||||
losAzimuth = (satPos.azimuth / (2.0 * Math.PI) * 360.0).toInt()
|
||||
tca = satPos.time
|
||||
polePassed = getPolePassed(satPos, satPos)
|
||||
|
||||
cal.add(Calendar.HOUR, -12)
|
||||
val startDate = cal.time
|
||||
cal.add(Calendar.HOUR, 24)
|
||||
val endDate = cal.time
|
||||
|
||||
return SatPassTime(
|
||||
startDate, endDate, tca, polePassed, aosAzimuth,
|
||||
losAzimuth, satPos.elevation / (2.0 * Math.PI) * 360.0
|
||||
)
|
||||
}
|
||||
|
||||
private fun nextSatPass(date: Date, windBack: Boolean = false): SatPassTime {
|
||||
val aosAzimuth: Int
|
||||
val losAzimuth: Int
|
||||
|
||||
@@ -187,14 +187,4 @@ class MainActivity : AppCompatActivity() {
|
||||
val navController = findNavController(R.id.nav_host)
|
||||
return navController.navigateUp(appBarConfig) || super.onSupportNavigateUp()
|
||||
}
|
||||
//
|
||||
// private fun ImageButton.enable() {
|
||||
// this.isEnabled = true
|
||||
// this.alpha = 1.0f
|
||||
// }
|
||||
//
|
||||
// private fun ImageButton.disable() {
|
||||
// this.isEnabled = false
|
||||
// this.alpha = 0.25f
|
||||
// }
|
||||
}
|
||||
@@ -29,6 +29,7 @@ import android.widget.FrameLayout
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import com.github.amsacode.predict4java.GroundStationPosition
|
||||
@@ -146,19 +147,19 @@ class MapViewFragment : Fragment() {
|
||||
private val scale = resources.displayMetrics.density
|
||||
private val groundTrackPaint = Paint().apply {
|
||||
isAntiAlias = true
|
||||
color = resources.getColor(R.color.satTrack, mainActivity.theme)
|
||||
color = ContextCompat.getColor(mainActivity, R.color.satTrack)
|
||||
style = Paint.Style.STROKE
|
||||
strokeWidth = scale
|
||||
}
|
||||
private val footprintPaint = Paint().apply {
|
||||
isAntiAlias = true
|
||||
color = resources.getColor(R.color.satFootprint, mainActivity.theme)
|
||||
color = ContextCompat.getColor(mainActivity, R.color.satFootprint)
|
||||
style = Paint.Style.STROKE
|
||||
strokeWidth = scale
|
||||
}
|
||||
private val txtPaint = Paint().apply {
|
||||
isAntiAlias = true
|
||||
color = resources.getColor(R.color.satFootprint, mainActivity.theme)
|
||||
color = ContextCompat.getColor(mainActivity, R.color.satFootprint)
|
||||
style = Paint.Style.FILL
|
||||
strokeWidth = scale
|
||||
textSize = 16f
|
||||
|
||||
@@ -245,7 +245,7 @@ class PassListFragment : Fragment() {
|
||||
|
||||
override fun onTick(millisUntilFinished: Long) {
|
||||
aosTimerText.text = String.format(
|
||||
mainActivity.getString(R.string.pat_timer_aos),
|
||||
mainActivity.getString(R.string.pat_timer),
|
||||
TimeUnit.MILLISECONDS.toHours(millisUntilFinished) % 60,
|
||||
TimeUnit.MILLISECONDS.toMinutes(millisUntilFinished) % 60,
|
||||
TimeUnit.MILLISECONDS.toSeconds(millisUntilFinished) % 60
|
||||
@@ -265,7 +265,7 @@ class PassListFragment : Fragment() {
|
||||
|
||||
override fun onTick(millisUntilFinished: Long) {
|
||||
aosTimerText.text = String.format(
|
||||
mainActivity.getString(R.string.pat_timer_los),
|
||||
mainActivity.getString(R.string.pat_timer),
|
||||
TimeUnit.MILLISECONDS.toHours(millisUntilFinished) % 60,
|
||||
TimeUnit.MILLISECONDS.toMinutes(millisUntilFinished) % 60,
|
||||
TimeUnit.MILLISECONDS.toSeconds(millisUntilFinished) % 60
|
||||
@@ -281,6 +281,6 @@ class PassListFragment : Fragment() {
|
||||
isTimerSet = false
|
||||
}
|
||||
if (resetToNull) aosTimerText.text =
|
||||
String.format(getString(R.string.pat_timer_aos), 0, 0, 0)
|
||||
String.format(getString(R.string.pat_timer), 0, 0, 0)
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,7 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.TextView
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
@@ -132,24 +133,24 @@ class PolarViewFragment : Fragment() {
|
||||
|
||||
private val radarPaint = Paint().apply {
|
||||
isAntiAlias = true
|
||||
color = resources.getColor(R.color.themeLight, mainActivity.theme)
|
||||
color = ContextCompat.getColor(mainActivity, R.color.themeLight)
|
||||
style = Paint.Style.STROKE
|
||||
strokeWidth = scale
|
||||
}
|
||||
private val txtPaint = Paint().apply {
|
||||
isAntiAlias = true
|
||||
color = resources.getColor(R.color.themeAccent, mainActivity.theme)
|
||||
color = ContextCompat.getColor(mainActivity, R.color.themeAccent)
|
||||
textSize = txtSize
|
||||
}
|
||||
private val trackPaint = Paint().apply {
|
||||
isAntiAlias = true
|
||||
color = resources.getColor(R.color.satTrack, mainActivity.theme)
|
||||
color = ContextCompat.getColor(mainActivity, R.color.satTrack)
|
||||
style = Paint.Style.STROKE
|
||||
strokeWidth = scale
|
||||
}
|
||||
private val satPaint = Paint().apply {
|
||||
isAntiAlias = true
|
||||
color = resources.getColor(R.color.themeAccent, mainActivity.theme)
|
||||
color = ContextCompat.getColor(mainActivity, R.color.themeAccent)
|
||||
style = Paint.Style.FILL
|
||||
}
|
||||
private val path: Path = Path()
|
||||
@@ -163,7 +164,7 @@ class PolarViewFragment : Fragment() {
|
||||
setPassText()
|
||||
drawRadarView(canvas)
|
||||
drawRadarText(canvas)
|
||||
drawPassTrajectory(canvas)
|
||||
if (!satPass.tle.isDeepspace) drawPassTrajectory(canvas)
|
||||
drawSatellite(canvas)
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ import com.rtbishop.look4sat.ui.PassListFragmentDirections
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
class SatPassAdapter : RecyclerView.Adapter<SatPassAdapter.SatPassHolder>() {
|
||||
class SatPassAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
|
||||
private var satPassList = mutableListOf<SatPass>()
|
||||
|
||||
@@ -71,15 +71,31 @@ class SatPassAdapter : RecyclerView.Adapter<SatPassAdapter.SatPassHolder>() {
|
||||
return satPassList.size
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SatPassHolder {
|
||||
val itemView = LayoutInflater
|
||||
.from(parent.context)
|
||||
.inflate(R.layout.card_pass, parent, false)
|
||||
return SatPassHolder(itemView)
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
return if (satPassList[position].tle.isDeepspace) 1
|
||||
else 0
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: SatPassHolder, position: Int) {
|
||||
holder.bind(satPassList[position])
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
return if (viewType == 0) {
|
||||
val itemView = LayoutInflater
|
||||
.from(parent.context)
|
||||
.inflate(R.layout.card_pass, parent, false)
|
||||
return SatPassHolder(itemView)
|
||||
} else {
|
||||
val itemView = LayoutInflater
|
||||
.from(parent.context)
|
||||
.inflate(R.layout.card_pass_geo, parent, false)
|
||||
SatPassGeoHolder(itemView)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
if (holder.itemViewType == 0) {
|
||||
(holder as SatPassHolder).bind(satPassList[position])
|
||||
} else {
|
||||
(holder as SatPassGeoHolder).bind(satPassList[position])
|
||||
}
|
||||
}
|
||||
|
||||
inner class SatPassHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||
@@ -123,4 +139,29 @@ class SatPassAdapter : RecyclerView.Adapter<SatPassAdapter.SatPassHolder>() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inner class SatPassGeoHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||
|
||||
private val context: Context = itemView.context
|
||||
private val satName = itemView.findViewById<TextView>(R.id.pass_geo_name)
|
||||
private val satId = itemView.findViewById<TextView>(R.id.pass_geo_id)
|
||||
private val satAz = itemView.findViewById<TextView>(R.id.pass_geo_az)
|
||||
private val satEl = itemView.findViewById<TextView>(R.id.pass_geo_el)
|
||||
|
||||
fun bind(satPass: SatPass) {
|
||||
val satPos = satPass.predictor.getSatPos(satPass.pass.startTime)
|
||||
val azimuth = satPos.azimuth * 180 / Math.PI
|
||||
|
||||
satName.text = satPass.tle.name
|
||||
satId.text = String.format(context.getString(R.string.pass_satId), satPass.tle.catnum)
|
||||
satAz.text = String.format(context.getString(R.string.pat_azimuth), azimuth)
|
||||
satEl.text =
|
||||
String.format(context.getString(R.string.pat_elevation), satPass.pass.maxEl)
|
||||
|
||||
itemView.setOnClickListener {
|
||||
val action = PassListFragmentDirections.actionPassToPolar(satPass)
|
||||
itemView.findNavController().navigate(action)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 22 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
@@ -2,9 +2,9 @@
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:opacity="opaque">
|
||||
<item android:drawable="@drawable/ic_launcher_background" />
|
||||
<item
|
||||
android:width="240dp"
|
||||
android:height="240dp"
|
||||
android:drawable="@drawable/splash_foreground"
|
||||
android:gravity="center" />
|
||||
<item>
|
||||
<bitmap
|
||||
android:gravity="center"
|
||||
android:src="@drawable/splash_front" />
|
||||
</item>
|
||||
</layer-list>
|
||||
@@ -26,7 +26,7 @@
|
||||
style="@style/ToolbarText"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/toolbar_filter"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
|
||||
@@ -29,8 +29,19 @@
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/card_pass_bg">
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/pass_background"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:contentDescription="@string/placeholder"
|
||||
android:scaleType="centerCrop"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:srcCompat="@drawable/card_pass_bg" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/pass_losAz"
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/card_pass_geo"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginEnd="4dp"
|
||||
app:cardElevation="4dp">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/pass_geo_background"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:contentDescription="@string/placeholder"
|
||||
android:scaleType="centerCrop"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:srcCompat="@drawable/card_pass_bg" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/pass_geo_img"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:contentDescription="@string/placeholder"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/pass_geo_name"
|
||||
app:layout_constraintStart_toStartOf="@+id/pass_geo_az"
|
||||
app:layout_constraintTop_toTopOf="@+id/pass_geo_name"
|
||||
app:srcCompat="@drawable/ic_pass_active" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/pass_geo_name"
|
||||
style="@style/CardPassName"
|
||||
android:text="@string/pass_satName"
|
||||
app:layout_constraintBaseline_toBaselineOf="@+id/pass_geo_id"
|
||||
app:layout_constraintEnd_toStartOf="@+id/pass_geo_id"
|
||||
app:layout_constraintHorizontal_bias="0.02"
|
||||
app:layout_constraintStart_toEndOf="@+id/pass_geo_img" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/pass_geo_id"
|
||||
style="@style/CardPassName"
|
||||
android:layout_marginTop="4dp"
|
||||
android:text="@string/pass_satId"
|
||||
app:layout_constraintEnd_toEndOf="@+id/pass_geo_el"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/pass_geo_az"
|
||||
style="@style/CardPassText"
|
||||
android:layout_marginStart="6dp"
|
||||
android:text="@string/pat_azimuth"
|
||||
app:layout_constraintBaseline_toBaselineOf="@+id/pass_geo_el"
|
||||
app:layout_constraintEnd_toStartOf="@+id/pass_geo_el"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintHorizontal_chainStyle="spread_inside"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/pass_geo_el"
|
||||
style="@style/CardPassText"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:text="@string/pat_elevation"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/pass_geo_az"
|
||||
app:layout_constraintTop_toBottomOf="@+id/pass_geo_id" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
@@ -90,15 +90,13 @@
|
||||
<string name="pat_longitude">Долгота: %.1f°</string>
|
||||
<string name="pat_range">Расст.: %.0f км</string>
|
||||
<string name="pat_altitude">Высота: %.0f км</string>
|
||||
<string name="pat_timer_aos">НПС -%02d:%02d:%02d</string>
|
||||
<string name="pat_timer_los">КПС -%02d:%02d:%02d</string>
|
||||
|
||||
<string name="trans_mode">Модуляция: %s</string>
|
||||
<string name="trans_inverted">Инверсия: %s</string>
|
||||
<string name="trans_up_low">Исход. канал: %.4f MHz</string>
|
||||
<string name="trans_up_lowHigh">Исход. канал: %.4f - %.4f MHz</string>
|
||||
<string name="trans_down_low">Вход. канал: %.4f MHz</string>
|
||||
<string name="trans_down_lowHigh">Вход. канал: %.4f - %.4f MHz</string>
|
||||
<string name="trans_up_low">Исходящий: %.4f MHz</string>
|
||||
<string name="trans_up_lowHigh">Исходящий: %.4f - %.4f MHz</string>
|
||||
<string name="trans_down_low">Входящий: %.4f MHz</string>
|
||||
<string name="trans_down_lowHigh">Входящий: %.4f - %.4f MHz</string>
|
||||
|
||||
<string name="info_swipe_text">Проведите по экрану вниз, чтобы обновить список пролетов
|
||||
для выбранных спутников</string>
|
||||
|
||||
@@ -102,8 +102,7 @@
|
||||
<string name="pat_longitude">Longitude: %.1f°</string>
|
||||
<string name="pat_range">Distance: %.0f km</string>
|
||||
<string name="pat_altitude">Altitude: %.0f km</string>
|
||||
<string name="pat_timer_aos">AOS -%02d:%02d:%02d</string>
|
||||
<string name="pat_timer_los">LOS -%02d:%02d:%02d</string>
|
||||
<string name="pat_timer" translatable="false">%02d:%02d:%02d</string>
|
||||
|
||||
<string name="trans_description" translatable="false">%s</string>
|
||||
<string name="trans_mode">Mode: %s</string>
|
||||
@@ -125,8 +124,7 @@
|
||||
<string name="about_subtitle">
|
||||
Amateur radio and weather satellites passes calculator for Android</string>
|
||||
<string name="about_thanks_to">Big thanks:</string>
|
||||
<string name="about_thanks_list">— To you for installing and using this app!
|
||||
\nMay your sky always be clear!\n
|
||||
<string name="about_thanks_list">— To you for installing and using this app! May your sky always be clear!\n
|
||||
|
||||
\n— To David A. B. Johnson, <a href="https://github.com/g4dpz">G4DPZ</a>, the author of
|
||||
predict4java library which this app is using for all the SGP4 model calculations.\n
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
<item name="android:layout_width">wrap_content</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:gravity">center</item>
|
||||
<item name="android:textSize">28sp</item>
|
||||
<item name="android:textSize">36sp</item>
|
||||
<item name="android:textStyle">bold</item>
|
||||
<item name="android:textColor">@color/themeAccent</item>
|
||||
</style>
|
||||
|
||||
Reference in new issue
Block a user