Implemented the Play Store readiness pass.
This commit is contained in:
@@ -1,8 +1,32 @@
|
||||
import java.util.Properties
|
||||
|
||||
plugins {
|
||||
alias(libs.plugins.android.application)
|
||||
alias(libs.plugins.kotlin.compose)
|
||||
}
|
||||
|
||||
val localProperties = Properties().apply {
|
||||
val file = rootProject.file("local.properties")
|
||||
if (file.isFile) {
|
||||
file.inputStream().use { load(it) }
|
||||
}
|
||||
}
|
||||
|
||||
fun releaseSecret(name: String): String? {
|
||||
return providers.environmentVariable(name).orNull ?: localProperties.getProperty(name)
|
||||
}
|
||||
|
||||
val releaseStoreFile = releaseSecret("NGX_RELEASE_STORE_FILE")
|
||||
val releaseStorePassword = releaseSecret("NGX_RELEASE_STORE_PASSWORD")
|
||||
val releaseKeyAlias = releaseSecret("NGX_RELEASE_KEY_ALIAS")
|
||||
val releaseKeyPassword = releaseSecret("NGX_RELEASE_KEY_PASSWORD")
|
||||
val hasReleaseSigning = listOf(
|
||||
releaseStoreFile,
|
||||
releaseStorePassword,
|
||||
releaseKeyAlias,
|
||||
releaseKeyPassword,
|
||||
).all { !it.isNullOrBlank() }
|
||||
|
||||
android {
|
||||
namespace = "net.rodakot.ngxhttpmonitoringclient"
|
||||
compileSdk {
|
||||
@@ -15,15 +39,30 @@ android {
|
||||
applicationId = "net.rodakot.ngxhttpmonitoringclient"
|
||||
minSdk = 24
|
||||
targetSdk = 36
|
||||
versionCode = 1
|
||||
versionName = "1.0"
|
||||
versionCode = (providers.gradleProperty("VERSION_CODE").orNull ?: "1").toInt()
|
||||
versionName = providers.gradleProperty("VERSION_NAME").orNull ?: "1.0.0"
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
if (hasReleaseSigning) {
|
||||
create("release") {
|
||||
storeFile = file(releaseStoreFile!!)
|
||||
storePassword = releaseStorePassword
|
||||
keyAlias = releaseKeyAlias
|
||||
keyPassword = releaseKeyPassword
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
isMinifyEnabled = false
|
||||
isMinifyEnabled = true
|
||||
isShrinkResources = true
|
||||
if (hasReleaseSigning) {
|
||||
signingConfig = signingConfigs.getByName("release")
|
||||
}
|
||||
proguardFiles(
|
||||
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||
"proguard-rules.pro"
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
|
||||
<application
|
||||
android:name=".NgxMonitorApplication"
|
||||
android:allowBackup="true"
|
||||
android:allowBackup="false"
|
||||
android:appCategory="productivity"
|
||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||
android:fullBackupContent="@xml/backup_rules"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
|
||||
@@ -587,17 +587,27 @@ private fun HistoryCockpit(history: List<MetricSummary>) {
|
||||
|
||||
@Composable
|
||||
private fun SettingsCockpit(server: ServerProfile, controller: MonitorController) {
|
||||
DataPanel("Alert Rules") {
|
||||
Column(verticalArrangement = Arrangement.spacedBy(10.dp)) {
|
||||
RuleRow("CPU limit", "${server.alertOverrides.cpuPercent ?: DefaultCpuThreshold}%")
|
||||
RuleRow("Memory limit", "${server.alertOverrides.memoryPercent ?: DefaultMemoryThreshold}%")
|
||||
RuleRow("Disk limit", "${server.alertOverrides.diskPercent ?: DefaultDiskThreshold}%")
|
||||
RuleRow("p95 latency", "${(server.alertOverrides.latencyP95Millis ?: DefaultLatencyP95ThresholdMs).toInt()} ms")
|
||||
RuleRow("5xx limit", "${server.alertOverrides.errors5xx ?: DefaultErrors5xxThreshold}")
|
||||
RuleRow("Fallback IPs", server.fallbackIpAddresses.ifEmpty { listOf("None") }.joinToString(", "))
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(10.dp)) {
|
||||
Button(onClick = controller::showEditSelectedServer, shape = RoundedCornerShape(8.dp)) { Text("Edit") }
|
||||
OutlinedButton(onClick = controller::deleteSelectedServer, shape = RoundedCornerShape(8.dp)) { Text("Delete") }
|
||||
Column(verticalArrangement = Arrangement.spacedBy(16.dp)) {
|
||||
DataPanel("Alert Rules") {
|
||||
Column(verticalArrangement = Arrangement.spacedBy(10.dp)) {
|
||||
RuleRow("CPU limit", "${server.alertOverrides.cpuPercent ?: DefaultCpuThreshold}%")
|
||||
RuleRow("Memory limit", "${server.alertOverrides.memoryPercent ?: DefaultMemoryThreshold}%")
|
||||
RuleRow("Disk limit", "${server.alertOverrides.diskPercent ?: DefaultDiskThreshold}%")
|
||||
RuleRow("p95 latency", "${(server.alertOverrides.latencyP95Millis ?: DefaultLatencyP95ThresholdMs).toInt()} ms")
|
||||
RuleRow("5xx limit", "${server.alertOverrides.errors5xx ?: DefaultErrors5xxThreshold}")
|
||||
RuleRow("Fallback IPs", server.fallbackIpAddresses.ifEmpty { listOf("None") }.joinToString(", "))
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(10.dp)) {
|
||||
Button(onClick = controller::showEditSelectedServer, shape = RoundedCornerShape(8.dp)) { Text("Edit") }
|
||||
OutlinedButton(onClick = controller::deleteSelectedServer, shape = RoundedCornerShape(8.dp)) { Text("Delete") }
|
||||
}
|
||||
}
|
||||
}
|
||||
DataPanel("Privacy") {
|
||||
Column(verticalArrangement = Arrangement.spacedBy(10.dp)) {
|
||||
RuleRow("Storage", "Server profiles, credentials, samples, alerts, and widget choices stay on this device.")
|
||||
RuleRow("Credentials", "Monitor tokens and Basic Auth passwords are encrypted with Android Keystore.")
|
||||
RuleRow("Network", "The app connects only to monitor endpoints configured by the user.")
|
||||
RuleRow("Backups", "Android cloud backup and device transfer are disabled for app data.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import android.content.Intent
|
||||
import android.graphics.Color
|
||||
import android.os.Bundle
|
||||
import android.view.Gravity
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.Button
|
||||
@@ -66,14 +67,14 @@ abstract class BaseWidgetConfigureActivity : Activity() {
|
||||
orientation = RadioGroup.VERTICAL
|
||||
servers.forEachIndexed { index, server ->
|
||||
addView(RadioButton(this@BaseWidgetConfigureActivity).apply {
|
||||
id = index + 1
|
||||
id = View.generateViewId()
|
||||
text = server.name
|
||||
setTextColor(Color.rgb(234, 240, 247))
|
||||
textSize = 16f
|
||||
setPadding(0, 10, 0, 10)
|
||||
})
|
||||
}
|
||||
check(1)
|
||||
check(getChildAt(0).id)
|
||||
}
|
||||
val scroll = ScrollView(this).apply {
|
||||
addView(serverGroup)
|
||||
@@ -98,7 +99,8 @@ abstract class BaseWidgetConfigureActivity : Activity() {
|
||||
}
|
||||
|
||||
root.addView(actionButton("Add ${mode.buttonLabel}") {
|
||||
val serverIndex = (serverGroup.checkedRadioButtonId - 1).coerceAtLeast(0)
|
||||
val checkedView = serverGroup.findViewById<RadioButton>(serverGroup.checkedRadioButtonId)
|
||||
val serverIndex = serverGroup.indexOfChild(checkedView).coerceAtLeast(0)
|
||||
val server = servers[serverIndex]
|
||||
when (mode) {
|
||||
WidgetConfigureMode.Server -> {
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
<item name="android:windowNoTitle">true</item>
|
||||
<item name="android:windowActionBar">false</item>
|
||||
<item name="android:windowLightStatusBar">false</item>
|
||||
<item name="android:windowLightNavigationBar">false</item>
|
||||
<item name="android:windowBackground">@color/command_black</item>
|
||||
<item name="android:fontFamily">sans</item>
|
||||
<item name="android:colorAccent">@color/signal_green</item>
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
Sample backup rules file; uncomment and customize as necessary.
|
||||
See https://developer.android.com/guide/topics/data/autobackup
|
||||
for details.
|
||||
Note: This file is ignored for devices older than API 31
|
||||
See https://developer.android.com/about/versions/12/backup-restore
|
||||
-->
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<full-backup-content>
|
||||
<!--
|
||||
<include domain="sharedpref" path="."/>
|
||||
<exclude domain="sharedpref" path="device.xml"/>
|
||||
-->
|
||||
</full-backup-content>
|
||||
<exclude
|
||||
domain="database"
|
||||
path="." />
|
||||
<exclude
|
||||
domain="sharedpref"
|
||||
path="." />
|
||||
<exclude
|
||||
domain="file"
|
||||
path="." />
|
||||
</full-backup-content>
|
||||
|
||||
@@ -1,19 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
Sample data extraction rules file; uncomment and customize as necessary.
|
||||
See https://developer.android.com/about/versions/12/backup-restore#xml-changes
|
||||
for details.
|
||||
-->
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<data-extraction-rules>
|
||||
<cloud-backup>
|
||||
<!-- TODO: Use <include> and <exclude> to control what is backed up.
|
||||
<include .../>
|
||||
<exclude .../>
|
||||
-->
|
||||
<exclude
|
||||
domain="database"
|
||||
path="." />
|
||||
<exclude
|
||||
domain="sharedpref"
|
||||
path="." />
|
||||
<exclude
|
||||
domain="file"
|
||||
path="." />
|
||||
</cloud-backup>
|
||||
<!--
|
||||
<device-transfer>
|
||||
<include .../>
|
||||
<exclude .../>
|
||||
<exclude
|
||||
domain="database"
|
||||
path="." />
|
||||
<exclude
|
||||
domain="sharedpref"
|
||||
path="." />
|
||||
<exclude
|
||||
domain="file"
|
||||
path="." />
|
||||
</device-transfer>
|
||||
-->
|
||||
</data-extraction-rules>
|
||||
</data-extraction-rules>
|
||||
|
||||
Reference in New Issue
Block a user