Single Flutter package at the repo root. All code, tests, assets, and platform directories moved from app/ to root. Package renamed from clide_app to clide — all imports rewritten. Merged pubspec combines core (ffi) and app (flutter, yaml, xterm) dependencies. Makefile simplified: no APP_PRESENT conditionals, no cd, no daemon lifecycle. 317 tests pass. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
161 lines
4.8 KiB
Dart
161 lines
4.8 KiB
Dart
/// Sidebar panel showing project diagnostics from pql.
|
|
library;
|
|
|
|
import 'dart:async';
|
|
|
|
import 'package:clide/kernel/kernel.dart';
|
|
import 'package:clide/widgets/widgets.dart';
|
|
import 'package:flutter/widgets.dart';
|
|
|
|
import 'problems_controller.dart';
|
|
|
|
class ProblemsView extends StatefulWidget {
|
|
const ProblemsView({super.key});
|
|
|
|
@override
|
|
State<ProblemsView> createState() => _ProblemsViewState();
|
|
}
|
|
|
|
class _ProblemsViewState extends State<ProblemsView> {
|
|
ProblemsController? _controller;
|
|
|
|
@override
|
|
void didChangeDependencies() {
|
|
super.didChangeDependencies();
|
|
if (_controller != null) return;
|
|
final kernel = ClideKernel.of(context);
|
|
_controller = ProblemsController(ipc: kernel.ipc);
|
|
unawaited(_controller!.refresh());
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_controller?.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final c = _controller;
|
|
if (c == null) return const SizedBox.shrink();
|
|
return ListenableBuilder(
|
|
listenable: c,
|
|
builder: (context, _) {
|
|
final tokens = ClideTheme.of(context).surface;
|
|
return Semantics(
|
|
label: 'problems panel',
|
|
container: true,
|
|
explicitChildNodes: true,
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
children: [
|
|
Padding(
|
|
padding: const EdgeInsets.symmetric(
|
|
horizontal: 12, vertical: 6),
|
|
child: Row(
|
|
children: [
|
|
Expanded(
|
|
child: ClideText(
|
|
'Problems (${c.problems.length})',
|
|
fontSize: clideFontCaption,
|
|
color: tokens.sidebarForeground,
|
|
),
|
|
),
|
|
Semantics(
|
|
button: true,
|
|
label: 'refresh problems',
|
|
child: GestureDetector(
|
|
onTap: () => unawaited(c.refresh()),
|
|
child: MouseRegion(
|
|
cursor: SystemMouseCursors.click,
|
|
child: ClideText(
|
|
'Refresh',
|
|
fontSize: clideFontCaption,
|
|
color: tokens.sidebarForeground,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
if (c.loading && c.problems.isEmpty)
|
|
const Padding(
|
|
padding: EdgeInsets.all(12),
|
|
child: ClideText('Scanning…', muted: true),
|
|
),
|
|
if (!c.loading && c.problems.isEmpty)
|
|
const Padding(
|
|
padding: EdgeInsets.all(12),
|
|
child: ClideText(
|
|
'No problems found.',
|
|
muted: true,
|
|
),
|
|
),
|
|
Expanded(
|
|
child: SingleChildScrollView(
|
|
padding: const EdgeInsets.symmetric(vertical: 4),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
for (final p in c.problems) _ProblemRow(problem: p),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
}
|
|
|
|
class _ProblemRow extends StatelessWidget {
|
|
const _ProblemRow({required this.problem});
|
|
final Problem problem;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final tokens = ClideTheme.of(context).surface;
|
|
return Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
Row(
|
|
children: [
|
|
ClideText(
|
|
problem.source,
|
|
fontSize: clideFontMono,
|
|
color: tokens.statusWarning,
|
|
fontFamily: clideMonoFamily,
|
|
),
|
|
const SizedBox(width: 6),
|
|
Expanded(
|
|
child: ClideText(
|
|
problem.message,
|
|
color: tokens.sidebarForeground,
|
|
maxLines: 2,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
if (problem.hint != null)
|
|
Padding(
|
|
padding: const EdgeInsets.only(left: 44, top: 2),
|
|
child: ClideText(
|
|
problem.hint!,
|
|
fontSize: clideFontMono,
|
|
muted: true,
|
|
fontFamily: clideMonoFamily,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|