commit cc0c4ae9344d5e4f29784b1a3aa8470d7ef97afb Author: PoliEcho Date: Mon Jan 19 16:45:49 2026 +0100 init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..aa724b7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild +.cxx +local.properties diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..9b3f131 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +MHD run Pathfinder \ No newline at end of file diff --git a/.idea/AndroidProjectSystem.xml b/.idea/AndroidProjectSystem.xml new file mode 100644 index 0000000..4a53bee --- /dev/null +++ b/.idea/AndroidProjectSystem.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..7643783 --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,123 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..79ee123 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..b86273d --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/copilot.data.migration.agent.xml b/.idea/copilot.data.migration.agent.xml new file mode 100644 index 0000000..4ea72a9 --- /dev/null +++ b/.idea/copilot.data.migration.agent.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/copilot.data.migration.ask.xml b/.idea/copilot.data.migration.ask.xml new file mode 100644 index 0000000..7ef04e2 --- /dev/null +++ b/.idea/copilot.data.migration.ask.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/copilot.data.migration.ask2agent.xml b/.idea/copilot.data.migration.ask2agent.xml new file mode 100644 index 0000000..1f2ea11 --- /dev/null +++ b/.idea/copilot.data.migration.ask2agent.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/copilot.data.migration.edit.xml b/.idea/copilot.data.migration.edit.xml new file mode 100644 index 0000000..8648f94 --- /dev/null +++ b/.idea/copilot.data.migration.edit.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml new file mode 100644 index 0000000..946bea8 --- /dev/null +++ b/.idea/deploymentTargetSelector.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/deviceManager.xml b/.idea/deviceManager.xml new file mode 100644 index 0000000..91f9558 --- /dev/null +++ b/.idea/deviceManager.xml @@ -0,0 +1,13 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..639c779 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..7061a0d --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,61 @@ + + + + \ No newline at end of file diff --git a/.idea/markdown.xml b/.idea/markdown.xml new file mode 100644 index 0000000..c61ea33 --- /dev/null +++ b/.idea/markdown.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/.idea/migrations.xml b/.idea/migrations.xml new file mode 100644 index 0000000..f8051a6 --- /dev/null +++ b/.idea/migrations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..b2c751a --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..16660f1 --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,17 @@ + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts new file mode 100644 index 0000000..2ec1bc6 --- /dev/null +++ b/app/build.gradle.kts @@ -0,0 +1,62 @@ +plugins { + alias(libs.plugins.android.application) + alias(libs.plugins.kotlin.compose) + alias(libs.plugins.kotlin.serialization) +} + +android { + namespace = "org.pupes.mhdrunpathfinder" + compileSdk { + version = release(36) + } + + defaultConfig { + applicationId = "org.pupes.mhdrunpathfinder" + minSdk = 29 + targetSdk = 36 + versionCode = 1 + versionName = "1.0" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + buildFeatures { + compose = true + buildConfig = true + } +} + +dependencies { + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.lifecycle.runtime.ktx) + implementation(libs.androidx.activity.compose) + implementation(platform(libs.androidx.compose.bom)) + implementation(libs.androidx.compose.ui) + implementation(libs.androidx.compose.ui.graphics) + implementation(libs.androidx.compose.ui.tooling.preview) + implementation(libs.androidx.compose.material3) + implementation("ovh.plrapps:mapcompose:3.2.3") + implementation("com.squareup.okhttp3:okhttp:4.12.0") + implementation(libs.kotlinx.serialization.json) + implementation(libs.androidx.appcompat) + testImplementation(libs.junit) + androidTestImplementation(libs.androidx.junit) + androidTestImplementation(libs.androidx.espresso.core) + androidTestImplementation(platform(libs.androidx.compose.bom)) + androidTestImplementation(libs.androidx.compose.ui.test.junit4) + debugImplementation(libs.androidx.compose.ui.tooling) + debugImplementation(libs.androidx.compose.ui.test.manifest) +} \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/app/src/androidTest/java/org/pupes/mhdrunpathfinder/ExampleInstrumentedTest.kt b/app/src/androidTest/java/org/pupes/mhdrunpathfinder/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..9d55eee --- /dev/null +++ b/app/src/androidTest/java/org/pupes/mhdrunpathfinder/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package org.pupes.mhdrunpathfinder + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("org.pupes.mhdrunpathfinder", appContext.packageName) + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..d9524f9 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/org/pupes/mhdrunpathfinder/HaukUtils.kt b/app/src/main/java/org/pupes/mhdrunpathfinder/HaukUtils.kt new file mode 100644 index 0000000..7263b28 --- /dev/null +++ b/app/src/main/java/org/pupes/mhdrunpathfinder/HaukUtils.kt @@ -0,0 +1,74 @@ +package org.pupes.mhdrunpathfinder + +import android.app.Activity +import android.os.Handler +import android.os.Looper +import android.widget.Toast +import kotlinx.serialization.json.Json +import okhttp3.OkHttpClient +import ovh.plrapps.mapcompose.api.moveMarker +import java.net.URL + +// OkHttpClient for making HTTP requests +val httpClient = OkHttpClient.Builder() + .build() + +private val HaukMainHandler = Handler(Looper.getMainLooper()) +private var HaukTrackingThread: Thread? = null +private var HaukIsTracking = false + +private fun fetchHaukPosition(haukUrl: String, callee: Activity) { + try { + val url = URL(haukUrl) + val targetId = url.toString().substringAfter("?") + + val request = okhttp3.Request.Builder() + .url("${url.protocol}://${url.host}/api/fetch.php?id=$targetId") + .header("User-Agent", "${BuildConfig.APPLICATION_ID}/${BuildConfig.VERSION_NAME} (Android)") + .build() + + httpClient.newCall(request).execute().use { response -> + var message = if (response.isSuccessful) { + response.body?.string() ?: "Empty response" + } else { + "Error: ${response.code} ${response.message}" + } + + message = "{" + message.substringAfter("{"); + val hauk_response = Json.decodeFromString(message) + + HaukMainHandler.post { + mapState.moveMarker("target_position", x = longitudeToXNormalized(hauk_response.points.last()[1]), y = latitudeToYNormalized(hauk_response.points.last()[0])) + } + + } + } catch (e: Exception) { + // Post UI update to main thread + HaukMainHandler.post { + Toast.makeText(callee, e.message ?: "Unknown error", Toast.LENGTH_LONG).show() + } + } +} + +// Start the timer with a URL: +fun startHaukTracking(url: String, callee: Activity) { + if (HaukIsTracking) return + + HaukIsTracking = true + HaukTrackingThread = Thread { + while (HaukIsTracking) { + fetchHaukPosition(url, callee) + try { + Thread.sleep(1000) // Wait 1 second between requests + } catch (e: InterruptedException) { + break + } + } + }.apply { start() } +} + +fun stopHaukTracking() { + HaukIsTracking = false + HaukTrackingThread?.interrupt() + HaukTrackingThread = null +} \ No newline at end of file diff --git a/app/src/main/java/org/pupes/mhdrunpathfinder/Helpers.kt b/app/src/main/java/org/pupes/mhdrunpathfinder/Helpers.kt new file mode 100644 index 0000000..8635262 --- /dev/null +++ b/app/src/main/java/org/pupes/mhdrunpathfinder/Helpers.kt @@ -0,0 +1,25 @@ +package org.pupes.mhdrunpathfinder + +import kotlin.math.PI +import kotlin.math.ln +import kotlin.math.tan + +fun longitudeToXNormalized(longitude: Double): Double { + return (longitude + 180.0) / 360.0 +} + + +fun latitudeToYNormalized(latitude: Double): Double { + // Clamp latitude to Web Mercator bounds + val lat = latitude.coerceIn(-85.05112878, 85.05112878) + + // Convert to radians + val latRad = lat * PI / 180.0 + + // Web Mercator projection formula + val mercatorY = ln(tan(PI / 4.0 + latRad / 2.0)) + + // Normalize to 0.0 - 1.0 range + // The mercator Y range is approximately -PI to PI + return 0.5 - (mercatorY / (2.0 * PI)) +} \ No newline at end of file diff --git a/app/src/main/java/org/pupes/mhdrunpathfinder/LocationUtils.kt b/app/src/main/java/org/pupes/mhdrunpathfinder/LocationUtils.kt new file mode 100644 index 0000000..8526106 --- /dev/null +++ b/app/src/main/java/org/pupes/mhdrunpathfinder/LocationUtils.kt @@ -0,0 +1,162 @@ +package org.pupes.mhdrunpathfinder + +import android.Manifest +import android.app.Activity +import android.content.Context +import android.content.pm.PackageManager +import android.location.Location +import android.location.LocationListener +import android.location.LocationManager +import android.os.Handler +import android.os.Looper +import android.widget.Toast +import androidx.core.app.ActivityCompat +import ovh.plrapps.mapcompose.api.moveMarker + +// Handler for main thread operations +private val LocationMainHandler = Handler(Looper.getMainLooper()) +private var locationManager: LocationManager? = null +private var locationListener: LocationListener? = null +private var isLocationTracking = false + +// Location update configuration +private const val MIN_TIME_BETWEEN_UPDATES = 1000L // 1 second in milliseconds +private const val MIN_DISTANCE_CHANGE = 0f // 0 meters - update on any movement + +// LocationListener callback +private val createLocationListener: (Activity) -> LocationListener = { callee -> + LocationListener { location -> + handleLocationUpdate(location, callee) + } +} + +private fun handleLocationUpdate(location: Location, callee: Activity) { + try { + val normalizedX = longitudeToXNormalized(location.longitude) + val normalizedY = latitudeToYNormalized(location.latitude) + + // Update marker on main thread + LocationMainHandler.post { + try { + mapState.moveMarker( + "current_position", + x = normalizedX, + y = normalizedY + ) + } catch (e: Exception) { + // Marker might not exist yet, silently ignore + } + } + } catch (e: Exception) { + LocationMainHandler.post { + Toast.makeText(callee, "Location error: ${e.message}", Toast.LENGTH_SHORT).show() + } + } +} + +// Check if location permissions are granted +private fun hasLocationPermissions(context: Context): Boolean { + return ActivityCompat.checkSelfPermission( + context, + Manifest.permission.ACCESS_FINE_LOCATION + ) == PackageManager.PERMISSION_GRANTED || + ActivityCompat.checkSelfPermission( + context, + Manifest.permission.ACCESS_COARSE_LOCATION + ) == PackageManager.PERMISSION_GRANTED +} + +// Start continuous location tracking +fun startLocationTracking(callee: Activity) { + if (isLocationTracking) { + Toast.makeText(callee, "Location tracking already active", Toast.LENGTH_SHORT).show() + return + } + + if (!hasLocationPermissions(callee)) { + Toast.makeText(callee, "Location permissions not granted", Toast.LENGTH_LONG).show() + // Request permissions + ActivityCompat.requestPermissions( + callee, + arrayOf( + Manifest.permission.ACCESS_FINE_LOCATION, + Manifest.permission.ACCESS_COARSE_LOCATION + ), + LOCATION_PERMISSION_REQUEST_CODE + ) + return + } + + try { + locationManager = callee.getSystemService(Context.LOCATION_SERVICE) as LocationManager + locationListener = createLocationListener(callee) + + // Try GPS first, then network provider + val providers = listOf( + LocationManager.GPS_PROVIDER, + LocationManager.NETWORK_PROVIDER + ) + + var providerFound = false + for (provider in providers) { + if (locationManager?.isProviderEnabled(provider) == true) { + try { + locationManager?.requestLocationUpdates( + provider, + MIN_TIME_BETWEEN_UPDATES, + MIN_DISTANCE_CHANGE, + locationListener!!, + Looper.getMainLooper() + ) + providerFound = true + + // Get last known location and update immediately + locationManager?.getLastKnownLocation(provider)?.let { location -> + handleLocationUpdate(location, callee) + } + + break + } catch (e: SecurityException) { + // Permission denied + Toast.makeText(callee, "Location permission denied", Toast.LENGTH_LONG).show() + return + } + } + } + + if (!providerFound) { + Toast.makeText(callee, "No location provider available. Please enable GPS or network location", Toast.LENGTH_LONG).show() + return + } + + isLocationTracking = true + Toast.makeText(callee, "Location tracking started", Toast.LENGTH_SHORT).show() + + } catch (e: Exception) { + Toast.makeText(callee, "Failed to start location tracking: ${e.message}", Toast.LENGTH_LONG).show() + } +} + +// Stop location tracking +fun stopLocationTracking() { + if (!isLocationTracking) return + + try { + locationListener?.let { listener -> + locationManager?.removeUpdates(listener) + } + locationListener = null + locationManager = null + isLocationTracking = false + } catch (e: Exception) { + // Silently handle cleanup errors + } +} + +// Get current tracking status +fun isLocationTrackingActive(): Boolean { + return isLocationTracking +} + +// Permission request code +const val LOCATION_PERMISSION_REQUEST_CODE = 1001 diff --git a/app/src/main/java/org/pupes/mhdrunpathfinder/MainActivity.kt b/app/src/main/java/org/pupes/mhdrunpathfinder/MainActivity.kt new file mode 100644 index 0000000..45cbbd0 --- /dev/null +++ b/app/src/main/java/org/pupes/mhdrunpathfinder/MainActivity.kt @@ -0,0 +1,153 @@ +package org.pupes.mhdrunpathfinder + +import android.R.attr.onClick +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.size +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedButton +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import kotlinx.serialization.Serializable +import ovh.plrapps.mapcompose.api.addLayer +import ovh.plrapps.mapcompose.api.addMarker +import ovh.plrapps.mapcompose.api.scrollTo +import ovh.plrapps.mapcompose.core.TileStreamProvider +import ovh.plrapps.mapcompose.ui.MapUI +import ovh.plrapps.mapcompose.ui.state.MapState +import java.net.URL + +@Serializable +data class HaukResponse( + val type: Int, + val expire: Long, + val serverTime: Double, + val interval: Int, + val points: List>, + val encrypted: Boolean, + val salt: String? = null +) + +// MapState configuration for OpenStreetMap +// Max zoom level is 18, tile size is 256x256 +// At zoom level 18, there are 2^18 = 262144 tiles in each dimension +// So fullWidth/Height = 256 * 262144 +val mapState = MapState( + levelCount = 19, // zoom levels 0-18 + fullWidth = 67108864, // 256 * 2^18 + fullHeight = 67108864, + tileSize = 256 +) + + + + +class MainActivity : ComponentActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + + setContent { + MaterialTheme { + Surface( + modifier = Modifier.fillMaxSize(), + color = MaterialTheme.colorScheme.background + ) { + OpenStreetMapScreen() + AddButton() + } + } + } + startHaukTracking("https://hauk.limit6.eu/?M4SJ-SH7I",this) + startLocationTracking(this) + + } + + override fun onDestroy() { + super.onDestroy() + stopHaukTracking() + stopLocationTracking() + } +} + +@Preview +@Composable +// When a composable with parameters is used with @Preview, +// a default value must be provided for the preview to render. +fun AddButton(onClick: () -> Unit = {}) { + OutlinedButton(onClick = { onClick() }) { + Text("Outlined") + } +} + +@Preview +@Composable +fun OpenStreetMapScreen() { + // Create tile stream provider for OpenStreetMap with User-Agent + val tileStreamProvider = TileStreamProvider { row, col, zoomLvl -> + try { + val url = URL("https://tile.openstreetmap.org/$zoomLvl/$col/$row.png") + val connection = url.openConnection() + // Set User-Agent header as required by OSM tile usage policy + // Format: AppId/Version (Platform) (Contact: email) + val userAgent = "${BuildConfig.APPLICATION_ID}/${BuildConfig.VERSION_NAME} (Android) (Contact: poliecho@pupes.org)" + connection.setRequestProperty("User-Agent", userAgent) + connection.getInputStream() + } catch (e: Exception) { + e.printStackTrace() + null + } + } + + + + /* Add a marker at the center of the map */ + mapState.addMarker("target_position", x = longitudeToXNormalized(14.4058031), y = latitudeToYNormalized(50.0756083)) { + Icon( + painter = painterResource(id = R.drawable.target), + contentDescription = null, + modifier = Modifier.size(20.dp), + tint = Color(0xFFFF0000) + ) + } + + /* Add a marker for current position */ + mapState.addMarker("current_position", x = longitudeToXNormalized(14.4378), y = latitudeToYNormalized(50.0755)) { + Icon( + painter = painterResource(id = R.drawable.user_location), + contentDescription = null, + modifier = Modifier.size(20.dp), + tint = Color(0xFF0000FF) // Blue color for current position + ) + } + + // Add the tile layer and set initial position + LaunchedEffect(Unit) { + mapState.addLayer(tileStreamProvider) + + // Scroll to Prague, Czech Republic + // Prague coordinates: latitude 50.0755, longitude 14.4378 + val normalizedX = longitudeToXNormalized(14.4378) + val normalizedY = latitudeToYNormalized(50.0755) + + // Use a higher scale to zoom in more (closer to 1.0 = more zoomed in) + mapState.scrollTo(normalizedX, normalizedY, destScale = 0.8) + } + + // Display the map + MapUI( + modifier = Modifier.fillMaxSize(), + state = mapState + ) +} + diff --git a/app/src/main/java/org/pupes/mhdrunpathfinder/ui/theme/Color.kt b/app/src/main/java/org/pupes/mhdrunpathfinder/ui/theme/Color.kt new file mode 100644 index 0000000..01096d7 --- /dev/null +++ b/app/src/main/java/org/pupes/mhdrunpathfinder/ui/theme/Color.kt @@ -0,0 +1,11 @@ +package org.pupes.mhdrunpathfinder.ui.theme + +import androidx.compose.ui.graphics.Color + +val Purple80 = Color(0xFFD0BCFF) +val PurpleGrey80 = Color(0xFFCCC2DC) +val Pink80 = Color(0xFFEFB8C8) + +val Purple40 = Color(0xFF6650a4) +val PurpleGrey40 = Color(0xFF625b71) +val Pink40 = Color(0xFF7D5260) \ No newline at end of file diff --git a/app/src/main/java/org/pupes/mhdrunpathfinder/ui/theme/Theme.kt b/app/src/main/java/org/pupes/mhdrunpathfinder/ui/theme/Theme.kt new file mode 100644 index 0000000..0fcd550 --- /dev/null +++ b/app/src/main/java/org/pupes/mhdrunpathfinder/ui/theme/Theme.kt @@ -0,0 +1,58 @@ +package org.pupes.mhdrunpathfinder.ui.theme + +import android.app.Activity +import android.os.Build +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.dynamicDarkColorScheme +import androidx.compose.material3.dynamicLightColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalContext + +private val DarkColorScheme = darkColorScheme( + primary = Purple80, + secondary = PurpleGrey80, + tertiary = Pink80 +) + +private val LightColorScheme = lightColorScheme( + primary = Purple40, + secondary = PurpleGrey40, + tertiary = Pink40 + + /* Other default colors to override + background = Color(0xFFFFFBFE), + surface = Color(0xFFFFFBFE), + onPrimary = Color.White, + onSecondary = Color.White, + onTertiary = Color.White, + onBackground = Color(0xFF1C1B1F), + onSurface = Color(0xFF1C1B1F), + */ +) + +@Composable +fun MHDRunPathfinderTheme( + darkTheme: Boolean = isSystemInDarkTheme(), + // Dynamic color is available on Android 12+ + dynamicColor: Boolean = true, + content: @Composable () -> Unit +) { + val colorScheme = when { + dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { + val context = LocalContext.current + if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) + } + + darkTheme -> DarkColorScheme + else -> LightColorScheme + } + + MaterialTheme( + colorScheme = colorScheme, + typography = Typography, + content = content + ) +} \ No newline at end of file diff --git a/app/src/main/java/org/pupes/mhdrunpathfinder/ui/theme/Type.kt b/app/src/main/java/org/pupes/mhdrunpathfinder/ui/theme/Type.kt new file mode 100644 index 0000000..a226350 --- /dev/null +++ b/app/src/main/java/org/pupes/mhdrunpathfinder/ui/theme/Type.kt @@ -0,0 +1,34 @@ +package org.pupes.mhdrunpathfinder.ui.theme + +import androidx.compose.material3.Typography +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.sp + +// Set of Material typography styles to start with +val Typography = Typography( + bodyLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 16.sp, + lineHeight = 24.sp, + letterSpacing = 0.5.sp + ) + /* Other default text styles to override + titleLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 22.sp, + lineHeight = 28.sp, + letterSpacing = 0.sp + ), + labelSmall = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Medium, + fontSize = 11.sp, + lineHeight = 16.sp, + letterSpacing = 0.5.sp + ) + */ +) \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/target.xml b/app/src/main/res/drawable/target.xml new file mode 100644 index 0000000..47c9e4f --- /dev/null +++ b/app/src/main/res/drawable/target.xml @@ -0,0 +1,26 @@ + + + + + + + diff --git a/app/src/main/res/drawable/user_location.xml b/app/src/main/res/drawable/user_location.xml new file mode 100644 index 0000000..0ccd866 --- /dev/null +++ b/app/src/main/res/drawable/user_location.xml @@ -0,0 +1,26 @@ + + + + + + + diff --git a/app/src/main/res/mipmap-anydpi/ic_launcher.xml b/app/src/main/res/mipmap-anydpi/ic_launcher.xml new file mode 100644 index 0000000..6f3b755 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi/ic_launcher.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml new file mode 100644 index 0000000..6f3b755 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/app/src/main/res/mipmap-hdpi/ic_launcher.webp new file mode 100644 index 0000000..c209e78 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp new file mode 100644 index 0000000..b2dfe3d Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/app/src/main/res/mipmap-mdpi/ic_launcher.webp new file mode 100644 index 0000000..4f0f1d6 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp new file mode 100644 index 0000000..62b611d Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp new file mode 100644 index 0000000..948a307 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..1b9a695 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp new file mode 100644 index 0000000..28d4b77 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9287f50 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp new file mode 100644 index 0000000..aa7d642 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9126ae3 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..f8c6127 --- /dev/null +++ b/app/src/main/res/values/colors.xml @@ -0,0 +1,10 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..a28da68 --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + MHD run Pathfinder + \ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml new file mode 100644 index 0000000..7bef42c --- /dev/null +++ b/app/src/main/res/values/themes.xml @@ -0,0 +1,5 @@ + + + +