Skip to content

Commit 1d2dd15

Browse files
authored
Merge pull request #878 from LucasXu0/logger_refactor
feat: [improvements] integrate logging library in AppFlowyEditor
2 parents edd520a + a404a96 commit 1d2dd15

File tree

16 files changed

+351
-39
lines changed

16 files changed

+351
-39
lines changed

frontend/app_flowy/packages/appflowy_editor/example/lib/main.dart

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,13 @@ class _MyHomePageState extends State<MyHomePage> {
9797
builder: (context, snapshot) {
9898
if (snapshot.hasData) {
9999
final data = Map<String, Object>.from(json.decode(snapshot.data!));
100-
return _buildAppFlowyEditor(EditorState(
101-
document: StateTree.fromJson(data),
102-
));
100+
final editorState = EditorState(document: StateTree.fromJson(data));
101+
editorState.logConfiguration
102+
..level = LogLevel.all
103+
..handler = (message) {
104+
debugPrint(message);
105+
};
106+
return _buildAppFlowyEditor(editorState);
103107
} else {
104108
return const Center(
105109
child: CircularProgressIndicator(),

frontend/app_flowy/packages/appflowy_editor/lib/appflowy_editor.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/// AppFlowyEditor library
22
library appflowy_editor;
33

4+
export 'src/infra/log.dart';
45
export 'src/document/node.dart';
56
export 'src/document/path.dart';
67
export 'src/document/position.dart';

frontend/app_flowy/packages/appflowy_editor/lib/src/editor_state.dart

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import 'dart:async';
2+
import 'package:appflowy_editor/src/infra/log.dart';
23
import 'package:appflowy_editor/src/service/service.dart';
34
import 'package:flutter/material.dart';
45

@@ -48,10 +49,15 @@ class EditorState {
4849
// Service reference.
4950
final service = FlowyService();
5051

52+
/// Configures log output parameters,
53+
/// such as log level and log output callbacks,
54+
/// with this variable.
55+
LogConfiguration get logConfiguration => LogConfiguration();
56+
5157
final UndoManager undoManager = UndoManager();
5258
Selection? _cursorSelection;
5359

54-
/// TODO: only for testing.
60+
// TODO: only for testing.
5561
bool disableSealTimer = false;
5662

5763
Selection? get cursorSelection {
@@ -120,7 +126,7 @@ class EditorState {
120126
_debouncedSealHistoryItemTimer =
121127
Timer(const Duration(milliseconds: 1000), () {
122128
if (undoManager.undoStack.isNonEmpty) {
123-
debugPrint('Seal history item');
129+
Log.editor.debug('Seal history item');
124130
final last = undoManager.undoStack.last;
125131
last.seal();
126132
}
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
import 'package:logging/logging.dart';
2+
3+
enum LogLevel {
4+
off,
5+
error,
6+
warn,
7+
info,
8+
debug,
9+
all,
10+
}
11+
12+
typedef LogHandler = void Function(String message);
13+
14+
/// Manages log service for [AppFlowyEditor]
15+
///
16+
/// Set the log level and config the handler depending on your need.
17+
class LogConfiguration {
18+
LogConfiguration._() {
19+
Logger.root.onRecord.listen((record) {
20+
if (handler != null) {
21+
handler!(
22+
'[${record.level.toLogLevel().name}][${record.loggerName}]: ${record.time}: ${record.message}',
23+
);
24+
}
25+
});
26+
}
27+
28+
factory LogConfiguration() => _logConfiguration;
29+
30+
static final LogConfiguration _logConfiguration = LogConfiguration._();
31+
32+
LogHandler? handler;
33+
34+
LogLevel _level = LogLevel.off;
35+
36+
LogLevel get level => _level;
37+
set level(LogLevel level) {
38+
_level = level;
39+
Logger.root.level = level.toLevel();
40+
}
41+
}
42+
43+
/// For logging message in AppFlowyEditor
44+
class Log {
45+
Log._({
46+
required this.name,
47+
}) : _logger = Logger(name);
48+
49+
final String name;
50+
late final Logger _logger;
51+
52+
/// For logging message related to [AppFlowyEditor].
53+
///
54+
/// For example, uses the logger when registering plugins
55+
/// or handling something related to [EditorState].
56+
static Log editor = Log._(name: 'editor');
57+
58+
/// For logging message related to [AppFlowySelectionService].
59+
///
60+
/// For example, uses the logger when updating or clearing selection.
61+
static Log selection = Log._(name: 'selection');
62+
63+
/// For logging message related to [AppFlowyKeyboardService].
64+
///
65+
/// For example, uses the logger when processing shortcut events.
66+
static Log keyboard = Log._(name: 'keyboard');
67+
68+
/// For logging message related to [AppFlowyInputService].
69+
///
70+
/// For example, uses the logger when processing text inputs.
71+
static Log input = Log._(name: 'input');
72+
73+
/// For logging message related to [AppFlowyScrollService].
74+
///
75+
/// For example, uses the logger when processing scroll events.
76+
static Log scroll = Log._(name: 'scroll');
77+
78+
/// For logging message related to UI.
79+
///
80+
/// For example, uses the logger when building the widget.
81+
static Log ui = Log._(name: 'ui');
82+
83+
void error(String message) => _logger.severe(message);
84+
void warn(String message) => _logger.warning(message);
85+
void info(String message) => _logger.info(message);
86+
void debug(String message) => _logger.fine(message);
87+
}
88+
89+
extension on LogLevel {
90+
Level toLevel() {
91+
switch (this) {
92+
case LogLevel.off:
93+
return Level.OFF;
94+
case LogLevel.error:
95+
return Level.SEVERE;
96+
case LogLevel.warn:
97+
return Level.WARNING;
98+
case LogLevel.info:
99+
return Level.INFO;
100+
case LogLevel.debug:
101+
return Level.FINE;
102+
case LogLevel.all:
103+
return Level.ALL;
104+
}
105+
}
106+
107+
String get name {
108+
switch (this) {
109+
case LogLevel.off:
110+
return 'OFF';
111+
case LogLevel.error:
112+
return 'ERROR';
113+
case LogLevel.warn:
114+
return 'WARN';
115+
case LogLevel.info:
116+
return 'INFO';
117+
case LogLevel.debug:
118+
return 'DEBUG';
119+
case LogLevel.all:
120+
return 'ALL';
121+
}
122+
}
123+
}
124+
125+
extension on Level {
126+
LogLevel toLogLevel() {
127+
if (this == Level.SEVERE) {
128+
return LogLevel.error;
129+
} else if (this == Level.WARNING) {
130+
return LogLevel.warn;
131+
} else if (this == Level.INFO) {
132+
return LogLevel.info;
133+
} else if (this == Level.FINE) {
134+
return LogLevel.debug;
135+
}
136+
return LogLevel.off;
137+
}
138+
}

frontend/app_flowy/packages/appflowy_editor/lib/src/render/rich_text/checkbox_text.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,6 @@ class _CheckboxNodeWidgetState extends State<CheckboxNodeWidget>
8383
name: check ? 'check' : 'uncheck',
8484
),
8585
onTap: () {
86-
debugPrint('[Checkbox] onTap...');
8786
TransactionBuilder(widget.editorState)
8887
..updateNode(widget.textNode, {
8988
StyleKey.checkbox: !check,

frontend/app_flowy/packages/appflowy_editor/lib/src/service/input_service.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import 'package:appflowy_editor/src/infra/log.dart';
12
import 'package:flutter/material.dart';
23
import 'package:flutter/services.dart';
34

@@ -243,7 +244,8 @@ class _AppFlowyInputState extends State<AppFlowyInput>
243244

244245
@override
245246
void updateEditingValueWithDeltas(List<TextEditingDelta> textEditingDeltas) {
246-
debugPrint(textEditingDeltas.map((delta) => delta.toString()).toString());
247+
Log.input
248+
.debug(textEditingDeltas.map((delta) => delta.toString()).toString());
247249

248250
apply(textEditingDeltas);
249251
}

frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers/copy_paste_handler.dart

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import 'package:appflowy_editor/appflowy_editor.dart';
22
import 'package:appflowy_editor/src/infra/html_converter.dart';
33
import 'package:appflowy_editor/src/document/node_iterator.dart';
4+
import 'package:appflowy_editor/src/infra/log.dart';
45
import 'package:flutter/material.dart';
56
import 'package:flutter/services.dart';
67
import 'package:rich_clipboard/rich_clipboard.dart';
@@ -19,10 +20,10 @@ _handleCopy(EditorState editorState) async {
1920
startOffset: selection.start.offset,
2021
endOffset: selection.end.offset)
2122
.toHTMLString();
22-
debugPrint('copy html: $htmlString');
23+
Log.keyboard.debug('copy html: $htmlString');
2324
RichClipboard.setData(RichClipboardData(html: htmlString));
2425
} else {
25-
debugPrint("unimplemented: copy non-text");
26+
Log.keyboard.debug('unimplemented: copy non-text');
2627
}
2728
return;
2829
}
@@ -37,7 +38,7 @@ _handleCopy(EditorState editorState) async {
3738
startOffset: selection.start.offset,
3839
endOffset: selection.end.offset)
3940
.toHTMLString();
40-
debugPrint('copy html: $copyString');
41+
Log.keyboard.debug('copy html: $copyString');
4142
RichClipboard.setData(RichClipboardData(html: copyString));
4243
}
4344

@@ -54,7 +55,7 @@ _pasteHTML(EditorState editorState, String html) {
5455
return;
5556
}
5657

57-
debugPrint('paste html: $html');
58+
Log.keyboard.debug('paste html: $html');
5859
final nodes = HTMLToNodesConverter(html).toNodes();
5960

6061
if (nodes.isEmpty) {
@@ -250,7 +251,6 @@ _handlePastePlainText(EditorState editorState, String plainText) {
250251
/// 1. copy the selected content
251252
/// 2. delete selected content
252253
_handleCut(EditorState editorState) {
253-
debugPrint('cut');
254254
_handleCopy(editorState);
255255
_deleteSelectedContent(editorState);
256256
}

frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers/delete_text_handler.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,6 @@ KeyEventResult _handleDelete(EditorState editorState, RawKeyEvent event) {
9797
if (textNodes.length == 1) {
9898
final textNode = textNodes.first;
9999
if (selection.start.offset >= textNode.delta.length) {
100-
debugPrint("merge next line");
101100
final nextNode = textNode.next;
102101
if (nextNode == null) {
103102
return KeyEventResult.ignored;

frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers/slash_handler.dart

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import 'dart:math';
33
import 'package:appflowy_editor/src/document/node.dart';
44
import 'package:appflowy_editor/src/editor_state.dart';
55
import 'package:appflowy_editor/src/infra/flowy_svg.dart';
6+
import 'package:appflowy_editor/src/infra/log.dart';
67
import 'package:appflowy_editor/src/operation/transaction_builder.dart';
78
import 'package:appflowy_editor/src/render/rich_text/rich_text_style.dart';
89
import 'package:appflowy_editor/src/service/default_text_operations/format_rich_text_style.dart';
@@ -50,12 +51,6 @@ final List<PopupListItem> _popupListItems = [
5051
icon: _popupListIcon('bullets'),
5152
handler: (editorState) => insertBulletedListAfterSelection(editorState),
5253
),
53-
// PopupListItem(
54-
// text: 'Numbered list',
55-
// keywords: ['numbered list'],
56-
// icon: _popupListIcon('number'),
57-
// handler: (editorState) => debugPrint('Not implement yet!'),
58-
// ),
5954
PopupListItem(
6055
text: 'To-do List',
6156
keywords: ['checkbox', 'todo'],
@@ -293,7 +288,7 @@ class _PopupListWidgetState extends State<PopupListWidget> {
293288
}
294289

295290
KeyEventResult _onKey(FocusNode node, RawKeyEvent event) {
296-
debugPrint('slash on key $event');
291+
Log.keyboard.debug('slash command, on key $event');
297292
if (event is! RawKeyDownEvent) {
298293
return KeyEventResult.ignored;
299294
}

frontend/app_flowy/packages/appflowy_editor/lib/src/service/keyboard_service.dart

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import 'package:appflowy_editor/appflowy_editor.dart';
2+
import 'package:appflowy_editor/src/infra/log.dart';
23
import 'package:flutter/services.dart';
34

45
import 'package:flutter/material.dart';
@@ -94,15 +95,13 @@ class _AppFlowyKeyboardState extends State<AppFlowyKeyboard>
9495

9596
@override
9697
KeyEventResult onKey(RawKeyEvent event) {
97-
debugPrint('on keyboard event $event');
98+
Log.keyboard.debug('on keyboard event $event');
9899

99100
if (event is! RawKeyDownEvent) {
100101
return KeyEventResult.ignored;
101102
}
102103

103104
for (final handler in widget.handlers) {
104-
// debugPrint('handle keyboard event $event by $handler');
105-
106105
KeyEventResult result = handler(widget.editorState, event);
107106

108107
switch (result) {
@@ -119,7 +118,7 @@ class _AppFlowyKeyboardState extends State<AppFlowyKeyboard>
119118
}
120119

121120
void _onFocusChange(bool value) {
122-
debugPrint('[KeyBoard Service] focus change $value');
121+
Log.keyboard.debug('on keyboard event focus change $value');
123122
}
124123

125124
KeyEventResult _onKey(FocusNode node, RawKeyEvent event) {

0 commit comments

Comments
 (0)