feat(m1): connect & browse — first-run flow, public content, contact
Some checks failed
PR Checks / android-build (pull_request) Failing after 33m35s

Implements M1 (functional Kotlin pass, docs/android/PLAN.md §9): the
first-run base-URL connect flow, brand-seeded Material 3 theming from
/public/settings, a Retrofit/OkHttp/kotlinx-serialization client with a
runtime host-selection interceptor (the base URL is not compiled in),
the layered repository stack returning a typed ApiResult for graceful
degradation, and functional Compose screens for Home/Status, News
(+ post detail), Wiki (+ detail), CMS pages (block renderer), and the
contact form. One shared, declarative navigation drawer. No auth yet (M3).

DTOs + the Retrofit interface are hand-written and spec-aligned rather
than openapi-generated: the committed swagger-output.json is produced by
swagger-autogen and its component schemas are meta-descriptive (nested
{type, example} wrappers), not codegen-clean, so a hand-authored client
module is the pragmatic "checked-in generated module" the plan allows
(§2). Shapes were matched against the website controllers/models.

JVM unit tests cover URL normalization, host rewriting, ApiResult/UiState
mapping, and brand-color parsing. `lint test assembleDebug` green locally.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NgyHnrNa8WwG3doxvxjuCr
This commit is contained in:
2026-07-19 17:09:33 -05:00
parent 91cd4585c0
commit 9019ded556
55 changed files with 3275 additions and 52 deletions

View File

@@ -8,5 +8,69 @@
<resources>
<!-- Fixed launcher name, baked at build even though in-app branding is per-shard (PLAN.md §13). -->
<string name="app_name">Runic Gateway</string>
<string name="app_scaffold_ready">Runic Gateway — scaffold ready</string>
<!-- ── Shared actions / errors ─────────────────────────────────────── -->
<string name="action_retry">Retry</string>
<string name="action_back">Back</string>
<string name="error_network">Can\'t reach the site. Check your connection and try again.</string>
<string name="error_not_found">This content couldn\'t be found.</string>
<string name="error_rate_limited">Too many requests. Please try again in a moment.</string>
<string name="error_shard_offline">The shard is offline right now.</string>
<string name="error_server">Something went wrong on the server. Please try again.</string>
<!-- ── First-run connect (§3) ──────────────────────────────────────── -->
<string name="connect_title">Connect to your shard</string>
<string name="connect_subtitle">Enter your shard\'s website address to get started.</string>
<string name="connect_url_label">Website address</string>
<string name="connect_url_hint">https://your-shard.example.com</string>
<string name="connect_button">Connect</string>
<string name="connect_connecting">Connecting…</string>
<string name="connect_error_blank">Enter a website address.</string>
<string name="connect_error_malformed">That doesn\'t look like a valid web address.</string>
<string name="connect_error_scheme">Only http and https addresses are supported.</string>
<string name="connect_error_insecure">A secure https address is required.</string>
<string name="connect_error_not_runic">That site isn\'t a Runic Gateway shard.</string>
<string name="connect_error_unreachable">Couldn\'t reach that site. Check the address and your connection.</string>
<string name="connect_error_server">The site responded with an error (%1$d). Try again shortly.</string>
<!-- ── Navigation menu (§5) ────────────────────────────────────────── -->
<string name="nav_open_menu">Open navigation menu</string>
<string name="menu_home">Home</string>
<string name="menu_news">News</string>
<string name="menu_wiki">Wiki</string>
<string name="menu_about">About</string>
<string name="menu_contact">Contact</string>
<string name="menu_change_server">Change server</string>
<!-- ── Home / status (§6.1) ────────────────────────────────────────── -->
<string name="home_status_live">Online</string>
<string name="home_status_maintenance">Under maintenance</string>
<string name="home_server_version">Server %1$s · API %2$s</string>
<!-- ── News & content (§6.1) ───────────────────────────────────────── -->
<string name="news_title">News &amp; content</string>
<string name="news_cat_news">News</string>
<string name="news_cat_screenshots">Screenshots</string>
<string name="news_cat_five_on_friday">Five on Friday</string>
<string name="news_cat_newsletter">Newsletter</string>
<string name="news_empty">No posts here yet.</string>
<!-- ── Wiki (§6.1) ─────────────────────────────────────────────────── -->
<string name="wiki_title">Wiki</string>
<string name="wiki_search_hint">Search the wiki</string>
<string name="wiki_empty">No pages found.</string>
<string name="wiki_section_tags">Tags</string>
<string name="wiki_section_backlinks">Linked from</string>
<!-- ── Contact (§6.1) ──────────────────────────────────────────────── -->
<string name="contact_title">Contact</string>
<string name="contact_name">Your name</string>
<string name="contact_email">Your email</string>
<string name="contact_message">Message</string>
<string name="contact_send">Send message</string>
<string name="contact_sending">Sending…</string>
<string name="contact_sent">Message sent — thank you!</string>
<string name="contact_fallback">This site has no mailer configured. Email directly: %1$s</string>
<string name="contact_validation">Please fill in every field.</string>
<string name="contact_error">Couldn\'t send your message. Please try again.</string>
</resources>