chat_bubbles icon indicating copy to clipboard operation
chat_bubbles copied to clipboard

Add Markdown support

Open gdelataillade opened this issue 1 year ago • 2 comments

Would it be relevant to add markdown support ? Generative AI uses markdown so for example instead of showing text wrapped in "**", markdown will show bold text.

flutter_markdown package could be used.

I can submit the PR if you want, my code is ready.

Otherwise, why not take a Widget child as parameter instead of a String text ? This way, you won't have to add a dependency to your package. That would be a breaking change though. Or a new widget MarkdownBubble ?

CleanShot 2024-02-21 at 12 21 00@2x

gdelataillade avatar Feb 21 '24 11:02 gdelataillade

Nice idea :D

yelkamel avatar Feb 21 '24 13:02 yelkamel

I've come across this problem. This is how I solved:

  1. Go to source code of the widget you want to use (I use BubbleSpecialTwo). In VSCode, you can do it by F12 or ALT+LeftClick.
  2. Copy the related widget and paste it to your codebase somewhere, wherever you hold your custom components.
  3. Rename the component to something else. I renamed to CustomBubbleSpecialTwo.
  4. Change text with child, which should be Widget instead of String.

I could send a PR for this but kinda busy right now. When I get freer and nobody still takes this issue, I can send a PR maybe.

I leave CustomBubbleSpecialTwo as an example:

import 'package:chat_bubbles/bubbles/bubble_special_two.dart';
import 'package:flutter/material.dart';

class CustomBubbleSpecialTwo extends StatelessWidget {
  final bool isSender;
  final Widget child;
  final bool tail;
  final Color color;
  final bool sent;
  final bool delivered;
  final bool seen;
  final TextStyle textStyle;
  final BoxConstraints? constraints;

  const CustomBubbleSpecialTwo({
    required this.child,
    super.key,
    this.isSender = true,
    this.constraints,
    this.color = Colors.white70,
    this.tail = true,
    this.sent = false,
    this.delivered = false,
    this.seen = false,
    this.textStyle = const TextStyle(
      color: Colors.black87,
      fontSize: 16,
    ),
  });

  ///chat bubble builder method
  @override
  Widget build(BuildContext context) {
    bool stateTick = false;
    Icon? stateIcon;
    if (sent) {
      stateTick = true;
      stateIcon = const Icon(
        Icons.done,
        size: 18,
        color: Color(0xFF97AD8E),
      );
    }
    if (delivered) {
      stateTick = true;
      stateIcon = const Icon(
        Icons.done_all,
        size: 18,
        color: Color(0xFF97AD8E),
      );
    }
    if (seen) {
      stateTick = true;
      stateIcon = const Icon(
        Icons.done_all,
        size: 18,
        color: Color(0xFF92DEDA),
      );
    }

    return Align(
      alignment: isSender ? Alignment.topRight : Alignment.topLeft,
      child: Padding(
        padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
        child: CustomPaint(
          painter: SpecialChatBubbleTwo(
            color: color,
            alignment: isSender ? Alignment.topRight : Alignment.topLeft,
            tail: tail,
          ),
          child: Container(
            constraints: constraints ??
                BoxConstraints(
                  maxWidth: MediaQuery.of(context).size.width * .8,
                ),
            margin: isSender
                ? stateTick
                    ? const EdgeInsets.fromLTRB(7, 7, 14, 7)
                    : const EdgeInsets.fromLTRB(7, 7, 17, 7)
                : const EdgeInsets.fromLTRB(17, 7, 7, 7),
            child: Stack(
              children: <Widget>[
                Padding(
                  padding: stateTick
                      ? const EdgeInsets.only(right: 20)
                      // ignore: use_named_constants
                      : const EdgeInsets.symmetric(),
                  child: child,
                ),
                if (stateIcon != null && stateTick)
                  Positioned(
                    bottom: 0,
                    right: 0,
                    child: stateIcon,
                  )
                else
                  const SizedBox(
                    width: 1,
                  ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

erayerdin avatar Mar 15 '24 15:03 erayerdin