Files
clide/lib/kernel/src/clipboard.dart
T
jpmschweitzerandClaude Opus 4.8 6d0ebab721 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>
2026-06-11 12:11:53 +02:00

53 lines
1.8 KiB
Dart

import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart' as flutter_services;
/// Typed, per-content-kind clipboard with a plaintext fallback.
///
/// Extensions write typed values (`write<GitHunk>(hunk)`) and read in
/// the same type (`readAs<GitHunk>()`). Anything with a `toPlain`
/// callback also syncs to the OS clipboard so external apps see
/// reasonable text. The history ring keeps the last [historyLimit]
/// entries per type for quick recall.
class ClideClipboard {
ClideClipboard({this.historyLimit = 16});
final int historyLimit;
final Map<Type, List<Object>> _history = {};
Future<void> write<T extends Object>(T value, {String Function(T)? toPlain}) async {
final bucket = _history.putIfAbsent(T, () => <Object>[]);
bucket.insert(0, value);
if (bucket.length > historyLimit) bucket.removeLast();
if (toPlain != null) {
await flutter_services.Clipboard.setData(flutter_services.ClipboardData(text: toPlain(value)));
}
}
T? readAs<T extends Object>() {
final bucket = _history[T];
if (bucket == null || bucket.isEmpty) return null;
return bucket.first as T;
}
List<T> historyOf<T extends Object>() {
final bucket = _history[T];
if (bucket == null) return const [];
return bucket.cast<T>().toList(growable: false);
}
Future<String?> readPlain() async {
final d = await flutter_services.Clipboard.getData('text/plain');
return d?.text;
}
Future<void> writePlain(String text) async {
await flutter_services.Clipboard.setData(flutter_services.ClipboardData(text: text));
final bucket = _history.putIfAbsent(String, () => <Object>[]);
bucket.insert(0, text);
if (bucket.length > historyLimit) bucket.removeLast();
}
@visibleForTesting
void clear() => _history.clear();
}