Flutter Link Previewer 🔗

Pub Version melos

A highly customizable Flutter widget for rendering a preview of a URL. It automatically fetches metadata (title, description, image) and displays it in a clean, animated card. It is a part of the Flyer Chat ecosystem.

Screenshot

✨ Features

  • 🪄 Automatic Preview Generation: Fetches preview data (title, description, image) from the first URL found in a given text.
  • 🎨 Highly Customizable: Control colors, padding, border radius, text styles, and more.
  • 🖼️ Smart Image Layout: Automatically displays images on the side (for square images) or at the bottom (for rectangular images).
  • 📐 Sophisticated Width Calculation: Aligns with parent content (like chat bubbles) for a visually consistent layout.
  • 🚀 Smooth Animations: Built-in fade and size transitions, which can be disabled if not needed.
  • 👆 Custom Tap Handling: Override the default behavior of opening the link in a browser.

🚀 Installation

Add this package to your pubspec.yaml:

dependencies:
  flutter_link_previewer: ^4.0.0

Then run flutter pub get.

📖 Usage

Standalone Usage

Here is a basic example of how to use the LinkPreview widget within a stateful widget. It's important to store the fetched LinkPreviewData in your state to avoid re-fetching on rebuilds. It is also recommended to cache it to avoid re-fetching across app restarts.

import 'package:flutter/material.dart';
import 'package:flutter_link_previewer/flutter_link_previewer.dart';
import 'package:flutter_chat_core/flutter_chat_core.dart' show LinkPreviewData;

class MyChatBubble extends StatefulWidget {
  const MyChatBubble({super.key, required this.message});

  final String message;

  @override
  State<MyChatBubble> createState() => _MyChatBubbleState();
}

class _MyChatBubbleState extends State<MyChatBubble> {
  LinkPreviewData? _linkPreviewData;

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.all(16),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(widget.message),
          LinkPreview(
            // The text that should be parsed to find the first URL
            text: widget.message,
            // Pass the cached preview data to avoid re-fetching
            linkPreviewData: _linkPreviewData,
            // Callback to store the fetched preview data
            onLinkPreviewDataFetched: (data) {
              setState(() {
                _linkPreviewData = data;
              });
            },
            // For a chat bubble, you would pass the message text here
            // to align the preview with the text bubble.
            parentContent: widget.message,
            // Customization example
            borderRadius: 4,
            sideBorderColor: Colors.white,
            sideBorderWidth: 4,
            insidePadding: const EdgeInsets.fromLTRB(12, 8, 8, 8),
            outsidePadding: const EdgeInsets.symmetric(vertical: 4),
            titleTextStyle: const TextStyle(
              fontWeight: FontWeight.bold,
              fontSize: 20,
            ),
          ),
        ],
      ),
    );
  }
}

Integration with Flyer Chat

If you are using flutter_chat_ui, you can easily add link previews by providing the linkPreviewBuilder in the Chat widget's builders parameter.

This builder works seamlessly with text messages provided by Flyer Chat. The Chat widget automatically calls this builder for text messages that contain a link. When preview data is fetched, you should update the message using your ChatController to cache the data within the message itself.

import 'package:flutter_chat_ui/flutter_chat_ui.dart';
import 'package:flutter_link_previewer/flutter_link_previewer.dart';
import 'package:flutter_chat_core/flutter_chat_core.dart';

Chat(
  // ... other Chat properties
  builders: Builders(
    linkPreviewBuilder: (context, message, isSentByMe) {
      return LinkPreview(
        text: message.text,
        linkPreviewData: message.linkPreviewData,
        onLinkPreviewDataFetched: (linkPreviewData) {
          // Use the chat controller to update the message with the fetched data.
          // This will automatically save it in the message's metadata.
          _chatController.updateMessage(
            message,
            message.copyWith(linkPreviewData: linkPreviewData),
          );
        },
        // You can still customize the appearance
        parentContent: message.text,
      );
    },
    // ... other builders
  ),
)

🤝 Contributing

Contributions are welcome! Please see the main project's Contributing Guide.

📜 License

Licensed under the MIT License. See the LICENSE file for details.