|
|
|
import 'dart:async';
|
|
|
|
import 'dart:convert';
|
|
|
|
import 'dart:io';
|
|
|
|
|
|
|
|
import 'package:flutter/foundation.dart';
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
import 'package:flutter/services.dart';
|
Merge master into dev (#258)
* Update issue templates
* Updating checkbox to handle tap (#186)
* updating checkbox to handle tap
* updating checkbox to handle long press and using UniqueKey() to avoid weird side effects
* removed useless doc
Co-authored-by: Kevin Despoulains <kevin.despoulains@scriptandgo.com>
* Simple viewer (#187)
* 2021-04-25
* 2021-04-26
* Fix simple viewer compilation error
* Upgrade version - checkbox supports tapping
* 171: support for non-scrollable text editor (#188)
Co-authored-by: Gyuri Majercsik <gyuri@fluttech.com>
* custom rules & optionally auto add newline for image embeds (#205)
* Adding missing overrides to make package work with Flutter 2.2.0 (#226)
* Improve SOC of raw editor (#227)
Improve separation of concerns for RawEditor by moving the code
for the text input client to a separate class, furthermore add
more comments.
* Upgrade version
* Improve SOC of raw editor (#228)
Improve separation of concerns for `RawEditor` by moving the code
for the keyboard to a separate class, furthermore add more comments.
The PR does not change the functionality of the code.
* Improve further SOC of raw editor
This improves separation of concerns for the RawEditor by moving
the code for the text selection delegate to a separate class,
furthermore add more comments.
The PR does not change the functionality of the code.
* Hide implementation files (#233)
* Fixes for flutter web (#234)
* Fix for Attribute object comparison
* Fix for "Unexpected null value" error on web
Clipboard is now supported on web, via a permission request through the browser
Co-authored-by: George Johnson <george@indiespring.com>
* Dispose ValueNotifier of cursor controller
* Remove getter for final operator
A getter for a final variable makes no sense, because the variable
cannot be reassigned. It is better to remove the unnecessary getter
and make the variable public.
* Add comments to cursor class
* Remove null exception when a disposed controller is set
* Disallow lines longer than 80 characters
* Don't create a lambda when a tear-off will do
* Move ResponsiveWidgets to example folder
This widget has nothing to do with the library and is only used in
the example, so it is moved to the example.
* Fix null exception
* Remove exception when widget is not mounted
* Fix exception when rect is not a number
* Fix paste (#236)
closes #235.
* Fix exception
* Add const types for image and divider embeds
This allows to reference the type.
* Fix relative path
* Add new logo
* Fix buttons which ignore toolbariconsize
Closes #189.
* Upgrade to 1.3.1
* Fix incorrect double to int cast, and guard against optional parent (#239)
* use ceil instead of floor to make sure won't cause overflow
* Fix example project Podfile (#241)
* Show arrow indicator on toolbar (#245)
* Add color parameter to Toolbar and ImageButton
In addition, change these widgets to stateless widgets, since these
widgets do not have a state and thus stateful is superfluous.
* Fix paste bug
* Remove extraneous toolbar dividers in certain configuration
Closes #193.
* Upgrade version to 1.3.2
* Format code
* Bump file_picker to 3.0.2+2
With version 3.0.2 `name` of the file_picker library becomes
non-nullable, so a warning was issued for users who had already
used version 3.0.2, as we still assumed that `name` is nullable.
Increasing the version and removing the exclamation mark removes
the warning.
* Fix a bug that Embed could be together with Text (#249)
* Fix #242 (#254)
* Upgrade to 1.3.3
* Format code
* bugfix:The return type 'bool' isn't a 'KeyEventResult'
Co-authored-by: Xin Yao <singerdmx@gmail.com>
Co-authored-by: kevinDespoulains <46108869+kevinDespoulains@users.noreply.github.com>
Co-authored-by: Kevin Despoulains <kevin.despoulains@scriptandgo.com>
Co-authored-by: em6m6e <50019687+em6m6e@users.noreply.github.com>
Co-authored-by: Gyuri Majercsik <majercsik.gyuri@gmail.com>
Co-authored-by: Gyuri Majercsik <gyuri@fluttech.com>
Co-authored-by: hyouuu <hyouuu@gmail.com>
Co-authored-by: Till Friebe <friebetill@gmail.com>
Co-authored-by: George <george.a.johnson@btopenworld.com>
Co-authored-by: George Johnson <george@indiespring.com>
Co-authored-by: Ben Chung <1330575+yzxben@users.noreply.github.com>
Co-authored-by: lucasbstn <64323294+lucasbstn@users.noreply.github.com>
4 years ago
|
|
|
import 'package:flutter_quill/flutter_quill.dart' hide Text;
|
|
|
|
import 'package:path/path.dart';
|
|
|
|
import 'package:path_provider/path_provider.dart';
|
|
|
|
import 'package:tuple/tuple.dart';
|
|
|
|
|
|
|
|
import '../universal_ui/universal_ui.dart';
|
|
|
|
import 'read_only_page.dart';
|
|
|
|
|
|
|
|
class HomePage extends StatefulWidget {
|
|
|
|
@override
|
|
|
|
_HomePageState createState() => _HomePageState();
|
|
|
|
}
|
|
|
|
|
|
|
|
class _HomePageState extends State<HomePage> {
|
|
|
|
QuillController? _controller;
|
|
|
|
final FocusNode _focusNode = FocusNode();
|
|
|
|
|
|
|
|
@override
|
|
|
|
void initState() {
|
|
|
|
super.initState();
|
|
|
|
_loadFromAssets();
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> _loadFromAssets() async {
|
|
|
|
try {
|
|
|
|
final result = await rootBundle.loadString('assets/sample_data.json');
|
|
|
|
final doc = Document.fromJson(jsonDecode(result));
|
|
|
|
setState(() {
|
|
|
|
_controller = QuillController(
|
|
|
|
document: doc, selection: const TextSelection.collapsed(offset: 0));
|
|
|
|
});
|
|
|
|
} catch (error) {
|
|
|
|
final doc = Document()..insert(0, 'Empty asset');
|
|
|
|
setState(() {
|
|
|
|
_controller = QuillController(
|
|
|
|
document: doc, selection: const TextSelection.collapsed(offset: 0));
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
if (_controller == null) {
|
|
|
|
return const Scaffold(body: Center(child: Text('Loading...')));
|
|
|
|
}
|
|
|
|
|
|
|
|
return Scaffold(
|
|
|
|
appBar: AppBar(
|
|
|
|
backgroundColor: Colors.grey.shade800,
|
|
|
|
elevation: 0,
|
|
|
|
centerTitle: false,
|
|
|
|
title: const Text(
|
|
|
|
'Flutter Quill',
|
|
|
|
),
|
|
|
|
actions: [],
|
|
|
|
),
|
|
|
|
drawer: Container(
|
|
|
|
constraints:
|
|
|
|
BoxConstraints(maxWidth: MediaQuery.of(context).size.width * 0.7),
|
|
|
|
color: Colors.grey.shade800,
|
|
|
|
child: _buildMenuBar(context),
|
|
|
|
),
|
|
|
|
body: RawKeyboardListener(
|
|
|
|
focusNode: FocusNode(),
|
|
|
|
onKey: (event) {
|
|
|
|
if (event.data.isControlPressed && event.character == 'b') {
|
|
|
|
if (_controller!
|
|
|
|
.getSelectionStyle()
|
|
|
|
.attributes
|
|
|
|
.keys
|
|
|
|
.contains('bold')) {
|
|
|
|
_controller!
|
|
|
|
.formatSelection(Attribute.clone(Attribute.bold, null));
|
|
|
|
} else {
|
|
|
|
_controller!.formatSelection(Attribute.bold);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
child: _buildWelcomeEditor(context),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Widget _buildWelcomeEditor(BuildContext context) {
|
|
|
|
var quillEditor = QuillEditor(
|
|
|
|
controller: _controller!,
|
|
|
|
scrollController: ScrollController(),
|
|
|
|
scrollable: true,
|
|
|
|
focusNode: _focusNode,
|
|
|
|
autoFocus: false,
|
|
|
|
readOnly: false,
|
|
|
|
placeholder: 'Add content',
|
|
|
|
expands: false,
|
|
|
|
padding: EdgeInsets.zero,
|
|
|
|
customStyles: DefaultStyles(
|
|
|
|
h1: DefaultTextBlockStyle(
|
|
|
|
const TextStyle(
|
|
|
|
fontSize: 32,
|
|
|
|
color: Colors.black,
|
|
|
|
height: 1.15,
|
|
|
|
fontWeight: FontWeight.w300,
|
|
|
|
),
|
|
|
|
const Tuple2(16, 0),
|
|
|
|
const Tuple2(0, 0),
|
|
|
|
null),
|
|
|
|
sizeSmall: const TextStyle(fontSize: 9),
|
|
|
|
));
|
|
|
|
if (kIsWeb) {
|
|
|
|
quillEditor = QuillEditor(
|
|
|
|
controller: _controller!,
|
|
|
|
scrollController: ScrollController(),
|
|
|
|
scrollable: true,
|
|
|
|
focusNode: _focusNode,
|
|
|
|
autoFocus: false,
|
|
|
|
readOnly: false,
|
|
|
|
placeholder: 'Add content',
|
|
|
|
expands: false,
|
|
|
|
padding: EdgeInsets.zero,
|
|
|
|
customStyles: DefaultStyles(
|
|
|
|
h1: DefaultTextBlockStyle(
|
|
|
|
const TextStyle(
|
|
|
|
fontSize: 32,
|
|
|
|
color: Colors.black,
|
|
|
|
height: 1.15,
|
|
|
|
fontWeight: FontWeight.w300,
|
|
|
|
),
|
|
|
|
const Tuple2(16, 0),
|
|
|
|
const Tuple2(0, 0),
|
|
|
|
null),
|
|
|
|
sizeSmall: const TextStyle(fontSize: 9),
|
|
|
|
),
|
|
|
|
embedBuilder: defaultEmbedBuilderWeb);
|
|
|
|
}
|
|
|
|
return SafeArea(
|
|
|
|
child: Column(
|
|
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
|
|
children: <Widget>[
|
|
|
|
Expanded(
|
|
|
|
flex: 15,
|
|
|
|
child: Container(
|
|
|
|
color: Colors.white,
|
|
|
|
padding: const EdgeInsets.only(left: 16, right: 16),
|
|
|
|
child: quillEditor,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
kIsWeb
|
|
|
|
? Expanded(
|
|
|
|
child: Container(
|
|
|
|
padding:
|
|
|
|
const EdgeInsets.symmetric(vertical: 16, horizontal: 8),
|
|
|
|
child: QuillToolbar.basic(
|
|
|
|
controller: _controller!,
|
|
|
|
onImagePickCallback: _onImagePickCallback),
|
|
|
|
))
|
|
|
|
: Container(
|
|
|
|
child: QuillToolbar.basic(
|
|
|
|
controller: _controller!,
|
|
|
|
onImagePickCallback: _onImagePickCallback),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Renders the image picked by imagePicker from local file storage
|
Merge master into dev (#258)
* Update issue templates
* Updating checkbox to handle tap (#186)
* updating checkbox to handle tap
* updating checkbox to handle long press and using UniqueKey() to avoid weird side effects
* removed useless doc
Co-authored-by: Kevin Despoulains <kevin.despoulains@scriptandgo.com>
* Simple viewer (#187)
* 2021-04-25
* 2021-04-26
* Fix simple viewer compilation error
* Upgrade version - checkbox supports tapping
* 171: support for non-scrollable text editor (#188)
Co-authored-by: Gyuri Majercsik <gyuri@fluttech.com>
* custom rules & optionally auto add newline for image embeds (#205)
* Adding missing overrides to make package work with Flutter 2.2.0 (#226)
* Improve SOC of raw editor (#227)
Improve separation of concerns for RawEditor by moving the code
for the text input client to a separate class, furthermore add
more comments.
* Upgrade version
* Improve SOC of raw editor (#228)
Improve separation of concerns for `RawEditor` by moving the code
for the keyboard to a separate class, furthermore add more comments.
The PR does not change the functionality of the code.
* Improve further SOC of raw editor
This improves separation of concerns for the RawEditor by moving
the code for the text selection delegate to a separate class,
furthermore add more comments.
The PR does not change the functionality of the code.
* Hide implementation files (#233)
* Fixes for flutter web (#234)
* Fix for Attribute object comparison
* Fix for "Unexpected null value" error on web
Clipboard is now supported on web, via a permission request through the browser
Co-authored-by: George Johnson <george@indiespring.com>
* Dispose ValueNotifier of cursor controller
* Remove getter for final operator
A getter for a final variable makes no sense, because the variable
cannot be reassigned. It is better to remove the unnecessary getter
and make the variable public.
* Add comments to cursor class
* Remove null exception when a disposed controller is set
* Disallow lines longer than 80 characters
* Don't create a lambda when a tear-off will do
* Move ResponsiveWidgets to example folder
This widget has nothing to do with the library and is only used in
the example, so it is moved to the example.
* Fix null exception
* Remove exception when widget is not mounted
* Fix exception when rect is not a number
* Fix paste (#236)
closes #235.
* Fix exception
* Add const types for image and divider embeds
This allows to reference the type.
* Fix relative path
* Add new logo
* Fix buttons which ignore toolbariconsize
Closes #189.
* Upgrade to 1.3.1
* Fix incorrect double to int cast, and guard against optional parent (#239)
* use ceil instead of floor to make sure won't cause overflow
* Fix example project Podfile (#241)
* Show arrow indicator on toolbar (#245)
* Add color parameter to Toolbar and ImageButton
In addition, change these widgets to stateless widgets, since these
widgets do not have a state and thus stateful is superfluous.
* Fix paste bug
* Remove extraneous toolbar dividers in certain configuration
Closes #193.
* Upgrade version to 1.3.2
* Format code
* Bump file_picker to 3.0.2+2
With version 3.0.2 `name` of the file_picker library becomes
non-nullable, so a warning was issued for users who had already
used version 3.0.2, as we still assumed that `name` is nullable.
Increasing the version and removing the exclamation mark removes
the warning.
* Fix a bug that Embed could be together with Text (#249)
* Fix #242 (#254)
* Upgrade to 1.3.3
* Format code
* bugfix:The return type 'bool' isn't a 'KeyEventResult'
Co-authored-by: Xin Yao <singerdmx@gmail.com>
Co-authored-by: kevinDespoulains <46108869+kevinDespoulains@users.noreply.github.com>
Co-authored-by: Kevin Despoulains <kevin.despoulains@scriptandgo.com>
Co-authored-by: em6m6e <50019687+em6m6e@users.noreply.github.com>
Co-authored-by: Gyuri Majercsik <majercsik.gyuri@gmail.com>
Co-authored-by: Gyuri Majercsik <gyuri@fluttech.com>
Co-authored-by: hyouuu <hyouuu@gmail.com>
Co-authored-by: Till Friebe <friebetill@gmail.com>
Co-authored-by: George <george.a.johnson@btopenworld.com>
Co-authored-by: George Johnson <george@indiespring.com>
Co-authored-by: Ben Chung <1330575+yzxben@users.noreply.github.com>
Co-authored-by: lucasbstn <64323294+lucasbstn@users.noreply.github.com>
4 years ago
|
|
|
// You can also upload the picked image to any server (eg : AWS s3
|
|
|
|
// or Firebase) and then return the uploaded image URL.
|
|
|
|
Future<String> _onImagePickCallback(File file) async {
|
|
|
|
// Copies the picked file from temporary cache to applications directory
|
|
|
|
final appDocDir = await getApplicationDocumentsDirectory();
|
|
|
|
final copiedFile =
|
|
|
|
await file.copy('${appDocDir.path}/${basename(file.path)}');
|
|
|
|
return copiedFile.path.toString();
|
|
|
|
}
|
|
|
|
|
|
|
|
Widget _buildMenuBar(BuildContext context) {
|
|
|
|
final size = MediaQuery.of(context).size;
|
|
|
|
const itemStyle = TextStyle(
|
|
|
|
color: Colors.white,
|
|
|
|
fontSize: 18,
|
|
|
|
fontWeight: FontWeight.bold,
|
|
|
|
);
|
|
|
|
return Column(
|
|
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
|
|
children: [
|
|
|
|
Divider(
|
|
|
|
thickness: 2,
|
|
|
|
color: Colors.white,
|
|
|
|
indent: size.width * 0.1,
|
|
|
|
endIndent: size.width * 0.1,
|
|
|
|
),
|
|
|
|
ListTile(
|
|
|
|
title: const Center(child: Text('Read only demo', style: itemStyle)),
|
|
|
|
dense: true,
|
|
|
|
visualDensity: VisualDensity.compact,
|
|
|
|
onTap: _readOnly,
|
|
|
|
),
|
|
|
|
Divider(
|
|
|
|
thickness: 2,
|
|
|
|
color: Colors.white,
|
|
|
|
indent: size.width * 0.1,
|
|
|
|
endIndent: size.width * 0.1,
|
|
|
|
),
|
|
|
|
],
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
void _readOnly() {
|
|
|
|
Navigator.push(
|
|
|
|
super.context,
|
|
|
|
MaterialPageRoute(
|
|
|
|
builder: (context) => ReadOnlyPage(),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|