First Commit of WearSignalK2

This commit is contained in:
2023-11-22 13:43:26 +01:00
commit 0f30f0206f
20 changed files with 958 additions and 0 deletions

81
app/build.gradle.kts Normal file
View File

@@ -0,0 +1,81 @@
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
}
android {
namespace = "net.dalsgaard.wearsignalk"
compileSdk = 33
defaultConfig {
applicationId = "net.dalsgaard.wearsignalk"
minSdk = 30
targetSdk = 33
versionCode = 1
versionName = "1.0"
vectorDrawables {
useSupportLibrary = true
}
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}
buildFeatures {
compose = true
}
composeOptions {
kotlinCompilerExtensionVersion = "1.4.3"
}
packaging {
resources {
excludes += "/META-INF/{AL2.0,LGPL2.1}"
}
}
}
dependencies {
implementation("androidx.core:core-ktx:1.9.0")
implementation("com.google.android.gms:play-services-wearable:18.1.0")
implementation("androidx.percentlayout:percentlayout:1.0.0")
implementation("androidx.legacy:legacy-support-v4:1.0.0")
implementation("androidx.recyclerview:recyclerview:1.3.1")
implementation(platform("androidx.compose:compose-bom:2023.03.00"))
implementation("androidx.compose.ui:ui")
implementation("androidx.compose.ui:ui-tooling-preview")
implementation("androidx.wear.compose:compose-material:1.0.0")
implementation("androidx.wear.compose:compose-foundation:1.0.0")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.5.1")
implementation("androidx.activity:activity-compose:1.5.1")
androidTestImplementation(platform("androidx.compose:compose-bom:2023.03.00"))
androidTestImplementation("androidx.compose.ui:ui-test-junit4")
debugImplementation("androidx.compose.ui:ui-tooling")
debugImplementation("androidx.compose.ui:ui-test-manifest")
// websocket functionality
implementation("io.ktor:ktor-client-core:2.3.4")
implementation("io.ktor:ktor-client-cio:2.3.4")
implementation("io.ktor:ktor-client-websockets:2.3.4")
// jsonpath functionality
implementation("com.nfeld.jsonpathkt:jsonpathkt:2.0.1")
// kotlin flow functionality for state propagation
implementation("androidx.lifecycle:lifecycle-runtime-compose:2.6.2")
}

21
app/proguard-rules.pro vendored Normal file
View File

@@ -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

View File

@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-feature android:name="android.hardware.type.watch" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@android:style/Theme.DeviceDefault">
<uses-library
android:name="com.google.android.wearable"
android:required="true" />
<!--
Set to true if your app is Standalone, that is, it does not require the handheld
app to run.
-->
<meta-data
android:name="com.google.android.wearable.standalone"
android:value="true" />
<activity
android:name=".presentation.MainActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@android:style/Theme.DeviceDefault">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@@ -0,0 +1,215 @@
package net.dalsgaard.wearsignalk.connection
import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.fasterxml.jackson.databind.JsonNode
import com.nfeld.jsonpathkt.JsonPath
import com.nfeld.jsonpathkt.extension.read
import io.ktor.client.HttpClient
import io.ktor.client.plugins.HttpTimeout
import io.ktor.client.plugins.websocket.WebSockets
import io.ktor.client.plugins.websocket.webSocket
import io.ktor.http.HttpMethod
import io.ktor.websocket.send
import io.ktor.websocket.Frame
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.runBlocking
import java.time.Instant
import kotlin.concurrent.thread
private const val TAG = "SignalKConnection"
private const val SUBSCRIPTION = "{\n" +
" \"context\": \"vessels.self\",\n" +
" \"subscribe\": [\n" +
" {\n" +
" \"path\": \"navigation.datetime\",\n" +
" \"period\": 5000\n" +
" },\n" +
" {\n" +
" \"path\": \"navigation.courseRhumbline.nextPoint\",\n" +
" \"period\": 5000\n" +
" },\n" +
" {\n" +
" \"path\": \"navigation.courseOverGroundTrue\",\n" +
" \"period\": 5000\n" +
" },\n" +
" {\n" +
" \"path\": \"navigation.position\",\n" +
" \"period\": 5000\n" +
" },\n" +
" {\n" +
" \"path\": \"navigation.speedOverGround\",\n" +
" \"period\": 5000\n" +
" }\n" +
" ]\n" +
"}\n"
public class KDataFlow<T>(inflow: Channel<T>, default: T): ViewModel() {
val data = flow { while(true) { emit(inflow.receive()) } }
.stateIn<T>(viewModelScope, SharingStarted.Lazily, default)
}
data class Position (val latitude: Double = 0.0, val longitude: Double = 0.0)
/**
* Interface for SignalK data values to KData structure mapping
*/
interface SignalKMapper {
suspend fun update(json : JsonNode) : Boolean
}
// navigation.datetime
class NavigationDatetimeMapper(val outflow: Channel<Instant>) : SignalKMapper {
override suspend fun update(json: JsonNode): Boolean {
val tstamputc = json?.read<String>("value")
val t = Instant.parse(tstamputc)
outflow.send(t)
return true
}
}
// navigation.courseRhumbline.nextPoint
class NavigationCourseRhumblineNextPointMapper : SignalKMapper {
override suspend fun update(json: JsonNode): Boolean {
val point = Pair(json?.read<Double>("value.latitude"), json?.read<Double>("value.longitude"))
/*
data.nextPointLatitude = point?.first
data.nextPointLongitude = point?.second
data.nextPointBearingTrue = json?.read<Double>("bearingTrue.value")
data.nextPointVMG = json?.read<Double>("velocityMadeGood.value")
data.nextPointDistance = json?.read<Double>("distance.value")
*/
return true
}
}
class NavigationPositionMapper(val outflow: Channel<Position>) : SignalKMapper {
override suspend fun update(json: JsonNode): Boolean {
val point = Pair(json?.read<Double>("value.latitude"), json?.read<Double>("value.longitude"))
if (point.first != null && point.second != null) {
outflow.send(Position(point.first!!, point.second!!))
return true
} else return false
}
}
class NavigationSpeedOverGroundMapper(val outflow: Channel<Double>) : SignalKMapper {
override suspend fun update(json: JsonNode): Boolean {
val speedOverGround = json?.read<Double>("value")
if (speedOverGround != null) outflow.send(speedOverGround)
return true
}
}
class NavigationCourseOverGroundMapper(val outflow: Channel<Double>) : SignalKMapper {
override suspend fun update(json: JsonNode): Boolean {
val courseOverGroundTrue = json?.read<Double>("value")
if (courseOverGroundTrue != null) outflow.send(courseOverGroundTrue)
return true
}
}
class SignalKConnection {
private val ws_url = "ws://nora.dalsgaard.net:3000/signalk/v1/stream?subscribe=none"
private var bgThread: Thread? = null;
private var keepRunning : Boolean = true
val navigationPositionChannel = Channel<Position>()
val datetimeChannel = Channel<Instant>()
val courseOverGroundTrueChannel = Channel<Double>()
val speedOverGroundChannel = Channel<Double>()
private val signalKmapper : Map<String,SignalKMapper>
init {
signalKmapper = mapOf(
"navigation.datetime" to NavigationDatetimeMapper(datetimeChannel),
"navigation.courseOverGroundTrue" to NavigationCourseOverGroundMapper(courseOverGroundTrueChannel),
"navigation.speedOverGround" to NavigationSpeedOverGroundMapper(speedOverGroundChannel),
"navigation.position" to NavigationPositionMapper(navigationPositionChannel),
"navigation.courseRhumbline.nextPoint" to NavigationCourseRhumblineNextPointMapper()
)
}
public fun getFlowPosition () : KDataFlow<Position> {
return KDataFlow(navigationPositionChannel, Position())
}
public fun getFlowDatetime () : KDataFlow<Instant> {
return KDataFlow(datetimeChannel, Instant.ofEpochMilli(0))
}
public fun getFlowCourseOverGround () : KDataFlow<Double> {
return KDataFlow(courseOverGroundTrueChannel, 0.0)
}
public fun getFlowSpeedOverGround () : KDataFlow<Double> {
return KDataFlow(speedOverGroundChannel, 0.0)
}
public fun stop () {
keepRunning = false
}
public fun start () {
this.bgThread = thread(start = true, isDaemon = true) {
while (keepRunning) {
Log.d(TAG, "Inside ConnectionThread")
val client = HttpClient {
install(WebSockets)
install(HttpTimeout) {
connectTimeoutMillis = 10_000
requestTimeoutMillis = 10_000
}
}
runBlocking {
client.webSocket(
method = HttpMethod.Get,
host = "nora.dalsgaard.net",
port = 3000,
path = "/signalk/v1/stream?subscribe=none"
) {
// get welcome message
val msg = incoming.receive().data.decodeToString()
Log.d(TAG, "Welcome message: $msg")
send(SUBSCRIPTION)
Log.d(TAG, "sent: $SUBSCRIPTION")
while (keepRunning) {
val othersMessage = incoming.receive() as? Frame.Text ?: continue
val body = othersMessage.data.decodeToString()
val json = JsonPath.parse(body)
val updates = json?.read<List<JsonNode>>("$.updates[*].values[*]")
if (updates != null) {
Log.d(TAG, "Got updates")
for (i in updates) {
val path = i.read<String>("path")
signalKmapper[path]?.update(i)
}
}
// Log.d(TAG, "data is now: $data")
}
Log.d(TAG, "closing websocket")
}
}
}
}
}
}

View File

@@ -0,0 +1,254 @@
/* While this template provides a good starting point for using Wear Compose, you can always
* take a look at https://github.com/android/wear-os-samples/tree/main/ComposeStarter and
* https://github.com/android/wear-os-samples/tree/main/ComposeAdvanced to find the most up to date
* changes to the libraries and their usages.
*/
package net.dalsgaard.wearsignalk.presentation
import android.graphics.drawable.Drawable
import android.util.Log
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.draw.scale
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.drawscope.DrawScope
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Devices
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.zIndex
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.wear.compose.material.MaterialTheme
import androidx.wear.compose.material.Text
import net.dalsgaard.wearsignalk.R
import net.dalsgaard.wearsignalk.connection.KDataFlow
import net.dalsgaard.wearsignalk.connection.Position
import net.dalsgaard.wearsignalk.connection.SignalKConnection
import net.dalsgaard.wearsignalk.presentation.theme.WearSignalKTheme
import net.dalsgaard.wearsignalk.util.Design
import net.dalsgaard.wearsignalk.util.Vector
import net.dalsgaard.wearsignalk.util.awd_ident
import net.dalsgaard.wearsignalk.util.cog_ident
import net.dalsgaard.wearsignalk.util.compass_rose
import net.dalsgaard.wearsignalk.util.eyeMatrix
import net.dalsgaard.wearsignalk.util.forSquareScreen
import net.dalsgaard.wearsignalk.util.latToString
import net.dalsgaard.wearsignalk.util.lonToString
import net.dalsgaard.wearsignalk.util.rotMatrix
import net.dalsgaard.wearsignalk.util.scaleMatrix
import net.dalsgaard.wearsignalk.util.ship
import java.time.Instant
import java.time.LocalTime
import java.time.OffsetDateTime
import java.time.ZoneOffset
import java.time.format.DateTimeFormatter
import kotlin.math.cos
import kotlin.math.min
import kotlin.math.round
import kotlin.math.sin
private const val TAG = "MainActivity"
class MainActivity : ComponentActivity() {
var conn = SignalKConnection()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.d(TAG, "onCreate in MainActivity")
conn.start()
setContent {
// WearApp("Android", conn.getKData())
WearApp("Android", conn)
}
}
}
fun drawDesign(design: Design, dr: DrawScope) {
for (t in design.traces) {
var idx_iterator = t.indices.iterator()
var last_idx = idx_iterator.next()
while (idx_iterator.hasNext()) {
val idx = idx_iterator.next()
dr.drawLine(t.color, start=Offset(design.points[last_idx].x, design.points[last_idx].y),
end=Offset(design.points[idx].x, design.points[idx].y), strokeWidth = t.width)
last_idx = idx
}
}
}
@Composable
fun WearApp(greetingName: String, conn: SignalKConnection) {
val cog_true_flow = conn.getFlowCourseOverGround()
WearSignalKTheme {
/* If you have enough items in your list, use [ScalingLazyColumn] which is an optimized
* version of LazyColumn for wear devices with some added features. For more information,
* see d.android.com/wear/compose.
*/
ship(conn.getFlowCourseOverGround())
Column (modifier = Modifier
.fillMaxSize()
.background(color = Color.Transparent)
.drawBehind
{
val min_dim = min(size.width, size.height)
val ship_ship = forSquareScreen(ship, min_dim)
drawDesign(ship_ship, this)
}, verticalArrangement = Arrangement.Center) {
Row(
modifier = Modifier
.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly
) { Time(conn.getFlowDatetime())
}
Row (modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly
) {
Column (modifier = Modifier, verticalArrangement = Arrangement.Center,Alignment.CenterHorizontally) {
courseOverGroundTrue(conn.getFlowCourseOverGround())
}
Column (modifier = Modifier, verticalArrangement = Arrangement.Center) {
speedOverGround(conn.getFlowSpeedOverGround())
}
}
Row(
modifier = Modifier
.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly
) {
Position(conn.getFlowPosition())
//Text("JD")
//Text(latToString(data.latitude!!))
//Text(lonToString(data.longitude!!))
}
}
}
}
@Composable
fun WearAppPreview(greetingName: String) {
WearSignalKTheme {
/* If you have enough items in your list, use [ScalingLazyColumn] which is an optimized
* version of LazyColumn for wear devices with some added features. For more information,
* see d.android.com/wear/compose.
*/
Column(
modifier = Modifier,
verticalArrangement = Arrangement.Center
) {
val data = Position(12.2, 55.2)
Column (modifier = Modifier, verticalArrangement = Arrangement.Center,Alignment.CenterHorizontally) {
Text("Boat Position Pre", Modifier.scale(0.8F))
Text(latToString(data.latitude!!))
Text(lonToString(data.longitude!!))
}
}
}
}
@Composable
fun ship(kdataflow : KDataFlow<Double>) {
val cog_rad by kdataflow.data.collectAsStateWithLifecycle()
Canvas(modifier = Modifier.fillMaxSize().background(Color.Transparent).zIndex(-1F)) {
val min_dim = min(size.width, size.height)
val true_heading = 0F // LocalTime.now().second * 6.0F
val heading = -(true_heading / 360.0 * 2.0 * Math.PI).toFloat()
val heading_rotate_matrix = rotMatrix(heading)
val compass = forSquareScreen(heading_rotate_matrix * compass_rose, min_dim)
drawDesign(compass, this)
// val cog = (2.0 * true_heading/360 * 2.0 * Math.PI).toFloat()
val cog = cog_rad.toFloat()
Log.d(TAG, "got cog to " + (cog * 180 / Math.PI))
val cog_rotate_matrix = rotMatrix(-cog.toFloat() + heading)
val cog_pointer = forSquareScreen(cog_rotate_matrix * cog_ident, min_dim)
drawDesign(cog_pointer, this)
val awd = (Math.PI/8*13).toFloat() // (1/2 * Math.PI).toFloat()
val awd_rotate_matrix = rotMatrix(-awd + heading)
val awd_pointer = forSquareScreen(awd_rotate_matrix * awd_ident, min_dim)
drawDesign(awd_pointer, this)
}
}
@Composable
fun courseOverGroundTrue(kdataflow : KDataFlow<Double>) {
val deg by kdataflow.data.collectAsStateWithLifecycle()
val deg360 = round(deg*180.0/Math.PI)
Text("COG", Modifier.scale(0.8F))
Text("%03.0f°".format(deg360))
}
@Composable
fun speedOverGround(kdataflow : KDataFlow<Double>) {
val spd by kdataflow.data.collectAsStateWithLifecycle()
val spd_kn = spd * 1.94384
Text("SOG", Modifier.scale(0.8F))
Text("%02.1fkn".format(spd_kn))
}
@Composable
fun Position(kdataflow : KDataFlow<Position>) {
val pos by kdataflow.data.collectAsStateWithLifecycle()
Column (modifier = Modifier.scale(0.8F), verticalArrangement = Arrangement.Center,Alignment.CenterHorizontally) {
Text(latToString(pos.latitude))
Text(lonToString(pos.longitude))
// Text("Boat Position", Modifier.scale(0.8F))
}
}
@Composable
fun Time(kdataflow : KDataFlow<Instant>) {
val time by kdataflow.data.collectAsStateWithLifecycle()
val timez = OffsetDateTime.ofInstant(time, ZoneOffset.UTC)
val fmt1 = DateTimeFormatter.ofPattern("MMM dd HH:mm")
Column (modifier = Modifier.scale(0.8F), verticalArrangement = Arrangement.Center,Alignment.CenterHorizontally) {
// Text("Boat Time", Modifier.scale(0.8F))
Text(timez.format(fmt1))
}
}
@Composable
fun Greeting(greetingName: String) {
Text(
modifier = Modifier.fillMaxWidth(),
textAlign = TextAlign.Center,
color = MaterialTheme.colors.primary,
text = stringResource(R.string.hello_world, greetingName)
)
}
@Preview(device = Devices.WEAR_OS_SMALL_ROUND, showSystemUi = true)
@Composable
fun DefaultPreview() {
WearAppPreview("Preview Android")
}

View File

@@ -0,0 +1,34 @@
package net.dalsgaard.wearsignalk.util
import kotlin.math.floor
private fun degToString (degrees: Double, dir : Char) : String {
val deg = floor(degrees)
val frac60 = 60 * (degrees - deg)
val min = floor(frac60)
val frac3600 = 60 * (frac60 - min)
val sec = floor(frac3600)
return "%03.0f°%02.0fʹ%02.0fʺ %s".format(deg, min, sec, dir)
}
public fun latToString (latitude: Double) : String {
return if (latitude > 0) {
degToString(latitude, 'E')
} else if (latitude < 0) {
degToString(-latitude, 'W')
} else {
"000°00ʹ00ʺ -"
}
}
public fun lonToString (longitude: Double) : String {
return if (longitude > 0) {
degToString(longitude, 'N')
} else if (longitude < 0) {
degToString(-longitude, 'S')
} else {
"000°00ʹ00ʺ -"
}
}

View File

@@ -0,0 +1,96 @@
package net.dalsgaard.wearsignalk.util
import androidx.compose.ui.graphics.Color
val compass_rose =
Design(listOf(Vector(0.0F, 0.5F), Vector(0.0F, 0.35F)), listOf(Design.Trace(listOf(0, 1), 5.0F, Color.Red))) +
Design(listOf(Vector(0.020869565217391303F, 0.2582608695652174F), Vector(0.02086956521739131F, 0.331304347826087F),
Vector(0.017391304347826084F, 0.2582608695652174F), Vector(-0.024347826086956518F, 0.3243478260869565F),
Vector(0.017391304347826084F, 0.2652173913043478F), Vector(-0.024347826086956518F, 0.331304347826087F),
Vector(-0.024347826086956525F, 0.2582608695652174F), Vector(-0.024347826086956518F, 0.331304347826087F),
Vector(0.03130434782608695F, 0.2582608695652174F), Vector(0.017391304347826084F, 0.2582608695652174F),
Vector(-0.013913043478260875F, 0.2582608695652174F), Vector(-0.03478260869565218F, 0.2582608695652174F),
Vector(0.031304347826086966F, 0.3313043478260869F), Vector(0.010434782608695656F, 0.331304347826087F)),
listOf(Design.Trace(listOf(0, 1), 2F, Color.Red),
Design.Trace(listOf(2, 3), 2F, Color.Red),
Design.Trace(listOf(4, 5), 2F, Color.Red),
Design.Trace(listOf(6, 7), 2F, Color.Red),
Design.Trace(listOf(8, 9), 2F, Color.Red),
Design.Trace(listOf(10, 11), 2F, Color.Red),
Design.Trace(listOf(12, 13), 2F, Color.Red))) +
Design(listOf(Vector(0.5F, 0.0F), Vector(0.35F, 0.0F)), listOf(Design.Trace(listOf(0, 1), 5.0F, Color.Gray))) +
Design(listOf(Vector(0.0F, -0.5F), Vector(0.0F, -0.35F)), listOf(Design.Trace(listOf(0, 1), 5.0F, Color.Gray))) +
Design(listOf(Vector(-0.5F, 0.0F), Vector(-0.35F, 0.0F)), listOf(Design.Trace(listOf(0, 1), 5.0F, Color.Gray))) +
Design(listOf(Vector(0.3535533905932738F, 0.35355339059327373F), Vector(0.3005203820042827F, 0.30052038200428266F)), listOf(Design.Trace(listOf(0, 1), 3.0F, Color.Gray))) +
Design(listOf(Vector(-0.35355339059327373F, 0.3535533905932738F), Vector(-0.30052038200428266F, 0.3005203820042827F)), listOf(Design.Trace(listOf(0, 1), 3.0F, Color.Gray))) +
Design(listOf(Vector(-0.35355339059327384F, -0.35355339059327373F), Vector(-0.30052038200428277F, -0.30052038200428266F)), listOf(Design.Trace(listOf(0, 1), 3.0F, Color.Gray))) +
Design(listOf(Vector(0.3535533905932737F, -0.35355339059327384F), Vector(0.3005203820042826F, -0.30052038200428277F)), listOf(Design.Trace(listOf(0, 1), 3.0F, Color.Gray))) +
Design(listOf(Vector(0.4903926402016152F, 0.09754516100806412F), Vector(0.4413533761814537F, 0.08779064490725771F)), listOf(Design.Trace(listOf(0, 1), 1.0F, Color.Gray))) +
Design(listOf(Vector(0.46193976625564337F, 0.1913417161825449F), Vector(0.415745789630079F, 0.1722075445642904F)), listOf(Design.Trace(listOf(0, 1), 1.0F, Color.Gray))) +
Design(listOf(Vector(0.4157348061512726F, 0.2777851165098011F), Vector(0.37416132553614534F, 0.250006604858821F)), listOf(Design.Trace(listOf(0, 1), 1.0F, Color.Gray))) +
Design(listOf(Vector(0.27778511650980114F, 0.4157348061512726F), Vector(0.25000660485882104F, 0.37416132553614534F)), listOf(Design.Trace(listOf(0, 1), 1.0F, Color.Gray))) +
Design(listOf(Vector(0.19134171618254492F, 0.46193976625564337F), Vector(0.17220754456429044F, 0.415745789630079F)), listOf(Design.Trace(listOf(0, 1), 1.0F, Color.Gray))) +
Design(listOf(Vector(0.09754516100806417F, 0.4903926402016152F), Vector(0.08779064490725776F, 0.4413533761814537F)), listOf(Design.Trace(listOf(0, 1), 1.0F, Color.Gray))) +
Design(listOf(Vector(-0.0975451610080641F, 0.4903926402016152F), Vector(-0.08779064490725769F, 0.4413533761814537F)), listOf(Design.Trace(listOf(0, 1), 1.0F, Color.Gray))) +
Design(listOf(Vector(-0.19134171618254486F, 0.46193976625564337F), Vector(-0.17220754456429038F, 0.415745789630079F)), listOf(Design.Trace(listOf(0, 1), 1.0F, Color.Gray))) +
Design(listOf(Vector(-0.277785116509801F, 0.41573480615127273F), Vector(-0.25000660485882087F, 0.37416132553614545F)), listOf(Design.Trace(listOf(0, 1), 1.0F, Color.Gray))) +
Design(listOf(Vector(-0.4157348061512727F, 0.2777851165098011F), Vector(-0.3741613255361454F, 0.250006604858821F)), listOf(Design.Trace(listOf(0, 1), 1.0F, Color.Gray))) +
Design(listOf(Vector(-0.46193976625564337F, 0.19134171618254495F), Vector(-0.415745789630079F, 0.17220754456429047F)), listOf(Design.Trace(listOf(0, 1), 1.0F, Color.Gray))) +
Design(listOf(Vector(-0.4903926402016152F, 0.0975451610080643F), Vector(-0.4413533761814537F, 0.08779064490725788F)), listOf(Design.Trace(listOf(0, 1), 1.0F, Color.Gray))) +
Design(listOf(Vector(-0.4903926402016152F, -0.09754516100806418F), Vector(-0.4413533761814537F, -0.08779064490725777F)), listOf(Design.Trace(listOf(0, 1), 1.0F, Color.Gray))) +
Design(listOf(Vector(-0.4619397662556434F, -0.19134171618254484F), Vector(-0.4157457896300791F, -0.17220754456429035F)), listOf(Design.Trace(listOf(0, 1), 1.0F, Color.Gray))) +
Design(listOf(Vector(-0.41573480615127273F, -0.277785116509801F), Vector(-0.37416132553614545F, -0.25000660485882087F)), listOf(Design.Trace(listOf(0, 1), 1.0F, Color.Gray))) +
Design(listOf(Vector(-0.2777851165098011F, -0.4157348061512726F), Vector(-0.250006604858821F, -0.37416132553614534F)), listOf(Design.Trace(listOf(0, 1), 1.0F, Color.Gray))) +
Design(listOf(Vector(-0.19134171618254517F, -0.46193976625564326F), Vector(-0.17220754456429066F, -0.41574578963007897F)), listOf(Design.Trace(listOf(0, 1), 1.0F, Color.Gray))) +
Design(listOf(Vector(-0.09754516100806433F, -0.49039264020161516F), Vector(-0.0877906449072579F, -0.44135337618145365F)), listOf(Design.Trace(listOf(0, 1), 1.0F, Color.Gray))) +
Design(listOf(Vector(0.09754516100806415F, -0.4903926402016152F), Vector(0.08779064490725774F, -0.4413533761814537F)), listOf(Design.Trace(listOf(0, 1), 1.0F, Color.Gray))) +
Design(listOf(Vector(0.191341716182545F, -0.4619397662556433F), Vector(0.1722075445642905F, -0.41574578963007897F)), listOf(Design.Trace(listOf(0, 1), 1.0F, Color.Gray))) +
Design(listOf(Vector(0.2777851165098009F, -0.41573480615127273F), Vector(0.2500066048588208F, -0.37416132553614545F)), listOf(Design.Trace(listOf(0, 1), 1.0F, Color.Gray))) +
Design(listOf(Vector(0.4157348061512726F, -0.2777851165098011F), Vector(0.37416132553614534F, -0.250006604858821F)), listOf(Design.Trace(listOf(0, 1), 1.0F, Color.Gray))) +
Design(listOf(Vector(0.46193976625564326F, -0.1913417161825452F), Vector(0.41574578963007897F, -0.1722075445642907F)), listOf(Design.Trace(listOf(0, 1), 1.0F, Color.Gray))) +
Design(listOf(Vector(0.49039264020161516F, -0.09754516100806436F), Vector(0.44135337618145365F, -0.08779064490725792F)), listOf(Design.Trace(listOf(0, 1), 1.0F, Color.Gray))) +
Design(emptyList(), emptyList())
val cog_ident_color = Color(0xAD, 0xD8, 0xE6)
val cog_ident =
Design(listOf(Vector(0.0F, 0.5F), Vector(0.0F, 0.4F),
Vector(-0.009937500000000002F, 0.3125F), Vector(-0.013062500000000001F, 0.3109375F), Vector(-0.016187500000000004F, 0.3078125F), Vector(-0.017750000000000005F, 0.3046875F), Vector(-0.017750000000000005F, 0.29843749999999997F), Vector(-0.016187500000000004F, 0.2953125F), Vector(-0.013062500000000005F, 0.2921875F), Vector(-0.009937500000000005F, 0.29062499999999997F), Vector(-0.005250000000000004F, 0.2890625F), Vector(0.002562499999999996F, 0.2890625F), Vector(0.007249999999999997F, 0.29062499999999997F), Vector(0.010374999999999999F, 0.2921875F), Vector(0.013499999999999998F, 0.2953125F), Vector(0.015062499999999996F, 0.29843749999999997F), Vector(0.015062499999999996F, 0.3046875F), Vector(0.013499999999999998F, 0.3078125F), Vector(0.010374999999999999F, 0.3109375F), Vector(0.007249999999999998F, 0.3125F),
Vector(-0.017750000000000002F, 0.32968749999999997F), Vector(-0.0161875F, 0.3265625F), Vector(-0.013062500000000001F, 0.3234375F), Vector(-0.009937500000000002F, 0.32187499999999997F), Vector(-0.005250000000000002F, 0.3203125F), Vector(0.0025624999999999984F, 0.3203125F), Vector(0.007249999999999999F, 0.32187499999999997F), Vector(0.010374999999999999F, 0.3234375F), Vector(0.013499999999999998F, 0.3265625F), Vector(0.0150625F, 0.32968749999999997F), Vector(0.0150625F, 0.3359375F), Vector(0.013500000000000002F, 0.3390625F), Vector(0.010375000000000002F, 0.3421875F), Vector(0.00725F, 0.34375F), Vector(0.0025624999999999997F, 0.34531249999999997F), Vector(-0.00525F, 0.34531249999999997F), Vector(-0.009937500000000002F, 0.34375F), Vector(-0.013062500000000001F, 0.3421875F), Vector(-0.0161875F, 0.3390625F), Vector(-0.017750000000000002F, 0.3359375F), Vector(-0.017750000000000002F, 0.32968749999999997F),
Vector(-0.009937499999999998F, 0.37968749999999996F), Vector(-0.013062499999999998F, 0.378125F), Vector(-0.0161875F, 0.375F), Vector(-0.017750000000000002F, 0.37187499999999996F), Vector(-0.017750000000000002F, 0.365625F), Vector(-0.0161875F, 0.3625F), Vector(-0.013062500000000001F, 0.359375F), Vector(-0.009937500000000002F, 0.3578125F), Vector(-0.00525F, 0.35624999999999996F), Vector(0.0025625000000000005F, 0.35624999999999996F), Vector(0.007250000000000001F, 0.3578125F), Vector(0.010375000000000002F, 0.359375F), Vector(0.013500000000000002F, 0.3625F), Vector(0.015062500000000003F, 0.365625F), Vector(0.015062500000000003F, 0.37187499999999996F), Vector(0.013500000000000002F, 0.375F), Vector(0.010375000000000002F, 0.378125F), Vector(0.007250000000000002F, 0.37968749999999996F), Vector(0.002562500000000002F, 0.37968749999999996F),
Vector(0.0025625000000000014F, 0.37187499999999996F), Vector(0.002562500000000002F, 0.37968749999999996F)),
listOf(Design.Trace(listOf(0, 1), 1.0F, cog_ident_color),
Design.Trace(listOf(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19), 1.0F, cog_ident_color),
Design.Trace(listOf(20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40), 1.0F, cog_ident_color),
Design.Trace(listOf(41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59), 1.0F, cog_ident_color),
Design.Trace(listOf(60, 61), 1.0F, cog_ident_color)))
val awd_ident_color = Color (0xFF, 0xF7, 0x00)
val awd_ident =
Design(listOf(Vector(0.0F, 0.5F), Vector(0.0F, 0.4F),
Vector(-0.018047619047619052F, 0.3F), Vector(0.015285714285714281F, 0.2873015873015873F),
Vector(-0.018047619047619052F, 0.3F), Vector(0.015285714285714284F, 0.3126984126984127F),
Vector(0.004174603174603171F, 0.292063492063492F), Vector(0.004174603174603172F, 0.3079365079365079F),
Vector(-0.018047619047619052F, 0.3126984126984127F), Vector(0.015285714285714284F, 0.3206349206349206F),
Vector(-0.01804761904761905F, 0.32857142857142857F), Vector(0.015285714285714284F, 0.3206349206349206F),
Vector(-0.01804761904761905F, 0.32857142857142857F), Vector(0.015285714285714284F, 0.3365079365079365F),
Vector(-0.01804761904761905F, 0.34444444444444444F), Vector(0.015285714285714284F, 0.3365079365079365F),
Vector(-0.01804761904761905F, 0.3555555555555555F), Vector(0.015285714285714284F, 0.3555555555555555F),
Vector(-0.01804761904761905F, 0.3555555555555555F), Vector(-0.01804761904761905F, 0.36666666666666664F), Vector(-0.01646031746031746F, 0.3714285714285714F), Vector(-0.013285714285714283F, 0.3746031746031746F), Vector(-0.010111111111111109F, 0.3761904761904762F), Vector(-0.0053492063492063474F, 0.37777777777777777F), Vector(0.002587301587301589F, 0.37777777777777777F), Vector(0.007349206349206351F, 0.3761904761904762F), Vector(0.010523809523809526F, 0.3746031746031746F), Vector(0.0136984126984127F, 0.3714285714285714F), Vector(0.015285714285714288F, 0.36666666666666664F), Vector(0.015285714285714284F, 0.3555555555555555F)),
listOf(Design.Trace(listOf(0, 1), 1.0F, awd_ident_color),
Design.Trace(listOf(2, 3), 1.0F, awd_ident_color),
Design.Trace(listOf(4, 5), 1.0F, awd_ident_color),
Design.Trace(listOf(6, 7), 1.0F, awd_ident_color),
Design.Trace(listOf(8, 9), 1.0F, awd_ident_color),
Design.Trace(listOf(10, 11), 1.0F, awd_ident_color),
Design.Trace(listOf(12, 13), 1.0F, awd_ident_color),
Design.Trace(listOf(14, 15), 1.0F, awd_ident_color),
Design.Trace(listOf(16, 17), 1.0F, awd_ident_color),
Design.Trace(listOf(18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29), 1.0F, awd_ident_color)))
val ship_color=Color(0x80, 0x85, 0x88)
val ship = Design(listOf(Vector(-0.008872458410351202F, -0.4F), Vector(-0.022181146025878007F, -0.39556377079482447F), Vector(-0.03844731977818854F, -0.38669131238447324F), Vector(-0.047319778188539746F, -0.37634011090573016F), Vector(-0.0857670979667283F, -0.24916820702402961F), Vector(-0.10646950092421442F, -0.1604436229205176F), Vector(-0.11386321626617377F, -0.10425138632162663F), Vector(-0.1168207024029575F, -0.04066543438077634F), Vector(-0.11534195933456563F, -0.0007393715341959335F), Vector(-0.11090573012939003F, 0.05841035120147875F), Vector(-0.10055452865064696F, 0.11608133086876156F), Vector(-0.08428835489833643F, 0.18558225508317933F), Vector(-0.051756007393715345F, 0.28170055452865067F), Vector(-0.011829944547134937F, 0.3748613678373383F), Vector(-0.001478743068391867F, 0.4F), Vector(0.001478743068391867F, 0.4F), Vector(0.011829944547134937F, 0.3748613678373383F), Vector(0.051756007393715345F, 0.28170055452865067F), Vector(0.08428835489833643F, 0.18558225508317933F), Vector(0.10055452865064696F, 0.11608133086876156F), Vector(0.11090573012939003F, 0.05841035120147875F), Vector(0.11534195933456563F, -0.0007393715341959335F), Vector(0.1168207024029575F, -0.04066543438077634F), Vector(0.11386321626617377F, -0.10425138632162663F), Vector(0.10646950092421442F, -0.1604436229205176F), Vector(0.0857670979667283F, -0.24916820702402961F), Vector(0.047319778188539746F, -0.37634011090573016F), Vector(0.03844731977818854F, -0.38669131238447324F), Vector(0.022181146025878007F, -0.39556377079482447F), Vector(0.008872458410351202F, -0.4F), Vector(-0.047319778188539746F, -0.37634011090573016F), Vector(-0.031053604436229208F, -0.3792975970425139F), Vector(-0.01478743068391867F, -0.38225508317929763F), Vector(0.01478743068391867F, -0.38225508317929763F), Vector(0.031053604436229208F, -0.3792975970425139F), Vector(0.047319778188539746F, -0.37634011090573016F), Vector(0.0F, -0.3127541589648799F), Vector(-0.002957486136783734F, -0.30683918669131244F), Vector(-0.001478743068391867F, -0.300924214417745F), Vector(0.0F, -0.22994454713493534F), Vector(0.001478743068391867F, -0.300924214417745F), Vector(0.002957486136783734F, -0.30683918669131244F), Vector(-0.002957486136783734F, -0.2935304990757856F), Vector(-0.03992606284658041F, -0.29500924214417745F), Vector(-0.05027726432532348F, -0.2905730129390019F), Vector(-0.05619223659889095F, -0.2802218114602588F), Vector(-0.062107208872458415F, -0.25951940850277266F), Vector(-0.06802218114602589F, -0.22107208872458411F), Vector(-0.07541589648798522F, -0.12643253234750462F), Vector(0.07541589648798522F, -0.12643253234750462F), Vector(0.06802218114602589F, -0.22107208872458411F), Vector(0.062107208872458415F, -0.25951940850277266F), Vector(0.05619223659889095F, -0.2802218114602588F), Vector(0.05027726432532348F, -0.2905730129390019F), Vector(0.03992606284658041F, -0.29500924214417745F), Vector(0.002957486136783734F, -0.2935304990757856F), Vector(-0.07245841035120149F, -0.12643253234750462F), Vector(-0.07245841035120149F, -0.01700554528650647F), Vector(-0.06802218114602589F, 0.042144177449168214F), Vector(-0.05914972273567468F, 0.09981515711645103F), Vector(-0.04584103512014788F, 0.15452865064695012F), Vector(-0.02957486136783734F, 0.21072088724584107F), Vector(-0.026617375231053605F, 0.21663585951940853F), Vector(-0.01922365988909427F, 0.21959334565619226F), Vector(-0.008872458410351202F, 0.22107208872458411F), Vector(0.008872458410351202F, 0.22107208872458411F), Vector(0.01922365988909427F, 0.21959334565619226F), Vector(0.026617375231053605F, 0.21663585951940853F), Vector(0.02957486136783734F, 0.21072088724584107F), Vector(0.04584103512014788F, 0.15452865064695012F), Vector(0.05914972273567468F, 0.09981515711645103F), Vector(0.06802218114602589F, 0.042144177449168214F), Vector(0.07245841035120149F, -0.01700554528650647F), Vector(0.07245841035120149F, -0.12643253234750462F)), listOf(Design.Trace(listOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 0), 2.0F, ship_color),
Design.Trace(listOf(30, 31, 32, 33, 34, 35), 2.0F, ship_color),
Design.Trace(listOf(36, 37, 38, 39, 40, 41, 36), 2.0F, ship_color),
Design.Trace(listOf(42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 42), 2.0F, ship_color),
Design.Trace(listOf(56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73), 2.0F, ship_color)))

View File

@@ -0,0 +1,26 @@
package net.dalsgaard.wearsignalk.util
import androidx.compose.ui.graphics.Color
data class Glyph (val points: List<List<Vector>>, val left: Float, val right: Float)
fun glyphJoin(glyphs: List<Glyph>, stroke: Float, color: Color) : Design
{
if (glyphs.size == 0) { return Design(emptyList(), emptyList()) }
// rearrange....
var left_extend=0F
val d_points = mutableListOf<Vector>()
val d_indices = mutableListOf<List<Int>>()
glyphs.forEach {
val move = Vector(left_extend - it.left, 0F)
it.points.forEach {
d_indices.add((d_points.size..(d_points.size + it.size)).toList())
d_points.addAll (move + it)
}
left_extend = left_extend + (it.right - it.left)
}
val move_back = Vector(-left_extend/2, 0F)
return Design(move_back + d_points, d_indices.map { Design.Trace(it, stroke, color)})
}

View File

@@ -0,0 +1,126 @@
package net.dalsgaard.wearsignalk.util
import androidx.compose.ui.graphics.Color
import kotlin.math.cos
import kotlin.math.max
import kotlin.math.min
import kotlin.math.sin
/**
* Model for a 'Design' - which is a list of points in the 2D space
* along information about which points are to be connected with lines
* of certain width and color.
*/
class Design (val points: List<Vector>, val traces: List<Trace>) {
data class Trace(val indices: List<Int>, val width: Float, val color: Color)
data class BoundingBox(val x0: Float, val y0: Float, val x1: Float, val y1: Float)
operator fun plus (o: Design) : Design {
return Design (points + o.points, traces + o.traces.map {
Trace(it.indices.map { it + points.size }, it.width, it.color)
})
}
operator fun plus (o: Vector) : Design {
return Design (o + points, traces)
}
fun boundingBox () : BoundingBox {
return points.fold (BoundingBox(Float.MAX_VALUE, Float.MAX_VALUE, Float.MIN_VALUE, Float.MIN_VALUE)) { acc, nxt ->
BoundingBox(
min(nxt.x, acc.x0),
min(nxt.y, acc.y0),
max(nxt.x, acc.x1),
max(nxt.y, acc.y1)
)
}
}
}
/**
* Maps a 1 by 1 design centered on (0,0) onto a
* square screen with inverted Y.
*/
fun forSquareScreen (d: Design, edge: Float) : Design {
return scaleMatrix(edge) * (Matrix(1f, 0f, 0f, -1f)*d + Vector(0.5f, 0.5f))
}
/**
* Model for a 2D vector, along with basic operators
*
*/
data class Vector (val x: Float, val y: Float) {
operator fun plus (o: Vector) : Vector {
return Vector (x+o.x, y+o.y)
}
operator fun minus (o: Vector) : Vector {
return Vector (x-o.x, y-o.y)
}
operator fun plus (o: List<Vector>) : List<Vector> {
return o.map {
Vector(x+it.x, y+it.y)
}
}
}
/**
* Model for a 2x2 matrix, along with a fairly extensive
* set of operators not only for matrices and vectors, but also
* for list of vectors and 'Designs'.
*/
data class Matrix (val a: Float, val b: Float, val c: Float, val d: Float) {
operator fun plus (o: Matrix) : Matrix {
return Matrix(a+o.a, b+o.b, c+o.c, d+o.d)
}
operator fun minus (o: Matrix) : Matrix {
return Matrix(a-o.a, b-o.b, c-o.c, d-o.d)
}
operator fun times (o: Matrix) : Matrix {
return Matrix(a*o.a + b*o.c, a*o.b + b*o.d, c*o.a + d*o.c, c*o.b + d*o.d)
}
operator fun times (o: Float) : Matrix {
return Matrix(a*o, b*o, c*o, d*o)
}
operator fun times (o: List<Vector>) : List<Vector> {
return o.map {
Vector(a*it.x + b*it.y, c*it.x + d*it.y)
}
}
operator fun times (o: Design) : Design {
return Design(this * o.points, o.traces)
}
}
/**
* Returns 2x2 matrix for rotation in the plane, angle given in radians.
*/
fun rotMatrix(theta: Float) : Matrix {
return Matrix(cos(theta), -sin(theta), sin(theta), cos(theta))
}
/**
* Returns the identity matrix.
*/
fun eyeMatrix() : Matrix {
return Matrix(1f, 0f, 0f, 1f)
}
/**
* Returns a scaling matrix,
* basically identical to: eyeMatrix()*factor.
*/
fun scaleMatrix(factor: Float) : Matrix {
return Matrix(factor, 0f, 0f, factor)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 982 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@@ -0,0 +1,3 @@
<resources>
<string name="hello_world">From the Round world,\nHello, %1$s!</string>
</resources>

View File

@@ -0,0 +1,8 @@
<resources>
<string name="app_name">WearSignalK</string>
<!--
This string is used for square devices and overridden by hello_world in
values-round/strings.xml for round devices.
-->
<string name="hello_world">From the Square world,\nHello, %1$s!</string>
</resources>

5
build.gradle.kts Normal file
View File

@@ -0,0 +1,5 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id("com.android.application") version "8.1.2" apply false
id("org.jetbrains.kotlin.android") version "1.8.10" apply false
}

24
gradle.properties Normal file
View File

@@ -0,0 +1,24 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app's APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
# Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official
# Enables namespacing of each library's R class so that its R class includes only the
# resources declared in the library itself and none from the library's dependencies,
# thereby reducing the size of the R class for that library
android.nonTransitiveRClass=true

View File

@@ -0,0 +1,6 @@
#Sat Oct 07 23:54:01 CEST 2023
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

18
settings.gradle.kts Normal file
View File

@@ -0,0 +1,18 @@
pluginManagement {
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
}
}
rootProject.name = "WearSignalK"
include(":app")