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:
98
lib/services/office/office_document.dart
Normal file
98
lib/services/office/office_document.dart
Normal file
@@ -0,0 +1,98 @@
|
||||
/// Shared OOXML document models for native Word/PPT parsing.
|
||||
library;
|
||||
|
||||
class OfficeTextRun {
|
||||
const OfficeTextRun({
|
||||
required this.text,
|
||||
this.x = 0,
|
||||
this.y = 0,
|
||||
this.width = 0,
|
||||
this.height = 0,
|
||||
this.fontSize = 18,
|
||||
});
|
||||
|
||||
final String text;
|
||||
final double x;
|
||||
final double y;
|
||||
final double width;
|
||||
final double height;
|
||||
final double fontSize;
|
||||
}
|
||||
|
||||
class OfficeImage {
|
||||
const OfficeImage({
|
||||
required this.bytesPath,
|
||||
this.x = 0,
|
||||
this.y = 0,
|
||||
this.width = 0,
|
||||
this.height = 0,
|
||||
});
|
||||
|
||||
final String bytesPath;
|
||||
final double x;
|
||||
final double y;
|
||||
final double width;
|
||||
final double height;
|
||||
}
|
||||
|
||||
class OfficeSlide {
|
||||
const OfficeSlide({
|
||||
required this.index,
|
||||
required this.width,
|
||||
required this.height,
|
||||
this.runs = const [],
|
||||
this.images = const [],
|
||||
this.plainText = '',
|
||||
});
|
||||
|
||||
final int index;
|
||||
final double width;
|
||||
final double height;
|
||||
final List<OfficeTextRun> runs;
|
||||
final List<OfficeImage> images;
|
||||
final String plainText;
|
||||
}
|
||||
|
||||
class ParsedPptx {
|
||||
const ParsedPptx({
|
||||
required this.sourcePath,
|
||||
required this.slides,
|
||||
});
|
||||
|
||||
final String sourcePath;
|
||||
final List<OfficeSlide> slides;
|
||||
|
||||
String get allText =>
|
||||
slides.map((s) => '--- Slide ${s.index + 1} ---\n${s.plainText}').join('\n\n');
|
||||
|
||||
/// Alias used by [PptxService.extractText].
|
||||
String get plainText => allText;
|
||||
}
|
||||
|
||||
enum DocBlockType { heading, paragraph, tableRow, image }
|
||||
|
||||
class DocBlock {
|
||||
const DocBlock({
|
||||
required this.type,
|
||||
required this.text,
|
||||
this.level = 0,
|
||||
this.imagePath,
|
||||
});
|
||||
|
||||
final DocBlockType type;
|
||||
final String text;
|
||||
final int level;
|
||||
final String? imagePath;
|
||||
}
|
||||
|
||||
class ParsedDocx {
|
||||
const ParsedDocx({
|
||||
required this.sourcePath,
|
||||
required this.blocks,
|
||||
});
|
||||
|
||||
final String sourcePath;
|
||||
final List<DocBlock> blocks;
|
||||
|
||||
String get plainText => blocks.map((b) => b.text).where((t) => t.isNotEmpty).join('\n');
|
||||
}
|
||||
Reference in New Issue
Block a user