Android – How to create rich text input like Telegram or WhatsApp chat pages in Flutter?

How to create rich text input like Telegram or WhatsApp chat pages in Flutter?… here is a solution to the problem.

How to create rich text input like Telegram or WhatsApp chat pages in Flutter?

How to create a rich text input like a Telegram chat page without showing reserved characters (e.g. **bold**, _italic_) in a text file?
see this screenshot

Solution

I found a way to do this by creating a custom TextEditingController, but the reserved characters are still there, just not visible :

import 'dart:ui';

import 'package:flutter/material.dart';

class RichTextFieldController extends TextEditingController {
  late final Pattern pattern;
  String pureText = '';
  final Map<String, TextStyle> map = {
    r'@.\w+': const TextStyle(color: Colors.blue),
    r'#.\w+': const TextStyle(color: Colors.blue),
    r'\*\*(.*?) \*\*': const TextStyle(fontWeight: FontWeight.bold),
    r'__(.*?) __': const TextStyle(fontStyle: FontStyle.italic),
    '~~(.*?) ~~': const TextStyle(decoration: TextDecoration.lineThrough),
    r'```(.*?) ```': const TextStyle(
      fontFamily: 'mono',
      fontFeatures: [FontFeature.tabularFigures()],
    )
  };

RichTextFieldController() {
    pattern = RegExp(map.keys.map((key) => key).join('|'), multiLine: true);
  }

@override
  set text(String newText) {
    value = value.copyWith(
      text: newText,
      selection: TextSelection.collapsed(offset: newText.length),
      composing: TextRange.empty,
    );
  }

@override
  TextSpan buildTextSpan({
    required context,
    TextStyle? style,
    required bool withComposing,
  }) {
    final List<InlineSpan> children = [];
    text.splitMapJoin(
      pattern,
      onMatch: (Match match) {
        String? formattedText;
        String? textPattern;
        final patterns = map.keys.toList();
        if (RegExp(patterns[0]).hasMatch(match[0]!)) {
          formattedText = match[0];
          textPattern = patterns[0];
        } else if (RegExp(patterns[1]).hasMatch(match[0]!)) {
          formattedText = match[0];
          textPattern = patterns[1];
        } else if (RegExp(patterns[2]).hasMatch(match[0]!)) {
          formattedText = match[0]!. replaceAll("**", "");
          textPattern = patterns[2];
        } else if (RegExp(patterns[3]).hasMatch(match[0]!)) {
          formattedText = match[0]!. replaceAll("__", "");
          textPattern = patterns[3];
        } else if (RegExp(patterns[4]).hasMatch(match[0]!)) {
          formattedText = match[0]!. replaceAll("~~", "");
          textPattern = patterns[4];
        } else if (RegExp(patterns[5]).hasMatch(match[0]!)) {
          formattedText = match[0]!. replaceAll("```", "");
          textPattern = patterns[5];
        }
        children.add(TextSpan(
          text: formattedText,
          style: style!. merge(map[textPattern!]),
        ));
        return "";
      },
      onNonMatch: (String text) {
        children.add(TextSpan(text: text, style: style));
        return "";
      },
    );

return TextSpan(style: style, children: children);
  }
}

Related Problems and Solutions