Merge branch 'GetStream:develop' into fix-web-attachments
This commit is contained in:
@@ -33,7 +33,7 @@ jobs:
|
|||||||
flutter-version: ${{ env.flutter_version }}
|
flutter-version: ${{ env.flutter_version }}
|
||||||
|
|
||||||
- name: "Install Tools"
|
- name: "Install Tools"
|
||||||
run: flutter pub global activate melos 1.0.0-dev.3
|
run: flutter pub global activate melos 1.0.0-dev.6
|
||||||
- name: "Bootstrap Workspace"
|
- name: "Bootstrap Workspace"
|
||||||
run: melos bootstrap
|
run: melos bootstrap
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ jobs:
|
|||||||
flutter-version: ${{ env.flutter_version }}
|
flutter-version: ${{ env.flutter_version }}
|
||||||
- name: "Install Tools"
|
- name: "Install Tools"
|
||||||
run: |
|
run: |
|
||||||
flutter pub global activate melos 1.0.0-dev.3
|
flutter pub global activate melos 1.0.0-dev.6
|
||||||
- name: "Bootstrap Workspace"
|
- name: "Bootstrap Workspace"
|
||||||
run: melos bootstrap
|
run: melos bootstrap
|
||||||
- name: "Dart Analyze"
|
- name: "Dart Analyze"
|
||||||
|
|||||||
@@ -44,10 +44,6 @@ final _levelEmojiMapper = {
|
|||||||
Level.SEVERE: '🚨',
|
Level.SEVERE: '🚨',
|
||||||
};
|
};
|
||||||
|
|
||||||
final _userAgent = 'stream-chat-dart-client-'
|
|
||||||
'${CurrentPlatform.name}-'
|
|
||||||
'${PACKAGE_VERSION.split('+')[0]}';
|
|
||||||
|
|
||||||
/// The official Dart client for Stream Chat,
|
/// The official Dart client for Stream Chat,
|
||||||
/// a service for building chat applications.
|
/// a service for building chat applications.
|
||||||
/// This library can be used on any Dart project and on both mobile and web apps
|
/// This library can be used on any Dart project and on both mobile and web apps
|
||||||
@@ -86,7 +82,7 @@ class StreamChatClient {
|
|||||||
location: location,
|
location: location,
|
||||||
connectTimeout: connectTimeout,
|
connectTimeout: connectTimeout,
|
||||||
receiveTimeout: receiveTimeout,
|
receiveTimeout: receiveTimeout,
|
||||||
headers: {'X-Stream-Client': _userAgent},
|
headers: {'X-Stream-Client': defaultUserAgent},
|
||||||
);
|
);
|
||||||
|
|
||||||
_chatApi = chatApi ??
|
_chatApi = chatApi ??
|
||||||
@@ -106,7 +102,7 @@ class StreamChatClient {
|
|||||||
tokenManager: _tokenManager,
|
tokenManager: _tokenManager,
|
||||||
handler: handleEvent,
|
handler: handleEvent,
|
||||||
logger: detachedLogger('🔌'),
|
logger: detachedLogger('🔌'),
|
||||||
queryParameters: {'X-Stream-Client': _userAgent},
|
queryParameters: {'X-Stream-Client': defaultUserAgent},
|
||||||
);
|
);
|
||||||
|
|
||||||
_retryPolicy = retryPolicy ??
|
_retryPolicy = retryPolicy ??
|
||||||
@@ -131,6 +127,14 @@ class StreamChatClient {
|
|||||||
_originalChatPersistenceClient = value;
|
_originalChatPersistenceClient = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Default user agent for all requests
|
||||||
|
static String defaultUserAgent = 'stream-chat-dart-client-'
|
||||||
|
'${CurrentPlatform.name}-'
|
||||||
|
'${PACKAGE_VERSION.split('+')[0]}';
|
||||||
|
|
||||||
|
/// Additionals headers for all requests
|
||||||
|
static Map<String, Object?> additionalHeaders = {};
|
||||||
|
|
||||||
ChatPersistenceClient? _originalChatPersistenceClient;
|
ChatPersistenceClient? _originalChatPersistenceClient;
|
||||||
|
|
||||||
/// Chat persistence client
|
/// Chat persistence client
|
||||||
|
|||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
import 'package:dio/dio.dart';
|
||||||
|
import 'package:stream_chat/stream_chat.dart';
|
||||||
|
|
||||||
|
/// Interceptor that sets additional headers for all requests.
|
||||||
|
class AdditionalHeadersInterceptor extends Interceptor {
|
||||||
|
@override
|
||||||
|
Future<void> onRequest(
|
||||||
|
RequestOptions options,
|
||||||
|
RequestInterceptorHandler handler,
|
||||||
|
) async {
|
||||||
|
options.headers = {
|
||||||
|
...options.headers,
|
||||||
|
...StreamChatClient.additionalHeaders,
|
||||||
|
};
|
||||||
|
return handler.next(options);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ import 'package:logging/logging.dart';
|
|||||||
import 'package:meta/meta.dart';
|
import 'package:meta/meta.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/connection_id_manager.dart';
|
import 'package:stream_chat/src/core/http/connection_id_manager.dart';
|
||||||
|
import 'package:stream_chat/src/core/http/interceptor/additional_headers_interceptor.dart';
|
||||||
import 'package:stream_chat/src/core/http/interceptor/auth_interceptor.dart';
|
import 'package:stream_chat/src/core/http/interceptor/auth_interceptor.dart';
|
||||||
import 'package:stream_chat/src/core/http/interceptor/connection_id_interceptor.dart';
|
import 'package:stream_chat/src/core/http/interceptor/connection_id_interceptor.dart';
|
||||||
import 'package:stream_chat/src/core/http/interceptor/logging_interceptor.dart';
|
import 'package:stream_chat/src/core/http/interceptor/logging_interceptor.dart';
|
||||||
@@ -41,6 +42,7 @@ class StreamHttpClient {
|
|||||||
..._options.headers,
|
..._options.headers,
|
||||||
}
|
}
|
||||||
..interceptors.addAll([
|
..interceptors.addAll([
|
||||||
|
AdditionalHeadersInterceptor(),
|
||||||
if (tokenManager != null) AuthInterceptor(this, tokenManager),
|
if (tokenManager != null) AuthInterceptor(this, tokenManager),
|
||||||
if (connectionIdManager != null)
|
if (connectionIdManager != null)
|
||||||
ConnectionIdInterceptor(connectionIdManager),
|
ConnectionIdInterceptor(connectionIdManager),
|
||||||
|
|||||||
@@ -118,9 +118,9 @@ void main() {
|
|||||||
|
|
||||||
setUpAll(() {
|
setUpAll(() {
|
||||||
// Fallback values
|
// Fallback values
|
||||||
registerFallbackValue<Message>(FakeMessage());
|
registerFallbackValue(FakeMessage());
|
||||||
registerFallbackValue<List<Message>>(<Message>[]);
|
registerFallbackValue(<Message>[]);
|
||||||
registerFallbackValue<AttachmentFile>(FakeAttachmentFile());
|
registerFallbackValue(FakeAttachmentFile());
|
||||||
|
|
||||||
// detached loggers
|
// detached loggers
|
||||||
when(() => client.detachedLogger(any())).thenAnswer((invocation) {
|
when(() => client.detachedLogger(any())).thenAnswer((invocation) {
|
||||||
@@ -176,9 +176,9 @@ void main() {
|
|||||||
|
|
||||||
setUpAll(() {
|
setUpAll(() {
|
||||||
// Fallback values
|
// Fallback values
|
||||||
registerFallbackValue<Message>(FakeMessage());
|
registerFallbackValue(FakeMessage());
|
||||||
registerFallbackValue<AttachmentFile>(FakeAttachmentFile());
|
registerFallbackValue(FakeAttachmentFile());
|
||||||
registerFallbackValue<Event>(FakeEvent());
|
registerFallbackValue(FakeEvent());
|
||||||
|
|
||||||
// detached loggers
|
// detached loggers
|
||||||
when(() => client.detachedLogger(any())).thenAnswer((invocation) {
|
when(() => client.detachedLogger(any())).thenAnswer((invocation) {
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ void main() {
|
|||||||
|
|
||||||
setUpAll(() {
|
setUpAll(() {
|
||||||
// fallback values
|
// fallback values
|
||||||
registerFallbackValue<User>(FakeUser());
|
registerFallbackValue(FakeUser());
|
||||||
});
|
});
|
||||||
|
|
||||||
setUp(() {
|
setUp(() {
|
||||||
@@ -230,7 +230,7 @@ void main() {
|
|||||||
|
|
||||||
setUpAll(() {
|
setUpAll(() {
|
||||||
// fallback values
|
// fallback values
|
||||||
registerFallbackValue<User>(FakeUser());
|
registerFallbackValue(FakeUser());
|
||||||
});
|
});
|
||||||
|
|
||||||
setUp(() {
|
setUp(() {
|
||||||
@@ -311,7 +311,7 @@ void main() {
|
|||||||
|
|
||||||
setUpAll(() {
|
setUpAll(() {
|
||||||
// fallback values
|
// fallback values
|
||||||
registerFallbackValue<User>(FakeUser());
|
registerFallbackValue(FakeUser());
|
||||||
});
|
});
|
||||||
|
|
||||||
setUp(() {
|
setUp(() {
|
||||||
@@ -399,7 +399,7 @@ void main() {
|
|||||||
|
|
||||||
setUpAll(() {
|
setUpAll(() {
|
||||||
// fallback values
|
// fallback values
|
||||||
registerFallbackValue<User>(FakeUser());
|
registerFallbackValue(FakeUser());
|
||||||
});
|
});
|
||||||
|
|
||||||
setUp(() {
|
setUp(() {
|
||||||
@@ -523,9 +523,9 @@ void main() {
|
|||||||
|
|
||||||
setUpAll(() {
|
setUpAll(() {
|
||||||
// fallback values
|
// fallback values
|
||||||
registerFallbackValue<Event>(FakeEvent());
|
registerFallbackValue(FakeEvent());
|
||||||
registerFallbackValue<PaginationParams>(const PaginationParams());
|
registerFallbackValue(const PaginationParams());
|
||||||
registerFallbackValue<ChannelState>(FakeChannelState());
|
registerFallbackValue(FakeChannelState());
|
||||||
});
|
});
|
||||||
|
|
||||||
setUp(() async {
|
setUp(() async {
|
||||||
@@ -827,9 +827,9 @@ void main() {
|
|||||||
|
|
||||||
setUpAll(() {
|
setUpAll(() {
|
||||||
// fallback values
|
// fallback values
|
||||||
registerFallbackValue<Event>(FakeEvent());
|
registerFallbackValue(FakeEvent());
|
||||||
registerFallbackValue<Message>(FakeMessage());
|
registerFallbackValue(FakeMessage());
|
||||||
registerFallbackValue<PaginationParams>(const PaginationParams());
|
registerFallbackValue(const PaginationParams());
|
||||||
});
|
});
|
||||||
|
|
||||||
setUp(() async {
|
setUp(() async {
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ void main() {
|
|||||||
|
|
||||||
setUp(() {
|
setUp(() {
|
||||||
fileUploader = StreamAttachmentFileUploader(client);
|
fileUploader = StreamAttachmentFileUploader(client);
|
||||||
registerFallbackValue<MultipartFile>(FakeMultiPartFile());
|
registerFallbackValue(FakeMultiPartFile());
|
||||||
});
|
});
|
||||||
|
|
||||||
Response successResponse(String path, {Object? data}) => Response(
|
Response successResponse(String path, {Object? data}) => Response(
|
||||||
|
|||||||
+29
@@ -0,0 +1,29 @@
|
|||||||
|
import 'package:dio/dio.dart';
|
||||||
|
import 'package:stream_chat/src/core/http/interceptor/additional_headers_interceptor.dart';
|
||||||
|
import 'package:stream_chat/stream_chat.dart';
|
||||||
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
late AdditionalHeadersInterceptor additionalHeadersInterceptor;
|
||||||
|
|
||||||
|
setUp(() {
|
||||||
|
additionalHeadersInterceptor = AdditionalHeadersInterceptor();
|
||||||
|
});
|
||||||
|
|
||||||
|
test(
|
||||||
|
'`onRequest` should add additional headers in the request',
|
||||||
|
() async {
|
||||||
|
final options = RequestOptions(path: 'test-path');
|
||||||
|
final handler = RequestInterceptorHandler();
|
||||||
|
|
||||||
|
StreamChatClient.additionalHeaders = {'test-header': 'test-value'};
|
||||||
|
additionalHeadersInterceptor.onRequest(options, handler);
|
||||||
|
|
||||||
|
final updatedOptions = (await handler.future).data as RequestOptions;
|
||||||
|
final updateHeaders = updatedOptions.headers;
|
||||||
|
|
||||||
|
expect(updateHeaders.containsKey('test-header'), isTrue);
|
||||||
|
expect(updateHeaders['test-header'], 'test-value');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ import 'package:mocktail/mocktail.dart';
|
|||||||
import 'package:stream_chat/src/core/api/responses.dart';
|
import 'package:stream_chat/src/core/api/responses.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/connection_id_manager.dart';
|
import 'package:stream_chat/src/core/http/connection_id_manager.dart';
|
||||||
|
import 'package:stream_chat/src/core/http/interceptor/additional_headers_interceptor.dart';
|
||||||
import 'package:stream_chat/src/core/http/interceptor/auth_interceptor.dart';
|
import 'package:stream_chat/src/core/http/interceptor/auth_interceptor.dart';
|
||||||
import 'package:stream_chat/src/core/http/interceptor/connection_id_interceptor.dart';
|
import 'package:stream_chat/src/core/http/interceptor/connection_id_interceptor.dart';
|
||||||
import 'package:stream_chat/src/core/http/interceptor/logging_interceptor.dart';
|
import 'package:stream_chat/src/core/http/interceptor/logging_interceptor.dart';
|
||||||
@@ -48,12 +49,23 @@ void main() {
|
|||||||
return dioError;
|
return dioError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test('UserAgentInterceptor should be added', () {
|
||||||
|
const apiKey = 'api-key';
|
||||||
|
final client = StreamHttpClient(apiKey);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
client.httpClient.interceptors
|
||||||
|
.whereType<AdditionalHeadersInterceptor>()
|
||||||
|
.length,
|
||||||
|
1);
|
||||||
|
});
|
||||||
|
|
||||||
test('AuthInterceptor should be added if tokenManager is provided', () {
|
test('AuthInterceptor should be added if tokenManager is provided', () {
|
||||||
const apiKey = 'api-key';
|
const apiKey = 'api-key';
|
||||||
final client = StreamHttpClient(apiKey, tokenManager: TokenManager());
|
final client = StreamHttpClient(apiKey, tokenManager: TokenManager());
|
||||||
|
|
||||||
expect(client.httpClient.interceptors.length, 1);
|
expect(
|
||||||
expect(client.httpClient.interceptors.first, isA<AuthInterceptor>());
|
client.httpClient.interceptors.whereType<AuthInterceptor>().length, 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
test(
|
test(
|
||||||
@@ -65,10 +77,11 @@ void main() {
|
|||||||
connectionIdManager: ConnectionIdManager(),
|
connectionIdManager: ConnectionIdManager(),
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(client.httpClient.interceptors.length, 1);
|
|
||||||
expect(
|
expect(
|
||||||
client.httpClient.interceptors.first,
|
client.httpClient.interceptors
|
||||||
isA<ConnectionIdInterceptor>(),
|
.whereType<ConnectionIdInterceptor>()
|
||||||
|
.length,
|
||||||
|
1,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -80,10 +93,9 @@ void main() {
|
|||||||
logger: Logger('test-logger'),
|
logger: Logger('test-logger'),
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(client.httpClient.interceptors.length, 1);
|
|
||||||
expect(
|
expect(
|
||||||
client.httpClient.interceptors.first,
|
client.httpClient.interceptors.whereType<LoggingInterceptor>().length,
|
||||||
isA<LoggingInterceptor>(),
|
1,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -110,7 +110,15 @@ class StreamChatState extends State<StreamChat> {
|
|||||||
onBackgroundEventReceived: widget.onBackgroundEventReceived,
|
onBackgroundEventReceived: widget.onBackgroundEventReceived,
|
||||||
backgroundKeepAlive: widget.backgroundKeepAlive,
|
backgroundKeepAlive: widget.backgroundKeepAlive,
|
||||||
connectivityStream: widget.connectivityStream,
|
connectivityStream: widget.connectivityStream,
|
||||||
child: widget.child ?? const Offstage(),
|
child: Builder(
|
||||||
|
builder: (context) {
|
||||||
|
StreamChatClient.additionalHeaders = {
|
||||||
|
'X-Stream-Client':
|
||||||
|
'${StreamChatClient.defaultUserAgent}-ui',
|
||||||
|
};
|
||||||
|
return widget.child ?? const Offstage();
|
||||||
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
+1
@@ -2,6 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import 'dart:async';
|
||||||
import 'dart:ui';
|
import 'dart:ui';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|||||||
+1
@@ -2,6 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import 'dart:async';
|
||||||
import 'dart:ui';
|
import 'dart:ui';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|||||||
+1
@@ -2,6 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import 'dart:async';
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
import 'dart:ui';
|
import 'dart:ui';
|
||||||
|
|
||||||
|
|||||||
+1
@@ -2,6 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import 'dart:async';
|
||||||
import 'dart:ui';
|
import 'dart:ui';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|||||||
+1
@@ -2,6 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import 'dart:async';
|
||||||
import 'dart:ui';
|
import 'dart:ui';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ class HomeScreen extends StatelessWidget {
|
|||||||
itemBuilder: (BuildContext context, int index) {
|
itemBuilder: (BuildContext context, int index) {
|
||||||
final _item = channels[index];
|
final _item = channels[index];
|
||||||
return ListTile(
|
return ListTile(
|
||||||
title: Text(_item.name!),
|
title: Text(_item.name ?? ''),
|
||||||
subtitle: StreamBuilder<Message?>(
|
subtitle: StreamBuilder<Message?>(
|
||||||
stream: _item.state!.lastMessageStream,
|
stream: _item.state!.lastMessageStream,
|
||||||
initialData: _item.state!.lastMessage,
|
initialData: _item.state!.lastMessage,
|
||||||
|
|||||||
@@ -95,7 +95,12 @@ class StreamChatCoreState extends State<StreamChatCore>
|
|||||||
Timer? _disconnectTimer;
|
Timer? _disconnectTimer;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => widget.child;
|
Widget build(BuildContext context) {
|
||||||
|
StreamChatClient.additionalHeaders = {
|
||||||
|
'X-Stream-Client': '${StreamChatClient.defaultUserAgent}-core',
|
||||||
|
};
|
||||||
|
return widget.child;
|
||||||
|
}
|
||||||
|
|
||||||
// coverage:ignore-start
|
// coverage:ignore-start
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import 'mocks.dart';
|
|||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
setUpAll(() {
|
setUpAll(() {
|
||||||
registerFallbackValue<PaginationParams>(const PaginationParams());
|
registerFallbackValue(const PaginationParams());
|
||||||
});
|
});
|
||||||
|
|
||||||
List<Channel> _generateChannels(
|
List<Channel> _generateChannels(
|
||||||
|
|||||||
Reference in New Issue
Block a user