omni_chat

pub.flutter-io.cn License: MIT

OmniChat is a professional, feature-rich Flutter chat UI package. It supports 17+ message types, built-in media viewers, audio waveform recording, swipe-to-reply, emoji reactions, profile card messages, screenshot protection, full theme customisation, and built-in localisation via OmniChatStrings.

Designed for FlutterFlow integration and any Flutter app.


✨ Features

Feature Details
17+ Message Types Text, Image, Video, Audio (waveform), Sticker (Lottie), GIF, Document, Location, Contact, Link Preview, Poll, Profile Card, View-Once Image, View-Once Video, System, Custom
Swipe-to-Reply Swipe any message left/right to quote-reply, with haptic feedback
Audio Waveform WhatsApp-style voice note with animated waveform, 1Γ—/1.5Γ—/2Γ— playback speed
Built-in Image Viewer Pinch-to-zoom, multi-image gallery swipe, hero animation
Built-in Video Player Full-screen player with seek, speed control, and landscape support
View-Once Media Ephemeral image & video that vanishes after one viewing
Profile Card @username card with verified badge; tapping navigates to profile
Media Source Badge πŸ“· Camera / πŸ–Ό Gallery label shown on image & video bubbles
Emoji Reactions Long-press β†’ pick emoji, reaction chips with counts
Message Editing Edit your own messages, shows "edited" indicator
Message Deletion Delete for me / delete for everyone
Encryption Banner πŸ”’ End-to-end encrypted banner + per-message lock icon
Screenshot Protection Android FLAG_SECURE toggle
Full Theming OmniChatTheme with light/dark presets and every token overridable
Wallpapers Solid color, gradient, or network/asset image background
FlutterFlow Ready Drop-in Custom Widget instructions below

πŸ“¦ Installation

dependencies:
  omni_chat: ^1.0.3
flutter pub get

Android permissions (AndroidManifest.xml)

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />

iOS (Info.plist)

<key>NSCameraUsageDescription</key>
<string>Required to capture photos and videos for chat</string>
<key>NSMicrophoneUsageDescription</key>
<string>Required to record voice messages</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Required to pick photos and videos from your library</string>

πŸš€ Quick Start

import 'package:omni_chat/omni_chat.dart';

OmniChatThemeScope(
  theme: OmniChatTheme.dark(),
  child: Column(
    children: [
      Expanded(
        child: OmniChatList(
          messages: _messages,       // List<ChatMessage>
          currentUserId: 'user_me',
          isEncrypted: true,
          screenshotProtection: true,
          onReply: (msg) => setState(() => _replyTo = msg),
          onProfileTap: (uid) => Navigator.pushNamed(context, '/profile/$uid'),
          onPollVote: (msg, optionId) { /* update your backend */ },
        ),
      ),
      OmniChatInput(
        replyMessage: _replyTo,
        onCancelReply: () => setState(() => _replyTo = null),
        onSendText: (text) => _sendMessage(TextMessage(...)),
        onSendAudio: (path, duration, waveform) => _sendMessage(AudioMessage(...)),
        onAttachment: (type) => _handleAttachment(type),
      ),
    ],
  ),
);

πŸ“¨ Message Types

All message types extend ChatMessage. Use ChatMessage.fromJson() and toJson() for serialisation.

Text

TextMessage(
  id: 'msg_1',
  senderId: 'user_a',
  timestamp: DateTime.now(),
  text: 'Hello @john! Check https://flutter.cn',
)

Image with source badge

ImageMessage(
  id: 'msg_2',
  senderId: 'user_b',
  timestamp: DateTime.now(),
  imageUrl: 'https://example.com/photo.jpg',
  caption: 'Look at this!',
  source: MediaSource.camera, // shows πŸ“· Camera badge
)

Audio (waveform)

AudioMessage(
  id: 'msg_3',
  senderId: 'user_a',
  timestamp: DateTime.now(),
  audioUrl: 'https://example.com/voice.m4a',
  duration: 45, // seconds
  waveformData: [0.2, 0.8, 0.5, 0.9, ...], // normalised amplitudes 0.0–1.0
  source: MediaSource.microphone,
)

Profile Card

ProfileCardMessage(
  id: 'msg_4',
  senderId: 'user_a',    // sender
  userId: 'user_a',      // profile being shared (same β†’ shows verified badge)
  username: 'odama_studio',
  displayName: 'Odama Studio',
  avatarUrl: 'https://example.com/avatar.jpg',
  isVerified: true,
  bio: 'Professional UI/UX design studio',
  timestamp: DateTime.now(),
)

View-Once Image

EphemeralImageMessage(
  id: 'msg_5',
  senderId: 'user_b',
  timestamp: DateTime.now(),
  imageUrl: 'https://example.com/secret.jpg',
  hasBeenViewed: false,
)

Custom Message

CustomMessage(
  id: 'msg_6',
  senderId: 'user_a',
  timestamp: DateTime.now(),
  customType: 'payment',
  payload: {'amount': 25.0, 'currency': 'USD'},
)

// In OmniChatList:
OmniChatList(
  messages: _messages,
  currentUserId: 'me',
  customMessageBuilder: (context, msg) {
    if (msg.customType == 'payment') {
      return PaymentBubble(payload: msg.payload);
    }
    return const SizedBox.shrink();
  },
)

🎨 Theming

// Built-in presets
OmniChatTheme.light()
OmniChatTheme.dark()

// Custom theme
OmniChatTheme.light().copyWith(
  outgoingBubbleColor: Color(0xFF4CAF50),
  bubbleRadius: 20,
  waveformActiveColor: Colors.teal,
  wallpaper: OmniChatWallpaper.gradient(
    LinearGradient(
      colors: [Color(0xFFE0F2F1), Color(0xFFB2DFDB)],
      begin: Alignment.topLeft,
      end: Alignment.bottomRight,
    ),
  ),
)

Wrap your widget tree with OmniChatThemeScope:

OmniChatThemeScope(
  theme: myTheme,
  child: OmniChatList(...),
)

πŸ”’ Security

OmniChatList(
  messages: _messages,
  currentUserId: 'me',
  isEncrypted: true,          // shows πŸ”’ banner
  screenshotProtection: true, // Android FLAG_SECURE
)

Note: iOS does not support complete screenshot prevention via Flutter. The encryption banner is shown but screenshots can still be taken. For sensitive apps, consider additional platform-channel implementations.


πŸ“± FlutterFlow Custom Widget Integration

  1. In FlutterFlow, go to Custom Code β†’ Custom Widgets β†’ Add Widget
  2. Name it OmniChatWidget
  3. Paste the following skeleton and adjust parameters as needed:
import 'package:omni_chat/omni_chat.dart';

class OmniChatWidget extends StatefulWidget {
  const OmniChatWidget({
    Key? key,
    required this.messages,       // List<dynamic> (JSON maps)
    required this.currentUserId,  // String
    this.isEncrypted = false,
    this.onSendText,              // Action
    this.onProfileTap,            // Action with userId param
  }) : super(key: key);

  final List<dynamic> messages;
  final String currentUserId;
  final bool isEncrypted;
  final Future<void> Function()? onSendText;
  final Future<void> Function()? onProfileTap;

  @override
  State<OmniChatWidget> createState() => _OmniChatWidgetState();
}

class _OmniChatWidgetState extends State<OmniChatWidget> {
  late List<ChatMessage> _parsed;

  @override
  void initState() {
    super.initState();
    _parsed = widget.messages
        .map((e) => ChatMessage.fromJson(Map<String, dynamic>.from(e as Map)))
        .toList();
  }

  @override
  Widget build(BuildContext context) {
    return OmniChatThemeScope(
      theme: OmniChatTheme.light(),
      child: Column(
        children: [
          Expanded(
            child: OmniChatList(
              messages: _parsed,
              currentUserId: widget.currentUserId,
              isEncrypted: widget.isEncrypted,
            ),
          ),
          OmniChatInput(
            onSendText: (_) => widget.onSendText?.call(),
          ),
        ],
      ),
    );
  }
}
  1. Add omni_chat to your FlutterFlow project's pubspec.yaml under Project Settings β†’ Custom Code β†’ pubspec.yaml.

🀝 Contributing

Pull requests are welcome! Please open an issue first to discuss changes.


πŸ“„ License

MIT Β© 2024 OmniChat Contributors

Libraries

omni_chat
OmniChat β€” Professional Flutter chat UI package.