Various changes to layouts, styles, strings and drawables

This commit is contained in:
Arty Bishop committed 2022-02-20 20:01:47 +00:00
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
@@ -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 -> {}
}