mirror of
https://github.com/atsunatsu/Look4Sat.git
synced 2026-10-04 03:37:21 +00:00
Various changes to layouts, styles, strings and drawables
This commit is contained in:
1 parent
567200cfe4
commit
9fd0d5f2e2
60 files changed
+368
-438
No files matched your search
@@ -29,9 +29,9 @@ import com.rtbishop.look4sat.R
|
||||
import com.rtbishop.look4sat.data.ISettingsHandler
|
||||
import com.rtbishop.look4sat.domain.ILocationHandler
|
||||
import com.rtbishop.look4sat.domain.QthConverter
|
||||
import com.rtbishop.look4sat.domain.QthConverter.round
|
||||
import com.rtbishop.look4sat.domain.model.DataState
|
||||
import com.rtbishop.look4sat.domain.predict.GeoPos
|
||||
import com.rtbishop.look4sat.domain.round
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
@@ -65,6 +65,7 @@ class LocalSource(
|
||||
return radiosDao.getRadios(catnum).toDomainRadios()
|
||||
}
|
||||
|
||||
@Suppress("BlockingMethodInNonBlockingContext")
|
||||
override suspend fun getFileStream(uri: String): InputStream? {
|
||||
return withContext(ioDispatcher) { resolver.openInputStream(Uri.parse(uri)) }
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import java.net.URL
|
||||
|
||||
class RemoteSource(private val ioDispatcher: CoroutineDispatcher) : IRemoteSource {
|
||||
|
||||
@Suppress("BlockingMethodInNonBlockingContext")
|
||||
override suspend fun getFileStream(url: String): InputStream? {
|
||||
return withContext(ioDispatcher) { URL(url).openStream() }
|
||||
}
|
||||
|
||||
@@ -19,21 +19,12 @@ package com.rtbishop.look4sat.presentation
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.content.res.Resources
|
||||
import android.widget.EditText
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.IdRes
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleEventObserver
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import java.net.InetSocketAddress
|
||||
import java.net.Socket
|
||||
import java.security.MessageDigest
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.regex.Pattern
|
||||
|
||||
fun Context.toast(text: String, duration: Int = Toast.LENGTH_SHORT) {
|
||||
Toast.makeText(this, text, duration).apply { show() }
|
||||
@@ -64,79 +55,3 @@ fun <T> Fragment.getNavResult(@IdRes id: Int, key: String, onResult: (result: T)
|
||||
fun <T> Fragment.setNavResult(key: String, value: T) {
|
||||
findNavController().previousBackStackEntry?.savedStateHandle?.set(key, value)
|
||||
}
|
||||
|
||||
fun Long.toTimerString(): String {
|
||||
val format = "%02d:%02d:%02d"
|
||||
val hours = TimeUnit.MILLISECONDS.toHours(this)
|
||||
val minutes = TimeUnit.MILLISECONDS.toMinutes(this) % 60
|
||||
val seconds = TimeUnit.MILLISECONDS.toSeconds(this) % 60
|
||||
return String.format(format, hours, minutes, seconds)
|
||||
}
|
||||
|
||||
fun Double.round(decimals: Int): Double {
|
||||
var multiplier = 1.0
|
||||
repeat(decimals) { multiplier *= 10 }
|
||||
return kotlin.math.round(this * multiplier) / multiplier
|
||||
}
|
||||
|
||||
fun String.getHash(type: String = "SHA-256"): String {
|
||||
val hexChars = "0123456789ABCDEF"
|
||||
val bytes = MessageDigest.getInstance(type).digest(this.toByteArray())
|
||||
val result = StringBuilder(bytes.size * 2)
|
||||
bytes.forEach {
|
||||
val i = it.toInt()
|
||||
result.append(hexChars[i shr 4 and 0x0f])
|
||||
result.append(hexChars[i and 0x0f])
|
||||
}
|
||||
return result.toString()
|
||||
}
|
||||
|
||||
fun String.isValidEmail(): Boolean {
|
||||
val expression = "^[\\w.-]+@([\\w\\-]+\\.)+[A-Z]{2,8}$"
|
||||
val pattern = Pattern.compile(expression, Pattern.CASE_INSENSITIVE)
|
||||
return pattern.matcher(this).matches()
|
||||
}
|
||||
|
||||
fun String.isValidIPv4(): Boolean {
|
||||
val ip4 = "^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(\\.(?!\$)|\$)){4}\$"
|
||||
return this.matches(ip4.toRegex())
|
||||
}
|
||||
|
||||
fun String.isValidPort(): Boolean {
|
||||
return this.isNotEmpty() && this.toInt() in 1024..65535
|
||||
}
|
||||
|
||||
fun Float.toPx(): Int = (this * Resources.getSystem().displayMetrics.density).toInt()
|
||||
|
||||
fun AlertDialog.Builder.setEditText(editText: EditText): AlertDialog.Builder {
|
||||
val container = FrameLayout(context)
|
||||
container.addView(editText)
|
||||
val containerParams = FrameLayout.LayoutParams(
|
||||
FrameLayout.LayoutParams.MATCH_PARENT,
|
||||
FrameLayout.LayoutParams.WRAP_CONTENT
|
||||
)
|
||||
val marginHorizontal = 32F
|
||||
val marginTop = 24F
|
||||
containerParams.topMargin = (marginTop / 2).toPx()
|
||||
containerParams.leftMargin = marginHorizontal.toInt()
|
||||
containerParams.rightMargin = marginHorizontal.toInt()
|
||||
container.layoutParams = containerParams
|
||||
val superContainer = FrameLayout(context)
|
||||
superContainer.addView(container)
|
||||
setView(superContainer)
|
||||
return this
|
||||
}
|
||||
|
||||
fun ping(hostname: String, port: Int): Int {
|
||||
val start = System.currentTimeMillis()
|
||||
val socket = Socket()
|
||||
try {
|
||||
socket.connect(InetSocketAddress(hostname, port), 6000)
|
||||
socket.close()
|
||||
} catch (exception: Exception) {
|
||||
exception.printStackTrace()
|
||||
println("Failed to ping: $hostname")
|
||||
return Int.MAX_VALUE
|
||||
}
|
||||
return (System.currentTimeMillis() - start).toInt()
|
||||
}
|
||||
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
package com.rtbishop.look4sat.presentation
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.pm.ActivityInfo
|
||||
import android.os.Bundle
|
||||
import androidx.activity.viewModels
|
||||
@@ -30,6 +31,7 @@ class MainActivity : AppCompatActivity() {
|
||||
|
||||
private val mainViewModel: MainViewModel by viewModels()
|
||||
|
||||
@SuppressLint("SourceLockedOrientationActivity")
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
|
||||
installSplashScreen()
|
||||
|
||||
@@ -129,7 +129,7 @@ class MapFragment : Fragment(R.layout.fragment_map) {
|
||||
textLabelFontSize = 24
|
||||
textLabelBackgroundColor = Color.TRANSPARENT
|
||||
textLabelForegroundColor =
|
||||
ContextCompat.getColor(requireContext(), R.color.themeAccent)
|
||||
ContextCompat.getColor(requireContext(), R.color.accent)
|
||||
setTextIcon(it.key.data.name)
|
||||
setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_CENTER)
|
||||
try {
|
||||
|
||||
@@ -30,8 +30,8 @@ import com.rtbishop.look4sat.R
|
||||
import com.rtbishop.look4sat.databinding.FragmentPassesBinding
|
||||
import com.rtbishop.look4sat.domain.model.DataState
|
||||
import com.rtbishop.look4sat.domain.predict.SatPass
|
||||
import com.rtbishop.look4sat.domain.toTimerString
|
||||
import com.rtbishop.look4sat.presentation.getNavResult
|
||||
import com.rtbishop.look4sat.presentation.toTimerString
|
||||
import com.rtbishop.look4sat.presentation.toast
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ import com.rtbishop.look4sat.data.ISettingsHandler
|
||||
import com.rtbishop.look4sat.databinding.FragmentRadarBinding
|
||||
import com.rtbishop.look4sat.domain.predict.SatPass
|
||||
import com.rtbishop.look4sat.domain.predict.SatPos
|
||||
import com.rtbishop.look4sat.presentation.toTimerString
|
||||
import com.rtbishop.look4sat.domain.toTimerString
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ import kotlin.math.sin
|
||||
|
||||
class RadarView(context: Context) : View(context) {
|
||||
|
||||
private val defaultColor = ContextCompat.getColor(context, R.color.themeAccent)
|
||||
private val defaultColor = ContextCompat.getColor(context, R.color.accent)
|
||||
private val scale = resources.displayMetrics.density
|
||||
private val radarWidth = resources.displayMetrics.widthPixels
|
||||
private val radarRadius = radarWidth * 0.48f
|
||||
@@ -38,7 +38,7 @@ class RadarView(context: Context) : View(context) {
|
||||
private var position: SatPos? = null
|
||||
private var positions: List<SatPos> = emptyList()
|
||||
|
||||
private var radarColor = ContextCompat.getColor(context, R.color.themeLight)
|
||||
private var radarColor = ContextCompat.getColor(context, R.color.textMain)
|
||||
private var radarCircleNum = 3
|
||||
private var radarPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
|
||||
color = radarColor
|
||||
@@ -79,7 +79,7 @@ class RadarView(context: Context) : View(context) {
|
||||
|
||||
private val arrowPath = Path()
|
||||
private var arrowPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
|
||||
color = ContextCompat.getColor(context, R.color.themeAccent)
|
||||
color = ContextCompat.getColor(context, R.color.accent)
|
||||
style = Paint.Style.FILL
|
||||
strokeWidth = strokeSize
|
||||
}
|
||||
@@ -135,7 +135,7 @@ class RadarView(context: Context) : View(context) {
|
||||
isTrackCreated = true
|
||||
}
|
||||
|
||||
canvas.drawColor(ContextCompat.getColor(context, R.color.surfaceCard))
|
||||
canvas.drawColor(ContextCompat.getColor(context, R.color.cardRegular))
|
||||
drawRadarCircle(canvas, cx, cy, radarRadius)
|
||||
drawRadarCross(canvas, cx, cy, radarRadius)
|
||||
drawRadarText(canvas, cx, radarRadius)
|
||||
|
||||
@@ -27,8 +27,8 @@ import com.rtbishop.look4sat.domain.predict.GeoPos
|
||||
import com.rtbishop.look4sat.domain.predict.Predictor
|
||||
import com.rtbishop.look4sat.domain.predict.SatPass
|
||||
import com.rtbishop.look4sat.domain.predict.SatPos
|
||||
import com.rtbishop.look4sat.domain.round
|
||||
import com.rtbishop.look4sat.framework.OrientationHandler
|
||||
import com.rtbishop.look4sat.presentation.round
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.isActive
|
||||
|
||||
+33
-33
@@ -34,11 +34,11 @@ import androidx.navigation.fragment.findNavController
|
||||
import com.rtbishop.look4sat.BuildConfig
|
||||
import com.rtbishop.look4sat.R
|
||||
import com.rtbishop.look4sat.databinding.FragmentSettingsBinding
|
||||
import com.rtbishop.look4sat.domain.isValidIPv4
|
||||
import com.rtbishop.look4sat.domain.isValidPort
|
||||
import com.rtbishop.look4sat.domain.model.DataState
|
||||
import com.rtbishop.look4sat.domain.predict.GeoPos
|
||||
import com.rtbishop.look4sat.presentation.getNavResult
|
||||
import com.rtbishop.look4sat.presentation.isValidIPv4
|
||||
import com.rtbishop.look4sat.presentation.isValidPort
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
||||
@AndroidEntryPoint
|
||||
@@ -94,28 +94,28 @@ class SettingsFragment : Fragment(R.layout.fragment_settings) {
|
||||
|
||||
private fun setupAboutCard() {
|
||||
binding.settingsInfo.aboutVersion.text =
|
||||
String.format(getString(R.string.about_version), BuildConfig.VERSION_NAME)
|
||||
// binding.settingsInfo.aboutBtnGithub.setOnClickListener {
|
||||
// gotoUrl("https://github.com/rt-bishop/Look4Sat/")
|
||||
// }
|
||||
// binding.settingsInfo.aboutBtnDonate.setOnClickListener {
|
||||
// gotoUrl("https://www.buymeacoffee.com/rtbishop")
|
||||
// }
|
||||
// binding.settingsInfo.aboutBtnFdroid.setOnClickListener {
|
||||
// gotoUrl("https://f-droid.org/en/packages/com.rtbishop.look4sat/")
|
||||
// }
|
||||
String.format(getString(R.string.app_version), BuildConfig.VERSION_NAME)
|
||||
binding.settingsGithubBtn.setOnClickListener {
|
||||
gotoUrl("https://github.com/rt-bishop/Look4Sat/")
|
||||
}
|
||||
binding.settingsFab.setOnClickListener {
|
||||
gotoUrl("https://www.buymeacoffee.com/rtbishop")
|
||||
}
|
||||
binding.settingsFdroidBtn.setOnClickListener {
|
||||
gotoUrl("https://f-droid.org/en/packages/com.rtbishop.look4sat/")
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupLocationCard() {
|
||||
setPositionText(viewModel.getStationPosition())
|
||||
binding.settingsLocation.locationBtnGps.setOnClickListener {
|
||||
binding.settingsLocation.positionBtnGps.setOnClickListener {
|
||||
locationRequest.launch(arrayOf(locationFine, locationCoarse))
|
||||
}
|
||||
binding.settingsLocation.locationBtnManual.setOnClickListener {
|
||||
binding.settingsLocation.positionBtnManual.setOnClickListener {
|
||||
val action = SettingsFragmentDirections.actionPrefsToLocation()
|
||||
findNavController().navigate(action)
|
||||
}
|
||||
binding.settingsLocation.locationBtnQth.setOnClickListener {
|
||||
binding.settingsLocation.positionBtnQth.setOnClickListener {
|
||||
val action = SettingsFragmentDirections.actionPrefsToLocator()
|
||||
findNavController().navigate(action)
|
||||
}
|
||||
@@ -136,11 +136,11 @@ class SettingsFragment : Fragment(R.layout.fragment_settings) {
|
||||
binding.settingsData.dataBtnClear.setOnClickListener { viewModel.clearData() }
|
||||
viewModel.entries.observe(viewLifecycleOwner) { number ->
|
||||
val entriesFormat = getString(R.string.fmt_entries)
|
||||
binding.settingsData.dataSatellites.text = String.format(entriesFormat, number)
|
||||
binding.settingsData.dataEntries.text = String.format(entriesFormat, number)
|
||||
}
|
||||
viewModel.radios.observe(viewLifecycleOwner) { number ->
|
||||
val radiosFormat = getString(R.string.fmt_radios)
|
||||
binding.settingsData.dataTransmitters.text = String.format(radiosFormat, number)
|
||||
binding.settingsData.dataRadios.text = String.format(radiosFormat, number)
|
||||
}
|
||||
getNavResult<List<String>>(R.id.nav_settings, "sources") { sources ->
|
||||
viewModel.updateDataFromWeb(sources)
|
||||
@@ -148,22 +148,22 @@ class SettingsFragment : Fragment(R.layout.fragment_settings) {
|
||||
}
|
||||
|
||||
private fun setupTrackingCard() {
|
||||
binding.settingsTracking.trackingSwitch.apply {
|
||||
binding.settingsTracking.remoteSwitch.apply {
|
||||
isChecked = viewModel.getRotatorEnabled()
|
||||
binding.settingsTracking.trackingIp.isEnabled = isChecked
|
||||
binding.settingsTracking.trackingIpEdit.setText(viewModel.getRotatorServer())
|
||||
binding.settingsTracking.trackingPort.isEnabled = isChecked
|
||||
binding.settingsTracking.trackingPortEdit.setText(viewModel.getRotatorPort())
|
||||
binding.settingsTracking.remoteIp.isEnabled = isChecked
|
||||
binding.settingsTracking.remoteIpEdit.setText(viewModel.getRotatorServer())
|
||||
binding.settingsTracking.remotePort.isEnabled = isChecked
|
||||
binding.settingsTracking.remotePortEdit.setText(viewModel.getRotatorPort())
|
||||
setOnCheckedChangeListener { _, isChecked ->
|
||||
viewModel.setRotatorEnabled(isChecked)
|
||||
binding.settingsTracking.trackingIp.isEnabled = isChecked
|
||||
binding.settingsTracking.trackingPort.isEnabled = isChecked
|
||||
binding.settingsTracking.remoteIp.isEnabled = isChecked
|
||||
binding.settingsTracking.remotePort.isEnabled = isChecked
|
||||
}
|
||||
}
|
||||
binding.settingsTracking.trackingIpEdit.doOnTextChanged { text, _, _, _ ->
|
||||
binding.settingsTracking.remoteIpEdit.doOnTextChanged { text, _, _, _ ->
|
||||
if (text.toString().isValidIPv4()) viewModel.setRotatorServer(text.toString())
|
||||
}
|
||||
binding.settingsTracking.trackingPortEdit.doOnTextChanged { text, _, _, _ ->
|
||||
binding.settingsTracking.remotePortEdit.doOnTextChanged { text, _, _, _ ->
|
||||
if (text.toString().isValidPort()) viewModel.setRotatorPort(text.toString())
|
||||
}
|
||||
}
|
||||
@@ -184,32 +184,32 @@ class SettingsFragment : Fragment(R.layout.fragment_settings) {
|
||||
}
|
||||
|
||||
private fun setupWarrantyCard() {
|
||||
binding.settingsWarranty.warrantyThanks.movementMethod = LinkMovementMethod.getInstance()
|
||||
binding.settingsWarranty.warrantyLicense.movementMethod = LinkMovementMethod.getInstance()
|
||||
binding.settingsWarranty.outroThanks.movementMethod = LinkMovementMethod.getInstance()
|
||||
binding.settingsWarranty.outroLicense.movementMethod = LinkMovementMethod.getInstance()
|
||||
}
|
||||
|
||||
private fun setPositionText(geoPos: GeoPos) {
|
||||
val latFormat = getString(R.string.location_lat)
|
||||
val lonFormat = getString(R.string.location_lon)
|
||||
binding.settingsLocation.locationLat.text = String.format(latFormat, geoPos.latitude)
|
||||
binding.settingsLocation.locationLon.text = String.format(lonFormat, geoPos.longitude)
|
||||
binding.settingsLocation.positionLat.text = String.format(latFormat, geoPos.latitude)
|
||||
binding.settingsLocation.positionLon.text = String.format(lonFormat, geoPos.longitude)
|
||||
}
|
||||
|
||||
private fun handleStationPosition(pos: DataState<GeoPos>) {
|
||||
when (pos) {
|
||||
is DataState.Success -> {
|
||||
setPositionText(pos.data)
|
||||
binding.settingsLocation.locationProgress.isIndeterminate = false
|
||||
binding.settingsLocation.positionProgress.isIndeterminate = false
|
||||
viewModel.setPositionHandled()
|
||||
showToast(getString(R.string.pref_pos_success))
|
||||
}
|
||||
is DataState.Error -> {
|
||||
binding.settingsLocation.locationProgress.isIndeterminate = false
|
||||
binding.settingsLocation.positionProgress.isIndeterminate = false
|
||||
viewModel.setPositionHandled()
|
||||
showToast(pos.message.toString())
|
||||
}
|
||||
DataState.Loading -> {
|
||||
binding.settingsLocation.locationProgress.isIndeterminate = true
|
||||
binding.settingsLocation.positionProgress.isIndeterminate = true
|
||||
}
|
||||
DataState.Handled -> {}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user