├── .flutter-plugins
├── .flutter-plugins-dependencies
├── .gitignore
├── .metadata
├── CHANGELOG.md
├── LICENSE
├── README.md
├── analysis_options.yaml
├── assets
├── emojies
│ ├── e1511.png
│ ├── e1512.png
│ ├── e1513.png
│ ├── e1514.png
│ ├── e1515.png
│ ├── e1516.png
│ ├── e1517.png
│ ├── e1518.png
│ ├── e1519.png
│ ├── e1520.png
│ ├── e1521.png
│ ├── e1522.png
│ ├── e1523.png
│ ├── e1524.png
│ ├── e1525.png
│ ├── e1526.png
│ ├── e1527.png
│ ├── e1528.png
│ ├── e1529.png
│ ├── e1530.png
│ ├── e1531.png
│ ├── e1532.png
│ ├── e1533.png
│ ├── e1534.png
│ ├── e1535.png
│ ├── e1536.png
│ ├── e1537.png
│ ├── e1538.png
│ ├── e1539.png
│ ├── e1540.png
│ ├── e1541.png
│ ├── e1542.png
│ ├── e1543.png
│ ├── e1544.png
│ ├── e1545.png
│ ├── e1546.png
│ ├── e1547.png
│ ├── e1548.png
│ ├── e1549.png
│ ├── e1550.png
│ ├── e1551.png
│ ├── e1552.png
│ ├── e1553.png
│ ├── e1554.png
│ ├── e1555.png
│ ├── e1556.png
│ ├── e1557.png
│ ├── e1558.png
│ ├── e1559.png
│ ├── e1560.png
│ ├── e1561.png
│ ├── e1562.png
│ ├── e1563.png
│ ├── e1564.png
│ ├── e1565.png
│ ├── e1566.png
│ ├── e1567.png
│ ├── e1568.png
│ ├── e1569.png
│ ├── e1570.png
│ ├── e1571.png
│ ├── e1572.png
│ ├── e1573.png
│ ├── e1574.png
│ ├── e1575.png
│ ├── e1576.png
│ ├── e1577.png
│ ├── e1578.png
│ ├── e1579.png
│ ├── e1580.png
│ ├── e1581.png
│ ├── e1582.png
│ ├── e1583.png
│ ├── e1584.png
│ ├── e1585.png
│ ├── e1586.png
│ ├── e1587.png
│ ├── e1588.png
│ ├── e1589.png
│ ├── e1590.png
│ ├── e1591.png
│ ├── e1592.png
│ ├── e1593.png
│ ├── e1594.png
│ ├── e1595.png
│ ├── e1596.png
│ ├── e1597.png
│ ├── e1598.png
│ ├── e1599.png
│ ├── e1600.png
│ ├── e1601.png
│ ├── e1602.png
│ ├── e1603.png
│ ├── e1604.png
│ ├── e1605.png
│ ├── e1606.png
│ ├── e1607.png
│ ├── e1608.png
│ ├── e1609.png
│ ├── e1610.png
│ ├── e1611.png
│ ├── e1612.png
│ ├── e1613.png
│ ├── e1614.png
│ ├── e1615.png
│ ├── e1616.png
│ ├── e1617.png
│ ├── e1618.png
│ ├── e1619.png
│ ├── e1620.png
│ ├── e1621.png
│ ├── e1622.png
│ ├── e1623.png
│ ├── e1624.png
│ ├── e1625.png
│ ├── e1626.png
│ ├── e1627.png
│ ├── e1628.png
│ ├── e1629.png
│ ├── e1630.png
│ ├── e1631.png
│ ├── e1632.png
│ ├── e1633.png
│ ├── e1634.png
│ ├── e1635.png
│ ├── e1636.png
│ ├── e1637.png
│ ├── e1638.png
│ ├── e1639.png
│ ├── e1640.png
│ ├── e1641.png
│ ├── e1642.png
│ ├── e1643.png
│ ├── e1644.png
│ ├── e1645.png
│ ├── e1646.png
│ ├── e1647.png
│ ├── e1648.png
│ ├── e1649.png
│ ├── e1650.png
│ ├── e1651.png
│ ├── e1652.png
│ ├── e1653.png
│ ├── e1654.png
│ ├── e1655.png
│ ├── e1656.png
│ ├── e1657.png
│ ├── e1658.png
│ ├── e1659.png
│ ├── e1660.png
│ ├── e1661.png
│ ├── e1662.png
│ ├── e1663.png
│ ├── e1664.png
│ ├── e1665.png
│ ├── e1666.png
│ ├── e1757.png
│ ├── e1758.png
│ ├── e1759.png
│ ├── e1760.png
│ ├── e1761.png
│ ├── e1762.png
│ ├── e1763.png
│ ├── e1764.png
│ ├── e1765.png
│ ├── e1766.png
│ ├── e1767.png
│ ├── e1768.png
│ ├── e1769.png
│ ├── e1779.png
│ ├── e1780.png
│ ├── e1781.png
│ ├── e1782.png
│ ├── e1783.png
│ ├── e1784.png
│ ├── e1785.png
│ ├── e1791.png
│ ├── e1792.png
│ ├── e1793.png
│ ├── e1794.png
│ ├── e1795.png
│ ├── e1796.png
│ ├── e1799.png
│ ├── e1819.png
│ ├── e1820.png
│ ├── e1821.png
│ ├── e1822.png
│ ├── e1823.png
│ └── e1824.png
├── fonts
│ ├── angkor
│ │ └── Angkor-Regular.ttf
│ ├── dancing_script
│ │ ├── DancingScript-Medium.ttf
│ │ └── DancingScript-Regular.ttf
│ ├── lato
│ │ └── Lato-Regular.ttf
│ ├── lora
│ │ ├── Lora-Medium.ttf
│ │ └── Lora-Regular.ttf
│ ├── madimiOne
│ │ └── MadimiOne-Regular.ttf
│ ├── merriweather
│ │ └── Merriweather-Regular.ttf
│ ├── montserrat
│ │ ├── Montserrat-Medium.ttf
│ │ └── Montserrat-Regular.ttf
│ ├── oswald
│ │ ├── Oswald-Medium.ttf
│ │ └── Oswald-Regular.ttf
│ ├── pacifico
│ │ └── Pacifico-Regular.ttf
│ ├── raleway
│ │ ├── Raleway-Medium.ttf
│ │ └── Raleway-Regular.ttf
│ └── roboto
│ │ ├── Roboto-Medium.ttf
│ │ └── Roboto-Regular.ttf
└── images
│ ├── 01_Cuppy_smile.webp
│ ├── 02_Cuppy_lol.webp
│ ├── 03_Cuppy_rofl.webp
│ ├── 04_Cuppy_sad.webp
│ ├── 05_Cuppy_cry.webp
│ ├── 06_Cuppy_love.webp
│ ├── 07_Cuppy_hate.webp
│ ├── 08_Cuppy_lovewithmug.webp
│ ├── 09_Cuppy_lovewithcookie.webp
│ ├── 10_Cuppy_hmm.webp
│ ├── 11_Cuppy_upset.webp
│ ├── 12_Cuppy_angry.webp
│ ├── 13_Cuppy_curious.webp
│ ├── 14_Cuppy_weird.webp
│ ├── 15_Cuppy_bluescreen.webp
│ ├── 16_Cuppy_angry.webp
│ ├── 17_Cuppy_tired.webp
│ ├── 18_Cuppy_workhard.webp
│ ├── 19_Cuppy_shine.webp
│ ├── 20_Cuppy_disgusting.webp
│ ├── 21_Cuppy_hi.webp
│ ├── 22_Cuppy_bye.webp
│ ├── 23_Cuppy_greentea.webp
│ ├── 24_Cuppy_phone.webp
│ ├── 25_Cuppy_battery.webp
│ └── tray_Cuppy.png
├── example
└── example.dart
├── lib
├── flutter_story_editor.dart
├── generated
│ └── assets.dart
└── src
│ ├── const
│ ├── const.dart
│ └── filters.dart
│ ├── controller
│ └── controller.dart
│ ├── enums
│ ├── story_editing_modes.dart
│ └── stroke_type.dart
│ ├── models
│ ├── simple_sketecher.dart
│ ├── stroke.dart
│ └── stroke_options.dart
│ ├── theme
│ └── style.dart
│ ├── utils
│ ├── matrix_gesture_detector.dart
│ └── utils.dart
│ ├── views
│ ├── main_control_views
│ │ ├── caption_view.dart
│ │ ├── filter_text_view.dart
│ │ ├── filters_view.dart
│ │ ├── image_view.dart
│ │ ├── main_controls_view.dart
│ │ ├── thumbnail_view.dart
│ │ ├── top_view.dart
│ │ └── trimmer_view.dart
│ ├── paint_control_views
│ │ ├── paint_controls_view.dart
│ │ └── paint_top_view.dart
│ ├── sticker_control_views
│ │ ├── sticker_control_view.dart
│ │ └── sticker_top_view.dart
│ └── text_control_views
│ │ ├── text_control_view.dart
│ │ └── text_top_view.dart
│ └── widgets
│ ├── draggable_sticker_widget.dart
│ ├── draggable_text_widget.dart
│ └── hue_color_picker_slider.dart
├── pubspec.yaml
├── screenshots
├── CropAndPaint.gif
├── Text.gif
├── VideoEditing.gif
├── image_1.png
├── image_10.png
├── image_11.png
├── image_12.png
├── image_2.png
├── image_3.png
├── image_4.png
├── image_5.png
├── image_6.png
├── image_7.png
└── image_8.png
└── test
└── flutter_story_editor_test.dart
/.flutter-plugins:
--------------------------------------------------------------------------------
1 | # This is a generated file; do not edit or check into version control.
2 | ffmpeg_kit_flutter=/Users/amirkhan/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-6.0.3/
3 | file_picker=/Users/amirkhan/.pub-cache/hosted/pub.dev/file_picker-8.0.1/
4 | flutter_keyboard_visibility=/Users/amirkhan/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility-6.0.0/
5 | flutter_keyboard_visibility_linux=/Users/amirkhan/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility_linux-1.0.0/
6 | flutter_keyboard_visibility_macos=/Users/amirkhan/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility_macos-1.0.0/
7 | flutter_keyboard_visibility_web=/Users/amirkhan/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility_web-2.0.0/
8 | flutter_keyboard_visibility_windows=/Users/amirkhan/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility_windows-1.0.0/
9 | flutter_plugin_android_lifecycle=/Users/amirkhan/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.19/
10 | image_cropper=/Users/amirkhan/.pub-cache/hosted/pub.dev/image_cropper-5.0.1/
11 | image_cropper_for_web=/Users/amirkhan/.pub-cache/hosted/pub.dev/image_cropper_for_web-3.0.0/
12 | path_provider=/Users/amirkhan/.pub-cache/hosted/pub.dev/path_provider-2.1.3/
13 | path_provider_android=/Users/amirkhan/.pub-cache/hosted/pub.dev/path_provider_android-2.2.4/
14 | path_provider_foundation=/Users/amirkhan/.pub-cache/hosted/pub.dev/path_provider_foundation-2.3.2/
15 | path_provider_linux=/Users/amirkhan/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/
16 | path_provider_windows=/Users/amirkhan/.pub-cache/hosted/pub.dev/path_provider_windows-2.2.1/
17 | video_player=/Users/amirkhan/.pub-cache/hosted/pub.dev/video_player-2.8.6/
18 | video_player_android=/Users/amirkhan/.pub-cache/hosted/pub.dev/video_player_android-2.4.14/
19 | video_player_avfoundation=/Users/amirkhan/.pub-cache/hosted/pub.dev/video_player_avfoundation-2.5.7/
20 | video_player_web=/Users/amirkhan/.pub-cache/hosted/pub.dev/video_player_web-2.3.0/
21 | video_thumbnail=/Users/amirkhan/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/
22 |
--------------------------------------------------------------------------------
/.flutter-plugins-dependencies:
--------------------------------------------------------------------------------
1 | {"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"ffmpeg_kit_flutter","path":"/Users/amirkhan/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-6.0.3/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/amirkhan/.pub-cache/hosted/pub.dev/file_picker-8.0.1/","native_build":true,"dependencies":[]},{"name":"flutter_keyboard_visibility","path":"/Users/amirkhan/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility-6.0.0/","native_build":true,"dependencies":[]},{"name":"image_cropper","path":"/Users/amirkhan/.pub-cache/hosted/pub.dev/image_cropper-5.0.1/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/Users/amirkhan/.pub-cache/hosted/pub.dev/path_provider_foundation-2.3.2/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Users/amirkhan/.pub-cache/hosted/pub.dev/video_player_avfoundation-2.5.7/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/amirkhan/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]}],"android":[{"name":"ffmpeg_kit_flutter","path":"/Users/amirkhan/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-6.0.3/","native_build":true,"dependencies":[]},{"name":"file_picker","path":"/Users/amirkhan/.pub-cache/hosted/pub.dev/file_picker-8.0.1/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_keyboard_visibility","path":"/Users/amirkhan/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility-6.0.0/","native_build":true,"dependencies":[]},{"name":"flutter_plugin_android_lifecycle","path":"/Users/amirkhan/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.19/","native_build":true,"dependencies":[]},{"name":"image_cropper","path":"/Users/amirkhan/.pub-cache/hosted/pub.dev/image_cropper-5.0.1/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Users/amirkhan/.pub-cache/hosted/pub.dev/path_provider_android-2.2.4/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Users/amirkhan/.pub-cache/hosted/pub.dev/video_player_android-2.4.14/","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"/Users/amirkhan/.pub-cache/hosted/pub.dev/video_thumbnail-0.5.3/","native_build":true,"dependencies":[]}],"macos":[{"name":"ffmpeg_kit_flutter","path":"/Users/amirkhan/.pub-cache/hosted/pub.dev/ffmpeg_kit_flutter-6.0.3/","native_build":true,"dependencies":[]},{"name":"flutter_keyboard_visibility_macos","path":"/Users/amirkhan/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility_macos-1.0.0/","native_build":false,"dependencies":[]},{"name":"path_provider_foundation","path":"/Users/amirkhan/.pub-cache/hosted/pub.dev/path_provider_foundation-2.3.2/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Users/amirkhan/.pub-cache/hosted/pub.dev/video_player_avfoundation-2.5.7/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"linux":[{"name":"flutter_keyboard_visibility_linux","path":"/Users/amirkhan/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility_linux-1.0.0/","native_build":false,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/amirkhan/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[]}],"windows":[{"name":"flutter_keyboard_visibility_windows","path":"/Users/amirkhan/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility_windows-1.0.0/","native_build":false,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/amirkhan/.pub-cache/hosted/pub.dev/path_provider_windows-2.2.1/","native_build":false,"dependencies":[]}],"web":[{"name":"file_picker","path":"/Users/amirkhan/.pub-cache/hosted/pub.dev/file_picker-8.0.1/","dependencies":[]},{"name":"flutter_keyboard_visibility_web","path":"/Users/amirkhan/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility_web-2.0.0/","dependencies":[]},{"name":"image_cropper_for_web","path":"/Users/amirkhan/.pub-cache/hosted/pub.dev/image_cropper_for_web-3.0.0/","dependencies":[]},{"name":"video_player_web","path":"/Users/amirkhan/.pub-cache/hosted/pub.dev/video_player_web-2.3.0/","dependencies":[]}]},"dependencyGraph":[{"name":"ffmpeg_kit_flutter","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_keyboard_visibility","dependencies":["flutter_keyboard_visibility_linux","flutter_keyboard_visibility_macos","flutter_keyboard_visibility_web","flutter_keyboard_visibility_windows"]},{"name":"flutter_keyboard_visibility_linux","dependencies":[]},{"name":"flutter_keyboard_visibility_macos","dependencies":[]},{"name":"flutter_keyboard_visibility_web","dependencies":[]},{"name":"flutter_keyboard_visibility_windows","dependencies":[]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"image_cropper","dependencies":["image_cropper_for_web"]},{"name":"image_cropper_for_web","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_thumbnail","dependencies":[]}],"date_created":"2024-04-18 19:26:10.952933","version":"3.19.0"}
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 | migrate_working_dir/
12 |
13 | # IntelliJ related
14 | *.iml
15 | *.ipr
16 | *.iws
17 | .idea/
18 |
19 | # The .vscode folder contains launch configuration and tasks you configure in
20 | # VS Code which you may wish to be included in version control, so this line
21 | # is commented out by default.
22 | #.vscode/
23 |
24 | # Flutter/Dart/Pub related
25 | # Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
26 | /pubspec.lock
27 | **/doc/api/
28 | .dart_tool/
29 | build/
30 |
--------------------------------------------------------------------------------
/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled and should not be manually edited.
5 |
6 | version:
7 | revision: "bae5e49bc2a867403c43b2aae2de8f8c33b037e4"
8 | channel: "stable"
9 |
10 | project_type: package
11 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## 0.0.2
2 |
3 | * Performance optimized, detailed documentation added, code improved.
4 |
5 | ## 0.0.1
6 |
7 | * Initial release of *Flutter Story Editor*
8 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 Muhammad Adnan
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # flutter_story_editor [](https://pub.dev/packages/flutter_story_editor)
2 |
3 | This package is created using style of the WhatsApp story image/video editor, with which you can edit images and videos both together. You can add texts, stickers, freehand finger drawing, apply filter, and undo. The edited images will be returned in a **onSave** call back as **List of Files**. You can then upload it to some storage or save it locally to your gallery.
4 |
5 | >> Video editing for now only support trimming. In future more video editing features will be added.
6 |
7 | ## Features
8 |
9 | ✅ You can edit Images, and videos both together.
10 |
11 | ✅ Draggable fancy text with (custom colors, font families, and resize)
12 |
13 | ✅ Draggable stickers & emojis
14 |
15 | ✅ Apply filters to images
16 |
17 | ✅ Freehand drawing over images
18 |
19 | ✅ Trimming video frames
20 |
21 | ## Future features
22 |
23 | 🚀 Drawing painting over video frames (requires platform specific work)
24 |
25 | 🚀 More image and video editing functionality like (WhatsApp & Instagram) stories
26 |
27 | 🚀 The UI is currently like WhatsApp, but I think we should go with something unique for flutter (your contribution & ideas will be very invaluable)
28 |
29 | 🚀 improve and enhance performance and existing features.
30 |
31 | ## Package Demo
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 | ## Installation
43 |
44 | Add flutter_story_editor: latest_version to your **pubspec.yaml** and then import it.
45 |
46 | ```dartimport 'package:stories_editor/stories_editor.dart';```
47 |
48 | ### Android
49 | add the following code to your `AndroidMAnifest.xml` file
50 | ```xml
51 |
55 | ```
56 | ### iOS
57 | add the following code to your `info.plist` file
58 |
59 | ```xml
60 | NSCameraUsageDescription
61 | Used to demonstrate image picker plugin
62 | NSMicrophoneUsageDescription
63 | Used to capture audio for image picker plugin
64 | NSPhotoLibraryUsageDescription
65 | Used to demonstrate image picker plugin
66 | ```
67 | ## How to use
68 | ```dart
69 | // Inialize controllers within the state
70 | FlutterStoryEditorController controller = FlutterStoryEditorController();
71 | final TextEditingController _captionController = TextEditingController();
72 |
73 | // TODO: create a method to pick files (videos and images) either separate or together.
74 |
75 |
76 | // Select files
77 | selectMedia().then((value) {
78 | if (_selectedMedia != null && _selectedMedia!.isNotEmpty) {
79 | showModalBottomSheet(
80 | isScrollControlled: true,
81 | isDismissible: false,
82 | enableDrag: false,
83 | context: context,
84 | builder: (context) {
85 |
86 | return FlutterStoryEditor(
87 | controller: controller,
88 | captionController: _captionController,
89 | selectedFiles: _selectedMedia,
90 | onSaveClickListener: (files) {
91 | // Here you go with your edited files.
92 | }
93 | );
94 | },
95 | );
96 | }
97 | },
98 | );
99 | }, icon: const Icon(Icons.upload, size: 50,)),
100 | ),
101 | ```
102 |
103 | For more information : visit example project inside `example/example.dart`.
104 |
105 | ## Screenshots
106 |
107 | Initial view & Multiple images selected
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 | Images & videos together & Apply filters
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 | Crop, scale and rotate & Add draggable stickers
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 | Add emojis & Add draggable fancy text
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 | Draw freehand painting over images
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 | ## Must read
155 |
156 | The initial release of `flutter_story_editor` may have small bugs, and issues. If you found some, and you're willing to contribute feel free to create issue and rasie a PR. Make sure you inform me through my [LinkedIn DM](https://www.linkedin.com/in/muhammad-adnan-23bb8821b/) for the issues you create in both cases either or not if you want to contribute.
157 |
158 | This package will be improved more along the time, your contribution will be very invaluable.
159 |
160 |
161 | ## Created & Maintained By
162 |
163 | [@MuhammadAdnan](https://github.com/AdnanKhan45), LinkedIn : [@MuhammadAdnan](https://www.linkedin.com/in/muhammad-adnan-23bb8821b/) , Instagram : [@MuhammadAdnan](https://www.instagram.com/dev.adnankhan/).
164 |
165 | YouTube : [@eTechViral](https://www.youtube.com/c/eTechViral)
166 |
--------------------------------------------------------------------------------
/analysis_options.yaml:
--------------------------------------------------------------------------------
1 | include: package:flutter_lints/flutter.yaml
2 |
3 | # Additional information about this file can be found at
4 | # https://dart.dev/guides/language/analysis-options
5 |
6 | analyzer:
7 | exclude:
8 | - lib/generated/assets.dart
9 |
10 |
--------------------------------------------------------------------------------
/assets/emojies/e1511.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1511.png
--------------------------------------------------------------------------------
/assets/emojies/e1512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1512.png
--------------------------------------------------------------------------------
/assets/emojies/e1513.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1513.png
--------------------------------------------------------------------------------
/assets/emojies/e1514.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1514.png
--------------------------------------------------------------------------------
/assets/emojies/e1515.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1515.png
--------------------------------------------------------------------------------
/assets/emojies/e1516.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1516.png
--------------------------------------------------------------------------------
/assets/emojies/e1517.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1517.png
--------------------------------------------------------------------------------
/assets/emojies/e1518.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1518.png
--------------------------------------------------------------------------------
/assets/emojies/e1519.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1519.png
--------------------------------------------------------------------------------
/assets/emojies/e1520.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1520.png
--------------------------------------------------------------------------------
/assets/emojies/e1521.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1521.png
--------------------------------------------------------------------------------
/assets/emojies/e1522.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1522.png
--------------------------------------------------------------------------------
/assets/emojies/e1523.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1523.png
--------------------------------------------------------------------------------
/assets/emojies/e1524.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1524.png
--------------------------------------------------------------------------------
/assets/emojies/e1525.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1525.png
--------------------------------------------------------------------------------
/assets/emojies/e1526.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1526.png
--------------------------------------------------------------------------------
/assets/emojies/e1527.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1527.png
--------------------------------------------------------------------------------
/assets/emojies/e1528.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1528.png
--------------------------------------------------------------------------------
/assets/emojies/e1529.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1529.png
--------------------------------------------------------------------------------
/assets/emojies/e1530.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1530.png
--------------------------------------------------------------------------------
/assets/emojies/e1531.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1531.png
--------------------------------------------------------------------------------
/assets/emojies/e1532.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1532.png
--------------------------------------------------------------------------------
/assets/emojies/e1533.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1533.png
--------------------------------------------------------------------------------
/assets/emojies/e1534.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1534.png
--------------------------------------------------------------------------------
/assets/emojies/e1535.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1535.png
--------------------------------------------------------------------------------
/assets/emojies/e1536.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1536.png
--------------------------------------------------------------------------------
/assets/emojies/e1537.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1537.png
--------------------------------------------------------------------------------
/assets/emojies/e1538.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1538.png
--------------------------------------------------------------------------------
/assets/emojies/e1539.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1539.png
--------------------------------------------------------------------------------
/assets/emojies/e1540.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1540.png
--------------------------------------------------------------------------------
/assets/emojies/e1541.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1541.png
--------------------------------------------------------------------------------
/assets/emojies/e1542.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1542.png
--------------------------------------------------------------------------------
/assets/emojies/e1543.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1543.png
--------------------------------------------------------------------------------
/assets/emojies/e1544.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1544.png
--------------------------------------------------------------------------------
/assets/emojies/e1545.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1545.png
--------------------------------------------------------------------------------
/assets/emojies/e1546.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1546.png
--------------------------------------------------------------------------------
/assets/emojies/e1547.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1547.png
--------------------------------------------------------------------------------
/assets/emojies/e1548.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1548.png
--------------------------------------------------------------------------------
/assets/emojies/e1549.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1549.png
--------------------------------------------------------------------------------
/assets/emojies/e1550.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1550.png
--------------------------------------------------------------------------------
/assets/emojies/e1551.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1551.png
--------------------------------------------------------------------------------
/assets/emojies/e1552.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1552.png
--------------------------------------------------------------------------------
/assets/emojies/e1553.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1553.png
--------------------------------------------------------------------------------
/assets/emojies/e1554.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1554.png
--------------------------------------------------------------------------------
/assets/emojies/e1555.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1555.png
--------------------------------------------------------------------------------
/assets/emojies/e1556.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1556.png
--------------------------------------------------------------------------------
/assets/emojies/e1557.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1557.png
--------------------------------------------------------------------------------
/assets/emojies/e1558.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1558.png
--------------------------------------------------------------------------------
/assets/emojies/e1559.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1559.png
--------------------------------------------------------------------------------
/assets/emojies/e1560.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1560.png
--------------------------------------------------------------------------------
/assets/emojies/e1561.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1561.png
--------------------------------------------------------------------------------
/assets/emojies/e1562.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1562.png
--------------------------------------------------------------------------------
/assets/emojies/e1563.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1563.png
--------------------------------------------------------------------------------
/assets/emojies/e1564.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1564.png
--------------------------------------------------------------------------------
/assets/emojies/e1565.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1565.png
--------------------------------------------------------------------------------
/assets/emojies/e1566.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1566.png
--------------------------------------------------------------------------------
/assets/emojies/e1567.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1567.png
--------------------------------------------------------------------------------
/assets/emojies/e1568.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1568.png
--------------------------------------------------------------------------------
/assets/emojies/e1569.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1569.png
--------------------------------------------------------------------------------
/assets/emojies/e1570.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1570.png
--------------------------------------------------------------------------------
/assets/emojies/e1571.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1571.png
--------------------------------------------------------------------------------
/assets/emojies/e1572.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1572.png
--------------------------------------------------------------------------------
/assets/emojies/e1573.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1573.png
--------------------------------------------------------------------------------
/assets/emojies/e1574.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1574.png
--------------------------------------------------------------------------------
/assets/emojies/e1575.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1575.png
--------------------------------------------------------------------------------
/assets/emojies/e1576.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1576.png
--------------------------------------------------------------------------------
/assets/emojies/e1577.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1577.png
--------------------------------------------------------------------------------
/assets/emojies/e1578.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1578.png
--------------------------------------------------------------------------------
/assets/emojies/e1579.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1579.png
--------------------------------------------------------------------------------
/assets/emojies/e1580.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1580.png
--------------------------------------------------------------------------------
/assets/emojies/e1581.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1581.png
--------------------------------------------------------------------------------
/assets/emojies/e1582.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1582.png
--------------------------------------------------------------------------------
/assets/emojies/e1583.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1583.png
--------------------------------------------------------------------------------
/assets/emojies/e1584.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1584.png
--------------------------------------------------------------------------------
/assets/emojies/e1585.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1585.png
--------------------------------------------------------------------------------
/assets/emojies/e1586.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1586.png
--------------------------------------------------------------------------------
/assets/emojies/e1587.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1587.png
--------------------------------------------------------------------------------
/assets/emojies/e1588.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1588.png
--------------------------------------------------------------------------------
/assets/emojies/e1589.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1589.png
--------------------------------------------------------------------------------
/assets/emojies/e1590.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1590.png
--------------------------------------------------------------------------------
/assets/emojies/e1591.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1591.png
--------------------------------------------------------------------------------
/assets/emojies/e1592.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1592.png
--------------------------------------------------------------------------------
/assets/emojies/e1593.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1593.png
--------------------------------------------------------------------------------
/assets/emojies/e1594.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1594.png
--------------------------------------------------------------------------------
/assets/emojies/e1595.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1595.png
--------------------------------------------------------------------------------
/assets/emojies/e1596.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1596.png
--------------------------------------------------------------------------------
/assets/emojies/e1597.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1597.png
--------------------------------------------------------------------------------
/assets/emojies/e1598.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1598.png
--------------------------------------------------------------------------------
/assets/emojies/e1599.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1599.png
--------------------------------------------------------------------------------
/assets/emojies/e1600.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1600.png
--------------------------------------------------------------------------------
/assets/emojies/e1601.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1601.png
--------------------------------------------------------------------------------
/assets/emojies/e1602.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1602.png
--------------------------------------------------------------------------------
/assets/emojies/e1603.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1603.png
--------------------------------------------------------------------------------
/assets/emojies/e1604.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1604.png
--------------------------------------------------------------------------------
/assets/emojies/e1605.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1605.png
--------------------------------------------------------------------------------
/assets/emojies/e1606.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1606.png
--------------------------------------------------------------------------------
/assets/emojies/e1607.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1607.png
--------------------------------------------------------------------------------
/assets/emojies/e1608.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1608.png
--------------------------------------------------------------------------------
/assets/emojies/e1609.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1609.png
--------------------------------------------------------------------------------
/assets/emojies/e1610.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1610.png
--------------------------------------------------------------------------------
/assets/emojies/e1611.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1611.png
--------------------------------------------------------------------------------
/assets/emojies/e1612.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1612.png
--------------------------------------------------------------------------------
/assets/emojies/e1613.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1613.png
--------------------------------------------------------------------------------
/assets/emojies/e1614.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1614.png
--------------------------------------------------------------------------------
/assets/emojies/e1615.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1615.png
--------------------------------------------------------------------------------
/assets/emojies/e1616.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1616.png
--------------------------------------------------------------------------------
/assets/emojies/e1617.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1617.png
--------------------------------------------------------------------------------
/assets/emojies/e1618.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1618.png
--------------------------------------------------------------------------------
/assets/emojies/e1619.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1619.png
--------------------------------------------------------------------------------
/assets/emojies/e1620.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1620.png
--------------------------------------------------------------------------------
/assets/emojies/e1621.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1621.png
--------------------------------------------------------------------------------
/assets/emojies/e1622.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1622.png
--------------------------------------------------------------------------------
/assets/emojies/e1623.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1623.png
--------------------------------------------------------------------------------
/assets/emojies/e1624.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1624.png
--------------------------------------------------------------------------------
/assets/emojies/e1625.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1625.png
--------------------------------------------------------------------------------
/assets/emojies/e1626.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1626.png
--------------------------------------------------------------------------------
/assets/emojies/e1627.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1627.png
--------------------------------------------------------------------------------
/assets/emojies/e1628.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1628.png
--------------------------------------------------------------------------------
/assets/emojies/e1629.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1629.png
--------------------------------------------------------------------------------
/assets/emojies/e1630.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1630.png
--------------------------------------------------------------------------------
/assets/emojies/e1631.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1631.png
--------------------------------------------------------------------------------
/assets/emojies/e1632.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1632.png
--------------------------------------------------------------------------------
/assets/emojies/e1633.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1633.png
--------------------------------------------------------------------------------
/assets/emojies/e1634.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1634.png
--------------------------------------------------------------------------------
/assets/emojies/e1635.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1635.png
--------------------------------------------------------------------------------
/assets/emojies/e1636.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1636.png
--------------------------------------------------------------------------------
/assets/emojies/e1637.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1637.png
--------------------------------------------------------------------------------
/assets/emojies/e1638.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1638.png
--------------------------------------------------------------------------------
/assets/emojies/e1639.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1639.png
--------------------------------------------------------------------------------
/assets/emojies/e1640.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1640.png
--------------------------------------------------------------------------------
/assets/emojies/e1641.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1641.png
--------------------------------------------------------------------------------
/assets/emojies/e1642.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1642.png
--------------------------------------------------------------------------------
/assets/emojies/e1643.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1643.png
--------------------------------------------------------------------------------
/assets/emojies/e1644.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1644.png
--------------------------------------------------------------------------------
/assets/emojies/e1645.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1645.png
--------------------------------------------------------------------------------
/assets/emojies/e1646.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1646.png
--------------------------------------------------------------------------------
/assets/emojies/e1647.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1647.png
--------------------------------------------------------------------------------
/assets/emojies/e1648.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1648.png
--------------------------------------------------------------------------------
/assets/emojies/e1649.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1649.png
--------------------------------------------------------------------------------
/assets/emojies/e1650.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1650.png
--------------------------------------------------------------------------------
/assets/emojies/e1651.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1651.png
--------------------------------------------------------------------------------
/assets/emojies/e1652.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1652.png
--------------------------------------------------------------------------------
/assets/emojies/e1653.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1653.png
--------------------------------------------------------------------------------
/assets/emojies/e1654.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1654.png
--------------------------------------------------------------------------------
/assets/emojies/e1655.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1655.png
--------------------------------------------------------------------------------
/assets/emojies/e1656.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1656.png
--------------------------------------------------------------------------------
/assets/emojies/e1657.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1657.png
--------------------------------------------------------------------------------
/assets/emojies/e1658.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1658.png
--------------------------------------------------------------------------------
/assets/emojies/e1659.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1659.png
--------------------------------------------------------------------------------
/assets/emojies/e1660.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1660.png
--------------------------------------------------------------------------------
/assets/emojies/e1661.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1661.png
--------------------------------------------------------------------------------
/assets/emojies/e1662.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1662.png
--------------------------------------------------------------------------------
/assets/emojies/e1663.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1663.png
--------------------------------------------------------------------------------
/assets/emojies/e1664.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1664.png
--------------------------------------------------------------------------------
/assets/emojies/e1665.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1665.png
--------------------------------------------------------------------------------
/assets/emojies/e1666.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1666.png
--------------------------------------------------------------------------------
/assets/emojies/e1757.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1757.png
--------------------------------------------------------------------------------
/assets/emojies/e1758.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1758.png
--------------------------------------------------------------------------------
/assets/emojies/e1759.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1759.png
--------------------------------------------------------------------------------
/assets/emojies/e1760.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1760.png
--------------------------------------------------------------------------------
/assets/emojies/e1761.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1761.png
--------------------------------------------------------------------------------
/assets/emojies/e1762.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1762.png
--------------------------------------------------------------------------------
/assets/emojies/e1763.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1763.png
--------------------------------------------------------------------------------
/assets/emojies/e1764.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1764.png
--------------------------------------------------------------------------------
/assets/emojies/e1765.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1765.png
--------------------------------------------------------------------------------
/assets/emojies/e1766.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1766.png
--------------------------------------------------------------------------------
/assets/emojies/e1767.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1767.png
--------------------------------------------------------------------------------
/assets/emojies/e1768.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1768.png
--------------------------------------------------------------------------------
/assets/emojies/e1769.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1769.png
--------------------------------------------------------------------------------
/assets/emojies/e1779.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1779.png
--------------------------------------------------------------------------------
/assets/emojies/e1780.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1780.png
--------------------------------------------------------------------------------
/assets/emojies/e1781.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1781.png
--------------------------------------------------------------------------------
/assets/emojies/e1782.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1782.png
--------------------------------------------------------------------------------
/assets/emojies/e1783.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1783.png
--------------------------------------------------------------------------------
/assets/emojies/e1784.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1784.png
--------------------------------------------------------------------------------
/assets/emojies/e1785.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1785.png
--------------------------------------------------------------------------------
/assets/emojies/e1791.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1791.png
--------------------------------------------------------------------------------
/assets/emojies/e1792.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1792.png
--------------------------------------------------------------------------------
/assets/emojies/e1793.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1793.png
--------------------------------------------------------------------------------
/assets/emojies/e1794.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1794.png
--------------------------------------------------------------------------------
/assets/emojies/e1795.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1795.png
--------------------------------------------------------------------------------
/assets/emojies/e1796.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1796.png
--------------------------------------------------------------------------------
/assets/emojies/e1799.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1799.png
--------------------------------------------------------------------------------
/assets/emojies/e1819.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1819.png
--------------------------------------------------------------------------------
/assets/emojies/e1820.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1820.png
--------------------------------------------------------------------------------
/assets/emojies/e1821.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1821.png
--------------------------------------------------------------------------------
/assets/emojies/e1822.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1822.png
--------------------------------------------------------------------------------
/assets/emojies/e1823.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1823.png
--------------------------------------------------------------------------------
/assets/emojies/e1824.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/emojies/e1824.png
--------------------------------------------------------------------------------
/assets/fonts/angkor/Angkor-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/fonts/angkor/Angkor-Regular.ttf
--------------------------------------------------------------------------------
/assets/fonts/dancing_script/DancingScript-Medium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/fonts/dancing_script/DancingScript-Medium.ttf
--------------------------------------------------------------------------------
/assets/fonts/dancing_script/DancingScript-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/fonts/dancing_script/DancingScript-Regular.ttf
--------------------------------------------------------------------------------
/assets/fonts/lato/Lato-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/fonts/lato/Lato-Regular.ttf
--------------------------------------------------------------------------------
/assets/fonts/lora/Lora-Medium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/fonts/lora/Lora-Medium.ttf
--------------------------------------------------------------------------------
/assets/fonts/lora/Lora-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/fonts/lora/Lora-Regular.ttf
--------------------------------------------------------------------------------
/assets/fonts/madimiOne/MadimiOne-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/fonts/madimiOne/MadimiOne-Regular.ttf
--------------------------------------------------------------------------------
/assets/fonts/merriweather/Merriweather-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/fonts/merriweather/Merriweather-Regular.ttf
--------------------------------------------------------------------------------
/assets/fonts/montserrat/Montserrat-Medium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/fonts/montserrat/Montserrat-Medium.ttf
--------------------------------------------------------------------------------
/assets/fonts/montserrat/Montserrat-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/fonts/montserrat/Montserrat-Regular.ttf
--------------------------------------------------------------------------------
/assets/fonts/oswald/Oswald-Medium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/fonts/oswald/Oswald-Medium.ttf
--------------------------------------------------------------------------------
/assets/fonts/oswald/Oswald-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/fonts/oswald/Oswald-Regular.ttf
--------------------------------------------------------------------------------
/assets/fonts/pacifico/Pacifico-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/fonts/pacifico/Pacifico-Regular.ttf
--------------------------------------------------------------------------------
/assets/fonts/raleway/Raleway-Medium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/fonts/raleway/Raleway-Medium.ttf
--------------------------------------------------------------------------------
/assets/fonts/raleway/Raleway-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/fonts/raleway/Raleway-Regular.ttf
--------------------------------------------------------------------------------
/assets/fonts/roboto/Roboto-Medium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/fonts/roboto/Roboto-Medium.ttf
--------------------------------------------------------------------------------
/assets/fonts/roboto/Roboto-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/fonts/roboto/Roboto-Regular.ttf
--------------------------------------------------------------------------------
/assets/images/01_Cuppy_smile.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/images/01_Cuppy_smile.webp
--------------------------------------------------------------------------------
/assets/images/02_Cuppy_lol.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/images/02_Cuppy_lol.webp
--------------------------------------------------------------------------------
/assets/images/03_Cuppy_rofl.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/images/03_Cuppy_rofl.webp
--------------------------------------------------------------------------------
/assets/images/04_Cuppy_sad.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/images/04_Cuppy_sad.webp
--------------------------------------------------------------------------------
/assets/images/05_Cuppy_cry.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/images/05_Cuppy_cry.webp
--------------------------------------------------------------------------------
/assets/images/06_Cuppy_love.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/images/06_Cuppy_love.webp
--------------------------------------------------------------------------------
/assets/images/07_Cuppy_hate.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/images/07_Cuppy_hate.webp
--------------------------------------------------------------------------------
/assets/images/08_Cuppy_lovewithmug.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/images/08_Cuppy_lovewithmug.webp
--------------------------------------------------------------------------------
/assets/images/09_Cuppy_lovewithcookie.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/images/09_Cuppy_lovewithcookie.webp
--------------------------------------------------------------------------------
/assets/images/10_Cuppy_hmm.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/images/10_Cuppy_hmm.webp
--------------------------------------------------------------------------------
/assets/images/11_Cuppy_upset.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/images/11_Cuppy_upset.webp
--------------------------------------------------------------------------------
/assets/images/12_Cuppy_angry.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/images/12_Cuppy_angry.webp
--------------------------------------------------------------------------------
/assets/images/13_Cuppy_curious.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/images/13_Cuppy_curious.webp
--------------------------------------------------------------------------------
/assets/images/14_Cuppy_weird.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/images/14_Cuppy_weird.webp
--------------------------------------------------------------------------------
/assets/images/15_Cuppy_bluescreen.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/images/15_Cuppy_bluescreen.webp
--------------------------------------------------------------------------------
/assets/images/16_Cuppy_angry.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/images/16_Cuppy_angry.webp
--------------------------------------------------------------------------------
/assets/images/17_Cuppy_tired.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/images/17_Cuppy_tired.webp
--------------------------------------------------------------------------------
/assets/images/18_Cuppy_workhard.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/images/18_Cuppy_workhard.webp
--------------------------------------------------------------------------------
/assets/images/19_Cuppy_shine.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/images/19_Cuppy_shine.webp
--------------------------------------------------------------------------------
/assets/images/20_Cuppy_disgusting.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/images/20_Cuppy_disgusting.webp
--------------------------------------------------------------------------------
/assets/images/21_Cuppy_hi.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/images/21_Cuppy_hi.webp
--------------------------------------------------------------------------------
/assets/images/22_Cuppy_bye.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/images/22_Cuppy_bye.webp
--------------------------------------------------------------------------------
/assets/images/23_Cuppy_greentea.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/images/23_Cuppy_greentea.webp
--------------------------------------------------------------------------------
/assets/images/24_Cuppy_phone.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/images/24_Cuppy_phone.webp
--------------------------------------------------------------------------------
/assets/images/25_Cuppy_battery.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/images/25_Cuppy_battery.webp
--------------------------------------------------------------------------------
/assets/images/tray_Cuppy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/assets/images/tray_Cuppy.png
--------------------------------------------------------------------------------
/example/example.dart:
--------------------------------------------------------------------------------
1 |
2 | import 'dart:io';
3 |
4 | import 'package:file_picker/file_picker.dart';
5 | import 'package:flutter/material.dart';
6 | import 'package:flutter_story_editor/flutter_story_editor.dart';
7 | import 'package:flutter_story_editor/src/controller/controller.dart';
8 |
9 | import 'package:path/path.dart' as path;
10 |
11 | class FlutterStoryEditorExample extends StatefulWidget {
12 | // final User? user;
13 | const FlutterStoryEditorExample({super.key});
14 |
15 | @override
16 | State createState() => _FlutterStoryEditorExampleState();
17 | }
18 |
19 | class _FlutterStoryEditorExampleState extends State with SingleTickerProviderStateMixin {
20 |
21 | FlutterStoryEditorController controller = FlutterStoryEditorController();
22 |
23 | final TextEditingController _captionController = TextEditingController();
24 |
25 |
26 |
27 | List? _selectedMedia;
28 |
29 | List? _mediaTypes; // To store the type of each selected file
30 |
31 | Future selectMedia() async {
32 | setState(() {
33 | _selectedMedia = null;
34 | _mediaTypes = null;
35 | });
36 |
37 | try {
38 | final result = await FilePicker.platform.pickFiles(
39 | type: FileType.media,
40 | allowMultiple: true,
41 | );
42 | if (result != null) {
43 | _selectedMedia = result.files.map((file) => File(file.path!)).toList();
44 |
45 | // Initialize the media types list
46 | _mediaTypes = List.filled(_selectedMedia!.length, '');
47 |
48 | // Determine the type of each selected file
49 | for (int i = 0; i < _selectedMedia!.length; i++) {
50 | String extension = path.extension(_selectedMedia![i].path)
51 | .toLowerCase();
52 | if (extension == '.jpg' || extension == '.jpeg' ||
53 | extension == '.png') {
54 | _mediaTypes![i] = 'image';
55 | } else if (extension == '.mp4' || extension == '.mov' ||
56 | extension == '.avi') {
57 | _mediaTypes![i] = 'video';
58 | }
59 | }
60 |
61 | setState(() {});
62 | } else {
63 |
64 | }
65 | } catch (e) {
66 | throw Exception("unable to pick files, please try again");
67 | }
68 | }
69 |
70 |
71 | @override
72 | Widget build(BuildContext context) {
73 | return Scaffold(
74 | body: Column(
75 | mainAxisAlignment: MainAxisAlignment.center,
76 | children: [
77 |
78 | Center(
79 | child: IconButton(onPressed: () {
80 |
81 |
82 | selectMedia().then(
83 | (value) {
84 |
85 | if (_selectedMedia != null && _selectedMedia!.isNotEmpty) {
86 | showModalBottomSheet(
87 | isScrollControlled: true,
88 | isDismissible: false,
89 | enableDrag: false,
90 | context: context,
91 | builder: (context) {
92 |
93 | return FlutterStoryEditor(
94 | controller: controller,
95 | captionController: _captionController,
96 | selectedFiles: _selectedMedia,
97 | onSaveClickListener: (files) {
98 | // Navigator.push(
99 | // context,
100 | // MaterialPageRoute(
101 | // builder: (context) => ImagesPage(files: files),
102 | // ),
103 | // );
104 | }
105 | );
106 | },
107 | );
108 | }
109 |
110 | },
111 | );
112 | }, icon: const Icon(Icons.upload, size: 50,)),
113 | ),
114 |
115 |
116 | const SizedBox(height: 10),
117 | const Text("Pick Files & Play with them")
118 |
119 | ],
120 | ),
121 | );
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/lib/generated/assets.dart:
--------------------------------------------------------------------------------
1 | ///This file is automatically generated. DO NOT EDIT, all your changes would be lost.
2 | class Assets {
3 | Assets._();
4 |
5 | static const String angkorAngkorRegular = 'assets/fonts/angkor/Angkor-Regular.ttf';
6 | static const String dancingScriptDancingScriptMedium = 'assets/fonts/dancing_script/DancingScript-Medium.ttf';
7 | static const String dancingScriptDancingScriptRegular = 'assets/fonts/dancing_script/DancingScript-Regular.ttf';
8 | static const String emojiesE1511 = 'assets/emojies/e1511.png';
9 | static const String emojiesE1512 = 'assets/emojies/e1512.png';
10 | static const String emojiesE1513 = 'assets/emojies/e1513.png';
11 | static const String emojiesE1514 = 'assets/emojies/e1514.png';
12 | static const String emojiesE1515 = 'assets/emojies/e1515.png';
13 | static const String emojiesE1516 = 'assets/emojies/e1516.png';
14 | static const String emojiesE1517 = 'assets/emojies/e1517.png';
15 | static const String emojiesE1518 = 'assets/emojies/e1518.png';
16 | static const String emojiesE1519 = 'assets/emojies/e1519.png';
17 | static const String emojiesE1520 = 'assets/emojies/e1520.png';
18 | static const String emojiesE1521 = 'assets/emojies/e1521.png';
19 | static const String emojiesE1522 = 'assets/emojies/e1522.png';
20 | static const String emojiesE1523 = 'assets/emojies/e1523.png';
21 | static const String emojiesE1524 = 'assets/emojies/e1524.png';
22 | static const String emojiesE1525 = 'assets/emojies/e1525.png';
23 | static const String emojiesE1526 = 'assets/emojies/e1526.png';
24 | static const String emojiesE1527 = 'assets/emojies/e1527.png';
25 | static const String emojiesE1528 = 'assets/emojies/e1528.png';
26 | static const String emojiesE1529 = 'assets/emojies/e1529.png';
27 | static const String emojiesE1530 = 'assets/emojies/e1530.png';
28 | static const String emojiesE1531 = 'assets/emojies/e1531.png';
29 | static const String emojiesE1532 = 'assets/emojies/e1532.png';
30 | static const String emojiesE1533 = 'assets/emojies/e1533.png';
31 | static const String emojiesE1534 = 'assets/emojies/e1534.png';
32 | static const String emojiesE1535 = 'assets/emojies/e1535.png';
33 | static const String emojiesE1536 = 'assets/emojies/e1536.png';
34 | static const String emojiesE1537 = 'assets/emojies/e1537.png';
35 | static const String emojiesE1538 = 'assets/emojies/e1538.png';
36 | static const String emojiesE1539 = 'assets/emojies/e1539.png';
37 | static const String emojiesE1540 = 'assets/emojies/e1540.png';
38 | static const String emojiesE1541 = 'assets/emojies/e1541.png';
39 | static const String emojiesE1542 = 'assets/emojies/e1542.png';
40 | static const String emojiesE1543 = 'assets/emojies/e1543.png';
41 | static const String emojiesE1544 = 'assets/emojies/e1544.png';
42 | static const String emojiesE1545 = 'assets/emojies/e1545.png';
43 | static const String emojiesE1546 = 'assets/emojies/e1546.png';
44 | static const String emojiesE1547 = 'assets/emojies/e1547.png';
45 | static const String emojiesE1548 = 'assets/emojies/e1548.png';
46 | static const String emojiesE1549 = 'assets/emojies/e1549.png';
47 | static const String emojiesE1550 = 'assets/emojies/e1550.png';
48 | static const String emojiesE1551 = 'assets/emojies/e1551.png';
49 | static const String emojiesE1552 = 'assets/emojies/e1552.png';
50 | static const String emojiesE1553 = 'assets/emojies/e1553.png';
51 | static const String emojiesE1554 = 'assets/emojies/e1554.png';
52 | static const String emojiesE1555 = 'assets/emojies/e1555.png';
53 | static const String emojiesE1556 = 'assets/emojies/e1556.png';
54 | static const String emojiesE1557 = 'assets/emojies/e1557.png';
55 | static const String emojiesE1558 = 'assets/emojies/e1558.png';
56 | static const String emojiesE1559 = 'assets/emojies/e1559.png';
57 | static const String emojiesE1560 = 'assets/emojies/e1560.png';
58 | static const String emojiesE1561 = 'assets/emojies/e1561.png';
59 | static const String emojiesE1562 = 'assets/emojies/e1562.png';
60 | static const String emojiesE1563 = 'assets/emojies/e1563.png';
61 | static const String emojiesE1564 = 'assets/emojies/e1564.png';
62 | static const String emojiesE1565 = 'assets/emojies/e1565.png';
63 | static const String emojiesE1566 = 'assets/emojies/e1566.png';
64 | static const String emojiesE1567 = 'assets/emojies/e1567.png';
65 | static const String emojiesE1568 = 'assets/emojies/e1568.png';
66 | static const String emojiesE1569 = 'assets/emojies/e1569.png';
67 | static const String emojiesE1570 = 'assets/emojies/e1570.png';
68 | static const String emojiesE1571 = 'assets/emojies/e1571.png';
69 | static const String emojiesE1572 = 'assets/emojies/e1572.png';
70 | static const String emojiesE1573 = 'assets/emojies/e1573.png';
71 | static const String emojiesE1574 = 'assets/emojies/e1574.png';
72 | static const String emojiesE1575 = 'assets/emojies/e1575.png';
73 | static const String emojiesE1576 = 'assets/emojies/e1576.png';
74 | static const String emojiesE1577 = 'assets/emojies/e1577.png';
75 | static const String emojiesE1578 = 'assets/emojies/e1578.png';
76 | static const String emojiesE1579 = 'assets/emojies/e1579.png';
77 | static const String emojiesE1580 = 'assets/emojies/e1580.png';
78 | static const String emojiesE1581 = 'assets/emojies/e1581.png';
79 | static const String emojiesE1582 = 'assets/emojies/e1582.png';
80 | static const String emojiesE1583 = 'assets/emojies/e1583.png';
81 | static const String emojiesE1584 = 'assets/emojies/e1584.png';
82 | static const String emojiesE1585 = 'assets/emojies/e1585.png';
83 | static const String emojiesE1586 = 'assets/emojies/e1586.png';
84 | static const String emojiesE1587 = 'assets/emojies/e1587.png';
85 | static const String emojiesE1588 = 'assets/emojies/e1588.png';
86 | static const String emojiesE1589 = 'assets/emojies/e1589.png';
87 | static const String emojiesE1590 = 'assets/emojies/e1590.png';
88 | static const String emojiesE1591 = 'assets/emojies/e1591.png';
89 | static const String emojiesE1592 = 'assets/emojies/e1592.png';
90 | static const String emojiesE1593 = 'assets/emojies/e1593.png';
91 | static const String emojiesE1594 = 'assets/emojies/e1594.png';
92 | static const String emojiesE1595 = 'assets/emojies/e1595.png';
93 | static const String emojiesE1596 = 'assets/emojies/e1596.png';
94 | static const String emojiesE1597 = 'assets/emojies/e1597.png';
95 | static const String emojiesE1598 = 'assets/emojies/e1598.png';
96 | static const String emojiesE1599 = 'assets/emojies/e1599.png';
97 | static const String emojiesE1600 = 'assets/emojies/e1600.png';
98 | static const String emojiesE1601 = 'assets/emojies/e1601.png';
99 | static const String emojiesE1602 = 'assets/emojies/e1602.png';
100 | static const String emojiesE1603 = 'assets/emojies/e1603.png';
101 | static const String emojiesE1604 = 'assets/emojies/e1604.png';
102 | static const String emojiesE1605 = 'assets/emojies/e1605.png';
103 | static const String emojiesE1606 = 'assets/emojies/e1606.png';
104 | static const String emojiesE1607 = 'assets/emojies/e1607.png';
105 | static const String emojiesE1608 = 'assets/emojies/e1608.png';
106 | static const String emojiesE1609 = 'assets/emojies/e1609.png';
107 | static const String emojiesE1610 = 'assets/emojies/e1610.png';
108 | static const String emojiesE1611 = 'assets/emojies/e1611.png';
109 | static const String emojiesE1612 = 'assets/emojies/e1612.png';
110 | static const String emojiesE1613 = 'assets/emojies/e1613.png';
111 | static const String emojiesE1614 = 'assets/emojies/e1614.png';
112 | static const String emojiesE1615 = 'assets/emojies/e1615.png';
113 | static const String emojiesE1616 = 'assets/emojies/e1616.png';
114 | static const String emojiesE1617 = 'assets/emojies/e1617.png';
115 | static const String emojiesE1618 = 'assets/emojies/e1618.png';
116 | static const String emojiesE1619 = 'assets/emojies/e1619.png';
117 | static const String emojiesE1620 = 'assets/emojies/e1620.png';
118 | static const String emojiesE1621 = 'assets/emojies/e1621.png';
119 | static const String emojiesE1622 = 'assets/emojies/e1622.png';
120 | static const String emojiesE1623 = 'assets/emojies/e1623.png';
121 | static const String emojiesE1624 = 'assets/emojies/e1624.png';
122 | static const String emojiesE1625 = 'assets/emojies/e1625.png';
123 | static const String emojiesE1626 = 'assets/emojies/e1626.png';
124 | static const String emojiesE1627 = 'assets/emojies/e1627.png';
125 | static const String emojiesE1628 = 'assets/emojies/e1628.png';
126 | static const String emojiesE1629 = 'assets/emojies/e1629.png';
127 | static const String emojiesE1630 = 'assets/emojies/e1630.png';
128 | static const String emojiesE1631 = 'assets/emojies/e1631.png';
129 | static const String emojiesE1632 = 'assets/emojies/e1632.png';
130 | static const String emojiesE1633 = 'assets/emojies/e1633.png';
131 | static const String emojiesE1634 = 'assets/emojies/e1634.png';
132 | static const String emojiesE1635 = 'assets/emojies/e1635.png';
133 | static const String emojiesE1636 = 'assets/emojies/e1636.png';
134 | static const String emojiesE1637 = 'assets/emojies/e1637.png';
135 | static const String emojiesE1638 = 'assets/emojies/e1638.png';
136 | static const String emojiesE1639 = 'assets/emojies/e1639.png';
137 | static const String emojiesE1640 = 'assets/emojies/e1640.png';
138 | static const String emojiesE1641 = 'assets/emojies/e1641.png';
139 | static const String emojiesE1642 = 'assets/emojies/e1642.png';
140 | static const String emojiesE1643 = 'assets/emojies/e1643.png';
141 | static const String emojiesE1644 = 'assets/emojies/e1644.png';
142 | static const String emojiesE1645 = 'assets/emojies/e1645.png';
143 | static const String emojiesE1646 = 'assets/emojies/e1646.png';
144 | static const String emojiesE1647 = 'assets/emojies/e1647.png';
145 | static const String emojiesE1648 = 'assets/emojies/e1648.png';
146 | static const String emojiesE1649 = 'assets/emojies/e1649.png';
147 | static const String emojiesE1650 = 'assets/emojies/e1650.png';
148 | static const String emojiesE1651 = 'assets/emojies/e1651.png';
149 | static const String emojiesE1652 = 'assets/emojies/e1652.png';
150 | static const String emojiesE1653 = 'assets/emojies/e1653.png';
151 | static const String emojiesE1654 = 'assets/emojies/e1654.png';
152 | static const String emojiesE1655 = 'assets/emojies/e1655.png';
153 | static const String emojiesE1656 = 'assets/emojies/e1656.png';
154 | static const String emojiesE1657 = 'assets/emojies/e1657.png';
155 | static const String emojiesE1658 = 'assets/emojies/e1658.png';
156 | static const String emojiesE1659 = 'assets/emojies/e1659.png';
157 | static const String emojiesE1660 = 'assets/emojies/e1660.png';
158 | static const String emojiesE1661 = 'assets/emojies/e1661.png';
159 | static const String emojiesE1662 = 'assets/emojies/e1662.png';
160 | static const String emojiesE1663 = 'assets/emojies/e1663.png';
161 | static const String emojiesE1664 = 'assets/emojies/e1664.png';
162 | static const String emojiesE1665 = 'assets/emojies/e1665.png';
163 | static const String emojiesE1666 = 'assets/emojies/e1666.png';
164 | static const String emojiesE1757 = 'assets/emojies/e1757.png';
165 | static const String emojiesE1758 = 'assets/emojies/e1758.png';
166 | static const String emojiesE1759 = 'assets/emojies/e1759.png';
167 | static const String emojiesE1760 = 'assets/emojies/e1760.png';
168 | static const String emojiesE1761 = 'assets/emojies/e1761.png';
169 | static const String emojiesE1762 = 'assets/emojies/e1762.png';
170 | static const String emojiesE1763 = 'assets/emojies/e1763.png';
171 | static const String emojiesE1764 = 'assets/emojies/e1764.png';
172 | static const String emojiesE1765 = 'assets/emojies/e1765.png';
173 | static const String emojiesE1766 = 'assets/emojies/e1766.png';
174 | static const String emojiesE1767 = 'assets/emojies/e1767.png';
175 | static const String emojiesE1768 = 'assets/emojies/e1768.png';
176 | static const String emojiesE1769 = 'assets/emojies/e1769.png';
177 | static const String emojiesE1779 = 'assets/emojies/e1779.png';
178 | static const String emojiesE1780 = 'assets/emojies/e1780.png';
179 | static const String emojiesE1781 = 'assets/emojies/e1781.png';
180 | static const String emojiesE1782 = 'assets/emojies/e1782.png';
181 | static const String emojiesE1783 = 'assets/emojies/e1783.png';
182 | static const String emojiesE1784 = 'assets/emojies/e1784.png';
183 | static const String emojiesE1785 = 'assets/emojies/e1785.png';
184 | static const String emojiesE1791 = 'assets/emojies/e1791.png';
185 | static const String emojiesE1792 = 'assets/emojies/e1792.png';
186 | static const String emojiesE1793 = 'assets/emojies/e1793.png';
187 | static const String emojiesE1794 = 'assets/emojies/e1794.png';
188 | static const String emojiesE1795 = 'assets/emojies/e1795.png';
189 | static const String emojiesE1796 = 'assets/emojies/e1796.png';
190 | static const String emojiesE1799 = 'assets/emojies/e1799.png';
191 | static const String emojiesE1819 = 'assets/emojies/e1819.png';
192 | static const String emojiesE1820 = 'assets/emojies/e1820.png';
193 | static const String emojiesE1821 = 'assets/emojies/e1821.png';
194 | static const String emojiesE1822 = 'assets/emojies/e1822.png';
195 | static const String emojiesE1823 = 'assets/emojies/e1823.png';
196 | static const String emojiesE1824 = 'assets/emojies/e1824.png';
197 | static const String images01CuppySmile = 'assets/images/01_Cuppy_smile.webp';
198 | static const String images02CuppyLol = 'assets/images/02_Cuppy_lol.webp';
199 | static const String images03CuppyRofl = 'assets/images/03_Cuppy_rofl.webp';
200 | static const String images04CuppySad = 'assets/images/04_Cuppy_sad.webp';
201 | static const String images05CuppyCry = 'assets/images/05_Cuppy_cry.webp';
202 | static const String images06CuppyLove = 'assets/images/06_Cuppy_love.webp';
203 | static const String images07CuppyHate = 'assets/images/07_Cuppy_hate.webp';
204 | static const String images08CuppyLovewithmug = 'assets/images/08_Cuppy_lovewithmug.webp';
205 | static const String images09CuppyLovewithcookie = 'assets/images/09_Cuppy_lovewithcookie.webp';
206 | static const String images10CuppyHmm = 'assets/images/10_Cuppy_hmm.webp';
207 | static const String images11CuppyUpset = 'assets/images/11_Cuppy_upset.webp';
208 | static const String images12CuppyAngry = 'assets/images/12_Cuppy_angry.webp';
209 | static const String images13CuppyCurious = 'assets/images/13_Cuppy_curious.webp';
210 | static const String images14CuppyWeird = 'assets/images/14_Cuppy_weird.webp';
211 | static const String images15CuppyBluescreen = 'assets/images/15_Cuppy_bluescreen.webp';
212 | static const String images16CuppyAngry = 'assets/images/16_Cuppy_angry.webp';
213 | static const String images17CuppyTired = 'assets/images/17_Cuppy_tired.webp';
214 | static const String images18CuppyWorkhard = 'assets/images/18_Cuppy_workhard.webp';
215 | static const String images19CuppyShine = 'assets/images/19_Cuppy_shine.webp';
216 | static const String images20CuppyDisgusting = 'assets/images/20_Cuppy_disgusting.webp';
217 | static const String images21CuppyHi = 'assets/images/21_Cuppy_hi.webp';
218 | static const String images22CuppyBye = 'assets/images/22_Cuppy_bye.webp';
219 | static const String images23CuppyGreentea = 'assets/images/23_Cuppy_greentea.webp';
220 | static const String images24CuppyPhone = 'assets/images/24_Cuppy_phone.webp';
221 | static const String images25CuppyBattery = 'assets/images/25_Cuppy_battery.webp';
222 | static const String imagesTrayCuppy = 'assets/images/tray_Cuppy.png';
223 | static const String latoLatoRegular = 'assets/fonts/lato/Lato-Regular.ttf';
224 | static const String loraLoraMedium = 'assets/fonts/lora/Lora-Medium.ttf';
225 | static const String loraLoraRegular = 'assets/fonts/lora/Lora-Regular.ttf';
226 | static const String madimiOneMadimiOneRegular = 'assets/fonts/madimiOne/MadimiOne-Regular.ttf';
227 | static const String merriweatherMerriweatherRegular = 'assets/fonts/merriweather/Merriweather-Regular.ttf';
228 | static const String montserratMontserratMedium = 'assets/fonts/montserrat/Montserrat-Medium.ttf';
229 | static const String montserratMontserratRegular = 'assets/fonts/montserrat/Montserrat-Regular.ttf';
230 | static const String oswaldOswaldMedium = 'assets/fonts/oswald/Oswald-Medium.ttf';
231 | static const String oswaldOswaldRegular = 'assets/fonts/oswald/Oswald-Regular.ttf';
232 | static const String pacificoPacificoRegular = 'assets/fonts/pacifico/Pacifico-Regular.ttf';
233 | static const String ralewayRalewayMedium = 'assets/fonts/raleway/Raleway-Medium.ttf';
234 | static const String ralewayRalewayRegular = 'assets/fonts/raleway/Raleway-Regular.ttf';
235 | static const String robotoRobotoMedium = 'assets/fonts/roboto/Roboto-Medium.ttf';
236 | static const String robotoRobotoRegular = 'assets/fonts/roboto/Roboto-Regular.ttf';
237 |
238 | }
239 |
--------------------------------------------------------------------------------
/lib/src/const/const.dart:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | import 'filters.dart';
6 |
7 | class Consts {
8 |
9 |
10 | static List filterNames = ["None", "Pop", "B&W", "Cool", "Chrome", "Film"];
11 |
12 |
13 | static List> filters = [
14 | noFiler,
15 | popFilter,
16 | blackAndWhiteFilter,
17 | coolFilter,
18 | chromeFilter,
19 | filmFilter
20 | ];
21 |
22 | static List stickers = [
23 | '01_Cuppy_smile.webp',
24 | '02_Cuppy_lol.webp',
25 | '03_Cuppy_rofl.webp',
26 | '04_Cuppy_sad.webp',
27 | '05_Cuppy_cry.webp',
28 | '06_Cuppy_love.webp',
29 | '07_Cuppy_hate.webp',
30 | '08_Cuppy_lovewithmug.webp',
31 | '09_Cuppy_lovewithcookie.webp',
32 | '10_Cuppy_hmm.webp',
33 | '11_Cuppy_upset.webp',
34 | '12_Cuppy_angry.webp',
35 | '13_Cuppy_curious.webp',
36 | '14_Cuppy_weird.webp',
37 | '15_Cuppy_bluescreen.webp',
38 | '16_Cuppy_angry.webp',
39 | '17_Cuppy_tired.webp',
40 | '18_Cuppy_workhard.webp',
41 | '19_Cuppy_shine.webp',
42 | '20_Cuppy_disgusting.webp',
43 | '21_Cuppy_hi.webp',
44 | '22_Cuppy_bye.webp',
45 | '23_Cuppy_greentea.webp',
46 | '24_Cuppy_phone.webp',
47 | '25_Cuppy_battery.webp',
48 | 'tray_Cuppy.png',
49 | ];
50 |
51 |
52 | static List emojies = [
53 | 'e1511.png',
54 | 'e1512.png',
55 | 'e1513.png',
56 | 'e1514.png',
57 | 'e1515.png',
58 | 'e1516.png',
59 | 'e1517.png',
60 | 'e1518.png',
61 | 'e1519.png',
62 | 'e1520.png',
63 | 'e1521.png',
64 | 'e1522.png',
65 | 'e1523.png',
66 | 'e1524.png',
67 | 'e1525.png',
68 | 'e1526.png',
69 | 'e1527.png',
70 | 'e1528.png',
71 | 'e1529.png',
72 | 'e1530.png',
73 | 'e1531.png',
74 | 'e1532.png',
75 | 'e1533.png',
76 | 'e1534.png',
77 | 'e1535.png',
78 | 'e1536.png',
79 | 'e1537.png',
80 | 'e1538.png',
81 | 'e1539.png',
82 | 'e1540.png',
83 | 'e1541.png',
84 | 'e1542.png',
85 | 'e1543.png',
86 | 'e1544.png',
87 | 'e1545.png',
88 | 'e1546.png',
89 | 'e1547.png',
90 | 'e1548.png',
91 | 'e1549.png',
92 | 'e1550.png',
93 | 'e1551.png',
94 | 'e1552.png',
95 | 'e1553.png',
96 | 'e1554.png',
97 | 'e1555.png',
98 | 'e1556.png',
99 | 'e1557.png',
100 | 'e1558.png',
101 | 'e1559.png',
102 | 'e1560.png',
103 | 'e1561.png',
104 | 'e1562.png',
105 | 'e1563.png',
106 | 'e1564.png',
107 | 'e1565.png',
108 | 'e1566.png',
109 | 'e1567.png',
110 | 'e1568.png',
111 | 'e1569.png',
112 | 'e1570.png',
113 | 'e1571.png',
114 | 'e1572.png',
115 | 'e1573.png',
116 | 'e1574.png',
117 | 'e1575.png',
118 | 'e1576.png',
119 | 'e1577.png',
120 | 'e1578.png',
121 | 'e1579.png',
122 | 'e1580.png',
123 | 'e1581.png',
124 | 'e1582.png',
125 | 'e1583.png',
126 | 'e1584.png',
127 | 'e1585.png',
128 | 'e1586.png',
129 | 'e1587.png',
130 | 'e1588.png',
131 | 'e1589.png',
132 | 'e1590.png',
133 | 'e1591.png',
134 | 'e1592.png',
135 | 'e1593.png',
136 | 'e1594.png',
137 | 'e1595.png',
138 | 'e1596.png',
139 | 'e1597.png',
140 | 'e1598.png',
141 | 'e1599.png',
142 | 'e1600.png',
143 | 'e1600.png',
144 | 'e1601.png',
145 | 'e1602.png',
146 | 'e1603.png',
147 | 'e1604.png',
148 | 'e1605.png',
149 | 'e1606.png',
150 | 'e1607.png',
151 | 'e1608.png',
152 | 'e1609.png',
153 | 'e1610.png',
154 | 'e1611.png',
155 | 'e1612.png',
156 | 'e1613.png',
157 | 'e1614.png',
158 | 'e1615.png',
159 | 'e1616.png',
160 | 'e1617.png',
161 | 'e1618.png',
162 | 'e1619.png',
163 | 'e1620.png',
164 | 'e1621.png',
165 | 'e1622.png',
166 | 'e1623.png',
167 | 'e1624.png',
168 | 'e1625.png',
169 | 'e1626.png',
170 | 'e1627.png',
171 | 'e1628.png',
172 | 'e1629.png',
173 | 'e1630.png',
174 | 'e1631.png',
175 | 'e1632.png',
176 | 'e1633.png',
177 | 'e1634.png',
178 | 'e1635.png',
179 | 'e1636.png',
180 | 'e1637.png',
181 | 'e1638.png',
182 | 'e1639.png',
183 | 'e1640.png',
184 | 'e1641.png',
185 | 'e1642.png',
186 | 'e1643.png',
187 | 'e1644.png',
188 | 'e1645.png',
189 | 'e1646.png',
190 | 'e1647.png',
191 | 'e1648.png',
192 | 'e1649.png',
193 | 'e1650.png',
194 | 'e1651.png',
195 | 'e1652.png',
196 | 'e1653.png',
197 | 'e1654.png',
198 | 'e1655.png',
199 | 'e1656.png',
200 | 'e1657.png',
201 | 'e1658.png',
202 | 'e1659.png',
203 | 'e1660.png',
204 | 'e1661.png',
205 | 'e1662.png',
206 | 'e1663.png',
207 | 'e1664.png',
208 | 'e1665.png',
209 | 'e1666.png',
210 | 'e1757.png',
211 | 'e1758.png',
212 | 'e1759.png',
213 | 'e1760.png',
214 | 'e1761.png',
215 | 'e1762.png',
216 | 'e1763.png',
217 | 'e1764.png',
218 | 'e1765.png',
219 | 'e1766.png',
220 | 'e1767.png',
221 | 'e1768.png',
222 | 'e1769.png',
223 | 'e1779.png',
224 | 'e1780.png',
225 | 'e1781.png',
226 | 'e1782.png',
227 | 'e1783.png',
228 | 'e1784.png',
229 | 'e1785.png',
230 | 'e1791.png',
231 | 'e1791.png',
232 | 'e1792.png',
233 | 'e1793.png',
234 | 'e1794.png',
235 | 'e1795.png',
236 | 'e1796.png',
237 | 'e1799.png',
238 | 'e1819.png',
239 | 'e1820.png',
240 | 'e1821.png',
241 | 'e1822.png',
242 | 'e1823.png',
243 | 'e1824.png',
244 |
245 | ];
246 |
247 | }
--------------------------------------------------------------------------------
/lib/src/const/filters.dart:
--------------------------------------------------------------------------------
1 | // No Filter: Identity Matrix
2 | import 'package:flutter/material.dart';
3 |
4 | const noFiler = [
5 | 1.0, 0.0, 0.0, 0.0, 0.0,
6 | 0.0, 1.0, 0.0, 0.0, 0.0,
7 | 0.0, 0.0, 1.0, 0.0, 0.0,
8 | 0.0, 0.0, 0.0, 1.0, 0.0
9 | ];
10 |
11 | // Black & White
12 | const blackAndWhiteFilter = [
13 | 0.3, 0.6, 0.1, 0.0, 0.0,
14 | 0.3, 0.6, 0.1, 0.0, 0.0,
15 | 0.3, 0.6, 0.1, 0.0, 0.0,
16 | 0.0, 0.0, 0.0, 1.0, 0.0
17 | ];
18 |
19 |
20 | // Pop: Increase saturation
21 | const popFilter = [
22 | 1.3, 0.0, 0.0, 0.0, 0.0,
23 | 0.0, 1.3, 0.0, 0.0, 0.0,
24 | 0.0, 0.0, 1.3, 0.0, 0.0,
25 | 0.0, 0.0, 0.0, 1.0, 0.0
26 | ];
27 |
28 | // Cool: Add a blue tint
29 | const coolFilter = [
30 | 1.0, 0.0, 0.0, 0.0, 0.0,
31 | 0.0, 1.0, 0.0, 0.0, 0.0,
32 | 0.0, 0.0, 1.2, 0.0, 0.0,
33 | 0.0, 0.0, 0.0, 1.0, 0.0
34 | ];
35 |
36 | // Chrome: Increase contrast
37 | const chromeFilter = [
38 | 1.5, 0.0, 0.0, 0.0, -0.2,
39 | 0.0, 1.5, 0.0, 0.0, -0.2,
40 | 0.0, 0.0, 1.5, 0.0, -0.2,
41 | 0.0, 0.0, 0.0, 1.0, 0.0
42 | ];
43 |
44 | // Film: Decrease saturation
45 | const filmFilter = [
46 | 0.8, 0.2, 0.2, 0.0, 0.0,
47 | 0.2, 0.8, 0.2, 0.0, 0.0,
48 | 0.2, 0.2, 0.8, 0.0, 0.0,
49 | 0.0, 0.0, 0.0, 1.0, 0.0
50 | ];
51 |
52 | final List textFilterColors = [
53 | Colors.white,
54 | Colors.black,
55 | Colors.red,
56 | Colors.orange,
57 | Colors.yellow,
58 | Colors.green,
59 | Colors.blue,
60 | Colors.indigo,
61 | Colors.purple, // Violet
62 | Colors.brown,
63 | ];
64 |
65 | List fontStyles = [
66 | const TextStyle(fontFamily: 'Roboto', color: Colors.white),
67 | const TextStyle(fontFamily: 'Merriweather', color: Colors.white),
68 | const TextStyle(fontFamily: 'Madimi One', fontWeight: FontWeight.bold, color: Colors.white),
69 |
70 | // Serif fonts (with small "tails" on letters):
71 | const TextStyle(fontFamily: 'Dancing Script', color: Colors.white),
72 | const TextStyle(fontFamily: 'Angkor', color: Colors.white),
73 | const TextStyle(fontFamily: 'Pacifico', color: Colors.white),
74 |
75 | // Sans-serif fonts (clean, without tails):
76 | const TextStyle(fontFamily: 'Montserrat', color: Colors.white),
77 | const TextStyle(fontFamily: 'Lato', color: Colors.white),
78 |
79 | // More stylized choices:
80 | const TextStyle(fontFamily: 'Oswald', color: Colors.white),
81 | const TextStyle(fontFamily: 'Raleway', color: Colors.white),
82 | const TextStyle(fontFamily: 'Lora', color: Colors.white),
83 | ];
84 |
--------------------------------------------------------------------------------
/lib/src/controller/controller.dart:
--------------------------------------------------------------------------------
1 |
2 |
3 | import 'dart:io';
4 | import 'package:flutter/material.dart';
5 | import 'package:flutter_story_editor/src/const/filters.dart';
6 | import 'package:flutter_story_editor/src/enums/story_editing_modes.dart';
7 | import 'package:flutter_story_editor/src/models/stroke.dart';
8 |
9 |
10 | /// A controller class for managing state in a Flutter story editing application.
11 | ///
12 | /// This class uses `ChangeNotifier` to provide updates to listeners about changes in the editing state,
13 | /// selected files, applied filters, and stroke data for the story being edited.
14 | class FlutterStoryEditorController extends ChangeNotifier {
15 | // Notifier for the current editing mode.
16 | final editingModeNotifier = ValueNotifier(StoryEditingModes.none);
17 |
18 | /// Gets the currently selected editing mode.
19 | StoryEditingModes get editingModeSelected => editingModeNotifier.value;
20 |
21 | /// Sets the editing mode and notifies listeners.
22 | set setStoryEditingModeSelected(StoryEditingModes newStoryEditingSelectedMode) {
23 | editingModeNotifier.value = newStoryEditingSelectedMode;
24 | notifyListeners();
25 | }
26 |
27 | // Notifier for the currently selected file.
28 | final fileNotifier = ValueNotifier(null);
29 |
30 | /// Gets the currently selected file.
31 | File? get fileSelected => fileNotifier.value;
32 |
33 | /// Sets the selected file and notifies listeners.
34 | set setFileSelected(File? newFile) {
35 | fileNotifier.value = newFile;
36 | notifyListeners();
37 | }
38 |
39 | // Notifier for the currently applied filter.
40 | final filterNotifier = ValueNotifier>(noFiler);
41 |
42 | /// Gets the currently applied filter.
43 | List? get filterSelected => filterNotifier.value;
44 |
45 | /// Sets the applied filter and notifies listeners.
46 | set setFilterSelected(List newFilter) {
47 | filterNotifier.value = newFilter;
48 | notifyListeners();
49 | }
50 |
51 | // Notifier for the lines editable on the UI, stored per file.
52 | final ValueNotifier>> uiEditableFileLinesNotifier = ValueNotifier>>([]);
53 |
54 | /// Gets the list of editable lines for all files.
55 | List> get uiEditableFileLines => uiEditableFileLinesNotifier.value;
56 |
57 | /// Sets the lines for a specific file index and notifies listeners.
58 | void setUiEditableFileLines(int index, List newLines) {
59 | uiEditableFileLinesNotifier.value[index] = newLines;
60 | // Ensuring a new list reference is set to trigger listeners
61 | uiEditableFileLinesNotifier.value = [...uiEditableFileLines];
62 | uiEditableFileLinesNotifier.notifyListeners();
63 | }
64 |
65 | /// Initializes editable lines for a specified number of files.
66 | void initializeUiEditableFileLines(int count) {
67 | uiEditableFileLinesNotifier.value = List.generate(count, (index) => []);
68 | notifyListeners();
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/lib/src/enums/story_editing_modes.dart:
--------------------------------------------------------------------------------
1 |
2 |
3 | enum StoryEditingModes {
4 | none,
5 | filters,
6 | paint,
7 | text,
8 | stickers,
9 | }
--------------------------------------------------------------------------------
/lib/src/enums/stroke_type.dart:
--------------------------------------------------------------------------------
1 |
2 | enum StrokeType { pen, marker, neon }
--------------------------------------------------------------------------------
/lib/src/models/simple_sketecher.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:perfect_freehand/perfect_freehand.dart';
3 |
4 | import 'stroke.dart';
5 |
6 |
7 |
8 | /// A custom painter class that draws a list of strokes on a canvas.
9 | ///
10 | /// Uses the `perfect_freehand` package to generate stroke outlines for natural hand-drawn effects.
11 | /// This painter is designed to be used in scenarios where dynamic, free-form drawing is needed.
12 | ///
13 | /// [lines] - List of `Stroke` objects containing the details of each line to be drawn, including points, color, and stroke options.
14 | class SimpleSketcher extends CustomPainter {
15 | final List lines;
16 |
17 | /// Constructs a `SimpleSketcher` that will paint the provided [lines].
18 | SimpleSketcher(this.lines);
19 |
20 | @override
21 | void paint(Canvas canvas, Size size) {
22 | Paint paint = Paint()
23 | ..strokeJoin = StrokeJoin.round // Ensures that stroke joins are rounded.
24 | ..strokeCap = StrokeCap.round // Ends of lines are rounded.
25 | ..strokeMiterLimit = 5 // The limit for the miter when strokes join.
26 | ..filterQuality = FilterQuality.high // Higher quality filter settings for better anti-aliasing.
27 | ..style = PaintingStyle.fill; // The paint will be used to fill the drawing.
28 |
29 | for (Stroke line in lines) {
30 | final options = line.options;
31 | final outlinePoints = getStroke(
32 | line.points,
33 | options: StrokeOptions(
34 | size: options.size, // The thickness of the stroke.
35 | thinning: options.thinning, // The degree to which the stroke thickness is reduced based on velocity.
36 | smoothing: options.smoothing, // How much the input points are smoothed before drawing.
37 | streamline: options.streamline, // How much the input points are corrected to form a smoother line.
38 | start: options.start, // Start tapering length.
39 | end: options.end, // End tapering length.
40 | simulatePressure: options.simulatePressure, // Simulates pressure sensitivity.
41 | isComplete: options.isComplete, // Indicates if the stroke is complete.
42 | ),
43 | );
44 |
45 | paint.color = line.color; // Set the color of the stroke.
46 |
47 | final path = Path();
48 | if (outlinePoints.isEmpty) return;
49 | if (outlinePoints.length < 2) {
50 | // Draws a circle for a single point to ensure it's visible.
51 | path.addOval(Rect.fromCircle(center: Offset(outlinePoints[0].dx, outlinePoints[0].dy), radius: 1));
52 | } else {
53 | // Draws the stroke as a series of quadratic bezier curves.
54 | path.moveTo(outlinePoints[0].dx, outlinePoints[0].dy);
55 | for (int i = 1; i < outlinePoints.length - 1; i++) {
56 | final p0 = outlinePoints[i];
57 | final p1 = outlinePoints[i + 1];
58 | path.quadraticBezierTo(p0.dx, p0.dy, (p0.dx + p1.dx) / 2, (p0.dy + p1.dy) / 2);
59 | }
60 | }
61 | canvas.drawPath(path, paint);
62 | }
63 | }
64 |
65 | @override
66 | bool shouldRepaint(SimpleSketcher oldDelegate) {
67 | // Indicates whether the painter should repaint.
68 | return oldDelegate.lines != lines;
69 | }
70 | }
71 |
72 |
73 |
74 |
--------------------------------------------------------------------------------
/lib/src/models/stroke.dart:
--------------------------------------------------------------------------------
1 |
2 | import 'package:flutter/material.dart';
3 | import 'package:perfect_freehand/perfect_freehand.dart';
4 |
5 | class Stroke {
6 | final List points;
7 | final Color color;
8 | final StrokeOptions options;
9 | const Stroke(this.points, this.color, this.options);
10 | }
--------------------------------------------------------------------------------
/lib/src/models/stroke_options.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_story_editor/src/enums/stroke_type.dart';
3 |
4 | class StrokeOptions {
5 | /// The base size (diameter) of the stroke.
6 | /// Range: [0,100]
7 | double size;
8 |
9 | /// The effect of pressure on the stroke's size.
10 | /// Range: [-1,1]
11 | double thinning;
12 |
13 | /// Controls the density of points along the stroke's edges.
14 | /// Range: [0,1]
15 | double smoothing;
16 |
17 | /// Controls the level of variation allowed in the input points.
18 | /// Range: [0,1]
19 | double streamline;
20 |
21 | // Whether to simulate pressure or use the point's provided pressures.
22 | final bool simulatePressure;
23 |
24 | // The distance to taper the front of the stroke.
25 | // Range: [0,100]
26 | double taperStart;
27 |
28 | // The distance to taper the end of the stroke.
29 | // Range: [0,100]
30 | double taperEnd;
31 |
32 | // Whether to add a cap to the start of the stroke.
33 | final bool capStart;
34 |
35 | // Whether to add a cap to the end of the stroke.
36 | final bool capEnd;
37 |
38 | // Whether the line is complete.
39 | final bool isComplete;
40 |
41 | //color of line
42 | Color color;
43 |
44 | StrokeType strokeType;
45 |
46 | StrokeOptions(
47 | {this.size = 3,
48 | this.thinning = 0.2,
49 | this.smoothing = 0.5,
50 | this.streamline = 0.5,
51 | this.taperStart = 0.0,
52 | this.capStart = true,
53 | this.taperEnd = 0.0,
54 | this.capEnd = true,
55 | this.simulatePressure = true,
56 | this.isComplete = false,
57 | this.color = Colors.white,
58 | this.strokeType = StrokeType.pen
59 | });
60 | }
--------------------------------------------------------------------------------
/lib/src/theme/style.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | const darkGreenColor = Color.fromRGBO(31, 44, 52, 1);
4 | const tealColor = Color.fromRGBO(0, 167, 131, 1);
5 |
6 |
--------------------------------------------------------------------------------
/lib/src/utils/matrix_gesture_detector.dart:
--------------------------------------------------------------------------------
1 |
2 | import 'dart:math';
3 |
4 | import 'package:flutter/widgets.dart';
5 |
6 | typedef MatrixGestureDetectorCallback = void Function(
7 | Matrix4 matrix,
8 | Matrix4 translationDeltaMatrix,
9 | Matrix4 scaleDeltaMatrix,
10 | Matrix4 rotationDeltaMatrix);
11 |
12 | /// [MatrixGestureDetector] detects translation, scale and rotation gestures
13 | /// and combines them into [Matrix4] object that can be used by [Transform] widget
14 | /// or by low level [CustomPainter] code. You can customize types of reported
15 | /// gestures by passing [shouldTranslate], [shouldScale] and [shouldRotate]
16 | /// parameters.
17 | ///
18 | class MatrixGestureDetector extends StatefulWidget {
19 | /// [Matrix4] change notification callback
20 | ///
21 | final MatrixGestureDetectorCallback onMatrixUpdate;
22 |
23 | /// The [child] contained by this detector.
24 | ///
25 | /// {@macro flutter.widgets.child}
26 | ///
27 | final Widget child;
28 |
29 | /// Whether to detect translation gestures during the event processing.
30 | ///
31 | /// Defaults to true.
32 | ///
33 | final bool shouldTranslate;
34 |
35 | /// Whether to detect scale gestures during the event processing.
36 | ///
37 | /// Defaults to true.
38 | ///
39 | final bool shouldScale;
40 |
41 | /// Whether to detect rotation gestures during the event processing.
42 | ///
43 | /// Defaults to true.
44 | ///
45 | final bool shouldRotate;
46 |
47 | /// Whether [ClipRect] widget should clip [child] widget.
48 | ///
49 | /// Defaults to true.
50 | ///
51 | final bool clipChild;
52 |
53 | /// The hit test behavior, passed to the underlying GestureDetector.
54 | ///
55 | /// Defaults to HitTestBehavior.deferToChild
56 | ///
57 | final HitTestBehavior behavior;
58 |
59 | /// When set, it will be used for computing a "fixed" focal point
60 | /// aligned relative to the size of this widget.
61 | final Alignment? focalPointAlignment;
62 |
63 | const MatrixGestureDetector({
64 | super.key,
65 | required this.onMatrixUpdate,
66 | required this.child,
67 | this.shouldTranslate = true,
68 | this.shouldScale = true,
69 | this.shouldRotate = true,
70 | this.clipChild = true,
71 | this.focalPointAlignment,
72 | this.behavior = HitTestBehavior.deferToChild,
73 | });
74 |
75 | @override
76 | MatrixGestureDetectorState createState() => MatrixGestureDetectorState();
77 |
78 | ///
79 | /// Compose the matrix from translation, scale and rotation matrices - you can
80 | /// pass a null to skip any matrix from composition.
81 | ///
82 | /// If [matrix] is not null the result of the composing will be concatenated
83 | /// to that [matrix], otherwise the identity matrix will be used.
84 | ///
85 | static Matrix4 compose(Matrix4? matrix, Matrix4? translationMatrix,
86 | Matrix4? scaleMatrix, Matrix4? rotationMatrix) {
87 | matrix ??= Matrix4.identity();
88 | if (translationMatrix != null) matrix = translationMatrix * matrix;
89 | if (scaleMatrix != null) matrix = scaleMatrix * matrix;
90 | if (rotationMatrix != null) matrix = rotationMatrix * matrix;
91 | return matrix!;
92 | }
93 |
94 | ///
95 | /// Decomposes [matrix] into [MatrixDecomposedValues.translation],
96 | /// [MatrixDecomposedValues.scale] and [MatrixDecomposedValues.rotation] components.
97 | ///
98 | static MatrixDecomposedValues decomposeToValues(Matrix4 matrix) {
99 | var array = matrix.applyToVector3Array([0, 0, 0, 1, 0, 0]);
100 | Offset translation = Offset(array[0], array[1]);
101 | Offset delta = Offset(array[3] - array[0], array[4] - array[1]);
102 | double scale = delta.distance;
103 | double rotation = delta.direction;
104 | return MatrixDecomposedValues(translation, scale, rotation);
105 | }
106 | }
107 |
108 | class MatrixGestureDetectorState extends State {
109 | Matrix4 translationDeltaMatrix = Matrix4.identity();
110 | Matrix4 scaleDeltaMatrix = Matrix4.identity();
111 | Matrix4 rotationDeltaMatrix = Matrix4.identity();
112 | Matrix4 matrix = Matrix4.identity();
113 |
114 | @override
115 | Widget build(BuildContext context) {
116 | Widget child =
117 | widget.clipChild ? ClipRect(child: widget.child) : widget.child;
118 | return GestureDetector(
119 | behavior: widget.behavior,
120 | onScaleStart: onScaleStart,
121 | onScaleUpdate: onScaleUpdate,
122 | child: child,
123 | );
124 | }
125 |
126 | ValueUpdater translationUpdater = ValueUpdater(
127 | value: Offset.zero,
128 | onUpdate: (oldVal, newVal) => newVal - oldVal,
129 | );
130 | ValueUpdater scaleUpdater = ValueUpdater(
131 | value: 1.0,
132 | onUpdate: (oldVal, newVal) => newVal / oldVal,
133 | );
134 | ValueUpdater rotationUpdater = ValueUpdater(
135 | value: 0.0,
136 | onUpdate: (oldVal, newVal) => newVal - oldVal,
137 | );
138 |
139 | void onScaleStart(ScaleStartDetails details) {
140 | translationUpdater.value = details.focalPoint;
141 | scaleUpdater.value = 1.0;
142 | rotationUpdater.value = 0.0;
143 | }
144 |
145 | void onScaleUpdate(ScaleUpdateDetails details) {
146 | translationDeltaMatrix = Matrix4.identity();
147 | scaleDeltaMatrix = Matrix4.identity();
148 | rotationDeltaMatrix = Matrix4.identity();
149 |
150 | // handle matrix translating
151 | if (widget.shouldTranslate) {
152 | Offset translationDelta = translationUpdater.update(details.focalPoint);
153 | translationDeltaMatrix = _translate(translationDelta);
154 | matrix = translationDeltaMatrix * matrix;
155 | }
156 |
157 | final focalPointAlignment = widget.focalPointAlignment;
158 | final focalPoint = focalPointAlignment == null
159 | ? details.localFocalPoint
160 | : focalPointAlignment.alongSize(context.size!);
161 |
162 | // handle matrix scaling
163 | if (widget.shouldScale && details.scale != 1.0) {
164 | double scaleDelta = scaleUpdater.update(details.scale);
165 | scaleDeltaMatrix = _scale(scaleDelta, focalPoint);
166 | matrix = scaleDeltaMatrix * matrix;
167 | }
168 |
169 | // handle matrix rotating
170 | if (widget.shouldRotate && details.rotation != 0.0) {
171 | double rotationDelta = rotationUpdater.update(details.rotation);
172 | rotationDeltaMatrix = _rotate(rotationDelta, focalPoint);
173 | matrix = rotationDeltaMatrix * matrix;
174 | }
175 |
176 | widget.onMatrixUpdate(
177 | matrix, translationDeltaMatrix, scaleDeltaMatrix, rotationDeltaMatrix);
178 | }
179 |
180 | Matrix4 _translate(Offset translation) {
181 | var dx = translation.dx;
182 | var dy = translation.dy;
183 |
184 | // ..[0] = 1 # x scale
185 | // ..[5] = 1 # y scale
186 | // ..[10] = 1 # diagonal "one"
187 | // ..[12] = dx # x translation
188 | // ..[13] = dy # y translation
189 | // ..[15] = 1 # diagonal "one"
190 | return Matrix4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, dx, dy, 0, 1);
191 | }
192 |
193 | Matrix4 _scale(double scale, Offset focalPoint) {
194 | var dx = (1 - scale) * focalPoint.dx;
195 | var dy = (1 - scale) * focalPoint.dy;
196 |
197 | // ..[0] = scale # x scale
198 | // ..[5] = scale # y scale
199 | // ..[10] = 1 # diagonal "one"
200 | // ..[12] = dx # x translation
201 | // ..[13] = dy # y translation
202 | // ..[15] = 1 # diagonal "one"
203 | return Matrix4(scale, 0, 0, 0, 0, scale, 0, 0, 0, 0, 1, 0, dx, dy, 0, 1);
204 | }
205 |
206 | Matrix4 _rotate(double angle, Offset focalPoint) {
207 | var c = cos(angle);
208 | var s = sin(angle);
209 | var dx = (1 - c) * focalPoint.dx + s * focalPoint.dy;
210 | var dy = (1 - c) * focalPoint.dy - s * focalPoint.dx;
211 |
212 | // ..[0] = c # x scale
213 | // ..[1] = s # y skew
214 | // ..[4] = -s # x skew
215 | // ..[5] = c # y scale
216 | // ..[10] = 1 # diagonal "one"
217 | // ..[12] = dx # x translation
218 | // ..[13] = dy # y translation
219 | // ..[15] = 1 # diagonal "one"
220 | return Matrix4(c, s, 0, 0, -s, c, 0, 0, 0, 0, 1, 0, dx, dy, 0, 1);
221 | }
222 | }
223 |
224 | typedef OnUpdate = T Function(T oldValue, T newValue);
225 |
226 | class ValueUpdater {
227 | final OnUpdate onUpdate;
228 | T value;
229 |
230 | ValueUpdater({
231 | required this.value,
232 | required this.onUpdate,
233 | });
234 |
235 | T update(T newValue) {
236 | T updated = onUpdate(value, newValue);
237 | value = newValue;
238 | return updated;
239 | }
240 | }
241 |
242 | class MatrixDecomposedValues {
243 | /// Translation, in most cases useful only for matrices that are nothing but
244 | /// a translation (no scale and no rotation).
245 | final Offset translation;
246 |
247 | /// Scaling factor.
248 | final double scale;
249 |
250 | /// Rotation in radians, (-pi..pi) range.
251 | final double rotation;
252 |
253 | MatrixDecomposedValues(this.translation, this.scale, this.rotation);
254 |
255 | @override
256 | String toString() {
257 | return 'MatrixDecomposedValues(translation: $translation, scale: ${scale.toStringAsFixed(3)}, rotation: ${rotation.toStringAsFixed(3)})';
258 | }
259 | }
--------------------------------------------------------------------------------
/lib/src/utils/utils.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 | import 'dart:typed_data';
3 | import 'dart:ui' as ui;
4 | import 'package:flutter/material.dart';
5 | import 'package:flutter/rendering.dart';
6 | import 'package:flutter_story_editor/src/theme/style.dart';
7 | import 'package:image_cropper/image_cropper.dart';
8 | import 'package:path_provider/path_provider.dart';
9 | import 'package:video_thumbnail/video_thumbnail.dart';
10 |
11 | /// Generates a thumbnail from a video file.
12 | ///
13 | /// [file] - The video file from which to generate the thumbnail.
14 | ///
15 | /// Returns a [Uint8List] containing the thumbnail data, or null if the file is not a video or is null.
16 | Future generateThumbnail(File? file) async {
17 | if (file == null) return null;
18 |
19 | Uint8List? thumbnail;
20 | // Supports mp4, mov, avi formats.
21 | if (file.path.endsWith('.mp4') || file.path.endsWith('.mov') || file.path.endsWith('.avi')) {
22 | thumbnail = await VideoThumbnail.thumbnailData(
23 | video: file.path,
24 | imageFormat: ImageFormat.JPEG,
25 | maxWidth: 128, // Width of the thumbnail.
26 | quality: 15, // Quality of the thumbnail.
27 | );
28 | }
29 |
30 | return thumbnail;
31 | }
32 |
33 | /// Converts a widget to an image file using its GlobalKey.
34 | ///
35 | /// [key] - GlobalKey of the widget to be converted.
36 | ///
37 | /// Returns a [File] containing the image data, or null if conversion fails.
38 | Future convertWidgetToImage(GlobalKey key) async {
39 | RenderRepaintBoundary? boundary = key.currentContext?.findRenderObject() as RenderRepaintBoundary?;
40 |
41 | if (boundary != null && boundary.isRepaintBoundary) {
42 | ui.Image boxImage = await boundary.toImage(pixelRatio: 3.0);
43 | ByteData? byteData = await boxImage.toByteData(format: ui.ImageByteFormat.png);
44 |
45 | if (byteData != null) {
46 | Uint8List imageData = byteData.buffer.asUint8List();
47 | final tempDir = await getTemporaryDirectory();
48 | final file = File('${tempDir.path}/image${DateTime.now().millisecondsSinceEpoch}.png');
49 | await file.create();
50 | await file.writeAsBytes(imageData);
51 |
52 | return file;
53 | }
54 | }
55 | return null;
56 | }
57 |
58 | /// Converts multiple widgets to images based on their GlobalKeys.
59 | ///
60 | /// [keys] - List of GlobalKeys for the widgets to be converted.
61 | ///
62 | /// Returns a list of [File]s containing the image data. Throws an exception if conversion fails.
63 | Future?> convertWidgetsToImages(List keys) async {
64 | List files = [];
65 |
66 | for (GlobalKey key in keys) {
67 | File? file = await convertWidgetToImage(key);
68 | if (file != null) files.add(file);
69 | }
70 |
71 | return files.isNotEmpty ? files : null;
72 | }
73 |
74 | /// Crops an image file.
75 | ///
76 | /// [context] - Build context from which this function is invoked.
77 | /// [file] - File to be cropped.
78 | ///
79 | /// Returns a [CroppedFile] containing the cropped image data, or null if cropping is cancelled.
80 | Future cropImage(BuildContext context, {required File file}) async {
81 | CroppedFile? croppedFile = await ImageCropper.platform.cropImage(
82 | sourcePath: file.path,
83 | aspectRatioPresets: Platform.isAndroid
84 | ? [CropAspectRatioPreset.square, CropAspectRatioPreset.ratio3x2, CropAspectRatioPreset.original, CropAspectRatioPreset.ratio4x3, CropAspectRatioPreset.ratio16x9]
85 | : [CropAspectRatioPreset.original, CropAspectRatioPreset.square, CropAspectRatioPreset.ratio3x2, CropAspectRatioPreset.ratio4x3, CropAspectRatioPreset.ratio5x3, CropAspectRatioPreset.ratio5x4, CropAspectRatioPreset.ratio7x5, CropAspectRatioPreset.ratio16x9],
86 | uiSettings: [
87 | AndroidUiSettings(toolbarTitle: 'Crop Image', toolbarColor: darkGreenColor, toolbarWidgetColor: Colors.white, activeControlsWidgetColor: tealColor, initAspectRatio: CropAspectRatioPreset.original, lockAspectRatio: false),
88 | IOSUiSettings(title: 'Crop Image'),
89 | WebUiSettings(context: context),
90 | ]);
91 |
92 | return croppedFile;
93 | }
94 |
95 | /// Determines if a file is a video.
96 | ///
97 | /// [file] - File to be checked.
98 | ///
99 | /// Returns [true] if the file is a video (.mp4, .mov, .avi); otherwise, returns [false].
100 | bool isVideo(File file) {
101 | return file.path.endsWith('.mp4') || file.path.endsWith('.mov') || file.path.endsWith('.avi');
102 | }
103 |
--------------------------------------------------------------------------------
/lib/src/views/main_control_views/caption_view.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_story_editor/src/theme/style.dart';
3 | import 'package:font_awesome_flutter/font_awesome_flutter.dart';
4 |
5 | // CaptionView is a StatelessWidget that provides UI for entering captions and initiating save operations.
6 | class CaptionView extends StatelessWidget {
7 | final TextEditingController captionController; // Controller for text input.
8 | final VoidCallback onSaveClickListener; // Callback function when the save button is clicked.
9 | final FocusNode? focusNode; // Optional focus node to manage focus behavior.
10 | final bool isSaving; // Boolean indicating whether a save operation is in progress.
11 |
12 | // Constructor initializing all fields with required annotations for mandatory fields.
13 | const CaptionView({
14 | super.key,
15 | required this.captionController,
16 | required this.onSaveClickListener,
17 | required this.isSaving,
18 | this.focusNode
19 | });
20 |
21 | @override
22 | Widget build(BuildContext context) {
23 | // Building the widget structure for the caption view.
24 | return Column(
25 | children: [
26 | Container(
27 | margin: const EdgeInsets.symmetric(horizontal: 10),
28 | width: double.infinity,
29 | height: 50,
30 | decoration: BoxDecoration(
31 | borderRadius: BorderRadius.circular(25), // Rounded corners for aesthetic appeal.
32 | color: darkGreenColor), // Background color set to dark green.
33 | child: TextFormField(
34 | focusNode: focusNode, // Assigning focus node if provided.
35 | controller: captionController, // Using the provided TextEditingController for text editing.
36 | style: const TextStyle(fontSize: 18), // Text style customization.
37 | cursorColor: tealColor, // Cursor color set to teal for visual consistency.
38 | decoration: const InputDecoration(
39 | border: InputBorder.none, // No visual border for the input field.
40 | prefixIcon: Icon(
41 | Icons.emoji_emotions_outlined,
42 | color: Colors.white,
43 | size: 28,
44 | ), // Icon for a visual hint at the start of the input field.
45 | hintText: "Add a caption...", // Placeholder text.
46 | contentPadding: EdgeInsets.symmetric(vertical: 15), // Padding inside the input field.
47 | hintStyle: TextStyle(color: Colors.white)), // Hint text style.
48 | ),
49 | ),
50 | Container(
51 | margin: const EdgeInsets.symmetric(horizontal: 10, vertical: 10),
52 | child: Row(
53 | mainAxisAlignment: MainAxisAlignment.spaceBetween, // Aligning children to the start and end of the row.
54 | children: [
55 | Container(
56 | padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 5),
57 | decoration: BoxDecoration(
58 | borderRadius: BorderRadius.circular(20), // Rounded corners for the container.
59 | color: darkGreenColor, // Background color set to dark green.
60 | ),
61 | child: const Row(
62 | children: [
63 | Icon(FontAwesomeIcons.circle, color: Colors.white,), // Icon for decorative purposes.
64 | SizedBox(
65 | width: 5,
66 | ),
67 | Text("Status (Contacts)", style: TextStyle(color: Colors.white),) // Text indicating the status.
68 | ],
69 | ),
70 | ),
71 | GestureDetector(
72 | onTap: onSaveClickListener, // Gesture detector to handle tap events on the save button.
73 | child: Container(
74 | width: 45,
75 | height: 45,
76 | decoration: BoxDecoration(
77 | borderRadius: BorderRadius.circular(25), // Rounded corners for the button.
78 | color: tealColor), // Background color set to teal.
79 | child: Center(
80 | child: isSaving
81 | ? const SizedBox(
82 | width: 20,
83 | height: 20,
84 | child: CircularProgressIndicator(
85 | color: Colors.white,
86 | ),
87 | ) // Circular progress indicator when saving.
88 | : const Icon(
89 | Icons.send_outlined,
90 | color: Colors.white,
91 | ), // Icon indicating send action.
92 | ),
93 | ),
94 | ),
95 | ],
96 | ),
97 | ),
98 | ],
99 | );
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/lib/src/views/main_control_views/filter_text_view.dart:
--------------------------------------------------------------------------------
1 |
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_story_editor/src/controller/controller.dart';
4 | import 'package:flutter_story_editor/src/enums/story_editing_modes.dart';
5 |
6 | class FilterTextView extends StatelessWidget {
7 | final FlutterStoryEditorController controller; // FlutterStoryEditorController to take decision based on certain editing state
8 | const FilterTextView({super.key, required this.controller});
9 |
10 | @override
11 | Widget build(BuildContext context) {
12 | return AnimatedOpacity(
13 | duration: const Duration(milliseconds: 200),
14 | opacity: controller.editingModeSelected ==StoryEditingModes.filters ? 0 : 1,
15 | child: AnimatedContainer(
16 | height: controller.editingModeSelected ==StoryEditingModes.filters
17 | ? 100
18 | : 50, // change height based on showFilters
19 | duration: const Duration(milliseconds: 300),
20 | child: const Column(
21 | children: [
22 | Icon(
23 | Icons.keyboard_arrow_up,
24 | size: 25,
25 | color: Colors.white,
26 | ),
27 | Text(
28 | "Filters",
29 | style: TextStyle(
30 | fontSize: 16,
31 | fontWeight: FontWeight.w400,
32 | color: Colors.white),
33 | ),
34 | ],
35 | ),
36 | ),
37 | );
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/lib/src/views/main_control_views/filters_view.dart:
--------------------------------------------------------------------------------
1 |
2 | import 'dart:io';
3 |
4 | import 'package:flutter/material.dart';
5 | import 'package:flutter_story_editor/src/const/const.dart';
6 | import 'package:flutter_story_editor/src/theme/style.dart';
7 |
8 | // FiltersView is a StatefulWidget that displays a horizontal list of filters for users to apply to their media.
9 | class FiltersView extends StatefulWidget {
10 | final List> selectedFilters; // List holding currently selected filters for each page.
11 | final List? selectedFiles; // Optional list of media files to apply filters on.
12 | final int currentPageIndex; // Index to identify the current page or media file.
13 | final Function(List) onFilterChange; // Callback function triggered on changing a filter.
14 |
15 | // Constructor initializing FiltersView with necessary parameters.
16 | const FiltersView({
17 | super.key,
18 | required this.selectedFilters,
19 | this.selectedFiles,
20 | required this.currentPageIndex,
21 | required this.onFilterChange
22 | });
23 |
24 | @override
25 | State createState() => _FiltersViewState();
26 | }
27 |
28 | // State class for FiltersView handling the UI and interaction.
29 | class _FiltersViewState extends State {
30 | @override
31 | Widget build(BuildContext context) {
32 | // Builds a scrollable horizontal list of filter options.
33 | return Container(
34 | height: 120, // Fixed height for the filter container.
35 | decoration: const BoxDecoration(color: darkGreenColor), // Background decoration of the filter container.
36 | child: ListView.builder(
37 | padding: const EdgeInsets.only(right: 10, left: 5),
38 | itemCount: Consts.filters.length, // Number of filters available from a constant source.
39 | scrollDirection: Axis.horizontal, // Makes the ListView scrollable horizontally.
40 | itemBuilder: (context, index) {
41 | return GestureDetector(
42 | onTap: () {
43 | setState(() {
44 | widget.selectedFilters[widget.currentPageIndex] = Consts.filters[index]; // Updates the selected filter for the current page.
45 | });
46 | widget.onFilterChange(widget.selectedFilters[widget.currentPageIndex]); // Triggers the callback with the new filter selection.
47 | },
48 | child: Container(
49 | margin: const EdgeInsets.only(top: 10, bottom: 10, left: 8),
50 | width: 65, // Fixed width for each filter item.
51 | height: 100, // Fixed height for each filter item.
52 | child: Stack(
53 | children: [
54 | // Displays the image with the selected filter applied.
55 | Positioned(
56 | top: 0,
57 | bottom: 0,
58 | left: 0,
59 | right: 0,
60 | child: ColorFiltered(
61 | colorFilter: ColorFilter.matrix(Consts.filters[index]),
62 | child: Image.file(
63 | widget.selectedFiles![widget.currentPageIndex],
64 | fit: BoxFit.cover,
65 | ),
66 | ),
67 | ),
68 | // Shows a checkmark if this filter is currently selected.
69 | widget.selectedFilters[widget.currentPageIndex] == Consts.filters[index]
70 | ? Align(
71 | alignment: Alignment.topRight,
72 | child: Container(
73 | width: 20,
74 | height: 20,
75 | margin: const EdgeInsets.symmetric(horizontal: 5, vertical: 5),
76 | decoration: BoxDecoration(
77 | shape: BoxShape.circle,
78 | border: Border.all(width: 1.5, color: Colors.black),
79 | color: tealColor,
80 | ),
81 | child: const Center(
82 | child: Icon(Icons.done, size: 15, color: Colors.black),
83 | ),
84 | ),
85 | )
86 | : Container(),
87 | // Filter name displayed at the bottom of the filter preview.
88 | Align(
89 | alignment: Alignment.bottomCenter,
90 | child: Container(
91 | width: 70,
92 | height: 25,
93 | padding: const EdgeInsets.symmetric(horizontal: 5, vertical: 5),
94 | decoration: BoxDecoration(color: Colors.black.withOpacity(0.4)),
95 | child: Text(
96 | Consts.filterNames[index],
97 | style: const TextStyle(fontWeight: FontWeight.bold, color: Colors.white),
98 | ),
99 | ),
100 | ),
101 | ],
102 | ),
103 | ),
104 | );
105 | },
106 | ),
107 | );
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/lib/src/views/main_control_views/image_view.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 | import 'package:flutter/cupertino.dart';
3 | import 'package:flutter/material.dart';
4 | import 'package:flutter_story_editor/src/const/filters.dart';
5 | import 'package:flutter_story_editor/src/controller/controller.dart';
6 | import 'package:flutter_story_editor/src/models/simple_sketecher.dart';
7 | import 'package:flutter_story_editor/src/models/stroke.dart';
8 | import 'package:flutter_story_editor/src/widgets/draggable_sticker_widget.dart';
9 | import 'package:flutter_story_editor/src/widgets/draggable_text_widget.dart';
10 |
11 | // ImageView is a StatefulWidget that displays an image along with applied filters, stickers, and text overlays.
12 | class ImageView extends StatefulWidget {
13 | final File file; // The image file to display.
14 | final List? filter; // The color filter to apply on the image.
15 | final FlutterStoryEditorController controller; // Controller for managing the story editing state.
16 | final List lines; // List of strokes for drawing on the image.
17 | final int storyIndex; // Index of the current story.
18 | final List> textList; // List of text widgets added to the current story.
19 | final List> stickerList; // List of sticker widgets added to the current story.
20 |
21 | // Constructor for initializing ImageView with required parameters.
22 | const ImageView({
23 | super.key,
24 | required this.file,
25 | this.filter,
26 | required this.controller,
27 | required this.lines,
28 | required this.textList,
29 | required this.storyIndex,
30 | required this.stickerList
31 | });
32 |
33 | @override
34 | State createState() => _ImageViewState();
35 | }
36 |
37 | // State class for ImageView, handling the display and interaction of the image, its filters, and overlays.
38 | class _ImageViewState extends State {
39 |
40 | @override
41 | Widget build(BuildContext context) {
42 | // Builds the UI components layered over each other in a stack.
43 | return Stack(
44 | alignment: Alignment.center,
45 | children: [
46 | // Display the image with an optional color filter applied.
47 | Row(
48 | children: [
49 | Expanded(child: ColorFiltered(
50 | colorFilter: ColorFilter.matrix(widget.filter ?? noFiler), // Apply the matrix filter or default to no filter.
51 | child: Image.file(widget.file, fit: BoxFit.cover) // Display the image file covering its container.
52 | )),
53 | ],
54 | ),
55 |
56 | // Custom painter that draws the strokes on the image.
57 | CustomPaint(
58 | painter: SimpleSketcher(widget.lines),
59 | child: Container(),
60 | ),
61 |
62 | // Display draggable sticker widgets.
63 | ...widget.stickerList[widget.storyIndex].map((draggableStickerWidget) {
64 | return draggableStickerWidget; // Render each sticker widget from the list.
65 | }),
66 |
67 | // Display draggable text widgets.
68 | ...widget.textList[widget.storyIndex].map((draggableTextWidget) {
69 | return draggableTextWidget; // Render each text widget from the list.
70 | }),
71 |
72 | ],
73 | );
74 | }
75 |
76 | }
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/lib/src/views/main_control_views/main_controls_view.dart:
--------------------------------------------------------------------------------
1 | // Import necessary Dart and Flutter packages.
2 |
3 | import 'dart:io';
4 | import 'dart:typed_data';
5 | import 'package:flutter/material.dart';
6 | import 'package:flutter_story_editor/src/controller/controller.dart';
7 | import 'package:flutter_story_editor/src/enums/story_editing_modes.dart';
8 | import 'package:flutter_story_editor/src/models/stroke.dart';
9 | import 'package:flutter_story_editor/src/utils/utils.dart';
10 | import 'package:flutter_story_editor/src/views/main_control_views/filters_view.dart';
11 | import 'package:flutter_story_editor/src/widgets/draggable_sticker_widget.dart';
12 | import 'package:flutter_story_editor/src/widgets/draggable_text_widget.dart';
13 |
14 | // Import additional custom views for different aspects of the UI.
15 |
16 | import 'caption_view.dart';
17 | import 'filter_text_view.dart';
18 | import 'thumbnail_view.dart';
19 | import 'top_view.dart';
20 |
21 | class MainControlsView extends StatefulWidget {
22 | final List? selectedFiles; // Optional list of media files selected for editing.
23 | final VoidCallback? onSaveClickListener; // Optional callback for save action.
24 | final TextEditingController? captionController; // Optional controller for caption text.
25 | final FlutterStoryEditorController controller; // Controller for managing editor states and interactions.
26 | final List uiViewEditableFiles; // List of editable media files for the UI.
27 | final List> selectedFilters; // List of filters applied to each media file.
28 | final List> textList; // Lists of draggable text widgets for each page.
29 | final List> stickerList; // Lists of draggable sticker widgets for each page.
30 | final Function(List) onFilterChange; // Callback for changing filters.
31 | final Function(File) onImageCrop; // Callback for cropping images.
32 | final VoidCallback onUndoClickListener; // Callback for undo actions.
33 | final VoidCallback onPaintClickListener; // Callback for activating paint mode.
34 | final VoidCallback onTextClickListener; // Callback for activating text mode.
35 | final VoidCallback onStickersClickListener; // Callback for activating stickers mode.
36 | final PageController pageController; // Controller for managing page transitions.
37 | final int currentPageIndex; // Index of the current page in the editor.
38 | final List lines; // List of stroke actions for drawing.
39 | final bool isSaving; // Flag to indicate if a save operation is in progress.
40 | final bool isFocused; // Flag to check if the keyboard is focused.
41 | final FocusNode? captionFocusNode; // Optional focus node for the caption input.
42 |
43 |
44 | const MainControlsView(
45 | {super.key,
46 | this.selectedFiles,
47 | this.onSaveClickListener,
48 | this.captionController,
49 | required this.controller,
50 | required this.isFocused,
51 | required this.uiViewEditableFiles,
52 | required this.selectedFilters,
53 | required this.onFilterChange,
54 | required this.onImageCrop,
55 | required this.onUndoClickListener,
56 | required this.pageController,
57 | required this.currentPageIndex,
58 | required this.onPaintClickListener,
59 | required this.onTextClickListener,
60 | required this.lines,
61 | required this.isSaving,
62 | required this.textList,
63 | this.captionFocusNode,
64 | required this.onStickersClickListener, required this.stickerList,
65 | });
66 |
67 | @override
68 | State createState() => _MainControlsViewState();
69 | }
70 |
71 | class _MainControlsViewState extends State {
72 | final Map _thumbnails = {}; // Cache for storing generated thumbnails for video files.
73 |
74 | // Variables for tracking original files before modifications.
75 | List? originalFiles;
76 |
77 | static const double maxVideoSizeMB = 50; // Maximum allowed video size in MB.
78 | static const double maxImageSizeMB = 5; // Maximum allowed image size in MB.
79 |
80 | // Function to generate thumbnails for video files asynchronously.
81 | void generateVideoFilesThumbnails() async {
82 | for (var file in widget.selectedFiles ?? []) {
83 | if (isVideo(file)) {
84 | var generatedThumbnail = await generateThumbnail(file);
85 | if (mounted) {
86 | setState(() {
87 | _thumbnails[file] = generatedThumbnail;
88 | });
89 | }
90 | }
91 | }
92 | }
93 |
94 | @override
95 | void initState() {
96 | super.initState();
97 |
98 | // Initial setup to generate thumbnails and handle large files.
99 | generateVideoFilesThumbnails();
100 |
101 | for (var file in widget.selectedFiles!) {
102 | final bytes = file.readAsBytesSync();
103 | final sizeInMB = bytes.lengthInBytes / (1024 * 1024);
104 |
105 | if (isVideo(file) && sizeInMB > maxVideoSizeMB) {
106 | Navigator.pop(context);
107 | }
108 |
109 | if (!isVideo(file) && sizeInMB > maxImageSizeMB) {
110 | Navigator.pop(context);
111 | }
112 | }
113 |
114 | originalFiles = List.from(widget.selectedFiles!);
115 | }
116 |
117 | // Function to crop images.
118 | void _cropImage(BuildContext context) {
119 | cropImage(
120 | context,
121 | file: originalFiles![widget.currentPageIndex],
122 | ).then((croppedFile) async {
123 | if (croppedFile != null) {
124 | File croppedImage = File(croppedFile.path);
125 | widget.onImageCrop(croppedImage);
126 | }
127 | });
128 | }
129 | @override
130 | Widget build(BuildContext context) {
131 | return Stack(
132 | alignment: Alignment.center,
133 | children: [
134 | for (File file in widget.selectedFiles!)
135 | if (!(isVideo(file)))
136 | Align(
137 | alignment: Alignment.topCenter,
138 | child: _buildTop(),
139 | ),
140 | Align(
141 | alignment: Alignment.bottomCenter,
142 | child: _buildBottom(),
143 | ),
144 | ],
145 | );
146 | }
147 |
148 | // Function to build the top view of the editor.
149 | Widget _buildTop() {
150 | return TopView(
151 | stickerList: widget.stickerList,
152 | textList: widget.textList,
153 | controller: widget.controller,
154 | lines: widget.lines,
155 | onTextClickListener: () {
156 | widget.onTextClickListener();
157 | },
158 | onStickersClickListener: () {
159 | widget.onStickersClickListener();
160 | },
161 | onPaintClickListener: () {
162 | widget.onPaintClickListener();
163 | },
164 | onUndoClickListener: widget.onUndoClickListener,
165 | currentPageIndex: widget.currentPageIndex,
166 | selectedFilters: widget.selectedFilters,
167 | selectedFile: widget.selectedFiles![widget.currentPageIndex],
168 | onTapCropListener: () {
169 | _cropImage(context);
170 | },
171 | );
172 | }
173 |
174 | // Function to build the bottom view of the editor.
175 | Widget _buildBottom() {
176 | return AnimatedPadding(
177 | duration: const Duration(milliseconds: 200),
178 | padding: EdgeInsets.only(
179 | bottom: MediaQuery.of(context).viewInsets.bottom,
180 | ),
181 | child: Column(
182 | children: [
183 | Expanded(
184 | child: Container(),
185 | ),
186 | if(widget.isFocused == false)
187 | isVideo(widget.selectedFiles![widget.currentPageIndex])
188 | ? Container()
189 | : FilterTextView(controller: widget.controller),
190 | const SizedBox(
191 | height: 5,
192 | ),
193 | Column(
194 | children: [
195 | if(widget.isFocused == false)
196 | ThumbnailView(
197 | controller: widget.controller,
198 | onThumbnailTapListener: (thumbnailItemIndex) {
199 | widget.pageController.jumpToPage(thumbnailItemIndex);
200 | },
201 | currentPageIndex: widget.currentPageIndex,
202 | thumbnails: _thumbnails,
203 | selectedFiles: widget.uiViewEditableFiles,
204 | selectedFilters: widget.selectedFilters,
205 | ),
206 | const SizedBox(
207 | height: 10,
208 | ),
209 |
210 | if (widget.controller.editingModeSelected == StoryEditingModes.filters)
211 | FiltersView(
212 | onFilterChange: (filter) {
213 | widget.onFilterChange(filter);
214 | },
215 | selectedFilters: widget.selectedFilters,
216 | currentPageIndex: widget.currentPageIndex,
217 | selectedFiles: originalFiles,
218 | )
219 | else
220 | if(widget.isFocused == false)
221 | CaptionView(
222 | focusNode: widget.captionFocusNode,
223 | isSaving: widget.isSaving,
224 | captionController: widget.captionController!,
225 | onSaveClickListener: widget.onSaveClickListener!,
226 | )
227 | ],
228 | ),
229 | ],
230 | ),
231 | );
232 | }
233 | }
234 |
--------------------------------------------------------------------------------
/lib/src/views/main_control_views/thumbnail_view.dart:
--------------------------------------------------------------------------------
1 | // Import necessary Dart and Flutter packages.
2 |
3 | import 'dart:io';
4 | import 'dart:math';
5 | import 'dart:typed_data';
6 | import 'package:flutter/material.dart';
7 | import 'package:flutter_story_editor/src/controller/controller.dart';
8 | import 'package:flutter_story_editor/src/models/simple_sketecher.dart';
9 | import 'package:flutter_story_editor/src/models/stroke.dart';
10 | import 'package:flutter_story_editor/src/theme/style.dart';
11 | import 'package:flutter_story_editor/src/utils/utils.dart';
12 | import 'package:perfect_freehand/perfect_freehand.dart';
13 |
14 | class ThumbnailView extends StatefulWidget {
15 | final List selectedFiles; // List of files selected for editing.
16 | final int currentPageIndex; // Current page index to indicate the selected thumbnail.
17 | final Map? thumbnails; // Optional map for storing thumbnails of video files.
18 | final List>? selectedFilters; // Optional list for storing filters applied to each thumbnail.
19 | final Function(int) onThumbnailTapListener; // Callback function to handle thumbnail taps.
20 | final FlutterStoryEditorController controller; // Controller to manage editing state and interactions.
21 |
22 | const ThumbnailView({
23 | super.key,
24 | required this.selectedFiles,
25 | required this.currentPageIndex,
26 | required this.onThumbnailTapListener,
27 | this.thumbnails,
28 | this.selectedFilters,
29 | required this.controller,
30 | });
31 |
32 | @override
33 | State createState() => _ThumbnailViewState();
34 | }
35 |
36 | class _ThumbnailViewState extends State {
37 | @override
38 | Widget build(BuildContext context) {
39 | return SingleChildScrollView(
40 | scrollDirection: Axis.horizontal,
41 | child: Padding(
42 | padding: const EdgeInsets.symmetric(horizontal: 5.0),
43 | child: Row(
44 | children: widget.selectedFiles.map((e) {
45 | int fileIndex = widget.selectedFiles.indexOf(e);
46 | return Container(
47 | width: 50,
48 | height: 50,
49 | decoration: BoxDecoration(
50 | border: Border.all(
51 | width: 1.5,
52 | color: widget.currentPageIndex == fileIndex
53 | ? tealColor
54 | : Colors.transparent),
55 | ),
56 | child: GestureDetector(
57 | onTap: () => widget.onThumbnailTapListener(fileIndex),
58 | child: ThumbnailViewItem(
59 | controller: widget.controller,
60 | index: fileIndex,
61 | image: e,
62 | selectedFiles: widget.selectedFiles,
63 | selectedFilters: widget.selectedFilters,
64 | thumbnails: widget.thumbnails,
65 | ),
66 | ),
67 | );
68 | }).toList(),
69 | )),
70 | );
71 | }
72 | }
73 |
74 | class ThumbnailViewItem extends StatefulWidget {
75 | final File image; // File for which the thumbnail is displayed.
76 | final FlutterStoryEditorController controller; // Controller to manage editing state and interactions.
77 | final int index; // Index of the thumbnail in the list.
78 | final Map? thumbnails; // Optional map for storing thumbnails of video files.
79 | final List>? selectedFilters; // Optional list for storing filters applied to each thumbnail.
80 | final List? selectedFiles; // Optional list of files being edited.
81 | const ThumbnailViewItem(
82 | {super.key,
83 | required this.index,
84 | this.thumbnails,
85 | this.selectedFilters,
86 | this.selectedFiles,
87 | required this.image,
88 | required this.controller});
89 |
90 | @override
91 | State createState() => _ThumbnailViewItemState();
92 | }
93 |
94 | class _ThumbnailViewItemState extends State {
95 |
96 | @override
97 | Widget build(BuildContext context) {
98 |
99 |
100 | double scaleFactor = min(
101 | 50.0 / MediaQuery.of(context).size.width,
102 | 50.0 / MediaQuery.of(context).size.height,
103 | );
104 |
105 | return ValueListenableBuilder>>(
106 | valueListenable: widget.controller.uiEditableFileLinesNotifier,
107 | builder: (BuildContext context, List> lines, Widget? child) {
108 |
109 |
110 | List scaledLines = lines[widget.index].map((line) {
111 |
112 |
113 |
114 | return Stroke(
115 | line.points.map((point) {
116 | return PointVector(
117 | point.x * scaleFactor * 1.8, point.y * scaleFactor * 0.9, point.pressure);
118 | }).toList(),
119 | line.color,
120 | StrokeOptions(
121 | size: 1
122 | ),
123 | );
124 | }).toList();
125 |
126 | if (isVideo(widget.image)) {
127 | if (widget.thumbnails != null) {
128 | return widget.thumbnails![widget.image] == null
129 | ? Container()
130 | : Stack(
131 | children: [
132 | Positioned(
133 | left: 0,
134 | right: 0,
135 | top: 0,
136 | bottom: 0,
137 | child: Image.memory(
138 | widget.thumbnails![widget.image]!,
139 | fit: BoxFit.cover,
140 | ),
141 | ),
142 | CustomPaint(
143 |
144 | painter: SimpleSketcher(scaledLines),
145 | child: Container(),
146 | )
147 | ],
148 | );
149 | } else {
150 | return Container(); // If thumbnail is not ready yet, just display an empty container.
151 | }
152 | } else {
153 | return ColorFiltered(
154 | colorFilter:
155 | ColorFilter.matrix(widget.selectedFilters![widget.index]),
156 | child: Stack(
157 | children: [
158 | Positioned(
159 | top: 0,
160 | left: 0,
161 | right: 0,
162 | bottom: 0,
163 | child: Image.file(
164 | widget.selectedFiles != null
165 | ? widget.selectedFiles![widget.index]
166 | : widget.image,
167 | fit: BoxFit.cover,
168 | ),
169 | ),
170 | CustomPaint(
171 | size: Size(
172 | 50.0 * MediaQuery.of(context).size.width / MediaQuery.of(context).size.height,
173 | 50.0,
174 | ),
175 | painter: SimpleSketcher(scaledLines),
176 | child: Container(),
177 | )
178 | ],
179 | ),
180 | );
181 | }
182 | },
183 | );
184 | }
185 | }
186 |
--------------------------------------------------------------------------------
/lib/src/views/main_control_views/top_view.dart:
--------------------------------------------------------------------------------
1 |
2 | import 'dart:io';
3 |
4 | import 'package:flutter/material.dart';
5 | import 'package:flutter_story_editor/src/const/filters.dart';
6 | import 'package:flutter_story_editor/src/controller/controller.dart';
7 | import 'package:flutter_story_editor/src/models/stroke.dart';
8 | import 'package:flutter_story_editor/src/utils/utils.dart';
9 | import 'package:flutter_story_editor/src/widgets/draggable_sticker_widget.dart';
10 | import 'package:flutter_story_editor/src/widgets/draggable_text_widget.dart';
11 | // TopView is a StatefulWidget that provides the top bar interface for story editing controls.
12 | class TopView extends StatefulWidget {
13 | final File selectedFile; // The currently selected file for editing.
14 | final VoidCallback onTapCropListener; // Callback for handling crop operations.
15 | final int currentPageIndex; // Index of the current page being edited.
16 | final List> selectedFilters; // Current filter applied to each file page.
17 | final List> textList; // List of text widgets added to each file page.
18 | final List> stickerList; // List of sticker widgets added to each file page.
19 | final VoidCallback onUndoClickListener; // Callback for undo operations.
20 | final VoidCallback onPaintClickListener; // Callback for activating the paint editing mode.
21 | final VoidCallback onTextClickListener; // Callback for activating the text editing mode.
22 | final VoidCallback onStickersClickListener; // Callback for activating the stickers editing mode.
23 | final List lines; // List of all drawing strokes on the current page.
24 | final FlutterStoryEditorController controller; // Controller for managing editor state.
25 |
26 | // Constructor for initializing TopView with required parameters.
27 | const TopView({
28 | super.key,
29 | required this.selectedFile,
30 | required this.onTapCropListener,
31 | required this.currentPageIndex,
32 | required this.selectedFilters,
33 | required this.onUndoClickListener,
34 | required this.onPaintClickListener,
35 | required this.lines,
36 | required this.controller,
37 | required this.onTextClickListener,
38 | required this.textList,
39 | required this.onStickersClickListener,
40 | required this.stickerList
41 | });
42 |
43 | @override
44 | State createState() => _TopViewState();
45 | }
46 |
47 | // State class for TopView, handles the rendering of the top toolbar.
48 | class _TopViewState extends State {
49 | @override
50 | Widget build(BuildContext context) {
51 | return Padding(
52 | padding: EdgeInsets.symmetric(horizontal: 15, vertical: Platform.isIOS ? 60 : 40), // Padding adjusted for platform differences.
53 | child: Column(
54 | children: [
55 | Row(
56 | mainAxisAlignment: MainAxisAlignment.spaceBetween, // Space between controls and the close icon.
57 | children: [
58 | // Close icon to exit the editor.
59 | GestureDetector(
60 | onTap: () {
61 | Navigator.of(context).pop();
62 | },
63 | child: const Icon(
64 | Icons.close_outlined,
65 | size: 30,
66 | color: Colors.white,
67 | )),
68 | // Conditional rendering if the selected file is not a video.
69 | if (!isVideo(widget.selectedFile))
70 | Row(
71 | children: [
72 | // Undo icon is shown if there are any changes that can be undone.
73 | widget.selectedFilters[widget.currentPageIndex] != noFiler || widget.lines.isNotEmpty || widget.textList[widget.currentPageIndex].isNotEmpty || widget.stickerList[widget.currentPageIndex].isNotEmpty ? GestureDetector(
74 | onTap: widget.onUndoClickListener,
75 | child: const Icon(
76 | Icons.undo,
77 | size: 30,
78 | color: Colors.white,
79 | ),
80 | ) : Container(),
81 | const SizedBox(
82 | width: 20,
83 | ),
84 | // Crop icon for image editing.
85 | GestureDetector(
86 | onTap: widget.onTapCropListener,
87 | child: const Icon(
88 | Icons.crop,
89 | size: 30,
90 | color: Colors.white,
91 | )),
92 | const SizedBox(
93 | width: 20,
94 | ),
95 | // Icon for accessing sticker controls.
96 | GestureDetector(
97 | onTap: widget.onStickersClickListener,
98 | child: const Icon(
99 | Icons.emoji_emotions_outlined,
100 | size: 30,
101 | color: Colors.white,
102 | ),
103 | ),
104 | const SizedBox(
105 | width: 20,
106 | ),
107 | // Icon for accessing text controls.
108 | GestureDetector(
109 | onTap: widget.onTextClickListener,
110 | child: const Icon(
111 | Icons.title,
112 | size: 30,
113 | color: Colors.white,
114 | ),
115 | ),
116 | const SizedBox(
117 | width: 20,
118 | ),
119 | // Icon for accessing painting controls.
120 | GestureDetector(
121 | onTap: widget.onPaintClickListener,
122 | child: const Icon(
123 | Icons.edit_outlined,
124 | size: 30,
125 | color: Colors.white,
126 | ),
127 | ),
128 | ],
129 | )
130 | ],
131 | ),
132 | ],
133 | ),
134 | );
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/lib/src/views/main_control_views/trimmer_view.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 | import 'dart:io';
3 | import 'package:flutter/material.dart';
4 | import 'package:flutter_story_editor/src/models/simple_sketecher.dart';
5 | import 'package:flutter_story_editor/src/models/stroke.dart';
6 | import 'package:flutter_story_editor/src/theme/style.dart';
7 |
8 | import 'package:video_trimmer/video_trimmer.dart';
9 |
10 | // TrimmerView is a StatefulWidget that provides a video trimming interface.
11 | class TrimmerView extends StatefulWidget {
12 | final File file; // File to be trimmed.
13 | final int pageIndex; // Index of the current page in the page controller.
14 | final PageController pageController; // Controller for page navigation.
15 | final Function(File) onTrimCompleted; // Callback function after trim is completed.
16 | final bool? trimOnAdjust; // If true, trims the video as adjustments are made.
17 | final List lines; // List of drawing strokes to be displayed over the video.
18 |
19 | // Constructor for initializing TrimmerView with required parameters.
20 | const TrimmerView({
21 | super.key,
22 | required this.file,
23 | required this.pageIndex,
24 | required this.pageController,
25 | required this.onTrimCompleted,
26 | this.trimOnAdjust = false,
27 | required this.lines
28 | });
29 |
30 | @override
31 | TrimmerViewState createState() => TrimmerViewState();
32 | }
33 |
34 | // State class for TrimmerView, handling video loading, trimming, and UI interactions.
35 | class TrimmerViewState extends State with AutomaticKeepAliveClientMixin {
36 | @override
37 | bool get wantKeepAlive => true; // Ensures state is kept when swiping between tabs.
38 |
39 | double _startValue = 0.0; // Start position of the trim.
40 | double _endValue = 0.0; // End position of the trim.
41 | final Trimmer _trimmer = Trimmer(); // Trimmer instance for handling video operations.
42 |
43 | bool _isPlaying = false; // Indicates if the video is currently playing.
44 | bool _progressVisibility = false; // Shows or hides the progress indicator.
45 | Timer? _debounce; // Timer for debouncing trim operations.
46 |
47 | // Asynchronously trims the video and updates the UI on completion.
48 | Future _trimVideo() async {
49 | setState(() {
50 | _progressVisibility = true; // Show progress bar.
51 | });
52 |
53 | String? value;
54 |
55 | // Perform the trim operation and handle the result.
56 | await _trimmer.saveTrimmedVideo(
57 | startValue: _startValue,
58 | endValue: _endValue,
59 | onSave: (value) {
60 | widget.onTrimCompleted(File(value!)); // Callback with the new file.
61 | }).then((value) {
62 | setState(() {
63 | _progressVisibility = false; // Hide progress bar.
64 | });
65 | });
66 |
67 | return value;
68 | }
69 |
70 | // Debounces the trim operation to avoid excessive processing.
71 | void _debounceTrim() {
72 | if (_debounce?.isActive ?? false) _debounce?.cancel();
73 | _debounce = Timer(const Duration(milliseconds: 500), () {
74 | _trimVideo();
75 | });
76 | }
77 |
78 | // Loads the video into the trimmer.
79 | void _loadVideo() {
80 | _trimmer.loadVideo(videoFile: widget.file);
81 | }
82 |
83 | @override
84 | void initState() {
85 | super.initState();
86 | _loadVideo(); // Initial video load.
87 |
88 | // Listener to stop video playback when swiping away from the page.
89 | widget.pageController.addListener(() async {
90 | if (widget.pageController.page!.round() != widget.pageIndex &&
91 | _isPlaying) {
92 | await _trimmer.videoPlaybackControl(
93 | startValue: _startValue, endValue: _endValue);
94 | setState(() => _isPlaying = false);
95 | }
96 | });
97 | }
98 |
99 | @override
100 | void dispose() {
101 | _trimmer.dispose(); // Clean up the trimmer resources.
102 | super.dispose();
103 | }
104 |
105 | @override
106 | Widget build(BuildContext context) {
107 | super.build(context); // Required for keeping state alive.
108 |
109 | return Scaffold(
110 | body: Builder(
111 | builder: (context) => Center(
112 | child: Container(
113 | color: Colors.black, // Background color.
114 | child: Stack(
115 | alignment: Alignment.center,
116 | children: [
117 | VideoViewer(trimmer: _trimmer), // Displays the video being trimmed.
118 | CustomPaint(
119 | painter: SimpleSketcher(widget.lines), // Overlays custom sketches on the video.
120 | child: Container(),
121 | ),
122 | Column(
123 | mainAxisAlignment: MainAxisAlignment.start,
124 | mainAxisSize: MainAxisSize.max,
125 | children: [
126 | // Trim viewer and editor.
127 | Container(
128 | margin: const EdgeInsets.only(top: 80, left: 6, right: 6),
129 | child: Center(
130 | child: TrimViewer(
131 | editorProperties: const TrimEditorProperties(
132 | ),
133 | areaProperties: const TrimAreaProperties(),
134 | trimmer: _trimmer,
135 | viewerHeight: 50.0,
136 | viewerWidth: MediaQuery.of(context).size.width,
137 | maxVideoLength: const Duration(seconds: 30),
138 | onChangeStart: (value) => _startValue = value,
139 | onChangeEnd: (value) {
140 | _endValue = value;
141 | widget.trimOnAdjust == true
142 | ? _debounceTrim()
143 | : null;
144 | },
145 | onChangePlaybackState: (value) {
146 | setState(() => _isPlaying = value);
147 | }),
148 | ),
149 | ),
150 | const SizedBox(height: 10),
151 | // Controls for manual save and progress indicator.
152 | if (widget.trimOnAdjust == false)
153 | Column(
154 | children: [
155 | Visibility(
156 | visible: _progressVisibility,
157 | child: const LinearProgressIndicator(
158 | backgroundColor: tealColor,
159 | ),
160 | ),
161 | ElevatedButton(
162 | onPressed: _progressVisibility
163 | ? null
164 | : () async {
165 | _trimVideo();
166 | },
167 | child: const Text("SAVE"),
168 | ),
169 | ],
170 | )
171 | ],
172 | ),
173 |
174 | // Play button to toggle video playback.
175 | TextButton(
176 | child: _isPlaying
177 | ? Container()
178 | : const Icon(
179 | Icons.play_arrow,
180 | size: 80.0,
181 | color: Colors.white,
182 | ),
183 | onPressed: () async {
184 | await _trimmer.videoPlaybackControl(
185 | startValue: _startValue,
186 | endValue: _endValue,
187 | );
188 | if (mounted) {
189 | setState(() {
190 | _isPlaying = false;
191 | });
192 | }
193 | },
194 | ),
195 |
196 |
197 | ],
198 | ),
199 | ),
200 | ),
201 | ),
202 | );
203 | }
204 | }
205 |
206 |
207 |
--------------------------------------------------------------------------------
/lib/src/views/paint_control_views/paint_controls_view.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 | import 'package:flutter/gestures.dart';
3 | import 'package:flutter/material.dart';
4 | import 'package:flutter_story_editor/src/controller/controller.dart';
5 | import 'package:flutter_story_editor/src/models/simple_sketecher.dart';
6 | import 'package:flutter_story_editor/src/models/stroke.dart';
7 | import 'package:flutter_story_editor/src/widgets/hue_color_picker_slider.dart';
8 | import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
9 | import 'package:perfect_freehand/perfect_freehand.dart';
10 |
11 | import 'paint_top_view.dart';
12 |
13 | // PaintControlsView provides a customizable painting interface over an image or video.
14 | class PaintControlsView extends StatefulWidget {
15 | final File selectedFile; // The file (image/video) being edited.
16 | final List uiEditableFileLines; // List of strokes drawn on the canvas.
17 | final VoidCallback onUndoClickListener; // Callback when the undo button is pressed.
18 | final Function(Stroke) onPointerDownUpdate; // Callback when a new stroke is started.
19 | final FlutterStoryEditorController controller; // Controller for managing editing state.
20 | final VoidCallback onDoneClickListener; // Callback when the done button is pressed.
21 |
22 | const PaintControlsView({
23 | super.key,
24 | required this.selectedFile,
25 | required this.controller,
26 | required this.uiEditableFileLines,
27 | required this.onPointerDownUpdate,
28 | required this.onUndoClickListener,
29 | required this.onDoneClickListener
30 | });
31 |
32 | @override
33 | PaintControlsViewState createState() => PaintControlsViewState();
34 | }
35 |
36 | class PaintControlsViewState extends State {
37 | HSVColor _pencilColor = HSVColor.fromColor(Colors.tealAccent); // Initial pencil color.
38 | Stroke? line; // Current stroke being drawn.
39 | double size = 3; // Initial stroke size.
40 |
41 | // Handles pointer down event, initializing a new stroke.
42 | void onPointerDown(PointerDownEvent details) {
43 | final box = context.findRenderObject() as RenderBox;
44 | final offset = box.globalToLocal(details.position);
45 | final point = details.kind == PointerDeviceKind.stylus
46 | ? PointVector(
47 | offset.dx,
48 | offset.dy / 2,
49 | (details.pressure - details.pressureMin) / (details.pressureMax - details.pressureMin),
50 | )
51 | : PointVector(offset.dx, offset.dy);
52 | final points = [point];
53 | line = Stroke(points, _pencilColor.toColor(), StrokeOptions(size: size));
54 | setState(() {
55 | widget.uiEditableFileLines.add(line!);
56 | });
57 | }
58 |
59 | // Updates the current stroke with new points as the pointer moves.
60 | void onPointerMove(PointerMoveEvent details) {
61 | final box = context.findRenderObject() as RenderBox;
62 | final offset = box.globalToLocal(details.position);
63 | final point = details.kind == PointerDeviceKind.stylus
64 | ? PointVector(
65 | offset.dx,
66 | offset.dy,
67 | (details.pressure - details.pressureMin) / (details.pressureMax - details.pressureMin),
68 | )
69 | : PointVector(offset.dx, offset.dy);
70 | setState(() {
71 | line!.points.add(point);
72 | });
73 | }
74 |
75 | // Finalizes the stroke when the pointer is lifted.
76 | void onPointerUp(PointerUpEvent details) {
77 | widget.onPointerDownUpdate(line!);
78 | line = null;
79 | }
80 |
81 | @override
82 | Widget build(BuildContext context) {
83 | // Building the widget's visual structure.
84 | return Stack(
85 | alignment: Alignment.center,
86 | children: [
87 | // Listener to handle touch events on the canvas.
88 | Listener(
89 | onPointerDown: onPointerDown,
90 | onPointerUp: onPointerUp,
91 | onPointerMove: onPointerMove,
92 | child: CustomPaint(
93 | painter: SimpleSketcher(widget.uiEditableFileLines),
94 | child: Container(),
95 | ),
96 | ),
97 | // Top bar with painting controls.
98 | Align(
99 | alignment: Alignment.topCenter,
100 | child: PaintTopView(
101 | lines: widget.uiEditableFileLines,
102 | onDoneClickListener: () {
103 | widget.onDoneClickListener();
104 | },
105 | controller: widget.controller,
106 | onUndoClickListener: widget.onUndoClickListener,
107 | selectedFile: widget.selectedFile,
108 | pencilColor: _pencilColor,
109 | ),
110 | ),
111 | // Bottom bar with size controls.
112 | Align(
113 | alignment: Alignment.bottomCenter,
114 | child: Padding(
115 | padding: const EdgeInsets.symmetric(vertical: 20.0),
116 | child: Row(
117 | mainAxisAlignment: MainAxisAlignment.spaceAround,
118 | children: [
119 | bottomIcon(MdiIcons.sizeM, isSelected: size == 3, onTap: () {
120 | setState(() {
121 | size = 3;
122 | });
123 | }),
124 | bottomIcon(MdiIcons.sizeL, isSelected: size == 6, onTap: () {
125 | setState(() {
126 | size = 6;
127 | });
128 | }),
129 | bottomIcon(MdiIcons.sizeXl, isSelected: size == 9, onTap: () {
130 | setState(() {
131 | size = 9;
132 | });
133 | }),
134 | bottomIcon(MdiIcons.sizeXxl, isSelected: size == 12, onTap: () {
135 | setState(() {
136 | size = 12;
137 | });
138 | }),
139 | ],
140 | ),
141 | ),
142 | ),
143 | // Slider for changing the pencil color.
144 | Positioned(
145 | top: 100,
146 | right: 28,
147 | child: HueColorPickerSlider(
148 | onChanged: (hsvColor) {
149 | setState(() {
150 | _pencilColor = hsvColor;
151 | });
152 | },
153 | ),
154 | ),
155 | ],
156 | );
157 | }
158 |
159 | // Helper function to create icons for selecting stroke size.
160 | bottomIcon(IconData icon, {VoidCallback? onTap, bool? isSelected}) {
161 | return GestureDetector(
162 | onTap: onTap,
163 | child: Container(
164 | width: 40,
165 | height: 40,
166 | decoration: BoxDecoration(borderRadius: BorderRadius.circular(20), color: Colors.white.withOpacity(.2), border: isSelected == true ? Border.all(width: 1, color: Colors.white) : null),
167 | child: Icon(
168 | icon,
169 | size: 30,
170 | color: Colors.white,
171 | ),
172 | ),
173 | );
174 | }
175 | }
176 |
--------------------------------------------------------------------------------
/lib/src/views/paint_control_views/paint_top_view.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 |
3 | import 'package:flutter/material.dart';
4 | import 'package:flutter_story_editor/src/controller/controller.dart';
5 | import 'package:flutter_story_editor/src/models/stroke.dart';
6 |
7 | class PaintTopView extends StatefulWidget {
8 | final File selectedFile;
9 | final VoidCallback onUndoClickListener;
10 | final FlutterStoryEditorController controller;
11 | final HSVColor? pencilColor;
12 | final VoidCallback onDoneClickListener;
13 | final List lines;
14 | const PaintTopView(
15 | {super.key,
16 | required this.selectedFile,
17 | required this.onUndoClickListener,
18 | required this.controller,
19 | this.pencilColor, required this.onDoneClickListener, required this.lines,
20 | });
21 |
22 | @override
23 | State createState() => _PaintTopViewState();
24 | }
25 |
26 | class _PaintTopViewState extends State {
27 | @override
28 | Widget build(BuildContext context) {
29 | return Padding(
30 | padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 40),
31 | child: Column(
32 | children: [
33 | Row(
34 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
35 | children: [
36 | GestureDetector(
37 | onTap: widget.onDoneClickListener,
38 | child: Container(
39 | padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 5),
40 | decoration: BoxDecoration(
41 | borderRadius: BorderRadius.circular(20),
42 | border: Border.all(width: 1, color: Colors.white)
43 | ),
44 | child: const Center(
45 | child: Text("Done", style: TextStyle(fontSize: 15, color: Colors.white),),
46 | ),
47 | ),
48 | ),
49 | Row(
50 | children: [
51 | widget.lines.isNotEmpty ?GestureDetector(
52 | onTap: widget.onUndoClickListener,
53 | child: const Icon(
54 | Icons.undo,
55 | size: 30,
56 | color: Colors.white,
57 | ),
58 | ) : Container(),
59 | const SizedBox(
60 | width: 20,
61 | ),
62 | GestureDetector(
63 | child: Container(
64 | width: 40,
65 | height: 40,
66 | decoration: BoxDecoration(
67 | borderRadius: BorderRadius.circular(20),
68 | color: widget.pencilColor!.toColor()
69 | ),
70 | child: const Icon(
71 | Icons.edit_outlined,
72 | size: 25,
73 | color: Colors.white,
74 | ),
75 | ),
76 | ),
77 | ],
78 | )
79 | ],
80 | ),
81 | ],
82 | ),
83 | );
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/lib/src/views/sticker_control_views/sticker_control_view.dart:
--------------------------------------------------------------------------------
1 | import 'dart:ui';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_story_editor/src/const/const.dart';
4 | import 'package:flutter_story_editor/src/controller/controller.dart';
5 |
6 | import 'sticker_top_view.dart';
7 |
8 | class StickerControlView extends StatefulWidget {
9 | final FlutterStoryEditorController controller;
10 | final Function(String) onStickerClickListener;
11 | const StickerControlView({super.key, required this.controller, required this.onStickerClickListener});
12 |
13 | @override
14 | State createState() => _StickerControlViewState();
15 | }
16 |
17 | class _StickerControlViewState extends State {
18 |
19 | bool isEmoji = false;
20 | @override
21 | Widget build(BuildContext context) {
22 | return Stack(
23 | children: [
24 | BackdropFilter(
25 | filter: ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0),
26 | child: Container(
27 | color: Colors.black12.withOpacity(0.2),
28 | ),
29 | ),
30 | Padding(
31 | padding: const EdgeInsets.only(left: 20, right: 20.0, top: 60),
32 | child: Column(
33 | crossAxisAlignment: CrossAxisAlignment.start,
34 | children: [
35 | StickerTopView(controller: widget.controller),
36 | const SizedBox(
37 | height: 20,
38 | ),
39 | Center(
40 | child: Row(
41 | mainAxisAlignment: MainAxisAlignment.center,
42 | children: [
43 | Expanded(
44 | child: GestureDetector(
45 | onTap: () {
46 | setState(() {
47 | isEmoji = false;
48 | });
49 | },
50 | child: Container(
51 | padding: const EdgeInsets.symmetric(horizontal: 25, vertical: 15),
52 | decoration: BoxDecoration(
53 | color: isEmoji == false? Colors.white : const Color.fromRGBO(30, 36, 40, 1),
54 | borderRadius: const BorderRadius.only(
55 | topLeft: Radius.circular(40),
56 | bottomLeft: Radius.circular(40),
57 | ),
58 | ),
59 | child: Center(
60 | child: Text("Stickers", style: TextStyle(color: isEmoji == false ? Colors.black : Colors.white, fontSize: 15),),
61 | ),
62 | ),
63 | ),
64 | ),
65 | Expanded(
66 | child: GestureDetector(
67 | onTap: () {
68 | setState(() {
69 | isEmoji = true;
70 | });
71 | },
72 | child: Container(
73 | padding: const EdgeInsets.symmetric(horizontal: 25, vertical: 15),
74 | decoration: BoxDecoration(
75 | color: isEmoji == true ? Colors.white : const Color.fromRGBO(30, 36, 40, 1),
76 | borderRadius: const BorderRadius.only(
77 | topRight: Radius.circular(40),
78 | bottomRight: Radius.circular(40),
79 | ),
80 | ),
81 | child: Center(
82 | child: Text("Emoji", style: TextStyle(color: isEmoji == true ? Colors.black : Colors.white, fontSize: 15),),
83 | ),
84 | ),
85 | ),
86 | ),
87 | ],
88 | ),
89 | ),
90 | const SizedBox(
91 | height: 20,
92 | ),
93 | Text(
94 | isEmoji == true ? "Emojis" :"Cuppy",
95 | style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w600, color: Colors.grey),
96 | ),
97 | const SizedBox(height: 20),
98 | if(isEmoji == false)
99 | Expanded(
100 | child: GridView.builder(
101 | gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
102 | crossAxisCount: 4, mainAxisSpacing: 20, crossAxisSpacing: 20, childAspectRatio: 1.2),
103 | physics: const ScrollPhysics(),
104 | itemCount: Consts.stickers.length,
105 | itemBuilder: (context, index) {
106 | final String sticker = Consts.stickers[index];
107 |
108 | return GestureDetector(
109 | onTap: () {
110 | widget.onStickerClickListener("assets/images/$sticker");
111 | },
112 | child: Image.asset("assets/images/$sticker"),
113 | );
114 | },
115 | ),
116 | )
117 | else
118 | Expanded(
119 | child: GridView.builder(
120 | gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
121 | crossAxisCount: 4, mainAxisSpacing: 20, crossAxisSpacing: 20, childAspectRatio: 1.2),
122 | physics: const ScrollPhysics(),
123 | itemCount: Consts.emojies.length,
124 | itemBuilder: (context, index) {
125 | final String emoji = Consts.emojies[index];
126 |
127 | return GestureDetector(
128 | onTap: () {
129 | widget.onStickerClickListener("assets/emojies/$emoji");
130 | },
131 | child: Image.asset("assets/emojies/$emoji"),
132 | );
133 | },
134 | ),
135 | )
136 | ],
137 | ),
138 | )
139 | ],
140 | );
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/lib/src/views/sticker_control_views/sticker_top_view.dart:
--------------------------------------------------------------------------------
1 |
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_story_editor/src/controller/controller.dart';
4 | import 'package:flutter_story_editor/src/enums/story_editing_modes.dart';
5 | import 'package:flutter_story_editor/src/theme/style.dart';
6 |
7 | class StickerTopView extends StatelessWidget {
8 | final FlutterStoryEditorController controller;
9 | const StickerTopView({super.key, required this.controller});
10 |
11 | @override
12 | Widget build(BuildContext context) {
13 | return Row(
14 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
15 | children: [
16 | GestureDetector(onTap: () {
17 | controller.setStoryEditingModeSelected = StoryEditingModes.none;
18 | },child: const Icon(Icons.arrow_back, size: 25, color: Colors.white,)),
19 | Container(
20 | width: 40,
21 | height: 40,
22 | decoration: const BoxDecoration(
23 | shape: BoxShape.circle,
24 | color: tealColor,
25 | ),
26 | child: const Center(
27 | child: Icon(Icons.emoji_emotions_outlined, color: Colors.white,),
28 | ),
29 | )
30 | ],
31 | );
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/lib/src/views/text_control_views/text_control_view.dart:
--------------------------------------------------------------------------------
1 |
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_story_editor/src/controller/controller.dart';
4 |
5 | import 'text_top_view.dart';
6 | class TextControlView extends StatelessWidget {
7 | final FlutterStoryEditorController controller;
8 | final VoidCallback? onAlignChangeClickListener;
9 | final IconData? icon;
10 | const TextControlView({super.key, required this.controller, this.onAlignChangeClickListener, this.icon});
11 |
12 | @override
13 | Widget build(BuildContext context) {
14 | return Stack(
15 | children: [
16 | Align(
17 | alignment: Alignment.topCenter,
18 | child: TextTopView(
19 | icon: icon,
20 | onAlignChangeClickListener: onAlignChangeClickListener,
21 | controller: controller,
22 | ),
23 | ),
24 | ],
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/lib/src/views/text_control_views/text_top_view.dart:
--------------------------------------------------------------------------------
1 |
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_story_editor/src/controller/controller.dart';
4 | import 'package:flutter_story_editor/src/enums/story_editing_modes.dart';
5 |
6 |
7 | class TextTopView extends StatelessWidget {
8 | final FlutterStoryEditorController controller;
9 | final VoidCallback? onAlignChangeClickListener;
10 | final IconData? icon;
11 | const TextTopView({super.key, required this.controller, this.onAlignChangeClickListener, this.icon});
12 |
13 | @override
14 | Widget build(BuildContext context) {
15 |
16 | return Padding(
17 | padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 40),
18 | child: Column(
19 | children: [
20 | Row(
21 | children: [
22 | GestureDetector(
23 | onTap: () {
24 | FocusScope.of(context).unfocus();
25 |
26 | controller.setStoryEditingModeSelected = StoryEditingModes.none;
27 |
28 | },
29 | child: Container(
30 | padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 5),
31 | decoration: BoxDecoration(
32 | borderRadius: BorderRadius.circular(20),
33 | border: Border.all(width: 1, color: Colors.white)
34 | ),
35 | child: const Center(
36 | child: Text("Done", style: TextStyle(fontSize: 15, color: Colors.white),),
37 | ),
38 | ),
39 | ),
40 | const SizedBox(width: 50),
41 | GestureDetector(
42 | onTap: () {
43 | onAlignChangeClickListener!();
44 | },
45 | child: Row(
46 | children: [
47 | Icon(icon ?? Icons.format_align_center, size: 30, color: Colors.white,)
48 | ],
49 | ),
50 | )
51 | ],
52 | ),
53 | ],
54 | ),
55 | );
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/lib/src/widgets/draggable_sticker_widget.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_story_editor/src/utils/matrix_gesture_detector.dart';
3 |
4 | class DraggableStickerWidget extends StatefulWidget {
5 | final String stickerPath;
6 | const DraggableStickerWidget({super.key, required this.stickerPath});
7 |
8 | @override
9 | State createState() => _DraggableStickerWidgetState();
10 | }
11 |
12 | class _DraggableStickerWidgetState extends State {
13 | Offset offset = const Offset(0, 0);
14 |
15 | @override
16 | Widget build(BuildContext context) {
17 | final ValueNotifier notifier = ValueNotifier(Matrix4.identity());
18 | return MatrixGestureDetector(
19 | onMatrixUpdate: (m, tm, sm, rm) {
20 | notifier.value = m;
21 | },
22 | child: AnimatedBuilder(
23 | animation: notifier,
24 | builder: (BuildContext context, Widget? child) {
25 | return Transform(
26 | transform: notifier.value,
27 | child: Align(alignment: Alignment.center, child: Image.asset(widget.stickerPath)),
28 | );
29 | },
30 |
31 | ),
32 | );
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/lib/src/widgets/hue_color_picker_slider.dart:
--------------------------------------------------------------------------------
1 |
2 | import 'package:flutter/material.dart';
3 | import 'package:hsv_color_pickers/hsv_color_pickers.dart';
4 |
5 | class HueColorPickerSlider extends StatefulWidget {
6 | final Function(HSVColor) onChanged;
7 | const HueColorPickerSlider({super.key, required this.onChanged});
8 |
9 | @override
10 | State createState() => _HueColorPickerSliderState();
11 | }
12 |
13 | class _HueColorPickerSliderState extends State {
14 | @override
15 | Widget build(BuildContext context) {
16 | return RotatedBox(
17 | quarterTurns: 1,
18 | child: HuePicker(
19 | trackHeight: 10,
20 | controller: HueController(HSVColor.fromColor(Colors.tealAccent)),
21 | onChanged: (HSVColor color) {
22 | widget.onChanged(color);
23 | },
24 | ),
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: flutter_story_editor
2 | description: "This package uses style of WhatsApp story image/video editor, you can edit images and videos. You can add texts, stickers, finger drawing, apply filter, and undo"
3 | version: 0.0.2
4 |
5 | license: MIT
6 |
7 |
8 | repository: https://github.com/AdnanKhan45/flutter_story_editor/tree/main
9 | homepage: https://github.com/AdnanKhan45/flutter_story_editor/blob/main/lib/flutter_story_editor.dart
10 |
11 | environment:
12 | sdk: '>=3.3.0 <4.0.0'
13 | flutter: ">=1.17.0"
14 |
15 | dependencies:
16 | flutter:
17 | sdk: flutter
18 | image_cropper: ^5.0.1
19 | video_player: ^2.8.6
20 | video_trimmer: ^3.0.1
21 | video_thumbnail: ^0.5.3
22 | hsv_color_pickers: ^0.3.0
23 | perfect_freehand: ^2.3.2
24 |
25 | file_picker: ^8.0.1
26 | path: ^1.9.0
27 | path_provider: ^2.1.3
28 | flutter_keyboard_visibility: ^6.0.0
29 | vector_math: ^2.1.4
30 | font_awesome_flutter: ^10.7.0
31 | material_design_icons_flutter: ^7.0.7296
32 |
33 | dev_dependencies:
34 | flutter_test:
35 | sdk: flutter
36 | flutter_lints: ^3.0.2
37 |
38 | # For information on the generic Dart part of this file, see the
39 | # following page: https://dart.dev/tools/pub/pubspec
40 |
41 | # The following section is specific to Flutter packages.
42 | flutter:
43 |
44 | # To add assets to your package, add an assets section, like this:
45 | assets:
46 | - assets/images/
47 | - assets/emojies/
48 |
49 | # An image asset can refer to one or more resolution-specific "variants", see
50 | # https://flutter.dev/assets-and-images/#resolution-aware
51 |
52 | # For details regarding adding assets from package dependencies, see
53 | # https://flutter.dev/assets-and-images/#from-packages
54 |
55 | # To add custom fonts to your application, add a fonts section here,
56 | # in this "flutter" section. Each entry in this list should have a
57 | # "family" key with the font family name, and a "fonts" key with a
58 | # list giving the asset and other descriptors for the font. For
59 | # example:
60 | fonts:
61 | - family: Roboto
62 | fonts:
63 | - asset: assets/fonts/roboto/Roboto-Regular.ttf
64 | - family: Merriweather
65 | fonts:
66 | - asset: assets/fonts/merriweather/Merriweather-Regular.ttf
67 | - family: Mandimi One
68 | fonts:
69 | - asset: assets/fonts/madimiOne/MadimiOne-Regular.ttf
70 | - family: Dancing Script
71 | fonts:
72 | - asset: assets/fonts/dancing_script/DancingScript-Regular.ttf
73 | - family: Angkor
74 | fonts:
75 | - asset: assets/fonts/angkor/Angkor-Regular.ttf
76 | - family: Montserrat
77 | fonts:
78 | - asset: assets/fonts/montserrat/Montserrat-Regular.ttf
79 | - family: Lato
80 | fonts:
81 | - asset: assets/fonts/lato/Lato-Regular.ttf
82 | - family: Oswald
83 | fonts:
84 | - asset: assets/fonts/oswald/Oswald-Regular.ttf
85 | - family: Raleway
86 | fonts:
87 | - asset: assets/fonts/raleway/Raleway-Regular.ttf
88 | - family: Lora
89 | fonts:
90 | - asset: assets/fonts/lora/Lora-Regular.ttf
91 | - family: Pacifico
92 | fonts:
93 | - asset: assets/fonts/pacifico/Pacifico-Regular.ttf
94 | #
95 | # For details regarding fonts in packages, see
96 | # https://flutter.dev/custom-fonts/#from-packages
97 |
--------------------------------------------------------------------------------
/screenshots/CropAndPaint.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/screenshots/CropAndPaint.gif
--------------------------------------------------------------------------------
/screenshots/Text.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/screenshots/Text.gif
--------------------------------------------------------------------------------
/screenshots/VideoEditing.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/screenshots/VideoEditing.gif
--------------------------------------------------------------------------------
/screenshots/image_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/screenshots/image_1.png
--------------------------------------------------------------------------------
/screenshots/image_10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/screenshots/image_10.png
--------------------------------------------------------------------------------
/screenshots/image_11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/screenshots/image_11.png
--------------------------------------------------------------------------------
/screenshots/image_12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/screenshots/image_12.png
--------------------------------------------------------------------------------
/screenshots/image_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/screenshots/image_2.png
--------------------------------------------------------------------------------
/screenshots/image_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/screenshots/image_3.png
--------------------------------------------------------------------------------
/screenshots/image_4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/screenshots/image_4.png
--------------------------------------------------------------------------------
/screenshots/image_5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/screenshots/image_5.png
--------------------------------------------------------------------------------
/screenshots/image_6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/screenshots/image_6.png
--------------------------------------------------------------------------------
/screenshots/image_7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/screenshots/image_7.png
--------------------------------------------------------------------------------
/screenshots/image_8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/screenshots/image_8.png
--------------------------------------------------------------------------------
/test/flutter_story_editor_test.dart:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanKhan45/flutter_story_editor/a61ea262265c2ab831e0dfaadb4849bea7d4f917/test/flutter_story_editor_test.dart
--------------------------------------------------------------------------------