Skip to content

Commit 64e3170

Browse files
committed
Add doc comments and resolve analyzer issues
1 parent dff3bb4 commit 64e3170

27 files changed

+355
-311
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Boustro
1+
# boustro
22

33
Boustro is a rich text editor for Flutter.
44

@@ -31,7 +31,7 @@ Boustro is split into 3 packages that are layered on top of each other.
3131
text possible and data structures to represent text formats and formatted
3232
text. The structure is similar to Android's [Spannable](https://developer.android.com/reference/android/text/Spannable).
3333
1. [boustro](packages/boustro): The actual rich text editor.
34-
1. [boustro_starter](packages/boustro_starter): Attributes, line modifiers and embeds to get started with.
34+
1. [boustro_starter](packages/boustro_starter): Attributes, line modifiers and embeds to get started with boustro.
3535

3636
## Limitations
3737

docs/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Boustro Documentation
2+
3+
This is a stub for in-depth documentation for boustro.
4+

example/lib/main.dart

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import 'package:boustro/src/scope.dart';
2-
import 'package:built_collection/built_collection.dart';
31
import 'package:boustro/boustro.dart';
42
import 'package:boustro_starter/boustro_starter.dart';
53
import 'package:boustro_starter/toolbar_items.dart' as toolbar_items;
@@ -114,9 +112,9 @@ class BulletListParagraphHandler extends LineParagraphModifier {
114112
Map<String, Object> properties,
115113
Widget child,
116114
) {
117-
return CharacterLeadingMarginModifier(
115+
return LeadingTextModifier(
118116
padding: 8,
119-
character: '\u2022',
117+
text: '\u2022',
120118
child: child,
121119
);
122120
}

packages/analysis_options.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ linter:
2525
avoid_annotating_with_dynamic: false
2626
avoid_as: false
2727
avoid_returning_null: false
28+
cascade_invocations: false
29+
flutter_style_todos: false
2830
lines_longer_than_80_chars: false
31+
prefer_constructors_over_static_methods: false
2932
prefer_double_quotes: false
3033
prefer_expression_function_bodies: false
31-
flutter_style_todos: false
3234
unnecessary_final: false
33-
unnecessary_this: false
34-
prefer_constructors_over_static_methods: false

packages/boustro/lib/src/context.dart

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import 'package:flutter/widgets.dart';
44

55
import 'document.dart';
66
import 'scope.dart';
7-
import 'widgets/document_controller.dart';
87
import 'widgets/editor.dart';
98

109
/// Determines how a [BoustroEditor] displays a
@@ -17,7 +16,7 @@ class BoustroContext {
1716
List<ParagraphEmbedBuilder>? embedHandlers,
1817
}) : this._(
1918
lineHandlers ?? const [],
20-
{for (var h in embedHandlers ?? <ParagraphEmbedBuilder>[]) h.key: h},
19+
{for (var h in embedHandlers ?? <ParagraphEmbedBuilder>[]) h.type: h},
2120
);
2221

2322
BoustroContext._(
@@ -40,10 +39,11 @@ class BoustroContext {
4039
///
4140
/// Each key should map to one handler.
4241
abstract class ParagraphEmbedBuilder {
42+
/// Constant base constructor for implementations.
4343
const ParagraphEmbedBuilder();
4444

4545
/// Identifier for this embed.
46-
String get key;
46+
String get type;
4747

4848
/// Function that builds the embed widget.
4949
Widget buildEmbed(
@@ -53,7 +53,9 @@ abstract class ParagraphEmbedBuilder {
5353
]);
5454
}
5555

56+
/// Wraps a line to modify how it's displayed.
5657
abstract class LineParagraphModifier {
58+
/// Constant base constructor for implementations.
5759
const LineParagraphModifier();
5860

5961
/// Determines the order in which line handlers are applied.

packages/boustro/lib/src/convert/convert_delta.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ class EmbedCodec {
5454
/// Create an embed codec.
5555
const EmbedCodec(this.key, this.decoder, this.encoder);
5656

57-
/// Identifies the type of the embed. See [ParagraphEmbedBuilder.key].
57+
/// Identifies the type of the embed. See [ParagraphEmbedBuilder.type].
5858
final String key;
5959

6060
/// Decoder for the embed value.

packages/boustro/lib/src/document.dart

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ import 'package:equatable/equatable.dart';
33
import 'package:flutter/foundation.dart';
44
import 'package:flutter_spanned_controller/flutter_spanned_controller.dart';
55

6+
import 'context.dart';
7+
68
/// Rich text represented as a list of [BoustroParagraph]s.
9+
@immutable
710
class BoustroDocument {
811
/// Create a new boustro document.
912
const BoustroDocument(this.paragraphs);
@@ -12,7 +15,7 @@ class BoustroDocument {
1215
final BuiltList<BoustroParagraph> paragraphs;
1316
}
1417

15-
/// A paragraph in a [BoustroDocument]. Is either a [BoustroLine] for rich text
18+
/// A paragraph in a [BoustroDocument]. Is either a [BoustroLine] for rich text,
1619
/// or a [BoustroParagraphEmbed] for other content.
1720
@immutable
1821
abstract class BoustroParagraph extends Equatable {
@@ -33,33 +36,34 @@ abstract class BoustroParagraph extends Equatable {
3336
) =>
3437
BoustroParagraphEmbed(type, value);
3538

39+
/// Execute [line] if this is a [BoustroLine] and [embed] if this is a
40+
/// [BoustroParagraphEmbed].
3641
T match<T>({
3742
required T Function(BoustroLine) line,
3843
required T Function(BoustroParagraphEmbed) embed,
3944
});
4045

46+
/// Same as [match], but directly get the members of this paragraph.
4147
T deconstruct<T>({
4248
required T Function(
4349
String text, SpanList spans, BuiltMap<String, Object> properties)
4450
line,
4551
required T Function(String type, Object value) embed,
4652
});
47-
48-
int get length => match(
49-
embed: (_) => 1,
50-
line: (l) => l.text.length,
51-
);
5253
}
5354

55+
/// Immutable representation of a line of rich text in a [BoustroDocument].
5456
@immutable
5557
class BoustroLine extends BoustroParagraph {
58+
/// Create a boustro line.
5659
BoustroLine(
5760
this.text,
5861
this.spanList, {
5962
BuiltMap<String, Object>? properties,
6063
}) : properties = properties ?? BuiltMap<String, Object>(),
6164
super._();
6265

66+
/// Create a boustro line with the text and spans of [spannedText].
6367
BoustroLine.fromSpanned(
6468
SpannedString spannedText, {
6569
BuiltMap<String, Object>? properties,
@@ -100,15 +104,32 @@ class BoustroLine extends BoustroParagraph {
100104
}
101105
}
102106

107+
/// Immutable representation of an embed in boustro.
108+
///
109+
/// Embeds are represented with a [type] that's used to find the matching
110+
/// [ParagraphEmbedBuilder] and a [value] which the builder uses to build a
111+
/// widget. The expected runtime type of [value] should be specified by the
112+
/// builder.
103113
@immutable
104114
class BoustroParagraphEmbed extends BoustroParagraph {
115+
/// Create an embed.
105116
const BoustroParagraphEmbed(this.type, this.value) : super._();
106117

118+
/// Create a copy of this embed with [this.value] replaced with [value].
107119
BoustroParagraphEmbed withValue(Object value) {
108120
return BoustroParagraphEmbed(type, value);
109121
}
110122

123+
/// Type of the embed.
124+
///
125+
/// Matched with [ParagraphEmbedBuilder.type] to find the builder that can
126+
/// translate [value] into a widget.
111127
final String type;
128+
129+
/// Value of the embed.
130+
///
131+
/// Can be any type, but should be of a type expected by the matching builder
132+
/// for [type].
112133
final Object value;
113134

114135
@override

packages/boustro/lib/src/result.dart

Lines changed: 0 additions & 25 deletions
This file was deleted.

packages/boustro/lib/src/scope.dart

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,52 @@
1+
import 'package:flutter/foundation.dart';
12
import 'package:flutter/widgets.dart';
23

4+
import 'document.dart';
35
import 'widgets/document_controller.dart';
6+
import 'widgets/editor.dart';
47

8+
/// Inherited widget that carries information about a boustro document.
9+
@immutable
510
class BoustroScope extends InheritedWidget {
6-
BoustroScope.editable({
7-
required DocumentController controller,
11+
/// Create a scope for an editable document with a document controller.
12+
const BoustroScope.editable({
13+
Key? key,
14+
required DocumentController this.controller,
815
required Widget child,
9-
}) : controller = controller,
10-
super(child: child);
16+
}) : document = null,
17+
super(key: key, child: child);
1118

12-
BoustroScope.readonly({
19+
/// Create a scope for a read-only document with a boustro document controller.
20+
const BoustroScope.readonly({
21+
Key? key,
22+
required BoustroDocument this.document,
1323
required Widget child,
1424
}) : controller = null,
15-
super(child: child);
25+
super(key: key, child: child);
1626

27+
/// Document controller of the editor. Null if [BoustroScope.readonly] was
28+
/// used.
1729
final DocumentController? controller;
1830

19-
bool get editable => controller != null;
31+
/// Document of the [BoustroView]. Null if [BoustroScope.readonly] was
32+
/// used.
33+
final BoustroDocument? document;
2034

35+
/// True if [BoustroScope.editable] was used, false if [BoustroScope.readonly]
36+
/// was used.
37+
bool get isEditable => controller != null;
38+
39+
/// Call [editable] if [isEditable] is true or [readonly] if it is not.
40+
T match<T>({
41+
required T Function(DocumentController) editable,
42+
required T Function(BoustroDocument) readonly,
43+
}) {
44+
return isEditable ? editable(controller!) : readonly(document!);
45+
}
46+
47+
/// Look for a boustro scope widget up the tree from [context].
48+
///
49+
/// Throws if there is no [BoustroScope] ancestor.
2150
static BoustroScope of(BuildContext context) {
2251
final scope = context.dependOnInheritedWidgetOfExactType<BoustroScope>();
2352
if (scope == null) {
@@ -42,6 +71,17 @@ class BoustroScope extends InheritedWidget {
4271

4372
@override
4473
bool updateShouldNotify(covariant BoustroScope oldWidget) {
45-
return editable != oldWidget.editable;
74+
return isEditable != oldWidget.isEditable;
75+
}
76+
77+
@override
78+
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
79+
super.debugFillProperties(properties);
80+
properties
81+
..add(DiagnosticsProperty<bool>('isEditable', isEditable))
82+
..add(DiagnosticsProperty<DocumentController?>('controller', controller,
83+
defaultValue: null))
84+
..add(DiagnosticsProperty<BoustroDocument?>('document', document,
85+
defaultValue: null));
4686
}
4787
}

packages/boustro/lib/src/widgets/document_controller.dart

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,28 @@ abstract class ParagraphState {
1313
/// Create a paragraph.
1414
const ParagraphState({required FocusNode focusNode}) : _focusNode = focusNode;
1515

16-
/// Use to focus this paragraph.
1716
final FocusNode _focusNode;
17+
18+
/// Manages focus for this paragraph.
1819
FocusNode get focusNode => _focusNode;
1920

21+
/// Discards resources used by this object.
2022
@mustCallSuper
2123
void dispose() {
2224
focusNode.dispose();
2325
}
2426

27+
/// Execute [line] if this is a [LineState] and [embed] if this is an
28+
/// [EmbedState].
2529
T match<T>({
2630
required T Function(LineState) line,
2731
required T Function(EmbedState) embed,
2832
});
2933
}
3034

3135
/// Holds focus node and state for a line of text.
36+
///
37+
/// This is the editable variant of [BoustroLine].
3238
@immutable
3339
class LineState extends ParagraphState {
3440
/// Create a text line.
@@ -39,6 +45,8 @@ class LineState extends ParagraphState {
3945
}) : properties = properties ?? BuiltMap<String, Object>(),
4046
super(focusNode: focusNode);
4147

48+
/// Create a copy of this line state, but with properties set to the new
49+
/// properties.
4250
LineState withProperties(
4351
Map<String, dynamic> properties,
4452
) {
@@ -70,7 +78,9 @@ class LineState extends ParagraphState {
7078
line(this);
7179
}
7280

73-
/// Holds [FocusNode] for a boustro embed.
81+
/// Holds [FocusNode] and content for a boustro embed.
82+
///
83+
/// This is the editable variant of [BoustroParagraphEmbed].
7484
@immutable
7585
class EmbedState extends ParagraphState {
7686
/// Create an embed.
@@ -79,6 +89,8 @@ class EmbedState extends ParagraphState {
7989
required this.content,
8090
}) : super(focusNode: focusNode);
8191

92+
/// Create a copy of this embed state, but with the value of its content set
93+
/// to the new value.
8294
EmbedState withValue(Object value) {
8395
return EmbedState(
8496
focusNode: focusNode,
@@ -89,14 +101,6 @@ class EmbedState extends ParagraphState {
89101
/// Content of the embed.
90102
final BoustroParagraphEmbed content;
91103

92-
@override
93-
void dispose() {
94-
try {
95-
(content.value as dynamic).dispose();
96-
} catch (NoSuchMethodError) {}
97-
super.dispose();
98-
}
99-
100104
@override
101105
T match<T>({
102106
required T Function(LineState) line,
@@ -276,6 +280,7 @@ class DocumentController extends ValueNotifier<BuiltList<ParagraphState>> {
276280
return newLine;
277281
}
278282

283+
/// Set the [LineState.properties] for [line].
279284
void setLineProperties(LineState line, Map<String, dynamic> properties) {
280285
final lineIndex = paragraphs.indexWhere((l) => l is LineState && l == line);
281286
if (lineIndex < 0) {
@@ -290,6 +295,9 @@ class DocumentController extends ValueNotifier<BuiltList<ParagraphState>> {
290295
);
291296
}
292297

298+
/// Remove the focused paragraph.
299+
///
300+
/// Does nothing if [focusedParagraph] is null.
293301
void removeCurrentParagraph() {
294302
final index = focusedParagraphIndex;
295303
if (index != null) {

0 commit comments

Comments
 (0)