chore: adopt Dart 3.9 toolchain — honest floor + tall-style reformat (T-353)
Raise the declared minimums in pubspec.yaml to what our deps already require: Flutter >=3.35.0 / Dart >=3.9.0 (was 3.19.0 / 3.5.0). alchemist 0.12 needs Flutter 3.32; Dart 3.9 first ships in Flutter 3.35, so 3.35 is the binding floor. Pin the exact build toolchain in .fvmrc (Flutter 3.44.1). Moving to the Dart 3.9 language level switches `dart format` to the new "tall" style and enables two new lints. This commit is the resulting mechanical churn, isolated from any behaviour change: - whole-tree `dart format` reformat (tall style) - `dart fix` for unnecessary_underscores + use_null_aware_elements No runtime behaviour change; `make test` green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,34 +1,22 @@
|
||||
import 'dart:ui' show Color;
|
||||
|
||||
class DecisionTypeColors {
|
||||
const DecisionTypeColors({
|
||||
required this.confirmed,
|
||||
required this.question,
|
||||
required this.rejected,
|
||||
});
|
||||
const DecisionTypeColors({required this.confirmed, required this.question, required this.rejected});
|
||||
|
||||
final Color confirmed;
|
||||
final Color question;
|
||||
final Color rejected;
|
||||
|
||||
Color forType(String? type) => switch (type) {
|
||||
'confirmed' => confirmed,
|
||||
'question' => question,
|
||||
'rejected' => rejected,
|
||||
_ => confirmed,
|
||||
};
|
||||
'confirmed' => confirmed,
|
||||
'question' => question,
|
||||
'rejected' => rejected,
|
||||
_ => confirmed,
|
||||
};
|
||||
|
||||
static const dark = DecisionTypeColors(
|
||||
confirmed: Color(0xFF7DD3A8),
|
||||
question: Color(0xFFE6C370),
|
||||
rejected: Color(0xFFE87D7D),
|
||||
);
|
||||
static const dark = DecisionTypeColors(confirmed: Color(0xFF7DD3A8), question: Color(0xFFE6C370), rejected: Color(0xFFE87D7D));
|
||||
|
||||
static const light = DecisionTypeColors(
|
||||
confirmed: Color(0xFF1D7A4E),
|
||||
question: Color(0xFFB08A20),
|
||||
rejected: Color(0xFFC03030),
|
||||
);
|
||||
static const light = DecisionTypeColors(confirmed: Color(0xFF1D7A4E), question: Color(0xFFB08A20), rejected: Color(0xFFC03030));
|
||||
|
||||
static DecisionTypeColors forTheme({required bool dark}) => dark ? DecisionTypeColors.dark : DecisionTypeColors.light;
|
||||
}
|
||||
|
||||
@@ -110,10 +110,7 @@ class _DecisionDetailViewState extends State<DecisionDetailView> {
|
||||
return ClidePaneChrome(
|
||||
title: id,
|
||||
subtitle: title,
|
||||
leading: ReaderPinButton(
|
||||
pinned: _nav?.hasPinned ?? false,
|
||||
onTap: _decision != null ? _onPin : null,
|
||||
),
|
||||
leading: ReaderPinButton(pinned: _nav?.hasPinned ?? false, onTap: _decision != null ? _onPin : null),
|
||||
trailing: [
|
||||
ReaderActionBar(
|
||||
canGoBack: _nav?.canGoBack ?? false,
|
||||
@@ -144,7 +141,11 @@ class _DecisionDetailViewState extends State<DecisionDetailView> {
|
||||
children: [
|
||||
ClideTooltip(
|
||||
message: type ?? 'confirmed',
|
||||
child: Container(width: 10, height: 10, decoration: BoxDecoration(color: typeColor, shape: BoxShape.circle)),
|
||||
child: Container(
|
||||
width: 10,
|
||||
height: 10,
|
||||
decoration: BoxDecoration(color: typeColor, shape: BoxShape.circle),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
ClideText(id, fontSize: clideFontSmall, color: typeColor, fontFamily: clideMonoFamily),
|
||||
@@ -159,21 +160,12 @@ class _DecisionDetailViewState extends State<DecisionDetailView> {
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
ClideText(title, fontSize: 15, fontWeight: FontWeight.w500),
|
||||
if (date != null) ...[
|
||||
const SizedBox(height: 6),
|
||||
ClideText(date, muted: true, fontSize: clideFontSmall, fontFamily: clideMonoFamily),
|
||||
],
|
||||
if (status != null && status != 'active') ...[
|
||||
const SizedBox(height: 8),
|
||||
_StatusBadge(status: status, tokens: tokens),
|
||||
],
|
||||
if (date != null) ...[const SizedBox(height: 6), ClideText(date, muted: true, fontSize: clideFontSmall, fontFamily: clideMonoFamily)],
|
||||
if (status != null && status != 'active') ...[const SizedBox(height: 8), _StatusBadge(status: status, tokens: tokens)],
|
||||
],
|
||||
),
|
||||
),
|
||||
if (body != null && body.isNotEmpty) ...[
|
||||
const SizedBox(height: 12),
|
||||
ClideMarkdown(body, onRecordTap: (id) => _navigateToRecord(context, id)),
|
||||
],
|
||||
if (body != null && body.isNotEmpty) ...[const SizedBox(height: 12), ClideMarkdown(body, onRecordTap: (id) => _navigateToRecord(context, id))],
|
||||
if (refs.isNotEmpty) ...[
|
||||
const SizedBox(height: 16),
|
||||
ClideText('CROSS-REFERENCES', fontSize: clideFontSmall, color: tokens.sidebarSectionHeader, fontFamily: clideMonoFamily),
|
||||
|
||||
@@ -139,12 +139,14 @@ class _DecisionsViewState extends State<DecisionsView> {
|
||||
final hasFilter = lf.isNotEmpty;
|
||||
final filtered = hasFilter
|
||||
? _decisions
|
||||
.where((d) =>
|
||||
d.id.toLowerCase().contains(lf) ||
|
||||
d.title.toLowerCase().contains(lf) ||
|
||||
(d.domain ?? '').toLowerCase().contains(lf) ||
|
||||
(d.type ?? '').contains(lf))
|
||||
.toList()
|
||||
.where(
|
||||
(d) =>
|
||||
d.id.toLowerCase().contains(lf) ||
|
||||
d.title.toLowerCase().contains(lf) ||
|
||||
(d.domain ?? '').toLowerCase().contains(lf) ||
|
||||
(d.type ?? '').contains(lf),
|
||||
)
|
||||
.toList()
|
||||
: _decisions;
|
||||
|
||||
final confirmed = filtered.where((d) => d.type == 'confirmed').toList();
|
||||
@@ -158,7 +160,9 @@ class _DecisionsViewState extends State<DecisionsView> {
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Expanded(child: ClideFilterBox(address: 'decisions.panel', hint: 'Filter decisions…', onChanged: (v) => setState(() => _filter = v))),
|
||||
Expanded(
|
||||
child: ClideFilterBox(address: 'decisions.panel', hint: 'Filter decisions…', onChanged: (v) => setState(() => _filter = v)),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 8),
|
||||
child: ClideTappable(
|
||||
@@ -180,39 +184,66 @@ class _DecisionsViewState extends State<DecisionsView> {
|
||||
ClideAccordion(
|
||||
label: 'CONFIRMED',
|
||||
count: confirmed.length,
|
||||
leading: Container(width: 8, height: 8, decoration: BoxDecoration(color: typeColors.confirmed, shape: BoxShape.circle)),
|
||||
leading: Container(
|
||||
width: 8,
|
||||
height: 8,
|
||||
decoration: BoxDecoration(color: typeColors.confirmed, shape: BoxShape.circle),
|
||||
),
|
||||
expanded: hasFilter || _isSectionExpanded('confirmed'),
|
||||
onToggle: () => _toggleSection('confirmed'),
|
||||
children: [
|
||||
for (final d in confirmed)
|
||||
_DecisionCard(
|
||||
entry: d, tokens: tokens, typeColors: typeColors, focused: d.id == _focusedId, focusKey: d.id == _focusedId ? _focusedKey : null)
|
||||
entry: d,
|
||||
tokens: tokens,
|
||||
typeColors: typeColors,
|
||||
focused: d.id == _focusedId,
|
||||
focusKey: d.id == _focusedId ? _focusedKey : null,
|
||||
),
|
||||
],
|
||||
),
|
||||
if (questions.isNotEmpty)
|
||||
ClideAccordion(
|
||||
label: 'QUESTIONS',
|
||||
count: questions.length,
|
||||
leading: Container(width: 8, height: 8, decoration: BoxDecoration(color: typeColors.question, shape: BoxShape.circle)),
|
||||
leading: Container(
|
||||
width: 8,
|
||||
height: 8,
|
||||
decoration: BoxDecoration(color: typeColors.question, shape: BoxShape.circle),
|
||||
),
|
||||
expanded: hasFilter || _isSectionExpanded('question'),
|
||||
onToggle: () => _toggleSection('question'),
|
||||
children: [
|
||||
for (final d in questions)
|
||||
_DecisionCard(
|
||||
entry: d, tokens: tokens, typeColors: typeColors, focused: d.id == _focusedId, focusKey: d.id == _focusedId ? _focusedKey : null)
|
||||
entry: d,
|
||||
tokens: tokens,
|
||||
typeColors: typeColors,
|
||||
focused: d.id == _focusedId,
|
||||
focusKey: d.id == _focusedId ? _focusedKey : null,
|
||||
),
|
||||
],
|
||||
),
|
||||
if (rejected.isNotEmpty)
|
||||
ClideAccordion(
|
||||
label: 'REJECTED',
|
||||
count: rejected.length,
|
||||
leading: Container(width: 8, height: 8, decoration: BoxDecoration(color: typeColors.rejected, shape: BoxShape.circle)),
|
||||
leading: Container(
|
||||
width: 8,
|
||||
height: 8,
|
||||
decoration: BoxDecoration(color: typeColors.rejected, shape: BoxShape.circle),
|
||||
),
|
||||
expanded: hasFilter || _isSectionExpanded('rejected'),
|
||||
onToggle: () => _toggleSection('rejected'),
|
||||
children: [
|
||||
for (final d in rejected)
|
||||
_DecisionCard(
|
||||
entry: d, tokens: tokens, typeColors: typeColors, focused: d.id == _focusedId, focusKey: d.id == _focusedId ? _focusedKey : null)
|
||||
entry: d,
|
||||
tokens: tokens,
|
||||
typeColors: typeColors,
|
||||
focused: d.id == _focusedId,
|
||||
focusKey: d.id == _focusedId ? _focusedKey : null,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
@@ -233,12 +264,12 @@ class _DecisionEntry {
|
||||
final String? status;
|
||||
|
||||
factory _DecisionEntry.fromJson(Map<String, dynamic> json) => _DecisionEntry(
|
||||
id: json['id'] as String? ?? '',
|
||||
title: json['title'] as String? ?? '',
|
||||
type: json['type'] as String?,
|
||||
domain: json['domain'] as String?,
|
||||
status: json['status'] as String?,
|
||||
);
|
||||
id: json['id'] as String? ?? '',
|
||||
title: json['title'] as String? ?? '',
|
||||
type: json['type'] as String?,
|
||||
domain: json['domain'] as String?,
|
||||
status: json['status'] as String?,
|
||||
);
|
||||
}
|
||||
|
||||
class _DecisionCard extends StatelessWidget {
|
||||
@@ -271,7 +302,11 @@ class _DecisionCard extends StatelessWidget {
|
||||
children: [
|
||||
ClideTooltip(
|
||||
message: entry.type ?? 'confirmed',
|
||||
child: Container(width: 8, height: 8, decoration: BoxDecoration(color: typeColor, shape: BoxShape.circle)),
|
||||
child: Container(
|
||||
width: 8,
|
||||
height: 8,
|
||||
decoration: BoxDecoration(color: typeColor, shape: BoxShape.circle),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 6),
|
||||
ClideText(entry.id, fontSize: clideFontSmall, color: tokens.globalTextMuted, fontFamily: clideMonoFamily),
|
||||
|
||||
@@ -37,21 +37,21 @@ class DecisionsExtension extends ClideExtension {
|
||||
|
||||
@override
|
||||
List<ContributionPoint> get contributions => [
|
||||
TabContribution(
|
||||
id: 'decisions.panel',
|
||||
slot: Slots.sidebar,
|
||||
title: 'Decisions',
|
||||
titleKey: 'tab.title',
|
||||
i18nNamespace: id,
|
||||
icon: PhosphorIcons.byName('lightbulb'),
|
||||
build: (_) => const DecisionsView(),
|
||||
),
|
||||
TabContribution(
|
||||
id: 'decisions.detail',
|
||||
slot: Slots.contextPanel,
|
||||
title: 'Decision',
|
||||
icon: PhosphorIcons.byName('lightbulb'),
|
||||
build: (_) => const DecisionDetailView(),
|
||||
),
|
||||
];
|
||||
TabContribution(
|
||||
id: 'decisions.panel',
|
||||
slot: Slots.sidebar,
|
||||
title: 'Decisions',
|
||||
titleKey: 'tab.title',
|
||||
i18nNamespace: id,
|
||||
icon: PhosphorIcons.byName('lightbulb'),
|
||||
build: (_) => const DecisionsView(),
|
||||
),
|
||||
TabContribution(
|
||||
id: 'decisions.detail',
|
||||
slot: Slots.contextPanel,
|
||||
title: 'Decision',
|
||||
icon: PhosphorIcons.byName('lightbulb'),
|
||||
build: (_) => const DecisionDetailView(),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user