refactor: rename internal Fai* design system + fai_ helpers to chain
Some checks failed
Security / Security check (push) Failing after 2s
Some checks failed
Security / Security check (push) Failing after 2s
The Studio design system, widgets and helpers carried a Fai* / fai_ prefix (FaiSpace, FaiColors, FaiTheme, FaiLog, 17 fai_*.dart files, the faiBinary* l10n keys). Studio is the Ch∆In product, so rename them to Chain* / chain_ — carefully preserving English fail/failure/failed. Also fix stale references: the 'fai' binary in l10n strings -> 'chain', FAI_* env vars (FAI_BIN/DATA_DIR/MODULES_DIR/TODAY/BOOTSTRAP_TOKEN) -> CHAIN_*, fai_platform -> fai_chain, fai_hub -> chain_hub. Vendor security-hook tooling (FAI_BANNED_TERMS_FILE) + the .fai bundle ext left. flutter analyze + test: clean (20 passed). Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
This commit is contained in:
parent
68d23ab7dd
commit
891acd2ba2
52 changed files with 1225 additions and 1225 deletions
|
|
@ -224,7 +224,7 @@ class _ApprovalsPageState extends State<ApprovalsPage>
|
|||
tooltip: AppLocalizations.of(context)!.approvalsReloadTooltip,
|
||||
onPressed: _refresh,
|
||||
),
|
||||
const SizedBox(width: FaiSpace.sm),
|
||||
const SizedBox(width: ChainSpace.sm),
|
||||
],
|
||||
),
|
||||
body: TabBarView(
|
||||
|
|
@ -288,7 +288,7 @@ class _PendingList extends StatelessWidget {
|
|||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
if (snapshot.hasError) {
|
||||
return FaiEmptyState(
|
||||
return ChainEmptyState(
|
||||
icon: Icons.cloud_off_outlined,
|
||||
iconColor: theme.colorScheme.error,
|
||||
title: l.hubUnreachable,
|
||||
|
|
@ -301,7 +301,7 @@ class _PendingList extends StatelessWidget {
|
|||
}
|
||||
final pending = snapshot.data ?? [];
|
||||
if (pending.isEmpty) {
|
||||
return FaiEmptyState(
|
||||
return ChainEmptyState(
|
||||
icon: Icons.task_alt_outlined,
|
||||
title: l.approvalsInboxZero,
|
||||
hint: l.approvalsInboxHint,
|
||||
|
|
@ -314,15 +314,15 @@ class _PendingList extends StatelessWidget {
|
|||
children: [
|
||||
ListView.separated(
|
||||
padding: EdgeInsets.fromLTRB(
|
||||
FaiSpace.xl,
|
||||
FaiSpace.xl,
|
||||
FaiSpace.xl,
|
||||
ChainSpace.xl,
|
||||
ChainSpace.xl,
|
||||
ChainSpace.xl,
|
||||
// Keep the last card clear of the floating
|
||||
// batch action bar.
|
||||
selected.isEmpty ? FaiSpace.xl : 96.0,
|
||||
selected.isEmpty ? ChainSpace.xl : 96.0,
|
||||
),
|
||||
itemCount: pending.length,
|
||||
separatorBuilder: (_, _) => const SizedBox(height: FaiSpace.md),
|
||||
separatorBuilder: (_, _) => const SizedBox(height: ChainSpace.md),
|
||||
itemBuilder: (context, i) {
|
||||
final a = pending[i];
|
||||
final isSelected = selectedIds.contains(a.id);
|
||||
|
|
@ -337,9 +337,9 @@ class _PendingList extends StatelessWidget {
|
|||
),
|
||||
if (selected.isNotEmpty)
|
||||
Positioned(
|
||||
left: FaiSpace.xl,
|
||||
right: FaiSpace.xl,
|
||||
bottom: FaiSpace.lg,
|
||||
left: ChainSpace.xl,
|
||||
right: ChainSpace.xl,
|
||||
bottom: ChainSpace.lg,
|
||||
child: _BatchActionBar(
|
||||
selectedCount: selected.length,
|
||||
totalCount: pending.length,
|
||||
|
|
@ -387,15 +387,15 @@ class _BatchActionBar extends StatelessWidget {
|
|||
final l = AppLocalizations.of(context)!;
|
||||
return Material(
|
||||
elevation: 4,
|
||||
borderRadius: BorderRadius.circular(FaiRadius.md),
|
||||
borderRadius: BorderRadius.circular(ChainRadius.md),
|
||||
color: theme.colorScheme.surfaceContainerHigh,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: FaiSpace.lg,
|
||||
vertical: FaiSpace.md,
|
||||
horizontal: ChainSpace.lg,
|
||||
vertical: ChainSpace.md,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(FaiRadius.md),
|
||||
borderRadius: BorderRadius.circular(ChainRadius.md),
|
||||
border: Border.all(color: theme.colorScheme.outlineVariant),
|
||||
),
|
||||
child: Row(
|
||||
|
|
@ -405,14 +405,14 @@ class _BatchActionBar extends StatelessWidget {
|
|||
size: 18,
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
const SizedBox(width: FaiSpace.sm),
|
||||
const SizedBox(width: ChainSpace.sm),
|
||||
Text(
|
||||
l.approvalsBatchSelected(selectedCount),
|
||||
style: theme.textTheme.bodyMedium?.copyWith(
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: FaiSpace.md),
|
||||
const SizedBox(width: ChainSpace.md),
|
||||
if (selectedCount < totalCount)
|
||||
TextButton(
|
||||
onPressed: inFlight ? null : onSelectAll,
|
||||
|
|
@ -434,7 +434,7 @@ class _BatchActionBar extends StatelessWidget {
|
|||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: FaiSpace.sm),
|
||||
const SizedBox(width: ChainSpace.sm),
|
||||
FilledButton.icon(
|
||||
onPressed: inFlight ? null : onApprove,
|
||||
icon: inFlight
|
||||
|
|
@ -470,7 +470,7 @@ class _HistoryList extends StatelessWidget {
|
|||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
if (snapshot.hasError) {
|
||||
return FaiEmptyState(
|
||||
return ChainEmptyState(
|
||||
icon: Icons.cloud_off_outlined,
|
||||
iconColor: theme.colorScheme.error,
|
||||
title: l.hubUnreachable,
|
||||
|
|
@ -483,16 +483,16 @@ class _HistoryList extends StatelessWidget {
|
|||
}
|
||||
final decided = snapshot.data ?? [];
|
||||
if (decided.isEmpty) {
|
||||
return FaiEmptyState(
|
||||
return ChainEmptyState(
|
||||
icon: Icons.history,
|
||||
title: l.approvalsHistoryEmpty,
|
||||
hint: l.approvalsHistoryEmptyHint,
|
||||
);
|
||||
}
|
||||
return ListView.separated(
|
||||
padding: const EdgeInsets.all(FaiSpace.xl),
|
||||
padding: const EdgeInsets.all(ChainSpace.xl),
|
||||
itemCount: decided.length,
|
||||
separatorBuilder: (_, _) => const SizedBox(height: FaiSpace.xs),
|
||||
separatorBuilder: (_, _) => const SizedBox(height: ChainSpace.xs),
|
||||
itemBuilder: (context, i) {
|
||||
final a = decided[i];
|
||||
return _HistoryRow(record: a);
|
||||
|
|
@ -522,7 +522,7 @@ class _ApprovalCard extends StatelessWidget {
|
|||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
final l = AppLocalizations.of(context)!;
|
||||
return FaiCard(
|
||||
return ChainCard(
|
||||
accentTop: true,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
|
|
@ -534,13 +534,13 @@ class _ApprovalCard extends StatelessWidget {
|
|||
onChanged: (_) => onToggleSelected(),
|
||||
visualDensity: VisualDensity.compact,
|
||||
),
|
||||
const SizedBox(width: FaiSpace.xs),
|
||||
FaiPill(
|
||||
const SizedBox(width: ChainSpace.xs),
|
||||
ChainPill(
|
||||
label: l.approvalsPillPending,
|
||||
tone: FaiPillTone.warning,
|
||||
tone: ChainPillTone.warning,
|
||||
icon: Icons.pending_outlined,
|
||||
),
|
||||
const SizedBox(width: FaiSpace.sm),
|
||||
const SizedBox(width: ChainSpace.sm),
|
||||
Expanded(
|
||||
child: Text(
|
||||
'${approval.flowName} › ${approval.stepId}',
|
||||
|
|
@ -550,17 +550,17 @@ class _ApprovalCard extends StatelessWidget {
|
|||
),
|
||||
),
|
||||
if (approval.expiresAt != null)
|
||||
FaiPill(
|
||||
ChainPill(
|
||||
label: _expiresInLabel(context, approval.expiresAt!),
|
||||
tone: FaiPillTone.neutral,
|
||||
tone: ChainPillTone.neutral,
|
||||
icon: Icons.schedule,
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: FaiSpace.lg),
|
||||
const SizedBox(height: ChainSpace.lg),
|
||||
Text(approval.prompt, style: theme.textTheme.bodyLarge),
|
||||
if (approval.payloadPreview != null) ...[
|
||||
const SizedBox(height: FaiSpace.md),
|
||||
const SizedBox(height: ChainSpace.md),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 4),
|
||||
child: Text(
|
||||
|
|
@ -574,27 +574,27 @@ class _ApprovalCard extends StatelessWidget {
|
|||
),
|
||||
Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(FaiSpace.md),
|
||||
padding: const EdgeInsets.all(ChainSpace.md),
|
||||
decoration: BoxDecoration(
|
||||
color: theme.colorScheme.surfaceContainerHigh,
|
||||
borderRadius: BorderRadius.circular(FaiRadius.sm),
|
||||
borderRadius: BorderRadius.circular(ChainRadius.sm),
|
||||
border: Border.all(color: theme.colorScheme.outlineVariant),
|
||||
),
|
||||
child: SelectableText(
|
||||
_prettyPreview(approval.payloadPreview!),
|
||||
style: FaiTheme.mono(
|
||||
style: ChainTheme.mono(
|
||||
size: 11,
|
||||
color: theme.colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
const SizedBox(height: FaiSpace.lg),
|
||||
const SizedBox(height: ChainSpace.lg),
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
approval.id,
|
||||
style: FaiTheme.mono(
|
||||
style: ChainTheme.mono(
|
||||
size: 10,
|
||||
color: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
|
|
@ -611,7 +611,7 @@ class _ApprovalCard extends StatelessWidget {
|
|||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: FaiSpace.sm),
|
||||
const SizedBox(width: ChainSpace.sm),
|
||||
FilledButton.icon(
|
||||
onPressed: onApprove,
|
||||
icon: const Icon(Icons.check, size: 16),
|
||||
|
|
@ -663,21 +663,21 @@ class _HistoryRow extends StatelessWidget {
|
|||
context: context,
|
||||
builder: (_) => _HistoryDialog(record: record),
|
||||
),
|
||||
borderRadius: BorderRadius.circular(FaiRadius.sm),
|
||||
borderRadius: BorderRadius.circular(ChainRadius.sm),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: FaiSpace.sm,
|
||||
vertical: FaiSpace.sm,
|
||||
horizontal: ChainSpace.sm,
|
||||
vertical: ChainSpace.sm,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
FaiPill(label: label, tone: tone, icon: icon),
|
||||
const SizedBox(width: FaiSpace.md),
|
||||
ChainPill(label: label, tone: tone, icon: icon),
|
||||
const SizedBox(width: ChainSpace.md),
|
||||
SizedBox(
|
||||
width: 150,
|
||||
child: Text(
|
||||
timeStr,
|
||||
style: FaiTheme.mono(
|
||||
style: ChainTheme.mono(
|
||||
size: 11,
|
||||
color: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
|
|
@ -693,7 +693,7 @@ class _HistoryRow extends StatelessWidget {
|
|||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: FaiSpace.md),
|
||||
const SizedBox(width: ChainSpace.md),
|
||||
if (record.decidedBy.isNotEmpty)
|
||||
Text(
|
||||
record.decidedBy,
|
||||
|
|
@ -707,24 +707,24 @@ class _HistoryRow extends StatelessWidget {
|
|||
);
|
||||
}
|
||||
|
||||
static (FaiPillTone, IconData, String) _statusPresentation(
|
||||
static (ChainPillTone, IconData, String) _statusPresentation(
|
||||
BuildContext context,
|
||||
String status,
|
||||
) {
|
||||
final l = AppLocalizations.of(context)!;
|
||||
switch (status) {
|
||||
case 'approved':
|
||||
return (FaiPillTone.success, Icons.check, l.approvalsPillApproved);
|
||||
return (ChainPillTone.success, Icons.check, l.approvalsPillApproved);
|
||||
case 'rejected':
|
||||
return (FaiPillTone.danger, Icons.close, l.approvalsPillRejected);
|
||||
return (ChainPillTone.danger, Icons.close, l.approvalsPillRejected);
|
||||
case 'expired':
|
||||
return (
|
||||
FaiPillTone.neutral,
|
||||
ChainPillTone.neutral,
|
||||
Icons.timer_off_outlined,
|
||||
l.approvalsPillExpired,
|
||||
);
|
||||
default:
|
||||
return (FaiPillTone.neutral, Icons.help_outline, status);
|
||||
return (ChainPillTone.neutral, Icons.help_outline, status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -743,8 +743,8 @@ class _HistoryDialog extends StatelessWidget {
|
|||
return AlertDialog(
|
||||
title: Row(
|
||||
children: [
|
||||
FaiPill(label: label, tone: tone, icon: icon),
|
||||
const SizedBox(width: FaiSpace.sm),
|
||||
ChainPill(label: label, tone: tone, icon: icon),
|
||||
const SizedBox(width: ChainSpace.sm),
|
||||
Expanded(
|
||||
child: Text(
|
||||
'${record.flowName} › ${record.stepId}',
|
||||
|
|
@ -779,7 +779,7 @@ class _HistoryDialog extends StatelessWidget {
|
|||
AppLocalizations.of(context)!.approvalsDialogReason,
|
||||
record.reason,
|
||||
),
|
||||
const SizedBox(height: FaiSpace.md),
|
||||
const SizedBox(height: ChainSpace.md),
|
||||
Text(
|
||||
AppLocalizations.of(context)!.approvalsDialogPrompt,
|
||||
style: theme.textTheme.labelSmall?.copyWith(
|
||||
|
|
@ -790,7 +790,7 @@ class _HistoryDialog extends StatelessWidget {
|
|||
const SizedBox(height: 4),
|
||||
SelectableText(record.prompt, style: theme.textTheme.bodyMedium),
|
||||
if (record.payloadPreview != null) ...[
|
||||
const SizedBox(height: FaiSpace.md),
|
||||
const SizedBox(height: ChainSpace.md),
|
||||
Text(
|
||||
AppLocalizations.of(context)!.approvalsPayloadPreview,
|
||||
style: theme.textTheme.labelSmall?.copyWith(
|
||||
|
|
@ -801,22 +801,22 @@ class _HistoryDialog extends StatelessWidget {
|
|||
const SizedBox(height: 4),
|
||||
Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(FaiSpace.sm),
|
||||
padding: const EdgeInsets.all(ChainSpace.sm),
|
||||
decoration: BoxDecoration(
|
||||
color: theme.colorScheme.surfaceContainerHigh,
|
||||
borderRadius: BorderRadius.circular(FaiRadius.sm),
|
||||
borderRadius: BorderRadius.circular(ChainRadius.sm),
|
||||
border: Border.all(color: theme.colorScheme.outlineVariant),
|
||||
),
|
||||
child: SelectableText(
|
||||
record.payloadPreview!,
|
||||
style: FaiTheme.mono(size: 11),
|
||||
style: ChainTheme.mono(size: 11),
|
||||
),
|
||||
),
|
||||
],
|
||||
const SizedBox(height: FaiSpace.md),
|
||||
const SizedBox(height: ChainSpace.md),
|
||||
Text(
|
||||
record.id,
|
||||
style: FaiTheme.mono(
|
||||
style: ChainTheme.mono(
|
||||
size: 10,
|
||||
color: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ class _AuditPageState extends State<AuditPage> {
|
|||
title: Text(AppLocalizations.of(context)!.auditTitle),
|
||||
actions: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: FaiSpace.lg),
|
||||
padding: const EdgeInsets.only(right: ChainSpace.lg),
|
||||
child: _FilterChips(
|
||||
value: _typeFilter,
|
||||
onChanged: (v) => setState(() => _typeFilter = v),
|
||||
|
|
@ -113,7 +113,7 @@ class _AuditPageState extends State<AuditPage> {
|
|||
tooltip: AppLocalizations.of(context)!.auditClearLogTooltip,
|
||||
onPressed: _onClearPressed,
|
||||
),
|
||||
const SizedBox(width: FaiSpace.sm),
|
||||
const SizedBox(width: ChainSpace.sm),
|
||||
],
|
||||
),
|
||||
body: Column(
|
||||
|
|
@ -123,14 +123,14 @@ class _AuditPageState extends State<AuditPage> {
|
|||
child: !_initialLoaded
|
||||
? const Center(child: CircularProgressIndicator())
|
||||
: _error != null && _events.isEmpty
|
||||
? FaiEmptyState(
|
||||
? ChainEmptyState(
|
||||
icon: Icons.cloud_off_outlined,
|
||||
iconColor: theme.colorScheme.error,
|
||||
title: AppLocalizations.of(context)!.hubUnreachable,
|
||||
hint: AppLocalizations.of(context)!.hubUnreachableHint,
|
||||
)
|
||||
: filtered.isEmpty
|
||||
? FaiEmptyState(
|
||||
? ChainEmptyState(
|
||||
icon: Icons.timeline_outlined,
|
||||
title: AppLocalizations.of(context)!.auditNoEvents,
|
||||
hint: AppLocalizations.of(context)!.auditNoEventsHint,
|
||||
|
|
@ -187,7 +187,7 @@ class _AuditPageState extends State<AuditPage> {
|
|||
Color _toneFor(String type, ThemeData theme) {
|
||||
if (type.endsWith('.failed')) return theme.colorScheme.error;
|
||||
if (type.endsWith('.completed')) return theme.colorScheme.primary;
|
||||
if (type.endsWith('.started')) return FaiColors.warning;
|
||||
if (type.endsWith('.started')) return ChainColors.warning;
|
||||
return theme.colorScheme.outline;
|
||||
}
|
||||
}
|
||||
|
|
@ -220,15 +220,15 @@ class _GroupedEventList extends StatelessWidget {
|
|||
final l = AppLocalizations.of(context)!;
|
||||
final items = _itemsWithHeaders(events, l);
|
||||
return ListView.builder(
|
||||
padding: const EdgeInsets.all(FaiSpace.xl),
|
||||
padding: const EdgeInsets.all(ChainSpace.xl),
|
||||
itemCount: items.length,
|
||||
itemBuilder: (context, i) {
|
||||
final item = items[i];
|
||||
if (item is _GroupHeader) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(
|
||||
top: i == 0 ? 0 : FaiSpace.lg,
|
||||
bottom: FaiSpace.sm,
|
||||
top: i == 0 ? 0 : ChainSpace.lg,
|
||||
bottom: ChainSpace.sm,
|
||||
),
|
||||
child: Text(
|
||||
item.label,
|
||||
|
|
@ -242,8 +242,8 @@ class _GroupedEventList extends StatelessWidget {
|
|||
}
|
||||
final e = (item as _EventItem).event;
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: FaiSpace.xs),
|
||||
child: FaiDataRow(
|
||||
padding: const EdgeInsets.only(bottom: ChainSpace.xs),
|
||||
child: ChainDataRow(
|
||||
accent: toneFor(e.type),
|
||||
leading: formatTime(e.timestamp),
|
||||
title: e.type,
|
||||
|
|
@ -328,7 +328,7 @@ class _FilterChips extends StatelessWidget {
|
|||
children: [
|
||||
for (final (v, label) in items)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: FaiSpace.xs),
|
||||
padding: const EdgeInsets.only(left: ChainSpace.xs),
|
||||
child: _ChipButton(
|
||||
label: label,
|
||||
selected: value == v,
|
||||
|
|
@ -378,14 +378,14 @@ class _ChipButtonState extends State<_ChipButton> {
|
|||
child: GestureDetector(
|
||||
onTap: widget.onTap,
|
||||
child: AnimatedContainer(
|
||||
duration: FaiMotion.fast,
|
||||
duration: ChainMotion.fast,
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: FaiSpace.md,
|
||||
horizontal: ChainSpace.md,
|
||||
vertical: 6,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: bg,
|
||||
borderRadius: BorderRadius.circular(FaiRadius.sm),
|
||||
borderRadius: BorderRadius.circular(ChainRadius.sm),
|
||||
border: Border.all(
|
||||
color: widget.selected
|
||||
? theme.colorScheme.primary.withValues(alpha: 0.3)
|
||||
|
|
@ -394,7 +394,7 @@ class _ChipButtonState extends State<_ChipButton> {
|
|||
),
|
||||
child: Text(
|
||||
widget.label,
|
||||
style: FaiTheme.mono(
|
||||
style: ChainTheme.mono(
|
||||
size: 11,
|
||||
weight: widget.selected ? FontWeight.w500 : FontWeight.w400,
|
||||
color: fg,
|
||||
|
|
@ -420,8 +420,8 @@ class _LiveStatusBar extends StatelessWidget {
|
|||
return Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: FaiSpace.xl,
|
||||
vertical: FaiSpace.sm,
|
||||
horizontal: ChainSpace.xl,
|
||||
vertical: ChainSpace.sm,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: theme.colorScheme.surfaceContainerHigh,
|
||||
|
|
@ -431,11 +431,11 @@ class _LiveStatusBar extends StatelessWidget {
|
|||
),
|
||||
child: Row(
|
||||
children: [
|
||||
FaiStatusDot(
|
||||
color: live ? FaiColors.success : FaiColors.danger,
|
||||
ChainStatusDot(
|
||||
color: live ? ChainColors.success : ChainColors.danger,
|
||||
pulsing: live,
|
||||
),
|
||||
const SizedBox(width: FaiSpace.sm),
|
||||
const SizedBox(width: ChainSpace.sm),
|
||||
Text(
|
||||
live ? l.auditLiveStatus(eventCount) : l.auditDisconnected(error!),
|
||||
style: theme.textTheme.bodySmall?.copyWith(
|
||||
|
|
@ -569,7 +569,7 @@ class _EventDetailDialogState extends State<_EventDetailDialog> {
|
|||
return AlertDialog(
|
||||
title: Text(event.type),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(FaiRadius.md),
|
||||
borderRadius: BorderRadius.circular(ChainRadius.md),
|
||||
),
|
||||
content: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 640, maxHeight: 560),
|
||||
|
|
@ -616,7 +616,7 @@ class _EventDetailDialogState extends State<_EventDetailDialog> {
|
|||
valueColor: theme.colorScheme.error,
|
||||
),
|
||||
if (detail.isNotEmpty) ...[
|
||||
const SizedBox(height: FaiSpace.md),
|
||||
const SizedBox(height: ChainSpace.md),
|
||||
Text(
|
||||
l.auditDetailHeader,
|
||||
style: theme.textTheme.labelSmall?.copyWith(
|
||||
|
|
@ -627,17 +627,17 @@ class _EventDetailDialogState extends State<_EventDetailDialog> {
|
|||
const SizedBox(height: 4),
|
||||
Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(FaiSpace.md),
|
||||
padding: const EdgeInsets.all(ChainSpace.md),
|
||||
decoration: BoxDecoration(
|
||||
color: theme.colorScheme.surfaceContainerHigh,
|
||||
borderRadius: BorderRadius.circular(FaiRadius.sm),
|
||||
borderRadius: BorderRadius.circular(ChainRadius.sm),
|
||||
border: Border.all(color: theme.colorScheme.outlineVariant),
|
||||
),
|
||||
child: SelectableText(detail, style: FaiTheme.mono(size: 11)),
|
||||
child: SelectableText(detail, style: ChainTheme.mono(size: 11)),
|
||||
),
|
||||
],
|
||||
if (_explanation != null || _explaining) ...[
|
||||
const SizedBox(height: FaiSpace.lg),
|
||||
const SizedBox(height: ChainSpace.lg),
|
||||
_ExplanationPanel(
|
||||
explaining: _explaining,
|
||||
result: _explanation,
|
||||
|
|
@ -729,7 +729,7 @@ class _FlowRunDialog extends StatelessWidget {
|
|||
return AlertDialog(
|
||||
title: Text(l.auditFlowRunDialogTitle(flowName)),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(FaiRadius.md),
|
||||
borderRadius: BorderRadius.circular(ChainRadius.md),
|
||||
),
|
||||
content: ConstrainedBox(
|
||||
constraints: BoxConstraints(maxWidth: 640, maxHeight: maxHeight),
|
||||
|
|
@ -743,15 +743,15 @@ class _FlowRunDialog extends StatelessWidget {
|
|||
color: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: FaiSpace.md),
|
||||
const SizedBox(height: ChainSpace.md),
|
||||
Flexible(
|
||||
child: ListView.separated(
|
||||
shrinkWrap: true,
|
||||
itemCount: related.length,
|
||||
separatorBuilder: (_, _) => const SizedBox(height: FaiSpace.xs),
|
||||
separatorBuilder: (_, _) => const SizedBox(height: ChainSpace.xs),
|
||||
itemBuilder: (context, i) {
|
||||
final e = related[i];
|
||||
return FaiDataRow(
|
||||
return ChainDataRow(
|
||||
accent: _toneFor(e.type, theme),
|
||||
leading: _formatRelativeTime(e.timestamp),
|
||||
title: e.type,
|
||||
|
|
@ -792,7 +792,7 @@ class _FlowRunDialog extends StatelessWidget {
|
|||
Color _toneFor(String type, ThemeData theme) {
|
||||
if (type.endsWith('.failed')) return theme.colorScheme.error;
|
||||
if (type.endsWith('.completed')) return theme.colorScheme.primary;
|
||||
if (type.endsWith('.started')) return FaiColors.warning;
|
||||
if (type.endsWith('.started')) return ChainColors.warning;
|
||||
return theme.colorScheme.outline;
|
||||
}
|
||||
}
|
||||
|
|
@ -831,7 +831,7 @@ class _Field extends StatelessWidget {
|
|||
child: SelectableText(
|
||||
value,
|
||||
style: mono
|
||||
? FaiTheme.mono(
|
||||
? ChainTheme.mono(
|
||||
size: 11,
|
||||
color: valueColor ?? theme.colorScheme.onSurface,
|
||||
)
|
||||
|
|
@ -875,10 +875,10 @@ class _ExplanationPanel extends StatelessWidget {
|
|||
: theme.colorScheme.error;
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(FaiSpace.md),
|
||||
padding: const EdgeInsets.all(ChainSpace.md),
|
||||
decoration: BoxDecoration(
|
||||
color: theme.colorScheme.surfaceContainerHigh,
|
||||
borderRadius: BorderRadius.circular(FaiRadius.sm),
|
||||
borderRadius: BorderRadius.circular(ChainRadius.sm),
|
||||
border: Border.all(color: color.withValues(alpha: 0.3)),
|
||||
),
|
||||
child: Column(
|
||||
|
|
@ -887,7 +887,7 @@ class _ExplanationPanel extends StatelessWidget {
|
|||
Row(
|
||||
children: [
|
||||
Icon(Icons.auto_awesome, size: 14, color: color),
|
||||
const SizedBox(width: FaiSpace.xs),
|
||||
const SizedBox(width: ChainSpace.xs),
|
||||
Text(
|
||||
l.auditSystemAi,
|
||||
style: theme.textTheme.labelSmall?.copyWith(
|
||||
|
|
@ -895,15 +895,15 @@ class _ExplanationPanel extends StatelessWidget {
|
|||
letterSpacing: 0.6,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: FaiSpace.xs),
|
||||
FaiPill(
|
||||
const SizedBox(width: ChainSpace.xs),
|
||||
ChainPill(
|
||||
label: privacyMode,
|
||||
tone: privacyMode == 'full'
|
||||
? FaiPillTone.warning
|
||||
: FaiPillTone.neutral,
|
||||
? ChainPillTone.warning
|
||||
: ChainPillTone.neutral,
|
||||
),
|
||||
if (result != null && result!.isSuccess && result!.cached) ...[
|
||||
const SizedBox(width: FaiSpace.xs),
|
||||
const SizedBox(width: ChainSpace.xs),
|
||||
Tooltip(
|
||||
message: () {
|
||||
final hits = result!.cacheHits > 1
|
||||
|
|
@ -913,9 +913,9 @@ class _ExplanationPanel extends StatelessWidget {
|
|||
? l.auditCachedTooltipUnknown(hits)
|
||||
: l.auditCachedTooltipKnown(result!.cachedAt, hits);
|
||||
}(),
|
||||
child: FaiPill(
|
||||
child: ChainPill(
|
||||
label: l.auditCachedPill,
|
||||
tone: FaiPillTone.success,
|
||||
tone: ChainPillTone.success,
|
||||
icon: Icons.bolt,
|
||||
),
|
||||
),
|
||||
|
|
@ -926,7 +926,7 @@ class _ExplanationPanel extends StatelessWidget {
|
|||
result!.cached
|
||||
? l.auditOriginalLatency(result!.latencyMs)
|
||||
: l.auditLatency(result!.latencyMs),
|
||||
style: FaiTheme.mono(
|
||||
style: ChainTheme.mono(
|
||||
size: 10,
|
||||
color: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
|
|
@ -934,7 +934,7 @@ class _ExplanationPanel extends StatelessWidget {
|
|||
if (result != null &&
|
||||
result!.isSuccess &&
|
||||
onRegenerate != null) ...[
|
||||
const SizedBox(width: FaiSpace.sm),
|
||||
const SizedBox(width: ChainSpace.sm),
|
||||
Tooltip(
|
||||
message: l.auditRegenerateTooltip,
|
||||
child: IconButton(
|
||||
|
|
@ -946,7 +946,7 @@ class _ExplanationPanel extends StatelessWidget {
|
|||
],
|
||||
],
|
||||
),
|
||||
const SizedBox(height: FaiSpace.sm),
|
||||
const SizedBox(height: ChainSpace.sm),
|
||||
if (explaining)
|
||||
Row(
|
||||
children: [
|
||||
|
|
@ -955,7 +955,7 @@ class _ExplanationPanel extends StatelessWidget {
|
|||
height: 14,
|
||||
child: CircularProgressIndicator(strokeWidth: 2),
|
||||
),
|
||||
const SizedBox(width: FaiSpace.sm),
|
||||
const SizedBox(width: ChainSpace.sm),
|
||||
Text(
|
||||
l.auditAskingFull,
|
||||
style: theme.textTheme.bodySmall?.copyWith(
|
||||
|
|
@ -974,7 +974,7 @@ class _ExplanationPanel extends StatelessWidget {
|
|||
),
|
||||
),
|
||||
if (result!.fixHint(l).isNotEmpty) ...[
|
||||
const SizedBox(height: FaiSpace.sm),
|
||||
const SizedBox(height: ChainSpace.sm),
|
||||
Text(
|
||||
l.auditFixLabel,
|
||||
style: theme.textTheme.labelSmall?.copyWith(
|
||||
|
|
@ -1063,7 +1063,7 @@ class _ClearAuditDialogState extends State<_ClearAuditDialog> {
|
|||
color: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: FaiSpace.lg),
|
||||
const SizedBox(height: ChainSpace.lg),
|
||||
TextField(
|
||||
controller: _reviewer,
|
||||
decoration: InputDecoration(
|
||||
|
|
@ -1072,7 +1072,7 @@ class _ClearAuditDialogState extends State<_ClearAuditDialog> {
|
|||
isDense: true,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: FaiSpace.md),
|
||||
const SizedBox(height: ChainSpace.md),
|
||||
ValueListenableBuilder<TextEditingValue>(
|
||||
valueListenable: _reason,
|
||||
builder: (_, _, _) => TextField(
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../data/error_presentation.dart';
|
||||
import '../data/fai_log.dart';
|
||||
import '../data/chain_log.dart';
|
||||
import '../data/hub.dart';
|
||||
import '../data/system_actions.dart';
|
||||
import '../l10n/app_localizations.dart';
|
||||
|
|
@ -47,7 +47,7 @@ class _DoctorPageState extends State<DoctorPage> {
|
|||
tooltip: AppLocalizations.of(context)!.doctorRecheckTooltip,
|
||||
onPressed: _refresh,
|
||||
),
|
||||
const SizedBox(width: FaiSpace.sm),
|
||||
const SizedBox(width: ChainSpace.sm),
|
||||
],
|
||||
),
|
||||
body: FutureBuilder<DoctorSnapshot>(
|
||||
|
|
@ -58,7 +58,7 @@ class _DoctorPageState extends State<DoctorPage> {
|
|||
}
|
||||
if (snapshot.hasError) {
|
||||
final l = AppLocalizations.of(context)!;
|
||||
return FaiEmptyState(
|
||||
return ChainEmptyState(
|
||||
icon: Icons.cloud_off_outlined,
|
||||
iconColor: Theme.of(context).colorScheme.error,
|
||||
title: l.hubUnreachable,
|
||||
|
|
@ -74,34 +74,34 @@ class _DoctorPageState extends State<DoctorPage> {
|
|||
s.update.updateAvailable ||
|
||||
(!s.update.manifestReachable && s.update.localVersion.isNotEmpty);
|
||||
return ListView(
|
||||
padding: const EdgeInsets.all(FaiSpace.xl),
|
||||
padding: const EdgeInsets.all(ChainSpace.xl),
|
||||
children: [
|
||||
if (showUpdate) _UpdateBanner(status: s.update),
|
||||
if (showUpdate) const SizedBox(height: FaiSpace.lg),
|
||||
if (showUpdate) const SizedBox(height: ChainSpace.lg),
|
||||
_SummaryStrip(snapshot: s),
|
||||
const SizedBox(height: FaiSpace.xl),
|
||||
const SizedBox(height: ChainSpace.xl),
|
||||
_Section(
|
||||
title: AppLocalizations.of(context)!.doctorEventLogSection,
|
||||
child: _EventLogPanel(snapshot: s, onRefresh: _refresh),
|
||||
),
|
||||
const SizedBox(height: FaiSpace.lg),
|
||||
const SizedBox(height: ChainSpace.lg),
|
||||
_Section(
|
||||
title: AppLocalizations.of(
|
||||
context,
|
||||
)!.doctorModulesApprovalsSection,
|
||||
child: _ModulesPanel(snapshot: s),
|
||||
),
|
||||
const SizedBox(height: FaiSpace.lg),
|
||||
const SizedBox(height: ChainSpace.lg),
|
||||
_Section(
|
||||
title: AppLocalizations.of(context)!.doctorHostServicesSection,
|
||||
child: _ServicesPanel(snapshot: s),
|
||||
),
|
||||
const SizedBox(height: FaiSpace.lg),
|
||||
const SizedBox(height: ChainSpace.lg),
|
||||
_Section(
|
||||
title: AppLocalizations.of(context)!.doctorDaemonFilesSection,
|
||||
child: _DaemonPathsPanel(paths: s.paths),
|
||||
),
|
||||
const SizedBox(height: FaiSpace.lg),
|
||||
const SizedBox(height: ChainSpace.lg),
|
||||
_Section(
|
||||
title: AppLocalizations.of(context)!.doctorDaemonControlSection,
|
||||
child: _DaemonActionsCard(),
|
||||
|
|
@ -128,8 +128,8 @@ class _Section extends StatelessWidget {
|
|||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: FaiSpace.xs,
|
||||
bottom: FaiSpace.sm,
|
||||
left: ChainSpace.xs,
|
||||
bottom: ChainSpace.sm,
|
||||
),
|
||||
child: Text(
|
||||
title.toUpperCase(),
|
||||
|
|
@ -162,17 +162,17 @@ class _SummaryStrip extends StatelessWidget {
|
|||
subtitle: l.doctorSummaryCapabilities(snapshot.capabilityCount),
|
||||
icon: Icons.extension_outlined,
|
||||
),
|
||||
const SizedBox(width: FaiSpace.md),
|
||||
const SizedBox(width: ChainSpace.md),
|
||||
_StatTile(
|
||||
label: l.doctorSummaryApprovals,
|
||||
value: snapshot.pendingApprovals.toString(),
|
||||
subtitle: l.doctorSummaryPending,
|
||||
icon: Icons.inbox_outlined,
|
||||
tone: snapshot.pendingApprovals > 0
|
||||
? FaiPillTone.warning
|
||||
: FaiPillTone.neutral,
|
||||
? ChainPillTone.warning
|
||||
: ChainPillTone.neutral,
|
||||
),
|
||||
const SizedBox(width: FaiSpace.md),
|
||||
const SizedBox(width: ChainSpace.md),
|
||||
_StatTile(
|
||||
label: l.doctorSummaryAudit,
|
||||
value: snapshot.chainHealthy ? '✓' : '⚠',
|
||||
|
|
@ -182,10 +182,10 @@ class _SummaryStrip extends StatelessWidget {
|
|||
),
|
||||
icon: Icons.shield_outlined,
|
||||
tone: snapshot.chainHealthy
|
||||
? FaiPillTone.success
|
||||
: FaiPillTone.danger,
|
||||
? ChainPillTone.success
|
||||
: ChainPillTone.danger,
|
||||
),
|
||||
const SizedBox(width: FaiSpace.md),
|
||||
const SizedBox(width: ChainSpace.md),
|
||||
_StatTile(
|
||||
label: l.doctorSummaryServices,
|
||||
value: snapshot.services.length.toString(),
|
||||
|
|
@ -202,36 +202,36 @@ class _StatTile extends StatelessWidget {
|
|||
final String value;
|
||||
final String subtitle;
|
||||
final IconData icon;
|
||||
final FaiPillTone tone;
|
||||
final ChainPillTone tone;
|
||||
|
||||
const _StatTile({
|
||||
required this.label,
|
||||
required this.value,
|
||||
required this.subtitle,
|
||||
required this.icon,
|
||||
this.tone = FaiPillTone.neutral,
|
||||
this.tone = ChainPillTone.neutral,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
final accentColor = switch (tone) {
|
||||
FaiPillTone.success => FaiColors.success,
|
||||
FaiPillTone.warning => FaiColors.warning,
|
||||
FaiPillTone.danger => theme.colorScheme.error,
|
||||
ChainPillTone.success => ChainColors.success,
|
||||
ChainPillTone.warning => ChainColors.warning,
|
||||
ChainPillTone.danger => theme.colorScheme.error,
|
||||
_ => theme.colorScheme.primary,
|
||||
};
|
||||
return Expanded(
|
||||
child: FaiCard(
|
||||
child: ChainCard(
|
||||
accentLeft: accentColor,
|
||||
padding: const EdgeInsets.all(FaiSpace.lg),
|
||||
padding: const EdgeInsets.all(ChainSpace.lg),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Icon(icon, size: 14, color: theme.colorScheme.onSurfaceVariant),
|
||||
const SizedBox(width: FaiSpace.xs),
|
||||
const SizedBox(width: ChainSpace.xs),
|
||||
Flexible(
|
||||
child: Text(
|
||||
label.toUpperCase(),
|
||||
|
|
@ -245,7 +245,7 @@ class _StatTile extends StatelessWidget {
|
|||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: FaiSpace.sm),
|
||||
const SizedBox(height: ChainSpace.sm),
|
||||
Text(
|
||||
value,
|
||||
style: theme.textTheme.displaySmall?.copyWith(
|
||||
|
|
@ -282,15 +282,15 @@ class _EventLogPanel extends StatelessWidget {
|
|||
final theme = Theme.of(context);
|
||||
final healthy = snapshot.chainHealthy;
|
||||
final l = AppLocalizations.of(context)!;
|
||||
return FaiCard(
|
||||
return ChainCard(
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
healthy ? Icons.verified_outlined : Icons.gpp_bad_outlined,
|
||||
size: 24,
|
||||
color: healthy ? FaiColors.success : theme.colorScheme.error,
|
||||
color: healthy ? ChainColors.success : theme.colorScheme.error,
|
||||
),
|
||||
const SizedBox(width: FaiSpace.lg),
|
||||
const SizedBox(width: ChainSpace.lg),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
|
|
@ -322,10 +322,10 @@ class _EventLogPanel extends StatelessWidget {
|
|||
icon: const Icon(Icons.fact_check_outlined, size: 16),
|
||||
label: Text(l.doctorVerifyNow),
|
||||
),
|
||||
const SizedBox(width: FaiSpace.sm),
|
||||
FaiPill(
|
||||
const SizedBox(width: ChainSpace.sm),
|
||||
ChainPill(
|
||||
label: healthy ? l.doctorChainPillOk : l.doctorChainPillTamper,
|
||||
tone: healthy ? FaiPillTone.success : FaiPillTone.danger,
|
||||
tone: healthy ? ChainPillTone.success : ChainPillTone.danger,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
@ -353,7 +353,7 @@ class _DaemonPathsPanel extends StatelessWidget {
|
|||
(l.doctorPathLog, paths.logPath, Icons.description_outlined, false),
|
||||
(
|
||||
l.doctorPathStudioErrors,
|
||||
FaiLog.instance.path,
|
||||
ChainLog.instance.path,
|
||||
Icons.report_problem_outlined,
|
||||
false,
|
||||
),
|
||||
|
|
@ -365,7 +365,7 @@ class _DaemonPathsPanel extends StatelessWidget {
|
|||
].where((e) => e.$2.isNotEmpty).toList();
|
||||
|
||||
if (entries.isEmpty) {
|
||||
return FaiCard(
|
||||
return ChainCard(
|
||||
child: Text(
|
||||
l.doctorPathsEmpty,
|
||||
style: Theme.of(context).textTheme.bodySmall,
|
||||
|
|
@ -373,7 +373,7 @@ class _DaemonPathsPanel extends StatelessWidget {
|
|||
);
|
||||
}
|
||||
|
||||
return FaiCard(
|
||||
return ChainCard(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
|
|
@ -416,7 +416,7 @@ class _PathRow extends StatelessWidget {
|
|||
child: Row(
|
||||
children: [
|
||||
Icon(icon, size: 16, color: theme.colorScheme.onSurfaceVariant),
|
||||
const SizedBox(width: FaiSpace.sm),
|
||||
const SizedBox(width: ChainSpace.sm),
|
||||
SizedBox(
|
||||
width: 90,
|
||||
child: Text(
|
||||
|
|
@ -429,13 +429,13 @@ class _PathRow extends StatelessWidget {
|
|||
Expanded(
|
||||
child: SelectableText(
|
||||
path,
|
||||
style: FaiTheme.mono(
|
||||
style: ChainTheme.mono(
|
||||
size: 11,
|
||||
color: theme.colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: FaiSpace.sm),
|
||||
const SizedBox(width: ChainSpace.sm),
|
||||
if (isLog || isConfig) ...[
|
||||
OutlinedButton.icon(
|
||||
onPressed: () => isConfig
|
||||
|
|
@ -447,7 +447,7 @@ class _PathRow extends StatelessWidget {
|
|||
visualDensity: VisualDensity.compact,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: FaiSpace.xs),
|
||||
const SizedBox(width: ChainSpace.xs),
|
||||
],
|
||||
OutlinedButton.icon(
|
||||
onPressed: () async {
|
||||
|
|
@ -494,7 +494,7 @@ class _DaemonActionsCardState extends State<_DaemonActionsCard> {
|
|||
|
||||
/// True when the last daemon action failed because no `fai`
|
||||
/// binary could be located. Swaps the raw output line for the
|
||||
/// actionable [FaiBinaryRecovery] block.
|
||||
/// actionable [ChainBinaryRecovery] block.
|
||||
bool _binaryMissing = false;
|
||||
ChannelStatusSnapshot? _channels;
|
||||
|
||||
|
|
@ -557,7 +557,7 @@ class _DaemonActionsCardState extends State<_DaemonActionsCard> {
|
|||
}
|
||||
}
|
||||
}
|
||||
return FaiCard(
|
||||
return ChainCard(
|
||||
// Row + Expanded forces the card to take the full width
|
||||
// its parent offers. Without this, the card hugs the
|
||||
// intrinsic width of the longest button row and ends up
|
||||
|
|
@ -575,10 +575,10 @@ class _DaemonActionsCardState extends State<_DaemonActionsCard> {
|
|||
: Icons.power_off_outlined,
|
||||
size: 18,
|
||||
color: active?.running == true
|
||||
? FaiColors.success
|
||||
? ChainColors.success
|
||||
: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
const SizedBox(width: FaiSpace.sm),
|
||||
const SizedBox(width: ChainSpace.sm),
|
||||
Expanded(
|
||||
child: Text(
|
||||
active == null
|
||||
|
|
@ -593,36 +593,36 @@ class _DaemonActionsCardState extends State<_DaemonActionsCard> {
|
|||
),
|
||||
),
|
||||
if (active != null) ...[
|
||||
const SizedBox(width: FaiSpace.sm),
|
||||
FaiPill(
|
||||
const SizedBox(width: ChainSpace.sm),
|
||||
ChainPill(
|
||||
label: active.running
|
||||
? l.doctorPillRunning
|
||||
: l.doctorPillStopped,
|
||||
tone: active.running
|
||||
? FaiPillTone.success
|
||||
: FaiPillTone.neutral,
|
||||
? ChainPillTone.success
|
||||
: ChainPillTone.neutral,
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
const SizedBox(height: FaiSpace.sm),
|
||||
const SizedBox(height: ChainSpace.sm),
|
||||
Text(
|
||||
l.doctorDaemonControlHint,
|
||||
style: theme.textTheme.bodySmall?.copyWith(
|
||||
color: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: FaiSpace.md),
|
||||
const SizedBox(height: ChainSpace.md),
|
||||
Wrap(
|
||||
spacing: FaiSpace.sm,
|
||||
runSpacing: FaiSpace.sm,
|
||||
spacing: ChainSpace.sm,
|
||||
runSpacing: ChainSpace.sm,
|
||||
children: [
|
||||
FilledButton.tonalIcon(
|
||||
onPressed: _busy
|
||||
? null
|
||||
: () => _run(
|
||||
l.daemonActionRestart,
|
||||
() => SystemActions.faiDaemon(['restart']),
|
||||
() => SystemActions.chainDaemon(['restart']),
|
||||
),
|
||||
icon: const Icon(Icons.restart_alt, size: 16),
|
||||
label: Text(l.doctorRestart),
|
||||
|
|
@ -633,7 +633,7 @@ class _DaemonActionsCardState extends State<_DaemonActionsCard> {
|
|||
? null
|
||||
: () => _run(
|
||||
l.daemonActionStart,
|
||||
() => SystemActions.faiDaemon(['start']),
|
||||
() => SystemActions.chainDaemon(['start']),
|
||||
),
|
||||
icon: const Icon(Icons.play_arrow, size: 16),
|
||||
label: Text(l.doctorStart),
|
||||
|
|
@ -643,7 +643,7 @@ class _DaemonActionsCardState extends State<_DaemonActionsCard> {
|
|||
? null
|
||||
: () => _run(
|
||||
l.daemonActionStop,
|
||||
() => SystemActions.faiDaemon(['stop']),
|
||||
() => SystemActions.chainDaemon(['stop']),
|
||||
),
|
||||
icon: const Icon(Icons.stop_circle_outlined, size: 16),
|
||||
label: Text(l.doctorStop),
|
||||
|
|
@ -653,7 +653,7 @@ class _DaemonActionsCardState extends State<_DaemonActionsCard> {
|
|||
? null
|
||||
: () => _run(
|
||||
l.daemonActionStatus,
|
||||
() => SystemActions.faiDaemon(['status']),
|
||||
() => SystemActions.chainDaemon(['status']),
|
||||
),
|
||||
icon: const Icon(Icons.health_and_safety_outlined, size: 16),
|
||||
label: Text(l.doctorStatusAction),
|
||||
|
|
@ -661,7 +661,7 @@ class _DaemonActionsCardState extends State<_DaemonActionsCard> {
|
|||
],
|
||||
),
|
||||
if (_busy) ...[
|
||||
const SizedBox(height: FaiSpace.md),
|
||||
const SizedBox(height: ChainSpace.md),
|
||||
Row(
|
||||
children: [
|
||||
const SizedBox(
|
||||
|
|
@ -669,7 +669,7 @@ class _DaemonActionsCardState extends State<_DaemonActionsCard> {
|
|||
height: 14,
|
||||
child: CircularProgressIndicator(strokeWidth: 2),
|
||||
),
|
||||
const SizedBox(width: FaiSpace.sm),
|
||||
const SizedBox(width: ChainSpace.sm),
|
||||
Text(
|
||||
l.doctorDaemonControlWorking,
|
||||
style: theme.textTheme.bodySmall?.copyWith(
|
||||
|
|
@ -680,27 +680,27 @@ class _DaemonActionsCardState extends State<_DaemonActionsCard> {
|
|||
),
|
||||
],
|
||||
if (_binaryMissing) ...[
|
||||
const SizedBox(height: FaiSpace.md),
|
||||
FaiBinaryRecovery(
|
||||
const SizedBox(height: ChainSpace.md),
|
||||
ChainBinaryRecovery(
|
||||
onLocated: () => _run(
|
||||
l.daemonActionStatus,
|
||||
() => SystemActions.faiDaemon(['status']),
|
||||
() => SystemActions.chainDaemon(['status']),
|
||||
),
|
||||
),
|
||||
],
|
||||
if (_output != null) ...[
|
||||
const SizedBox(height: FaiSpace.md),
|
||||
const SizedBox(height: ChainSpace.md),
|
||||
Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(FaiSpace.sm),
|
||||
padding: const EdgeInsets.all(ChainSpace.sm),
|
||||
decoration: BoxDecoration(
|
||||
color: theme.colorScheme.surfaceContainerHigh,
|
||||
borderRadius: BorderRadius.circular(FaiRadius.sm),
|
||||
borderRadius: BorderRadius.circular(ChainRadius.sm),
|
||||
border: Border.all(color: theme.colorScheme.outlineVariant),
|
||||
),
|
||||
child: SelectableText(
|
||||
_output!,
|
||||
style: FaiTheme.mono(
|
||||
style: ChainTheme.mono(
|
||||
size: 11,
|
||||
color: theme.colorScheme.onSurface,
|
||||
),
|
||||
|
|
@ -732,7 +732,7 @@ class _ModulesPanel extends StatelessWidget {
|
|||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
final l = AppLocalizations.of(context)!;
|
||||
return FaiCard(
|
||||
return ChainCard(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
|
|
@ -743,7 +743,7 @@ class _ModulesPanel extends StatelessWidget {
|
|||
size: 18,
|
||||
color: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
const SizedBox(width: FaiSpace.sm),
|
||||
const SizedBox(width: ChainSpace.sm),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
|
|
@ -767,17 +767,17 @@ class _ModulesPanel extends StatelessWidget {
|
|||
],
|
||||
),
|
||||
),
|
||||
FaiPill(
|
||||
ChainPill(
|
||||
label: snapshot.moduleCount > 0
|
||||
? l.doctorPillLoaded
|
||||
: l.doctorPillEmpty,
|
||||
tone: snapshot.moduleCount > 0
|
||||
? FaiPillTone.success
|
||||
: FaiPillTone.neutral,
|
||||
? ChainPillTone.success
|
||||
: ChainPillTone.neutral,
|
||||
),
|
||||
],
|
||||
),
|
||||
const Divider(height: FaiSpace.xl),
|
||||
const Divider(height: ChainSpace.xl),
|
||||
Row(
|
||||
children: [
|
||||
Icon(
|
||||
|
|
@ -785,7 +785,7 @@ class _ModulesPanel extends StatelessWidget {
|
|||
size: 18,
|
||||
color: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
const SizedBox(width: FaiSpace.sm),
|
||||
const SizedBox(width: ChainSpace.sm),
|
||||
Text(
|
||||
snapshot.pendingApprovals == 0
|
||||
? l.doctorApprovalsNone
|
||||
|
|
@ -794,9 +794,9 @@ class _ModulesPanel extends StatelessWidget {
|
|||
),
|
||||
const Spacer(),
|
||||
if (snapshot.pendingApprovals > 0)
|
||||
FaiPill(
|
||||
ChainPill(
|
||||
label: l.doctorApprovalsAttentionPill,
|
||||
tone: FaiPillTone.warning,
|
||||
tone: ChainPillTone.warning,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
@ -819,10 +819,10 @@ class _ServicesPanel extends StatelessWidget {
|
|||
// Wrap on narrow windows so the mono-spaced hint
|
||||
// (`add to ~/.chain/config.yaml under services:`) does not
|
||||
// overflow horizontally past the card's right edge.
|
||||
return FaiCard(
|
||||
return ChainCard(
|
||||
child: Wrap(
|
||||
spacing: FaiSpace.sm,
|
||||
runSpacing: FaiSpace.xs,
|
||||
spacing: ChainSpace.sm,
|
||||
runSpacing: ChainSpace.xs,
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
Row(
|
||||
|
|
@ -833,7 +833,7 @@ class _ServicesPanel extends StatelessWidget {
|
|||
size: 18,
|
||||
color: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
const SizedBox(width: FaiSpace.sm),
|
||||
const SizedBox(width: ChainSpace.sm),
|
||||
Text(
|
||||
l.doctorServicesEmpty,
|
||||
style: theme.textTheme.bodyMedium?.copyWith(
|
||||
|
|
@ -844,7 +844,7 @@ class _ServicesPanel extends StatelessWidget {
|
|||
),
|
||||
Text(
|
||||
l.doctorServicesEmptyHint,
|
||||
style: FaiTheme.mono(
|
||||
style: ChainTheme.mono(
|
||||
size: 11,
|
||||
color: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
|
|
@ -853,7 +853,7 @@ class _ServicesPanel extends StatelessWidget {
|
|||
),
|
||||
);
|
||||
}
|
||||
return FaiCard(
|
||||
return ChainCard(
|
||||
padding: EdgeInsets.zero,
|
||||
child: Column(
|
||||
children: [
|
||||
|
|
@ -861,7 +861,7 @@ class _ServicesPanel extends StatelessWidget {
|
|||
if (i > 0)
|
||||
Divider(height: 1, color: theme.colorScheme.outlineVariant),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(FaiSpace.lg),
|
||||
padding: const EdgeInsets.all(ChainSpace.lg),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
|
|
@ -869,25 +869,25 @@ class _ServicesPanel extends StatelessWidget {
|
|||
size: 16,
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
const SizedBox(width: FaiSpace.sm),
|
||||
const SizedBox(width: ChainSpace.sm),
|
||||
Text(
|
||||
snapshot.services[i].name,
|
||||
style: theme.textTheme.titleSmall?.copyWith(
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: FaiSpace.md),
|
||||
const SizedBox(width: ChainSpace.md),
|
||||
Text(
|
||||
snapshot.services[i].endpoint,
|
||||
style: FaiTheme.mono(
|
||||
style: ChainTheme.mono(
|
||||
size: 11,
|
||||
color: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
for (final tag in snapshot.services[i].tags) ...[
|
||||
FaiPill(label: tag, tone: FaiPillTone.neutral),
|
||||
const SizedBox(width: FaiSpace.xs),
|
||||
ChainPill(label: tag, tone: ChainPillTone.neutral),
|
||||
const SizedBox(width: ChainSpace.xs),
|
||||
],
|
||||
],
|
||||
),
|
||||
|
|
@ -917,7 +917,7 @@ class _UpdateBannerState extends State<_UpdateBanner> {
|
|||
_applying = true;
|
||||
_applyOutput = null;
|
||||
});
|
||||
final r = await SystemActions.faiUpdateApply(widget.status.channel);
|
||||
final r = await SystemActions.chainUpdateApply(widget.status.channel);
|
||||
if (!mounted) return;
|
||||
setState(() {
|
||||
_applying = false;
|
||||
|
|
@ -945,7 +945,7 @@ class _UpdateBannerState extends State<_UpdateBanner> {
|
|||
final body = available
|
||||
? l.doctorUpdateBody(status.channel, status.latestVersion)
|
||||
: (status.reason ?? l.doctorUpdateUnreachableBody(status.channel));
|
||||
return FaiCard(
|
||||
return ChainCard(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
|
|
@ -953,7 +953,7 @@ class _UpdateBannerState extends State<_UpdateBanner> {
|
|||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Icon(iconData, size: 20, color: iconColor),
|
||||
const SizedBox(width: FaiSpace.md),
|
||||
const SizedBox(width: ChainSpace.md),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
|
|
@ -967,7 +967,7 @@ class _UpdateBannerState extends State<_UpdateBanner> {
|
|||
const SizedBox(height: 2),
|
||||
Text(
|
||||
body,
|
||||
style: FaiTheme.mono(
|
||||
style: ChainTheme.mono(
|
||||
size: 11,
|
||||
color: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
|
|
@ -976,7 +976,7 @@ class _UpdateBannerState extends State<_UpdateBanner> {
|
|||
const SizedBox(height: 4),
|
||||
Text(
|
||||
l.doctorReleaseNotes(status.releaseNotesUrl!),
|
||||
style: FaiTheme.mono(
|
||||
style: ChainTheme.mono(
|
||||
size: 11,
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
|
|
@ -999,16 +999,16 @@ class _UpdateBannerState extends State<_UpdateBanner> {
|
|||
_applying ? l.doctorApplying : l.doctorApplyUpdate,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: FaiSpace.sm),
|
||||
FaiPill(
|
||||
const SizedBox(width: ChainSpace.sm),
|
||||
ChainPill(
|
||||
label: available ? l.doctorPillNew : l.doctorPillOffline,
|
||||
tone: available ? FaiPillTone.success : FaiPillTone.neutral,
|
||||
tone: available ? ChainPillTone.success : ChainPillTone.neutral,
|
||||
),
|
||||
],
|
||||
),
|
||||
if (_applyOutput != null) ...[
|
||||
const SizedBox(height: FaiSpace.md),
|
||||
FaiErrorBox(text: _applyOutput!, maxHeight: 240),
|
||||
const SizedBox(height: ChainSpace.md),
|
||||
ChainErrorBox(text: _applyOutput!, maxHeight: 240),
|
||||
],
|
||||
],
|
||||
),
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ class _FederationPageState extends State<FederationPage> {
|
|||
tooltip: l.federationReloadTooltip,
|
||||
onPressed: _refresh,
|
||||
),
|
||||
const SizedBox(width: FaiSpace.sm),
|
||||
const SizedBox(width: ChainSpace.sm),
|
||||
],
|
||||
),
|
||||
floatingActionButton: FloatingActionButton.extended(
|
||||
|
|
@ -118,7 +118,7 @@ class _FederationPageState extends State<FederationPage> {
|
|||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
if (snapshot.hasError) {
|
||||
return FaiEmptyState(
|
||||
return ChainEmptyState(
|
||||
icon: Icons.cloud_off_outlined,
|
||||
iconColor: theme.colorScheme.error,
|
||||
title: l.hubUnreachable,
|
||||
|
|
@ -131,7 +131,7 @@ class _FederationPageState extends State<FederationPage> {
|
|||
}
|
||||
final sats = snapshot.data ?? [];
|
||||
if (sats.isEmpty) {
|
||||
return FaiEmptyState(
|
||||
return ChainEmptyState(
|
||||
icon: Icons.hub_outlined,
|
||||
title: l.federationEmptyTitle,
|
||||
hint: l.federationEmptyHint,
|
||||
|
|
@ -143,9 +143,9 @@ class _FederationPageState extends State<FederationPage> {
|
|||
);
|
||||
}
|
||||
return ListView.separated(
|
||||
padding: const EdgeInsets.all(FaiSpace.xl),
|
||||
padding: const EdgeInsets.all(ChainSpace.xl),
|
||||
itemCount: sats.length,
|
||||
separatorBuilder: (_, _) => const SizedBox(height: FaiSpace.md),
|
||||
separatorBuilder: (_, _) => const SizedBox(height: ChainSpace.md),
|
||||
itemBuilder: (context, i) => _SatelliteCard(satellite: sats[i]),
|
||||
);
|
||||
},
|
||||
|
|
@ -162,19 +162,19 @@ class _SatelliteCard extends StatelessWidget {
|
|||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
final l = AppLocalizations.of(context)!;
|
||||
return FaiCard(
|
||||
return ChainCard(
|
||||
accentTop: true,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
FaiPill(
|
||||
ChainPill(
|
||||
label: l.federationPillConnected,
|
||||
tone: FaiPillTone.success,
|
||||
tone: ChainPillTone.success,
|
||||
icon: Icons.link,
|
||||
),
|
||||
const SizedBox(width: FaiSpace.sm),
|
||||
const SizedBox(width: ChainSpace.sm),
|
||||
Expanded(
|
||||
child: Text(
|
||||
satellite.displayName,
|
||||
|
|
@ -183,19 +183,19 @@ class _SatelliteCard extends StatelessWidget {
|
|||
),
|
||||
),
|
||||
),
|
||||
FaiPill(
|
||||
ChainPill(
|
||||
label: satellite.region.isEmpty
|
||||
? l.federationRegionNone
|
||||
: satellite.region,
|
||||
tone: FaiPillTone.neutral,
|
||||
tone: ChainPillTone.neutral,
|
||||
icon: Icons.public,
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: FaiSpace.md),
|
||||
const SizedBox(height: ChainSpace.md),
|
||||
Wrap(
|
||||
spacing: FaiSpace.md,
|
||||
runSpacing: FaiSpace.xs,
|
||||
spacing: ChainSpace.md,
|
||||
runSpacing: ChainSpace.xs,
|
||||
children: [
|
||||
_meta(theme, 'v${satellite.hubVersion}'),
|
||||
_meta(theme, 'wire ${satellite.wireVersion}'),
|
||||
|
|
@ -203,7 +203,7 @@ class _SatelliteCard extends StatelessWidget {
|
|||
],
|
||||
),
|
||||
if (satellite.capabilities.isNotEmpty) ...[
|
||||
const SizedBox(height: FaiSpace.md),
|
||||
const SizedBox(height: ChainSpace.md),
|
||||
Text(
|
||||
l.federationCapabilities(satellite.capabilities.length),
|
||||
style: theme.textTheme.labelSmall?.copyWith(
|
||||
|
|
@ -213,13 +213,13 @@ class _SatelliteCard extends StatelessWidget {
|
|||
),
|
||||
const SizedBox(height: 4),
|
||||
Wrap(
|
||||
spacing: FaiSpace.xs,
|
||||
runSpacing: FaiSpace.xs,
|
||||
spacing: ChainSpace.xs,
|
||||
runSpacing: ChainSpace.xs,
|
||||
children: satellite.capabilities
|
||||
.map(
|
||||
(c) => FaiPill(
|
||||
(c) => ChainPill(
|
||||
label: c,
|
||||
tone: FaiPillTone.accent,
|
||||
tone: ChainPillTone.accent,
|
||||
icon: Icons.extension_outlined,
|
||||
),
|
||||
)
|
||||
|
|
@ -233,7 +233,7 @@ class _SatelliteCard extends StatelessWidget {
|
|||
|
||||
Widget _meta(ThemeData theme, String text) => Text(
|
||||
text,
|
||||
style: FaiTheme.mono(size: 10, color: theme.colorScheme.onSurfaceVariant),
|
||||
style: ChainTheme.mono(size: 10, color: theme.colorScheme.onSurfaceVariant),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -261,11 +261,11 @@ class _EnrollmentDialog extends StatelessWidget {
|
|||
Text(l.federationTokenLabel, style: theme.textTheme.labelSmall),
|
||||
const SizedBox(height: 4),
|
||||
_CopyableBlock(text: enrollment.token, copiedMsg: l.federationCopied),
|
||||
const SizedBox(height: FaiSpace.md),
|
||||
const SizedBox(height: ChainSpace.md),
|
||||
Text(l.federationConfigLabel, style: theme.textTheme.labelSmall),
|
||||
const SizedBox(height: 4),
|
||||
_CopyableBlock(text: config, copiedMsg: l.federationCopied),
|
||||
const SizedBox(height: FaiSpace.md),
|
||||
const SizedBox(height: ChainSpace.md),
|
||||
Text(
|
||||
l.federationEnrollmentHint,
|
||||
style: theme.textTheme.bodySmall?.copyWith(
|
||||
|
|
@ -299,19 +299,19 @@ class _CopyableBlock extends StatelessWidget {
|
|||
Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.fromLTRB(
|
||||
FaiSpace.md,
|
||||
FaiSpace.md,
|
||||
ChainSpace.md,
|
||||
ChainSpace.md,
|
||||
40,
|
||||
FaiSpace.md,
|
||||
ChainSpace.md,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: theme.colorScheme.surfaceContainerHigh,
|
||||
borderRadius: BorderRadius.circular(FaiRadius.sm),
|
||||
borderRadius: BorderRadius.circular(ChainRadius.sm),
|
||||
border: Border.all(color: theme.colorScheme.outlineVariant),
|
||||
),
|
||||
child: SelectableText(
|
||||
text,
|
||||
style: FaiTheme.mono(size: 11, color: theme.colorScheme.onSurface),
|
||||
style: ChainTheme.mono(size: 11, color: theme.colorScheme.onSurface),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ class _ModulesPageState extends State<ModulesPage> {
|
|||
tooltip: AppLocalizations.of(context)!.modulesReloadTooltip,
|
||||
onPressed: _refresh,
|
||||
),
|
||||
const SizedBox(width: FaiSpace.sm),
|
||||
const SizedBox(width: ChainSpace.sm),
|
||||
],
|
||||
),
|
||||
body: FutureBuilder<List<ModuleSummary>>(
|
||||
|
|
@ -59,7 +59,7 @@ class _ModulesPageState extends State<ModulesPage> {
|
|||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
if (snapshot.hasError) {
|
||||
return FaiEmptyState(
|
||||
return ChainEmptyState(
|
||||
icon: Icons.cloud_off_outlined,
|
||||
iconColor: Theme.of(context).colorScheme.error,
|
||||
title: l.hubUnreachable,
|
||||
|
|
@ -72,22 +72,22 @@ class _ModulesPageState extends State<ModulesPage> {
|
|||
}
|
||||
final modules = snapshot.data ?? [];
|
||||
if (modules.isEmpty) {
|
||||
return FaiEmptyState(
|
||||
return ChainEmptyState(
|
||||
icon: Icons.extension_outlined,
|
||||
title: l.modulesNoneTitle,
|
||||
hint: l.modulesNoneHint,
|
||||
);
|
||||
}
|
||||
return ListView(
|
||||
padding: const EdgeInsets.all(FaiSpace.xl),
|
||||
padding: const EdgeInsets.all(ChainSpace.xl),
|
||||
children: [
|
||||
_RecentActivityPanel(future: _historyFuture),
|
||||
const SizedBox(height: FaiSpace.md),
|
||||
const SizedBox(height: ChainSpace.md),
|
||||
for (var i = 0; i < modules.length; i++) ...[
|
||||
if (i > 0) const SizedBox(height: FaiSpace.md),
|
||||
if (i > 0) const SizedBox(height: ChainSpace.md),
|
||||
GestureDetector(
|
||||
onTap: () async {
|
||||
final uninstalled = await FaiModuleSheet.show(
|
||||
final uninstalled = await ChainModuleSheet.show(
|
||||
context,
|
||||
modules[i].name,
|
||||
);
|
||||
|
|
@ -116,7 +116,7 @@ class _ModuleCard extends StatelessWidget {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
return FaiCard(
|
||||
return ChainCard(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
|
|
@ -128,15 +128,15 @@ class _ModuleCard extends StatelessWidget {
|
|||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: FaiSpace.sm),
|
||||
FaiPill(
|
||||
const SizedBox(width: ChainSpace.sm),
|
||||
ChainPill(
|
||||
label: 'v${module.version}',
|
||||
tone: FaiPillTone.neutral,
|
||||
tone: ChainPillTone.neutral,
|
||||
monospace: true,
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: FaiSpace.md),
|
||||
const SizedBox(height: ChainSpace.md),
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
|
|
@ -152,13 +152,13 @@ class _ModuleCard extends StatelessWidget {
|
|||
),
|
||||
Expanded(
|
||||
child: Wrap(
|
||||
spacing: FaiSpace.xs,
|
||||
runSpacing: FaiSpace.xs,
|
||||
spacing: ChainSpace.xs,
|
||||
runSpacing: ChainSpace.xs,
|
||||
children: module.capabilities
|
||||
.map(
|
||||
(c) => FaiPill(
|
||||
(c) => ChainPill(
|
||||
label: c,
|
||||
tone: FaiPillTone.accent,
|
||||
tone: ChainPillTone.accent,
|
||||
monospace: true,
|
||||
),
|
||||
)
|
||||
|
|
@ -192,12 +192,12 @@ class _RecentActivityPanel extends StatelessWidget {
|
|||
if (events.isEmpty) return const SizedBox.shrink();
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: FaiSpace.md,
|
||||
vertical: FaiSpace.sm,
|
||||
horizontal: ChainSpace.md,
|
||||
vertical: ChainSpace.sm,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: theme.colorScheme.surfaceContainer,
|
||||
borderRadius: BorderRadius.circular(FaiRadius.sm),
|
||||
borderRadius: BorderRadius.circular(ChainRadius.sm),
|
||||
border: Border.all(color: theme.colorScheme.outlineVariant),
|
||||
),
|
||||
child: Column(
|
||||
|
|
@ -219,7 +219,7 @@ class _RecentActivityPanel extends StatelessWidget {
|
|||
fontSize: 10,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: FaiSpace.sm),
|
||||
const SizedBox(width: ChainSpace.sm),
|
||||
Text(
|
||||
AppLocalizations.of(
|
||||
context,
|
||||
|
|
@ -230,7 +230,7 @@ class _RecentActivityPanel extends StatelessWidget {
|
|||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: FaiSpace.xs),
|
||||
const SizedBox(height: ChainSpace.xs),
|
||||
for (final e in events) _ActivityRow(event: e),
|
||||
],
|
||||
),
|
||||
|
|
@ -248,7 +248,7 @@ class _ActivityRow extends StatelessWidget {
|
|||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
final installed = event.type == 'module.installed';
|
||||
final accent = installed ? FaiColors.success : FaiColors.warning;
|
||||
final accent = installed ? ChainColors.success : ChainColors.warning;
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 2),
|
||||
child: Row(
|
||||
|
|
@ -263,7 +263,7 @@ class _ActivityRow extends StatelessWidget {
|
|||
width: 150,
|
||||
child: Text(
|
||||
_formatTimestamp(event.timestamp.toLocal()),
|
||||
style: FaiTheme.mono(
|
||||
style: ChainTheme.mono(
|
||||
size: 10,
|
||||
color: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -35,14 +35,14 @@ class WelcomePage extends StatelessWidget {
|
|||
final hubDown = StudioShellState.of(context)?.connected == false;
|
||||
return Scaffold(
|
||||
backgroundColor: theme.scaffoldBackgroundColor,
|
||||
appBar: AppBar(titleSpacing: FaiSpace.xl, title: Text(l.navWelcome)),
|
||||
appBar: AppBar(titleSpacing: ChainSpace.xl, title: Text(l.navWelcome)),
|
||||
body: SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(
|
||||
FaiSpace.xl,
|
||||
FaiSpace.lg,
|
||||
FaiSpace.xl,
|
||||
FaiSpace.xxl,
|
||||
ChainSpace.xl,
|
||||
ChainSpace.lg,
|
||||
ChainSpace.xl,
|
||||
ChainSpace.xxl,
|
||||
),
|
||||
// Center the 960-px content column on wide windows
|
||||
// so the right margin matches the left rather than
|
||||
|
|
@ -59,24 +59,24 @@ class WelcomePage extends StatelessWidget {
|
|||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const _Hero(),
|
||||
const SizedBox(height: FaiSpace.xxl),
|
||||
const SizedBox(height: ChainSpace.xxl),
|
||||
// When the hub is down the onboarding checklist
|
||||
// would render dead (all-unchecked, nothing to
|
||||
// probe). Lead with a "start the hub" card
|
||||
// instead; restore the checklist once connected.
|
||||
if (hubDown) ...[
|
||||
const _HubDownHero(),
|
||||
const SizedBox(height: FaiSpace.xxl),
|
||||
const SizedBox(height: ChainSpace.xxl),
|
||||
] else
|
||||
const _OnboardingChecklist(),
|
||||
const _PillarRow(),
|
||||
const SizedBox(height: FaiSpace.xxl),
|
||||
const SizedBox(height: ChainSpace.xxl),
|
||||
const _SectionLabel(textKey: _SectionLabelKey.trust),
|
||||
const SizedBox(height: FaiSpace.md),
|
||||
const SizedBox(height: ChainSpace.md),
|
||||
const _TrustPosture(),
|
||||
const SizedBox(height: FaiSpace.xxl),
|
||||
const SizedBox(height: ChainSpace.xxl),
|
||||
const _SectionLabel(textKey: _SectionLabelKey.docs),
|
||||
const SizedBox(height: FaiSpace.md),
|
||||
const SizedBox(height: ChainSpace.md),
|
||||
const _DocsRow(),
|
||||
],
|
||||
),
|
||||
|
|
@ -100,9 +100,9 @@ class _Hero extends StatelessWidget {
|
|||
final l = AppLocalizations.of(context)!;
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(FaiSpace.xxl),
|
||||
padding: const EdgeInsets.all(ChainSpace.xxl),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(FaiRadius.md),
|
||||
borderRadius: BorderRadius.circular(ChainRadius.md),
|
||||
gradient: LinearGradient(
|
||||
colors: [
|
||||
theme.colorScheme.primary.withValues(alpha: 0.18),
|
||||
|
|
@ -123,7 +123,7 @@ class _Hero extends StatelessWidget {
|
|||
Row(
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.all(FaiSpace.md),
|
||||
padding: const EdgeInsets.all(ChainSpace.md),
|
||||
decoration: BoxDecoration(
|
||||
color: theme.colorScheme.primary.withValues(alpha: 0.14),
|
||||
shape: BoxShape.circle,
|
||||
|
|
@ -134,7 +134,7 @@ class _Hero extends StatelessWidget {
|
|||
color: theme.colorScheme.primary,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: FaiSpace.lg),
|
||||
const SizedBox(width: ChainSpace.lg),
|
||||
Expanded(
|
||||
child: Text(
|
||||
l.welcomeHeroTitle,
|
||||
|
|
@ -145,7 +145,7 @@ class _Hero extends StatelessWidget {
|
|||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: FaiSpace.lg),
|
||||
const SizedBox(height: ChainSpace.lg),
|
||||
Text(
|
||||
l.welcomeHeroSubtitle,
|
||||
style: theme.textTheme.titleMedium?.copyWith(
|
||||
|
|
@ -189,13 +189,13 @@ class _HubDownHeroState extends State<_HubDownHero> {
|
|||
final l = AppLocalizations.of(context)!;
|
||||
// No `fai` binary → "Start hub" cannot work; lead the
|
||||
// operator to the install guide instead.
|
||||
final canStart = SystemActions.faiBinaryExists();
|
||||
final canStart = SystemActions.chainBinaryExists();
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(FaiSpace.xl),
|
||||
padding: const EdgeInsets.all(ChainSpace.xl),
|
||||
decoration: BoxDecoration(
|
||||
color: theme.colorScheme.errorContainer.withValues(alpha: 0.35),
|
||||
borderRadius: BorderRadius.circular(FaiRadius.md),
|
||||
borderRadius: BorderRadius.circular(ChainRadius.md),
|
||||
border: Border.all(
|
||||
color: theme.colorScheme.error.withValues(alpha: 0.4),
|
||||
),
|
||||
|
|
@ -210,7 +210,7 @@ class _HubDownHeroState extends State<_HubDownHero> {
|
|||
size: 24,
|
||||
color: theme.colorScheme.error,
|
||||
),
|
||||
const SizedBox(width: FaiSpace.md),
|
||||
const SizedBox(width: ChainSpace.md),
|
||||
Expanded(
|
||||
child: Text(
|
||||
l.welcomeHubDownTitle,
|
||||
|
|
@ -221,7 +221,7 @@ class _HubDownHeroState extends State<_HubDownHero> {
|
|||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: FaiSpace.md),
|
||||
const SizedBox(height: ChainSpace.md),
|
||||
Text(
|
||||
l.welcomeHubDownBody,
|
||||
style: theme.textTheme.bodyMedium?.copyWith(
|
||||
|
|
@ -229,15 +229,15 @@ class _HubDownHeroState extends State<_HubDownHero> {
|
|||
height: 1.45,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: FaiSpace.xs),
|
||||
const SizedBox(height: ChainSpace.xs),
|
||||
Text(
|
||||
l.welcomeHubDownEndpoint(HubService.instance.endpointLabel),
|
||||
style: FaiTheme.mono(
|
||||
style: ChainTheme.mono(
|
||||
size: 11,
|
||||
color: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: FaiSpace.lg),
|
||||
const SizedBox(height: ChainSpace.lg),
|
||||
if (canStart)
|
||||
FilledButton.icon(
|
||||
onPressed: _starting ? null : _start,
|
||||
|
|
@ -253,8 +253,8 @@ class _HubDownHeroState extends State<_HubDownHero> {
|
|||
),
|
||||
)
|
||||
else
|
||||
const FaiBinaryRecovery(),
|
||||
const SizedBox(height: FaiSpace.sm),
|
||||
const ChainBinaryRecovery(),
|
||||
const SizedBox(height: ChainSpace.sm),
|
||||
TextButton.icon(
|
||||
icon: const Icon(Icons.open_in_new, size: 16),
|
||||
label: Text(l.welcomeHubDownDocsLink),
|
||||
|
|
@ -323,7 +323,7 @@ class _PillarRow extends StatelessWidget {
|
|||
children: [
|
||||
for (final p in pillars) ...[
|
||||
_Pillar(icon: p.$1, title: p.$2, body: p.$3),
|
||||
const SizedBox(height: FaiSpace.md),
|
||||
const SizedBox(height: ChainSpace.md),
|
||||
],
|
||||
],
|
||||
);
|
||||
|
|
@ -339,7 +339,7 @@ class _PillarRow extends StatelessWidget {
|
|||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
for (var i = 0; i < pillars.length; i++) ...[
|
||||
if (i > 0) const SizedBox(width: FaiSpace.md),
|
||||
if (i > 0) const SizedBox(width: ChainSpace.md),
|
||||
Expanded(
|
||||
child: _Pillar(
|
||||
icon: pillars[i].$1,
|
||||
|
|
@ -367,24 +367,24 @@ class _Pillar extends StatelessWidget {
|
|||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(FaiSpace.lg),
|
||||
padding: const EdgeInsets.all(ChainSpace.lg),
|
||||
decoration: BoxDecoration(
|
||||
color: theme.colorScheme.surfaceContainer,
|
||||
borderRadius: BorderRadius.circular(FaiRadius.md),
|
||||
borderRadius: BorderRadius.circular(ChainRadius.md),
|
||||
border: Border.all(color: theme.colorScheme.outlineVariant),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Icon(icon, size: 28, color: theme.colorScheme.primary),
|
||||
const SizedBox(height: FaiSpace.md),
|
||||
const SizedBox(height: ChainSpace.md),
|
||||
Text(
|
||||
title,
|
||||
style: theme.textTheme.titleLarge?.copyWith(
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: FaiSpace.sm),
|
||||
const SizedBox(height: ChainSpace.sm),
|
||||
Text(
|
||||
body,
|
||||
style: theme.textTheme.bodyMedium?.copyWith(
|
||||
|
|
@ -427,7 +427,7 @@ class _TrustPosture extends StatelessWidget {
|
|||
return Column(
|
||||
children: [
|
||||
for (var i = 0; i < rows.length; i++) ...[
|
||||
if (i > 0) const SizedBox(height: FaiSpace.sm),
|
||||
if (i > 0) const SizedBox(height: ChainSpace.sm),
|
||||
_TrustRow(icon: rows[i].$1, title: rows[i].$2, body: rows[i].$3),
|
||||
],
|
||||
],
|
||||
|
|
@ -450,17 +450,17 @@ class _TrustRow extends StatelessWidget {
|
|||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(FaiSpace.lg),
|
||||
padding: const EdgeInsets.all(ChainSpace.lg),
|
||||
decoration: BoxDecoration(
|
||||
color: theme.colorScheme.surfaceContainer,
|
||||
borderRadius: BorderRadius.circular(FaiRadius.md),
|
||||
borderRadius: BorderRadius.circular(ChainRadius.md),
|
||||
border: Border.all(color: theme.colorScheme.outlineVariant),
|
||||
),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Icon(icon, size: 22, color: theme.colorScheme.primary),
|
||||
const SizedBox(width: FaiSpace.lg),
|
||||
const SizedBox(width: ChainSpace.lg),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
|
|
@ -601,13 +601,13 @@ class _OnboardingChecklistState extends State<_OnboardingChecklist> {
|
|||
_aiOk,
|
||||
l.welcomeChecklistAi,
|
||||
l.welcomeChecklistAiHint,
|
||||
() => FaiSettingsDialog.show(context),
|
||||
() => ChainSettingsDialog.show(context),
|
||||
),
|
||||
(
|
||||
_mcpOk,
|
||||
l.welcomeChecklistMcp,
|
||||
l.welcomeChecklistMcpHint,
|
||||
() => FaiSettingsDialog.show(context),
|
||||
() => ChainSettingsDialog.show(context),
|
||||
),
|
||||
(
|
||||
_moduleOk,
|
||||
|
|
@ -623,7 +623,7 @@ class _OnboardingChecklistState extends State<_OnboardingChecklist> {
|
|||
),
|
||||
];
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: FaiSpace.xxl),
|
||||
padding: const EdgeInsets.only(bottom: ChainSpace.xxl),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
|
|
@ -661,11 +661,11 @@ class _OnboardingChecklistState extends State<_OnboardingChecklist> {
|
|||
color: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: FaiSpace.md),
|
||||
const SizedBox(height: ChainSpace.md),
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: theme.colorScheme.surfaceContainer,
|
||||
borderRadius: BorderRadius.circular(FaiRadius.md),
|
||||
borderRadius: BorderRadius.circular(ChainRadius.md),
|
||||
border: Border.all(color: theme.colorScheme.outlineVariant),
|
||||
),
|
||||
child: Column(
|
||||
|
|
@ -684,7 +684,7 @@ class _OnboardingChecklistState extends State<_OnboardingChecklist> {
|
|||
),
|
||||
),
|
||||
if (allDone) ...[
|
||||
const SizedBox(height: FaiSpace.md),
|
||||
const SizedBox(height: ChainSpace.md),
|
||||
_AllDoneCelebration(onDismiss: _dismiss),
|
||||
],
|
||||
],
|
||||
|
|
@ -707,19 +707,19 @@ class _AllDoneCelebration extends StatelessWidget {
|
|||
final theme = Theme.of(context);
|
||||
final l = AppLocalizations.of(context)!;
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(FaiSpace.lg),
|
||||
padding: const EdgeInsets.all(ChainSpace.lg),
|
||||
decoration: BoxDecoration(
|
||||
color: FaiColors.success.withValues(alpha: 0.08),
|
||||
borderRadius: BorderRadius.circular(FaiRadius.md),
|
||||
border: Border.all(color: FaiColors.success.withValues(alpha: 0.35)),
|
||||
color: ChainColors.success.withValues(alpha: 0.08),
|
||||
borderRadius: BorderRadius.circular(ChainRadius.md),
|
||||
border: Border.all(color: ChainColors.success.withValues(alpha: 0.35)),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Icon(Icons.celebration_outlined, color: FaiColors.success),
|
||||
const SizedBox(width: FaiSpace.sm),
|
||||
Icon(Icons.celebration_outlined, color: ChainColors.success),
|
||||
const SizedBox(width: ChainSpace.sm),
|
||||
Expanded(
|
||||
child: Text(
|
||||
l.welcomeChecklistAllSetTitle,
|
||||
|
|
@ -741,7 +741,7 @@ class _AllDoneCelebration extends StatelessWidget {
|
|||
color: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: FaiSpace.md),
|
||||
const SizedBox(height: ChainSpace.md),
|
||||
_NextStepRow(
|
||||
icon: Icons.timeline_outlined,
|
||||
title: l.welcomeChecklistNextAuditTitle,
|
||||
|
|
@ -797,12 +797,12 @@ class _NextStepRow extends StatelessWidget {
|
|||
final theme = Theme.of(context);
|
||||
final canActivate = doc != null && onOpenDoc != null;
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: FaiSpace.sm),
|
||||
padding: const EdgeInsets.only(bottom: ChainSpace.sm),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Icon(icon, size: 18, color: theme.colorScheme.primary),
|
||||
const SizedBox(width: FaiSpace.md),
|
||||
const SizedBox(width: ChainSpace.md),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
|
|
@ -823,7 +823,7 @@ class _NextStepRow extends StatelessWidget {
|
|||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: FaiSpace.md),
|
||||
const SizedBox(width: ChainSpace.md),
|
||||
OutlinedButton(
|
||||
onPressed: canActivate ? () => onOpenDoc!(doc!) : null,
|
||||
child: Text(buttonLabel),
|
||||
|
|
@ -856,16 +856,16 @@ class _ChecklistRow extends StatelessWidget {
|
|||
final theme = Theme.of(context);
|
||||
final l = AppLocalizations.of(context)!;
|
||||
final row = Padding(
|
||||
padding: const EdgeInsets.all(FaiSpace.lg),
|
||||
padding: const EdgeInsets.all(ChainSpace.lg),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Icon(
|
||||
done ? Icons.check_circle : Icons.radio_button_unchecked,
|
||||
size: 20,
|
||||
color: done ? FaiColors.success : theme.colorScheme.outline,
|
||||
color: done ? ChainColors.success : theme.colorScheme.outline,
|
||||
),
|
||||
const SizedBox(width: FaiSpace.lg),
|
||||
const SizedBox(width: ChainSpace.lg),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
|
|
@ -890,10 +890,10 @@ class _ChecklistRow extends StatelessWidget {
|
|||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: FaiSpace.md),
|
||||
FaiPill(
|
||||
const SizedBox(width: ChainSpace.md),
|
||||
ChainPill(
|
||||
label: done ? l.welcomeChecklistDone : l.welcomeChecklistTodo,
|
||||
tone: done ? FaiPillTone.success : FaiPillTone.neutral,
|
||||
tone: done ? ChainPillTone.success : ChainPillTone.neutral,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
@ -985,7 +985,7 @@ class _DocsRow extends StatelessWidget {
|
|||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: FaiSpace.md),
|
||||
const SizedBox(height: ChainSpace.md),
|
||||
LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
final twoCols = constraints.maxWidth >= 640;
|
||||
|
|
@ -997,16 +997,16 @@ class _DocsRow extends StatelessWidget {
|
|||
return Column(
|
||||
children: [
|
||||
for (var i = 0; i < _kDocs.length; i++) ...[
|
||||
if (i > 0) const SizedBox(height: FaiSpace.md),
|
||||
if (i > 0) const SizedBox(height: ChainSpace.md),
|
||||
_DocCard(entry: _kDocs[i]),
|
||||
],
|
||||
],
|
||||
);
|
||||
}
|
||||
final cardWidth = (constraints.maxWidth - FaiSpace.md) / 2;
|
||||
final cardWidth = (constraints.maxWidth - ChainSpace.md) / 2;
|
||||
return Wrap(
|
||||
spacing: FaiSpace.md,
|
||||
runSpacing: FaiSpace.md,
|
||||
spacing: ChainSpace.md,
|
||||
runSpacing: ChainSpace.md,
|
||||
children: [
|
||||
for (final d in _kDocs)
|
||||
SizedBox(
|
||||
|
|
@ -1045,30 +1045,30 @@ class _DocCardState extends State<_DocCard> {
|
|||
onEnter: (_) => setState(() => _hovered = true),
|
||||
onExit: (_) => setState(() => _hovered = false),
|
||||
child: AnimatedContainer(
|
||||
duration: FaiMotion.base,
|
||||
curve: FaiMotion.easing,
|
||||
duration: ChainMotion.base,
|
||||
curve: ChainMotion.easing,
|
||||
transform: Matrix4.translationValues(0, _hovered ? -2 : 0, 0),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(FaiRadius.md),
|
||||
boxShadow: _hovered ? FaiElevation.medium(theme.brightness) : null,
|
||||
borderRadius: BorderRadius.circular(ChainRadius.md),
|
||||
boxShadow: _hovered ? ChainElevation.medium(theme.brightness) : null,
|
||||
),
|
||||
child: Material(
|
||||
color: theme.colorScheme.surfaceContainer,
|
||||
borderRadius: BorderRadius.circular(FaiRadius.md),
|
||||
borderRadius: BorderRadius.circular(ChainRadius.md),
|
||||
child: InkWell(
|
||||
onTap: () => _DocReaderSheet.show(context, entry),
|
||||
borderRadius: BorderRadius.circular(FaiRadius.md),
|
||||
borderRadius: BorderRadius.circular(ChainRadius.md),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(FaiSpace.lg),
|
||||
padding: const EdgeInsets.all(ChainSpace.lg),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(FaiRadius.md),
|
||||
borderRadius: BorderRadius.circular(ChainRadius.md),
|
||||
border: Border.all(color: theme.colorScheme.outlineVariant),
|
||||
),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Icon(entry.icon, size: 22, color: theme.colorScheme.primary),
|
||||
const SizedBox(width: FaiSpace.lg),
|
||||
const SizedBox(width: ChainSpace.lg),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
|
|
@ -1159,7 +1159,7 @@ class _DocReaderSheet extends StatefulWidget {
|
|||
backgroundColor: Theme.of(context).colorScheme.surfaceContainer,
|
||||
elevation: 8,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(FaiRadius.md)),
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(ChainRadius.md)),
|
||||
),
|
||||
builder: (_) => _DocReaderSheet(entry: entry),
|
||||
);
|
||||
|
|
@ -1191,7 +1191,7 @@ class _DocReaderSheetState extends State<_DocReaderSheet> {
|
|||
// the .dart_tool asset manifest can be inconsistent with
|
||||
// the compiled binary — surface "rebuild Studio" as a
|
||||
// first-class hint rather than just dumping the raw
|
||||
// PlatformException string into FaiErrorBox.
|
||||
// PlatformException string into ChainErrorBox.
|
||||
try {
|
||||
return await rootBundle.loadString(localised);
|
||||
} catch (firstErr) {
|
||||
|
|
@ -1219,7 +1219,7 @@ class _DocReaderSheetState extends State<_DocReaderSheet> {
|
|||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: FaiSpace.sm),
|
||||
padding: const EdgeInsets.symmetric(vertical: ChainSpace.sm),
|
||||
child: Container(
|
||||
width: 40,
|
||||
height: 4,
|
||||
|
|
@ -1231,10 +1231,10 @@ class _DocReaderSheetState extends State<_DocReaderSheet> {
|
|||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(
|
||||
FaiSpace.xxl,
|
||||
FaiSpace.sm,
|
||||
FaiSpace.lg,
|
||||
FaiSpace.sm,
|
||||
ChainSpace.xxl,
|
||||
ChainSpace.sm,
|
||||
ChainSpace.lg,
|
||||
ChainSpace.sm,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
|
|
@ -1243,7 +1243,7 @@ class _DocReaderSheetState extends State<_DocReaderSheet> {
|
|||
size: 20,
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
const SizedBox(width: FaiSpace.sm),
|
||||
const SizedBox(width: ChainSpace.sm),
|
||||
Expanded(
|
||||
child: Text(
|
||||
widget.entry.title(l),
|
||||
|
|
@ -1268,7 +1268,7 @@ class _DocReaderSheetState extends State<_DocReaderSheet> {
|
|||
builder: (context, snap) {
|
||||
if (snap.connectionState == ConnectionState.waiting) {
|
||||
return const Padding(
|
||||
padding: EdgeInsets.all(FaiSpace.xxl),
|
||||
padding: EdgeInsets.all(ChainSpace.xxl),
|
||||
child: Center(child: CircularProgressIndicator()),
|
||||
);
|
||||
}
|
||||
|
|
@ -1276,7 +1276,7 @@ class _DocReaderSheetState extends State<_DocReaderSheet> {
|
|||
final err = snap.error;
|
||||
final structured = err is _DocReaderError ? err : null;
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(FaiSpace.xxl),
|
||||
padding: const EdgeInsets.all(ChainSpace.xxl),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
|
|
@ -1286,21 +1286,21 @@ class _DocReaderSheetState extends State<_DocReaderSheet> {
|
|||
color: theme.colorScheme.error,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: FaiSpace.sm),
|
||||
const SizedBox(height: ChainSpace.sm),
|
||||
if (structured != null)
|
||||
FaiErrorBox(
|
||||
ChainErrorBox(
|
||||
text: structured.localizedBody(l),
|
||||
isError: true,
|
||||
maxHeight: 200,
|
||||
)
|
||||
else
|
||||
FaiErrorBox(
|
||||
ChainErrorBox(
|
||||
error: err,
|
||||
isError: true,
|
||||
maxHeight: 200,
|
||||
),
|
||||
if (structured != null) ...[
|
||||
const SizedBox(height: FaiSpace.md),
|
||||
const SizedBox(height: ChainSpace.md),
|
||||
TextButton.icon(
|
||||
icon: const Icon(Icons.open_in_new, size: 16),
|
||||
label: Text(structured.forgejoUrl),
|
||||
|
|
@ -1314,14 +1314,14 @@ class _DocReaderSheetState extends State<_DocReaderSheet> {
|
|||
}
|
||||
return Markdown(
|
||||
data: snap.data ?? '',
|
||||
padding: const EdgeInsets.all(FaiSpace.xxl),
|
||||
padding: const EdgeInsets.all(ChainSpace.xxl),
|
||||
selectable: true,
|
||||
onTapLink: (text, href, title) async {
|
||||
if (href != null && href.isNotEmpty) {
|
||||
await SystemActions.openInOs(href);
|
||||
}
|
||||
},
|
||||
styleSheet: FaiTheme.markdownStyle(theme),
|
||||
styleSheet: ChainTheme.markdownStyle(theme),
|
||||
);
|
||||
},
|
||||
),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue