{"id":28287850,"url":"https://github.com/0xc3u/indiko.maui.controls.chat","last_synced_at":"2026-06-27T17:00:32.148Z","repository":{"id":280260932,"uuid":"884762185","full_name":"0xc3u/Indiko.Maui.Controls.Chat","owner":"0xc3u","description":"Indiko.Maui.Controls.Chat","archived":false,"fork":false,"pushed_at":"2026-06-26T08:29:33.000Z","size":4232,"stargazers_count":30,"open_issues_count":2,"forks_count":7,"subscribers_count":4,"default_branch":"main","last_synced_at":"2026-06-26T09:17:41.468Z","etag":null,"topics":["android","chat","chatview","dotnet","ios","maui","recyclerview","uicollectionview","view"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/0xc3u.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-11-07T10:47:10.000Z","updated_at":"2026-06-26T08:29:35.000Z","dependencies_parsed_at":"2025-03-02T11:26:11.972Z","dependency_job_id":"365cef49-0946-4db0-abfc-306253134343","html_url":"https://github.com/0xc3u/Indiko.Maui.Controls.Chat","commit_stats":null,"previous_names":["0xc3u/indiko.maui.controls.chat"],"tags_count":14,"template":false,"template_full_name":null,"purl":"pkg:github/0xc3u/Indiko.Maui.Controls.Chat","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/0xc3u%2FIndiko.Maui.Controls.Chat","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/0xc3u%2FIndiko.Maui.Controls.Chat/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/0xc3u%2FIndiko.Maui.Controls.Chat/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/0xc3u%2FIndiko.Maui.Controls.Chat/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/0xc3u","download_url":"https://codeload.github.com/0xc3u/Indiko.Maui.Controls.Chat/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/0xc3u%2FIndiko.Maui.Controls.Chat/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34860893,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-27T02:00:06.362Z","response_time":126,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","chat","chatview","dotnet","ios","maui","recyclerview","uicollectionview","view"],"created_at":"2025-05-21T22:14:31.119Z","updated_at":"2026-06-27T17:00:32.142Z","avatar_url":"https://github.com/0xc3u.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ChatView Control for MAUI.NET\n\nThe `ChatView` control is a highly customizable chat interface for MAUI.NET applications. It supports various features such as displaying messages, handling user interactions, managing replies, emoji reactions, avatars, and system messages. The control is optimized for native performance using platform-specific components like `RecyclerView` on Android and `UICollectionView` on iOS.\n\n![Indiko.Maui.Controls.Chat](nuget.png)\n\n## Screenshots\n\n| Android | iOS                |\n|--------------|----------------------------|\n| ![chatview_android](https://github.com/user-attachments/assets/5a45c70a-49fa-451a-b044-0c4c9fa8b49b) | ![chatview_ios](https://github.com/user-attachments/assets/e62c0f75-7dfd-41d2-9ffb-4141556187fa) |\n\n## Build Status\n![ci](https://github.com/0xc3u/Indiko.Maui.Controls.Chat/actions/workflows/symanticrelease.yml/badge.svg)\n\n## Installation\n\nYou can install the `Indiko.Maui.Controls.Chat` package via NuGet Package Manager or CLI:\n\n[![NuGet](https://img.shields.io/nuget/v/Indiko.Maui.Controls.Chat.svg?label=NuGet)](https://www.nuget.org/packages/Indiko.Maui.Controls.Chat/)\n\n### NuGet Package Manager\n```bash\nInstall-Package Indiko.Maui.Controls.Chat\n```\n\n### .NET CLI\n```bash\ndotnet add package Indiko.Maui.Controls.Chat\n```\n\n---\n\n### Adding to Your Project\nTo use the ChatView in your project, add the control to your app builder:\n\n```csharp\nusing Microsoft.Maui.Hosting;\nusing Indiko.Maui.Controls.Chat;\n\nvar builder = MauiApp.CreateBuilder();\nbuilder.UseChatView();\n```\n\n---\n\n## Features\n\n- **Message Display**: Renders text, image, video, audio (voice note), system, and date-separator messages.\n- **Voice Notes**: Audio messages render as a play/pause button, a tap-to-seek waveform, and an elapsed/total duration label, with native playback on both platforms.\n- **Media Bubbles**: Images and videos are sized to the content's aspect ratio (capped) so a photo never blows up the bubble.\n- **Media Captions**: Image and video messages can carry a text caption (the message's `TextContent`), shown under the media in the same bubble.\n- **Tap-to-Play Video**: Videos show a blurred first-frame poster with a play button; nothing auto-plays while scrolling. Tapping play opens the video **full screen** with native controls (play/pause + seek bar) by default — set `OpenVideoFullScreen=\"False\"` to play inline in the bubble instead.\n- **Full-Screen Image Viewer**: Tapping an image opens a full-screen viewer with pinch-to-zoom, pan and double-tap zoom. `MessageTapped` still fires; set `OpenImageFullScreen=\"False\"` to handle the tap yourself.\n- **Reply Support**: Reply-to-message functionality with previews of the original message.\n- **Tap-to-Jump Reply**: Tapping a message's reply preview scrolls to the original message it replies to and briefly highlights it. Toggle with `EnableJumpToRepliedMessage`; set the flash color with `RepliedMessageHighlightColor` (or `Transparent` to disable it); `RepliedMessageTappedCommand` notifies your view model with the original message.\n- **Swipe-to-Reply**: Swipe a bubble to the right to start a reply. It raises the **same** event as the context menu's \"Reply\" item — `LongPressedCommand` fires with a `ContextAction` (`Name == \"reply\"`, `Message ==` the swiped message) — so you implement reply logic once for both gestures. The row springs back (haptic on iOS, clamped slide on Android). Toggle with `EnableSwipeToReply`; the action name is configurable via `SwipeReplyActionName`.\n- **Emoji Reactions**: Allows emoji reactions with reaction counts and participant details.\n- **Avatars**: Displays sender avatars (image or initials) with customizable appearance.\n- **Sender Names (group chats)**: Shows `SenderName` above incoming bubbles, de-duplicated for consecutive messages from the same sender. Toggle with `ShowSenderName`; style with `SenderNameTextColor` / `SenderNameFontSize`.\n- **Clickable Links**: URLs, phone numbers and email addresses in text messages are detected and tappable (browser / dialer / mail). Toggle with `DetectLinks`; style with `LinkTextColor`. Long-press-to-react still works.\n- **Date Separators \u0026 \"New Messages\" Separator**: Group messages by day and highlight where unread messages begin.\n- **Customizable Styling**: Flexible styling for message backgrounds, text colors, fonts, and more.\n- **Commands and Events**: Handles user interactions like taps, emoji reactions, and scrolls.\n- **Smart Scrolling**: On iOS the list is rendered with an inverted `UICollectionView`, so the newest message rests at the bottom with no animated jump on open; supports scroll-to-last-message and scroll-to-first-new-message.\n- **Scroll-to-Bottom Button**: A floating button appears when the user scrolls away from the newest message; tapping it jumps back to the bottom. An optional badge counts messages that arrive while scrolled up. Fully styleable — toggle with `ShowScrollToBottomButton`; style with `ScrollToBottomButtonBackgroundColor`, `ScrollToBottomButtonIconColor`, `ScrollToBottomButtonSize`, `ScrollToBottomButtonMargin`; the badge with `ShowScrollToBottomBadge`, `ScrollToBottomBadgeBackgroundColor`, `ScrollToBottomBadgeTextColor`, `ScrollToBottomBadgeFontSize`.\n- **Load More Messages**: Supports dynamic loading of older messages via a bound command; prepended messages keep the viewport stable.\n- **Native Performance**: Uses `RecyclerView` on Android and `UICollectionView` on iOS for smooth performance.\n- **Long Press Gesture**: Displays a configured context menu (emoji reactions + actions) on any message — text, image, video and voice note.\n\n---\n\n## Requirements\n\n- .NET 10 (`net10.0-android`, `net10.0-ios`)\n- Minimum OS: Android 12 (API 31)+ / iOS 14.2+\n\n---\n\n## Supported Message Types\n\n| Message Type | Description                                                                 |\n|--------------|-----------------------------------------------------------------------------|\n| `Text`       | Standard text messages.                                                     |\n| `Image`      | Image messages (PNG/JPEG bytes in `BinaryContent`); aspect-sized bubble.    |\n| `Video`      | Video messages (bytes in `BinaryContent`); blurred poster + tap-to-play.     |\n| `Audio`      | Voice notes (bytes in `BinaryContent`) with play/pause, waveform, duration. |\n| `System`     | System-generated / service messages.                                        |\n| `Date`       | Day separator row (usually inserted by your app between date groups).        |\n\n---\n\n## Models\n\n### `ChatMessage`\nRepresents an individual message in the chat.\n\n```csharp\npublic class ChatMessage\n{\n    public string MessageId { get; set; }\n    public DateTime Timestamp { get; set; }\n    public string TextContent { get; set; }\n    public byte[] BinaryContent { get; set; }          // image / video / audio payload\n    public bool IsOwnMessage { get; set; }\n    public string SenderId { get; set; }\n    public byte[] SenderAvatar { get; set; }\n    public string SenderInitials { get; set; }\n    public string SenderName { get; set; }        // shown above incoming bubbles in group chats\n    public MessageType MessageType { get; set; }\n    public MessageReadState ReadState { get; set; }\n    public MessageDeliveryState DeliveryState { get; set; }\n    public bool IsRepliedMessage =\u003e ReplyToMessage != null;\n    public RepliedMessage ReplyToMessage { get; set; }\n    public List\u003cChatMessageReaction\u003e Reactions { get; set; } = [];\n\n    // Audio (voice note) — both optional.\n    public TimeSpan? AudioDuration { get; set; }       // shown while idle; derived from the file if null\n    public float[] AudioWaveform { get; set; }         // normalized 0..1 samples; a stable\n                                                       // pseudo-waveform is generated when null\n}\n```\n\n### `ChatMessageReaction`\nRepresents reactions (emojis) on a message.\n\n```csharp\npublic class ChatMessageReaction\n{\n    public string Emoji { get; set; }\n    public int Count { get; set; }\n    public List\u003cstring\u003e ParticipantIds { get; set; } = new List\u003cstring\u003e();\n}\n```\n\n### `RepliedMessage`\nRepresents a replied message with a preview.\n\n```csharp\npublic class RepliedMessage\n{\n    public string MessageId { get; set; }\n    public string TextPreview { get; set; }\n    public string SenderId { get; set; }\n\n    public static string GenerateTextPreview(string text, int maxLength = 50)\n    {\n        if (string.IsNullOrEmpty(text)) return string.Empty;\n        return text.Length \u003e maxLength ? text[..maxLength] + \"...\" : text;\n    }\n}\n```\n\n### `ContextMenuItem`\nRepresents an item in the context menu.\n\n```csharp\npublic class ContextMenuItem\n{\n    public string Name { get; set; }\n    public string Tag { get; set; }\n    public bool IsDestructive { get; set; }\n}\n```\n\n### `ContextAction`\nRepresents an action triggered from the context menu.\n\n```csharp\npublic class ContextAction\n{\n    public string Name { get; set; }\n    public object AdditionalData { get; set; }\n    public ChatMessage Message { get; set; }\n}\n```\n\n### Enums\n\n#### `MessageDeliveryState`\n- `Sent`\n- `Delivered`\n- `Read`\n\n#### `MessageReadState`\n- `New`\n- `Unread`\n- `Read`\n\n#### `MessageType`\n- `Text`\n- `Image`\n- `Video`\n- `Audio`\n- `System`\n- `Date`\n\n---\n\n## Commands\n\n| Command                          | Description                                                    |\n|----------------------------------|----------------------------------------------------------------|\n| `ScrolledCommand`                | Triggered when the chat view is scrolled. See example below.   |\n| `MessageTappedCommand`           | Triggered when a message is tapped.                           |\n| `AvatarTappedCommand`            | Triggered when an avatar is tapped.                           |\n| `EmojiReactionTappedCommand`     | Triggered when an emoji reaction is tapped.                   |\n| `LoadMoreMessagesCommand`        | Invoked when more messages need to be loaded.                 |\n| `ScrolledToLastMessageCommand`   | Triggered when scrolled to the last message.                  |\n| `LongPressedCommand`             | Triggered by a context-menu action **and** by swipe-to-reply; receives a `ContextAction` (`Name`, `Message`). Swipe sends `Name == \"reply\"`. |\n| `RepliedMessageTappedCommand`    | Triggered when a reply preview is tapped; passes the original `ChatMessage` it refers to. |\n\n---\n\n## Styling\n\n| Property                         | Default Value       | Description                                       |\n|----------------------------------|---------------------|---------------------------------------------------|\n| `SystemMessageBackgroundColor`   | LightYellow         | Background color for system messages.            |\n| `SystemMessageTextColor`         | Red                | Text color for system messages.                 |\n| `SystemMessageFontSize`          | 14                 | Font size for system messages.                  |\n| `DateTextFontSize`               | 14                 | Font size for date separator text.              |\n| `DateTextColor`                  | LightGray           | Color for date separator text.                   |\n| `AvatarBackgroundColor`          | LightBlue           | Background color for avatars.                   |\n| `AvatarTextColor`                | White              | Text color for avatar initials.                 |\n| `OwnMessageBackgroundColor`      | LightBlue           | Background color for the user's messages.         |\n| `OwnMessageTextColor`            | Black              | Text color for the user's messages.              |\n| `OwnMessageFontSize`             | 14                 | Font size for the user's messages.               |\n| `OtherMessageBackgroundColor`    | LightGray           | Background color for other users' messages.       |\n| `OtherMessageTextColor`          | Black              | Text color for other users' messages.            |\n| `OtherMessageFontSize`           | 14                 | Font size for other users' messages.             |\n| `MessageFontSize`                | 14                 | Font size for messages.                          |\n| `DateTextColor`                  | LightGray           | Color for date separator text.                   |\n| `AvatarSize`                     | 36                 | Size of avatars.                                 |\n| `ScrollToLastMessage`            | true               | Auto-scrolls to the last message.                |\n| `ShowNewMessagesSeperator`       | false              | Enables or disables the new message separator.   |\n| `EmojiReactionFontSize`          | 10                 | Font size for emoji reactions.                   |\n| `ReplyMessageBackgroundColor`    | LightYellow         | Background color for replied message previews.   |\n| `ReplyMessageFontSize`           | 10                 | Font size for replied message previews.          |\n| `ReplyMessageTextColor`          | Black              | Text color for replied message previews.         |\n| `ContextMenuBackgroundColor`     | White              | Background color for the context menu.           |\n| `ContextMenuTextColor`           | Black              | Text color for the context menu.                 |\n| `ContextMenuDestructiveTextColor`| Red                | Text color for destructive actions in the context menu. |\n| `ContextMenuDividerColor`        | LightGray           | Color for the context menu divider.              |\n| `ContextMenuDividerHeight`       | 1                  | Height of the context menu divider.              |\n| `ContextMenuFontSize`            | 14                 | Font size for the context menu.                  |\n| `ContextMenuReactionFontSize`    | 18                 | Font size for reaction items in the context menu.|\n| `ShowScrollToBottomButton`       | true               | Shows the floating scroll-to-bottom button when scrolled up. |\n| `ScrollToBottomButtonBackgroundColor` | White         | Fill color of the scroll-to-bottom button.       |\n| `ScrollToBottomButtonIconColor`  | Black              | Color of the chevron icon.                       |\n| `ScrollToBottomButtonSize`       | 44                 | Diameter of the scroll-to-bottom button.         |\n| `ScrollToBottomButtonMargin`     | 16                 | Spacing from the bottom/trailing edges.          |\n| `ShowScrollToBottomBadge`        | true               | Shows the unread-count badge on the button.      |\n| `ScrollToBottomBadgeBackgroundColor` | Red            | Fill color of the unread-count badge.            |\n| `ScrollToBottomBadgeTextColor`   | White              | Text color of the unread-count badge.            |\n| `ScrollToBottomBadgeFontSize`    | 12                 | Font size of the unread-count badge.             |\n| `EnableJumpToRepliedMessage`     | true               | Tapping a reply preview scrolls to the original message. |\n| `RepliedMessageHighlightColor`   | translucent amber  | Color flashed over the original message on jump (Transparent disables it). |\n\n---\n\n## Usage\n\n\u003e **Platform-Specific Note:** The platform-specific code for iOS and Android uses a caching mechanism for images and video-based messages. The binary content of such messages is stored in the device's cache folder for optimized performance and memory management.\n\n\u003e **Note:** The `ChatView` control is solely responsible for rendering different message types. It does not include features like a text input box or a send button. These components need to be implemented by the user in the MAUI.NET app, as demonstrated in the `Indiko.Maui.Controls.Chat.Sample` project.\n\n### Managing the `Messages` Collection\n\n`Messages` is an `ObservableRangeCollection\u003cChatMessage\u003e` — an `ObservableCollection` with bulk operations so large updates raise a single notification (important for scroll performance):\n\n```csharp\nChatMessages.Add(message);                 // append a new (newest) message\nChatMessages.AddRange(newMessages);        // append many at once\nChatMessages.InsertRange(0, olderMessages);// prepend older messages (infinite-scroll load-more)\nChatMessages.ReplaceRange(allMessages);    // replace the whole conversation\n```\n\nUse `InsertRange(0, ...)` from your `LoadMoreMessagesCommand` handler to add older history; the control keeps the current viewport stable instead of jumping.\n\n### Sending Images and Voice Notes\n\nMedia is passed as raw bytes in `BinaryContent` together with the matching `MessageType`. The control writes the bytes to the platform cache and renders/plays them natively.\n\n```csharp\n// Image\nChatMessages.Add(new ChatMessage\n{\n    MessageId = Guid.NewGuid().ToString(),\n    Timestamp = DateTime.Now,\n    IsOwnMessage = true,\n    MessageType = MessageType.Image,\n    BinaryContent = imageBytes,            // PNG/JPEG\n    TextContent = \"optional caption\",      // shown under the image in the same bubble\n});\n\n// Voice note\nChatMessages.Add(new ChatMessage\n{\n    MessageId = Guid.NewGuid().ToString(),\n    Timestamp = DateTime.Now,\n    IsOwnMessage = true,\n    MessageType = MessageType.Audio,\n    BinaryContent = audioBytes,            // e.g. m4a / mp3 / wav\n    AudioDuration = TimeSpan.FromSeconds(3), // optional; derived from the file if omitted\n    AudioWaveform = samples,               // optional float[] (0..1); a pseudo-waveform is drawn if omitted\n});\n```\n\nThe voice-note bubble shows a play/pause button, a tap-to-seek waveform, and the elapsed/total duration. Supply `AudioWaveform` (e.g. amplitudes captured while recording) for an accurate waveform; otherwise the control renders a stable per-message pseudo-waveform.\n\n### Emoji Reaction Tapped Event Handling Example\n\nTo handle the `EmojiReactionTappedCommand` properly, you can define a method in your ViewModel as follows:\n\n```csharp\n[RelayCommand]\nprivate void OnEmojiReactionTapped(ChatMessage message)\n{\n    Console.WriteLine($\"Emoji Reaction tapped: {message.MessageId}\");\n}\n```\n\n### Message Clicked Event Handling Example\n\nTo handle the `MessageTappedCommand` properly, you can define a method in your ViewModel as follows:\n\n```csharp\n[RelayCommand]\nprivate void OnMessageTapped(ChatMessage message)\n{\n    Console.WriteLine($\"Message tapped for message: {message.MessageId}\");\n}\n```\n\n### Avatar Clicked Event Handling Example\n\nTo handle the `AvatarTappedCommand` properly, you can define a method in your ViewModel as follows:\n\n```csharp\n[RelayCommand]\nprivate void OnAvatarTapped(ChatMessage message)\n{\n    Console.WriteLine($\"Avatar tapped for message: {message.MessageId}\");\n}\n```\n\n### Scrolled Event Handling Example\n\nTo handle the `ScrolledCommand` properly, you can define a method in your ViewModel as follows:\n\n```csharp\n[RelayCommand]\nprivate void Scrolled(ScrolledArgs scrolledArgs)\n{\n    // Handle scroll event logic\n    Console.WriteLine($\"Scrolled to position: X={scrolledArgs.X}, Y={scrolledArgs.Y}\");\n}\n```\n\n### Long Press Gesture Event Handling Example\n\nTo handle the `LongPressedCommand` properly, you can define a method in your ViewModel as follows:\n\n```csharp\n[RelayCommand]\npublic void LongPressed(ContextAction contextAction)\n{\n    switch (contextAction.Name)\n    {\n        case \"reply\":\n            Console.WriteLine($\"Reply to message: {contextAction.Message.MessageId}\");\n            break;\n        case \"delete\":\n            Console.WriteLine($\"Delete message: {contextAction.Message.MessageId}\");\n            break;\n        case \"copy\":\n            Console.WriteLine($\"Copy message: {contextAction.Message.MessageId}\");\n            break;\n        case \"react\":\n            ChatMessageReaction chatMessageReaction = contextAction.AdditionalData as ChatMessageReaction;\n            Console.WriteLine($\"React to message: {contextAction.Message.MessageId}, Additional Data: {chatMessageReaction.Emoji}\");\n            break;\n    }\n}\n```\n\n### XAML Example\n\n```xml\nxmlns:idk=\"clr-namespace:Indiko.Maui.Controls.Chat;assembly=Indiko.Maui.Controls.Chat\"\n...\n\n\u003cidk:ChatView Grid.Row=\"0\" x:Name=\"chatView\"\n\n    OwnMessageBackgroundColor=\"{StaticResource Primary}\"\n    OwnMessageTextColor=\"{StaticResource White}\"\n    OtherMessageBackgroundColor=\"{StaticResource Secondary}\"\n    OtherMessageTextColor=\"{StaticResource Black}\"\n    DateTextColor=\"{StaticResource Gray500}\"\n    DateTextFontSize=\"14\"\n    MessageTimeTextColor=\"{StaticResource Gray200}\"\n    NewMessagesSeperatorTextColor=\"{StaticResource Primary}\"\n    NewMessagesSeperatorFontSize=\"16\"\n    NewMessagesSeperatorText=\"New Messages\"\n    AvatarTextColor=\"{StaticResource White}\"\n    AvatarBackgroundColor=\"{StaticResource Tertiary}\"\n    Messages=\"{Binding ChatMessages}\"\n    EmojiReactionFontSize=\"14\"\n    EmojiReactionTextColor=\"{StaticResource Primary}\"\n    ReplyMessageBackgroundColor=\"{StaticResource Tertiary}\"\n    ReplyMessageTextColor=\"{StaticResource White}\"\n    LoadMoreMessagesCommand=\"{Binding LoadOlderMessagesCommand}\"\n    ScrolledCommand=\"{Binding ScrolledCommand}\"\n    AvatarTappedCommand=\"{Binding AvatarTappedCommand}\"\n    MessageTappedCommand=\"{Binding MessageTappedCommand}\"\n    EmojiReactionTappedCommand=\"{Binding EmojiReactionTappedCommand}\"\n    SendIcon=\"send.png\"\n    DeliveredIcon=\"check.png\"\n    ReadIcon=\"read.png\"\n    ScrollToFirstNewMessage=\"True\"\n    ShowNewMessagesSeperator=\"True\"\n    ScrolledToLastMessageCommand=\"{Binding ScrolledToLastMessageCommand}\"\n    SystemMessageBackgroundColor=\"{StaticResource Yellow300Accent}\"\n    SystemMessageTextColor=\"{StaticResource Tertiary}\"\n    SystemMessageFontSize=\"14\"\n    ContextMenuBackgroundColor=\"{StaticResource White}\"\n    ContextMenuTextColor=\"{StaticResource Black}\"\n    ContextMenuDestructiveTextColor=\"{StaticResource Red}\"\n    ContextMenuDividerColor=\"{StaticResource LightGray}\"\n    ContextMenuDividerHeight=\"1\"\n    ContextMenuFontSize=\"14\"\n    ContextMenuReactionFontSize=\"18\"\n    EnableContextMenu=\"True\"\n    LongPressedCommand=\"{Binding LongPressedCommand}\"\u003e\n\n\u003c/idk:ChatView\u003e\n```\n\n### Code-Behind Example\n\n```csharp\nvar chatView = new ChatView\n{\n    Messages = new ObservableRangeCollection\u003cChatMessage\u003e(),\n    MessageTappedCommand = new Command\u003cChatMessage\u003e(OnMessageTapped),\n    AvatarTappedCommand = new Command(OnAvatarTapped),\n    LoadMoreMessagesCommand = new Command(OnLoadMoreMessages),\n    OwnMessageBackgroundColor = Colors.LightBlue,\n    OtherMessageBackgroundColor = Colors.LightGray,\n    ShowNewMessagesSeperator = true,\n    NewMessagesSeperatorText = \"New Messages\",\n    ContextMenuItems = new List\u003cContextMenuItem\u003e\n    {\n        new() { Name = \"Copy\", Tag = \"copy\" },\n        new() { Name = \"Reply\", Tag = \"reply\" },\n        new() { Name = \"Delete\", Tag = \"delete\", IsDestructive = true },\n    },\n    LongPressedCommand = new Command\u003cContextAction\u003e(OnLongPressed)\n};\n\nvoid OnMessageTapped(ChatMessage message)\n{\n    // Handle message tap\n}\n\nvoid OnAvatarTapped()\n{\n    // Handle avatar tap\n}\n\nvoid OnLoadMoreMessages()\n{\n    // Load older messages\n}\n\nvoid OnLongPressed(ContextAction contextAction)\n{\n    // Handle long press actions\n}\n```\n\n---\n\n## Documentation\n\nComprehensive technical documentation for all types, methods, and properties is available in the [`/docs`](docs/) folder. The documentation is auto-generated from the codebase using Roslyn analysis.\n\n### Quick Links\n\n- **[Documentation Index](docs/index.md)** — Start here for an overview\n- **[API Reference](docs/classes/)** — Browse all classes and types\n- **[Namespace Overview](docs/namespaces/)** — Organized by namespace\n- **[Architecture Diagrams](docs/index.md#diagrams)** — Class hierarchy and dependencies\n\n### Features\n\n- 📚 Complete API reference for all public types\n- 🔗 Cross-referenced type links\n- 📊 Mermaid diagrams for visualization\n- 📝 XML documentation comments included\n- 🔄 Version controlled alongside code\n\n### Regenerating Documentation\n\nAfter making code changes, regenerate the documentation:\n\n```bash\ndotnet run --project tools/Tools.CodeDocGenerator/Tools.CodeDocGenerator.csproj\n```\n\nSee the [documentation guide](docs/README.md) for more details.\n\n---\n\n## Contributing\n\nWe encourage you to contribute to the development of the `ChatView` control! Whether you're fixing bugs, adding new features, or enhancing the documentation, your contributions make a difference.\n\nIf you find the `ChatView` control helpful, please consider leaving a ⭐ on the repository. It helps others discover this project and shows your support!\n\nContributions are welcome! Please follow the guidelines for creating feature branches, writing commit messages, and submitting pull requests.\n\n---\n\n# How to Contribute\n\nThank you for considering contributing to our project! Please follow these guidelines to ensure a smooth process.\n\n## 1. Work on a Feature Branch\n\nAlways create a new branch for your feature or fix. This keeps the main branch clean and makes it easier to manage changes.\n\n```bash\ngit checkout -b feature/your-feature-name\n```\n\n## 2. Start a Pull Request\n\nOnce your feature is complete, push your branch to the repository and start a pull request to merge it into the main branch. Ensure all tests pass and your code follows the project's coding standards.\n\n```bash\ngit push origin feature/your-feature-name\n```\n\nThen, create a pull request on GitHub and provide a clear description of your changes.\n\n## 3. Use Semantic Release Prefixes for Commits\n\nWhen committing your changes, use semantic release prefixes to categorize your commits. This helps in generating automated release notes and versioning.\n\nThe commit contains the following structural elements to communicate intent to the consumers of your library:\n\n- **fix:** a commit of the type fix patches a bug in your codebase (this correlates with PATCH in Semantic Versioning).\n- **feat:** a commit of the type feat introduces a new feature to the codebase (this correlates with MINOR in Semantic Versioning).\n- **BREAKING CHANGE:** a commit that has a footer BREAKING CHANGE:, or appends a ! after the type/scope, introduces a breaking API change (correlating with MAJOR in Semantic Versioning). A BREAKING CHANGE can be part of commits of any type.\n- Types other than fix: and feat: are allowed. For example, @commitlint/config-conventional (based on the Angular convention) recommends:\n  - **build:** Changes that affect the build system or external dependencies\n  - **chore:** Other changes that don't modify src or test files\n  - **ci:** Changes to our CI configuration files and scripts\n  - **docs:** Documentation only changes\n  - **style:** Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)\n  - **refactor:** A code change that neither fixes a bug nor adds a feature\n  - **perf:** A code change that improves performance\n  - **test:** Adding missing tests or correcting existing tests\n\nFooters other than BREAKING CHANGE: \u003cdescription\u003e may be provided and follow a convention similar to git trailer format. Additional types are not mandated by the Conventional Commits specification and have no implicit effect in Semantic Versioning (unless they include a BREAKING CHANGE). A scope may be provided to a commit’s type, to provide additional contextual information and is contained within parenthesis, e.g., feat(parser): add ability to parse arrays.\n\nExample commit messages:\n\n```bash\ngit commit -m \"fix: resolve issue with user authentication\"\ngit commit -m \"feat: add new payment gateway integration\"\ngit commit -m \"BREAKING CHANGE: update API endpoints\"\n```\n\n## 4. Write Meaningful Commit Messages\n\nCommit messages should be concise yet descriptive. They should explain the \"what\" and \"why\" of your changes.\n\n- **Good Example:** `fix: correct typo in user profile page`\n- **Bad Example:** `fixed stuff`\n\n## Additional Tips\n\n- Ensure your code adheres to the project's coding standards and guidelines.\n- Include tests for new features or bug fixes.\n- Keep your commits atomic; a single commit should represent a single logical change.\n- Update the documentation to reflect any new features or changes.\n\nWe appreciate your contributions and look forward to your pull requests!\n\nHappy coding!\n\n---\n\n## License\n\nThis project is licensed under the MIT License.\n\n---\n\nThis updated documentation includes the new properties and functionality for the long press gesture feature, ensuring that users understand how to configure and use the context menu for chat message actions.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F0xc3u%2Findiko.maui.controls.chat","html_url":"https://awesome.ecosyste.ms/projects/github.com%2F0xc3u%2Findiko.maui.controls.chat","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F0xc3u%2Findiko.maui.controls.chat/lists"}