mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: [improvements] integrate logging library in AppFlowyEditor
This commit is contained in:
parent
a0753cea2d
commit
c36ccc39ce
@ -97,9 +97,13 @@ class _MyHomePageState extends State<MyHomePage> {
|
|||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
if (snapshot.hasData) {
|
if (snapshot.hasData) {
|
||||||
final data = Map<String, Object>.from(json.decode(snapshot.data!));
|
final data = Map<String, Object>.from(json.decode(snapshot.data!));
|
||||||
return _buildAppFlowyEditor(EditorState(
|
final editorState = EditorState(document: StateTree.fromJson(data));
|
||||||
document: StateTree.fromJson(data),
|
editorState.logConfiguration
|
||||||
));
|
..level = LogLevel.all
|
||||||
|
..handler = (message) {
|
||||||
|
debugPrint(message);
|
||||||
|
};
|
||||||
|
return _buildAppFlowyEditor(editorState);
|
||||||
} else {
|
} else {
|
||||||
return const Center(
|
return const Center(
|
||||||
child: CircularProgressIndicator(),
|
child: CircularProgressIndicator(),
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
/// AppFlowyEditor library
|
/// AppFlowyEditor library
|
||||||
library appflowy_editor;
|
library appflowy_editor;
|
||||||
|
|
||||||
|
export 'src/infra/log.dart';
|
||||||
export 'src/document/node.dart';
|
export 'src/document/node.dart';
|
||||||
export 'src/document/path.dart';
|
export 'src/document/path.dart';
|
||||||
export 'src/document/position.dart';
|
export 'src/document/position.dart';
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
import 'package:appflowy_editor/src/infra/log.dart';
|
||||||
import 'package:appflowy_editor/src/service/service.dart';
|
import 'package:appflowy_editor/src/service/service.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
@ -48,10 +49,15 @@ class EditorState {
|
|||||||
// Service reference.
|
// Service reference.
|
||||||
final service = FlowyService();
|
final service = FlowyService();
|
||||||
|
|
||||||
|
/// Configures log output parameters,
|
||||||
|
/// such as log level and log output callbacks,
|
||||||
|
/// with this variable.
|
||||||
|
LogConfiguration get logConfiguration => LogConfiguration();
|
||||||
|
|
||||||
final UndoManager undoManager = UndoManager();
|
final UndoManager undoManager = UndoManager();
|
||||||
Selection? _cursorSelection;
|
Selection? _cursorSelection;
|
||||||
|
|
||||||
/// TODO: only for testing.
|
// TODO: only for testing.
|
||||||
bool disableSealTimer = false;
|
bool disableSealTimer = false;
|
||||||
|
|
||||||
Selection? get cursorSelection {
|
Selection? get cursorSelection {
|
||||||
@ -120,7 +126,7 @@ class EditorState {
|
|||||||
_debouncedSealHistoryItemTimer =
|
_debouncedSealHistoryItemTimer =
|
||||||
Timer(const Duration(milliseconds: 1000), () {
|
Timer(const Duration(milliseconds: 1000), () {
|
||||||
if (undoManager.undoStack.isNonEmpty) {
|
if (undoManager.undoStack.isNonEmpty) {
|
||||||
debugPrint('Seal history item');
|
Log.editor.debug('Seal history item');
|
||||||
final last = undoManager.undoStack.last;
|
final last = undoManager.undoStack.last;
|
||||||
last.seal();
|
last.seal();
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,109 @@
|
|||||||
|
import 'package:logging/logging.dart';
|
||||||
|
|
||||||
|
enum LogLevel {
|
||||||
|
off,
|
||||||
|
error,
|
||||||
|
warn,
|
||||||
|
info,
|
||||||
|
debug,
|
||||||
|
all,
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef LogHandler = void Function(String message);
|
||||||
|
|
||||||
|
class LogConfiguration {
|
||||||
|
LogConfiguration._() {
|
||||||
|
Logger.root.onRecord.listen((record) {
|
||||||
|
if (handler != null) {
|
||||||
|
handler!(
|
||||||
|
'[${record.level.toLogLevel().name}][${record.loggerName}]: ${record.time}: ${record.message}');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
factory LogConfiguration() => _logConfiguration;
|
||||||
|
|
||||||
|
static final LogConfiguration _logConfiguration = LogConfiguration._();
|
||||||
|
|
||||||
|
LogHandler? handler;
|
||||||
|
|
||||||
|
LogLevel _level = LogLevel.off;
|
||||||
|
|
||||||
|
LogLevel get level => _level;
|
||||||
|
set level(LogLevel level) {
|
||||||
|
_level = level;
|
||||||
|
Logger.root.level = level.toLevel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Log {
|
||||||
|
Log._({
|
||||||
|
required this.name,
|
||||||
|
}) : _logger = Logger(name);
|
||||||
|
|
||||||
|
final String name;
|
||||||
|
late final Logger _logger;
|
||||||
|
|
||||||
|
static Log editor = Log._(name: 'editor');
|
||||||
|
static Log selection = Log._(name: 'selection');
|
||||||
|
static Log keyboard = Log._(name: 'keyboard');
|
||||||
|
static Log input = Log._(name: 'input');
|
||||||
|
static Log scroll = Log._(name: 'scroll');
|
||||||
|
static Log ui = Log._(name: 'ui');
|
||||||
|
|
||||||
|
void error(String message) => _logger.severe(message);
|
||||||
|
void warn(String message) => _logger.warning(message);
|
||||||
|
void info(String message) => _logger.info(message);
|
||||||
|
void debug(String message) => _logger.fine(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
extension on LogLevel {
|
||||||
|
Level toLevel() {
|
||||||
|
switch (this) {
|
||||||
|
case LogLevel.off:
|
||||||
|
return Level.OFF;
|
||||||
|
case LogLevel.error:
|
||||||
|
return Level.SEVERE;
|
||||||
|
case LogLevel.warn:
|
||||||
|
return Level.WARNING;
|
||||||
|
case LogLevel.info:
|
||||||
|
return Level.INFO;
|
||||||
|
case LogLevel.debug:
|
||||||
|
return Level.FINE;
|
||||||
|
case LogLevel.all:
|
||||||
|
return Level.ALL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String get name {
|
||||||
|
switch (this) {
|
||||||
|
case LogLevel.off:
|
||||||
|
return 'OFF';
|
||||||
|
case LogLevel.error:
|
||||||
|
return 'ERROR';
|
||||||
|
case LogLevel.warn:
|
||||||
|
return 'WARN';
|
||||||
|
case LogLevel.info:
|
||||||
|
return 'INFO';
|
||||||
|
case LogLevel.debug:
|
||||||
|
return 'DEBUG';
|
||||||
|
case LogLevel.all:
|
||||||
|
return 'ALL';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension on Level {
|
||||||
|
LogLevel toLogLevel() {
|
||||||
|
if (this == Level.SEVERE) {
|
||||||
|
return LogLevel.error;
|
||||||
|
} else if (this == Level.WARNING) {
|
||||||
|
return LogLevel.warn;
|
||||||
|
} else if (this == Level.INFO) {
|
||||||
|
return LogLevel.info;
|
||||||
|
} else if (this == Level.FINE) {
|
||||||
|
return LogLevel.debug;
|
||||||
|
}
|
||||||
|
return LogLevel.off;
|
||||||
|
}
|
||||||
|
}
|
@ -83,7 +83,6 @@ class _CheckboxNodeWidgetState extends State<CheckboxNodeWidget>
|
|||||||
name: check ? 'check' : 'uncheck',
|
name: check ? 'check' : 'uncheck',
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
debugPrint('[Checkbox] onTap...');
|
|
||||||
TransactionBuilder(widget.editorState)
|
TransactionBuilder(widget.editorState)
|
||||||
..updateNode(widget.textNode, {
|
..updateNode(widget.textNode, {
|
||||||
StyleKey.checkbox: !check,
|
StyleKey.checkbox: !check,
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import 'package:appflowy_editor/src/infra/log.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
@ -243,7 +244,8 @@ class _AppFlowyInputState extends State<AppFlowyInput>
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void updateEditingValueWithDeltas(List<TextEditingDelta> textEditingDeltas) {
|
void updateEditingValueWithDeltas(List<TextEditingDelta> textEditingDeltas) {
|
||||||
debugPrint(textEditingDeltas.map((delta) => delta.toString()).toString());
|
Log.input
|
||||||
|
.debug(textEditingDeltas.map((delta) => delta.toString()).toString());
|
||||||
|
|
||||||
apply(textEditingDeltas);
|
apply(textEditingDeltas);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||||
import 'package:appflowy_editor/src/infra/html_converter.dart';
|
import 'package:appflowy_editor/src/infra/html_converter.dart';
|
||||||
import 'package:appflowy_editor/src/document/node_iterator.dart';
|
import 'package:appflowy_editor/src/document/node_iterator.dart';
|
||||||
|
import 'package:appflowy_editor/src/infra/log.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:rich_clipboard/rich_clipboard.dart';
|
import 'package:rich_clipboard/rich_clipboard.dart';
|
||||||
@ -19,10 +20,10 @@ _handleCopy(EditorState editorState) async {
|
|||||||
startOffset: selection.start.offset,
|
startOffset: selection.start.offset,
|
||||||
endOffset: selection.end.offset)
|
endOffset: selection.end.offset)
|
||||||
.toHTMLString();
|
.toHTMLString();
|
||||||
debugPrint('copy html: $htmlString');
|
Log.keyboard.debug('copy html: $htmlString');
|
||||||
RichClipboard.setData(RichClipboardData(html: htmlString));
|
RichClipboard.setData(RichClipboardData(html: htmlString));
|
||||||
} else {
|
} else {
|
||||||
debugPrint("unimplemented: copy non-text");
|
Log.keyboard.debug('unimplemented: copy non-text');
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -37,7 +38,7 @@ _handleCopy(EditorState editorState) async {
|
|||||||
startOffset: selection.start.offset,
|
startOffset: selection.start.offset,
|
||||||
endOffset: selection.end.offset)
|
endOffset: selection.end.offset)
|
||||||
.toHTMLString();
|
.toHTMLString();
|
||||||
debugPrint('copy html: $copyString');
|
Log.keyboard.debug('copy html: $copyString');
|
||||||
RichClipboard.setData(RichClipboardData(html: copyString));
|
RichClipboard.setData(RichClipboardData(html: copyString));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,7 +55,7 @@ _pasteHTML(EditorState editorState, String html) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
debugPrint('paste html: $html');
|
Log.keyboard.debug('paste html: $html');
|
||||||
final nodes = HTMLToNodesConverter(html).toNodes();
|
final nodes = HTMLToNodesConverter(html).toNodes();
|
||||||
|
|
||||||
if (nodes.isEmpty) {
|
if (nodes.isEmpty) {
|
||||||
@ -250,7 +251,6 @@ _handlePastePlainText(EditorState editorState, String plainText) {
|
|||||||
/// 1. copy the selected content
|
/// 1. copy the selected content
|
||||||
/// 2. delete selected content
|
/// 2. delete selected content
|
||||||
_handleCut(EditorState editorState) {
|
_handleCut(EditorState editorState) {
|
||||||
debugPrint('cut');
|
|
||||||
_handleCopy(editorState);
|
_handleCopy(editorState);
|
||||||
_deleteSelectedContent(editorState);
|
_deleteSelectedContent(editorState);
|
||||||
}
|
}
|
||||||
|
@ -97,7 +97,6 @@ KeyEventResult _handleDelete(EditorState editorState, RawKeyEvent event) {
|
|||||||
if (textNodes.length == 1) {
|
if (textNodes.length == 1) {
|
||||||
final textNode = textNodes.first;
|
final textNode = textNodes.first;
|
||||||
if (selection.start.offset >= textNode.delta.length) {
|
if (selection.start.offset >= textNode.delta.length) {
|
||||||
debugPrint("merge next line");
|
|
||||||
final nextNode = textNode.next;
|
final nextNode = textNode.next;
|
||||||
if (nextNode == null) {
|
if (nextNode == null) {
|
||||||
return KeyEventResult.ignored;
|
return KeyEventResult.ignored;
|
||||||
|
@ -3,6 +3,7 @@ import 'dart:math';
|
|||||||
import 'package:appflowy_editor/src/document/node.dart';
|
import 'package:appflowy_editor/src/document/node.dart';
|
||||||
import 'package:appflowy_editor/src/editor_state.dart';
|
import 'package:appflowy_editor/src/editor_state.dart';
|
||||||
import 'package:appflowy_editor/src/infra/flowy_svg.dart';
|
import 'package:appflowy_editor/src/infra/flowy_svg.dart';
|
||||||
|
import 'package:appflowy_editor/src/infra/log.dart';
|
||||||
import 'package:appflowy_editor/src/operation/transaction_builder.dart';
|
import 'package:appflowy_editor/src/operation/transaction_builder.dart';
|
||||||
import 'package:appflowy_editor/src/render/rich_text/rich_text_style.dart';
|
import 'package:appflowy_editor/src/render/rich_text/rich_text_style.dart';
|
||||||
import 'package:appflowy_editor/src/service/default_text_operations/format_rich_text_style.dart';
|
import 'package:appflowy_editor/src/service/default_text_operations/format_rich_text_style.dart';
|
||||||
@ -50,12 +51,6 @@ final List<PopupListItem> _popupListItems = [
|
|||||||
icon: _popupListIcon('bullets'),
|
icon: _popupListIcon('bullets'),
|
||||||
handler: (editorState) => insertBulletedListAfterSelection(editorState),
|
handler: (editorState) => insertBulletedListAfterSelection(editorState),
|
||||||
),
|
),
|
||||||
// PopupListItem(
|
|
||||||
// text: 'Numbered list',
|
|
||||||
// keywords: ['numbered list'],
|
|
||||||
// icon: _popupListIcon('number'),
|
|
||||||
// handler: (editorState) => debugPrint('Not implement yet!'),
|
|
||||||
// ),
|
|
||||||
PopupListItem(
|
PopupListItem(
|
||||||
text: 'To-do List',
|
text: 'To-do List',
|
||||||
keywords: ['checkbox', 'todo'],
|
keywords: ['checkbox', 'todo'],
|
||||||
@ -293,7 +288,7 @@ class _PopupListWidgetState extends State<PopupListWidget> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
KeyEventResult _onKey(FocusNode node, RawKeyEvent event) {
|
KeyEventResult _onKey(FocusNode node, RawKeyEvent event) {
|
||||||
debugPrint('slash on key $event');
|
Log.keyboard.debug('slash command, on key $event');
|
||||||
if (event is! RawKeyDownEvent) {
|
if (event is! RawKeyDownEvent) {
|
||||||
return KeyEventResult.ignored;
|
return KeyEventResult.ignored;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||||
|
import 'package:appflowy_editor/src/infra/log.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@ -94,15 +95,13 @@ class _AppFlowyKeyboardState extends State<AppFlowyKeyboard>
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
KeyEventResult onKey(RawKeyEvent event) {
|
KeyEventResult onKey(RawKeyEvent event) {
|
||||||
debugPrint('on keyboard event $event');
|
Log.keyboard.debug('on keyboard event $event');
|
||||||
|
|
||||||
if (event is! RawKeyDownEvent) {
|
if (event is! RawKeyDownEvent) {
|
||||||
return KeyEventResult.ignored;
|
return KeyEventResult.ignored;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (final handler in widget.handlers) {
|
for (final handler in widget.handlers) {
|
||||||
// debugPrint('handle keyboard event $event by $handler');
|
|
||||||
|
|
||||||
KeyEventResult result = handler(widget.editorState, event);
|
KeyEventResult result = handler(widget.editorState, event);
|
||||||
|
|
||||||
switch (result) {
|
switch (result) {
|
||||||
@ -119,7 +118,7 @@ class _AppFlowyKeyboardState extends State<AppFlowyKeyboard>
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _onFocusChange(bool value) {
|
void _onFocusChange(bool value) {
|
||||||
debugPrint('[KeyBoard Service] focus change $value');
|
Log.keyboard.debug('on keyboard event focus change $value');
|
||||||
}
|
}
|
||||||
|
|
||||||
KeyEventResult _onKey(FocusNode node, RawKeyEvent event) {
|
KeyEventResult _onKey(FocusNode node, RawKeyEvent event) {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import 'package:appflowy_editor/src/document/node.dart';
|
import 'package:appflowy_editor/src/document/node.dart';
|
||||||
import 'package:appflowy_editor/src/editor_state.dart';
|
import 'package:appflowy_editor/src/editor_state.dart';
|
||||||
|
import 'package:appflowy_editor/src/infra/log.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
@ -86,7 +87,7 @@ class AppFlowyRenderPlugin extends AppFlowyRenderPluginService {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void register(String name, NodeWidgetBuilder builder) {
|
void register(String name, NodeWidgetBuilder builder) {
|
||||||
debugPrint('[Plugins] registering $name...');
|
Log.editor.info('registers plugin($name)...');
|
||||||
_validatePlugin(name);
|
_validatePlugin(name);
|
||||||
_builders[name] = builder;
|
_builders[name] = builder;
|
||||||
}
|
}
|
||||||
@ -111,7 +112,7 @@ class AppFlowyRenderPlugin extends AppFlowyRenderPluginService {
|
|||||||
builder: (_, child) {
|
builder: (_, child) {
|
||||||
return Consumer<TextNode>(
|
return Consumer<TextNode>(
|
||||||
builder: ((_, value, child) {
|
builder: ((_, value, child) {
|
||||||
debugPrint('Text Node is rebuilding...');
|
Log.ui.debug('TextNode is rebuilding...');
|
||||||
return builder.build(context);
|
return builder.build(context);
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
@ -122,7 +123,7 @@ class AppFlowyRenderPlugin extends AppFlowyRenderPluginService {
|
|||||||
builder: (_, child) {
|
builder: (_, child) {
|
||||||
return Consumer<Node>(
|
return Consumer<Node>(
|
||||||
builder: ((_, value, child) {
|
builder: ((_, value, child) {
|
||||||
debugPrint('Node is rebuilding...');
|
Log.ui.debug('Node is rebuilding...');
|
||||||
return builder.build(context);
|
return builder.build(context);
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import 'package:appflowy_editor/src/infra/log.dart';
|
||||||
import 'package:flutter/gestures.dart';
|
import 'package:flutter/gestures.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:appflowy_editor/src/extensions/object_extensions.dart';
|
import 'package:appflowy_editor/src/extensions/object_extensions.dart';
|
||||||
@ -113,13 +114,13 @@ class _AppFlowyScrollState extends State<AppFlowyScroll>
|
|||||||
@override
|
@override
|
||||||
void disable() {
|
void disable() {
|
||||||
_scrollEnabled = false;
|
_scrollEnabled = false;
|
||||||
debugPrint('[scroll] $_scrollEnabled');
|
Log.scroll.debug('disable scroll service');
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void enable() {
|
void enable() {
|
||||||
_scrollEnabled = true;
|
_scrollEnabled = true;
|
||||||
debugPrint('[scroll] $_scrollEnabled');
|
Log.scroll.debug('enable scroll service');
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onPointerSignal(PointerSignalEvent event) {
|
void _onPointerSignal(PointerSignalEvent event) {
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import 'package:appflowy_editor/src/infra/log.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:appflowy_editor/src/document/node.dart';
|
import 'package:appflowy_editor/src/document/node.dart';
|
||||||
@ -185,12 +186,12 @@ class _AppFlowySelectionState extends State<AppFlowySelection>
|
|||||||
|
|
||||||
if (selection != null) {
|
if (selection != null) {
|
||||||
if (selection.isCollapsed) {
|
if (selection.isCollapsed) {
|
||||||
/// updates cursor area.
|
// updates cursor area.
|
||||||
debugPrint('updating cursor, $selection');
|
Log.selection.debug('update cursor area, $selection');
|
||||||
_updateCursorAreas(selection.start);
|
_updateCursorAreas(selection.start);
|
||||||
} else {
|
} else {
|
||||||
// updates selection area.
|
// updates selection area.
|
||||||
debugPrint('updating selection, $selection');
|
Log.selection.debug('update cursor area, $selection');
|
||||||
_updateSelectionAreas(selection);
|
_updateSelectionAreas(selection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -312,14 +313,10 @@ class _AppFlowySelectionState extends State<AppFlowySelection>
|
|||||||
|
|
||||||
// compute the selection in range.
|
// compute the selection in range.
|
||||||
if (first != null && last != null) {
|
if (first != null && last != null) {
|
||||||
bool isDownward = (identical(first, last))
|
|
||||||
? panStartOffset.dx < panEndOffset.dx
|
|
||||||
: panStartOffset.dy < panEndOffset.dy;
|
|
||||||
final start =
|
final start =
|
||||||
first.getSelectionInRange(panStartOffset, panEndOffset).start;
|
first.getSelectionInRange(panStartOffset, panEndOffset).start;
|
||||||
final end = last.getSelectionInRange(panStartOffset, panEndOffset).end;
|
final end = last.getSelectionInRange(panStartOffset, panEndOffset).end;
|
||||||
final selection = Selection(start: start, end: end);
|
final selection = Selection(start: start, end: end);
|
||||||
debugPrint('[_onPanUpdate] isDownward = $isDownward, $selection');
|
|
||||||
updateSelection(selection);
|
updateSelection(selection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import 'dart:collection';
|
import 'dart:collection';
|
||||||
|
|
||||||
import 'package:appflowy_editor/src/document/selection.dart';
|
import 'package:appflowy_editor/src/document/selection.dart';
|
||||||
|
import 'package:appflowy_editor/src/infra/log.dart';
|
||||||
import 'package:appflowy_editor/src/operation/operation.dart';
|
import 'package:appflowy_editor/src/operation/operation.dart';
|
||||||
import 'package:appflowy_editor/src/operation/transaction_builder.dart';
|
import 'package:appflowy_editor/src/operation/transaction_builder.dart';
|
||||||
import 'package:appflowy_editor/src/operation/transaction.dart';
|
import 'package:appflowy_editor/src/operation/transaction.dart';
|
||||||
import 'package:appflowy_editor/src/editor_state.dart';
|
import 'package:appflowy_editor/src/editor_state.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
|
||||||
|
|
||||||
/// A [HistoryItem] contains list of operations committed by users.
|
/// A [HistoryItem] contains list of operations committed by users.
|
||||||
/// If a [HistoryItem] is not sealed, operations can be added sequentially.
|
/// If a [HistoryItem] is not sealed, operations can be added sequentially.
|
||||||
@ -112,7 +112,7 @@ class UndoManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
undo() {
|
undo() {
|
||||||
debugPrint('undo');
|
Log.editor.debug('undo');
|
||||||
final s = state;
|
final s = state;
|
||||||
if (s == null) {
|
if (s == null) {
|
||||||
return;
|
return;
|
||||||
@ -131,7 +131,7 @@ class UndoManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
redo() {
|
redo() {
|
||||||
debugPrint('redo');
|
Log.editor.debug('redo');
|
||||||
final s = state;
|
final s = state;
|
||||||
if (s == null) {
|
if (s == null) {
|
||||||
return;
|
return;
|
||||||
|
@ -16,6 +16,7 @@ dependencies:
|
|||||||
flutter_svg: ^1.1.1+1
|
flutter_svg: ^1.1.1+1
|
||||||
provider: ^6.0.3
|
provider: ^6.0.3
|
||||||
url_launcher: ^6.1.5
|
url_launcher: ^6.1.5
|
||||||
|
logging: ^1.0.2
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
@ -0,0 +1,169 @@
|
|||||||
|
import 'package:appflowy_editor/src/infra/log.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'test_editor.dart';
|
||||||
|
|
||||||
|
void main() async {
|
||||||
|
group('log.dart', () {
|
||||||
|
testWidgets('test LogConfiguration in EditorState', (tester) async {
|
||||||
|
TestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
|
const text = 'Welcome to Appflowy 😁';
|
||||||
|
|
||||||
|
final List<String> logs = [];
|
||||||
|
|
||||||
|
final editor = tester.editor;
|
||||||
|
editor.editorState.logConfiguration
|
||||||
|
..level = LogLevel.all
|
||||||
|
..handler = (message) {
|
||||||
|
logs.add(message);
|
||||||
|
};
|
||||||
|
|
||||||
|
Log.editor.debug(text);
|
||||||
|
expect(logs.last.contains('DEBUG'), true);
|
||||||
|
expect(logs.length, 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('test LogLevel.all', () {
|
||||||
|
const text = 'Welcome to Appflowy 😁';
|
||||||
|
|
||||||
|
final List<String> logs = [];
|
||||||
|
LogConfiguration()
|
||||||
|
..level = LogLevel.all
|
||||||
|
..handler = (message) {
|
||||||
|
logs.add(message);
|
||||||
|
};
|
||||||
|
|
||||||
|
Log.editor.debug(text);
|
||||||
|
expect(logs.last.contains('DEBUG'), true);
|
||||||
|
Log.editor.info(text);
|
||||||
|
expect(logs.last.contains('INFO'), true);
|
||||||
|
Log.editor.warn(text);
|
||||||
|
expect(logs.last.contains('WARN'), true);
|
||||||
|
Log.editor.error(text);
|
||||||
|
expect(logs.last.contains('ERROR'), true);
|
||||||
|
|
||||||
|
expect(logs.length, 4);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('test LogLevel.off', () {
|
||||||
|
const text = 'Welcome to Appflowy 😁';
|
||||||
|
|
||||||
|
final List<String> logs = [];
|
||||||
|
LogConfiguration()
|
||||||
|
..level = LogLevel.off
|
||||||
|
..handler = (message) {
|
||||||
|
logs.add(message);
|
||||||
|
};
|
||||||
|
|
||||||
|
Log.editor.debug(text);
|
||||||
|
Log.editor.info(text);
|
||||||
|
Log.editor.warn(text);
|
||||||
|
Log.editor.error(text);
|
||||||
|
|
||||||
|
expect(logs.length, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('test LogLevel.error', () {
|
||||||
|
const text = 'Welcome to Appflowy 😁';
|
||||||
|
|
||||||
|
final List<String> logs = [];
|
||||||
|
LogConfiguration()
|
||||||
|
..level = LogLevel.error
|
||||||
|
..handler = (message) {
|
||||||
|
logs.add(message);
|
||||||
|
};
|
||||||
|
|
||||||
|
Log.editor.debug(text);
|
||||||
|
Log.editor.info(text);
|
||||||
|
Log.editor.warn(text);
|
||||||
|
Log.editor.error(text);
|
||||||
|
|
||||||
|
expect(logs.length, 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('test LogLevel.warn', () {
|
||||||
|
const text = 'Welcome to Appflowy 😁';
|
||||||
|
|
||||||
|
final List<String> logs = [];
|
||||||
|
LogConfiguration()
|
||||||
|
..level = LogLevel.warn
|
||||||
|
..handler = (message) {
|
||||||
|
logs.add(message);
|
||||||
|
};
|
||||||
|
|
||||||
|
Log.editor.debug(text);
|
||||||
|
Log.editor.info(text);
|
||||||
|
Log.editor.warn(text);
|
||||||
|
Log.editor.error(text);
|
||||||
|
|
||||||
|
expect(logs.length, 2);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('test LogLevel.info', () {
|
||||||
|
const text = 'Welcome to Appflowy 😁';
|
||||||
|
|
||||||
|
final List<String> logs = [];
|
||||||
|
LogConfiguration()
|
||||||
|
..level = LogLevel.info
|
||||||
|
..handler = (message) {
|
||||||
|
logs.add(message);
|
||||||
|
};
|
||||||
|
|
||||||
|
Log.editor.debug(text);
|
||||||
|
Log.editor.info(text);
|
||||||
|
Log.editor.warn(text);
|
||||||
|
Log.editor.error(text);
|
||||||
|
|
||||||
|
expect(logs.length, 3);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('test LogLevel.debug', () {
|
||||||
|
const text = 'Welcome to Appflowy 😁';
|
||||||
|
|
||||||
|
final List<String> logs = [];
|
||||||
|
LogConfiguration()
|
||||||
|
..level = LogLevel.debug
|
||||||
|
..handler = (message) {
|
||||||
|
logs.add(message);
|
||||||
|
};
|
||||||
|
|
||||||
|
Log.editor.debug(text);
|
||||||
|
Log.editor.info(text);
|
||||||
|
Log.editor.warn(text);
|
||||||
|
Log.editor.error(text);
|
||||||
|
|
||||||
|
expect(logs.length, 4);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('test logger', () {
|
||||||
|
const text = 'Welcome to Appflowy 😁';
|
||||||
|
|
||||||
|
final List<String> logs = [];
|
||||||
|
LogConfiguration()
|
||||||
|
..level = LogLevel.all
|
||||||
|
..handler = (message) {
|
||||||
|
logs.add(message);
|
||||||
|
};
|
||||||
|
|
||||||
|
Log.editor.debug(text);
|
||||||
|
expect(logs.last.contains('editor'), true);
|
||||||
|
|
||||||
|
Log.selection.debug(text);
|
||||||
|
expect(logs.last.contains('selection'), true);
|
||||||
|
|
||||||
|
Log.keyboard.debug(text);
|
||||||
|
expect(logs.last.contains('keyboard'), true);
|
||||||
|
|
||||||
|
Log.input.debug(text);
|
||||||
|
expect(logs.last.contains('input'), true);
|
||||||
|
|
||||||
|
Log.scroll.debug(text);
|
||||||
|
expect(logs.last.contains('scroll'), true);
|
||||||
|
|
||||||
|
Log.ui.debug(text);
|
||||||
|
expect(logs.last.contains('ui'), true);
|
||||||
|
|
||||||
|
expect(logs.length, 6);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user