diff --git a/docs/wear-os-implementation-plan.md b/docs/wear-os-implementation-plan.md
new file mode 100644
index 00000000..54d3eee7
--- /dev/null
+++ b/docs/wear-os-implementation-plan.md
@@ -0,0 +1,241 @@
+# Bitchat for Pixel Watch — Implementation Plan
+
+> **Status tracker**: each milestone carries a status (`pending` / `in-progress` / `done`) and a
+> checklist. A milestone may only be started when the previous milestone's success criteria pass.
+> Update statuses in this file as work progresses.
+
+| Milestone | Title | Status |
+|-----------|-------|--------|
+| M0 | Scaffolding & plan document | done |
+| M1 | Shared core compiles on Wear | pending |
+| M2 | BLE transport & background service on watch | pending |
+| M3 | Global chat | pending |
+| M4 | Noise DMs & people screen | pending |
+| M5 | File/image receive & display — **DEFERRED** (post-M7, later day) | deferred |
+| M6 | ADB test hook & mesh_lab interop | pending |
+| M7 | Polish & final design pass | pending |
+
+---
+
+## 1. Context for a fresh coding agent
+
+- **Reference app**: this repository (`bitchat-android`) is a fully working, decentralized BLE mesh
+ chat client. Single Gradle module `:app`, root package `com.bitchat.android`, applicationId
+ `com.bitchat.droid`. See `AGENTS.md` for the full architecture overview.
+- **Goal**: a new `:wear` Gradle module (applicationId `com.bitchat.watch`) — a standalone Wear OS
+ app for the Pixel Watch. **Bluetooth mesh only**: global chat, Noise-encrypted direct messages,
+ and receiving/displaying files & images. It must be a fully interoperable bitchat client: scan,
+ advertise, connect, relay, handshake, and exchange messages with the Android (and iOS) apps.
+- **Explicitly out of scope**: no internet features (no Nostr, no Tor/Arti, no relays), no GPS /
+ geohash / location channels, no Wi-Fi Aware, no hotspot/APK sharing, no voice notes recording.
+ The watch manifest must not even declare `INTERNET` or location permissions.
+- **Hard constraint**: **zero modifications to `:app` production code.** The only allowed changes
+ to shared repo files are: `settings.gradle.kts` (add `include(":wear")`), entries in
+ `gradle/libs.versions.toml` (new wear dependencies only), the new `wear/` directory, and docs.
+ All shared Kotlin code is consumed by the `:wear` module *in place* via Gradle source sets —
+ files are never moved, copied, or edited.
+
+## 2. Code reuse strategy (shared source sets)
+
+Wear OS is Android. `android.util.Log`, `android.bluetooth.*`, `EncryptedSharedPreferences`
+(androidx.security), BouncyCastle, and coroutines all work on the watch, so the vast majority of
+the bitchat protocol stack compiles unmodified.
+
+In `wear/build.gradle.kts`:
+
+```kotlin
+sourceSets["main"].java.srcDir("../app/src/main/java") // with include filters (see below)
+```
+
+**Include** (iteratively refined by fixing compile errors — the include list lives in
+`wear/build.gradle.kts` with comments):
+
+- `protocol/**` — wire format, `BinaryProtocol`, `CompressionUtil`, `MessagePadding`
+- `model/**` — `BitchatMessage`, `BitchatFilePacket`, `FragmentPayload`, `NoiseEncrypted`,
+ `IdentityAnnouncement`, `RoutedPacket`
+- `noise/**` — `NoiseSession`, `NoiseSessionManager`, `NoiseEncryptionService`,
+ `NoiseChannelEncryption`, vendored pure-Java `noise/southernstorm/**`
+- `crypto/**` — `EncryptionService`
+- `identity/**` — `SecureIdentityStateManager`
+- `mesh/**` — BLE stack (`BluetoothConnectionManager`, GATT server/client managers, broadcaster,
+ tracker, permission manager), `FragmentManager`, `SecurityManager`, `PacketProcessor`,
+ `MessageHandler`, `PeerManager`, `StoreForwardManager`, `MeshTransport`, `MeshService`,
+ `TransferProgressManager`, `PrivateMediaTransfer`, `PowerManager`
+- `services/AppStateStore.kt` — process-wide state store
+- `util/AppConstants.kt` — shared constants (GATT UUIDs, fragmentation sizes)
+- Small transitive deps the compiler reveals (known: `ui/debug/DebugSettingsManager.kt` is
+ referenced from the mesh layer — include the file, not the package)
+
+**Exclude**: `ui/**` (except forced single-file includes), `onboarding/**`, `nostr/**`, `net/**`,
+`geohash/**`, `wifi-aware/**`, `hotspot/**`, `features/voice/**`, `service/MeshForegroundService.kt`
+(wear gets its own service), `BitchatApplication.kt`, `MainActivity.kt`.
+
+**Tests**: the app's own unit tests for shared packages (`protocol`, `noise`, `crypto`, `mesh`)
+are wired into the `:wear` test source set the same way (srcDir + includes), so shared behavior is
+continuously verified on both modules.
+
+**Resources**: font files cannot be selectively shared via srcDir cleanly — copy the 4 Geist Mono
+font files (`app/src/main/res/font/geist_mono_*`) into `wear/src/main/res/font/`. Theme/palette/
+peer-color logic is re-created as wear-owned files mirroring `ui/theme/` values exactly.
+
+## 3. Watch UX design
+
+Wear Compose Material3 (round-screen safe by default):
+
+- **Screens**: Chat (global timeline) → People (connected peers w/ RSSI, unread badges) →
+ DM conversation. Edge-swipe back, `TimeText` scaffold, rotary crown scrolling.
+- **Visual identity** (mirrors `ui/theme/` exactly): black background `#000000`, green primary
+ `#32D74B`, error `#FF453A`, orange accent for self/mentions, djb2-hash stable peer colors
+ (`PeerColors.kt` algorithm), Geist Mono typography, `BitchatMotion` timing tokens
+ (120/180/240 ms) for all animations.
+- **Input**: text field using the Pixel Watch Gboard IME, plus voice dictation via
+ `RecognizerIntent`. Haptic feedback on incoming messages.
+- **Background**: wear-owned foreground service (type `connectedDevice`) keeps scan/advertise
+ alive; shared `PowerManager` provides duty-cycling.
+
+## 4. Hardware & test environment
+
+- Pixel Watch connected via ADB (target device for all milestones; screencaps via
+ `adb exec-out screencap`).
+- Two phones running the Android bitchat app, also on ADB, for interop testing (used heavily from
+ M6; manual interop checks from M2 onward).
+- Design verification: at every UI milestone, take ADB screencaps of every screen and review them
+ for round-screen clipping, element visibility, contrast, and touch-target size. A milestone does
+ not pass until its screencap set is approved.
+
+## 5. Risks & notes
+
+- `BluetoothMeshService` (legacy monolith) vs `MeshCore` — prefer wiring the shared components
+ directly (MeshCore-style composition) in the wear service.
+- `mesh/` references `ui/debug/DebugSettingsManager` — include that single file; do not pull in
+ the debug UI sheet.
+- Wear BLE MTUs are small; the shared fragmentation layer (469-byte fragments) already handles
+ this.
+- `EncryptedSharedPreferences` (androidx.security-crypto) works on Wear OS — identity persistence
+ is reused as-is.
+- Watch has no camera/gallery: file transfer is **receive + display only** (confirmed decision).
+
+---
+
+## Milestones
+
+### M0 — Scaffolding & plan document
+
+- [x] Write this plan to `docs/wear-os-implementation-plan.md`
+- [x] Create `:wear` module: `wear/build.gradle.kts`, manifest
+ (``, standalone, BT permissions,
+ **no INTERNET/location**), `MainActivity` with hello-world screen using the ported theme
+- [x] Add Wear Compose dependencies to `gradle/libs.versions.toml`; `include(":wear")` in
+ `settings.gradle.kts`
+- [x] Build, install, and launch on the physical Pixel Watch via ADB; take first screencap
+
+**Success criteria**: `./gradlew :wear:assembleDebug` green; app launches on the watch;
+`git diff --name-only` shows no changes under `app/src/`.
+**Result**: PASSED — installed on Pixel Watch 3 (serial 4C201JEAYW0020), launch screencap shows
+"bitchat" wordmark (green `#32D74B`, Geist Mono, black background) correctly centered on the
+round display. No `app/src/` changes.
+
+---
+
+### M1 — Shared core compiles on Wear
+
+- [ ] Configure srcDir include list in `wear/build.gradle.kts`; resolve transitive dependencies by
+ extending includes (never by copying Kotlin sources)
+- [ ] Copy Geist Mono fonts; create wear theme/palette/peer-color files mirroring `ui/theme/`
+- [ ] Wire shared unit tests (`protocol`, `noise`, `crypto`, `mesh`) into `:wear` test source set
+- [ ] `./gradlew :app:test :wear:test` green
+
+**Success criteria**: the entire shared stack (protocol, noise, crypto, identity, mesh, model,
+AppStateStore) compiles into `:wear`; both modules' unit tests pass; `app/src/` untouched.
+
+---
+
+### M2 — BLE transport & background service on watch
+
+- [ ] Wear onboarding flow: Bluetooth-enable check + runtime permission requests
+ (`BLUETOOTH_SCAN/CONNECT/ADVERTISE`), watch-styled screens
+- [ ] `WearMeshService` foreground service (type `connectedDevice`); wire shared
+ `BluetoothConnectionManager` + mesh components; start scanning + advertising
+- [ ] Internal debug screen: discovered peers with RSSI (temporary, replaced by real UI in M3/M4)
+- [ ] Manual interop check: watch and one phone mutually discover
+
+**Success criteria**: the phone's bitchat app lists the watch as a connected peer and vice versa
+(logcat + screencap evidence); mesh survives the screen turning off (ambient mode) for 5 minutes.
+
+---
+
+### M3 — Global chat
+
+- [ ] Nickname onboarding; identity announcement over the mesh
+- [ ] Send/receive/relay public `BitchatMessage`s (relay/TTL comes free from shared mesh code)
+- [ ] Chat timeline UI (`ScalingLazyColumn`, message bubbles per bitchat style, peer colors,
+ timestamps) + composer (IME + `RecognizerIntent` dictation) + incoming-message haptics
+- [ ] Design check: ADB screencaps of onboarding, chat (empty/populated), composer; review for
+ round-screen clipping/visibility/contrast
+
+**Success criteria**: two-way public chat between watch and phone; messages the watch relays reach
+a second phone that is only connected through the first (relay proof); screencap set approved.
+
+---
+
+### M4 — Noise DMs & people screen
+
+- [ ] People screen: connected peers, nicknames, RSSI, unread-DM badges
+- [ ] Tap peer → Noise XX handshake (shared `EncryptionService`/`NoiseSessionManager`) → DM thread
+- [ ] DM conversation UI; unread counters; delivery/read receipts if supported by shared code
+- [ ] Identity persistence (`EncryptedSharedPreferences`); stale-session detection & automatic
+ re-handshake after watch app restart
+- [ ] Design check: screencaps of people screen, handshake state, DM thread
+
+**Success criteria**: encrypted DM round trip with the phone; DMs survive a watch app restart
+(session recovery); screencap set approved.
+
+---
+
+### M5 — File/image receive & display — **DEFERRED**
+
+> Deferred to a later day (after M7). Milestones M6 and M7 do not depend on M5 and proceed
+> without it. The mesh_lab `file` scenario for the watch is skipped until M5 is un-deferred.
+
+- [ ] Receive broadcast files (`MessageType.FILE_TRANSFER`, `BitchatFilePacket` TLV decode,
+ fragment reassembly — all shared)
+- [ ] Receive Noise-encrypted private files (`NoisePayloadType.FILE_TRANSFER`)
+- [ ] Inline image rendering in chat timelines; full-screen image viewer (pinch/crown zoom);
+ non-image files saved with a way to open/share them
+- [ ] Transfer progress indicator; respect shared fragment/size caps
+- [ ] Design check: screencaps of inline image, full-screen viewer, transfer progress
+
+**Success criteria**: phone→watch image renders inline in both global chat and DM; SHA-256 of
+received file matches sender; screencap set approved. (Sending files from the watch is out of
+scope.)
+
+---
+
+### M6 — ADB test hook & mesh_lab interop
+
+- [ ] Wear debug-only `TestHookReceiver` (`wear/src/debug/`) mirroring the phone's command set:
+ `ping`, `start`, `stop`, `whoami`, `set_nickname`, `scan`, `peers`, `connect`, `handshake`,
+ `session`, `announce`, `broadcast_msg`, `dm_send`, `dm_recv`, `msg_recv`, `file_recv`, `state`,
+ `clear_results` — broadcast action `com.bitchat.watch.TEST_HOOK`, same JSON-result-file protocol
+- [ ] Extend `tools/release_gate/mesh_lab.py`: `--serial-watch` argument and phone↔watch scenarios
+ (`dm`, `broadcast`, `session_recovery`, `all`; `file` excluded while M5 is deferred), reusing
+ the existing `Device`/`cmd` machinery
+- [ ] Run full scenario suite phone↔watch; store evidence JSON
+
+**Success criteria**:
+`python3 tools/release_gate/mesh_lab.py scenario all --serial-a --serial-watch `
+exits 0 with evidence files; no manual intervention.
+
+---
+
+### M7 — Polish & final design pass
+
+- [ ] Animations/transitions per `BitchatMotion` tokens; message-appear animations; screen
+ transitions; rotary scroll feel; splash screen & app icon (bitchat wordmark style)
+- [ ] Power/battery: verify shared `PowerManager` duty-cycling behaves on Wear; ambient-mode
+ behavior; memory audit (fragment/image caps)
+- [ ] Full screencap design review of every screen and state; fix all findings
+- [ ] Update this document: all milestones `done`; add a short "how to build/run/test" section
+
+**Success criteria**: all milestones marked `done`; interop suite green; final screencap set
+approved; a fresh agent can build, install, and test the watch app from this document alone.
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 95e83d07..4745b097 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -21,6 +21,10 @@ navigation-compose = "2.9.8"
# Accompanist
accompanist-permissions = "0.37.3"
+# Wear OS
+wear-compose = "1.6.2"
+wear-tooling-preview = "1.0.0"
+
# Cryptography
bouncycastle = "1.85"
tink-android = "1.23.0"
@@ -95,6 +99,11 @@ androidx-navigation-compose = { module = "androidx.navigation:navigation-compose
# Accompanist
accompanist-permissions = { module = "com.google.accompanist:accompanist-permissions", version.ref = "accompanist-permissions" }
+# Wear OS
+androidx-wear-compose-foundation = { module = "androidx.wear.compose:compose-foundation", version.ref = "wear-compose" }
+androidx-wear-compose-material3 = { module = "androidx.wear.compose:compose-material3", version.ref = "wear-compose" }
+androidx-wear-tooling-preview = { module = "androidx.wear:wear-tooling-preview", version.ref = "wear-tooling-preview" }
+
# Cryptography
bouncycastle-bcprov = { module = "org.bouncycastle:bcprov-jdk18on", version.ref = "bouncycastle" }
google-tink-android = { module = "com.google.crypto.tink:tink-android", version.ref = "tink-android" }
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 53c50616..0d96a216 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -17,4 +17,5 @@ dependencyResolutionManagement {
rootProject.name = "bitchat-android"
include(":app")
+include(":wear")
// Using published Arti AAR; local module not included
diff --git a/wear/build.gradle.kts b/wear/build.gradle.kts
new file mode 100644
index 00000000..72c4d57c
--- /dev/null
+++ b/wear/build.gradle.kts
@@ -0,0 +1,89 @@
+import org.jetbrains.kotlin.gradle.dsl.JvmTarget
+
+plugins {
+ alias(libs.plugins.android.application)
+ alias(libs.plugins.kotlin.parcelize)
+ alias(libs.plugins.kotlin.compose)
+}
+
+android {
+ namespace = "com.bitchat.watch"
+ compileSdk = libs.versions.compileSdk.get().toInt()
+
+ defaultConfig {
+ applicationId = "com.bitchat.watch"
+ minSdk = 30 // Wear OS 3 (Pixel Watch 1); BLE APIs match the phone app's usage
+ targetSdk = libs.versions.targetSdk.get().toInt()
+ versionCode = 1
+ versionName = "0.1.0"
+
+ vectorDrawables {
+ useSupportLibrary = true
+ }
+ }
+
+ buildTypes {
+ release {
+ isMinifyEnabled = true
+ isShrinkResources = true
+ proguardFiles(
+ getDefaultProguardFile("proguard-android-optimize.txt"),
+ "proguard-rules.pro"
+ )
+ }
+ }
+
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_11
+ targetCompatibility = JavaVersion.VERSION_11
+ }
+ buildFeatures {
+ compose = true
+ buildConfig = true
+ }
+ packaging {
+ resources {
+ excludes += "/META-INF/{AL2.0,LGPL2.1}"
+ }
+ }
+ lint {
+ abortOnError = false
+ checkReleaseBuilds = false
+ }
+}
+
+kotlin {
+ compilerOptions {
+ jvmTarget.set(JvmTarget.JVM_11)
+ }
+}
+
+dependencies {
+ implementation(libs.androidx.core.ktx)
+ implementation(libs.androidx.activity.compose)
+
+ // Wear Compose
+ implementation(libs.androidx.wear.compose.foundation)
+ implementation(libs.androidx.wear.compose.material3)
+ implementation(libs.androidx.wear.tooling.preview)
+
+ // Lifecycle
+ implementation(libs.bundles.lifecycle)
+ implementation(libs.androidx.lifecycle.process)
+
+ // Coroutines
+ implementation(libs.kotlinx.coroutines.android)
+
+ // Cryptography (shared Noise/encryption stack)
+ implementation(libs.bouncycastle.bcprov)
+
+ // JSON (BitchatMessage model)
+ implementation(libs.gson)
+
+ // Security preferences (Noise identity persistence)
+ implementation(libs.androidx.security.crypto)
+
+ // Testing
+ testImplementation(libs.bundles.testing)
+ debugImplementation(libs.androidx.compose.ui.tooling)
+}
diff --git a/wear/src/main/AndroidManifest.xml b/wear/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..231bc058
--- /dev/null
+++ b/wear/src/main/AndroidManifest.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/wear/src/main/java/com/bitchat/watch/MainActivity.kt b/wear/src/main/java/com/bitchat/watch/MainActivity.kt
new file mode 100644
index 00000000..25afe11a
--- /dev/null
+++ b/wear/src/main/java/com/bitchat/watch/MainActivity.kt
@@ -0,0 +1,52 @@
+package com.bitchat.watch
+
+import android.os.Bundle
+import androidx.activity.ComponentActivity
+import androidx.activity.compose.setContent
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.padding
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.dp
+import androidx.wear.compose.material3.MaterialTheme
+import androidx.wear.compose.material3.Text
+import com.bitchat.watch.ui.theme.BitchatWearTheme
+
+class MainActivity : ComponentActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContent {
+ BitchatWearTheme {
+ PlaceholderScreen()
+ }
+ }
+ }
+}
+
+@Composable
+fun PlaceholderScreen() {
+ Column(
+ modifier = Modifier
+ .fillMaxSize()
+ .padding(24.dp),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ verticalArrangement = Arrangement.Center
+ ) {
+ Text(
+ text = "bitchat",
+ style = MaterialTheme.typography.titleLarge,
+ fontWeight = FontWeight.Bold,
+ color = MaterialTheme.colorScheme.primary
+ )
+ Text(
+ text = "mesh initializing",
+ style = MaterialTheme.typography.bodySmall,
+ color = MaterialTheme.colorScheme.onSurfaceVariant,
+ modifier = Modifier.padding(top = 8.dp)
+ )
+ }
+}
diff --git a/wear/src/main/java/com/bitchat/watch/ui/theme/BitchatPalette.kt b/wear/src/main/java/com/bitchat/watch/ui/theme/BitchatPalette.kt
new file mode 100644
index 00000000..5ae88981
--- /dev/null
+++ b/wear/src/main/java/com/bitchat/watch/ui/theme/BitchatPalette.kt
@@ -0,0 +1,38 @@
+package com.bitchat.watch.ui.theme
+
+import androidx.compose.runtime.Immutable
+import androidx.compose.runtime.staticCompositionLocalOf
+import androidx.compose.ui.graphics.Color
+
+@Immutable
+data class BitchatPalette(
+ val inputOutline: Color,
+ val inputOutlineFocused: Color,
+ val inputSurface: Color,
+ val inputSurfaceFocused: Color,
+ val inputButton: Color,
+ val textTertiary: Color,
+ val accentOrange: Color,
+ val accentPurple: Color,
+ val peerColors: PeerColorStyle,
+)
+
+val DarkBitchatPalette = BitchatPalette(
+ inputOutline = Color(0xFF333635),
+ inputOutlineFocused = Color(0xFF5A605D),
+ inputSurface = Color(0xFF0B0B0B),
+ inputSurfaceFocused = Color(0xFF151515),
+ inputButton = Color(0xFF1E1E1E),
+ textTertiary = Color(0xFF6B776B),
+ accentOrange = Color(0xFFFF9F0A),
+ accentPurple = Color(0xFFBF5AF2),
+ peerColors = PeerColorStyle.Dark,
+)
+
+val LocalBitchatPalette = staticCompositionLocalOf { DarkBitchatPalette }
+
+object BitchatMotion {
+ const val QUICK_MS = 120
+ const val STANDARD_MS = 180
+ const val EMPHASIZED_MS = 240
+}
diff --git a/wear/src/main/java/com/bitchat/watch/ui/theme/PeerColors.kt b/wear/src/main/java/com/bitchat/watch/ui/theme/PeerColors.kt
new file mode 100644
index 00000000..4d8c390b
--- /dev/null
+++ b/wear/src/main/java/com/bitchat/watch/ui/theme/PeerColors.kt
@@ -0,0 +1,35 @@
+package com.bitchat.watch.ui.theme
+
+import androidx.compose.runtime.Immutable
+import androidx.compose.ui.graphics.Color
+import kotlin.math.abs
+
+@Immutable
+data class PeerColorStyle(
+ val saturation: Float,
+ val value: Float,
+) {
+ companion object {
+ val Dark = PeerColorStyle(saturation = 0.55f, value = 0.82f)
+ }
+}
+
+fun colorForPeer(stableKey: String, palette: BitchatPalette): Color {
+ var hash = 5381UL
+ for (byte in stableKey.toByteArray()) {
+ hash = ((hash shl 5) + hash) + byte.toUByte().toULong()
+ }
+
+ var hue = (hash % 360UL).toDouble() / 360.0
+ val orange = 30.0 / 360.0
+ if (abs(hue - orange) < 0.05) {
+ hue = (hue + 0.12) % 1.0
+ }
+
+ val style = palette.peerColors
+ return Color.hsv(
+ hue = (hue * 360).toFloat(),
+ saturation = style.saturation,
+ value = style.value
+ )
+}
diff --git a/wear/src/main/java/com/bitchat/watch/ui/theme/Theme.kt b/wear/src/main/java/com/bitchat/watch/ui/theme/Theme.kt
new file mode 100644
index 00000000..3f928aba
--- /dev/null
+++ b/wear/src/main/java/com/bitchat/watch/ui/theme/Theme.kt
@@ -0,0 +1,42 @@
+package com.bitchat.watch.ui.theme
+
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.ui.graphics.Color
+import androidx.wear.compose.material3.ColorScheme
+import androidx.wear.compose.material3.MaterialTheme
+
+val BitchatWearColorScheme = ColorScheme(
+ primary = Color(0xFF32D74B),
+ onPrimary = Color.Black,
+ primaryContainer = Color(0xFF163D1D),
+ onPrimaryContainer = Color(0xFFB8F5C1),
+ secondary = Color(0xFF0A84FF),
+ onSecondary = Color.Black,
+ secondaryContainer = Color(0xFF082E54),
+ onSecondaryContainer = Color(0xFFC2E0FF),
+ tertiary = Color(0xFFFF9F0A),
+ onTertiary = Color.Black,
+ background = Color(0xFF000000),
+ onBackground = Color(0xFFF5F5F5),
+ surfaceContainer = Color(0xFF0E150E),
+ surfaceContainerLow = Color(0xFF0B0B0B),
+ surfaceContainerHigh = Color(0xFF182118),
+ onSurface = Color(0xFFF5F5F5),
+ onSurfaceVariant = Color(0xFF9AA69A),
+ outline = Color(0xFF2A3A2A),
+ outlineVariant = Color(0xFF1C271C),
+ error = Color(0xFFFF453A),
+ onError = Color.Black,
+)
+
+@Composable
+fun BitchatWearTheme(content: @Composable () -> Unit) {
+ CompositionLocalProvider(LocalBitchatPalette provides DarkBitchatPalette) {
+ MaterialTheme(
+ colorScheme = BitchatWearColorScheme,
+ typography = BitchatWearTypography,
+ content = content
+ )
+ }
+}
diff --git a/wear/src/main/java/com/bitchat/watch/ui/theme/Typography.kt b/wear/src/main/java/com/bitchat/watch/ui/theme/Typography.kt
new file mode 100644
index 00000000..ff66567d
--- /dev/null
+++ b/wear/src/main/java/com/bitchat/watch/ui/theme/Typography.kt
@@ -0,0 +1,43 @@
+package com.bitchat.watch.ui.theme
+
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.font.Font
+import androidx.compose.ui.text.font.FontFamily
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.sp
+import androidx.wear.compose.material3.Typography
+import com.bitchat.watch.R
+
+val BitchatFontFamily = FontFamily(
+ Font(R.font.geist_mono_regular, FontWeight.Normal),
+ Font(R.font.geist_mono_medium, FontWeight.Medium),
+ Font(R.font.geist_mono_semibold, FontWeight.SemiBold),
+ Font(R.font.geist_mono_bold, FontWeight.Bold),
+)
+
+val BitchatWearTypography = Typography(
+ defaultFontFamily = BitchatFontFamily,
+)
+
+object ChatVisualTokens {
+ val MessageBodyStyle = TextStyle(
+ fontFamily = BitchatFontFamily,
+ fontWeight = FontWeight.Normal,
+ fontSize = 13.sp,
+ lineHeight = 17.sp,
+ )
+
+ val SenderStyle = TextStyle(
+ fontFamily = BitchatFontFamily,
+ fontWeight = FontWeight.SemiBold,
+ fontSize = 13.sp,
+ lineHeight = 15.sp,
+ )
+
+ val SystemActionStyle = TextStyle(
+ fontFamily = BitchatFontFamily,
+ fontWeight = FontWeight.Medium,
+ fontSize = 11.sp,
+ lineHeight = 14.sp,
+ )
+}
diff --git a/wear/src/main/res/drawable/ic_launcher.xml b/wear/src/main/res/drawable/ic_launcher.xml
new file mode 100644
index 00000000..f1b68e08
--- /dev/null
+++ b/wear/src/main/res/drawable/ic_launcher.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
diff --git a/wear/src/main/res/font/geist_mono_bold.ttf b/wear/src/main/res/font/geist_mono_bold.ttf
new file mode 100644
index 00000000..90eb8a86
Binary files /dev/null and b/wear/src/main/res/font/geist_mono_bold.ttf differ
diff --git a/wear/src/main/res/font/geist_mono_medium.ttf b/wear/src/main/res/font/geist_mono_medium.ttf
new file mode 100644
index 00000000..ff49ece5
Binary files /dev/null and b/wear/src/main/res/font/geist_mono_medium.ttf differ
diff --git a/wear/src/main/res/font/geist_mono_regular.ttf b/wear/src/main/res/font/geist_mono_regular.ttf
new file mode 100644
index 00000000..50c9d5a6
Binary files /dev/null and b/wear/src/main/res/font/geist_mono_regular.ttf differ
diff --git a/wear/src/main/res/font/geist_mono_semibold.ttf b/wear/src/main/res/font/geist_mono_semibold.ttf
new file mode 100644
index 00000000..1b21724d
Binary files /dev/null and b/wear/src/main/res/font/geist_mono_semibold.ttf differ
diff --git a/wear/src/main/res/values/strings.xml b/wear/src/main/res/values/strings.xml
new file mode 100644
index 00000000..c89fc442
--- /dev/null
+++ b/wear/src/main/res/values/strings.xml
@@ -0,0 +1,4 @@
+
+
+ bitchat
+