Initial commit: Конвертор координат GPS → APRS, Maidenhead
- Kotlin + Jetpack Compose (Material 3) - Конвертация в APRS, Maidenhead, DMS форматы - Полноэкранный режим - Иконка приложения - Min SDK: 21, Target SDK: 34 Версия: 1.0.0 Дата: 2026-03-02 Автор: UA1ZBE Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
46
app/build.gradle.kts
Normal file
@@ -0,0 +1,46 @@
|
||||
plugins {
|
||||
id("com.android.application")
|
||||
id("org.jetbrains.kotlin.android")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.example.aprs"
|
||||
compileSdk = 34
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "com.example.aprs"
|
||||
// Jetpack Compose requires API 21+
|
||||
minSdk = 21
|
||||
targetSdk = 34
|
||||
versionCode = 1
|
||||
versionName = "1.0"
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
compose = true
|
||||
}
|
||||
|
||||
composeOptions {
|
||||
kotlinCompilerExtensionVersion = "1.5.3"
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
jvmTarget = "11"
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("androidx.core:core-ktx:1.10.1")
|
||||
implementation("androidx.activity:activity-compose:1.8.0")
|
||||
implementation("androidx.compose.ui:ui:1.5.0")
|
||||
implementation("androidx.compose.ui:ui-graphics:1.5.0")
|
||||
implementation("androidx.compose.material:material:1.5.0")
|
||||
implementation("androidx.compose.material3:material3:1.1.2")
|
||||
implementation("androidx.compose.material:material-icons-extended:1.5.0")
|
||||
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.1")
|
||||
}
|
||||
22
app/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.example.aprs">
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<uses-feature android:name="android.hardware.location.gps" android:required="false" />
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:label="Конвертор координат"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:theme="@style/Theme.APRSApp">
|
||||
<activity android:name="com.example.aprs.MainActivity"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
107
app/src/main/java/com/example/aprs/LocationUtils.kt
Normal file
@@ -0,0 +1,107 @@
|
||||
package com.example.aprs
|
||||
|
||||
import kotlin.math.floor
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.sin
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.atan
|
||||
import kotlin.math.sqrt
|
||||
import kotlin.math.PI
|
||||
import kotlin.math.ln
|
||||
|
||||
object LocationUtils {
|
||||
// Convert decimal degrees to APRS position format: DDMM.MM N / DDDMM.MM E
|
||||
fun toAprs(lat: Double, lon: Double): String {
|
||||
val latHem = if (lat >= 0) "N" else "S"
|
||||
val lonHem = if (lon >= 0) "E" else "W"
|
||||
|
||||
val latAbs = abs(lat)
|
||||
val lonAbs = abs(lon)
|
||||
|
||||
val latDeg = floor(latAbs).toInt()
|
||||
val latMin = (latAbs - latDeg) * 60.0
|
||||
|
||||
val lonDeg = floor(lonAbs).toInt()
|
||||
val lonMin = (lonAbs - lonDeg) * 60.0
|
||||
|
||||
return String.format(
|
||||
"%02d%05.2f%s/%03d%05.2f%s",
|
||||
latDeg,
|
||||
latMin,
|
||||
latHem,
|
||||
lonDeg,
|
||||
lonMin,
|
||||
lonHem
|
||||
)
|
||||
}
|
||||
|
||||
// Maidenhead locator (6 chars) from lat/lon
|
||||
fun toMaidenhead(lat: Double, lon: Double): String {
|
||||
var adjLon = lon + 180.0
|
||||
var adjLat = lat + 90.0
|
||||
|
||||
val fieldLon = (adjLon / 20.0).toInt()
|
||||
val fieldLat = (adjLat / 10.0).toInt()
|
||||
|
||||
val squareLon = ((adjLon % 20) / 2).toInt()
|
||||
val squareLat = ((adjLat % 10) / 1).toInt()
|
||||
|
||||
val subsLon = (((adjLon - fieldLon * 20 - squareLon * 2) * 60) / 5).toInt()
|
||||
val subsLat = (((adjLat - fieldLat * 10 - squareLat * 1) * 60) / 2.5).toInt()
|
||||
|
||||
val a = 'A'.code
|
||||
|
||||
val fieldChars = charArrayOf((a + fieldLon).toChar(), (a + fieldLat).toChar())
|
||||
val squareChars = charArrayOf(('0'.code + squareLon).toChar(), ('0'.code + squareLat).toChar())
|
||||
val subsChars = charArrayOf((a + subsLon).toChar(), (a + subsLat).toChar())
|
||||
|
||||
return String(charArrayOf(fieldChars[0], fieldChars[1], squareChars[0], squareChars[1], subsChars[0], subsChars[1]))
|
||||
}
|
||||
|
||||
// Convert lat/lon to UTM coordinates
|
||||
fun toUTM(lat: Double, lon: Double): String {
|
||||
val k0 = 0.9996
|
||||
val a = 6378137.0
|
||||
val eSquared = 0.00669438
|
||||
val e = sqrt(eSquared)
|
||||
val ePrimeSquared = eSquared / (1 - eSquared)
|
||||
|
||||
val latRad = lat * PI / 180.0
|
||||
val lonRad = lon * PI / 180.0
|
||||
|
||||
val zone = ((lon + 180) / 6).toInt() + 1
|
||||
|
||||
val lonOrigin = (zone - 1) * 6 - 180 + 3
|
||||
val lonOriginRad = lonOrigin * PI / 180.0
|
||||
|
||||
val n = a / sqrt(1 - eSquared * sin(latRad) * sin(latRad))
|
||||
val T = tan(latRad) * tan(latRad)
|
||||
val C = ePrimeSquared * cos(latRad) * cos(latRad)
|
||||
val A = cos(latRad) * (lonRad - lonOriginRad)
|
||||
|
||||
val M = a * ((1 - eSquared / 4 - 3 * eSquared * eSquared / 64 - 5 * eSquared * eSquared * eSquared / 256) * latRad
|
||||
- (3 * eSquared / 8 + 3 * eSquared * eSquared / 32 + 45 * eSquared * eSquared * eSquared / 1024) * sin(2 * latRad)
|
||||
+ (15 * eSquared * eSquared / 256 + 45 * eSquared * eSquared * eSquared / 1024) * sin(4 * latRad)
|
||||
- (35 * eSquared * eSquared * eSquared / 3072) * sin(6 * latRad))
|
||||
|
||||
val UTMEasting = (k0 * n * (A + (1 - T + C) * A * A * A / 6
|
||||
+ (5 - 18 * T + T * T + 72 * C - 58 * ePrimeSquared) * A * A * A * A * A / 120)
|
||||
+ 500000.0).toLong()
|
||||
|
||||
val UTMNorthing = (k0 * (M + n * tan(latRad) * (A * A / 2 + (5 - T + 9 * C + 4 * C * C) * A * A * A * A / 24
|
||||
+ (61 - 58 * T + T * T + 600 * C - 330 * ePrimeSquared) * A * A * A * A * A * A / 720))
|
||||
+ (if (lat < 0) 10000000.0 else 0.0)).toLong()
|
||||
|
||||
val zoneLetter = getUtmZoneLetter(lat, lon)
|
||||
|
||||
return String.format("%d%s %06d %07d", zone, zoneLetter, UTMEasting, UTMNorthing)
|
||||
}
|
||||
|
||||
private fun tan(rad: Double): Double = sin(rad) / cos(rad)
|
||||
|
||||
private fun getUtmZoneLetter(lat: Double, lon: Double): String {
|
||||
val letters = "CDEFGHJKLMNPQRSTUVWXX"
|
||||
val latIndex = ((lat + 80) / 8).toInt().coerceIn(0, letters.length - 1)
|
||||
return letters[latIndex].toString()
|
||||
}
|
||||
}
|
||||
340
app/src/main/java/com/example/aprs/MainActivity.kt
Normal file
@@ -0,0 +1,340 @@
|
||||
package com.example.aprs
|
||||
|
||||
import android.Manifest
|
||||
import android.content.Context
|
||||
import android.location.Location
|
||||
import android.location.LocationListener
|
||||
import android.location.LocationManager
|
||||
import android.os.Bundle
|
||||
import android.view.WindowManager
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.*
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.WindowCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.core.view.WindowInsetsControllerCompat
|
||||
|
||||
var permissionGranted by mutableStateOf(false)
|
||||
|
||||
class MainActivity : ComponentActivity() {
|
||||
|
||||
internal val permissionLauncher = registerForActivityResult(ActivityResultContracts.RequestPermission()) { granted ->
|
||||
permissionGranted = granted
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
// Включаем полноэкранный режим
|
||||
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||
WindowInsetsControllerCompat(window, window.decorView).apply {
|
||||
hide(WindowInsetsCompat.Type.statusBars())
|
||||
hide(WindowInsetsCompat.Type.navigationBars())
|
||||
systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
|
||||
}
|
||||
|
||||
// Делаем контент за статус-баром и навигацией
|
||||
window.setFlags(
|
||||
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
|
||||
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
|
||||
)
|
||||
|
||||
setContent {
|
||||
MaterialTheme(
|
||||
colorScheme = darkColorScheme()
|
||||
) {
|
||||
Surface(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
color = Color(0xFF0D0D0D)
|
||||
) {
|
||||
CoordinateConverterScreen(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun CoordinateConverterScreen(activity: MainActivity) {
|
||||
var location by remember { mutableStateOf<Location?>(null) }
|
||||
var isUpdating by remember { mutableStateOf(false) }
|
||||
val context = activity.applicationContext
|
||||
val scrollState = rememberScrollState()
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
val granted = ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == android.content.pm.PackageManager.PERMISSION_GRANTED
|
||||
permissionGranted = granted
|
||||
if (!granted) {
|
||||
activity.permissionLauncher.launch(Manifest.permission.ACCESS_FINE_LOCATION)
|
||||
}
|
||||
}
|
||||
|
||||
DisposableEffect(permissionGranted) {
|
||||
val lm = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
|
||||
val listener = object : LocationListener {
|
||||
override fun onLocationChanged(loc: Location) {
|
||||
location = loc
|
||||
isUpdating = false
|
||||
}
|
||||
|
||||
override fun onProviderEnabled(provider: String) {}
|
||||
override fun onProviderDisabled(provider: String) {}
|
||||
override fun onStatusChanged(provider: String?, status: Int, extras: Bundle?) {}
|
||||
}
|
||||
|
||||
if (permissionGranted) {
|
||||
try {
|
||||
isUpdating = true
|
||||
val last = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER) ?: lm.getLastKnownLocation(LocationManager.NETWORK_PROVIDER)
|
||||
if (last != null) {
|
||||
location = last
|
||||
isUpdating = false
|
||||
}
|
||||
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000L, 0f, listener)
|
||||
} catch (e: SecurityException) {
|
||||
isUpdating = false
|
||||
}
|
||||
}
|
||||
|
||||
onDispose {
|
||||
lm.removeUpdates(listener)
|
||||
}
|
||||
}
|
||||
|
||||
val lat = location?.latitude ?: 0.0
|
||||
val lon = location?.longitude ?: 0.0
|
||||
val hasLocation = location != null
|
||||
|
||||
val aprs = if (hasLocation) LocationUtils.toAprs(lat, lon) else "—"
|
||||
val maiden = if (hasLocation) LocationUtils.toMaidenhead(lat, lon) else "—"
|
||||
val dmsLat = if (hasLocation) toDMS(lat, true) else "—"
|
||||
val dmsLon = if (hasLocation) toDMS(lon, false) else "—"
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.verticalScroll(scrollState)
|
||||
.padding(16.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
// Header
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
Text(
|
||||
text = "Конвертор координат",
|
||||
fontSize = 28.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = Color.White
|
||||
)
|
||||
Text(
|
||||
text = "GPS → APRS, Maidenhead",
|
||||
fontSize = 14.sp,
|
||||
color = Color.Gray,
|
||||
modifier = Modifier.padding(top = 4.dp)
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
|
||||
// Status indicator
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.clip(RoundedCornerShape(16.dp))
|
||||
.background(
|
||||
if (isUpdating) Brush.horizontalGradient(listOf(Color(0xFFFFA500), Color(0xFFFF6600)))
|
||||
else if (hasLocation) Brush.horizontalGradient(listOf(Color(0xFF00C853), Color(0xFF69F0AE)))
|
||||
else Brush.horizontalGradient(listOf(Color(0xFFB0BEC5), Color(0xFF78909C)))
|
||||
)
|
||||
.padding(horizontal = 16.dp, vertical = 8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Icon(
|
||||
imageVector = if (isUpdating) Icons.Default.Refresh else if (hasLocation) Icons.Default.CheckCircle else Icons.Default.LocationOff,
|
||||
contentDescription = null,
|
||||
tint = Color.White,
|
||||
modifier = Modifier.size(20.dp)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Text(
|
||||
text = if (isUpdating) "Получение GPS..." else if (hasLocation) "GPS активен" else "Нет GPS",
|
||||
color = Color.White,
|
||||
fontWeight = FontWeight.Medium
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
|
||||
// Decimal coordinates card
|
||||
CoordinateCard(
|
||||
title = "Десятичные координаты",
|
||||
icon = Icons.Default.MyLocation,
|
||||
gradient = listOf(Color(0xFF2196F3), Color(0xFF64B5F6))
|
||||
) {
|
||||
CoordinateRow(label = "Широта", value = if (hasLocation) String.format("%.6f°", lat) else "—")
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
CoordinateRow(label = "Долгота", value = if (hasLocation) String.format("%.6f°", lon) else "—")
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
|
||||
// DMS coordinates card
|
||||
CoordinateCard(
|
||||
title = "Градусы, минуты, секунды",
|
||||
icon = Icons.Default.Place,
|
||||
gradient = listOf(Color(0xFF9C27B0), Color(0xFFBA68C8))
|
||||
) {
|
||||
CoordinateRow(label = "Широта", value = dmsLat)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
CoordinateRow(label = "Долгота", value = dmsLon)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
|
||||
// APRS card
|
||||
CoordinateCard(
|
||||
title = "APRS формат",
|
||||
icon = Icons.Default.Radio,
|
||||
gradient = listOf(Color(0xFFFF5722), Color(0xFFFF8A65))
|
||||
) {
|
||||
Text(
|
||||
text = aprs,
|
||||
fontSize = 16.sp,
|
||||
fontFamily = androidx.compose.ui.text.font.FontFamily.Monospace,
|
||||
color = Color(0xFFFFCCBC),
|
||||
modifier = Modifier.padding(vertical = 8.dp)
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
|
||||
// Maidenhead card
|
||||
CoordinateCard(
|
||||
title = "Maidenhead (QTH локатор)",
|
||||
icon = Icons.Default.GridOn,
|
||||
gradient = listOf(Color(0xFF00BCD4), Color(0xFF4DD0E1))
|
||||
) {
|
||||
Text(
|
||||
text = maiden,
|
||||
fontSize = 24.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontFamily = androidx.compose.ui.text.font.FontFamily.Monospace,
|
||||
color = Color(0xFFB2EBF2),
|
||||
modifier = Modifier.padding(vertical = 8.dp)
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(48.dp))
|
||||
|
||||
// Footer
|
||||
Text(
|
||||
text = "© 2026 UA1ZBE",
|
||||
fontSize = 14.sp,
|
||||
fontWeight = FontWeight.Medium,
|
||||
color = Color(0xFF9C27B0)
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun CoordinateCard(
|
||||
title: String,
|
||||
icon: ImageVector,
|
||||
gradient: List<Color>,
|
||||
content: @Composable ColumnScope.() -> Unit
|
||||
) {
|
||||
Card(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
colors = CardDefaults.cardColors(containerColor = Color(0xFF1A1A1A))
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp)
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(40.dp)
|
||||
.clip(RoundedCornerShape(12.dp))
|
||||
.background(Brush.horizontalGradient(gradient)),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Icon(
|
||||
imageVector = icon,
|
||||
contentDescription = null,
|
||||
tint = Color.White,
|
||||
modifier = Modifier.size(22.dp)
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.width(12.dp))
|
||||
Text(
|
||||
text = title,
|
||||
fontSize = 16.sp,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
color = Color.White
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
content()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun CoordinateRow(label: String, value: String) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(
|
||||
text = label,
|
||||
fontSize = 14.sp,
|
||||
color = Color.Gray
|
||||
)
|
||||
Text(
|
||||
text = value,
|
||||
fontSize = 16.sp,
|
||||
fontWeight = FontWeight.Medium,
|
||||
color = Color.White,
|
||||
fontFamily = androidx.compose.ui.text.font.FontFamily.Monospace
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun toDMS(coordinate: Double, isLatitude: Boolean): String {
|
||||
val abs = kotlin.math.abs(coordinate)
|
||||
val deg = abs.toInt()
|
||||
val minFloat = (abs - deg) * 60
|
||||
val min = minFloat.toInt()
|
||||
val sec = (minFloat - min) * 60
|
||||
val direction = when {
|
||||
isLatitude -> if (coordinate >= 0) "N" else "S"
|
||||
else -> if (coordinate >= 0) "E" else "W"
|
||||
}
|
||||
return String.format("%d° %d' %.2f\" %s", deg, min, sec, direction)
|
||||
}
|
||||
5
app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
BIN
app/src/main/res/mipmap-hdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 7.4 KiB |
BIN
app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
Normal file
|
After Width: | Height: | Size: 204 KiB |
BIN
app/src/main/res/mipmap-mdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
BIN
app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
Normal file
|
After Width: | Height: | Size: 204 KiB |
BIN
app/src/main/res/mipmap-xhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
Normal file
|
After Width: | Height: | Size: 204 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
Normal file
|
After Width: | Height: | Size: 204 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 41 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
Normal file
|
After Width: | Height: | Size: 204 KiB |
4
app/src/main/res/values/ic_launcher_background.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="ic_launcher_background">#1A1A1A</color>
|
||||
</resources>
|
||||
4
app/src/main/res/values/strings.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">Конвертор координат</string>
|
||||
</resources>
|
||||
12
app/src/main/res/values/themes.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<style name="Theme.APRSApp" parent="android:Theme.Material.Light.NoActionBar">
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:navigationBarColor">@android:color/transparent</item>
|
||||
<item name="android:windowFullscreen">true</item>
|
||||
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
||||
<item name="android:enforceNavigationBarContrast">false</item>
|
||||
<item name="android:enforceStatusBarContrast">false</item>
|
||||
</style>
|
||||
</resources>
|
||||