remove dead code and fix analyzer warnings
Unused _resolvePtycPath (bin/clide.dart), _TrafficDot (app.dart and clide_column_hat.dart), stale @override on _spawned field (claude_pane.dart), duplicate import and unused local in test_app.dart, unnecessary non-null assertions in project.dart. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
+1
-1
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"exported_at": "2026-05-03T19:52:13Z",
|
||||
"exported_at": "2026-05-03T19:52:26Z",
|
||||
"decisions": [
|
||||
{
|
||||
"id": "D-1",
|
||||
|
||||
+11
-27
@@ -242,10 +242,7 @@ Future<void> _runCliArgs(
|
||||
// Responses come back on the same socket. Events may be interleaved
|
||||
// (the daemon broadcasts), so we skip events until we see the
|
||||
// response whose id matches our request.
|
||||
final lines = socket
|
||||
.cast<List<int>>()
|
||||
.transform(utf8.decoder)
|
||||
.transform(const LineSplitter());
|
||||
final lines = socket.cast<List<int>>().transform(utf8.decoder).transform(const LineSplitter());
|
||||
|
||||
try {
|
||||
await for (final line in lines) {
|
||||
@@ -346,11 +343,14 @@ Future<void> _runGit(List<String> args) async {
|
||||
final rest = args.sublist(1);
|
||||
final setUpstream = rest.contains('-u');
|
||||
final positional = rest.where((a) => a != '-u').toList();
|
||||
await _runCliArgs('git.push', {
|
||||
if (setUpstream) 'setUpstream': true,
|
||||
if (positional.isNotEmpty) 'remote': positional[0],
|
||||
if (positional.length > 1) 'branch': positional[1],
|
||||
}, exitOnOk: true);
|
||||
await _runCliArgs(
|
||||
'git.push',
|
||||
{
|
||||
if (setUpstream) 'setUpstream': true,
|
||||
if (positional.isNotEmpty) 'remote': positional[0],
|
||||
if (positional.length > 1) 'branch': positional[1],
|
||||
},
|
||||
exitOnOk: true);
|
||||
default:
|
||||
_die('unknown git verb: ${args.first}');
|
||||
}
|
||||
@@ -390,13 +390,11 @@ Future<void> _runTail(List<String> args) async {
|
||||
void quit() {
|
||||
unawaited(socket.close());
|
||||
}
|
||||
|
||||
ProcessSignal.sigint.watch().listen((_) => quit());
|
||||
ProcessSignal.sigterm.watch().listen((_) => quit());
|
||||
|
||||
final lines = socket
|
||||
.cast<List<int>>()
|
||||
.transform(utf8.decoder)
|
||||
.transform(const LineSplitter());
|
||||
final lines = socket.cast<List<int>>().transform(utf8.decoder).transform(const LineSplitter());
|
||||
|
||||
try {
|
||||
await for (final line in lines) {
|
||||
@@ -428,20 +426,6 @@ void _emitError({
|
||||
stderr.writeln(jsonEncode(err.toJson()));
|
||||
}
|
||||
|
||||
String _resolvePtycPath() {
|
||||
final self = Platform.resolvedExecutable;
|
||||
final binDir = File(self).parent.path;
|
||||
final candidates = [
|
||||
'$binDir/../ptyc/bin/ptyc',
|
||||
'$binDir/ptyc',
|
||||
'ptyc',
|
||||
];
|
||||
for (final c in candidates) {
|
||||
if (File(c).existsSync()) return c;
|
||||
}
|
||||
return 'ptyc';
|
||||
}
|
||||
|
||||
Never _die(String msg) {
|
||||
_emitError(
|
||||
code: IpcExitCode.userError,
|
||||
|
||||
+29
-44
@@ -92,30 +92,30 @@ class _RootShellState extends State<_RootShell> {
|
||||
autofocus: true,
|
||||
onKeyEvent: _onKey,
|
||||
child: ColoredBox(
|
||||
color: tokens.globalBackground,
|
||||
child: ClideResizeBorder(
|
||||
windowControls: widget.services.window,
|
||||
child: Column(
|
||||
children: [
|
||||
_HatBar(kernel: widget.services),
|
||||
Expanded(
|
||||
child: DialogHost(
|
||||
router: widget.services.dialog,
|
||||
child: Stack(
|
||||
children: [
|
||||
const Positioned.fill(child: RootLayout()),
|
||||
const ClidePalette(),
|
||||
const Positioned.fill(child: _WelcomeOverlay()),
|
||||
],
|
||||
color: tokens.globalBackground,
|
||||
child: ClideResizeBorder(
|
||||
windowControls: widget.services.window,
|
||||
child: Column(
|
||||
children: [
|
||||
_HatBar(kernel: widget.services),
|
||||
Expanded(
|
||||
child: DialogHost(
|
||||
router: widget.services.dialog,
|
||||
child: Stack(
|
||||
children: [
|
||||
const Positioned.fill(child: RootLayout()),
|
||||
const ClidePalette(),
|
||||
const Positioned.fill(child: _WelcomeOverlay()),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -308,23 +308,6 @@ class _RightHatContent extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class _TrafficDot extends StatelessWidget {
|
||||
const _TrafficDot({required this.color, required this.onTap});
|
||||
final Color color;
|
||||
final VoidCallback onTap;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ClideTappable(
|
||||
onTap: onTap,
|
||||
builder: (context, hovered, _) => Container(
|
||||
width: 12, height: 12,
|
||||
decoration: BoxDecoration(color: hovered ? color : color.withAlpha(0xCC), shape: BoxShape.circle),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _WinBtn extends StatelessWidget {
|
||||
const _WinBtn({required this.icon, required this.onTap, required this.tokens, this.isClose = false});
|
||||
final ClideIconPainter icon;
|
||||
@@ -338,7 +321,8 @@ class _WinBtn extends StatelessWidget {
|
||||
return ClideTappable(
|
||||
onTap: onTap,
|
||||
builder: (context, hovered, _) => Container(
|
||||
width: 36, height: hatHeight,
|
||||
width: 36,
|
||||
height: hatHeight,
|
||||
color: hovered ? hoverBg : null,
|
||||
alignment: Alignment.center,
|
||||
child: ClideIcon(icon, size: 14, color: hovered && isClose ? const Color(0xFFFFFFFF) : tokens.chromeForeground),
|
||||
@@ -435,9 +419,9 @@ class _ProjectSwitcherDropdownState extends State<_ProjectSwitcherDropdown> {
|
||||
widget.kernel.panels.activateTab(Slots.workspace, 'claude.primary');
|
||||
} else {
|
||||
widget.kernel.dialog.show((ctx, dismiss) => _NotARepoDialog(
|
||||
path: picked,
|
||||
onDismiss: () => dismiss(),
|
||||
));
|
||||
path: picked,
|
||||
onDismiss: () => dismiss(),
|
||||
));
|
||||
}
|
||||
}
|
||||
return;
|
||||
@@ -515,8 +499,7 @@ class _ProjectSwitcherDropdownState extends State<_ProjectSwitcherDropdown> {
|
||||
children: [
|
||||
_ActionRow(label: 'Open Local Project', shortcut: Platform.isMacOS ? '⌘O' : 'Ctrl+O', tokens: tokens, onTap: _openFolder),
|
||||
_ActionRow(label: 'New Window', shortcut: Platform.isMacOS ? '⌘⇧N' : 'Ctrl+Shift+N', tokens: tokens, onTap: _newWindow),
|
||||
if (widget.kernel.project.isOpen)
|
||||
_ActionRow(label: 'Close Project', shortcut: '', tokens: tokens, onTap: _closeWorkspace),
|
||||
if (widget.kernel.project.isOpen) _ActionRow(label: 'Close Project', shortcut: '', tokens: tokens, onTap: _closeWorkspace),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -589,8 +572,7 @@ class _ActionRow extends StatelessWidget {
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(child: ClideText(label, fontSize: 14)),
|
||||
if (shortcut != null && shortcut!.isNotEmpty)
|
||||
ClideText(shortcut!, fontSize: 12, color: tokens.globalTextMuted, fontFamily: clideMonoFamily),
|
||||
if (shortcut != null && shortcut!.isNotEmpty) ClideText(shortcut!, fontSize: 12, color: tokens.globalTextMuted, fontFamily: clideMonoFamily),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -629,7 +611,10 @@ class _OpenFolderDialogState extends State<_OpenFolderDialog> {
|
||||
Future<void> _submit() async {
|
||||
final path = _controller.text.trim();
|
||||
if (path.isEmpty) return;
|
||||
setState(() { _loading = true; _error = null; });
|
||||
setState(() {
|
||||
_loading = true;
|
||||
_error = null;
|
||||
});
|
||||
try {
|
||||
await widget.onOpen(path);
|
||||
} catch (_) {
|
||||
|
||||
@@ -29,8 +29,7 @@ class ClaudePane extends StatefulWidget {
|
||||
this.isPrimary = true,
|
||||
this.secondaryIndex,
|
||||
this.showChrome = true,
|
||||
}) : assert(isPrimary || secondaryIndex != null,
|
||||
'secondary panes need an index');
|
||||
}) : assert(isPrimary || secondaryIndex != null, 'secondary panes need an index');
|
||||
|
||||
final bool isPrimary;
|
||||
final bool showChrome;
|
||||
@@ -52,9 +51,9 @@ class _ClaudePaneState extends State<ClaudePane> {
|
||||
String? _error;
|
||||
String _statusLine = 'attaching…';
|
||||
|
||||
@override
|
||||
bool _spawned = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_terminal = Terminal(maxLines: _maxLines);
|
||||
@@ -120,9 +119,7 @@ class _ClaudePaneState extends State<ClaudePane> {
|
||||
repoRoot = (rootResp.data['path'] as String?) ?? repoRoot;
|
||||
}
|
||||
|
||||
_sessionName = widget.isPrimary
|
||||
? primarySessionName(repoRoot)
|
||||
: secondarySessionName(repoRoot, widget.secondaryIndex!);
|
||||
_sessionName = widget.isPrimary ? primarySessionName(repoRoot) : secondarySessionName(repoRoot, widget.secondaryIndex!);
|
||||
|
||||
// tmux-wrapped session for persistence (D-041).
|
||||
// -x/-y set the initial window size; without them tmux defaults
|
||||
@@ -135,8 +132,10 @@ class _ClaudePaneState extends State<ClaudePane> {
|
||||
'-A',
|
||||
'-s',
|
||||
_sessionName!,
|
||||
'-x', '$cols',
|
||||
'-y', '$rows',
|
||||
'-x',
|
||||
'$cols',
|
||||
'-y',
|
||||
'$rows',
|
||||
];
|
||||
print('[spawn] cols=${_terminal.viewWidth} rows=${_terminal.viewHeight}');
|
||||
var resp = await ipc.request('pane.spawn', args: {
|
||||
@@ -264,9 +263,7 @@ class _ClaudePaneState extends State<ClaudePane> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final title = widget.isPrimary
|
||||
? 'claude — primary'
|
||||
: 'claude — secondary ${widget.secondaryIndex}';
|
||||
final title = widget.isPrimary ? 'claude — primary' : 'claude — secondary ${widget.secondaryIndex}';
|
||||
final body = _error != null
|
||||
? Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
|
||||
@@ -96,7 +96,7 @@ class ProjectManager extends ChangeNotifier {
|
||||
|
||||
// Tell the backend isolate to (re)initialize services for this workspace.
|
||||
if (_onProjectOpen != null) {
|
||||
await _onProjectOpen!(root);
|
||||
await _onProjectOpen(root);
|
||||
}
|
||||
|
||||
await _settings.setProjectDir(_current);
|
||||
@@ -135,7 +135,7 @@ class ProjectManager extends ChangeNotifier {
|
||||
// the merged UI thread). Falls back to direct Process.run for tests
|
||||
// and the CLI binary.
|
||||
if (_onValidateProject != null) {
|
||||
return _onValidateProject!(path);
|
||||
return _onValidateProject(path);
|
||||
}
|
||||
try {
|
||||
final r = await Process.run(_toolchain.git, ['rev-parse', '--show-toplevel'], workingDirectory: path, environment: _toolchain.gitEnv);
|
||||
|
||||
+77
-75
@@ -40,7 +40,6 @@ import 'src/panes/registry.dart';
|
||||
import 'src/pty/session.dart';
|
||||
import 'kernel/src/toolchain.dart';
|
||||
import 'src/daemon/dispatcher.dart';
|
||||
import 'src/ipc/envelope.dart';
|
||||
import 'src/pty/env.dart' show expandedPath;
|
||||
|
||||
const _timeout = Duration(seconds: 30);
|
||||
@@ -98,11 +97,11 @@ class _ClideTestAppState extends State<ClideTestApp> {
|
||||
|
||||
print('[testmode] === done ($passed passed, $failed failed, ${_results.length} total) ===');
|
||||
print('[testmode:json] ${jsonEncode({
|
||||
'passed': passed,
|
||||
'failed': failed,
|
||||
'total': _results.length,
|
||||
'failures': failedNames,
|
||||
})}');
|
||||
'passed': passed,
|
||||
'failed': failed,
|
||||
'total': _results.length,
|
||||
'failures': failedNames,
|
||||
})}');
|
||||
|
||||
setState(() => _done = true);
|
||||
await Future<void>.delayed(const Duration(seconds: 2));
|
||||
@@ -165,16 +164,13 @@ class _ClideTestAppState extends State<ClideTestApp> {
|
||||
});
|
||||
|
||||
await _testAsync('git rev-parse (project.open sim)', () async {
|
||||
final r = await Process.run(tc.git, ['rev-parse', '--show-toplevel'],
|
||||
workingDirectory: workDir, environment: tc.gitEnv);
|
||||
final r = await Process.run(tc.git, ['rev-parse', '--show-toplevel'], workingDirectory: workDir, environment: tc.gitEnv);
|
||||
return 'exit=${r.exitCode} ${(r.stdout as String).trim()}';
|
||||
});
|
||||
|
||||
await _testAsync('sequential git calls', () async {
|
||||
final r1 = await Process.run(tc.git, ['rev-parse', '--show-toplevel'],
|
||||
workingDirectory: workDir, environment: tc.gitEnv);
|
||||
final r2 = await Process.run(tc.git, ['rev-parse', '--abbrev-ref', 'HEAD'],
|
||||
workingDirectory: workDir, environment: tc.gitEnv);
|
||||
final r1 = await Process.run(tc.git, ['rev-parse', '--show-toplevel'], workingDirectory: workDir, environment: tc.gitEnv);
|
||||
final r2 = await Process.run(tc.git, ['rev-parse', '--abbrev-ref', 'HEAD'], workingDirectory: workDir, environment: tc.gitEnv);
|
||||
return 'root=${(r1.stdout as String).trim()} branch=${(r2.stdout as String).trim()}';
|
||||
});
|
||||
|
||||
@@ -182,8 +178,7 @@ class _ClideTestAppState extends State<ClideTestApp> {
|
||||
final paths = await compute(resolveToolchainPaths, workDir);
|
||||
final tc2 = Toolchain();
|
||||
tc2.applyResolved(paths);
|
||||
final r = await Process.run(tc2.git, ['rev-parse', '--show-toplevel'],
|
||||
workingDirectory: workDir, environment: tc2.gitEnv);
|
||||
final r = await Process.run(tc2.git, ['rev-parse', '--show-toplevel'], workingDirectory: workDir, environment: tc2.gitEnv);
|
||||
return 'exit=${r.exitCode} ${(r.stdout as String).trim()}';
|
||||
});
|
||||
|
||||
@@ -317,7 +312,9 @@ class _ClideTestAppState extends State<ClideTestApp> {
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
try { await appDir.delete(recursive: true); } catch (_) {}
|
||||
try {
|
||||
await appDir.delete(recursive: true);
|
||||
} catch (_) {}
|
||||
} catch (e) {
|
||||
_addResult('ext:boot', false, '$e');
|
||||
}
|
||||
@@ -335,7 +332,6 @@ class _ClideTestAppState extends State<ClideTestApp> {
|
||||
final dispatcher = DaemonDispatcher();
|
||||
final bus = DaemonBus();
|
||||
final eventSink = _TestEventSink(bus);
|
||||
final workDir2 = Directory(workDir);
|
||||
final paneRegistry = PaneRegistry(events: eventSink);
|
||||
registerPaneCommands(dispatcher, paneRegistry);
|
||||
final ipc = InProcessClient(log: Logger(), events: bus, dispatcher: dispatcher);
|
||||
@@ -382,8 +378,7 @@ class _ClideTestAppState extends State<ClideTestApp> {
|
||||
final parent = sv[0];
|
||||
final child = sv[1];
|
||||
pkg_ffi.calloc.free(sv);
|
||||
final proc = await Process.start('/tmp/checkfd', [],
|
||||
environment: {...Platform.environment, 'PTYC_SOCK_FD': '$child'});
|
||||
final proc = await Process.start('/tmp/checkfd', [], environment: {...Platform.environment, 'PTYC_SOCK_FD': '$child'});
|
||||
final stderr = await proc.stderr.transform(utf8.decoder).join();
|
||||
final exit = await proc.exitCode;
|
||||
libc.close(parent);
|
||||
@@ -422,60 +417,60 @@ class _ClideTestAppState extends State<ClideTestApp> {
|
||||
});
|
||||
|
||||
if (!Platform.isMacOS) {
|
||||
// Additional direct PtySession tests (Linux only — no merged thread).
|
||||
// Additional direct PtySession tests (Linux only — no merged thread).
|
||||
|
||||
// Test 1: spawn /bin/echo via PtySession, read output
|
||||
await _testAsync('pty spawn echo', () async {
|
||||
final session = await PtySession.spawn(
|
||||
argv: ['/bin/echo', 'CLIDE_PTY_TEST_OK'],
|
||||
cwd: workDir,
|
||||
ptycPath: tc.ptyc,
|
||||
);
|
||||
final bytes = <int>[];
|
||||
final done = Completer<void>();
|
||||
session.output.listen(bytes.addAll, onDone: () => done.complete());
|
||||
await done.future.timeout(const Duration(seconds: 5));
|
||||
await session.close();
|
||||
final output = utf8.decode(bytes, allowMalformed: true);
|
||||
final ok = output.contains('CLIDE_PTY_TEST_OK');
|
||||
return ok ? 'output contains marker' : 'marker not found in ${output.length} bytes';
|
||||
});
|
||||
// Test 1: spawn /bin/echo via PtySession, read output
|
||||
await _testAsync('pty spawn echo', () async {
|
||||
final session = await PtySession.spawn(
|
||||
argv: ['/bin/echo', 'CLIDE_PTY_TEST_OK'],
|
||||
cwd: workDir,
|
||||
ptycPath: tc.ptyc,
|
||||
);
|
||||
final bytes = <int>[];
|
||||
final done = Completer<void>();
|
||||
session.output.listen(bytes.addAll, onDone: () => done.complete());
|
||||
await done.future.timeout(const Duration(seconds: 5));
|
||||
await session.close();
|
||||
final output = utf8.decode(bytes, allowMalformed: true);
|
||||
final ok = output.contains('CLIDE_PTY_TEST_OK');
|
||||
return ok ? 'output contains marker' : 'marker not found in ${output.length} bytes';
|
||||
});
|
||||
|
||||
// Test 2: spawn shell, write a command, verify output
|
||||
await _testAsync('pty spawn shell', () async {
|
||||
final session = await PtySession.spawn(
|
||||
argv: [tc.shell, '-c', 'echo CLIDE_SHELL_TEST'],
|
||||
cwd: workDir,
|
||||
ptycPath: tc.ptyc,
|
||||
);
|
||||
final bytes = <int>[];
|
||||
final done = Completer<void>();
|
||||
session.output.listen(bytes.addAll, onDone: () => done.complete());
|
||||
await done.future.timeout(const Duration(seconds: 5));
|
||||
await session.close();
|
||||
final output = utf8.decode(bytes, allowMalformed: true);
|
||||
final ok = output.contains('CLIDE_SHELL_TEST');
|
||||
return ok ? 'shell output contains marker' : 'marker not found in ${output.length} bytes';
|
||||
});
|
||||
// Test 2: spawn shell, write a command, verify output
|
||||
await _testAsync('pty spawn shell', () async {
|
||||
final session = await PtySession.spawn(
|
||||
argv: [tc.shell, '-c', 'echo CLIDE_SHELL_TEST'],
|
||||
cwd: workDir,
|
||||
ptycPath: tc.ptyc,
|
||||
);
|
||||
final bytes = <int>[];
|
||||
final done = Completer<void>();
|
||||
session.output.listen(bytes.addAll, onDone: () => done.complete());
|
||||
await done.future.timeout(const Duration(seconds: 5));
|
||||
await session.close();
|
||||
final output = utf8.decode(bytes, allowMalformed: true);
|
||||
final ok = output.contains('CLIDE_SHELL_TEST');
|
||||
return ok ? 'shell output contains marker' : 'marker not found in ${output.length} bytes';
|
||||
});
|
||||
|
||||
// Test 3: spawn interactive shell, write to stdin, verify file creation
|
||||
await _testAsync('pty write to child', () async {
|
||||
final marker = '/tmp/clide-pty-test-${DateTime.now().millisecondsSinceEpoch}';
|
||||
final session = await PtySession.spawn(
|
||||
argv: [tc.shell],
|
||||
cwd: workDir,
|
||||
ptycPath: tc.ptyc,
|
||||
);
|
||||
session.write(utf8.encode('touch $marker && exit\n'));
|
||||
final bytes = <int>[];
|
||||
final done = Completer<void>();
|
||||
session.output.listen(bytes.addAll, onDone: () => done.complete());
|
||||
await done.future.timeout(const Duration(seconds: 5));
|
||||
await session.close();
|
||||
final fileCreated = File(marker).existsSync();
|
||||
if (fileCreated) File(marker).deleteSync();
|
||||
return fileCreated ? 'file created + cleaned up' : 'file not created';
|
||||
});
|
||||
// Test 3: spawn interactive shell, write to stdin, verify file creation
|
||||
await _testAsync('pty write to child', () async {
|
||||
final marker = '/tmp/clide-pty-test-${DateTime.now().millisecondsSinceEpoch}';
|
||||
final session = await PtySession.spawn(
|
||||
argv: [tc.shell],
|
||||
cwd: workDir,
|
||||
ptycPath: tc.ptyc,
|
||||
);
|
||||
session.write(utf8.encode('touch $marker && exit\n'));
|
||||
final bytes = <int>[];
|
||||
final done = Completer<void>();
|
||||
session.output.listen(bytes.addAll, onDone: () => done.complete());
|
||||
await done.future.timeout(const Duration(seconds: 5));
|
||||
await session.close();
|
||||
final fileCreated = File(marker).existsSync();
|
||||
if (fileCreated) File(marker).deleteSync();
|
||||
return fileCreated ? 'file created + cleaned up' : 'file not created';
|
||||
});
|
||||
} // end !Platform.isMacOS
|
||||
|
||||
print('[testmode]');
|
||||
@@ -513,8 +508,7 @@ class _ClideTestAppState extends State<ClideTestApp> {
|
||||
|
||||
Future<void> _testExec(String label, String bin, List<String> args, String workDir, {Map<String, String>? env}) async {
|
||||
try {
|
||||
final r = await Process.run(bin, args, workingDirectory: workDir, environment: env)
|
||||
.timeout(const Duration(seconds: 5));
|
||||
final r = await Process.run(bin, args, workingDirectory: workDir, environment: env).timeout(const Duration(seconds: 5));
|
||||
final stdout = (r.stdout as String).trim();
|
||||
final stderr = (r.stderr as String).trim();
|
||||
final firstLine = stdout.isNotEmpty ? stdout.split('\n').first : (stderr.isNotEmpty ? stderr.split('\n').first : '(empty)');
|
||||
@@ -545,7 +539,8 @@ class _ClideTestAppState extends State<ClideTestApp> {
|
||||
children: [
|
||||
const Text('ClideTestApp', style: TextStyle(color: Color(0xFFCDD6F4), fontSize: 20, fontWeight: FontWeight.bold, decoration: TextDecoration.none)),
|
||||
const SizedBox(height: 4),
|
||||
Text(_done ? 'Done — exiting' : 'Running tests...', style: const TextStyle(color: Color(0xFF6C7086), fontSize: 13, decoration: TextDecoration.none)),
|
||||
Text(_done ? 'Done — exiting' : 'Running tests...',
|
||||
style: const TextStyle(color: Color(0xFF6C7086), fontSize: 13, decoration: TextDecoration.none)),
|
||||
const SizedBox(height: 16),
|
||||
Expanded(
|
||||
child: ListView.builder(
|
||||
@@ -556,10 +551,17 @@ class _ClideTestAppState extends State<ClideTestApp> {
|
||||
padding: const EdgeInsets.symmetric(vertical: 2),
|
||||
child: Row(
|
||||
children: [
|
||||
Text(r.ok ? '●' : '●', style: TextStyle(color: r.ok ? const Color(0xFFA6E3A1) : const Color(0xFFF38BA8), fontSize: 12, decoration: TextDecoration.none)),
|
||||
Text(r.ok ? '●' : '●',
|
||||
style: TextStyle(color: r.ok ? const Color(0xFFA6E3A1) : const Color(0xFFF38BA8), fontSize: 12, decoration: TextDecoration.none)),
|
||||
const SizedBox(width: 8),
|
||||
SizedBox(width: 220, child: Text(r.name, style: const TextStyle(color: Color(0xFFCDD6F4), fontSize: 12, fontFamily: 'monospace', decoration: TextDecoration.none))),
|
||||
Expanded(child: Text(r.output, style: const TextStyle(color: Color(0xFF9399B2), fontSize: 12, fontFamily: 'monospace', decoration: TextDecoration.none), overflow: TextOverflow.ellipsis)),
|
||||
SizedBox(
|
||||
width: 220,
|
||||
child: Text(r.name,
|
||||
style: const TextStyle(color: Color(0xFFCDD6F4), fontSize: 12, fontFamily: 'monospace', decoration: TextDecoration.none))),
|
||||
Expanded(
|
||||
child: Text(r.output,
|
||||
style: const TextStyle(color: Color(0xFF9399B2), fontSize: 12, fontFamily: 'monospace', decoration: TextDecoration.none),
|
||||
overflow: TextOverflow.ellipsis)),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
@@ -21,14 +21,12 @@ class ColumnHat extends StatelessWidget {
|
||||
final String? projectLabel;
|
||||
final String? branchLabel;
|
||||
|
||||
factory ColumnHat.left({required WindowControls windowControls}) =>
|
||||
ColumnHat._(position: HatPosition.left, windowControls: windowControls);
|
||||
factory ColumnHat.left({required WindowControls windowControls}) => ColumnHat._(position: HatPosition.left, windowControls: windowControls);
|
||||
|
||||
factory ColumnHat.center({required WindowControls windowControls, String? project, String? branch}) =>
|
||||
ColumnHat._(position: HatPosition.center, windowControls: windowControls, projectLabel: project, branchLabel: branch);
|
||||
|
||||
factory ColumnHat.right({required WindowControls windowControls}) =>
|
||||
ColumnHat._(position: HatPosition.right, windowControls: windowControls);
|
||||
factory ColumnHat.right({required WindowControls windowControls}) => ColumnHat._(position: HatPosition.right, windowControls: windowControls);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -101,27 +99,6 @@ class _RightContent extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class _TrafficDot extends StatelessWidget {
|
||||
const _TrafficDot({required this.color, required this.onTap});
|
||||
final Color color;
|
||||
final VoidCallback onTap;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ClideTappable(
|
||||
onTap: onTap,
|
||||
builder: (context, hovered, _) => Container(
|
||||
width: 12,
|
||||
height: 12,
|
||||
decoration: BoxDecoration(
|
||||
color: hovered ? color : color.withAlpha(0xCC),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _WinButton extends StatelessWidget {
|
||||
const _WinButton({required this.icon, required this.onTap, required this.tokens, this.isClose = false});
|
||||
final ClideIconPainter icon;
|
||||
|
||||
Reference in New Issue
Block a user