Appflowy: Feature of the week

Table of contents

Built for people who value privacy

AppFlowy's Rich Text Editor for Flutter is a groundbreaking innovation that promises not only a flawless experience but a truly mind-blowing journey for developers. In a world where precision and personalization are paramount, AppFlowy has redefined the boundaries of what's possible in software development.

Let's quickly walk through what the text editor is about

Discover the power of AppFlowy's Rich Text Editor with the ability to:

  1. Create advanced and user-friendly editors.

  2. Customize various features specific to your needs, including:

    • Block components (e.g., form input controls, numbered lists, and rich text widgets)

    • Keyboard shortcuts

    • Themes

    • Selection menu

    • Toolbar menu

Today we are introducing the Customizing Editor Features. A user experience customization feature consisting of

  • Customizing a shortcut event

  • Customizing theme

Introducing you your inner Superhero

Customizing a Shortcut Event: In the world of text editing, efficiency is key. With the ability to customize shortcut events, users can streamline their workflow, ensuring that their most frequently used actions are just a keypress away. This feature empowers users to set up their keyboard shortcuts, making the editing process faster and more intuitive.

Tailored Themes: The visual appeal and readability of your text editor can significantly impact your work experience. AppFlowy's Rich Text Editor takes personalization to the next level with the option to customize themes. Whether you prefer a light or dark mode the tailored themes feature allows you to create an editing environment that suits your style and enhances your productivity.

Short-cut event

Light theme

Dark theme

How Customizing short-cut event works

First, make sure you have the Appflowy package installed within the pubspec yaml of your project

flutter pub add appflowy_editor
flutter pub get

Just like how you make use of short-cut events to automate activities on some of the daily software you use, making life easier. Appflowy makes it much more interesting. From setting a special character as a specific shortcut function to making use of them anywhere within the text editor.

Let's make use of the underscore character (_) adding it to the start and end of the text changing the text style to 'italics'

  • First, we create a blank document, this allows us to write text on our editor
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:flutter/material.dart';

class UnderScoreToItalic extends StatelessWidget {
  const UnderScoreToItalic({super.key});

  @override
  Widget build(BuildContext context) {
    return AppFlowyEditor.custom(
      editorState: EditorState.blank(withInitialText: true),
      blockComponentBuilders: standardBlockComponentBuilderMap,
      characterShortcutEvents: const [],
    );
  }
}

We move on to set a specific character that will represent our short-cut event, changing our text to italics when added at the start and end of the text.

We are making use of an underscore (_)

import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:flutter/material.dart';

class UnderScoreToItalic extends StatelessWidget {
  const UnderScoreToItalic({super.key});

  @override
  Widget build(BuildContext context) {
    return AppFlowyEditor.custom(
      editorState: EditorState.blank(withInitialText: true),
      blockComponentBuilders: standardBlockComponentBuilderMap,
      characterShortcutEvents: [
        underScoreToItalicEvent,
      ],
    );
  }
}

CharacterShortcutEvent underScoreToItalicEvent = CharacterShortcutEvent(
  key: 'Underscore to italic',
  character: '_',
  handler: (editorState) async => handleFormatByWrappingWithSingleCharacter(
    editorState: editorState,
    character: '_',
    formatStyle: FormatStyleByWrappingWithSingleChar.italic,
  ),
);

There you have it!

You can decide to go ahead with any character you wish to. There are no ends to the text editor.

How do we customize our Editor's theme

Pretty simple! First, we will customize out style by customizing the EditorStyle and the block style with BlockComponentConfiguration within your code

EditorStyle customizeEditorStyle() {
  return EditorStyle(
    padding: PlatformExtension.isDesktopOrWeb
        ? const EdgeInsets.only(left: 100, right: 100, top: 20)
        : const EdgeInsets.symmetric(horizontal: 20),
    cursorColor: Colors.green,
    selectionColor: Colors.green,
    textStyleConfiguration: TextStyleConfiguration(
      text: const TextStyle(
        fontSize: 18.0,
        color: Colors.white54,
      ),
      bold: const TextStyle(
        fontWeight: FontWeight.w900,
      ),
      href: TextStyle(
        color: Colors.amber,
        decoration: TextDecoration.combine(
          [
            TextDecoration.overline,
            TextDecoration.underline,
          ],
        ),
      ),
      code: const TextStyle(
        fontSize: 14.0,
        fontStyle: FontStyle.italic,
        color: Colors.blue,
        backgroundColor: Colors.black12,
      ),
    ),
    textSpanDecorator: (context, node, index, text, textSpan) {
      final attributes = text.attributes;
      final href = attributes?[AppFlowyRichTextKeys.href];
      if (href != null) {
        return TextSpan(
          text: text.text,
          style: textSpan.style,
          recognizer: TapGestureRecognizer()
            ..onTap = () {
              debugPrint('onTap: $href');
            },
        );
      }
      return textSpan;
    },
  );
}

Map<String, BlockComponentBuilder> customBuilder() {
  final configuration = BlockComponentConfiguration(
    padding: (node) {
      if (HeadingBlockKeys.type == node.type) {
        return const EdgeInsets.symmetric(vertical: 30);
      }
      return const EdgeInsets.symmetric(vertical: 10);
    },
    textStyle: (node) {
      if (HeadingBlockKeys.type == node.type) {
        return const TextStyle(color: Colors.yellow);
      }
      return const TextStyle();
    },
  );

  // customize heading block style
  return {
    ...standardBlockComponentBuilderMap,
    // heading block
    HeadingBlockKeys.type: HeadingBlockComponentBuilder(
      configuration: configuration,
    ),
    // todo-list block
    TodoListBlockKeys.type: TodoListBlockComponentBuilder(
      configuration: configuration,
      iconBuilder: (context, node) {
        final checked = node.attributes[TodoListBlockKeys.checked] as bool;
        return Icon(
          checked ? Icons.check_box : Icons.check_box_outline_blank,
          size: 20,
          color: Colors.white,
        );
      },
    ),
    // bulleted list block
    BulletedListBlockKeys.type: BulletedListBlockComponentBuilder(
      configuration: configuration,
      iconBuilder: (context, node) {
        return const Icon(
          Icons.circle,
          size: 20,
          color: Colors.green,
        );
      },
    ),
    // quote block
    QuoteBlockKeys.type: QuoteBlockComponentBuilder(
      configuration: configuration,
      iconBuilder: (context, node) {
        return const EditorSvg(
          width: 20,
          height: 20,
          padding: EdgeInsets.only(right: 5.0),
          name: 'quote',
          color: Colors.pink,
        );
      },
    ),
  };
}

This will not make any difference on the editor till we inject it into the AppFlowyEditor

@override
Widget build(BuildContext context) {
  return Scaffold(
    body: Container(
      alignment: Alignment.topCenter,
      child: AppFlowyEditor(
        editorState: EditorState.blank(),
        editorStyle: customizeEditorStyle(),
        blockComponentBuilders: customBuilder(),
      ),
    ),
  );
}

Get ready for a much more flexible and amazing way of customizing the rich text editor, tailoring it to deliver projects as you like it!

0
Subscribe to my newsletter

Read articles from Oluwaseyi Ogunjinmi directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Oluwaseyi Ogunjinmi
Oluwaseyi Ogunjinmi

A skilled software engineer with expertise in Golang, Kubernetes, and backend systems , autonomous machine development. Focused on building scalable solutions and enhancing deployment efficiency. A solid interest in biology and ecosystems. A skilled technical writer.