From 566555f6bd10dcc8b5c52c1a40fa5715e077746e Mon Sep 17 00:00:00 2001 From: Naser Elziadna Date: Fri, 10 Jan 2025 08:01:23 +0200 Subject: [PATCH] majdolean ya habibit albi --- lib/domain/models/effects/text_effect.dart | 38 +++-- lib/presentation/common/widgets/popover.dart | 1 + .../painting/brush_preview_painter.dart | 8 +- .../screens/canvas_screen/canvas_screen.dart | 131 +++++++++++------- 4 files changed, 104 insertions(+), 74 deletions(-) diff --git a/lib/domain/models/effects/text_effect.dart b/lib/domain/models/effects/text_effect.dart index bcc29e6..4279cf8 100644 --- a/lib/domain/models/effects/text_effect.dart +++ b/lib/domain/models/effects/text_effect.dart @@ -8,13 +8,21 @@ import 'package:doddle/main.dart'; import 'package:flutter/material.dart'; class TextEffect extends PenEffect { - BrushSettingsState get settings => globalRef.read(brushSettingsProvider(PenTool.textPen)); - + BrushSettingsState get settings => + globalRef.read(brushSettingsProvider(PenTool.textPen)); + String get text => settings.getValue('text') ?? 'Hello'; double get fontSize => settings.getValue('fontSize') ?? 20.0; bool get randomRotation => settings.getValue('randomRotation') ?? false; double get wordSpacing => settings.getValue('wordSpacing') ?? 0.0; double get letterSpacing => settings.getValue('letterSpacing') ?? 0.0; + TextDirection? get textDirection { + final text = settings.getValue('text') ?? ''; + // Check if text contains RTL characters + final rtlPattern = + RegExp(r'[\u0591-\u07FF\u200F\u202B\u202E\uFB1D-\uFDFD\uFE70-\uFEFC]'); + return rtlPattern.hasMatch(text) ? TextDirection.rtl : TextDirection.ltr; + } @override void paint(Canvas canvas, Path path, Paint paint) { @@ -30,32 +38,20 @@ class TextEffect extends PenEffect { letterSpacing: letterSpacing, ), ), - textDirection: TextDirection.ltr, + textDirection: textDirection ?? TextDirection.rtl, ); textPainter.layout(); for (var point in drawController.points!) { if (point?.offset == null) continue; - + final positions = getSymmetricalPositions(point!.offset!); - + for (var position in positions) { - canvas.save(); - canvas.translate(position.dx, position.dy); - - if (randomRotation) { - - final rotation = (point.pressure ?? 0) * 2 * pi; - canvas.rotate(rotation); - } - - textPainter.paint( - canvas, - Offset(-textPainter.width / 2, -textPainter.height / 2), - ); - - canvas.restore(); + textPainter.layout(); + + textPainter.paint(canvas, position); } } } -} \ No newline at end of file +} diff --git a/lib/presentation/common/widgets/popover.dart b/lib/presentation/common/widgets/popover.dart index f16284f..218b0af 100644 --- a/lib/presentation/common/widgets/popover.dart +++ b/lib/presentation/common/widgets/popover.dart @@ -51,6 +51,7 @@ class _PopoverState extends State with SingleTickerProviderStateMixin { clipBehavior: Clip.antiAlias, constraints: BoxConstraints( maxWidth: 90.w, + maxHeight: 93.h ), decoration: BoxDecoration( color: theme.cardColor, diff --git a/lib/presentation/painting/brush_preview_painter.dart b/lib/presentation/painting/brush_preview_painter.dart index 5bfa6b5..97c2803 100644 --- a/lib/presentation/painting/brush_preview_painter.dart +++ b/lib/presentation/painting/brush_preview_painter.dart @@ -21,9 +21,9 @@ class BrushPreviewPainter extends CustomPainter { final currentPenTool = ref.read(canvasNotifierProvider).penTool; // Special handling for text brush preview - if (currentPenTool == PenTool.textPen) { - _drawTextPreview(canvas, size); - } else { + // if (currentPenTool == PenTool.textPen) { + // _drawTextPreview(canvas, size); + // } else { // Original wave preview for other brushes final points = _generatePreviewPoints(size); final controller = DrawController( @@ -46,7 +46,7 @@ class BrushPreviewPainter extends CustomPainter { _drawPreviewPoints(canvas, path, paint, effect, points); effect.paint(canvas, path, paint); } - } + // } canvas.restore(); } diff --git a/lib/presentation/screens/canvas_screen/canvas_screen.dart b/lib/presentation/screens/canvas_screen/canvas_screen.dart index c0bae92..075c529 100644 --- a/lib/presentation/screens/canvas_screen/canvas_screen.dart +++ b/lib/presentation/screens/canvas_screen/canvas_screen.dart @@ -7,6 +7,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import 'package:screen_recorder/screen_recorder.dart'; +import 'package:sizer/sizer.dart'; import '../../../generated/assets.gen.dart'; import '../../../domain/models/draw_controller.dart'; import '../../../domain/models/point.dart'; @@ -29,17 +30,17 @@ class CanvasScreen extends ConsumerStatefulWidget { class _CanvasScreenState extends ConsumerState { static Size kCanvasSize = Size.zero; - // late bool ignorePointer; - // late int pointerCount; + final TransformationController _transformationController = + TransformationController(); + bool showResetScaleTranslateToCanvas = false; @override void initState() { super.initState(); - // ignorePointer = false; - // pointerCount = 1; WidgetsBinding.instance.addPostFrameCallback((_) { - // ref.read(canvasNotifierProvider.notifier).initializeEffects(); - ref.read(canvasNotifierProvider.notifier).setGlobalKey(CanvasScreen.globalKey!); + ref + .read(canvasNotifierProvider.notifier) + .setGlobalKey(CanvasScreen.globalKey!); }); } @@ -106,7 +107,22 @@ class _CanvasScreenState extends ConsumerState { ), ), ), - body: _buildCanvas(), + body: Stack( + children: [ + _buildCanvas(), + Positioned( + right: 16, + bottom: 80, + child: Visibility( + visible: showResetScaleTranslateToCanvas, + child: FloatingActionButton( + onPressed: _resetCanvas, + child: const Icon(Icons.center_focus_strong), + ), + ), + ), + ], + ), bottomSheet: const ToolsWidget(), ), ); @@ -118,6 +134,7 @@ class _CanvasScreenState extends ConsumerState { return Container( color: Colors.purple[800], child: InteractiveViewer( + transformationController: _transformationController, panEnabled: false, scaleEnabled: true, minScale: 0.1, @@ -140,18 +157,27 @@ class _CanvasScreenState extends ConsumerState { ); } + void _resetCanvas() { + _transformationController.value = Matrix4.identity() + ..scale(1.0) + ..translate(1.w, -1.h); + setState(() { + showResetScaleTranslateToCanvas = false; + }); + } + void _handleGestureStart(PointerEvent pointerEvent) { if (ref.read(canvasNotifierProvider).isPanActive) return; // if (ignorePointer == false && pointerCount == 1) { - if (ref.read(canvasNotifierProvider).isRandomColor) { - final random = Random(); - final color = Color.fromRGBO( - random.nextInt(256), - random.nextInt(256), - random.nextInt(256), - 1, - ); - ref.read(canvasNotifierProvider.notifier).changeColor(color, true); + if (ref.read(canvasNotifierProvider).isRandomColor) { + final random = Random(); + final color = Color.fromRGBO( + random.nextInt(256), + random.nextInt(256), + random.nextInt(256), + 1, + ); + ref.read(canvasNotifierProvider.notifier).changeColor(color, true); } // } } @@ -159,47 +185,49 @@ class _CanvasScreenState extends ConsumerState { void _handleGestureUpdate(PointerEvent pointerEvent) { if (ref.read(canvasNotifierProvider).isPanActive) return; // if (ignorePointer == false && pointerCount == 1) { - setState(() { - kCanvasSize = Size( - MediaQuery.of(context).size.width, - MediaQuery.of(context).size.height - (AppBar().preferredSize.height), - ); - var pinSpaceX = -20; - var pinSpaceY = -160; + setState(() { + kCanvasSize = Size( + MediaQuery.of(context).size.width, + MediaQuery.of(context).size.height - (AppBar().preferredSize.height), + ); + var pinSpaceX = -20; + var pinSpaceY = -160; - Offset point = pointerEvent.localPosition; - point = point.translate( - -((kCanvasSize.width / 2) + pinSpaceX), - -((kCanvasSize.height / 2) + pinSpaceY), - ); + Offset point = pointerEvent.localPosition; + point = point.translate( + -((kCanvasSize.width / 2) + pinSpaceX), + -((kCanvasSize.height / 2) + pinSpaceY), + ); - ref.read(canvasNotifierProvider.notifier).addPoint(Point(offset: point, pressure: pointerEvent.pressure)); - }); + ref + .read(canvasNotifierProvider.notifier) + .addPoint(Point(offset: point, pressure: pointerEvent.pressure)); + }); // } } void _handleGestureEnd(PointerEvent pointerEvent) { // if (ref.read(canvasNotifierProvider).isPanActive) return; // if (ignorePointer == false && pointerCount == 1) { - setState(() { - kCanvasSize = Size( - MediaQuery.of(context).size.width, - MediaQuery.of(context).size.height - (AppBar().preferredSize.height), - ); - var pinSpaceX = -20; - var pinSpaceY = -160; + setState(() { + kCanvasSize = Size( + MediaQuery.of(context).size.width, + MediaQuery.of(context).size.height - (AppBar().preferredSize.height), + ); + var pinSpaceX = -20; + var pinSpaceY = -160; - Offset point = pointerEvent.localPosition; - point = point.translate( - -((kCanvasSize.width / 2) + pinSpaceX), - -((kCanvasSize.height / 2) + pinSpaceY), - ); + Offset point = pointerEvent.localPosition; + point = point.translate( + -((kCanvasSize.width / 2) + pinSpaceX), + -((kCanvasSize.height / 2) + pinSpaceY), + ); - ref.read(canvasNotifierProvider.notifier).addPoint( - Point(offset: point), - end: true, - ); - }); + ref.read(canvasNotifierProvider.notifier).addPoint( + Point(offset: point), + end: true, + ); + }); // } } @@ -238,7 +266,7 @@ class _CanvasScreenState extends ConsumerState { void _handleInteractionUpdate(ScaleUpdateDetails details) { print('pan update ${details.pointerCount}'); - if(details.pointerCount > 1) { + if (details.pointerCount > 1) { //clear last point ref.read(canvasNotifierProvider.notifier).clearPoints(); } @@ -249,12 +277,17 @@ class _CanvasScreenState extends ConsumerState { } void _handleInteractionStart(ScaleStartDetails details) { - if(details.pointerCount > 1) { + if (details.pointerCount > 1) { print('pan active ${details.pointerCount}'); ref.read(canvasNotifierProvider.notifier).setPanActive(true); //clear last point ref.read(canvasNotifierProvider.notifier).clearPoints(); + setState(() { + showResetScaleTranslateToCanvas = true; + }); } + // _previousScale = _transformationController.value.getMaxScaleOnAxis(); + // _previousOffset = _transformationController.toScene(Offset.zero); // setState(() { // ignorePointer = details.pointerCount > 1; // pointerCount = details.pointerCount;