feat: word counter service (#705)
* feat: word counter service * chore: minor improvement * test: add expect for stop() * fix: code review
This commit is contained in:
parent
7000a19d81
commit
9c27b8e309
1 changed files with 310 additions and 59 deletions
|
|
@ -1,9 +1,11 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:example/pages/desktop_editor.dart';
|
||||
import 'package:example/pages/mobile_editor.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
|
||||
class Editor extends StatefulWidget {
|
||||
const Editor({
|
||||
|
|
@ -25,58 +27,118 @@ class Editor extends StatefulWidget {
|
|||
}
|
||||
|
||||
class _EditorState extends State<Editor> {
|
||||
bool isInitialized = false;
|
||||
|
||||
EditorState? editorState;
|
||||
WordCountService? wordCountService;
|
||||
|
||||
@override
|
||||
void didUpdateWidget(covariant Editor oldWidget) {
|
||||
if (oldWidget.jsonString != widget.jsonString) {
|
||||
editorState = null;
|
||||
isInitialized = false;
|
||||
}
|
||||
super.didUpdateWidget(oldWidget);
|
||||
}
|
||||
|
||||
int wordCount = 0;
|
||||
int charCount = 0;
|
||||
|
||||
void registerWordCounter() {
|
||||
wordCountService?.removeListener(onWordCountUpdate);
|
||||
wordCountService?.dispose();
|
||||
|
||||
wordCountService = WordCountService(editorState: editorState!)..register();
|
||||
wordCountService!.addListener(onWordCountUpdate);
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
onWordCountUpdate();
|
||||
});
|
||||
}
|
||||
|
||||
void onWordCountUpdate() {
|
||||
setState(() {
|
||||
wordCount = wordCountService!.wordCount;
|
||||
charCount = wordCountService!.charCount;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
editorState?.dispose();
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
color: Colors.white,
|
||||
child: FutureBuilder<String>(
|
||||
future: widget.jsonString,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData &&
|
||||
snapshot.connectionState == ConnectionState.done) {
|
||||
EditorState editorState = EditorState(
|
||||
document: Document.fromJson(
|
||||
Map<String, Object>.from(
|
||||
json.decode(snapshot.data!),
|
||||
),
|
||||
),
|
||||
);
|
||||
editorState.logConfiguration
|
||||
..handler = debugPrint
|
||||
..level = LogLevel.off;
|
||||
return Stack(
|
||||
children: [
|
||||
ColoredBox(
|
||||
color: Colors.white,
|
||||
child: FutureBuilder<String>(
|
||||
future: widget.jsonString,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData &&
|
||||
snapshot.connectionState == ConnectionState.done) {
|
||||
if (!isInitialized || editorState == null) {
|
||||
isInitialized = true;
|
||||
EditorState editorState = EditorState(
|
||||
document: Document.fromJson(
|
||||
Map<String, Object>.from(
|
||||
json.decode(snapshot.data!),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
editorState.transactionStream.listen((event) {
|
||||
if (event.$1 == TransactionTime.after) {
|
||||
widget.onEditorStateChange(editorState);
|
||||
editorState.logConfiguration
|
||||
..handler = debugPrint
|
||||
..level = LogLevel.off;
|
||||
|
||||
editorState.transactionStream.listen((event) {
|
||||
if (event.$1 == TransactionTime.after) {
|
||||
widget.onEditorStateChange(editorState);
|
||||
}
|
||||
});
|
||||
|
||||
this.editorState = editorState;
|
||||
registerWordCounter();
|
||||
}
|
||||
|
||||
if (PlatformExtension.isDesktopOrWeb) {
|
||||
return DesktopEditor(
|
||||
editorState: editorState!,
|
||||
textDirection: widget.textDirection,
|
||||
);
|
||||
} else if (PlatformExtension.isMobile) {
|
||||
return MobileEditor(editorState: editorState!);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.editorState = editorState;
|
||||
|
||||
if (PlatformExtension.isDesktopOrWeb) {
|
||||
return DesktopEditor(
|
||||
editorState: editorState,
|
||||
textDirection: widget.textDirection,
|
||||
);
|
||||
} else if (PlatformExtension.isMobile) {
|
||||
return MobileEditor(
|
||||
editorState: editorState,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return const SizedBox.shrink();
|
||||
},
|
||||
),
|
||||
return const SizedBox.shrink();
|
||||
},
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 2, horizontal: 12),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.black.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: const Radius.circular(8),
|
||||
bottomLeft: PlatformExtension.isMobile
|
||||
? const Radius.circular(8)
|
||||
: Radius.zero,
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
'Word Count: $wordCount | Character Count: $charCount',
|
||||
style: const TextStyle(fontSize: 11),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue