// 笔画数据模型 — 手写不可变类(避免 build_runner 依赖) import 'dart:collection'; /// 画笔类型 enum BrushType { pen('pen'), pencil('pencil'), marker('marker'), eraser('eraser'); const BrushType(this.value); final String value; } /// 笔画点 class StrokePoint { const StrokePoint({ required this.x, required this.y, this.pressure = 0.5, this.timestamp = 0, }); final double x; final double y; final double pressure; final int timestamp; StrokePoint copyWith({ double? x, double? y, double? pressure, int? timestamp, }) => StrokePoint( x: x ?? this.x, y: y ?? this.y, pressure: pressure ?? this.pressure, timestamp: timestamp ?? this.timestamp, ); Map toJson() => { 'x': x, 'y': y, 'pressure': pressure, 'timestamp': timestamp, }; factory StrokePoint.fromJson(Map json) => StrokePoint( x: (json['x'] as num).toDouble(), y: (json['y'] as num).toDouble(), pressure: (json['pressure'] as num?)?.toDouble() ?? 0.5, timestamp: (json['timestamp'] as int?) ?? 0, ); } /// 笔画 class Stroke { const Stroke({ required this.id, required this.points, this.brushType = BrushType.pen, this.color = '#2D2420', this.width = 3.0, }); final String id; final List points; final BrushType brushType; final String color; final double width; Stroke copyWith({ String? id, List? points, BrushType? brushType, String? color, double? width, }) => Stroke( id: id ?? this.id, points: points ?? this.points, brushType: brushType ?? this.brushType, color: color ?? this.color, width: width ?? this.width, ); Map toJson() => { 'id': id, 'points': points.map((p) => p.toJson()).toList(), 'brushType': brushType.value, 'color': color, 'width': width, }; factory Stroke.fromJson(Map json) => Stroke( id: json['id'] as String, points: UnmodifiableListView( (json['points'] as List) .map((p) => StrokePoint.fromJson(p as Map)) .toList(), ), brushType: BrushType.values.firstWhere( (b) => b.value == json['brushType'], orElse: () => BrushType.pen, ), color: (json['color'] as String?) ?? '#2D2420', width: (json['width'] as num?)?.toDouble() ?? 3.0, ); }