├── .circleci
└── config.yml
├── .gitignore
├── .metadata
├── CHANGELOG.md
├── LICENSE
├── README.md
├── analysis_options.yaml
├── assets
├── Record_1.gif
└── Screenshot_1.jpg
├── example
├── .gitignore
├── .metadata
├── README.md
├── analysis_options.yaml
├── android
│ ├── .gitignore
│ ├── app
│ │ ├── build.gradle
│ │ └── src
│ │ │ ├── debug
│ │ │ └── AndroidManifest.xml
│ │ │ ├── main
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── kotlin
│ │ │ │ └── com
│ │ │ │ │ └── example
│ │ │ │ │ └── example
│ │ │ │ │ └── MainActivity.kt
│ │ │ └── res
│ │ │ │ ├── drawable-v21
│ │ │ │ └── launch_background.xml
│ │ │ │ ├── drawable
│ │ │ │ └── launch_background.xml
│ │ │ │ ├── mipmap-hdpi
│ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-mdpi
│ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xxxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ │ ├── values-night
│ │ │ │ └── styles.xml
│ │ │ │ └── values
│ │ │ │ └── styles.xml
│ │ │ └── profile
│ │ │ └── AndroidManifest.xml
│ ├── build.gradle
│ ├── gradle.properties
│ ├── gradle
│ │ └── wrapper
│ │ │ └── gradle-wrapper.properties
│ └── settings.gradle
├── ios
│ ├── .gitignore
│ ├── Flutter
│ │ ├── AppFrameworkInfo.plist
│ │ ├── Debug.xcconfig
│ │ └── Release.xcconfig
│ ├── Runner.xcodeproj
│ │ ├── project.pbxproj
│ │ ├── project.xcworkspace
│ │ │ ├── contents.xcworkspacedata
│ │ │ └── xcshareddata
│ │ │ │ ├── IDEWorkspaceChecks.plist
│ │ │ │ └── WorkspaceSettings.xcsettings
│ │ └── xcshareddata
│ │ │ └── xcschemes
│ │ │ └── Runner.xcscheme
│ ├── Runner.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ ├── IDEWorkspaceChecks.plist
│ │ │ └── WorkspaceSettings.xcsettings
│ └── Runner
│ │ ├── AppDelegate.swift
│ │ ├── Assets.xcassets
│ │ ├── AppIcon.appiconset
│ │ │ ├── Contents.json
│ │ │ ├── Icon-App-1024x1024@1x.png
│ │ │ ├── Icon-App-20x20@1x.png
│ │ │ ├── Icon-App-20x20@2x.png
│ │ │ ├── Icon-App-20x20@3x.png
│ │ │ ├── Icon-App-29x29@1x.png
│ │ │ ├── Icon-App-29x29@2x.png
│ │ │ ├── Icon-App-29x29@3x.png
│ │ │ ├── Icon-App-40x40@1x.png
│ │ │ ├── Icon-App-40x40@2x.png
│ │ │ ├── Icon-App-40x40@3x.png
│ │ │ ├── Icon-App-60x60@2x.png
│ │ │ ├── Icon-App-60x60@3x.png
│ │ │ ├── Icon-App-76x76@1x.png
│ │ │ ├── Icon-App-76x76@2x.png
│ │ │ └── Icon-App-83.5x83.5@2x.png
│ │ └── LaunchImage.imageset
│ │ │ ├── Contents.json
│ │ │ ├── LaunchImage.png
│ │ │ ├── LaunchImage@2x.png
│ │ │ ├── LaunchImage@3x.png
│ │ │ └── README.md
│ │ ├── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ │ ├── Info.plist
│ │ └── Runner-Bridging-Header.h
├── lib
│ ├── main.dart
│ └── result.dart
├── pubspec.lock
├── pubspec.yaml
└── test
│ └── widget_test.dart
├── lib
├── easy_image_editor.dart
└── src
│ ├── editor_view.dart
│ ├── matrix_gesture_detector.dart
│ └── resizable_widget.dart
├── pubspec.lock
├── pubspec.yaml
└── test
└── easy_image_editor_test.dart
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | # Use the latest 2.1 version of CircleCI pipeline process engine.
2 | # See: https://circleci.com/docs/2.0/configuration-reference
3 | version: 2.1
4 |
5 | # Define a job to be invoked later in a workflow.
6 | # See: https://circleci.com/docs/2.0/configuration-reference/#jobs
7 | jobs:
8 | say-hello:
9 | # Specify the execution environment. You can specify an image from Dockerhub or use one of our Convenience Images from CircleCI's Developer Hub.
10 | # See: https://circleci.com/docs/2.0/configuration-reference/#docker-machine-macos-windows-executor
11 | docker:
12 | - image: cimg/base:stable
13 | # Add steps to the job
14 | # See: https://circleci.com/docs/2.0/configuration-reference/#steps
15 | steps:
16 | - checkout
17 | - run:
18 | name: "Say hello"
19 | command: "echo Hello, World!"
20 |
21 | # Invoke jobs via workflows
22 | # See: https://circleci.com/docs/2.0/configuration-reference/#workflows
23 | workflows:
24 | say-hello-workflow:
25 | jobs:
26 | - say-hello
27 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 |
12 | # IntelliJ related
13 | *.iml
14 | *.ipr
15 | *.iws
16 | .idea/
17 |
18 | # The .vscode folder contains launch configuration and tasks you configure in
19 | # VS Code which you may wish to be included in version control, so this line
20 | # is commented out by default.
21 | #.vscode/
22 |
23 | # Flutter/Dart/Pub related
24 | **/doc/api/
25 | .dart_tool/
26 | .flutter-plugins
27 | .flutter-plugins-dependencies
28 | .packages
29 | .pub-cache/
30 | .pub/
31 | build/
32 |
33 | # Android related
34 | **/android/**/gradle-wrapper.jar
35 | **/android/.gradle
36 | **/android/captures/
37 | **/android/gradlew
38 | **/android/gradlew.bat
39 | **/android/local.properties
40 | **/android/**/GeneratedPluginRegistrant.java
41 |
42 | # iOS/XCode related
43 | **/ios/**/*.mode1v3
44 | **/ios/**/*.mode2v3
45 | **/ios/**/*.moved-aside
46 | **/ios/**/*.pbxuser
47 | **/ios/**/*.perspectivev3
48 | **/ios/**/*sync/
49 | **/ios/**/.sconsign.dblite
50 | **/ios/**/.tags*
51 | **/ios/**/.vagrant/
52 | **/ios/**/DerivedData/
53 | **/ios/**/Icon?
54 | **/ios/**/Pods/
55 | **/ios/**/.symlinks/
56 | **/ios/**/profile
57 | **/ios/**/xcuserdata
58 | **/ios/.generated/
59 | **/ios/Flutter/App.framework
60 | **/ios/Flutter/Flutter.framework
61 | **/ios/Flutter/Flutter.podspec
62 | **/ios/Flutter/Generated.xcconfig
63 | **/ios/Flutter/ephemeral
64 | **/ios/Flutter/app.flx
65 | **/ios/Flutter/app.zip
66 | **/ios/Flutter/flutter_assets/
67 | **/ios/Flutter/flutter_export_environment.sh
68 | **/ios/ServiceDefinitions.json
69 | **/ios/Runner/GeneratedPluginRegistrant.*
70 |
71 | # Exceptions to above rules.
72 | !**/ios/**/default.mode1v3
73 | !**/ios/**/default.mode2v3
74 | !**/ios/**/default.pbxuser
75 | !**/ios/**/default.perspectivev3
76 |
--------------------------------------------------------------------------------
/.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: 18116933e77adc82f80866c928266a5b4f1ed645
8 | channel: stable
9 |
10 | project_type: package
11 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## 1.0.3
2 | * fix bug
3 | * added EasyImageEditorController to perform operations
4 | * update example app
5 |
6 | ## 1.0.2
7 | * fix bug
8 | * now editor allow handle all actions manually like move, rotate, zoom, flip
9 | * user can enable and disable touch actions
10 |
11 | ## 1.0.1
12 | * fix issue and update README.md
13 |
14 | ## 0.0.1
15 |
16 | * TODO: Describe initial release.
17 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2022 easy_image_editor
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
13 |
14 | # Easy Image Editor
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | EasyImageEditor use for add any kind of widget over the background image or color and move that widget, resize, rotate.
30 |
31 |
32 |
33 |
34 |
35 | ## Features
36 |
37 | 1) change editor background color.
38 | 2) add any widget as background in editor.
39 | 3) add any widget over the editor.
40 | 4) move, resize, flip, zoom and rotate added widget.
41 | 5) update added widget with another widget.
42 | 6) allow undo and redo.
43 | 7) allow single and multiple selection.
44 | 8) allow change border color and remove icon.
45 | 9) remove added widget.
46 | 10) handle all action manually
47 |
48 | ## Getting started
49 |
50 | First, add `easy_image_editor` as a [dependency in your pubspec.yaml file](https://flutter.dev/docs/development/platform-integration/platform-channels).
51 | then add this line in your file `import 'package:easy_image_editor/easy_image_editor.dart';`
52 |
53 | ## Usage
54 |
55 | ```dart
56 | import 'package:easy_image_editor/easy_image_editor.dart';
57 |
58 | class _MyHomePageState extends State {
59 | late EasyImageEditorController _easyImageEditorController;
60 | ...
61 |
62 | @override
63 | void initState() {
64 | super.initState();
65 | ...
66 | }
67 | ...
68 |
69 | @override
70 | Widget build(BuildContext context) {
71 | return Scaffold(
72 | ...
73 | body: EditorView(
74 | onInitialize: (controller) {
75 | setState(() {
76 | _easyImageEditorController = controller;
77 | });
78 | },
79 | ),
80 | ...
81 | );
82 | }
83 | ...
84 | }
85 | ```
86 | for more detail and usage see /example/lib/main.dart
87 |
88 | ## Additional information
89 |
90 | 1) `borderColor` use for set border color of widget default value `Colors.black`.
91 | 2) `removeIcon` set remove icon of widget default value `Icon(Icons.cancel)`.
92 | 3) `onViewTouch` this event call when widget touch.
93 | 4) `onViewTouchOver` this event call when widget touch remove.
94 | 5) `addBackgroundColor` set background color of editor.
95 | 6) `addBackgroundView` set background color of editor. it will overlap background color.
96 | 7) `addView` add any kind of view over the editor.
97 | 8) `updateView` update added view in editor.
98 | 9) `canEditMultipleView` set edit selection mode multiple or single default value `true`.
99 | 10) `hideViewControl` it will hide borders and remove icons of all added widget.
100 | 11) `showViewControl` it will show borders and remove icons of all added widget.
101 | 12) `onClick` this event call when widget click.
102 | 13) `clickToFocusAndMove` if you set true then any widget move, rotate, zoom by touch when user click's on default value `false`.
103 | 14) `moveView` move widget over the editor programmatically.
104 | 15) `rotateView` rotate widget over the editor programmatically.
105 | 16) `zoomInOutView` zoom in or out widget over the editor programmatically.
106 | 17) `flipView` flip vertical or horizontal widget over the editor programmatically.
107 | 18) `updateMatrix` update widget matrix over the editor programmatically like your way.
108 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/assets/Record_1.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rajeshbdabhi/easy_image_editor/57bc36fc65508d72bd6888058f8359edd598ac1c/assets/Record_1.gif
--------------------------------------------------------------------------------
/assets/Screenshot_1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rajeshbdabhi/easy_image_editor/57bc36fc65508d72bd6888058f8359edd598ac1c/assets/Screenshot_1.jpg
--------------------------------------------------------------------------------
/example/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 |
12 | # IntelliJ related
13 | *.iml
14 | *.ipr
15 | *.iws
16 | .idea/
17 |
18 | # The .vscode folder contains launch configuration and tasks you configure in
19 | # VS Code which you may wish to be included in version control, so this line
20 | # is commented out by default.
21 | #.vscode/
22 |
23 | # Flutter/Dart/Pub related
24 | **/doc/api/
25 | **/ios/Flutter/.last_build_id
26 | .dart_tool/
27 | .flutter-plugins
28 | .flutter-plugins-dependencies
29 | .packages
30 | .pub-cache/
31 | .pub/
32 | /build/
33 |
34 | # Web related
35 | lib/generated_plugin_registrant.dart
36 |
37 | # Symbolication related
38 | app.*.symbols
39 |
40 | # Obfuscation related
41 | app.*.map.json
42 |
43 | # Android Studio will place build artifacts here
44 | /android/app/debug
45 | /android/app/profile
46 | /android/app/release
47 |
--------------------------------------------------------------------------------
/example/.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: 18116933e77adc82f80866c928266a5b4f1ed645
8 | channel: stable
9 |
10 | project_type: app
11 |
--------------------------------------------------------------------------------
/example/README.md:
--------------------------------------------------------------------------------
1 | # example
2 |
3 | A new Flutter project.
4 |
5 | ## Getting Started
6 |
7 | This project is a starting point for a Flutter application.
8 |
9 | A few resources to get you started if this is your first Flutter project:
10 |
11 | - [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab)
12 | - [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook)
13 |
14 | For help getting started with Flutter, view our
15 | [online documentation](https://flutter.dev/docs), which offers tutorials,
16 | samples, guidance on mobile development, and a full API reference.
17 |
--------------------------------------------------------------------------------
/example/analysis_options.yaml:
--------------------------------------------------------------------------------
1 | # This file configures the analyzer, which statically analyzes Dart code to
2 | # check for errors, warnings, and lints.
3 | #
4 | # The issues identified by the analyzer are surfaced in the UI of Dart-enabled
5 | # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
6 | # invoked from the command line by running `flutter analyze`.
7 |
8 | # The following line activates a set of recommended lints for Flutter apps,
9 | # packages, and plugins designed to encourage good coding practices.
10 | include: package:flutter_lints/flutter.yaml
11 |
12 | linter:
13 | # The lint rules applied to this project can be customized in the
14 | # section below to disable rules from the `package:flutter_lints/flutter.yaml`
15 | # included above or to enable additional rules. A list of all available lints
16 | # and their documentation is published at
17 | # https://dart-lang.github.io/linter/lints/index.html.
18 | #
19 | # Instead of disabling a lint rule for the entire project in the
20 | # section below, it can also be suppressed for a single line of code
21 | # or a specific dart file by using the `// ignore: name_of_lint` and
22 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file
23 | # producing the lint.
24 | rules:
25 | # avoid_print: false # Uncomment to disable the `avoid_print` rule
26 | # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
27 |
28 | # Additional information about this file can be found at
29 | # https://dart.dev/guides/language/analysis-options
30 |
--------------------------------------------------------------------------------
/example/android/.gitignore:
--------------------------------------------------------------------------------
1 | gradle-wrapper.jar
2 | /.gradle
3 | /captures/
4 | /gradlew
5 | /gradlew.bat
6 | /local.properties
7 | GeneratedPluginRegistrant.java
8 |
9 | # Remember to never publicly share your keystore.
10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
11 | key.properties
12 | **/*.keystore
13 | **/*.jks
14 |
--------------------------------------------------------------------------------
/example/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | def localProperties = new Properties()
2 | def localPropertiesFile = rootProject.file('local.properties')
3 | if (localPropertiesFile.exists()) {
4 | localPropertiesFile.withReader('UTF-8') { reader ->
5 | localProperties.load(reader)
6 | }
7 | }
8 |
9 | def flutterRoot = localProperties.getProperty('flutter.sdk')
10 | if (flutterRoot == null) {
11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
12 | }
13 |
14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
15 | if (flutterVersionCode == null) {
16 | flutterVersionCode = '1'
17 | }
18 |
19 | def flutterVersionName = localProperties.getProperty('flutter.versionName')
20 | if (flutterVersionName == null) {
21 | flutterVersionName = '1.0'
22 | }
23 |
24 | apply plugin: 'com.android.application'
25 | apply plugin: 'kotlin-android'
26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
27 |
28 | android {
29 | compileSdkVersion 31
30 |
31 | compileOptions {
32 | sourceCompatibility JavaVersion.VERSION_1_8
33 | targetCompatibility JavaVersion.VERSION_1_8
34 | }
35 |
36 | kotlinOptions {
37 | jvmTarget = '1.8'
38 | }
39 |
40 | sourceSets {
41 | main.java.srcDirs += 'src/main/kotlin'
42 | }
43 |
44 | defaultConfig {
45 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
46 | applicationId "com.example.example"
47 | minSdkVersion 16
48 | targetSdkVersion 31
49 | versionCode flutterVersionCode.toInteger()
50 | versionName flutterVersionName
51 | }
52 |
53 | buildTypes {
54 | release {
55 | // TODO: Add your own signing config for the release build.
56 | // Signing with the debug keys for now, so `flutter run --release` works.
57 | signingConfig signingConfigs.debug
58 | }
59 | }
60 | }
61 |
62 | flutter {
63 | source '../..'
64 | }
65 |
66 | dependencies {
67 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
68 | }
69 |
--------------------------------------------------------------------------------
/example/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
13 |
17 |
21 |
26 |
30 |
31 |
32 |
33 |
34 |
35 |
37 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.example.example
2 |
3 | import io.flutter.embedding.android.FlutterActivity
4 |
5 | class MainActivity: FlutterActivity() {
6 | }
7 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable-v21/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rajeshbdabhi/easy_image_editor/57bc36fc65508d72bd6888058f8359edd598ac1c/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rajeshbdabhi/easy_image_editor/57bc36fc65508d72bd6888058f8359edd598ac1c/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rajeshbdabhi/easy_image_editor/57bc36fc65508d72bd6888058f8359edd598ac1c/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rajeshbdabhi/easy_image_editor/57bc36fc65508d72bd6888058f8359edd598ac1c/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rajeshbdabhi/easy_image_editor/57bc36fc65508d72bd6888058f8359edd598ac1c/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values-night/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/example/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext.kotlin_version = '1.6.10'
3 | repositories {
4 | google()
5 | mavenCentral()
6 | }
7 |
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:4.1.0'
10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
11 | }
12 | }
13 |
14 | allprojects {
15 | repositories {
16 | google()
17 | mavenCentral()
18 | }
19 | }
20 |
21 | rootProject.buildDir = '../build'
22 | subprojects {
23 | project.buildDir = "${rootProject.buildDir}/${project.name}"
24 | project.evaluationDependsOn(':app')
25 | }
26 |
27 | task clean(type: Delete) {
28 | delete rootProject.buildDir
29 | }
30 |
--------------------------------------------------------------------------------
/example/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 | android.useAndroidX=true
3 | android.enableJetifier=true
4 |
--------------------------------------------------------------------------------
/example/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Jun 23 08:50:38 CEST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip
7 |
--------------------------------------------------------------------------------
/example/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
4 | def properties = new Properties()
5 |
6 | assert localPropertiesFile.exists()
7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
8 |
9 | def flutterSdkPath = properties.getProperty("flutter.sdk")
10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
12 |
--------------------------------------------------------------------------------
/example/ios/.gitignore:
--------------------------------------------------------------------------------
1 | **/dgph
2 | *.mode1v3
3 | *.mode2v3
4 | *.moved-aside
5 | *.pbxuser
6 | *.perspectivev3
7 | **/*sync/
8 | .sconsign.dblite
9 | .tags*
10 | **/.vagrant/
11 | **/DerivedData/
12 | Icon?
13 | **/Pods/
14 | **/.symlinks/
15 | profile
16 | xcuserdata
17 | **/.generated/
18 | Flutter/App.framework
19 | Flutter/Flutter.framework
20 | Flutter/Flutter.podspec
21 | Flutter/Generated.xcconfig
22 | Flutter/ephemeral/
23 | Flutter/app.flx
24 | Flutter/app.zip
25 | Flutter/flutter_assets/
26 | Flutter/flutter_export_environment.sh
27 | ServiceDefinitions.json
28 | Runner/GeneratedPluginRegistrant.*
29 |
30 | # Exceptions to above rules.
31 | !default.mode1v3
32 | !default.mode2v3
33 | !default.pbxuser
34 | !default.perspectivev3
35 |
--------------------------------------------------------------------------------
/example/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | App
9 | CFBundleIdentifier
10 | io.flutter.flutter.app
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | App
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | MinimumOSVersion
24 | 9.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/example/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Generated.xcconfig"
2 |
--------------------------------------------------------------------------------
/example/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Generated.xcconfig"
2 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
11 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
12 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
13 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
14 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
15 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
16 | /* End PBXBuildFile section */
17 |
18 | /* Begin PBXCopyFilesBuildPhase section */
19 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = {
20 | isa = PBXCopyFilesBuildPhase;
21 | buildActionMask = 2147483647;
22 | dstPath = "";
23 | dstSubfolderSpec = 10;
24 | files = (
25 | );
26 | name = "Embed Frameworks";
27 | runOnlyForDeploymentPostprocessing = 0;
28 | };
29 | /* End PBXCopyFilesBuildPhase section */
30 |
31 | /* Begin PBXFileReference section */
32 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; };
33 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; };
34 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
35 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; };
36 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
37 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; };
38 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; };
39 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; };
40 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
41 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
42 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
43 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
44 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
45 | /* End PBXFileReference section */
46 |
47 | /* Begin PBXFrameworksBuildPhase section */
48 | 97C146EB1CF9000F007C117D /* Frameworks */ = {
49 | isa = PBXFrameworksBuildPhase;
50 | buildActionMask = 2147483647;
51 | files = (
52 | );
53 | runOnlyForDeploymentPostprocessing = 0;
54 | };
55 | /* End PBXFrameworksBuildPhase section */
56 |
57 | /* Begin PBXGroup section */
58 | 9740EEB11CF90186004384FC /* Flutter */ = {
59 | isa = PBXGroup;
60 | children = (
61 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
62 | 9740EEB21CF90195004384FC /* Debug.xcconfig */,
63 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
64 | 9740EEB31CF90195004384FC /* Generated.xcconfig */,
65 | );
66 | name = Flutter;
67 | sourceTree = "";
68 | };
69 | 97C146E51CF9000F007C117D = {
70 | isa = PBXGroup;
71 | children = (
72 | 9740EEB11CF90186004384FC /* Flutter */,
73 | 97C146F01CF9000F007C117D /* Runner */,
74 | 97C146EF1CF9000F007C117D /* Products */,
75 | );
76 | sourceTree = "";
77 | };
78 | 97C146EF1CF9000F007C117D /* Products */ = {
79 | isa = PBXGroup;
80 | children = (
81 | 97C146EE1CF9000F007C117D /* Runner.app */,
82 | );
83 | name = Products;
84 | sourceTree = "";
85 | };
86 | 97C146F01CF9000F007C117D /* Runner */ = {
87 | isa = PBXGroup;
88 | children = (
89 | 97C146FA1CF9000F007C117D /* Main.storyboard */,
90 | 97C146FD1CF9000F007C117D /* Assets.xcassets */,
91 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
92 | 97C147021CF9000F007C117D /* Info.plist */,
93 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
94 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
95 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
96 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
97 | );
98 | path = Runner;
99 | sourceTree = "";
100 | };
101 | /* End PBXGroup section */
102 |
103 | /* Begin PBXNativeTarget section */
104 | 97C146ED1CF9000F007C117D /* Runner */ = {
105 | isa = PBXNativeTarget;
106 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
107 | buildPhases = (
108 | 9740EEB61CF901F6004384FC /* Run Script */,
109 | 97C146EA1CF9000F007C117D /* Sources */,
110 | 97C146EB1CF9000F007C117D /* Frameworks */,
111 | 97C146EC1CF9000F007C117D /* Resources */,
112 | 9705A1C41CF9048500538489 /* Embed Frameworks */,
113 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
114 | );
115 | buildRules = (
116 | );
117 | dependencies = (
118 | );
119 | name = Runner;
120 | productName = Runner;
121 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
122 | productType = "com.apple.product-type.application";
123 | };
124 | /* End PBXNativeTarget section */
125 |
126 | /* Begin PBXProject section */
127 | 97C146E61CF9000F007C117D /* Project object */ = {
128 | isa = PBXProject;
129 | attributes = {
130 | LastUpgradeCheck = 1020;
131 | ORGANIZATIONNAME = "";
132 | TargetAttributes = {
133 | 97C146ED1CF9000F007C117D = {
134 | CreatedOnToolsVersion = 7.3.1;
135 | LastSwiftMigration = 1100;
136 | };
137 | };
138 | };
139 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
140 | compatibilityVersion = "Xcode 9.3";
141 | developmentRegion = en;
142 | hasScannedForEncodings = 0;
143 | knownRegions = (
144 | en,
145 | Base,
146 | );
147 | mainGroup = 97C146E51CF9000F007C117D;
148 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
149 | projectDirPath = "";
150 | projectRoot = "";
151 | targets = (
152 | 97C146ED1CF9000F007C117D /* Runner */,
153 | );
154 | };
155 | /* End PBXProject section */
156 |
157 | /* Begin PBXResourcesBuildPhase section */
158 | 97C146EC1CF9000F007C117D /* Resources */ = {
159 | isa = PBXResourcesBuildPhase;
160 | buildActionMask = 2147483647;
161 | files = (
162 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
163 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
164 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
165 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
166 | );
167 | runOnlyForDeploymentPostprocessing = 0;
168 | };
169 | /* End PBXResourcesBuildPhase section */
170 |
171 | /* Begin PBXShellScriptBuildPhase section */
172 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
173 | isa = PBXShellScriptBuildPhase;
174 | buildActionMask = 2147483647;
175 | files = (
176 | );
177 | inputPaths = (
178 | );
179 | name = "Thin Binary";
180 | outputPaths = (
181 | );
182 | runOnlyForDeploymentPostprocessing = 0;
183 | shellPath = /bin/sh;
184 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
185 | };
186 | 9740EEB61CF901F6004384FC /* Run Script */ = {
187 | isa = PBXShellScriptBuildPhase;
188 | buildActionMask = 2147483647;
189 | files = (
190 | );
191 | inputPaths = (
192 | );
193 | name = "Run Script";
194 | outputPaths = (
195 | );
196 | runOnlyForDeploymentPostprocessing = 0;
197 | shellPath = /bin/sh;
198 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
199 | };
200 | /* End PBXShellScriptBuildPhase section */
201 |
202 | /* Begin PBXSourcesBuildPhase section */
203 | 97C146EA1CF9000F007C117D /* Sources */ = {
204 | isa = PBXSourcesBuildPhase;
205 | buildActionMask = 2147483647;
206 | files = (
207 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
208 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
209 | );
210 | runOnlyForDeploymentPostprocessing = 0;
211 | };
212 | /* End PBXSourcesBuildPhase section */
213 |
214 | /* Begin PBXVariantGroup section */
215 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = {
216 | isa = PBXVariantGroup;
217 | children = (
218 | 97C146FB1CF9000F007C117D /* Base */,
219 | );
220 | name = Main.storyboard;
221 | sourceTree = "";
222 | };
223 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
224 | isa = PBXVariantGroup;
225 | children = (
226 | 97C147001CF9000F007C117D /* Base */,
227 | );
228 | name = LaunchScreen.storyboard;
229 | sourceTree = "";
230 | };
231 | /* End PBXVariantGroup section */
232 |
233 | /* Begin XCBuildConfiguration section */
234 | 249021D3217E4FDB00AE95B9 /* Profile */ = {
235 | isa = XCBuildConfiguration;
236 | buildSettings = {
237 | ALWAYS_SEARCH_USER_PATHS = NO;
238 | CLANG_ANALYZER_NONNULL = YES;
239 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
240 | CLANG_CXX_LIBRARY = "libc++";
241 | CLANG_ENABLE_MODULES = YES;
242 | CLANG_ENABLE_OBJC_ARC = YES;
243 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
244 | CLANG_WARN_BOOL_CONVERSION = YES;
245 | CLANG_WARN_COMMA = YES;
246 | CLANG_WARN_CONSTANT_CONVERSION = YES;
247 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
248 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
249 | CLANG_WARN_EMPTY_BODY = YES;
250 | CLANG_WARN_ENUM_CONVERSION = YES;
251 | CLANG_WARN_INFINITE_RECURSION = YES;
252 | CLANG_WARN_INT_CONVERSION = YES;
253 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
254 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
255 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
256 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
257 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
258 | CLANG_WARN_STRICT_PROTOTYPES = YES;
259 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
260 | CLANG_WARN_UNREACHABLE_CODE = YES;
261 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
262 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
263 | COPY_PHASE_STRIP = NO;
264 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
265 | ENABLE_NS_ASSERTIONS = NO;
266 | ENABLE_STRICT_OBJC_MSGSEND = YES;
267 | GCC_C_LANGUAGE_STANDARD = gnu99;
268 | GCC_NO_COMMON_BLOCKS = YES;
269 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
270 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
271 | GCC_WARN_UNDECLARED_SELECTOR = YES;
272 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
273 | GCC_WARN_UNUSED_FUNCTION = YES;
274 | GCC_WARN_UNUSED_VARIABLE = YES;
275 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
276 | MTL_ENABLE_DEBUG_INFO = NO;
277 | SDKROOT = iphoneos;
278 | SUPPORTED_PLATFORMS = iphoneos;
279 | TARGETED_DEVICE_FAMILY = "1,2";
280 | VALIDATE_PRODUCT = YES;
281 | };
282 | name = Profile;
283 | };
284 | 249021D4217E4FDB00AE95B9 /* Profile */ = {
285 | isa = XCBuildConfiguration;
286 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
287 | buildSettings = {
288 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
289 | CLANG_ENABLE_MODULES = YES;
290 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
291 | ENABLE_BITCODE = NO;
292 | INFOPLIST_FILE = Runner/Info.plist;
293 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
294 | PRODUCT_BUNDLE_IDENTIFIER = com.example.example;
295 | PRODUCT_NAME = "$(TARGET_NAME)";
296 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
297 | SWIFT_VERSION = 5.0;
298 | VERSIONING_SYSTEM = "apple-generic";
299 | };
300 | name = Profile;
301 | };
302 | 97C147031CF9000F007C117D /* Debug */ = {
303 | isa = XCBuildConfiguration;
304 | buildSettings = {
305 | ALWAYS_SEARCH_USER_PATHS = NO;
306 | CLANG_ANALYZER_NONNULL = YES;
307 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
308 | CLANG_CXX_LIBRARY = "libc++";
309 | CLANG_ENABLE_MODULES = YES;
310 | CLANG_ENABLE_OBJC_ARC = YES;
311 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
312 | CLANG_WARN_BOOL_CONVERSION = YES;
313 | CLANG_WARN_COMMA = YES;
314 | CLANG_WARN_CONSTANT_CONVERSION = YES;
315 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
316 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
317 | CLANG_WARN_EMPTY_BODY = YES;
318 | CLANG_WARN_ENUM_CONVERSION = YES;
319 | CLANG_WARN_INFINITE_RECURSION = YES;
320 | CLANG_WARN_INT_CONVERSION = YES;
321 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
322 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
323 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
324 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
325 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
326 | CLANG_WARN_STRICT_PROTOTYPES = YES;
327 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
328 | CLANG_WARN_UNREACHABLE_CODE = YES;
329 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
330 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
331 | COPY_PHASE_STRIP = NO;
332 | DEBUG_INFORMATION_FORMAT = dwarf;
333 | ENABLE_STRICT_OBJC_MSGSEND = YES;
334 | ENABLE_TESTABILITY = YES;
335 | GCC_C_LANGUAGE_STANDARD = gnu99;
336 | GCC_DYNAMIC_NO_PIC = NO;
337 | GCC_NO_COMMON_BLOCKS = YES;
338 | GCC_OPTIMIZATION_LEVEL = 0;
339 | GCC_PREPROCESSOR_DEFINITIONS = (
340 | "DEBUG=1",
341 | "$(inherited)",
342 | );
343 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
344 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
345 | GCC_WARN_UNDECLARED_SELECTOR = YES;
346 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
347 | GCC_WARN_UNUSED_FUNCTION = YES;
348 | GCC_WARN_UNUSED_VARIABLE = YES;
349 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
350 | MTL_ENABLE_DEBUG_INFO = YES;
351 | ONLY_ACTIVE_ARCH = YES;
352 | SDKROOT = iphoneos;
353 | TARGETED_DEVICE_FAMILY = "1,2";
354 | };
355 | name = Debug;
356 | };
357 | 97C147041CF9000F007C117D /* Release */ = {
358 | isa = XCBuildConfiguration;
359 | buildSettings = {
360 | ALWAYS_SEARCH_USER_PATHS = NO;
361 | CLANG_ANALYZER_NONNULL = YES;
362 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
363 | CLANG_CXX_LIBRARY = "libc++";
364 | CLANG_ENABLE_MODULES = YES;
365 | CLANG_ENABLE_OBJC_ARC = YES;
366 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
367 | CLANG_WARN_BOOL_CONVERSION = YES;
368 | CLANG_WARN_COMMA = YES;
369 | CLANG_WARN_CONSTANT_CONVERSION = YES;
370 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
371 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
372 | CLANG_WARN_EMPTY_BODY = YES;
373 | CLANG_WARN_ENUM_CONVERSION = YES;
374 | CLANG_WARN_INFINITE_RECURSION = YES;
375 | CLANG_WARN_INT_CONVERSION = YES;
376 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
377 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
378 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
379 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
380 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
381 | CLANG_WARN_STRICT_PROTOTYPES = YES;
382 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
383 | CLANG_WARN_UNREACHABLE_CODE = YES;
384 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
385 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
386 | COPY_PHASE_STRIP = NO;
387 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
388 | ENABLE_NS_ASSERTIONS = NO;
389 | ENABLE_STRICT_OBJC_MSGSEND = YES;
390 | GCC_C_LANGUAGE_STANDARD = gnu99;
391 | GCC_NO_COMMON_BLOCKS = YES;
392 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
393 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
394 | GCC_WARN_UNDECLARED_SELECTOR = YES;
395 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
396 | GCC_WARN_UNUSED_FUNCTION = YES;
397 | GCC_WARN_UNUSED_VARIABLE = YES;
398 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
399 | MTL_ENABLE_DEBUG_INFO = NO;
400 | SDKROOT = iphoneos;
401 | SUPPORTED_PLATFORMS = iphoneos;
402 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
403 | TARGETED_DEVICE_FAMILY = "1,2";
404 | VALIDATE_PRODUCT = YES;
405 | };
406 | name = Release;
407 | };
408 | 97C147061CF9000F007C117D /* Debug */ = {
409 | isa = XCBuildConfiguration;
410 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
411 | buildSettings = {
412 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
413 | CLANG_ENABLE_MODULES = YES;
414 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
415 | ENABLE_BITCODE = NO;
416 | INFOPLIST_FILE = Runner/Info.plist;
417 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
418 | PRODUCT_BUNDLE_IDENTIFIER = com.example.example;
419 | PRODUCT_NAME = "$(TARGET_NAME)";
420 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
421 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
422 | SWIFT_VERSION = 5.0;
423 | VERSIONING_SYSTEM = "apple-generic";
424 | };
425 | name = Debug;
426 | };
427 | 97C147071CF9000F007C117D /* Release */ = {
428 | isa = XCBuildConfiguration;
429 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
430 | buildSettings = {
431 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
432 | CLANG_ENABLE_MODULES = YES;
433 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
434 | ENABLE_BITCODE = NO;
435 | INFOPLIST_FILE = Runner/Info.plist;
436 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
437 | PRODUCT_BUNDLE_IDENTIFIER = com.example.example;
438 | PRODUCT_NAME = "$(TARGET_NAME)";
439 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
440 | SWIFT_VERSION = 5.0;
441 | VERSIONING_SYSTEM = "apple-generic";
442 | };
443 | name = Release;
444 | };
445 | /* End XCBuildConfiguration section */
446 |
447 | /* Begin XCConfigurationList section */
448 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
449 | isa = XCConfigurationList;
450 | buildConfigurations = (
451 | 97C147031CF9000F007C117D /* Debug */,
452 | 97C147041CF9000F007C117D /* Release */,
453 | 249021D3217E4FDB00AE95B9 /* Profile */,
454 | );
455 | defaultConfigurationIsVisible = 0;
456 | defaultConfigurationName = Release;
457 | };
458 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
459 | isa = XCConfigurationList;
460 | buildConfigurations = (
461 | 97C147061CF9000F007C117D /* Debug */,
462 | 97C147071CF9000F007C117D /* Release */,
463 | 249021D4217E4FDB00AE95B9 /* Profile */,
464 | );
465 | defaultConfigurationIsVisible = 0;
466 | defaultConfigurationName = Release;
467 | };
468 | /* End XCConfigurationList section */
469 | };
470 | rootObject = 97C146E61CF9000F007C117D /* Project object */;
471 | }
472 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/ios/Runner/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import Flutter
3 |
4 | @UIApplicationMain
5 | @objc class AppDelegate: FlutterAppDelegate {
6 | override func application(
7 | _ application: UIApplication,
8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
9 | ) -> Bool {
10 | GeneratedPluginRegistrant.register(with: self)
11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "Icon-App-20x20@2x.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "Icon-App-20x20@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "Icon-App-29x29@1x.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "Icon-App-29x29@2x.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "29x29",
29 | "idiom" : "iphone",
30 | "filename" : "Icon-App-29x29@3x.png",
31 | "scale" : "3x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "Icon-App-40x40@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "40x40",
41 | "idiom" : "iphone",
42 | "filename" : "Icon-App-40x40@3x.png",
43 | "scale" : "3x"
44 | },
45 | {
46 | "size" : "60x60",
47 | "idiom" : "iphone",
48 | "filename" : "Icon-App-60x60@2x.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "60x60",
53 | "idiom" : "iphone",
54 | "filename" : "Icon-App-60x60@3x.png",
55 | "scale" : "3x"
56 | },
57 | {
58 | "size" : "20x20",
59 | "idiom" : "ipad",
60 | "filename" : "Icon-App-20x20@1x.png",
61 | "scale" : "1x"
62 | },
63 | {
64 | "size" : "20x20",
65 | "idiom" : "ipad",
66 | "filename" : "Icon-App-20x20@2x.png",
67 | "scale" : "2x"
68 | },
69 | {
70 | "size" : "29x29",
71 | "idiom" : "ipad",
72 | "filename" : "Icon-App-29x29@1x.png",
73 | "scale" : "1x"
74 | },
75 | {
76 | "size" : "29x29",
77 | "idiom" : "ipad",
78 | "filename" : "Icon-App-29x29@2x.png",
79 | "scale" : "2x"
80 | },
81 | {
82 | "size" : "40x40",
83 | "idiom" : "ipad",
84 | "filename" : "Icon-App-40x40@1x.png",
85 | "scale" : "1x"
86 | },
87 | {
88 | "size" : "40x40",
89 | "idiom" : "ipad",
90 | "filename" : "Icon-App-40x40@2x.png",
91 | "scale" : "2x"
92 | },
93 | {
94 | "size" : "76x76",
95 | "idiom" : "ipad",
96 | "filename" : "Icon-App-76x76@1x.png",
97 | "scale" : "1x"
98 | },
99 | {
100 | "size" : "76x76",
101 | "idiom" : "ipad",
102 | "filename" : "Icon-App-76x76@2x.png",
103 | "scale" : "2x"
104 | },
105 | {
106 | "size" : "83.5x83.5",
107 | "idiom" : "ipad",
108 | "filename" : "Icon-App-83.5x83.5@2x.png",
109 | "scale" : "2x"
110 | },
111 | {
112 | "size" : "1024x1024",
113 | "idiom" : "ios-marketing",
114 | "filename" : "Icon-App-1024x1024@1x.png",
115 | "scale" : "1x"
116 | }
117 | ],
118 | "info" : {
119 | "version" : 1,
120 | "author" : "xcode"
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rajeshbdabhi/easy_image_editor/57bc36fc65508d72bd6888058f8359edd598ac1c/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rajeshbdabhi/easy_image_editor/57bc36fc65508d72bd6888058f8359edd598ac1c/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rajeshbdabhi/easy_image_editor/57bc36fc65508d72bd6888058f8359edd598ac1c/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rajeshbdabhi/easy_image_editor/57bc36fc65508d72bd6888058f8359edd598ac1c/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rajeshbdabhi/easy_image_editor/57bc36fc65508d72bd6888058f8359edd598ac1c/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rajeshbdabhi/easy_image_editor/57bc36fc65508d72bd6888058f8359edd598ac1c/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rajeshbdabhi/easy_image_editor/57bc36fc65508d72bd6888058f8359edd598ac1c/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rajeshbdabhi/easy_image_editor/57bc36fc65508d72bd6888058f8359edd598ac1c/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rajeshbdabhi/easy_image_editor/57bc36fc65508d72bd6888058f8359edd598ac1c/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rajeshbdabhi/easy_image_editor/57bc36fc65508d72bd6888058f8359edd598ac1c/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rajeshbdabhi/easy_image_editor/57bc36fc65508d72bd6888058f8359edd598ac1c/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rajeshbdabhi/easy_image_editor/57bc36fc65508d72bd6888058f8359edd598ac1c/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rajeshbdabhi/easy_image_editor/57bc36fc65508d72bd6888058f8359edd598ac1c/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rajeshbdabhi/easy_image_editor/57bc36fc65508d72bd6888058f8359edd598ac1c/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rajeshbdabhi/easy_image_editor/57bc36fc65508d72bd6888058f8359edd598ac1c/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "LaunchImage.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "LaunchImage@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "LaunchImage@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rajeshbdabhi/easy_image_editor/57bc36fc65508d72bd6888058f8359edd598ac1c/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rajeshbdabhi/easy_image_editor/57bc36fc65508d72bd6888058f8359edd598ac1c/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rajeshbdabhi/easy_image_editor/57bc36fc65508d72bd6888058f8359edd598ac1c/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md:
--------------------------------------------------------------------------------
1 | # Launch Screen Assets
2 |
3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory.
4 |
5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
--------------------------------------------------------------------------------
/example/ios/Runner/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/example/ios/Runner/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/example/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | example
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | $(FLUTTER_BUILD_NAME)
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(FLUTTER_BUILD_NUMBER)
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UISupportedInterfaceOrientations
30 |
31 | UIInterfaceOrientationPortrait
32 | UIInterfaceOrientationLandscapeLeft
33 | UIInterfaceOrientationLandscapeRight
34 |
35 | UISupportedInterfaceOrientations~ipad
36 |
37 | UIInterfaceOrientationPortrait
38 | UIInterfaceOrientationPortraitUpsideDown
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 | UIViewControllerBasedStatusBarAppearance
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/example/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
2 |
--------------------------------------------------------------------------------
/example/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:image_picker/image_picker.dart';
3 | import 'package:easy_image_editor/easy_image_editor.dart';
4 | import 'dart:io';
5 | import 'result.dart';
6 |
7 | void main() {
8 | runApp(const MyApp());
9 | }
10 |
11 | class MyApp extends StatelessWidget {
12 | const MyApp({Key? key}) : super(key: key);
13 |
14 | // This widget is the root of your application.
15 | @override
16 | Widget build(BuildContext context) {
17 | return MaterialApp(
18 | title: 'Flutter Demo',
19 | theme: ThemeData(
20 | // This is the theme of your application.
21 | //
22 | // Try running your application with "flutter run". You'll see the
23 | // application has a blue toolbar. Then, without quitting the app, try
24 | // changing the primarySwatch below to Colors.green and then invoke
25 | // "hot reload" (press "r" in the console where you ran "flutter run",
26 | // or simply save your changes to "hot reload" in a Flutter IDE).
27 | // Notice that the counter didn't reset back to zero; the application
28 | // is not restarted.
29 | primarySwatch: Colors.blue,
30 | ),
31 | home: const MyHomePage(title: 'Flutter Demo Home Page'),
32 | );
33 | }
34 | }
35 |
36 | class MyHomePage extends StatefulWidget {
37 | const MyHomePage({Key? key, required this.title}) : super(key: key);
38 |
39 | // This widget is the home page of your application. It is stateful, meaning
40 | // that it has a State object (defined below) that contains fields that affect
41 | // how it looks.
42 |
43 | // This class is the configuration for the state. It holds the values (in this
44 | // case the title) provided by the parent (in this case the App widget) and
45 | // used by the build method of the State. Fields in a Widget subclass are
46 | // always marked "final".
47 |
48 | final String title;
49 |
50 | @override
51 | State createState() => _MyHomePageState();
52 | }
53 |
54 | class _MyHomePageState extends State {
55 | late EasyImageEditorController _easyImageEditorController;
56 | final ImagePicker _picker = ImagePicker();
57 |
58 | //late EditorView editorView;
59 |
60 | final List _colorArray = [
61 | Colors.red,
62 | Colors.black,
63 | Colors.white,
64 | Colors.amber,
65 | Colors.black38,
66 | Colors.yellow,
67 | Colors.orange,
68 | Colors.deepOrange,
69 | Colors.pink,
70 | Colors.blue,
71 | Colors.cyan,
72 | Colors.deepPurple,
73 | Colors.teal,
74 | ];
75 |
76 | @override
77 | void initState() {
78 | super.initState();
79 | //_easyImageEditorController.canEditMultipleView(true);
80 | }
81 |
82 | @override
83 | Widget build(BuildContext context) {
84 | return Scaffold(
85 | appBar: AppBar(
86 | title: Text(widget.title),
87 | actions: [
88 | IconButton(
89 | onPressed: () =>
90 | _easyImageEditorController.canEditMultipleView(false),
91 | icon: const Icon(Icons.photo_size_select_large),
92 | ),
93 | IconButton(
94 | onPressed: () =>
95 | _easyImageEditorController.canEditMultipleView(true),
96 | icon: const Icon(Icons.select_all),
97 | ),
98 | IconButton(
99 | onPressed: () => _easyImageEditorController.undo(),
100 | icon: const Icon(Icons.undo),
101 | ),
102 | IconButton(
103 | onPressed: () => _easyImageEditorController.redo(),
104 | icon: const Icon(Icons.redo),
105 | ),
106 | IconButton(
107 | onPressed: () {
108 | _easyImageEditorController.saveEditing().then((value) {
109 | if (value != null) {
110 | Navigator.push(
111 | context,
112 | MaterialPageRoute(
113 | builder: (builder) => Result(uint8list: value)));
114 | }
115 | });
116 | },
117 | icon: const Icon(Icons.done_all),
118 | ),
119 | ],
120 | ),
121 | body: EditorView(
122 | borderColor: Colors.red,
123 | clickToFocusAndMove: false,
124 | onInitialize: (controller) {
125 | setState(() {
126 | _easyImageEditorController = controller;
127 | });
128 | },
129 | removeIcon: const Icon(
130 | Icons.cancel_outlined,
131 | size: 20.0,
132 | ),
133 | onViewTouchOver: (position, widget, widgetType) {
134 | debugPrint("onViewTouch: $position, $widgetType");
135 | },
136 | onClick: (position, widget, widgetType) {
137 | debugPrint("onViewClick");
138 | if (widgetType == "text") {
139 | Text _text = widget as Text;
140 | _addText(position, _text);
141 | }
142 | },
143 | ),
144 | bottomNavigationBar: BottomNavigationBar(
145 | items: const [
146 | BottomNavigationBarItem(
147 | icon: Icon(Icons.text_fields),
148 | label: "Add Text",
149 | ),
150 | BottomNavigationBarItem(
151 | icon: Icon(Icons.image),
152 | label: "Add Image",
153 | ),
154 | BottomNavigationBarItem(
155 | icon: Icon(Icons.color_lens),
156 | label: "Add Color",
157 | ),
158 | ],
159 | onTap: (position) {
160 | switch (position) {
161 | case 0:
162 | _addText(null, null);
163 | break;
164 | case 1:
165 | _addImage();
166 | break;
167 | case 2:
168 | _addBg();
169 | break;
170 | }
171 | },
172 | ),
173 | );
174 | }
175 |
176 | void _addText(int? position, Text? text) {
177 | final textEditController = TextEditingController(text: text?.data);
178 | Color? textColor = text?.style?.color;
179 |
180 | showModalBottomSheet(
181 | context: context,
182 | builder: (BuildContext context) {
183 | return StatefulBuilder(builder: (context, stateSetter) {
184 | return Column(
185 | children: [
186 | Padding(
187 | padding: const EdgeInsets.all(10.0),
188 | child: TextField(
189 | controller: textEditController,
190 | keyboardType: TextInputType.text,
191 | textInputAction: TextInputAction.done,
192 | decoration: const InputDecoration(
193 | hintText: "Enter Text",
194 | ),
195 | style: TextStyle(color: textColor),
196 | ),
197 | ),
198 | SizedBox(
199 | height: 60,
200 | child: ListView.builder(
201 | shrinkWrap: true,
202 | itemCount: _colorArray.length,
203 | scrollDirection: Axis.horizontal,
204 | itemBuilder: (context, index) {
205 | return InkWell(
206 | onTap: () {
207 | stateSetter(() {
208 | textColor = _colorArray[index];
209 | });
210 | },
211 | child: Container(
212 | height: 50.0,
213 | width: 50.0,
214 | color: _colorArray[index],
215 | ),
216 | );
217 | },
218 | ),
219 | ),
220 | InkWell(
221 | onTap: () {
222 | if (textEditController.text.isNotEmpty) {
223 | Navigator.pop(context);
224 |
225 | if (text == null) {
226 | _easyImageEditorController.addView(
227 | Text(
228 | textEditController.text,
229 | style: TextStyle(
230 | fontSize: 20.0,
231 | color: textColor,
232 | ),
233 | ),
234 | widgetType: "text",
235 | );
236 | } else {
237 | _easyImageEditorController.updateView(
238 | position!,
239 | Text(
240 | textEditController.text,
241 | style: TextStyle(
242 | fontSize: 20.0,
243 | color: textColor,
244 | fontWeight: FontWeight.bold,
245 | ),
246 | ),
247 | );
248 | }
249 | }
250 | },
251 | child: Container(
252 | width: 100.0,
253 | margin: const EdgeInsets.all(20.0),
254 | padding: const EdgeInsets.all(10.0),
255 | decoration: BoxDecoration(
256 | color: Theme.of(context).primaryColor,
257 | borderRadius:
258 | const BorderRadius.all(Radius.circular(10))),
259 | child: const Center(
260 | child: Text("Add"),
261 | ),
262 | ),
263 | ),
264 | ],
265 | );
266 | });
267 | });
268 | }
269 |
270 | _addBg() {
271 | showModalBottomSheet(
272 | context: context,
273 | builder: (context) {
274 | return SizedBox(
275 | height: 60,
276 | child: ListView.builder(
277 | shrinkWrap: true,
278 | itemCount: _colorArray.length,
279 | scrollDirection: Axis.horizontal,
280 | itemBuilder: (context, index) {
281 | return InkWell(
282 | onTap: () {
283 | Navigator.pop(context);
284 | _easyImageEditorController
285 | .addBackgroundColor(_colorArray[index]);
286 | },
287 | child: Container(
288 | height: 50.0,
289 | width: 50.0,
290 | color: _colorArray[index],
291 | ),
292 | );
293 | },
294 | ),
295 | );
296 | });
297 | }
298 |
299 | _addImage() {
300 | showModalBottomSheet(
301 | context: context,
302 | builder: (context) {
303 | return Row(
304 | mainAxisAlignment: MainAxisAlignment.spaceEvenly,
305 | children: [
306 | InkWell(
307 | onTap: () async {
308 | final XFile? image =
309 | await _picker.pickImage(source: ImageSource.gallery);
310 | if (image != null) {
311 | Navigator.pop(context);
312 | _easyImageEditorController
313 | .addBackgroundView(Image.file(File(image.path)));
314 | }
315 | },
316 | child: const Padding(
317 | padding: EdgeInsets.all(20),
318 | child: Text(
319 | "Set Background",
320 | style: TextStyle(fontSize: 18.0),
321 | ),
322 | ),
323 | ),
324 | InkWell(
325 | onTap: () async {
326 | final XFile? image =
327 | await _picker.pickImage(source: ImageSource.gallery);
328 | if (image != null) {
329 | Navigator.pop(context);
330 | _easyImageEditorController.addView(
331 | Image.file(
332 | File(image.path),
333 | height: 200,
334 | width: 200,
335 | ),
336 | widgetType: "image");
337 | }
338 | },
339 | child: const Padding(
340 | padding: EdgeInsets.all(20),
341 | child: Text(
342 | "Add View",
343 | style: TextStyle(fontSize: 18.0),
344 | ),
345 | ),
346 | ),
347 | ],
348 | );
349 | });
350 | }
351 | }
352 |
--------------------------------------------------------------------------------
/example/lib/result.dart:
--------------------------------------------------------------------------------
1 | import 'dart:typed_data';
2 |
3 | import 'package:flutter/material.dart';
4 |
5 | class Result extends StatefulWidget {
6 | const Result({key, required this.uint8list}) : super(key: key);
7 |
8 | final Uint8List uint8list;
9 |
10 | @override
11 | _ResultState createState() => _ResultState();
12 | }
13 |
14 | class _ResultState extends State {
15 | @override
16 | Widget build(BuildContext context) {
17 | return Image.memory(widget.uint8list);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/example/pubspec.lock:
--------------------------------------------------------------------------------
1 | # Generated by pub
2 | # See https://dart.dev/tools/pub/glossary#lockfile
3 | packages:
4 | async:
5 | dependency: transitive
6 | description:
7 | name: async
8 | url: "https://pub.dartlang.org"
9 | source: hosted
10 | version: "2.8.1"
11 | boolean_selector:
12 | dependency: transitive
13 | description:
14 | name: boolean_selector
15 | url: "https://pub.dartlang.org"
16 | source: hosted
17 | version: "2.1.0"
18 | characters:
19 | dependency: transitive
20 | description:
21 | name: characters
22 | url: "https://pub.dartlang.org"
23 | source: hosted
24 | version: "1.1.0"
25 | charcode:
26 | dependency: transitive
27 | description:
28 | name: charcode
29 | url: "https://pub.dartlang.org"
30 | source: hosted
31 | version: "1.3.1"
32 | clock:
33 | dependency: transitive
34 | description:
35 | name: clock
36 | url: "https://pub.dartlang.org"
37 | source: hosted
38 | version: "1.1.0"
39 | collection:
40 | dependency: transitive
41 | description:
42 | name: collection
43 | url: "https://pub.dartlang.org"
44 | source: hosted
45 | version: "1.15.0"
46 | cross_file:
47 | dependency: transitive
48 | description:
49 | name: cross_file
50 | url: "https://pub.dartlang.org"
51 | source: hosted
52 | version: "0.3.2"
53 | cupertino_icons:
54 | dependency: "direct main"
55 | description:
56 | name: cupertino_icons
57 | url: "https://pub.dartlang.org"
58 | source: hosted
59 | version: "1.0.4"
60 | easy_image_editor:
61 | dependency: "direct dev"
62 | description:
63 | path: ".."
64 | relative: true
65 | source: path
66 | version: "1.0.3"
67 | fake_async:
68 | dependency: transitive
69 | description:
70 | name: fake_async
71 | url: "https://pub.dartlang.org"
72 | source: hosted
73 | version: "1.2.0"
74 | flutter:
75 | dependency: "direct main"
76 | description: flutter
77 | source: sdk
78 | version: "0.0.0"
79 | flutter_lints:
80 | dependency: "direct dev"
81 | description:
82 | name: flutter_lints
83 | url: "https://pub.dartlang.org"
84 | source: hosted
85 | version: "1.0.4"
86 | flutter_plugin_android_lifecycle:
87 | dependency: transitive
88 | description:
89 | name: flutter_plugin_android_lifecycle
90 | url: "https://pub.dartlang.org"
91 | source: hosted
92 | version: "2.0.5"
93 | flutter_test:
94 | dependency: "direct dev"
95 | description: flutter
96 | source: sdk
97 | version: "0.0.0"
98 | flutter_web_plugins:
99 | dependency: transitive
100 | description: flutter
101 | source: sdk
102 | version: "0.0.0"
103 | http:
104 | dependency: transitive
105 | description:
106 | name: http
107 | url: "https://pub.dartlang.org"
108 | source: hosted
109 | version: "0.13.4"
110 | http_parser:
111 | dependency: transitive
112 | description:
113 | name: http_parser
114 | url: "https://pub.dartlang.org"
115 | source: hosted
116 | version: "4.0.0"
117 | image_picker:
118 | dependency: "direct dev"
119 | description:
120 | name: image_picker
121 | url: "https://pub.dartlang.org"
122 | source: hosted
123 | version: "0.8.4+11"
124 | image_picker_for_web:
125 | dependency: transitive
126 | description:
127 | name: image_picker_for_web
128 | url: "https://pub.dartlang.org"
129 | source: hosted
130 | version: "2.1.6"
131 | image_picker_platform_interface:
132 | dependency: transitive
133 | description:
134 | name: image_picker_platform_interface
135 | url: "https://pub.dartlang.org"
136 | source: hosted
137 | version: "2.4.4"
138 | js:
139 | dependency: transitive
140 | description:
141 | name: js
142 | url: "https://pub.dartlang.org"
143 | source: hosted
144 | version: "0.6.3"
145 | lints:
146 | dependency: transitive
147 | description:
148 | name: lints
149 | url: "https://pub.dartlang.org"
150 | source: hosted
151 | version: "1.0.1"
152 | matcher:
153 | dependency: transitive
154 | description:
155 | name: matcher
156 | url: "https://pub.dartlang.org"
157 | source: hosted
158 | version: "0.12.10"
159 | matrix4_transform:
160 | dependency: transitive
161 | description:
162 | name: matrix4_transform
163 | url: "https://pub.dartlang.org"
164 | source: hosted
165 | version: "2.0.1"
166 | meta:
167 | dependency: transitive
168 | description:
169 | name: meta
170 | url: "https://pub.dartlang.org"
171 | source: hosted
172 | version: "1.7.0"
173 | path:
174 | dependency: transitive
175 | description:
176 | name: path
177 | url: "https://pub.dartlang.org"
178 | source: hosted
179 | version: "1.8.0"
180 | plugin_platform_interface:
181 | dependency: transitive
182 | description:
183 | name: plugin_platform_interface
184 | url: "https://pub.dartlang.org"
185 | source: hosted
186 | version: "2.1.2"
187 | screenshot:
188 | dependency: transitive
189 | description:
190 | name: screenshot
191 | url: "https://pub.dartlang.org"
192 | source: hosted
193 | version: "1.2.3"
194 | sky_engine:
195 | dependency: transitive
196 | description: flutter
197 | source: sdk
198 | version: "0.0.99"
199 | source_span:
200 | dependency: transitive
201 | description:
202 | name: source_span
203 | url: "https://pub.dartlang.org"
204 | source: hosted
205 | version: "1.8.1"
206 | stack_trace:
207 | dependency: transitive
208 | description:
209 | name: stack_trace
210 | url: "https://pub.dartlang.org"
211 | source: hosted
212 | version: "1.10.0"
213 | stream_channel:
214 | dependency: transitive
215 | description:
216 | name: stream_channel
217 | url: "https://pub.dartlang.org"
218 | source: hosted
219 | version: "2.1.0"
220 | string_scanner:
221 | dependency: transitive
222 | description:
223 | name: string_scanner
224 | url: "https://pub.dartlang.org"
225 | source: hosted
226 | version: "1.1.0"
227 | term_glyph:
228 | dependency: transitive
229 | description:
230 | name: term_glyph
231 | url: "https://pub.dartlang.org"
232 | source: hosted
233 | version: "1.2.0"
234 | test_api:
235 | dependency: transitive
236 | description:
237 | name: test_api
238 | url: "https://pub.dartlang.org"
239 | source: hosted
240 | version: "0.4.2"
241 | typed_data:
242 | dependency: transitive
243 | description:
244 | name: typed_data
245 | url: "https://pub.dartlang.org"
246 | source: hosted
247 | version: "1.3.0"
248 | vector_math:
249 | dependency: transitive
250 | description:
251 | name: vector_math
252 | url: "https://pub.dartlang.org"
253 | source: hosted
254 | version: "2.1.0"
255 | sdks:
256 | dart: ">=2.14.0 <3.0.0"
257 | flutter: ">=2.5.0"
258 |
--------------------------------------------------------------------------------
/example/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: example
2 | description: A new Flutter project.
3 |
4 | # The following line prevents the package from being accidentally published to
5 | # pub.dev using `flutter pub publish`. This is preferred for private packages.
6 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev
7 |
8 | # The following defines the version and build number for your application.
9 | # A version number is three numbers separated by dots, like 1.2.43
10 | # followed by an optional build number separated by a +.
11 | # Both the version and the builder number may be overridden in flutter
12 | # build by specifying --build-name and --build-number, respectively.
13 | # In Android, build-name is used as versionName while build-number used as versionCode.
14 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning
15 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
16 | # Read more about iOS versioning at
17 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
18 | version: 1.0.0+1
19 |
20 | environment:
21 | sdk: ">=2.12.0 <3.0.0"
22 |
23 | # Dependencies specify other packages that your package needs in order to work.
24 | # To automatically upgrade your package dependencies to the latest versions
25 | # consider running `flutter pub upgrade --major-versions`. Alternatively,
26 | # dependencies can be manually updated by changing the version numbers below to
27 | # the latest version available on pub.dev. To see which dependencies have newer
28 | # versions available, run `flutter pub outdated`.
29 | dependencies:
30 | flutter:
31 | sdk: flutter
32 |
33 |
34 | # The following adds the Cupertino Icons font to your application.
35 | # Use with the CupertinoIcons class for iOS style icons.
36 | cupertino_icons: ^1.0.2
37 |
38 | dev_dependencies:
39 | flutter_test:
40 | sdk: flutter
41 | easy_image_editor:
42 | path: ../
43 | image_picker: ^0.8.4+11
44 |
45 | # The "flutter_lints" package below contains a set of recommended lints to
46 | # encourage good coding practices. The lint set provided by the package is
47 | # activated in the `analysis_options.yaml` file located at the root of your
48 | # package. See that file for information about deactivating specific lint
49 | # rules and activating additional ones.
50 | flutter_lints: ^1.0.0
51 |
52 | # For information on the generic Dart part of this file, see the
53 | # following page: https://dart.dev/tools/pub/pubspec
54 |
55 | # The following section is specific to Flutter.
56 | flutter:
57 |
58 | # The following line ensures that the Material Icons font is
59 | # included with your application, so that you can use the icons in
60 | # the material Icons class.
61 | uses-material-design: true
62 |
63 | # To add assets to your application, add an assets section, like this:
64 | # assets:
65 | # - images/a_dot_burr.jpeg
66 | # - images/a_dot_ham.jpeg
67 |
68 | # An image asset can refer to one or more resolution-specific "variants", see
69 | # https://flutter.dev/assets-and-images/#resolution-aware.
70 |
71 | # For details regarding adding assets from package dependencies, see
72 | # https://flutter.dev/assets-and-images/#from-packages
73 |
74 | # To add custom fonts to your application, add a fonts section here,
75 | # in this "flutter" section. Each entry in this list should have a
76 | # "family" key with the font family name, and a "fonts" key with a
77 | # list giving the asset and other descriptors for the font. For
78 | # example:
79 | # fonts:
80 | # - family: Schyler
81 | # fonts:
82 | # - asset: fonts/Schyler-Regular.ttf
83 | # - asset: fonts/Schyler-Italic.ttf
84 | # style: italic
85 | # - family: Trajan Pro
86 | # fonts:
87 | # - asset: fonts/TrajanPro.ttf
88 | # - asset: fonts/TrajanPro_Bold.ttf
89 | # weight: 700
90 | #
91 | # For details regarding fonts from package dependencies,
92 | # see https://flutter.dev/custom-fonts/#from-packages
93 |
--------------------------------------------------------------------------------
/example/test/widget_test.dart:
--------------------------------------------------------------------------------
1 | // This is a basic Flutter widget test.
2 | //
3 | // To perform an interaction with a widget in your test, use the WidgetTester
4 | // utility that Flutter provides. For example, you can send tap and scroll
5 | // gestures. You can also use WidgetTester to find child widgets in the widget
6 | // tree, read text, and verify that the values of widget properties are correct.
7 |
8 | import 'package:flutter/material.dart';
9 | import 'package:flutter_test/flutter_test.dart';
10 |
11 | import 'package:example/main.dart';
12 |
13 | void main() {
14 | testWidgets('Counter increments smoke test', (WidgetTester tester) async {
15 | // Build our app and trigger a frame.
16 | await tester.pumpWidget(const MyApp());
17 |
18 | // Verify that our counter starts at 0.
19 | expect(find.text('0'), findsOneWidget);
20 | expect(find.text('1'), findsNothing);
21 |
22 | // Tap the '+' icon and trigger a frame.
23 | await tester.tap(find.byIcon(Icons.add));
24 | await tester.pump();
25 |
26 | // Verify that our counter has incremented.
27 | expect(find.text('0'), findsNothing);
28 | expect(find.text('1'), findsOneWidget);
29 | });
30 | }
31 |
--------------------------------------------------------------------------------
/lib/easy_image_editor.dart:
--------------------------------------------------------------------------------
1 | library easy_image_editor;
2 |
3 | export 'src/editor_view.dart';
4 | export 'src/resizable_widget.dart';
5 |
--------------------------------------------------------------------------------
/lib/src/editor_view.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:matrix4_transform/matrix4_transform.dart';
3 | import 'package:screenshot/screenshot.dart';
4 | import 'dart:typed_data';
5 | import 'resizable_widget.dart';
6 |
7 | class EasyImageEditorController {
8 | _EditorViewState? _editorViewState;
9 |
10 | void _init(_EditorViewState editorViewState) {
11 | _editorViewState = editorViewState;
12 | }
13 |
14 | /// This function user for add view in editor
15 | void addView(Widget view, {String? widgetType}) =>
16 | _editorViewState?._addView(view, widgetType);
17 |
18 | /// update view of given position.
19 | void updateView(int position, Widget view) =>
20 | _editorViewState?._updateView(position, view);
21 |
22 | /// hide Border and Remove button from all views
23 | void hideViewControl() => _editorViewState?._disableEditMode();
24 |
25 | /// show Border and Remove button in all views
26 | void showViewControl() => _editorViewState?._enableEditModel();
27 |
28 | /// allow editor to move, zoom and rotate multiple views. if you set true than only one view can move, zoom and rotate default value is true.
29 | void canEditMultipleView(bool isMultipleSelection) =>
30 | _editorViewState?._setSelectionMode(!isMultipleSelection);
31 |
32 | /// set editor background view it will overlap background color.
33 | void addBackgroundView(Widget? view) => _editorViewState?._addBGView(view);
34 |
35 | /// set editor background color.
36 | void addBackgroundColor(Color color) => _editorViewState?._addBGColor(color);
37 |
38 | /// redo your changes
39 | void redo() => _editorViewState?._redo();
40 |
41 | /// undo your changes
42 | void undo() => _editorViewState?._undo();
43 |
44 | /// move view by provide position and move type like left, right and his his value.
45 | /// Ex. position = 0, moveType = MoveType.left, value = 10
46 | void moveView(int position, MoveType moveType, double value) =>
47 | _editorViewState?._moveView(position, moveType, value);
48 |
49 | /// rotate particular view
50 | void rotateView(int position, double rotateDegree) =>
51 | _editorViewState?._rotateView(position, rotateDegree);
52 |
53 | /// zoom In and Out view
54 | /// for zoom view value > 1
55 | /// for zoom out view value < 0 like (0.1)
56 | void zoomInOutView(int position, double value) =>
57 | _editorViewState?._zoomInOut(position, value);
58 |
59 | /// update matrix of particular view
60 | void updateMatrix(int position, Matrix4 matrix4) =>
61 | _editorViewState?._updateMatrix(position, matrix4);
62 |
63 | /// flip particular view
64 | void flipView(int position, bool isHorizontal) =>
65 | _editorViewState?._flipView(position, isHorizontal);
66 |
67 | /// save all edited views and his position and return Uint8List data.
68 | Future saveEditing() {
69 | assert(_editorViewState != null);
70 |
71 | return _editorViewState!._saveView();
72 | }
73 | }
74 |
75 | class EditorView extends StatefulWidget {
76 | const EditorView({
77 | key,
78 | required this.onInitialize,
79 | this.onViewTouch,
80 | this.onViewTouchOver,
81 | this.onClick,
82 | this.clickToFocusAndMove = false,
83 | this.borderColor = Colors.black,
84 | this.removeIcon = const Icon(
85 | Icons.cancel,
86 | size: 20.0,
87 | ),
88 | }) : super(key: key);
89 |
90 | @override
91 | _EditorViewState createState() => _EditorViewState();
92 |
93 | final Function(EasyImageEditorController) onInitialize;
94 |
95 | /// this event fire every time you touch view.
96 | final Function(int, Widget, String?)? onViewTouch;
97 |
98 | /// this event fire every time when user remove touch from view.
99 | final Function(int, Widget, String?)? onViewTouchOver;
100 |
101 | /// this event fire every time when user click view.
102 | final Function(int, Widget, String?)? onClick;
103 |
104 | /// set border color of widget
105 | final Color borderColor;
106 |
107 | /// set remove icon
108 | final Icon removeIcon;
109 |
110 | final bool clickToFocusAndMove;
111 | }
112 |
113 | class _EditorViewState extends State {
114 | final ScreenshotController _screenshotController = ScreenshotController();
115 |
116 | final List _widgetList = [];
117 | final List widgetList = [];
118 |
119 | bool isSingleMove = false;
120 |
121 | Color? _backgroundColor;
122 | Widget? _backgroundWidget;
123 |
124 | Future _saveView() async {
125 | _disableEditMode();
126 | return await _screenshotController.capture();
127 | }
128 |
129 | void _addBGView(Widget? view) {
130 | if (mounted) {
131 | setState(() {
132 | _backgroundWidget = view;
133 | });
134 | } else {
135 | _backgroundWidget = view;
136 | }
137 | }
138 |
139 | void _addBGColor(Color color) {
140 | if (mounted) {
141 | setState(() {
142 | _backgroundColor = color;
143 | });
144 | } else {
145 | _backgroundColor = color;
146 | }
147 | }
148 |
149 | void _setSelectionMode(bool isSingleSelection) {
150 | if (mounted) {
151 | setState(() {
152 | isSingleMove = isSingleSelection;
153 |
154 | if (isSingleMove) {
155 | _disableEditMode();
156 | } else {
157 | _enableEditModel();
158 | }
159 | });
160 | } else {
161 | isSingleMove = isSingleSelection;
162 | }
163 | }
164 |
165 | void _disableEditMode() {
166 | if (mounted) {
167 | setState(() {
168 | for (var element in _widgetList) {
169 | element.showRemoveIcon = false;
170 | element.canMove = false;
171 | element.borderColor = Colors.transparent;
172 | element.updateView();
173 | }
174 | });
175 | }
176 | //screenshotController.capture().then((value) => null);
177 | }
178 |
179 | void _enableEditModel() {
180 | if (mounted) {
181 | setState(() {
182 | for (var element in _widgetList) {
183 | element.showRemoveIcon = true;
184 | element.canMove = true;
185 | element.borderColor = widget.borderColor;
186 | element.updateView();
187 | }
188 | });
189 | }
190 | }
191 |
192 | void _updateView(int position, Widget view) {
193 | assert(position >= 0 &&
194 | _widgetList.isNotEmpty &&
195 | _widgetList.length - 1 <= position);
196 | setState(() {
197 | debugPrint("viewUpdated");
198 | _widgetList[position].resizableWidget = view;
199 | _widgetList[position].updateView();
200 | });
201 | }
202 |
203 | void _addView(Widget view, String? widgetType) {
204 | if (mounted) {
205 | setState(() {
206 | _addViewInList(view, widgetType);
207 | });
208 | } else {
209 | _addViewInList(view, widgetType);
210 | }
211 | }
212 |
213 | void _addViewInList(Widget view, String? widgetType, {Matrix4? matrix4}) {
214 | if (_widgetList.isNotEmpty) {
215 | final lastViewItem = _widgetList.last;
216 | lastViewItem.showRemoveIcon = false;
217 | lastViewItem.borderColor = Colors.transparent;
218 | lastViewItem.canMove = false;
219 | lastViewItem.updateView();
220 | }
221 |
222 | final resizableView = ResizableWidget(
223 | key: ObjectKey(DateTime.now().toString()),
224 | position: _widgetList.length,
225 | canMove: true,
226 | borderColor: widget.borderColor,
227 | removeIcon: widget.removeIcon,
228 | resizableWidget: view,
229 | widgetType: widgetType,
230 | matrix4: matrix4,
231 | onRemoveClick: (key, index) {
232 | setState(() {
233 | //_widgetList.removeWhere((element) => element.key == key);
234 | try {
235 | final removeView =
236 | _widgetList.firstWhere((element) => element.key == key);
237 | removeView.isVisible = false;
238 | removeView.updateView();
239 | } catch (_) {}
240 | });
241 | },
242 | onClick: (key, index, widgetType) {
243 | if (widget.clickToFocusAndMove) {
244 | setState(() {
245 | final finalIndex =
246 | _widgetList.indexWhere((element) => element.key == key);
247 |
248 | final touchView = _widgetList.removeAt(finalIndex);
249 | touchView.showRemoveIcon = true;
250 | touchView.canMove = true;
251 | touchView.borderColor = widget.borderColor;
252 | touchView.updateView();
253 | _widgetList.add(touchView);
254 |
255 | if (widget.onClick != null) {
256 | widget.onClick!(_widgetList.length - 1, touchView.resizableWidget,
257 | touchView.widgetType);
258 | }
259 |
260 | if (isSingleMove) {
261 | for (var element in _widgetList) {
262 | if (element != touchView) {
263 | element.showRemoveIcon = false;
264 | element.borderColor = Colors.transparent;
265 | element.canMove = false;
266 | element.updateView();
267 | }
268 | }
269 | }
270 | });
271 | } else {
272 | final finalIndex =
273 | _widgetList.indexWhere((element) => element.key == key);
274 |
275 | final touchView = _widgetList[finalIndex];
276 |
277 | if (widget.onClick != null) {
278 | widget.onClick!(_widgetList.length - 1, touchView.resizableWidget,
279 | touchView.widgetType);
280 | }
281 | }
282 | },
283 | onSetTop: (key, index, widgetType) {
284 | debugPrint("onTouch");
285 | if (!widget.clickToFocusAndMove) {
286 | setState(() {
287 | final finalIndex =
288 | _widgetList.indexWhere((element) => element.key == key);
289 |
290 | final touchView = _widgetList.removeAt(finalIndex);
291 | touchView.showRemoveIcon = true;
292 | touchView.canMove = true;
293 | touchView.borderColor = widget.borderColor;
294 | touchView.updateView();
295 | _widgetList.add(touchView);
296 |
297 | if (widget.onViewTouch != null) {
298 | widget.onViewTouch!(_widgetList.length - 1,
299 | touchView.resizableWidget, touchView.widgetType);
300 | }
301 |
302 | if (isSingleMove) {
303 | for (var element in _widgetList) {
304 | if (element != touchView) {
305 | element.showRemoveIcon = false;
306 | element.borderColor = Colors.transparent;
307 | element.canMove = false;
308 | element.updateView();
309 | }
310 | }
311 | }
312 | });
313 | }
314 | },
315 | onTouchOver: (key, position, matrix) {
316 | if (widget.onViewTouchOver != null) {
317 | final touchView =
318 | _widgetList.firstWhere((element) => element.key == key);
319 | widget.onViewTouchOver!(_widgetList.length - 1,
320 | touchView.resizableWidget, touchView.widgetType);
321 | }
322 | },
323 | );
324 |
325 | _widgetList.add(resizableView);
326 | }
327 |
328 | void _undo() {
329 | if (_widgetList.isNotEmpty) {
330 | try {
331 | setState(() {
332 | final lastUnVisibleView =
333 | _widgetList.lastWhere((element) => element.isVisible);
334 | lastUnVisibleView.isVisible = false;
335 | lastUnVisibleView.updateView();
336 | });
337 | } catch (_) {}
338 | }
339 | }
340 |
341 | void _redo() {
342 | if (_widgetList.isNotEmpty) {
343 | try {
344 | setState(() {
345 | final lastUnVisibleView =
346 | _widgetList.firstWhere((element) => !element.isVisible);
347 | lastUnVisibleView.isVisible = true;
348 | lastUnVisibleView.updateView();
349 | });
350 | } catch (_) {}
351 | }
352 | }
353 |
354 | void _flipView(int position, bool isHorizontal) {
355 | assert(position >= 0 &&
356 | _widgetList.isNotEmpty &&
357 | _widgetList.length - 1 <= position);
358 |
359 | setState(() {
360 | final view = _widgetList[position];
361 | var myTransform = Matrix4Transform.from(view.matrix4!);
362 | if (isHorizontal) {
363 | _widgetList[position]
364 | .updateMatrix(myTransform.flipHorizontally().matrix4);
365 | } else {
366 | _widgetList[position]
367 | .updateMatrix(myTransform.flipVertically().matrix4);
368 | }
369 | });
370 | }
371 |
372 | void _updateMatrix(int position, Matrix4 matrix) {
373 | assert(position >= 0 &&
374 | _widgetList.isNotEmpty &&
375 | _widgetList.length - 1 <= position);
376 | setState(() {
377 | _widgetList[position].updateMatrix(matrix);
378 | });
379 | }
380 |
381 | void _zoomInOut(int position, double value) {
382 | assert(position >= 0 &&
383 | _widgetList.isNotEmpty &&
384 | _widgetList.length - 1 <= position);
385 | setState(() {
386 | final view = _widgetList[position];
387 | var myTransform = Matrix4Transform.from(view.matrix4!);
388 | _widgetList[position].updateMatrix(myTransform.scale(value).matrix4);
389 | });
390 | }
391 |
392 | void _rotateView(int position, double rotateDegree) {
393 | assert(position >= 0 &&
394 | _widgetList.isNotEmpty &&
395 | _widgetList.length - 1 <= position);
396 | setState(() {
397 | final view = _widgetList[position];
398 | var myTransform = Matrix4Transform.from(view.matrix4!);
399 | _widgetList[position].updateMatrix(myTransform
400 | .rotateByCenterDegrees(
401 | rotateDegree, Size(view.getWidth(), view.getHeight()))
402 | .matrix4);
403 | });
404 | }
405 |
406 | void _moveView(int position, MoveType moveType, double value) {
407 | assert(position >= 0 &&
408 | _widgetList.isNotEmpty &&
409 | _widgetList.length - 1 <= position);
410 |
411 | setState(() {
412 | final view = _widgetList[position];
413 | var myTransform = Matrix4Transform.from(view.matrix4!);
414 | if (moveType == MoveType.right) {
415 | _widgetList[position].updateMatrix(myTransform.right(value).matrix4);
416 | } else if (moveType == MoveType.bottom) {
417 | _widgetList[position].updateMatrix(myTransform.down(value).matrix4);
418 | } else if (moveType == MoveType.top) {
419 | _widgetList[position].updateMatrix(myTransform.up(value).matrix4);
420 | } else if (moveType == MoveType.left) {
421 | _widgetList[position].updateMatrix(myTransform.left(value).matrix4);
422 | }
423 | });
424 | }
425 |
426 | @override
427 | void initState() {
428 | super.initState();
429 |
430 | WidgetsBinding.instance?.addPostFrameCallback((_) {
431 | EasyImageEditorController easyImageEditorController =
432 | EasyImageEditorController();
433 | easyImageEditorController._init(this);
434 | widget.onInitialize(easyImageEditorController);
435 | });
436 |
437 | if (widget.clickToFocusAndMove) {
438 | _setSelectionMode(true);
439 | }
440 | }
441 |
442 | @override
443 | Widget build(BuildContext context) {
444 | return Screenshot(
445 | controller: _screenshotController,
446 | child: Container(
447 | height: MediaQuery.of(context).size.height,
448 | width: MediaQuery.of(context).size.width,
449 | color: (_backgroundColor != null) ? _backgroundColor : Colors.white,
450 | child: ClipRect(
451 | child: Stack(
452 | children: [
453 | if (_backgroundWidget != null)
454 | Positioned(
455 | top: 0,
456 | left: 0,
457 | right: 0,
458 | bottom: 0,
459 | child: _backgroundWidget!,
460 | ),
461 | ..._widgetList,
462 | ],
463 | ),
464 | ),
465 | ),
466 | );
467 | }
468 | }
469 |
470 | enum MoveType {
471 | left,
472 | right,
473 | top,
474 | bottom,
475 | }
476 |
--------------------------------------------------------------------------------
/lib/src/matrix_gesture_detector.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/widgets.dart';
2 | import 'dart:math';
3 |
4 | typedef MatrixGestureDetectorCallback = void Function(
5 | Matrix4 matrix,
6 | Matrix4 translationDeltaMatrix,
7 | Matrix4 scaleDeltaMatrix,
8 | Matrix4 rotationDeltaMatrix);
9 |
10 | /// [MatrixGestureDetector] detects translation, scale and rotation gestures
11 | /// and combines them into [Matrix4] object that can be used by [Transform] widget
12 | /// or by low level [CustomPainter] code. You can customize types of reported
13 | /// gestures by passing [shouldTranslate], [shouldScale] and [shouldRotate]
14 | /// parameters.
15 | ///
16 | // ignore: must_be_immutable
17 | class MatrixGestureDetector extends StatefulWidget {
18 | /// [Matrix4] change notification callback
19 | ///
20 | final MatrixGestureDetectorCallback onMatrixUpdate;
21 |
22 | /// The [child] contained by this detector.
23 | ///
24 | /// {@macro flutter.widgets.child}
25 | ///
26 | final Widget child;
27 |
28 | /// Whether to detect translation gestures during the event processing.
29 | ///
30 | /// Defaults to true.
31 | ///
32 | final bool shouldTranslate;
33 |
34 | /// Whether to detect scale gestures during the event processing.
35 | ///
36 | /// Defaults to true.
37 | ///
38 | final bool shouldScale;
39 |
40 | /// Whether to detect rotation gestures during the event processing.
41 | ///
42 | /// Defaults to true.
43 | ///
44 | final bool shouldRotate;
45 |
46 | /// Whether [ClipRect] widget should clip [child] widget.
47 | ///
48 | /// Defaults to true.
49 | ///
50 | final bool clipChild;
51 |
52 | /// When set, it will be used for computing a "fixed" focal point
53 | /// aligned relative to the size of this widget.
54 | final Alignment? focalPointAlignment;
55 |
56 | Matrix4? matrix4Old;
57 |
58 | MatrixGestureDetector({
59 | Key? key,
60 | required this.onMatrixUpdate,
61 | required this.child,
62 | this.matrix4Old,
63 | this.shouldTranslate = true,
64 | this.shouldScale = true,
65 | this.shouldRotate = true,
66 | this.clipChild = true,
67 | this.focalPointAlignment,
68 | }) : super(key: key);
69 |
70 | @override
71 | _MatrixGestureDetectorState createState() => _MatrixGestureDetectorState();
72 |
73 | ///
74 | /// Compose the matrix from translation, scale and rotation matrices - you can
75 | /// pass a null to skip any matrix from composition.
76 | ///
77 | /// If [matrix] is not null the result of the composing will be concatenated
78 | /// to that [matrix], otherwise the identity matrix will be used.
79 | ///
80 | static Matrix4 compose(Matrix4? matrix, Matrix4? translationMatrix,
81 | Matrix4? scaleMatrix, Matrix4? rotationMatrix) {
82 | matrix ??= Matrix4.identity();
83 | if (translationMatrix != null) matrix = translationMatrix * matrix;
84 | if (scaleMatrix != null) matrix = scaleMatrix * matrix;
85 | if (rotationMatrix != null) matrix = rotationMatrix * matrix;
86 | return matrix!;
87 | }
88 |
89 | ///
90 | /// Decomposes [matrix] into [MatrixDecomposedValues.translation],
91 | /// [MatrixDecomposedValues.scale] and [MatrixDecomposedValues.rotation] components.
92 | ///
93 | static MatrixDecomposedValues decomposeToValues(Matrix4 matrix) {
94 | var array = matrix.applyToVector3Array([0, 0, 0, 1, 0, 0]);
95 | Offset translation = Offset(array[0], array[1]);
96 | Offset delta = Offset(array[3] - array[0], array[4] - array[1]);
97 | double scale = delta.distance;
98 | double rotation = delta.direction;
99 | return MatrixDecomposedValues(translation, scale, rotation);
100 | }
101 | }
102 |
103 | class _MatrixGestureDetectorState extends State {
104 | Matrix4 translationDeltaMatrix = Matrix4.identity();
105 | Matrix4 scaleDeltaMatrix = Matrix4.identity();
106 | Matrix4 rotationDeltaMatrix = Matrix4.identity();
107 | Matrix4 matrix = Matrix4.identity();
108 |
109 | @override
110 | Widget build(BuildContext context) {
111 | Widget child =
112 | widget.clipChild ? ClipRect(child: widget.child) : widget.child;
113 | return GestureDetector(
114 | onScaleStart: onScaleStart,
115 | onScaleUpdate: onScaleUpdate,
116 | child: child,
117 | );
118 | }
119 |
120 | _ValueUpdater translationUpdater = _ValueUpdater(
121 | value: Offset.zero,
122 | onUpdate: (oldVal, newVal) => newVal - oldVal,
123 | );
124 | _ValueUpdater scaleUpdater = _ValueUpdater(
125 | value: 1.0,
126 | onUpdate: (oldVal, newVal) => newVal / oldVal,
127 | );
128 | _ValueUpdater rotationUpdater = _ValueUpdater(
129 | value: 0.0,
130 | onUpdate: (oldVal, newVal) => newVal - oldVal,
131 | );
132 |
133 | void onScaleStart(ScaleStartDetails details) {
134 | translationUpdater.value = details.focalPoint;
135 | scaleUpdater.value = 1.0;
136 | rotationUpdater.value = 0.0;
137 | }
138 |
139 | void onScaleUpdate(ScaleUpdateDetails details) {
140 | translationDeltaMatrix = Matrix4.identity();
141 | scaleDeltaMatrix = Matrix4.identity();
142 | rotationDeltaMatrix = Matrix4.identity();
143 |
144 | if (widget.matrix4Old != null) {
145 | matrix = widget.matrix4Old!;
146 | widget.matrix4Old = null;
147 | }
148 |
149 | // handle matrix translating
150 | if (widget.shouldTranslate) {
151 | Offset translationDelta = translationUpdater.update(details.focalPoint);
152 | translationDeltaMatrix = _translate(translationDelta);
153 | matrix = translationDeltaMatrix * matrix;
154 | }
155 |
156 | final focalPointAlignment = widget.focalPointAlignment;
157 | final focalPoint = focalPointAlignment == null
158 | ? details.localFocalPoint
159 | : focalPointAlignment.alongSize(context.size!);
160 |
161 | // handle matrix scaling
162 | if (widget.shouldScale && details.scale != 1.0) {
163 | double scaleDelta = scaleUpdater.update(details.scale);
164 | scaleDeltaMatrix = _scale(scaleDelta, focalPoint);
165 | matrix = scaleDeltaMatrix * matrix;
166 | }
167 |
168 | // handle matrix rotating
169 | if (widget.shouldRotate && details.rotation != 0.0) {
170 | double rotationDelta = rotationUpdater.update(details.rotation);
171 | rotationDeltaMatrix = _rotate(rotationDelta, focalPoint);
172 | matrix = rotationDeltaMatrix * matrix;
173 | }
174 |
175 | widget.onMatrixUpdate(
176 | matrix, translationDeltaMatrix, scaleDeltaMatrix, rotationDeltaMatrix);
177 | }
178 |
179 | Matrix4 _translate(Offset translation) {
180 | var dx = translation.dx;
181 | var dy = translation.dy;
182 |
183 | // ..[0] = 1 # x scale
184 | // ..[5] = 1 # y scale
185 | // ..[10] = 1 # diagonal "one"
186 | // ..[12] = dx # x translation
187 | // ..[13] = dy # y translation
188 | // ..[15] = 1 # diagonal "one"
189 | return Matrix4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, dx, dy, 0, 1);
190 | }
191 |
192 | Matrix4 _scale(double scale, Offset focalPoint) {
193 | var dx = (1 - scale) * focalPoint.dx;
194 | var dy = (1 - scale) * focalPoint.dy;
195 |
196 | // ..[0] = scale # x scale
197 | // ..[5] = scale # y scale
198 | // ..[10] = 1 # diagonal "one"
199 | // ..[12] = dx # x translation
200 | // ..[13] = dy # y translation
201 | // ..[15] = 1 # diagonal "one"
202 | return Matrix4(scale, 0, 0, 0, 0, scale, 0, 0, 0, 0, 1, 0, dx, dy, 0, 1);
203 | }
204 |
205 | Matrix4 _rotate(double angle, Offset focalPoint) {
206 | var c = cos(angle);
207 | var s = sin(angle);
208 | var dx = (1 - c) * focalPoint.dx + s * focalPoint.dy;
209 | var dy = (1 - c) * focalPoint.dy - s * focalPoint.dx;
210 |
211 | // ..[0] = c # x scale
212 | // ..[1] = s # y skew
213 | // ..[4] = -s # x skew
214 | // ..[5] = c # y scale
215 | // ..[10] = 1 # diagonal "one"
216 | // ..[12] = dx # x translation
217 | // ..[13] = dy # y translation
218 | // ..[15] = 1 # diagonal "one"
219 | return Matrix4(c, s, 0, 0, -s, c, 0, 0, 0, 0, 1, 0, dx, dy, 0, 1);
220 | }
221 | }
222 |
223 | typedef _OnUpdate = T Function(T oldValue, T newValue);
224 |
225 | class _ValueUpdater {
226 | final _OnUpdate onUpdate;
227 | T value;
228 |
229 | _ValueUpdater({
230 | required this.value,
231 | required this.onUpdate,
232 | });
233 |
234 | T update(T newValue) {
235 | T updated = onUpdate(value, newValue);
236 | value = newValue;
237 | return updated;
238 | }
239 | }
240 |
241 | class MatrixDecomposedValues {
242 | /// Translation, in most cases useful only for matrices that are nothing but
243 | /// a translation (no scale and no rotation).
244 | final Offset translation;
245 |
246 | /// Scaling factor.
247 | final double scale;
248 |
249 | /// Rotation in radians, (-pi..pi) range.
250 | final double rotation;
251 |
252 | MatrixDecomposedValues(this.translation, this.scale, this.rotation);
253 |
254 | @override
255 | String toString() {
256 | return 'MatrixDecomposedValues(translation: $translation, scale: ${scale.toStringAsFixed(3)}, rotation: ${rotation.toStringAsFixed(3)})';
257 | }
258 | }
259 |
--------------------------------------------------------------------------------
/lib/src/resizable_widget.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'matrix_gesture_detector.dart';
3 | import 'dart:async';
4 | import 'dart:math' as math;
5 |
6 | // ignore: must_be_immutable
7 | class ResizableWidget extends StatefulWidget {
8 | ResizableWidget({
9 | key,
10 | required this.position,
11 | required this.resizableWidget,
12 | this.canMove = true,
13 | this.showRemoveIcon = true,
14 | this.borderColor = Colors.black,
15 | this.widgetType,
16 | this.matrix4,
17 | this.isVisible = true,
18 | this.removeIcon = const Icon(
19 | Icons.close,
20 | size: 20.0,
21 | ),
22 | required this.onRemoveClick,
23 | required this.onSetTop,
24 | required this.onClick,
25 | required this.onTouchOver,
26 | }) : super(key: key);
27 |
28 | final int position;
29 | Widget resizableWidget;
30 | bool canMove;
31 | bool showRemoveIcon;
32 | Color borderColor;
33 | String? widgetType;
34 | Matrix4? matrix4;
35 | bool isVisible;
36 | final Icon removeIcon;
37 |
38 | /// return widget key and his position
39 | final Function(Key, int) onRemoveClick;
40 |
41 | /// return widget key, position and his type if you added
42 | final Function(Key, int, String?) onSetTop;
43 |
44 | /// return widget key, position and his type if you added
45 | final Function(Key, int, String?) onClick;
46 |
47 | /// return widget key, position and his matrix
48 | final Function(Key, int, Matrix4) onTouchOver;
49 |
50 | final resizableWidgetState = _ResizableWidgetState();
51 |
52 | @override
53 | // ignore: no_logic_in_create_state
54 | _ResizableWidgetState createState() => resizableWidgetState;
55 |
56 | void updateMatrix(Matrix4 matrix4) =>
57 | resizableWidgetState._setMatrix(matrix4);
58 |
59 | void updateView() {
60 | // ignore: invalid_use_of_protected_member
61 | resizableWidgetState.setState(() {});
62 | }
63 |
64 | double getX() => resizableWidgetState._getX();
65 |
66 | double getY() => resizableWidgetState._getY();
67 |
68 | double getAngle() => resizableWidgetState._getAngle();
69 |
70 | double getHeight() => resizableWidgetState._getHeight();
71 |
72 | double getWidth() => resizableWidgetState._getWidth();
73 | }
74 |
75 | class _ResizableWidgetState extends State {
76 | GlobalKey key = GlobalKey();
77 |
78 | Matrix4 matrix = Matrix4.identity();
79 |
80 | bool _isTouched = false;
81 |
82 | Timer? _timer;
83 |
84 | void _setMatrix(Matrix4 matrix4) {
85 | widget.matrix4 = matrix4;
86 | if (mounted) {
87 | setState(() {
88 | matrix = matrix4;
89 | });
90 | } else {
91 | matrix = matrix4;
92 | }
93 | }
94 |
95 | double _getX() {
96 | RenderBox box = key.currentContext?.findRenderObject() as RenderBox;
97 | Offset position = box.localToGlobal(Offset.zero);
98 | return position.dx;
99 | }
100 |
101 | double _getY() {
102 | RenderBox box = key.currentContext?.findRenderObject() as RenderBox;
103 | Offset position = box.localToGlobal(Offset.zero);
104 | return position.dy - 87.6;
105 | }
106 |
107 | double _getAngle() {
108 | RenderBox box = key.currentContext?.findRenderObject() as RenderBox;
109 | Offset position = box.localToGlobal(Offset.zero);
110 | return -math.atan2(position.dy - 87.6, position.dx);
111 | }
112 |
113 | double _getWidth() {
114 | RenderBox box = key.currentContext?.findRenderObject() as RenderBox;
115 | return box.size.width;
116 | }
117 |
118 | double _getHeight() {
119 | RenderBox box = key.currentContext?.findRenderObject() as RenderBox;
120 | return box.size.height;
121 | }
122 |
123 | @override
124 | void initState() {
125 | super.initState();
126 | if (widget.matrix4 != null) {
127 | setState(() {
128 | matrix = widget.matrix4!;
129 | });
130 | } else {
131 | widget.matrix4 = matrix;
132 | }
133 | }
134 |
135 | @override
136 | Widget build(BuildContext context) {
137 | return (widget.isVisible)
138 | ? Transform(
139 | transform: matrix,
140 | child: Stack(
141 | key: key,
142 | children: [
143 | MatrixGestureDetector(
144 | onMatrixUpdate:
145 | (Matrix4 m, Matrix4 tm, Matrix4 sm, Matrix4 rm) {
146 | setState(() {
147 | if (widget.canMove) {
148 | matrix = m;
149 | widget.matrix4 = m;
150 | }
151 | if (!_isTouched) {
152 | _isTouched = true;
153 | widget.onSetTop(
154 | widget.key!, widget.position, widget.widgetType);
155 | }
156 | });
157 |
158 | if (_timer?.isActive ?? false) {
159 | _timer?.cancel();
160 | _timer = null;
161 | }
162 |
163 | _timer = Timer(const Duration(milliseconds: 600), () {
164 | widget.onTouchOver(widget.key!, widget.position, m);
165 | if (mounted) {
166 | setState(() {
167 | _isTouched = false;
168 | });
169 | }
170 | });
171 | },
172 | focalPointAlignment: Alignment.center,
173 | matrix4Old: matrix,
174 | child: InkWell(
175 | onTap: () {
176 | debugPrint("click Top");
177 | widget.onClick(
178 | widget.key!, widget.position, widget.widgetType);
179 | widget.onSetTop(
180 | widget.key!, widget.position, widget.widgetType);
181 | },
182 | child: Container(
183 | padding: const EdgeInsets.all(10.0),
184 | decoration: BoxDecoration(
185 | border:
186 | Border.all(color: widget.borderColor, width: 1.0),
187 | borderRadius:
188 | const BorderRadius.all(Radius.circular(5.0)),
189 | ),
190 | child: widget.resizableWidget,
191 | ),
192 | ),
193 | ),
194 | if (widget.showRemoveIcon)
195 | Positioned(
196 | top: 0,
197 | left: 0,
198 | child: InkWell(
199 | onTap: () {
200 | widget.onRemoveClick(widget.key!, widget.position);
201 | },
202 | child: widget.removeIcon,
203 | ),
204 | ),
205 | ],
206 | ),
207 | )
208 | : Container();
209 | }
210 | }
211 |
--------------------------------------------------------------------------------
/pubspec.lock:
--------------------------------------------------------------------------------
1 | # Generated by pub
2 | # See https://dart.dev/tools/pub/glossary#lockfile
3 | packages:
4 | _fe_analyzer_shared:
5 | dependency: transitive
6 | description:
7 | name: _fe_analyzer_shared
8 | url: "https://pub.dartlang.org"
9 | source: hosted
10 | version: "31.0.0"
11 | analyzer:
12 | dependency: transitive
13 | description:
14 | name: analyzer
15 | url: "https://pub.dartlang.org"
16 | source: hosted
17 | version: "2.8.0"
18 | args:
19 | dependency: transitive
20 | description:
21 | name: args
22 | url: "https://pub.dartlang.org"
23 | source: hosted
24 | version: "2.3.0"
25 | async:
26 | dependency: transitive
27 | description:
28 | name: async
29 | url: "https://pub.dartlang.org"
30 | source: hosted
31 | version: "2.8.1"
32 | boolean_selector:
33 | dependency: transitive
34 | description:
35 | name: boolean_selector
36 | url: "https://pub.dartlang.org"
37 | source: hosted
38 | version: "2.1.0"
39 | characters:
40 | dependency: transitive
41 | description:
42 | name: characters
43 | url: "https://pub.dartlang.org"
44 | source: hosted
45 | version: "1.1.0"
46 | charcode:
47 | dependency: transitive
48 | description:
49 | name: charcode
50 | url: "https://pub.dartlang.org"
51 | source: hosted
52 | version: "1.3.1"
53 | cli_util:
54 | dependency: transitive
55 | description:
56 | name: cli_util
57 | url: "https://pub.dartlang.org"
58 | source: hosted
59 | version: "0.3.5"
60 | clock:
61 | dependency: transitive
62 | description:
63 | name: clock
64 | url: "https://pub.dartlang.org"
65 | source: hosted
66 | version: "1.1.0"
67 | collection:
68 | dependency: transitive
69 | description:
70 | name: collection
71 | url: "https://pub.dartlang.org"
72 | source: hosted
73 | version: "1.15.0"
74 | convert:
75 | dependency: transitive
76 | description:
77 | name: convert
78 | url: "https://pub.dartlang.org"
79 | source: hosted
80 | version: "3.0.1"
81 | coverage:
82 | dependency: transitive
83 | description:
84 | name: coverage
85 | url: "https://pub.dartlang.org"
86 | source: hosted
87 | version: "1.0.3"
88 | crypto:
89 | dependency: transitive
90 | description:
91 | name: crypto
92 | url: "https://pub.dartlang.org"
93 | source: hosted
94 | version: "3.0.1"
95 | fake_async:
96 | dependency: transitive
97 | description:
98 | name: fake_async
99 | url: "https://pub.dartlang.org"
100 | source: hosted
101 | version: "1.2.0"
102 | file:
103 | dependency: transitive
104 | description:
105 | name: file
106 | url: "https://pub.dartlang.org"
107 | source: hosted
108 | version: "6.1.2"
109 | flutter:
110 | dependency: "direct main"
111 | description: flutter
112 | source: sdk
113 | version: "0.0.0"
114 | flutter_lints:
115 | dependency: "direct dev"
116 | description:
117 | name: flutter_lints
118 | url: "https://pub.dartlang.org"
119 | source: hosted
120 | version: "1.0.4"
121 | flutter_test:
122 | dependency: "direct dev"
123 | description: flutter
124 | source: sdk
125 | version: "0.0.0"
126 | frontend_server_client:
127 | dependency: transitive
128 | description:
129 | name: frontend_server_client
130 | url: "https://pub.dartlang.org"
131 | source: hosted
132 | version: "2.1.2"
133 | glob:
134 | dependency: transitive
135 | description:
136 | name: glob
137 | url: "https://pub.dartlang.org"
138 | source: hosted
139 | version: "2.0.2"
140 | http_multi_server:
141 | dependency: transitive
142 | description:
143 | name: http_multi_server
144 | url: "https://pub.dartlang.org"
145 | source: hosted
146 | version: "3.2.0"
147 | http_parser:
148 | dependency: transitive
149 | description:
150 | name: http_parser
151 | url: "https://pub.dartlang.org"
152 | source: hosted
153 | version: "4.0.0"
154 | io:
155 | dependency: transitive
156 | description:
157 | name: io
158 | url: "https://pub.dartlang.org"
159 | source: hosted
160 | version: "1.0.3"
161 | js:
162 | dependency: transitive
163 | description:
164 | name: js
165 | url: "https://pub.dartlang.org"
166 | source: hosted
167 | version: "0.6.3"
168 | lints:
169 | dependency: transitive
170 | description:
171 | name: lints
172 | url: "https://pub.dartlang.org"
173 | source: hosted
174 | version: "1.0.1"
175 | logging:
176 | dependency: transitive
177 | description:
178 | name: logging
179 | url: "https://pub.dartlang.org"
180 | source: hosted
181 | version: "1.0.2"
182 | matcher:
183 | dependency: transitive
184 | description:
185 | name: matcher
186 | url: "https://pub.dartlang.org"
187 | source: hosted
188 | version: "0.12.10"
189 | matrix4_transform:
190 | dependency: "direct main"
191 | description:
192 | name: matrix4_transform
193 | url: "https://pub.dartlang.org"
194 | source: hosted
195 | version: "2.0.1"
196 | meta:
197 | dependency: transitive
198 | description:
199 | name: meta
200 | url: "https://pub.dartlang.org"
201 | source: hosted
202 | version: "1.7.0"
203 | mime:
204 | dependency: transitive
205 | description:
206 | name: mime
207 | url: "https://pub.dartlang.org"
208 | source: hosted
209 | version: "1.0.1"
210 | node_preamble:
211 | dependency: transitive
212 | description:
213 | name: node_preamble
214 | url: "https://pub.dartlang.org"
215 | source: hosted
216 | version: "2.0.1"
217 | package_config:
218 | dependency: transitive
219 | description:
220 | name: package_config
221 | url: "https://pub.dartlang.org"
222 | source: hosted
223 | version: "2.0.2"
224 | path:
225 | dependency: transitive
226 | description:
227 | name: path
228 | url: "https://pub.dartlang.org"
229 | source: hosted
230 | version: "1.8.0"
231 | pedantic:
232 | dependency: transitive
233 | description:
234 | name: pedantic
235 | url: "https://pub.dartlang.org"
236 | source: hosted
237 | version: "1.11.1"
238 | pool:
239 | dependency: transitive
240 | description:
241 | name: pool
242 | url: "https://pub.dartlang.org"
243 | source: hosted
244 | version: "1.5.0"
245 | pub_semver:
246 | dependency: transitive
247 | description:
248 | name: pub_semver
249 | url: "https://pub.dartlang.org"
250 | source: hosted
251 | version: "2.1.1"
252 | screenshot:
253 | dependency: "direct main"
254 | description:
255 | name: screenshot
256 | url: "https://pub.dartlang.org"
257 | source: hosted
258 | version: "1.2.3"
259 | shelf:
260 | dependency: transitive
261 | description:
262 | name: shelf
263 | url: "https://pub.dartlang.org"
264 | source: hosted
265 | version: "1.2.0"
266 | shelf_packages_handler:
267 | dependency: transitive
268 | description:
269 | name: shelf_packages_handler
270 | url: "https://pub.dartlang.org"
271 | source: hosted
272 | version: "3.0.0"
273 | shelf_static:
274 | dependency: transitive
275 | description:
276 | name: shelf_static
277 | url: "https://pub.dartlang.org"
278 | source: hosted
279 | version: "1.1.0"
280 | shelf_web_socket:
281 | dependency: transitive
282 | description:
283 | name: shelf_web_socket
284 | url: "https://pub.dartlang.org"
285 | source: hosted
286 | version: "1.0.1"
287 | sky_engine:
288 | dependency: transitive
289 | description: flutter
290 | source: sdk
291 | version: "0.0.99"
292 | source_map_stack_trace:
293 | dependency: transitive
294 | description:
295 | name: source_map_stack_trace
296 | url: "https://pub.dartlang.org"
297 | source: hosted
298 | version: "2.1.0"
299 | source_maps:
300 | dependency: transitive
301 | description:
302 | name: source_maps
303 | url: "https://pub.dartlang.org"
304 | source: hosted
305 | version: "0.10.10"
306 | source_span:
307 | dependency: transitive
308 | description:
309 | name: source_span
310 | url: "https://pub.dartlang.org"
311 | source: hosted
312 | version: "1.8.1"
313 | stack_trace:
314 | dependency: transitive
315 | description:
316 | name: stack_trace
317 | url: "https://pub.dartlang.org"
318 | source: hosted
319 | version: "1.10.0"
320 | stream_channel:
321 | dependency: transitive
322 | description:
323 | name: stream_channel
324 | url: "https://pub.dartlang.org"
325 | source: hosted
326 | version: "2.1.0"
327 | string_scanner:
328 | dependency: transitive
329 | description:
330 | name: string_scanner
331 | url: "https://pub.dartlang.org"
332 | source: hosted
333 | version: "1.1.0"
334 | term_glyph:
335 | dependency: transitive
336 | description:
337 | name: term_glyph
338 | url: "https://pub.dartlang.org"
339 | source: hosted
340 | version: "1.2.0"
341 | test:
342 | dependency: "direct dev"
343 | description:
344 | name: test
345 | url: "https://pub.dartlang.org"
346 | source: hosted
347 | version: "1.17.10"
348 | test_api:
349 | dependency: transitive
350 | description:
351 | name: test_api
352 | url: "https://pub.dartlang.org"
353 | source: hosted
354 | version: "0.4.2"
355 | test_core:
356 | dependency: transitive
357 | description:
358 | name: test_core
359 | url: "https://pub.dartlang.org"
360 | source: hosted
361 | version: "0.4.0"
362 | typed_data:
363 | dependency: transitive
364 | description:
365 | name: typed_data
366 | url: "https://pub.dartlang.org"
367 | source: hosted
368 | version: "1.3.0"
369 | vector_math:
370 | dependency: transitive
371 | description:
372 | name: vector_math
373 | url: "https://pub.dartlang.org"
374 | source: hosted
375 | version: "2.1.0"
376 | vm_service:
377 | dependency: transitive
378 | description:
379 | name: vm_service
380 | url: "https://pub.dartlang.org"
381 | source: hosted
382 | version: "7.5.0"
383 | watcher:
384 | dependency: transitive
385 | description:
386 | name: watcher
387 | url: "https://pub.dartlang.org"
388 | source: hosted
389 | version: "1.0.1"
390 | web_socket_channel:
391 | dependency: transitive
392 | description:
393 | name: web_socket_channel
394 | url: "https://pub.dartlang.org"
395 | source: hosted
396 | version: "2.1.0"
397 | webkit_inspection_protocol:
398 | dependency: transitive
399 | description:
400 | name: webkit_inspection_protocol
401 | url: "https://pub.dartlang.org"
402 | source: hosted
403 | version: "1.0.0"
404 | yaml:
405 | dependency: transitive
406 | description:
407 | name: yaml
408 | url: "https://pub.dartlang.org"
409 | source: hosted
410 | version: "3.1.0"
411 | sdks:
412 | dart: ">=2.14.0 <3.0.0"
413 | flutter: ">=1.17.0"
414 |
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: easy_image_editor
2 | description: Easy Image Editor is usefull for add any widget and move, resize and set over the main image or color
3 | repository: https://github.com/rajeshbdabhi/easy_image_editor
4 | homepage: https://github.com/rajeshbdabhi/easy_image_editor
5 | version: 1.0.3
6 |
7 | environment:
8 | sdk: ">=2.12.0 <3.0.0"
9 | flutter: ">=1.17.0"
10 |
11 | dependencies:
12 | flutter:
13 | sdk: flutter
14 | matrix4_transform: ^2.0.1
15 | screenshot: ^1.2.3
16 |
17 | dev_dependencies:
18 | flutter_test:
19 | sdk: flutter
20 | flutter_lints: ^1.0.0
21 | test: ^1.17.10
22 |
23 | # For information on the generic Dart part of this file, see the
24 | # following page: https://dart.dev/tools/pub/pubspec
25 |
26 | # The following section is specific to Flutter.
27 | flutter:
28 |
29 | # To add assets to your package, add an assets section, like this:
30 | # assets:
31 | # - images/a_dot_burr.jpeg
32 | # - images/a_dot_ham.jpeg
33 | #
34 | # For details regarding assets in packages, see
35 | # https://flutter.dev/assets-and-images/#from-packages
36 | #
37 | # An image asset can refer to one or more resolution-specific "variants", see
38 | # https://flutter.dev/assets-and-images/#resolution-aware.
39 |
40 | # To add custom fonts to your package, add a fonts section here,
41 | # in this "flutter" section. Each entry in this list should have a
42 | # "family" key with the font family name, and a "fonts" key with a
43 | # list giving the asset and other descriptors for the font. For
44 | # example:
45 | # fonts:
46 | # - family: Schyler
47 | # fonts:
48 | # - asset: fonts/Schyler-Regular.ttf
49 | # - asset: fonts/Schyler-Italic.ttf
50 | # style: italic
51 | # - family: Trajan Pro
52 | # fonts:
53 | # - asset: fonts/TrajanPro.ttf
54 | # - asset: fonts/TrajanPro_Bold.ttf
55 | # weight: 700
56 | #
57 | # For details regarding fonts in packages, see
58 | # https://flutter.dev/custom-fonts/#from-packages
59 |
--------------------------------------------------------------------------------
/test/easy_image_editor_test.dart:
--------------------------------------------------------------------------------
1 | import 'package:test/test.dart';
2 |
3 | import 'package:easy_image_editor/easy_image_editor.dart';
4 |
5 | void main() {
6 | test('should editor save image', () {
7 | EditorView(
8 | onInitialize: (controller) {
9 | expect("controller.saveEditing()", null);
10 | },
11 | );
12 | });
13 | }
14 |
--------------------------------------------------------------------------------