feat: theme, app entry points, and the sage identity
Clockula's seed is #6B7A5C, the third step of the family's colour cycle. Calendula's slate (#5C6B7A) and Agendula's mauve (#7A5C6B) are the same three bytes rotated — and that byte rotation is exactly a 120° hue rotation, so the three seeds sit at 210°, 330° and 90° with identical saturation and lightness. The fallback schemes are therefore not eyeballed: they are Agendula's hand-picked scheme with its hue rotated the same 120°, which keeps the three apps structurally one palette turned rather than three colours picked. The cycle closes at three. The launcher icon keeps the family's Calendula bloom badge path-for-path and swaps the task card for a clock dial, drawn as a 308° arc so the badge overhangs into a gap rather than colliding with the stroke — the same device Agendula uses to open its card's corner. MainActivity is M0 scaffolding: theme plus the crash surface, with a placeholder where the four-tab shell and the live pill land in M4. The theme follows stored preferences from M2, once there are any. The manifest declares no permissions yet, deliberately. Clockula's permission set belongs to the alarm engine and is declared in M3 alongside the receivers and the ringing service that need it, so the manifest never claims a capability the code cannot honour. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L94fydiJC37LtxVusNQBDy
This commit is contained in:
co-authored by
Claude Opus 5
parent
9fb02d5083
commit
5ddec0f248
@@ -0,0 +1,57 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<!--
|
||||
No permissions yet, deliberately. Clockula's permission set is the alarm
|
||||
engine's (USE_EXACT_ALARM, POST_NOTIFICATIONS, RECEIVE_BOOT_COMPLETED,
|
||||
USE_FULL_SCREEN_INTENT, FOREGROUND_SERVICE*) and it is declared in M3
|
||||
alongside the receivers and the ringing service that need it — so the
|
||||
manifest never claims a capability the code cannot yet honour. See
|
||||
docs/PLAN.md §4.
|
||||
-->
|
||||
|
||||
<application
|
||||
android:name=".ClockulaApp"
|
||||
android:allowBackup="true"
|
||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||
android:fullBackupContent="@xml/backup_rules"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:localeConfig="@xml/locales_config"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.Clockula"
|
||||
tools:targetApi="35">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTop"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<!-- Standalone crash-report surface; MainActivity routes here on a
|
||||
startup crash-loop. Not exported, kept out of recents. -->
|
||||
<activity
|
||||
android:name=".ui.crash.CrashReportActivity"
|
||||
android:exported="false"
|
||||
android:excludeFromRecents="true"
|
||||
android:launchMode="singleTask" />
|
||||
|
||||
<!-- Persists the per-app language on API < 33, where the platform
|
||||
per-app-languages API is unavailable. On 33+ this is a no-op. -->
|
||||
<service
|
||||
android:name="androidx.appcompat.app.AppLocalesMetadataHolderService"
|
||||
android:enabled="false"
|
||||
android:exported="false">
|
||||
<meta-data
|
||||
android:name="autoStoreLocales"
|
||||
android:value="true" />
|
||||
</service>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
@@ -0,0 +1,34 @@
|
||||
package de.jeanlucmakiola.clockula
|
||||
|
||||
import android.app.Application
|
||||
import dagger.hilt.android.HiltAndroidApp
|
||||
import de.jeanlucmakiola.floret.crash.CrashConfig
|
||||
import de.jeanlucmakiola.floret.crash.CrashReporter
|
||||
|
||||
/**
|
||||
* Application entry point. Registered as android:name=".ClockulaApp".
|
||||
*
|
||||
* For now this is Hilt init plus crash capture. From M3 it also owns the launch-
|
||||
* time alarm re-sync: an alarm's next fire time is resolved against the current
|
||||
* zone, never stored absolutely (docs/PLAN.md §4), so anything that could have
|
||||
* moved while the app was closed has to be re-resolved before the user can see
|
||||
* a stale one.
|
||||
*/
|
||||
@HiltAndroidApp
|
||||
class ClockulaApp : Application() {
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
// Install first thing so startup crashes are captured too (privacy-
|
||||
// respecting, on-device; the user submits the report by hand).
|
||||
CrashReporter.install(
|
||||
this,
|
||||
CrashConfig(
|
||||
appLabel = getString(R.string.app_name),
|
||||
newIssueUrl = getString(R.string.report_issue_url),
|
||||
chooseIssueUrl = getString(R.string.report_issue_url),
|
||||
issueTitle = getString(R.string.crash_report_issue_title),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
package de.jeanlucmakiola.clockula
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import de.jeanlucmakiola.clockula.ui.crash.CrashReportActivity
|
||||
import de.jeanlucmakiola.clockula.ui.theme.ClockulaTheme
|
||||
import de.jeanlucmakiola.floret.crash.CrashReportDialog
|
||||
import de.jeanlucmakiola.floret.crash.CrashReporter
|
||||
import de.jeanlucmakiola.floret.crash.submitCrashReport
|
||||
|
||||
/**
|
||||
* Single activity. M0 scaffolding: it brings up the theme and the crash surface
|
||||
* and nothing else. The four-tab shell and the live pill (docs/PLAN.md §9) land
|
||||
* in M4, and the theme starts following stored preferences once the data layer
|
||||
* exists in M2 — until then [ClockulaTheme]'s own defaults (follow-system,
|
||||
* dynamic colour) stand in.
|
||||
*/
|
||||
@AndroidEntryPoint
|
||||
class MainActivity : ComponentActivity() {
|
||||
|
||||
// A captured crash report awaiting the user's decision, surfaced as a dialog
|
||||
// over the app on the next launch (the single-crash path). A startup
|
||||
// crash-loop is handled out of band, before setContent — see below.
|
||||
private var pendingCrashReport by mutableStateOf<String?>(null)
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
// If the app keeps crashing as it starts, the main UI can't be trusted
|
||||
// to come up. Route to the standalone report screen instead of
|
||||
// re-entering the crashing graph.
|
||||
if (CrashReporter.isCrashLoop(this)) {
|
||||
startActivity(Intent(this, CrashReportActivity::class.java))
|
||||
finish()
|
||||
return
|
||||
}
|
||||
|
||||
enableEdgeToEdge()
|
||||
|
||||
// Surface a single captured crash as a dialog on the next launch.
|
||||
if (CrashReporter.shouldPrompt(this)) pendingCrashReport = CrashReporter.pendingReport(this)
|
||||
|
||||
setContent {
|
||||
ClockulaTheme {
|
||||
Placeholder(Modifier.fillMaxSize())
|
||||
pendingCrashReport?.let { report ->
|
||||
CrashReportDialog(
|
||||
report = report,
|
||||
onSend = {
|
||||
submitCrashReport(this@MainActivity, report)
|
||||
CrashReporter.clearReport(this@MainActivity)
|
||||
pendingCrashReport = null
|
||||
},
|
||||
onDismiss = {
|
||||
CrashReporter.dismissPrompt(this@MainActivity)
|
||||
pendingCrashReport = null
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
// A successful start breaks any loop; reset the timing trail so a later
|
||||
// ordinary crash isn't mistaken for a loop.
|
||||
CrashReporter.markHealthy(this)
|
||||
}
|
||||
}
|
||||
|
||||
/** Stands in for the app shell until M4. Proves the theme resolves and renders. */
|
||||
@Composable
|
||||
private fun Placeholder(modifier: Modifier = Modifier) {
|
||||
Surface(modifier, color = MaterialTheme.colorScheme.background) {
|
||||
Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
|
||||
Text(
|
||||
text = stringResourceAppName(),
|
||||
style = MaterialTheme.typography.displaySmall,
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun stringResourceAppName(): String =
|
||||
androidx.compose.ui.res.stringResource(R.string.app_name)
|
||||
@@ -0,0 +1,61 @@
|
||||
package de.jeanlucmakiola.clockula.ui.crash
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.ui.Modifier
|
||||
import de.jeanlucmakiola.clockula.ui.theme.ClockulaTheme
|
||||
import de.jeanlucmakiola.floret.crash.CrashReportDialog
|
||||
import de.jeanlucmakiola.floret.crash.CrashReporter
|
||||
import de.jeanlucmakiola.floret.crash.submitCrashReport
|
||||
|
||||
/**
|
||||
* Standalone surface for a captured crash report. [MainActivity] routes here
|
||||
* when it detects a startup crash-loop (see [CrashReporter.isCrashLoop]): the
|
||||
* main UI can't be trusted to start, so this screen stays clear of the app's
|
||||
* Hilt graph, DataStore-backed theme and Compose content — it only reads the
|
||||
* report file and shows the kit's report dialog. Plain [ClockulaTheme] defaults
|
||||
* (follow-system, dynamic colour) avoid touching anything that might be the
|
||||
* cause of the crash. The reusable machinery lives in floret-kit's core-crash.
|
||||
*/
|
||||
class CrashReportActivity : ComponentActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
val report = CrashReporter.pendingReport(this)
|
||||
if (report == null) {
|
||||
finish()
|
||||
return
|
||||
}
|
||||
enableEdgeToEdge()
|
||||
setContent {
|
||||
ClockulaTheme {
|
||||
// Opaque backdrop so the dialog doesn't float over a bare task.
|
||||
Surface(Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.surface) {}
|
||||
CrashReportDialog(
|
||||
report = report,
|
||||
onSend = {
|
||||
submitCrashReport(this, report)
|
||||
CrashReporter.clearReport(this)
|
||||
finish()
|
||||
},
|
||||
onDismiss = {
|
||||
CrashReporter.clearReport(this)
|
||||
finish()
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
// Reaching this screen breaks the loop; reset the timing trail so a
|
||||
// later ordinary crash isn't mistaken for a loop.
|
||||
CrashReporter.markHealthy(this)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package de.jeanlucmakiola.clockula.ui.theme
|
||||
|
||||
import androidx.compose.material3.darkColorScheme
|
||||
import androidx.compose.material3.lightColorScheme
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
/**
|
||||
* Seed color anchoring the entire palette. A muted sage, completing the family's
|
||||
* colour cycle: Calendula's cool slate ([0xFF5C6B7A]) and Agendula's warm mauve
|
||||
* ([0xFF7A5C6B]) are the same three bytes rotated, and this is the third
|
||||
* rotation.
|
||||
*
|
||||
* The byte rotation is not a coincidence of notation — it is exactly a 120° hue
|
||||
* rotation. The three seeds sit at 210°, 330° and 90° at identical saturation
|
||||
* and lightness, so the family reads as one palette turned, not three colours
|
||||
* picked. The cycle closes at three; a fourth app needs a different idea.
|
||||
*/
|
||||
val ClockulaSeed: Color = Color(0xFF6B7A5C)
|
||||
|
||||
/**
|
||||
* Fallback light scheme for devices without dynamic color (API < 31) or when the
|
||||
* user disables it. Dynamic color (API 31+) is the real path; these are
|
||||
* Agendula's hand-picked approximation with its hue rotated the same 120°, so
|
||||
* the siblings' schemes stay structurally identical rather than independently
|
||||
* eyeballed.
|
||||
*/
|
||||
val ClockulaLightFallback = lightColorScheme(
|
||||
primary = Color(0xFF5C6A4E),
|
||||
onPrimary = Color(0xFFFFFFFF),
|
||||
primaryContainer = Color(0xFFE8F6D9),
|
||||
onPrimaryContainer = Color(0xFF1D2A10),
|
||||
secondary = Color(0xFF627055),
|
||||
onSecondary = Color(0xFFFFFFFF),
|
||||
background = Color(0xFFFCFEFB),
|
||||
onBackground = Color(0xFF1C1F1A),
|
||||
surface = Color(0xFFFCFEFB),
|
||||
onSurface = Color(0xFF1C1F1A),
|
||||
)
|
||||
|
||||
val ClockulaDarkFallback = darkColorScheme(
|
||||
primary = Color(0xFFCEE2BA),
|
||||
onPrimary = Color(0xFF334025),
|
||||
primaryContainer = Color(0xFF4A583B),
|
||||
onPrimaryContainer = Color(0xFFE8F6D9),
|
||||
secondary = Color(0xFFCAD8BC),
|
||||
onSecondary = Color(0xFF313A28),
|
||||
background = Color(0xFF141611),
|
||||
onBackground = Color(0xFFE4E9E0),
|
||||
surface = Color(0xFF141611),
|
||||
onSurface = Color(0xFFE4E9E0),
|
||||
)
|
||||
@@ -0,0 +1,28 @@
|
||||
package de.jeanlucmakiola.clockula.ui.theme
|
||||
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import de.jeanlucmakiola.floret.identity.FloretExpressiveTheme
|
||||
|
||||
/**
|
||||
* Clockula's theme: the family's [FloretExpressiveTheme] machinery (dynamic
|
||||
* colour on API 31+, system light/dark, the standard motion scheme) fed with
|
||||
* Clockula's own identity — its seed-derived fallback schemes
|
||||
* ([ClockulaLightFallback] / [ClockulaDarkFallback]) and [ClockulaTypography].
|
||||
* The mechanics live in floret-kit; the look stays here.
|
||||
*/
|
||||
@Composable
|
||||
fun ClockulaTheme(
|
||||
darkTheme: Boolean = isSystemInDarkTheme(),
|
||||
dynamicColor: Boolean = true,
|
||||
content: @Composable () -> Unit,
|
||||
) {
|
||||
FloretExpressiveTheme(
|
||||
lightScheme = ClockulaLightFallback,
|
||||
darkScheme = ClockulaDarkFallback,
|
||||
darkTheme = darkTheme,
|
||||
dynamicColor = dynamicColor,
|
||||
typography = ClockulaTypography,
|
||||
content = content,
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package de.jeanlucmakiola.clockula.ui.theme
|
||||
|
||||
import androidx.compose.material3.Typography
|
||||
|
||||
/**
|
||||
* Default Material 3 Expressive typography. A clock app is mostly one enormous
|
||||
* number, so the readout scale is the real typographic decision here — it gets
|
||||
* settled against a working stopwatch in M7, not guessed at in the scaffolding.
|
||||
*/
|
||||
val ClockulaTypography = Typography()
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="@color/ic_launcher_background" />
|
||||
</shape>
|
||||
@@ -0,0 +1,93 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Clockula launcher icon foreground.
|
||||
|
||||
A rounded line-art clock face, plus the same small Calendula bloom badge in
|
||||
the bottom-right corner that Calendula and Agendula carry — the family mark,
|
||||
kept path-for-path identical so the three icons read as siblings.
|
||||
|
||||
Strokes render in off-white (#FAF6F0) over the sage background drawable
|
||||
(drawable/ic_launcher_background.xml = @color/ic_launcher_background, the
|
||||
third 120-degree hue rotation of Calendula's slate; see ui/theme/Color.kt).
|
||||
The same vector fills the <monochrome> slot so Android 13+ themed-icon
|
||||
launchers can recolour it.
|
||||
|
||||
Geometry: the dial is centred on (252, 242.5) with r=110, matching the task
|
||||
card's centre in Agendula's icon so the two sit identically in the grid. The
|
||||
dial is drawn as a 308-degree arc rather than a closed circle, breaking
|
||||
between roughly 20 and 72 degrees below the horizontal so the bloom badge
|
||||
overhangs into a gap instead of colliding with the stroke — the same device
|
||||
Agendula uses to open its card's bottom-right corner.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="512"
|
||||
android:viewportHeight="512">
|
||||
<group
|
||||
android:pivotX="256"
|
||||
android:pivotY="242.76"
|
||||
android:scaleX="0.66"
|
||||
android:scaleY="0.66"
|
||||
android:translateY="13.24">
|
||||
<!-- Dial: open at the bottom-right for the bloom -->
|
||||
<path
|
||||
android:strokeColor="#FFFAF6F0"
|
||||
android:strokeWidth="20"
|
||||
android:strokeLineCap="round"
|
||||
android:strokeLineJoin="round"
|
||||
android:pathData="M355.4 280.1 A110 110 0 1 0 286.0 347.1" />
|
||||
<!-- Minute hand, straight up -->
|
||||
<path
|
||||
android:strokeColor="#FFFAF6F0"
|
||||
android:strokeWidth="20"
|
||||
android:strokeLineCap="round"
|
||||
android:strokeLineJoin="round"
|
||||
android:pathData="M252 242.5 L252 152.5" />
|
||||
<!-- Hour hand -->
|
||||
<path
|
||||
android:strokeColor="#FFFAF6F0"
|
||||
android:strokeWidth="20"
|
||||
android:strokeLineCap="round"
|
||||
android:strokeLineJoin="round"
|
||||
android:pathData="M252 242.5 L312 242.5" />
|
||||
<!-- Calendula bloom: petals around the centre -->
|
||||
<path
|
||||
android:strokeColor="#FFFAF6F0"
|
||||
android:strokeWidth="16"
|
||||
android:strokeLineCap="round"
|
||||
android:strokeLineJoin="round"
|
||||
android:pathData="M346.672 323.721C356.301 323.721 364.107 312.367 364.107 298.361C364.107 284.354 356.301 273 346.672 273C337.042 273 329.236 284.354 329.236 298.361C329.236 312.367 337.042 323.721 346.672 323.721Z" />
|
||||
<path
|
||||
android:strokeColor="#FFFAF6F0"
|
||||
android:strokeWidth="16"
|
||||
android:strokeLineCap="round"
|
||||
android:strokeLineJoin="round"
|
||||
android:pathData="M355.716 330.293C358.692 339.451 371.903 343.366 385.224 339.038C398.544 334.71 406.931 323.777 403.955 314.619C400.98 305.461 387.769 301.546 374.448 305.874C361.127 310.202 352.741 321.135 355.716 330.293Z" />
|
||||
<path
|
||||
android:strokeColor="#FFFAF6F0"
|
||||
android:strokeWidth="16"
|
||||
android:strokeLineCap="round"
|
||||
android:strokeLineJoin="round"
|
||||
android:pathData="M352.262 340.926C344.471 346.586 344.83 360.36 353.063 371.691C361.295 383.022 374.284 387.62 382.075 381.96C389.865 376.3 389.506 362.526 381.274 351.194C373.041 339.863 360.052 335.266 352.262 340.926Z" />
|
||||
<path
|
||||
android:strokeColor="#FFFAF6F0"
|
||||
android:strokeWidth="16"
|
||||
android:strokeLineCap="round"
|
||||
android:strokeLineJoin="round"
|
||||
android:pathData="M341.082 340.926C333.291 335.266 320.302 339.863 312.069 351.194C303.837 362.526 303.478 376.3 311.268 381.96C319.059 387.62 332.048 383.022 340.28 371.691C348.513 360.36 348.872 346.585 341.082 340.926Z" />
|
||||
<path
|
||||
android:strokeColor="#FFFAF6F0"
|
||||
android:strokeWidth="16"
|
||||
android:strokeLineCap="round"
|
||||
android:strokeLineJoin="round"
|
||||
android:pathData="M337.627 330.293C340.602 321.135 332.216 310.202 318.895 305.874C305.574 301.546 292.363 305.461 289.388 314.619C286.412 323.777 294.799 334.71 308.119 339.038C321.44 343.366 334.651 339.451 337.627 330.293Z" />
|
||||
<!-- Bloom centre -->
|
||||
<path
|
||||
android:strokeColor="#FFFAF6F0"
|
||||
android:strokeWidth="16"
|
||||
android:strokeLineCap="round"
|
||||
android:strokeLineJoin="round"
|
||||
android:pathData="M346.672 342.742C351.924 342.742 356.182 338.484 356.182 333.232C356.182 327.979 351.924 323.721 346.672 323.721C341.419 323.721 337.161 327.979 337.161 333.232C337.161 338.484 341.419 342.742 346.672 342.742Z" />
|
||||
</group>
|
||||
</vector>
|
||||
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Notification status-bar icon: a simple clock face, tinted white by the system. -->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="#FFFFFFFF">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M12,2A10,10 0 1,0 12,22A10,10 0 1,0 12,2M12,20A8,8 0 1,1 12,4A8,8 0 1,1 12,20" />
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M12.5,7h-1.5v6l5.2,3.1l0.8,-1.2l-4.5,-2.7z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
||||
@@ -0,0 +1,7 @@
|
||||
<resources>
|
||||
<!-- Seed color: muted sage. Material 3 derives Light & Dark schemes from this.
|
||||
The third 120-degree hue rotation of Calendula's slate; see ui/theme/Color.kt. -->
|
||||
<color name="seed">#FF6B7A5C</color>
|
||||
<!-- Adaptive icon background -->
|
||||
<color name="ic_launcher_background">#FF6B7A5C</color>
|
||||
</resources>
|
||||
@@ -0,0 +1,8 @@
|
||||
<resources>
|
||||
<string name="app_name">Clockula</string>
|
||||
<string name="app_tagline">A modern Material 3 Expressive clock app.\nComing into bloom.</string>
|
||||
|
||||
<!-- Crash reporting (floret-kit core-crash) -->
|
||||
<string name="crash_report_issue_title">Crash report</string>
|
||||
<string name="report_issue_url" translatable="false">https://codeberg.org/jlmakiola/clockula/issues/new</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,7 @@
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<style name="Theme.Clockula" parent="android:Theme.Material.Light.NoActionBar">
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:navigationBarColor">@android:color/transparent</item>
|
||||
<item name="android:windowLightStatusBar">true</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<full-backup-content>
|
||||
<!-- No file-based backups; settings live in DataStore which is backed up by default. -->
|
||||
</full-backup-content>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<data-extraction-rules>
|
||||
<cloud-backup>
|
||||
<!-- Allow DataStore backup, exclude nothing extra. -->
|
||||
</cloud-backup>
|
||||
<device-transfer>
|
||||
</device-transfer>
|
||||
</data-extraction-rules>
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
The languages Clockula ships translations for. Single source of truth: each
|
||||
entry needs a matching res/values-<tag>/strings.xml, and is surfaced in both
|
||||
the in-app language picker (parsed at runtime by AppLanguage) and the system
|
||||
per-app language settings (Android 13+, via android:localeConfig). To add a
|
||||
translation, drop in the values-<tag> folder and add one <locale> line here.
|
||||
-->
|
||||
<locale-config xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<locale android:name="en" />
|
||||
</locale-config>
|
||||
Reference in New Issue
Block a user