feat: unified shell, diagnostics pack, native Office, sticky board
All checks were successful
CI / Windows build (push) Successful in 14m22s

Make Surface remote debugging and classroom workflows viable: always-on
structured logs with one-click zip export, a single AppShell chrome,
OOXML PPTX/DOCX annotation without LibreOffice, and a first-class sticky
board. Also drop spike/legacy ink widgets and tighten pen feel
(predictor, PenInfoHistory, page-tile layer).

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-05 17:55:27 +08:00
parent 3cabc7e074
commit d346cc2670
49 changed files with 2883 additions and 2515 deletions

View File

@@ -0,0 +1,99 @@
// Frame / hitch sampler for diagnostic packs.
import 'badnote_log.dart';
class FrameSample {
FrameSample({
required this.at,
required this.label,
required this.ms,
this.dropped = false,
});
final DateTime at;
final String label;
final double ms;
final bool dropped;
Map<String, Object?> toJson() => {
'at': at.toIso8601String(),
'label': label,
'ms': ms,
'dropped': dropped,
};
}
class FrameSampler {
FrameSampler._();
static final FrameSampler instance = FrameSampler._();
static const int capacity = 500;
final List<FrameSample> _samples = <FrameSample>[];
int overBudget = 0;
int total = 0;
/// Budget for a single frame at 60fps.
static const double budgetMs = 16.6;
void record(String label, double ms, {bool dropped = false}) {
total++;
final over = ms > budgetMs;
if (over) overBudget++;
final sample = FrameSample(
at: DateTime.now(),
label: label,
ms: ms,
dropped: dropped || over,
);
_samples.add(sample);
if (_samples.length > capacity) {
_samples.removeRange(0, _samples.length - capacity);
}
if (over || dropped) {
BadNoteLog.instance.warn(
LogSubsystem.frame,
'slow_frame',
fields: {'label': label, 'ms': ms, 'dropped': dropped},
);
}
}
void recordZoom({
required double rawScale,
required bool scaleDrop,
required bool focalDrop,
required double focalJumpPx,
}) {
record(
'zoom',
scaleDrop || focalDrop ? budgetMs + 1 : 8,
dropped: scaleDrop || focalDrop,
);
BadNoteLog.instance.debug(
LogSubsystem.frame,
'zoom',
fields: {
'rawScale': rawScale,
'scaleDrop': scaleDrop,
'focalDrop': focalDrop,
'focalJumpPx': focalJumpPx,
},
);
}
List<Map<String, Object?>> toJsonList() =>
_samples.map((s) => s.toJson()).toList(growable: false);
Map<String, Object?> summary() => {
'total': total,
'overBudget': overBudget,
'budgetMs': budgetMs,
'recent': toJsonList(),
};
void reset() {
_samples.clear();
overBudget = 0;
total = 0;
}
}