creek

The AI Image Editor of 2030

lib/data/models/canvas_models.dart (4072B)


  1import 'dart:ui';
  2import 'package:flutter/material.dart';
  3
  4enum DragHandle { none, topLeft, topRight, bottomLeft, bottomRight, center }
  5
  6enum LayerType { sketch, image }
  7
  8class DrawingPoint {
  9  final Offset offset;
 10  final Paint paint;
 11  const DrawingPoint({required this.offset, required this.paint});
 12
 13  Map<String, dynamic> toMap() => {'dx': offset.dx, 'dy': offset.dy};
 14
 15  factory DrawingPoint.fromMap(Map<String, dynamic> map) {
 16    return DrawingPoint(
 17      offset: Offset(map['dx'] ?? 0, map['dy'] ?? 0),
 18      paint: Paint(),
 19    );
 20  }
 21}
 22
 23class DrawingPath {
 24  final List<DrawingPoint> points;
 25  final Color color;
 26  final double strokeWidth;
 27  final bool isEraser;
 28
 29  DrawingPath({
 30    required this.points,
 31    required this.color,
 32    required this.strokeWidth,
 33    required this.isEraser,
 34  });
 35
 36  Map<String, dynamic> toMap() {
 37    return {
 38      'points': points.map((p) => p.toMap()).toList(),
 39      'color': color.value,
 40      'strokeWidth': strokeWidth,
 41      'isEraser': isEraser,
 42    };
 43  }
 44
 45  factory DrawingPath.fromMap(Map<String, dynamic> map) {
 46    return DrawingPath(
 47      points:
 48          (map['points'] as List).map((p) => DrawingPoint.fromMap(p)).toList(),
 49      color: Color(map['color']),
 50      strokeWidth: (map['strokeWidth'] as num).toDouble(),
 51      isEraser: map['isEraser'] ?? false,
 52    );
 53  }
 54}
 55
 56// Layer Models
 57abstract class CanvasLayer {
 58  final String id;
 59  final LayerType type;
 60  bool isVisible;
 61
 62  CanvasLayer({required this.id, required this.type, this.isVisible = true});
 63
 64  Map<String, dynamic> toMap();
 65
 66  static CanvasLayer fromMap(Map<String, dynamic> map) {
 67    if (map['type'] == 'sketch') {
 68      return SketchLayer.fromMap(map);
 69    } else {
 70      return ImageLayer.fromMap(map);
 71    }
 72  }
 73}
 74
 75class SketchLayer extends CanvasLayer {
 76  final List<DrawingPath> paths;
 77  final bool isMagicDraw;
 78
 79  SketchLayer({
 80    required String id,
 81    this.paths = const [],
 82    this.isMagicDraw = false,
 83    bool isVisible = true,
 84  }) : super(id: id, type: LayerType.sketch, isVisible: isVisible);
 85
 86  @override
 87  Map<String, dynamic> toMap() {
 88    return {
 89      'id': id,
 90      'type': 'sketch',
 91      'paths': paths.map((p) => p.toMap()).toList(),
 92      'isMagicDraw': isMagicDraw,
 93      'isVisible': isVisible,
 94    };
 95  }
 96
 97  factory SketchLayer.fromMap(Map<String, dynamic> map) {
 98    return SketchLayer(
 99      id: map['id'],
100      paths: (map['paths'] as List).map((p) => DrawingPath.fromMap(p)).toList(),
101      isMagicDraw: map['isMagicDraw'] ?? false,
102      isVisible: map['isVisible'] ?? true,
103    );
104  }
105}
106
107class ImageLayer extends CanvasLayer {
108  final Map<String, dynamic> data;
109
110  ImageLayer({required String id, required this.data, bool isVisible = true})
111    : super(id: id, type: LayerType.image, isVisible: isVisible);
112
113  @override
114  Map<String, dynamic> toMap() {
115    final encodableData = Map<String, dynamic>.from(data);
116
117    if (encodableData['position'] is Offset) {
118      final pos = encodableData['position'] as Offset;
119      encodableData['position'] = {'dx': pos.dx, 'dy': pos.dy};
120    }
121
122    if (encodableData['size'] is Size) {
123      final size = encodableData['size'] as Size;
124      encodableData['size'] = {'width': size.width, 'height': size.height};
125    }
126
127    return {
128      'id': id,
129      'type': 'image',
130      'data': encodableData,
131      'isVisible': isVisible,
132    };
133  }
134
135  factory ImageLayer.fromMap(Map<String, dynamic> map) {
136    final data = Map<String, dynamic>.from(map['data']);
137    // Restore Offset/Size objects
138    if (data['position'] is Map) {
139      data['position'] = Offset(
140        (data['position']['dx'] as num).toDouble(),
141        (data['position']['dy'] as num).toDouble(),
142      );
143    }
144    if (data['size'] is Map) {
145      data['size'] = Size(
146        (data['size']['width'] as num).toDouble(),
147        (data['size']['height'] as num).toDouble(),
148      );
149    }
150
151    return ImageLayer(
152      id: map['id'],
153      data: data,
154      isVisible: map['isVisible'] ?? true,
155    );
156  }
157}
158
159class CanvasState {
160  final List<CanvasLayer> layers;
161  CanvasState(this.layers);
162}