Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: move members of magnifier feature into a separate files when possible (not final yet) #2251

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions lib/src/editor/editor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ import 'widgets/delegate.dart';
import 'widgets/float_cursor.dart';
import 'widgets/text/text_selection.dart';

part './magnifier/quill_editor_magnifier_ext.dart';

/// Base interface for editable render objects.
abstract class RenderAbstractEditor implements TextLayoutMetrics {
TextSelection selectWordAtPosition(TextPosition position);
Expand Down
22 changes: 22 additions & 0 deletions lib/src/editor/magnifier/quill_editor_magnifier_ext.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
part of '../editor.dart';

extension QuillEditorSelectionGestureDetectorBuilderMagnifierExt
on _QuillEditorSelectionGestureDetectorBuilder {
void _showMagnifierIfSupportedByPlatform(Offset positionToShow) {
switch (defaultTargetPlatform) {
case TargetPlatform.android:
case TargetPlatform.iOS:
editor?.showMagnifier(positionToShow);
default:
}
}

void _hideMagnifierIfSupportedByPlatform() {
switch (defaultTargetPlatform) {
case TargetPlatform.android:
case TargetPlatform.iOS:
editor?.hideMagnifier();
default:
}
}
}
14 changes: 14 additions & 0 deletions lib/src/editor/magnifier/quill_magnifier_controller.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import 'package:flutter/widgets.dart';
import 'package:meta/meta.dart';

// TODO: See the difference between Flutter MagnifierController and QuillMagnifierController
// and document it.
@internal
@experimental
abstract class QuillMagnifierController {
void showMagnifier(Offset positionToShow);

void updateMagnifier(Offset positionToShow);

void hideMagnifier();
}
27 changes: 27 additions & 0 deletions lib/src/editor/magnifier/quill_raw_editor_state_magnifier_ext.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
part of '../raw_editor/raw_editor_state.dart';

extension QuillRawEditorStateMagnifierExt on QuillRawEditorState {
void _hideMagnifier() {
if (_selectionOverlay == null) return;
_selectionOverlay?.hideMagnifier();
}

void _showMagnifier(ui.Offset positionToShow) {
if (_hasFocus == false) return;
if (_selectionOverlay == null) return;
final position = renderEditor.getPositionForOffset(positionToShow);
if (_selectionOverlay!.magnifierIsVisible) {
_selectionOverlay!
.updateMagnifier(position, positionToShow, renderEditor);
} else {
_selectionOverlay!.showMagnifier(position, positionToShow, renderEditor);
}
}

void _updateMagnifier(ui.Offset positionToShow) =>
showMagnifier(positionToShow);

TextMagnifierConfiguration get _magnifierConfiguration =>
widget.configurations.magnifierConfiguration ??
TextMagnifier.adaptiveMagnifierConfiguration;
}
116 changes: 116 additions & 0 deletions lib/src/editor/magnifier/text_selection_magnifier_ext.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
part of '../widgets/text/text_selection.dart';

final MagnifierController _magnifierController = MagnifierController();

/// Restore the selection context menu after the magnifier is dismissed.
/// Fix: https://github.com/singerdmx/flutter-quill/issues/2046
bool _restoreToolbar = false;

extension EditorTextSelectionOverlayMagnifierExt on EditorTextSelectionOverlay {
// build magnifier info
MagnifierInfo _buildMagnifier(
{required RenderEditor renderEditable,
required Offset globalGesturePosition,
required TextPosition currentTextPosition}) {
final globalRenderEditableTopLeft =
renderEditable.localToGlobal(Offset.zero);
final localCaretRect =
renderEditable.getLocalRectForCaret(currentTextPosition);

final lineAtOffset = renderEditable.getLineAtOffset(currentTextPosition);
final positionAtEndOfLine = TextPosition(
offset: lineAtOffset.extentOffset,
affinity: TextAffinity.upstream,
);

// Default affinity is downstream.
final positionAtBeginningOfLine = TextPosition(
offset: lineAtOffset.baseOffset,
);

final lineBoundaries = Rect.fromPoints(
renderEditable.getLocalRectForCaret(positionAtBeginningOfLine).topCenter,
renderEditable.getLocalRectForCaret(positionAtEndOfLine).bottomCenter,
);

return MagnifierInfo(
fieldBounds: globalRenderEditableTopLeft & renderEditable.size,
globalGesturePosition: globalGesturePosition,
caretRect: localCaretRect.shift(globalRenderEditableTopLeft),
currentLineBoundaries: lineBoundaries.shift(globalRenderEditableTopLeft),
);
}

void _showMagnifier(MagnifierInfo initialMagnifierInfo) {
// Hide toolbar
if (toolbar != null) {
_restoreToolbar = true;
hideToolbar();
} else {
_restoreToolbar = false;
}

// Update magnifier Info
_magnifierInfo.value = initialMagnifierInfo;

final builtMagnifier = magnifierConfiguration.magnifierBuilder(
context,
_magnifierController,
_magnifierInfo,
);

if (builtMagnifier == null) return;

_magnifierController.show(
context: context,
below: magnifierConfiguration.shouldDisplayHandlesInMagnifier
? null
: _handles?.elementAtOrNull(0),
builder: (_) => builtMagnifier,
);
}

void _updateMagnifier(MagnifierInfo magnifierInfo) {
if (_magnifierController.overlayEntry == null) {
return;
}
_magnifierInfo.value = magnifierInfo;
}

// TODO: Why we're having private and public methods for showMagnifier, and updateMagnifier?
// Is this internal API that is for public use?
// Once we know the reason, explain and document it.

void showMagnifier(
TextPosition position, Offset offset, RenderEditor editor) {
_showMagnifier(
_buildMagnifier(
currentTextPosition: position,
globalGesturePosition: offset,
renderEditable: editor,
),
);
}

void updateMagnifier(
TextPosition position, Offset offset, RenderEditor editor) {
_updateMagnifier(
_buildMagnifier(
currentTextPosition: position,
globalGesturePosition: offset,
renderEditable: editor,
),
);
}

void hideMagnifier() {
if (_magnifierController.overlayEntry == null) {
return;
}
_magnifierController.hide();
if (_restoreToolbar) {
_restoreToolbar = false;
showToolbar();
}
}
}
22 changes: 3 additions & 19 deletions lib/src/editor/raw_editor/raw_editor.dart
Original file line number Diff line number Diff line change
@@ -1,19 +1,9 @@
import 'dart:ui' show Offset;

import 'package:flutter/widgets.dart'
show
AnimationController,
BuildContext,
ScrollController,
State,
StatefulWidget,
TextSelectionDelegate,
Widget,
immutable;
import 'package:flutter/widgets.dart';

import '../../common/structs/offset_value.dart';
import '../../controller/quill_controller.dart';
import '../editor.dart';
import '../magnifier/quill_magnifier_controller.dart';
import '../widgets/text/text_selection.dart';
import 'config/raw_editor_configurations.dart';
import 'raw_editor_state.dart';
Expand Down Expand Up @@ -73,7 +63,7 @@ class QuillEditorGlyphHeights {
/// Base interface for the editor state which defines contract used by
/// various mixins.
abstract class EditorState extends State<QuillRawEditor>
implements TextSelectionDelegate {
implements TextSelectionDelegate, QuillMagnifierController {
ScrollController get scrollController;

RenderEditor get renderEditor;
Expand All @@ -95,11 +85,5 @@ abstract class EditorState extends State<QuillRawEditor>

void requestKeyboard();

void showMagnifier(Offset positionToShow);

void updateMagnifier(Offset positionToShow);

void hideMagnifier();

void toggleToolbar([bool hideHandles = true]);
Comment on lines -98 to -103
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why those methods added here?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably bad design to be here

}
28 changes: 8 additions & 20 deletions lib/src/editor/raw_editor/raw_editor_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ import 'raw_editor_state_text_input_client_mixin.dart';
import 'raw_editor_text_boundaries.dart';
import 'scribble_focusable.dart';

part '../magnifier/quill_raw_editor_state_magnifier_ext.dart';

class QuillRawEditorState extends EditorState
with
AutomaticKeepAliveClientMixin<QuillRawEditor>,
Expand Down Expand Up @@ -1114,8 +1116,7 @@ class QuillRawEditorState extends EditorState
? null
: (context) =>
widget.configurations.contextMenuBuilder!(context, this),
magnifierConfiguration: widget.configurations.magnifierConfiguration ??
TextMagnifier.adaptiveMagnifierConfiguration,
magnifierConfiguration: _magnifierConfiguration,
Copy link
Collaborator Author

@EchoEllet EchoEllet Sep 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The expression:

widget.configurations.magnifierConfiguration ??
          TextMagnifier.adaptiveMagnifierConfiguration

has been extracted into _magnifierConfiguration (quill_raw_editor_state_magnifier_ext.dart).

The name is not quite descriptive and needs to be changed or at least documented.

);
}

Expand Down Expand Up @@ -1505,26 +1506,13 @@ class QuillRawEditorState extends EditorState
bool get shareEnabled => false;

@override
void hideMagnifier() {
if (_selectionOverlay == null) return;
_selectionOverlay?.hideMagnifier();
}
void hideMagnifier() => _hideMagnifier();
Copy link
Collaborator Author

@EchoEllet EchoEllet Sep 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The _hideMagnifier is in the new file quill_raw_editor_state_magnifier_ext.dart. I would generally introduce this in a different way but since I'm not sure why it's done this way, I had to extract the implementation of those three methods into a private method that can be accessed only from this file. The main goal is to clean up the code, in general, this change needs to be improved as well, should be documented in a clear way.

Same for showMagnifier and updateMagnifier.


@override
void showMagnifier(ui.Offset positionToShow) {
if (_hasFocus == false) return;
if (_selectionOverlay == null) return;
final position = renderEditor.getPositionForOffset(positionToShow);
if (_selectionOverlay!.magnifierIsVisible) {
_selectionOverlay!
.updateMagnifier(position, positionToShow, renderEditor);
} else {
_selectionOverlay!.showMagnifier(position, positionToShow, renderEditor);
}
}
void showMagnifier(ui.Offset positionToShow) =>
_showMagnifier(positionToShow);

@override
void updateMagnifier(ui.Offset positionToShow) {
showMagnifier(positionToShow);
}
void updateMagnifier(ui.Offset positionToShow) =>
_updateMagnifier(positionToShow);
}
Loading
Loading