feat: unified shell, diagnostics pack, native Office, sticky board
All checks were successful
CI / Windows build (push) Successful in 14m22s
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:
121
lib/diagnostics/pen_event_ring.dart
Normal file
121
lib/diagnostics/pen_event_ring.dart
Normal file
@@ -0,0 +1,121 @@
|
||||
// Rolling ring of recent pen / arbiter events for diagnostic export.
|
||||
|
||||
class PenEventRecord {
|
||||
PenEventRecord({
|
||||
required this.at,
|
||||
required this.kind,
|
||||
required this.pointerId,
|
||||
this.pressure,
|
||||
this.tiltX,
|
||||
this.tiltY,
|
||||
this.barrel = false,
|
||||
this.eraser = false,
|
||||
this.inverted = false,
|
||||
this.decision,
|
||||
this.note,
|
||||
});
|
||||
|
||||
final DateTime at;
|
||||
final String kind; // down|move|up|hw|arbiter
|
||||
final int pointerId;
|
||||
final double? pressure;
|
||||
final double? tiltX;
|
||||
final double? tiltY;
|
||||
final bool barrel;
|
||||
final bool eraser;
|
||||
final bool inverted;
|
||||
final String? decision; // draw|pan|reject
|
||||
final String? note;
|
||||
|
||||
Map<String, Object?> toJson() => {
|
||||
'at': at.toIso8601String(),
|
||||
'kind': kind,
|
||||
'pointerId': pointerId,
|
||||
if (pressure != null) 'pressure': pressure,
|
||||
if (tiltX != null) 'tiltX': tiltX,
|
||||
if (tiltY != null) 'tiltY': tiltY,
|
||||
'barrel': barrel,
|
||||
'eraser': eraser,
|
||||
'inverted': inverted,
|
||||
if (decision != null) 'decision': decision,
|
||||
if (note != null) 'note': note,
|
||||
};
|
||||
}
|
||||
|
||||
class PenEventRing {
|
||||
PenEventRing._();
|
||||
static final PenEventRing instance = PenEventRing._();
|
||||
|
||||
static const int capacity = 2000;
|
||||
final List<PenEventRecord> _events = <PenEventRecord>[];
|
||||
|
||||
void add(PenEventRecord event) {
|
||||
_events.add(event);
|
||||
if (_events.length > capacity) {
|
||||
_events.removeRange(0, _events.length - capacity);
|
||||
}
|
||||
}
|
||||
|
||||
void recordPointer({
|
||||
required String kind,
|
||||
required int pointerId,
|
||||
required String deviceKind,
|
||||
double? pressure,
|
||||
String? decision,
|
||||
String? note,
|
||||
}) {
|
||||
add(PenEventRecord(
|
||||
at: DateTime.now(),
|
||||
kind: kind,
|
||||
pointerId: pointerId,
|
||||
pressure: pressure,
|
||||
decision: decision,
|
||||
note: note ?? deviceKind,
|
||||
));
|
||||
}
|
||||
|
||||
void recordHardware({
|
||||
required bool barrel,
|
||||
required bool eraser,
|
||||
required bool inverted,
|
||||
required double tiltX,
|
||||
required double tiltY,
|
||||
}) {
|
||||
add(PenEventRecord(
|
||||
at: DateTime.now(),
|
||||
kind: 'hw',
|
||||
pointerId: -1,
|
||||
barrel: barrel,
|
||||
eraser: eraser,
|
||||
inverted: inverted,
|
||||
tiltX: tiltX,
|
||||
tiltY: tiltY,
|
||||
));
|
||||
}
|
||||
|
||||
void recordArbiter({
|
||||
required int activeCount,
|
||||
required String deviceKind,
|
||||
required bool draw,
|
||||
required bool fingerDrawing,
|
||||
}) {
|
||||
add(PenEventRecord(
|
||||
at: DateTime.now(),
|
||||
kind: 'arbiter',
|
||||
pointerId: -1,
|
||||
decision: draw ? 'draw' : 'pan',
|
||||
note: 'count=$activeCount kind=$deviceKind finger=$fingerDrawing',
|
||||
));
|
||||
}
|
||||
|
||||
List<PenEventRecord> recent({Duration? window}) {
|
||||
if (window == null) return List.unmodifiable(_events);
|
||||
final cut = DateTime.now().subtract(window);
|
||||
return _events.where((e) => e.at.isAfter(cut)).toList(growable: false);
|
||||
}
|
||||
|
||||
List<Map<String, Object?>> toJsonList({Duration? window}) =>
|
||||
recent(window: window).map((e) => e.toJson()).toList(growable: false);
|
||||
|
||||
void clear() => _events.clear();
|
||||
}
|
||||
Reference in New Issue
Block a user