Skip to content

Commit 4188c34

Browse files
authored
fix: QuillEditor doesn't respect the system keyboard brightness by default on iOS (singerdmx#2522)
* fix: QuillEditor doesn't respect the system keyboard brightness by default on iOS * test: add tests for keyboardAppearance, characterShortcutEvents and spaceShortcutEvents are no longer required, Deprecate in favor of
1 parent 462fea3 commit 4188c34

File tree

8 files changed

+186
-80
lines changed

8 files changed

+186
-80
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1010
1111
## [Unreleased]
1212

13+
### Fixed
14+
15+
- **[iOS]** `QuillEditor` doesn't respect the system keyboard brightness by default [#2522](https://github.com/singerdmx/flutter-quill/pull/2522).
16+
- Add a default empty list for `characterShortcutEvents` and `spaceShortcutEvents` in `QuillRawEditorConfig` [#2522](https://github.com/singerdmx/flutter-quill/pull/2522).
17+
- Deprecate `QuillEditorState.configurations` in favor of `QuillEditorState.config`.
18+
1319
## [11.1.1] - 2025-03-19
1420

1521
### Fixed

example/pubspec.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ packages:
252252
path: "../flutter_quill_test"
253253
relative: true
254254
source: path
255-
version: "11.0.0"
255+
version: "11.1.0"
256256
flutter_test:
257257
dependency: "direct dev"
258258
description: flutter

lib/src/editor/config/editor_config.dart

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class QuillEditorConfig {
4444
this.maxContentWidth,
4545
this.customStyles,
4646
this.textCapitalization = TextCapitalization.sentences,
47-
this.keyboardAppearance = Brightness.light,
47+
this.keyboardAppearance,
4848
this.scrollPhysics,
4949
this.onLaunchUrl,
5050
this.onTapDown,
@@ -312,17 +312,17 @@ class QuillEditorConfig {
312312
///
313313
/// Defaults to Material/Cupertino App Brightness.
314314
///
315-
/// The keyboardd appearance will set using the following:
315+
/// The keyboard appearance will set using the following:
316316
///
317317
/// ```dart
318-
/// widget.configurations.keyboardAppearance ??
318+
/// widget.config.keyboardAppearance ??
319319
/// CupertinoTheme.maybeBrightnessOf(context) ??
320320
/// Theme.of(context).brightness
321321
/// ```
322322
///
323323
/// See also: https://github.com/flutter/flutter/blob/06b9f7ba0bef2b5b44a643c73f4295a096de1202/packages/flutter/lib/src/services/text_input.dart#L621-L626
324324
/// and [QuillRawEditorConfig.keyboardAppearance]
325-
final Brightness keyboardAppearance;
325+
final Brightness? keyboardAppearance;
326326

327327
/// The [ScrollPhysics] to use when vertically scrolling the input.
328328
///

lib/src/editor/editor.dart

Lines changed: 62 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -192,21 +192,23 @@ class QuillEditorState extends State<QuillEditor>
192192

193193
QuillController get controller => widget.controller;
194194

195+
@Deprecated('Use config instead')
195196
QuillEditorConfig get configurations => widget.config;
197+
QuillEditorConfig get config => widget.config;
196198

197199
@override
198200
void initState() {
199201
super.initState();
200-
_editorKey = configurations.editorKey ?? GlobalKey<EditorState>();
202+
_editorKey = config.editorKey ?? GlobalKey<EditorState>();
201203
_selectionGestureDetectorBuilder =
202204
_QuillEditorSelectionGestureDetectorBuilder(
203205
this,
204-
configurations.detectWordBoundary,
206+
config.detectWordBoundary,
205207
);
206208

207209
final focusNode = widget.focusNode;
208210

209-
if (configurations.autoFocus) {
211+
if (config.autoFocus) {
210212
focusNode.requestFocus();
211213
}
212214

@@ -222,7 +224,7 @@ class QuillEditorState extends State<QuillEditor>
222224
Widget build(BuildContext context) {
223225
final theme = Theme.of(context);
224226
final selectionTheme =
225-
configurations.textSelectionThemeData ?? TextSelectionTheme.of(context);
227+
config.textSelectionThemeData ?? TextSelectionTheme.of(context);
226228

227229
TextSelectionControls textSelectionControls;
228230
bool paintCursorAboveText;
@@ -252,8 +254,8 @@ class QuillEditorState extends State<QuillEditor>
252254
theme.colorScheme.primary.withValues(alpha: 0.40);
253255
}
254256

255-
final showSelectionToolbar = configurations.enableInteractiveSelection &&
256-
configurations.enableSelectionToolbar;
257+
final showSelectionToolbar =
258+
config.enableInteractiveSelection && config.enableSelectionToolbar;
257259

258260
final child = QuillRawEditor(
259261
key: _editorKey,
@@ -265,71 +267,68 @@ class QuillEditorState extends State<QuillEditor>
265267
customLeadingBuilder: widget.config.customLeadingBlockBuilder,
266268
focusNode: widget.focusNode,
267269
scrollController: widget.scrollController,
268-
scrollable: configurations.scrollable,
269-
enableAlwaysIndentOnTab: configurations.enableAlwaysIndentOnTab,
270-
scrollBottomInset: configurations.scrollBottomInset,
271-
padding: configurations.padding,
270+
scrollable: config.scrollable,
271+
enableAlwaysIndentOnTab: config.enableAlwaysIndentOnTab,
272+
scrollBottomInset: config.scrollBottomInset,
273+
padding: config.padding,
272274
readOnly: controller.readOnly,
273-
checkBoxReadOnly: configurations.checkBoxReadOnly,
274-
disableClipboard: configurations.disableClipboard,
275-
placeholder: configurations.placeholder,
276-
onLaunchUrl: configurations.onLaunchUrl,
275+
checkBoxReadOnly: config.checkBoxReadOnly,
276+
disableClipboard: config.disableClipboard,
277+
placeholder: config.placeholder,
278+
onLaunchUrl: config.onLaunchUrl,
277279
contextMenuBuilder: showSelectionToolbar
278-
? (configurations.contextMenuBuilder ??
280+
? (config.contextMenuBuilder ??
279281
QuillRawEditorConfig.defaultContextMenuBuilder)
280282
: null,
281283
showSelectionHandles: isMobile,
282-
showCursor: configurations.showCursor ?? true,
284+
showCursor: config.showCursor ?? true,
283285
cursorStyle: CursorStyle(
284286
color: cursorColor,
285287
backgroundColor: Colors.grey,
286288
width: 2,
287289
radius: cursorRadius,
288290
offset: cursorOffset,
289-
paintAboveText:
290-
configurations.paintCursorAboveText ?? paintCursorAboveText,
291+
paintAboveText: config.paintCursorAboveText ?? paintCursorAboveText,
291292
opacityAnimates: cursorOpacityAnimates,
292293
),
293-
textCapitalization: configurations.textCapitalization,
294-
minHeight: configurations.minHeight,
295-
maxHeight: configurations.maxHeight,
296-
maxContentWidth: configurations.maxContentWidth,
297-
customStyles: configurations.customStyles,
298-
expands: configurations.expands,
299-
autoFocus: configurations.autoFocus,
294+
textCapitalization: config.textCapitalization,
295+
minHeight: config.minHeight,
296+
maxHeight: config.maxHeight,
297+
maxContentWidth: config.maxContentWidth,
298+
customStyles: config.customStyles,
299+
expands: config.expands,
300+
autoFocus: config.autoFocus,
300301
selectionColor: selectionColor,
301-
selectionCtrls:
302-
configurations.textSelectionControls ?? textSelectionControls,
303-
keyboardAppearance: configurations.keyboardAppearance,
304-
enableInteractiveSelection: configurations.enableInteractiveSelection,
305-
scrollPhysics: configurations.scrollPhysics,
302+
selectionCtrls: config.textSelectionControls ?? textSelectionControls,
303+
keyboardAppearance: config.keyboardAppearance,
304+
enableInteractiveSelection: config.enableInteractiveSelection,
305+
scrollPhysics: config.scrollPhysics,
306306
embedBuilder: _getEmbedBuilder,
307-
textSpanBuilder: configurations.textSpanBuilder,
308-
linkActionPickerDelegate: configurations.linkActionPickerDelegate,
309-
customStyleBuilder: configurations.customStyleBuilder,
310-
customRecognizerBuilder: configurations.customRecognizerBuilder,
311-
floatingCursorDisabled: configurations.floatingCursorDisabled,
312-
customShortcuts: configurations.customShortcuts,
313-
customActions: configurations.customActions,
314-
customLinkPrefixes: configurations.customLinkPrefixes,
315-
onTapOutsideEnabled: configurations.onTapOutsideEnabled,
316-
onTapOutside: configurations.onTapOutside,
317-
dialogTheme: configurations.dialogTheme,
318-
contentInsertionConfiguration:
319-
configurations.contentInsertionConfiguration,
320-
enableScribble: configurations.enableScribble,
321-
onScribbleActivated: configurations.onScribbleActivated,
322-
scribbleAreaInsets: configurations.scribbleAreaInsets,
323-
readOnlyMouseCursor: configurations.readOnlyMouseCursor,
324-
textInputAction: configurations.textInputAction,
325-
onPerformAction: configurations.onPerformAction,
307+
textSpanBuilder: config.textSpanBuilder,
308+
linkActionPickerDelegate: config.linkActionPickerDelegate,
309+
customStyleBuilder: config.customStyleBuilder,
310+
customRecognizerBuilder: config.customRecognizerBuilder,
311+
floatingCursorDisabled: config.floatingCursorDisabled,
312+
customShortcuts: config.customShortcuts,
313+
customActions: config.customActions,
314+
customLinkPrefixes: config.customLinkPrefixes,
315+
onTapOutsideEnabled: config.onTapOutsideEnabled,
316+
onTapOutside: config.onTapOutside,
317+
dialogTheme: config.dialogTheme,
318+
contentInsertionConfiguration: config.contentInsertionConfiguration,
319+
enableScribble: config.enableScribble,
320+
onScribbleActivated: config.onScribbleActivated,
321+
scribbleAreaInsets: config.scribbleAreaInsets,
322+
readOnlyMouseCursor: config.readOnlyMouseCursor,
323+
textInputAction: config.textInputAction,
324+
onPerformAction: config.onPerformAction,
326325
),
327326
);
328327

329328
final editor = selectionEnabled
330329
? _selectionGestureDetectorBuilder.build(
331330
behavior: HitTestBehavior.translucent,
332-
detectWordBoundary: configurations.detectWordBoundary,
331+
detectWordBoundary: config.detectWordBoundary,
333332
child: child,
334333
)
335334
: child;
@@ -352,7 +351,7 @@ class QuillEditorState extends State<QuillEditor>
352351
}
353352

354353
EmbedBuilder _getEmbedBuilder(Embed node) {
355-
final builders = configurations.embedBuilders;
354+
final builders = config.embedBuilders;
356355

357356
if (builders != null) {
358357
for (final builder in builders) {
@@ -362,7 +361,7 @@ class QuillEditorState extends State<QuillEditor>
362361
}
363362
}
364363

365-
final unknownEmbedBuilder = configurations.unknownEmbedBuilder;
364+
final unknownEmbedBuilder = config.unknownEmbedBuilder;
366365
if (unknownEmbedBuilder != null) {
367366
return unknownEmbedBuilder;
368367
}
@@ -382,7 +381,7 @@ class QuillEditorState extends State<QuillEditor>
382381
bool get forcePressEnabled => false;
383382

384383
@override
385-
bool get selectionEnabled => configurations.enableInteractiveSelection;
384+
bool get selectionEnabled => config.enableInteractiveSelection;
386385

387386
/// Throws [StateError] if [_editorKey] is not connected to [QuillRawEditor] correctly.
388387
///
@@ -423,9 +422,9 @@ class _QuillEditorSelectionGestureDetectorBuilder
423422

424423
@override
425424
void onSingleLongTapMoveUpdate(LongPressMoveUpdateDetails details) {
426-
if (_state.configurations.onSingleLongTapMoveUpdate != null) {
425+
if (_state.config.onSingleLongTapMoveUpdate != null) {
427426
if (renderEditor != null &&
428-
_state.configurations.onSingleLongTapMoveUpdate!(
427+
_state.config.onSingleLongTapMoveUpdate!(
429428
details,
430429
renderEditor!.getPositionForOffset,
431430
)) {
@@ -474,9 +473,9 @@ class _QuillEditorSelectionGestureDetectorBuilder
474473

475474
@override
476475
void onTapDown(TapDownDetails details) {
477-
if (_state.configurations.onTapDown != null) {
476+
if (_state.config.onTapDown != null) {
478477
if (renderEditor != null &&
479-
_state.configurations.onTapDown!(
478+
_state.config.onTapDown!(
480479
details,
481480
renderEditor!.getPositionForOffset,
482481
)) {
@@ -495,9 +494,9 @@ class _QuillEditorSelectionGestureDetectorBuilder
495494

496495
@override
497496
void onSingleTapUp(TapUpDetails details) {
498-
if (_state.configurations.onTapUp != null &&
497+
if (_state.config.onTapUp != null &&
499498
renderEditor != null &&
500-
_state.configurations.onTapUp!(
499+
_state.config.onTapUp!(
501500
details,
502501
renderEditor!.getPositionForOffset,
503502
)) {
@@ -583,9 +582,9 @@ class _QuillEditorSelectionGestureDetectorBuilder
583582

584583
@override
585584
void onSingleLongTapStart(LongPressStartDetails details) {
586-
if (_state.configurations.onSingleLongTapStart != null) {
585+
if (_state.config.onSingleLongTapStart != null) {
587586
if (renderEditor != null &&
588-
_state.configurations.onSingleLongTapStart!(
587+
_state.config.onSingleLongTapStart!(
589588
details,
590589
renderEditor!.getPositionForOffset,
591590
)) {
@@ -608,9 +607,9 @@ class _QuillEditorSelectionGestureDetectorBuilder
608607

609608
@override
610609
void onSingleLongTapEnd(LongPressEndDetails details) {
611-
if (_state.configurations.onSingleLongTapEnd != null) {
610+
if (_state.config.onSingleLongTapEnd != null) {
612611
if (renderEditor != null) {
613-
if (_state.configurations.onSingleLongTapEnd!(
612+
if (_state.config.onSingleLongTapEnd!(
614613
details,
615614
renderEditor!.getPositionForOffset,
616615
)) {

lib/src/editor/raw_editor/config/raw_editor_config.dart

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ class QuillRawEditorConfig {
2828
required this.embedBuilder,
2929
required this.textSpanBuilder,
3030
required this.autoFocus,
31-
required this.characterShortcutEvents,
32-
required this.spaceShortcutEvents,
31+
this.characterShortcutEvents = const [],
32+
this.spaceShortcutEvents = const [],
3333
@experimental this.onKeyPressed,
3434
this.showCursor = true,
3535
this.scrollable = true,
@@ -315,10 +315,10 @@ class QuillRawEditorConfig {
315315
///
316316
/// Defaults to Material/Cupertino App Brightness.
317317
///
318-
/// The keyboardd appearance will set using the following:
318+
/// The keyboard appearance will set using the following:
319319
///
320320
/// ```dart
321-
/// widget.configurations.keyboardAppearance ??
321+
/// widget.config.keyboardAppearance ??
322322
/// CupertinoTheme.maybeBrightnessOf(context) ??
323323
/// Theme.of(context).brightness
324324
/// ```

lib/src/editor/raw_editor/raw_editor_state_text_input_client_mixin.dart

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import 'dart:ui' show lerpDouble;
22

3-
import 'package:flutter/animation.dart' show Curves;
4-
import 'package:flutter/cupertino.dart' show CupertinoTheme;
5-
import 'package:flutter/foundation.dart' show ValueNotifier, kIsWeb;
6-
import 'package:flutter/material.dart' show Theme;
7-
import 'package:flutter/scheduler.dart' show SchedulerBinding;
3+
import 'package:flutter/cupertino.dart';
4+
import 'package:flutter/foundation.dart';
5+
import 'package:flutter/material.dart';
6+
import 'package:flutter/scheduler.dart';
87
import 'package:flutter/services.dart';
8+
import 'package:meta/meta.dart';
99

1010
import '../../delta/delta_diff.dart';
1111
import '../../document/document.dart';
@@ -62,6 +62,14 @@ mixin RawEditorStateTextInputClientMixin on EditorState
6262
}
6363
}
6464

65+
/// This setting is only honored on iOS devices.
66+
@visibleForTesting
67+
@internal
68+
Brightness createKeyboardAppearance() =>
69+
widget.config.keyboardAppearance ??
70+
CupertinoTheme.maybeBrightnessOf(context) ??
71+
Theme.of(context).brightness;
72+
6573
void openConnectionIfNeeded() {
6674
if (!shouldCreateInputConnection) {
6775
return;
@@ -76,9 +84,7 @@ mixin RawEditorStateTextInputClientMixin on EditorState
7684
readOnly: widget.config.readOnly,
7785
inputAction: widget.config.textInputAction,
7886
enableSuggestions: !widget.config.readOnly,
79-
keyboardAppearance: widget.config.keyboardAppearance ??
80-
CupertinoTheme.maybeBrightnessOf(context) ??
81-
Theme.of(context).brightness,
87+
keyboardAppearance: createKeyboardAppearance(),
8288
textCapitalization: widget.config.textCapitalization,
8389
allowedMimeTypes: widget.config.contentInsertionConfiguration == null
8490
? const <String>[]

0 commit comments

Comments
 (0)