Merge branch 'develop' into ISSUE-1456/SendingMessageIndicatorFix
This commit is contained in:
@@ -50,7 +50,7 @@ pubspec.lock
|
||||
# If you don't generate documentation locally you can remove this line.
|
||||
doc/api/
|
||||
|
||||
# Avoid committing generated Javascript files:
|
||||
# Avoid committing generated JavaScript files:
|
||||
*.dart.js
|
||||
*.info.json # Produced by the --dump-info flag.
|
||||
*.js # When generated by dart2js. Don't specify *.js if your
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
- [#1456](https://github.com/GetStream/stream-chat-flutter/issues/1456) Fixed logic for showing that a message was read using sending indicator.
|
||||
- [#1462](https://github.com/GetStream/stream-chat-flutter/issues/1462) Fixed support for iPad in the share button for images.
|
||||
- [#1475](https://github.com/GetStream/stream-chat-flutter/issues/1475) Fixed typo to fix compilation.
|
||||
|
||||
✅ Added
|
||||
|
||||
@@ -12,7 +13,11 @@
|
||||
|
||||
🔄 Changed
|
||||
|
||||
- Updated `share_plus` dependency to `^6.3.0`
|
||||
- Updated dependencies to resolvable versions.
|
||||
|
||||
🚀 Improved
|
||||
-
|
||||
- Improved draw of reaction options. [#1455](https://github.com/GetStream/stream-chat-flutter/pull/1455)
|
||||
|
||||
## 5.3.0
|
||||
|
||||
@@ -82,7 +87,7 @@
|
||||
✅ Added
|
||||
|
||||
- Added `StreamMemberGridView` and `StreamMemberListView`.
|
||||
- Added support for additional text field params in `StreamMessageInput`
|
||||
- Added support for additional text field parameters in `StreamMessageInput`
|
||||
* `maxLines`
|
||||
* `minLines`
|
||||
* `textInputAction`
|
||||
@@ -267,7 +272,7 @@
|
||||
- Fix commands resetting the `StreamMessageInputController.value`.
|
||||
- [[#996]](https://github.com/GetStream/stream-chat-flutter/issues/996) Videos break bottom photo
|
||||
carousal.
|
||||
- Fix: URLs with path and/or query params are not enriched.
|
||||
- Fix: URLs with path and/or query parameters are not enriched.
|
||||
- [[#1194]](https://github.com/GetStream/stream-chat-flutter/issues/1194) Request permission to
|
||||
access gallery when opening the file picker.
|
||||
|
||||
@@ -931,11 +936,11 @@ typedef MessageBuilder = Widget Function(
|
||||
## 1.0.0-beta
|
||||
|
||||
- **Refreshed widgets design**
|
||||
- Improved api documentation
|
||||
- Improved API documentation
|
||||
- Updated `stream_chat` dependency to `^1.0.0-beta`
|
||||
- Extracted sample app into dedicated [repo](https://github.com/GetStream/flutter-samples)
|
||||
- Reimplemented existing widgets
|
||||
using [stream_chat_flutter_core](https://pub.dev/packages/stream_chat_flutter_core)
|
||||
- Extracted sample app into dedicated [repository](https://github.com/GetStream/flutter-samples)
|
||||
- Re-implemented existing widgets
|
||||
using [`stream_chat_flutter_core`](https://pub.dev/packages/stream_chat_flutter_core)
|
||||
|
||||
## 0.2.21
|
||||
|
||||
@@ -944,7 +949,7 @@ typedef MessageBuilder = Widget Function(
|
||||
|
||||
## 0.2.20+4
|
||||
|
||||
- Fix channelPreview when the message list is empty
|
||||
- Fix `channelPreview` when the message list is empty
|
||||
|
||||
## 0.2.20+3
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ It teaches you how to use this SDK and also shows how to make frequently require
|
||||
|
||||
## Example App
|
||||
|
||||
This repo includes a fully functional example app with setup instructions.
|
||||
This repository includes a fully functional example app with setup instructions.
|
||||
The example is available under the [example](https://github.com/GetStream/stream-chat-flutter/tree/master/packages/stream_chat_flutter/example) folder.
|
||||
|
||||
## Add dependency
|
||||
@@ -46,7 +46,7 @@ You should then run `flutter packages get`
|
||||
|
||||
### Android
|
||||
|
||||
The package uses [photo_manager](https://pub.dev/packages/photo_manager) to access the device's photo library.
|
||||
The package uses [`photo_manager`](https://pub.dev/packages/photo_manager) to access the device's photo library.
|
||||
Follow [this wiki](https://pub.dev/packages/photo_manager#android-10-q-29) to fulfil the Android requirements.
|
||||
You need to take additional steps if you are targeting Android 13. Read [this section](https://pub.dev/packages/photo_manager#android-13-api-33-extra-configs) for more information.
|
||||
|
||||
@@ -56,9 +56,9 @@ The library uses [flutter file picker plugin](https://github.com/miguelpruivo/fl
|
||||
files from the os.
|
||||
Follow [this wiki](https://github.com/miguelpruivo/flutter_file_picker/wiki/Setup#ios) to fulfill iOS requirements.
|
||||
|
||||
We also use [video_player](https://pub.dev/packages/video_player) to reproduce videos. Follow [this guide](https://pub.dev/packages/video_player#installation) to fulfill the requirements.
|
||||
We also use [`video_player`](https://pub.dev/packages/video_player) to reproduce videos. Follow [this guide](https://pub.dev/packages/video_player#installation) to fulfill the requirements.
|
||||
|
||||
To pick images from the camera, we use the [image_picker](https://pub.dev/packages/image_picker) plugin.
|
||||
To pick images from the camera, we use the [`image_picker`](https://pub.dev/packages/image_picker) plugin.
|
||||
Follow [these instructions](https://pub.dev/packages/image_picker#ios) to check the requirements.
|
||||
|
||||
### Web
|
||||
@@ -71,7 +71,7 @@ For the web, edit your `index.html` and add the following in the `<body>` tag in
|
||||
|
||||
### MacOS
|
||||
|
||||
For MacOS use the [file_selector](https://pub.dev/packages/file_selector#macos) package.
|
||||
For MacOS use the [`file_selector`](https://pub.dev/packages/file_selector#macos) package.
|
||||
Follow [these instructions](https://pub.dev/packages/file_selector#macos) to check the requirements.
|
||||
|
||||
You also need to add the following [entitlement](https://docs.flutter.dev/development/platform-integration/desktop#entitlements-and-the-app-sandbox):
|
||||
@@ -89,8 +89,8 @@ If it seems related to the [flutter file picker plugin](https://github.com/migue
|
||||
## Docs
|
||||
|
||||
This package provides UI components required for integrating Stream Chat into your application.
|
||||
Alternatively, you may use the core package [stream_chat_flutter_core](https://github.com/GetStream/stream-chat-flutter/tree/master/packages/stream_chat_flutter_core) which allows more customisation and provides business logic but no UI components.
|
||||
If you require the maximum amount of control over the API, please use the low level client package: [stream_chat](https://github.com/GetStream/stream-chat-flutter/tree/master/packages/stream_chat).
|
||||
Alternatively, you may use the core package [`stream_chat_flutter_core`](https://github.com/GetStream/stream-chat-flutter/tree/master/packages/stream_chat_flutter_core) which allows more customisation and provides business logic but no UI components.
|
||||
If you require the maximum amount of control over the API, please use the low level client package: [`stream_chat`](https://github.com/GetStream/stream-chat-flutter/tree/master/packages/stream_chat).
|
||||
|
||||
### UI Components
|
||||
|
||||
@@ -176,7 +176,7 @@ Out of the box, all chat widgets use their default styling, and there are two wa
|
||||
|
||||
### Offline storage
|
||||
|
||||
To add data persistance you can extend the class `ChatPersistenceClient` and pass an instance to the `StreamChatClient`.
|
||||
To add data persistence you can extend the class `ChatPersistenceClient` and pass an instance to the `StreamChatClient`.
|
||||
|
||||
```dart
|
||||
class CustomChatPersistentClient extends ChatPersistenceClient {
|
||||
@@ -208,7 +208,7 @@ final client = StreamChatClient(
|
||||
## Contributing
|
||||
|
||||
We welcome code changes that improve this library or fix a problem,
|
||||
please make sure to follow all best practices and add tests if applicable before submitting a Pull Request on Github.
|
||||
please make sure to follow all best practices and add tests if applicable before submitting a Pull Request on GitHub.
|
||||
We are pleased to merge your code into the official repository.
|
||||
Make sure to sign our [Contributor License Agreement (CLA)](https://docs.google.com/forms/d/e/1FAIpQLScFKsKkAJI7mhCr7K9rEIOpqIDThrWxuvxnwUq2XkHyG154vQ/viewform) first.
|
||||
See our license file for more details.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 51;
|
||||
objectVersion = 54;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
@@ -199,6 +199,7 @@
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
alwaysOutOfDate = 1;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
@@ -235,6 +236,7 @@
|
||||
};
|
||||
9740EEB61CF901F6004384FC /* Run Script */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
alwaysOutOfDate = 1;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
|
||||
@@ -61,5 +61,7 @@
|
||||
<string>Explain why your app uses the mic</string>
|
||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||
<true/>
|
||||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -177,7 +177,7 @@ class _SplitViewState extends State<SplitView> {
|
||||
: Center(
|
||||
child: Text(
|
||||
'Pick a channel to show the messages 💬',
|
||||
style: Theme.of(context).textTheme.headline5,
|
||||
style: Theme.of(context).textTheme.headlineSmall,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -78,7 +78,7 @@ class _SplitViewState extends State<SplitView> {
|
||||
: Center(
|
||||
child: Text(
|
||||
'Pick a channel to show the messages 💬',
|
||||
style: Theme.of(context).textTheme.headline5,
|
||||
style: Theme.of(context).textTheme.headlineSmall,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -21,7 +21,7 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||
///
|
||||
/// - We set up the Chat [StreamChatClient] with the API key
|
||||
///
|
||||
/// - We set the the current user for Chat with [StreamChatClient.connectUser]
|
||||
/// - We set the current user for Chat with [StreamChatClient.connectUser]
|
||||
/// and a pre-generated user token
|
||||
///
|
||||
/// - We make [StreamChat] the root Widget of our application
|
||||
|
||||
@@ -8,10 +8,9 @@
|
||||
|
||||
#include <dart_vlc/dart_vlc_plugin.h>
|
||||
#include <desktop_drop/desktop_drop_plugin.h>
|
||||
#include <screen_retriever/screen_retriever_plugin.h>
|
||||
#include <file_selector_linux/file_selector_plugin.h>
|
||||
#include <sqlite3_flutter_libs/sqlite3_flutter_libs_plugin.h>
|
||||
#include <url_launcher_linux/url_launcher_plugin.h>
|
||||
#include <window_manager/window_manager_plugin.h>
|
||||
|
||||
void fl_register_plugins(FlPluginRegistry* registry) {
|
||||
g_autoptr(FlPluginRegistrar) dart_vlc_registrar =
|
||||
@@ -20,16 +19,13 @@ void fl_register_plugins(FlPluginRegistry* registry) {
|
||||
g_autoptr(FlPluginRegistrar) desktop_drop_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "DesktopDropPlugin");
|
||||
desktop_drop_plugin_register_with_registrar(desktop_drop_registrar);
|
||||
g_autoptr(FlPluginRegistrar) screen_retriever_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "ScreenRetrieverPlugin");
|
||||
screen_retriever_plugin_register_with_registrar(screen_retriever_registrar);
|
||||
g_autoptr(FlPluginRegistrar) file_selector_linux_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin");
|
||||
file_selector_plugin_register_with_registrar(file_selector_linux_registrar);
|
||||
g_autoptr(FlPluginRegistrar) sqlite3_flutter_libs_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "Sqlite3FlutterLibsPlugin");
|
||||
sqlite3_flutter_libs_plugin_register_with_registrar(sqlite3_flutter_libs_registrar);
|
||||
g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
|
||||
url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);
|
||||
g_autoptr(FlPluginRegistrar) window_manager_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "WindowManagerPlugin");
|
||||
window_manager_plugin_register_with_registrar(window_manager_registrar);
|
||||
}
|
||||
|
||||
@@ -5,10 +5,9 @@
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
dart_vlc
|
||||
desktop_drop
|
||||
screen_retriever
|
||||
file_selector_linux
|
||||
sqlite3_flutter_libs
|
||||
url_launcher_linux
|
||||
window_manager
|
||||
)
|
||||
|
||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 51;
|
||||
objectVersion = 54;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXAggregateTarget section */
|
||||
@@ -203,7 +203,7 @@
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 0920;
|
||||
LastUpgradeCheck = 0930;
|
||||
LastUpgradeCheck = 1300;
|
||||
ORGANIZATIONNAME = "";
|
||||
TargetAttributes = {
|
||||
33CC10EC2044A3C60003C045 = {
|
||||
@@ -256,6 +256,7 @@
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
3399D490228B24CF009A79C7 /* ShellScript */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
alwaysOutOfDate = 1;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
@@ -404,7 +405,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.11;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.14;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = macosx;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
@@ -484,7 +485,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.11;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.14;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = macosx;
|
||||
@@ -531,7 +532,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.11;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.14;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = macosx;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1000"
|
||||
LastUpgradeVersion = "1300"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
||||
@@ -19,6 +19,7 @@ version: 1.0.0+1
|
||||
|
||||
environment:
|
||||
sdk: '>=2.17.0 <3.0.0'
|
||||
flutter: ">=1.17.0"
|
||||
|
||||
dependencies:
|
||||
# The following adds the Cupertino Icons font to your application.
|
||||
@@ -27,7 +28,7 @@ dependencies:
|
||||
cupertino_icons: ^1.0.4
|
||||
flutter:
|
||||
sdk: flutter
|
||||
responsive_builder: ^0.4.2
|
||||
responsive_builder: ^0.6.4
|
||||
stream_chat_flutter:
|
||||
path: ../
|
||||
stream_chat_localizations:
|
||||
|
||||
+4
-10
@@ -6,16 +6,14 @@
|
||||
|
||||
#include "generated_plugin_registrant.h"
|
||||
|
||||
#include <connectivity_plus_windows/connectivity_plus_windows_plugin.h>
|
||||
#include <connectivity_plus/connectivity_plus_windows_plugin.h>
|
||||
#include <dart_vlc/dart_vlc_plugin.h>
|
||||
#include <desktop_drop/desktop_drop_plugin.h>
|
||||
#include <file_selector_windows/file_selector_windows.h>
|
||||
#include <flutter_native_view/flutter_native_view_plugin.h>
|
||||
#include <screen_retriever/screen_retriever_plugin.h>
|
||||
#include <share_plus/share_plus_windows_plugin_c_api.h>
|
||||
#include <sqlite3_flutter_libs/sqlite3_flutter_libs_plugin.h>
|
||||
#include <thumblr_windows/thumblr_windows_plugin.h>
|
||||
#include <url_launcher_windows/url_launcher_windows.h>
|
||||
#include <window_manager/window_manager_plugin.h>
|
||||
|
||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||
ConnectivityPlusWindowsPluginRegisterWithRegistrar(
|
||||
@@ -26,16 +24,12 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||
registry->GetRegistrarForPlugin("DesktopDropPlugin"));
|
||||
FileSelectorWindowsRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("FileSelectorWindows"));
|
||||
FlutterNativeViewPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("FlutterNativeViewPlugin"));
|
||||
ScreenRetrieverPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("ScreenRetrieverPlugin"));
|
||||
SharePlusWindowsPluginCApiRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("SharePlusWindowsPluginCApi"));
|
||||
Sqlite3FlutterLibsPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("Sqlite3FlutterLibsPlugin"));
|
||||
ThumblrWindowsPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("ThumblrWindowsPlugin"));
|
||||
UrlLauncherWindowsRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("UrlLauncherWindows"));
|
||||
WindowManagerPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("WindowManagerPlugin"));
|
||||
}
|
||||
|
||||
@@ -3,16 +3,14 @@
|
||||
#
|
||||
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
connectivity_plus_windows
|
||||
connectivity_plus
|
||||
dart_vlc
|
||||
desktop_drop
|
||||
file_selector_windows
|
||||
flutter_native_view
|
||||
screen_retriever
|
||||
share_plus
|
||||
sqlite3_flutter_libs
|
||||
thumblr_windows
|
||||
url_launcher_windows
|
||||
window_manager
|
||||
)
|
||||
|
||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||
|
||||
@@ -162,8 +162,8 @@ class StreamChannelHeader extends StatelessWidget
|
||||
showMessage: showConnectionStateTile && showStatus,
|
||||
message: statusString,
|
||||
child: AppBar(
|
||||
toolbarTextStyle: theme.textTheme.bodyText2,
|
||||
titleTextStyle: theme.textTheme.headline6,
|
||||
toolbarTextStyle: theme.textTheme.bodyMedium,
|
||||
titleTextStyle: theme.textTheme.titleLarge,
|
||||
systemOverlayStyle: theme.brightness == Brightness.dark
|
||||
? SystemUiOverlayStyle.light
|
||||
: SystemUiOverlayStyle.dark,
|
||||
|
||||
@@ -131,8 +131,8 @@ class StreamChannelListHeader extends StatelessWidget
|
||||
showMessage: showConnectionStateTile && showStatus,
|
||||
message: statusString,
|
||||
child: AppBar(
|
||||
toolbarTextStyle: theme.textTheme.bodyText2,
|
||||
titleTextStyle: theme.textTheme.headline6,
|
||||
toolbarTextStyle: theme.textTheme.bodyMedium,
|
||||
titleTextStyle: theme.textTheme.titleLarge,
|
||||
systemOverlayStyle: theme.brightness == Brightness.dark
|
||||
? SystemUiOverlayStyle.light
|
||||
: SystemUiOverlayStyle.dark,
|
||||
@@ -181,7 +181,10 @@ class StreamChannelListHeader extends StatelessWidget
|
||||
package: 'stream_chat_flutter',
|
||||
width: 24,
|
||||
height: 24,
|
||||
color: color,
|
||||
colorFilter: ColorFilter.mode(
|
||||
color,
|
||||
BlendMode.srcIn,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
|
||||
@@ -80,8 +80,8 @@ class StreamGalleryHeader extends StatelessWidget
|
||||
final galleryHeaderThemeData = StreamGalleryHeaderTheme.of(context);
|
||||
final theme = Theme.of(context);
|
||||
return AppBar(
|
||||
toolbarTextStyle: theme.textTheme.bodyText2,
|
||||
titleTextStyle: theme.textTheme.headline6,
|
||||
toolbarTextStyle: theme.textTheme.bodyMedium,
|
||||
titleTextStyle: theme.textTheme.titleLarge,
|
||||
systemOverlayStyle: theme.brightness == Brightness.dark
|
||||
? SystemUiOverlayStyle.light
|
||||
: SystemUiOverlayStyle.dark,
|
||||
|
||||
+8
-115
@@ -2,6 +2,7 @@ import 'dart:ui';
|
||||
|
||||
import 'package:flutter/material.dart' hide ButtonStyle;
|
||||
import 'package:stream_chat_flutter/src/message_actions_modal/mam_widgets.dart';
|
||||
import 'package:stream_chat_flutter/src/message_widget/reactions/reactions_align.dart';
|
||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||
|
||||
/// {@template messageActionsModal}
|
||||
@@ -97,34 +98,12 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
|
||||
|
||||
Widget _showMessageOptionsModal() {
|
||||
final mediaQueryData = MediaQuery.of(context);
|
||||
final size = mediaQueryData.size;
|
||||
final user = StreamChat.of(context).currentUser;
|
||||
final orientation = mediaQueryData.orientation;
|
||||
|
||||
final roughMaxSize = size.width * 2 / 3;
|
||||
var messageTextLength = widget.message.text!.length;
|
||||
if (widget.message.quotedMessage != null) {
|
||||
var quotedMessageLength =
|
||||
(widget.message.quotedMessage!.text?.length ?? 0) + 40;
|
||||
if (widget.message.quotedMessage!.attachments.isNotEmpty) {
|
||||
quotedMessageLength += 40;
|
||||
}
|
||||
if (quotedMessageLength > messageTextLength) {
|
||||
messageTextLength = quotedMessageLength;
|
||||
}
|
||||
}
|
||||
final roughSentenceSize = messageTextLength *
|
||||
(widget.messageTheme.messageTextStyle?.fontSize ?? 1) *
|
||||
1.2;
|
||||
final divFactor = widget.message.attachments.isNotEmpty
|
||||
? 1
|
||||
: (roughSentenceSize == 0 ? 1 : (roughSentenceSize / roughMaxSize));
|
||||
|
||||
final fontSize = widget.messageTheme.messageTextStyle?.fontSize;
|
||||
final streamChatThemeData = StreamChatTheme.of(context);
|
||||
|
||||
final numberOfReactions =
|
||||
StreamChatConfiguration.of(context).reactionIcons.length;
|
||||
final shiftFactor =
|
||||
numberOfReactions < 5 ? (5 - numberOfReactions) * 0.1 : 0.0;
|
||||
final channel = StreamChannel.of(context).channel;
|
||||
|
||||
final child = Center(
|
||||
@@ -142,11 +121,12 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
|
||||
builder: (context, constraints) {
|
||||
return Align(
|
||||
alignment: Alignment(
|
||||
_calculateReactionsHorizontalAlignmentValue(
|
||||
calculateReactionsHorizontalAlignment(
|
||||
user,
|
||||
divFactor,
|
||||
shiftFactor,
|
||||
widget.message,
|
||||
constraints,
|
||||
fontSize,
|
||||
orientation,
|
||||
),
|
||||
0,
|
||||
),
|
||||
@@ -156,7 +136,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
|
||||
);
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
const SizedBox(height: 10),
|
||||
IgnorePointer(
|
||||
child: widget.messageWidget,
|
||||
),
|
||||
@@ -281,93 +261,6 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
|
||||
);
|
||||
}
|
||||
|
||||
double _calculateReactionsHorizontalAlignmentValue(
|
||||
User? user,
|
||||
num divFactor,
|
||||
double shiftFactor,
|
||||
BoxConstraints constraints,
|
||||
) {
|
||||
var result = 0.0;
|
||||
var cont = true;
|
||||
if (user?.id == widget.message.user?.id) {
|
||||
if (divFactor >= 1.0) {
|
||||
// This calculation is hacky and does not cover all bases!!!
|
||||
// A better option is needed!
|
||||
|
||||
// Landscape calculations
|
||||
if (constraints.maxWidth == 1350) {
|
||||
// 12.7 iPad Pro
|
||||
result = shiftFactor + 0.5;
|
||||
cont = false;
|
||||
} else if (constraints.maxWidth == 1178) {
|
||||
// 11 inch iPad Pro
|
||||
result = shiftFactor + 0.42;
|
||||
cont = false;
|
||||
} else if (constraints.maxWidth == 1164) {
|
||||
// iPad Air 4
|
||||
result = shiftFactor + 0.4;
|
||||
cont = false;
|
||||
} else if (constraints.maxWidth == 1117) {
|
||||
// iPad Mini 6
|
||||
result = shiftFactor + 0.37;
|
||||
cont = false;
|
||||
} else if (constraints.maxWidth == 1064) {
|
||||
// iPad 9th gen
|
||||
result = shiftFactor + 0.33;
|
||||
cont = false;
|
||||
} else if (constraints.maxWidth == 1008) {
|
||||
// 9.7 inch iPad Pro
|
||||
result = shiftFactor + 0.3;
|
||||
cont = false;
|
||||
} else if (constraints.maxWidth >= 200 && constraints.maxWidth <= 400) {
|
||||
// Phone (?)
|
||||
result = shiftFactor - 0.2;
|
||||
cont = false;
|
||||
}
|
||||
|
||||
if (cont) {
|
||||
// Portrait calculations
|
||||
if (constraints.maxWidth == 1008) {
|
||||
// 12.7 iPad Pro
|
||||
result = shiftFactor + 0.3;
|
||||
} else if (constraints.maxWidth == 818) {
|
||||
// 11 inch iPad Pro
|
||||
result = shiftFactor + 0.07;
|
||||
} else if (constraints.maxWidth == 804) {
|
||||
// iPad Air 4
|
||||
result = shiftFactor + 0.04;
|
||||
} else if (constraints.maxWidth == 794) {
|
||||
// iPad 9th gen
|
||||
result = shiftFactor + 0.02;
|
||||
} else if (constraints.maxWidth >= 752) {
|
||||
// 9.7 inch iPad Pro
|
||||
result = shiftFactor - 0.05;
|
||||
} else if (constraints.maxWidth == 728) {
|
||||
// iPad Mini 6
|
||||
result = shiftFactor - 0.1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result = 1.2 - divFactor;
|
||||
}
|
||||
} else {
|
||||
if (divFactor >= 1.0) {
|
||||
result = shiftFactor + 0.2;
|
||||
} else {
|
||||
result = -(1.2 - divFactor);
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure reactions don't get pushed past the edge of the screen.
|
||||
//
|
||||
// Hacky!!! Needs improvement!!!
|
||||
if (result > 1) {
|
||||
return 1;
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
InkWell _buildCustomAction(
|
||||
BuildContext context,
|
||||
StreamMessageAction messageAction,
|
||||
|
||||
@@ -80,7 +80,6 @@ class StreamMessageTextField extends StatefulWidget {
|
||||
this.textAlignVertical,
|
||||
this.textDirection,
|
||||
this.readOnly = false,
|
||||
ToolbarOptions? toolbarOptions,
|
||||
this.showCursor,
|
||||
this.autofocus = false,
|
||||
this.obscuringCharacter = '•',
|
||||
@@ -155,31 +154,7 @@ class StreamMessageTextField extends StatefulWidget {
|
||||
keyboardType = keyboardType ??
|
||||
(maxLines == 1 ? TextInputType.text : TextInputType.multiline),
|
||||
enableInteractiveSelection =
|
||||
enableInteractiveSelection ?? (!readOnly || !obscureText),
|
||||
toolbarOptions = toolbarOptions ??
|
||||
(obscureText
|
||||
? (readOnly
|
||||
// No point in even offering "Select All" in a read-only obscured
|
||||
// field.
|
||||
? const ToolbarOptions()
|
||||
// Writable, but obscured.
|
||||
: const ToolbarOptions(
|
||||
selectAll: true,
|
||||
paste: true,
|
||||
))
|
||||
: (readOnly
|
||||
// Read-only, not obscured.
|
||||
? const ToolbarOptions(
|
||||
selectAll: true,
|
||||
copy: true,
|
||||
)
|
||||
// Writable, not obscured.
|
||||
: const ToolbarOptions(
|
||||
copy: true,
|
||||
cut: true,
|
||||
selectAll: true,
|
||||
paste: true,
|
||||
)));
|
||||
enableInteractiveSelection ?? (!readOnly || !obscureText);
|
||||
|
||||
/// Controls the message being edited.
|
||||
///
|
||||
@@ -304,13 +279,6 @@ class StreamMessageTextField extends StatefulWidget {
|
||||
/// {@macro flutter.widgets.editableText.readOnly}
|
||||
final bool readOnly;
|
||||
|
||||
/// Configuration of toolbar options.
|
||||
///
|
||||
/// If not set, select all and paste will default to be enabled. Copy and cut
|
||||
/// will be disabled if [obscureText] is true. If [readOnly] is true,
|
||||
/// paste and cut will be disabled regardless.
|
||||
final ToolbarOptions toolbarOptions;
|
||||
|
||||
/// {@macro flutter.widgets.editableText.showCursor}
|
||||
final bool? showCursor;
|
||||
|
||||
@@ -720,7 +688,6 @@ class _StreamMessageTextFieldState extends State<StreamMessageTextField>
|
||||
textAlignVertical: widget.textAlignVertical,
|
||||
textDirection: widget.textDirection,
|
||||
readOnly: widget.readOnly,
|
||||
toolbarOptions: widget.toolbarOptions,
|
||||
showCursor: widget.showCursor,
|
||||
autofocus: widget.autofocus,
|
||||
obscuringCharacter: widget.obscuringCharacter,
|
||||
|
||||
+22
-39
@@ -2,6 +2,7 @@ import 'dart:ui';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stream_chat_flutter/src/message_widget/reactions/reaction_bubble.dart';
|
||||
import 'package:stream_chat_flutter/src/message_widget/reactions/reactions_align.dart';
|
||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||
|
||||
/// {@template streamMessageReactionsModal}
|
||||
@@ -39,35 +40,13 @@ class StreamMessageReactionsModal extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final size = MediaQuery.of(context).size;
|
||||
final user = StreamChat.of(context).currentUser;
|
||||
final _userPermissions = StreamChannel.of(context).channel.ownCapabilities;
|
||||
final orientation = MediaQuery.of(context).orientation;
|
||||
|
||||
final hasReactionPermission =
|
||||
_userPermissions.contains(PermissionType.sendReaction);
|
||||
|
||||
final roughMaxSize = size.width * 2 / 3;
|
||||
var messageTextLength = message.text!.length;
|
||||
if (message.quotedMessage != null) {
|
||||
var quotedMessageLength = message.quotedMessage!.text!.length + 40;
|
||||
if (message.quotedMessage!.attachments.isNotEmpty) {
|
||||
quotedMessageLength += 40;
|
||||
}
|
||||
if (quotedMessageLength > messageTextLength) {
|
||||
messageTextLength = quotedMessageLength;
|
||||
}
|
||||
}
|
||||
final roughSentenceSize = messageTextLength *
|
||||
(messageTheme.messageTextStyle?.fontSize ?? 1) *
|
||||
1.2;
|
||||
final divFactor = message.attachments.isNotEmpty
|
||||
? 1
|
||||
: (roughSentenceSize == 0 ? 1 : (roughSentenceSize / roughMaxSize));
|
||||
|
||||
final numberOfReactions =
|
||||
StreamChatConfiguration.of(context).reactionIcons.length;
|
||||
final shiftFactor =
|
||||
numberOfReactions < 5 ? (5 - numberOfReactions) * 0.1 : 0.0;
|
||||
final fontSize = messageTheme.messageTextStyle?.fontSize;
|
||||
|
||||
final child = Center(
|
||||
child: SingleChildScrollView(
|
||||
@@ -79,22 +58,26 @@ class StreamMessageReactionsModal extends StatelessWidget {
|
||||
children: <Widget>[
|
||||
if ((showReactions ?? hasReactionPermission) &&
|
||||
(message.status == MessageSendingStatus.sent))
|
||||
Align(
|
||||
alignment: Alignment(
|
||||
user!.id == message.user!.id
|
||||
? (divFactor >= 1.0
|
||||
? -0.2 - shiftFactor
|
||||
: (1.2 - divFactor))
|
||||
: (divFactor >= 1.0
|
||||
? shiftFactor + 0.2
|
||||
: -(1.2 - divFactor)),
|
||||
0,
|
||||
),
|
||||
child: StreamReactionPicker(
|
||||
message: message,
|
||||
),
|
||||
LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
return Align(
|
||||
alignment: Alignment(
|
||||
calculateReactionsHorizontalAlignment(
|
||||
user,
|
||||
message,
|
||||
constraints,
|
||||
fontSize,
|
||||
orientation,
|
||||
),
|
||||
0,
|
||||
),
|
||||
child: StreamReactionPicker(
|
||||
message: message,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
const SizedBox(height: 10),
|
||||
IgnorePointer(
|
||||
child: messageWidget,
|
||||
),
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||
|
||||
/// This method calculates the align that the modal of reactions should have.
|
||||
/// This is an approximation based on the size of the message and the
|
||||
/// available space in the screen.
|
||||
double calculateReactionsHorizontalAlignment(
|
||||
User? user,
|
||||
Message message,
|
||||
BoxConstraints constraints,
|
||||
double? fontSize,
|
||||
Orientation orientation,
|
||||
) {
|
||||
final maxWidth = constraints.maxWidth;
|
||||
|
||||
final roughSentenceSize = message.roughMessageSize(fontSize);
|
||||
final hasAttachments = message.attachments.isNotEmpty;
|
||||
final isReply = message.quotedMessageId != null;
|
||||
final isAttachment = hasAttachments && !isReply;
|
||||
|
||||
// divFactor is the percentage of the available space that the message takes.
|
||||
// When the divFactor is bigger than 0.5 that means that the messages is
|
||||
// bigger than 50% of the available space and the modal should have an offset
|
||||
// in the direction that the message grows. When the divFactor is smaller
|
||||
// than 0.5 then the offset should be to he side opposite of the message
|
||||
// growth.
|
||||
// In resume, when divFactor > 0.5 then result > 0, when divFactor < 0.5
|
||||
// then result < 0.
|
||||
var divFactor = 0.5;
|
||||
|
||||
// When in portrait, attachments normally take 75% of the screen, when in
|
||||
// landscape, attachments normally take 50% of the screen.
|
||||
if (isAttachment) {
|
||||
if (orientation == Orientation.portrait) {
|
||||
divFactor = 0.75;
|
||||
} else {
|
||||
divFactor = 0.5;
|
||||
}
|
||||
} else {
|
||||
divFactor = roughSentenceSize == 0 ? 0.5 : (roughSentenceSize / maxWidth);
|
||||
}
|
||||
|
||||
final signal = user?.id == message.user?.id ? 1 : -1;
|
||||
final result = signal * (1 - divFactor * 2.0);
|
||||
|
||||
return _capResult(result);
|
||||
}
|
||||
|
||||
// Ensure reactions don't get pushed past the edge of the screen.
|
||||
//
|
||||
// This happens if divFactor is really big. When this happens, we can simply
|
||||
// move the model all the way to the end of screen.
|
||||
double _capResult(double result) {
|
||||
if (result > 1.0) {
|
||||
return 1;
|
||||
} else if (result < -1.0) {
|
||||
return -1;
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -1088,7 +1088,12 @@ class StreamSvgIcon extends StatelessWidget {
|
||||
key: key,
|
||||
width: width,
|
||||
height: height,
|
||||
color: color,
|
||||
colorFilter: color != null
|
||||
? ColorFilter.mode(
|
||||
color!,
|
||||
BlendMode.srcIn,
|
||||
)
|
||||
: null,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,8 +149,8 @@ class StreamThreadHeader extends StatelessWidget
|
||||
final theme = Theme.of(context);
|
||||
return AppBar(
|
||||
automaticallyImplyLeading: false,
|
||||
toolbarTextStyle: theme.textTheme.bodyText2,
|
||||
titleTextStyle: theme.textTheme.headline6,
|
||||
toolbarTextStyle: theme.textTheme.bodyMedium,
|
||||
titleTextStyle: theme.textTheme.titleLarge,
|
||||
systemOverlayStyle: theme.brightness == Brightness.dark
|
||||
? SystemUiOverlayStyle.light
|
||||
: SystemUiOverlayStyle.dark,
|
||||
|
||||
+1
-1
@@ -409,7 +409,7 @@ class StreamChannelListErrorWidget extends StatelessWidget {
|
||||
TextSpan(text: context.translations.loadingChannelsError),
|
||||
],
|
||||
),
|
||||
style: Theme.of(context).textTheme.headline6,
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
),
|
||||
TextButton(
|
||||
onPressed: onPressed,
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:diacritic/diacritic.dart';
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
@@ -12,6 +14,16 @@ extension StringExtension on String {
|
||||
String capitalize() =>
|
||||
isNotEmpty ? '${this[0].toUpperCase()}${substring(1).toLowerCase()}' : '';
|
||||
|
||||
/// Returns the biggest line of a text.
|
||||
String biggestLine() {
|
||||
if (contains('\n')) {
|
||||
return split('\n')
|
||||
.reduce((curr, next) => curr.length > next.length ? curr : next);
|
||||
} else {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether the string contains only emoji's or not.
|
||||
///
|
||||
/// Emojis guidelines
|
||||
@@ -353,6 +365,33 @@ extension MessageX on Message {
|
||||
return copyWith(text: messageTextToRender);
|
||||
}
|
||||
|
||||
/// Returns an approximation of message size
|
||||
double roughMessageSize(double? fontSize) {
|
||||
var messageTextLength = min(text!.biggestLine().length, 65);
|
||||
|
||||
if (quotedMessage != null) {
|
||||
var quotedMessageLength =
|
||||
(min(quotedMessage!.text?.biggestLine().length ?? 0, 65)) + 8;
|
||||
|
||||
if (quotedMessage!.attachments.isNotEmpty) {
|
||||
quotedMessageLength += 8;
|
||||
}
|
||||
|
||||
if (quotedMessageLength > messageTextLength * 1.2) {
|
||||
messageTextLength = quotedMessageLength;
|
||||
}
|
||||
}
|
||||
|
||||
// Quoted message have a smaller font, so it is necessary to reduce the
|
||||
// size of the multiplier to count for the smaller font.
|
||||
var multiplier = 0.55;
|
||||
if (quotedMessage != null) {
|
||||
multiplier = 0.45;
|
||||
}
|
||||
|
||||
return messageTextLength * (fontSize ?? 1) * multiplier;
|
||||
}
|
||||
|
||||
/// It returns the message with the translated text if available locally
|
||||
Message translate(String language) =>
|
||||
copyWith(text: i18n?['${language}_text'] ?? text);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'package:stream_chat_flutter/src/video/vlc/vlc_stub.dart'
|
||||
if (dart.library.io) 'vlc_manager_desktop.dart'
|
||||
if (dar.library.html) 'vlc_manager_web.dart';
|
||||
if (dart.library.html) 'vlc_manager_web.dart';
|
||||
|
||||
/// {@template vlcManager}
|
||||
/// An abstract class for the purpose of ensuring Flutter applications that
|
||||
|
||||
@@ -12,12 +12,11 @@ environment:
|
||||
dependencies:
|
||||
cached_network_image: ^3.0.0
|
||||
chewie: ^1.3.4
|
||||
collection: ^1.15.0
|
||||
collection: ^1.17.0
|
||||
contextmenu: ^3.0.0
|
||||
dart_vlc: ^0.4.0
|
||||
desktop_drop: ^0.4.0
|
||||
diacritic: ^0.1.3
|
||||
dio: ^4.0.6
|
||||
ezanimation: ^0.6.0
|
||||
file_picker: ^5.2.4
|
||||
file_selector: ^0.9.0
|
||||
@@ -25,14 +24,13 @@ dependencies:
|
||||
sdk: flutter
|
||||
flutter_markdown: ^0.6.1
|
||||
flutter_portal: ^1.0.0
|
||||
flutter_svg: ^1.0.1
|
||||
http: ^0.13.4
|
||||
flutter_svg: ^2.0.4
|
||||
http_parser: ^4.0.0
|
||||
image_gallery_saver: ^1.7.1
|
||||
image_picker: ^0.8.2
|
||||
jiffy: ^5.0.0
|
||||
lottie: ^2.0.0
|
||||
meta: ^1.3.0
|
||||
meta: ^1.8.0
|
||||
path_provider: ^2.0.9
|
||||
photo_manager: ^2.5.2
|
||||
photo_view: ^0.14.0
|
||||
@@ -44,7 +42,7 @@ dependencies:
|
||||
thumblr: ^0.0.4
|
||||
url_launcher: ^6.1.0
|
||||
video_player: ^2.4.5
|
||||
video_player_macos: ^1.0.6
|
||||
video_player_macos: ^2.0.1
|
||||
video_thumbnail: ^0.5.0
|
||||
|
||||
flutter:
|
||||
@@ -56,9 +54,9 @@ flutter:
|
||||
uses-material-design: true
|
||||
|
||||
dev_dependencies:
|
||||
dart_code_metrics: ^4.4.0
|
||||
dart_code_metrics: ^5.7.0
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
golden_toolkit: ^0.13.0
|
||||
golden_toolkit: ^0.15.0
|
||||
mocktail: ^0.3.0
|
||||
path: ^1.8.0
|
||||
path: ^1.8.2
|
||||
|
||||
Reference in New Issue
Block a user