added project'

This commit is contained in:
brahim 2022-10-30 15:25:33 +07:00
commit 4dd5d2f6ff
121 changed files with 14320 additions and 0 deletions

9
.flutter-plugins Normal file
View File

@ -0,0 +1,9 @@
# This is a generated file; do not edit or check into version control.
file_picker=/Users/mac/developer/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-5.2.2/
flutter_inappwebview=/Users/mac/developer/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_inappwebview-6.0.0-beta.11/
flutter_keyboard_visibility=/Users/mac/developer/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_keyboard_visibility-5.4.0/
flutter_keyboard_visibility_linux=/Users/mac/developer/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_keyboard_visibility_linux-1.0.0/
flutter_keyboard_visibility_macos=/Users/mac/developer/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_keyboard_visibility_macos-1.0.0/
flutter_keyboard_visibility_web=/Users/mac/developer/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_keyboard_visibility_web-2.0.0/
flutter_keyboard_visibility_windows=/Users/mac/developer/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_keyboard_visibility_windows-1.0.0/
flutter_plugin_android_lifecycle=/Users/mac/developer/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.7/

View File

@ -0,0 +1 @@
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"file_picker","path":"/Users/mac/developer/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-5.2.2/","native_build":true,"dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/mac/developer/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_inappwebview-6.0.0-beta.11/","native_build":true,"dependencies":[]},{"name":"flutter_keyboard_visibility","path":"/Users/mac/developer/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_keyboard_visibility-5.4.0/","native_build":true,"dependencies":[]}],"android":[{"name":"file_picker","path":"/Users/mac/developer/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-5.2.2/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_inappwebview","path":"/Users/mac/developer/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_inappwebview-6.0.0-beta.11/","native_build":true,"dependencies":[]},{"name":"flutter_keyboard_visibility","path":"/Users/mac/developer/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_keyboard_visibility-5.4.0/","native_build":true,"dependencies":[]},{"name":"flutter_plugin_android_lifecycle","path":"/Users/mac/developer/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-2.0.7/","native_build":true,"dependencies":[]}],"macos":[{"name":"flutter_inappwebview","path":"/Users/mac/developer/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_inappwebview-6.0.0-beta.11/","native_build":true,"dependencies":[]},{"name":"flutter_keyboard_visibility_macos","path":"/Users/mac/developer/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_keyboard_visibility_macos-1.0.0/","native_build":false,"dependencies":[]}],"linux":[{"name":"flutter_keyboard_visibility_linux","path":"/Users/mac/developer/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_keyboard_visibility_linux-1.0.0/","native_build":false,"dependencies":[]}],"windows":[{"name":"flutter_keyboard_visibility_windows","path":"/Users/mac/developer/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_keyboard_visibility_windows-1.0.0/","native_build":false,"dependencies":[]}],"web":[{"name":"file_picker","path":"/Users/mac/developer/flutter/.pub-cache/hosted/pub.dartlang.org/file_picker-5.2.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/mac/developer/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_inappwebview-6.0.0-beta.11/","dependencies":[]},{"name":"flutter_keyboard_visibility_web","path":"/Users/mac/developer/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_keyboard_visibility_web-2.0.0/","dependencies":[]}]},"dependencyGraph":[{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"flutter_inappwebview","dependencies":[]},{"name":"flutter_keyboard_visibility","dependencies":["flutter_keyboard_visibility_linux","flutter_keyboard_visibility_macos","flutter_keyboard_visibility_web","flutter_keyboard_visibility_windows"]},{"name":"flutter_keyboard_visibility_linux","dependencies":[]},{"name":"flutter_keyboard_visibility_macos","dependencies":[]},{"name":"flutter_keyboard_visibility_web","dependencies":[]},{"name":"flutter_keyboard_visibility_windows","dependencies":[]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]}],"date_created":"2022-10-30 15:22:45.754664","version":"3.3.6"}

30
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@ -0,0 +1,30 @@
---
name: Bug report
about: Create a report to help us improve
title: "[BUG]"
labels: bug
assignees: tneotia
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Device:**
Add device details here.
**Additional context**
Add any other context about the problem here.

View File

@ -0,0 +1,17 @@
---
name: Feature request
about: Suggest an idea for this project
title: "[FEATURE]"
labels: enhancement
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Additional context**
Add any other context or screenshots about the feature request here.

10
.github/ISSUE_TEMPLATE/question.md vendored Normal file
View File

@ -0,0 +1,10 @@
---
name: Question
about: Ask a question about this project
title: "[QUESTION]"
labels: question
assignees: ''
---
Type question here.

7
.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
.DS_Store
.dart_tool/
.packages
.pub/
build/

10
.metadata Normal file
View File

@ -0,0 +1,10 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
version:
revision: a29104a69b102a7485cd00d358eaeab219d258ab
channel: beta
project_type: plugin

244
CHANGELOG.md Normal file
View File

@ -0,0 +1,244 @@
## [2.5.0] - 2022-06-04
* Support Flutter 3.0 (remove warnings) (@Cteq3132)
* [BREAKING] Support modifying `foreColorSelected` and `backColorSelected` when using a custom dialog for font coloring
* If you are using a custom `updateStatus` function for the font coloring, that function is now defined as `updateStatus(Color)`
* Added `disabled` parameter to automatically disable editor on initial load
* Fixed white background color appearing sometimes when pressing backspace on text
* Added `useHybridComposition` parameter in case devs want to disable this behavior (improves animations of app)
* [WEB] Fixed editor height being 0 when `initialText` is `null` (@dab246)
* Migrated example to Android embedding V2
* Removed woff fonts to allow iOS App Store submissions
## [2.4.0] - 2021-10-30
* Improved color picker
* Added scrollable support to picker
* Fixed issue where keyboard would disappear and prevent users from selecting a new color
* Added support for getting selected text in Flutter Web (`controller.getSelectedTextWeb()`)
* Added support for spellcheck
* Added support for custom options in summernote initialization
* Added support for a hard stop on character limit (will not allow user to type further)
* Fixed bug where focusing editor would scroll it back to the top and not show the caret position
* Fixed height not updating in Flutter Web when `callbacks` was `null`
* Updated dependencies and fixed flutter_colorpicker dependency error (@eliudio)
## [2.3.0] - 2021-09-09
* Potentially fixed bad state error for `stream.first`
* Fixed Summernote-@-Mention not inserting text after selecting the dropdown item
* Fixed whitespace after @ sign when inserting a mention
* Add support for overriding URL loading on mobile with `onNavigationRequestMobile` callback
* Hide keyboard when opening color picker dialog
* Use try/catch on `SystemChannel` call on web to prevent exception
* Added a character counter for text in the editor - access via `controller.characterCount`
* Fixed auto adjust height not working in some cases
* Fixed editor height not updating when focused after a TextField was previously focused
* Updated dependencies (@JEuler)
NOTE: If you are on Flutter Beta+, you must use `dependency_overrides` in `pubspec.yaml`!!
```yaml
dependency_overrides:
flutter_colorpicker: ^0.5.0
```
## [2.2.0+1] - 2021-06-15 (BETA)
* Updated `flutter_colorpicker` to the latest version to fix deprecations on Flutter beta+
* [NOTE] Do not use this version on Flutter stable!
## [2.2.0] - 2021-06-14
* Fixed null safety warnings due to latest `file_picker` version
* Potentially fixed editor controller creating a new instance on widget rebuild
* Fixed issue where custom HTML files would have custom JS replaced with built-in JS
* Fixed darkMode not applying when `filePath` is used on Android
* Fixed "null" text showing as the hint when no hint is given
* Added new `onChangeSelection` callback that passes the editor settings whenever the user changes
their current selection (e.g. tap on a different word, create a new node, select text, etc)
* Added support for custom JS injection on Flutter Web
* Fixed minor bug with automatic height adjustment on mobile
* Added new `ToolbarType.nativeExpandable` which allows the user to switch between the
scrollview or gridview toolbar on the fly
* Support setting the `inputmode` for the editor, which changes the virtual keyboard display on mobile devices (e.g. number pad, email keyboard, etc)
* [BREAKING] renamed `onChange` callback to `onChangeContent`
* [BREAKING] disabled a lot of the buttons by default, now only around half of the editor buttons
are enabled to improve the UX. You can still re-enable the rest if you want.
* [BREAKING] min Flutter version requirement bumped to 2.2.0
## [2.1.1] - 2021-05-22
* Fixed bottom overflow error on `AlertDialog`s if the screen size is small
* Fixed `StyleButtons(style: false)` would not remove the style dropdown
* Fixed JS/Dart communication hiccup on Web (make sure `postMessage` data is not null)
* Code cleanup
## [2.1.0+1] - 2021-05-11
* Hotfix for `copyWith` not defined for `ScrollBehavior` in v2.1.0
## [2.1.0] - 2021-05-10
* Fixed `setState` and `Stream.first` error on page dispose
* Fixed height adjustment not working
* Fixed `getText` on Web
* Improved dropdown UX when `ToolbarPosition.belowEditor` by opening upwards and making it scrollable after a certain height
## [2.0.1] - 2021-04-28
* Added support for setting custom `UserScript`s on the webview (mobile only)
* Added support for customizing the context menu (menu when user selects text) for the webview (mobile only)
* Added `LongPressGestureRecognizer` to the webview to allow users to select text via a long press (mobile only)
* You can set the duration before the long press is recognized via `HtmlEditorOptions > mobileLongPressDuration`
* Added support for placing the toolbar wherever using `HtmlToolbarOptions > toolbarPosition: ToolbarPosition.custom`
* See the README if you'd like to use any of these new features. `UserScript` and the context menu customization have external documentation via flutter_inappwebview - the docs are linked in the README.
## [2.0.0+1] - 2021-04-22
* Transitioned to fully native controls! These are extremely customizable and have much better UX than the previous controls.
* [BREAKING] refactored a lot of options into separate constructors
* [BREAKING] refactored toolbar classes, so toolbar customizations will need updating
* Added a bunch of interceptors and callbacks for button presses
* Added the ability to make custom buttons and set their positions
* Added native support for numerous Summernote plugins
* [BREAKING] removed all Summernote plugins except Summernote @ Mention. The package now supports the majority of plugins out of the box.
* Reduced package size by removing the Summernote plugin files
* Reduced size further by using a stripped-down version of Summernote @ Mention libs
* Added `execCommand` to controller to help you create custom toolbar buttons
* Improved automatic height adjustment
* Bumped dependencies
* [BREAKING] Require Flutter 2.0.0+
* As always, see the README for full documentation on these changes
* See the [Migration Guide](https://github.com/tneotia/html-editor-enhanced/wiki/v2.0.0-Migration-Guide) for help migrating your v1.x.x widget code
## [1.8.0] - 2021-04-07
* Add support for `getSuggestionsMobile` (Summernote @ Mentions Plugin) - allows you to programatically return the list of mentions.
* Only supported on mobile.
* [BREAKING] renamed `mentions` to `mentionsWeb` as a result of this change
* Added support for the remainder of Summernote callbacks:
* `onBeforeCommand`
* `onChangeCodeview`
* `onDialogShown`
* `onImageUploadError`
* `onMouseDown`
* `onMouseUp`
* `onScroll`
* See the README for how these work.
* Added a few new functions:
* recalculateHeight(): recalculates the editor height and applies it
* addNotification(): adds a notification bar to the bottom of the editor in a specified style with specified text
* removeNotification(): removes the current notification from the bottom of the editor
* Fixed blank space at the bottom of the editor when `showBottomToolbar: false`
* Fixed 'Android resource linking failed' (bumped flutter_inappwebview to 5.3.1+1)
## [1.7.1] - 2021-03-26
* Fixed bug where initial text would not be inserted and default toolbar would be shown regardless of editor options
* Significantly improved keyboard height detection (detect when keyboard comes up and goes down)
* Adjusted HTML processing algorithm to fix issues where `"` and `'` would not be properly escaped on HTML insertion
* Added `processNewLineAsBr` - this will replace any `\n` in the input string to `<br/>` rather than the default `""`
* Applied processing to `setHint()` and `insertHtml()` functions
* Added support for returning the file's base64 data in `onImageUpload` and `onFileUpload`
* Now you can use `MultipartFile.fromBytes()` to upload to server - [example](https://github.com/tneotia/html-editor-enhanced#example-for-onimageupload-and-onimagelinkinsert)
* Added support for `onFileUploadError` and `onFileLinkInsert` (Summernote File plugin)
* Added support for `maximumFileSize` (Summernote File plugin)
* See the README for more details on these changes
## [1.7.0+1] - 2021-03-22
* Fixed `type 'double' is not a subtype of type 'int?' in type cast` on iOS
* By extension this fixes the `adjustHeightForKeyboard` not working on iOS
* Fixed `Bad state: Cannot add new events after calling close` exception when disposing the page containing the editor
* Fixed web page not found when inserting a video URL (see [here](https://github.com/summernote/summernote/issues/3252))
## [1.7.0] - 2021-03-17
* [BREAKING]:
* Refactored `height`, `autoAdjustHeight`, `decoration`, `showBottomToolbar`, and `darkMode` into new `HtmlEditorOptions` class - see README for how to migrate
* Removed 'Summernote Classes' plugin
* Sorry for all the breaking changes lately - I think I've finally figured out how I want to do the API design so there should be far less in future releases
* Added `onImageUpload` callback that fires when an image is inserted via `<input type="file">`
* Added `onImageLinkInsert` callback that fires when an image is inserted via URL
* Added `shouldEnsureVisible` that scrolls the editor into view when it is focused or text is typed, kind of like `TextField`s
* Added `adjustHeightForKeyboard` (default true) that adjusts the editor's height when the keyboard is active to ensure no content is cut off by the keyboard
* Added `filePath` which allows you to provide a completely custom HTML file to load
* If you plan on using any of the above, it is highly recommend looking at the README for more details and examples.
* Removed disabled scroll feature since it prevented the editor from scrolling even when the editor content was larger than the height
* Code cleanup
## [1.6.0] - 2021-03-13
* [BREAKING] removed `dispose()` method on controller
* The editor no longer uses a `Stream` to get text and therefore nothing needs to be disposed
* Added `onInit` callback that fires once the editor is ready to function and accept JS
* Added a few new parameters:
* `autoAdjustHeight` - for `HtmlEditor`: default true, automatically adjusts the height of the editor to make sure scrolling is not necessary
* `processInputHtml` - for `HtmlEditorController`: processes input HTML (e.g. new lines become `<br/>`)
* `processOutputHtml` - for `HtmlEditorController`: processes output HTML (e.g. `<p><br/><p>` becomes `""`)
* Added more plugins:
* Summernote Case Converter
* Summernote List Styles
* Summernote RTL
* Summernote @ Mention
* Summernote Codewrapper
* Summernote File
* See the README for more details.
* Added shim for dart:ui to remove the `ui.PlatformViewRegistry not found` error
* Added the summernote-no-plugins.html file to load a de-bloated HTML file when no plugins are active
* Fixed bug where two editors would be initialized in the same webview in some cases
* Reduced the size of assets to ~650kb - ~300kb summernote libs, ~350kb plugin libs
* Code cleanup
## [1.5.0+1] - 2021-03-10
* Fixed getText() returning null on mobile for any device
## [1.5.0] - 2021-03-01
* Nullsafety preview
* Added Flutter's Hybrid Composition to the HTML Editor. This significantly improves the keyboard experience on Android.
## [1.4.0] - 2021-03-01
* [BREAKING] removed `HtmlParser` for calling methods, instead you now must pass an `HtmlEditorController` to the plugin (like a `TextField`). All methods are accessible from that controller. See the usage section in the README for an example.
* This allows you to have multiple independent editors on a page, whereas earlier the package would not know which editor the method should be called on.
* Add support for certain Summernote plugins from [Summernote Awesome](https://github.com/summernote/awesome-summernote). See the README for details on the API and the currently supported plugins.
* Nullsafety pre-release coming soon.
## [1.3.0] - 2021-02-23
* Add official support for Flutter Web
* Add support for modifying the toolbar options. See the README for details on the API.
* Add support for a native dark mode
* Removed image_picker plugin and image button in toolbar because users can insert images via the image button in Summernote
* [BREAKING] Removed the `imageWidth` and `useBottomSheet` params due to the above change
## [1.2.0+1] - 2021-02-20
* Add support for accessing `InAppWebViewController` via a getter
* Add support for inserting files via the editor dialog itself
* Add methods:
* toggle code view
* enable/disable editor
* undo/redo
* inserting plaintext/HTML/images/links
* Add callbacks:
* onChange
* onEnter
* onFocus/onBlur/onBlurCodeview
* onKeyUp/onKeyDown
* onPaste
* Downgraded dependencies to non-nullsafety to prevent errors
* Updated docs and example app to showcase new features, refer to those for info on the above changes
## [1.1.1] - 2021-02-19
* Minor update to add documentation to code and completely refactor/reorganize code
## [1.1.0] - 2021-02-19
* Switch webview dependency to `flutter_inappwebview`
* Remove localserver, instead get Summernote HTML directly from assets (improves performance and loading speeds)
* [BREAKING] Switch to `StatelessWidget`
* You no longer need a `GlobalKey` for the `HtmlEditorState`. All of the methods are static and can be called like so:
```dart
HtmlEditor.setEmpty();
```
* Fix deprecations and update dependencies
## Flutter HTML Editor changes by xrb21
## [1.0.1] - 2020-05-07
* Update Readme usage for iOS
## [1.0.0] - 2020-05-07
* fixing iOS blank screen
* fixing text hint
## [0.0.2+1] - 2020-05-02
* fixing path packages
## [0.0.2] - 2020-05-02
* Change link repo
## [0.0.1] - 2020-05-02
* Initial Release

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 tneotia Tanay Neotia
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:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
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.

1135
README.md Normal file

File diff suppressed because it is too large Load Diff

1
analysis_options.yaml Normal file
View File

@ -0,0 +1 @@
include: package:pedantic/analysis_options.yaml

46
example/.gitignore vendored Normal file
View File

@ -0,0 +1,46 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/
# Flutter/Dart/Pub related
**/doc/api/
**/ios/Flutter/.last_build_id
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
.packages
.pub-cache/
.pub/
/build/
# Web related
lib/generated_plugin_registrant.dart
# Symbolication related
app.*.symbols
# Obfuscation related
app.*.map.json
# Android Studio will place build artifacts here
/android/app/debug
/android/app/profile
/android/app/release

10
example/.metadata Normal file
View File

@ -0,0 +1,10 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
version:
revision: a29104a69b102a7485cd00d358eaeab219d258ab
channel: beta
project_type: app

16
example/README.md Normal file
View File

@ -0,0 +1,16 @@
# html_editor_enhanced_example
Demonstrates how to use the html_editor_enhanced plugin.
## Getting Started
This project is a starting point for a Flutter application.
A few resources to get you started if this is your first Flutter project:
- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab)
- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook)
For help getting started with Flutter, view our
[online documentation](https://flutter.dev/docs), which offers tutorials,
samples, guidance on mobile development, and a full API reference.

11
example/android/.gitignore vendored Normal file
View File

@ -0,0 +1,11 @@
gradle-wrapper.jar
/.gradle
/captures/
/gradlew
/gradlew.bat
/local.properties
GeneratedPluginRegistrant.java
# Remember to never publicly share your keystore.
# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
key.properties

View File

@ -0,0 +1,63 @@
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader('UTF-8') { reader ->
localProperties.load(reader)
}
}
def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
flutterVersionCode = '1'
}
def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
flutterVersionName = '1.0'
}
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android {
compileSdkVersion 33
aaptOptions {
noCompress 'html', 'txt'
}
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.tanayneotia.html_editor_enhanced_example"
minSdkVersion 21
targetSdkVersion 33
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig signingConfigs.debug
}
}
}
flutter {
source '../..'
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
}

View File

@ -0,0 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.tanayneotia.html_editor_enhanced_example">
<!-- Flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>

View File

@ -0,0 +1,57 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.tanayneotia.html_editor_enhanced_example">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.CAMERA"/>
<application
android:name="${applicationName}"
android:label="html_editor_enhanced_example"
android:icon="@mipmap/ic_launcher"
android:requestLegacyExternalStorage="true">
<provider
android:name="com.pichillilorenzo.flutter_inappwebview.InAppWebViewFileProvider"
android:authorities="${applicationId}.flutter_inappwebview.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" />
</provider>
<activity
android:name=".MainActivity"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize"
android:exported="true">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<!-- Displays an Android View that continues showing the launch screen
Drawable until Flutter paints its first frame, then this splash
screen fades out. A splash screen is useful to avoid any visual
gap between the end of Android's launch screen and the painting of
Flutter's first frame. -->
<meta-data
android:name="io.flutter.embedding.android.SplashScreenDrawable"
android:resource="@drawable/launch_background"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</application>
</manifest>

View File

@ -0,0 +1,13 @@
package id.ercode.example;
import androidx.annotation.NonNull;
import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.plugins.GeneratedPluginRegistrant;
public class MainActivity extends FlutterActivity {
@Override
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine);
}
}

View File

@ -0,0 +1,6 @@
package com.tanayneotia.example
import io.flutter.embedding.android.FlutterActivity
class MainActivity: FlutterActivity() {
}

View File

@ -0,0 +1,6 @@
package com.tanayneotia.html_editor_enhanced_example
import io.flutter.embedding.android.FlutterActivity
class MainActivity: FlutterActivity() {
}

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="?android:colorBackground" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@android:color/white" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>

Binary file not shown.

After

Width:  |  Height:  |  Size: 544 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 442 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 721 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
Flutter draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
Flutter draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>

View File

@ -0,0 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.tanayneotia.html_editor_enhanced_example">
<!-- Flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>

View File

@ -0,0 +1,31 @@
buildscript {
ext.kotlin_version = '1.6.10'
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.1.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
allprojects {
repositories {
google()
jcenter()
}
}
rootProject.buildDir = '../build'
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
project.evaluationDependsOn(':app')
}
task clean(type: Delete) {
delete rootProject.buildDir
}

View File

@ -0,0 +1,3 @@
org.gradle.jvmargs=-Xmx1536M
android.useAndroidX=true
android.enableJetifier=true

View File

@ -0,0 +1,6 @@
#Fri Jun 23 08:50:38 CEST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip

View File

@ -0,0 +1,11 @@
include ':app'
def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
def properties = new Properties()
assert localPropertiesFile.exists()
localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
def flutterSdkPath = properties.getProperty("flutter.sdk")
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"

32
example/ios/.gitignore vendored Normal file
View File

@ -0,0 +1,32 @@
*.mode1v3
*.mode2v3
*.moved-aside
*.pbxuser
*.perspectivev3
**/*sync/
.sconsign.dblite
.tags*
**/.vagrant/
**/DerivedData/
Icon?
**/Pods/
**/.symlinks/
profile
xcuserdata
**/.generated/
Flutter/App.framework
Flutter/Flutter.framework
Flutter/Flutter.podspec
Flutter/Generated.xcconfig
Flutter/app.flx
Flutter/app.zip
Flutter/flutter_assets/
Flutter/flutter_export_environment.sh
ServiceDefinitions.json
Runner/GeneratedPluginRegistrant.*
# Exceptions to above rules.
!default.mode1v3
!default.mode2v3
!default.pbxuser
!default.perspectivev3

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>App</string>
<key>CFBundleIdentifier</key>
<string>io.flutter.flutter.app</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>App</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>9.0</string>
</dict>
</plist>

View File

@ -0,0 +1,2 @@
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig"

View File

@ -0,0 +1,2 @@
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig"

41
example/ios/Podfile Normal file
View File

@ -0,0 +1,41 @@
# Uncomment this line to define a global platform for your project
# platform :ios, '9.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release,
}
def flutter_root
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
unless File.exist?(generated_xcode_build_settings_path)
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
end
File.foreach(generated_xcode_build_settings_path) do |line|
matches = line.match(/FLUTTER_ROOT\=(.*)/)
return matches[1].strip if matches
end
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
end
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
flutter_ios_podfile_setup
target 'Runner' do
use_frameworks!
use_modular_headers!
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
end
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
end
end

89
example/ios/Podfile.lock Normal file
View File

@ -0,0 +1,89 @@
PODS:
- DKImagePickerController/Core (4.3.4):
- DKImagePickerController/ImageDataManager
- DKImagePickerController/Resource
- DKImagePickerController/ImageDataManager (4.3.4)
- DKImagePickerController/PhotoGallery (4.3.4):
- DKImagePickerController/Core
- DKPhotoGallery
- DKImagePickerController/Resource (4.3.4)
- DKPhotoGallery (0.0.17):
- DKPhotoGallery/Core (= 0.0.17)
- DKPhotoGallery/Model (= 0.0.17)
- DKPhotoGallery/Preview (= 0.0.17)
- DKPhotoGallery/Resource (= 0.0.17)
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Core (0.0.17):
- DKPhotoGallery/Model
- DKPhotoGallery/Preview
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Model (0.0.17):
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Preview (0.0.17):
- DKPhotoGallery/Model
- DKPhotoGallery/Resource
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Resource (0.0.17):
- SDWebImage
- SwiftyGif
- file_picker (0.0.1):
- DKImagePickerController/PhotoGallery
- Flutter
- Flutter (1.0.0)
- flutter_inappwebview (0.0.1):
- Flutter
- flutter_inappwebview/Core (= 0.0.1)
- OrderedSet (~> 5.0)
- flutter_inappwebview/Core (0.0.1):
- Flutter
- OrderedSet (~> 5.0)
- flutter_keyboard_visibility (0.0.1):
- Flutter
- OrderedSet (5.0.0)
- SDWebImage (5.13.2):
- SDWebImage/Core (= 5.13.2)
- SDWebImage/Core (5.13.2)
- SwiftyGif (5.4.3)
DEPENDENCIES:
- file_picker (from `.symlinks/plugins/file_picker/ios`)
- Flutter (from `Flutter`)
- flutter_inappwebview (from `.symlinks/plugins/flutter_inappwebview/ios`)
- flutter_keyboard_visibility (from `.symlinks/plugins/flutter_keyboard_visibility/ios`)
SPEC REPOS:
trunk:
- DKImagePickerController
- DKPhotoGallery
- OrderedSet
- SDWebImage
- SwiftyGif
EXTERNAL SOURCES:
file_picker:
:path: ".symlinks/plugins/file_picker/ios"
Flutter:
:path: Flutter
flutter_inappwebview:
:path: ".symlinks/plugins/flutter_inappwebview/ios"
flutter_keyboard_visibility:
:path: ".symlinks/plugins/flutter_keyboard_visibility/ios"
SPEC CHECKSUMS:
DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac
DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179
file_picker: 817ab1d8cd2da9d2da412a417162deee3500fc95
Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a
flutter_inappwebview: bfd58618f49dc62f2676de690fc6dcda1d6c3721
flutter_keyboard_visibility: 0339d06371254c3eb25eeb90ba8d17dca8f9c069
OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c
SDWebImage: 72f86271a6f3139cc7e4a89220946489d4b9a866
SwiftyGif: 6c3eafd0ce693cad58bb63d2b2fb9bacb8552780
PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c
COCOAPODS: 1.11.3

View File

@ -0,0 +1,539 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 50;
objects = {
/* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
A337FE4295531DD50664781E /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 55E3FF9EC5994F34E0646A50 /* Pods_Runner.framework */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
0BCF426A5747D60733C82961 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
55E3FF9EC5994F34E0646A50 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
95BEBE361EC0B4EDA3C51470 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
A16C753DD94EA25E0B34474C /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
97C146EB1CF9000F007C117D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
A337FE4295531DD50664781E /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
2F92D2CED148D42F9515C21A /* Pods */ = {
isa = PBXGroup;
children = (
A16C753DD94EA25E0B34474C /* Pods-Runner.debug.xcconfig */,
0BCF426A5747D60733C82961 /* Pods-Runner.release.xcconfig */,
95BEBE361EC0B4EDA3C51470 /* Pods-Runner.profile.xcconfig */,
);
name = Pods;
path = Pods;
sourceTree = "<group>";
};
484111EC931D7601963471BA /* Frameworks */ = {
isa = PBXGroup;
children = (
55E3FF9EC5994F34E0646A50 /* Pods_Runner.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
9740EEB31CF90195004384FC /* Generated.xcconfig */,
);
name = Flutter;
sourceTree = "<group>";
};
97C146E51CF9000F007C117D = {
isa = PBXGroup;
children = (
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
2F92D2CED148D42F9515C21A /* Pods */,
484111EC931D7601963471BA /* Frameworks */,
);
sourceTree = "<group>";
};
97C146EF1CF9000F007C117D /* Products */ = {
isa = PBXGroup;
children = (
97C146EE1CF9000F007C117D /* Runner.app */,
);
name = Products;
sourceTree = "<group>";
};
97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup;
children = (
97C146FA1CF9000F007C117D /* Main.storyboard */,
97C146FD1CF9000F007C117D /* Assets.xcassets */,
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
97C147021CF9000F007C117D /* Info.plist */,
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
);
path = Runner;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
97C146ED1CF9000F007C117D /* Runner */ = {
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
3BBEA2A067581CB1B09777D0 /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
AC0125F04139E6587D7ECBB1 /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = Runner;
productName = Runner;
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1300;
ORGANIZATIONNAME = "";
TargetAttributes = {
97C146ED1CF9000F007C117D = {
CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 1100;
};
};
};
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 97C146E51CF9000F007C117D;
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
97C146ED1CF9000F007C117D /* Runner */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
97C146EC1CF9000F007C117D /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Thin Binary";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
};
3BBEA2A067581CB1B09777D0 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Run Script";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
AC0125F04139E6587D7ECBB1 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
97C146EA1CF9000F007C117D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C146FB1CF9000F007C117D /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C147001CF9000F007C117D /* Base */,
);
name = LaunchScreen.storyboard;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
249021D3217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Profile;
};
249021D4217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.tanayneotia.htmlEditorEnhancedExample;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Profile;
};
97C147031CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
97C147041CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
97C147061CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.tanayneotia.htmlEditorEnhancedExample;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
};
97C147071CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.tanayneotia.htmlEditorEnhancedExample;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147031CF9000F007C117D /* Debug */,
97C147041CF9000F007C117D /* Release */,
249021D3217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147061CF9000F007C117D /* Debug */,
97C147071CF9000F007C117D /* Release */,
249021D4217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 97C146E61CF9000F007C117D /* Project object */;
}

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>

View File

@ -0,0 +1,91 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1300"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Profile"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>

View File

@ -0,0 +1,6 @@
#import <Flutter/Flutter.h>
#import <UIKit/UIKit.h>
@interface AppDelegate : FlutterAppDelegate
@end

View File

@ -0,0 +1,13 @@
#import "AppDelegate.h"
#import "GeneratedPluginRegistrant.h"
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[GeneratedPluginRegistrant registerWithRegistry:self];
// Override point for customization after application launch.
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
@end

View File

@ -0,0 +1,13 @@
import UIKit
import Flutter
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}

View File

@ -0,0 +1,122 @@
{
"images" : [
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@3x.png",
"scale" : "3x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@3x.png",
"scale" : "3x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@3x.png",
"scale" : "3x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@2x.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@3x.png",
"scale" : "3x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@1x.png",
"scale" : "1x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@1x.png",
"scale" : "1x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@1x.png",
"scale" : "1x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@2x.png",
"scale" : "2x"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "Icon-App-83.5x83.5@2x.png",
"scale" : "2x"
},
{
"size" : "1024x1024",
"idiom" : "ios-marketing",
"filename" : "Icon-App-1024x1024@1x.png",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 564 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@ -0,0 +1,23 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "LaunchImage.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

View File

@ -0,0 +1,5 @@
# Launch Screen Assets
You can customize the launch screen with your own desired assets by replacing the image files in this directory.
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.

View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Ydg-fD-yQy"/>
<viewControllerLayoutGuide type="bottom" id="xbc-2k-c8Z"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4">
</imageView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="1a2-6s-vTC"/>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4X2-HB-R7a"/>
</constraints>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
<resources>
<image name="LaunchImage" width="168" height="185"/>
</resources>
</document>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
</dependencies>
<scenes>
<!--Flutter View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>

View File

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>html_editor_enhanced_example</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
</dict>
</plist>

View File

@ -0,0 +1 @@
#import "GeneratedPluginRegistrant.h"

View File

@ -0,0 +1,9 @@
#import <Flutter/Flutter.h>
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char* argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}

455
example/lib/main.dart Normal file
View File

@ -0,0 +1,455 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:html_editor_enhanced/html_editor.dart';
import 'package:file_picker/file_picker.dart';
void main() => runApp(HtmlEditorExampleApp());
class HtmlEditorExampleApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(),
darkTheme: ThemeData.dark(),
home: HtmlEditorExample(title: 'Flutter HTML Editor Example'),
);
}
}
class HtmlEditorExample extends StatefulWidget {
HtmlEditorExample({Key? key, required this.title}) : super(key: key);
final String title;
@override
_HtmlEditorExampleState createState() => _HtmlEditorExampleState();
}
class _HtmlEditorExampleState extends State<HtmlEditorExample> {
String result = '';
final HtmlEditorController controller = HtmlEditorController();
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
if (!kIsWeb) {
controller.clearFocus();
}
},
child: Scaffold(
appBar: AppBar(
title: Text(widget.title),
elevation: 0,
actions: [
IconButton(
icon: Icon(Icons.refresh),
onPressed: () {
if (kIsWeb) {
controller.reloadWeb();
} else {
controller.editorController!.reload();
}
})
],
),
floatingActionButton: FloatingActionButton(
onPressed: () {
controller.toggleCodeView();
},
child: Text(r'<\>',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18)),
),
body: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
HtmlEditor(
controller: controller,
htmlEditorOptions: HtmlEditorOptions(
hint: 'Your text here...',
shouldEnsureVisible: true,
//initialText: "<p>text content initial, if any</p>",
),
htmlToolbarOptions: HtmlToolbarOptions(
toolbarPosition: ToolbarPosition.aboveEditor, //by default
toolbarType: ToolbarType.nativeScrollable, //by default
onButtonPressed:
(ButtonType type, bool? status, Function? updateStatus) {
print(
"button '${describeEnum(type)}' pressed, the current selected status is $status");
return true;
},
onDropdownChanged: (DropdownType type, dynamic changed,
Function(dynamic)? updateSelectedItem) {
print(
"dropdown '${describeEnum(type)}' changed to $changed");
return true;
},
mediaLinkInsertInterceptor:
(String url, InsertFileType type) {
print(url);
return true;
},
mediaUploadInterceptor:
(PlatformFile file, InsertFileType type) async {
print(file.name); //filename
print(file.size); //size in bytes
print(file.extension); //file extension (eg jpeg or mp4)
return true;
},
),
otherOptions: OtherOptions(height: 550),
callbacks: Callbacks(onBeforeCommand: (String? currentHtml) {
print('html before change is $currentHtml');
}, onChangeContent: (String? changed) {
print('content changed to $changed');
}, onChangeCodeview: (String? changed) {
print('code changed to $changed');
}, onChangeSelection: (EditorSettings settings) {
print('parent element is ${settings.parentElement}');
print('font name is ${settings.fontName}');
}, onDialogShown: () {
print('dialog shown');
}, onEnter: () {
print('enter/return pressed');
}, onFocus: () {
print('editor focused');
}, onBlur: () {
print('editor unfocused');
}, onBlurCodeview: () {
print('codeview either focused or unfocused');
}, onInit: () {
print('init');
},
//this is commented because it overrides the default Summernote handlers
/*onImageLinkInsert: (String? url) {
print(url ?? "unknown url");
},
onImageUpload: (FileUpload file) async {
print(file.name);
print(file.size);
print(file.type);
print(file.base64);
},*/
onImageUploadError: (FileUpload? file, String? base64Str,
UploadError error) {
print(describeEnum(error));
print(base64Str ?? '');
if (file != null) {
print(file.name);
print(file.size);
print(file.type);
}
}, onKeyDown: (int? keyCode) {
print('$keyCode key downed');
print(
'current character count: ${controller.characterCount}');
}, onKeyUp: (int? keyCode) {
print('$keyCode key released');
}, onMouseDown: () {
print('mouse downed');
}, onMouseUp: () {
print('mouse released');
}, onNavigationRequestMobile: (String url) {
print(url);
return NavigationActionPolicy.ALLOW;
}, onPaste: () {
print('pasted into editor');
}, onScroll: () {
print('editor scrolled');
}),
plugins: [
SummernoteAtMention(
getSuggestionsMobile: (String value) {
var mentions = <String>['test1', 'test2', 'test3'];
return mentions
.where((element) => element.contains(value))
.toList();
},
mentionsWeb: ['test1', 'test2', 'test3'],
onSelect: (String value) {
print(value);
}),
],
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextButton(
style: TextButton.styleFrom(
backgroundColor: Colors.blueGrey),
onPressed: () {
controller.undo();
},
child:
Text('Undo', style: TextStyle(color: Colors.white)),
),
SizedBox(
width: 16,
),
TextButton(
style: TextButton.styleFrom(
backgroundColor: Colors.blueGrey),
onPressed: () {
controller.clear();
},
child:
Text('Reset', style: TextStyle(color: Colors.white)),
),
SizedBox(
width: 16,
),
TextButton(
style: TextButton.styleFrom(
backgroundColor:
Theme.of(context).colorScheme.secondary),
onPressed: () async {
var txt = await controller.getText();
if (txt.contains('src=\"data:')) {
txt =
'<text removed due to base-64 data, displaying the text could cause the app to crash>';
}
setState(() {
result = txt;
});
},
child: Text(
'Submit',
style: TextStyle(color: Colors.white),
),
),
SizedBox(
width: 16,
),
TextButton(
style: TextButton.styleFrom(
backgroundColor:
Theme.of(context).colorScheme.secondary),
onPressed: () {
controller.redo();
},
child: Text(
'Redo',
style: TextStyle(color: Colors.white),
),
),
],
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(result),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextButton(
style: TextButton.styleFrom(
backgroundColor: Colors.blueGrey),
onPressed: () {
controller.disable();
},
child: Text('Disable',
style: TextStyle(color: Colors.white)),
),
SizedBox(
width: 16,
),
TextButton(
style: TextButton.styleFrom(
backgroundColor:
Theme.of(context).colorScheme.secondary),
onPressed: () async {
controller.enable();
},
child: Text(
'Enable',
style: TextStyle(color: Colors.white),
),
),
],
),
),
SizedBox(height: 16),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextButton(
style: TextButton.styleFrom(
backgroundColor:
Theme.of(context).colorScheme.secondary),
onPressed: () {
controller.insertText('Google');
},
child: Text('Insert Text',
style: TextStyle(color: Colors.white)),
),
SizedBox(
width: 16,
),
TextButton(
style: TextButton.styleFrom(
backgroundColor:
Theme.of(context).colorScheme.secondary),
onPressed: () {
controller.insertHtml(
'''<p style="color: blue">Google in blue</p>''');
},
child: Text('Insert HTML',
style: TextStyle(color: Colors.white)),
),
],
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextButton(
style: TextButton.styleFrom(
backgroundColor:
Theme.of(context).colorScheme.secondary),
onPressed: () async {
controller.insertLink(
'Google linked', 'https://google.com', true);
},
child: Text(
'Insert Link',
style: TextStyle(color: Colors.white),
),
),
SizedBox(
width: 16,
),
TextButton(
style: TextButton.styleFrom(
backgroundColor:
Theme.of(context).colorScheme.secondary),
onPressed: () {
controller.insertNetworkImage(
'https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png',
filename: 'Google network image');
},
child: Text(
'Insert network image',
style: TextStyle(color: Colors.white),
),
),
],
),
),
SizedBox(height: 16),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextButton(
style: TextButton.styleFrom(
backgroundColor: Colors.blueGrey),
onPressed: () {
controller.addNotification(
'Info notification', NotificationType.info);
},
child:
Text('Info', style: TextStyle(color: Colors.white)),
),
SizedBox(
width: 16,
),
TextButton(
style: TextButton.styleFrom(
backgroundColor: Colors.blueGrey),
onPressed: () {
controller.addNotification(
'Warning notification', NotificationType.warning);
},
child: Text('Warning',
style: TextStyle(color: Colors.white)),
),
SizedBox(
width: 16,
),
TextButton(
style: TextButton.styleFrom(
backgroundColor:
Theme.of(context).colorScheme.secondary),
onPressed: () async {
controller.addNotification(
'Success notification', NotificationType.success);
},
child: Text(
'Success',
style: TextStyle(color: Colors.white),
),
),
SizedBox(
width: 16,
),
TextButton(
style: TextButton.styleFrom(
backgroundColor:
Theme.of(context).colorScheme.secondary),
onPressed: () {
controller.addNotification(
'Danger notification', NotificationType.danger);
},
child: Text(
'Danger',
style: TextStyle(color: Colors.white),
),
),
],
),
),
SizedBox(height: 16),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextButton(
style: TextButton.styleFrom(
backgroundColor: Colors.blueGrey),
onPressed: () {
controller.addNotification('Plaintext notification',
NotificationType.plaintext);
},
child: Text('Plaintext',
style: TextStyle(color: Colors.white)),
),
SizedBox(
width: 16,
),
TextButton(
style: TextButton.styleFrom(
backgroundColor:
Theme.of(context).colorScheme.secondary),
onPressed: () async {
controller.removeNotification();
},
child: Text(
'Remove',
style: TextStyle(color: Colors.white),
),
),
],
),
),
],
),
),
),
);
}
}

278
example/pubspec.lock Normal file
View File

@ -0,0 +1,278 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
async:
dependency: transitive
description:
name: async
url: "https://pub.dartlang.org"
source: hosted
version: "2.9.0"
boolean_selector:
dependency: transitive
description:
name: boolean_selector
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
characters:
dependency: transitive
description:
name: characters
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.1"
clock:
dependency: transitive
description:
name: clock
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.1"
collection:
dependency: transitive
description:
name: collection
url: "https://pub.dartlang.org"
source: hosted
version: "1.16.0"
cupertino_icons:
dependency: "direct main"
description:
name: cupertino_icons
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.5"
fake_async:
dependency: transitive
description:
name: fake_async
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.1"
ffi:
dependency: transitive
description:
name: ffi
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.1"
file_picker:
dependency: transitive
description:
name: file_picker
url: "https://pub.dartlang.org"
source: hosted
version: "5.2.0+1"
flex_color_picker:
dependency: transitive
description:
name: flex_color_picker
url: "https://pub.dartlang.org"
source: hosted
version: "2.6.1"
flex_seed_scheme:
dependency: transitive
description:
name: flex_seed_scheme
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1"
flutter:
dependency: "direct main"
description: flutter
source: sdk
version: "0.0.0"
flutter_inappwebview:
dependency: transitive
description:
name: flutter_inappwebview
url: "https://pub.dartlang.org"
source: hosted
version: "5.4.4+3"
flutter_keyboard_visibility:
dependency: transitive
description:
name: flutter_keyboard_visibility
url: "https://pub.dartlang.org"
source: hosted
version: "5.3.0"
flutter_keyboard_visibility_platform_interface:
dependency: transitive
description:
name: flutter_keyboard_visibility_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
flutter_keyboard_visibility_web:
dependency: transitive
description:
name: flutter_keyboard_visibility_web
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
flutter_plugin_android_lifecycle:
dependency: transitive
description:
name: flutter_plugin_android_lifecycle
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.7"
flutter_test:
dependency: "direct dev"
description: flutter
source: sdk
version: "0.0.0"
flutter_web_plugins:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
html_editor_enhanced:
dependency: "direct main"
description:
path: ".."
relative: true
source: path
version: "2.5.0"
infinite_listview:
dependency: transitive
description:
name: infinite_listview
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
js:
dependency: transitive
description:
name: js
url: "https://pub.dartlang.org"
source: hosted
version: "0.6.4"
matcher:
dependency: transitive
description:
name: matcher
url: "https://pub.dartlang.org"
source: hosted
version: "0.12.12"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.5"
meta:
dependency: transitive
description:
name: meta
url: "https://pub.dartlang.org"
source: hosted
version: "1.8.0"
numberpicker:
dependency: transitive
description:
name: numberpicker
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.1"
path:
dependency: transitive
description:
name: path
url: "https://pub.dartlang.org"
source: hosted
version: "1.8.2"
pedantic:
dependency: transitive
description:
name: pedantic
url: "https://pub.dartlang.org"
source: hosted
version: "1.11.1"
plugin_platform_interface:
dependency: transitive
description:
name: plugin_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.3"
pointer_interceptor:
dependency: transitive
description:
name: pointer_interceptor
url: "https://pub.dartlang.org"
source: hosted
version: "0.9.3+3"
sky_engine:
dependency: transitive
description: flutter
source: sdk
version: "0.0.99"
source_span:
dependency: transitive
description:
name: source_span
url: "https://pub.dartlang.org"
source: hosted
version: "1.9.0"
stack_trace:
dependency: transitive
description:
name: stack_trace
url: "https://pub.dartlang.org"
source: hosted
version: "1.10.0"
stream_channel:
dependency: transitive
description:
name: stream_channel
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
string_scanner:
dependency: transitive
description:
name: string_scanner
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.1"
term_glyph:
dependency: transitive
description:
name: term_glyph
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.1"
test_api:
dependency: transitive
description:
name: test_api
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.12"
vector_math:
dependency: transitive
description:
name: vector_math
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.2"
visibility_detector:
dependency: transitive
description:
name: visibility_detector
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.3"
win32:
dependency: transitive
description:
name: win32
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.0"
sdks:
dart: ">=2.18.0 <3.0.0"
flutter: ">=3.3.0"

71
example/pubspec.yaml Normal file
View File

@ -0,0 +1,71 @@
name: html_editor_enhanced_example
description: Demonstrates how to use the html_editor_enhanced plugin.
# The following line prevents the package from being accidentally published to
# pub.dev using `pub publish`. This is preferred for private packages.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
environment:
sdk: '>=2.12.0 <3.0.0'
dependencies:
flutter:
sdk: flutter
html_editor_enhanced:
# When depending on this package from a real application you should use:
# html_editor_enhanced: ^x.y.z
# See https://dart.dev/tools/pub/dependencies#version-constraints
# The example app is bundled with the plugin so we use a path dependency on
# the parent directory to use the current plugin's version.
path: ../
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.4
dev_dependencies:
flutter_test:
sdk: flutter
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
# The following section is specific to Flutter.
flutter:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true
# To add assets to your application, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware.
# For details regarding adding assets from package dependencies, see
# https://flutter.dev/assets-and-images/#from-packages
# To add custom fonts to your application, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
# fonts:
# - family: Schyler
# fonts:
# - asset: fonts/Schyler-Regular.ttf
# - asset: fonts/Schyler-Italic.ttf
# style: italic
# - family: Trajan Pro
# fonts:
# - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf
# weight: 700
#
# For details regarding fonts from package dependencies,
# see https://flutter.dev/custom-fonts/#from-packages

BIN
example/web/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 917 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

45
example/web/index.html Normal file
View File

@ -0,0 +1,45 @@
<!DOCTYPE html>
<html>
<head>
<!--
If you are serving your web app in a path other than the root, change the
href value below to reflect the base path you are serving from.
The path provided below has to start and end with a slash "/" in order for
it to work correctly.
Fore more details:
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base
-->
<base href="/">
<meta charset="UTF-8">
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
<meta name="description" content="A new Flutter project.">
<!-- iOS meta tags & icons -->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="apple-mobile-web-app-title" content="example">
<link rel="apple-touch-icon" href="icons/Icon-192.png">
<!-- Favicon -->
<link rel="icon" type="image/png" href="favicon.png"/>
<title>example</title>
<link rel="manifest" href="manifest.json">
</head>
<body>
<!-- This script installs service_worker.js to provide PWA functionality to
application. For more information, see:
https://developers.google.com/web/fundamentals/primers/service-workers -->
<script>
if ('serviceWorker' in navigator) {
window.addEventListener('flutter-first-frame', function () {
navigator.serviceWorker.register('flutter_service_worker.js');
});
}
</script>
<script src="main.dart.js" type="application/javascript"></script>
</body>
</html>

23
example/web/manifest.json Normal file
View File

@ -0,0 +1,23 @@
{
"name": "example",
"short_name": "example",
"start_url": ".",
"display": "standalone",
"background_color": "#0175C2",
"theme_color": "#0175C2",
"description": "A new Flutter project.",
"orientation": "portrait-primary",
"prefer_related_applications": false,
"icons": [
{
"src": "icons/Icon-192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "icons/Icon-512.png",
"sizes": "512x512",
"type": "image/png"
}
]
}

Binary file not shown.

Binary file not shown.

2
lib/assets/jquery.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,403 @@
class SelectionPreserver {
constructor(rootNode) {
if (rootNode === undefined || rootNode === null) {
throw new Error("Please provide a valid rootNode.");
}
this.rootNode = rootNode;
this.rangeStartContainerAddress = null;
this.rangeStartOffset = null;
}
preserve() {
const selection = window.getSelection();
this.rangeStartOffset = selection.getRangeAt(0).startOffset;
this.rangeStartContainerAddress = this.findRangeStartContainerAddress(
selection
);
}
restore(restoreIndex) {
if (
this.rangeStartOffset === null ||
this.rangeStartContainerAddress === null
) {
throw new Error("Please call preserve() first.");
}
let rangeStartContainer = this.findRangeStartContainer();
const range = document.createRange();
const offSet = restoreIndex || this.rangeStartOffset;
range.setStart(rangeStartContainer, offSet);
range.collapse();
const selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
}
findRangeStartContainer() {
let rangeStartContainer = this.rootNode;
this.rangeStartContainerAddress.forEach(address => {
rangeStartContainer = rangeStartContainer.childNodes[address];
});
return rangeStartContainer;
}
findRangeStartContainerAddress(selection) {
let rangeStartContainerAddress = [];
for (
let currentContainer = selection.getRangeAt(0).startContainer;
currentContainer !== this.rootNode;
currentContainer = currentContainer.parentNode
) {
const parent = currentContainer.parentElement;
const children = parent.childNodes;
for (let i = 0; i < children.length; i++) {
if (children[i] === currentContainer) {
rangeStartContainerAddress = [i, ...rangeStartContainerAddress];
break;
}
}
}
return rangeStartContainerAddress;
}
}
const WORD_REGEX = /^[^\s]+$/;
const UP_KEY_CODE = 38;
const DOWN_KEY_CODE = 40;
const ENTER_KEY_CODE = 13;
(function(factory) {
if (typeof define === "function" && define.amd) {
define(["jquery"], factory);
} else if (typeof module === "object" && module.exports) {
module.exports = factory(require("jquery"));
} else {
factory(window.jQuery);
}
})(function($) {
$.extend($.summernote.plugins, {
summernoteAtMention: function(context) {
/************************
* Setup instance vars. *
************************/
this.editableEl = context.layoutInfo.editable[0];
this.editorEl = context.layoutInfo.editor[0];
this.autocompleteAnchor = { left: null, top: null };
this.autocompleteContainer = null;
this.showingAutocomplete = false;
this.selectedIndex = null;
this.suggestions = null;
this.getSuggestions = _ => {
return [];
};
/********************
* Read-in options. *
********************/
if (
context.options &&
context.options.callbacks &&
context.options.callbacks.summernoteAtMention
) {
const summernoteCallbacks =
context.options.callbacks.summernoteAtMention;
if (summernoteCallbacks.getSuggestions) {
this.getSuggestions = summernoteCallbacks.getSuggestions;
}
if (summernoteCallbacks.onSelect) {
this.onSelect = summernoteCallbacks.onSelect;
}
}
/**********
* Events *
**********/
this.events = {
"summernote.blur": () => {
if (this.showingAutocomplete) this.hideAutocomplete();
},
"summernote.keydown": (_, event) => {
if (this.showingAutocomplete) {
switch (event.keyCode) {
case ENTER_KEY_CODE: {
event.preventDefault();
event.stopPropagation();
this.handleEnter();
break;
}
case UP_KEY_CODE: {
event.preventDefault();
event.stopPropagation();
const newIndex =
this.selectedIndex === 0 ? 0 : this.selectedIndex - 1;
this.updateAutocomplete(this.suggestions, newIndex);
break;
}
case DOWN_KEY_CODE: {
event.preventDefault();
event.stopPropagation();
const newIndex =
this.selectedIndex === this.suggestions.length - 1
? this.selectedIndex
: this.selectedIndex + 1;
this.updateAutocomplete(this.suggestions, newIndex);
break;
}
}
}
},
"summernote.keyup": async (_, event) => {
const selection = document.getSelection();
const currentText = selection.anchorNode.nodeValue;
const { word, absoluteIndex } = this.findWordAndIndices(
currentText || "",
selection.anchorOffset
);
const trimmedWord = word.slice(1);
if (
this.showingAutocomplete &&
![DOWN_KEY_CODE, UP_KEY_CODE, ENTER_KEY_CODE].includes(
event.keyCode
)
) {
if (word[0] === "@") {
const suggestions = await this.getSuggestions(trimmedWord);
this.updateAutocomplete(suggestions, this.selectedIndex);
} else {
this.hideAutocomplete();
}
} else if (!this.showingAutocomplete && word[0] === "@") {
this.suggestions = await this.getSuggestions(trimmedWord);
this.selectedIndex = 0;
this.showAutocomplete(absoluteIndex, selection.anchorNode);
}
}
};
/***********
* Helpers *
***********/
this.handleEnter = () => {
this.handleSelection();
};
this.handleClick = suggestion => {
const selectedIndex = this.suggestions.findIndex(s => s === suggestion);
if (selectedIndex === -1) {
throw new Error("Unable to find suggestion in suggestions.");
}
this.selectedIndex = selectedIndex;
this.handleSelection();
};
this.handleSelection = () => {
if (this.suggestions === null || this.suggestions.length === 0) {
return;
}
const newWord = this.suggestions[this.selectedIndex].trimStart();
if (this.onSelect !== undefined) {
this.onSelect(newWord);
}
const selection = document.getSelection();
const currentText = selection.anchorNode.nodeValue;
const { word, absoluteIndex } = this.findWordAndIndices(
currentText || "",
selection.anchorOffset
);
const selectionPreserver = new SelectionPreserver(this.editableEl);
selectionPreserver.preserve();
selection.anchorNode.textContent =
currentText.slice(0, absoluteIndex + 1) +
newWord +
" " +
currentText.slice(absoluteIndex + word.length);
selectionPreserver.restore(absoluteIndex + newWord.length + 1);
if (context.options.callbacks.onChange !== undefined) {
context.options.callbacks.onChange(this.editableEl.innerHTML);
}
};
this.updateAutocomplete = (suggestions, selectedIndex) => {
this.selectedIndex = selectedIndex;
this.suggestions = suggestions;
this.renderAutocomplete();
};
this.showAutocomplete = (atTextIndex, indexAnchor) => {
if (this.showingAutocomplete) {
throw new Error(
"Cannot call showAutocomplete if autocomplete is already showing."
);
}
this.setAutocompleteAnchor(atTextIndex, indexAnchor);
this.renderAutocompleteContainer();
this.renderAutocomplete();
this.showingAutocomplete = true;
};
this.renderAutocompleteContainer = () => {
this.autocompleteContainer = document.createElement("div");
this.autocompleteContainer.style.top =
String(this.autocompleteAnchor.top) + "px";
this.autocompleteContainer.style.left =
String(this.autocompleteAnchor.left) + "px";
this.autocompleteContainer.style.position = "absolute";
this.autocompleteContainer.style.backgroundColor = "#e4e4e4";
this.autocompleteContainer.style.zIndex = Number.MAX_SAFE_INTEGER;
document.body.appendChild(this.autocompleteContainer);
};
this.renderAutocomplete = () => {
if (this.autocompleteContainer === null) {
throw new Error(
"Cannot call renderAutocomplete without an autocompleteContainer. "
);
}
const autocompleteContent = document.createElement("div");
this.suggestions.forEach((suggestion, idx) => {
const suggestionDiv = document.createElement("div");
suggestionDiv.textContent = suggestion;
suggestionDiv.style.padding = "5px 10px";
if (this.selectedIndex === idx) {
suggestionDiv.style.backgroundColor = "#2e6da4";
suggestionDiv.style.color = "white";
}
suggestionDiv.addEventListener("mousedown", () => {
this.handleClick(suggestion);
});
autocompleteContent.appendChild(suggestionDiv);
});
this.autocompleteContainer.innerHTML = "";
this.autocompleteContainer.appendChild(autocompleteContent);
};
this.hideAutocomplete = () => {
if (!this.showingAutocomplete)
throw new Error(
"Cannot call hideAutocomplete if autocomplete is not showing."
);
document.body.removeChild(this.autocompleteContainer);
this.autocompleteAnchor = { left: null, top: null };
this.selectedIndex = null;
this.suggestions = null;
this.showingAutocomplete = false;
};
this.findWordAndIndices = (text, offset) => {
if (offset > text.length) {
return { word: "", relativeIndex: 0 };
} else {
let leftWord = "";
let rightWord = "";
let relativeIndex = 0;
let absoluteIndex = offset;
for (let currentOffset = offset; currentOffset > 0; currentOffset--) {
if (text[currentOffset - 1].match(WORD_REGEX)) {
leftWord = text[currentOffset - 1] + leftWord;
relativeIndex++;
absoluteIndex--;
} else {
break;
}
}
for (
let currentOffset = offset - 1;
currentOffset > 0 && currentOffset < text.length - 1;
currentOffset++
) {
if (text[currentOffset + 1].match(WORD_REGEX)) {
rightWord = rightWord + text[currentOffset + 1];
} else {
break;
}
}
return {
word: leftWord + rightWord,
relativeIndex,
absoluteIndex
};
}
};
this.setAutocompleteAnchor = (atTextIndex, indexAnchor) => {
let html = indexAnchor.parentNode.innerHTML;
const text = indexAnchor.nodeValue;
let atIndex = -1;
for (let i = 0; i <= atTextIndex; i++) {
if (text[i] === "@") {
atIndex++;
}
}
let htmlIndex;
for (let i = 0, htmlAtIndex = 0; i < html.length; i++) {
if (html[i] === "@") {
if (htmlAtIndex === atIndex) {
htmlIndex = i;
break;
} else {
htmlAtIndex++;
}
}
}
const atNodeId = "at-node-" + String(Math.floor(Math.random() * 10000));
const spanString = `<span id="${atNodeId}">@</span>`;
const selectionPreserver = new SelectionPreserver(this.editableEl);
selectionPreserver.preserve();
indexAnchor.parentNode.innerHTML =
html.slice(0, htmlIndex) + spanString + html.slice(htmlIndex + 1);
const anchorElement = document.querySelector("#" + atNodeId);
const anchorBoundingRect = anchorElement.getBoundingClientRect();
this.autocompleteAnchor = {
top: anchorBoundingRect.top + anchorBoundingRect.height + 2,
left: anchorBoundingRect.left
};
selectionPreserver.findRangeStartContainer().parentNode.innerHTML = html;
selectionPreserver.restore();
};
}
});
});

View File

@ -0,0 +1,24 @@
.note-editing-area, .note-status-output, .note-codable, .CodeMirror, .CodeMirror-gutter, .note-modal-content, .note-input, .note-editable {
background: #121212 !important;
}
.panel-heading, .note-toolbar, .note-statusbar {
background: #343434 !important;
}
input, select, textarea, .CodeMirror, .note-editable, [class^="note-icon-"], .caseConverter-toggle,
button > b, button > code, button > var, button > kbd, button > samp, button > small, button > ins, button > del, button > p, button > i {
color: #fff !important;
}
textarea:focus, input:focus, span, label, .note-status-output {
color: #fff !important;
}
.note-icon-font {
color: #000 !important;
}
.note-btn:not(.note-color-btn) {
background-color: #121212 !important;
}
.note-btn:focus,
.note-btn:active,
.note-btn.active {
background-color: #343434 !important;
}

1470
lib/assets/summernote-lite.min.css vendored Normal file

File diff suppressed because it is too large Load Diff

3
lib/assets/summernote-lite.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,32 @@
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<meta name="description" content="Flutter Summernote HTML Editor">
<meta name="author" content="tneotia">
<title>Summernote Text Editor HTML</title>
<script src="jquery.min.js"></script>
<!--summernote js and css-->
<link href="summernote-lite.min.css" rel="stylesheet">
<script src="summernote-lite.min.js"></script>
<!--darkCSS-->
</head>
<body>
<div id="summernote-2"></div>
<!--headString-->
<!--summernoteScripts-->
<!--minor styling to improve editor design-->
<style>
body {
display: block;
margin: 0px;
}
.note-editor.note-airframe, .note-editor.note-frame {
border: 0px solid #a9a9a9;
}
.note-frame {
border-radius: 0px;
}
</style>
</body>
</html>

View File

@ -0,0 +1,31 @@
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<meta name="description" content="Flutter Summernote HTML Editor">
<meta name="author" content="tneotia">
<title>Summernote Text Editor HTML</title>
<script src="jquery.min.js"></script>
<!--summernote js and css-->
<link href="summernote-lite.min.css" rel="stylesheet">
<script src="summernote-lite.min.js"></script>
</head>
<body>
<div id="summernote-2"></div>
<!--summernote at mention plugin-->
<script src="plugins/summernote-at-mention/summernote-at-mention.js"></script>
<!--minor styling to improve editor design-->
<style>
body {
display: block;
margin: 0px;
}
.note-editor.note-airframe, .note-editor.note-frame {
border: 0px solid #a9a9a9;
}
.note-frame {
border-radius: 0px;
}
</style>
</body>
</html>

102
lib/html_editor.dart Normal file
View File

@ -0,0 +1,102 @@
library html_editor;
export 'package:html_editor_enhanced/src/widgets/toolbar_widget.dart';
export 'package:html_editor_enhanced/utils/callbacks.dart';
export 'package:html_editor_enhanced/utils/toolbar.dart';
export 'package:html_editor_enhanced/utils/plugins.dart';
export 'package:html_editor_enhanced/utils/file_upload_model.dart';
export 'package:html_editor_enhanced/utils/options.dart';
export 'package:html_editor_enhanced/utils/utils.dart'
hide setState, intersperse, getRandString;
export 'package:html_editor_enhanced/src/html_editor_unsupported.dart'
if (dart.library.html) 'package:html_editor_enhanced/src/html_editor_web.dart'
if (dart.library.io) 'package:html_editor_enhanced/src/html_editor_mobile.dart';
export 'package:html_editor_enhanced/src/html_editor_controller_unsupported.dart'
if (dart.library.html) 'package:html_editor_enhanced/src/html_editor_controller_web.dart'
if (dart.library.io) 'package:html_editor_enhanced/src/html_editor_controller_mobile.dart';
export 'package:html_editor_enhanced/utils/shims/flutter_inappwebview_fake.dart'
if (dart.library.io) 'package:flutter_inappwebview/flutter_inappwebview.dart';
/// Defines the 3 different cases for file insertion failing
enum UploadError { unsupportedFile, exceededMaxSize, jsException }
/// Manages the notification type for a notification displayed at the bottom of
/// the editor
enum NotificationType { info, warning, success, danger, plaintext }
/// Manages the way the toolbar displays:
/// [nativeGrid] - a grid view (non scrollable) of all the buttons
/// [nativeScrollable] - a scrollable one-line view of all the buttons
/// [nativeExpandable] - has an icon to switch between grid and scrollable formats
/// on the fly
/// [summernote] - uses the default summernote buttons (no native controls and
/// reduced feature support) //todo
enum ToolbarType { nativeGrid, nativeScrollable, nativeExpandable }
/// Manages the position of the toolbar, whether above or below the editor
/// [custom] - removes the toolbar. This is useful when you want to implement the
/// toolbar in a custom location using [ToolbarWidget]
///
/// Note: This is ignored when [ToolbarType.summernote] is set.
enum ToolbarPosition { aboveEditor, belowEditor, custom }
/// Returns the type of button pressed in the `onButtonPressed` function
enum ButtonType {
style,
bold,
italic,
underline,
clearFormatting,
strikethrough,
superscript,
subscript,
foregroundColor,
highlightColor,
ul,
ol,
alignLeft,
alignCenter,
alignRight,
alignJustify,
increaseIndent,
decreaseIndent,
ltr,
rtl,
link,
picture,
audio,
video,
otherFile,
table,
hr,
fullscreen,
codeview,
undo,
redo,
help,
copy,
paste
}
/// Returns the type of dropdown changed in the `onDropdownChanged` function
enum DropdownType {
style,
fontName,
fontSize,
fontSizeUnit,
listStyles,
lineHeight,
caseConverter
}
/// Sets the direction the dropdown menu opens
enum DropdownMenuDirection { down, up }
/// Returns the type of file inserted in `onLinkInsertInt
enum InsertFileType { image, audio, video }
/// Sets how the virtual keyboard appears on mobile devices
enum HtmlInputType { decimal, email, numeric, tel, url, text }

View File

@ -0,0 +1,291 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:html_editor_enhanced/html_editor.dart';
import 'package:html_editor_enhanced/src/html_editor_controller_unsupported.dart'
as unsupported;
/// Controller for mobile
class HtmlEditorController extends unsupported.HtmlEditorController {
HtmlEditorController({
this.processInputHtml = true,
this.processNewLineAsBr = false,
this.processOutputHtml = true,
});
/// Toolbar widget state to call various methods. For internal use only.
@override
ToolbarWidgetState? toolbar;
/// Determines whether text processing should happen on input HTML, e.g.
/// whether a new line should be converted to a <br>.
///
/// The default value is false.
@override
final bool processInputHtml;
/// Determines whether newlines (\n) should be written as <br>. This is not
/// recommended for HTML documents.
///
/// The default value is false.
@override
final bool processNewLineAsBr;
/// Determines whether text processing should happen on output HTML, e.g.
/// whether <p><br></p> is returned as "". For reference, Summernote uses
/// that HTML as the default HTML (when no text is in the editor).
///
/// The default value is true.
@override
final bool processOutputHtml;
/// Manages the [InAppWebViewController] for the [HtmlEditorController]
InAppWebViewController? _editorController;
/// Allows the [InAppWebViewController] for the Html editor to be accessed
/// outside of the package itself for endless control and customization.
@override
// ignore: unnecessary_getters_setters
InAppWebViewController? get editorController => _editorController;
/// Internal method to set the [InAppWebViewController] when webview initialization
/// is complete
@override
// ignore: unnecessary_getters_setters
set editorController(dynamic controller) =>
_editorController = controller as InAppWebViewController?;
/// A function to quickly call a document.execCommand function in a readable format
@override
void execCommand(String command, {String? argument}) {
_evaluateJavascript(
source:
"document.execCommand('$command', false${argument == null ? "" : ", '$argument'"});");
}
/// Gets the text from the editor and returns it as a [String].
@override
Future<String> getText() async {
var text = await _evaluateJavascript(
source: "\$('#summernote-2').summernote('code');") as String?;
if (processOutputHtml &&
(text == null ||
text.isEmpty ||
text == '<p></p>' ||
text == '<p><br></p>' ||
text == '<p><br/></p>')) text = '';
return text ?? '';
}
/// Sets the text of the editor. Some pre-processing is applied to convert
/// [String] elements like "\n" to HTML elements.
@override
void setText(String text) {
text = _processHtml(html: text);
_evaluateJavascript(
source: "\$('#summernote-2').summernote('code', '$text');");
}
/// Sets the editor to full-screen mode.
@override
void setFullScreen() {
_evaluateJavascript(
source: '\$("#summernote-2").summernote("fullscreen.toggle");');
}
/// Sets the focus to the editor.
@override
void setFocus() {
_evaluateJavascript(source: "\$('#summernote-2').summernote('focus');");
}
/// Clears the editor of any text.
@override
void clear() {
_evaluateJavascript(source: "\$('#summernote-2').summernote('reset');");
}
/// Sets the hint for the editor.
@override
void setHint(String text) {
text = _processHtml(html: text);
var hint = '\$(".note-placeholder").html("$text");';
_evaluateJavascript(source: hint);
}
/// toggles the codeview in the Html editor
@override
void toggleCodeView() {
_evaluateJavascript(
source: "\$('#summernote-2').summernote('codeview.toggle');");
}
/// disables the Html editor
@override
void disable() {
toolbar!.disable();
_evaluateJavascript(source: "\$('#summernote-2').summernote('disable');");
}
/// enables the Html editor
@override
void enable() {
toolbar!.enable();
_evaluateJavascript(source: "\$('#summernote-2').summernote('enable');");
}
/// Undoes the last action
@override
void undo() {
_evaluateJavascript(source: "\$('#summernote-2').summernote('undo');");
}
/// Redoes the last action
@override
void redo() {
_evaluateJavascript(source: "\$('#summernote-2').summernote('redo');");
}
/// Insert text at the end of the current HTML content in the editor
/// Note: This method should only be used for plaintext strings
@override
void insertText(String text) {
_evaluateJavascript(
source: "\$('#summernote-2').summernote('insertText', '$text');");
}
/// Insert HTML at the position of the cursor in the editor
/// Note: This method should not be used for plaintext strings
@override
void insertHtml(String html) {
html = _processHtml(html: html);
_evaluateJavascript(
source: "\$('#summernote-2').summernote('pasteHTML', '$html');");
}
/// Insert a network image at the position of the cursor in the editor
@override
void insertNetworkImage(String url, {String filename = ''}) {
_evaluateJavascript(
source:
"\$('#summernote-2').summernote('insertImage', '$url', '$filename');");
}
/// Insert a link at the position of the cursor in the editor
@override
void insertLink(String text, String url, bool isNewWindow) {
_evaluateJavascript(source: """
\$('#summernote-2').summernote('createLink', {
text: "$text",
url: '$url',
isNewWindow: $isNewWindow
});
""");
}
/// Clears the focus from the webview by hiding the keyboard, calling the
/// clearFocus method on the [InAppWebViewController], and resetting the height
/// in case it was changed.
@override
void clearFocus() {
SystemChannels.textInput.invokeMethod('TextInput.hide');
}
/// Reloads the IFrameElement, throws an exception on mobile
@override
void reloadWeb() {
throw Exception(
'Non-Flutter Web environment detected, please make sure you are importing package:html_editor_enhanced/html_editor.dart and check kIsWeb before calling this function');
}
/// Resets the height of the editor back to the original if it was changed to
/// accommodate the keyboard. This should only be used on mobile, and only
/// when [adjustHeightForKeyboard] is enabled.
@override
void resetHeight() {
_evaluateJavascript(
source:
"window.flutter_inappwebview.callHandler('setHeight', 'reset');");
}
/// Recalculates the height of the editor to remove any vertical scrolling.
/// This method will not do anything if [autoAdjustHeight] is turned off.
@override
void recalculateHeight() {
_evaluateJavascript(
source:
"var height = document.body.scrollHeight; window.flutter_inappwebview.callHandler('setHeight', height);");
}
/// Add a notification to the bottom of the editor. This is styled similar to
/// Bootstrap alerts. You can set the HTML to be displayed in the alert,
/// and the notificationType determines how the alert is displayed.
@override
void addNotification(String html, NotificationType notificationType) async {
await _evaluateJavascript(source: """
\$('.note-status-output').html(
'<div class="alert alert-${describeEnum(notificationType)}">$html</div>'
);
""");
recalculateHeight();
}
/// Remove the current notification from the bottom of the editor
@override
void removeNotification() async {
await _evaluateJavascript(source: "\$('.note-status-output').empty();");
recalculateHeight();
}
/// Helper function to process input html
String _processHtml({required html}) {
if (processInputHtml) {
html = html
.replaceAll("'", r"\'")
.replaceAll('"', r'\"')
.replaceAll('\r', '')
.replaceAll('\r\n', '');
}
if (processNewLineAsBr) {
html = html.replaceAll('\n', '<br/>').replaceAll('\n\n', '<br/>');
} else {
html = html.replaceAll('\n', '').replaceAll('\n\n', '');
}
return html;
}
/// Helper function to evaluate JS and check the current environment
dynamic _evaluateJavascript({required source}) async {
if (!kIsWeb) {
if (editorController == null || await editorController!.isLoading()) {
throw Exception(
'HTML editor is still loading, please wait before evaluating this JS: $source!');
}
var result = await editorController!.evaluateJavascript(source: source);
return result;
} else {
throw Exception(
'Flutter Web environment detected, please make sure you are importing package:html_editor_enhanced/html_editor.dart');
}
}
/// Internal function to change list style on Web
@override
void changeListStyle(String changed) {}
/// Internal function to change line height on Web
@override
void changeLineHeight(String changed) {}
/// Internal function to change text direction on Web
@override
void changeTextDirection(String changed) {}
/// Internal function to change case on Web
@override
void changeCase(String changed) {}
/// Internal function to insert table on Web
@override
void insertTable(String dimensions) {}
}

View File

@ -0,0 +1,174 @@
import 'package:html_editor_enhanced/html_editor.dart';
import 'package:meta/meta.dart';
/// Fallback controller (should never be used)
class HtmlEditorController {
HtmlEditorController({
this.processInputHtml = true,
this.processNewLineAsBr = false,
this.processOutputHtml = true,
});
/// Toolbar widget state to call various methods. For internal use only.
@internal
ToolbarWidgetState? toolbar;
/// Determines whether text processing should happen on input HTML, e.g.
/// whether a new line should be converted to a <br>.
///
/// The default value is true.
final bool processInputHtml;
/// Determines whether newlines (\n) should be written as <br>. This is not
/// recommended for HTML documents.
///
/// The default value is false.
final bool processNewLineAsBr;
/// Determines whether text processing should happen on output HTML, e.g.
/// whether <p><br></p> is returned as "". For reference, Summernote uses
/// that HTML as the default HTML (when no text is in the editor).
///
/// The default value is true.
final bool processOutputHtml;
/// Internally tracks the character count in the editor
int _characterCount = 0;
/// Gets the current character count
// ignore: unnecessary_getters_setters
int get characterCount => _characterCount;
/// Sets the current character count. Marked as internal method - this should
/// not be used outside of the package itself.
// ignore: unnecessary_getters_setters
@internal
set characterCount(int count) => _characterCount = count;
/// Allows the [InAppWebViewController] for the Html editor to be accessed
/// outside of the package itself for endless control and customization.
dynamic get editorController => null;
/// Internal method to set the [InAppWebViewController] when webview initialization
/// is complete
@internal
set editorController(dynamic controller) => {};
/// Internal method to set the view ID when iframe initialization
/// is complete
@internal
set viewId(String? viewId) => {};
/// Add a notification to the bottom of the editor. This is styled similar to
/// Bootstrap alerts. You can set the HTML to be displayed in the alert,
/// and the notificationType determines how the alert is displayed.
void addNotification(String html, NotificationType notificationType) {}
/// Clears the editor of any text.
void clear() {}
/// Clears the focus from the webview by hiding the keyboard, calling the
/// clearFocus method on the [InAppWebViewController], and resetting the height
/// in case it was changed.
void clearFocus() {}
/// disables the Html editor
void disable() {}
/// enables the Html editor
void enable() {}
/// A function to quickly call a document.execCommand function in a readable format
void execCommand(String command, {String? argument}) {}
/// A function to execute JS passed as a [WebScript] to the editor. This should
/// only be used on Flutter Web.
Future<dynamic> evaluateJavascriptWeb(String name,
{bool hasReturnValue = false}) =>
Future.value();
/// Gets the text from the editor and returns it as a [String].
Future<String> getText() => Future.value('');
/// Gets the selected HTML from the editor. You should use
/// [controller.editorController.getSelectedText()] on mobile.
///
/// [withHtmlTags] may not work properly when the selected text is entirely
/// within one HTML tag. However if the selected text spans multiple different
/// tags, it should work as expected.
Future<String> getSelectedTextWeb({bool withHtmlTags = false}) =>
Future.value('');
/// Insert HTML at the position of the cursor in the editor
/// Note: This method should not be used for plaintext strings
void insertHtml(String html) {}
/// Insert a link at the position of the cursor in the editor
void insertLink(String text, String url, bool isNewWindow) {}
/// Insert a network image at the position of the cursor in the editor
void insertNetworkImage(String url, {String filename = ''}) {}
/// Insert text at the end of the current HTML content in the editor
/// Note: This method should only be used for plaintext strings
void insertText(String text) {}
/// Recalculates the height of the editor to remove any vertical scrolling.
/// This method will not do anything if [autoAdjustHeight] is turned off.
void recalculateHeight() {}
/// Redoes the last action
void redo() {}
/// Refresh the page
///
/// Note: This should only be used in Flutter Web!!!
void reloadWeb() {}
/// Remove the current notification from the bottom of the editor
void removeNotification() {}
/// Resets the height of the editor back to the original if it was changed to
/// accommodate the keyboard. This should only be used on mobile, and only
/// when [adjustHeightForKeyboard] is enabled.
void resetHeight() {}
/// Sets the hint for the editor.
void setHint(String text) {}
/// Sets the focus to the editor.
void setFocus() {}
/// Sets the editor to full-screen mode.
void setFullScreen() {}
/// Sets the text of the editor. Some pre-processing is applied to convert
/// [String] elements like "\n" to HTML elements.
void setText(String text) {}
/// toggles the codeview in the Html editor
void toggleCodeView() {}
/// Undoes the last action
void undo() {}
/// Internal function to change list style on Web
@internal
void changeListStyle(String changed) {}
/// Internal function to change line height on Web
@internal
void changeLineHeight(String changed) {}
/// Internal function to change text direction on Web
@internal
void changeTextDirection(String changed) {}
/// Internal function to change case on Web
@internal
void changeCase(String changed) {}
/// Internal function to insert table on Web
@internal
void insertTable(String dimensions) {}
}

View File

@ -0,0 +1,329 @@
import 'dart:convert';
// ignore: avoid_web_libraries_in_flutter
import 'dart:html' as html;
import 'package:flutter/foundation.dart';
import 'package:html_editor_enhanced/html_editor.dart';
import 'package:html_editor_enhanced/src/html_editor_controller_unsupported.dart'
as unsupported;
import 'package:meta/meta.dart';
/// Controller for web
class HtmlEditorController extends unsupported.HtmlEditorController {
HtmlEditorController({
this.processInputHtml = true,
this.processNewLineAsBr = false,
this.processOutputHtml = true,
});
/// Toolbar widget state to call various methods. For internal use only.
@override
ToolbarWidgetState? toolbar;
/// Determines whether text processing should happen on input HTML, e.g.
/// whether a new line should be converted to a <br>.
///
/// The default value is true.
@override
final bool processInputHtml;
/// Determines whether newlines (\n) should be written as <br>. This is not
/// recommended for HTML documents.
///
/// The default value is false.
@override
final bool processNewLineAsBr;
/// Determines whether text processing should happen on output HTML, e.g.
/// whether <p><br></p> is returned as "". For reference, Summernote uses
/// that HTML as the default HTML (when no text is in the editor).
///
/// The default value is true.
@override
final bool processOutputHtml;
/// Manages the view ID for the [HtmlEditorController] on web
String? _viewId;
/// Internal method to set the view ID when iframe initialization
/// is complete
@override
@internal
set viewId(String? viewId) => _viewId = viewId;
/// Gets the text from the editor and returns it as a [String].
@override
Future<String> getText() async {
_evaluateJavascriptWeb(data: {'type': 'toIframe: getText'});
var e = await html.window.onMessage.firstWhere(
(element) => json.decode(element.data)['type'] == 'toDart: getText');
String text = json.decode(e.data)['text'];
if (processOutputHtml &&
(text.isEmpty ||
text == '<p></p>' ||
text == '<p><br></p>' ||
text == '<p><br/></p>')) text = '';
return text;
}
@override
Future<String> getSelectedTextWeb({bool withHtmlTags = false}) async {
if (withHtmlTags) {
_evaluateJavascriptWeb(data: {'type': 'toIframe: getSelectedTextHtml'});
} else {
_evaluateJavascriptWeb(data: {'type': 'toIframe: getSelectedText'});
}
var e = await html.window.onMessage.firstWhere((element) =>
json.decode(element.data)['type'] == 'toDart: getSelectedText');
return json.decode(e.data)['text'];
}
/// Sets the text of the editor. Some pre-processing is applied to convert
/// [String] elements like "\n" to HTML elements.
@override
void setText(String text) {
text = _processHtml(html: text);
_evaluateJavascriptWeb(data: {'type': 'toIframe: setText', 'text': text});
}
/// Sets the editor to full-screen mode.
@override
void setFullScreen() {
_evaluateJavascriptWeb(data: {'type': 'toIframe: setFullScreen'});
}
/// Sets the focus to the editor.
@override
void setFocus() {
_evaluateJavascriptWeb(data: {'type': 'toIframe: setFocus'});
}
/// Clears the editor of any text.
@override
void clear() {
_evaluateJavascriptWeb(data: {'type': 'toIframe: clear'});
}
/// Sets the hint for the editor.
@override
void setHint(String text) {
text = _processHtml(html: text);
_evaluateJavascriptWeb(data: {'type': 'toIframe: setHint', 'text': text});
}
/// toggles the codeview in the Html editor
@override
void toggleCodeView() {
_evaluateJavascriptWeb(data: {'type': 'toIframe: toggleCodeview'});
}
/// disables the Html editor
@override
void disable() {
toolbar!.disable();
_evaluateJavascriptWeb(data: {'type': 'toIframe: disable'});
}
/// enables the Html editor
@override
void enable() {
toolbar!.enable();
_evaluateJavascriptWeb(data: {'type': 'toIframe: enable'});
}
/// Undoes the last action
@override
void undo() {
_evaluateJavascriptWeb(data: {'type': 'toIframe: undo'});
}
/// Redoes the last action
@override
void redo() {
_evaluateJavascriptWeb(data: {'type': 'toIframe: redo'});
}
/// Insert text at the end of the current HTML content in the editor
/// Note: This method should only be used for plaintext strings
@override
void insertText(String text) {
_evaluateJavascriptWeb(
data: {'type': 'toIframe: insertText', 'text': text});
}
/// Insert HTML at the position of the cursor in the editor
/// Note: This method should not be used for plaintext strings
@override
void insertHtml(String html) {
html = _processHtml(html: html);
_evaluateJavascriptWeb(
data: {'type': 'toIframe: insertHtml', 'html': html});
}
/// Insert a network image at the position of the cursor in the editor
@override
void insertNetworkImage(String url, {String filename = ''}) {
_evaluateJavascriptWeb(data: {
'type': 'toIframe: insertNetworkImage',
'url': url,
'filename': filename
});
}
/// Insert a link at the position of the cursor in the editor
@override
void insertLink(String text, String url, bool isNewWindow) {
_evaluateJavascriptWeb(data: {
'type': 'toIframe: insertLink',
'text': text,
'url': url,
'isNewWindow': isNewWindow
});
}
/// Clears the focus from the webview by hiding the keyboard, calling the
/// clearFocus method on the [InAppWebViewController], and resetting the height
/// in case it was changed.
@override
void clearFocus() {
throw Exception(
'Flutter Web environment detected, please make sure you are importing package:html_editor_enhanced/html_editor.dart and check kIsWeb before calling this method.');
}
/// Resets the height of the editor back to the original if it was changed to
/// accommodate the keyboard. This should only be used on mobile, and only
/// when [adjustHeightForKeyboard] is enabled.
@override
void resetHeight() {
throw Exception(
'Flutter Web environment detected, please make sure you are importing package:html_editor_enhanced/html_editor.dart and check kIsWeb before calling this method.');
}
/// Refresh the page
///
/// Note: This should only be used in Flutter Web!!!
@override
void reloadWeb() {
_evaluateJavascriptWeb(data: {'type': 'toIframe: reload'});
}
/// Recalculates the height of the editor to remove any vertical scrolling.
/// This method will not do anything if [autoAdjustHeight] is turned off.
@override
void recalculateHeight() {
_evaluateJavascriptWeb(data: {
'type': 'toIframe: getHeight',
});
}
/// A function to quickly call a document.execCommand function in a readable format
@override
void execCommand(String command, {String? argument}) {
_evaluateJavascriptWeb(data: {
'type': 'toIframe: execCommand',
'command': command,
'argument': argument
});
}
/// A function to execute JS passed as a [WebScript] to the editor. This should
/// only be used on Flutter Web.
@override
Future<dynamic> evaluateJavascriptWeb(String name,
{bool hasReturnValue = false}) async {
_evaluateJavascriptWeb(data: {'type': 'toIframe: $name'});
if (hasReturnValue) {
var e = await html.window.onMessage.firstWhere(
(element) => json.decode(element.data)['type'] == 'toDart: $name');
return json.decode(e.data);
}
}
/// Internal function to change list style on Web
@override
void changeListStyle(String changed) {
_evaluateJavascriptWeb(
data: {'type': 'toIframe: changeListStyle', 'changed': changed});
}
/// Internal function to change line height on Web
@override
void changeLineHeight(String changed) {
_evaluateJavascriptWeb(
data: {'type': 'toIframe: changeLineHeight', 'changed': changed});
}
/// Internal function to change text direction on Web
@override
void changeTextDirection(String direction) {
_evaluateJavascriptWeb(data: {
'type': 'toIframe: changeTextDirection',
'direction': direction
});
}
/// Internal function to change case on Web
@override
void changeCase(String changed) {
_evaluateJavascriptWeb(
data: {'type': 'toIframe: changeCase', 'case': changed});
}
/// Internal function to insert table on Web
@override
void insertTable(String dimensions) {
_evaluateJavascriptWeb(
data: {'type': 'toIframe: insertTable', 'dimensions': dimensions});
}
/// Add a notification to the bottom of the editor. This is styled similar to
/// Bootstrap alerts. You can set the HTML to be displayed in the alert,
/// and the notificationType determines how the alert is displayed.
@override
void addNotification(String html, NotificationType notificationType) {
if (notificationType == NotificationType.plaintext) {
_evaluateJavascriptWeb(
data: {'type': 'toIframe: addNotification', 'html': html});
} else {
_evaluateJavascriptWeb(data: {
'type': 'toIframe: addNotification',
'html': html,
'alertType': 'alert alert-${describeEnum(notificationType)}'
});
}
recalculateHeight();
}
/// Remove the current notification from the bottom of the editor
@override
void removeNotification() {
_evaluateJavascriptWeb(data: {'type': 'toIframe: removeNotification'});
recalculateHeight();
}
/// Helper function to process input html
String _processHtml({required html}) {
if (processInputHtml) {
html = html.replaceAll('\r', '').replaceAll('\r\n', '');
}
if (processNewLineAsBr) {
html = html.replaceAll('\n', '<br/>').replaceAll('\n\n', '<br/>');
} else {
html = html.replaceAll('\n', '').replaceAll('\n\n', '');
}
return html;
}
/// Helper function to run javascript and check current environment
void _evaluateJavascriptWeb({required Map<String, Object?> data}) async {
if (kIsWeb) {
data['view'] = _viewId;
final jsonEncoder = JsonEncoder();
var json = jsonEncoder.convert(data);
html.window.postMessage(json, '*');
} else {
throw Exception(
'Non-Flutter Web environment detected, please make sure you are importing package:html_editor_enhanced/html_editor.dart');
}
}
}

View File

@ -0,0 +1,57 @@
import 'package:html_editor_enhanced/html_editor.dart'
hide HtmlEditorController;
import 'package:html_editor_enhanced/src/html_editor_controller_mobile.dart';
import 'package:html_editor_enhanced/src/widgets/html_editor_widget_mobile.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
/// HtmlEditor class for mobile
class HtmlEditor extends StatelessWidget {
HtmlEditor({
Key? key,
required this.controller,
this.callbacks,
this.htmlEditorOptions = const HtmlEditorOptions(),
this.htmlToolbarOptions = const HtmlToolbarOptions(),
this.otherOptions = const OtherOptions(),
this.plugins = const [],
}) : super(key: key);
/// The controller that is passed to the widget, which allows multiple [HtmlEditor]
/// widgets to be used on the same page independently.
final HtmlEditorController controller;
/// Sets & activates Summernote's callbacks. See the functions available in
/// [Callbacks] for more details.
final Callbacks? callbacks;
/// Defines options for the html editor
final HtmlEditorOptions htmlEditorOptions;
/// Defines options for the editor toolbar
final HtmlToolbarOptions htmlToolbarOptions;
/// Defines other options
final OtherOptions otherOptions;
/// Sets the list of Summernote plugins enabled in the editor.
final List<Plugins> plugins;
@override
Widget build(BuildContext context) {
if (!kIsWeb) {
return HtmlEditorWidget(
key: key,
controller: controller,
callbacks: callbacks,
plugins: plugins,
htmlEditorOptions: htmlEditorOptions,
htmlToolbarOptions: htmlToolbarOptions,
otherOptions: otherOptions,
);
} else {
return Text(
'Flutter Web environment detected, please make sure you are importing package:html_editor_enhanced/html_editor.dart');
}
}
}

Some files were not shown because too many files have changed in this diff Show More