small changes

This commit is contained in:
2026-06-24 12:17:15 +02:00
parent 6bb1772608
commit 28e2309894
12 changed files with 79 additions and 82 deletions

View File

@ -23,7 +23,8 @@ android {
buildTypes { buildTypes {
release { release {
isMinifyEnabled = false isMinifyEnabled = true
isShrinkResources = true
proguardFiles( proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"), getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro" "proguard-rules.pro"
@ -36,6 +37,7 @@ android {
} }
buildFeatures { buildFeatures {
compose = true compose = true
buildConfig = true
} }
} }

View File

@ -1,21 +1,15 @@
# Add project specific ProGuard rules here. # Gson models used for API parsing.
# You can control the set of applied configuration files using the -keep class com.tomhempel.coordinatorapp.data.** { *; }
# proguardFiles setting in build.gradle. -keep class com.tomhempel.coordinatorapp.network.** { *; }
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following # AndroidX Security crypto (EncryptedSharedPreferences / MasterKey)
# and specify the fully qualified class name to the JavaScript interface -keep class androidx.security.crypto.** { *; }
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for # Gson reflective serialization
# debugging stack traces. -keepattributes Signature
#-keepattributes SourceFile,LineNumberTable -keepattributes *Annotation*
-dontwarn sun.misc.**
# If you keep the line number information, uncomment this to # Keep line numbers for crash reports.
# hide the original source file name. -keepattributes SourceFile,LineNumberTable
#-renamesourcefileattribute SourceFile -renamesourcefileattribute SourceFile

View File

@ -5,7 +5,7 @@
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<application <application
android:allowBackup="true" android:allowBackup="false"
android:dataExtractionRules="@xml/data_extraction_rules" android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules" android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"

View File

@ -0,0 +1,11 @@
package com.tomhempel.coordinatorapp.network
import android.util.Log
import com.tomhempel.coordinatorapp.BuildConfig
internal object ApiLog {
fun response(label: String, httpCode: Int, body: String?) {
if (!BuildConfig.DEBUG) return
Log.d("NAT_AS_API", "$label HTTP $httpCode (${body?.length ?: 0} bytes)")
}
}

View File

@ -176,6 +176,7 @@ object NatAsApiClient {
private inline fun <T> execute(request: Request, parse: (JsonObject) -> T): T { private inline fun <T> execute(request: Request, parse: (JsonObject) -> T): T {
client.newCall(request).execute().use { response -> client.newCall(request).execute().use { response ->
val bodyText = response.body?.string() val bodyText = response.body?.string()
ApiLog.response("${request.method} ${request.url.encodedPath}", response.code, bodyText)
val root = parseEnvelope(response.code, bodyText) val root = parseEnvelope(response.code, bodyText)
val data = root.get("data") val data = root.get("data")
return when { return when {

View File

@ -1,6 +1,7 @@
package com.tomhempel.coordinatorapp.ui.components package com.tomhempel.coordinatorapp.ui.components
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
@ -15,7 +16,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.vectorResource import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
@ -44,25 +44,19 @@ fun CoordinatorBrandBadge(
iconSize: Dp = 40.dp, iconSize: Dp = 40.dp,
) { ) {
val scheme = MaterialTheme.colorScheme val scheme = MaterialTheme.colorScheme
val shape = RoundedCornerShape(22.dp)
Box( Box(
modifier = modifier modifier = modifier
.size(size) .size(size)
.clip(RoundedCornerShape(22.dp)) .clip(shape)
.background( .border(1.dp, scheme.outline, shape)
Brush.linearGradient( .background(scheme.surface),
colors = listOf(
scheme.primary,
scheme.primary.copy(alpha = 0.82f),
scheme.primaryContainer,
),
),
),
contentAlignment = Alignment.Center, contentAlignment = Alignment.Center,
) { ) {
Icon( Icon(
imageVector = ImageVector.vectorResource(R.drawable.ic_coordinator_mark), imageVector = ImageVector.vectorResource(R.drawable.ic_coordinator_mark),
contentDescription = null, contentDescription = null,
tint = scheme.onPrimary, tint = scheme.primary,
modifier = Modifier.size(iconSize), modifier = Modifier.size(iconSize),
) )
} }

View File

@ -25,7 +25,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.Dp
@ -40,15 +39,7 @@ fun CoordinatorBackground(
Box( Box(
modifier = modifier modifier = modifier
.fillMaxSize() .fillMaxSize()
.background( .background(scheme.background),
Brush.verticalGradient(
colors = listOf(
scheme.background,
scheme.surfaceVariant,
scheme.background,
),
),
),
) { ) {
content() content()
} }

View File

@ -3,7 +3,7 @@ package com.tomhempel.coordinatorapp.ui.theme
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
val BrandPurple = Color(0xFF6E56CF) val BrandPurple = Color(0xFF6E56CF)
val BrandPurpleDark = Color(0xFF9B8AE8) val BrandPurpleDark = Color(0xFF8F84B8)
val BrandWindowBg = Color(0xFFF4F8F7) val BrandWindowBg = Color(0xFFF4F8F7)
val BrandSurface = Color(0xFFFFFFFF) val BrandSurface = Color(0xFFFFFFFF)
@ -13,9 +13,9 @@ val BrandStroke = Color(0xFFD5E4E0)
val BrandDestructive = Color(0xFFC62828) val BrandDestructive = Color(0xFFC62828)
val BrandAccentContainer = Color(0xFFE6F4F0) val BrandAccentContainer = Color(0xFFE6F4F0)
val BrandWindowBgDark = Color(0xFF121A19) val BrandWindowBgDark = Color(0xFF0F1413)
val BrandSurfaceDark = Color(0xFF1E2A28) val BrandSurfaceDark = Color(0xFF171D1C)
val BrandTextLight = Color(0xFFE8F2F0) val BrandTextLight = Color(0xFFE4EDEB)
val BrandTextMutedDark = Color(0xFF8AA39E) val BrandTextMutedDark = Color(0xFF7F9490)
val BrandStrokeDark = Color(0xFF2D403C) val BrandStrokeDark = Color(0xFF2B3634)
val BrandAccentContainerDark = Color(0xFF243532) val BrandAccentContainerDark = Color(0xFF222A28)

View File

@ -30,14 +30,14 @@ private val LightColorScheme = lightColorScheme(
private val DarkColorScheme = darkColorScheme( private val DarkColorScheme = darkColorScheme(
primary = BrandPurpleDark, primary = BrandPurpleDark,
onPrimary = Color(0xFF1F163D), onPrimary = BrandWindowBgDark,
primaryContainer = BrandAccentContainerDark, primaryContainer = BrandAccentContainerDark,
onPrimaryContainer = BrandTextLight, onPrimaryContainer = BrandTextLight,
background = BrandWindowBgDark, background = BrandWindowBgDark,
onBackground = BrandTextLight, onBackground = BrandTextLight,
surface = BrandSurfaceDark, surface = BrandSurfaceDark,
onSurface = BrandTextLight, onSurface = BrandTextLight,
surfaceVariant = BrandAccentContainerDark, surfaceVariant = BrandSurfaceDark,
onSurfaceVariant = BrandTextMutedDark, onSurfaceVariant = BrandTextMutedDark,
outline = BrandStrokeDark, outline = BrandStrokeDark,
error = BrandDestructive, error = BrandDestructive,

View File

@ -45,13 +45,30 @@ class CoordinatorViewModel(application: Application) : AndroidViewModel(applicat
counselors = counselors, counselors = counselors,
) )
} }
} catch (_: Exception) { } catch (e: ApiException) {
SessionStore.clear(context) if (e.isAuthError()) {
_uiState.update { CoordinatorUiState() } SessionStore.clear(context)
_uiState.update { CoordinatorUiState() }
} else {
_uiState.update {
CoordinatorUiState(
errorMessage = e.message ?: "Could not verify session",
)
}
}
} catch (e: Exception) {
_uiState.update {
CoordinatorUiState(
errorMessage = e.message ?: "Could not verify session",
)
}
} }
} }
} }
private fun ApiException.isAuthError(): Boolean =
code == "UNAUTHORIZED" || code == "FORBIDDEN" || code == "PASSWORD_CHANGE_REQUIRED"
fun login(username: String, password: String) { fun login(username: String, password: String) {
val trimmedUser = username.trim() val trimmedUser = username.trim()
if (trimmedUser.isBlank() || password.isBlank()) { if (trimmedUser.isBlank() || password.isBlank()) {

View File

@ -1,13 +1,6 @@
<?xml version="1.0" encoding="utf-8"?><!-- <?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
-->
<full-backup-content> <full-backup-content>
<!-- <exclude domain="sharedpref" path="." />
<include domain="sharedpref" path="."/> <exclude domain="database" path="." />
<exclude domain="sharedpref" path="device.xml"/> <exclude domain="file" path="." />
-->
</full-backup-content> </full-backup-content>

View File

@ -1,19 +1,13 @@
<?xml version="1.0" encoding="utf-8"?><!-- <?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.
-->
<data-extraction-rules> <data-extraction-rules>
<cloud-backup> <cloud-backup>
<!-- TODO: Use <include> and <exclude> to control what is backed up. <exclude domain="sharedpref" path="." />
<include .../> <exclude domain="database" path="." />
<exclude .../> <exclude domain="file" path="." />
-->
</cloud-backup> </cloud-backup>
<!--
<device-transfer> <device-transfer>
<include .../> <exclude domain="sharedpref" path="." />
<exclude .../> <exclude domain="database" path="." />
<exclude domain="file" path="." />
</device-transfer> </device-transfer>
-->
</data-extraction-rules> </data-extraction-rules>