├── .cursor └── rules │ ├── 1-architecture-overview.mdc │ ├── 2-chat-controller.mdc │ ├── 3-customization.mdc │ ├── 4-core-models.mdc │ ├── 5-core-values-and-decisions.mdc │ └── 6-streaming-text-message.mdc ├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── analysis_options.yaml ├── banner.png ├── examples └── flyer_chat │ ├── .env │ ├── .gitignore │ ├── .metadata │ ├── README.md │ ├── analysis_options.yaml │ ├── android │ ├── .gitignore │ ├── app │ │ ├── build.gradle.kts │ │ └── src │ │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ │ ├── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── kotlin │ │ │ │ └── flyer │ │ │ │ │ └── chat │ │ │ │ │ └── flyer_chat │ │ │ │ │ └── MainActivity.kt │ │ │ └── res │ │ │ │ ├── drawable-v21 │ │ │ │ └── launch_background.xml │ │ │ │ ├── drawable │ │ │ │ └── launch_background.xml │ │ │ │ ├── mipmap-hdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── values-night │ │ │ │ └── styles.xml │ │ │ │ └── values │ │ │ │ └── styles.xml │ │ │ └── profile │ │ │ └── AndroidManifest.xml │ ├── build.gradle.kts │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ └── gradle-wrapper.properties │ └── settings.gradle.kts │ ├── assets │ └── pattern.png │ ├── integration_test │ └── list_test.dart │ ├── ios │ ├── .gitignore │ ├── Flutter │ │ ├── AppFrameworkInfo.plist │ │ ├── Debug.xcconfig │ │ └── Release.xcconfig │ ├── Podfile │ ├── Podfile.lock │ ├── Runner.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ │ └── WorkspaceSettings.xcsettings │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── Runner.xcscheme │ ├── Runner.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── WorkspaceSettings.xcsettings │ ├── Runner │ │ ├── AppDelegate.swift │ │ ├── Assets.xcassets │ │ │ ├── AppIcon.appiconset │ │ │ │ ├── Contents.json │ │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ │ ├── Icon-App-20x20@1x.png │ │ │ │ ├── Icon-App-20x20@2x.png │ │ │ │ ├── Icon-App-20x20@3x.png │ │ │ │ ├── Icon-App-29x29@1x.png │ │ │ │ ├── Icon-App-29x29@2x.png │ │ │ │ ├── Icon-App-29x29@3x.png │ │ │ │ ├── Icon-App-40x40@1x.png │ │ │ │ ├── Icon-App-40x40@2x.png │ │ │ │ ├── Icon-App-40x40@3x.png │ │ │ │ ├── Icon-App-60x60@2x.png │ │ │ │ ├── Icon-App-60x60@3x.png │ │ │ │ ├── Icon-App-76x76@1x.png │ │ │ │ ├── Icon-App-76x76@2x.png │ │ │ │ └── Icon-App-83.5x83.5@2x.png │ │ │ └── LaunchImage.imageset │ │ │ │ ├── Contents.json │ │ │ │ ├── LaunchImage.png │ │ │ │ ├── LaunchImage@2x.png │ │ │ │ ├── LaunchImage@3x.png │ │ │ │ └── README.md │ │ ├── Base.lproj │ │ │ ├── LaunchScreen.storyboard │ │ │ └── Main.storyboard │ │ ├── Info.plist │ │ └── Runner-Bridging-Header.h │ └── RunnerTests │ │ └── RunnerTests.swift │ ├── lib │ ├── api │ │ ├── api.dart │ │ ├── api_service.dart │ │ ├── connection_status.dart │ │ ├── upload_file.dart │ │ └── websocket_service.dart │ ├── api_get_chat_id.dart │ ├── api_get_initial_messages.dart │ ├── basic.dart │ ├── create_message.dart │ ├── gemini.dart │ ├── gemini_stream_manager.dart │ ├── hive_chat_controller.dart │ ├── local.dart │ ├── main.dart │ ├── pagination.dart │ └── widgets │ │ └── composer_action_bar.dart │ ├── linux │ ├── .gitignore │ ├── CMakeLists.txt │ ├── flutter │ │ ├── CMakeLists.txt │ │ ├── generated_plugin_registrant.cc │ │ ├── generated_plugin_registrant.h │ │ └── generated_plugins.cmake │ └── runner │ │ ├── CMakeLists.txt │ │ ├── main.cc │ │ ├── my_application.cc │ │ └── my_application.h │ ├── macos │ ├── .gitignore │ ├── Flutter │ │ ├── Flutter-Debug.xcconfig │ │ ├── Flutter-Release.xcconfig │ │ └── GeneratedPluginRegistrant.swift │ ├── Podfile │ ├── Podfile.lock │ ├── Runner.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ └── xcshareddata │ │ │ │ └── IDEWorkspaceChecks.plist │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── Runner.xcscheme │ ├── Runner.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ ├── Runner │ │ ├── AppDelegate.swift │ │ ├── Assets.xcassets │ │ │ └── AppIcon.appiconset │ │ │ │ ├── Contents.json │ │ │ │ ├── app_icon_1024.png │ │ │ │ ├── app_icon_128.png │ │ │ │ ├── app_icon_16.png │ │ │ │ ├── app_icon_256.png │ │ │ │ ├── app_icon_32.png │ │ │ │ ├── app_icon_512.png │ │ │ │ └── app_icon_64.png │ │ ├── Base.lproj │ │ │ └── MainMenu.xib │ │ ├── Configs │ │ │ ├── AppInfo.xcconfig │ │ │ ├── Debug.xcconfig │ │ │ ├── Release.xcconfig │ │ │ └── Warnings.xcconfig │ │ ├── DebugProfile.entitlements │ │ ├── Info.plist │ │ ├── MainFlutterWindow.swift │ │ └── Release.entitlements │ └── RunnerTests │ │ └── RunnerTests.swift │ ├── pubspec.yaml │ ├── web │ ├── favicon.png │ ├── icons │ │ ├── Icon-192.png │ │ ├── Icon-512.png │ │ ├── Icon-maskable-192.png │ │ └── Icon-maskable-512.png │ ├── index.html │ └── manifest.json │ └── windows │ ├── .gitignore │ ├── CMakeLists.txt │ ├── flutter │ ├── CMakeLists.txt │ ├── generated_plugin_registrant.cc │ ├── generated_plugin_registrant.h │ └── generated_plugins.cmake │ └── runner │ ├── CMakeLists.txt │ ├── Runner.rc │ ├── flutter_window.cpp │ ├── flutter_window.h │ ├── main.cpp │ ├── resource.h │ ├── resources │ └── app_icon.ico │ ├── runner.exe.manifest │ ├── utils.cpp │ ├── utils.h │ ├── win32_window.cpp │ └── win32_window.h ├── melos.yaml ├── packages ├── cross_cache │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── analysis_options.yaml │ ├── example │ │ └── README.md │ ├── lib │ │ ├── cross_cache.dart │ │ └── src │ │ │ ├── cache │ │ │ ├── base_cache.dart │ │ │ ├── cache.dart │ │ │ ├── html.dart │ │ │ └── io.dart │ │ │ ├── cached_network_image.dart │ │ │ └── cross_cache.dart │ ├── pubspec.yaml │ └── test │ │ ├── cross_cache_test.dart │ │ └── transparent_image.dart ├── flutter_chat_core │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── analysis_options.yaml │ ├── build.yaml │ ├── example │ │ └── README.md │ ├── lib │ │ ├── flutter_chat_core.dart │ │ └── src │ │ │ ├── chat_controller │ │ │ ├── chat_controller.dart │ │ │ ├── chat_operation.dart │ │ │ ├── in_memory_chat_controller.dart │ │ │ ├── scroll_to_message_mixin.dart │ │ │ └── upload_progress_mixin.dart │ │ │ ├── models │ │ │ ├── builders.dart │ │ │ ├── builders.freezed.dart │ │ │ ├── duration_converter.dart │ │ │ ├── epoch_date_time_converter.dart │ │ │ ├── link_preview_data.dart │ │ │ ├── link_preview_data.freezed.dart │ │ │ ├── link_preview_data.g.dart │ │ │ ├── message.dart │ │ │ ├── message.freezed.dart │ │ │ ├── message.g.dart │ │ │ ├── message_group_status.dart │ │ │ ├── user.dart │ │ │ ├── user.freezed.dart │ │ │ └── user.g.dart │ │ │ ├── theme │ │ │ ├── chat_theme.dart │ │ │ ├── chat_theme.freezed.dart │ │ │ └── chat_theme_extension.dart │ │ │ └── utils │ │ │ ├── get_icon_for_status.dart │ │ │ ├── is_only_emoji.dart │ │ │ ├── link_preview_position.dart │ │ │ ├── typedefs.dart │ │ │ └── user_cache.dart │ ├── pubspec.yaml │ └── test │ │ ├── chat_controller │ │ ├── in_memory_chat_controller_test.dart │ │ └── mock_data.dart │ │ ├── models │ │ ├── link_preview_data_test.dart │ │ └── message_test.dart │ │ └── utils │ │ └── only_emoji_test.dart ├── flutter_chat_ui │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── analysis_options.yaml │ ├── example │ │ └── README.md │ ├── lib │ │ ├── flutter_chat_ui.dart │ │ └── src │ │ │ ├── avatar.dart │ │ │ ├── chat.dart │ │ │ ├── chat_animated_list │ │ │ ├── chat_animated_list.dart │ │ │ ├── chat_animated_list_reversed.dart │ │ │ └── sliver_spacing.dart │ │ │ ├── chat_message │ │ │ ├── chat_message.dart │ │ │ └── chat_message_internal.dart │ │ │ ├── composer.dart │ │ │ ├── empty_chat_list.dart │ │ │ ├── is_typing.dart │ │ │ ├── load_more.dart │ │ │ ├── scroll_to_bottom.dart │ │ │ ├── simple_text_message.dart │ │ │ ├── username.dart │ │ │ └── utils │ │ │ ├── composer_height_notifier.dart │ │ │ ├── keyboard_mixin.dart │ │ │ ├── load_more_notifier.dart │ │ │ ├── message_list_diff.dart │ │ │ └── typedefs.dart │ └── pubspec.yaml ├── flyer_chat_audio_message │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── analysis_options.yaml │ ├── lib │ │ ├── flyer_chat_audio_message.dart │ │ └── src │ │ │ └── flyer_chat_audio_message.dart │ └── pubspec.yaml ├── flyer_chat_custom_message │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── analysis_options.yaml │ ├── lib │ │ ├── flyer_chat_custom_message.dart │ │ └── src │ │ │ └── flyer_chat_custom_message.dart │ └── pubspec.yaml ├── flyer_chat_file_message │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── analysis_options.yaml │ ├── example │ │ └── README.md │ ├── lib │ │ ├── flyer_chat_file_message.dart │ │ └── src │ │ │ └── flyer_chat_file_message.dart │ └── pubspec.yaml ├── flyer_chat_image_message │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── analysis_options.yaml │ ├── example │ │ └── README.md │ ├── lib │ │ ├── flyer_chat_image_message.dart │ │ └── src │ │ │ ├── flyer_chat_image_message.dart │ │ │ └── get_image_dimensions.dart │ └── pubspec.yaml ├── flyer_chat_location_message │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── analysis_options.yaml │ ├── lib │ │ ├── flyer_chat_location_message.dart │ │ └── src │ │ │ └── flyer_chat_location_message.dart │ └── pubspec.yaml ├── flyer_chat_system_message │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── analysis_options.yaml │ ├── example │ │ └── README.md │ ├── lib │ │ ├── flyer_chat_system_message.dart │ │ └── src │ │ │ └── flyer_chat_system_message.dart │ └── pubspec.yaml ├── flyer_chat_text_message │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── analysis_options.yaml │ ├── example │ │ └── README.md │ ├── lib │ │ ├── flyer_chat_text_message.dart │ │ └── src │ │ │ └── flyer_chat_text_message.dart │ └── pubspec.yaml ├── flyer_chat_text_stream_message │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── analysis_options.yaml │ ├── example │ │ └── README.md │ ├── lib │ │ ├── flyer_chat_text_stream_message.dart │ │ └── src │ │ │ ├── flyer_chat_text_stream_message.dart │ │ │ ├── stream_state.dart │ │ │ └── text_segment.dart │ └── pubspec.yaml └── flyer_chat_video_message │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── analysis_options.yaml │ ├── lib │ ├── flyer_chat_video_message.dart │ └── src │ │ └── flyer_chat_video_message.dart │ └── pubspec.yaml └── pubspec.yaml /.cursor/rules/1-architecture-overview.mdc: -------------------------------------------------------------------------------- 1 | --- 2 | description: 3 | globs: 4 | alwaysApply: true 5 | --- 6 | # Flyer Chat - Project Architecture Overview 7 | 8 | The project uses a Melos-managed monorepo structure: 9 | 10 | - `/examples` - Contains demo applications showcasing various features. 11 | - `/packages` - Houses the core and supplementary packages. 12 | 13 | ## Core Packages 14 | 15 | - `packages/flutter_chat_core` ([flutter_chat_core/lib](mdc:packages/flutter_chat_core/lib)) - Provides the foundational models, controllers, and theming utilities. It has minimal dependencies. 16 | - `packages/flutter_chat_ui` ([flutter_chat_ui/lib](mdc:packages/flutter_chat_ui/lib)) - The main UI package containing the primary chat widgets. Also designed with minimal dependencies. 17 | - `packages/cross_cache` ([cross_cache/lib](mdc:packages/cross_cache/lib)) - Handles image caching across different platforms (IO and web). 18 | 19 | ## Message Type Packages 20 | 21 | Additional message types are implemented in separate packages, typically prefixed with `flyer_chat_`. These are optional and allow users to include only the message types they need. 22 | 23 | - Example: `packages/flyer_chat_text_message` ([flyer_chat_text_message/lib](mdc:packages/flyer_chat_text_message/lib)) 24 | - Example: `packages/flyer_chat_image_message` ([flyer_chat_image_message/lib](mdc:packages/flyer_chat_image_message/lib)) 25 | 26 | Refer to the `packages` directory for a full list. 27 | 28 | ## Key Goal 29 | 30 | Support all Flutter platforms (iOS, Android, Web, macOS, Windows, Linux). Avoid platform-specific imports (like `dart:io`) in core packages. 31 | -------------------------------------------------------------------------------- /.cursor/rules/2-chat-controller.mdc: -------------------------------------------------------------------------------- 1 | --- 2 | description: 3 | globs: 4 | alwaysApply: true 5 | --- 6 | # Flyer Chat - Chat Controller 7 | 8 | The `ChatController` is the central component for managing message state within the chat UI. 9 | 10 | ## Core Responsibilities 11 | 12 | - Provides methods to add, update, and remove messages. 13 | - Allows both user interactions (e.g., sending a message) and internal updates (e.g., an image message updating its dimensions) to modify the message list. 14 | 15 | ## Implementations 16 | 17 | - **Interface**: Defined in [chat_controller.dart](mdc:packages/flutter_chat_core/lib/src/chat_controller/chat_controller.dart). 18 | - **Default**: `InMemoryChatController` ([in_memory_chat_controller.dart](mdc:packages/flutter_chat_core/lib/src/chat_controller/in_memory_chat_controller.dart)) is provided for easy setup, but it does not persist messages across app restarts. 19 | - **Custom Persistence**: Users are expected to create custom implementations for persistent storage (saving messages). Examples using Sembast ([sembast_chat_controller.dart](mdc:examples/flyer_chat/lib/sembast_chat_controller.dart)) and Hive ([hive_chat_controller.dart](mdc:examples/flyer_chat/lib/hive_chat_controller.dart)) can be found in the `/examples` directory. 20 | 21 | ## Usage 22 | 23 | The `Chat` widget requires a `ChatController` instance to function. 24 | -------------------------------------------------------------------------------- /.cursor/rules/3-customization.mdc: -------------------------------------------------------------------------------- 1 | --- 2 | description: 3 | globs: 4 | alwaysApply: true 5 | --- 6 | # Flyer Chat - Customization 7 | 8 | Flyer Chat offers extensive customization through two primary mechanisms: 9 | 10 | ## 1. Theming (`ChatTheme`) 11 | 12 | - Controls the overall look and feel (colors, typography, shapes). 13 | - Defined in `flutter_chat_core`: 14 | - [chat_theme.dart](mdc:packages/flutter_chat_core/lib/src/theme/chat_theme.dart) 15 | - [chat_theme_extension.dart](mdc:packages/flutter_chat_core/lib/src/theme/chat_theme_extension.dart) 16 | - Uses Material Design principles. 17 | - Passed to the main `Chat` widget ([chat.dart](mdc:packages/flutter_chat_ui/lib/src/chat.dart)). 18 | - Widgets should use theme values by default but allow overrides via parameters. 19 | - Good example: [simple_text_message.dart](mdc:packages/flutter_chat_ui/lib/src/simple_text_message.dart) 20 | 21 | ## 2. Builders (`Builders`) 22 | 23 | - Allows replacing *any* UI component with a custom implementation. 24 | - The `Builders` model is defined in [builders.dart](mdc:packages/flutter_chat_core/lib/src/models/builders.dart). 25 | - Passed as a parameter to the `Chat` widget ([chat.dart](mdc:packages/flutter_chat_ui/lib/src/chat.dart)). 26 | - Enables swapping out the composer, message bubbles, specific message types (text, image, etc.), date headers, status indicators, and more. 27 | - Provides maximum flexibility for UI modifications. 28 | -------------------------------------------------------------------------------- /.cursor/rules/4-core-models.mdc: -------------------------------------------------------------------------------- 1 | --- 2 | description: 3 | globs: 4 | alwaysApply: true 5 | --- 6 | # Flyer Chat - Core Data Models 7 | 8 | Core data structures are defined in `flutter_chat_core`. 9 | 10 | ## Message Model 11 | 12 | - Base model for all message types. 13 | - Defined in [message.dart](mdc:packages/flutter_chat_core/lib/src/models/message.dart). 14 | - Contains common fields like `id`, `authorId`, `createdAt`, `roomId`, `type`, `metadata`. 15 | - Includes nullable `DateTime?` fields for status tracking (`sentAt`, `deliveredAt`, `seenAt`, `failedAt`, etc.). 16 | - Specific message types (Text, Image, File, Custom, System, etc.) extend or implement this base structure, often adding type-specific fields (e.g., `text` for `TextMessage`, `source` for `ImageMessage`). 17 | 18 | ## User Model 19 | 20 | - Represents a user in the chat. 21 | - Defined in [user.dart](mdc:packages/flutter_chat_core/lib/src/models/user.dart). 22 | - Contains fields like `id`, `name`, `imageSource`, `role`, `metadata`. 23 | 24 | ## Other Models 25 | 26 | - `ChatTheme`: Configuration for UI styling ([chat_theme.dart](mdc:packages/flutter_chat_core/lib/src/theme/chat_theme.dart)). 27 | - `Builders`: Configuration for custom UI components ([builders.dart](mdc:packages/flutter_chat_core/lib/src/models/builders.dart)). 28 | -------------------------------------------------------------------------------- /.cursor/rules/5-core-values-and-decisions.mdc: -------------------------------------------------------------------------------- 1 | --- 2 | description: 3 | globs: 4 | alwaysApply: true 5 | --- 6 | # Flyer Chat - Core Values & Architectural Decisions 7 | 8 | ## Core Values 9 | 10 | - **Performance** - Always optimize for performance. 11 | - **Animations** - Smooth, polished animations are essential. 12 | - **Resource Management** - Properly clean up resources (e.g., controllers, streams). 13 | - **Customization** - Provide flexible customization options (Theme, Builders). 14 | - **Modularity** - Extract specific message types to separate packages. 15 | - **Platform Support** - Support all Flutter platforms (avoid `dart:io` in core). 16 | 17 | ## Key Architectural Decisions 18 | 19 | - Minimal dependencies in core packages (`flutter_chat_core`, `flutter_chat_ui`). 20 | - Extraction of message type implementations to optional packages. 21 | - Builder pattern ([builders.dart](mdc:packages/flutter_chat_core/lib/src/models/builders.dart)) for complete customization. 22 | - Using `provider` for state management and dependency injection. Shared logic is registered via `MultiProvider` in the main `Chat` widget ([chat.dart](mdc:packages/flutter_chat_ui/lib/src/chat.dart)). 23 | - Support for both regular and reversed chat list layouts. 24 | - Controller-based state management (`ChatController` interface). 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | migrate_working_dir/ 12 | 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # The .vscode folder contains launch configuration and tasks you configure in 20 | # VS Code which you may wish to be included in version control, so this line 21 | # is commented out by default. 22 | #.vscode/ 23 | 24 | # Flutter/Dart/Pub related 25 | # Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. 26 | pubspec.lock 27 | **/doc/api/ 28 | **/ios/Flutter/.last_build_id 29 | .dart_tool/ 30 | .flutter-plugins 31 | .flutter-plugins-dependencies 32 | .pub-cache/ 33 | .pub/ 34 | build/ 35 | 36 | # Symbolication related 37 | app.*.symbols 38 | 39 | # Obfuscation related 40 | app.*.map.json 41 | 42 | # Android Studio will place build artifacts here 43 | /android/app/debug 44 | /android/app/profile 45 | /android/app/release 46 | 47 | pubspec_overrides.yaml 48 | coverage/ 49 | 50 | devtools_options.yaml 51 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:flutter_lints/flutter.yaml 2 | 3 | analyzer: 4 | exclude: 5 | - "**/*.g.dart" 6 | - "**/*.freezed.dart" 7 | 8 | linter: 9 | rules: 10 | - always_declare_return_types 11 | - avoid_unused_constructor_parameters 12 | - directives_ordering 13 | - omit_local_variable_types 14 | - prefer_final_locals 15 | - prefer_relative_imports 16 | - prefer_single_quotes 17 | - sort_pub_dependencies 18 | - type_annotate_public_apis 19 | - unawaited_futures 20 | - use_named_constants 21 | -------------------------------------------------------------------------------- /banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flyerhq/flutter_chat_ui/4fe6b2049f242a507a26ce09a016fe5d6929f750/banner.png -------------------------------------------------------------------------------- /examples/flyer_chat/.env: -------------------------------------------------------------------------------- 1 | DEFAULT_CHAT_ID= 2 | GEMINI_API_KEY= 3 | -------------------------------------------------------------------------------- /examples/flyer_chat/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .build/ 9 | .buildlog/ 10 | .history 11 | .svn/ 12 | .swiftpm/ 13 | migrate_working_dir/ 14 | 15 | # IntelliJ related 16 | *.iml 17 | *.ipr 18 | *.iws 19 | .idea/ 20 | 21 | # The .vscode folder contains launch configuration and tasks you configure in 22 | # VS Code which you may wish to be included in version control, so this line 23 | # is commented out by default. 24 | #.vscode/ 25 | 26 | # Flutter/Dart/Pub related 27 | **/doc/api/ 28 | **/ios/Flutter/.last_build_id 29 | .dart_tool/ 30 | .flutter-plugins 31 | .flutter-plugins-dependencies 32 | .pub-cache/ 33 | .pub/ 34 | /build/ 35 | 36 | # Symbolication related 37 | app.*.symbols 38 | 39 | # Obfuscation related 40 | app.*.map.json 41 | 42 | # Android Studio will place build artifacts here 43 | /android/app/debug 44 | /android/app/profile 45 | /android/app/release 46 | 47 | DerivedData/ 48 | .env 49 | -------------------------------------------------------------------------------- /examples/flyer_chat/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: "8defaa71a77c16e8547abdbfad2053ce3a6e2d5b" 8 | channel: "stable" 9 | 10 | project_type: app 11 | 12 | # Tracks metadata for the flutter migrate command 13 | migration: 14 | platforms: 15 | - platform: root 16 | create_revision: 8defaa71a77c16e8547abdbfad2053ce3a6e2d5b 17 | base_revision: 8defaa71a77c16e8547abdbfad2053ce3a6e2d5b 18 | - platform: android 19 | create_revision: 8defaa71a77c16e8547abdbfad2053ce3a6e2d5b 20 | base_revision: 8defaa71a77c16e8547abdbfad2053ce3a6e2d5b 21 | - platform: ios 22 | create_revision: 8defaa71a77c16e8547abdbfad2053ce3a6e2d5b 23 | base_revision: 8defaa71a77c16e8547abdbfad2053ce3a6e2d5b 24 | - platform: linux 25 | create_revision: 8defaa71a77c16e8547abdbfad2053ce3a6e2d5b 26 | base_revision: 8defaa71a77c16e8547abdbfad2053ce3a6e2d5b 27 | - platform: macos 28 | create_revision: 8defaa71a77c16e8547abdbfad2053ce3a6e2d5b 29 | base_revision: 8defaa71a77c16e8547abdbfad2053ce3a6e2d5b 30 | - platform: web 31 | create_revision: 8defaa71a77c16e8547abdbfad2053ce3a6e2d5b 32 | base_revision: 8defaa71a77c16e8547abdbfad2053ce3a6e2d5b 33 | - platform: windows 34 | create_revision: 8defaa71a77c16e8547abdbfad2053ce3a6e2d5b 35 | base_revision: 8defaa71a77c16e8547abdbfad2053ce3a6e2d5b 36 | 37 | # User provided section 38 | 39 | # List of Local paths (relative to this file) that should be 40 | # ignored by the migrate tool. 41 | # 42 | # Files that are not part of the templates will be ignored by default. 43 | unmanaged_files: 44 | - 'lib/main.dart' 45 | - 'ios/Runner.xcodeproj/project.pbxproj' 46 | -------------------------------------------------------------------------------- /examples/flyer_chat/README.md: -------------------------------------------------------------------------------- 1 | # flyer_chat 2 | 3 | A new Flutter project. 4 | 5 | ## Getting Started 6 | 7 | This project is a starting point for a Flutter application. 8 | 9 | A few resources to get you started if this is your first Flutter project: 10 | 11 | - [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) 12 | - [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) 13 | 14 | For help getting started with Flutter development, view the 15 | [online documentation](https://docs.flutter.dev/), which offers tutorials, 16 | samples, guidance on mobile development, and a full API reference. 17 | -------------------------------------------------------------------------------- /examples/flyer_chat/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: ../../analysis_options.yaml 2 | -------------------------------------------------------------------------------- /examples/flyer_chat/android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | .cxx/ 9 | 10 | # Remember to never publicly share your keystore. 11 | # See https://flutter.dev/to/reference-keystore 12 | key.properties 13 | **/*.keystore 14 | **/*.jks 15 | -------------------------------------------------------------------------------- /examples/flyer_chat/android/app/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("com.android.application") 3 | id("kotlin-android") 4 | // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. 5 | id("dev.flutter.flutter-gradle-plugin") 6 | } 7 | 8 | android { 9 | namespace = "flyer.chat.flyer_chat" 10 | compileSdk = flutter.compileSdkVersion 11 | ndkVersion = flutter.ndkVersion 12 | 13 | compileOptions { 14 | sourceCompatibility = JavaVersion.VERSION_11 15 | targetCompatibility = JavaVersion.VERSION_11 16 | } 17 | 18 | kotlinOptions { 19 | jvmTarget = JavaVersion.VERSION_11.toString() 20 | } 21 | 22 | defaultConfig { 23 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 24 | applicationId = "flyer.chat.flyer_chat" 25 | // You can update the following values to match your application needs. 26 | // For more information, see: https://flutter.dev/to/review-gradle-config. 27 | minSdk = 23 28 | targetSdk = flutter.targetSdkVersion 29 | versionCode = flutter.versionCode 30 | versionName = flutter.versionName 31 | } 32 | 33 | buildTypes { 34 | release { 35 | // TODO: Add your own signing config for the release build. 36 | // Signing with the debug keys for now, so `flutter run --release` works. 37 | signingConfig = signingConfigs.getByName("debug") 38 | } 39 | } 40 | } 41 | 42 | flutter { 43 | source = "../.." 44 | } 45 | -------------------------------------------------------------------------------- /examples/flyer_chat/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/flyer_chat/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 15 | 19 | 23 | 24 | 25 | 26 | 27 | 28 | 30 | 33 | 34 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /examples/flyer_chat/android/app/src/main/kotlin/flyer/chat/flyer_chat/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package flyer.chat.flyer_chat 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity : FlutterActivity() 6 | -------------------------------------------------------------------------------- /examples/flyer_chat/android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /examples/flyer_chat/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /examples/flyer_chat/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flyerhq/flutter_chat_ui/4fe6b2049f242a507a26ce09a016fe5d6929f750/examples/flyer_chat/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /examples/flyer_chat/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flyerhq/flutter_chat_ui/4fe6b2049f242a507a26ce09a016fe5d6929f750/examples/flyer_chat/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /examples/flyer_chat/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flyerhq/flutter_chat_ui/4fe6b2049f242a507a26ce09a016fe5d6929f750/examples/flyer_chat/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /examples/flyer_chat/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flyerhq/flutter_chat_ui/4fe6b2049f242a507a26ce09a016fe5d6929f750/examples/flyer_chat/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /examples/flyer_chat/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flyerhq/flutter_chat_ui/4fe6b2049f242a507a26ce09a016fe5d6929f750/examples/flyer_chat/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /examples/flyer_chat/android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /examples/flyer_chat/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /examples/flyer_chat/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/flyer_chat/android/build.gradle.kts: -------------------------------------------------------------------------------- 1 | allprojects { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | } 6 | } 7 | 8 | val newBuildDir: Directory = rootProject.layout.buildDirectory.dir("../../build").get() 9 | rootProject.layout.buildDirectory.value(newBuildDir) 10 | 11 | subprojects { 12 | val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name) 13 | project.layout.buildDirectory.value(newSubprojectBuildDir) 14 | } 15 | subprojects { 16 | project.evaluationDependsOn(":app") 17 | } 18 | 19 | tasks.register("clean") { 20 | delete(rootProject.layout.buildDirectory) 21 | } 22 | -------------------------------------------------------------------------------- /examples/flyer_chat/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /examples/flyer_chat/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip 6 | -------------------------------------------------------------------------------- /examples/flyer_chat/android/settings.gradle.kts: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | val flutterSdkPath = run { 3 | val properties = java.util.Properties() 4 | file("local.properties").inputStream().use { properties.load(it) } 5 | val flutterSdkPath = properties.getProperty("flutter.sdk") 6 | require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } 7 | flutterSdkPath 8 | } 9 | 10 | includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") 11 | 12 | repositories { 13 | google() 14 | mavenCentral() 15 | gradlePluginPortal() 16 | } 17 | } 18 | 19 | plugins { 20 | id("dev.flutter.flutter-plugin-loader") version "1.0.0" 21 | id("com.android.application") version "8.7.3" apply false 22 | id("org.jetbrains.kotlin.android") version "2.1.0" apply false 23 | } 24 | 25 | include(":app") 26 | -------------------------------------------------------------------------------- /examples/flyer_chat/assets/pattern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flyerhq/flutter_chat_ui/4fe6b2049f242a507a26ce09a016fe5d6929f750/examples/flyer_chat/assets/pattern.png -------------------------------------------------------------------------------- /examples/flyer_chat/ios/.gitignore: -------------------------------------------------------------------------------- 1 | **/dgph 2 | *.mode1v3 3 | *.mode2v3 4 | *.moved-aside 5 | *.pbxuser 6 | *.perspectivev3 7 | **/*sync/ 8 | .sconsign.dblite 9 | .tags* 10 | **/.vagrant/ 11 | **/DerivedData/ 12 | Icon? 13 | **/Pods/ 14 | **/.symlinks/ 15 | profile 16 | xcuserdata 17 | **/.generated/ 18 | Flutter/App.framework 19 | Flutter/Flutter.framework 20 | Flutter/Flutter.podspec 21 | Flutter/Generated.xcconfig 22 | Flutter/ephemeral/ 23 | Flutter/app.flx 24 | Flutter/app.zip 25 | Flutter/flutter_assets/ 26 | Flutter/flutter_export_environment.sh 27 | ServiceDefinitions.json 28 | Runner/GeneratedPluginRegistrant.* 29 | 30 | # Exceptions to above rules. 31 | !default.mode1v3 32 | !default.mode2v3 33 | !default.pbxuser 34 | !default.perspectivev3 35 | -------------------------------------------------------------------------------- /examples/flyer_chat/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 12.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /examples/flyer_chat/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /examples/flyer_chat/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /examples/flyer_chat/ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '12.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def flutter_root 14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) 15 | unless File.exist?(generated_xcode_build_settings_path) 16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" 17 | end 18 | 19 | File.foreach(generated_xcode_build_settings_path) do |line| 20 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 21 | return matches[1].strip if matches 22 | end 23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" 24 | end 25 | 26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 27 | 28 | flutter_ios_podfile_setup 29 | 30 | target 'Runner' do 31 | use_frameworks! 32 | 33 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) 34 | target 'RunnerTests' do 35 | inherit! :search_paths 36 | end 37 | end 38 | 39 | post_install do |installer| 40 | installer.pods_project.targets.each do |target| 41 | flutter_additional_ios_build_settings(target) 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /examples/flyer_chat/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/flyer_chat/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /examples/flyer_chat/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /examples/flyer_chat/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /examples/flyer_chat/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /examples/flyer_chat/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /examples/flyer_chat/ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import Flutter 2 | import UIKit 3 | 4 | @main 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /examples/flyer_chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flyerhq/flutter_chat_ui/4fe6b2049f242a507a26ce09a016fe5d6929f750/examples/flyer_chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /examples/flyer_chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flyerhq/flutter_chat_ui/4fe6b2049f242a507a26ce09a016fe5d6929f750/examples/flyer_chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /examples/flyer_chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flyerhq/flutter_chat_ui/4fe6b2049f242a507a26ce09a016fe5d6929f750/examples/flyer_chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /examples/flyer_chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flyerhq/flutter_chat_ui/4fe6b2049f242a507a26ce09a016fe5d6929f750/examples/flyer_chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /examples/flyer_chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flyerhq/flutter_chat_ui/4fe6b2049f242a507a26ce09a016fe5d6929f750/examples/flyer_chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /examples/flyer_chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flyerhq/flutter_chat_ui/4fe6b2049f242a507a26ce09a016fe5d6929f750/examples/flyer_chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /examples/flyer_chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flyerhq/flutter_chat_ui/4fe6b2049f242a507a26ce09a016fe5d6929f750/examples/flyer_chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /examples/flyer_chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flyerhq/flutter_chat_ui/4fe6b2049f242a507a26ce09a016fe5d6929f750/examples/flyer_chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /examples/flyer_chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flyerhq/flutter_chat_ui/4fe6b2049f242a507a26ce09a016fe5d6929f750/examples/flyer_chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /examples/flyer_chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flyerhq/flutter_chat_ui/4fe6b2049f242a507a26ce09a016fe5d6929f750/examples/flyer_chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /examples/flyer_chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flyerhq/flutter_chat_ui/4fe6b2049f242a507a26ce09a016fe5d6929f750/examples/flyer_chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /examples/flyer_chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flyerhq/flutter_chat_ui/4fe6b2049f242a507a26ce09a016fe5d6929f750/examples/flyer_chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /examples/flyer_chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flyerhq/flutter_chat_ui/4fe6b2049f242a507a26ce09a016fe5d6929f750/examples/flyer_chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /examples/flyer_chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flyerhq/flutter_chat_ui/4fe6b2049f242a507a26ce09a016fe5d6929f750/examples/flyer_chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /examples/flyer_chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flyerhq/flutter_chat_ui/4fe6b2049f242a507a26ce09a016fe5d6929f750/examples/flyer_chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /examples/flyer_chat/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /examples/flyer_chat/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flyerhq/flutter_chat_ui/4fe6b2049f242a507a26ce09a016fe5d6929f750/examples/flyer_chat/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /examples/flyer_chat/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flyerhq/flutter_chat_ui/4fe6b2049f242a507a26ce09a016fe5d6929f750/examples/flyer_chat/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /examples/flyer_chat/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flyerhq/flutter_chat_ui/4fe6b2049f242a507a26ce09a016fe5d6929f750/examples/flyer_chat/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /examples/flyer_chat/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /examples/flyer_chat/ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /examples/flyer_chat/ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /examples/flyer_chat/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | Flyer Chat 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | flyer_chat 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | $(FLUTTER_BUILD_NUMBER) 25 | LSRequiresIPhoneOS 26 | 27 | NSCameraUsageDescription 28 | Example 29 | NSPhotoLibraryUsageDescription 30 | Example 31 | UILaunchStoryboardName 32 | LaunchScreen 33 | UIMainStoryboardFile 34 | Main 35 | UISupportedInterfaceOrientations 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationLandscapeLeft 39 | UIInterfaceOrientationLandscapeRight 40 | 41 | UISupportedInterfaceOrientations~ipad 42 | 43 | UIInterfaceOrientationPortrait 44 | UIInterfaceOrientationPortraitUpsideDown 45 | UIInterfaceOrientationLandscapeLeft 46 | UIInterfaceOrientationLandscapeRight 47 | 48 | CADisableMinimumFrameDurationOnPhone 49 | 50 | UIApplicationSupportsIndirectInputEvents 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /examples/flyer_chat/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /examples/flyer_chat/ios/RunnerTests/RunnerTests.swift: -------------------------------------------------------------------------------- 1 | import Flutter 2 | import UIKit 3 | import XCTest 4 | 5 | class RunnerTests: XCTestCase { 6 | 7 | func testExample() { 8 | // If you add code to the Runner application, consider adding tests here. 9 | // See https://developer.apple.com/documentation/xctest for more information about using XCTest. 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /examples/flyer_chat/lib/api/api_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:dio/dio.dart'; 2 | import 'package:flutter_chat_core/flutter_chat_core.dart'; 3 | 4 | class ApiService { 5 | final String baseUrl; 6 | final String chatId; 7 | final Dio dio; 8 | 9 | ApiService({required this.baseUrl, required this.chatId, required this.dio}); 10 | 11 | Future> send(Message message) async { 12 | try { 13 | final response = await dio.post>( 14 | '$baseUrl/chat/$chatId/message', 15 | data: message.toJson(), 16 | ); 17 | return response.data!; 18 | } catch (e) { 19 | throw 'Failed to send message: $e'; 20 | } 21 | } 22 | 23 | Future delete(Message message) async { 24 | try { 25 | await dio.delete( 26 | '$baseUrl/chat/$chatId/message', 27 | data: {'id': message.id}, 28 | ); 29 | } catch (e) { 30 | throw 'Failed to delete message: $e'; 31 | } 32 | } 33 | 34 | Future flush() async { 35 | try { 36 | await dio.post('$baseUrl/chat/$chatId/message-flush'); 37 | } catch (e) { 38 | throw 'Failed to flush messages: $e'; 39 | } 40 | } 41 | 42 | Future seen(MessageID messageId) async { 43 | try { 44 | await dio.post('$baseUrl/chat/$chatId/seen', data: {'msgId': messageId}); 45 | } catch (e) { 46 | throw 'Failed to mark message as seen: $e'; 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /examples/flyer_chat/lib/api/connection_status.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:flutter/material.dart'; 4 | 5 | import 'websocket_service.dart'; 6 | 7 | class ConnectionStatus extends StatefulWidget { 8 | final ChatWebSocketService webSocketService; 9 | 10 | const ConnectionStatus({super.key, required this.webSocketService}); 11 | 12 | @override 13 | State createState() => _ConnectionStatusState(); 14 | } 15 | 16 | class _ConnectionStatusState extends State { 17 | late final StreamSubscription _wsStatusSubscription; 18 | WebSocketStatus _wsStatus = WebSocketStatus.disconnected; 19 | 20 | @override 21 | void initState() { 22 | super.initState(); 23 | _wsStatusSubscription = widget.webSocketService.status.listen((status) { 24 | setState(() { 25 | _wsStatus = status; 26 | }); 27 | }); 28 | } 29 | 30 | @override 31 | void dispose() { 32 | _wsStatusSubscription.cancel(); 33 | super.dispose(); 34 | } 35 | 36 | Color _getStatusColor() { 37 | switch (_wsStatus) { 38 | case WebSocketStatus.disconnected: 39 | return Colors.red; 40 | case WebSocketStatus.connecting: 41 | case WebSocketStatus.reconnecting: 42 | return Colors.orange; 43 | case WebSocketStatus.connected: 44 | return Colors.green; 45 | } 46 | } 47 | 48 | @override 49 | Widget build(BuildContext context) { 50 | return Container( 51 | width: 12, 52 | height: 12, 53 | decoration: BoxDecoration( 54 | shape: BoxShape.circle, 55 | color: _getStatusColor(), 56 | ), 57 | ); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /examples/flyer_chat/lib/api_get_chat_id.dart: -------------------------------------------------------------------------------- 1 | import 'package:dio/dio.dart'; 2 | 3 | Future getChatId(Dio dio) async { 4 | try { 5 | final response = await dio.post>( 6 | 'https://whatever.diamanthq.dev/chat', 7 | ); 8 | 9 | final data = response.data?['chat_id'] as String? ?? ''; 10 | 11 | return data; 12 | } catch (e) { 13 | rethrow; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /examples/flyer_chat/lib/api_get_initial_messages.dart: -------------------------------------------------------------------------------- 1 | import 'package:dio/dio.dart'; 2 | import 'package:flutter_chat_core/flutter_chat_core.dart'; 3 | 4 | Future> getInitialMessages( 5 | Dio dio, { 6 | required String chatId, 7 | }) async { 8 | try { 9 | final response = await dio.get>( 10 | 'https://whatever.diamanthq.dev/chat/$chatId/message', 11 | ); 12 | 13 | final data = response.data?['data'] as List? ?? []; 14 | final mappedData = data.map((e) => Message.fromJson(e)); 15 | 16 | return mappedData.toList(); 17 | } catch (e) { 18 | rethrow; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /examples/flyer_chat/lib/basic.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_chat_core/flutter_chat_core.dart'; 5 | import 'package:flutter_chat_ui/flutter_chat_ui.dart'; 6 | 7 | class Basic extends StatefulWidget { 8 | const Basic({super.key}); 9 | 10 | @override 11 | BasicState createState() => BasicState(); 12 | } 13 | 14 | class BasicState extends State { 15 | final _chatController = InMemoryChatController(); 16 | 17 | @override 18 | void dispose() { 19 | _chatController.dispose(); 20 | super.dispose(); 21 | } 22 | 23 | @override 24 | Widget build(BuildContext context) { 25 | return Scaffold( 26 | body: Chat( 27 | chatController: _chatController, 28 | currentUserId: 'user1', 29 | onMessageSend: (text) { 30 | _chatController.insertMessage( 31 | TextMessage( 32 | // Better to use UUID or similar for the ID - IDs must be unique 33 | id: '${Random().nextInt(1000) + 1}', 34 | authorId: 'user1', 35 | createdAt: DateTime.now().toUtc(), 36 | text: text, 37 | ), 38 | ); 39 | }, 40 | resolveUser: (UserID id) async { 41 | return User(id: id, name: 'John Doe'); 42 | }, 43 | ), 44 | ); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /examples/flyer_chat/lib/create_message.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | import 'package:dio/dio.dart'; 4 | import 'package:flutter_chat_core/flutter_chat_core.dart'; 5 | import 'package:flutter_lorem/flutter_lorem.dart'; 6 | import 'package:uuid/uuid.dart'; 7 | 8 | Future createMessage( 9 | UserID authorId, 10 | Dio dio, { 11 | bool? textOnly, 12 | bool? localOnly, 13 | String? text, 14 | }) async { 15 | const uuid = Uuid(); 16 | Message message; 17 | 18 | if (Random().nextBool() || textOnly == true || text != null) { 19 | message = TextMessage( 20 | id: uuid.v4(), 21 | authorId: authorId, 22 | createdAt: DateTime.now().toUtc(), 23 | sentAt: localOnly == true ? DateTime.now().toUtc() : null, 24 | text: text ?? lorem(paragraphs: 1, words: Random().nextInt(30) + 1), 25 | metadata: isOnlyEmoji(text ?? '') ? {'isOnlyEmoji': true} : null, 26 | ); 27 | } else { 28 | final orientation = ['portrait', 'square', 'wide'][Random().nextInt(3)]; 29 | late double width, height; 30 | 31 | if (orientation == 'portrait') { 32 | width = 200; 33 | height = 400; 34 | } else if (orientation == 'square') { 35 | width = 200; 36 | height = 200; 37 | } else { 38 | width = 400; 39 | height = 200; 40 | } 41 | 42 | final response = await dio.get( 43 | 'https://whatever.diamanthq.dev/image?w=${width.toInt()}&h=${height.toInt()}&seed=${Random().nextInt(501)}', 44 | options: Options( 45 | headers: { 46 | 'Access-Control-Allow-Origin': '*', 47 | 'Content-Type': 'application/json', 48 | 'Accept': '*/*', 49 | }, 50 | ), 51 | ); 52 | 53 | message = ImageMessage( 54 | id: uuid.v4(), 55 | authorId: authorId, 56 | createdAt: DateTime.now().toUtc(), 57 | sentAt: localOnly == true ? DateTime.now().toUtc() : null, 58 | source: response.data['img'], 59 | thumbhash: response.data['thumbhash'], 60 | blurhash: response.data['blurhash'], 61 | ); 62 | } 63 | 64 | // return ImageMessage( 65 | // id: uuid.v4(), 66 | // author: author, 67 | // createdAt: DateTime.now().toUtc(), 68 | // sentAt: localOnly == true ? DateTime.now().toUtc() : null, 69 | // source: 70 | // 'https://www.hdcarwallpapers.com/walls/audi_r8_spyder_v10_performance_rwd_2021_4k_8k-HD.jpg', 71 | // thumbhash: '2gcODIKwdmg9eId1l4qTb2v4xw', 72 | // blurhash: 'LPFFjU00^+IV~W4n%LRkROM|WBxu', 73 | // ); 74 | 75 | return message; 76 | } 77 | -------------------------------------------------------------------------------- /examples/flyer_chat/lib/widgets/composer_action_bar.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class ComposerActionButton { 4 | final IconData icon; 5 | final String title; 6 | final VoidCallback onPressed; 7 | final bool destructive; 8 | 9 | const ComposerActionButton({ 10 | required this.icon, 11 | required this.title, 12 | required this.onPressed, 13 | this.destructive = false, 14 | }); 15 | } 16 | 17 | class ComposerActionBar extends StatelessWidget { 18 | final List buttons; 19 | 20 | const ComposerActionBar({super.key, required this.buttons}); 21 | 22 | @override 23 | Widget build(BuildContext context) { 24 | return SizedBox( 25 | width: double.infinity, 26 | child: SingleChildScrollView( 27 | physics: const BouncingScrollPhysics( 28 | parent: AlwaysScrollableScrollPhysics(), 29 | ), 30 | scrollDirection: Axis.horizontal, 31 | padding: const EdgeInsets.fromLTRB(16, 8, 16, 0), 32 | child: Row( 33 | mainAxisAlignment: MainAxisAlignment.start, 34 | crossAxisAlignment: CrossAxisAlignment.center, 35 | children: [ 36 | for (var i = 0; i < buttons.length; i++) ...[ 37 | if (i > 0) const SizedBox(width: 8), 38 | OutlinedButton.icon( 39 | icon: Icon( 40 | buttons[i].icon, 41 | color: buttons[i].destructive ? Colors.red : null, 42 | ), 43 | label: Text( 44 | buttons[i].title, 45 | style: TextStyle( 46 | color: buttons[i].destructive ? Colors.red : null, 47 | ), 48 | ), 49 | style: OutlinedButton.styleFrom( 50 | foregroundColor: buttons[i].destructive ? Colors.red : null, 51 | shape: RoundedRectangleBorder( 52 | borderRadius: BorderRadius.circular(20), 53 | ), 54 | padding: const EdgeInsets.symmetric( 55 | horizontal: 16, 56 | vertical: 8, 57 | ), 58 | ), 59 | onPressed: buttons[i].onPressed, 60 | ), 61 | ], 62 | ], 63 | ), 64 | ), 65 | ); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /examples/flyer_chat/linux/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ephemeral 2 | -------------------------------------------------------------------------------- /examples/flyer_chat/linux/flutter/generated_plugin_registrant.cc: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #include "generated_plugin_registrant.h" 8 | 9 | #include 10 | #include 11 | 12 | void fl_register_plugins(FlPluginRegistry* registry) { 13 | g_autoptr(FlPluginRegistrar) file_selector_linux_registrar = 14 | fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin"); 15 | file_selector_plugin_register_with_registrar(file_selector_linux_registrar); 16 | g_autoptr(FlPluginRegistrar) isar_flutter_libs_registrar = 17 | fl_plugin_registry_get_registrar_for_plugin(registry, "IsarFlutterLibsPlugin"); 18 | isar_flutter_libs_plugin_register_with_registrar(isar_flutter_libs_registrar); 19 | } 20 | -------------------------------------------------------------------------------- /examples/flyer_chat/linux/flutter/generated_plugin_registrant.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #ifndef GENERATED_PLUGIN_REGISTRANT_ 8 | #define GENERATED_PLUGIN_REGISTRANT_ 9 | 10 | #include 11 | 12 | // Registers Flutter plugins. 13 | void fl_register_plugins(FlPluginRegistry* registry); 14 | 15 | #endif // GENERATED_PLUGIN_REGISTRANT_ 16 | -------------------------------------------------------------------------------- /examples/flyer_chat/linux/flutter/generated_plugins.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Generated file, do not edit. 3 | # 4 | 5 | list(APPEND FLUTTER_PLUGIN_LIST 6 | file_selector_linux 7 | isar_flutter_libs 8 | ) 9 | 10 | list(APPEND FLUTTER_FFI_PLUGIN_LIST 11 | ) 12 | 13 | set(PLUGIN_BUNDLED_LIBRARIES) 14 | 15 | foreach(plugin ${FLUTTER_PLUGIN_LIST}) 16 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) 17 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) 18 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $) 19 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) 20 | endforeach(plugin) 21 | 22 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) 23 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) 24 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) 25 | endforeach(ffi_plugin) 26 | -------------------------------------------------------------------------------- /examples/flyer_chat/linux/runner/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | project(runner LANGUAGES CXX) 3 | 4 | # Define the application target. To change its name, change BINARY_NAME in the 5 | # top-level CMakeLists.txt, not the value here, or `flutter run` will no longer 6 | # work. 7 | # 8 | # Any new source files that you add to the application should be added here. 9 | add_executable(${BINARY_NAME} 10 | "main.cc" 11 | "my_application.cc" 12 | "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" 13 | ) 14 | 15 | # Apply the standard set of build settings. This can be removed for applications 16 | # that need different build settings. 17 | apply_standard_settings(${BINARY_NAME}) 18 | 19 | # Add preprocessor definitions for the application ID. 20 | add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") 21 | 22 | # Add dependency libraries. Add any application-specific dependencies here. 23 | target_link_libraries(${BINARY_NAME} PRIVATE flutter) 24 | target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) 25 | 26 | target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") 27 | -------------------------------------------------------------------------------- /examples/flyer_chat/linux/runner/main.cc: -------------------------------------------------------------------------------- 1 | #include "my_application.h" 2 | 3 | int main(int argc, char** argv) { 4 | g_autoptr(MyApplication) app = my_application_new(); 5 | return g_application_run(G_APPLICATION(app), argc, argv); 6 | } 7 | -------------------------------------------------------------------------------- /examples/flyer_chat/linux/runner/my_application.h: -------------------------------------------------------------------------------- 1 | #ifndef FLUTTER_MY_APPLICATION_H_ 2 | #define FLUTTER_MY_APPLICATION_H_ 3 | 4 | #include 5 | 6 | G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, 7 | GtkApplication) 8 | 9 | /** 10 | * my_application_new: 11 | * 12 | * Creates a new Flutter-based application. 13 | * 14 | * Returns: a new #MyApplication. 15 | */ 16 | MyApplication* my_application_new(); 17 | 18 | #endif // FLUTTER_MY_APPLICATION_H_ 19 | -------------------------------------------------------------------------------- /examples/flyer_chat/macos/.gitignore: -------------------------------------------------------------------------------- 1 | # Flutter-related 2 | **/Flutter/ephemeral/ 3 | **/Pods/ 4 | 5 | # Xcode-related 6 | **/dgph 7 | **/xcuserdata/ 8 | -------------------------------------------------------------------------------- /examples/flyer_chat/macos/Flutter/Flutter-Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /examples/flyer_chat/macos/Flutter/Flutter-Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /examples/flyer_chat/macos/Flutter/GeneratedPluginRegistrant.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | import FlutterMacOS 6 | import Foundation 7 | 8 | import file_picker 9 | import file_selector_macos 10 | import isar_flutter_libs 11 | import path_provider_foundation 12 | 13 | func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { 14 | FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin")) 15 | FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) 16 | IsarFlutterLibsPlugin.register(with: registry.registrar(forPlugin: "IsarFlutterLibsPlugin")) 17 | PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) 18 | } 19 | -------------------------------------------------------------------------------- /examples/flyer_chat/macos/Podfile: -------------------------------------------------------------------------------- 1 | platform :osx, '10.14' 2 | 3 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 4 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 5 | 6 | project 'Runner', { 7 | 'Debug' => :debug, 8 | 'Profile' => :release, 9 | 'Release' => :release, 10 | } 11 | 12 | def flutter_root 13 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) 14 | unless File.exist?(generated_xcode_build_settings_path) 15 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" 16 | end 17 | 18 | File.foreach(generated_xcode_build_settings_path) do |line| 19 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 20 | return matches[1].strip if matches 21 | end 22 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" 23 | end 24 | 25 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 26 | 27 | flutter_macos_podfile_setup 28 | 29 | target 'Runner' do 30 | use_frameworks! 31 | 32 | flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) 33 | target 'RunnerTests' do 34 | inherit! :search_paths 35 | end 36 | end 37 | 38 | post_install do |installer| 39 | installer.pods_project.targets.each do |target| 40 | flutter_additional_macos_build_settings(target) 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /examples/flyer_chat/macos/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - file_picker (0.0.1): 3 | - FlutterMacOS 4 | - file_selector_macos (0.0.1): 5 | - FlutterMacOS 6 | - FlutterMacOS (1.0.0) 7 | - isar_flutter_libs (1.0.0): 8 | - FlutterMacOS 9 | - path_provider_foundation (0.0.1): 10 | - Flutter 11 | - FlutterMacOS 12 | 13 | DEPENDENCIES: 14 | - file_picker (from `Flutter/ephemeral/.symlinks/plugins/file_picker/macos`) 15 | - file_selector_macos (from `Flutter/ephemeral/.symlinks/plugins/file_selector_macos/macos`) 16 | - FlutterMacOS (from `Flutter/ephemeral`) 17 | - isar_flutter_libs (from `Flutter/ephemeral/.symlinks/plugins/isar_flutter_libs/macos`) 18 | - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`) 19 | 20 | EXTERNAL SOURCES: 21 | file_picker: 22 | :path: Flutter/ephemeral/.symlinks/plugins/file_picker/macos 23 | file_selector_macos: 24 | :path: Flutter/ephemeral/.symlinks/plugins/file_selector_macos/macos 25 | FlutterMacOS: 26 | :path: Flutter/ephemeral 27 | isar_flutter_libs: 28 | :path: Flutter/ephemeral/.symlinks/plugins/isar_flutter_libs/macos 29 | path_provider_foundation: 30 | :path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin 31 | 32 | SPEC CHECKSUMS: 33 | file_picker: 7584aae6fa07a041af2b36a2655122d42f578c1a 34 | file_selector_macos: 6280b52b459ae6c590af5d78fc35c7267a3c4b31 35 | FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 36 | isar_flutter_libs: a65381780401f81ad6bf3f2e7cd0de5698fb98c4 37 | path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564 38 | 39 | PODFILE CHECKSUM: 7eb978b976557c8c1cd717d8185ec483fd090a82 40 | 41 | COCOAPODS: 1.16.2 42 | -------------------------------------------------------------------------------- /examples/flyer_chat/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /examples/flyer_chat/macos/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /examples/flyer_chat/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /examples/flyer_chat/macos/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | @main 5 | class AppDelegate: FlutterAppDelegate { 6 | override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { 7 | return true 8 | } 9 | 10 | override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { 11 | return true 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /examples/flyer_chat/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "app_icon_16.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "app_icon_32.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "app_icon_32.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "app_icon_64.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "app_icon_128.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "app_icon_256.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "app_icon_256.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "app_icon_512.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "app_icon_512.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "512x512", 59 | "idiom" : "mac", 60 | "filename" : "app_icon_1024.png", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /examples/flyer_chat/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flyerhq/flutter_chat_ui/4fe6b2049f242a507a26ce09a016fe5d6929f750/examples/flyer_chat/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png -------------------------------------------------------------------------------- /examples/flyer_chat/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flyerhq/flutter_chat_ui/4fe6b2049f242a507a26ce09a016fe5d6929f750/examples/flyer_chat/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png -------------------------------------------------------------------------------- /examples/flyer_chat/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flyerhq/flutter_chat_ui/4fe6b2049f242a507a26ce09a016fe5d6929f750/examples/flyer_chat/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png -------------------------------------------------------------------------------- /examples/flyer_chat/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flyerhq/flutter_chat_ui/4fe6b2049f242a507a26ce09a016fe5d6929f750/examples/flyer_chat/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png -------------------------------------------------------------------------------- /examples/flyer_chat/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flyerhq/flutter_chat_ui/4fe6b2049f242a507a26ce09a016fe5d6929f750/examples/flyer_chat/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png -------------------------------------------------------------------------------- /examples/flyer_chat/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flyerhq/flutter_chat_ui/4fe6b2049f242a507a26ce09a016fe5d6929f750/examples/flyer_chat/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png -------------------------------------------------------------------------------- /examples/flyer_chat/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flyerhq/flutter_chat_ui/4fe6b2049f242a507a26ce09a016fe5d6929f750/examples/flyer_chat/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png -------------------------------------------------------------------------------- /examples/flyer_chat/macos/Runner/Configs/AppInfo.xcconfig: -------------------------------------------------------------------------------- 1 | // Application-level settings for the Runner target. 2 | // 3 | // This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the 4 | // future. If not, the values below would default to using the project name when this becomes a 5 | // 'flutter create' template. 6 | 7 | // The application's name. By default this is also the title of the Flutter window. 8 | PRODUCT_NAME = flyer_chat 9 | 10 | // The application's bundle identifier 11 | PRODUCT_BUNDLE_IDENTIFIER = flyer.chat.flyerChat 12 | 13 | // The copyright displayed in application information 14 | PRODUCT_COPYRIGHT = Copyright © 2025 flyer.chat. All rights reserved. 15 | -------------------------------------------------------------------------------- /examples/flyer_chat/macos/Runner/Configs/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Debug.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /examples/flyer_chat/macos/Runner/Configs/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Release.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /examples/flyer_chat/macos/Runner/Configs/Warnings.xcconfig: -------------------------------------------------------------------------------- 1 | WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings 2 | GCC_WARN_UNDECLARED_SELECTOR = YES 3 | CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES 4 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE 5 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES 6 | CLANG_WARN_PRAGMA_PACK = YES 7 | CLANG_WARN_STRICT_PROTOTYPES = YES 8 | CLANG_WARN_COMMA = YES 9 | GCC_WARN_STRICT_SELECTOR_MATCH = YES 10 | CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES 11 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES 12 | GCC_WARN_SHADOW = YES 13 | CLANG_WARN_UNREACHABLE_CODE = YES 14 | -------------------------------------------------------------------------------- /examples/flyer_chat/macos/Runner/DebugProfile.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.cs.allow-jit 8 | 9 | com.apple.security.network.client 10 | 11 | com.apple.security.network.server 12 | 13 | com.apple.security.files.user-selected.read-only 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /examples/flyer_chat/macos/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSMinimumSystemVersion 24 | $(MACOSX_DEPLOYMENT_TARGET) 25 | NSHumanReadableCopyright 26 | $(PRODUCT_COPYRIGHT) 27 | NSMainNibFile 28 | MainMenu 29 | NSPrincipalClass 30 | NSApplication 31 | 32 | 33 | -------------------------------------------------------------------------------- /examples/flyer_chat/macos/Runner/MainFlutterWindow.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | class MainFlutterWindow: NSWindow { 5 | override func awakeFromNib() { 6 | let flutterViewController = FlutterViewController() 7 | let windowFrame = self.frame 8 | self.contentViewController = flutterViewController 9 | self.setFrame(windowFrame, display: true) 10 | 11 | RegisterGeneratedPlugins(registry: flutterViewController) 12 | 13 | super.awakeFromNib() 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /examples/flyer_chat/macos/Runner/Release.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /examples/flyer_chat/macos/RunnerTests/RunnerTests.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | import XCTest 4 | 5 | class RunnerTests: XCTestCase { 6 | 7 | func testExample() { 8 | // If you add code to the Runner application, consider adding tests here. 9 | // See https://developer.apple.com/documentation/xctest for more information about using XCTest. 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /examples/flyer_chat/web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flyerhq/flutter_chat_ui/4fe6b2049f242a507a26ce09a016fe5d6929f750/examples/flyer_chat/web/favicon.png -------------------------------------------------------------------------------- /examples/flyer_chat/web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flyerhq/flutter_chat_ui/4fe6b2049f242a507a26ce09a016fe5d6929f750/examples/flyer_chat/web/icons/Icon-192.png -------------------------------------------------------------------------------- /examples/flyer_chat/web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flyerhq/flutter_chat_ui/4fe6b2049f242a507a26ce09a016fe5d6929f750/examples/flyer_chat/web/icons/Icon-512.png -------------------------------------------------------------------------------- /examples/flyer_chat/web/icons/Icon-maskable-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flyerhq/flutter_chat_ui/4fe6b2049f242a507a26ce09a016fe5d6929f750/examples/flyer_chat/web/icons/Icon-maskable-192.png -------------------------------------------------------------------------------- /examples/flyer_chat/web/icons/Icon-maskable-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flyerhq/flutter_chat_ui/4fe6b2049f242a507a26ce09a016fe5d6929f750/examples/flyer_chat/web/icons/Icon-maskable-512.png -------------------------------------------------------------------------------- /examples/flyer_chat/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | flyer_chat 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /examples/flyer_chat/web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "flyer_chat", 3 | "short_name": "flyer_chat", 4 | "start_url": ".", 5 | "display": "standalone", 6 | "background_color": "#0175C2", 7 | "theme_color": "#0175C2", 8 | "description": "A new Flutter project.", 9 | "orientation": "portrait-primary", 10 | "prefer_related_applications": false, 11 | "icons": [ 12 | { 13 | "src": "icons/Icon-192.png", 14 | "sizes": "192x192", 15 | "type": "image/png" 16 | }, 17 | { 18 | "src": "icons/Icon-512.png", 19 | "sizes": "512x512", 20 | "type": "image/png" 21 | }, 22 | { 23 | "src": "icons/Icon-maskable-192.png", 24 | "sizes": "192x192", 25 | "type": "image/png", 26 | "purpose": "maskable" 27 | }, 28 | { 29 | "src": "icons/Icon-maskable-512.png", 30 | "sizes": "512x512", 31 | "type": "image/png", 32 | "purpose": "maskable" 33 | } 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /examples/flyer_chat/windows/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ephemeral/ 2 | 3 | # Visual Studio user-specific files. 4 | *.suo 5 | *.user 6 | *.userosscache 7 | *.sln.docstates 8 | 9 | # Visual Studio build-related files. 10 | x64/ 11 | x86/ 12 | 13 | # Visual Studio cache files 14 | # files ending in .cache can be ignored 15 | *.[Cc]ache 16 | # but keep track of directories ending in .cache 17 | !*.[Cc]ache/ 18 | -------------------------------------------------------------------------------- /examples/flyer_chat/windows/flutter/generated_plugin_registrant.cc: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #include "generated_plugin_registrant.h" 8 | 9 | #include 10 | #include 11 | 12 | void RegisterPlugins(flutter::PluginRegistry* registry) { 13 | FileSelectorWindowsRegisterWithRegistrar( 14 | registry->GetRegistrarForPlugin("FileSelectorWindows")); 15 | IsarFlutterLibsPluginRegisterWithRegistrar( 16 | registry->GetRegistrarForPlugin("IsarFlutterLibsPlugin")); 17 | } 18 | -------------------------------------------------------------------------------- /examples/flyer_chat/windows/flutter/generated_plugin_registrant.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #ifndef GENERATED_PLUGIN_REGISTRANT_ 8 | #define GENERATED_PLUGIN_REGISTRANT_ 9 | 10 | #include 11 | 12 | // Registers Flutter plugins. 13 | void RegisterPlugins(flutter::PluginRegistry* registry); 14 | 15 | #endif // GENERATED_PLUGIN_REGISTRANT_ 16 | -------------------------------------------------------------------------------- /examples/flyer_chat/windows/flutter/generated_plugins.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Generated file, do not edit. 3 | # 4 | 5 | list(APPEND FLUTTER_PLUGIN_LIST 6 | file_selector_windows 7 | isar_flutter_libs 8 | ) 9 | 10 | list(APPEND FLUTTER_FFI_PLUGIN_LIST 11 | ) 12 | 13 | set(PLUGIN_BUNDLED_LIBRARIES) 14 | 15 | foreach(plugin ${FLUTTER_PLUGIN_LIST}) 16 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) 17 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) 18 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $) 19 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) 20 | endforeach(plugin) 21 | 22 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) 23 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) 24 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) 25 | endforeach(ffi_plugin) 26 | -------------------------------------------------------------------------------- /examples/flyer_chat/windows/runner/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | project(runner LANGUAGES CXX) 3 | 4 | # Define the application target. To change its name, change BINARY_NAME in the 5 | # top-level CMakeLists.txt, not the value here, or `flutter run` will no longer 6 | # work. 7 | # 8 | # Any new source files that you add to the application should be added here. 9 | add_executable(${BINARY_NAME} WIN32 10 | "flutter_window.cpp" 11 | "main.cpp" 12 | "utils.cpp" 13 | "win32_window.cpp" 14 | "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" 15 | "Runner.rc" 16 | "runner.exe.manifest" 17 | ) 18 | 19 | # Apply the standard set of build settings. This can be removed for applications 20 | # that need different build settings. 21 | apply_standard_settings(${BINARY_NAME}) 22 | 23 | # Add preprocessor definitions for the build version. 24 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") 25 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") 26 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") 27 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") 28 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") 29 | 30 | # Disable Windows macros that collide with C++ standard library functions. 31 | target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") 32 | 33 | # Add dependency libraries and include directories. Add any application-specific 34 | # dependencies here. 35 | target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) 36 | target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") 37 | target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") 38 | 39 | # Run the Flutter tool portions of the build. This must not be removed. 40 | add_dependencies(${BINARY_NAME} flutter_assemble) 41 | -------------------------------------------------------------------------------- /examples/flyer_chat/windows/runner/flutter_window.cpp: -------------------------------------------------------------------------------- 1 | #include "flutter_window.h" 2 | 3 | #include 4 | 5 | #include "flutter/generated_plugin_registrant.h" 6 | 7 | FlutterWindow::FlutterWindow(const flutter::DartProject& project) 8 | : project_(project) {} 9 | 10 | FlutterWindow::~FlutterWindow() {} 11 | 12 | bool FlutterWindow::OnCreate() { 13 | if (!Win32Window::OnCreate()) { 14 | return false; 15 | } 16 | 17 | RECT frame = GetClientArea(); 18 | 19 | // The size here must match the window dimensions to avoid unnecessary surface 20 | // creation / destruction in the startup path. 21 | flutter_controller_ = std::make_unique( 22 | frame.right - frame.left, frame.bottom - frame.top, project_); 23 | // Ensure that basic setup of the controller was successful. 24 | if (!flutter_controller_->engine() || !flutter_controller_->view()) { 25 | return false; 26 | } 27 | RegisterPlugins(flutter_controller_->engine()); 28 | SetChildContent(flutter_controller_->view()->GetNativeWindow()); 29 | 30 | flutter_controller_->engine()->SetNextFrameCallback([&]() { 31 | this->Show(); 32 | }); 33 | 34 | // Flutter can complete the first frame before the "show window" callback is 35 | // registered. The following call ensures a frame is pending to ensure the 36 | // window is shown. It is a no-op if the first frame hasn't completed yet. 37 | flutter_controller_->ForceRedraw(); 38 | 39 | return true; 40 | } 41 | 42 | void FlutterWindow::OnDestroy() { 43 | if (flutter_controller_) { 44 | flutter_controller_ = nullptr; 45 | } 46 | 47 | Win32Window::OnDestroy(); 48 | } 49 | 50 | LRESULT 51 | FlutterWindow::MessageHandler(HWND hwnd, UINT const message, 52 | WPARAM const wparam, 53 | LPARAM const lparam) noexcept { 54 | // Give Flutter, including plugins, an opportunity to handle window messages. 55 | if (flutter_controller_) { 56 | std::optional result = 57 | flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, 58 | lparam); 59 | if (result) { 60 | return *result; 61 | } 62 | } 63 | 64 | switch (message) { 65 | case WM_FONTCHANGE: 66 | flutter_controller_->engine()->ReloadSystemFonts(); 67 | break; 68 | } 69 | 70 | return Win32Window::MessageHandler(hwnd, message, wparam, lparam); 71 | } 72 | -------------------------------------------------------------------------------- /examples/flyer_chat/windows/runner/flutter_window.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_FLUTTER_WINDOW_H_ 2 | #define RUNNER_FLUTTER_WINDOW_H_ 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include "win32_window.h" 10 | 11 | // A window that does nothing but host a Flutter view. 12 | class FlutterWindow : public Win32Window { 13 | public: 14 | // Creates a new FlutterWindow hosting a Flutter view running |project|. 15 | explicit FlutterWindow(const flutter::DartProject& project); 16 | virtual ~FlutterWindow(); 17 | 18 | protected: 19 | // Win32Window: 20 | bool OnCreate() override; 21 | void OnDestroy() override; 22 | LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, 23 | LPARAM const lparam) noexcept override; 24 | 25 | private: 26 | // The project to run. 27 | flutter::DartProject project_; 28 | 29 | // The Flutter instance hosted by this window. 30 | std::unique_ptr flutter_controller_; 31 | }; 32 | 33 | #endif // RUNNER_FLUTTER_WINDOW_H_ 34 | -------------------------------------------------------------------------------- /examples/flyer_chat/windows/runner/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "flutter_window.h" 6 | #include "utils.h" 7 | 8 | int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, 9 | _In_ wchar_t *command_line, _In_ int show_command) { 10 | // Attach to console when present (e.g., 'flutter run') or create a 11 | // new console when running with a debugger. 12 | if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { 13 | CreateAndAttachConsole(); 14 | } 15 | 16 | // Initialize COM, so that it is available for use in the library and/or 17 | // plugins. 18 | ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); 19 | 20 | flutter::DartProject project(L"data"); 21 | 22 | std::vector command_line_arguments = 23 | GetCommandLineArguments(); 24 | 25 | project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); 26 | 27 | FlutterWindow window(project); 28 | Win32Window::Point origin(10, 10); 29 | Win32Window::Size size(1280, 720); 30 | if (!window.Create(L"flyer_chat", origin, size)) { 31 | return EXIT_FAILURE; 32 | } 33 | window.SetQuitOnClose(true); 34 | 35 | ::MSG msg; 36 | while (::GetMessage(&msg, nullptr, 0, 0)) { 37 | ::TranslateMessage(&msg); 38 | ::DispatchMessage(&msg); 39 | } 40 | 41 | ::CoUninitialize(); 42 | return EXIT_SUCCESS; 43 | } 44 | -------------------------------------------------------------------------------- /examples/flyer_chat/windows/runner/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by Runner.rc 4 | // 5 | #define IDI_APP_ICON 101 6 | 7 | // Next default values for new objects 8 | // 9 | #ifdef APSTUDIO_INVOKED 10 | #ifndef APSTUDIO_READONLY_SYMBOLS 11 | #define _APS_NEXT_RESOURCE_VALUE 102 12 | #define _APS_NEXT_COMMAND_VALUE 40001 13 | #define _APS_NEXT_CONTROL_VALUE 1001 14 | #define _APS_NEXT_SYMED_VALUE 101 15 | #endif 16 | #endif 17 | -------------------------------------------------------------------------------- /examples/flyer_chat/windows/runner/resources/app_icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flyerhq/flutter_chat_ui/4fe6b2049f242a507a26ce09a016fe5d6929f750/examples/flyer_chat/windows/runner/resources/app_icon.ico -------------------------------------------------------------------------------- /examples/flyer_chat/windows/runner/runner.exe.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PerMonitorV2 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /examples/flyer_chat/windows/runner/utils.cpp: -------------------------------------------------------------------------------- 1 | #include "utils.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | void CreateAndAttachConsole() { 11 | if (::AllocConsole()) { 12 | FILE *unused; 13 | if (freopen_s(&unused, "CONOUT$", "w", stdout)) { 14 | _dup2(_fileno(stdout), 1); 15 | } 16 | if (freopen_s(&unused, "CONOUT$", "w", stderr)) { 17 | _dup2(_fileno(stdout), 2); 18 | } 19 | std::ios::sync_with_stdio(); 20 | FlutterDesktopResyncOutputStreams(); 21 | } 22 | } 23 | 24 | std::vector GetCommandLineArguments() { 25 | // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. 26 | int argc; 27 | wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); 28 | if (argv == nullptr) { 29 | return std::vector(); 30 | } 31 | 32 | std::vector command_line_arguments; 33 | 34 | // Skip the first argument as it's the binary name. 35 | for (int i = 1; i < argc; i++) { 36 | command_line_arguments.push_back(Utf8FromUtf16(argv[i])); 37 | } 38 | 39 | ::LocalFree(argv); 40 | 41 | return command_line_arguments; 42 | } 43 | 44 | std::string Utf8FromUtf16(const wchar_t* utf16_string) { 45 | if (utf16_string == nullptr) { 46 | return std::string(); 47 | } 48 | unsigned int target_length = ::WideCharToMultiByte( 49 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, 50 | -1, nullptr, 0, nullptr, nullptr) 51 | -1; // remove the trailing null character 52 | int input_length = (int)wcslen(utf16_string); 53 | std::string utf8_string; 54 | if (target_length == 0 || target_length > utf8_string.max_size()) { 55 | return utf8_string; 56 | } 57 | utf8_string.resize(target_length); 58 | int converted_length = ::WideCharToMultiByte( 59 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, 60 | input_length, utf8_string.data(), target_length, nullptr, nullptr); 61 | if (converted_length == 0) { 62 | return std::string(); 63 | } 64 | return utf8_string; 65 | } 66 | -------------------------------------------------------------------------------- /examples/flyer_chat/windows/runner/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_UTILS_H_ 2 | #define RUNNER_UTILS_H_ 3 | 4 | #include 5 | #include 6 | 7 | // Creates a console for the process, and redirects stdout and stderr to 8 | // it for both the runner and the Flutter library. 9 | void CreateAndAttachConsole(); 10 | 11 | // Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string 12 | // encoded in UTF-8. Returns an empty std::string on failure. 13 | std::string Utf8FromUtf16(const wchar_t* utf16_string); 14 | 15 | // Gets the command line arguments passed in as a std::vector, 16 | // encoded in UTF-8. Returns an empty std::vector on failure. 17 | std::vector GetCommandLineArguments(); 18 | 19 | #endif // RUNNER_UTILS_H_ 20 | -------------------------------------------------------------------------------- /melos.yaml: -------------------------------------------------------------------------------- 1 | name: flyer_chat_workspace 2 | repository: https://github.com/flyerhq/flutter_chat_ui 3 | 4 | packages: 5 | - examples/* 6 | - packages/* 7 | 8 | scripts: 9 | test:selective: 10 | run: melos exec --fail-fast -- flutter test --no-pub --coverage 11 | description: run flutter test for a specific package 12 | packageFilters: 13 | dirExists: test 14 | test: 15 | run: melos run test:selective --no-select 16 | description: run flutter test in all packages 17 | coverage:selective: 18 | exec: genhtml coverage/lcov.info -o coverage/html 19 | description: generate coverage for a specific package 20 | packageFilters: 21 | dirExists: test 22 | coverage: 23 | run: melos run test && melos run coverage:selective --no-select 24 | description: generate coverage for all packages 25 | analyze: 26 | exec: dart analyze --fatal-infos . 27 | description: run `dart analyze` in all packages 28 | build: 29 | exec: dart run build_runner build --delete-conflicting-outputs 30 | packageFilters: 31 | dependsOn: build_runner 32 | format: 33 | run: dart format --set-exit-if-changed . 34 | description: run `dart format --set-exit-if-changed .` in all packages 35 | fix: 36 | run: dart fix --apply . 37 | description: run `dart fix --apply .` in all packages 38 | 39 | command: 40 | version: 41 | workspaceChangelog: false 42 | -------------------------------------------------------------------------------- /packages/cross_cache/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 1.0.2 2 | 3 | - **FIX**: improve documentation and add example. ([113141b3](https://github.com/flyerhq/flutter_chat_ui/commit/113141b31de52a166eea54625f4cdd5b80bb897a)) 4 | 5 | ## 1.0.1 6 | 7 | - **FIX**: document public APIs. 8 | 9 | ## 1.0.0 10 | 11 | - First stable release 12 | 13 | ## 0.0.12 14 | 15 | - Version bump to match other packages 16 | 17 | ## 0.0.11 18 | 19 | - Version bump to match other packages 20 | 21 | ## 0.0.10 22 | 23 | - Migrated web storage implementation from `indexed_db` to `idb_shim` for improved cross-platform compatibility and better performance 24 | 25 | ## 0.0.9 26 | 27 | - Version bump to match other packages 28 | 29 | ## 0.0.8 30 | 31 | - Version bump to match other packages 32 | 33 | ## 0.0.7 34 | 35 | - Require Flutter 3.29 and Dart 3.7 36 | 37 | ## 0.0.6 38 | 39 | - Version bump to match other packages 40 | 41 | ## 0.0.5 42 | 43 | - Version bump to match other packages 44 | 45 | ## 0.0.4 46 | 47 | - Version bump to match other packages 48 | 49 | ## 0.0.3 50 | 51 | - Added new methods: 52 | - `delete(String key)` – delete entries 53 | - `updateKey(String key, String newKey)` – rename keys while keeping the data 54 | - `CustomNetworkImage` is now `CachedNetworkImage` and has been moved to the cross-cache package 55 | - Exposed the `set` method for better flexibility 56 | 57 | ## 0.0.2 58 | 59 | - Bump version to support flutter_chat_ui v2 alpha release 60 | 61 | ## 0.0.1 62 | 63 | - Initial release 64 | -------------------------------------------------------------------------------- /packages/cross_cache/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Oleksandr Demchenko 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/cross_cache/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: ../../analysis_options.yaml 2 | -------------------------------------------------------------------------------- /packages/cross_cache/example/README.md: -------------------------------------------------------------------------------- 1 | ```dart 2 | import 'package:flutter/material.dart'; 3 | import 'package:cross_cache/cross_cache.dart'; 4 | 5 | class MyWidget extends StatefulWidget { 6 | @override 7 | _MyWidgetState createState() => _MyWidgetState(); 8 | } 9 | 10 | class _MyWidgetState extends State { 11 | final _cache = CrossCache(); // Create an instance 12 | 13 | @override 14 | void dispose() { 15 | _cache.dispose(); // Dispose the cache 16 | super.dispose(); 17 | } 18 | 19 | @override 20 | Widget build(BuildContext context) { 21 | return Image( 22 | image: CachedNetworkImage( 23 | 'https://example.com/image.jpg', 24 | _cache, // Pass the cache instance 25 | headers: {'Authorization': 'Bearer YOUR_TOKEN'}, // Optional headers 26 | ), 27 | loadingBuilder: (context, child, loadingProgress) { 28 | if (loadingProgress == null) return child; 29 | return Center( 30 | child: CircularProgressIndicator( 31 | value: loadingProgress.expectedTotalBytes != null 32 | ? loadingProgress.cumulativeBytesLoaded / loadingProgress.expectedTotalBytes! 33 | : null, 34 | ), 35 | ); 36 | }, 37 | errorBuilder: (context, error, stackTrace) => Icon(Icons.error), 38 | ); 39 | } 40 | } 41 | 42 | ``` -------------------------------------------------------------------------------- /packages/cross_cache/lib/cross_cache.dart: -------------------------------------------------------------------------------- 1 | /// Cross Cache package. Provides a cache for images and files. 2 | library; 3 | 4 | export 'src/cached_network_image.dart'; 5 | export 'src/cross_cache.dart'; 6 | -------------------------------------------------------------------------------- /packages/cross_cache/lib/src/cache/base_cache.dart: -------------------------------------------------------------------------------- 1 | import 'dart:typed_data'; 2 | 3 | /// Abstract base class defining the interface for a platform-specific cache. 4 | /// 5 | /// Implementations handle the actual storage mechanism (e.g., file system, IndexedDB). 6 | abstract class BaseCache { 7 | /// Stores the given [value] associated with the [key]. 8 | /// 9 | /// If the key already exists, its value is overwritten. 10 | Future set(String key, Uint8List value); 11 | 12 | /// Retrieves the value associated with the [key]. 13 | /// 14 | /// Throws an exception if the key is not found. 15 | Future get(String key); 16 | 17 | /// Checks if the cache contains an entry for the given [key]. 18 | Future contains(String key); 19 | 20 | /// Removes the entry associated with the [key] from the cache. 21 | /// 22 | /// Does nothing if the key is not found. 23 | Future delete(String key); 24 | 25 | /// Renames an existing cache entry from [key] to [newKey]. 26 | /// 27 | /// Throws an exception if the original [key] is not found. 28 | Future updateKey(String key, String newKey); 29 | 30 | /// Releases any resources held by the cache instance. 31 | /// 32 | /// For example, closes database connections. 33 | void dispose(); 34 | } 35 | -------------------------------------------------------------------------------- /packages/cross_cache/lib/src/cache/cache.dart: -------------------------------------------------------------------------------- 1 | import 'dart:typed_data'; 2 | 3 | import 'base_cache.dart'; 4 | 5 | /// Default [BaseCache] implementation for unsupported platforms. 6 | /// 7 | /// All methods throw [UnimplementedError]. 8 | class Cache extends BaseCache { 9 | @override 10 | Future set(String key, Uint8List value) { 11 | throw UnimplementedError( 12 | 'Cache is not available in your current platform.', 13 | ); 14 | } 15 | 16 | @override 17 | Future get(String key) { 18 | throw UnimplementedError( 19 | 'Cache is not available in your current platform.', 20 | ); 21 | } 22 | 23 | @override 24 | Future contains(String key) { 25 | throw UnimplementedError( 26 | 'Cache is not available in your current platform.', 27 | ); 28 | } 29 | 30 | @override 31 | Future delete(String key) { 32 | throw UnimplementedError( 33 | 'Cache is not available in your current platform.', 34 | ); 35 | } 36 | 37 | @override 38 | Future updateKey(String key, String newKey) { 39 | throw UnimplementedError( 40 | 'Cache is not available in your current platform.', 41 | ); 42 | } 43 | 44 | @override 45 | void dispose() { 46 | throw UnimplementedError( 47 | 'Cache is not available in your current platform.', 48 | ); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /packages/cross_cache/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: cross_cache 2 | version: 1.0.2 3 | description: > 4 | Cross-platform cache manager for Flutter using IndexedDB for web, file system 5 | for mobile and desktop, and Dio for network requests. #cache #indexeddb #dio 6 | homepage: https://flyer.chat 7 | repository: https://github.com/flyerhq/flutter_chat_ui 8 | 9 | environment: 10 | sdk: ">=3.7.0 <4.0.0" 11 | flutter: ">=3.29.0" 12 | 13 | dependencies: 14 | cross_file: ^0.3.4+2 15 | crypto: ^3.0.6 16 | dio: ^5.8.0+1 17 | flutter: 18 | sdk: flutter 19 | idb_shim: ^2.6.5+1 20 | path_provider: ^2.1.5 21 | 22 | dev_dependencies: 23 | flutter_lints: ^5.0.0 24 | flutter_test: 25 | sdk: flutter 26 | http_mock_adapter: ^0.6.1 27 | -------------------------------------------------------------------------------- /packages/cross_cache/test/transparent_image.dart: -------------------------------------------------------------------------------- 1 | import 'dart:typed_data'; 2 | 3 | final transparentImage = Uint8List.fromList([ 4 | 0x89, 5 | 0x50, 6 | 0x4E, 7 | 0x47, 8 | 0x0D, 9 | 0x0A, 10 | 0x1A, 11 | 0x0A, 12 | 0x00, 13 | 0x00, 14 | 0x00, 15 | 0x0D, 16 | 0x49, 17 | 0x48, 18 | 0x44, 19 | 0x52, 20 | 0x00, 21 | 0x00, 22 | 0x00, 23 | 0x01, 24 | 0x00, 25 | 0x00, 26 | 0x00, 27 | 0x01, 28 | 0x08, 29 | 0x06, 30 | 0x00, 31 | 0x00, 32 | 0x00, 33 | 0x1F, 34 | 0x15, 35 | 0xC4, 36 | 0x89, 37 | 0x00, 38 | 0x00, 39 | 0x00, 40 | 0x0A, 41 | 0x49, 42 | 0x44, 43 | 0x41, 44 | 0x54, 45 | 0x78, 46 | 0x9C, 47 | 0x63, 48 | 0x00, 49 | 0x01, 50 | 0x00, 51 | 0x00, 52 | 0x05, 53 | 0x00, 54 | 0x01, 55 | 0x0D, 56 | 0x0A, 57 | 0x2D, 58 | 0xB4, 59 | 0x00, 60 | 0x00, 61 | 0x00, 62 | 0x00, 63 | 0x49, 64 | 0x45, 65 | 0x4E, 66 | 0x44, 67 | 0xAE, 68 | 0x42, 69 | 0x60, 70 | 0x82, 71 | ]); 72 | -------------------------------------------------------------------------------- /packages/flutter_chat_core/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Oleksandr Demchenko 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/flutter_chat_core/README.md: -------------------------------------------------------------------------------- 1 | # [Flyer Chat](https://flyer.chat) 💬 Core Package 2 | 3 | [![Pub Version](https://img.shields.io/pub/v/flutter_chat_core?logo=flutter&color=orange)](https://pub.dev/packages/flutter_chat_core) [![Stars](https://img.shields.io/github/stars/flyerhq/flutter_chat_ui?style=flat&color=orange&logo=github)](https://github.com/flyerhq/flutter_chat_ui/stargazers) [![melos](https://img.shields.io/badge/maintained%20with-melos-ffffff.svg?color=orange)](https://github.com/invertase/melos) 4 | 5 | This package contains the core foundation for the [Flyer Chat](https://flyer.chat) ecosystem, including data models, controllers, theming, and utilities. 6 | 7 | ## Purpose 8 | 9 | This package provides the essential building blocks (like message models, `ChatTheme`, `ChatController` interfaces) required by [`flutter_chat_ui`](https://github.com/flyerhq/flutter_chat_ui/tree/main/packages/flutter_chat_ui) and other `flyer_chat_*` message widget packages. 10 | 11 | It is **not** intended for standalone use outside the Flyer Chat ecosystem. Its components are designed to work together with the main UI package. 12 | 13 | ## Installation 14 | 15 | To use Flutter chat UI, you need to add both `flutter_chat_ui` and the core package `flutter_chat_core` (which contains necessary data models and types) to your `pubspec.yaml`: 16 | 17 | ```yaml 18 | dependencies: 19 | flutter_chat_core: ^2.0.0 20 | flutter_chat_ui: ^2.0.0 21 | ``` 22 | 23 | Then run `flutter pub get`. 24 | 25 | ## Usage 26 | 27 | The classes and utilities within this package are used implicitly when you configure and use the `Chat` widget from `flutter_chat_ui`. You will interact with its models (like text message, image message, etc.) when managing chat data and potentially use its `ChatTheme` and `Builders` for customization. 28 | 29 | For detailed usage, customization options, different message types, controllers, and more complex scenarios, please refer to the **full documentation**: 30 | 31 | ➡️ **[flyer.chat/docs/flutter/introduction](https://flyer.chat/docs/flutter/introduction)** ⬅️ 32 | 33 | Explore the comprehensive [example application](https://github.com/flyerhq/flutter_chat_ui/tree/main/examples/flyer_chat) to see various features and customizations in action. 34 | 35 | ## License 36 | 37 | Licensed under the MIT License. See the [LICENSE](https://github.com/flyerhq/flutter_chat_ui/blob/main/packages/flutter_chat_core/LICENSE) file for details. 38 | -------------------------------------------------------------------------------- /packages/flutter_chat_core/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: ../../analysis_options.yaml 2 | -------------------------------------------------------------------------------- /packages/flutter_chat_core/build.yaml: -------------------------------------------------------------------------------- 1 | targets: 2 | $default: 3 | builders: 4 | json_serializable: 5 | options: 6 | explicit_to_json: true 7 | include_if_null: false 8 | -------------------------------------------------------------------------------- /packages/flutter_chat_core/example/README.md: -------------------------------------------------------------------------------- 1 | ```dart 2 | import 'dart:math'; 3 | 4 | import 'package:flutter/material.dart'; 5 | import 'package:flutter_chat_core/flutter_chat_core.dart'; 6 | import 'package:flutter_chat_ui/flutter_chat_ui.dart'; 7 | 8 | class Basic extends StatefulWidget { 9 | const Basic({super.key}); 10 | 11 | @override 12 | BasicState createState() => BasicState(); 13 | } 14 | 15 | class BasicState extends State { 16 | final _chatController = InMemoryChatController(); 17 | 18 | @override 19 | void dispose() { 20 | _chatController.dispose(); 21 | super.dispose(); 22 | } 23 | 24 | @override 25 | Widget build(BuildContext context) { 26 | return Scaffold( 27 | body: Chat( 28 | chatController: _chatController, 29 | currentUserId: 'user1', 30 | onMessageSend: (text) { 31 | _chatController.insertMessage( 32 | TextMessage( 33 | // Better to use UUID or similar for the ID - IDs must be unique 34 | id: '${Random().nextInt(1000) + 1}', 35 | authorId: 'user1', 36 | createdAt: DateTime.now().toUtc(), 37 | text: text, 38 | ), 39 | ); 40 | }, 41 | resolveUser: (UserID id) async { 42 | return User(id: id, name: 'John Doe'); 43 | }, 44 | ), 45 | ); 46 | } 47 | } 48 | 49 | ``` -------------------------------------------------------------------------------- /packages/flutter_chat_core/lib/flutter_chat_core.dart: -------------------------------------------------------------------------------- 1 | /// Flutter Chat Core package. Provides the core functionality for the flutter_chat_ui package. 2 | library; 3 | 4 | export 'src/chat_controller/chat_controller.dart'; 5 | export 'src/chat_controller/chat_operation.dart'; 6 | export 'src/chat_controller/in_memory_chat_controller.dart'; 7 | export 'src/chat_controller/scroll_to_message_mixin.dart'; 8 | export 'src/chat_controller/upload_progress_mixin.dart'; 9 | export 'src/models/builders.dart'; 10 | export 'src/models/link_preview_data.dart'; 11 | export 'src/models/message.dart'; 12 | export 'src/models/message_group_status.dart'; 13 | export 'src/models/user.dart'; 14 | export 'src/theme/chat_theme.dart'; 15 | export 'src/theme/chat_theme_extension.dart'; 16 | export 'src/utils/get_icon_for_status.dart'; 17 | export 'src/utils/is_only_emoji.dart'; 18 | export 'src/utils/link_preview_position.dart'; 19 | export 'src/utils/typedefs.dart'; 20 | export 'src/utils/user_cache.dart'; 21 | -------------------------------------------------------------------------------- /packages/flutter_chat_core/lib/src/chat_controller/chat_operation.dart: -------------------------------------------------------------------------------- 1 | import '../models/message.dart'; 2 | 3 | /// Enum representing the type of operation performed on the chat message list. 4 | enum ChatOperationType { insert, insertAll, update, remove, set } 5 | 6 | /// Represents a single operation performed on the message list managed by a [ChatController]. 7 | /// 8 | /// Instances of this class are emitted by the [ChatController.operationsStream] 9 | /// to notify listeners about changes. 10 | class ChatOperation { 11 | /// The type of operation performed. 12 | final ChatOperationType type; 13 | 14 | /// The message before an update operation. Null for other types. 15 | final Message? oldMessage; 16 | 17 | /// The affected message (inserted, updated, removed). Null for `set` or `insertAll`. 18 | final Message? message; 19 | 20 | /// The index where the message was inserted or removed. Null for `update` and `set`. 21 | /// For `insertAll`, this is the starting index of the insertion. 22 | final int? index; 23 | 24 | /// A list of messages, used by `insertAll` and `set` operations. 25 | /// Null for other operation types. 26 | final List? messages; 27 | 28 | ChatOperation._( 29 | this.type, { 30 | this.oldMessage, 31 | this.message, 32 | this.index, 33 | this.messages, 34 | }); 35 | 36 | /// Creates an insert operation. 37 | factory ChatOperation.insert(Message message, int index) => 38 | ChatOperation._(ChatOperationType.insert, message: message, index: index); 39 | 40 | /// Creates an insertAll operation, for inserting multiple messages at a specified index. 41 | factory ChatOperation.insertAll(List messages, int index) => 42 | ChatOperation._( 43 | ChatOperationType.insertAll, 44 | messages: messages, 45 | index: index, 46 | ); 47 | 48 | /// Creates an update operation. 49 | factory ChatOperation.update( 50 | Message oldMessage, 51 | Message message, 52 | int index, 53 | ) => ChatOperation._( 54 | ChatOperationType.update, 55 | oldMessage: oldMessage, 56 | message: message, 57 | index: index, 58 | ); 59 | 60 | /// Creates a remove operation. 61 | factory ChatOperation.remove(Message message, int index) => 62 | ChatOperation._(ChatOperationType.remove, message: message, index: index); 63 | 64 | /// Creates a set operation (signifying a full list replacement). 65 | /// 66 | /// The [messages] parameter contains the new list of messages. Passing an empty list 67 | /// signifies that the chat list should be cleared. 68 | factory ChatOperation.set(List messages) => 69 | ChatOperation._(ChatOperationType.set, messages: messages); 70 | } 71 | -------------------------------------------------------------------------------- /packages/flutter_chat_core/lib/src/models/duration_converter.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | /// Converts a [Duration] to and from an [int] representing seconds. 4 | class DurationConverter implements JsonConverter { 5 | const DurationConverter(); 6 | 7 | @override 8 | Duration fromJson(int json) => Duration(seconds: json); 9 | 10 | @override 11 | int toJson(Duration object) => object.inSeconds; 12 | } 13 | -------------------------------------------------------------------------------- /packages/flutter_chat_core/lib/src/models/epoch_date_time_converter.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | /// A [JsonConverter] for converting between [DateTime] and epoch timestamps (milliseconds since epoch). 4 | class EpochDateTimeConverter implements JsonConverter { 5 | /// Creates a const instance of [EpochDateTimeConverter]. 6 | const EpochDateTimeConverter(); 7 | 8 | @override 9 | DateTime fromJson(int json) => 10 | DateTime.fromMillisecondsSinceEpoch(json, isUtc: true); 11 | 12 | @override 13 | int toJson(DateTime object) => object.toUtc().millisecondsSinceEpoch; 14 | } 15 | -------------------------------------------------------------------------------- /packages/flutter_chat_core/lib/src/models/link_preview_data.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | 3 | part 'link_preview_data.freezed.dart'; 4 | part 'link_preview_data.g.dart'; 5 | 6 | /// Represents the data extracted for a link preview. 7 | @freezed 8 | abstract class LinkPreviewData with _$LinkPreviewData { 9 | /// Creates a [LinkPreviewData] instance. 10 | const factory LinkPreviewData({ 11 | /// The original URL link. 12 | required String link, 13 | 14 | /// A description extracted from the link source. 15 | String? description, 16 | 17 | /// The preview data of an image extracted from the link 18 | ImagePreviewData? image, 19 | 20 | /// The title extracted from the link source. 21 | String? title, 22 | }) = _LinkPreviewData; 23 | 24 | const LinkPreviewData._(); 25 | 26 | /// Creates a [LinkPreviewData] instance from a JSON map. 27 | factory LinkPreviewData.fromJson(Map json) => 28 | _$LinkPreviewDataFromJson(json); 29 | } 30 | 31 | /// Represents the data extracted for a link preview image. 32 | @freezed 33 | abstract class ImagePreviewData with _$ImagePreviewData { 34 | /// Creates a [ImagePreviewData] instance. 35 | const factory ImagePreviewData({ 36 | /// The URL of an image associated with the link. 37 | required String url, 38 | 39 | /// The image width. 40 | required double width, 41 | 42 | /// The image height. 43 | required double height, 44 | }) = _ImagePreviewData; 45 | 46 | const ImagePreviewData._(); 47 | 48 | /// Creates a [ImagePreviewData] instance from a JSON map. 49 | factory ImagePreviewData.fromJson(Map json) => 50 | _$ImagePreviewDataFromJson(json); 51 | } 52 | -------------------------------------------------------------------------------- /packages/flutter_chat_core/lib/src/models/link_preview_data.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'link_preview_data.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | _LinkPreviewData _$LinkPreviewDataFromJson(Map json) => 10 | _LinkPreviewData( 11 | link: json['link'] as String, 12 | description: json['description'] as String?, 13 | image: 14 | json['image'] == null 15 | ? null 16 | : ImagePreviewData.fromJson( 17 | json['image'] as Map, 18 | ), 19 | title: json['title'] as String?, 20 | ); 21 | 22 | Map _$LinkPreviewDataToJson(_LinkPreviewData instance) => 23 | { 24 | 'link': instance.link, 25 | if (instance.description case final value?) 'description': value, 26 | if (instance.image?.toJson() case final value?) 'image': value, 27 | if (instance.title case final value?) 'title': value, 28 | }; 29 | 30 | _ImagePreviewData _$ImagePreviewDataFromJson(Map json) => 31 | _ImagePreviewData( 32 | url: json['url'] as String, 33 | width: (json['width'] as num).toDouble(), 34 | height: (json['height'] as num).toDouble(), 35 | ); 36 | 37 | Map _$ImagePreviewDataToJson(_ImagePreviewData instance) => 38 | { 39 | 'url': instance.url, 40 | 'width': instance.width, 41 | 'height': instance.height, 42 | }; 43 | -------------------------------------------------------------------------------- /packages/flutter_chat_core/lib/src/models/message_group_status.dart: -------------------------------------------------------------------------------- 1 | /// Represents the grouping status of a message within a sequence of messages 2 | /// from the same author sent close together in time. 3 | class MessageGroupStatus { 4 | /// True if this is the first message in the group. 5 | final bool isFirst; 6 | 7 | /// True if this is the last message in the group. 8 | final bool isLast; 9 | 10 | /// True if this is a message in the middle of the group (neither first nor last). 11 | final bool isMiddle; 12 | 13 | /// Creates a [MessageGroupStatus] instance. 14 | const MessageGroupStatus({ 15 | required this.isFirst, 16 | required this.isLast, 17 | required this.isMiddle, 18 | }); 19 | } 20 | -------------------------------------------------------------------------------- /packages/flutter_chat_core/lib/src/models/user.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | 3 | import '../utils/typedefs.dart' show UserID; 4 | import 'epoch_date_time_converter.dart'; 5 | 6 | part 'user.freezed.dart'; 7 | part 'user.g.dart'; 8 | 9 | /// Represents a user in the chat system. 10 | @freezed 11 | abstract class User with _$User { 12 | /// Creates a [User] instance. 13 | const factory User({ 14 | /// Unique identifier for the user. 15 | required UserID id, 16 | 17 | /// The user's display name. 18 | String? name, 19 | 20 | /// URL or source string for the user's avatar image. 21 | String? imageSource, 22 | 23 | /// Timestamp when the user was created. 24 | @EpochDateTimeConverter() DateTime? createdAt, 25 | 26 | /// Additional custom metadata associated with the user. 27 | Map? metadata, 28 | }) = _User; 29 | 30 | const User._(); 31 | 32 | /// Creates a [User] instance from a JSON map. 33 | factory User.fromJson(Map json) => _$UserFromJson(json); 34 | } 35 | -------------------------------------------------------------------------------- /packages/flutter_chat_core/lib/src/models/user.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'user.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | _User _$UserFromJson(Map json) => _User( 10 | id: json['id'] as String, 11 | name: json['name'] as String?, 12 | imageSource: json['imageSource'] as String?, 13 | createdAt: _$JsonConverterFromJson( 14 | json['createdAt'], 15 | const EpochDateTimeConverter().fromJson, 16 | ), 17 | metadata: json['metadata'] as Map?, 18 | ); 19 | 20 | Map _$UserToJson(_User instance) => { 21 | 'id': instance.id, 22 | if (instance.name case final value?) 'name': value, 23 | if (instance.imageSource case final value?) 'imageSource': value, 24 | if (_$JsonConverterToJson( 25 | instance.createdAt, 26 | const EpochDateTimeConverter().toJson, 27 | ) 28 | case final value?) 29 | 'createdAt': value, 30 | if (instance.metadata case final value?) 'metadata': value, 31 | }; 32 | 33 | Value? _$JsonConverterFromJson( 34 | Object? json, 35 | Value? Function(Json json) fromJson, 36 | ) => json == null ? null : fromJson(json as Json); 37 | 38 | Json? _$JsonConverterToJson( 39 | Value? value, 40 | Json? Function(Value value) toJson, 41 | ) => value == null ? null : toJson(value); 42 | -------------------------------------------------------------------------------- /packages/flutter_chat_core/lib/src/theme/chat_theme_extension.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | import 'chat_theme.dart'; 4 | 5 | /// Extension methods for [ChatTheme] to simplify modifications. 6 | extension ChatThemeExtensions on ChatTheme { 7 | /// Creates a copy of the theme with updated light colors. 8 | /// 9 | /// Uses [ChatColors.light] as the base and overrides specified colors. 10 | ChatTheme withLightColors({ 11 | Color? primary, 12 | Color? onPrimary, 13 | Color? surface, 14 | Color? onSurface, 15 | Color? surfaceContainer, 16 | Color? surfaceContainerLow, 17 | Color? surfaceContainerHigh, 18 | }) { 19 | final light = ChatColors.light(); 20 | return copyWith( 21 | colors: light.copyWith( 22 | primary: primary ?? light.primary, 23 | onPrimary: onPrimary ?? light.onPrimary, 24 | surface: surface ?? light.surface, 25 | onSurface: onSurface ?? light.onSurface, 26 | surfaceContainer: surfaceContainer ?? light.surfaceContainer, 27 | surfaceContainerLow: surfaceContainerLow ?? light.surfaceContainerLow, 28 | surfaceContainerHigh: 29 | surfaceContainerHigh ?? light.surfaceContainerHigh, 30 | ), 31 | ); 32 | } 33 | 34 | /// Creates a copy of the theme with updated dark colors. 35 | /// 36 | /// Uses [ChatColors.dark] as the base and overrides specified colors. 37 | ChatTheme withDarkColors({ 38 | Color? primary, 39 | Color? onPrimary, 40 | Color? surface, 41 | Color? onSurface, 42 | Color? surfaceContainer, 43 | Color? surfaceContainerLow, 44 | Color? surfaceContainerHigh, 45 | }) { 46 | final dark = ChatColors.dark(); 47 | return copyWith( 48 | colors: dark.copyWith( 49 | primary: primary ?? dark.primary, 50 | onPrimary: onPrimary ?? dark.onPrimary, 51 | surface: surface ?? dark.surface, 52 | onSurface: onSurface ?? dark.onSurface, 53 | surfaceContainer: surfaceContainer ?? dark.surfaceContainer, 54 | surfaceContainerLow: surfaceContainerLow ?? dark.surfaceContainerLow, 55 | surfaceContainerHigh: surfaceContainerHigh ?? dark.surfaceContainerHigh, 56 | ), 57 | ); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /packages/flutter_chat_core/lib/src/utils/get_icon_for_status.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import '../utils/typedefs.dart' show MessageStatus; 4 | 5 | /// Returns the appropriate [IconData] for a given [MessageStatus]. 6 | IconData getIconForStatus(MessageStatus status) { 7 | switch (status) { 8 | case MessageStatus.delivered: 9 | return Icons.check; 10 | case MessageStatus.error: 11 | return Icons.error_outline; 12 | case MessageStatus.seen: 13 | return Icons.done_all; 14 | case MessageStatus.sending: 15 | return Icons.cloud_upload_outlined; 16 | case MessageStatus.sent: 17 | return Icons.check; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/flutter_chat_core/lib/src/utils/link_preview_position.dart: -------------------------------------------------------------------------------- 1 | /// Enum controlling the position of the link preview widget. 2 | enum LinkPreviewPosition { top, bottom, none } 3 | -------------------------------------------------------------------------------- /packages/flutter_chat_core/lib/src/utils/typedefs.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/widgets.dart'; 2 | 3 | import '../models/message.dart'; 4 | import '../models/user.dart'; 5 | 6 | /// Re-export of [DateFormat] from the `intl` package for convenience. 7 | export 'package:intl/intl.dart' show DateFormat; 8 | 9 | /// Alias for a message ID (String). 10 | typedef MessageID = String; 11 | 12 | /// Alias for a user ID (String). 13 | typedef UserID = String; 14 | 15 | /// Represents the delivery status of a message. 16 | enum MessageStatus { delivered, error, seen, sending, sent } 17 | 18 | /// Defines the position of the timestamp and status indicator relative to the message content. 19 | enum TimeAndStatusPosition { start, end, inline } 20 | 21 | /// Defines the mode for grouping messages. Default is [timeDifference]. 22 | enum MessagesGroupingMode { timeDifference, sameMinute, sameHour, sameDay } 23 | 24 | /// Signature for a callback function that resolves a [User] object from a [UserID]. 25 | typedef ResolveUserCallback = Future Function(UserID id); 26 | 27 | /// Signature for a function that builds a single chat list item widget. 28 | /// Used by [ChatAnimatedList] and [ChatAnimatedListReversed]. 29 | typedef ChatItem = 30 | Widget Function( 31 | BuildContext context, 32 | Message message, 33 | int index, 34 | Animation animation, { 35 | MessagesGroupingMode? messagesGroupingMode, 36 | int? messageGroupingTimeoutInSeconds, 37 | bool? isRemoved, 38 | }); 39 | -------------------------------------------------------------------------------- /packages/flutter_chat_core/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flutter_chat_core 2 | version: 2.6.1 3 | description: > 4 | Core package for Flutter chat apps, complementing flutter_chat_ui. 5 | Contains models and core functionality. #chat #ui 6 | homepage: https://flyer.chat 7 | repository: https://github.com/flyerhq/flutter_chat_ui 8 | 9 | environment: 10 | sdk: ">=3.7.0 <4.0.0" 11 | flutter: ">=3.29.0" 12 | 13 | dependencies: 14 | dio: ^5.8.0+1 15 | flutter: 16 | sdk: flutter 17 | freezed_annotation: ^3.0.0 18 | intl: '>=0.19.0 <1.0.0' 19 | json_annotation: ^4.9.0 20 | path_provider: ^2.1.5 21 | 22 | dev_dependencies: 23 | build_runner: ^2.4.15 24 | flutter_lints: ^5.0.0 25 | flutter_test: 26 | sdk: flutter 27 | freezed: ^3.0.6 28 | json_serializable: ^6.9.4 29 | -------------------------------------------------------------------------------- /packages/flutter_chat_core/test/chat_controller/in_memory_chat_controller_test.dart: -------------------------------------------------------------------------------- 1 | // import 'package:flutter_chat_core/flutter_chat_core.dart'; 2 | import 'package:flutter_test/flutter_test.dart'; 3 | 4 | // import 'mock_data.dart'; 5 | 6 | void main() { 7 | group('InMemoryChatController', () { 8 | // late InMemoryChatController inMemoryChatController; 9 | 10 | // setUp(() { 11 | // inMemoryChatController = InMemoryChatController(messages: mockData); 12 | // }); 13 | 14 | // test('inserts a new message at the end', () { 15 | // final newMessage = TextMessage( 16 | // id: '21', 17 | // authorId: 'me', 18 | // text: 'test', 19 | // ); 20 | 21 | // inMemoryChatController.insertMessage(newMessage); 22 | 23 | // expect(inMemoryChatController.get(20), newMessage); 24 | // }); 25 | 26 | // test('removes first message using set', () { 27 | // final newData = mockData.sublist(1); 28 | 29 | // inMemoryChatController.setMessages(newData); 30 | 31 | // expect(inMemoryChatController.get(0).id, '2'); 32 | // }); 33 | 34 | // test('adds multiple messages using set', () { 35 | // final newMessage1 = TextMessage( 36 | // id: '21', 37 | // authorId: 'me', 38 | // text: 'test', 39 | // ); 40 | 41 | // final newMessage2 = TextMessage( 42 | // id: '22', 43 | // authorId: 'me', 44 | // text: 'test', 45 | // ); 46 | 47 | // inMemoryChatController.setMessages([...mockData, newMessage1, newMessage2]); 48 | 49 | // expect(inMemoryChatController.get(20), newMessage1); 50 | // expect(inMemoryChatController.get(21), newMessage2); 51 | // }); 52 | 53 | // test('adds keeps inserted message when using set without it', () { 54 | // final message = TextMessage( 55 | // id: '21', 56 | // authorId: 'me', 57 | // text: 'test', 58 | // ); 59 | 60 | // inMemoryChatController.insertMessage(message); 61 | 62 | // expect(inMemoryChatController.get(20), message); 63 | 64 | // inMemoryChatController.setMessages(mockData); 65 | 66 | // expect(inMemoryChatController.get(20), message); 67 | // }); 68 | }); 69 | } 70 | -------------------------------------------------------------------------------- /packages/flutter_chat_core/test/models/link_preview_data_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_chat_core/flutter_chat_core.dart'; 2 | import 'package:flutter_test/flutter_test.dart'; 3 | 4 | void main() { 5 | group('LinkPreviewData', () { 6 | late LinkPreviewData linkPreviewData; 7 | 8 | setUp(() { 9 | final json = { 10 | 'link': 'https://google.com', 11 | 'description': 'Google homepage', 12 | 'image': { 13 | 'url': 'https://google.com/logo.png', 14 | 'width': 100.0, 15 | 'height': 100.0, 16 | }, 17 | 'title': 'Google', 18 | }; 19 | 20 | linkPreviewData = LinkPreviewData.fromJson(json); 21 | }); 22 | 23 | test('initializes correctly from a JSON', () { 24 | expect(linkPreviewData.link, 'https://google.com'); 25 | expect(linkPreviewData.description, 'Google homepage'); 26 | expect(linkPreviewData.image!.url, 'https://google.com/logo.png'); 27 | expect(linkPreviewData.image!.width, 100.0); 28 | expect(linkPreviewData.image!.height, 100.0); 29 | expect(linkPreviewData.title, 'Google'); 30 | }); 31 | 32 | test('treats objects with the same properties as equal', () { 33 | final json = { 34 | 'link': 'https://google.com', 35 | 'description': 'Google homepage', 36 | 'image': { 37 | 'url': 'https://google.com/logo.png', 38 | 'width': 100.0, 39 | 'height': 100.0, 40 | }, 41 | 'title': 'Google', 42 | }; 43 | 44 | final linkPreviewData2 = LinkPreviewData.fromJson(json); 45 | 46 | // Two objects with the same properties should be equal. 47 | expect(linkPreviewData == linkPreviewData2, true); 48 | 49 | // Change one property of linkPreviewData2. 50 | final copiedLinkPreview = linkPreviewData2.copyWith(title: null); 51 | 52 | // The original and the changed objects should not be equal. 53 | expect(linkPreviewData == copiedLinkPreview, false); 54 | }); 55 | }); 56 | } 57 | -------------------------------------------------------------------------------- /packages/flutter_chat_core/test/utils/only_emoji_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_chat_core/flutter_chat_core.dart'; 2 | import 'package:flutter_test/flutter_test.dart'; 3 | 4 | void main() { 5 | group('isOnlyEmoji', () { 6 | test('returns false for empty string', () { 7 | expect(isOnlyEmoji(''), isFalse); 8 | }); 9 | 10 | test('returns false for whitespace only', () { 11 | expect(isOnlyEmoji(' '), isFalse); 12 | }); 13 | 14 | test('returns true for single emoji', () { 15 | expect(isOnlyEmoji('👍'), isTrue); 16 | }); 17 | 18 | test('returns true for multiple emojis', () { 19 | expect(isOnlyEmoji('😀😃😄'), isTrue); 20 | }); 21 | 22 | test('returns true for emojis with whitespace', () { 23 | expect(isOnlyEmoji('👋 😎 🎉'), isTrue); 24 | }); 25 | 26 | test('returns false for text with emojis', () { 27 | expect(isOnlyEmoji('Hello 👋'), isFalse); 28 | }); 29 | 30 | test('returns false for text only', () { 31 | expect(isOnlyEmoji('Hello world'), isFalse); 32 | }); 33 | 34 | test('returns true for complex emojis', () { 35 | expect(isOnlyEmoji('👨‍👩‍👧‍👦'), isTrue); 36 | }); 37 | 38 | test('returns true for emoji with modifiers', () { 39 | expect(isOnlyEmoji('👍🏻'), isTrue); 40 | }); 41 | 42 | test('returns false for numbers', () { 43 | expect(isOnlyEmoji('123'), isFalse); 44 | }); 45 | 46 | test('returns false for special characters', () { 47 | expect(isOnlyEmoji('!@#\$%'), isFalse); 48 | }); 49 | 50 | test('returns true for multiline emojis', () { 51 | expect(isOnlyEmoji('😀\n😃\n😄'), isTrue); 52 | }); 53 | 54 | test('returns true for multiline emojis with spaces', () { 55 | expect(isOnlyEmoji('👋 😎\n🎉 ✨'), isTrue); 56 | }); 57 | 58 | test('returns false for multiline text with emojis', () { 59 | expect(isOnlyEmoji('Hello 👋\nWorld 😊'), isFalse); 60 | }); 61 | }); 62 | } 63 | -------------------------------------------------------------------------------- /packages/flutter_chat_ui/README.md: -------------------------------------------------------------------------------- 1 | # [Flyer Chat](https://flyer.chat) 💬 2 | 3 | [![Ship faster with a go-to chat SDK for Flutter](../../banner.png)](https://flyer.chat/docs/flutter/introduction/) 4 | 5 | [![Pub Version](https://img.shields.io/pub/v/flutter_chat_ui?logo=flutter&color=orange)](https://pub.dev/packages/flutter_chat_ui) [![Pub Likes](https://img.shields.io/pub/likes/flutter_chat_ui?logo=flutter&color=orange&label=pub%20likes)](https://pub.dev/packages/flutter_chat_ui) [![Stars](https://img.shields.io/github/stars/flyerhq/flutter_chat_ui?style=flat&color=orange&logo=github)](https://github.com/flyerhq/flutter_chat_ui/stargazers) [![melos](https://img.shields.io/badge/maintained%20with-melos-ffffff.svg?color=orange)](https://github.com/invertase/melos) 6 | 7 | Flyer Chat is an open-source chat UI package for Flutter applications, designed for performance, customization, and ease of integration. 8 | 9 | ## ✨ Features 10 | 11 | - 🔄 **Backend-agnostic**: Connect to any backend service. 12 | - 🧬 **Adaptable**: Perfect for real-time messengers, generative AI agents and LLM-based assistants, support platforms, and beyond. 13 | - 🎨 **Highly Customizable**: Tailor the UI with extensive theme options and builder functions. 14 | - 🧩 **Modular**: Pick and choose the features you want. You can change any part of the UI or swap it with your own custom implementation. 15 | - ⚡ **Performance Optimized**: Built for speed and smooth animations. 16 | - 🌐 **Cross-Platform**: Supports iOS, Android, Web, macOS, Windows, and Linux. 17 | - 📜 **Open Source**: Free to use under the Apache 2.0 License. 18 | 19 | ## 🚀 Installation 20 | 21 | Add the package to your `pubspec.yaml`: 22 | 23 | ```yaml 24 | dependencies: 25 | flutter_chat_core: ^2.0.0 26 | flutter_chat_ui: ^2.0.0 27 | ``` 28 | 29 | Then, import and use the `Chat` widget. 30 | 31 | ## 📚 Documentation & Examples 32 | 33 | For detailed usage, customization options, different message types, controllers, and more complex scenarios, please refer to the **full documentation**: 34 | 35 | ➡️ **[flyer.chat/docs/flutter/introduction](https://flyer.chat/docs/flutter/introduction)** ⬅️ 36 | 37 | Explore the comprehensive [example application](https://github.com/flyerhq/flutter_chat_ui/tree/main/examples/flyer_chat) to see various features and customizations in action. 38 | 39 | ## 🤝 Contributing 40 | 41 | Contributions are welcome! Please see the [CONTRIBUTING.md](https://github.com/flyerhq/flutter_chat_ui/blob/main/CONTRIBUTING.md) file in the main repository for guidelines. 42 | 43 | ## 📜 License 44 | 45 | Licensed under the Apache License, Version 2.0. See the [LICENSE](https://github.com/flyerhq/flutter_chat_ui/blob/main/packages/flutter_chat_ui/LICENSE) file for details. 46 | -------------------------------------------------------------------------------- /packages/flutter_chat_ui/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: ../../analysis_options.yaml 2 | -------------------------------------------------------------------------------- /packages/flutter_chat_ui/example/README.md: -------------------------------------------------------------------------------- 1 | ```dart 2 | import 'dart:math'; 3 | 4 | import 'package:flutter/material.dart'; 5 | import 'package:flutter_chat_core/flutter_chat_core.dart'; 6 | import 'package:flutter_chat_ui/flutter_chat_ui.dart'; 7 | 8 | class Basic extends StatefulWidget { 9 | const Basic({super.key}); 10 | 11 | @override 12 | BasicState createState() => BasicState(); 13 | } 14 | 15 | class BasicState extends State { 16 | final _chatController = InMemoryChatController(); 17 | 18 | @override 19 | void dispose() { 20 | _chatController.dispose(); 21 | super.dispose(); 22 | } 23 | 24 | @override 25 | Widget build(BuildContext context) { 26 | return Scaffold( 27 | body: Chat( 28 | chatController: _chatController, 29 | currentUserId: 'user1', 30 | onMessageSend: (text) { 31 | _chatController.insertMessage( 32 | TextMessage( 33 | // Better to use UUID or similar for the ID - IDs must be unique 34 | id: '${Random().nextInt(1000) + 1}', 35 | authorId: 'user1', 36 | createdAt: DateTime.now().toUtc(), 37 | text: text, 38 | ), 39 | ); 40 | }, 41 | resolveUser: (UserID id) async { 42 | return User(id: id, name: 'John Doe'); 43 | }, 44 | ), 45 | ); 46 | } 47 | } 48 | 49 | ``` -------------------------------------------------------------------------------- /packages/flutter_chat_ui/lib/flutter_chat_ui.dart: -------------------------------------------------------------------------------- 1 | /// Flutter Chat UI package. Provides the UI for the Flyer Chat. 2 | library; 3 | 4 | export 'src/avatar.dart'; 5 | export 'src/chat.dart'; 6 | export 'src/chat_animated_list/chat_animated_list.dart'; 7 | export 'src/chat_animated_list/chat_animated_list_reversed.dart'; 8 | export 'src/chat_message/chat_message.dart'; 9 | export 'src/composer.dart'; 10 | export 'src/empty_chat_list.dart'; 11 | export 'src/is_typing.dart'; 12 | export 'src/load_more.dart'; 13 | export 'src/scroll_to_bottom.dart'; 14 | export 'src/simple_text_message.dart'; 15 | export 'src/username.dart'; 16 | export 'src/utils/composer_height_notifier.dart'; 17 | export 'src/utils/load_more_notifier.dart'; 18 | export 'src/utils/typedefs.dart'; 19 | -------------------------------------------------------------------------------- /packages/flutter_chat_ui/lib/src/chat_animated_list/sliver_spacing.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:provider/provider.dart'; 3 | 4 | import '../../flutter_chat_ui.dart'; 5 | import '../utils/keyboard_mixin.dart'; 6 | 7 | /// A sliver widget that creates vertical spacing at the end of a chat list. 8 | /// 9 | /// This widget is primarily used to account for the height of the composer, 10 | /// optional bottom padding, and the keyboard (when visible). 11 | /// It consumes [ComposerHeightNotifier] to dynamically adjust its spacing 12 | /// based on the composer's height and uses [KeyboardMixin] to react to 13 | /// keyboard visibility changes. 14 | class SliverSpacing extends StatefulWidget { 15 | /// Optional padding to add below the composer area. 16 | final double? bottomPadding; 17 | 18 | /// Whether to automatically account for the bottom safe area (notch, home indicator). 19 | /// Defaults to true if not specified, but behavior depends on how it's used in parent. 20 | final bool? handleSafeArea; 21 | 22 | /// Callback function invoked when the detected keyboard height changes. 23 | /// 24 | /// The reported `height` is the adjusted keyboard height, considering the 25 | /// initial safe area. 26 | final void Function(double height)? onKeyboardHeightChanged; 27 | 28 | /// Creates a [SliverSpacing] widget. 29 | const SliverSpacing({ 30 | super.key, 31 | this.bottomPadding, 32 | this.handleSafeArea, 33 | this.onKeyboardHeightChanged, 34 | }); 35 | 36 | @override 37 | State createState() => _SliverSpacingState(); 38 | } 39 | 40 | class _SliverSpacingState extends State 41 | with WidgetsBindingObserver, KeyboardMixin { 42 | @override 43 | Widget build(BuildContext context) { 44 | final safeArea = MediaQuery.of(context).padding.bottom; 45 | return Consumer( 46 | builder: (context, heightNotifier, child) { 47 | return SliverPadding( 48 | padding: EdgeInsets.only( 49 | bottom: 50 | heightNotifier.height + 51 | (widget.bottomPadding ?? 0) + 52 | (widget.handleSafeArea == true ? safeArea : 0), 53 | ), 54 | ); 55 | }, 56 | ); 57 | } 58 | 59 | @override 60 | void onKeyboardHeightChanged(double height) { 61 | widget.onKeyboardHeightChanged?.call(height); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /packages/flutter_chat_ui/lib/src/load_more.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_chat_core/flutter_chat_core.dart'; 3 | import 'package:provider/provider.dart'; 4 | 5 | import 'utils/load_more_notifier.dart'; 6 | 7 | /// A widget displayed at the top of the chat list when paginating 8 | /// (loading more historical messages). 9 | /// 10 | /// Typically shows a [CircularProgressIndicator]. 11 | class LoadMore extends StatefulWidget { 12 | /// Color of the progress indicator. Defaults to theme's `onSurface`. 13 | final Color? color; 14 | 15 | /// Vertical padding around the indicator. 16 | final double? padding; 17 | 18 | /// Size (diameter) of the progress indicator. 19 | final double? size; 20 | 21 | /// Creates a load more indicator widget. 22 | const LoadMore({super.key, this.color, this.padding = 20, this.size = 20}); 23 | 24 | @override 25 | State createState() => _LoadMoreState(); 26 | } 27 | 28 | class _LoadMoreState extends State { 29 | final _key = GlobalKey(); 30 | 31 | @override 32 | void initState() { 33 | super.initState(); 34 | WidgetsBinding.instance.addPostFrameCallback((_) => _measure()); 35 | } 36 | 37 | @override 38 | Widget build(BuildContext context) { 39 | final theme = context.select( 40 | (ChatTheme t) => (onSurface: t.colors.onSurface), 41 | ); 42 | 43 | return Padding( 44 | key: _key, 45 | padding: EdgeInsets.symmetric(vertical: widget.padding ?? 0), 46 | child: Center( 47 | child: SizedBox( 48 | height: widget.size, 49 | width: widget.size, 50 | child: CircularProgressIndicator( 51 | color: widget.color ?? theme.onSurface, 52 | strokeCap: StrokeCap.round, 53 | ), 54 | ), 55 | ), 56 | ); 57 | } 58 | 59 | void _measure() { 60 | if (!mounted) return; 61 | 62 | final renderBox = _key.currentContext?.findRenderObject() as RenderBox?; 63 | if (renderBox != null) { 64 | final height = renderBox.size.height; 65 | context.read().setHeight(height); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /packages/flutter_chat_ui/lib/src/username.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_chat_core/flutter_chat_core.dart'; 3 | import 'package:provider/provider.dart'; 4 | 5 | /// A widget that displays a user's name. 6 | /// 7 | /// Fetches user data using the provided [userId] and [ResolveUserCallback]. 8 | /// Uses [UserCache] for efficient user data retrieval. 9 | /// Displays the user's name if available, otherwise an empty string. 10 | class Username extends StatelessWidget { 11 | /// The ID of the user whose name is to be displayed. 12 | final UserID userId; 13 | 14 | /// Optional text style for the username. 15 | final TextStyle? style; 16 | 17 | /// Creates a username widget. 18 | const Username({super.key, required this.userId, this.style}); 19 | 20 | @override 21 | Widget build(BuildContext context) { 22 | final resolveUser = context.read(); 23 | final userCache = context.watch(); 24 | 25 | // Try to get from cache synchronously first 26 | final cachedUser = userCache.getSync(userId); 27 | 28 | if (cachedUser != null) { 29 | // Sync path - no FutureBuilder needed 30 | return _buildUsername(context, cachedUser); 31 | } 32 | 33 | // Async path - use FutureBuilder with cache 34 | return FutureBuilder( 35 | // This will update the cache when resolved 36 | future: userCache.getOrResolve(userId, resolveUser), 37 | builder: (context, snapshot) { 38 | return _buildUsername(context, snapshot.data); 39 | }, 40 | ); 41 | } 42 | 43 | Widget _buildUsername(BuildContext context, User? user) { 44 | final theme = context.select( 45 | (ChatTheme t) => ( 46 | labelMedium: t.typography.labelMedium, 47 | onSurface: t.colors.onSurface, 48 | ), 49 | ); 50 | 51 | final defaultStyle = theme.labelMedium.copyWith(color: theme.onSurface); 52 | 53 | return Text(user?.name ?? '', style: style ?? defaultStyle); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /packages/flutter_chat_ui/lib/src/utils/composer_height_notifier.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | 3 | /// A [ChangeNotifier] used to track the height of the message composer. 4 | /// 5 | /// Allows other widgets (like the chat list) to react to composer height changes, 6 | /// for example, by adjusting padding. 7 | class ComposerHeightNotifier extends ChangeNotifier { 8 | double _height = 0; 9 | 10 | /// The current measured height of the composer. 11 | double get height => _height; 12 | 13 | /// Sets the composer height and notifies listeners if it changes. 14 | void setHeight(double newHeight) { 15 | if (_height != newHeight) { 16 | _height = newHeight; 17 | notifyListeners(); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/flutter_chat_ui/lib/src/utils/keyboard_mixin.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:math'; 3 | import 'package:flutter/material.dart'; 4 | 5 | /// A mixin for State classes that provides keyboard height detection and notification. 6 | /// 7 | /// Automatically handles listening to `WidgetsBinding` for metrics changes 8 | /// and debounces updates to avoid rapid firing during keyboard animations. 9 | mixin KeyboardMixin 10 | on State, WidgetsBindingObserver { 11 | Timer? _keyboardDebounceTimer; 12 | double _previousKeyboardHeight = 0; 13 | double _initialSafeArea = 0; 14 | bool _initialized = false; 15 | 16 | /// Abstract method to be implemented by the consuming State. 17 | /// Called when the keyboard height changes (after debouncing). 18 | /// The provided [height] is adjusted for the initial bottom safe area. 19 | void onKeyboardHeightChanged(double height); 20 | 21 | @override 22 | void initState() { 23 | super.initState(); 24 | WidgetsBinding.instance.addObserver(this); 25 | } 26 | 27 | @override 28 | void didChangeDependencies() { 29 | super.didChangeDependencies(); 30 | if (!_initialized) { 31 | _initialSafeArea = MediaQuery.of(context).padding.bottom; 32 | _initialized = true; 33 | } 34 | } 35 | 36 | @override 37 | void dispose() { 38 | WidgetsBinding.instance.removeObserver(this); 39 | _keyboardDebounceTimer?.cancel(); 40 | super.dispose(); 41 | } 42 | 43 | @override 44 | void didChangeMetrics() { 45 | super.didChangeMetrics(); 46 | if (!mounted) return; 47 | 48 | final keyboardHeight = View.of(context).viewInsets.bottom; 49 | final pixelRatio = MediaQuery.of(context).devicePixelRatio; 50 | if (keyboardHeight != _previousKeyboardHeight) { 51 | _previousKeyboardHeight = keyboardHeight; 52 | 53 | _keyboardDebounceTimer?.cancel(); 54 | _keyboardDebounceTimer = Timer(const Duration(milliseconds: 100), () { 55 | if (mounted) { 56 | onKeyboardHeightChanged( 57 | max(keyboardHeight / pixelRatio - _initialSafeArea, 0), 58 | ); 59 | } 60 | }); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /packages/flutter_chat_ui/lib/src/utils/load_more_notifier.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | 3 | /// A [ChangeNotifier] used to track the height and loading state 4 | /// of the "Load More" indicator widget. 5 | class LoadMoreNotifier extends ChangeNotifier { 6 | double _height = 0; 7 | bool _isLoading = false; 8 | 9 | /// The current measured height of the LoadMore widget. 10 | double get height => _height; 11 | 12 | /// Whether the LoadMore widget is currently indicating a loading state. 13 | bool get isLoading => _isLoading; 14 | 15 | /// Sets the height of the LoadMore widget and notifies listeners if it changes. 16 | void setHeight(double newHeight) { 17 | if (_height != newHeight) { 18 | _height = newHeight; 19 | notifyListeners(); 20 | } 21 | } 22 | 23 | /// Sets the loading state and notifies listeners if it changes. 24 | void setLoading(bool loading) { 25 | if (_isLoading != loading) { 26 | _isLoading = loading; 27 | notifyListeners(); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /packages/flutter_chat_ui/lib/src/utils/message_list_diff.dart: -------------------------------------------------------------------------------- 1 | import 'package:diffutil_dart/diffutil.dart' as diffutil; 2 | import 'package:flutter_chat_core/flutter_chat_core.dart'; 3 | 4 | /// A [diffutil.ListDiffDelegate] implementation for comparing lists of [Message] objects. 5 | /// 6 | /// Used by `diffutil_dart` to calculate differences between old and new message lists 7 | /// for efficient updates in animated lists. 8 | class MessageListDiff extends diffutil.ListDiffDelegate { 9 | /// Creates a diff delegate for comparing two message lists. 10 | MessageListDiff(super.oldList, super.newList); 11 | 12 | /// Checks if the content of two messages at the given positions is the same. 13 | /// Uses [equalityChecker] from `freezed_annotation` for deep comparison. 14 | @override 15 | bool areContentsTheSame(int oldItemPosition, int newItemPosition) => 16 | equalityChecker(oldList[oldItemPosition], newList[newItemPosition]); 17 | 18 | /// Checks if two messages at the given positions represent the same item. 19 | /// Compares messages based on their unique [id]. 20 | @override 21 | bool areItemsTheSame(int oldItemPosition, int newItemPosition) => 22 | oldList[oldItemPosition].id == newList[newItemPosition].id; 23 | } 24 | -------------------------------------------------------------------------------- /packages/flutter_chat_ui/lib/src/utils/typedefs.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/widgets.dart'; 2 | import 'package:flutter_chat_core/flutter_chat_core.dart'; 3 | 4 | /// Callback signature for when a message is tapped. 5 | /// Provides the tapped [message], its [index], and [TapUpDetails]. 6 | typedef OnMessageTapCallback = 7 | void Function(Message message, {int index, TapUpDetails details}); 8 | 9 | /// Callback signature for when a message is long-pressed. 10 | /// Provides the long-pressed [message], its [index], and [LongPressStartDetails]. 11 | typedef OnMessageLongPressCallback = 12 | void Function(Message message, {int index, LongPressStartDetails details}); 13 | 14 | /// Callback signature for when the user attempts to send a message. 15 | /// Provides the [text] entered by the user. 16 | typedef OnMessageSendCallback = void Function(String text); 17 | 18 | /// Callback signature for when the attachment button in the composer is tapped. 19 | typedef OnAttachmentTapCallback = VoidCallback; 20 | 21 | /// Callback signature for requesting pagination (loading more messages). 22 | /// Should return a [Future] that completes when the loading is finished. 23 | typedef PaginationCallback = Future Function(); 24 | 25 | /// Signature for a function that resolves the animation duration for a specific message. 26 | /// Used for customizing insert/remove animations in the chat list. 27 | typedef MessageAnimationDurationResolver = Duration? Function(Message message); 28 | -------------------------------------------------------------------------------- /packages/flutter_chat_ui/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flutter_chat_ui 2 | version: 2.5.2 3 | description: > 4 | Free and open-source chat SDK. Build fast, real-time apps and generative 5 | AI agents with a high-performance, customizable, cross-platform UI. 6 | homepage: https://flyer.chat 7 | repository: https://github.com/flyerhq/flutter_chat_ui 8 | 9 | environment: 10 | sdk: ">=3.7.0 <4.0.0" 11 | flutter: ">=3.29.0" 12 | 13 | dependencies: 14 | cross_cache: ^1.0.2 15 | diffutil_dart: ^4.0.1 16 | flutter: 17 | sdk: flutter 18 | flutter_chat_core: ^2.6.1 19 | provider: ^6.1.4 20 | scrollview_observer: ^1.26.0 21 | 22 | dev_dependencies: 23 | flutter_lints: ^5.0.0 24 | flutter_test: 25 | sdk: flutter 26 | -------------------------------------------------------------------------------- /packages/flyer_chat_audio_message/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.0.12 2 | 3 | - Version bump to match other packages 4 | 5 | ## 0.0.11 6 | 7 | - Version bump to match other packages 8 | 9 | ## 0.0.10 10 | 11 | - Version bump to match other packages 12 | 13 | ## 0.0.9 14 | 15 | - Version bump to match other packages 16 | 17 | ## 0.0.8 18 | 19 | - Version bump to match other packages 20 | 21 | ## 0.0.7 22 | 23 | - Require Flutter 3.29 and Dart 3.7 24 | 25 | ## 0.0.6 26 | 27 | - Version bump to match other packages 28 | 29 | ## 0.0.5 30 | 31 | - Version bump to match other packages 32 | 33 | ## 0.0.4 34 | 35 | - Version bump to match other packages 36 | 37 | ## 0.0.3 38 | 39 | - Version bump to match other packages 40 | 41 | ## 0.0.1 42 | 43 | - Initial release 44 | -------------------------------------------------------------------------------- /packages/flyer_chat_audio_message/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Oleksandr Demchenko 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/flyer_chat_audio_message/README.md: -------------------------------------------------------------------------------- 1 | # [Flyer Chat](https://flyer.chat) 💬 Audio Message Widget (Planned) 2 | 3 | [![Pub Version](https://img.shields.io/pub/v/flyer_chat_audio_message?logo=flutter&color=orange)](https://pub.dev/packages/flyer_chat_audio_message) [![Stars](https://img.shields.io/github/stars/flyerhq/flutter_chat_ui?style=flat&color=orange&logo=github)](https://github.com/flyerhq/flutter_chat_ui/stargazers) [![melos](https://img.shields.io/badge/maintained%20with-melos-ffffff.svg?color=orange)](https://github.com/invertase/melos) 4 | 5 | **Note:** This package is planned but not yet implemented 🚧. 6 | 7 | This package will provide an opinionated audio message widget for use with the [`flutter_chat_ui`](https://github.com/flyerhq/flutter_chat_ui/tree/main/packages/flutter_chat_ui) package. 8 | -------------------------------------------------------------------------------- /packages/flyer_chat_audio_message/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: ../../analysis_options.yaml 2 | -------------------------------------------------------------------------------- /packages/flyer_chat_audio_message/lib/flyer_chat_audio_message.dart: -------------------------------------------------------------------------------- 1 | export 'src/flyer_chat_audio_message.dart'; 2 | -------------------------------------------------------------------------------- /packages/flyer_chat_audio_message/lib/src/flyer_chat_audio_message.dart: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /packages/flyer_chat_audio_message/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flyer_chat_audio_message 2 | version: 0.0.12 3 | description: > 4 | Audio message package for Flutter chat apps, complementing flutter_chat_ui. #chat #ui 5 | homepage: https://flyer.chat 6 | repository: https://github.com/flyerhq/flutter_chat_ui 7 | 8 | environment: 9 | sdk: ">=3.7.0 <4.0.0" 10 | flutter: ">=3.29.0" 11 | 12 | dependencies: 13 | flutter: 14 | sdk: flutter 15 | 16 | dev_dependencies: 17 | flutter_lints: ^5.0.0 18 | flutter_test: 19 | sdk: flutter 20 | -------------------------------------------------------------------------------- /packages/flyer_chat_custom_message/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.0.12+1 2 | 3 | - **FIX**: update documentation. ([2ec05db2](https://github.com/flyerhq/flutter_chat_ui/commit/2ec05db24f3fb469658a3fd3a27a7c3c739826e9)) 4 | 5 | ## 0.0.12 6 | 7 | - Version bump to match other packages 8 | 9 | ## 0.0.11 10 | 11 | - Version bump to match other packages 12 | 13 | ## 0.0.10 14 | 15 | - Version bump to match other packages 16 | 17 | ## 0.0.9 18 | 19 | - Version bump to match other packages 20 | 21 | ## 0.0.8 22 | 23 | - Version bump to match other packages 24 | 25 | ## 0.0.7 26 | 27 | - Require Flutter 3.29 and Dart 3.7 28 | 29 | ## 0.0.6 30 | 31 | - Version bump to match other packages 32 | 33 | ## 0.0.5 34 | 35 | - Version bump to match other packages 36 | 37 | ## 0.0.4 38 | 39 | - Version bump to match other packages 40 | 41 | ## 0.0.3 42 | 43 | - Version bump to match other packages 44 | 45 | ## 0.0.1 46 | 47 | - Initial release 48 | -------------------------------------------------------------------------------- /packages/flyer_chat_custom_message/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Oleksandr Demchenko 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/flyer_chat_custom_message/README.md: -------------------------------------------------------------------------------- 1 | # [Flyer Chat](https://flyer.chat) 💬 Custom Message (Placeholder) 2 | 3 | [![Pub Version](https://img.shields.io/pub/v/flyer_chat_custom_message?logo=flutter&color=orange)](https://pub.dev/packages/flyer_chat_custom_message) [![Stars](https://img.shields.io/github/stars/flyerhq/flutter_chat_ui?style=flat&color=orange&logo=github)](https://github.com/flyerhq/flutter_chat_ui/stargazers) [![melos](https://img.shields.io/badge/maintained%20with-melos-ffffff.svg?color=orange)](https://github.com/invertase/melos) 4 | 5 | **Note:** This package has no implementation and serves as a placeholder to showcase the pattern for handling custom message types within [Flyer Chat](https://flyer.chat). 6 | 7 | ## Implementing Custom Messages 8 | 9 | To render your own custom messages: 10 | 11 | 1. When creating a message instance that represents your custom data, use the custom message type provided by `flutter_chat_core`. This type includes standard fields like `id`, `authorId`, `createdAt`, etc. 12 | 2. Store your custom data within the `metadata` field (a `Map`) of the custom message. For simple cases, this might be all you need. If you intend to support several distinct types of custom messages, you could use this `metadata` to help your `customMessageBuilder` decide which widget to display, for example, by including a specific key like `'customType': 'poll'`. 13 | 3. Use the `customMessageBuilder` provided by the main [`flutter_chat_ui`](https://github.com/flyerhq/flutter_chat_ui/tree/main/packages/flutter_chat_ui) package's `Builders` to render your widget based on the message instance passed to the builder. 14 | 15 | ```dart 16 | import 'package:flutter_chat_ui/flutter_chat_ui.dart'; 17 | 18 | Chat( 19 | builders: Builders( 20 | customMessageBuilder: (context, message, index, { 21 | required bool isSentByMe, 22 | MessageGroupStatus? groupStatus, 23 | }) => 24 | const SizedBox.shrink(), 25 | ), 26 | ); 27 | ``` -------------------------------------------------------------------------------- /packages/flyer_chat_custom_message/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: ../../analysis_options.yaml 2 | -------------------------------------------------------------------------------- /packages/flyer_chat_custom_message/lib/flyer_chat_custom_message.dart: -------------------------------------------------------------------------------- 1 | export 'src/flyer_chat_custom_message.dart'; 2 | -------------------------------------------------------------------------------- /packages/flyer_chat_custom_message/lib/src/flyer_chat_custom_message.dart: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /packages/flyer_chat_custom_message/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flyer_chat_custom_message 2 | version: 0.0.12+1 3 | description: > 4 | Custom message package for Flutter chat apps, complementing flutter_chat_ui. #chat #ui 5 | homepage: https://flyer.chat 6 | repository: https://github.com/flyerhq/flutter_chat_ui 7 | 8 | environment: 9 | sdk: ">=3.7.0 <4.0.0" 10 | flutter: ">=3.29.0" 11 | 12 | dependencies: 13 | flutter: 14 | sdk: flutter 15 | 16 | dev_dependencies: 17 | flutter_lints: ^5.0.0 18 | flutter_test: 19 | sdk: flutter 20 | -------------------------------------------------------------------------------- /packages/flyer_chat_file_message/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Oleksandr Demchenko 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/flyer_chat_file_message/README.md: -------------------------------------------------------------------------------- 1 | # [Flyer Chat](https://flyer.chat) 💬 File Message Widget 2 | 3 | [![Pub Version](https://img.shields.io/pub/v/flyer_chat_file_message?logo=flutter&color=orange)](https://pub.dev/packages/flyer_chat_file_message) [![Stars](https://img.shields.io/github/stars/flyerhq/flutter_chat_ui?style=flat&color=orange&logo=github)](https://github.com/flyerhq/flutter_chat_ui/stargazers) [![melos](https://img.shields.io/badge/maintained%20with-melos-ffffff.svg?color=orange)](https://github.com/invertase/melos) 4 | 5 | This package provides an opinionated file message widget for use with the [`flutter_chat_ui`](https://github.com/flyerhq/flutter_chat_ui/tree/main/packages/flutter_chat_ui) package. 6 | 7 | ## Purpose 8 | 9 | This widget is designed specifically to render file messages within a `flutter_chat_ui` implementation. It relies on models and themes provided by [`flutter_chat_core`](https://github.com/flyerhq/flutter_chat_ui/tree/main/packages/flutter_chat_core) and is not intended for standalone use outside the [Flyer Chat](https://flyer.chat) ecosystem. 10 | 11 | ## Installation 12 | 13 | Add this package to your `pubspec.yaml` alongside `flutter_chat_ui`: 14 | 15 | ```yaml 16 | dependencies: 17 | flutter_chat_ui: ^2.0.0 18 | flyer_chat_file_message: ^2.0.0 19 | ``` 20 | 21 | Then run `flutter pub get`. 22 | 23 | ## Usage 24 | 25 | ```dart 26 | import 'package:flutter_chat_ui/flutter_chat_ui.dart'; 27 | import 'package:flyer_chat_file_message/flyer_chat_file_message.dart'; 28 | 29 | Chat( 30 | builders: Builders( 31 | fileMessageBuilder: (context, message, index, { 32 | required bool isSentByMe, 33 | MessageGroupStatus? groupStatus, 34 | }) => 35 | FlyerChatFileMessage(message: message, index: index), 36 | ), 37 | ); 38 | ``` 39 | 40 | ## License 41 | 42 | Licensed under the MIT License. See the [LICENSE](https://github.com/flyerhq/flutter_chat_ui/blob/main/packages/flyer_chat_file_message/LICENSE) file for details. 43 | -------------------------------------------------------------------------------- /packages/flyer_chat_file_message/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: ../../analysis_options.yaml 2 | -------------------------------------------------------------------------------- /packages/flyer_chat_file_message/example/README.md: -------------------------------------------------------------------------------- 1 | ```dart 2 | import 'dart:math'; 3 | 4 | import 'package:flutter/material.dart'; 5 | import 'package:flutter_chat_core/flutter_chat_core.dart'; 6 | import 'package:flutter_chat_ui/flutter_chat_ui.dart'; 7 | import 'package:flyer_chat_file_message/flyer_chat_file_message.dart'; 8 | 9 | class Basic extends StatefulWidget { 10 | const Basic({super.key}); 11 | 12 | @override 13 | BasicState createState() => BasicState(); 14 | } 15 | 16 | class BasicState extends State { 17 | final _chatController = InMemoryChatController(); 18 | 19 | @override 20 | void dispose() { 21 | _chatController.dispose(); 22 | super.dispose(); 23 | } 24 | 25 | @override 26 | Widget build(BuildContext context) { 27 | return Scaffold( 28 | body: Chat( 29 | builders: Builders( 30 | fileMessageBuilder: (context, message, index, { 31 | required bool isSentByMe, 32 | MessageGroupStatus? groupStatus, 33 | }) => 34 | FlyerChatFileMessage(message: message, index: index), 35 | ), 36 | chatController: _chatController, 37 | currentUserId: 'user1', 38 | onAttachmentTap: () { 39 | // Implement a file picker to allow users to select files. For a comprehensive example, refer to: 40 | // https://github.com/flyerhq/flutter_chat_ui/blob/main/examples/flyer_chat 41 | final fileMessage = FileMessage( 42 | // Better to use UUID or similar for the ID - IDs must be unique 43 | id: '${Random().nextInt(1000) + 1}', 44 | authorId: 'user1', 45 | createdAt: DateTime.now().toUtc(), 46 | source: filePath, 47 | name: fileName, 48 | size: fileSize, 49 | ); 50 | _chatController.insertMessage(fileMessage); 51 | }, 52 | onMessageSend: (text) {}, 53 | resolveUser: (UserID id) async { 54 | return User(id: id, name: 'John Doe'); 55 | }, 56 | ), 57 | ); 58 | } 59 | } 60 | 61 | ``` -------------------------------------------------------------------------------- /packages/flyer_chat_file_message/lib/flyer_chat_file_message.dart: -------------------------------------------------------------------------------- 1 | /// Flyer Chat File Message package. Provides a widget for file messages. 2 | library; 3 | 4 | export 'src/flyer_chat_file_message.dart'; 5 | -------------------------------------------------------------------------------- /packages/flyer_chat_file_message/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flyer_chat_file_message 2 | version: 2.2.1 3 | description: > 4 | File message package for Flutter chat apps, complementing flutter_chat_ui. #chat #ui 5 | homepage: https://flyer.chat 6 | repository: https://github.com/flyerhq/flutter_chat_ui 7 | 8 | environment: 9 | sdk: ">=3.7.0 <4.0.0" 10 | flutter: ">=3.29.0" 11 | 12 | dependencies: 13 | flutter: 14 | sdk: flutter 15 | flutter_chat_core: ^2.6.1 16 | intl: '>=0.19.0 <1.0.0' 17 | provider: ^6.1.4 18 | 19 | dev_dependencies: 20 | flutter_lints: ^5.0.0 21 | flutter_test: 22 | sdk: flutter 23 | -------------------------------------------------------------------------------- /packages/flyer_chat_image_message/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Oleksandr Demchenko 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/flyer_chat_image_message/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: ../../analysis_options.yaml 2 | -------------------------------------------------------------------------------- /packages/flyer_chat_image_message/example/README.md: -------------------------------------------------------------------------------- 1 | ```dart 2 | import 'dart:math'; 3 | 4 | import 'package:flutter/material.dart'; 5 | import 'package:flutter_chat_core/flutter_chat_core.dart'; 6 | import 'package:flutter_chat_ui/flutter_chat_ui.dart'; 7 | import 'package:flyer_chat_image_message/flyer_chat_image_message.dart'; 8 | 9 | class Basic extends StatefulWidget { 10 | const Basic({super.key}); 11 | 12 | @override 13 | BasicState createState() => BasicState(); 14 | } 15 | 16 | class BasicState extends State { 17 | final _chatController = InMemoryChatController(); 18 | 19 | @override 20 | void dispose() { 21 | _chatController.dispose(); 22 | super.dispose(); 23 | } 24 | 25 | @override 26 | Widget build(BuildContext context) { 27 | return Scaffold( 28 | body: Chat( 29 | builders: Builders( 30 | imageMessageBuilder: (context, message, index, { 31 | required bool isSentByMe, 32 | MessageGroupStatus? groupStatus, 33 | }) => 34 | FlyerChatImageMessage(message: message, index: index), 35 | ), 36 | chatController: _chatController, 37 | currentUserId: 'user1', 38 | onAttachmentTap: () { 39 | // Implement an image picker to allow users to select images. For a comprehensive example, refer to: 40 | // https://github.com/flyerhq/flutter_chat_ui/blob/main/examples/flyer_chat 41 | final imageMessage = ImageMessage( 42 | // Better to use UUID or similar for the ID - IDs must be unique 43 | id: '${Random().nextInt(1000) + 1}', 44 | authorId: 'user1', 45 | createdAt: DateTime.now().toUtc(), 46 | source: image.path, 47 | ); 48 | _chatController.insertMessage(imageMessage); 49 | }, 50 | onMessageSend: (text) {}, 51 | resolveUser: (UserID id) async { 52 | return User(id: id, name: 'John Doe'); 53 | }, 54 | ), 55 | ); 56 | } 57 | } 58 | 59 | ``` -------------------------------------------------------------------------------- /packages/flyer_chat_image_message/lib/flyer_chat_image_message.dart: -------------------------------------------------------------------------------- 1 | /// Flyer Chat Image Message package. Provides a widget for image messages. 2 | library; 3 | 4 | export 'src/flyer_chat_image_message.dart'; 5 | export 'src/get_image_dimensions.dart'; 6 | -------------------------------------------------------------------------------- /packages/flyer_chat_image_message/lib/src/get_image_dimensions.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'package:flutter/widgets.dart'; 3 | 4 | /// Represents the width and height dimensions of an image. 5 | typedef Dimensions = (double width, double height); 6 | 7 | /// Asynchronously retrieves the dimensions (width and height) of an image 8 | /// provided by an [ImageProvider]. 9 | /// 10 | /// Uses an [ImageStreamListener] to get the image details once resolved. 11 | /// 12 | /// Returns a [Future] that completes with a [Dimensions] record, or completes 13 | /// with an error if the image cannot be resolved or its dimensions determined. 14 | Future getImageDimensions(ImageProvider provider) { 15 | final completer = Completer(); 16 | const config = ImageConfiguration.empty; 17 | 18 | provider 19 | .obtainKey(config) 20 | .then((key) { 21 | final stream = provider.resolve(config); 22 | 23 | final listener = ImageStreamListener( 24 | (image, synchronousCall) { 25 | completer.complete(( 26 | image.image.width.toDouble(), 27 | image.image.height.toDouble(), 28 | )); 29 | }, 30 | onError: (exception, stackTrace) { 31 | completer.completeError(exception, stackTrace); 32 | }, 33 | ); 34 | 35 | stream.addListener(listener); 36 | 37 | completer.future.whenComplete(() { 38 | stream.removeListener(listener); 39 | }); 40 | }) 41 | .catchError((error) { 42 | completer.completeError(error); 43 | }); 44 | 45 | return completer.future; 46 | } 47 | -------------------------------------------------------------------------------- /packages/flyer_chat_image_message/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flyer_chat_image_message 2 | version: 2.1.10 3 | description: > 4 | Image message package for Flutter chat apps, complementing flutter_chat_ui. 5 | Supports caching, ThumbHash and BlurHash. #chat #ui 6 | homepage: https://flyer.chat 7 | repository: https://github.com/flyerhq/flutter_chat_ui 8 | 9 | environment: 10 | sdk: ">=3.7.0 <4.0.0" 11 | flutter: ">=3.29.0" 12 | 13 | dependencies: 14 | blurhash_dart: ^1.2.1 15 | cross_cache: ^1.0.2 16 | flutter: 17 | sdk: flutter 18 | flutter_chat_core: ^2.6.1 19 | image: ^4.5.4 20 | provider: ^6.1.4 21 | thumbhash: ^0.1.0+1 22 | 23 | dev_dependencies: 24 | flutter_lints: ^5.0.0 25 | flutter_test: 26 | sdk: flutter 27 | -------------------------------------------------------------------------------- /packages/flyer_chat_location_message/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.0.12 2 | 3 | - Version bump to match other packages 4 | 5 | ## 0.0.11 6 | 7 | - Version bump to match other packages 8 | 9 | ## 0.0.10 10 | 11 | - Version bump to match other packages 12 | 13 | ## 0.0.9 14 | 15 | - Version bump to match other packages 16 | 17 | ## 0.0.8 18 | 19 | - Version bump to match other packages 20 | 21 | ## 0.0.7 22 | 23 | - Require Flutter 3.29 and Dart 3.7 24 | 25 | ## 0.0.6 26 | 27 | - Version bump to match other packages 28 | 29 | ## 0.0.5 30 | 31 | - Version bump to match other packages 32 | 33 | ## 0.0.4 34 | 35 | - Version bump to match other packages 36 | 37 | ## 0.0.3 38 | 39 | - Version bump to match other packages 40 | 41 | ## 0.0.1 42 | 43 | - Initial release 44 | -------------------------------------------------------------------------------- /packages/flyer_chat_location_message/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Oleksandr Demchenko 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/flyer_chat_location_message/README.md: -------------------------------------------------------------------------------- 1 | # [Flyer Chat](https://flyer.chat) 💬 Location Message Widget (Planned) 2 | 3 | [![Pub Version](https://img.shields.io/pub/v/flyer_chat_location_message?logo=flutter&color=orange)](https://pub.dev/packages/flyer_chat_location_message) [![Stars](https://img.shields.io/github/stars/flyerhq/flutter_chat_ui?style=flat&color=orange&logo=github)](https://github.com/flyerhq/flutter_chat_ui/stargazers) [![melos](https://img.shields.io/badge/maintained%20with-melos-ffffff.svg?color=orange)](https://github.com/invertase/melos) 4 | 5 | **Note:** This package is planned but not yet implemented 🚧. 6 | 7 | This package will provide an opinionated location message widget for use with the [`flutter_chat_ui`](https://github.com/flyerhq/flutter_chat_ui/tree/main/packages/flutter_chat_ui) package. 8 | -------------------------------------------------------------------------------- /packages/flyer_chat_location_message/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: ../../analysis_options.yaml 2 | -------------------------------------------------------------------------------- /packages/flyer_chat_location_message/lib/flyer_chat_location_message.dart: -------------------------------------------------------------------------------- 1 | export 'src/flyer_chat_location_message.dart'; 2 | -------------------------------------------------------------------------------- /packages/flyer_chat_location_message/lib/src/flyer_chat_location_message.dart: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /packages/flyer_chat_location_message/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flyer_chat_location_message 2 | version: 0.0.12 3 | description: > 4 | Location message package for Flutter chat apps, complementing flutter_chat_ui. #chat #ui 5 | homepage: https://flyer.chat 6 | repository: https://github.com/flyerhq/flutter_chat_ui 7 | 8 | environment: 9 | sdk: ">=3.7.0 <4.0.0" 10 | flutter: ">=3.29.0" 11 | 12 | dependencies: 13 | flutter: 14 | sdk: flutter 15 | 16 | dev_dependencies: 17 | flutter_lints: ^5.0.0 18 | flutter_test: 19 | sdk: flutter 20 | -------------------------------------------------------------------------------- /packages/flyer_chat_system_message/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 2.1.9 2 | 3 | - Update a dependency to the latest release. 4 | 5 | ## 2.1.8 6 | 7 | - **FIX**: update documentation. ([2ec05db2](https://github.com/flyerhq/flutter_chat_ui/commit/2ec05db24f3fb469658a3fd3a27a7c3c739826e9)) 8 | - **FIX**: perf improvements ([#807](https://github.com/flyerhq/flutter_chat_ui/issues/807)). ([71e6d690](https://github.com/flyerhq/flutter_chat_ui/commit/71e6d69027d520c351b00c5e85e30cd97dabd321)) 9 | 10 | ## 2.1.7 11 | 12 | - Update a dependency to the latest release. 13 | 14 | ## 2.1.6 15 | 16 | - Update a dependency to the latest release. 17 | 18 | ## 2.1.5 19 | 20 | - Update a dependency to the latest release. 21 | 22 | ## 2.1.4 23 | 24 | - Update a dependency to the latest release. 25 | 26 | ## 2.1.3 27 | 28 | - Update a dependency to the latest release. 29 | 30 | ## 2.1.2 31 | 32 | - Update a dependency to the latest release. 33 | 34 | ## 2.1.1 35 | 36 | - Update a dependency to the latest release. 37 | 38 | ## 2.1.0 39 | 40 | - **FEAT**: rename chat controller methods. ([dc1bf57d](https://github.com/flyerhq/flutter_chat_ui/commit/dc1bf57d9b5f9655805589fdda5581759b9cc1a9)) 41 | 42 | ## 2.0.2 43 | 44 | - **FIX**: improve documentation and add example. ([113141b3](https://github.com/flyerhq/flutter_chat_ui/commit/113141b31de52a166eea54625f4cdd5b80bb897a)) 45 | 46 | ## 2.0.1 47 | 48 | - **FIX**: document public APIs. 49 | 50 | ## 2.0.0 51 | 52 | - First stable release 53 | 54 | ## 0.0.12 55 | 56 | **⚠️ Breaking Changes ⚠️** 57 | 58 | - The default sentinel values that previously allowed users to set specific properties to `null` have been removed. Instead, please use `Colors.transparent`, `BorderRadius.zero`, or `TextStyle()` to achieve the desired effect. Passing `null` will now use the standard configuration. 59 | 60 | ## 0.0.11 61 | 62 | - Version bump to match other packages 63 | 64 | ## 0.0.10 65 | 66 | - Version bump to match other packages 67 | 68 | ## 0.0.9 69 | 70 | - Added system message for displaying system notifications and events in chat 71 | 72 | ## 0.0.8 73 | 74 | - Version bump to match other packages 75 | 76 | ## 0.0.7 77 | 78 | - Require Flutter 3.29 and Dart 3.7 79 | 80 | ## 0.0.6 81 | 82 | - Version bump to match other packages 83 | 84 | ## 0.0.5 85 | 86 | - Version bump to match other packages 87 | 88 | ## 0.0.4 89 | 90 | - Version bump to match other packages 91 | 92 | ## 0.0.3 93 | 94 | - Version bump to match other packages 95 | 96 | ## 0.0.1 97 | 98 | - Initial release 99 | -------------------------------------------------------------------------------- /packages/flyer_chat_system_message/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Oleksandr Demchenko 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/flyer_chat_system_message/README.md: -------------------------------------------------------------------------------- 1 | # [Flyer Chat](https://flyer.chat) 💬 System Message Widget 2 | 3 | [![Pub Version](https://img.shields.io/pub/v/flyer_chat_system_message?logo=flutter&color=orange)](https://pub.dev/packages/flyer_chat_system_message) [![Stars](https://img.shields.io/github/stars/flyerhq/flutter_chat_ui?style=flat&color=orange&logo=github)](https://github.com/flyerhq/flutter_chat_ui/stargazers) [![melos](https://img.shields.io/badge/maintained%20with-melos-ffffff.svg?color=orange)](https://github.com/invertase/melos) 4 | 5 | This package provides an opinionated system message widget for use with the [`flutter_chat_ui`](https://github.com/flyerhq/flutter_chat_ui/tree/main/packages/flutter_chat_ui) package. 6 | 7 | ## Purpose 8 | 9 | This widget is designed specifically to render system messages (e.g., user joined/left) within a `flutter_chat_ui` implementation. It relies on models and themes provided by [`flutter_chat_core`](https://github.com/flyerhq/flutter_chat_ui/tree/main/packages/flutter_chat_core) and is not intended for standalone use outside the [Flyer Chat](https://flyer.chat) ecosystem. 10 | 11 | ## Installation 12 | 13 | Add this package to your `pubspec.yaml` alongside `flutter_chat_ui`: 14 | 15 | ```yaml 16 | dependencies: 17 | flutter_chat_ui: ^2.0.0 18 | flyer_chat_system_message: ^2.0.0 19 | ``` 20 | 21 | Then run `flutter pub get`. 22 | 23 | ## Usage 24 | 25 | ```dart 26 | import 'package:flutter_chat_ui/flutter_chat_ui.dart'; 27 | import 'package:flyer_chat_system_message/flyer_chat_system_message.dart'; 28 | 29 | Chat( 30 | builders: Builders( 31 | systemMessageBuilder: (context, message, index, { 32 | required bool isSentByMe, 33 | MessageGroupStatus? groupStatus, 34 | }) => 35 | FlyerChatSystemMessage(message: message, index: index), 36 | ), 37 | ); 38 | ``` 39 | 40 | ## License 41 | 42 | Licensed under the MIT License. See the [LICENSE](https://github.com/flyerhq/flutter_chat_ui/blob/main/packages/flyer_chat_system_message/LICENSE) file for details. 43 | -------------------------------------------------------------------------------- /packages/flyer_chat_system_message/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: ../../analysis_options.yaml 2 | -------------------------------------------------------------------------------- /packages/flyer_chat_system_message/example/README.md: -------------------------------------------------------------------------------- 1 | ```dart 2 | import 'dart:math'; 3 | 4 | import 'package:flutter/material.dart'; 5 | import 'package:flutter_chat_core/flutter_chat_core.dart'; 6 | import 'package:flutter_chat_ui/flutter_chat_ui.dart'; 7 | import 'package:flyer_chat_system_message/flyer_chat_system_message.dart'; 8 | 9 | class Basic extends StatefulWidget { 10 | const Basic({super.key}); 11 | 12 | @override 13 | BasicState createState() => BasicState(); 14 | } 15 | 16 | class BasicState extends State { 17 | final _chatController = InMemoryChatController(); 18 | 19 | @override 20 | void dispose() { 21 | _chatController.dispose(); 22 | super.dispose(); 23 | } 24 | 25 | @override 26 | Widget build(BuildContext context) { 27 | return Scaffold( 28 | body: Chat( 29 | builders: Builders( 30 | systemMessageBuilder: (context, message, index, { 31 | required bool isSentByMe, 32 | MessageGroupStatus? groupStatus, 33 | }) => 34 | FlyerChatSystemMessage(message: message, index: index), 35 | ), 36 | chatController: _chatController, 37 | currentUserId: 'user1', 38 | onMessageSend: (text) { 39 | _chatController.insertMessage( 40 | SystemMessage( 41 | // Better to use UUID or similar for the ID - IDs must be unique 42 | id: '${Random().nextInt(1000) + 1}', 43 | authorId: 'system', 44 | createdAt: DateTime.now().toUtc(), 45 | text: text, 46 | ), 47 | ); 48 | }, 49 | resolveUser: (UserID id) async { 50 | return User(id: id, name: 'John Doe'); 51 | }, 52 | ), 53 | ); 54 | } 55 | } 56 | 57 | ``` -------------------------------------------------------------------------------- /packages/flyer_chat_system_message/lib/flyer_chat_system_message.dart: -------------------------------------------------------------------------------- 1 | /// Flyer Chat System Message package. Provides a widget for system messages. 2 | library; 3 | 4 | export 'src/flyer_chat_system_message.dart'; 5 | -------------------------------------------------------------------------------- /packages/flyer_chat_system_message/lib/src/flyer_chat_system_message.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_chat_core/flutter_chat_core.dart'; 3 | import 'package:provider/provider.dart'; 4 | 5 | /// A widget that displays a system message, typically used for informational 6 | /// messages like "User joined the chat". 7 | class FlyerChatSystemMessage extends StatelessWidget { 8 | /// The system message data model. 9 | final SystemMessage message; 10 | 11 | /// The index of the message in the list. 12 | final int index; 13 | 14 | /// Padding around the message content. 15 | final EdgeInsetsGeometry? padding; 16 | 17 | /// Background color of the message container. 18 | final Color? backgroundColor; 19 | 20 | /// Text style for the system message. 21 | final TextStyle? textStyle; 22 | 23 | /// Creates a widget to display a system message. 24 | const FlyerChatSystemMessage({ 25 | super.key, 26 | required this.message, 27 | required this.index, 28 | this.padding = const EdgeInsets.symmetric(horizontal: 0, vertical: 4), 29 | this.backgroundColor, 30 | this.textStyle, 31 | }); 32 | 33 | @override 34 | Widget build(BuildContext context) { 35 | final theme = context.select( 36 | (ChatTheme t) => ( 37 | bodySmall: t.typography.bodySmall, 38 | onSurface: t.colors.onSurface, 39 | surfaceContainer: t.colors.surfaceContainer, 40 | ), 41 | ); 42 | final resolvedBackgroundColor = backgroundColor ?? theme.surfaceContainer; 43 | final resolvedTextStyle = 44 | textStyle ?? theme.bodySmall.copyWith(color: theme.onSurface); 45 | 46 | return Center( 47 | child: Container( 48 | width: double.infinity, 49 | padding: padding, 50 | decoration: BoxDecoration(color: resolvedBackgroundColor), 51 | child: Text( 52 | message.text, 53 | style: resolvedTextStyle, 54 | textAlign: TextAlign.center, 55 | ), 56 | ), 57 | ); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /packages/flyer_chat_system_message/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flyer_chat_system_message 2 | version: 2.1.9 3 | description: > 4 | System message package for Flutter chat apps, complementing flutter_chat_ui. #chat #ui 5 | homepage: https://flyer.chat 6 | repository: https://github.com/flyerhq/flutter_chat_ui 7 | 8 | environment: 9 | sdk: ">=3.7.0 <4.0.0" 10 | flutter: ">=3.29.0" 11 | 12 | dependencies: 13 | flutter: 14 | sdk: flutter 15 | flutter_chat_core: ^2.6.1 16 | provider: ^6.1.4 17 | 18 | dev_dependencies: 19 | flutter_lints: ^5.0.0 20 | flutter_test: 21 | sdk: flutter 22 | -------------------------------------------------------------------------------- /packages/flyer_chat_text_message/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Oleksandr Demchenko 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/flyer_chat_text_message/README.md: -------------------------------------------------------------------------------- 1 | # [Flyer Chat](https://flyer.chat) 💬 Text Message Widget 2 | 3 | [![Pub Version](https://img.shields.io/pub/v/flyer_chat_text_message?logo=flutter&color=orange)](https://pub.dev/packages/flyer_chat_text_message) [![Stars](https://img.shields.io/github/stars/flyerhq/flutter_chat_ui?style=flat&color=orange&logo=github)](https://github.com/flyerhq/flutter_chat_ui/stargazers) [![melos](https://img.shields.io/badge/maintained%20with-melos-ffffff.svg?color=orange)](https://github.com/invertase/melos) 4 | 5 | This package provides an opinionated text message widget for use with the [`flutter_chat_ui`](https://github.com/flyerhq/flutter_chat_ui/tree/main/packages/flutter_chat_ui) package. It includes support for markdown rendering. 6 | 7 | ## Purpose 8 | 9 | This widget is designed specifically to render text messages within a `flutter_chat_ui` implementation. It relies on models and themes provided by [`flutter_chat_core`](https://github.com/flyerhq/flutter_chat_ui/tree/main/packages/flutter_chat_core) and is not intended for standalone use outside the [Flyer Chat](https://flyer.chat) ecosystem. 10 | 11 | ## Installation 12 | 13 | Add this package to your `pubspec.yaml` alongside `flutter_chat_ui`: 14 | 15 | ```yaml 16 | dependencies: 17 | flutter_chat_ui: ^2.0.0 18 | flyer_chat_text_message: ^2.0.0 19 | ``` 20 | 21 | Then run `flutter pub get`. 22 | 23 | ## Usage 24 | 25 | ```dart 26 | import 'package:flutter_chat_ui/flutter_chat_ui.dart'; 27 | import 'package:flyer_chat_text_message/flyer_chat_text_message.dart'; 28 | 29 | Chat( 30 | builders: Builders( 31 | textMessageBuilder: (context, message, index, { 32 | required bool isSentByMe, 33 | MessageGroupStatus? groupStatus, 34 | }) => 35 | FlyerChatTextMessage(message: message, index: index), 36 | ), 37 | ); 38 | ``` 39 | 40 | ## License 41 | 42 | Licensed under the MIT License. See the [LICENSE](https://github.com/flyerhq/flutter_chat_ui/blob/main/packages/flyer_chat_text_message/LICENSE) file for details. 43 | -------------------------------------------------------------------------------- /packages/flyer_chat_text_message/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: ../../analysis_options.yaml 2 | -------------------------------------------------------------------------------- /packages/flyer_chat_text_message/example/README.md: -------------------------------------------------------------------------------- 1 | ```dart 2 | import 'dart:math'; 3 | 4 | import 'package:flutter/material.dart'; 5 | import 'package:flutter_chat_core/flutter_chat_core.dart'; 6 | import 'package:flutter_chat_ui/flutter_chat_ui.dart'; 7 | import 'package:flyer_chat_text_message/flyer_chat_text_message.dart'; 8 | 9 | class Basic extends StatefulWidget { 10 | const Basic({super.key}); 11 | 12 | @override 13 | BasicState createState() => BasicState(); 14 | } 15 | 16 | class BasicState extends State { 17 | final _chatController = InMemoryChatController(); 18 | 19 | @override 20 | void dispose() { 21 | _chatController.dispose(); 22 | super.dispose(); 23 | } 24 | 25 | @override 26 | Widget build(BuildContext context) { 27 | return Scaffold( 28 | body: Chat( 29 | builders: Builders( 30 | textMessageBuilder: (context, message, index, { 31 | required bool isSentByMe, 32 | MessageGroupStatus? groupStatus, 33 | }) => 34 | FlyerChatTextMessage(message: message, index: index), 35 | ), 36 | chatController: _chatController, 37 | currentUserId: 'user1', 38 | onMessageSend: (text) { 39 | _chatController.insertMessage( 40 | TextMessage( 41 | // Better to use UUID or similar for the ID - IDs must be unique 42 | id: '${Random().nextInt(1000) + 1}', 43 | authorId: 'user1', 44 | createdAt: DateTime.now().toUtc(), 45 | text: text, 46 | ), 47 | ); 48 | }, 49 | resolveUser: (UserID id) async { 50 | return User(id: id, name: 'John Doe'); 51 | }, 52 | ), 53 | ); 54 | } 55 | } 56 | 57 | ``` -------------------------------------------------------------------------------- /packages/flyer_chat_text_message/lib/flyer_chat_text_message.dart: -------------------------------------------------------------------------------- 1 | /// Flyer Chat Text Message package. Provides a widget for simple text messages. 2 | library; 3 | 4 | export 'src/flyer_chat_text_message.dart'; 5 | -------------------------------------------------------------------------------- /packages/flyer_chat_text_message/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flyer_chat_text_message 2 | version: 2.3.1 3 | description: > 4 | Text message package for Flutter chat apps, complementing flutter_chat_ui. #chat #ui 5 | homepage: https://flyer.chat 6 | repository: https://github.com/flyerhq/flutter_chat_ui 7 | 8 | environment: 9 | sdk: ">=3.7.0 <4.0.0" 10 | flutter: ">=3.29.0" 11 | 12 | dependencies: 13 | flutter: 14 | sdk: flutter 15 | flutter_chat_core: ^2.6.1 16 | gpt_markdown: ^1.0.16 17 | provider: ^6.1.4 18 | 19 | dev_dependencies: 20 | flutter_lints: ^5.0.0 21 | flutter_test: 22 | sdk: flutter 23 | -------------------------------------------------------------------------------- /packages/flyer_chat_text_stream_message/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 2.2.1 2 | 3 | - Update a dependency to the latest release. 4 | 5 | ## 2.2.0 6 | 7 | - **FIX**: introduce status field back ([#809](https://github.com/flyerhq/flutter_chat_ui/issues/809)). ([1aadf874](https://github.com/flyerhq/flutter_chat_ui/commit/1aadf8747d81672422a0e40363b0c2aeaa9e3efd)) 8 | - **FIX**: update documentation. ([2ec05db2](https://github.com/flyerhq/flutter_chat_ui/commit/2ec05db24f3fb469658a3fd3a27a7c3c739826e9)) 9 | - **FIX**: perf improvements ([#807](https://github.com/flyerhq/flutter_chat_ui/issues/807)). ([71e6d690](https://github.com/flyerhq/flutter_chat_ui/commit/71e6d69027d520c351b00c5e85e30cd97dabd321)) 10 | - **FEAT**: time and status grouping same minute fix [#764](https://github.com/flyerhq/flutter_chat_ui/issues/764) ([#792](https://github.com/flyerhq/flutter_chat_ui/issues/792)). ([61c04002](https://github.com/flyerhq/flutter_chat_ui/commit/61c04002153897113f47c239e059511b1e3468ec)) 11 | 12 | ## 2.1.7 13 | 14 | - Update a dependency to the latest release. 15 | 16 | ## 2.1.6 17 | 18 | - Update a dependency to the latest release. 19 | 20 | ## 2.1.5 21 | 22 | - Update a dependency to the latest release. 23 | 24 | ## 2.1.4 25 | 26 | - Update a dependency to the latest release. 27 | 28 | ## 2.1.3 29 | 30 | - Update a dependency to the latest release. 31 | 32 | ## 2.1.2 33 | 34 | - Update a dependency to the latest release. 35 | 36 | ## 2.1.1 37 | 38 | - Update a dependency to the latest release. 39 | 40 | ## 2.1.0 41 | 42 | - **FEAT**: rename chat controller methods. ([dc1bf57d](https://github.com/flyerhq/flutter_chat_ui/commit/dc1bf57d9b5f9655805589fdda5581759b9cc1a9)) 43 | 44 | ## 2.0.4 45 | 46 | - Update a dependency to the latest release. 47 | 48 | ## 2.0.3 49 | 50 | - **FIX**: add example. ([77c55e82](https://github.com/flyerhq/flutter_chat_ui/commit/77c55e829ebac99a0e7c754258b7e4f39767ca9e)) 51 | 52 | ## 2.0.2 53 | 54 | - **FIX**: improve documentation. ([19ce9641](https://github.com/flyerhq/flutter_chat_ui/commit/19ce9641d341cd297cd83219e989914e7bc78af0)) 55 | 56 | ## 2.0.1 57 | 58 | - **FIX**: document public APIs. 59 | 60 | ## 2.0.0 61 | 62 | - First stable release 63 | 64 | ## 0.0.12 65 | 66 | - Initial release 67 | -------------------------------------------------------------------------------- /packages/flyer_chat_text_stream_message/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Oleksandr Demchenko 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/flyer_chat_text_stream_message/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: ../../analysis_options.yaml 2 | -------------------------------------------------------------------------------- /packages/flyer_chat_text_stream_message/example/README.md: -------------------------------------------------------------------------------- 1 | ```dart 2 | import 'dart:math'; 3 | 4 | import 'package:flutter/material.dart'; 5 | import 'package:flutter_chat_core/flutter_chat_core.dart'; 6 | import 'package:flutter_chat_ui/flutter_chat_ui.dart'; 7 | import 'package:flyer_chat_text_stream_message/flyer_chat_text_stream_message.dart'; 8 | 9 | class Basic extends StatefulWidget { 10 | const Basic({super.key}); 11 | 12 | @override 13 | BasicState createState() => BasicState(); 14 | } 15 | 16 | class BasicState extends State { 17 | final _chatController = InMemoryChatController(); 18 | 19 | @override 20 | void dispose() { 21 | _chatController.dispose(); 22 | super.dispose(); 23 | } 24 | 25 | @override 26 | Widget build(BuildContext context) { 27 | return Scaffold( 28 | body: Chat( 29 | builders: Builders( 30 | textStreamMessageBuilder: (context, message, index, { 31 | required bool isSentByMe, 32 | MessageGroupStatus? groupStatus, 33 | }) { 34 | // To see a practical implementation of the stream manager, check the main example app at 35 | // https://github.com/flyerhq/flutter_chat_ui/tree/main/examples/flyer_chat 36 | final streamState = context.watch().getState( 37 | message.streamId, 38 | ); 39 | // Return the stream message widget, passing the state 40 | return FlyerChatTextStreamMessage( 41 | message: message, 42 | index: index, 43 | streamState: streamState, 44 | ); 45 | }, 46 | ), 47 | chatController: _chatController, 48 | currentUserId: 'user1', 49 | onMessageSend: (text) { 50 | _chatController.insertMessage( 51 | // For a comprehensive example of how to implement the stream manager and work with streamIds, refer to the main example application available at 52 | // https://github.com/flyerhq/flutter_chat_ui/tree/main/examples/flyer_chat 53 | TextStreamMessage( 54 | id: streamId, 55 | authorId: 'agent1', 56 | createdAt: DateTime.now().toUtc(), 57 | streamId: streamId, 58 | ) 59 | ); 60 | }, 61 | resolveUser: (UserID id) async { 62 | return User(id: id, name: 'John Doe'); 63 | }, 64 | ), 65 | ); 66 | } 67 | } 68 | 69 | ``` -------------------------------------------------------------------------------- /packages/flyer_chat_text_stream_message/lib/flyer_chat_text_stream_message.dart: -------------------------------------------------------------------------------- 1 | /// Flyer Chat Text Stream Message package. Provides a widget for streamed text messages. 2 | library; 3 | 4 | export 'src/flyer_chat_text_stream_message.dart'; 5 | export 'src/stream_state.dart'; 6 | export 'src/text_segment.dart'; 7 | -------------------------------------------------------------------------------- /packages/flyer_chat_text_stream_message/lib/src/stream_state.dart: -------------------------------------------------------------------------------- 1 | /// Represents the state of a streaming text message. 2 | /// 3 | /// This state should be managed externally (e.g., using a dedicated manager 4 | /// like [GeminiStreamManager] in the example app) and provided to the 5 | /// [FlyerChatTextStreamMessage] widget. 6 | sealed class StreamState { 7 | /// Creates a constant [StreamState]. 8 | const StreamState(); 9 | } 10 | 11 | /// Initial state before any data arrives or completion/error occurs. 12 | /// 13 | /// The UI typically shows a loading indicator in this state. 14 | class StreamStateLoading extends StreamState { 15 | /// Creates a constant [StreamStateLoading]. 16 | const StreamStateLoading(); 17 | } 18 | 19 | /// State while the stream is actively receiving chunks. 20 | class StreamStateStreaming extends StreamState { 21 | /// The full text accumulated so far, including all received chunks. 22 | final String accumulatedText; 23 | 24 | /// Creates a [StreamStateStreaming] with the current accumulated text. 25 | const StreamStateStreaming(this.accumulatedText); 26 | } 27 | 28 | /// State when the stream has finished successfully. 29 | /// 30 | /// The UI might display the final text or transition to a regular 31 | /// `TextMessage` depending on the external manager's implementation. 32 | class StreamStateCompleted extends StreamState { 33 | /// The final, complete text content received from the stream. 34 | final String finalText; 35 | 36 | /// Creates a [StreamStateCompleted] with the final text. 37 | const StreamStateCompleted(this.finalText); 38 | } 39 | 40 | /// State when the stream encountered an error during generation. 41 | /// 42 | /// The UI might display the partial text along with an error indicator, 43 | /// or transition to a `TextMessage` indicating the error. 44 | class StreamStateError extends StreamState { 45 | /// The error object that caused the stream to fail. 46 | final Object error; 47 | 48 | /// Text accumulated before the error occurred (optional). 49 | /// 50 | /// This can be useful for displaying partial results. 51 | final String? accumulatedText; 52 | 53 | /// Creates a [StreamStateError]. 54 | const StreamStateError(this.error, {this.accumulatedText}); 55 | } 56 | -------------------------------------------------------------------------------- /packages/flyer_chat_text_stream_message/lib/src/text_segment.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/animation.dart'; 2 | 3 | /// Represents a segment of text within the streaming message display. 4 | /// Used internally by [FlyerChatTextStreamMessage] when using the 5 | /// [TextStreamMessageMode.animatedOpacity] mode. 6 | sealed class TextSegment { 7 | /// The text content of this segment. 8 | final String text; 9 | 10 | /// Creates a constant text segment. 11 | const TextSegment(this.text); 12 | } 13 | 14 | /// A segment of text that is static and fully visible. 15 | class StaticSegment extends TextSegment { 16 | /// Creates a static text segment with the given [text]. 17 | StaticSegment(super.text); 18 | } 19 | 20 | /// A segment of text that is currently animating (fading in). 21 | class AnimatingSegment extends TextSegment { 22 | /// The animation controller driving the fade-in effect. 23 | final AnimationController controller; 24 | 25 | /// The fade animation, typically ranging from 0.0 to 1.0. 26 | final Animation fadeAnimation; 27 | 28 | /// Creates an animating text segment. 29 | AnimatingSegment(super.text, this.controller, this.fadeAnimation); 30 | 31 | /// Disposes the associated animation controller. 32 | void dispose() { 33 | controller.dispose(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /packages/flyer_chat_text_stream_message/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flyer_chat_text_stream_message 2 | version: 2.2.1 3 | description: > 4 | Text stream message package for Flutter chat apps, complementing flutter_chat_ui. #chat #ui 5 | homepage: https://flyer.chat 6 | repository: https://github.com/flyerhq/flutter_chat_ui 7 | 8 | environment: 9 | sdk: ">=3.7.0 <4.0.0" 10 | flutter: ">=3.29.0" 11 | 12 | dependencies: 13 | flutter: 14 | sdk: flutter 15 | flutter_chat_core: ^2.6.1 16 | gpt_markdown: ^1.0.16 17 | provider: ^6.1.4 18 | 19 | dev_dependencies: 20 | flutter_lints: ^5.0.0 21 | flutter_test: 22 | sdk: flutter 23 | -------------------------------------------------------------------------------- /packages/flyer_chat_video_message/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.0.12 2 | 3 | - Version bump to match other packages 4 | 5 | ## 0.0.11 6 | 7 | - Version bump to match other packages 8 | 9 | ## 0.0.10 10 | 11 | - Version bump to match other packages 12 | 13 | ## 0.0.9 14 | 15 | - Version bump to match other packages 16 | 17 | ## 0.0.8 18 | 19 | - Version bump to match other packages 20 | 21 | ## 0.0.7 22 | 23 | - Require Flutter 3.29 and Dart 3.7 24 | 25 | ## 0.0.6 26 | 27 | - Version bump to match other packages 28 | 29 | ## 0.0.5 30 | 31 | - Version bump to match other packages 32 | 33 | ## 0.0.4 34 | 35 | - Version bump to match other packages 36 | 37 | ## 0.0.3 38 | 39 | - Version bump to match other packages 40 | 41 | ## 0.0.1 42 | 43 | - Initial release 44 | -------------------------------------------------------------------------------- /packages/flyer_chat_video_message/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Oleksandr Demchenko 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/flyer_chat_video_message/README.md: -------------------------------------------------------------------------------- 1 | # [Flyer Chat](https://flyer.chat) 💬 Video Message Widget (Planned) 2 | 3 | [![Pub Version](https://img.shields.io/pub/v/flyer_chat_video_message?logo=flutter&color=orange)](https://pub.dev/packages/flyer_chat_video_message) [![Stars](https://img.shields.io/github/stars/flyerhq/flutter_chat_ui?style=flat&color=orange&logo=github)](https://github.com/flyerhq/flutter_chat_ui/stargazers) [![melos](https://img.shields.io/badge/maintained%20with-melos-ffffff.svg?color=orange)](https://github.com/invertase/melos) 4 | 5 | **Note:** This package is planned but not yet implemented 🚧. 6 | 7 | This package will provide an opinionated video message widget for use with the [`flutter_chat_ui`](https://github.com/flyerhq/flutter_chat_ui/tree/main/packages/flutter_chat_ui) package. 8 | -------------------------------------------------------------------------------- /packages/flyer_chat_video_message/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: ../../analysis_options.yaml 2 | -------------------------------------------------------------------------------- /packages/flyer_chat_video_message/lib/flyer_chat_video_message.dart: -------------------------------------------------------------------------------- 1 | export 'src/flyer_chat_video_message.dart'; 2 | -------------------------------------------------------------------------------- /packages/flyer_chat_video_message/lib/src/flyer_chat_video_message.dart: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /packages/flyer_chat_video_message/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flyer_chat_video_message 2 | version: 0.0.12 3 | description: > 4 | Video message package for Flutter chat apps, complementing flutter_chat_ui. #chat #ui 5 | homepage: https://flyer.chat 6 | repository: https://github.com/flyerhq/flutter_chat_ui 7 | 8 | environment: 9 | sdk: ">=3.7.0 <4.0.0" 10 | flutter: ">=3.29.0" 11 | 12 | dependencies: 13 | flutter: 14 | sdk: flutter 15 | 16 | dev_dependencies: 17 | flutter_lints: ^5.0.0 18 | flutter_test: 19 | sdk: flutter 20 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: chat 2 | 3 | environment: 4 | sdk: ">=3.7.0 <4.0.0" 5 | dev_dependencies: 6 | flutter_lints: ^5.0.0 7 | melos: ^6.3.2 8 | --------------------------------------------------------------------------------