mirror of
https://github.com/hanzo-templates/flutter-chat.git
synced 2026-10-30 20:52:58 +00:00
The catalogue shipped 71 web templates and one EMPTY `mobile` repo, so "build an app" had no starting point on the platform people actually ship to. This is the iOS lane — Expo/React Native and Flutter for cross-platform, SwiftUI for native. The constraint that shaped every file here: an iOS archive needs macOS + Xcode + a signing identity, and our arc fleet has none. hanzoai has 519 registered runners and every one reports `os: linux`; luxfi has 151, same story; zooai has none. The only macOS builds in the org today (hanzoai/world build-desktop.yml) run on GitHub-HOSTED macos-14, which is exactly what the house CI rule says not to do. So `hanzo.yml` declares only what a Linux arc runner can genuinely execute — typecheck + web bundle for Expo, analyze + test + web for Flutter, `swiftc -parse` for SwiftUI — and the macOS archive lives in a separate `workflow_dispatch`-only `ios.yml`. A job pinned to a label no runner advertises would sit queued forever if it fired on push; parking it is honest, a permanently-yellow check is not. The README of every template states the gap and the one command that closes it. Same reasoning on the demos. Expo and Flutter both have a real web target, so `<slug>.hanzo.app` serves the SAME source the simulator runs. SwiftUI has no web target, so those two templates ship with no demo link rather than a screenshot pretending to be one. Upstreams are permissive only and recorded per template: expo/expo templates (MIT), flutter/samples (BSD-3-Clause), XcodeGen (MIT). Second measured gap, found while wiring this up: `hanzo-templates` is not in arcd's `orgs:` list either (hanzoai, luxfi, zooai, parsdao, zenlm), so the Linux jobs would queue with no runner too. Both gaps are one installer re-run, no code change; both are spelled out in every README rather than left to be discovered on the first red build. Third gap, found by probing rather than assuming, and FIXED here: every run in this org died as `startup_failure` with no logs and no annotation. A bare `runs-on: [self-hosted, linux]` probe queued fine while the same job importing hanzoai/ci failed identically at @v1 and at a pinned SHA — so it was never the tag. The org defaulted GITHUB_TOKEN to `read`, and the reusable declares `permissions: packages: write`; a caller cannot exceed the org maximum, so GitHub kills the run before creating a job. hanzo-templates now defaults to `write` like hanzoai/luxfi/zooai, and runs reach `queued` — the honest state, waiting on gap 2.
71 lines
2.0 KiB
Dart
71 lines
2.0 KiB
Dart
import 'package:flutter/material.dart';
|
|
|
|
import 'hanzo.dart';
|
|
|
|
class SettingsPage extends StatelessWidget {
|
|
const SettingsPage({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final h = Hanzo.instance;
|
|
return Scaffold(
|
|
appBar: AppBar(title: const Text('Settings')),
|
|
body: ListView(
|
|
padding: const EdgeInsets.all(16),
|
|
children: [
|
|
_Field(label: 'API base', initial: h.base, onChanged: (v) => h.base = v),
|
|
_Field(label: 'Model', initial: h.model, onChanged: (v) => h.model = v),
|
|
_Field(
|
|
label: 'API key',
|
|
initial: h.key,
|
|
obscure: true,
|
|
hint: 'Held in memory only. Persist it with flutter_secure_storage before you ship.',
|
|
onChanged: (v) => h.key = v,
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class _Field extends StatelessWidget {
|
|
const _Field({
|
|
required this.label,
|
|
required this.initial,
|
|
required this.onChanged,
|
|
this.obscure = false,
|
|
this.hint,
|
|
});
|
|
|
|
final String label, initial;
|
|
final String? hint;
|
|
final bool obscure;
|
|
final ValueChanged<String> onChanged;
|
|
|
|
@override
|
|
Widget build(BuildContext context) => Padding(
|
|
padding: const EdgeInsets.only(bottom: 18),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(label, style: Theme.of(context).textTheme.titleSmall),
|
|
const SizedBox(height: 6),
|
|
TextFormField(
|
|
initialValue: initial,
|
|
obscureText: obscure,
|
|
autocorrect: false,
|
|
onChanged: onChanged,
|
|
decoration: InputDecoration(
|
|
hintText: obscure ? 'sk-…' : null,
|
|
contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
|
),
|
|
),
|
|
if (hint != null) ...[
|
|
const SizedBox(height: 6),
|
|
Text(hint!, style: const TextStyle(color: Colors.white54, fontSize: 13)),
|
|
],
|
|
],
|
|
),
|
|
);
|
|
}
|