diff --git a/CHANGELOG.md b/CHANGELOG.md index 503743c..aa14e5a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ - Adds option to manual focus in the camera - Adds support to switch between front and back camera during video recording - Adds basic face filters +- Improves image editor like emojies or text under a drawing can be moved +- Fixes issue with emojis disappearing in the image editor ## 0.0.86 diff --git a/lib/src/database/daos/reactions.dao.dart b/lib/src/database/daos/reactions.dao.dart index 59ef34a..286fc68 100644 --- a/lib/src/database/daos/reactions.dao.dart +++ b/lib/src/database/daos/reactions.dao.dart @@ -22,7 +22,7 @@ class ReactionsDao extends DatabaseAccessor with _$ReactionsDaoMixin { String emoji, bool remove, ) async { - if (!isEmoji(emoji)) { + if (!isOneEmoji(emoji)) { Log.error('Did not update reaction as it is not an emoji!'); return; } @@ -59,7 +59,7 @@ class ReactionsDao extends DatabaseAccessor with _$ReactionsDaoMixin { String emoji, bool remove, ) async { - if (!isEmoji(emoji)) { + if (!isOneEmoji(emoji)) { Log.error('Did not update reaction as it is not an emoji!'); return; } diff --git a/lib/src/services/intent/links.intent.dart b/lib/src/services/intent/links.intent.dart index c4a1066..055eae8 100644 --- a/lib/src/services/intent/links.intent.dart +++ b/lib/src/services/intent/links.intent.dart @@ -13,7 +13,7 @@ import 'package:twonly/src/services/api/mediafiles/upload.service.dart'; import 'package:twonly/src/services/signal/session.signal.dart'; import 'package:twonly/src/utils/log.dart'; import 'package:twonly/src/utils/misc.dart'; -import 'package:twonly/src/views/camera/share_image_editor_view.dart'; +import 'package:twonly/src/views/camera/share_image_editor.view.dart'; import 'package:twonly/src/views/chats/add_new_user.view.dart'; import 'package:twonly/src/views/components/alert_dialog.dart'; import 'package:twonly/src/views/contact/contact.view.dart'; diff --git a/lib/src/views/camera/camera_preview_components/camera_preview.dart b/lib/src/views/camera/camera_preview_components/camera_preview.dart index cde7474..991748d 100644 --- a/lib/src/views/camera/camera_preview_components/camera_preview.dart +++ b/lib/src/views/camera/camera_preview_components/camera_preview.dart @@ -23,32 +23,54 @@ class MainCameraPreview extends StatelessWidget { requiredHeight: 0, additionalPadding: 59, bottomNavigation: Container(), - child: Screenshot( - controller: mainCameraController.screenshotController, - child: AspectRatio( - aspectRatio: 9 / 16, - child: ClipRect( - child: FittedBox( - fit: BoxFit.cover, - child: SizedBox( - width: mainCameraController - .cameraController!.value.previewSize!.height, - height: mainCameraController - .cameraController!.value.previewSize!.width, - child: CameraPreview( - key: mainCameraController.cameraPreviewKey, - mainCameraController.cameraController!, - child: Stack( - children: [ - if (mainCameraController.customPaint != null) - Positioned.fill( - child: mainCameraController.customPaint!, - ), - if (mainCameraController.facePaint != null) - Positioned.fill( - child: mainCameraController.facePaint!, - ), - if (mainCameraController.focusPointOffset != null) + child: Stack( + children: [ + Screenshot( + controller: mainCameraController.screenshotController, + child: AspectRatio( + aspectRatio: 9 / 16, + child: ClipRect( + child: FittedBox( + fit: BoxFit.cover, + child: SizedBox( + width: mainCameraController + .cameraController!.value.previewSize!.height, + height: mainCameraController + .cameraController!.value.previewSize!.width, + child: CameraPreview( + key: mainCameraController.cameraPreviewKey, + mainCameraController.cameraController!, + child: Stack( + children: [ + if (mainCameraController.customPaint != null) + Positioned.fill( + child: mainCameraController.customPaint!, + ), + if (mainCameraController.facePaint != null) + Positioned.fill( + child: mainCameraController.facePaint!, + ), + ], + ), + ), + ), + ), + ), + ), + ), + if (mainCameraController.focusPointOffset != null) + AspectRatio( + aspectRatio: 9 / 16, + child: ClipRect( + child: FittedBox( + fit: BoxFit.cover, + child: SizedBox( + width: mainCameraController + .cameraController!.value.previewSize!.height, + height: mainCameraController + .cameraController!.value.previewSize!.width, + child: Stack( + children: [ Positioned( top: mainCameraController.focusPointOffset!.dy - 40, left: @@ -65,14 +87,14 @@ class MainCameraPreview extends StatelessWidget { ), ), ), - ) - ], + ), + ], + ), ), ), ), ), - ), - ), + ], ), ), ); diff --git a/lib/src/views/camera/camera_preview_components/camera_preview_controller_view.dart b/lib/src/views/camera/camera_preview_components/camera_preview_controller_view.dart index fe387ee..b5ae1b7 100644 --- a/lib/src/views/camera/camera_preview_components/camera_preview_controller_view.dart +++ b/lib/src/views/camera/camera_preview_components/camera_preview_controller_view.dart @@ -27,8 +27,8 @@ import 'package:twonly/src/views/camera/camera_preview_components/permissions_vi import 'package:twonly/src/views/camera/camera_preview_components/send_to.dart'; import 'package:twonly/src/views/camera/camera_preview_components/video_recording_time.dart'; import 'package:twonly/src/views/camera/camera_preview_components/zoom_selector.dart'; -import 'package:twonly/src/views/camera/image_editor/action_button.dart'; -import 'package:twonly/src/views/camera/share_image_editor_view.dart'; +import 'package:twonly/src/views/camera/share_image_editor/action_button.dart'; +import 'package:twonly/src/views/camera/share_image_editor.view.dart'; import 'package:twonly/src/views/components/avatar_icon.component.dart'; import 'package:twonly/src/views/components/loader.dart'; import 'package:twonly/src/views/components/media_view_sizing.dart'; diff --git a/lib/src/views/camera/camera_preview_components/face_filters.dart b/lib/src/views/camera/camera_preview_components/face_filters.dart index f4826a0..8c880a7 100644 --- a/lib/src/views/camera/camera_preview_components/face_filters.dart +++ b/lib/src/views/camera/camera_preview_components/face_filters.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; -import 'package:twonly/src/views/camera/painters/face_filters/beard_filter_painter.dart'; -import 'package:twonly/src/views/camera/painters/face_filters/dog_filter_painter.dart'; +import 'package:twonly/src/views/camera/camera_preview_components/painters/face_filters/beard_filter_painter.dart'; +import 'package:twonly/src/views/camera/camera_preview_components/painters/face_filters/dog_filter_painter.dart'; enum FaceFilterType { none, diff --git a/lib/src/views/camera/camera_preview_components/main_camera_controller.dart b/lib/src/views/camera/camera_preview_components/main_camera_controller.dart index f710797..fb433ce 100644 --- a/lib/src/views/camera/camera_preview_components/main_camera_controller.dart +++ b/lib/src/views/camera/camera_preview_components/main_camera_controller.dart @@ -19,10 +19,10 @@ import 'package:twonly/src/utils/qr.dart'; import 'package:twonly/src/utils/screenshot.dart'; import 'package:twonly/src/views/camera/camera_preview_components/camera_preview_controller_view.dart'; import 'package:twonly/src/views/camera/camera_preview_components/face_filters.dart'; -import 'package:twonly/src/views/camera/painters/barcode_detector_painter.dart'; -import 'package:twonly/src/views/camera/painters/face_filters/beard_filter_painter.dart'; -import 'package:twonly/src/views/camera/painters/face_filters/dog_filter_painter.dart'; -import 'package:twonly/src/views/camera/painters/face_filters/face_filter_painter.dart'; +import 'package:twonly/src/views/camera/camera_preview_components/painters/barcode_detector_painter.dart'; +import 'package:twonly/src/views/camera/camera_preview_components/painters/face_filters/beard_filter_painter.dart'; +import 'package:twonly/src/views/camera/camera_preview_components/painters/face_filters/dog_filter_painter.dart'; +import 'package:twonly/src/views/camera/camera_preview_components/painters/face_filters/face_filter_painter.dart'; class ScannedVerifiedContact { ScannedVerifiedContact({ diff --git a/lib/src/views/camera/painters/barcode_detector_painter.dart b/lib/src/views/camera/camera_preview_components/painters/barcode_detector_painter.dart similarity index 100% rename from lib/src/views/camera/painters/barcode_detector_painter.dart rename to lib/src/views/camera/camera_preview_components/painters/barcode_detector_painter.dart diff --git a/lib/src/views/camera/painters/coordinates_translator.dart b/lib/src/views/camera/camera_preview_components/painters/coordinates_translator.dart similarity index 100% rename from lib/src/views/camera/painters/coordinates_translator.dart rename to lib/src/views/camera/camera_preview_components/painters/coordinates_translator.dart diff --git a/lib/src/views/camera/painters/face_filters/beard_filter_painter.dart b/lib/src/views/camera/camera_preview_components/painters/face_filters/beard_filter_painter.dart similarity index 95% rename from lib/src/views/camera/painters/face_filters/beard_filter_painter.dart rename to lib/src/views/camera/camera_preview_components/painters/face_filters/beard_filter_painter.dart index 95f2b12..3477bb6 100644 --- a/lib/src/views/camera/painters/face_filters/beard_filter_painter.dart +++ b/lib/src/views/camera/camera_preview_components/painters/face_filters/beard_filter_painter.dart @@ -6,8 +6,8 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:google_mlkit_face_detection/google_mlkit_face_detection.dart'; import 'package:twonly/src/utils/log.dart'; -import 'package:twonly/src/views/camera/painters/coordinates_translator.dart'; -import 'package:twonly/src/views/camera/painters/face_filters/face_filter_painter.dart'; +import 'package:twonly/src/views/camera/camera_preview_components/painters/coordinates_translator.dart'; +import 'package:twonly/src/views/camera/camera_preview_components/painters/face_filters/face_filter_painter.dart'; class BeardFilterPainter extends FaceFilterPainter { BeardFilterPainter( diff --git a/lib/src/views/camera/painters/face_filters/dog_filter_painter.dart b/lib/src/views/camera/camera_preview_components/painters/face_filters/dog_filter_painter.dart similarity index 96% rename from lib/src/views/camera/painters/face_filters/dog_filter_painter.dart rename to lib/src/views/camera/camera_preview_components/painters/face_filters/dog_filter_painter.dart index 5ca873c..3643c33 100644 --- a/lib/src/views/camera/painters/face_filters/dog_filter_painter.dart +++ b/lib/src/views/camera/camera_preview_components/painters/face_filters/dog_filter_painter.dart @@ -6,8 +6,8 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:google_mlkit_face_detection/google_mlkit_face_detection.dart'; import 'package:twonly/src/utils/log.dart'; -import 'package:twonly/src/views/camera/painters/coordinates_translator.dart'; -import 'package:twonly/src/views/camera/painters/face_filters/face_filter_painter.dart'; +import 'package:twonly/src/views/camera/camera_preview_components/painters/coordinates_translator.dart'; +import 'package:twonly/src/views/camera/camera_preview_components/painters/face_filters/face_filter_painter.dart'; class DogFilterPainter extends FaceFilterPainter { DogFilterPainter( diff --git a/lib/src/views/camera/painters/face_filters/face_filter_painter.dart b/lib/src/views/camera/camera_preview_components/painters/face_filters/face_filter_painter.dart similarity index 100% rename from lib/src/views/camera/painters/face_filters/face_filter_painter.dart rename to lib/src/views/camera/camera_preview_components/painters/face_filters/face_filter_painter.dart diff --git a/lib/src/views/camera/camera_send_to_view.dart b/lib/src/views/camera/camera_send_to.view.dart similarity index 100% rename from lib/src/views/camera/camera_send_to_view.dart rename to lib/src/views/camera/camera_send_to.view.dart diff --git a/lib/src/views/camera/image_editor/data/data.dart b/lib/src/views/camera/image_editor/data/data.dart deleted file mode 100755 index a686020..0000000 --- a/lib/src/views/camera/image_editor/data/data.dart +++ /dev/null @@ -1,710 +0,0 @@ -Map emojiWeights = {}; - -List emojis = [ - '๐Ÿ˜€', - '๐Ÿ˜', - '๐Ÿ˜‚', - '๐Ÿคฃ', - '๐Ÿ˜ƒ', - '๐Ÿ˜„', - '๐Ÿ˜…', - '๐Ÿ˜†', - '๐Ÿ˜‰', - '๐Ÿ˜Š', - '๐Ÿ˜‹', - '๐Ÿ˜Ž', - '๐Ÿ˜', - '๐Ÿ˜˜', - '๐Ÿฅฐ', - '๐Ÿ˜—', - '๐Ÿ˜™', - '๐Ÿ˜š', - '๐Ÿ™‚๏ธ', - '๐Ÿค—', - '๐Ÿคฉ', - '๐Ÿค”', - '๐Ÿค”', - '๐Ÿคจ', - '๐Ÿ˜', - '๐Ÿ˜‘', - '๐Ÿ˜ถ', - '๐Ÿ™„', - '๐Ÿ˜', - '๐Ÿ˜ฃ', - '๐Ÿ˜ฅ', - '๐Ÿ˜ฎ', - '๐Ÿค', - '๐Ÿ˜ฏ', - '๐Ÿ˜ช', - '๐Ÿ˜ซ', - '๐Ÿ˜ด', - '๐Ÿ˜Œ', - '๐Ÿ˜›', - '๐Ÿ˜œ', - '๐Ÿ˜', - '๐Ÿคค', - '๐Ÿ˜’', - '๐Ÿ˜“', - '๐Ÿ˜”', - '๐Ÿ˜•', - '๐Ÿ™ƒ', - '๐Ÿค‘', - '๐Ÿ˜ฒ', - '๐Ÿ™', - '๐Ÿ˜–', - '๐Ÿ˜ž', - '๐Ÿ˜Ÿ', - '๐Ÿ˜ค', - '๐Ÿ˜ข', - '๐Ÿ˜ญ', - '๐Ÿ˜ฆ', - '๐Ÿ˜ง', - '๐Ÿ˜จ', - '๐Ÿ˜ฉ', - '๐Ÿคฏ', - '๐Ÿ˜ฌ', - '๐Ÿ˜ฐ', - '๐Ÿ˜ฑ', - '๐Ÿฅต', - '๐Ÿฅถ', - '๐Ÿ˜ณ', - '๐Ÿคช', - '๐Ÿ˜ต', - '๐Ÿ˜ก', - '๐Ÿ˜ ', - '๐Ÿคฌ', - '๐Ÿ˜ท', - '๐Ÿค’', - '๐Ÿค•', - '๐Ÿคข', - '๐Ÿคฎ', - '๐Ÿคง', - '๐Ÿ˜‡', - '๐Ÿค ', - '๐Ÿคก', - '๐Ÿฅณ', - '๐Ÿฅด', - '๐Ÿคฅ', - '๐Ÿคซ', - '๐Ÿคญ', - '๐Ÿคญ', - '๐Ÿง', - '๐Ÿค“', - '๐Ÿ˜ˆ', - '๐Ÿ‘ฟ', - '๐Ÿ‘น', - '๐Ÿ‘บ', - '๐Ÿ’€', - '๐Ÿ‘ป', - '๐Ÿ‘ฝ', - '๐Ÿค–', - '๐Ÿ’ฉ', - '๐Ÿ˜บ', - '๐Ÿ˜ธ', - '๐Ÿ˜น', - '๐Ÿ˜ป', - '๐Ÿ˜ผ', - '๐Ÿ˜ฝ', - '๐Ÿ™€', - '๐Ÿ˜ฟ', - '๐Ÿ˜พ', - '๐Ÿ˜พ', - - /// People and Fantasy - '๐Ÿ‘ถ', - '๐Ÿ‘ง', - '๐Ÿง’', - '๐Ÿ‘ฉ', - '๐Ÿง‘', - '๐Ÿ‘จ', - '๐Ÿ‘ต', - '๐Ÿ‘ด', - '๐Ÿ‘ฒ', - '๐Ÿ‘ณโ€โ™€๏ธโ€๏ธ', - '๐Ÿ‘ณโ€โ™‚๏ธ๏ธโ€๏ธ', - '๐Ÿง•๏ธ๏ธโ€๏ธ', - '๐Ÿง”โ€', - '๐Ÿ‘ฑโ€โ™‚๏ธ๏ธโ€', - '๐Ÿ‘ฑโ€โ™€๏ธ๏ธ๏ธโ€', - '๐Ÿ‘จโ€๐Ÿฆฐ๏ธ๏ธ๏ธโ€', - '๐Ÿ‘ฉโ€๐Ÿฆฐโ€', - '๐Ÿ‘จโ€๐Ÿฆฑโ€โ€', - '๐Ÿ‘จโ€๐Ÿฆฒโ€โ€', - '๐Ÿ‘ฉโ€๐Ÿฆฒโ€โ€', - '๐Ÿ‘จโ€๐Ÿฆณโ€โ€', - '๐Ÿ‘ฉโ€๐Ÿฆณโ€โ€', - '๐Ÿฆธโ€โ™€๏ธโ€โ€', - '๐Ÿฆธโ€โ™‚๏ธ๏ธโ€โ€', - '๐Ÿฆนโ€โ™€๏ธ๏ธ๏ธโ€โ€', - '๐Ÿฆนโ€โ™‚๏ธ๏ธ๏ธ๏ธโ€โ€', - '๐Ÿ‘ฎโ€โ™€๏ธโ€โ€', - '๐Ÿ‘ฎโ€โ™‚๏ธ๏ธโ€โ€', - '๐Ÿ‘ทโ€โ™€๏ธ๏ธ๏ธโ€โ€', - '๐Ÿ‘ทโ€โ™‚๏ธ๏ธ๏ธ๏ธโ€โ€', - '๐Ÿ’‚โ€โ™€๏ธ๏ธ๏ธ๏ธ๏ธโ€โ€', - '๐Ÿ’‚โ€โ™‚๏ธ๏ธ๏ธ๏ธ๏ธ๏ธโ€โ€', - '๐Ÿ•ต๏ธโ€โ™€๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธโ€โ€', - '๐Ÿ•ต๏ธโ€โ™‚๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธโ€โ€', - '๐Ÿ‘ฉโ€โš•๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธโ€โ€', - '๐Ÿ‘จโ€โš•๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธโ€โ€', - '๐Ÿ‘ฉโ€๐ŸŒพ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธโ€โ€', - '๐Ÿ‘จโ€๐ŸŒพโ€โ€', - '๐Ÿ‘ฉโ€๐Ÿณโ€โ€', - '๐Ÿ‘จโ€๐Ÿณโ€โ€', - '๐Ÿ‘ฉโ€๐ŸŽ“โ€โ€', - '๐Ÿ‘จโ€๐ŸŽ“โ€โ€', - '๐Ÿ‘ฉโ€๐ŸŽคโ€โ€', - '๐Ÿ‘จโ€๐ŸŽคโ€โ€', - '๐Ÿ‘ฉโ€๐Ÿซโ€โ€', - '๐Ÿ‘จโ€๐Ÿซโ€โ€', - '๐Ÿ‘ฉโ€๐Ÿญโ€โ€', - '๐Ÿ‘จโ€๐Ÿญโ€โ€', - '๐Ÿ‘ฉโ€๐Ÿ’ปโ€โ€', - '๐Ÿ‘จโ€๐Ÿ’ปโ€โ€', - '๐Ÿ‘ฉโ€๐Ÿ’ผโ€โ€', - '๐Ÿ‘จโ€๐Ÿ’ผโ€โ€', - '๐Ÿ‘ฉโ€๐Ÿ”งโ€โ€', - '๐Ÿ‘จโ€๐Ÿ”งโ€โ€', - '๐Ÿ‘ฉโ€๐Ÿ”ฌโ€โ€', - '๐Ÿ‘จโ€๐Ÿ”ฌโ€โ€', - '๐Ÿ‘ฉโ€๐ŸŽจโ€โ€', - '๐Ÿ‘จโ€๐ŸŽจโ€โ€', - '๐Ÿ‘ฉโ€๐Ÿš’โ€โ€', - '๐Ÿ‘จโ€๐Ÿš’โ€โ€', - '๐Ÿ‘ฉโ€โœˆ๏ธโ€โ€', - '๐Ÿ‘จโ€โœˆ๏ธ๏ธโ€โ€', - '๐Ÿ‘ฉโ€๐Ÿš€โ€โ€', - '๐Ÿ‘จโ€๐Ÿš€โ€โ€', - '๐Ÿ‘ฉโ€โš–๏ธโ€โ€', - '๐Ÿ‘จโ€โš–๏ธ๏ธโ€โ€', - '๐Ÿ‘ฐโ€โ€', - '๐Ÿคตโ€โ€', - '๐Ÿ‘ธโ€โ€', - '๐Ÿคดโ€โ€', - '๐Ÿคถโ€โ€', - '๐ŸŽ…โ€โ€', - '๐Ÿง™โ€โ™€๏ธโ€โ€', - '๐Ÿง™โ€โ™‚๏ธ๏ธโ€โ€', - '๐Ÿงโ€โ™€๏ธ๏ธ๏ธโ€โ€', - '๐Ÿงโ€โ™‚๏ธโ€โ€', - '๐Ÿง›โ€โ™€๏ธ๏ธโ€โ€', - '๐Ÿง›โ€โ™‚๏ธ๏ธ๏ธโ€โ€', - '๐ŸงŸโ€โ™€๏ธ๏ธ๏ธ๏ธโ€โ€', - '๐ŸงŸโ€โ™‚๏ธ๏ธ๏ธ๏ธ๏ธโ€โ€', - '๐Ÿงžโ€โ™€๏ธ๏ธ๏ธ๏ธ๏ธ๏ธโ€โ€', - '๐Ÿงžโ€โ™‚๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธโ€โ€', - '๐Ÿงœโ€โ™€๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธโ€โ€', - '๐Ÿงœโ€โ™‚๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธโ€โ€', - '๐Ÿงšโ€โ™€๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธโ€โ€', - '๐Ÿงšโ€โ™‚๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธโ€โ€', - '๐Ÿ‘ผ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธโ€โ€', - '๐Ÿคฐโ€โ€', - '๐Ÿคฑโ€โ€', - '๐Ÿ™‡โ€โ™€๏ธโ€โ€', - '๐Ÿ™‡โ€โ™‚๏ธโ€โ€', - '๐Ÿ’โ€โ™€๏ธ๏ธโ€โ€', - '๐Ÿ’โ€โ™‚๏ธ๏ธ๏ธโ€โ€', - '๐Ÿ™…โ€โ™€๏ธ๏ธ๏ธ๏ธโ€โ€', - '๐Ÿ™…โ€โ™‚๏ธโ€โ€', - '๐Ÿ™†โ€โ™€๏ธ๏ธโ€โ€', - '๐Ÿ™†โ€โ™‚๏ธ๏ธ๏ธโ€โ€', - '๐Ÿ™‹โ€โ™€๏ธ๏ธ๏ธ๏ธโ€โ€', - '๐Ÿ™‹โ€โ™‚๏ธโ€โ€', - '๐Ÿคฆโ€โ™€๏ธ๏ธโ€โ€', - '๐Ÿคฆโ€โ™‚๏ธ๏ธ๏ธโ€โ€', - '๐Ÿคทโ€โ™€๏ธ๏ธ๏ธ๏ธโ€โ€', - '๐Ÿคทโ€โ™‚๏ธ๏ธ๏ธ๏ธ๏ธโ€โ€', - '๐Ÿ™Žโ€โ™€๏ธ๏ธ๏ธ๏ธ๏ธ๏ธโ€โ€', - '๐Ÿ™Žโ€โ™‚๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธโ€โ€', - '๐Ÿ™โ€โ™€๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธโ€โ€', - '๐Ÿ™โ€โ™‚๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธโ€โ€', - '๐Ÿ’‡โ€โ™€๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธโ€โ€', - '๐Ÿ’‡โ€โ™‚๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธโ€โ€', - '๐Ÿ’†โ€โ™€๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธโ€โ€', - '๐Ÿ’†โ€โ™‚๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธโ€โ€', - '๐Ÿง–โ€โ™€๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธโ€โ€', - '๐Ÿง–โ€โ™‚๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธโ€โ€', - '๐Ÿ’…๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธโ€โ€', - '๐Ÿคณ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธโ€โ€', - '๐Ÿ’ƒ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธโ€โ€', - '๐Ÿ•บ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธโ€โ€', - '๐Ÿ‘ฏโ€โ™€๏ธโ€โ€', - '๐Ÿ‘ฏโ€โ™‚๏ธ๏ธโ€โ€', - '๐Ÿ•ด๏ธ๏ธโ€โ€', - '๐Ÿšถโ€โ™€๏ธ๏ธโ€โ€', - '๐Ÿšถโ€โ™‚๏ธ๏ธ๏ธโ€โ€', - '๐Ÿƒโ€โ™€๏ธ๏ธ๏ธ๏ธโ€โ€', - '๐Ÿƒโ€โ™‚๏ธโ€โ€', - '๐Ÿ‘ซ๏ธโ€โ€', - '๐Ÿ‘ญโ€โ€', - '๐Ÿ‘ฌโ€โ€', - '๐Ÿ’‘โ€โ€', - '๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ‘ฉโ€โ€', - '๐Ÿ‘จโ€โค๏ธโ€๐Ÿ‘จโ€โ€', - '๐Ÿ’โ€โ€', - '๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉโ€โ€', - '๐Ÿ‘จโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จโ€โ€', - '๐Ÿ‘ชโ€โ€', - '๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€โ€', - '๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆโ€โ€', - '๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆโ€โ€', - '๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘งโ€โ€', - '๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘ฆโ€โ€', - '๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€โ€', - '๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆโ€โ€', - '๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆโ€โ€', - '๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘งโ€โ€', - '๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘ฆโ€โ€', - '๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘งโ€โ€', - '๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘งโ€๐Ÿ‘ฆโ€โ€', - '๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆโ€โ€', - '๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘งโ€๐Ÿ‘งโ€โ€', - '๐Ÿ‘ฉโ€๐Ÿ‘ฆโ€โ€', - '๐Ÿ‘ฉโ€๐Ÿ‘งโ€โ€', - '๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆโ€โ€', - '๐Ÿ‘ฉโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆโ€โ€', - '๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘งโ€โ€', - '๐Ÿ‘จโ€๐Ÿ‘ฆโ€โ€', - '๐Ÿ‘จโ€๐Ÿ‘งโ€โ€', - '๐Ÿ‘จโ€๐Ÿ‘งโ€๐Ÿ‘ฆโ€โ€', - '๐Ÿ‘จโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆโ€โ€', - '๐Ÿ‘จโ€๐Ÿ‘งโ€๐Ÿ‘งโ€โ€', - '๐Ÿคฒโ€โ€', - '๐Ÿ‘โ€โ€', - '๐Ÿ™Œโ€โ€', - '๐Ÿ‘โ€โ€', - '๐Ÿคโ€โ€', - '๐Ÿ‘โ€โ€', - '๐Ÿ‘Žโ€โ€', - '๐Ÿ‘Šโ€โ€', - 'โœŠโ€โ€', - '๐Ÿค›โ€โ€', - '๐Ÿคœโ€โ€', - '๐Ÿคžโ€โ€', - 'โœŒ๏ธโ€โ€', - '๐ŸคŸ๏ธโ€โ€', - '๐Ÿค˜โ€โ€', - '๐Ÿ‘Œโ€โ€', - '๐Ÿ‘ˆโ€โ€', - '๐Ÿ‘‰โ€โ€', - '๐Ÿ‘†โ€โ€', - '๐Ÿ‘‡โ€โ€', - 'โ˜๏ธโ€โ€', - 'โœ‹๏ธโ€โ€', - '๐Ÿคš๏ธโ€โ€', - '๐Ÿคš๏ธโ€โ€', - '๐Ÿ–โ€โ€', - '๐Ÿ––โ€โ€', - '๐Ÿ‘‹โ€โ€', - '๐Ÿค™โ€โ€', - '๐Ÿ’ชโ€โ€', - '๐Ÿฆตโ€โ€', - '๐Ÿฆถโ€โ€', - '๐Ÿ–•โ€โ€', - 'โœ๏ธโ€โ€', - '๐Ÿ™๏ธโ€โ€', - '๐Ÿ’โ€โ€', - '๐Ÿ’„โ€โ€', - '๐Ÿ’‹โ€โ€', - '๐Ÿ‘„โ€โ€', - '๐Ÿ‘…โ€โ€', - '๐Ÿ‘‚โ€โ€', - '๐Ÿ‘ƒโ€โ€', - '๐Ÿ‘ฃโ€โ€', - '๐Ÿ‘โ€โ€', - '๐Ÿ‘€โ€โ€', - '๐Ÿง โ€โ€', - '๐Ÿฆดโ€โ€', - '๐Ÿฆทโ€โ€', - '๐Ÿ—ฃโ€โ€', - '๐Ÿ‘คโ€โ€', - '๐Ÿ‘ฅโ€โ€', - '๐Ÿงฅโ€โ€', - '๐Ÿ‘šโ€โ€', - '๐Ÿ‘•โ€โ€', - '๐Ÿ‘–โ€โ€', - '๐Ÿ‘”โ€โ€', - '๐Ÿ‘—โ€โ€', - '๐Ÿ‘™โ€โ€', - '๐Ÿ‘˜โ€โ€', - '๐Ÿ‘ โ€โ€', - '๐Ÿ‘กโ€โ€', - '๐Ÿ‘ขโ€โ€', - '๐Ÿ‘žโ€โ€', - '๐Ÿ‘Ÿโ€โ€', - '๐Ÿฅพโ€โ€', - '๐Ÿฅฟโ€โ€', - '๐Ÿงฆโ€โ€', - '๐Ÿงคโ€โ€', - '๐Ÿงฃโ€โ€', - '๐ŸŽฉโ€โ€', - '๐Ÿงขโ€โ€', - '๐Ÿ‘’โ€โ€', - '๐ŸŽ“โ€โ€', - 'โ›‘โ€โ€', - '๐Ÿ‘‘โ€โ€', - '๐Ÿ‘โ€โ€', - '๐Ÿ‘›โ€โ€', - '๐Ÿ‘œโ€โ€', - '๐Ÿ’ผโ€โ€', - '๐ŸŽ’โ€โ€', - '๐Ÿ‘“โ€โ€', - '๐Ÿ•ถโ€โ€', - '๐Ÿฅฝโ€โ€', - '๐Ÿฅผโ€โ€', - '๐ŸŒ‚โ€โ€', - '๐Ÿงตโ€โ€', - '๐Ÿงถโ€โ€', - - /// Animals - '๐Ÿถโ€โ€', - '๐Ÿฑโ€โ€', - '๐Ÿญโ€โ€', - '๐Ÿฐโ€โ€', - '๐ŸฆŠโ€โ€', - '๐Ÿฆโ€โ€', - '๐Ÿปโ€โ€', - '๐Ÿฆ˜โ€โ€', - '๐Ÿฆกโ€โ€', - '๐Ÿจโ€โ€', - '๐Ÿฏโ€โ€', - '๐Ÿฆโ€โ€', - '๐Ÿผโ€โ€', - '๐Ÿผโ€โ€', - '๐Ÿฎโ€โ€', - '๐Ÿทโ€โ€', - '๐Ÿฝโ€โ€', - '๐Ÿธโ€โ€', - '๐Ÿตโ€โ€', - '๐Ÿ™ˆโ€โ€', - '๐Ÿ™‰โ€โ€', - '๐Ÿ™Šโ€โ€', - '๐Ÿ’โ€โ€', - '๐Ÿ”โ€โ€', - '๐Ÿงโ€โ€', - '๐Ÿฆโ€โ€', - '๐Ÿคโ€โ€', - '๐Ÿฃโ€โ€', - '๐Ÿฅโ€โ€', - '๐Ÿฆ†โ€โ€', - '๐Ÿฆขโ€โ€', - '๐Ÿฆ…โ€โ€', - '๐Ÿฆ‰โ€โ€', - '๐Ÿฆšโ€โ€', - '๐Ÿฆœโ€โ€', - '๐Ÿฆ‡โ€โ€', - '๐Ÿบโ€โ€', - '๐Ÿ—โ€โ€', - '๐Ÿดโ€โ€', - '๐Ÿฆ„โ€โ€', - '๐Ÿโ€โ€', - '๐Ÿ›โ€โ€', - '๐Ÿฆ‹โ€โ€', - '๐ŸŒโ€โ€', - '๐Ÿšโ€โ€', - '๐Ÿžโ€โ€', - '๐Ÿœโ€โ€', - '๐Ÿฆ—โ€โ€', - '๐Ÿ•ทโ€โ€', - '๐Ÿ•ธโ€โ€', - '๐Ÿฆ‚โ€โ€', - '๐ŸฆŸโ€โ€', - '๐Ÿฆ โ€โ€', - '๐Ÿขโ€โ€', - '๐Ÿโ€โ€', - '๐ŸฆŽโ€โ€', - '๐Ÿฆ–โ€โ€', - '๐Ÿฆ•โ€โ€', - '๐Ÿ™โ€โ€', - '๐Ÿฆ‘โ€โ€', - '๐Ÿฆโ€โ€', - '๐Ÿฆ€โ€โ€', - '๐Ÿกโ€โ€', - '๐Ÿ โ€โ€', - '๐ŸŸโ€โ€', - '๐Ÿฌโ€โ€', - '๐Ÿณโ€โ€', - '๐Ÿ‹โ€โ€', - '๐Ÿฆˆโ€โ€', - '๐ŸŠโ€โ€', - '๐Ÿ…โ€โ€', - '๐Ÿ†โ€โ€', - '๐Ÿฆ“โ€โ€', - '๐Ÿฆโ€โ€', - '๐Ÿ˜โ€โ€', - '๐Ÿฆโ€โ€', - '๐Ÿฆ›โ€โ€', - '๐Ÿชโ€โ€', - '๐Ÿซโ€โ€', - '๐Ÿฆ™โ€โ€', - '๐Ÿฆ’โ€โ€', - '๐Ÿƒโ€โ€', - '๐Ÿ‚โ€โ€', - '๐Ÿ„โ€โ€', - '๐ŸŽโ€โ€', - '๐Ÿ–โ€โ€', - '๐Ÿโ€โ€', - '๐Ÿโ€โ€', - '๐ŸฆŒโ€โ€', - '๐Ÿ•โ€โ€', - '๐Ÿฉโ€โ€', - '๐Ÿˆโ€โ€', - '๐Ÿ“โ€โ€', - '๐Ÿฆƒโ€โ€', - '๐Ÿ•Šโ€โ€', - '๐Ÿ‡โ€โ€', - '๐Ÿโ€โ€', - '๐Ÿ€โ€โ€', - '๐Ÿฟโ€โ€', - '๐Ÿฆ”โ€โ€', - '๐Ÿพโ€', - '๐Ÿ‰โ€', - '๐Ÿฒโ€', - '๐ŸŒตโ€', - '๐ŸŽ„โ€', - '๐ŸŒฒโ€', - '๐ŸŒณโ€', - '๐ŸŒดโ€', - '๐ŸŒฑโ€', - '๐ŸŒฟโ€', - 'โ˜˜๏ธโ€', - '๐ŸŽ๏ธโ€', - '๐ŸŽ‹๏ธโ€', - '๐Ÿƒโ€', - '๐Ÿ‚โ€', - '๐Ÿโ€', - '๐Ÿ„โ€', - '๐ŸŒพ๏ธโ€', - '๐Ÿ’๏ธโ€', - '๐ŸŒท๏ธโ€', - '๐ŸŒนโ€', - '๐Ÿฅ€โ€', - '๐ŸŒบโ€', - '๐ŸŒธโ€', - '๐ŸŒผโ€', - '๐ŸŒป๏ธโ€', - '๐ŸŒžโ€', - '๐ŸŒโ€', - '๐ŸŒ›โ€', - '๐ŸŒœโ€', - '๐ŸŒšโ€', - '๐ŸŒ•โ€', - '๐ŸŒ–โ€', - '๐ŸŒ—โ€', - '๐ŸŒ˜โ€', - '๐ŸŒ‘โ€', - '๐ŸŒ’โ€', - '๐ŸŒ”โ€', - '๐ŸŒ™โ€', - '๐ŸŒŽโ€', - '๐ŸŒโ€', - '๐ŸŒโ€', - '๐Ÿ’ซโ€', - 'โญ๏ธโ€', - '๐ŸŒŸ๏ธโ€', - 'โœจ๏ธโ€', - 'โšก๏ธ๏ธโ€', - 'โ˜„๏ธ๏ธ๏ธโ€', - '๐Ÿ’ฅ๏ธ๏ธ๏ธโ€', - '๐Ÿ”ฅโ€', - '๐ŸŒชโ€', - '๐ŸŒˆโ€', - 'โ˜€๏ธโ€', - '๐ŸŒค๏ธโ€', - 'โ›…๏ธ๏ธโ€', - '๐ŸŒฅ๏ธ๏ธโ€', - 'โ˜๏ธ๏ธโ€', - '๐ŸŒฆ๏ธ๏ธโ€', - '๐ŸŒง๏ธโ€', - 'โ›ˆโ€', - '๐ŸŒฉโ€', - '๐ŸŒจโ€', - 'โ„๏ธโ€', - 'โ˜ƒ๏ธ๏ธโ€', - 'โ›„๏ธ๏ธ๏ธโ€', - '๐ŸŒฌ๏ธ๏ธ๏ธโ€', - '๐Ÿ’จ๏ธ๏ธ๏ธโ€', - '๐Ÿ’ง๏ธ๏ธ๏ธโ€', - '๐Ÿ’ฆ๏ธ๏ธ๏ธโ€', - 'โ˜”๏ธ๏ธ๏ธ๏ธโ€', - 'โ˜‚๏ธ๏ธ๏ธ๏ธ๏ธโ€', - '๐ŸŒŠ๏ธ๏ธ๏ธ๏ธ๏ธโ€', - '๐ŸŒซ๏ธ๏ธ๏ธ๏ธโ€', - - /// Foods - '๐Ÿโ€', - '๐ŸŽโ€', - '๐Ÿโ€', - '๐ŸŠโ€', - '๐Ÿ‹โ€', - '๐ŸŒโ€', - '๐Ÿ‰โ€', - '๐Ÿ‡โ€', - '๐Ÿ“โ€', - '๐Ÿˆโ€', - '๐Ÿ’โ€', - '๐Ÿ‘โ€', - '๐Ÿโ€', - '๐Ÿฅญโ€', - '๐Ÿฅฅโ€', - '๐Ÿฅโ€', - '๐Ÿ…โ€', - '๐Ÿ†โ€', - '๐Ÿฅ‘โ€', - '๐Ÿฅฆโ€', - '๐Ÿฅ’โ€', - '๐Ÿฅฌโ€', - '๐ŸŒถโ€', - '๐ŸŒฝโ€', - '๐Ÿฅ•โ€', - '๐Ÿฅ”โ€', - '๐Ÿ โ€', - '๐Ÿฅโ€', - '๐Ÿžโ€', - '๐Ÿฅ–โ€', - '๐Ÿฅจโ€', - '๐Ÿฅฏโ€', - '๐Ÿง€โ€', - '๐Ÿฅšโ€', - '๐Ÿณโ€', - '๐Ÿฅžโ€', - '๐Ÿฅ“โ€', - '๐Ÿฅฉโ€', - '๐Ÿ—โ€', - '๐Ÿ–โ€', - '๐ŸŒญโ€', - '๐Ÿ”โ€', - '๐ŸŸโ€', - '๐Ÿ•โ€', - '๐Ÿฅชโ€', - '๐Ÿฅ™โ€', - '๐ŸŒฎโ€', - '๐ŸŒฏโ€', - '๐Ÿฅ—โ€', - '๐Ÿฅ˜โ€', - '๐Ÿฅซโ€', - '๐Ÿโ€', - '๐Ÿœโ€', - '๐Ÿฒโ€', - '๐Ÿ›โ€', - '๐Ÿฃโ€', - '๐Ÿฑโ€', - '๐ŸฅŸโ€', - '๐Ÿคโ€', - '๐Ÿ™โ€', - '๐Ÿšโ€', - '๐Ÿ˜โ€', - '๐Ÿฅโ€', - '๐Ÿฅฎโ€', - '๐Ÿฅ โ€', - '๐Ÿขโ€', - '๐Ÿงโ€', - '๐Ÿจโ€', - '๐Ÿฆโ€', - '๐Ÿฅงโ€', - '๐Ÿฐโ€', - '๐ŸŽ‚โ€', - '๐Ÿฎโ€', - '๐Ÿญโ€', - '๐Ÿฌโ€', - '๐Ÿซโ€', - '๐Ÿฟโ€', - '๐Ÿง‚โ€', - '๐Ÿฉโ€', - '๐Ÿชโ€', - '๐ŸŒฐโ€', - '๐Ÿฅœโ€', - '๐Ÿฏโ€', - '๐Ÿฅ›โ€', - '๐Ÿผโ€', - 'โ˜•๏ธโ€', - '๐Ÿต๏ธโ€', - '๐Ÿฅค๏ธโ€', - '๐Ÿถโ€', - '๐Ÿบโ€', - '๐Ÿปโ€', - '๐Ÿฅ‚โ€', - '๐Ÿทโ€', - '๐Ÿธโ€', - '๐Ÿนโ€', - '๐Ÿพโ€', - '๐Ÿฅ„โ€', - '๐Ÿดโ€', - '๐Ÿฝโ€', - '๐Ÿฅฃโ€', - '๐Ÿฅกโ€', - '๐Ÿฅขโ€', - - /// Activity and Sports - 'โšฝ๏ธโ€', - '๐Ÿ€๏ธโ€', - '๐Ÿˆโ€', - 'โšพ๏ธโ€', - '๐ŸฅŽ๏ธโ€', - '๐Ÿ๏ธโ€', - '๐Ÿ‰โ€', - '๐ŸŽพโ€', - '๐Ÿฅโ€', - '๐ŸŽฑโ€', - '๐Ÿ“โ€', - '๐Ÿธโ€', - '๐Ÿฅ…โ€', - '๐Ÿ’โ€', - '๐Ÿ‘โ€', - '๐Ÿฅโ€', - '๐Ÿโ€', - 'โ›ณ๏ธโ€', - '๐Ÿน๏ธโ€', - '๐ŸŽฃ๏ธโ€', - '๐ŸฅŠโ€', - '๐Ÿฅ‹โ€', - '๐ŸŽฝโ€', - 'โ›ธโ€', - '๐ŸฅŒโ€', - '๐Ÿ›ทโ€', - '๐Ÿ›นโ€', - '๐ŸŽฟโ€', - 'โ›ทโ€', - '๐Ÿ‚โ€', - '๐Ÿ‹๏ธโ€โ™€๏ธโ€', - '๐Ÿ‹๐Ÿผโ€โ™€๏ธโ€', - '๐Ÿ‹๐Ÿฝโ€โ™€๏ธ๏ธโ€', - '๐Ÿ‹๐Ÿพโ€โ™€๏ธ๏ธ๏ธโ€', - '๐Ÿ‹๐Ÿฟโ€โ™€๏ธ๏ธ๏ธ๏ธโ€', - '๐Ÿ‹๏ธโ€โ™‚๏ธ๏ธ๏ธ๏ธโ€', - '๐Ÿ‹๐Ÿปโ€โ™‚๏ธ๏ธ๏ธ๏ธโ€', - '๐Ÿ‹๐Ÿผโ€โ™‚๏ธ๏ธ๏ธ๏ธโ€', - '๐Ÿ‹๐Ÿฝโ€โ™‚๏ธ๏ธ๏ธ๏ธโ€', - '๐Ÿ‹๐Ÿพโ€โ™‚๏ธ๏ธ๏ธ๏ธโ€', - '๐Ÿ‹๐Ÿฟโ€โ™‚๏ธ๏ธ๏ธ๏ธโ€', - '๐Ÿคผโ€โ™€๏ธ๏ธ๏ธ๏ธโ€', - '๐Ÿคผโ€โ™‚๏ธ๏ธ๏ธ๏ธโ€', - '๐Ÿคธโ€โ™€๏ธ๏ธ๏ธ๏ธโ€', - '๐Ÿคธ๐Ÿปโ€โ™€๏ธ๏ธ๏ธ๏ธโ€', - '๐Ÿคธ๐Ÿผโ€โ™€๏ธ๏ธ๏ธ๏ธโ€', - '๐Ÿคธ๐Ÿฝโ€โ™€๏ธ๏ธ๏ธ๏ธโ€', - '๐Ÿคธ๐Ÿฟโ€โ™€๏ธ๏ธ๏ธ๏ธ๏ธโ€', - '๐Ÿคธโ€โ™‚๏ธ๏ธ๏ธ๏ธโ€', - '๐Ÿคธ๐Ÿปโ€โ™‚๏ธ๏ธ๏ธ๏ธโ€', - '๐Ÿคธ๐Ÿผโ€โ™‚๏ธ๏ธ๏ธ๏ธ๏ธโ€', - '๐Ÿคธ๐Ÿฝโ€โ™‚๏ธ๏ธ๏ธ๏ธ๏ธ๏ธโ€', - '๐Ÿคธ๐Ÿพโ€โ™‚๏ธ๏ธ๏ธ๏ธ๏ธ๏ธโ€', - '๐Ÿคธ๐Ÿฟโ€โ™‚๏ธ๏ธ๏ธ๏ธ๏ธ๏ธโ€', - 'โ›น๏ธโ€โ™€๏ธ๏ธ๏ธ๏ธ๏ธ๏ธโ€', - 'โ›น๐Ÿปโ€โ™€๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธโ€', - 'โ›น๐Ÿผโ€โ™€๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธโ€', - 'โ›น๐Ÿฝโ€โ™€๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธโ€', - 'โ›น๐Ÿพโ€โ™€๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธโ€', - 'โ›น๐Ÿฟโ€โ™€๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธโ€', - 'โ›น๏ธโ€โ™‚๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธโ€', - 'โ›น๐Ÿปโ€โ™‚๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธโ€', - 'โ›น๐Ÿผโ€โ™‚๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธโ€', - 'โ›น๐Ÿฝโ€โ™‚๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธโ€', - 'โ›น๐Ÿพโ€โ™‚๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธ๏ธโ€', - 'โ›น๐Ÿฟโ€โ™‚๏ธโ€', - '๐Ÿคบ๏ธโ€', - '๐Ÿคพโ€โ™€๏ธโ€', - '๐Ÿคพ๐Ÿปโ€โ™€๏ธ๏ธโ€', - '๐Ÿคพ๐Ÿผโ€โ™€๏ธ๏ธ๏ธโ€', - '๐Ÿคพ๐Ÿพโ€โ™€๏ธ๏ธ๏ธ๏ธโ€', -]; diff --git a/lib/src/views/camera/image_editor/layers/emoji_layer.dart b/lib/src/views/camera/image_editor/layers/emoji_layer.dart deleted file mode 100755 index 32ddcc3..0000000 --- a/lib/src/views/camera/image_editor/layers/emoji_layer.dart +++ /dev/null @@ -1,173 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:font_awesome_flutter/font_awesome_flutter.dart'; -import 'package:twonly/src/views/camera/image_editor/action_button.dart'; -import 'package:twonly/src/views/camera/image_editor/data/layer.dart'; - -/// Emoji layer -class EmojiLayer extends StatefulWidget { - const EmojiLayer({ - required this.layerData, - super.key, - this.onUpdate, - }); - final EmojiLayerData layerData; - final VoidCallback? onUpdate; - - @override - State createState() => _EmojiLayerState(); -} - -class _EmojiLayerState extends State { - double initialRotation = 0; - Offset initialOffset = Offset.zero; - Offset initialFocalPoint = Offset.zero; - double initialScale = 1; - bool deleteLayer = false; - bool twoPointerWhereDown = false; - final GlobalKey outlineKey = GlobalKey(); - final GlobalKey emojiKey = GlobalKey(); - int pointers = 0; - bool display = false; - - @override - void initState() { - super.initState(); - - if (widget.layerData.offset.dy == 0) { - // Set the initial offset to the center of the screen - WidgetsBinding.instance.addPostFrameCallback((_) { - setState(() { - widget.layerData.offset = Offset( - MediaQuery.of(context).size.width / 2 - (153 / 2), - MediaQuery.of(context).size.height / 2 - (153 / 2) - 100, - ); - }); - display = true; - }); - } else { - display = true; - } - } - - @override - Widget build(BuildContext context) { - if (!display) return Container(); - if (widget.layerData.isDeleted) return Container(); - return Stack( - key: outlineKey, - children: [ - Positioned( - left: widget.layerData.offset.dx, - top: widget.layerData.offset.dy, - child: Listener( - onPointerUp: (details) { - setState(() { - pointers--; - if (pointers == 0) { - twoPointerWhereDown = false; - } - if (deleteLayer) { - widget.layerData.isDeleted = true; - widget.onUpdate!(); - } - }); - }, - onPointerDown: (details) { - setState(() { - pointers++; - }); - }, - child: GestureDetector( - onScaleStart: (details) { - initialScale = widget.layerData.size; - initialRotation = widget.layerData.rotation; - initialOffset = widget.layerData.offset; - initialFocalPoint = - Offset(details.focalPoint.dx, details.focalPoint.dy); - - setState(() {}); - }, - onScaleUpdate: (details) async { - if (twoPointerWhereDown && details.pointerCount != 2) { - return; - } - final outlineBox = - outlineKey.currentContext!.findRenderObject()! as RenderBox; - - final emojiBox = - emojiKey.currentContext!.findRenderObject()! as RenderBox; - - final isAtTheBottom = - (widget.layerData.offset.dy + emojiBox.size.height / 2) > - outlineBox.size.height - 80; - final isInTheCenter = MediaQuery.of(context).size.width / 2 - - 30 < - (widget.layerData.offset.dx + - emojiBox.size.width / 2) && - MediaQuery.of(context).size.width / 2 + 20 > - (widget.layerData.offset.dx + emojiBox.size.width / 2); - - if (isAtTheBottom && isInTheCenter) { - if (!deleteLayer) { - await HapticFeedback.heavyImpact(); - } - deleteLayer = true; - } else { - deleteLayer = false; - } - setState(() { - twoPointerWhereDown = details.pointerCount >= 2; - widget.layerData.size = initialScale * details.scale; - if (widget.layerData.size > 96) { - // https://github.com/twonlyapp/twonly-app/issues/349 - widget.layerData.size = 96; - } - // print(widget.layerData.size); - widget.layerData.rotation = - initialRotation + details.rotation; - - // Update the position based on the translation - final dx = (initialOffset.dx) + - (details.focalPoint.dx - initialFocalPoint.dx); - final dy = (initialOffset.dy) + - (details.focalPoint.dy - initialFocalPoint.dy); - widget.layerData.offset = Offset(dx, dy); - }); - }, - child: Transform.rotate( - angle: widget.layerData.rotation, - key: emojiKey, - child: Container( - padding: const EdgeInsets.all(44), - color: Colors.transparent, - child: Text( - widget.layerData.text, - style: TextStyle( - fontSize: widget.layerData.size, - ), - ), - ), - ), - ), - ), - ), - if (pointers > 0) - Positioned( - left: 0, - right: 0, - bottom: 20, - child: Center( - child: GestureDetector( - child: ActionButton( - FontAwesomeIcons.trashCan, - tooltipText: '', - color: deleteLayer ? Colors.red : Colors.white, - ), - ), - ), - ), - ], - ); - } -} diff --git a/lib/src/views/camera/share_image_view.dart b/lib/src/views/camera/share_image_contact_selection.view.dart similarity index 99% rename from lib/src/views/camera/share_image_view.dart rename to lib/src/views/camera/share_image_contact_selection.view.dart index 0c22e03..0ecbbab 100644 --- a/lib/src/views/camera/share_image_view.dart +++ b/lib/src/views/camera/share_image_contact_selection.view.dart @@ -13,7 +13,7 @@ import 'package:twonly/src/services/api/mediafiles/upload.service.dart'; import 'package:twonly/src/services/flame.service.dart'; import 'package:twonly/src/services/mediafiles/mediafile.service.dart'; import 'package:twonly/src/utils/misc.dart'; -import 'package:twonly/src/views/camera/share_image_components/best_friends_selector.dart'; +import 'package:twonly/src/views/camera/share_image_contact_selection/best_friends_selector.dart'; import 'package:twonly/src/views/components/avatar_icon.component.dart'; import 'package:twonly/src/views/components/flame.dart'; import 'package:twonly/src/views/components/headline.dart'; diff --git a/lib/src/views/camera/share_image_components/best_friends_selector.dart b/lib/src/views/camera/share_image_contact_selection/best_friends_selector.dart similarity index 100% rename from lib/src/views/camera/share_image_components/best_friends_selector.dart rename to lib/src/views/camera/share_image_contact_selection/best_friends_selector.dart diff --git a/lib/src/views/camera/share_image_components/select_show_time.dart b/lib/src/views/camera/share_image_contact_selection/select_show_time.dart similarity index 100% rename from lib/src/views/camera/share_image_components/select_show_time.dart rename to lib/src/views/camera/share_image_contact_selection/select_show_time.dart diff --git a/lib/src/views/camera/share_image_editor_view.dart b/lib/src/views/camera/share_image_editor.view.dart similarity index 97% rename from lib/src/views/camera/share_image_editor_view.dart rename to lib/src/views/camera/share_image_editor.view.dart index 28e3cb8..cd4ecbf 100644 --- a/lib/src/views/camera/share_image_editor_view.dart +++ b/lib/src/views/camera/share_image_editor.view.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'dart:collection'; + import 'package:drift/drift.dart' show Value; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -18,13 +19,13 @@ import 'package:twonly/src/utils/screenshot.dart'; import 'package:twonly/src/utils/storage.dart'; import 'package:twonly/src/views/camera/camera_preview_components/main_camera_controller.dart'; import 'package:twonly/src/views/camera/camera_preview_components/save_to_gallery.dart'; -import 'package:twonly/src/views/camera/image_editor/action_button.dart'; -import 'package:twonly/src/views/camera/image_editor/data/image_item.dart'; -import 'package:twonly/src/views/camera/image_editor/data/layer.dart'; -import 'package:twonly/src/views/camera/image_editor/layers_viewer.dart'; -import 'package:twonly/src/views/camera/image_editor/modules/all_emojis.dart'; -import 'package:twonly/src/views/camera/share_image_components/select_show_time.dart'; -import 'package:twonly/src/views/camera/share_image_view.dart'; +import 'package:twonly/src/views/camera/share_image_contact_selection.view.dart'; +import 'package:twonly/src/views/camera/share_image_contact_selection/select_show_time.dart'; +import 'package:twonly/src/views/camera/share_image_editor/action_button.dart'; +import 'package:twonly/src/views/camera/share_image_editor/data/image_item.dart'; +import 'package:twonly/src/views/camera/share_image_editor/data/layer.dart'; +import 'package:twonly/src/views/camera/share_image_editor/layers_viewer.dart'; +import 'package:twonly/src/views/components/emoji_picker.bottom.dart'; import 'package:twonly/src/views/components/media_view_sizing.dart'; import 'package:twonly/src/views/components/notification_badge.dart'; import 'package:video_player/video_player.dart'; diff --git a/lib/src/views/camera/image_editor/action_button.dart b/lib/src/views/camera/share_image_editor/action_button.dart similarity index 100% rename from lib/src/views/camera/image_editor/action_button.dart rename to lib/src/views/camera/share_image_editor/action_button.dart diff --git a/lib/src/views/camera/image_editor/data/image_item.dart b/lib/src/views/camera/share_image_editor/data/image_item.dart similarity index 100% rename from lib/src/views/camera/image_editor/data/image_item.dart rename to lib/src/views/camera/share_image_editor/data/image_item.dart diff --git a/lib/src/views/camera/image_editor/data/layer.dart b/lib/src/views/camera/share_image_editor/data/layer.dart similarity index 95% rename from lib/src/views/camera/image_editor/data/layer.dart rename to lib/src/views/camera/share_image_editor/data/layer.dart index b8e8622..04b5e34 100755 --- a/lib/src/views/camera/image_editor/data/layer.dart +++ b/lib/src/views/camera/share_image_editor/data/layer.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:hand_signature/signature.dart'; -import 'package:twonly/src/views/camera/image_editor/data/image_item.dart'; +import 'package:twonly/src/views/camera/share_image_editor/data/image_item.dart'; /// Layer class with some common properties class Layer { @@ -51,7 +51,7 @@ class EmojiLayerData extends Layer { EmojiLayerData({ required super.key, this.text = '', - this.size = 64, + this.size = 94, super.offset, super.opacity, super.rotation, diff --git a/lib/src/views/camera/image_editor/layers/background_layer.dart b/lib/src/views/camera/share_image_editor/layers/background.layer.dart similarity index 93% rename from lib/src/views/camera/image_editor/layers/background_layer.dart rename to lib/src/views/camera/share_image_editor/layers/background.layer.dart index 300ae17..e4158af 100755 --- a/lib/src/views/camera/image_editor/layers/background_layer.dart +++ b/lib/src/views/camera/share_image_editor/layers/background.layer.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:twonly/src/views/camera/image_editor/data/layer.dart'; +import 'package:twonly/src/views/camera/share_image_editor/data/layer.dart'; class BackgroundLayer extends StatefulWidget { const BackgroundLayer({ diff --git a/lib/src/views/camera/image_editor/layers/draw_layer.dart b/lib/src/views/camera/share_image_editor/layers/draw.layer.dart similarity index 79% rename from lib/src/views/camera/image_editor/layers/draw_layer.dart rename to lib/src/views/camera/share_image_editor/layers/draw.layer.dart index 4207c39..64d528e 100644 --- a/lib/src/views/camera/image_editor/layers/draw_layer.dart +++ b/lib/src/views/camera/share_image_editor/layers/draw.layer.dart @@ -1,12 +1,11 @@ import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:hand_signature/signature.dart'; -// ignore: implementation_imports -import 'package:hand_signature/src/utils.dart'; + import 'package:twonly/src/utils/misc.dart'; -import 'package:twonly/src/utils/screenshot.dart'; -import 'package:twonly/src/views/camera/image_editor/action_button.dart'; -import 'package:twonly/src/views/camera/image_editor/data/layer.dart'; +import 'package:twonly/src/views/camera/share_image_editor/action_button.dart'; +import 'package:twonly/src/views/camera/share_image_editor/data/layer.dart'; +import 'package:twonly/src/views/camera/share_image_editor/layers/draw/custom_hand_signature.dart'; class DrawLayer extends StatefulWidget { const DrawLayer({ @@ -23,8 +22,6 @@ class DrawLayer extends StatefulWidget { class _DrawLayerState extends State { Color currentColor = Colors.red; - ScreenshotController screenshotController = ScreenshotController(); - List undoList = []; bool skipNextEvent = false; bool showMagnifyingGlass = false; @@ -85,17 +82,11 @@ class _DrawLayerState extends State { fit: StackFit.expand, children: [ Positioned.fill( - child: Container( - decoration: const BoxDecoration( - color: Colors.transparent, - ), - child: Screenshot( - controller: screenshotController, - child: HandSignature( - control: widget.layerData.control, - drawer: CustomSignatureDrawer(color: currentColor, width: 7), - ), - ), + child: CustomHandSignature( + control: widget.layerData.control, + isModificationEnabled: widget.layerData.isEditing, + currentColor: currentColor, + width: 7, ), ), if (widget.layerData.isEditing && widget.layerData.showCustomButtons) @@ -211,12 +202,12 @@ class _DrawLayerState extends State { top: 50 + (185 * _sliderValue), child: MagnifyingGlass(color: currentColor), ), - if (!widget.layerData.isEditing) - Positioned.fill( - child: Container( - color: Colors.transparent, - ), - ), + // if (!widget.layerData.isEditing) + // Positioned.fill( + // child: Container( + // color: Colors.transparent, + // ), + // ), ], ); } @@ -244,33 +235,3 @@ class MagnifyingGlass extends StatelessWidget { ); } } - -class CustomSignatureDrawer extends HandSignatureDrawer { - const CustomSignatureDrawer({ - this.width = 1.0, - this.color = Colors.black, - }); - final Color color; - final double width; - - @override - void paint(Canvas canvas, Size size, List paths) { - for (final path in paths) { - var lineColor = color; - if (path.setup.args!['color'] != null) { - lineColor = path.setup.args!['color'] as Color; - } else { - path.setup.args!['color'] = color; - } - final paint = Paint() - ..color = lineColor - ..style = PaintingStyle.stroke - ..strokeCap = StrokeCap.round - ..strokeJoin = StrokeJoin.round - ..strokeWidth = width; - if (path.isFilled) { - canvas.drawPath(PathUtil.toLinePath(path.lines), paint); - } - } - } -} diff --git a/lib/src/views/camera/share_image_editor/layers/draw/custom_hand_signature.dart b/lib/src/views/camera/share_image_editor/layers/draw/custom_hand_signature.dart new file mode 100644 index 0000000..e5f0e74 --- /dev/null +++ b/lib/src/views/camera/share_image_editor/layers/draw/custom_hand_signature.dart @@ -0,0 +1,77 @@ +import 'package:flutter/material.dart'; +import 'package:hand_signature/signature.dart'; +// ignore: implementation_imports +import 'package:hand_signature/src/utils.dart'; + +class CustomHandSignature extends StatelessWidget { + const CustomHandSignature({ + required this.control, + required this.isModificationEnabled, + required this.currentColor, + required this.width, + super.key, + }); + + /// The controller that manages the creation and manipulation of signature paths. + final HandSignatureControl control; + final bool isModificationEnabled; + final Color currentColor; + final double width; + + @override + Widget build(BuildContext context) { + control.params = SignaturePaintParams( + color: currentColor, + strokeWidth: 7, + ); + + final drawer = CustomSignatureDrawer(color: currentColor, width: width); + + if (isModificationEnabled) { + return HandSignature( + control: control, + drawer: drawer, + ); + } + + return IgnorePointer( + child: ClipRRect( + child: HandSignaturePaint( + control: control, + drawer: drawer, + onSize: control.notifyDimension, + ), + ), + ); + } +} + +class CustomSignatureDrawer extends HandSignatureDrawer { + const CustomSignatureDrawer({ + this.width = 1.0, + this.color = Colors.black, + }); + final Color color; + final double width; + + @override + void paint(Canvas canvas, Size size, List paths) { + for (final path in paths) { + var lineColor = color; + if (path.setup.args!['color'] != null) { + lineColor = path.setup.args!['color'] as Color; + } else { + path.setup.args!['color'] = color; + } + final paint = Paint() + ..color = lineColor + ..style = PaintingStyle.stroke + ..strokeCap = StrokeCap.round + ..strokeJoin = StrokeJoin.round + ..strokeWidth = width; + if (path.isFilled) { + canvas.drawPath(PathUtil.toLinePath(path.lines), paint); + } + } + } +} diff --git a/lib/src/views/camera/share_image_editor/layers/emoji.layer.dart b/lib/src/views/camera/share_image_editor/layers/emoji.layer.dart new file mode 100755 index 0000000..b82c1ee --- /dev/null +++ b/lib/src/views/camera/share_image_editor/layers/emoji.layer.dart @@ -0,0 +1,248 @@ +import 'dart:ui' as ui; + +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'package:twonly/src/utils/log.dart'; +import 'package:twonly/src/views/camera/share_image_editor/action_button.dart'; +import 'package:twonly/src/views/camera/share_image_editor/data/layer.dart'; + +/// Emoji layer +class EmojiLayer extends StatefulWidget { + const EmojiLayer({ + required this.layerData, + super.key, + this.onUpdate, + }); + final EmojiLayerData layerData; + final VoidCallback? onUpdate; + + @override + State createState() => _EmojiLayerState(); +} + +class _EmojiLayerState extends State { + double initialRotation = 0; + Offset initialOffset = Offset.zero; + Offset initialFocalPoint = Offset.zero; + double initialScale = 1; + bool deleteLayer = false; + bool twoPointerWhereDown = false; + final GlobalKey outlineKey = GlobalKey(); + final GlobalKey emojiKey = GlobalKey(); + int pointers = 0; + bool display = false; + + @override + void initState() { + super.initState(); + + if (widget.layerData.offset.dy == 0) { + // Set the initial offset to the center of the screen + WidgetsBinding.instance.addPostFrameCallback((_) { + setState(() { + widget.layerData.offset = Offset( + MediaQuery.of(context).size.width / 2 - (153 / 2), + MediaQuery.of(context).size.height / 2 - (153 / 2) - 100, + ); + }); + display = true; + }); + } else { + display = true; + } + } + + @override + Widget build(BuildContext context) { + if (!display) return Container(); + if (widget.layerData.isDeleted) return Container(); + return Stack( + key: outlineKey, + children: [ + Positioned( + left: widget.layerData.offset.dx, + top: widget.layerData.offset.dy, + child: PhysicalModel( + color: Colors.transparent, + borderRadius: BorderRadius.circular(180), + clipBehavior: Clip.antiAlias, + child: Listener( + onPointerUp: (details) { + setState(() { + pointers--; + if (pointers == 0) { + twoPointerWhereDown = false; + } + if (deleteLayer) { + widget.layerData.isDeleted = true; + widget.onUpdate!(); + } + }); + }, + onPointerDown: (details) { + setState(() { + pointers++; + }); + }, + child: GestureDetector( + onScaleStart: (details) { + initialScale = widget.layerData.size; + initialRotation = widget.layerData.rotation; + initialOffset = widget.layerData.offset; + initialFocalPoint = + Offset(details.focalPoint.dx, details.focalPoint.dy); + + setState(() {}); + }, + onScaleUpdate: (details) async { + if (twoPointerWhereDown && details.pointerCount != 2) { + return; + } + final outlineBox = outlineKey.currentContext! + .findRenderObject()! as RenderBox; + + final emojiBox = + emojiKey.currentContext!.findRenderObject()! as RenderBox; + + final isAtTheBottom = + (widget.layerData.offset.dy + emojiBox.size.height / 2) > + outlineBox.size.height - 80; + final isInTheCenter = + MediaQuery.of(context).size.width / 2 - 30 < + (widget.layerData.offset.dx + + emojiBox.size.width / 2) && + MediaQuery.of(context).size.width / 2 + 20 > + (widget.layerData.offset.dx + + emojiBox.size.width / 2); + + if (isAtTheBottom && isInTheCenter) { + if (!deleteLayer) { + await HapticFeedback.heavyImpact(); + } + deleteLayer = true; + } else { + deleteLayer = false; + } + setState(() { + twoPointerWhereDown = details.pointerCount >= 2; + widget.layerData.size = initialScale * details.scale; + // print(widget.layerData.size); + widget.layerData.rotation = + initialRotation + details.rotation; + + // Update the position based on the translation + final dx = (initialOffset.dx) + + (details.focalPoint.dx - initialFocalPoint.dx); + final dy = (initialOffset.dy) + + (details.focalPoint.dy - initialFocalPoint.dy); + widget.layerData.offset = Offset(dx, dy); + }); + }, + child: Transform.rotate( + angle: widget.layerData.rotation, + key: emojiKey, + child: Container( + padding: const EdgeInsets.all(44), + color: Colors.transparent, + child: ScreenshotEmoji( + emoji: widget.layerData.text, + displaySize: widget.layerData.size, + ), + ), + ), + ), + ), + ), + ), + if (pointers > 0) + Positioned( + left: 0, + right: 0, + bottom: 20, + child: Center( + child: GestureDetector( + child: ActionButton( + FontAwesomeIcons.trashCan, + tooltipText: '', + color: deleteLayer ? Colors.red : Colors.white, + ), + ), + ), + ), + ], + ); + } +} + +// Workaround: https://github.com/twonlyapp/twonly-app/issues/349 +class ScreenshotEmoji extends StatefulWidget { + const ScreenshotEmoji({ + required this.emoji, + required this.displaySize, + super.key, + }); + final String emoji; + final double displaySize; + + @override + State createState() => _ScreenshotEmojiState(); +} + +class _ScreenshotEmojiState extends State { + final GlobalKey _boundaryKey = GlobalKey(); + ui.Image? _capturedImage; + + @override + void initState() { + super.initState(); + // Capture the emoji immediately after the first frame + WidgetsBinding.instance.addPostFrameCallback((_) => _captureEmoji()); + } + + Future _captureEmoji() async { + try { + final boundary = _boundaryKey.currentContext?.findRenderObject() + as RenderRepaintBoundary?; + if (boundary == null) return; + + final image = await boundary.toImage(pixelRatio: 4); + setState(() { + _capturedImage = image; + }); + } catch (e) { + Log.error('Error capturing emoji: $e'); + } + } + + @override + Widget build(BuildContext context) { + if (_capturedImage != null) { + return SizedBox( + width: widget.displaySize, + height: widget.displaySize, + child: RawImage( + image: _capturedImage, + fit: BoxFit.contain, + ), + ); + } + + return Stack( + children: [ + Positioned( + top: -200, // hide from the user as the size changes with the image + child: RepaintBoundary( + key: _boundaryKey, + child: Text( + widget.emoji, + style: const TextStyle(fontSize: 94), + ), + ), + ), + SizedBox(width: widget.displaySize, height: widget.displaySize), + ], + ); + } +} diff --git a/lib/src/views/camera/image_editor/layers/filter_layer.dart b/lib/src/views/camera/share_image_editor/layers/filter.layer.dart similarity index 89% rename from lib/src/views/camera/image_editor/layers/filter_layer.dart rename to lib/src/views/camera/share_image_editor/layers/filter.layer.dart index 813ea66..1648dff 100644 --- a/lib/src/views/camera/image_editor/layers/filter_layer.dart +++ b/lib/src/views/camera/share_image_editor/layers/filter.layer.dart @@ -2,10 +2,10 @@ import 'dart:async'; import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; -import 'package:twonly/src/views/camera/image_editor/data/layer.dart'; -import 'package:twonly/src/views/camera/image_editor/layers/filters/datetime_filter.dart'; -import 'package:twonly/src/views/camera/image_editor/layers/filters/image_filter.dart'; -import 'package:twonly/src/views/camera/image_editor/layers/filters/location_filter.dart'; +import 'package:twonly/src/views/camera/share_image_editor/data/layer.dart'; +import 'package:twonly/src/views/camera/share_image_editor/layers/filters/datetime_filter.dart'; +import 'package:twonly/src/views/camera/share_image_editor/layers/filters/image_filter.dart'; +import 'package:twonly/src/views/camera/share_image_editor/layers/filters/location_filter.dart'; /// Main layer class FilterLayer extends StatefulWidget { diff --git a/lib/src/views/camera/image_editor/layers/filters/datetime_filter.dart b/lib/src/views/camera/share_image_editor/layers/filters/datetime_filter.dart similarity index 89% rename from lib/src/views/camera/image_editor/layers/filters/datetime_filter.dart rename to lib/src/views/camera/share_image_editor/layers/filters/datetime_filter.dart index d85e8b7..78bae80 100644 --- a/lib/src/views/camera/image_editor/layers/filters/datetime_filter.dart +++ b/lib/src/views/camera/share_image_editor/layers/filters/datetime_filter.dart @@ -1,7 +1,7 @@ import 'package:clock/clock.dart'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; -import 'package:twonly/src/views/camera/image_editor/layers/filter_layer.dart'; +import 'package:twonly/src/views/camera/share_image_editor/layers/filter.layer.dart'; class DateTimeFilter extends StatelessWidget { const DateTimeFilter({super.key, this.color = Colors.white}); diff --git a/lib/src/views/camera/image_editor/layers/filters/image_filter.dart b/lib/src/views/camera/share_image_editor/layers/filters/image_filter.dart similarity index 87% rename from lib/src/views/camera/image_editor/layers/filters/image_filter.dart rename to lib/src/views/camera/share_image_editor/layers/filters/image_filter.dart index 25e1b90..920a9e4 100644 --- a/lib/src/views/camera/image_editor/layers/filters/image_filter.dart +++ b/lib/src/views/camera/share_image_editor/layers/filters/image_filter.dart @@ -1,6 +1,6 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; -import 'package:twonly/src/views/camera/image_editor/layers/filter_layer.dart'; +import 'package:twonly/src/views/camera/share_image_editor/layers/filter.layer.dart'; class ImageFilter extends StatelessWidget { const ImageFilter({required this.imagePath, super.key}); diff --git a/lib/src/views/camera/image_editor/layers/filters/location_filter.dart b/lib/src/views/camera/share_image_editor/layers/filters/location_filter.dart similarity index 96% rename from lib/src/views/camera/image_editor/layers/filters/location_filter.dart rename to lib/src/views/camera/share_image_editor/layers/filters/location_filter.dart index fa38367..d2d36fa 100644 --- a/lib/src/views/camera/image_editor/layers/filters/location_filter.dart +++ b/lib/src/views/camera/share_image_editor/layers/filters/location_filter.dart @@ -11,8 +11,8 @@ import 'package:path_provider/path_provider.dart'; import 'package:twonly/globals.dart'; import 'package:twonly/src/model/protobuf/api/websocket/server_to_client.pb.dart'; import 'package:twonly/src/utils/log.dart'; -import 'package:twonly/src/views/camera/image_editor/layers/filter_layer.dart'; -import 'package:twonly/src/views/camera/image_editor/layers/filters/datetime_filter.dart'; +import 'package:twonly/src/views/camera/share_image_editor/layers/filter.layer.dart'; +import 'package:twonly/src/views/camera/share_image_editor/layers/filters/datetime_filter.dart'; class LocationFilter extends StatefulWidget { const LocationFilter({super.key}); diff --git a/lib/src/views/camera/image_editor/layers/text_layer.dart b/lib/src/views/camera/share_image_editor/layers/text.layer.dart similarity index 98% rename from lib/src/views/camera/image_editor/layers/text_layer.dart rename to lib/src/views/camera/share_image_editor/layers/text.layer.dart index 5e9627f..3e1da6a 100755 --- a/lib/src/views/camera/image_editor/layers/text_layer.dart +++ b/lib/src/views/camera/share_image_editor/layers/text.layer.dart @@ -5,8 +5,8 @@ import 'package:flutter/services.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:provider/provider.dart'; import 'package:twonly/src/providers/image_editor.provider.dart'; -import 'package:twonly/src/views/camera/image_editor/action_button.dart'; -import 'package:twonly/src/views/camera/image_editor/data/layer.dart'; +import 'package:twonly/src/views/camera/share_image_editor/action_button.dart'; +import 'package:twonly/src/views/camera/share_image_editor/data/layer.dart'; /// Text layer class TextLayer extends StatefulWidget { diff --git a/lib/src/views/camera/image_editor/layers_viewer.dart b/lib/src/views/camera/share_image_editor/layers_viewer.dart similarity index 62% rename from lib/src/views/camera/image_editor/layers_viewer.dart rename to lib/src/views/camera/share_image_editor/layers_viewer.dart index 11312d1..2cb51e7 100644 --- a/lib/src/views/camera/image_editor/layers_viewer.dart +++ b/lib/src/views/camera/share_image_editor/layers_viewer.dart @@ -1,10 +1,10 @@ import 'package:flutter/material.dart'; -import 'package:twonly/src/views/camera/image_editor/data/layer.dart'; -import 'package:twonly/src/views/camera/image_editor/layers/background_layer.dart'; -import 'package:twonly/src/views/camera/image_editor/layers/draw_layer.dart'; -import 'package:twonly/src/views/camera/image_editor/layers/emoji_layer.dart'; -import 'package:twonly/src/views/camera/image_editor/layers/filter_layer.dart'; -import 'package:twonly/src/views/camera/image_editor/layers/text_layer.dart'; +import 'package:twonly/src/views/camera/share_image_editor/data/layer.dart'; +import 'package:twonly/src/views/camera/share_image_editor/layers/background.layer.dart'; +import 'package:twonly/src/views/camera/share_image_editor/layers/draw.layer.dart'; +import 'package:twonly/src/views/camera/share_image_editor/layers/emoji.layer.dart'; +import 'package:twonly/src/views/camera/share_image_editor/layers/filter.layer.dart'; +import 'package:twonly/src/views/camera/share_image_editor/layers/text.layer.dart'; /// View stacked layers (unbounded height, width) class LayersViewer extends StatelessWidget { @@ -37,7 +37,9 @@ class LayersViewer extends StatelessWidget { ...layers .where( (layerItem) => - layerItem is EmojiLayerData || layerItem is DrawLayerData, + layerItem is EmojiLayerData || + layerItem is DrawLayerData || + layerItem is TextLayerData, ) .map((layerItem) { if (layerItem is EmojiLayerData) { @@ -52,16 +54,15 @@ class LayersViewer extends StatelessWidget { layerData: layerItem, onUpdate: onUpdate, ); + } else if (layerItem is TextLayerData) { + return TextLayer( + key: layerItem.key, + layerData: layerItem, + onUpdate: onUpdate, + ); } return Container(); }), - ...layers.whereType().map((layerItem) { - return TextLayer( - key: layerItem.key, - layerData: layerItem, - onUpdate: onUpdate, - ); - }), ], ); } diff --git a/lib/src/views/chats/chat_list_components/group_list_item.dart b/lib/src/views/chats/chat_list_components/group_list_item.dart index a87e7d8..7a6cbbb 100644 --- a/lib/src/views/chats/chat_list_components/group_list_item.dart +++ b/lib/src/views/chats/chat_list_components/group_list_item.dart @@ -9,7 +9,7 @@ import 'package:twonly/src/database/tables/messages.table.dart'; import 'package:twonly/src/database/twonly.db.dart'; import 'package:twonly/src/services/api/mediafiles/download.service.dart'; import 'package:twonly/src/utils/misc.dart'; -import 'package:twonly/src/views/camera/camera_send_to_view.dart'; +import 'package:twonly/src/views/camera/camera_send_to.view.dart'; import 'package:twonly/src/views/chats/chat_list_components/last_message_time.dart'; import 'package:twonly/src/views/chats/chat_messages.view.dart'; import 'package:twonly/src/views/chats/chat_messages_components/message_send_state_icon.dart'; diff --git a/lib/src/views/chats/chat_messages_components/message_context_menu.dart b/lib/src/views/chats/chat_messages_components/message_context_menu.dart index 62a9456..210c6ba 100644 --- a/lib/src/views/chats/chat_messages_components/message_context_menu.dart +++ b/lib/src/views/chats/chat_messages_components/message_context_menu.dart @@ -14,8 +14,8 @@ import 'package:twonly/src/model/protobuf/client/generated/messages.pbserver.dar import 'package:twonly/src/services/api/messages.dart'; import 'package:twonly/src/services/mediafiles/mediafile.service.dart'; import 'package:twonly/src/utils/misc.dart'; -import 'package:twonly/src/views/camera/image_editor/data/layer.dart'; -import 'package:twonly/src/views/camera/image_editor/modules/all_emojis.dart'; +import 'package:twonly/src/views/camera/share_image_editor/data/layer.dart'; +import 'package:twonly/src/views/components/emoji_picker.bottom.dart'; import 'package:twonly/src/views/chats/message_info.view.dart'; import 'package:twonly/src/views/components/alert_dialog.dart'; import 'package:twonly/src/views/components/context_menu.component.dart'; diff --git a/lib/src/views/chats/chat_messages_components/message_input.dart b/lib/src/views/chats/chat_messages_components/message_input.dart index 24d252a..6c195c7 100644 --- a/lib/src/views/chats/chat_messages_components/message_input.dart +++ b/lib/src/views/chats/chat_messages_components/message_input.dart @@ -14,7 +14,7 @@ import 'package:twonly/src/database/twonly.db.dart'; import 'package:twonly/src/services/api/mediafiles/upload.service.dart'; import 'package:twonly/src/services/api/messages.dart'; import 'package:twonly/src/utils/misc.dart'; -import 'package:twonly/src/views/camera/camera_send_to_view.dart'; +import 'package:twonly/src/views/camera/camera_send_to.view.dart'; import 'package:twonly/src/views/chats/chat_messages_components/entries/chat_audio_entry.dart'; class MessageInput extends StatefulWidget { diff --git a/lib/src/views/chats/chat_messages_components/message_send_state_icon.dart b/lib/src/views/chats/chat_messages_components/message_send_state_icon.dart index 95485ba..a2cec19 100644 --- a/lib/src/views/chats/chat_messages_components/message_send_state_icon.dart +++ b/lib/src/views/chats/chat_messages_components/message_send_state_icon.dart @@ -112,7 +112,7 @@ class _MessageSendStateIconState extends State { case MessageSendState.receivedOpened: icon = Icon(Icons.crop_square, size: 14, color: color); if (message.content != null) { - if (isEmoji(message.content!)) { + if (isOneEmoji(message.content!)) { icon = Text( message.content!, style: const TextStyle(fontSize: 12), diff --git a/lib/src/views/chats/media_viewer.view.dart b/lib/src/views/chats/media_viewer.view.dart index 9544731..7760c61 100644 --- a/lib/src/views/chats/media_viewer.view.dart +++ b/lib/src/views/chats/media_viewer.view.dart @@ -20,7 +20,7 @@ import 'package:twonly/src/services/mediafiles/mediafile.service.dart'; import 'package:twonly/src/services/notifications/background.notifications.dart'; import 'package:twonly/src/utils/log.dart'; import 'package:twonly/src/utils/misc.dart'; -import 'package:twonly/src/views/camera/camera_send_to_view.dart'; +import 'package:twonly/src/views/camera/camera_send_to.view.dart'; import 'package:twonly/src/views/chats/media_viewer_components/reaction_buttons.component.dart'; import 'package:twonly/src/views/components/animate_icon.dart'; import 'package:twonly/src/views/components/loader.dart'; diff --git a/lib/src/views/chats/media_viewer_components/reaction_buttons.component.dart b/lib/src/views/chats/media_viewer_components/reaction_buttons.component.dart index 5da9f3d..827c954 100644 --- a/lib/src/views/chats/media_viewer_components/reaction_buttons.component.dart +++ b/lib/src/views/chats/media_viewer_components/reaction_buttons.component.dart @@ -5,8 +5,8 @@ import 'package:flutter/scheduler.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:twonly/globals.dart'; import 'package:twonly/src/utils/misc.dart'; -import 'package:twonly/src/views/camera/image_editor/data/layer.dart'; -import 'package:twonly/src/views/camera/image_editor/modules/all_emojis.dart'; +import 'package:twonly/src/views/camera/share_image_editor/data/layer.dart'; +import 'package:twonly/src/views/components/emoji_picker.bottom.dart'; import 'package:twonly/src/views/chats/media_viewer_components/emoji_reactions_row.component.dart'; import 'package:twonly/src/views/components/animate_icon.dart'; diff --git a/lib/src/views/components/animate_icon.dart b/lib/src/views/components/animate_icon.dart index 28f6462..eb77cd9 100644 --- a/lib/src/views/components/animate_icon.dart +++ b/lib/src/views/components/animate_icon.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:lottie/lottie.dart'; -import 'package:twonly/src/views/camera/image_editor/data/data.dart'; // animations from: https://googlefonts.github.io/noto-emoji-animation/ // from https://github.com/eitanliu/emoji_regex/tree/master @@ -9,11 +8,8 @@ RegExp emojiRegex() => RegExp( r'[#*0-9]\uFE0F?\u20E3|[\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23ED-\u23EF\u23F1\u23F2\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB\u25FC\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u2648-\u2653\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u267F\u2692\u2694-\u2697\u2699\u269B\u269C\u26A0\u26A7\u26AA\u26B0\u26B1\u26BD\u26BE\u26C4\u26C8\u26CF\u26D1\u26D3\u26E9\u26F0-\u26F5\u26F7\u26F8\u26FA\u2702\u2708\u2709\u270F\u2712\u2714\u2716\u271D\u2721\u2733\u2734\u2744\u2747\u2757\u2763\u27A1\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B55\u3030\u303D\u3297\u3299]\uFE0F?|[\u261D\u270C\u270D](?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?|[\u270A\u270B](?:\uD83C[\uDFFB-\uDFFF])?|[\u23E9-\u23EC\u23F0\u23F3\u25FD\u2693\u26A1\u26AB\u26C5\u26CE\u26D4\u26EA\u26FD\u2705\u2728\u274C\u274E\u2753-\u2755\u2795-\u2797\u27B0\u27BF\u2B50]|\u26F9(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|\u2764\uFE0F?(?:\u200D(?:\uD83D\uDD25|\uD83E\uDE79))?|\uD83C(?:[\uDC04\uDD70\uDD71\uDD7E\uDD7F\uDE02\uDE37\uDF21\uDF24-\uDF2C\uDF36\uDF7D\uDF96\uDF97\uDF99-\uDF9B\uDF9E\uDF9F\uDFCD\uDFCE\uDFD4-\uDFDF\uDFF5\uDFF7]\uFE0F?|[\uDF85\uDFC2\uDFC7](?:\uD83C[\uDFFB-\uDFFF])?|[\uDFC3\uDFC4\uDFCA](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDFCB\uDFCC](?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDCCF\uDD8E\uDD91-\uDD9A\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF84\uDF86-\uDF93\uDFA0-\uDFC1\uDFC5\uDFC6\uDFC8\uDFC9\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF8-\uDFFF]|\uDDE6\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF]|\uDDE7\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF]|\uDDE8\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF5\uDDF7\uDDFA-\uDDFF]|\uDDE9\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF]|\uDDEA\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA]|\uDDEB\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7]|\uDDEC\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE]|\uDDED\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA]|\uDDEE\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9]|\uDDEF\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5]|\uDDF0\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF]|\uDDF1\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE]|\uDDF2\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF]|\uDDF3\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF]|\uDDF4\uD83C\uDDF2|\uDDF5\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE]|\uDDF6\uD83C\uDDE6|\uDDF7\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC]|\uDDF8\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF]|\uDDF9\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF]|\uDDFA\uD83C[\uDDE6\uDDEC\uDDF2\uDDF3\uDDF8\uDDFE\uDDFF]|\uDDFB\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA]|\uDDFC\uD83C[\uDDEB\uDDF8]|\uDDFD\uD83C\uDDF0|\uDDFE\uD83C[\uDDEA\uDDF9]|\uDDFF\uD83C[\uDDE6\uDDF2\uDDFC]|\uDFF3\uFE0F?(?:\u200D(?:\u26A7\uFE0F?|\uD83C\uDF08))?|\uDFF4(?:\u200D\u2620\uFE0F?|\uDB40\uDC67\uDB40\uDC62\uDB40(?:\uDC65\uDB40\uDC6E\uDB40\uDC67|\uDC73\uDB40\uDC63\uDB40\uDC74|\uDC77\uDB40\uDC6C\uDB40\uDC73)\uDB40\uDC7F)?)|\uD83D(?:[\uDC08\uDC26](?:\u200D\u2B1B)?|[\uDC3F\uDCFD\uDD49\uDD4A\uDD6F\uDD70\uDD73\uDD76-\uDD79\uDD87\uDD8A-\uDD8D\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA\uDECB\uDECD-\uDECF\uDEE0-\uDEE5\uDEE9\uDEF0\uDEF3]\uFE0F?|[\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDC8F\uDC91\uDCAA\uDD7A\uDD95\uDD96\uDE4C\uDE4F\uDEC0\uDECC](?:\uD83C[\uDFFB-\uDFFF])?|[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDD74\uDD90](?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?|[\uDC00-\uDC07\uDC09-\uDC14\uDC16-\uDC25\uDC27-\uDC3A\uDC3C-\uDC3E\uDC40\uDC44\uDC45\uDC51-\uDC65\uDC6A\uDC79-\uDC7B\uDC7D-\uDC80\uDC84\uDC88-\uDC8E\uDC90\uDC92-\uDCA9\uDCAB-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDDA4\uDDFB-\uDE2D\uDE2F-\uDE34\uDE37-\uDE44\uDE48-\uDE4A\uDE80-\uDEA2\uDEA4-\uDEB3\uDEB7-\uDEBF\uDEC1-\uDEC5\uDED0-\uDED2\uDED5-\uDED7\uDEDC-\uDEDF\uDEEB\uDEEC\uDEF4-\uDEFC\uDFE0-\uDFEB\uDFF0]|\uDC15(?:\u200D\uD83E\uDDBA)?|\uDC3B(?:\u200D\u2744\uFE0F?)?|\uDC41\uFE0F?(?:\u200D\uD83D\uDDE8\uFE0F?)?|\uDC68(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDC68\uDC69]\u200D\uD83D(?:\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?)|[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?)|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFC-\uDFFF])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB\uDFFD-\uDFFF])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB-\uDFFD\uDFFF])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB-\uDFFE])))?))?|\uDC69(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?[\uDC68\uDC69]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?|\uDC69\u200D\uD83D(?:\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?))|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFC-\uDFFF])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB\uDFFD-\uDFFF])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFD\uDFFF])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFE])))?))?|\uDC6F(?:\u200D[\u2640\u2642]\uFE0F?)?|\uDD75(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|\uDE2E(?:\u200D\uD83D\uDCA8)?|\uDE35(?:\u200D\uD83D\uDCAB)?|\uDE36(?:\u200D\uD83C\uDF2B\uFE0F?)?)|\uD83E(?:[\uDD0C\uDD0F\uDD18-\uDD1F\uDD30-\uDD34\uDD36\uDD77\uDDB5\uDDB6\uDDBB\uDDD2\uDDD3\uDDD5\uDEC3-\uDEC5\uDEF0\uDEF2-\uDEF8](?:\uD83C[\uDFFB-\uDFFF])?|[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDDDE\uDDDF](?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDD0D\uDD0E\uDD10-\uDD17\uDD20-\uDD25\uDD27-\uDD2F\uDD3A\uDD3F-\uDD45\uDD47-\uDD76\uDD78-\uDDB4\uDDB7\uDDBA\uDDBC-\uDDCC\uDDD0\uDDE0-\uDDFF\uDE70-\uDE7C\uDE80-\uDE88\uDE90-\uDEBD\uDEBF-\uDEC2\uDECE-\uDEDB\uDEE0-\uDEE8]|\uDD3C(?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF])?|\uDDD1(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1))|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFC-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB\uDFFD-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB-\uDFFD\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB-\uDFFE]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?))?|\uDEF1(?:\uD83C(?:\uDFFB(?:\u200D\uD83E\uDEF2\uD83C[\uDFFC-\uDFFF])?|\uDFFC(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB\uDFFD-\uDFFF])?|\uDFFD(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])?|\uDFFE(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB-\uDFFD\uDFFF])?|\uDFFF(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB-\uDFFE])?))?)', ); -bool isEmoji(String character) { +bool isOneEmoji(String character) { final matches = emojiRegex().allMatches(character); - if (emojis.contains(character)) { - return true; - } if (matches.length == 1) { final match = matches.first; return match.start == 0 && match.end == character.length; @@ -226,7 +222,7 @@ class EmojiAnimation extends StatelessWidget { static bool supported(String emoji) { if (emoji.length > 4) return false; - return animatedIcons.containsKey(emoji) || isEmoji(emoji); + return animatedIcons.containsKey(emoji) || isOneEmoji(emoji); } @override @@ -239,7 +235,7 @@ class EmojiAnimation extends StatelessWidget { 'assets/animated_icons/${animatedIcons[emoji]}', repeat: repeat, ); - } else if (isEmoji(emoji)) { + } else if (isOneEmoji(emoji)) { return Text( emoji, style: const TextStyle(fontSize: 60), diff --git a/lib/src/views/camera/image_editor/modules/all_emojis.dart b/lib/src/views/components/emoji_picker.bottom.dart similarity index 97% rename from lib/src/views/camera/image_editor/modules/all_emojis.dart rename to lib/src/views/components/emoji_picker.bottom.dart index a19d30d..cbca1a4 100755 --- a/lib/src/views/camera/image_editor/modules/all_emojis.dart +++ b/lib/src/views/components/emoji_picker.bottom.dart @@ -2,7 +2,7 @@ import 'dart:io'; import 'package:emoji_picker_flutter/emoji_picker_flutter.dart'; import 'package:flutter/material.dart'; import 'package:twonly/src/utils/misc.dart'; -import 'package:twonly/src/views/camera/image_editor/data/layer.dart'; +import 'package:twonly/src/views/camera/share_image_editor/data/layer.dart'; class EmojiPickerBottom extends StatelessWidget { const EmojiPickerBottom({super.key}); diff --git a/lib/src/views/home.view.dart b/lib/src/views/home.view.dart index b19210c..16018e1 100644 --- a/lib/src/views/home.view.dart +++ b/lib/src/views/home.view.dart @@ -14,7 +14,7 @@ import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/views/camera/camera_preview_components/camera_preview.dart'; import 'package:twonly/src/views/camera/camera_preview_components/camera_preview_controller_view.dart'; import 'package:twonly/src/views/camera/camera_preview_components/main_camera_controller.dart'; -import 'package:twonly/src/views/camera/share_image_editor_view.dart'; +import 'package:twonly/src/views/camera/share_image_editor.view.dart'; import 'package:twonly/src/views/chats/chat_list.view.dart'; import 'package:twonly/src/views/memories/memories.view.dart'; diff --git a/lib/src/views/memories/memories_photo_slider.view.dart b/lib/src/views/memories/memories_photo_slider.view.dart index b0cfaf5..2b1c9b4 100644 --- a/lib/src/views/memories/memories_photo_slider.view.dart +++ b/lib/src/views/memories/memories_photo_slider.view.dart @@ -9,7 +9,7 @@ import 'package:twonly/src/services/api/mediafiles/upload.service.dart'; import 'package:twonly/src/utils/log.dart'; import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/views/camera/camera_preview_components/save_to_gallery.dart'; -import 'package:twonly/src/views/camera/share_image_editor_view.dart'; +import 'package:twonly/src/views/camera/share_image_editor.view.dart'; import 'package:twonly/src/views/components/alert_dialog.dart'; import 'package:twonly/src/views/components/media_view_sizing.dart'; import 'package:twonly/src/views/components/video_player_wrapper.dart'; diff --git a/lib/src/views/settings/help/credits.view.dart b/lib/src/views/settings/help/credits.view.dart index ca50aa8..4a3cfaa 100644 --- a/lib/src/views/settings/help/credits.view.dart +++ b/lib/src/views/settings/help/credits.view.dart @@ -4,7 +4,7 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:twonly/src/utils/misc.dart'; -import 'package:twonly/src/views/camera/image_editor/layers/filters/location_filter.dart'; +import 'package:twonly/src/views/camera/share_image_editor/layers/filters/location_filter.dart'; import 'package:url_launcher/url_launcher.dart'; class UrlListTitle extends StatelessWidget { diff --git a/test/unit_test.dart b/test/unit_test.dart index c8eb739..80a4db4 100644 --- a/test/unit_test.dart +++ b/test/unit_test.dart @@ -8,10 +8,10 @@ import 'package:twonly/src/views/components/animate_icon.dart'; void main() { group('testing utils', () { test('test isEmoji function', () { - expect(isEmoji('Hallo'), false); - expect(isEmoji('๐Ÿ˜‚'), true); - expect(isEmoji('๐Ÿ˜‚๐Ÿ˜‚'), false); - expect(isEmoji('Hallo ๐Ÿ˜‚'), false); + expect(isOneEmoji('Hallo'), false); + expect(isOneEmoji('๐Ÿ˜‚'), true); + expect(isOneEmoji('๐Ÿ˜‚๐Ÿ˜‚'), false); + expect(isOneEmoji('Hallo ๐Ÿ˜‚'), false); }); test('test proof-of-work simple', () async {