1. changed translation locale country code to lower case (#946)

pull/950/head
Jimmy Li 3 years ago committed by GitHub
parent 206d524609
commit 22200b8812
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 521
      example/assets/sample_data_nomedia.json
  2. 11
      example/lib/main.dart
  3. 3
      example/lib/pages/home_page.dart
  4. 3
      example/lib/pages/read_only_page.dart
  5. 2
      lib/src/translations/toolbar.i18n.dart
  6. 21
      lib/src/widgets/delegate.dart
  7. 2
      lib/src/widgets/editor.dart
  8. 80
      lib/src/widgets/raw_editor.dart
  9. 55
      lib/src/widgets/text_selection.dart

@ -0,0 +1,521 @@
[
{
"insert": "Flutter Quill"
},
{
"attributes": {
"header": 1
},
"insert": "\n"
},
{
"insert": "\nRich text editor for Flutter"
},
{
"attributes": {
"header": 2
},
"insert": "\n"
},
{
"insert": "Quill component for Flutter"
},
{
"attributes": {
"header": 3
},
"insert": "\n"
},
{
"insert": "This "
},
{
"attributes": {
"italic": true,
"background": "transparent"
},
"insert": "library"
},
{
"insert": " supports "
},
{
"attributes": {
"bold": true,
"background": "#ebd6ff"
},
"insert": "mobile"
},
{
"insert": " platform "
},
{
"attributes": {
"underline": true,
"bold": true,
"color": "#e60000"
},
"insert": "only"
},
{
"attributes": {
"color": "rgba(0, 0, 0, 0.847)"
},
"insert": " and "
},
{
"attributes": {
"strike": true,
"color": "black"
},
"insert": "web"
},
{
"insert": " is not supported.\nYou are welcome to use "
},
{
"attributes": {
"link": "https://bulletjournal.us/home/index.html"
},
"insert": "Bullet Journal"
},
{
"insert": ":\nTrack personal and group journals (ToDo, Note, Ledger) from multiple views with timely reminders"
},
{
"attributes": {
"list": "ordered"
},
"insert": "\n"
},
{
"insert": "Share your tasks and notes with teammates, and see changes as they happen in real-time, across all devices"
},
{
"attributes": {
"list": "ordered"
},
"insert": "\n"
},
{
"insert": "Check out what you and your teammates are working on each day"
},
{
"attributes": {
"list": "ordered"
},
"insert": "\n"
},
{
"insert": "\nSplitting bills with friends can never be easier."
},
{
"attributes": {
"list": "bullet"
},
"insert": "\n"
},
{
"insert": "Start creating a group and invite your friends to join."
},
{
"attributes": {
"list": "bullet"
},
"insert": "\n"
},
{
"insert": "Create a BuJo of Ledger type to see expense or balance summary."
},
{
"attributes": {
"list": "bullet"
},
"insert": "\n"
},
{
"insert": "\nAttach one or multiple labels to tasks, notes or transactions. Later you can track them just using the label(s)."
},
{
"attributes": {
"blockquote": true
},
"insert": "\n"
},
{
"insert": "\nvar BuJo = 'Bullet' + 'Journal'"
},
{
"attributes": {
"code-block": true
},
"insert": "\n"
},
{
"insert": "\nStart tracking in your browser"
},
{
"attributes": {
"indent": 1
},
"insert": "\n"
},
{
"insert": "Stop the timer on your phone"
},
{
"attributes": {
"indent": 1
},
"insert": "\n"
},
{
"insert": "All your time entries are synced"
},
{
"attributes": {
"indent": 2
},
"insert": "\n"
},
{
"insert": "between the phone apps"
},
{
"attributes": {
"indent": 2
},
"insert": "\n"
},
{
"insert": "and the website."
},
{
"attributes": {
"indent": 3
},
"insert": "\n"
},
{
"insert": "\n"
},
{
"insert": "\nCenter Align"
},
{
"attributes": {
"align": "center"
},
"insert": "\n"
},
{
"insert": "Right Align"
},
{
"attributes": {
"align": "right"
},
"insert": "\n"
},
{
"insert": "Justify Align"
},
{
"attributes": {
"align": "justify"
},
"insert": "\n"
},
{
"insert": "Have trouble finding things? "
},
{
"attributes": {
"list": "ordered"
},
"insert": "\n"
},
{
"insert": "Just type in the search bar"
},
{
"attributes": {
"indent": 1,
"list": "ordered"
},
"insert": "\n"
},
{
"insert": "and easily find contents"
},
{
"attributes": {
"indent": 2,
"list": "ordered"
},
"insert": "\n"
},
{
"insert": "across projects or folders."
},
{
"attributes": {
"indent": 2,
"list": "ordered"
},
"insert": "\n"
},
{
"insert": "It matches text in your note or task."
},
{
"attributes": {
"indent": 1,
"list": "ordered"
},
"insert": "\n"
},
{
"insert": "Enable reminders so that you will get notified by"
},
{
"attributes": {
"list": "ordered"
},
"insert": "\n"
},
{
"insert": "email"
},
{
"attributes": {
"indent": 1,
"list": "ordered"
},
"insert": "\n"
},
{
"insert": "message on your phone"
},
{
"attributes": {
"indent": 1,
"list": "ordered"
},
"insert": "\n"
},
{
"insert": "popup on the web site"
},
{
"attributes": {
"indent": 1,
"list": "ordered"
},
"insert": "\n"
},
{
"insert": "Create a BuJo serving as project or folder"
},
{
"attributes": {
"list": "bullet"
},
"insert": "\n"
},
{
"insert": "Organize your"
},
{
"attributes": {
"indent": 1,
"list": "bullet"
},
"insert": "\n"
},
{
"insert": "tasks"
},
{
"attributes": {
"indent": 2,
"list": "bullet"
},
"insert": "\n"
},
{
"insert": "notes"
},
{
"attributes": {
"indent": 2,
"list": "bullet"
},
"insert": "\n"
},
{
"insert": "transactions"
},
{
"attributes": {
"indent": 2,
"list": "bullet"
},
"insert": "\n"
},
{
"insert": "under BuJo "
},
{
"attributes": {
"indent": 3,
"list": "bullet"
},
"insert": "\n"
},
{
"insert": "See them in Calendar"
},
{
"attributes": {
"list": "bullet"
},
"insert": "\n"
},
{
"insert": "or hierarchical view"
},
{
"attributes": {
"indent": 1,
"list": "bullet"
},
"insert": "\n"
},
{
"insert": "this is a check list"
},
{
"attributes": {
"list": "checked"
},
"insert": "\n"
},
{
"insert": "this is a uncheck list"
},
{
"attributes": {
"list": "unchecked"
},
"insert": "\n"
},
{
"insert": "Font "
},
{
"attributes": {
"font": "sans-serif"
},
"insert": "Sans Serif"
},
{
"insert": " "
},
{
"attributes": {
"font": "serif"
},
"insert": "Serif"
},
{
"insert": " "
},
{
"attributes": {
"font": "monospace"
},
"insert": "Monospace"
},
{
"insert": " Size "
},
{
"attributes": {
"size": "small"
},
"insert": "Small"
},
{
"insert": " "
},
{
"attributes": {
"size": "large"
},
"insert": "Large"
},
{
"insert": " "
},
{
"attributes": {
"size": "huge"
},
"insert": "Huge"
},
{
"attributes": {
"size": "15.0"
},
"insert": "font size 15"
},
{
"insert": " "
},
{
"attributes": {
"size": "35"
},
"insert": "font size 35"
},
{
"insert": " "
},
{
"attributes": {
"size": "20"
},
"insert": "font size 20"
},
{
"attributes": {
"token": "built_in"
},
"insert": " diff"
},
{
"attributes": {
"token": "operator"
},
"insert": "-match"
},
{
"attributes": {
"token": "literal"
},
"insert": "-patch"
},
{
"insert": {
"image": "https://user-images.githubusercontent.com/122956/72955931-ccc07900-3d52-11ea-89b1-d468a6e2aa2b.png"
},
"attributes": {
"width": "230",
"style": "display: block; margin: auto;"
}
},
{
"insert": "\n"
}
]

@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'pages/home_page.dart';
void main() {
@ -30,6 +30,15 @@ class MyApp extends StatelessWidget {
// closer together (more dense) than on mobile platforms.
visualDensity: VisualDensity.adaptivePlatformDensity,
),
localizationsDelegates: [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: [
const Locale('en', "US"),
const Locale('zh', "HK"),
],
home: HomePage(),
);
}

@ -7,6 +7,7 @@ import 'package:filesystem_picker/filesystem_picker.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_quill/extensions.dart';
import 'package:flutter_quill/flutter_quill.dart' hide Text;
import 'package:flutter_quill_extensions/flutter_quill_extensions.dart';
import 'package:path/path.dart';
@ -33,7 +34,7 @@ class _HomePageState extends State<HomePage> {
Future<void> _loadFromAssets() async {
try {
final result = await rootBundle.loadString('assets/sample_data.json');
final result = await rootBundle.loadString(isDesktop() ? 'assets/sample_data_nomedia.json' : 'assets/sample_data.json');
final doc = Document.fromJson(jsonDecode(result));
setState(() {
_controller = QuillController(

@ -1,5 +1,6 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_quill/extensions.dart';
import 'package:flutter_quill/flutter_quill.dart' hide Text;
import 'package:flutter_quill_extensions/flutter_quill_extensions.dart';
@ -19,7 +20,7 @@ class _ReadOnlyPageState extends State<ReadOnlyPage> {
@override
Widget build(BuildContext context) {
return DemoScaffold(
documentFilename: 'sample_data.json',
documentFilename: isDesktop() ? 'assets/sample_data_nomedia.json' : 'sample_data_nomedia.json',
builder: _buildContent,
showToolbar: _edit == true,
floatingActionButton: FloatingActionButton.extended(

@ -734,7 +734,7 @@ extension Localization on String {
'Camera': 'Camera',
'Video': 'Video',
},
'zh_HK': {
'zh_hk': {
'Paste a link': '貼上連結',
'Ok': '確定',
'Select Color': '選擇顏色',

@ -2,6 +2,7 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter_quill/src/utils/platform.dart';
import '../../flutter_quill.dart';
import 'text_selection.dart';
@ -111,6 +112,7 @@ class EditorTextSelectionGestureDetectorBuilder {
// For backwards-compatibility, we treat a null kind the same as touch.
final kind = details.kind;
shouldShowSelectionToolbar = kind == null ||
kind == PointerDeviceKind.mouse || // this is added to enable word selection by mouse double tap
kind == PointerDeviceKind.touch ||
kind == PointerDeviceKind.stylus;
}
@ -178,6 +180,14 @@ class EditorTextSelectionGestureDetectorBuilder {
}
}
/// onSingleTapUp for mouse right click
@protected
void onSecondarySingleTapUp(TapUpDetails details) { // added to show toolbar by right click
if (shouldShowSelectionToolbar) {
editor!.showToolbar();
}
}
/// Handler for [EditorTextSelectionGestureDetector.onSingleTapCancel].
///
/// By default, it services as place holder to enable subclass override.
@ -311,6 +321,13 @@ class EditorTextSelectionGestureDetectorBuilder {
@protected
void onDragSelectionEnd(DragEndDetails details) {
renderEditor!.handleDragEnd(details);
if (isDesktop()) { // added to show selection copy/paste toolbar after drag to select
if (delegate.selectionEnabled) {
if (shouldShowSelectionToolbar) {
editor!.showToolbar();
}
}
}
}
/// Returns a [EditorTextSelectionGestureDetector] configured with
@ -330,6 +347,10 @@ class EditorTextSelectionGestureDetectorBuilder {
onSingleLongTapMoveUpdate: onSingleLongTapMoveUpdate,
onSingleLongTapEnd: onSingleLongTapEnd,
onDoubleTapDown: onDoubleTapDown,
onSecondaryTapDown: null,
onSecondarySingleTapUp: onSecondarySingleTapUp,
onSecondarySingleTapCancel: null,
onSecondaryDoubleTapDown: null,
onDragSelectionStart: onDragSelectionStart,
onDragSelectionUpdate: onDragSelectionUpdate,
onDragSelectionEnd: onDragSelectionEnd,

@ -640,7 +640,7 @@ class _QuillEditorSelectionGestureDetectorBuilder
try {
if (delegate.selectionEnabled && !_isPositionSelected(details)) {
final _platform = Theme.of(_state.context).platform;
if (isAppleOS(_platform)) {
if (isAppleOS(_platform) || isDesktop()) { // added isDesktop() to enable extend selection in Windows platform
switch (details.kind) {
case PointerDeviceKind.mouse:
case PointerDeviceKind.stylus:

@ -362,14 +362,21 @@ class RawEditorState extends EditorState
return QuillStyles(
data: _styles!,
child: Actions(
actions: _actions,
child: Focus(
focusNode: widget.focusNode,
child: QuillKeyboardListener(
child: Container(
constraints: constraints,
child: child,
child: Shortcuts(
shortcuts: <LogicalKeySet, Intent>{ // shortcuts added for Windows platform
LogicalKeySet(LogicalKeyboardKey.escape): HideSelectionToolbarIntent(),
LogicalKeySet(LogicalKeyboardKey.control, LogicalKeyboardKey.keyZ): const UndoTextIntent(SelectionChangedCause.keyboard),
LogicalKeySet(LogicalKeyboardKey.control, LogicalKeyboardKey.keyY): const RedoTextIntent(SelectionChangedCause.keyboard),
},
child: Actions(
actions: _actions,
child: Focus(
focusNode: widget.focusNode,
child: QuillKeyboardListener(
child: Container(
constraints: constraints,
child: child,
),
),
),
),
@ -1172,6 +1179,10 @@ class RawEditorState extends EditorState
CopySelectionTextIntent: _makeOverridable(_CopySelectionAction(this)),
PasteTextIntent: _makeOverridable(CallbackAction<PasteTextIntent>(
onInvoke: (intent) => pasteText(intent.cause))),
HideSelectionToolbarIntent: _makeOverridable(_HideSelectionToolbarAction(this)),
UndoTextIntent: _makeOverridable(_UndoKeyboardAction(this)),
RedoTextIntent: _makeOverridable(_RedoKeyboardAction(this)),
};
@override
@ -1868,3 +1879,56 @@ class _CopySelectionAction extends ContextAction<CopySelectionTextIntent> {
state.textEditingValue.selection.isValid &&
!state.textEditingValue.selection.isCollapsed;
}
// intent class for "escape" key to dismiss selection toolbar in Windows platform
class HideSelectionToolbarIntent extends Intent {
const HideSelectionToolbarIntent();
}
class _HideSelectionToolbarAction extends ContextAction<HideSelectionToolbarIntent> {
_HideSelectionToolbarAction(this.state);
final RawEditorState state;
@override
void invoke(HideSelectionToolbarIntent intent, [BuildContext? context]) {
state.hideToolbar();
}
@override
bool get isActionEnabled =>
state.textEditingValue.selection.isValid;
}
class _UndoKeyboardAction extends ContextAction<UndoTextIntent> {
_UndoKeyboardAction(this.state);
final RawEditorState state;
@override
void invoke(UndoTextIntent intent, [BuildContext? context]) {
if (state.controller.hasUndo) {
state.controller.undo();
}
}
@override
bool get isActionEnabled => true;
}
class _RedoKeyboardAction extends ContextAction<RedoTextIntent> {
_RedoKeyboardAction(this.state);
final RawEditorState state;
@override
void invoke(RedoTextIntent intent, [BuildContext? context]) {
if (state.controller.hasRedo) {
state.controller.redo();
}
}
@override
bool get isActionEnabled => true;
}

@ -695,6 +695,10 @@ class EditorTextSelectionGestureDetector extends StatefulWidget {
this.onForcePressEnd,
this.onSingleTapUp,
this.onSingleTapCancel,
this.onSecondaryTapDown,
this.onSecondarySingleTapUp,
this.onSecondarySingleTapCancel,
this.onSecondaryDoubleTapDown,
this.onSingleLongTapStart,
this.onSingleLongTapMoveUpdate,
this.onSingleLongTapEnd,
@ -730,6 +734,15 @@ class EditorTextSelectionGestureDetector extends StatefulWidget {
/// another gesture from the touch is recognized.
final GestureTapCancelCallback? onSingleTapCancel;
/// onTapDown for mouse right click
final GestureTapDownCallback? onSecondaryTapDown;
/// onTapUp for mouse right click
final GestureTapUpCallback? onSecondarySingleTapUp;
/// onTapCancel for mouse right click
final GestureTapCancelCallback? onSecondarySingleTapCancel;
/// onDoubleTap for mouse right click
final GestureTapDownCallback? onSecondaryDoubleTapDown;
/// Called for a single long tap that's sustained for longer than
/// [kLongPressTimeout] but not necessarily lifted. Not called for a
/// double-tap-hold, which calls [onDoubleTapDown] instead.
@ -781,6 +794,9 @@ class _EditorTextSelectionGestureDetectorState
// subsequent tap up / tap hold of the same tap.
bool _isDoubleTap = false;
// _isDoubleTap for mouse right click
bool _isSecondaryDoubleTap = false;
@override
void dispose() {
_doubleTapTimer?.cancel();
@ -829,6 +845,40 @@ class _EditorTextSelectionGestureDetectorState
}
}
// added secondary tap function for mouse right click to show toolbar
void _handleSecondaryTapDown(TapDownDetails details) {
if (widget.onSecondaryTapDown != null) {
widget.onSecondaryTapDown!(details);
}
if (_doubleTapTimer != null &&
_isWithinDoubleTapTolerance(details.globalPosition)) {
if (widget.onSecondaryDoubleTapDown != null) {
widget.onSecondaryDoubleTapDown!(details);
}
_doubleTapTimer!.cancel();
_doubleTapTimeout();
_isDoubleTap = true;
}
}
void _handleSecondaryTapUp(TapUpDetails details) {
if (!_isSecondaryDoubleTap) {
if (widget.onSecondarySingleTapUp != null) {
widget.onSecondarySingleTapUp!(details);
}
_lastTapOffset = details.globalPosition;
_doubleTapTimer = Timer(kDoubleTapTimeout, _doubleTapTimeout);
}
_isSecondaryDoubleTap = false;
}
void _handleSecondaryTapCancel() {
if (widget.onSecondarySingleTapCancel != null) {
widget.onSecondarySingleTapCancel!();
}
}
DragStartDetails? _lastDragStartDetails;
DragUpdateDetails? _lastDragUpdateDetails;
Timer? _dragUpdateThrottleTimer;
@ -940,7 +990,10 @@ class _EditorTextSelectionGestureDetectorState
instance
..onTapDown = _handleTapDown
..onTapUp = _handleTapUp
..onTapCancel = _handleTapCancel;
..onTapCancel = _handleTapCancel
..onSecondaryTapDown = _handleSecondaryTapDown
..onSecondaryTapUp = _handleSecondaryTapUp
..onSecondaryTapCancel = _handleSecondaryTapCancel;
},
);

Loading…
Cancel
Save