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

iOS caret color in dark mode not as expected (barely visible) #2042

Open
simonbengtsson opened this issue May 26, 2024 · 20 comments
Open

iOS caret color in dark mode not as expected (barely visible) #2042

simonbengtsson opened this issue May 26, 2024 · 20 comments
Assignees
Labels
area_supereditor Pertains to SuperEditor awaiting-customer-feedback Waiting for the customer to respond to us bounty_junior f:clickup platform_ios Applies to use on iOS time:2 type_bug Something isn't working

Comments

@simonbengtsson
Copy link

simonbengtsson commented May 26, 2024

Package Version
"super_editor, GitHub, stable branch"

To Reproduce

  1. Run example editor with iOS in darkmode
  2. Toggle to dark theme with FAB button

Actual behavior
The caret is black and hard to see since editor background is a dark grey.

Expected behavior
The caret to be visible. I expect the caret color to be red since this is set in the caretStyle and what is happening on macOS.

Platform
iOS. The issue is not happening on mac or web (or it does but the caret gets the correct color after refocusing the editor). Not tried other platforms.

Flutter version
Flutter 3.22.0 • channel stable
Framework • revision 5dcb86f68f (2 weeks ago) • 2024-05-09 07:39:20 -0500
Engine • revision f6344b75dc
Tools • Dart 3.4.0 • DevTools 2.34.3

Screenshots
issue

This is the same problem as described in #1347, but I can reproduce every time on iOS.

@simonbengtsson simonbengtsson added the type_bug Something isn't working label May 26, 2024
@matthew-carroll matthew-carroll added area_supereditor Pertains to SuperEditor platform_ios Applies to use on iOS bounty_junior f:superlist Funded by Superlist time: 1 1hr or less labels May 26, 2024
@angelosilvestre
Copy link
Collaborator

@simonbengtsson To update the caret color on iOS, you need to provide a handleColor to SuperEditorIosControlsController.

That way, you can customize the caret for iOS:

@angelosilvestre angelosilvestre added the awaiting-customer-feedback Waiting for the customer to respond to us label Jun 6, 2024
@simonbengtsson
Copy link
Author

simonbengtsson commented Jun 9, 2024

Got it! So SuperEditorIosControlsController.handleColor on iOS, SuperEditorAndroidControlsController.controlsColor on android and DefaultCaretOverlayBuilder.caretStyle.color on all other platforms.

Since SuperEditorIosControlsController.handleColor and SuperEditorAndroidControlsController.controlsColor are final I assume then that the idea is that you create new controllers and dispose the old one if the theme changes?

@angelosilvestre
Copy link
Collaborator

Since SuperEditorIosControlsController.handleColor and SuperEditorAndroidControlsController.controlsColor are final I assume then that the idea is that you create new controllers and dispose the old one if the theme changes?

@simonbengtsson Yeah, you'll need to do that.

@angelosilvestre angelosilvestre removed the awaiting-customer-feedback Waiting for the customer to respond to us label Jun 11, 2024
@matthew-carroll matthew-carroll added f:clickup and removed f:superlist Funded by Superlist labels Jun 15, 2024
@matthew-carroll
Copy link
Contributor

@simonbengtsson did that work for you? If so, can you paste the code that you had to write to get the effect you want? I'd like for us to take a look at how much work that is and see if it makes sense to create an easier pathway.

@simonbengtsson
Copy link
Author

simonbengtsson commented Jun 18, 2024

Actually no. When reassigning the _iosControlsController in the build method it crashes with the exception below. It feels wrong to reassign a controller in the build method so make sense I guess. Have no immediate idea for where else to do it however. For now we have set the cursor color to always be our primary color which kind of works in both dark and light mode.

OverlayPortalController.show() should not be called during build.
'package:flutter/src/widgets/overlay.dart':
Failed assertion: line 1791 pos 7: 'SchedulerBinding.instance.schedulerPhase != SchedulerPhase.persistentCallbacks'

My attempt was just adding the following lines to the _buildEditor method in example_editor.dart L370.

  Widget _buildEditor(BuildContext context) {
    final isLight = Theme.of(context).brightness == Brightness.light;

    // Added code
    _iosControlsController.dispose();
    _iosControlsController = SuperEditorIosControlsController(
      handleColor: isLight ? Colors.black : Colors.redAccent,
    );

    [...]

@angelosilvestre
Copy link
Collaborator

@simonbengtsson You should try to update it on the didChangeDependencies method.

@simonbengtsson
Copy link
Author

simonbengtsson commented Jun 19, 2024

Tried now, but didChangeDependencies was not called when "Change theme" button in the example editor is clicked. Used the following code:

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    final isLight = Theme.of(context).brightness == Brightness.light;
    _iosControlsController.dispose();
    _iosControlsController = SuperEditorIosControlsController(
      handleColor: isLight ? Colors.black : Colors.redAccent,
    );
    print('Reassigned ${isLight}'); // Only called once, not on theme change
  }

@angelosilvestre
Copy link
Collaborator

@simonbengtsson @matthew-carroll I took a look at this. The didChangeDependencies isn't been called because used there isn't the themed context. The ExampleEditor's ancestor theme doesn't change from light to dark, only the theme that is inside ExampleEditor, around the editor, that changes.

To solve this, the theme should be moved up, outside of ExampleEditor.

@override
Widget build(BuildContext context) {
  return ValueListenableBuilder(
    valueListenable: _brightness,
    builder: (context, brightness, child) {
      return Theme(
        data: ThemeData(brightness: brightness),
        child: child!,
      );
    },
    child: Builder(
      // This builder captures the new theme
      builder: (themedContext) {
      ...
     }   
   ),
 );
}

@matthew-carroll
Copy link
Contributor

@angelosilvestre if that resolves the issue in the demo app, let's go ahead and make the change. Then let's take another look at how much code is involved with such a simple behavior.

@angelosilvestre
Copy link
Collaborator

@matthew-carroll After taking a better look, I noticed that SuperEditorIosHandlesDocumentLayerBuilder has a handleColor property, so we shouldn't need to rely on SuperEditorIosControlsController for that.

However, I noticed this isn't working correctly even for desktop. The color doesn't update immediately:

2024-06-24.20-31-22.mov

This looks like a deeper problem in ContentLayers. Maybe it isn't working correctly when changing the layer builders?

@matthew-carroll matthew-carroll added time:2 and removed time: 1 1hr or less labels Jul 1, 2024
@matthew-carroll
Copy link
Contributor

@angelosilvestre can you dig deeper and try to find out where the problem is?

@angelosilvestre
Copy link
Collaborator

@matthew-carroll After taking a deeper look, I found that the cause is that performLayout isn't being called in ContentLayers. As a result, the layer builders aren't re-creating the layers.

When switching between light and dark mode, the only thing that we change in the editor is the font color. Because of that, only markNeedsPaint gets called, and not markNeedsLayout. We can confirm this by also changing the font size in the dark mode styles. If the font size changes, the layout is invalidated and the layer builder recreates the layer.

A possible solution can be achieved by making every SuperEditorLayerBuilder implement the == and then on SuperEditorState.didUpdateWidget checking if any layer builder changed. If a layer builder changed, we should call markNeedsLayout on the ContentLayers render object.

What do you think of that approach? Do you have any other ideas?

@matthew-carroll
Copy link
Contributor

@angelosilvestre I'm not entirely sure about the implications here, but on the surface of the issue, I don't know why we'd want to re-run layout for color changes. Layout is generally expensive and we should only run it when layout truly changes.

Is there a particular reason that you're suggesting we re-run layout for color changes?

@angelosilvestre
Copy link
Collaborator

Because without a re-run of the layout, the overlayers won't be rebuilt, so they won't pick the new colors.

@matthew-carroll
Copy link
Contributor

To help me understand exactly what's happening here, can you please write a failing test and open a PR with that test failure?

@angelosilvestre
Copy link
Collaborator

@matthew-carroll Opened #2388

@lucasjinreal
Copy link

I set handlerColor when in dark mode the cursor color still black....

@angelosilvestre
Copy link
Collaborator

@simonbengtsson @lucasjinreal This should now work as expected. Please see this comment #2302 (comment)

@angelosilvestre angelosilvestre added the awaiting-customer-feedback Waiting for the customer to respond to us label Dec 31, 2024
@lucasjinreal
Copy link

Hi, can u point out which version start from could fix this?

@angelosilvestre
Copy link
Collaborator

@lucasjinreal We didn't release a new pub version yet, but you can add a dependency to the latest main.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area_supereditor Pertains to SuperEditor awaiting-customer-feedback Waiting for the customer to respond to us bounty_junior f:clickup platform_ios Applies to use on iOS time:2 type_bug Something isn't working
Projects
None yet
Development

No branches or pull requests

4 participants