Merge branch 'develop'
This commit is contained in:
@@ -39,36 +39,36 @@ jobs:
|
|||||||
run: melos bootstrap
|
run: melos bootstrap
|
||||||
|
|
||||||
- name: "Stream Chat Metrics"
|
- name: "Stream Chat Metrics"
|
||||||
uses: dart-code-checker/dart-code-metrics-action@v1
|
uses: dart-code-checker/dart-code-metrics-action@v2.0.0
|
||||||
with:
|
with:
|
||||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
relative_path: 'packages/stream_chat'
|
relative_path: 'packages/stream_chat'
|
||||||
folders: ${{ env.folders }}
|
folders: ${{ env.folders }}
|
||||||
|
|
||||||
- name: "Stream Chat Flutter Core Metrics"
|
- name: "Stream Chat Flutter Core Metrics"
|
||||||
uses: dart-code-checker/dart-code-metrics-action@v1
|
uses: dart-code-checker/dart-code-metrics-action@v2.0.0
|
||||||
with:
|
with:
|
||||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
relative_path: 'packages/stream_chat_flutter_core'
|
relative_path: 'packages/stream_chat_flutter_core'
|
||||||
folders: ${{ env.folders }}
|
folders: ${{ env.folders }}
|
||||||
|
|
||||||
- name: "Stream Chat Flutter Metrics"
|
- name: "Stream Chat Flutter Metrics"
|
||||||
uses: dart-code-checker/dart-code-metrics-action@v1
|
uses: dart-code-checker/dart-code-metrics-action@v2.0.0
|
||||||
with:
|
with:
|
||||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
relative_path: 'packages/stream_chat_flutter'
|
relative_path: 'packages/stream_chat_flutter'
|
||||||
folders: ${{ env.folders }}
|
folders: ${{ env.folders }}
|
||||||
|
|
||||||
- name: "Stream Chat Localizations Metrics"
|
- name: "Stream Chat Localizations Metrics"
|
||||||
uses: dart-code-checker/dart-code-metrics-action@v1
|
uses: dart-code-checker/dart-code-metrics-action@v2.0.0
|
||||||
with:
|
with:
|
||||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
relative_path: 'packages/stream_chat_localizations'
|
relative_path: 'packages/stream_chat_localizations'
|
||||||
folders: ${{ env.folders }}
|
folders: ${{ env.folders }}
|
||||||
|
|
||||||
- name: "Stream Chat Persistence Metrics"
|
- name: "Stream Chat Persistence Metrics"
|
||||||
uses: dart-code-checker/dart-code-metrics-action@v1
|
uses: dart-code-checker/dart-code-metrics-action@v2.0.0
|
||||||
with:
|
with:
|
||||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
relative_path: 'packages/stream_chat_persistence'
|
relative_path: 'packages/stream_chat_persistence'
|
||||||
folders: ${{ env.folders }}
|
folders: ${{ env.folders }}
|
||||||
|
|||||||
@@ -3,4 +3,4 @@
|
|||||||
# Fast fail the script on failures.
|
# Fast fail the script on failures.
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
pub global run remove_from_coverage:remove_from_coverage -f coverage/lcov.info -r '\.g\.dart$' -r '\.freezed\.dart$'
|
flutter pub global run remove_from_coverage:remove_from_coverage -f coverage/lcov.info -r '\.g\.dart$' -r '\.freezed\.dart$'
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ jobs:
|
|||||||
- name: "Install Tools"
|
- name: "Install Tools"
|
||||||
run: |
|
run: |
|
||||||
flutter pub global activate melos ${{ env.melos_version }}
|
flutter pub global activate melos ${{ env.melos_version }}
|
||||||
pub global activate remove_from_coverage
|
flutter pub global activate remove_from_coverage
|
||||||
- name: "Bootstrap Workspace"
|
- name: "Bootstrap Workspace"
|
||||||
run: melos bootstrap
|
run: melos bootstrap
|
||||||
- name: "Flutter Test"
|
- name: "Flutter Test"
|
||||||
|
|||||||
@@ -147,6 +147,21 @@ linter:
|
|||||||
- tighten_type_of_initializing_formals
|
- tighten_type_of_initializing_formals
|
||||||
- null_check_on_nullable_type_parameter
|
- null_check_on_nullable_type_parameter
|
||||||
|
|
||||||
|
- conditional_uri_does_not_exist
|
||||||
|
- secure_pubspec_urls
|
||||||
|
- sized_box_shrink_expand
|
||||||
|
- unnecessary_constructor_name
|
||||||
|
- unnecessary_late
|
||||||
|
- use_colored_box
|
||||||
|
- use_decorated_box
|
||||||
|
- use_enums
|
||||||
|
- use_super_parameters
|
||||||
|
- avoid_escaping_inner_quotes
|
||||||
|
- unnecessary_overrides
|
||||||
|
- prefer_null_aware_method_calls
|
||||||
|
- use_named_constants
|
||||||
|
- use_raw_strings
|
||||||
|
|
||||||
# https://dartcodemetrics.dev/docs/getting-started/introduction
|
# https://dartcodemetrics.dev/docs/getting-started/introduction
|
||||||
dart_code_metrics:
|
dart_code_metrics:
|
||||||
rules:
|
rules:
|
||||||
|
|||||||
@@ -0,0 +1,144 @@
|
|||||||
|
---
|
||||||
|
id: error_reporting_with_sentry
|
||||||
|
sidebar_position: 15
|
||||||
|
title: Error Reporting With Sentry
|
||||||
|
---
|
||||||
|
|
||||||
|
Error Reporting With Sentry
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
|
||||||
|
While one always tries to create apps that are free of bugs, they're sure to crop up from time to time. Since buggy apps lead to unhappy users and customers, it's important to understand how often your users experience bugs and where those bugs occur. That way, you can prioritize the bugs with the highest impact and work to fix them.
|
||||||
|
|
||||||
|
Whenever an error occurs, create a report containing the error that occurred and the associated stack trace. You can then send the report to an error tracking service, such as [Sentry](https://sentry.io/), [Rollbar](https://rollbar.com/), or [Firebase Crashlytics](https://firebase.google.com/docs/crashlytics).
|
||||||
|
|
||||||
|
The error tracking service aggregates all of the crashes your users experience and groups them together. This allows you to know how often your app fails and where your users run into trouble.
|
||||||
|
|
||||||
|
In this guide, learn how to report Stream Chat errors to the [Sentry](https://sentry.io/welcome/) crash reporting service using the following steps.
|
||||||
|
|
||||||
|
### 1. Get a DSN From Sentry
|
||||||
|
|
||||||
|
Before reporting errors to Sentry, you need a “DSN” to uniquely identify your app with the Sentry service:
|
||||||
|
To get a DSN, use the following steps:
|
||||||
|
|
||||||
|
- [Create an account with Sentry](https://sentry.io/signup/).
|
||||||
|
- Log in to the account.
|
||||||
|
- Create a new Flutter project.
|
||||||
|
- Copy the code snippet that includes the DSN.
|
||||||
|
|
||||||
|
### 2. Import the Sentry package
|
||||||
|
|
||||||
|
Import the `sentry_flutter` package into your app. The sentry package makes it easier to send error reports to the Sentry error tracking service.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
dependencies:
|
||||||
|
sentry_flutter: <latest_version>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Initialize the Sentry SDK
|
||||||
|
|
||||||
|
Initialize the SDK to capture different unhandled errors automatically.
|
||||||
|
|
||||||
|
```dart
|
||||||
|
import 'package:sentry_flutter/sentry_flutter.dart';
|
||||||
|
|
||||||
|
Future<void> main() async {
|
||||||
|
await SentryFlutter.init(
|
||||||
|
(options) => options.dsn = 'https://[email protected]/example',
|
||||||
|
appRunner: () => runApp(const MyApp()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Or, if you want to run your app in your own error zone, use `runZonedGuarded`:
|
||||||
|
|
||||||
|
```dart
|
||||||
|
void main() async {
|
||||||
|
/// Captures errors reported by the Flutter framework.
|
||||||
|
FlutterError.onError = (FlutterErrorDetails details) {
|
||||||
|
if (kDebugMode) {
|
||||||
|
// In development mode, simply print to console.
|
||||||
|
FlutterError.dumpErrorToConsole(details);
|
||||||
|
} else {
|
||||||
|
// In production mode, report to the application zone to report to Sentry.
|
||||||
|
Zone.current.handleUncaughtError(details.exception, details.stack!);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Future<void> _reportError(dynamic error, StackTrace stackTrace) async {
|
||||||
|
// Print the exception to the console.
|
||||||
|
if (kDebugMode) {
|
||||||
|
// Print the full stack trace in debug mode.
|
||||||
|
print(stackTrace);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
// Send the Exception and Stacktrace to sentry in Production mode.
|
||||||
|
await Sentry.captureException(error, stackTrace: stackTrace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
runZonedGuarded(
|
||||||
|
() async {
|
||||||
|
await SentryFlutter.init(
|
||||||
|
(options) => options.dsn = 'https://[email protected]/example',
|
||||||
|
);
|
||||||
|
runApp(const MyApp());
|
||||||
|
},
|
||||||
|
_reportError,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Alternatively, you can pass the DSN to Flutter using the **dart-define** tag:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
--dart-define SENTRY_DSN=https://[email protected]/example
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Integration With StreamChat Applications
|
||||||
|
|
||||||
|
Override the default `logHandlerFunction` to send errors to Sentry.
|
||||||
|
|
||||||
|
```dart
|
||||||
|
void sampleAppLogHandler(LogRecord record) async {
|
||||||
|
if (kDebugMode) StreamChatClient.defaultLogHandler(record);
|
||||||
|
|
||||||
|
// Report errors to Sentry
|
||||||
|
if (record.error != null || record.stackTrace != null) {
|
||||||
|
await Sentry.captureException(
|
||||||
|
record.error,
|
||||||
|
stackTrace: record.stackTrace,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StreamChatClient buildStreamChatClient(
|
||||||
|
String apiKey, {
|
||||||
|
Level logLevel = Level.SEVERE,
|
||||||
|
}) {
|
||||||
|
return StreamChatClient(
|
||||||
|
apiKey,
|
||||||
|
logLevel: logLevel,
|
||||||
|
logHandlerFunction: sampleAppLogHandler, // Pass the overridden logHandlerFunction
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Capture Errors Programmatically
|
||||||
|
|
||||||
|
Besides the automatic error reporting that Sentry generates by importing and initializing the SDK,
|
||||||
|
you can use the API to manually report errors to Sentry:
|
||||||
|
|
||||||
|
```dart
|
||||||
|
await Sentry.captureException(exception, stackTrace: stackTrace);
|
||||||
|
```
|
||||||
|
|
||||||
|
For more information, see the [Sentry API](https://pub.dev/documentation/sentry_flutter/latest/sentry_flutter/sentry_flutter-library.html) docs on Pub.
|
||||||
|
|
||||||
|
### Complete Example
|
||||||
|
|
||||||
|
To view a working example, see the [Stream Sample app](https://github.com/GetStream/flutter-samples/tree/main/packages/stream_chat_v1).
|
||||||
|
|
||||||
|
### Learn More
|
||||||
|
|
||||||
|
Extensive documentation about using the Sentry SDK can be found on [Sentry's site](https://docs.sentry.io/platforms/flutter/).
|
||||||
+13
-2
@@ -1,4 +1,5 @@
|
|||||||
name: stream_chat_flutter
|
name: stream_chat_flutter
|
||||||
|
repository: https://github.com/GetStream/stream-chat-flutter
|
||||||
|
|
||||||
versioning:
|
versioning:
|
||||||
mode: independent
|
mode: independent
|
||||||
@@ -7,6 +8,10 @@ packages:
|
|||||||
- packages/**
|
- packages/**
|
||||||
|
|
||||||
scripts:
|
scripts:
|
||||||
|
postclean:
|
||||||
|
run: melos run clean:flutter --no-select
|
||||||
|
description: Runs "flutter clean" in all Flutter packages
|
||||||
|
|
||||||
lint:all:
|
lint:all:
|
||||||
run: melos run analyze && melos run format
|
run: melos run analyze && melos run format
|
||||||
description: Run all static analysis checks
|
description: Run all static analysis checks
|
||||||
@@ -74,6 +79,12 @@ scripts:
|
|||||||
flutter: true
|
flutter: true
|
||||||
dir-exists: test
|
dir-exists: test
|
||||||
|
|
||||||
|
clean:flutter:
|
||||||
|
run: melos exec -c 4 --fail-fast -- "flutter clean"
|
||||||
|
description: Run Flutter clean for a specific package in this project.
|
||||||
|
select-package:
|
||||||
|
flutter: true
|
||||||
|
|
||||||
coverage:ignore-file:
|
coverage:ignore-file:
|
||||||
run: |
|
run: |
|
||||||
melos exec -c 5 --fail-fast -- "\$MELOS_ROOT_PATH/.github/workflows/scripts/remove-from-coverage.sh"
|
melos exec -c 5 --fail-fast -- "\$MELOS_ROOT_PATH/.github/workflows/scripts/remove-from-coverage.sh"
|
||||||
@@ -91,5 +102,5 @@ dev_dependencies:
|
|||||||
dart_code_metrics: ^4.4.0
|
dart_code_metrics: ^4.4.0
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=2.12.0 <3.0.0'
|
sdk: '>=2.17.0 <3.0.0'
|
||||||
flutter: '>=1.17.0 <2.0.0'
|
flutter: '>=1.17.0 <3.0.0'
|
||||||
@@ -1,3 +1,25 @@
|
|||||||
|
## 4.2.0
|
||||||
|
|
||||||
|
✅ Added
|
||||||
|
|
||||||
|
- Added `PaginationParams.createdAtAfterOrEqual` for message pagination.
|
||||||
|
- Added `PaginationParams.createdAtAfter` for message pagination.
|
||||||
|
- Added `PaginationParams.createdAtBeforeOrEqual` for message pagination.
|
||||||
|
- Added `PaginationParams.createdAtBefore` for message pagination.
|
||||||
|
- Added `PaginationParams.createdAtAround` for message pagination.
|
||||||
|
- Added support for `channel.disabled`, `channel.hidden` and `channel.truncatedAt` in `Channel`.
|
||||||
|
- Added support for `channel.membership` and `channel.membershipStream` in `Channel`.
|
||||||
|
- `Channel` now listens for `member.updated` events and updates the `Channel.members` accordingly.
|
||||||
|
|
||||||
|
🔄 Changed
|
||||||
|
|
||||||
|
- Deprecated `PaginationParams.before` and `PaginationParams.after`. Use `PaginationParams.limit` instead.
|
||||||
|
|
||||||
|
🐞 Fixed
|
||||||
|
|
||||||
|
- [[#1147]](https://github.com/GetStream/stream-chat-flutter/issues/1147) `channel.unset` not updating the extra data
|
||||||
|
stream.
|
||||||
|
|
||||||
## 4.1.0
|
## 4.1.0
|
||||||
|
|
||||||
✅ Added
|
✅ Added
|
||||||
|
|||||||
@@ -43,10 +43,10 @@ class StreamExample extends StatelessWidget {
|
|||||||
/// To initialize this example, an instance of
|
/// To initialize this example, an instance of
|
||||||
/// [client] and [channel] is required.
|
/// [client] and [channel] is required.
|
||||||
const StreamExample({
|
const StreamExample({
|
||||||
Key? key,
|
super.key,
|
||||||
required this.client,
|
required this.client,
|
||||||
required this.channel,
|
required this.channel,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
/// Instance of [StreamChatClient] we created earlier.
|
/// Instance of [StreamChatClient] we created earlier.
|
||||||
/// This contains information about our application and connection state.
|
/// This contains information about our application and connection state.
|
||||||
@@ -67,9 +67,9 @@ class StreamExample extends StatelessWidget {
|
|||||||
class HomeScreen extends StatelessWidget {
|
class HomeScreen extends StatelessWidget {
|
||||||
/// [HomeScreen] is constructed using the [Channel] we defined earlier.
|
/// [HomeScreen] is constructed using the [Channel] we defined earlier.
|
||||||
const HomeScreen({
|
const HomeScreen({
|
||||||
Key? key,
|
super.key,
|
||||||
required this.channel,
|
required this.channel,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
/// Channel object containing the [Channel.id] we'd like to observe.
|
/// Channel object containing the [Channel.id] we'd like to observe.
|
||||||
final Channel channel;
|
final Channel channel;
|
||||||
@@ -119,10 +119,10 @@ class HomeScreen extends StatelessWidget {
|
|||||||
class MessageView extends StatefulWidget {
|
class MessageView extends StatefulWidget {
|
||||||
/// Message takes the latest list of messages and the current channel.
|
/// Message takes the latest list of messages and the current channel.
|
||||||
const MessageView({
|
const MessageView({
|
||||||
Key? key,
|
super.key,
|
||||||
required this.messages,
|
required this.messages,
|
||||||
required this.channel,
|
required this.channel,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
/// List of messages sent in the given channel.
|
/// List of messages sent in the given channel.
|
||||||
final List<Message> messages;
|
final List<Message> messages;
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ publish_to: "none"
|
|||||||
version: 1.0.0+1
|
version: 1.0.0+1
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=2.12.0 <3.0.0'
|
sdk: '>=2.17.0 <3.0.0'
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
cupertino_icons: ^1.0.0
|
cupertino_icons: ^1.0.0
|
||||||
|
|||||||
@@ -171,6 +171,18 @@ class Channel {
|
|||||||
return state!.channelStateStream.map((cs) => cs.channel?.config);
|
return state!.channelStateStream.map((cs) => cs.channel?.config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Relationship of the current user to this channel.
|
||||||
|
Member? get membership {
|
||||||
|
_checkInitialized();
|
||||||
|
return state!._channelState.membership;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Relationship of the current user to this channel as a stream.
|
||||||
|
Stream<Member?> get membershipStream {
|
||||||
|
_checkInitialized();
|
||||||
|
return state!.channelStateStream.map((cs) => cs.membership);
|
||||||
|
}
|
||||||
|
|
||||||
/// Channel user creator.
|
/// Channel user creator.
|
||||||
User? get createdBy {
|
User? get createdBy {
|
||||||
_checkInitialized();
|
_checkInitialized();
|
||||||
@@ -195,6 +207,42 @@ class Channel {
|
|||||||
return state!.channelStateStream.map((cs) => cs.channel?.frozen == true);
|
return state!.channelStateStream.map((cs) => cs.channel?.frozen == true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Channel disabled status.
|
||||||
|
bool get disabled {
|
||||||
|
_checkInitialized();
|
||||||
|
return state!._channelState.channel?.disabled == true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Channel disabled status as a stream.
|
||||||
|
Stream<bool> get disabledStream {
|
||||||
|
_checkInitialized();
|
||||||
|
return state!.channelStateStream.map((cs) => cs.channel?.disabled == true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Channel hidden status.
|
||||||
|
bool get hidden {
|
||||||
|
_checkInitialized();
|
||||||
|
return state!._channelState.channel?.hidden == true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Channel hidden status as a stream.
|
||||||
|
Stream<bool> get hiddenStream {
|
||||||
|
_checkInitialized();
|
||||||
|
return state!.channelStateStream.map((cs) => cs.channel?.hidden == true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The last date at which the channel got truncated.
|
||||||
|
DateTime? get truncatedAt {
|
||||||
|
_checkInitialized();
|
||||||
|
return state!._channelState.channel?.truncatedAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The last date at which the channel got truncated as a stream.
|
||||||
|
Stream<DateTime?> get truncatedAtStream {
|
||||||
|
_checkInitialized();
|
||||||
|
return state!.channelStateStream.map((cs) => cs.channel?.truncatedAt);
|
||||||
|
}
|
||||||
|
|
||||||
/// Cooldown count
|
/// Cooldown count
|
||||||
int get cooldown {
|
int get cooldown {
|
||||||
_checkInitialized();
|
_checkInitialized();
|
||||||
@@ -1540,6 +1588,8 @@ class ChannelClientState {
|
|||||||
|
|
||||||
_listenMemberRemoved();
|
_listenMemberRemoved();
|
||||||
|
|
||||||
|
_listenMemberUpdated();
|
||||||
|
|
||||||
_listenMemberBanned();
|
_listenMemberBanned();
|
||||||
|
|
||||||
_listenMemberUnbanned();
|
_listenMemberUnbanned();
|
||||||
@@ -1632,6 +1682,18 @@ class ChannelClientState {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _listenMemberUpdated() {
|
||||||
|
_subscriptions.add(_channel.on(EventType.memberUpdated).listen((Event e) {
|
||||||
|
final member = e.member;
|
||||||
|
final existingMembers = channelState.members ?? [];
|
||||||
|
updateChannelState(channelState.copyWith(
|
||||||
|
members: existingMembers
|
||||||
|
.map((m) => m.userId == member!.userId ? member : m)
|
||||||
|
.toList(growable: false),
|
||||||
|
));
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
void _listenChannelUpdated() {
|
void _listenChannelUpdated() {
|
||||||
_subscriptions.add(_channel.on(EventType.channelUpdated).listen((Event e) {
|
_subscriptions.add(_channel.on(EventType.channelUpdated).listen((Event e) {
|
||||||
final channel = e.channel!;
|
final channel = e.channel!;
|
||||||
@@ -2173,7 +2235,7 @@ class ChannelClientState {
|
|||||||
|
|
||||||
/// The channel threads related to this channel.
|
/// The channel threads related to this channel.
|
||||||
Map<String, List<Message>> get threads =>
|
Map<String, List<Message>> get threads =>
|
||||||
_threadsController.value.map((key, value) => MapEntry(key, value));
|
_threadsController.value.map(MapEntry.new);
|
||||||
|
|
||||||
/// The channel threads related to this channel as a stream.
|
/// The channel threads related to this channel as a stream.
|
||||||
Stream<Map<String, List<Message>>> get threadsStream =>
|
Stream<Map<String, List<Message>>> get threadsStream =>
|
||||||
|
|||||||
@@ -10,15 +10,6 @@ enum PushProvider {
|
|||||||
apn,
|
apn,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper extension for [PushProvider]
|
|
||||||
extension PushProviderX on PushProvider {
|
|
||||||
/// Returns the string notion for [PushProvider].
|
|
||||||
String get name => {
|
|
||||||
PushProvider.apn: 'apn',
|
|
||||||
PushProvider.firebase: 'firebase',
|
|
||||||
}[this]!;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Defines the api dedicated to device operations
|
/// Defines the api dedicated to device operations
|
||||||
class DeviceApi {
|
class DeviceApi {
|
||||||
/// Initialize a new device api
|
/// Initialize a new device api
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
// ignore_for_file: deprecated_member_use_from_same_package
|
||||||
|
|
||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:json_annotation/json_annotation.dart';
|
import 'package:json_annotation/json_annotation.dart';
|
||||||
|
|
||||||
@@ -69,6 +71,11 @@ class PaginationParams extends Equatable {
|
|||||||
this.greaterThanOrEqual,
|
this.greaterThanOrEqual,
|
||||||
this.lessThan,
|
this.lessThan,
|
||||||
this.lessThanOrEqual,
|
this.lessThanOrEqual,
|
||||||
|
this.createdAtAfterOrEqual,
|
||||||
|
this.createdAtAfter,
|
||||||
|
this.createdAtBeforeOrEqual,
|
||||||
|
this.createdAtBefore,
|
||||||
|
this.createdAtAround,
|
||||||
}) : assert(
|
}) : assert(
|
||||||
offset == null || offset == 0 || next == null,
|
offset == null || offset == 0 || next == null,
|
||||||
'Cannot specify non-zero `offset` with `next` parameter',
|
'Cannot specify non-zero `offset` with `next` parameter',
|
||||||
@@ -82,9 +89,11 @@ class PaginationParams extends Equatable {
|
|||||||
final int limit;
|
final int limit;
|
||||||
|
|
||||||
/// The amount of items requested before message ID from the APIs.
|
/// The amount of items requested before message ID from the APIs.
|
||||||
|
@Deprecated('before is deprecated, use limit instead')
|
||||||
final int before;
|
final int before;
|
||||||
|
|
||||||
/// The amount of items requested after message ID from the APIs.
|
/// The amount of items requested after message ID from the APIs.
|
||||||
|
@Deprecated('after is deprecated, use limit instead')
|
||||||
final int after;
|
final int after;
|
||||||
|
|
||||||
/// The offset of requesting items.
|
/// The offset of requesting items.
|
||||||
@@ -113,6 +122,26 @@ class PaginationParams extends Equatable {
|
|||||||
@JsonKey(name: 'id_lte')
|
@JsonKey(name: 'id_lte')
|
||||||
final String? lessThanOrEqual;
|
final String? lessThanOrEqual;
|
||||||
|
|
||||||
|
/// Filter on createdAt greater than or equal the given value.
|
||||||
|
@JsonKey(name: 'created_at_after_or_equal')
|
||||||
|
final DateTime? createdAtAfterOrEqual;
|
||||||
|
|
||||||
|
/// Filter on createdAt greater than the given value.
|
||||||
|
@JsonKey(name: 'created_at_after')
|
||||||
|
final DateTime? createdAtAfter;
|
||||||
|
|
||||||
|
/// Filter on createdAt smaller than or equal the given value.
|
||||||
|
@JsonKey(name: 'created_at_before_or_equal')
|
||||||
|
final DateTime? createdAtBeforeOrEqual;
|
||||||
|
|
||||||
|
/// Filter on createdAt smaller than the given value.
|
||||||
|
@JsonKey(name: 'created_at_before')
|
||||||
|
final DateTime? createdAtBefore;
|
||||||
|
|
||||||
|
/// Filter on createdAt around the given value.
|
||||||
|
@JsonKey(name: 'created_at_around')
|
||||||
|
final DateTime? createdAtAround;
|
||||||
|
|
||||||
/// Serialize model to json
|
/// Serialize model to json
|
||||||
Map<String, dynamic> toJson() => _$PaginationParamsToJson(this);
|
Map<String, dynamic> toJson() => _$PaginationParamsToJson(this);
|
||||||
|
|
||||||
@@ -128,6 +157,11 @@ class PaginationParams extends Equatable {
|
|||||||
String? greaterThanOrEqual,
|
String? greaterThanOrEqual,
|
||||||
String? lessThan,
|
String? lessThan,
|
||||||
String? lessThanOrEqual,
|
String? lessThanOrEqual,
|
||||||
|
DateTime? createdAtAfterOrEqual,
|
||||||
|
DateTime? createdAtAfter,
|
||||||
|
DateTime? createdAtBeforeOrEqual,
|
||||||
|
DateTime? createdAtBefore,
|
||||||
|
DateTime? createdAtAround,
|
||||||
}) =>
|
}) =>
|
||||||
PaginationParams(
|
PaginationParams(
|
||||||
limit: limit ?? this.limit,
|
limit: limit ?? this.limit,
|
||||||
@@ -140,6 +174,13 @@ class PaginationParams extends Equatable {
|
|||||||
greaterThanOrEqual: greaterThanOrEqual ?? this.greaterThanOrEqual,
|
greaterThanOrEqual: greaterThanOrEqual ?? this.greaterThanOrEqual,
|
||||||
lessThan: lessThan ?? this.lessThan,
|
lessThan: lessThan ?? this.lessThan,
|
||||||
lessThanOrEqual: lessThanOrEqual ?? this.lessThanOrEqual,
|
lessThanOrEqual: lessThanOrEqual ?? this.lessThanOrEqual,
|
||||||
|
createdAtAfterOrEqual:
|
||||||
|
createdAtAfterOrEqual ?? this.createdAtAfterOrEqual,
|
||||||
|
createdAtAfter: createdAtAfter ?? this.createdAtAfter,
|
||||||
|
createdAtBeforeOrEqual:
|
||||||
|
createdAtBeforeOrEqual ?? this.createdAtBeforeOrEqual,
|
||||||
|
createdAtBefore: createdAtBefore ?? this.createdAtBefore,
|
||||||
|
createdAtAround: createdAtAround ?? this.createdAtAround,
|
||||||
);
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -30,6 +30,21 @@ PaginationParams _$PaginationParamsFromJson(Map<String, dynamic> json) =>
|
|||||||
greaterThanOrEqual: json['id_gte'] as String?,
|
greaterThanOrEqual: json['id_gte'] as String?,
|
||||||
lessThan: json['id_lt'] as String?,
|
lessThan: json['id_lt'] as String?,
|
||||||
lessThanOrEqual: json['id_lte'] as String?,
|
lessThanOrEqual: json['id_lte'] as String?,
|
||||||
|
createdAtAfterOrEqual: json['created_at_after_or_equal'] == null
|
||||||
|
? null
|
||||||
|
: DateTime.parse(json['created_at_after_or_equal'] as String),
|
||||||
|
createdAtAfter: json['created_at_after'] == null
|
||||||
|
? null
|
||||||
|
: DateTime.parse(json['created_at_after'] as String),
|
||||||
|
createdAtBeforeOrEqual: json['created_at_before_or_equal'] == null
|
||||||
|
? null
|
||||||
|
: DateTime.parse(json['created_at_before_or_equal'] as String),
|
||||||
|
createdAtBefore: json['created_at_before'] == null
|
||||||
|
? null
|
||||||
|
: DateTime.parse(json['created_at_before'] as String),
|
||||||
|
createdAtAround: json['created_at_around'] == null
|
||||||
|
? null
|
||||||
|
: DateTime.parse(json['created_at_around'] as String),
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> _$PaginationParamsToJson(PaginationParams instance) {
|
Map<String, dynamic> _$PaginationParamsToJson(PaginationParams instance) {
|
||||||
@@ -52,6 +67,15 @@ Map<String, dynamic> _$PaginationParamsToJson(PaginationParams instance) {
|
|||||||
writeNotNull('id_gte', instance.greaterThanOrEqual);
|
writeNotNull('id_gte', instance.greaterThanOrEqual);
|
||||||
writeNotNull('id_lt', instance.lessThan);
|
writeNotNull('id_lt', instance.lessThan);
|
||||||
writeNotNull('id_lte', instance.lessThanOrEqual);
|
writeNotNull('id_lte', instance.lessThanOrEqual);
|
||||||
|
writeNotNull('created_at_after_or_equal',
|
||||||
|
instance.createdAtAfterOrEqual?.toIso8601String());
|
||||||
|
writeNotNull('created_at_after', instance.createdAtAfter?.toIso8601String());
|
||||||
|
writeNotNull('created_at_before_or_equal',
|
||||||
|
instance.createdAtBeforeOrEqual?.toIso8601String());
|
||||||
|
writeNotNull(
|
||||||
|
'created_at_before', instance.createdAtBefore?.toIso8601String());
|
||||||
|
writeNotNull(
|
||||||
|
'created_at_around', instance.createdAtAround?.toIso8601String());
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,9 +21,9 @@ class StreamChatError with EquatableMixin implements Exception {
|
|||||||
class StreamWebSocketError extends StreamChatError {
|
class StreamWebSocketError extends StreamChatError {
|
||||||
///
|
///
|
||||||
const StreamWebSocketError(
|
const StreamWebSocketError(
|
||||||
String message, {
|
super.message, {
|
||||||
this.data,
|
this.data,
|
||||||
}) : super(message);
|
});
|
||||||
|
|
||||||
///
|
///
|
||||||
factory StreamWebSocketError.fromStreamError(Map<String, Object?> error) {
|
factory StreamWebSocketError.fromStreamError(Map<String, Object?> error) {
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ class AuthInterceptor extends Interceptor {
|
|||||||
final params = {'user_id': token.userId};
|
final params = {'user_id': token.userId};
|
||||||
final headers = {
|
final headers = {
|
||||||
'Authorization': token.rawValue,
|
'Authorization': token.rawValue,
|
||||||
'stream-auth-type': token.authType.raw,
|
'stream-auth-type': token.authType.name,
|
||||||
};
|
};
|
||||||
options
|
options
|
||||||
..queryParameters.addAll(params)
|
..queryParameters.addAll(params)
|
||||||
|
|||||||
@@ -6,14 +6,11 @@ class StreamChatDioError extends DioError {
|
|||||||
/// Initialize a stream chat dio error
|
/// Initialize a stream chat dio error
|
||||||
StreamChatDioError({
|
StreamChatDioError({
|
||||||
required this.error,
|
required this.error,
|
||||||
required RequestOptions requestOptions,
|
required super.requestOptions,
|
||||||
Response? response,
|
super.response,
|
||||||
DioErrorType type = DioErrorType.other,
|
super.type,
|
||||||
}) : super(
|
}) : super(
|
||||||
error: error,
|
error: error,
|
||||||
requestOptions: requestOptions,
|
|
||||||
response: response,
|
|
||||||
type: type,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -18,15 +18,6 @@ enum AuthType {
|
|||||||
anonymous,
|
anonymous,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extension for returning the AuthType as a string
|
|
||||||
extension AuthTypeX on AuthType {
|
|
||||||
/// Returns the AuthType as a string
|
|
||||||
String get raw => {
|
|
||||||
AuthType.jwt: 'jwt',
|
|
||||||
AuthType.anonymous: 'anonymous',
|
|
||||||
}[this]!;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Token designed to store the JWT and the user it is related to.
|
/// Token designed to store the JWT and the user it is related to.
|
||||||
class Token extends Equatable {
|
class Token extends Equatable {
|
||||||
const Token._({
|
const Token._({
|
||||||
|
|||||||
@@ -90,6 +90,9 @@ class AttachmentFile {
|
|||||||
/// Union class to hold various [UploadState] of a attachment.
|
/// Union class to hold various [UploadState] of a attachment.
|
||||||
@freezed
|
@freezed
|
||||||
class UploadState with _$UploadState {
|
class UploadState with _$UploadState {
|
||||||
|
// Dummy private constructor in order to use getters
|
||||||
|
const UploadState._();
|
||||||
|
|
||||||
/// Preparing state of the union
|
/// Preparing state of the union
|
||||||
const factory UploadState.preparing() = Preparing;
|
const factory UploadState.preparing() = Preparing;
|
||||||
|
|
||||||
@@ -108,10 +111,7 @@ class UploadState with _$UploadState {
|
|||||||
/// Creates a new instance from a json
|
/// Creates a new instance from a json
|
||||||
factory UploadState.fromJson(Map<String, dynamic> json) =>
|
factory UploadState.fromJson(Map<String, dynamic> json) =>
|
||||||
_$UploadStateFromJson(json);
|
_$UploadStateFromJson(json);
|
||||||
}
|
|
||||||
|
|
||||||
/// Helper extension for UploadState
|
|
||||||
extension UploadStateX on UploadState? {
|
|
||||||
/// Returns true if state is [Preparing]
|
/// Returns true if state is [Preparing]
|
||||||
bool get isPreparing => this is Preparing;
|
bool get isPreparing => this is Preparing;
|
||||||
|
|
||||||
|
|||||||
@@ -103,25 +103,29 @@ class _$UploadStateCopyWithImpl<$Res> implements $UploadStateCopyWith<$Res> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
abstract class $PreparingCopyWith<$Res> {
|
abstract class _$$PreparingCopyWith<$Res> {
|
||||||
factory $PreparingCopyWith(Preparing value, $Res Function(Preparing) then) =
|
factory _$$PreparingCopyWith(
|
||||||
_$PreparingCopyWithImpl<$Res>;
|
_$Preparing value, $Res Function(_$Preparing) then) =
|
||||||
|
__$$PreparingCopyWithImpl<$Res>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
class _$PreparingCopyWithImpl<$Res> extends _$UploadStateCopyWithImpl<$Res>
|
class __$$PreparingCopyWithImpl<$Res> extends _$UploadStateCopyWithImpl<$Res>
|
||||||
implements $PreparingCopyWith<$Res> {
|
implements _$$PreparingCopyWith<$Res> {
|
||||||
_$PreparingCopyWithImpl(Preparing _value, $Res Function(Preparing) _then)
|
__$$PreparingCopyWithImpl(
|
||||||
: super(_value, (v) => _then(v as Preparing));
|
_$Preparing _value, $Res Function(_$Preparing) _then)
|
||||||
|
: super(_value, (v) => _then(v as _$Preparing));
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Preparing get _value => super._value as Preparing;
|
_$Preparing get _value => super._value as _$Preparing;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
@JsonSerializable()
|
@JsonSerializable()
|
||||||
class _$Preparing implements Preparing {
|
class _$Preparing extends Preparing {
|
||||||
const _$Preparing({final String? $type}) : $type = $type ?? 'preparing';
|
const _$Preparing({final String? $type})
|
||||||
|
: $type = $type ?? 'preparing',
|
||||||
|
super._();
|
||||||
|
|
||||||
factory _$Preparing.fromJson(Map<String, dynamic> json) =>
|
factory _$Preparing.fromJson(Map<String, dynamic> json) =>
|
||||||
_$$PreparingFromJson(json);
|
_$$PreparingFromJson(json);
|
||||||
@@ -137,7 +141,7 @@ class _$Preparing implements Preparing {
|
|||||||
@override
|
@override
|
||||||
bool operator ==(dynamic other) {
|
bool operator ==(dynamic other) {
|
||||||
return identical(this, other) ||
|
return identical(this, other) ||
|
||||||
(other.runtimeType == runtimeType && other is Preparing);
|
(other.runtimeType == runtimeType && other is _$Preparing);
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(ignore: true)
|
||||||
@@ -224,35 +228,37 @@ class _$Preparing implements Preparing {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class Preparing implements UploadState {
|
abstract class Preparing extends UploadState {
|
||||||
const factory Preparing() = _$Preparing;
|
const factory Preparing() = _$Preparing;
|
||||||
|
const Preparing._() : super._();
|
||||||
|
|
||||||
factory Preparing.fromJson(Map<String, dynamic> json) = _$Preparing.fromJson;
|
factory Preparing.fromJson(Map<String, dynamic> json) = _$Preparing.fromJson;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
abstract class $InProgressCopyWith<$Res> {
|
abstract class _$$InProgressCopyWith<$Res> {
|
||||||
factory $InProgressCopyWith(
|
factory _$$InProgressCopyWith(
|
||||||
InProgress value, $Res Function(InProgress) then) =
|
_$InProgress value, $Res Function(_$InProgress) then) =
|
||||||
_$InProgressCopyWithImpl<$Res>;
|
__$$InProgressCopyWithImpl<$Res>;
|
||||||
$Res call({int uploaded, int total});
|
$Res call({int uploaded, int total});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
class _$InProgressCopyWithImpl<$Res> extends _$UploadStateCopyWithImpl<$Res>
|
class __$$InProgressCopyWithImpl<$Res> extends _$UploadStateCopyWithImpl<$Res>
|
||||||
implements $InProgressCopyWith<$Res> {
|
implements _$$InProgressCopyWith<$Res> {
|
||||||
_$InProgressCopyWithImpl(InProgress _value, $Res Function(InProgress) _then)
|
__$$InProgressCopyWithImpl(
|
||||||
: super(_value, (v) => _then(v as InProgress));
|
_$InProgress _value, $Res Function(_$InProgress) _then)
|
||||||
|
: super(_value, (v) => _then(v as _$InProgress));
|
||||||
|
|
||||||
@override
|
@override
|
||||||
InProgress get _value => super._value as InProgress;
|
_$InProgress get _value => super._value as _$InProgress;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
$Res call({
|
$Res call({
|
||||||
Object? uploaded = freezed,
|
Object? uploaded = freezed,
|
||||||
Object? total = freezed,
|
Object? total = freezed,
|
||||||
}) {
|
}) {
|
||||||
return _then(InProgress(
|
return _then(_$InProgress(
|
||||||
uploaded: uploaded == freezed
|
uploaded: uploaded == freezed
|
||||||
? _value.uploaded
|
? _value.uploaded
|
||||||
: uploaded // ignore: cast_nullable_to_non_nullable
|
: uploaded // ignore: cast_nullable_to_non_nullable
|
||||||
@@ -267,10 +273,11 @@ class _$InProgressCopyWithImpl<$Res> extends _$UploadStateCopyWithImpl<$Res>
|
|||||||
|
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
@JsonSerializable()
|
@JsonSerializable()
|
||||||
class _$InProgress implements InProgress {
|
class _$InProgress extends InProgress {
|
||||||
const _$InProgress(
|
const _$InProgress(
|
||||||
{required this.uploaded, required this.total, final String? $type})
|
{required this.uploaded, required this.total, final String? $type})
|
||||||
: $type = $type ?? 'inProgress';
|
: $type = $type ?? 'inProgress',
|
||||||
|
super._();
|
||||||
|
|
||||||
factory _$InProgress.fromJson(Map<String, dynamic> json) =>
|
factory _$InProgress.fromJson(Map<String, dynamic> json) =>
|
||||||
_$$InProgressFromJson(json);
|
_$$InProgressFromJson(json);
|
||||||
@@ -292,7 +299,7 @@ class _$InProgress implements InProgress {
|
|||||||
bool operator ==(dynamic other) {
|
bool operator ==(dynamic other) {
|
||||||
return identical(this, other) ||
|
return identical(this, other) ||
|
||||||
(other.runtimeType == runtimeType &&
|
(other.runtimeType == runtimeType &&
|
||||||
other is InProgress &&
|
other is _$InProgress &&
|
||||||
const DeepCollectionEquality().equals(other.uploaded, uploaded) &&
|
const DeepCollectionEquality().equals(other.uploaded, uploaded) &&
|
||||||
const DeepCollectionEquality().equals(other.total, total));
|
const DeepCollectionEquality().equals(other.total, total));
|
||||||
}
|
}
|
||||||
@@ -306,8 +313,8 @@ class _$InProgress implements InProgress {
|
|||||||
|
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(ignore: true)
|
||||||
@override
|
@override
|
||||||
$InProgressCopyWith<InProgress> get copyWith =>
|
_$$InProgressCopyWith<_$InProgress> get copyWith =>
|
||||||
_$InProgressCopyWithImpl<InProgress>(this, _$identity);
|
__$$InProgressCopyWithImpl<_$InProgress>(this, _$identity);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@optionalTypeArgs
|
@optionalTypeArgs
|
||||||
@@ -389,9 +396,10 @@ class _$InProgress implements InProgress {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class InProgress implements UploadState {
|
abstract class InProgress extends UploadState {
|
||||||
const factory InProgress(
|
const factory InProgress(
|
||||||
{required final int uploaded, required final int total}) = _$InProgress;
|
{required final int uploaded, required final int total}) = _$InProgress;
|
||||||
|
const InProgress._() : super._();
|
||||||
|
|
||||||
factory InProgress.fromJson(Map<String, dynamic> json) =
|
factory InProgress.fromJson(Map<String, dynamic> json) =
|
||||||
_$InProgress.fromJson;
|
_$InProgress.fromJson;
|
||||||
@@ -399,30 +407,32 @@ abstract class InProgress implements UploadState {
|
|||||||
int get uploaded => throw _privateConstructorUsedError;
|
int get uploaded => throw _privateConstructorUsedError;
|
||||||
int get total => throw _privateConstructorUsedError;
|
int get total => throw _privateConstructorUsedError;
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(ignore: true)
|
||||||
$InProgressCopyWith<InProgress> get copyWith =>
|
_$$InProgressCopyWith<_$InProgress> get copyWith =>
|
||||||
throw _privateConstructorUsedError;
|
throw _privateConstructorUsedError;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
abstract class $SuccessCopyWith<$Res> {
|
abstract class _$$SuccessCopyWith<$Res> {
|
||||||
factory $SuccessCopyWith(Success value, $Res Function(Success) then) =
|
factory _$$SuccessCopyWith(_$Success value, $Res Function(_$Success) then) =
|
||||||
_$SuccessCopyWithImpl<$Res>;
|
__$$SuccessCopyWithImpl<$Res>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
class _$SuccessCopyWithImpl<$Res> extends _$UploadStateCopyWithImpl<$Res>
|
class __$$SuccessCopyWithImpl<$Res> extends _$UploadStateCopyWithImpl<$Res>
|
||||||
implements $SuccessCopyWith<$Res> {
|
implements _$$SuccessCopyWith<$Res> {
|
||||||
_$SuccessCopyWithImpl(Success _value, $Res Function(Success) _then)
|
__$$SuccessCopyWithImpl(_$Success _value, $Res Function(_$Success) _then)
|
||||||
: super(_value, (v) => _then(v as Success));
|
: super(_value, (v) => _then(v as _$Success));
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Success get _value => super._value as Success;
|
_$Success get _value => super._value as _$Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
@JsonSerializable()
|
@JsonSerializable()
|
||||||
class _$Success implements Success {
|
class _$Success extends Success {
|
||||||
const _$Success({final String? $type}) : $type = $type ?? 'success';
|
const _$Success({final String? $type})
|
||||||
|
: $type = $type ?? 'success',
|
||||||
|
super._();
|
||||||
|
|
||||||
factory _$Success.fromJson(Map<String, dynamic> json) =>
|
factory _$Success.fromJson(Map<String, dynamic> json) =>
|
||||||
_$$SuccessFromJson(json);
|
_$$SuccessFromJson(json);
|
||||||
@@ -438,7 +448,7 @@ class _$Success implements Success {
|
|||||||
@override
|
@override
|
||||||
bool operator ==(dynamic other) {
|
bool operator ==(dynamic other) {
|
||||||
return identical(this, other) ||
|
return identical(this, other) ||
|
||||||
(other.runtimeType == runtimeType && other is Success);
|
(other.runtimeType == runtimeType && other is _$Success);
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(ignore: true)
|
||||||
@@ -525,33 +535,34 @@ class _$Success implements Success {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class Success implements UploadState {
|
abstract class Success extends UploadState {
|
||||||
const factory Success() = _$Success;
|
const factory Success() = _$Success;
|
||||||
|
const Success._() : super._();
|
||||||
|
|
||||||
factory Success.fromJson(Map<String, dynamic> json) = _$Success.fromJson;
|
factory Success.fromJson(Map<String, dynamic> json) = _$Success.fromJson;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
abstract class $FailedCopyWith<$Res> {
|
abstract class _$$FailedCopyWith<$Res> {
|
||||||
factory $FailedCopyWith(Failed value, $Res Function(Failed) then) =
|
factory _$$FailedCopyWith(_$Failed value, $Res Function(_$Failed) then) =
|
||||||
_$FailedCopyWithImpl<$Res>;
|
__$$FailedCopyWithImpl<$Res>;
|
||||||
$Res call({String error});
|
$Res call({String error});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
class _$FailedCopyWithImpl<$Res> extends _$UploadStateCopyWithImpl<$Res>
|
class __$$FailedCopyWithImpl<$Res> extends _$UploadStateCopyWithImpl<$Res>
|
||||||
implements $FailedCopyWith<$Res> {
|
implements _$$FailedCopyWith<$Res> {
|
||||||
_$FailedCopyWithImpl(Failed _value, $Res Function(Failed) _then)
|
__$$FailedCopyWithImpl(_$Failed _value, $Res Function(_$Failed) _then)
|
||||||
: super(_value, (v) => _then(v as Failed));
|
: super(_value, (v) => _then(v as _$Failed));
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Failed get _value => super._value as Failed;
|
_$Failed get _value => super._value as _$Failed;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
$Res call({
|
$Res call({
|
||||||
Object? error = freezed,
|
Object? error = freezed,
|
||||||
}) {
|
}) {
|
||||||
return _then(Failed(
|
return _then(_$Failed(
|
||||||
error: error == freezed
|
error: error == freezed
|
||||||
? _value.error
|
? _value.error
|
||||||
: error // ignore: cast_nullable_to_non_nullable
|
: error // ignore: cast_nullable_to_non_nullable
|
||||||
@@ -562,9 +573,10 @@ class _$FailedCopyWithImpl<$Res> extends _$UploadStateCopyWithImpl<$Res>
|
|||||||
|
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
@JsonSerializable()
|
@JsonSerializable()
|
||||||
class _$Failed implements Failed {
|
class _$Failed extends Failed {
|
||||||
const _$Failed({required this.error, final String? $type})
|
const _$Failed({required this.error, final String? $type})
|
||||||
: $type = $type ?? 'failed';
|
: $type = $type ?? 'failed',
|
||||||
|
super._();
|
||||||
|
|
||||||
factory _$Failed.fromJson(Map<String, dynamic> json) =>
|
factory _$Failed.fromJson(Map<String, dynamic> json) =>
|
||||||
_$$FailedFromJson(json);
|
_$$FailedFromJson(json);
|
||||||
@@ -584,7 +596,7 @@ class _$Failed implements Failed {
|
|||||||
bool operator ==(dynamic other) {
|
bool operator ==(dynamic other) {
|
||||||
return identical(this, other) ||
|
return identical(this, other) ||
|
||||||
(other.runtimeType == runtimeType &&
|
(other.runtimeType == runtimeType &&
|
||||||
other is Failed &&
|
other is _$Failed &&
|
||||||
const DeepCollectionEquality().equals(other.error, error));
|
const DeepCollectionEquality().equals(other.error, error));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -595,8 +607,8 @@ class _$Failed implements Failed {
|
|||||||
|
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(ignore: true)
|
||||||
@override
|
@override
|
||||||
$FailedCopyWith<Failed> get copyWith =>
|
_$$FailedCopyWith<_$Failed> get copyWith =>
|
||||||
_$FailedCopyWithImpl<Failed>(this, _$identity);
|
__$$FailedCopyWithImpl<_$Failed>(this, _$identity);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@optionalTypeArgs
|
@optionalTypeArgs
|
||||||
@@ -678,12 +690,14 @@ class _$Failed implements Failed {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class Failed implements UploadState {
|
abstract class Failed extends UploadState {
|
||||||
const factory Failed({required final String error}) = _$Failed;
|
const factory Failed({required final String error}) = _$Failed;
|
||||||
|
const Failed._() : super._();
|
||||||
|
|
||||||
factory Failed.fromJson(Map<String, dynamic> json) = _$Failed.fromJson;
|
factory Failed.fromJson(Map<String, dynamic> json) = _$Failed.fromJson;
|
||||||
|
|
||||||
String get error => throw _privateConstructorUsedError;
|
String get error => throw _privateConstructorUsedError;
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(ignore: true)
|
||||||
$FailedCopyWith<Failed> get copyWith => throw _privateConstructorUsedError;
|
_$$FailedCopyWith<_$Failed> get copyWith =>
|
||||||
|
throw _privateConstructorUsedError;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,9 +22,12 @@ class ChannelModel {
|
|||||||
DateTime? updatedAt,
|
DateTime? updatedAt,
|
||||||
this.deletedAt,
|
this.deletedAt,
|
||||||
this.memberCount = 0,
|
this.memberCount = 0,
|
||||||
this.extraData = const {},
|
Map<String, Object?> extraData = const {},
|
||||||
this.team,
|
this.team,
|
||||||
this.cooldown = 0,
|
this.cooldown = 0,
|
||||||
|
bool? disabled,
|
||||||
|
bool? hidden,
|
||||||
|
DateTime? truncatedAt,
|
||||||
}) : assert(
|
}) : assert(
|
||||||
(cid != null && cid.contains(':')) || (id != null && type != null),
|
(cid != null && cid.contains(':')) || (id != null && type != null),
|
||||||
'provide either a cid or an id and type',
|
'provide either a cid or an id and type',
|
||||||
@@ -34,7 +37,18 @@ class ChannelModel {
|
|||||||
cid = cid ?? '$type:$id',
|
cid = cid ?? '$type:$id',
|
||||||
config = config ?? ChannelConfig(),
|
config = config ?? ChannelConfig(),
|
||||||
createdAt = createdAt ?? DateTime.now(),
|
createdAt = createdAt ?? DateTime.now(),
|
||||||
updatedAt = updatedAt ?? DateTime.now();
|
updatedAt = updatedAt ?? DateTime.now(),
|
||||||
|
|
||||||
|
// TODO: Make them top-level fields in v5
|
||||||
|
// For backwards compatibility, set 'disabled', 'hidden'
|
||||||
|
// and 'truncated_at' in [extraData].
|
||||||
|
extraData = {
|
||||||
|
...extraData,
|
||||||
|
if (disabled != null) 'disabled': disabled,
|
||||||
|
if (hidden != null) 'hidden': hidden,
|
||||||
|
if (truncatedAt != null)
|
||||||
|
'truncated_at': truncatedAt.toIso8601String(),
|
||||||
|
};
|
||||||
|
|
||||||
/// Create a new instance from a json
|
/// Create a new instance from a json
|
||||||
factory ChannelModel.fromJson(Map<String, dynamic> json) =>
|
factory ChannelModel.fromJson(Map<String, dynamic> json) =>
|
||||||
@@ -92,6 +106,22 @@ class ChannelModel {
|
|||||||
@JsonKey(includeIfNull: false)
|
@JsonKey(includeIfNull: false)
|
||||||
final int cooldown;
|
final int cooldown;
|
||||||
|
|
||||||
|
/// True if the channel is disabled
|
||||||
|
@JsonKey(ignore: true)
|
||||||
|
bool? get disabled => extraData['disabled'] as bool?;
|
||||||
|
|
||||||
|
/// True if the channel is hidden
|
||||||
|
@JsonKey(ignore: true)
|
||||||
|
bool? get hidden => extraData['hidden'] as bool?;
|
||||||
|
|
||||||
|
/// The date of the last time channel got truncated
|
||||||
|
@JsonKey(ignore: true)
|
||||||
|
DateTime? get truncatedAt {
|
||||||
|
final truncatedAt = extraData['truncated_at'] as String?;
|
||||||
|
if (truncatedAt == null) return null;
|
||||||
|
return DateTime.parse(truncatedAt);
|
||||||
|
}
|
||||||
|
|
||||||
/// Map of custom channel extraData
|
/// Map of custom channel extraData
|
||||||
@JsonKey(includeIfNull: false)
|
@JsonKey(includeIfNull: false)
|
||||||
final Map<String, Object?> extraData;
|
final Map<String, Object?> extraData;
|
||||||
@@ -145,6 +175,9 @@ class ChannelModel {
|
|||||||
Map<String, Object?>? extraData,
|
Map<String, Object?>? extraData,
|
||||||
String? team,
|
String? team,
|
||||||
int? cooldown,
|
int? cooldown,
|
||||||
|
bool? disabled,
|
||||||
|
bool? hidden,
|
||||||
|
DateTime? truncatedAt,
|
||||||
}) =>
|
}) =>
|
||||||
ChannelModel(
|
ChannelModel(
|
||||||
id: id ?? this.id,
|
id: id ?? this.id,
|
||||||
@@ -162,6 +195,14 @@ class ChannelModel {
|
|||||||
extraData: extraData ?? this.extraData,
|
extraData: extraData ?? this.extraData,
|
||||||
team: team ?? this.team,
|
team: team ?? this.team,
|
||||||
cooldown: cooldown ?? this.cooldown,
|
cooldown: cooldown ?? this.cooldown,
|
||||||
|
disabled: disabled ?? extraData?['disabled'] as bool? ?? this.disabled,
|
||||||
|
hidden: hidden ?? extraData?['hidden'] as bool? ?? this.hidden,
|
||||||
|
truncatedAt: truncatedAt ??
|
||||||
|
(extraData?['truncated_at'] == null
|
||||||
|
? null
|
||||||
|
// ignore: cast_nullable_to_non_nullable
|
||||||
|
: DateTime.parse(extraData?['truncated_at'] as String)) ??
|
||||||
|
this.truncatedAt,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Returns a new [ChannelModel] that is a combination of this channelModel
|
/// Returns a new [ChannelModel] that is a combination of this channelModel
|
||||||
@@ -181,9 +222,12 @@ class ChannelModel {
|
|||||||
updatedAt: other.updatedAt,
|
updatedAt: other.updatedAt,
|
||||||
deletedAt: other.deletedAt,
|
deletedAt: other.deletedAt,
|
||||||
memberCount: other.memberCount,
|
memberCount: other.memberCount,
|
||||||
extraData: {...extraData, ...other.extraData},
|
extraData: other.extraData,
|
||||||
team: other.team,
|
team: other.team,
|
||||||
cooldown: other.cooldown,
|
cooldown: other.cooldown,
|
||||||
|
disabled: other.disabled,
|
||||||
|
hidden: other.hidden,
|
||||||
|
truncatedAt: other.truncatedAt,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ class ChannelState {
|
|||||||
this.watcherCount,
|
this.watcherCount,
|
||||||
this.watchers,
|
this.watchers,
|
||||||
this.read,
|
this.read,
|
||||||
|
this.membership,
|
||||||
});
|
});
|
||||||
|
|
||||||
/// The channel to which this state belongs
|
/// The channel to which this state belongs
|
||||||
@@ -42,6 +43,9 @@ class ChannelState {
|
|||||||
/// The list of channel reads
|
/// The list of channel reads
|
||||||
final List<Read>? read;
|
final List<Read>? read;
|
||||||
|
|
||||||
|
/// Relationship of the current user to this channel.
|
||||||
|
final Member? membership;
|
||||||
|
|
||||||
/// Create a new instance from a json
|
/// Create a new instance from a json
|
||||||
static ChannelState fromJson(Map<String, dynamic> json) =>
|
static ChannelState fromJson(Map<String, dynamic> json) =>
|
||||||
_$ChannelStateFromJson(json);
|
_$ChannelStateFromJson(json);
|
||||||
@@ -58,6 +62,7 @@ class ChannelState {
|
|||||||
int? watcherCount,
|
int? watcherCount,
|
||||||
List<User>? watchers,
|
List<User>? watchers,
|
||||||
List<Read>? read,
|
List<Read>? read,
|
||||||
|
Member? membership,
|
||||||
}) =>
|
}) =>
|
||||||
ChannelState(
|
ChannelState(
|
||||||
channel: channel ?? this.channel,
|
channel: channel ?? this.channel,
|
||||||
@@ -67,5 +72,6 @@ class ChannelState {
|
|||||||
watcherCount: watcherCount ?? this.watcherCount,
|
watcherCount: watcherCount ?? this.watcherCount,
|
||||||
watchers: watchers ?? this.watchers,
|
watchers: watchers ?? this.watchers,
|
||||||
read: read ?? this.read,
|
read: read ?? this.read,
|
||||||
|
membership: membership ?? this.membership,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,9 @@ ChannelState _$ChannelStateFromJson(Map<String, dynamic> json) => ChannelState(
|
|||||||
read: (json['read'] as List<dynamic>?)
|
read: (json['read'] as List<dynamic>?)
|
||||||
?.map((e) => Read.fromJson(e as Map<String, dynamic>))
|
?.map((e) => Read.fromJson(e as Map<String, dynamic>))
|
||||||
.toList(),
|
.toList(),
|
||||||
|
membership: json['membership'] == null
|
||||||
|
? null
|
||||||
|
: Member.fromJson(json['membership'] as Map<String, dynamic>),
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> _$ChannelStateToJson(ChannelState instance) =>
|
Map<String, dynamic> _$ChannelStateToJson(ChannelState instance) =>
|
||||||
@@ -38,4 +41,5 @@ Map<String, dynamic> _$ChannelStateToJson(ChannelState instance) =>
|
|||||||
'watcher_count': instance.watcherCount,
|
'watcher_count': instance.watcherCount,
|
||||||
'watchers': instance.watchers?.map((e) => e.toJson()).toList(),
|
'watchers': instance.watchers?.map((e) => e.toJson()).toList(),
|
||||||
'read': instance.read?.map((e) => e.toJson()).toList(),
|
'read': instance.read?.map((e) => e.toJson()).toList(),
|
||||||
|
'membership': instance.membership?.toJson(),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -177,36 +177,25 @@ class EventChannel extends ChannelModel {
|
|||||||
/// Constructor used for json serialization
|
/// Constructor used for json serialization
|
||||||
EventChannel({
|
EventChannel({
|
||||||
this.members,
|
this.members,
|
||||||
String? id,
|
super.id,
|
||||||
String? type,
|
super.type,
|
||||||
required String cid,
|
required String super.cid,
|
||||||
required ChannelConfig config,
|
super.ownCapabilities,
|
||||||
User? createdBy,
|
required ChannelConfig super.config,
|
||||||
bool frozen = false,
|
super.createdBy,
|
||||||
DateTime? lastMessageAt,
|
super.frozen,
|
||||||
required DateTime createdAt,
|
super.lastMessageAt,
|
||||||
required DateTime updatedAt,
|
required DateTime super.createdAt,
|
||||||
DateTime? deletedAt,
|
required DateTime super.updatedAt,
|
||||||
int memberCount = 0,
|
super.deletedAt,
|
||||||
|
super.memberCount,
|
||||||
Map<String, Object?>? extraData,
|
Map<String, Object?>? extraData,
|
||||||
int cooldown = 0,
|
super.cooldown,
|
||||||
String? team,
|
super.team,
|
||||||
}) : super(
|
super.disabled,
|
||||||
id: id,
|
super.hidden,
|
||||||
type: type,
|
super.truncatedAt,
|
||||||
cid: cid,
|
}) : super(extraData: extraData ?? {});
|
||||||
config: config,
|
|
||||||
createdBy: createdBy,
|
|
||||||
frozen: frozen,
|
|
||||||
lastMessageAt: lastMessageAt,
|
|
||||||
createdAt: createdAt,
|
|
||||||
updatedAt: updatedAt,
|
|
||||||
deletedAt: deletedAt,
|
|
||||||
memberCount: memberCount,
|
|
||||||
extraData: extraData ?? {},
|
|
||||||
cooldown: cooldown,
|
|
||||||
team: team,
|
|
||||||
);
|
|
||||||
|
|
||||||
/// Create a new instance from a json
|
/// Create a new instance from a json
|
||||||
factory EventChannel.fromJson(Map<String, dynamic> json) =>
|
factory EventChannel.fromJson(Map<String, dynamic> json) =>
|
||||||
|
|||||||
@@ -81,6 +81,9 @@ EventChannel _$EventChannelFromJson(Map<String, dynamic> json) => EventChannel(
|
|||||||
id: json['id'] as String?,
|
id: json['id'] as String?,
|
||||||
type: json['type'] as String?,
|
type: json['type'] as String?,
|
||||||
cid: json['cid'] as String,
|
cid: json['cid'] as String,
|
||||||
|
ownCapabilities: (json['own_capabilities'] as List<dynamic>?)
|
||||||
|
?.map((e) => e as String)
|
||||||
|
.toList(),
|
||||||
config: ChannelConfig.fromJson(json['config'] as Map<String, dynamic>),
|
config: ChannelConfig.fromJson(json['config'] as Map<String, dynamic>),
|
||||||
createdBy: json['created_by'] == null
|
createdBy: json['created_by'] == null
|
||||||
? null
|
? null
|
||||||
|
|||||||
@@ -53,29 +53,43 @@ enum FilterOperator {
|
|||||||
nor,
|
nor,
|
||||||
|
|
||||||
/// Matches any list that contains the specified value
|
/// Matches any list that contains the specified value
|
||||||
contains,
|
contains;
|
||||||
}
|
|
||||||
|
|
||||||
/// Helper extension for [FilterOperator]
|
@override
|
||||||
extension FilterOperatorX on FilterOperator {
|
String toString() {
|
||||||
/// Converts [FilterOperator] into rew values
|
switch (this) {
|
||||||
String get rawValue => {
|
case FilterOperator.equal:
|
||||||
FilterOperator.equal: '\$eq',
|
return r'$eq';
|
||||||
FilterOperator.notEqual: '\$ne',
|
case FilterOperator.notEqual:
|
||||||
FilterOperator.greater: '\$gt',
|
return r'$ne';
|
||||||
FilterOperator.greaterOrEqual: '\$gte',
|
case FilterOperator.greater:
|
||||||
FilterOperator.less: '\$lt',
|
return r'$gt';
|
||||||
FilterOperator.lessOrEqual: '\$lte',
|
case FilterOperator.greaterOrEqual:
|
||||||
FilterOperator.in_: '\$in',
|
return r'$gte';
|
||||||
FilterOperator.notIn: '\$nin',
|
case FilterOperator.less:
|
||||||
FilterOperator.query: '\$q',
|
return r'$lt';
|
||||||
FilterOperator.autoComplete: '\$autocomplete',
|
case FilterOperator.lessOrEqual:
|
||||||
FilterOperator.exists: '\$exists',
|
return r'$lte';
|
||||||
FilterOperator.and: '\$and',
|
case FilterOperator.in_:
|
||||||
FilterOperator.or: '\$or',
|
return r'$in';
|
||||||
FilterOperator.nor: '\$nor',
|
case FilterOperator.notIn:
|
||||||
FilterOperator.contains: '\$contains',
|
return r'$nin';
|
||||||
}[this]!;
|
case FilterOperator.query:
|
||||||
|
return r'$q';
|
||||||
|
case FilterOperator.autoComplete:
|
||||||
|
return r'$autocomplete';
|
||||||
|
case FilterOperator.exists:
|
||||||
|
return r'$exists';
|
||||||
|
case FilterOperator.and:
|
||||||
|
return r'$and';
|
||||||
|
case FilterOperator.or:
|
||||||
|
return r'$or';
|
||||||
|
case FilterOperator.nor:
|
||||||
|
return r'$nor';
|
||||||
|
case FilterOperator.contains:
|
||||||
|
return r'$contains';
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stream supports a limited set of filters for querying channels,
|
/// Stream supports a limited set of filters for querying channels,
|
||||||
@@ -96,11 +110,11 @@ class Filter extends Equatable {
|
|||||||
this.key,
|
this.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
Filter._({
|
const Filter._({
|
||||||
required FilterOperator operator,
|
required FilterOperator operator,
|
||||||
required this.value,
|
required this.value,
|
||||||
this.key,
|
this.key,
|
||||||
}) : operator = operator.rawValue;
|
}) : operator = '$operator';
|
||||||
|
|
||||||
/// An empty filter
|
/// An empty filter
|
||||||
const Filter.empty()
|
const Filter.empty()
|
||||||
@@ -215,7 +229,7 @@ class Filter extends Equatable {
|
|||||||
/// Serializes to json object
|
/// Serializes to json object
|
||||||
Map<String, Object?> toJson() {
|
Map<String, Object?> toJson() {
|
||||||
final json = <String, Object?>{};
|
final json = <String, Object?>{};
|
||||||
final groupOperators = _groupOperators.map((it) => it.rawValue);
|
final groupOperators = _groupOperators.map((it) => '$it');
|
||||||
|
|
||||||
if (groupOperators.contains(operator)) {
|
if (groupOperators.contains(operator)) {
|
||||||
// Filters with group operators are encoded in the following form:
|
// Filters with group operators are encoded in the following form:
|
||||||
|
|||||||
@@ -17,34 +17,20 @@ class OwnUser extends User {
|
|||||||
this.totalUnreadCount = 0,
|
this.totalUnreadCount = 0,
|
||||||
this.unreadChannels = 0,
|
this.unreadChannels = 0,
|
||||||
this.channelMutes = const [],
|
this.channelMutes = const [],
|
||||||
required String id,
|
required super.id,
|
||||||
String? role,
|
super.role,
|
||||||
String? name,
|
super.name,
|
||||||
String? image,
|
super.image,
|
||||||
DateTime? createdAt,
|
super.createdAt,
|
||||||
DateTime? updatedAt,
|
super.updatedAt,
|
||||||
DateTime? lastActive,
|
super.lastActive,
|
||||||
bool online = false,
|
super.online,
|
||||||
Map<String, Object?> extraData = const {},
|
super.extraData,
|
||||||
bool banned = false,
|
super.banned,
|
||||||
DateTime? banExpires,
|
super.banExpires,
|
||||||
List<String> teams = const [],
|
super.teams,
|
||||||
String? language,
|
super.language,
|
||||||
}) : super(
|
});
|
||||||
id: id,
|
|
||||||
role: role,
|
|
||||||
name: name,
|
|
||||||
image: image,
|
|
||||||
createdAt: createdAt,
|
|
||||||
updatedAt: updatedAt,
|
|
||||||
lastActive: lastActive,
|
|
||||||
online: online,
|
|
||||||
extraData: extraData,
|
|
||||||
banned: banned,
|
|
||||||
banExpires: banExpires,
|
|
||||||
teams: teams,
|
|
||||||
language: language,
|
|
||||||
);
|
|
||||||
|
|
||||||
/// Create a new instance from json.
|
/// Create a new instance from json.
|
||||||
factory OwnUser.fromJson(Map<String, dynamic> json) => _$OwnUserFromJson(
|
factory OwnUser.fromJson(Map<String, dynamic> json) => _$OwnUserFromJson(
|
||||||
@@ -55,6 +41,9 @@ class OwnUser extends User {
|
|||||||
factory OwnUser.fromUser(User user) => OwnUser(
|
factory OwnUser.fromUser(User user) => OwnUser(
|
||||||
id: user.id,
|
id: user.id,
|
||||||
role: user.role,
|
role: user.role,
|
||||||
|
// Using extraData value in order to not use id as name.
|
||||||
|
name: user.extraData['name'] as String?,
|
||||||
|
image: user.image,
|
||||||
createdAt: user.createdAt,
|
createdAt: user.createdAt,
|
||||||
updatedAt: user.updatedAt,
|
updatedAt: user.updatedAt,
|
||||||
lastActive: user.lastActive,
|
lastActive: user.lastActive,
|
||||||
@@ -90,10 +79,11 @@ class OwnUser extends User {
|
|||||||
OwnUser(
|
OwnUser(
|
||||||
id: id ?? this.id,
|
id: id ?? this.id,
|
||||||
role: role ?? this.role,
|
role: role ?? this.role,
|
||||||
// if null, it will be retrieved from extraData['name']
|
name: name ??
|
||||||
name: name,
|
extraData?['name'] as String? ??
|
||||||
// if null, it will be retrieved from extraData['image']
|
// Using extraData value in order to not use id as name.
|
||||||
image: image,
|
this.extraData['name'] as String?,
|
||||||
|
image: image ?? extraData?['image'] as String? ?? this.image,
|
||||||
banned: banned ?? this.banned,
|
banned: banned ?? this.banned,
|
||||||
banExpires: banExpires ?? this.banExpires,
|
banExpires: banExpires ?? this.banExpires,
|
||||||
createdAt: createdAt ?? this.createdAt,
|
createdAt: createdAt ?? this.createdAt,
|
||||||
@@ -117,6 +107,9 @@ class OwnUser extends User {
|
|||||||
return copyWith(
|
return copyWith(
|
||||||
id: other.id,
|
id: other.id,
|
||||||
role: other.role,
|
role: other.role,
|
||||||
|
// Using extraData value in order to not use id as name.
|
||||||
|
name: other.extraData['name'] as String?,
|
||||||
|
image: other.image,
|
||||||
banned: other.banned,
|
banned: other.banned,
|
||||||
channelMutes: other.channelMutes,
|
channelMutes: other.channelMutes,
|
||||||
createdAt: other.createdAt,
|
createdAt: other.createdAt,
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ class User extends Equatable {
|
|||||||
this.language,
|
this.language,
|
||||||
}) : createdAt = createdAt ?? DateTime.now(),
|
}) : createdAt = createdAt ?? DateTime.now(),
|
||||||
updatedAt = updatedAt ?? DateTime.now(),
|
updatedAt = updatedAt ?? DateTime.now(),
|
||||||
|
// TODO: Make them top-level fields in v5
|
||||||
// For backwards compatibility, set 'name', 'image' in [extraData].
|
// For backwards compatibility, set 'name', 'image' in [extraData].
|
||||||
extraData = {
|
extraData = {
|
||||||
...extraData,
|
...extraData,
|
||||||
@@ -171,10 +172,11 @@ class User extends Equatable {
|
|||||||
User(
|
User(
|
||||||
id: id ?? this.id,
|
id: id ?? this.id,
|
||||||
role: role ?? this.role,
|
role: role ?? this.role,
|
||||||
// if null, it will be retrieved from extraData['name']
|
name: name ??
|
||||||
name: name,
|
extraData?['name'] as String? ??
|
||||||
// if null, it will be retrieved from extraData['image']
|
// Using extraData value in order to not use id as name.
|
||||||
image: image,
|
this.extraData['name'] as String?,
|
||||||
|
image: image ?? extraData?['image'] as String? ?? this.image,
|
||||||
createdAt: createdAt ?? this.createdAt,
|
createdAt: createdAt ?? this.createdAt,
|
||||||
updatedAt: updatedAt ?? this.updatedAt,
|
updatedAt: updatedAt ?? this.updatedAt,
|
||||||
lastActive: lastActive ?? this.lastActive,
|
lastActive: lastActive ?? this.lastActive,
|
||||||
|
|||||||
@@ -73,6 +73,9 @@ class EventType {
|
|||||||
/// Event sent when a member is removed to a channel
|
/// Event sent when a member is removed to a channel
|
||||||
static const String memberRemoved = 'member.removed';
|
static const String memberRemoved = 'member.removed';
|
||||||
|
|
||||||
|
/// Event sent when a member is updated in a channel
|
||||||
|
static const String memberUpdated = 'member.updated';
|
||||||
|
|
||||||
/// Event sent when a member is removed to a channel
|
/// Event sent when a member is removed to a channel
|
||||||
static const String userBanned = 'user.banned';
|
static const String userBanned = 'user.banned';
|
||||||
|
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
///
|
|
||||||
enum Location {
|
|
||||||
///
|
|
||||||
usEast,
|
|
||||||
|
|
||||||
///
|
|
||||||
euWest,
|
|
||||||
|
|
||||||
///
|
|
||||||
mumbai,
|
|
||||||
|
|
||||||
///
|
|
||||||
sydney,
|
|
||||||
|
|
||||||
///
|
|
||||||
singapore,
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
extension LocationX on Location {
|
|
||||||
///
|
|
||||||
String get name => {
|
|
||||||
Location.usEast: 'us-east',
|
|
||||||
Location.euWest: 'dublin',
|
|
||||||
Location.mumbai: 'mumbai',
|
|
||||||
Location.sydney: 'sydney',
|
|
||||||
Location.singapore: 'singapore',
|
|
||||||
}[this]!;
|
|
||||||
}
|
|
||||||
@@ -6,7 +6,6 @@ import 'package:logging/logging.dart';
|
|||||||
import 'package:meta/meta.dart';
|
import 'package:meta/meta.dart';
|
||||||
import 'package:rxdart/rxdart.dart';
|
import 'package:rxdart/rxdart.dart';
|
||||||
import 'package:stream_chat/src/core/error/error.dart';
|
import 'package:stream_chat/src/core/error/error.dart';
|
||||||
import 'package:stream_chat/src/core/http/token.dart';
|
|
||||||
import 'package:stream_chat/src/core/http/token_manager.dart';
|
import 'package:stream_chat/src/core/http/token_manager.dart';
|
||||||
import 'package:stream_chat/src/core/models/event.dart';
|
import 'package:stream_chat/src/core/models/event.dart';
|
||||||
import 'package:stream_chat/src/core/models/user.dart';
|
import 'package:stream_chat/src/core/models/user.dart';
|
||||||
@@ -163,7 +162,7 @@ class WebSocket with TimerHelper {
|
|||||||
'json': jsonEncode(params),
|
'json': jsonEncode(params),
|
||||||
'api_key': apiKey,
|
'api_key': apiKey,
|
||||||
'authorization': token.rawValue,
|
'authorization': token.rawValue,
|
||||||
'stream-auth-type': token.authType.raw,
|
'stream-auth-type': token.authType.name,
|
||||||
...queryParameters,
|
...queryParameters,
|
||||||
};
|
};
|
||||||
final scheme = baseUrl.startsWith('https') ? 'wss' : 'ws';
|
final scheme = baseUrl.startsWith('https') ? 'wss' : 'ws';
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ export './src/core/models/user.dart';
|
|||||||
export './src/core/util/extension.dart';
|
export './src/core/util/extension.dart';
|
||||||
export './src/db/chat_persistence_client.dart';
|
export './src/db/chat_persistence_client.dart';
|
||||||
export './src/event_type.dart';
|
export './src/event_type.dart';
|
||||||
export './src/location.dart';
|
|
||||||
export './src/permission_type.dart';
|
export './src/permission_type.dart';
|
||||||
export './src/ws/connection_status.dart';
|
export './src/ws/connection_status.dart';
|
||||||
export 'src/client/channel.dart';
|
export 'src/client/channel.dart';
|
||||||
@@ -67,5 +66,4 @@ export 'src/core/models/user.dart';
|
|||||||
export 'src/core/util/extension.dart';
|
export 'src/core/util/extension.dart';
|
||||||
export 'src/db/chat_persistence_client.dart';
|
export 'src/db/chat_persistence_client.dart';
|
||||||
export 'src/event_type.dart';
|
export 'src/event_type.dart';
|
||||||
export 'src/location.dart';
|
|
||||||
export 'src/ws/connection_status.dart';
|
export 'src/ws/connection_status.dart';
|
||||||
|
|||||||
@@ -3,4 +3,4 @@ import 'package:stream_chat/src/client/client.dart';
|
|||||||
/// Current package version
|
/// Current package version
|
||||||
/// Used in [StreamChatClient] to build the `x-stream-client` header
|
/// Used in [StreamChatClient] to build the `x-stream-client` header
|
||||||
// ignore: constant_identifier_names
|
// ignore: constant_identifier_names
|
||||||
const PACKAGE_VERSION = '4.1.0';
|
const PACKAGE_VERSION = '4.2.0';
|
||||||
|
|||||||
@@ -1,22 +1,22 @@
|
|||||||
name: stream_chat
|
name: stream_chat
|
||||||
homepage: https://getstream.io/
|
homepage: https://getstream.io/
|
||||||
description: The official Dart client for Stream Chat, a service for building chat applications.
|
description: The official Dart client for Stream Chat, a service for building chat applications.
|
||||||
version: 4.1.0
|
version: 4.2.0
|
||||||
repository: https://github.com/GetStream/stream-chat-flutter
|
repository: https://github.com/GetStream/stream-chat-flutter
|
||||||
issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues
|
issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=2.12.0 <3.0.0'
|
sdk: '>=2.17.0 <3.0.0'
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
async: ^2.5.0
|
async: ^2.5.0
|
||||||
collection: ^1.15.0
|
collection: ^1.15.0
|
||||||
dio: ^4.0.0
|
dio: ^4.0.0
|
||||||
equatable: ^2.0.0
|
equatable: ^2.0.0
|
||||||
freezed_annotation: ^1.0.0
|
freezed_annotation: ^2.0.3
|
||||||
http_parser: ^4.0.0
|
http_parser: ^4.0.0
|
||||||
jose: ^0.3.2
|
jose: ^0.3.2
|
||||||
json_annotation: ^4.3.0
|
json_annotation: ^4.5.0
|
||||||
logging: ^1.0.1
|
logging: ^1.0.1
|
||||||
meta: ^1.3.0
|
meta: ^1.3.0
|
||||||
mime: ^1.0.0
|
mime: ^1.0.0
|
||||||
@@ -28,7 +28,7 @@ dependencies:
|
|||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
build_runner: ^2.0.1
|
build_runner: ^2.0.1
|
||||||
dart_code_metrics: ^4.4.0
|
dart_code_metrics: ^4.4.0
|
||||||
freezed: ^1.0.0
|
freezed: ^2.0.3
|
||||||
json_serializable: ^6.0.1
|
json_serializable: ^6.2.0
|
||||||
mocktail: ^0.3.0
|
mocktail: ^0.3.0
|
||||||
test: ^1.17.12
|
test: ^1.17.12
|
||||||
@@ -11,6 +11,7 @@
|
|||||||
},
|
},
|
||||||
"watchers": [],
|
"watchers": [],
|
||||||
"read": [],
|
"read": [],
|
||||||
|
"membership": null,
|
||||||
"messages": [
|
"messages": [
|
||||||
{
|
{
|
||||||
"id": "dry-meadow-0-2b73cc8b-cd86-4a01-8d40-bd82ad07a030",
|
"id": "dry-meadow-0-2b73cc8b-cd86-4a01-8d40-bd82ad07a030",
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import 'package:mocktail/mocktail.dart';
|
import 'package:mocktail/mocktail.dart';
|
||||||
import 'package:stream_chat/src/core/api/device_api.dart';
|
|
||||||
import 'package:stream_chat/src/core/http/token.dart';
|
import 'package:stream_chat/src/core/http/token.dart';
|
||||||
import 'package:stream_chat/src/core/models/banned_user.dart';
|
import 'package:stream_chat/src/core/models/banned_user.dart';
|
||||||
import 'package:stream_chat/stream_chat.dart';
|
import 'package:stream_chat/stream_chat.dart';
|
||||||
@@ -2514,7 +2513,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test(
|
test(
|
||||||
'''setting the `currentUser` should also compute and update the unreadCounts''',
|
'setting the `currentUser` should also compute and update the unreadCounts',
|
||||||
() {
|
() {
|
||||||
final state = client.state;
|
final state = client.state;
|
||||||
final initialUser = OwnUser.fromUser(user);
|
final initialUser = OwnUser.fromUser(user);
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ void main() {
|
|||||||
expect(updateHeaders.containsKey('Authorization'), isTrue);
|
expect(updateHeaders.containsKey('Authorization'), isTrue);
|
||||||
expect(updateHeaders['Authorization'], token.rawValue);
|
expect(updateHeaders['Authorization'], token.rawValue);
|
||||||
expect(updateHeaders.containsKey('stream-auth-type'), isTrue);
|
expect(updateHeaders.containsKey('stream-auth-type'), isTrue);
|
||||||
expect(updateHeaders['stream-auth-type'], token.authType.raw);
|
expect(updateHeaders['stream-auth-type'], token.authType.name);
|
||||||
expect(updatedQueryParams.containsKey('user_id'), isTrue);
|
expect(updatedQueryParams.containsKey('user_id'), isTrue);
|
||||||
expect(updatedQueryParams['user_id'], token.userId);
|
expect(updatedQueryParams['user_id'], token.userId);
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ void main() {
|
|||||||
expect(token.userId, userId);
|
expect(token.userId, userId);
|
||||||
expect(token.rawValue, isEmpty);
|
expect(token.rawValue, isEmpty);
|
||||||
expect(token.authType, AuthType.anonymous);
|
expect(token.authType, AuthType.anonymous);
|
||||||
expect(token.authType.raw, AuthType.anonymous.raw);
|
expect(token.authType.name, AuthType.anonymous.name);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('`.fromRawValue` should create token from rawValue', () {
|
test('`.fromRawValue` should create token from rawValue', () {
|
||||||
@@ -36,7 +36,7 @@ void main() {
|
|||||||
expect(token.userId, userId);
|
expect(token.userId, userId);
|
||||||
expect(token.rawValue, isNotEmpty);
|
expect(token.rawValue, isNotEmpty);
|
||||||
expect(token.authType, AuthType.jwt);
|
expect(token.authType, AuthType.jwt);
|
||||||
expect(token.authType.raw, AuthType.jwt.raw);
|
expect(token.authType.name, AuthType.jwt.name);
|
||||||
});
|
});
|
||||||
|
|
||||||
test(
|
test(
|
||||||
@@ -51,7 +51,7 @@ void main() {
|
|||||||
expect(token.userId, user.id);
|
expect(token.userId, user.id);
|
||||||
expect(token.rawValue, isNotEmpty);
|
expect(token.rawValue, isNotEmpty);
|
||||||
expect(token.authType, AuthType.jwt);
|
expect(token.authType, AuthType.jwt);
|
||||||
expect(token.authType.raw, AuthType.jwt.raw);
|
expect(token.authType.name, AuthType.jwt.name);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ void main() {
|
|||||||
channel: ChannelModel.fromJson(j['channel']),
|
channel: ChannelModel.fromJson(j['channel']),
|
||||||
members: [],
|
members: [],
|
||||||
messages:
|
messages:
|
||||||
|
// ignore: unnecessary_lambdas
|
||||||
(j['messages'] as List).map((m) => Message.fromJson(m)).toList(),
|
(j['messages'] as List).map((m) => Message.fromJson(m)).toList(),
|
||||||
read: [],
|
read: [],
|
||||||
watcherCount: 5,
|
watcherCount: 5,
|
||||||
|
|||||||
@@ -55,4 +55,140 @@ void main() {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('hidden property and extraData manipulation', () {
|
||||||
|
final channel = ChannelModel(cid: 'test:cid', hidden: false);
|
||||||
|
|
||||||
|
expect(channel.hidden, false);
|
||||||
|
expect(channel.extraData['hidden'], false);
|
||||||
|
print(channel.toJson());
|
||||||
|
expect(channel.toJson(), {
|
||||||
|
'id': 'cid',
|
||||||
|
'type': 'test',
|
||||||
|
'frozen': false,
|
||||||
|
'cooldown': 0,
|
||||||
|
'hidden': false,
|
||||||
|
});
|
||||||
|
expect(ChannelModel.fromJson(channel.toJson()).toJson(), {
|
||||||
|
'id': 'cid',
|
||||||
|
'type': 'test',
|
||||||
|
'frozen': false,
|
||||||
|
'cooldown': 0,
|
||||||
|
'hidden': false,
|
||||||
|
});
|
||||||
|
|
||||||
|
var newChannel = channel.copyWith(
|
||||||
|
extraData: {'hidden': true},
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(newChannel.extraData['hidden'], true);
|
||||||
|
expect(newChannel.hidden, true);
|
||||||
|
|
||||||
|
newChannel = channel.copyWith(
|
||||||
|
hidden: false,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(newChannel.extraData['hidden'], false);
|
||||||
|
expect(newChannel.hidden, false);
|
||||||
|
|
||||||
|
newChannel = channel.copyWith(
|
||||||
|
hidden: true,
|
||||||
|
extraData: {'hidden': true},
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(newChannel.extraData['hidden'], true);
|
||||||
|
expect(newChannel.hidden, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('disabled property and extraData manipulation', () {
|
||||||
|
final channel = ChannelModel(cid: 'test:cid', disabled: false);
|
||||||
|
|
||||||
|
expect(channel.disabled, false);
|
||||||
|
expect(channel.extraData['disabled'], false);
|
||||||
|
print(channel.toJson());
|
||||||
|
expect(channel.toJson(), {
|
||||||
|
'id': 'cid',
|
||||||
|
'type': 'test',
|
||||||
|
'frozen': false,
|
||||||
|
'cooldown': 0,
|
||||||
|
'disabled': false,
|
||||||
|
});
|
||||||
|
expect(ChannelModel.fromJson(channel.toJson()).toJson(), {
|
||||||
|
'id': 'cid',
|
||||||
|
'type': 'test',
|
||||||
|
'frozen': false,
|
||||||
|
'cooldown': 0,
|
||||||
|
'disabled': false,
|
||||||
|
});
|
||||||
|
|
||||||
|
var newChannel = channel.copyWith(
|
||||||
|
extraData: {'disabled': true},
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(newChannel.extraData['disabled'], true);
|
||||||
|
expect(newChannel.disabled, true);
|
||||||
|
|
||||||
|
newChannel = channel.copyWith(
|
||||||
|
hidden: false,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(newChannel.extraData['disabled'], false);
|
||||||
|
expect(newChannel.disabled, false);
|
||||||
|
|
||||||
|
newChannel = channel.copyWith(
|
||||||
|
hidden: true,
|
||||||
|
extraData: {'disabled': true},
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(newChannel.extraData['disabled'], true);
|
||||||
|
expect(newChannel.disabled, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('truncatedAt property and extraData manipulation', () {
|
||||||
|
final currentDate = DateTime.now();
|
||||||
|
final channel = ChannelModel(cid: 'test:cid', truncatedAt: currentDate);
|
||||||
|
|
||||||
|
expect(channel.truncatedAt, currentDate);
|
||||||
|
expect(channel.extraData['truncated_at'], currentDate.toIso8601String());
|
||||||
|
print(channel.toJson());
|
||||||
|
expect(channel.toJson(), {
|
||||||
|
'id': 'cid',
|
||||||
|
'type': 'test',
|
||||||
|
'frozen': false,
|
||||||
|
'cooldown': 0,
|
||||||
|
'truncated_at': currentDate.toIso8601String(),
|
||||||
|
});
|
||||||
|
expect(ChannelModel.fromJson(channel.toJson()).toJson(), {
|
||||||
|
'id': 'cid',
|
||||||
|
'type': 'test',
|
||||||
|
'frozen': false,
|
||||||
|
'cooldown': 0,
|
||||||
|
'truncated_at': currentDate.toIso8601String(),
|
||||||
|
});
|
||||||
|
|
||||||
|
final dateOne = DateTime.now();
|
||||||
|
var newChannel = channel.copyWith(
|
||||||
|
extraData: {'truncated_at': dateOne.toIso8601String()},
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(newChannel.extraData['truncated_at'], dateOne.toIso8601String());
|
||||||
|
expect(newChannel.truncatedAt, dateOne);
|
||||||
|
|
||||||
|
final dateTwo = DateTime.now();
|
||||||
|
newChannel = channel.copyWith(
|
||||||
|
truncatedAt: dateTwo,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(newChannel.extraData['truncated_at'], dateTwo.toIso8601String());
|
||||||
|
expect(newChannel.truncatedAt, dateTwo);
|
||||||
|
|
||||||
|
final dateThree = DateTime.now();
|
||||||
|
newChannel = channel.copyWith(
|
||||||
|
truncatedAt: dateThree,
|
||||||
|
extraData: {'truncated_at': dateThree.toIso8601String()},
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(newChannel.extraData['truncated_at'], dateThree.toIso8601String());
|
||||||
|
expect(newChannel.truncatedAt, dateThree);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ void main() {
|
|||||||
final filter = Filter.equal(key, value);
|
final filter = Filter.equal(key, value);
|
||||||
expect(filter.key, key);
|
expect(filter.key, key);
|
||||||
expect(filter.value, value);
|
expect(filter.value, value);
|
||||||
expect(filter.operator, FilterOperator.equal.rawValue);
|
expect(filter.operator, FilterOperator.equal.toString());
|
||||||
});
|
});
|
||||||
|
|
||||||
test('notEqual', () {
|
test('notEqual', () {
|
||||||
@@ -20,7 +20,7 @@ void main() {
|
|||||||
final filter = Filter.notEqual(key, value);
|
final filter = Filter.notEqual(key, value);
|
||||||
expect(filter.key, key);
|
expect(filter.key, key);
|
||||||
expect(filter.value, value);
|
expect(filter.value, value);
|
||||||
expect(filter.operator, FilterOperator.notEqual.rawValue);
|
expect(filter.operator, FilterOperator.notEqual.toString());
|
||||||
});
|
});
|
||||||
|
|
||||||
test('greater', () {
|
test('greater', () {
|
||||||
@@ -29,7 +29,7 @@ void main() {
|
|||||||
final filter = Filter.greater(key, value);
|
final filter = Filter.greater(key, value);
|
||||||
expect(filter.key, key);
|
expect(filter.key, key);
|
||||||
expect(filter.value, value);
|
expect(filter.value, value);
|
||||||
expect(filter.operator, FilterOperator.greater.rawValue);
|
expect(filter.operator, FilterOperator.greater.toString());
|
||||||
});
|
});
|
||||||
|
|
||||||
test('greaterOrEqual', () {
|
test('greaterOrEqual', () {
|
||||||
@@ -38,7 +38,7 @@ void main() {
|
|||||||
final filter = Filter.greaterOrEqual(key, value);
|
final filter = Filter.greaterOrEqual(key, value);
|
||||||
expect(filter.key, key);
|
expect(filter.key, key);
|
||||||
expect(filter.value, value);
|
expect(filter.value, value);
|
||||||
expect(filter.operator, FilterOperator.greaterOrEqual.rawValue);
|
expect(filter.operator, FilterOperator.greaterOrEqual.toString());
|
||||||
});
|
});
|
||||||
|
|
||||||
test('less', () {
|
test('less', () {
|
||||||
@@ -47,7 +47,7 @@ void main() {
|
|||||||
final filter = Filter.less(key, value);
|
final filter = Filter.less(key, value);
|
||||||
expect(filter.key, key);
|
expect(filter.key, key);
|
||||||
expect(filter.value, value);
|
expect(filter.value, value);
|
||||||
expect(filter.operator, FilterOperator.less.rawValue);
|
expect(filter.operator, FilterOperator.less.toString());
|
||||||
});
|
});
|
||||||
|
|
||||||
test('lessOrEqual', () {
|
test('lessOrEqual', () {
|
||||||
@@ -56,7 +56,7 @@ void main() {
|
|||||||
final filter = Filter.lessOrEqual(key, value);
|
final filter = Filter.lessOrEqual(key, value);
|
||||||
expect(filter.key, key);
|
expect(filter.key, key);
|
||||||
expect(filter.value, value);
|
expect(filter.value, value);
|
||||||
expect(filter.operator, FilterOperator.lessOrEqual.rawValue);
|
expect(filter.operator, FilterOperator.lessOrEqual.toString());
|
||||||
});
|
});
|
||||||
|
|
||||||
test('in', () {
|
test('in', () {
|
||||||
@@ -65,7 +65,7 @@ void main() {
|
|||||||
final filter = Filter.in_(key, values);
|
final filter = Filter.in_(key, values);
|
||||||
expect(filter.key, key);
|
expect(filter.key, key);
|
||||||
expect(filter.value, values);
|
expect(filter.value, values);
|
||||||
expect(filter.operator, FilterOperator.in_.rawValue);
|
expect(filter.operator, FilterOperator.in_.toString());
|
||||||
});
|
});
|
||||||
|
|
||||||
test('in', () {
|
test('in', () {
|
||||||
@@ -74,7 +74,7 @@ void main() {
|
|||||||
final filter = Filter.in_(key, values);
|
final filter = Filter.in_(key, values);
|
||||||
expect(filter.key, key);
|
expect(filter.key, key);
|
||||||
expect(filter.value, values);
|
expect(filter.value, values);
|
||||||
expect(filter.operator, FilterOperator.in_.rawValue);
|
expect(filter.operator, FilterOperator.in_.toString());
|
||||||
});
|
});
|
||||||
|
|
||||||
test('notIn', () {
|
test('notIn', () {
|
||||||
@@ -83,7 +83,7 @@ void main() {
|
|||||||
final filter = Filter.notIn(key, values);
|
final filter = Filter.notIn(key, values);
|
||||||
expect(filter.key, key);
|
expect(filter.key, key);
|
||||||
expect(filter.value, values);
|
expect(filter.value, values);
|
||||||
expect(filter.operator, FilterOperator.notIn.rawValue);
|
expect(filter.operator, FilterOperator.notIn.toString());
|
||||||
});
|
});
|
||||||
|
|
||||||
test('query', () {
|
test('query', () {
|
||||||
@@ -92,7 +92,7 @@ void main() {
|
|||||||
final filter = Filter.query(key, value);
|
final filter = Filter.query(key, value);
|
||||||
expect(filter.key, key);
|
expect(filter.key, key);
|
||||||
expect(filter.value, value);
|
expect(filter.value, value);
|
||||||
expect(filter.operator, FilterOperator.query.rawValue);
|
expect(filter.operator, FilterOperator.query.toString());
|
||||||
});
|
});
|
||||||
|
|
||||||
test('autoComplete', () {
|
test('autoComplete', () {
|
||||||
@@ -101,7 +101,7 @@ void main() {
|
|||||||
final filter = Filter.autoComplete(key, value);
|
final filter = Filter.autoComplete(key, value);
|
||||||
expect(filter.key, key);
|
expect(filter.key, key);
|
||||||
expect(filter.value, value);
|
expect(filter.value, value);
|
||||||
expect(filter.operator, FilterOperator.autoComplete.rawValue);
|
expect(filter.operator, FilterOperator.autoComplete.toString());
|
||||||
});
|
});
|
||||||
|
|
||||||
test('exists', () {
|
test('exists', () {
|
||||||
@@ -109,7 +109,7 @@ void main() {
|
|||||||
final filter = Filter.exists(key);
|
final filter = Filter.exists(key);
|
||||||
expect(filter.key, key);
|
expect(filter.key, key);
|
||||||
expect(filter.value, isTrue);
|
expect(filter.value, isTrue);
|
||||||
expect(filter.operator, FilterOperator.exists.rawValue);
|
expect(filter.operator, FilterOperator.exists.toString());
|
||||||
});
|
});
|
||||||
|
|
||||||
test('notExists', () {
|
test('notExists', () {
|
||||||
@@ -117,13 +117,13 @@ void main() {
|
|||||||
final filter = Filter.notExists(key);
|
final filter = Filter.notExists(key);
|
||||||
expect(filter.key, key);
|
expect(filter.key, key);
|
||||||
expect(filter.value, isFalse);
|
expect(filter.value, isFalse);
|
||||||
expect(filter.operator, FilterOperator.exists.rawValue);
|
expect(filter.operator, FilterOperator.exists.toString());
|
||||||
});
|
});
|
||||||
|
|
||||||
test('custom', () {
|
test('custom', () {
|
||||||
const key = 'testKey';
|
const key = 'testKey';
|
||||||
const value = 'testValue';
|
const value = 'testValue';
|
||||||
const operator = '\$customOperator';
|
const operator = r'$customOperator';
|
||||||
const filter = Filter.custom(operator: operator, key: key, value: value);
|
const filter = Filter.custom(operator: operator, key: key, value: value);
|
||||||
expect(filter.key, key);
|
expect(filter.key, key);
|
||||||
expect(filter.value, value);
|
expect(filter.value, value);
|
||||||
@@ -149,7 +149,7 @@ void main() {
|
|||||||
final filter = Filter.contains(key, values);
|
final filter = Filter.contains(key, values);
|
||||||
expect(filter.key, key);
|
expect(filter.key, key);
|
||||||
expect(filter.value, values);
|
expect(filter.value, values);
|
||||||
expect(filter.operator, FilterOperator.contains.rawValue);
|
expect(filter.operator, FilterOperator.contains.toString());
|
||||||
});
|
});
|
||||||
|
|
||||||
group('groupedOperator', () {
|
group('groupedOperator', () {
|
||||||
@@ -161,21 +161,21 @@ void main() {
|
|||||||
final filter = Filter.and(filters);
|
final filter = Filter.and(filters);
|
||||||
expect(filter.key, isNull);
|
expect(filter.key, isNull);
|
||||||
expect(filter.value, filters);
|
expect(filter.value, filters);
|
||||||
expect(filter.operator, FilterOperator.and.rawValue);
|
expect(filter.operator, FilterOperator.and.toString());
|
||||||
});
|
});
|
||||||
|
|
||||||
test('or', () {
|
test('or', () {
|
||||||
final filter = Filter.or(filters);
|
final filter = Filter.or(filters);
|
||||||
expect(filter.key, isNull);
|
expect(filter.key, isNull);
|
||||||
expect(filter.value, filters);
|
expect(filter.value, filters);
|
||||||
expect(filter.operator, FilterOperator.or.rawValue);
|
expect(filter.operator, FilterOperator.or.toString());
|
||||||
});
|
});
|
||||||
|
|
||||||
test('nor', () {
|
test('nor', () {
|
||||||
final filter = Filter.nor(filters);
|
final filter = Filter.nor(filters);
|
||||||
expect(filter.key, isNull);
|
expect(filter.key, isNull);
|
||||||
expect(filter.value, filters);
|
expect(filter.value, filters);
|
||||||
expect(filter.operator, FilterOperator.nor.rawValue);
|
expect(filter.operator, FilterOperator.nor.toString());
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -189,7 +189,7 @@ void main() {
|
|||||||
final encoded = json.encode(filter);
|
final encoded = json.encode(filter);
|
||||||
expect(
|
expect(
|
||||||
encoded,
|
encoded,
|
||||||
'{"$key":{"${FilterOperator.equal.rawValue}":${json.encode(value)}}}',
|
'''{"$key":{"${FilterOperator.equal.toString()}":${json.encode(value)}}}''',
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
test('listValue', () {
|
test('listValue', () {
|
||||||
@@ -199,7 +199,7 @@ void main() {
|
|||||||
final encoded = json.encode(filter);
|
final encoded = json.encode(filter);
|
||||||
expect(
|
expect(
|
||||||
encoded,
|
encoded,
|
||||||
'{"$key":{"${FilterOperator.in_.rawValue}":${json.encode(values)}}}',
|
'''{"$key":{"${FilterOperator.in_.toString()}":${json.encode(values)}}}''',
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -243,7 +243,7 @@ void main() {
|
|||||||
final encoded = json.encode(filter);
|
final encoded = json.encode(filter);
|
||||||
expect(
|
expect(
|
||||||
encoded,
|
encoded,
|
||||||
'{"${FilterOperator.and.rawValue}":${json.encode(filters)}}',
|
'{"${FilterOperator.and.toString()}":${json.encode(filters)}}',
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
## 4.2.0
|
||||||
|
|
||||||
|
🐞 Fixed
|
||||||
|
|
||||||
|
- [[#1133]](https://github.com/GetStream/stream-chat-flutter/issues/1133) Visibility override flags not being passed to `StreamMessageActionsModal`
|
||||||
|
|
||||||
## 4.1.0
|
## 4.1.0
|
||||||
|
|
||||||
✅ Added
|
✅ Added
|
||||||
@@ -8,7 +14,9 @@
|
|||||||
🐞 Fixed
|
🐞 Fixed
|
||||||
|
|
||||||
- Fixed attachment picker ui.
|
- Fixed attachment picker ui.
|
||||||
|
- Fixed StreamChannelHeader and StreamThreadHeader subtitle alignment.
|
||||||
- Fixed message widget thread indicator in reverse mode.
|
- Fixed message widget thread indicator in reverse mode.
|
||||||
|
- [[#1044]](https://github.com/GetStream/stream-chat-flutter/issues/1044): Refactor StreamMessageWidget bottom row to use Text.rich.
|
||||||
|
|
||||||
🔄 Changed
|
🔄 Changed
|
||||||
|
|
||||||
|
|||||||
@@ -47,10 +47,10 @@ class MyApp extends StatelessWidget {
|
|||||||
/// If you'd prefer using minimal wrapper widgets for your app, please see
|
/// If you'd prefer using minimal wrapper widgets for your app, please see
|
||||||
/// our other package, `stream_chat_flutter_core`.
|
/// our other package, `stream_chat_flutter_core`.
|
||||||
const MyApp({
|
const MyApp({
|
||||||
Key? key,
|
super.key,
|
||||||
required this.client,
|
required this.client,
|
||||||
required this.channel,
|
required this.channel,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
/// Instance of Stream Client.
|
/// Instance of Stream Client.
|
||||||
///
|
///
|
||||||
@@ -94,8 +94,8 @@ class MyApp extends StatelessWidget {
|
|||||||
class ChannelPage extends StatelessWidget {
|
class ChannelPage extends StatelessWidget {
|
||||||
/// Creates the page that shows the list of messages
|
/// Creates the page that shows the list of messages
|
||||||
const ChannelPage({
|
const ChannelPage({
|
||||||
Key? key,
|
super.key,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => Scaffold(
|
Widget build(BuildContext context) => Scaffold(
|
||||||
|
|||||||
@@ -22,9 +22,9 @@ void main() async {
|
|||||||
|
|
||||||
class MyApp extends StatelessWidget {
|
class MyApp extends StatelessWidget {
|
||||||
const MyApp({
|
const MyApp({
|
||||||
Key? key,
|
super.key,
|
||||||
required this.client,
|
required this.client,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
final StreamChatClient client;
|
final StreamChatClient client;
|
||||||
|
|
||||||
@@ -40,8 +40,8 @@ class MyApp extends StatelessWidget {
|
|||||||
|
|
||||||
class SplitView extends StatefulWidget {
|
class SplitView extends StatefulWidget {
|
||||||
const SplitView({
|
const SplitView({
|
||||||
Key? key,
|
super.key,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_SplitViewState createState() => _SplitViewState();
|
_SplitViewState createState() => _SplitViewState();
|
||||||
@@ -86,9 +86,9 @@ class _SplitViewState extends State<SplitView> {
|
|||||||
|
|
||||||
class ChannelListPage extends StatefulWidget {
|
class ChannelListPage extends StatefulWidget {
|
||||||
const ChannelListPage({
|
const ChannelListPage({
|
||||||
Key? key,
|
super.key,
|
||||||
this.onTap,
|
this.onTap,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
final void Function(Channel)? onTap;
|
final void Function(Channel)? onTap;
|
||||||
|
|
||||||
@@ -118,8 +118,8 @@ class _ChannelListPageState extends State<ChannelListPage> {
|
|||||||
|
|
||||||
class ChannelPage extends StatelessWidget {
|
class ChannelPage extends StatelessWidget {
|
||||||
const ChannelPage({
|
const ChannelPage({
|
||||||
Key? key,
|
super.key,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => Navigator(
|
Widget build(BuildContext context) => Navigator(
|
||||||
|
|||||||
@@ -58,10 +58,10 @@ void main() async {
|
|||||||
|
|
||||||
class MyApp extends StatelessWidget {
|
class MyApp extends StatelessWidget {
|
||||||
const MyApp({
|
const MyApp({
|
||||||
Key? key,
|
super.key,
|
||||||
required this.client,
|
required this.client,
|
||||||
required this.channel,
|
required this.channel,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
final StreamChatClient client;
|
final StreamChatClient client;
|
||||||
|
|
||||||
@@ -86,8 +86,8 @@ class MyApp extends StatelessWidget {
|
|||||||
|
|
||||||
class ChannelPage extends StatelessWidget {
|
class ChannelPage extends StatelessWidget {
|
||||||
const ChannelPage({
|
const ChannelPage({
|
||||||
Key? key,
|
super.key,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => Scaffold(
|
Widget build(BuildContext context) => Scaffold(
|
||||||
|
|||||||
@@ -51,9 +51,9 @@ void main() async {
|
|||||||
|
|
||||||
class MyApp extends StatelessWidget {
|
class MyApp extends StatelessWidget {
|
||||||
const MyApp({
|
const MyApp({
|
||||||
Key? key,
|
super.key,
|
||||||
required this.client,
|
required this.client,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
final StreamChatClient client;
|
final StreamChatClient client;
|
||||||
|
|
||||||
@@ -73,9 +73,9 @@ class MyApp extends StatelessWidget {
|
|||||||
|
|
||||||
class ChannelListPage extends StatefulWidget {
|
class ChannelListPage extends StatefulWidget {
|
||||||
const ChannelListPage({
|
const ChannelListPage({
|
||||||
Key? key,
|
super.key,
|
||||||
required this.client,
|
required this.client,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
final StreamChatClient client;
|
final StreamChatClient client;
|
||||||
|
|
||||||
@@ -121,8 +121,8 @@ class _ChannelListPageState extends State<ChannelListPage> {
|
|||||||
|
|
||||||
class ChannelPage extends StatelessWidget {
|
class ChannelPage extends StatelessWidget {
|
||||||
const ChannelPage({
|
const ChannelPage({
|
||||||
Key? key,
|
super.key,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => Scaffold(
|
Widget build(BuildContext context) => Scaffold(
|
||||||
|
|||||||
@@ -51,9 +51,9 @@ Future<void> main() async {
|
|||||||
|
|
||||||
class MyApp extends StatelessWidget {
|
class MyApp extends StatelessWidget {
|
||||||
const MyApp({
|
const MyApp({
|
||||||
Key? key,
|
super.key,
|
||||||
required this.client,
|
required this.client,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
final StreamChatClient client;
|
final StreamChatClient client;
|
||||||
|
|
||||||
@@ -71,8 +71,8 @@ class MyApp extends StatelessWidget {
|
|||||||
|
|
||||||
class ChannelListPage extends StatefulWidget {
|
class ChannelListPage extends StatefulWidget {
|
||||||
const ChannelListPage({
|
const ChannelListPage({
|
||||||
Key? key,
|
super.key,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<ChannelListPage> createState() => _ChannelListPageState();
|
State<ChannelListPage> createState() => _ChannelListPageState();
|
||||||
@@ -164,8 +164,8 @@ class _ChannelListPageState extends State<ChannelListPage> {
|
|||||||
|
|
||||||
class ChannelPage extends StatelessWidget {
|
class ChannelPage extends StatelessWidget {
|
||||||
const ChannelPage({
|
const ChannelPage({
|
||||||
Key? key,
|
super.key,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
|||||||
@@ -38,9 +38,9 @@ Future<void> main() async {
|
|||||||
|
|
||||||
class MyApp extends StatelessWidget {
|
class MyApp extends StatelessWidget {
|
||||||
const MyApp({
|
const MyApp({
|
||||||
Key? key,
|
super.key,
|
||||||
required this.client,
|
required this.client,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
final StreamChatClient client;
|
final StreamChatClient client;
|
||||||
|
|
||||||
@@ -58,8 +58,8 @@ class MyApp extends StatelessWidget {
|
|||||||
|
|
||||||
class ChannelListPage extends StatefulWidget {
|
class ChannelListPage extends StatefulWidget {
|
||||||
const ChannelListPage({
|
const ChannelListPage({
|
||||||
Key? key,
|
super.key,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<ChannelListPage> createState() => _ChannelListPageState();
|
State<ChannelListPage> createState() => _ChannelListPageState();
|
||||||
@@ -102,8 +102,8 @@ class _ChannelListPageState extends State<ChannelListPage> {
|
|||||||
|
|
||||||
class ChannelPage extends StatelessWidget {
|
class ChannelPage extends StatelessWidget {
|
||||||
const ChannelPage({
|
const ChannelPage({
|
||||||
Key? key,
|
super.key,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => Scaffold(
|
Widget build(BuildContext context) => Scaffold(
|
||||||
@@ -125,9 +125,9 @@ class ChannelPage extends StatelessWidget {
|
|||||||
|
|
||||||
class ThreadPage extends StatelessWidget {
|
class ThreadPage extends StatelessWidget {
|
||||||
const ThreadPage({
|
const ThreadPage({
|
||||||
Key? key,
|
super.key,
|
||||||
this.parent,
|
this.parent,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
final Message? parent;
|
final Message? parent;
|
||||||
|
|
||||||
|
|||||||
@@ -41,9 +41,9 @@ Future<void> main() async {
|
|||||||
|
|
||||||
class MyApp extends StatelessWidget {
|
class MyApp extends StatelessWidget {
|
||||||
const MyApp({
|
const MyApp({
|
||||||
Key? key,
|
super.key,
|
||||||
required this.client,
|
required this.client,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
final StreamChatClient client;
|
final StreamChatClient client;
|
||||||
|
|
||||||
@@ -61,8 +61,8 @@ class MyApp extends StatelessWidget {
|
|||||||
|
|
||||||
class ChannelListPage extends StatefulWidget {
|
class ChannelListPage extends StatefulWidget {
|
||||||
const ChannelListPage({
|
const ChannelListPage({
|
||||||
Key? key,
|
super.key,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<ChannelListPage> createState() => _ChannelListPageState();
|
State<ChannelListPage> createState() => _ChannelListPageState();
|
||||||
@@ -105,8 +105,8 @@ class _ChannelListPageState extends State<ChannelListPage> {
|
|||||||
|
|
||||||
class ChannelPage extends StatelessWidget {
|
class ChannelPage extends StatelessWidget {
|
||||||
const ChannelPage({
|
const ChannelPage({
|
||||||
Key? key,
|
super.key,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@@ -139,7 +139,7 @@ class ChannelPage extends StatelessWidget {
|
|||||||
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.all(5),
|
padding: const EdgeInsets.all(5),
|
||||||
child: Container(
|
child: DecoratedBox(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
color: color,
|
color: color,
|
||||||
|
|||||||
@@ -48,9 +48,9 @@ Future<void> main() async {
|
|||||||
|
|
||||||
class MyApp extends StatelessWidget {
|
class MyApp extends StatelessWidget {
|
||||||
const MyApp({
|
const MyApp({
|
||||||
Key? key,
|
super.key,
|
||||||
required this.client,
|
required this.client,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
final StreamChatClient client;
|
final StreamChatClient client;
|
||||||
|
|
||||||
@@ -101,8 +101,8 @@ class MyApp extends StatelessWidget {
|
|||||||
|
|
||||||
class ChannelListPage extends StatefulWidget {
|
class ChannelListPage extends StatefulWidget {
|
||||||
const ChannelListPage({
|
const ChannelListPage({
|
||||||
Key? key,
|
super.key,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<ChannelListPage> createState() => _ChannelListPageState();
|
State<ChannelListPage> createState() => _ChannelListPageState();
|
||||||
@@ -145,8 +145,8 @@ class _ChannelListPageState extends State<ChannelListPage> {
|
|||||||
|
|
||||||
class ChannelPage extends StatelessWidget {
|
class ChannelPage extends StatelessWidget {
|
||||||
const ChannelPage({
|
const ChannelPage({
|
||||||
Key? key,
|
super.key,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => Scaffold(
|
Widget build(BuildContext context) => Scaffold(
|
||||||
@@ -168,9 +168,9 @@ class ChannelPage extends StatelessWidget {
|
|||||||
|
|
||||||
class ThreadPage extends StatelessWidget {
|
class ThreadPage extends StatelessWidget {
|
||||||
const ThreadPage({
|
const ThreadPage({
|
||||||
Key? key,
|
super.key,
|
||||||
this.parent,
|
this.parent,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
final Message? parent;
|
final Message? parent;
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
|||||||
version: 1.0.0+1
|
version: 1.0.0+1
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=2.12.0 <3.0.0'
|
sdk: '>=2.17.0 <3.0.0'
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
# The following adds the Cupertino Icons font to your application.
|
# The following adds the Cupertino Icons font to your application.
|
||||||
|
|||||||
+1
-1
@@ -320,7 +320,7 @@ class _PositionedListState extends State<PositionedList> {
|
|||||||
void _schedulePositionNotificationUpdate() {
|
void _schedulePositionNotificationUpdate() {
|
||||||
if (!updateScheduled) {
|
if (!updateScheduled) {
|
||||||
updateScheduled = true;
|
updateScheduled = true;
|
||||||
SchedulerBinding.instance!.addPostFrameCallback((_) {
|
SchedulerBinding.instance.addPostFrameCallback((_) {
|
||||||
if (registeredElements.value == null) {
|
if (registeredElements.value == null) {
|
||||||
updateScheduled = false;
|
updateScheduled = false;
|
||||||
return;
|
return;
|
||||||
|
|||||||
+2
-2
@@ -439,7 +439,7 @@ class _ScrollablePositionedListState extends State<ScrollablePositionedList>
|
|||||||
}
|
}
|
||||||
if (_isTransitioning) {
|
if (_isTransitioning) {
|
||||||
_stopScroll(canceled: true);
|
_stopScroll(canceled: true);
|
||||||
SchedulerBinding.instance!.addPostFrameCallback((_) {
|
SchedulerBinding.instance.addPostFrameCallback((_) {
|
||||||
_startScroll(
|
_startScroll(
|
||||||
index: index,
|
index: index,
|
||||||
alignment: alignment,
|
alignment: alignment,
|
||||||
@@ -488,7 +488,7 @@ class _ScrollablePositionedListState extends State<ScrollablePositionedList>
|
|||||||
final startCompleter = Completer<void>();
|
final startCompleter = Completer<void>();
|
||||||
final endCompleter = Completer<void>();
|
final endCompleter = Completer<void>();
|
||||||
startAnimationCallback = () {
|
startAnimationCallback = () {
|
||||||
SchedulerBinding.instance!.addPostFrameCallback((_) {
|
SchedulerBinding.instance.addPostFrameCallback((_) {
|
||||||
startAnimationCallback = () {};
|
startAnimationCallback = () {};
|
||||||
|
|
||||||
opacity.parent = _opacityAnimation(opacityAnimationWeights).animate(
|
opacity.parent = _opacityAnimation(opacityAnimationWeights).animate(
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
export 'attachment_upload_state_builder.dart';
|
export 'attachment_upload_state_builder.dart';
|
||||||
export 'attachment_widget.dart'
|
export 'attachment_widget.dart' show AttachmentError, AttachmentSource;
|
||||||
show AttachmentError, AttachmentSource, AttachmentSourceX;
|
|
||||||
export 'file_attachment.dart';
|
export 'file_attachment.dart';
|
||||||
export 'giphy_attachment.dart';
|
export 'giphy_attachment.dart';
|
||||||
export 'image_attachment.dart';
|
export 'image_attachment.dart';
|
||||||
|
|||||||
@@ -11,10 +11,10 @@ typedef AttachmentTitle = StreamAttachmentTitle;
|
|||||||
class StreamAttachmentTitle extends StatelessWidget {
|
class StreamAttachmentTitle extends StatelessWidget {
|
||||||
/// Supply attachment and theme for constructing title
|
/// Supply attachment and theme for constructing title
|
||||||
const StreamAttachmentTitle({
|
const StreamAttachmentTitle({
|
||||||
Key? key,
|
super.key,
|
||||||
required this.attachment,
|
required this.attachment,
|
||||||
required this.messageTheme,
|
required this.messageTheme,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
/// Theme to apply to text
|
/// Theme to apply to text
|
||||||
final StreamMessageThemeData messageTheme;
|
final StreamMessageThemeData messageTheme;
|
||||||
|
|||||||
+10
-21
@@ -19,14 +19,14 @@ typedef AttachmentUploadStateBuilder = StreamAttachmentUploadStateBuilder;
|
|||||||
class StreamAttachmentUploadStateBuilder extends StatelessWidget {
|
class StreamAttachmentUploadStateBuilder extends StatelessWidget {
|
||||||
/// Constructor for creating an [StreamAttachmentUploadStateBuilder] widget
|
/// Constructor for creating an [StreamAttachmentUploadStateBuilder] widget
|
||||||
const StreamAttachmentUploadStateBuilder({
|
const StreamAttachmentUploadStateBuilder({
|
||||||
Key? key,
|
super.key,
|
||||||
required this.message,
|
required this.message,
|
||||||
required this.attachment,
|
required this.attachment,
|
||||||
this.failedBuilder,
|
this.failedBuilder,
|
||||||
this.successBuilder,
|
this.successBuilder,
|
||||||
this.inProgressBuilder,
|
this.inProgressBuilder,
|
||||||
this.preparingBuilder,
|
this.preparingBuilder,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
/// Message which attachment is added to
|
/// Message which attachment is added to
|
||||||
final Message message;
|
final Message message;
|
||||||
@@ -85,30 +85,24 @@ class StreamAttachmentUploadStateBuilder extends StatelessWidget {
|
|||||||
|
|
||||||
class _IconButton extends StatelessWidget {
|
class _IconButton extends StatelessWidget {
|
||||||
const _IconButton({
|
const _IconButton({
|
||||||
Key? key,
|
|
||||||
this.icon,
|
this.icon,
|
||||||
this.iconSize = 24.0,
|
|
||||||
this.onPressed,
|
this.onPressed,
|
||||||
this.fillColor,
|
});
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
final Widget? icon;
|
final Widget? icon;
|
||||||
final double iconSize;
|
|
||||||
final VoidCallback? onPressed;
|
final VoidCallback? onPressed;
|
||||||
final Color? fillColor;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => SizedBox(
|
Widget build(BuildContext context) => SizedBox(
|
||||||
height: iconSize,
|
height: 24,
|
||||||
width: iconSize,
|
width: 24,
|
||||||
child: RawMaterialButton(
|
child: RawMaterialButton(
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
highlightElevation: 0,
|
highlightElevation: 0,
|
||||||
focusElevation: 0,
|
focusElevation: 0,
|
||||||
hoverElevation: 0,
|
hoverElevation: 0,
|
||||||
onPressed: onPressed,
|
onPressed: onPressed,
|
||||||
fillColor:
|
fillColor: StreamChatTheme.of(context).colorTheme.overlayDark,
|
||||||
fillColor ?? StreamChatTheme.of(context).colorTheme.overlayDark,
|
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(16),
|
borderRadius: BorderRadius.circular(16),
|
||||||
),
|
),
|
||||||
@@ -118,10 +112,7 @@ class _IconButton extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _PreparingState extends StatelessWidget {
|
class _PreparingState extends StatelessWidget {
|
||||||
const _PreparingState({
|
const _PreparingState({required this.attachmentId});
|
||||||
Key? key,
|
|
||||||
required this.attachmentId,
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
final String attachmentId;
|
final String attachmentId;
|
||||||
|
|
||||||
@@ -155,11 +146,10 @@ class _PreparingState extends StatelessWidget {
|
|||||||
|
|
||||||
class _InProgressState extends StatelessWidget {
|
class _InProgressState extends StatelessWidget {
|
||||||
const _InProgressState({
|
const _InProgressState({
|
||||||
Key? key,
|
|
||||||
required this.sent,
|
required this.sent,
|
||||||
required this.total,
|
required this.total,
|
||||||
required this.attachmentId,
|
required this.attachmentId,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
final int sent;
|
final int sent;
|
||||||
final int total;
|
final int total;
|
||||||
@@ -195,11 +185,10 @@ class _InProgressState extends StatelessWidget {
|
|||||||
|
|
||||||
class _FailedState extends StatelessWidget {
|
class _FailedState extends StatelessWidget {
|
||||||
const _FailedState({
|
const _FailedState({
|
||||||
Key? key,
|
|
||||||
this.error,
|
this.error,
|
||||||
required this.messageId,
|
required this.messageId,
|
||||||
required this.attachmentId,
|
required this.attachmentId,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
final String? error;
|
final String? error;
|
||||||
final String messageId;
|
final String messageId;
|
||||||
@@ -222,7 +211,7 @@ class _FailedState extends StatelessWidget {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
Center(
|
Center(
|
||||||
child: Container(
|
child: DecoratedBox(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
color: theme.colorTheme.overlayDark.withOpacity(0.6),
|
color: theme.colorTheme.overlayDark.withOpacity(0.6),
|
||||||
|
|||||||
@@ -7,14 +7,10 @@ enum AttachmentSource {
|
|||||||
local,
|
local,
|
||||||
|
|
||||||
/// Attachment is uploaded
|
/// Attachment is uploaded
|
||||||
network,
|
network;
|
||||||
}
|
|
||||||
|
|
||||||
/// Extension for identifying type of attachment
|
|
||||||
extension AttachmentSourceX on AttachmentSource {
|
|
||||||
/// The [when] method is the equivalent to pattern matching.
|
/// The [when] method is the equivalent to pattern matching.
|
||||||
/// Its prototype depends on the AttachmentSource defined.
|
/// Its prototype depends on the AttachmentSource defined.
|
||||||
// ignore: missing_return
|
|
||||||
T when<T>({
|
T when<T>({
|
||||||
required T Function() local,
|
required T Function() local,
|
||||||
required T Function() network,
|
required T Function() network,
|
||||||
@@ -38,13 +34,12 @@ typedef AttachmentWidget = StreamAttachmentWidget;
|
|||||||
abstract class StreamAttachmentWidget extends StatelessWidget {
|
abstract class StreamAttachmentWidget extends StatelessWidget {
|
||||||
/// Constructor for creating attachment widget
|
/// Constructor for creating attachment widget
|
||||||
const StreamAttachmentWidget({
|
const StreamAttachmentWidget({
|
||||||
Key? key,
|
super.key,
|
||||||
required this.message,
|
required this.message,
|
||||||
required this.attachment,
|
required this.attachment,
|
||||||
this.size,
|
this.size,
|
||||||
AttachmentSource? source,
|
AttachmentSource? source,
|
||||||
}) : _source = source,
|
}) : _source = source;
|
||||||
super(key: key);
|
|
||||||
|
|
||||||
/// Size of attachments
|
/// Size of attachments
|
||||||
final Size? size;
|
final Size? size;
|
||||||
@@ -68,9 +63,9 @@ abstract class StreamAttachmentWidget extends StatelessWidget {
|
|||||||
class AttachmentError extends StatelessWidget {
|
class AttachmentError extends StatelessWidget {
|
||||||
/// Constructor for creating AttachmentError
|
/// Constructor for creating AttachmentError
|
||||||
const AttachmentError({
|
const AttachmentError({
|
||||||
Key? key,
|
super.key,
|
||||||
this.size,
|
this.size,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
/// Size of error
|
/// Size of error
|
||||||
final Size? size;
|
final Size? size;
|
||||||
|
|||||||
@@ -20,19 +20,14 @@ typedef FileAttachment = StreamFileAttachment;
|
|||||||
class StreamFileAttachment extends StreamAttachmentWidget {
|
class StreamFileAttachment extends StreamAttachmentWidget {
|
||||||
/// Constructor for creating a widget when attachment is of type 'file'
|
/// Constructor for creating a widget when attachment is of type 'file'
|
||||||
const StreamFileAttachment({
|
const StreamFileAttachment({
|
||||||
Key? key,
|
super.key,
|
||||||
required Message message,
|
required super.message,
|
||||||
required Attachment attachment,
|
required super.attachment,
|
||||||
Size? size,
|
super.size,
|
||||||
this.title,
|
this.title,
|
||||||
this.trailing,
|
this.trailing,
|
||||||
this.onAttachmentTap,
|
this.onAttachmentTap,
|
||||||
}) : super(
|
});
|
||||||
key: key,
|
|
||||||
message: message,
|
|
||||||
attachment: attachment,
|
|
||||||
size: size,
|
|
||||||
);
|
|
||||||
|
|
||||||
/// Title for attachment
|
/// Title for attachment
|
||||||
final Widget? title;
|
final Widget? title;
|
||||||
|
|||||||
@@ -15,19 +15,14 @@ typedef GiphyAttachment = StreamGiphyAttachment;
|
|||||||
class StreamGiphyAttachment extends StreamAttachmentWidget {
|
class StreamGiphyAttachment extends StreamAttachmentWidget {
|
||||||
/// Constructor for creating a [StreamGiphyAttachment] widget
|
/// Constructor for creating a [StreamGiphyAttachment] widget
|
||||||
const StreamGiphyAttachment({
|
const StreamGiphyAttachment({
|
||||||
Key? key,
|
super.key,
|
||||||
required Message message,
|
required super.message,
|
||||||
required Attachment attachment,
|
required super.attachment,
|
||||||
Size? size,
|
super.size,
|
||||||
this.onShowMessage,
|
this.onShowMessage,
|
||||||
this.onReturnAction,
|
this.onReturnAction,
|
||||||
this.onAttachmentTap,
|
this.onAttachmentTap,
|
||||||
}) : super(
|
});
|
||||||
key: key,
|
|
||||||
message: message,
|
|
||||||
attachment: attachment,
|
|
||||||
size: size,
|
|
||||||
);
|
|
||||||
|
|
||||||
/// Callback when show message is tapped
|
/// Callback when show message is tapped
|
||||||
final ShowMessageCallback? onShowMessage;
|
final ShowMessageCallback? onShowMessage;
|
||||||
|
|||||||
@@ -15,21 +15,16 @@ typedef ImageAttachment = StreamImageAttachment;
|
|||||||
class StreamImageAttachment extends StreamAttachmentWidget {
|
class StreamImageAttachment extends StreamAttachmentWidget {
|
||||||
/// Constructor for creating a [StreamImageAttachment] widget
|
/// Constructor for creating a [StreamImageAttachment] widget
|
||||||
const StreamImageAttachment({
|
const StreamImageAttachment({
|
||||||
Key? key,
|
super.key,
|
||||||
required Message message,
|
required super.message,
|
||||||
required Attachment attachment,
|
required super.attachment,
|
||||||
required this.messageTheme,
|
required this.messageTheme,
|
||||||
Size? size,
|
super.size,
|
||||||
this.showTitle = false,
|
this.showTitle = false,
|
||||||
this.onShowMessage,
|
this.onShowMessage,
|
||||||
this.onReturnAction,
|
this.onReturnAction,
|
||||||
this.onAttachmentTap,
|
this.onAttachmentTap,
|
||||||
}) : super(
|
});
|
||||||
key: key,
|
|
||||||
message: message,
|
|
||||||
attachment: attachment,
|
|
||||||
size: size,
|
|
||||||
);
|
|
||||||
|
|
||||||
/// [StreamMessageThemeData] for showing image title
|
/// [StreamMessageThemeData] for showing image title
|
||||||
final StreamMessageThemeData messageTheme;
|
final StreamMessageThemeData messageTheme;
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ typedef UrlAttachment = StreamUrlAttachment;
|
|||||||
class StreamUrlAttachment extends StatelessWidget {
|
class StreamUrlAttachment extends StatelessWidget {
|
||||||
/// Constructor for creating a [StreamUrlAttachment]
|
/// Constructor for creating a [StreamUrlAttachment]
|
||||||
const StreamUrlAttachment({
|
const StreamUrlAttachment({
|
||||||
Key? key,
|
super.key,
|
||||||
required this.urlAttachment,
|
required this.urlAttachment,
|
||||||
required this.hostDisplayName,
|
required this.hostDisplayName,
|
||||||
required this.messageTheme,
|
required this.messageTheme,
|
||||||
@@ -21,7 +21,7 @@ class StreamUrlAttachment extends StatelessWidget {
|
|||||||
vertical: 8,
|
vertical: 8,
|
||||||
),
|
),
|
||||||
this.onLinkTap,
|
this.onLinkTap,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
/// Attachment to be displayed
|
/// Attachment to be displayed
|
||||||
final Attachment urlAttachment;
|
final Attachment urlAttachment;
|
||||||
@@ -70,7 +70,7 @@ class StreamUrlAttachment extends StatelessWidget {
|
|||||||
Positioned(
|
Positioned(
|
||||||
left: 0,
|
left: 0,
|
||||||
bottom: -1,
|
bottom: -1,
|
||||||
child: Container(
|
child: DecoratedBox(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: const BorderRadius.only(
|
borderRadius: const BorderRadius.only(
|
||||||
topRight: Radius.circular(16),
|
topRight: Radius.circular(16),
|
||||||
|
|||||||
@@ -14,20 +14,15 @@ typedef VideoAttachment = StreamVideoAttachment;
|
|||||||
class StreamVideoAttachment extends StreamAttachmentWidget {
|
class StreamVideoAttachment extends StreamAttachmentWidget {
|
||||||
/// Constructor for creating a [StreamVideoAttachment] widget
|
/// Constructor for creating a [StreamVideoAttachment] widget
|
||||||
const StreamVideoAttachment({
|
const StreamVideoAttachment({
|
||||||
Key? key,
|
super.key,
|
||||||
required Message message,
|
required super.message,
|
||||||
required Attachment attachment,
|
required super.attachment,
|
||||||
required this.messageTheme,
|
required this.messageTheme,
|
||||||
Size? size,
|
super.size,
|
||||||
this.onShowMessage,
|
this.onShowMessage,
|
||||||
this.onReturnAction,
|
this.onReturnAction,
|
||||||
this.onAttachmentTap,
|
this.onAttachmentTap,
|
||||||
}) : super(
|
});
|
||||||
key: key,
|
|
||||||
message: message,
|
|
||||||
attachment: attachment,
|
|
||||||
size: size,
|
|
||||||
);
|
|
||||||
|
|
||||||
/// [StreamMessageThemeData] for showing title
|
/// [StreamMessageThemeData] for showing title
|
||||||
final StreamMessageThemeData messageTheme;
|
final StreamMessageThemeData messageTheme;
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ typedef DownloadedPathCallback = void Function(String? path);
|
|||||||
class AttachmentActionsModal extends StatelessWidget {
|
class AttachmentActionsModal extends StatelessWidget {
|
||||||
/// Returns a new [AttachmentActionsModal]
|
/// Returns a new [AttachmentActionsModal]
|
||||||
const AttachmentActionsModal({
|
const AttachmentActionsModal({
|
||||||
Key? key,
|
super.key,
|
||||||
required this.attachment,
|
required this.attachment,
|
||||||
required this.message,
|
required this.message,
|
||||||
this.onShowMessage,
|
this.onShowMessage,
|
||||||
@@ -30,7 +30,7 @@ class AttachmentActionsModal extends StatelessWidget {
|
|||||||
this.showSave = true,
|
this.showSave = true,
|
||||||
this.showDelete = true,
|
this.showDelete = true,
|
||||||
this.customActions = const [],
|
this.customActions = const [],
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
/// The attachment object for which the actions are to be performed
|
/// The attachment object for which the actions are to be performed
|
||||||
final Attachment attachment;
|
final Attachment attachment;
|
||||||
|
|||||||
@@ -6,11 +6,11 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
|||||||
class StreamBackButton extends StatelessWidget {
|
class StreamBackButton extends StatelessWidget {
|
||||||
/// Constructor for creating back button
|
/// Constructor for creating back button
|
||||||
const StreamBackButton({
|
const StreamBackButton({
|
||||||
Key? key,
|
super.key,
|
||||||
this.onPressed,
|
this.onPressed,
|
||||||
this.showUnreads = false,
|
this.showUnreads = false,
|
||||||
this.cid,
|
this.cid,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
/// Callback for when button is pressed
|
/// Callback for when button is pressed
|
||||||
final VoidCallback? onPressed;
|
final VoidCallback? onPressed;
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
|||||||
class ChannelAvatar extends StatelessWidget {
|
class ChannelAvatar extends StatelessWidget {
|
||||||
/// Instantiate a new ChannelImage
|
/// Instantiate a new ChannelImage
|
||||||
const ChannelAvatar({
|
const ChannelAvatar({
|
||||||
Key? key,
|
super.key,
|
||||||
this.channel,
|
this.channel,
|
||||||
this.constraints,
|
this.constraints,
|
||||||
this.onTap,
|
this.onTap,
|
||||||
@@ -60,7 +60,7 @@ class ChannelAvatar extends StatelessWidget {
|
|||||||
this.selected = false,
|
this.selected = false,
|
||||||
this.selectionColor,
|
this.selectionColor,
|
||||||
this.selectionThickness = 4,
|
this.selectionThickness = 4,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
/// [BorderRadius] to display the widget
|
/// [BorderRadius] to display the widget
|
||||||
final BorderRadius? borderRadius;
|
final BorderRadius? borderRadius;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
|||||||
@Deprecated("Use 'StreamChannelInfoBottomSheet' instead")
|
@Deprecated("Use 'StreamChannelInfoBottomSheet' instead")
|
||||||
class ChannelBottomSheet extends StatefulWidget {
|
class ChannelBottomSheet extends StatefulWidget {
|
||||||
/// Constructor for creating bottom sheet
|
/// Constructor for creating bottom sheet
|
||||||
const ChannelBottomSheet({Key? key, this.onViewInfoTap}) : super(key: key);
|
const ChannelBottomSheet({super.key, this.onViewInfoTap});
|
||||||
|
|
||||||
/// Callback when 'View Info' is tapped
|
/// Callback when 'View Info' is tapped
|
||||||
final VoidCallback? onViewInfoTap;
|
final VoidCallback? onViewInfoTap;
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ class StreamChannelHeader extends StatelessWidget
|
|||||||
implements PreferredSizeWidget {
|
implements PreferredSizeWidget {
|
||||||
/// Creates a channel header
|
/// Creates a channel header
|
||||||
const StreamChannelHeader({
|
const StreamChannelHeader({
|
||||||
Key? key,
|
super.key,
|
||||||
this.showBackButton = true,
|
this.showBackButton = true,
|
||||||
this.onBackPressed,
|
this.onBackPressed,
|
||||||
this.onTitleTap,
|
this.onTitleTap,
|
||||||
@@ -74,8 +74,7 @@ class StreamChannelHeader extends StatelessWidget
|
|||||||
this.actions,
|
this.actions,
|
||||||
this.backgroundColor,
|
this.backgroundColor,
|
||||||
this.elevation = 1,
|
this.elevation = 1,
|
||||||
}) : preferredSize = const Size.fromHeight(kToolbarHeight),
|
}) : preferredSize = const Size.fromHeight(kToolbarHeight);
|
||||||
super(key: key);
|
|
||||||
|
|
||||||
/// True if this header shows the leading back button
|
/// True if this header shows the leading back button
|
||||||
final bool showBackButton;
|
final bool showBackButton;
|
||||||
|
|||||||
@@ -13,12 +13,12 @@ typedef ChannelInfo = StreamChannelInfo;
|
|||||||
class StreamChannelInfo extends StatelessWidget {
|
class StreamChannelInfo extends StatelessWidget {
|
||||||
/// Constructor which creates a [StreamChannelInfo] widget
|
/// Constructor which creates a [StreamChannelInfo] widget
|
||||||
const StreamChannelInfo({
|
const StreamChannelInfo({
|
||||||
Key? key,
|
super.key,
|
||||||
required this.channel,
|
required this.channel,
|
||||||
this.textStyle,
|
this.textStyle,
|
||||||
this.showTypingIndicator = true,
|
this.showTypingIndicator = true,
|
||||||
this.parentId,
|
this.parentId,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
/// The channel about which the info is to be displayed
|
/// The channel about which the info is to be displayed
|
||||||
final Channel channel;
|
final Channel channel;
|
||||||
@@ -100,12 +100,10 @@ class StreamChannelInfo extends StatelessWidget {
|
|||||||
return alternativeWidget ?? const Offstage();
|
return alternativeWidget ?? const Offstage();
|
||||||
}
|
}
|
||||||
|
|
||||||
return Align(
|
return StreamTypingIndicator(
|
||||||
child: StreamTypingIndicator(
|
parentId: parentId,
|
||||||
parentId: parentId,
|
style: textStyle,
|
||||||
style: textStyle,
|
alternativeWidget: alternativeWidget,
|
||||||
alternativeWidget: alternativeWidget,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,7 +138,7 @@ class StreamChannelInfo extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
style: TextButton.styleFrom(
|
style: TextButton.styleFrom(
|
||||||
padding: const EdgeInsets.all(0),
|
padding: EdgeInsets.zero,
|
||||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||||
visualDensity: const VisualDensity(
|
visualDensity: const VisualDensity(
|
||||||
horizontal: VisualDensity.minimumDensity,
|
horizontal: VisualDensity.minimumDensity,
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ class StreamChannelListHeader extends StatelessWidget
|
|||||||
implements PreferredSizeWidget {
|
implements PreferredSizeWidget {
|
||||||
/// Instantiates a ChannelListHeader
|
/// Instantiates a ChannelListHeader
|
||||||
const StreamChannelListHeader({
|
const StreamChannelListHeader({
|
||||||
Key? key,
|
super.key,
|
||||||
this.client,
|
this.client,
|
||||||
this.titleBuilder,
|
this.titleBuilder,
|
||||||
this.onUserAvatarTap,
|
this.onUserAvatarTap,
|
||||||
@@ -67,7 +67,7 @@ class StreamChannelListHeader extends StatelessWidget
|
|||||||
this.actions,
|
this.actions,
|
||||||
this.backgroundColor,
|
this.backgroundColor,
|
||||||
this.elevation = 1,
|
this.elevation = 1,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
/// Pass this if you don't have a [StreamChatClient] in your widget tree.
|
/// Pass this if you don't have a [StreamChatClient] in your widget tree.
|
||||||
final StreamChatClient? client;
|
final StreamChatClient? client;
|
||||||
@@ -155,9 +155,7 @@ class StreamChannelListHeader extends StatelessWidget
|
|||||||
showOnlineStatus: false,
|
showOnlineStatus: false,
|
||||||
onTap: onUserAvatarTap ??
|
onTap: onUserAvatarTap ??
|
||||||
(_) {
|
(_) {
|
||||||
if (preNavigationCallback != null) {
|
preNavigationCallback?.call();
|
||||||
preNavigationCallback!();
|
|
||||||
}
|
|
||||||
Scaffold.of(context).openDrawer();
|
Scaffold.of(context).openDrawer();
|
||||||
},
|
},
|
||||||
borderRadius: channelListHeaderThemeData
|
borderRadius: channelListHeaderThemeData
|
||||||
|
|||||||
@@ -57,8 +57,9 @@ typedef ViewInfoCallback = void Function(Channel);
|
|||||||
@Deprecated("Use 'StreamChannelListView' instead")
|
@Deprecated("Use 'StreamChannelListView' instead")
|
||||||
class ChannelListView extends StatefulWidget {
|
class ChannelListView extends StatefulWidget {
|
||||||
/// Instantiate a new ChannelListView
|
/// Instantiate a new ChannelListView
|
||||||
|
@Deprecated("Use 'StreamChannelListView' instead")
|
||||||
ChannelListView({
|
ChannelListView({
|
||||||
Key? key,
|
super.key,
|
||||||
this.filter,
|
this.filter,
|
||||||
this.sort,
|
this.sort,
|
||||||
this.state = true,
|
this.state = true,
|
||||||
@@ -93,8 +94,7 @@ class ChannelListView extends StatefulWidget {
|
|||||||
this.onDeletePressed,
|
this.onDeletePressed,
|
||||||
this.swipeActions,
|
this.swipeActions,
|
||||||
this.channelListController,
|
this.channelListController,
|
||||||
}) : limit = limit ?? pagination?.limit ?? 25,
|
}) : limit = limit ?? pagination?.limit ?? 25;
|
||||||
super(key: key);
|
|
||||||
|
|
||||||
/// If true a default swipe to action behaviour will be added to this widget
|
/// If true a default swipe to action behaviour will be added to this widget
|
||||||
final bool swipeToAction;
|
final bool swipeToAction;
|
||||||
@@ -688,7 +688,7 @@ class _ChannelListViewState extends State<ChannelListView> {
|
|||||||
initialData: false,
|
initialData: false,
|
||||||
errorBuilder: (context, err) {
|
errorBuilder: (context, err) {
|
||||||
final theme = StreamChatTheme.of(context);
|
final theme = StreamChatTheme.of(context);
|
||||||
return Container(
|
return ColoredBox(
|
||||||
color: theme.colorTheme.textLowEmphasis.withOpacity(0.9),
|
color: theme.colorTheme.textLowEmphasis.withOpacity(0.9),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
|
|||||||
@@ -10,10 +10,10 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
|||||||
class ChannelName extends StatelessWidget {
|
class ChannelName extends StatelessWidget {
|
||||||
/// Instantiate a new ChannelName
|
/// Instantiate a new ChannelName
|
||||||
const ChannelName({
|
const ChannelName({
|
||||||
Key? key,
|
super.key,
|
||||||
this.textStyle,
|
this.textStyle,
|
||||||
this.textOverflow = TextOverflow.ellipsis,
|
this.textOverflow = TextOverflow.ellipsis,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
/// The style of the text displayed
|
/// The style of the text displayed
|
||||||
final TextStyle? textStyle;
|
final TextStyle? textStyle;
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ class ChannelPreview extends StatelessWidget {
|
|||||||
/// Constructor for creating [ChannelPreview]
|
/// Constructor for creating [ChannelPreview]
|
||||||
const ChannelPreview({
|
const ChannelPreview({
|
||||||
required this.channel,
|
required this.channel,
|
||||||
Key? key,
|
super.key,
|
||||||
this.onTap,
|
this.onTap,
|
||||||
this.onLongPress,
|
this.onLongPress,
|
||||||
this.onImageTap,
|
this.onImageTap,
|
||||||
@@ -34,7 +34,7 @@ class ChannelPreview extends StatelessWidget {
|
|||||||
this.leading,
|
this.leading,
|
||||||
this.sendingIndicator,
|
this.sendingIndicator,
|
||||||
this.trailing,
|
this.trailing,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
/// Function called when tapping this widget
|
/// Function called when tapping this widget
|
||||||
final void Function(Channel)? onTap;
|
final void Function(Channel)? onTap;
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ class StreamCommandsOverlay extends StatelessWidget {
|
|||||||
required this.onCommandResult,
|
required this.onCommandResult,
|
||||||
required this.size,
|
required this.size,
|
||||||
required this.channel,
|
required this.channel,
|
||||||
Key? key,
|
super.key,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
/// The size of the overlay
|
/// The size of the overlay
|
||||||
final Size size;
|
final Size size;
|
||||||
@@ -60,7 +60,7 @@ class StreamCommandsOverlay extends StatelessWidget {
|
|||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
),
|
),
|
||||||
child: ListView(
|
child: ListView(
|
||||||
padding: const EdgeInsets.all(0),
|
padding: EdgeInsets.zero,
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
children: [
|
children: [
|
||||||
if (commands.isNotEmpty)
|
if (commands.isNotEmpty)
|
||||||
|
|||||||
@@ -15,12 +15,12 @@ typedef ConnectionStatusBuilder = StreamConnectionStatusBuilder;
|
|||||||
class StreamConnectionStatusBuilder extends StatelessWidget {
|
class StreamConnectionStatusBuilder extends StatelessWidget {
|
||||||
/// Creates a new ConnectionStatusBuilder
|
/// Creates a new ConnectionStatusBuilder
|
||||||
const StreamConnectionStatusBuilder({
|
const StreamConnectionStatusBuilder({
|
||||||
Key? key,
|
super.key,
|
||||||
required this.statusBuilder,
|
required this.statusBuilder,
|
||||||
this.connectionStatusStream,
|
this.connectionStatusStream,
|
||||||
this.errorBuilder,
|
this.errorBuilder,
|
||||||
this.loadingBuilder,
|
this.loadingBuilder,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
/// The asynchronous computation to which this builder is currently connected.
|
/// The asynchronous computation to which this builder is currently connected.
|
||||||
final Stream<ConnectionStatus>? connectionStatusStream;
|
final Stream<ConnectionStatus>? connectionStatusStream;
|
||||||
|
|||||||
@@ -13,10 +13,10 @@ typedef DateDivider = StreamDateDivider;
|
|||||||
class StreamDateDivider extends StatelessWidget {
|
class StreamDateDivider extends StatelessWidget {
|
||||||
/// Constructor for creating a [StreamDateDivider]
|
/// Constructor for creating a [StreamDateDivider]
|
||||||
const StreamDateDivider({
|
const StreamDateDivider({
|
||||||
Key? key,
|
super.key,
|
||||||
required this.dateTime,
|
required this.dateTime,
|
||||||
this.uppercase = false,
|
this.uppercase = false,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
/// [DateTime] to display
|
/// [DateTime] to display
|
||||||
final DateTime dateTime;
|
final DateTime dateTime;
|
||||||
|
|||||||
@@ -13,13 +13,13 @@ typedef DeletedMessage = StreamDeletedMessage;
|
|||||||
class StreamDeletedMessage extends StatelessWidget {
|
class StreamDeletedMessage extends StatelessWidget {
|
||||||
/// Constructor to create [StreamDeletedMessage]
|
/// Constructor to create [StreamDeletedMessage]
|
||||||
const StreamDeletedMessage({
|
const StreamDeletedMessage({
|
||||||
Key? key,
|
super.key,
|
||||||
required this.messageTheme,
|
required this.messageTheme,
|
||||||
this.borderRadiusGeometry,
|
this.borderRadiusGeometry,
|
||||||
this.shape,
|
this.shape,
|
||||||
this.borderSide,
|
this.borderSide,
|
||||||
this.reverse = false,
|
this.reverse = false,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
/// The theme of the message
|
/// The theme of the message
|
||||||
final StreamMessageThemeData messageTheme;
|
final StreamMessageThemeData messageTheme;
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ class StreamEmojiOverlay extends StatelessWidget {
|
|||||||
required this.query,
|
required this.query,
|
||||||
required this.onEmojiResult,
|
required this.onEmojiResult,
|
||||||
required this.size,
|
required this.size,
|
||||||
Key? key,
|
super.key,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
/// The size of the overlay
|
/// The size of the overlay
|
||||||
final Size size;
|
final Size size;
|
||||||
@@ -65,7 +65,7 @@ class StreamEmojiOverlay extends StatelessWidget {
|
|||||||
color: _streamChatTheme.colorTheme.barsBg,
|
color: _streamChatTheme.colorTheme.barsBg,
|
||||||
),
|
),
|
||||||
child: ListView.builder(
|
child: ListView.builder(
|
||||||
padding: const EdgeInsets.all(0),
|
padding: EdgeInsets.zero,
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
itemCount: emojis.length + 1,
|
itemCount: emojis.length + 1,
|
||||||
itemBuilder: (context, i) {
|
itemBuilder: (context, i) {
|
||||||
|
|||||||
@@ -31,15 +31,14 @@ typedef FullScreenMedia = StreamFullScreenMedia;
|
|||||||
class StreamFullScreenMedia extends StatefulWidget {
|
class StreamFullScreenMedia extends StatefulWidget {
|
||||||
/// Instantiate a new FullScreenImage
|
/// Instantiate a new FullScreenImage
|
||||||
const StreamFullScreenMedia({
|
const StreamFullScreenMedia({
|
||||||
Key? key,
|
super.key,
|
||||||
required this.mediaAttachmentPackages,
|
required this.mediaAttachmentPackages,
|
||||||
this.startIndex = 0,
|
this.startIndex = 0,
|
||||||
String? userName,
|
String? userName,
|
||||||
this.onShowMessage,
|
this.onShowMessage,
|
||||||
this.attachmentActionsModalBuilder,
|
this.attachmentActionsModalBuilder,
|
||||||
this.autoplayVideos = false,
|
this.autoplayVideos = false,
|
||||||
}) : userName = userName ?? '',
|
}) : userName = userName ?? '';
|
||||||
super(key: key);
|
|
||||||
|
|
||||||
/// The url of the image
|
/// The url of the image
|
||||||
final List<StreamAttachmentPackage> mediaAttachmentPackages;
|
final List<StreamAttachmentPackage> mediaAttachmentPackages;
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ class StreamGalleryFooter extends StatefulWidget
|
|||||||
implements PreferredSizeWidget {
|
implements PreferredSizeWidget {
|
||||||
/// Creates a StreamGalleryFooter
|
/// Creates a StreamGalleryFooter
|
||||||
const StreamGalleryFooter({
|
const StreamGalleryFooter({
|
||||||
Key? key,
|
super.key,
|
||||||
this.onBackPressed,
|
this.onBackPressed,
|
||||||
this.onTitleTap,
|
this.onTitleTap,
|
||||||
this.onImageTap,
|
this.onImageTap,
|
||||||
@@ -29,8 +29,7 @@ class StreamGalleryFooter extends StatefulWidget
|
|||||||
required this.mediaAttachmentPackages,
|
required this.mediaAttachmentPackages,
|
||||||
this.mediaSelectedCallBack,
|
this.mediaSelectedCallBack,
|
||||||
this.backgroundColor,
|
this.backgroundColor,
|
||||||
}) : preferredSize = const Size.fromHeight(kToolbarHeight),
|
}) : preferredSize = const Size.fromHeight(kToolbarHeight);
|
||||||
super(key: key);
|
|
||||||
|
|
||||||
/// Callback to call when pressing the back button.
|
/// Callback to call when pressing the back button.
|
||||||
/// By default it calls [Navigator.pop]
|
/// By default it calls [Navigator.pop]
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ class StreamGalleryHeader extends StatelessWidget
|
|||||||
implements PreferredSizeWidget {
|
implements PreferredSizeWidget {
|
||||||
/// Creates a channel header
|
/// Creates a channel header
|
||||||
const StreamGalleryHeader({
|
const StreamGalleryHeader({
|
||||||
Key? key,
|
super.key,
|
||||||
required this.message,
|
required this.message,
|
||||||
required this.attachment,
|
required this.attachment,
|
||||||
this.showBackButton = true,
|
this.showBackButton = true,
|
||||||
@@ -38,8 +38,7 @@ class StreamGalleryHeader extends StatelessWidget
|
|||||||
this.sentAt = '',
|
this.sentAt = '',
|
||||||
this.backgroundColor,
|
this.backgroundColor,
|
||||||
this.attachmentActionsModalBuilder,
|
this.attachmentActionsModalBuilder,
|
||||||
}) : preferredSize = const Size.fromHeight(kToolbarHeight),
|
}) : preferredSize = const Size.fromHeight(kToolbarHeight);
|
||||||
super(key: key);
|
|
||||||
|
|
||||||
/// True if this header shows the leading back button
|
/// True if this header shows the leading back button
|
||||||
final bool showBackButton;
|
final bool showBackButton;
|
||||||
|
|||||||
@@ -13,10 +13,10 @@ typedef GradientAvatar = StreamGradientAvatar;
|
|||||||
class StreamGradientAvatar extends StatefulWidget {
|
class StreamGradientAvatar extends StatefulWidget {
|
||||||
/// Constructor for [StreamGradientAvatar]
|
/// Constructor for [StreamGradientAvatar]
|
||||||
const StreamGradientAvatar({
|
const StreamGradientAvatar({
|
||||||
Key? key,
|
super.key,
|
||||||
required this.name,
|
required this.name,
|
||||||
required this.userId,
|
required this.userId,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
/// Name of user to shorten and display
|
/// Name of user to shorten and display
|
||||||
final String name;
|
final String name;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ typedef GroupAvatar = StreamGroupAvatar;
|
|||||||
class StreamGroupAvatar extends StatelessWidget {
|
class StreamGroupAvatar extends StatelessWidget {
|
||||||
/// Constructor for creating a [StreamGroupAvatar]
|
/// Constructor for creating a [StreamGroupAvatar]
|
||||||
const StreamGroupAvatar({
|
const StreamGroupAvatar({
|
||||||
Key? key,
|
super.key,
|
||||||
this.channel,
|
this.channel,
|
||||||
required this.members,
|
required this.members,
|
||||||
this.constraints,
|
this.constraints,
|
||||||
@@ -20,7 +20,7 @@ class StreamGroupAvatar extends StatelessWidget {
|
|||||||
this.selected = false,
|
this.selected = false,
|
||||||
this.selectionColor,
|
this.selectionColor,
|
||||||
this.selectionThickness = 4,
|
this.selectionThickness = 4,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
/// The channel of the avatar
|
/// The channel of the avatar
|
||||||
final Channel? channel;
|
final Channel? channel;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ typedef ImageGroup = StreamImageGroup;
|
|||||||
class StreamImageGroup extends StatelessWidget {
|
class StreamImageGroup extends StatelessWidget {
|
||||||
/// Constructor for creating [StreamImageGroup] widget
|
/// Constructor for creating [StreamImageGroup] widget
|
||||||
const StreamImageGroup({
|
const StreamImageGroup({
|
||||||
Key? key,
|
super.key,
|
||||||
required this.images,
|
required this.images,
|
||||||
required this.message,
|
required this.message,
|
||||||
required this.messageTheme,
|
required this.messageTheme,
|
||||||
@@ -19,7 +19,7 @@ class StreamImageGroup extends StatelessWidget {
|
|||||||
this.onReturnAction,
|
this.onReturnAction,
|
||||||
this.onShowMessage,
|
this.onShowMessage,
|
||||||
this.onAttachmentTap,
|
this.onAttachmentTap,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
/// List of attachments to show
|
/// List of attachments to show
|
||||||
final List<Attachment> images;
|
final List<Attachment> images;
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ typedef InfoTile = StreamInfoTile;
|
|||||||
class StreamInfoTile extends StatelessWidget {
|
class StreamInfoTile extends StatelessWidget {
|
||||||
/// Constructor for creating an [StreamInfoTile] widget
|
/// Constructor for creating an [StreamInfoTile] widget
|
||||||
const StreamInfoTile({
|
const StreamInfoTile({
|
||||||
Key? key,
|
super.key,
|
||||||
required this.message,
|
required this.message,
|
||||||
required this.child,
|
required this.child,
|
||||||
required this.showMessage,
|
required this.showMessage,
|
||||||
@@ -20,7 +20,7 @@ class StreamInfoTile extends StatelessWidget {
|
|||||||
this.childAnchor,
|
this.childAnchor,
|
||||||
this.textStyle,
|
this.textStyle,
|
||||||
this.backgroundColor,
|
this.backgroundColor,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
/// String to display
|
/// String to display
|
||||||
final String message;
|
final String message;
|
||||||
|
|||||||
@@ -391,7 +391,7 @@ class DefaultTranslations implements Translations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get sendMessagePermissionError =>
|
String get sendMessagePermissionError =>
|
||||||
'You don\'t have permission to send messages';
|
"You don't have permission to send messages";
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get emptyMessagesText => 'There are no messages currently';
|
String get emptyMessagesText => 'There are no messages currently';
|
||||||
@@ -528,7 +528,7 @@ class DefaultTranslations implements Translations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get operationCouldNotBeCompletedText =>
|
String get operationCouldNotBeCompletedText =>
|
||||||
'The operation couldn\'t be completed.';
|
"The operation couldn't be completed.";
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get replyLabel => 'Reply';
|
String get replyLabel => 'Reply';
|
||||||
|
|||||||
@@ -18,11 +18,11 @@ typedef MediaListView = StreamMediaListView;
|
|||||||
class StreamMediaListView extends StatefulWidget {
|
class StreamMediaListView extends StatefulWidget {
|
||||||
/// Constructor for creating a [StreamMediaListView] widget
|
/// Constructor for creating a [StreamMediaListView] widget
|
||||||
const StreamMediaListView({
|
const StreamMediaListView({
|
||||||
Key? key,
|
super.key,
|
||||||
this.selectedIds = const [],
|
this.selectedIds = const [],
|
||||||
this.onSelect,
|
this.onSelect,
|
||||||
this.controller,
|
this.controller,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
/// Stores the media selected
|
/// Stores the media selected
|
||||||
final List<String> selectedIds;
|
final List<String> selectedIds;
|
||||||
@@ -67,11 +67,9 @@ class _StreamMediaListViewState extends State<StreamMediaListView> {
|
|||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 1, vertical: 1),
|
padding: const EdgeInsets.symmetric(horizontal: 1, vertical: 1),
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () {
|
onTap: widget.onSelect == null
|
||||||
if (widget.onSelect != null) {
|
? null
|
||||||
widget.onSelect!(media);
|
: () => widget.onSelect!(media),
|
||||||
}
|
|
||||||
},
|
|
||||||
child: Stack(
|
child: Stack(
|
||||||
children: [
|
children: [
|
||||||
AspectRatio(
|
AspectRatio(
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ typedef MessageActionsModal = StreamMessageActionsModal;
|
|||||||
class StreamMessageActionsModal extends StatefulWidget {
|
class StreamMessageActionsModal extends StatefulWidget {
|
||||||
/// Constructor for creating a [StreamMessageActionsModal] widget
|
/// Constructor for creating a [StreamMessageActionsModal] widget
|
||||||
const StreamMessageActionsModal({
|
const StreamMessageActionsModal({
|
||||||
Key? key,
|
super.key,
|
||||||
required this.message,
|
required this.message,
|
||||||
required this.messageWidget,
|
required this.messageWidget,
|
||||||
required this.messageTheme,
|
required this.messageTheme,
|
||||||
@@ -32,7 +32,7 @@ class StreamMessageActionsModal extends StatefulWidget {
|
|||||||
this.reverse = false,
|
this.reverse = false,
|
||||||
this.customActions = const [],
|
this.customActions = const [],
|
||||||
this.onCopyTap,
|
this.onCopyTap,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
/// Widget that shows the message
|
/// Widget that shows the message
|
||||||
final Widget messageWidget;
|
final Widget messageWidget;
|
||||||
@@ -252,7 +252,7 @@ class _StreamMessageActionsModalState extends State<StreamMessageActionsModal> {
|
|||||||
sigmaX: 10,
|
sigmaX: 10,
|
||||||
sigmaY: 10,
|
sigmaY: 10,
|
||||||
),
|
),
|
||||||
child: Container(
|
child: ColoredBox(
|
||||||
color: streamChatThemeData.colorTheme.overlay,
|
color: streamChatThemeData.colorTheme.overlay,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -406,9 +406,7 @@ class _StreamMessageActionsModalState extends State<StreamMessageActionsModal> {
|
|||||||
return InkWell(
|
return InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
if (widget.onReplyTap != null) {
|
widget.onReplyTap?.call(widget.message);
|
||||||
widget.onReplyTap!(widget.message);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 11, horizontal: 16),
|
padding: const EdgeInsets.symmetric(vertical: 11, horizontal: 16),
|
||||||
@@ -660,9 +658,7 @@ class _StreamMessageActionsModalState extends State<StreamMessageActionsModal> {
|
|||||||
return InkWell(
|
return InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
if (widget.onThreadReplyTap != null) {
|
widget.onThreadReplyTap?.call(widget.message);
|
||||||
widget.onThreadReplyTap!(widget.message);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 11, horizontal: 16),
|
padding: const EdgeInsets.symmetric(vertical: 11, horizontal: 16),
|
||||||
|
|||||||
@@ -163,7 +163,7 @@ const _kDefaultMaxAttachmentSize = 20971520; // 20MB in Bytes
|
|||||||
class MessageInput extends StatefulWidget {
|
class MessageInput extends StatefulWidget {
|
||||||
/// Instantiate a new MessageInput
|
/// Instantiate a new MessageInput
|
||||||
const MessageInput({
|
const MessageInput({
|
||||||
Key? key,
|
super.key,
|
||||||
this.onMessageSent,
|
this.onMessageSent,
|
||||||
this.preMessageSending,
|
this.preMessageSending,
|
||||||
this.parentMessage,
|
this.parentMessage,
|
||||||
@@ -197,11 +197,10 @@ class MessageInput extends StatefulWidget {
|
|||||||
this.customOverlays = const [],
|
this.customOverlays = const [],
|
||||||
this.mentionAllAppUsers = false,
|
this.mentionAllAppUsers = false,
|
||||||
this.shouldKeepFocusAfterMessage,
|
this.shouldKeepFocusAfterMessage,
|
||||||
}) : assert(
|
}) : assert(
|
||||||
initialMessage == null || editMessage == null,
|
initialMessage == null || editMessage == null,
|
||||||
"Can't provide both `initialMessage` and `editMessage`",
|
"Can't provide both `initialMessage` and `editMessage`",
|
||||||
),
|
);
|
||||||
super(key: key);
|
|
||||||
|
|
||||||
/// List of options for showing overlays
|
/// List of options for showing overlays
|
||||||
final List<OverlayOptions> customOverlays;
|
final List<OverlayOptions> customOverlays;
|
||||||
@@ -628,7 +627,7 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
color: _messageInputTheme.expandButtonColor,
|
color: _messageInputTheme.expandButtonColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
padding: const EdgeInsets.all(0),
|
padding: EdgeInsets.zero,
|
||||||
constraints: const BoxConstraints.tightFor(
|
constraints: const BoxConstraints.tightFor(
|
||||||
height: 24,
|
height: 24,
|
||||||
width: 24,
|
width: 24,
|
||||||
@@ -797,7 +796,7 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
child: IconButton(
|
child: IconButton(
|
||||||
icon: StreamSvgIcon.closeSmall(),
|
icon: StreamSvgIcon.closeSmall(),
|
||||||
splashRadius: 24,
|
splashRadius: 24,
|
||||||
padding: const EdgeInsets.all(0),
|
padding: EdgeInsets.zero,
|
||||||
constraints: const BoxConstraints.tightFor(
|
constraints: const BoxConstraints.tightFor(
|
||||||
height: 24,
|
height: 24,
|
||||||
width: 24,
|
width: 24,
|
||||||
@@ -980,7 +979,7 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
return AnimatedContainer(
|
return AnimatedContainer(
|
||||||
duration: _openFilePickerSection
|
duration: _openFilePickerSection
|
||||||
? const Duration(milliseconds: 300)
|
? const Duration(milliseconds: 300)
|
||||||
: const Duration(),
|
: Duration.zero,
|
||||||
curve: Curves.easeOut,
|
curve: Curves.easeOut,
|
||||||
height: _openFilePickerSection ? _kMinMediaPickerSize : 0,
|
height: _openFilePickerSection ? _kMinMediaPickerSize : 0,
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
@@ -1034,7 +1033,7 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
padding: const EdgeInsets.all(0),
|
padding: EdgeInsets.zero,
|
||||||
icon: StreamSvgIcon.record(
|
icon: StreamSvgIcon.record(
|
||||||
color: _getIconColor(3),
|
color: _getIconColor(3),
|
||||||
),
|
),
|
||||||
@@ -1436,9 +1435,9 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
default:
|
default:
|
||||||
return Container(
|
return const ColoredBox(
|
||||||
color: Colors.black26,
|
color: Colors.black26,
|
||||||
child: const Icon(Icons.insert_drive_file),
|
child: Icon(Icons.insert_drive_file),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1453,7 +1452,7 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
? _messageInputTheme.actionButtonColor
|
? _messageInputTheme.actionButtonColor
|
||||||
: _messageInputTheme.actionButtonIdleColor),
|
: _messageInputTheme.actionButtonIdleColor),
|
||||||
),
|
),
|
||||||
padding: const EdgeInsets.all(0),
|
padding: EdgeInsets.zero,
|
||||||
constraints: const BoxConstraints.tightFor(
|
constraints: const BoxConstraints.tightFor(
|
||||||
height: 24,
|
height: 24,
|
||||||
width: 24,
|
width: 24,
|
||||||
@@ -1482,7 +1481,7 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
? _messageInputTheme.actionButtonColor
|
? _messageInputTheme.actionButtonColor
|
||||||
: _messageInputTheme.actionButtonIdleColor,
|
: _messageInputTheme.actionButtonIdleColor,
|
||||||
),
|
),
|
||||||
padding: const EdgeInsets.all(0),
|
padding: EdgeInsets.zero,
|
||||||
constraints: const BoxConstraints.tightFor(
|
constraints: const BoxConstraints.tightFor(
|
||||||
height: 24,
|
height: 24,
|
||||||
width: 24,
|
width: 24,
|
||||||
@@ -1699,7 +1698,7 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
padding: const EdgeInsets.all(8),
|
padding: const EdgeInsets.all(8),
|
||||||
child: IconButton(
|
child: IconButton(
|
||||||
onPressed: sendMessage,
|
onPressed: sendMessage,
|
||||||
padding: const EdgeInsets.all(0),
|
padding: EdgeInsets.zero,
|
||||||
splashRadius: 24,
|
splashRadius: 24,
|
||||||
constraints: const BoxConstraints.tightFor(
|
constraints: const BoxConstraints.tightFor(
|
||||||
height: 24,
|
height: 24,
|
||||||
@@ -1926,7 +1925,6 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
|
|
||||||
class _PickerWidget extends StatefulWidget {
|
class _PickerWidget extends StatefulWidget {
|
||||||
const _PickerWidget({
|
const _PickerWidget({
|
||||||
Key? key,
|
|
||||||
required this.filePickerIndex,
|
required this.filePickerIndex,
|
||||||
required this.containsFile,
|
required this.containsFile,
|
||||||
required this.selectedMedias,
|
required this.selectedMedias,
|
||||||
@@ -1934,7 +1932,7 @@ class _PickerWidget extends StatefulWidget {
|
|||||||
required this.onMediaSelected,
|
required this.onMediaSelected,
|
||||||
required this.streamChatTheme,
|
required this.streamChatTheme,
|
||||||
required this.mediaListViewController,
|
required this.mediaListViewController,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
final int filePickerIndex;
|
final int filePickerIndex;
|
||||||
final bool containsFile;
|
final bool containsFile;
|
||||||
@@ -2002,7 +2000,7 @@ class _PickerWidgetState extends State<_PickerWidget> {
|
|||||||
onTap: () async {
|
onTap: () async {
|
||||||
PhotoManager.openSetting();
|
PhotoManager.openSetting();
|
||||||
},
|
},
|
||||||
child: Container(
|
child: ColoredBox(
|
||||||
color: widget.streamChatTheme.colorTheme.inputBg,
|
color: widget.streamChatTheme.colorTheme.inputBg,
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
@@ -2040,10 +2038,7 @@ class _PickerWidgetState extends State<_PickerWidget> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _CountdownButton extends StatelessWidget {
|
class _CountdownButton extends StatelessWidget {
|
||||||
const _CountdownButton({
|
const _CountdownButton({required this.count});
|
||||||
Key? key,
|
|
||||||
required this.count,
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
final int count;
|
final int count;
|
||||||
|
|
||||||
|
|||||||
@@ -169,7 +169,7 @@ typedef MessageListView = StreamMessageListView;
|
|||||||
class StreamMessageListView extends StatefulWidget {
|
class StreamMessageListView extends StatefulWidget {
|
||||||
/// Instantiate a new StreamMessageListView.
|
/// Instantiate a new StreamMessageListView.
|
||||||
const StreamMessageListView({
|
const StreamMessageListView({
|
||||||
Key? key,
|
super.key,
|
||||||
this.showScrollToBottom = true,
|
this.showScrollToBottom = true,
|
||||||
this.scrollToBottomBuilder,
|
this.scrollToBottomBuilder,
|
||||||
this.messageBuilder,
|
this.messageBuilder,
|
||||||
@@ -206,7 +206,7 @@ class StreamMessageListView extends StatefulWidget {
|
|||||||
this.paginationLoadingIndicatorBuilder,
|
this.paginationLoadingIndicatorBuilder,
|
||||||
this.keyboardDismissBehavior = ScrollViewKeyboardDismissBehavior.onDrag,
|
this.keyboardDismissBehavior = ScrollViewKeyboardDismissBehavior.onDrag,
|
||||||
this.spacingWidgetBuilder,
|
this.spacingWidgetBuilder,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
/// [ScrollViewKeyboardDismissBehavior] the defines how this [PositionedList] will
|
/// [ScrollViewKeyboardDismissBehavior] the defines how this [PositionedList] will
|
||||||
/// dismiss the keyboard automatically.
|
/// dismiss the keyboard automatically.
|
||||||
@@ -751,7 +751,7 @@ class _StreamMessageListViewState extends State<StreamMessageListView> {
|
|||||||
StreamMessageListViewTheme.of(context).backgroundImage;
|
StreamMessageListViewTheme.of(context).backgroundImage;
|
||||||
|
|
||||||
if (backgroundColor != null || backgroundImage != null) {
|
if (backgroundColor != null || backgroundImage != null) {
|
||||||
return Container(
|
return DecoratedBox(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: backgroundColor,
|
color: backgroundColor,
|
||||||
image: backgroundImage,
|
image: backgroundImage,
|
||||||
@@ -889,7 +889,7 @@ class _StreamMessageListViewState extends State<StreamMessageListView> {
|
|||||||
initialIndex = 0;
|
initialIndex = 0;
|
||||||
await streamChannel!.reloadChannel();
|
await streamChannel!.reloadChannel();
|
||||||
|
|
||||||
WidgetsBinding.instance?.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
_scrollController!.jumpTo(index: 0);
|
_scrollController!.jumpTo(index: 0);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@@ -1039,9 +1039,7 @@ class _StreamMessageListViewState extends State<StreamMessageListView> {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
onMessageTap: (message) {
|
onMessageTap: (message) {
|
||||||
if (widget.onMessageTap != null) {
|
widget.onMessageTap?.call(message);
|
||||||
widget.onMessageTap!(message);
|
|
||||||
}
|
|
||||||
FocusScope.of(context).unfocus();
|
FocusScope.of(context).unfocus();
|
||||||
},
|
},
|
||||||
showPinButton: currentUserMember != null &&
|
showPinButton: currentUserMember != null &&
|
||||||
@@ -1066,9 +1064,7 @@ class _StreamMessageListViewState extends State<StreamMessageListView> {
|
|||||||
StreamSystemMessage(
|
StreamSystemMessage(
|
||||||
message: message,
|
message: message,
|
||||||
onMessageTap: (message) {
|
onMessageTap: (message) {
|
||||||
if (widget.onSystemMessageTap != null) {
|
widget.onSystemMessageTap?.call(message);
|
||||||
widget.onSystemMessageTap!(message);
|
|
||||||
}
|
|
||||||
FocusScope.of(context).unfocus();
|
FocusScope.of(context).unfocus();
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -1230,9 +1226,7 @@ class _StreamMessageListViewState extends State<StreamMessageListView> {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
onMessageTap: (message) {
|
onMessageTap: (message) {
|
||||||
if (widget.onMessageTap != null) {
|
widget.onMessageTap?.call(message);
|
||||||
widget.onMessageTap!(message);
|
|
||||||
}
|
|
||||||
FocusScope.of(context).unfocus();
|
FocusScope.of(context).unfocus();
|
||||||
},
|
},
|
||||||
showPinButton: currentUserMember != null &&
|
showPinButton: currentUserMember != null &&
|
||||||
@@ -1287,8 +1281,8 @@ class _StreamMessageListViewState extends State<StreamMessageListView> {
|
|||||||
),
|
),
|
||||||
duration: const Duration(seconds: 3),
|
duration: const Duration(seconds: 3),
|
||||||
onEnd: () => initialMessageHighlightComplete = true,
|
onEnd: () => initialMessageHighlightComplete = true,
|
||||||
builder: (_, color, child) => Container(
|
builder: (_, color, child) => ColoredBox(
|
||||||
color: color,
|
color: color!,
|
||||||
child: child,
|
child: child,
|
||||||
),
|
),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
@@ -1341,7 +1335,7 @@ class _StreamMessageListViewState extends State<StreamMessageListView> {
|
|||||||
if (event.message?.parentId == widget.parentMessage?.id &&
|
if (event.message?.parentId == widget.parentMessage?.id &&
|
||||||
event.message!.user!.id ==
|
event.message!.user!.id ==
|
||||||
streamChannel!.channel.client.state.currentUser!.id) {
|
streamChannel!.channel.client.state.currentUser!.id) {
|
||||||
WidgetsBinding.instance!.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
_scrollController?.scrollTo(
|
_scrollController?.scrollTo(
|
||||||
index: 0,
|
index: 0,
|
||||||
duration: const Duration(seconds: 1),
|
duration: const Duration(seconds: 1),
|
||||||
@@ -1389,11 +1383,10 @@ class _StreamMessageListViewState extends State<StreamMessageListView> {
|
|||||||
void _getOnThreadTap() {
|
void _getOnThreadTap() {
|
||||||
if (widget.onThreadTap != null) {
|
if (widget.onThreadTap != null) {
|
||||||
_onThreadTap = (Message message) {
|
_onThreadTap = (Message message) {
|
||||||
|
final threadBuilder = widget.threadBuilder;
|
||||||
widget.onThreadTap!(
|
widget.onThreadTap!(
|
||||||
message,
|
message,
|
||||||
widget.threadBuilder != null
|
threadBuilder != null ? threadBuilder(context, message) : null,
|
||||||
? widget.threadBuilder!(context, message)
|
|
||||||
: null,
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
} else if (widget.threadBuilder != null) {
|
} else if (widget.threadBuilder != null) {
|
||||||
@@ -1431,13 +1424,12 @@ class _StreamMessageListViewState extends State<StreamMessageListView> {
|
|||||||
|
|
||||||
class _LoadingIndicator extends StatelessWidget {
|
class _LoadingIndicator extends StatelessWidget {
|
||||||
const _LoadingIndicator({
|
const _LoadingIndicator({
|
||||||
Key? key,
|
|
||||||
required this.streamTheme,
|
required this.streamTheme,
|
||||||
required this.isThreadConversation,
|
required this.isThreadConversation,
|
||||||
required this.direction,
|
required this.direction,
|
||||||
required this.streamChannel,
|
required this.streamChannel,
|
||||||
this.indicatorBuilder,
|
this.indicatorBuilder,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
final StreamChatThemeData streamTheme;
|
final StreamChatThemeData streamTheme;
|
||||||
final bool isThreadConversation;
|
final bool isThreadConversation;
|
||||||
@@ -1454,7 +1446,7 @@ class _LoadingIndicator extends StatelessWidget {
|
|||||||
key: Key('LOADING-INDICATOR $direction'),
|
key: Key('LOADING-INDICATOR $direction'),
|
||||||
stream: stream,
|
stream: stream,
|
||||||
initialData: false,
|
initialData: false,
|
||||||
errorBuilder: (context, error) => Container(
|
errorBuilder: (context, error) => ColoredBox(
|
||||||
color: streamTheme.colorTheme.accentError.withOpacity(0.2),
|
color: streamTheme.colorTheme.accentError.withOpacity(0.2),
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Text(context.translations.loadingMessagesError),
|
child: Text(context.translations.loadingMessagesError),
|
||||||
|
|||||||
@@ -15,14 +15,14 @@ typedef MessageReactionsModal = StreamMessageReactionsModal;
|
|||||||
class StreamMessageReactionsModal extends StatelessWidget {
|
class StreamMessageReactionsModal extends StatelessWidget {
|
||||||
/// Constructor for creating a [StreamMessageReactionsModal] reactions
|
/// Constructor for creating a [StreamMessageReactionsModal] reactions
|
||||||
const StreamMessageReactionsModal({
|
const StreamMessageReactionsModal({
|
||||||
Key? key,
|
super.key,
|
||||||
required this.message,
|
required this.message,
|
||||||
required this.messageWidget,
|
required this.messageWidget,
|
||||||
required this.messageTheme,
|
required this.messageTheme,
|
||||||
this.showReactions,
|
this.showReactions,
|
||||||
this.reverse = false,
|
this.reverse = false,
|
||||||
this.onUserAvatarTap,
|
this.onUserAvatarTap,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
/// Widget that shows the message
|
/// Widget that shows the message
|
||||||
final Widget messageWidget;
|
final Widget messageWidget;
|
||||||
|
|||||||
@@ -16,11 +16,11 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
|||||||
class MessageSearchItem extends StatelessWidget {
|
class MessageSearchItem extends StatelessWidget {
|
||||||
/// Instantiate a new MessageSearchItem
|
/// Instantiate a new MessageSearchItem
|
||||||
const MessageSearchItem({
|
const MessageSearchItem({
|
||||||
Key? key,
|
super.key,
|
||||||
required this.getMessageResponse,
|
required this.getMessageResponse,
|
||||||
this.onTap,
|
this.onTap,
|
||||||
this.showOnlineStatus = true,
|
this.showOnlineStatus = true,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
/// [Message] displayed
|
/// [Message] displayed
|
||||||
final GetMessageResponse getMessageResponse;
|
final GetMessageResponse getMessageResponse;
|
||||||
|
|||||||
@@ -54,8 +54,9 @@ typedef EmptyMessageSearchBuilder = Widget Function(
|
|||||||
@Deprecated("Use 'StreamMessageSearchListView' instead")
|
@Deprecated("Use 'StreamMessageSearchListView' instead")
|
||||||
class MessageSearchListView extends StatefulWidget {
|
class MessageSearchListView extends StatefulWidget {
|
||||||
/// Instantiate a new MessageSearchListView
|
/// Instantiate a new MessageSearchListView
|
||||||
|
@Deprecated("Use 'StreamMessageSearchListView' instead")
|
||||||
const MessageSearchListView({
|
const MessageSearchListView({
|
||||||
Key? key,
|
super.key,
|
||||||
required this.filters,
|
required this.filters,
|
||||||
this.messageQuery,
|
this.messageQuery,
|
||||||
this.sortOptions,
|
this.sortOptions,
|
||||||
@@ -72,7 +73,7 @@ class MessageSearchListView extends StatefulWidget {
|
|||||||
this.loadingBuilder,
|
this.loadingBuilder,
|
||||||
this.childBuilder,
|
this.childBuilder,
|
||||||
this.messageSearchListController,
|
this.messageSearchListController,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
/// Message String to search on
|
/// Message String to search on
|
||||||
final String? messageQuery;
|
final String? messageQuery;
|
||||||
@@ -238,7 +239,7 @@ class _MessageSearchListViewState extends State<MessageSearchListView> {
|
|||||||
initialData: false,
|
initialData: false,
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
if (snapshot.hasError) {
|
if (snapshot.hasError) {
|
||||||
return Container(
|
return ColoredBox(
|
||||||
color: StreamChatTheme.of(context)
|
color: StreamChatTheme.of(context)
|
||||||
.colorTheme
|
.colorTheme
|
||||||
.accentError
|
.accentError
|
||||||
|
|||||||
@@ -14,12 +14,12 @@ typedef MessageText = StreamMessageText;
|
|||||||
class StreamMessageText extends StatelessWidget {
|
class StreamMessageText extends StatelessWidget {
|
||||||
/// Constructor for creating a [StreamMessageText] widget
|
/// Constructor for creating a [StreamMessageText] widget
|
||||||
const StreamMessageText({
|
const StreamMessageText({
|
||||||
Key? key,
|
super.key,
|
||||||
required this.message,
|
required this.message,
|
||||||
required this.messageTheme,
|
required this.messageTheme,
|
||||||
this.onMentionTap,
|
this.onMentionTap,
|
||||||
this.onLinkTap,
|
this.onLinkTap,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
/// Message whose text is to be displayed
|
/// Message whose text is to be displayed
|
||||||
final Message message;
|
final Message message;
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ typedef MessageWidget = StreamMessageWidget;
|
|||||||
class StreamMessageWidget extends StatefulWidget {
|
class StreamMessageWidget extends StatefulWidget {
|
||||||
/// Creates a new instance of the message widget.
|
/// Creates a new instance of the message widget.
|
||||||
StreamMessageWidget({
|
StreamMessageWidget({
|
||||||
Key? key,
|
super.key,
|
||||||
required this.message,
|
required this.message,
|
||||||
required this.messageTheme,
|
required this.messageTheme,
|
||||||
this.reverse = false,
|
this.reverse = false,
|
||||||
@@ -105,7 +105,7 @@ class StreamMessageWidget extends StatefulWidget {
|
|||||||
this.customActions = const [],
|
this.customActions = const [],
|
||||||
this.onAttachmentTap,
|
this.onAttachmentTap,
|
||||||
this.usernameBuilder,
|
this.usernameBuilder,
|
||||||
}) : attachmentBuilders = {
|
}) : attachmentBuilders = {
|
||||||
'image': (context, message, attachments) {
|
'image': (context, message, attachments) {
|
||||||
final border = RoundedRectangleBorder(
|
final border = RoundedRectangleBorder(
|
||||||
borderRadius: attachmentBorderRadiusGeometry ?? BorderRadius.zero,
|
borderRadius: attachmentBorderRadiusGeometry ?? BorderRadius.zero,
|
||||||
@@ -261,8 +261,7 @@ class StreamMessageWidget extends StatefulWidget {
|
|||||||
.toList(),
|
.toList(),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
}..addAll(customAttachmentBuilders ?? {}),
|
}..addAll(customAttachmentBuilders ?? {});
|
||||||
super(key: key);
|
|
||||||
|
|
||||||
/// Function called on mention tap
|
/// Function called on mention tap
|
||||||
final void Function(User)? onMentionTap;
|
final void Function(User)? onMentionTap;
|
||||||
@@ -878,7 +877,7 @@ class _StreamMessageWidgetState extends State<StreamMessageWidget>
|
|||||||
const Offstage();
|
const Offstage();
|
||||||
}
|
}
|
||||||
|
|
||||||
final children = <Widget>[];
|
final children = <WidgetSpan>[];
|
||||||
|
|
||||||
final threadParticipants = widget.message.threadParticipants?.take(2);
|
final threadParticipants = widget.message.threadParticipants?.take(2);
|
||||||
final showThreadParticipants = threadParticipants?.isNotEmpty == true;
|
final showThreadParticipants = threadParticipants?.isNotEmpty == true;
|
||||||
@@ -909,68 +908,72 @@ class _StreamMessageWidgetState extends State<StreamMessageWidget>
|
|||||||
const usernameKey = Key('username');
|
const usernameKey = Key('username');
|
||||||
|
|
||||||
children.addAll([
|
children.addAll([
|
||||||
if (showUsername) _buildUsername(usernameKey),
|
if (showUsername) WidgetSpan(child: _buildUsername(usernameKey)),
|
||||||
if (showTimeStamp)
|
if (showTimeStamp)
|
||||||
Text(
|
WidgetSpan(
|
||||||
Jiffy(widget.message.createdAt.toLocal()).jm,
|
child: Text(
|
||||||
style: widget.messageTheme.createdAtStyle,
|
Jiffy(widget.message.createdAt.toLocal()).jm,
|
||||||
|
style: widget.messageTheme.createdAtStyle,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (showSendingIndicator)
|
||||||
|
WidgetSpan(
|
||||||
|
child: _buildSendingIndicator(),
|
||||||
),
|
),
|
||||||
if (showSendingIndicator) _buildSendingIndicator(),
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
final showThreadTail = !(hasUrlAttachments || isGiphy || isOnlyEmoji) &&
|
final showThreadTail = !(hasUrlAttachments || isGiphy || isOnlyEmoji) &&
|
||||||
(showThreadReplyIndicator || showInChannel);
|
(showThreadReplyIndicator || showInChannel);
|
||||||
|
|
||||||
final threadIndicatorWidgets = <Widget>[
|
final threadIndicatorWidgets = <WidgetSpan>[
|
||||||
if (showThreadTail)
|
if (showThreadTail)
|
||||||
Container(
|
WidgetSpan(
|
||||||
margin: EdgeInsets.only(
|
child: Container(
|
||||||
bottom: context.textScaleFactor *
|
margin: EdgeInsets.only(
|
||||||
((widget.messageTheme.repliesStyle?.fontSize ?? 1) / 2),
|
bottom: context.textScaleFactor *
|
||||||
),
|
((widget.messageTheme.repliesStyle?.fontSize ?? 1) / 2),
|
||||||
child: CustomPaint(
|
),
|
||||||
size: const Size(16, 32) * context.textScaleFactor,
|
child: CustomPaint(
|
||||||
painter: _ThreadReplyPainter(
|
size: const Size(16, 32) * context.textScaleFactor,
|
||||||
context: context,
|
painter: _ThreadReplyPainter(
|
||||||
color: widget.messageTheme.messageBorderColor,
|
context: context,
|
||||||
reverse: widget.reverse,
|
color: widget.messageTheme.messageBorderColor,
|
||||||
|
reverse: widget.reverse,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (showInChannel || showThreadReplyIndicator) ...[
|
if (showInChannel || showThreadReplyIndicator) ...[
|
||||||
if (showThreadParticipants)
|
if (showThreadParticipants)
|
||||||
SizedBox.fromSize(
|
WidgetSpan(
|
||||||
size: Size((threadParticipants!.length * 8.0) + 8, 16),
|
child: SizedBox.fromSize(
|
||||||
child: _buildThreadParticipantsIndicator(threadParticipants),
|
size: Size((threadParticipants!.length * 8.0) + 8, 16),
|
||||||
|
child: _buildThreadParticipantsIndicator(threadParticipants),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
WidgetSpan(
|
||||||
|
child: InkWell(
|
||||||
|
onTap: widget.onThreadTap != null ? onThreadTap : null,
|
||||||
|
child: Text(msg, style: widget.messageTheme.repliesStyle),
|
||||||
),
|
),
|
||||||
InkWell(
|
|
||||||
onTap: widget.onThreadTap != null ? onThreadTap : null,
|
|
||||||
child: Text(msg, style: widget.messageTheme.repliesStyle),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
return Row(
|
if (widget.reverse) {
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
children.addAll(threadIndicatorWidgets.reversed);
|
||||||
mainAxisAlignment:
|
} else {
|
||||||
widget.reverse ? MainAxisAlignment.end : MainAxisAlignment.start,
|
children.insertAll(0, threadIndicatorWidgets);
|
||||||
children: [
|
}
|
||||||
if (showThreadTail && !widget.reverse) ...threadIndicatorWidgets,
|
|
||||||
...children.map(
|
return Text.rich(
|
||||||
(child) {
|
TextSpan(
|
||||||
Widget mappedChild = SizedBox(
|
children: [
|
||||||
height: context.textScaleFactor * 14,
|
...children,
|
||||||
child: child,
|
].insertBetween(const WidgetSpan(child: SizedBox(width: 8))),
|
||||||
);
|
),
|
||||||
if (child.key == usernameKey) {
|
maxLines: 1,
|
||||||
mappedChild = Flexible(child: mappedChild);
|
textAlign: widget.reverse ? TextAlign.right : TextAlign.left,
|
||||||
}
|
|
||||||
return mappedChild;
|
|
||||||
},
|
|
||||||
),
|
|
||||||
if (showThreadTail && widget.reverse)
|
|
||||||
...threadIndicatorWidgets.reversed,
|
|
||||||
].insertBetween(const SizedBox(width: 8)),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1076,7 +1079,7 @@ class _StreamMessageWidgetState extends State<StreamMessageWidget>
|
|||||||
showTimestamp: false,
|
showTimestamp: false,
|
||||||
translateUserAvatar: false,
|
translateUserAvatar: false,
|
||||||
showSendingIndicator: false,
|
showSendingIndicator: false,
|
||||||
padding: const EdgeInsets.all(0),
|
padding: EdgeInsets.zero,
|
||||||
showReactionPickerIndicator: widget.showReactions &&
|
showReactionPickerIndicator: widget.showReactions &&
|
||||||
(widget.message.status == MessageSendingStatus.sent) &&
|
(widget.message.status == MessageSendingStatus.sent) &&
|
||||||
channel.ownCapabilities.contains(PermissionType.sendReaction),
|
channel.ownCapabilities.contains(PermissionType.sendReaction),
|
||||||
@@ -1107,6 +1110,13 @@ class _StreamMessageWidgetState extends State<StreamMessageWidget>
|
|||||||
widget.onThreadTap != null,
|
widget.onThreadTap != null,
|
||||||
showFlagButton: widget.showFlagButton,
|
showFlagButton: widget.showFlagButton,
|
||||||
customActions: widget.customActions,
|
customActions: widget.customActions,
|
||||||
|
showDeleteMessage: widget.showDeleteMessage || isDeleteFailed,
|
||||||
|
showEditMessage: widget.showEditMessage &&
|
||||||
|
!isDeleteFailed &&
|
||||||
|
!widget.message.attachments
|
||||||
|
.any((element) => element.type == 'giphy'),
|
||||||
|
showPinButton: widget.showPinButton,
|
||||||
|
showReactions: widget.showReactions,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -1133,7 +1143,7 @@ class _StreamMessageWidgetState extends State<StreamMessageWidget>
|
|||||||
showTimestamp: false,
|
showTimestamp: false,
|
||||||
translateUserAvatar: false,
|
translateUserAvatar: false,
|
||||||
showSendingIndicator: false,
|
showSendingIndicator: false,
|
||||||
padding: const EdgeInsets.all(0),
|
padding: EdgeInsets.zero,
|
||||||
showReactionPickerIndicator: widget.showReactions &&
|
showReactionPickerIndicator: widget.showReactions &&
|
||||||
(widget.message.status == MessageSendingStatus.sent) &&
|
(widget.message.status == MessageSendingStatus.sent) &&
|
||||||
channel.ownCapabilities.contains(PermissionType.sendReaction),
|
channel.ownCapabilities.contains(PermissionType.sendReaction),
|
||||||
@@ -1259,6 +1269,7 @@ class _StreamMessageWidgetState extends State<StreamMessageWidget>
|
|||||||
);
|
);
|
||||||
if (isMessageRead) {
|
if (isMessageRead) {
|
||||||
child = Row(
|
child = Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
if (memberCount > 2)
|
if (memberCount > 2)
|
||||||
Text(
|
Text(
|
||||||
@@ -1396,11 +1407,9 @@ class _StreamMessageWidgetState extends State<StreamMessageWidget>
|
|||||||
|
|
||||||
class _ThreadParticipants extends StatelessWidget {
|
class _ThreadParticipants extends StatelessWidget {
|
||||||
const _ThreadParticipants({
|
const _ThreadParticipants({
|
||||||
Key? key,
|
|
||||||
required StreamChatThemeData streamChatTheme,
|
required StreamChatThemeData streamChatTheme,
|
||||||
required this.threadParticipants,
|
required this.threadParticipants,
|
||||||
}) : _streamChatTheme = streamChatTheme,
|
}) : _streamChatTheme = streamChatTheme;
|
||||||
super(key: key);
|
|
||||||
|
|
||||||
final StreamChatThemeData _streamChatTheme;
|
final StreamChatThemeData _streamChatTheme;
|
||||||
final Iterable<User> threadParticipants;
|
final Iterable<User> threadParticipants;
|
||||||
@@ -1423,7 +1432,7 @@ class _ThreadParticipants extends StatelessWidget {
|
|||||||
padding: const EdgeInsets.all(1),
|
padding: const EdgeInsets.all(1),
|
||||||
child: StreamUserAvatar(
|
child: StreamUserAvatar(
|
||||||
user: user,
|
user: user,
|
||||||
constraints: BoxConstraints.loose(const Size.fromRadius(7)),
|
constraints: BoxConstraints.tight(const Size.fromRadius(7)),
|
||||||
showOnlineStatus: false,
|
showOnlineStatus: false,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -17,12 +17,12 @@ class StreamMultiOverlay extends StatelessWidget {
|
|||||||
/// [childAnchor] - the anchor relative to the child
|
/// [childAnchor] - the anchor relative to the child
|
||||||
/// [child] - the child widget
|
/// [child] - the child widget
|
||||||
const StreamMultiOverlay({
|
const StreamMultiOverlay({
|
||||||
Key? key,
|
super.key,
|
||||||
required this.overlayOptions,
|
required this.overlayOptions,
|
||||||
required this.child,
|
required this.child,
|
||||||
required this.overlayAnchor,
|
required this.overlayAnchor,
|
||||||
required this.childAnchor,
|
required this.childAnchor,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
/// The list of overlay options
|
/// The list of overlay options
|
||||||
final List<OverlayOptions> overlayOptions;
|
final List<OverlayOptions> overlayOptions;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ typedef OptionListTile = StreamOptionListTile;
|
|||||||
class StreamOptionListTile extends StatelessWidget {
|
class StreamOptionListTile extends StatelessWidget {
|
||||||
/// Constructor for creating [StreamOptionListTile]
|
/// Constructor for creating [StreamOptionListTile]
|
||||||
const StreamOptionListTile({
|
const StreamOptionListTile({
|
||||||
Key? key,
|
super.key,
|
||||||
required this.title,
|
required this.title,
|
||||||
this.leading,
|
this.leading,
|
||||||
this.trailing,
|
this.trailing,
|
||||||
@@ -20,7 +20,7 @@ class StreamOptionListTile extends StatelessWidget {
|
|||||||
this.tileColor,
|
this.tileColor,
|
||||||
this.separatorColor,
|
this.separatorColor,
|
||||||
this.titleTextStyle,
|
this.titleTextStyle,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
/// Title for tile
|
/// Title for tile
|
||||||
final String title;
|
final String title;
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ typedef QuotedMessageWidget = StreamQuotedMessageWidget;
|
|||||||
class StreamQuotedMessageWidget extends StatelessWidget {
|
class StreamQuotedMessageWidget extends StatelessWidget {
|
||||||
/// Creates a new instance of the widget.
|
/// Creates a new instance of the widget.
|
||||||
const StreamQuotedMessageWidget({
|
const StreamQuotedMessageWidget({
|
||||||
Key? key,
|
super.key,
|
||||||
required this.message,
|
required this.message,
|
||||||
required this.messageTheme,
|
required this.messageTheme,
|
||||||
this.reverse = false,
|
this.reverse = false,
|
||||||
@@ -27,7 +27,7 @@ class StreamQuotedMessageWidget extends StatelessWidget {
|
|||||||
this.attachmentThumbnailBuilders,
|
this.attachmentThumbnailBuilders,
|
||||||
this.padding = const EdgeInsets.all(8),
|
this.padding = const EdgeInsets.all(8),
|
||||||
this.onTap,
|
this.onTap,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
/// The message
|
/// The message
|
||||||
final Message message;
|
final Message message;
|
||||||
@@ -251,12 +251,10 @@ class StreamQuotedMessageWidget extends StatelessWidget {
|
|||||||
|
|
||||||
class _VideoAttachmentThumbnail extends StatefulWidget {
|
class _VideoAttachmentThumbnail extends StatefulWidget {
|
||||||
const _VideoAttachmentThumbnail({
|
const _VideoAttachmentThumbnail({
|
||||||
Key? key,
|
super.key,
|
||||||
required this.attachment,
|
required this.attachment,
|
||||||
this.size = const Size(32, 32),
|
});
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
final Size size;
|
|
||||||
final Attachment attachment;
|
final Attachment attachment;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -285,8 +283,8 @@ class _VideoAttachmentThumbnailState extends State<_VideoAttachmentThumbnail> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => SizedBox(
|
Widget build(BuildContext context) => SizedBox(
|
||||||
height: widget.size.height,
|
height: 32,
|
||||||
width: widget.size.width,
|
width: 32,
|
||||||
child: _controller.value.isInitialized
|
child: _controller.value.isInitialized
|
||||||
? VideoPlayer(_controller)
|
? VideoPlayer(_controller)
|
||||||
: const CircularProgressIndicator(),
|
: const CircularProgressIndicator(),
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ typedef ReactionBubble = StreamReactionBubble;
|
|||||||
class StreamReactionBubble extends StatelessWidget {
|
class StreamReactionBubble extends StatelessWidget {
|
||||||
/// Constructor for creating a [StreamReactionBubble]
|
/// Constructor for creating a [StreamReactionBubble]
|
||||||
const StreamReactionBubble({
|
const StreamReactionBubble({
|
||||||
Key? key,
|
super.key,
|
||||||
required this.reactions,
|
required this.reactions,
|
||||||
required this.borderColor,
|
required this.borderColor,
|
||||||
required this.backgroundColor,
|
required this.backgroundColor,
|
||||||
@@ -23,7 +23,7 @@ class StreamReactionBubble extends StatelessWidget {
|
|||||||
this.flipTail = false,
|
this.flipTail = false,
|
||||||
this.highlightOwnReactions = true,
|
this.highlightOwnReactions = true,
|
||||||
this.tailCirclesSpacing = 0,
|
this.tailCirclesSpacing = 0,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
/// Reactions to show
|
/// Reactions to show
|
||||||
final List<Reaction> reactions;
|
final List<Reaction> reactions;
|
||||||
|
|||||||
@@ -19,9 +19,9 @@ typedef ReactionPicker = StreamReactionPicker;
|
|||||||
class StreamReactionPicker extends StatefulWidget {
|
class StreamReactionPicker extends StatefulWidget {
|
||||||
/// Constructor for creating a [StreamReactionPicker] widget
|
/// Constructor for creating a [StreamReactionPicker] widget
|
||||||
const StreamReactionPicker({
|
const StreamReactionPicker({
|
||||||
Key? key,
|
super.key,
|
||||||
required this.message,
|
required this.message,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
/// Message to attach the reaction to
|
/// Message to attach the reaction to
|
||||||
final Message message;
|
final Message message;
|
||||||
|
|||||||
@@ -11,11 +11,11 @@ typedef SendingIndicator = StreamSendingIndicator;
|
|||||||
class StreamSendingIndicator extends StatelessWidget {
|
class StreamSendingIndicator extends StatelessWidget {
|
||||||
/// Constructor for creating a [StreamSendingIndicator] widget
|
/// Constructor for creating a [StreamSendingIndicator] widget
|
||||||
const StreamSendingIndicator({
|
const StreamSendingIndicator({
|
||||||
Key? key,
|
super.key,
|
||||||
required this.message,
|
required this.message,
|
||||||
this.isMessageRead = false,
|
this.isMessageRead = false,
|
||||||
this.size = 12,
|
this.size = 12,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
/// Message for sending indicator
|
/// Message for sending indicator
|
||||||
final Message message;
|
final Message message;
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user