diff --git a/.github/workflows/dart_code_metrics.yaml b/.github/workflows/dart_code_metrics.yaml new file mode 100644 index 00000000..1272babc --- /dev/null +++ b/.github/workflows/dart_code_metrics.yaml @@ -0,0 +1,73 @@ +name: Dart Code Metrics + +env: + flutter_version: "2.5.0" + folders: "lib, test" + +on: + pull_request: + push: + branches: + - master + - develop + +jobs: + check: + name: dart-code-metrics + runs-on: ubuntu-latest + steps: + - name: "Git Checkout" + uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: "Cache Flutter dependencies" + uses: actions/cache@v2 + with: + path: /opt/hostedtoolcache/flutter + key: ${{ env.flutter_version }}-flutter + + - name: "Install Flutter" + uses: subosito/flutter-action@v1 + with: + flutter-version: ${{ env.flutter_version }} + + - name: "Install Tools" + run: flutter pub global activate melos 1.0.0-dev.3 + - name: "Bootstrap Workspace" + run: melos bootstrap + + - name: "Stream Chat Metrics" + uses: dart-code-checker/dart-code-metrics-action@v1 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + relative_path: 'packages/stream_chat' + folders: ${{ env.folders }} + + - name: "Stream Chat Flutter Core Metrics" + uses: dart-code-checker/dart-code-metrics-action@v1 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + relative_path: 'packages/stream_chat_flutter_core' + folders: ${{ env.folders }} + + - name: "Stream Chat Flutter Metrics" + uses: dart-code-checker/dart-code-metrics-action@v1 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + relative_path: 'packages/stream_chat_flutter' + folders: ${{ env.folders }} + + - name: "Stream Chat Localizations Metrics" + uses: dart-code-checker/dart-code-metrics-action@v1 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + relative_path: 'packages/stream_chat_localizations' + folders: ${{ env.folders }} + + - name: "Stream Chat Persistence Metrics" + uses: dart-code-checker/dart-code-metrics-action@v1 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + relative_path: 'packages/stream_chat_persistence' + folders: ${{ env.folders }} \ No newline at end of file diff --git a/.github/workflows/stream_flutter_workflow.yml b/.github/workflows/stream_flutter_workflow.yml index 28063c18..1eb5082a 100644 --- a/.github/workflows/stream_flutter_workflow.yml +++ b/.github/workflows/stream_flutter_workflow.yml @@ -31,7 +31,7 @@ jobs: flutter-version: ${{ env.flutter_version }} - name: "Install Tools" run: | - flutter pub global activate melos + flutter pub global activate melos 1.0.0-dev.3 - name: "Bootstrap Workspace" run: melos bootstrap - name: "Dart Analyze" diff --git a/analysis_options.yaml b/analysis_options.yaml index 71604a87..a1fa9388 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1,7 +1,9 @@ analyzer: + plugins: + - dart_code_metrics exclude: - packages/*/lib/**/*.g.dart - - packages/*/lib/src/emoji + - packages/*/lib/src/emoji/** - packages/*/lib/**/*.freezed.dart linter: @@ -143,4 +145,35 @@ linter: - cast_nullable_to_non_nullable - unnecessary_null_checks - tighten_type_of_initializing_formals - - null_check_on_nullable_type_parameter \ No newline at end of file + - null_check_on_nullable_type_parameter + +# https://dartcodemetrics.dev/docs/getting-started/introduction +dart_code_metrics: + rules: + # Dart Specific + - binary-expression-operand-order + - double-literal-format + - prefer-match-file-name: + exclude: + - packages/*/test/** + - packages/*/example/** + - packages/**/util/** + - packages/**/utils.dart + - packages/stream_chat/lib/src/client/client.dart + - packages/stream_chat/lib/src/core/api/responses.dart + - packages/stream_chat/lib/src/core/api/requests.dart + - packages/stream_chat/lib/src/core/platform_detector/** + - packages/stream_chat_persistence/lib/src/db/shared/** + - packages/stream_chat_localizations/lib/src/stream_chat_localizations.dart + - no-boolean-literal-compare + - no-equal-then-else + - no-empty-block: + exclude: + - packages/*/test/** + - prefer-trailing-comma: + exclude: + - packages/*/test/** + + # Flutter specific + - always-remove-listener + - avoid-unnecessary-setstate \ No newline at end of file diff --git a/melos.yaml b/melos.yaml index 6fee8f6f..4e1c08ac 100644 --- a/melos.yaml +++ b/melos.yaml @@ -11,6 +11,10 @@ scripts: run: melos run analyze && melos run format description: Run all static analysis checks + analyze:all: + run: melos run analyze && melos run metrics + description: Run all + analyze: run: | melos exec -c 5 --ignore="*example*" -- \ @@ -24,6 +28,14 @@ scripts: description: | Run `flutter format --set-exit-if-changed .` in all packages. + metrics: + run: | + melos exec -c 1 --ignore="*example*" -- \ + flutter pub run dart_code_metrics:metrics analyze lib + description: | + Run `dart_code_metrics` in all packages. + - Note: you can also rely on your IDEs Dart Analysis / Issues window. + lint:pub: run: | melos exec -c 5 --no-private --ignore="*example*" -- \ @@ -71,10 +83,13 @@ scripts: docs: run: | - npm install -g https://github.com/GetStream/stream-chat-docusaurus-cli && - npx stream-chat-docusaurus -i -s + npm install -g https://github.com/GetStream/stream-chat-docusaurus-cli && + npx stream-chat-docusaurus -i -s description: Runs the docusaurus documentation locally. +dev_dependencies: + dart_code_metrics: ^4.4.0 + environment: sdk: '>=2.12.0 <3.0.0' - flutter: '>=1.22.4 <2.0.0' \ No newline at end of file + flutter: '>=1.17.0 <2.0.0' \ No newline at end of file diff --git a/packages/stream_chat/example/pubspec.yaml b/packages/stream_chat/example/pubspec.yaml index 1b092b3e..cf1f3874 100644 --- a/packages/stream_chat/example/pubspec.yaml +++ b/packages/stream_chat/example/pubspec.yaml @@ -1,4 +1,4 @@ -name: example +name: stream_chat_example description: A new Flutter project. publish_to: "none" @@ -11,8 +11,7 @@ dependencies: cupertino_icons: ^1.0.0 flutter: sdk: flutter - stream_chat: - path: ../ + stream_chat: ^2.2.1 dev_dependencies: flutter_test: diff --git a/packages/stream_chat/lib/src/client/channel.dart b/packages/stream_chat/lib/src/client/channel.dart index 2fd4bea9..e3f1139f 100644 --- a/packages/stream_chat/lib/src/client/channel.dart +++ b/packages/stream_chat/lib/src/client/channel.dart @@ -521,7 +521,7 @@ class Channel { state!.addMessage(message); try { - if (message.attachments.any((it) => !it.uploadState.isSuccess) == true) { + if (message.attachments.any((it) => !it.uploadState.isSuccess)) { final attachmentsUploadCompleter = Completer(); _messageAttachmentsUploadCompleter[message.id] = attachmentsUploadCompleter; @@ -849,12 +849,12 @@ class Channel { ..update(type, (value) { if (enforceUnique) return value; return value + 1; - }, ifAbsent: () => 1), + }, ifAbsent: () => 1), // ignore: prefer-trailing-comma reactionScores: {...message.reactionScores ?? {}} ..update(type, (value) { if (enforceUnique) return value; return value + 1; - }, ifAbsent: () => 1), + }, ifAbsent: () => 1), // ignore: prefer-trailing-comma latestReactions: latestReactions, ownReactions: ownReactions, ); @@ -878,7 +878,9 @@ class Channel { /// Delete a reaction from this channel. Future deleteReaction( - Message message, Reaction reaction) async { + Message message, + Reaction reaction, + ) async { final type = reaction.type; final user = _client.state.currentUser; @@ -1336,7 +1338,7 @@ class Channel { type, clearHistory: clearHistory, ); - if (clearHistory == true) { + if (clearHistory) { state!.truncate(); final cid = _cid; if (cid != null) { @@ -1501,28 +1503,27 @@ class ChannelClientState { final expiredAttachmentMessagesId = channelState.messages .where((m) => !_updatedMessagesIds.contains(m.id) && - m.attachments.isNotEmpty == true && + m.attachments.isNotEmpty && m.attachments.any((e) { - final url = e.imageUrl ?? e.assetUrl; - if (url == null || !url.contains('')) { - return false; - } - final uri = Uri.parse(url); - if (!uri.host.endsWith('stream-io-cdn.com') || - uri.queryParameters['Expires'] == null) { - return false; - } - final secondsFromEpoch = - int.parse(uri.queryParameters['Expires']!); - final expiration = DateTime.fromMillisecondsSinceEpoch( - secondsFromEpoch * 1000); - return expiration.isBefore(DateTime.now()); - }) == - true) + final url = e.imageUrl ?? e.assetUrl; + if (url == null || !url.contains('')) { + return false; + } + final uri = Uri.parse(url); + if (!uri.host.endsWith('stream-io-cdn.com') || + uri.queryParameters['Expires'] == null) { + return false; + } + final secondsFromEpoch = + int.parse(uri.queryParameters['Expires']!); + final expiration = + DateTime.fromMillisecondsSinceEpoch(secondsFromEpoch * 1000); + return expiration.isBefore(DateTime.now()); + })) .map((e) => e.id) .toList(); - if (expiredAttachmentMessagesId.isNotEmpty == true) { + if (expiredAttachmentMessagesId.isNotEmpty) { await _channel._initializedCompleter.future; _updatedMessagesIds.addAll(expiredAttachmentMessagesId); _channel.getMessagesById(expiredAttachmentMessagesId); @@ -1546,7 +1547,8 @@ class ChannelClientState { final user = e.user; updateChannelState(channelState.copyWith( members: List.from( - channelState.members..removeWhere((m) => m.userId == user!.id)), + channelState.members..removeWhere((m) => m.userId == user!.id), + ), )); })); } @@ -1647,7 +1649,7 @@ class ChannelClientState { ); addMessage(message); - if (message.pinned == true) { + if (message.pinned) { _channelState = _channelState.copyWith( pinnedMessages: [ ..._channelState.pinnedMessages, @@ -1794,9 +1796,8 @@ class ChannelClientState { channelStateStream.map((cs) => cs.pinnedMessages.toList()); /// Get channel last message. - Message? get lastMessage => _channelState.messages.isNotEmpty == true - ? _channelState.messages.last - : null; + Message? get lastMessage => + _channelState.messages.isNotEmpty ? _channelState.messages.last : null; /// Get channel last message. Stream get lastMessageStream => @@ -1859,8 +1860,8 @@ class ChannelClientState { (m) => m.user.id == message.user?.id, ) != null; - return message.silent != true && - message.shadowed != true && + return !message.silent && + !message.shadowed && message.user?.id != userId && !userIsMuted; } @@ -1898,9 +1899,7 @@ class ChannelClientState { ...updatedState.messages, ..._channelState.messages .where((m) => - updatedState.messages - .any((newMessage) => newMessage.id == m.id) != - true) + !updatedState.messages.any((newMessage) => newMessage.id == m.id)) .toList(), ]..sort(_sortByCreatedAt); @@ -1908,9 +1907,7 @@ class ChannelClientState { ...updatedState.watchers, ..._channelState.watchers .where((w) => - updatedState.watchers - .any((newWatcher) => newWatcher.id == w.id) != - true) + !updatedState.watchers.any((newWatcher) => newWatcher.id == w.id)) .toList(), ]; @@ -1922,9 +1919,7 @@ class ChannelClientState { ...updatedState.read, ..._channelState.read .where((r) => - updatedState.read - .any((newRead) => newRead.user.id == r.user.id) != - true) + !updatedState.read.any((newRead) => newRead.user.id == r.user.id)) .toList(), ]; @@ -2031,7 +2026,7 @@ class ChannelClientState { .on() .where((event) => event.user != null && - members.any((m) => m.userId == event.user!.id) == true) + members.any((m) => m.userId == event.user!.id)) .listen( (event) { final newMembers = List.from(members); diff --git a/packages/stream_chat/lib/src/core/api/channel_api.dart b/packages/stream_chat/lib/src/core/api/channel_api.dart index 619e0980..63cf5458 100644 --- a/packages/stream_chat/lib/src/core/api/channel_api.dart +++ b/packages/stream_chat/lib/src/core/api/channel_api.dart @@ -75,7 +75,7 @@ class ChannelApi { if (messageLimit != null) 'message_limit': messageLimit, // pagination - ...paginationParams.toJson() + ...paginationParams.toJson(), }), }, ); diff --git a/packages/stream_chat/lib/src/core/api/device_api.dart b/packages/stream_chat/lib/src/core/api/device_api.dart index 2d2b9d7b..f4b7f0b1 100644 --- a/packages/stream_chat/lib/src/core/api/device_api.dart +++ b/packages/stream_chat/lib/src/core/api/device_api.dart @@ -7,7 +7,7 @@ enum PushProvider { firebase, /// Send notifications using Apple's Push Notification service - apn + apn, } /// Helper extension for [PushProvider] diff --git a/packages/stream_chat/lib/src/core/error/chat_error_code.dart b/packages/stream_chat/lib/src/core/error/chat_error_code.dart index 6391428d..d597000a 100644 --- a/packages/stream_chat/lib/src/core/error/chat_error_code.dart +++ b/packages/stream_chat/lib/src/core/error/chat_error_code.dart @@ -90,7 +90,7 @@ enum ChatErrorCode { internalSystemError, /// No access to requested channels - noAccessToChannels + noAccessToChannels, } const _errorCodeWithDescription = { @@ -98,14 +98,20 @@ const _errorCodeWithDescription = { MapEntry(1000, 'Unauthorised, token not defined'), ChatErrorCode.inputError: MapEntry(4, 'Wrong data/parameter is sent to the API'), - ChatErrorCode.duplicateUsername: MapEntry(6, - 'Duplicate username is sent while enforce_unique_usernames is enabled'), + ChatErrorCode.duplicateUsername: MapEntry( + 6, + 'Duplicate username is sent while enforce_unique_usernames is enabled', + ), ChatErrorCode.messageTooLong: MapEntry(20, 'Message is too long'), ChatErrorCode.eventNotSupported: MapEntry(18, 'Event is not supported'), - ChatErrorCode.channelFeatureNotSupported: MapEntry(19, - 'The feature is currently disabled on the dashboard (i.e. Reactions & Replies)'), - ChatErrorCode.multipleNestling: MapEntry(21, - 'Multiple Levels Reply is not supported - the API only supports 1 level deep reply threads'), + ChatErrorCode.channelFeatureNotSupported: MapEntry( + 19, + 'The feature is currently disabled on the dashboard (i.e. Reactions & Replies)', + ), + ChatErrorCode.multipleNestling: MapEntry( + 21, + 'Multiple Levels Reply is not supported - the API only supports 1 level deep reply threads', + ), ChatErrorCode.customCommandEndpointCall: MapEntry(45, 'Custom Command handler returned an error'), ChatErrorCode.customCommandEndpointMissing: diff --git a/packages/stream_chat/lib/src/core/error/stream_chat_error.dart b/packages/stream_chat/lib/src/core/error/stream_chat_error.dart index 13ccef2a..ce234c84 100644 --- a/packages/stream_chat/lib/src/core/error/stream_chat_error.dart +++ b/packages/stream_chat/lib/src/core/error/stream_chat_error.dart @@ -35,7 +35,8 @@ class StreamWebSocketError extends StreamChatError { /// factory StreamWebSocketError.fromWebSocketChannelError( - WebSocketChannelException error) { + WebSocketChannelException error, + ) { final message = error.message ?? ''; return StreamWebSocketError(message); } diff --git a/packages/stream_chat/lib/src/core/http/interceptor/logging_interceptor.dart b/packages/stream_chat/lib/src/core/http/interceptor/logging_interceptor.dart index f78b46ea..57ffda7d 100644 --- a/packages/stream_chat/lib/src/core/http/interceptor/logging_interceptor.dart +++ b/packages/stream_chat/lib/src/core/http/interceptor/logging_interceptor.dart @@ -105,8 +105,11 @@ class LoggingInterceptor extends Interceptor { final formDataMap = {} ..addEntries(data.fields) ..addEntries(data.files); - _printMapAsTable(_logPrintRequest, formDataMap, - header: 'Form data | ${data.boundary}'); + _printMapAsTable( + _logPrintRequest, + formDataMap, + header: 'Form data | ${data.boundary}', + ); } else { _printBlock(_logPrintRequest, data.toString()); } @@ -201,14 +204,19 @@ class LoggingInterceptor extends Interceptor { } void _printRequestHeader( - void Function(Object) logPrint, RequestOptions options) { + void Function(Object) logPrint, + RequestOptions options, + ) { final uri = options.uri; final method = options.method; _printBoxed(logPrint, header: 'Request ║ $method ', text: uri.toString()); } - void _printLine(void Function(Object) logPrint, - [String pre = '', String suf = '╝']) => + void _printLine( + void Function(Object) logPrint, [ + String pre = '', + String suf = '╝', + ]) => logPrint('$pre${'═' * maxWidth}$suf'); void _printKV(void Function(Object) logPrint, String? key, Object? v) { @@ -227,8 +235,10 @@ class LoggingInterceptor extends Interceptor { final lines = (msg.length / maxWidth).ceil(); for (var i = 0; i < lines; ++i) { logPrint((i >= 0 ? '║ ' : '') + - msg.substring(i * maxWidth, - math.min(i * maxWidth + maxWidth, msg.length))); + msg.substring( + i * maxWidth, + math.min(i * maxWidth + maxWidth, msg.length), + )); } } @@ -301,8 +311,13 @@ class LoggingInterceptor extends Interceptor { if (compact) { logPrint('║${_indent(tabs)} $e${!isLast ? ',' : ''}'); } else { - _printPrettyMap(logPrint, e, - tabs: tabs + 1, isListItem: true, isLast: isLast); + _printPrettyMap( + logPrint, + e, + tabs: tabs + 1, + isListItem: true, + isLast: isLast, + ); } } else { logPrint('║${_indent(tabs + 2)} $e${isLast ? '' : ','}'); diff --git a/packages/stream_chat/lib/src/core/models/attachment.dart b/packages/stream_chat/lib/src/core/models/attachment.dart index ca7e0afc..09fe1083 100644 --- a/packages/stream_chat/lib/src/core/models/attachment.dart +++ b/packages/stream_chat/lib/src/core/models/attachment.dart @@ -56,12 +56,15 @@ class Attachment extends Equatable { /// Create a new instance from a json factory Attachment.fromJson(Map json) => _$AttachmentFromJson( - Serializer.moveToExtraDataFromRoot(json, topLevelFields)); + Serializer.moveToExtraDataFromRoot(json, topLevelFields), + ); /// Create a new instance from a db data factory Attachment.fromData(Map json) => _$AttachmentFromJson(Serializer.moveToExtraDataFromRoot( - json, topLevelFields + dbSpecificTopLevelFields)); + json, + topLevelFields + dbSpecificTopLevelFields, + )); ///The attachment type based on the URL resource. This can be: audio, ///image or video diff --git a/packages/stream_chat/lib/src/core/models/attachment_file.dart b/packages/stream_chat/lib/src/core/models/attachment_file.dart index c6983b74..e855f7e3 100644 --- a/packages/stream_chat/lib/src/core/models/attachment_file.dart +++ b/packages/stream_chat/lib/src/core/models/attachment_file.dart @@ -11,54 +11,6 @@ part 'attachment_file.freezed.dart'; part 'attachment_file.g.dart'; -/// Union class to hold various [UploadState] of a attachment. -@freezed -class UploadState with _$UploadState { - /// Preparing state of the union - const factory UploadState.preparing() = Preparing; - - /// InProgress state of the union - const factory UploadState.inProgress({ - required int uploaded, - required int total, - }) = InProgress; - - /// Success state of the union - const factory UploadState.success() = Success; - - /// Failed state of the union - const factory UploadState.failed({required String error}) = Failed; - - /// Creates a new instance from a json - factory UploadState.fromJson(Map json) => - _$UploadStateFromJson(json); -} - -/// Helper extension for UploadState -extension UploadStateX on UploadState? { - /// Returns true if state is [Preparing] - bool get isPreparing => this is Preparing; - - /// Returns true if state is [InProgress] - bool get isInProgress => this is InProgress; - - /// Returns true if state is [Success] - bool get isSuccess => this is Success; - - /// Returns true if state is [Failed] - bool get isFailed => this is Failed; -} - -Uint8List? _fromString(String? bytes) { - if (bytes == null) return null; - return Uint8List.fromList(bytes.codeUnits); -} - -String? _toString(Uint8List? bytes) { - if (bytes == null) return null; - return String.fromCharCodes(bytes); -} - /// The class that contains the information about an attachment file @JsonSerializable() class AttachmentFile { @@ -135,3 +87,51 @@ class AttachmentFile { return multiPartFile; } } + +/// Union class to hold various [UploadState] of a attachment. +@freezed +class UploadState with _$UploadState { + /// Preparing state of the union + const factory UploadState.preparing() = Preparing; + + /// InProgress state of the union + const factory UploadState.inProgress({ + required int uploaded, + required int total, + }) = InProgress; + + /// Success state of the union + const factory UploadState.success() = Success; + + /// Failed state of the union + const factory UploadState.failed({required String error}) = Failed; + + /// Creates a new instance from a json + factory UploadState.fromJson(Map json) => + _$UploadStateFromJson(json); +} + +/// Helper extension for UploadState +extension UploadStateX on UploadState? { + /// Returns true if state is [Preparing] + bool get isPreparing => this is Preparing; + + /// Returns true if state is [InProgress] + bool get isInProgress => this is InProgress; + + /// Returns true if state is [Success] + bool get isSuccess => this is Success; + + /// Returns true if state is [Failed] + bool get isFailed => this is Failed; +} + +Uint8List? _fromString(String? bytes) { + if (bytes == null) return null; + return Uint8List.fromList(bytes.codeUnits); +} + +String? _toString(Uint8List? bytes) { + if (bytes == null) return null; + return String.fromCharCodes(bytes); +} diff --git a/packages/stream_chat/lib/src/core/models/channel_model.dart b/packages/stream_chat/lib/src/core/models/channel_model.dart index 7892cc10..ed7c2c2e 100644 --- a/packages/stream_chat/lib/src/core/models/channel_model.dart +++ b/packages/stream_chat/lib/src/core/models/channel_model.dart @@ -38,7 +38,8 @@ class ChannelModel { /// Create a new instance from a json factory ChannelModel.fromJson(Map json) => _$ChannelModelFromJson( - Serializer.moveToExtraDataFromRoot(json, topLevelFields)); + Serializer.moveToExtraDataFromRoot(json, topLevelFields), + ); /// The id of this channel final String id; diff --git a/packages/stream_chat/lib/src/core/models/message.dart b/packages/stream_chat/lib/src/core/models/message.dart index 490bd981..10ff713e 100644 --- a/packages/stream_chat/lib/src/core/models/message.dart +++ b/packages/stream_chat/lib/src/core/models/message.dart @@ -81,7 +81,8 @@ class Message extends Equatable { /// Create a new instance from a json factory Message.fromJson(Map json) => _$MessageFromJson( - Serializer.moveToExtraDataFromRoot(json, topLevelFields)); + Serializer.moveToExtraDataFromRoot(json, topLevelFields), + ); /// The message ID. This is either created by Stream or set client side when /// the message is added. diff --git a/packages/stream_chat/lib/src/core/models/own_user.dart b/packages/stream_chat/lib/src/core/models/own_user.dart index f65735ab..243f170c 100644 --- a/packages/stream_chat/lib/src/core/models/own_user.dart +++ b/packages/stream_chat/lib/src/core/models/own_user.dart @@ -48,7 +48,8 @@ class OwnUser extends User { /// Create a new instance from json. factory OwnUser.fromJson(Map json) => _$OwnUserFromJson( - Serializer.moveToExtraDataFromRoot(json, topLevelFields)); + Serializer.moveToExtraDataFromRoot(json, topLevelFields), + ); /// Create a new instance from [User] object. factory OwnUser.fromUser(User user) => OwnUser( diff --git a/packages/stream_chat/pubspec.yaml b/packages/stream_chat/pubspec.yaml index 0638bc51..e2f0356a 100644 --- a/packages/stream_chat/pubspec.yaml +++ b/packages/stream_chat/pubspec.yaml @@ -27,7 +27,8 @@ dependencies: dev_dependencies: build_runner: ^2.0.1 + dart_code_metrics: ^4.4.0 freezed: ^0.14.1+3 json_serializable: ^5.0.2 mocktail: ^0.1.1 - test: ^1.18.2 + test: ^1.17.12 \ No newline at end of file diff --git a/packages/stream_chat/test/src/client/channel_test.dart b/packages/stream_chat/test/src/client/channel_test.dart index 6ec26d27..c2ea57b5 100644 --- a/packages/stream_chat/test/src/client/channel_test.dart +++ b/packages/stream_chat/test/src/client/channel_test.dart @@ -291,7 +291,7 @@ void main() { (index) => Attachment( id: 'test-attachment-id-$index', type: index.isEven ? 'image' : 'file', - file: AttachmentFile(size: 33 * index, path: 'test-file-path'), + file: AttachmentFile(size: index * 33, path: 'test-file-path'), ), ); @@ -498,7 +498,7 @@ void main() { (index) => Attachment( id: 'test-attachment-id-$index', type: index.isEven ? 'image' : 'file', - file: AttachmentFile(size: 33 * index, path: 'test-file-path'), + file: AttachmentFile(size: index * 33, path: 'test-file-path'), ), ); diff --git a/packages/stream_chat_flutter/example/lib/tutorial_part_6.dart b/packages/stream_chat_flutter/example/lib/tutorial_part_6.dart index 2fbdcbee..af59d300 100644 --- a/packages/stream_chat_flutter/example/lib/tutorial_part_6.dart +++ b/packages/stream_chat_flutter/example/lib/tutorial_part_6.dart @@ -34,7 +34,7 @@ Future main() async { await client.connectUser( User(id: 'super-band-9'), - '''eyJ0eXAiO«iJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A''', + '''eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A''', ); runApp( diff --git a/packages/stream_chat_flutter/example/pubspec.yaml b/packages/stream_chat_flutter/example/pubspec.yaml index d3fec032..9c7ae6ee 100644 --- a/packages/stream_chat_flutter/example/pubspec.yaml +++ b/packages/stream_chat_flutter/example/pubspec.yaml @@ -1,4 +1,4 @@ -name: example +name: stream_chat_flutter_example description: A new Flutter project. # The following line prevents the package from being accidentally published to @@ -27,17 +27,9 @@ dependencies: cupertino_icons: ^1.0.3 flutter: sdk: flutter - # stream_chat: - # path: ../../stream_chat - # stream_chat_flutter_core: - # path: ../../stream_chat_flutter_core - stream_chat_flutter: - path: ../ - stream_chat_localizations: - path: ../../stream_chat_localizations - stream_chat_persistence: - path: ../../stream_chat_persistence - + stream_chat_flutter: ^2.2.1 + stream_chat_localizations: ^1.1.0 + stream_chat_persistence: ^2.2.0 dev_dependencies: flutter_test: diff --git a/packages/stream_chat_flutter/lib/src/attachment/attachment_upload_state_builder.dart b/packages/stream_chat_flutter/lib/src/attachment/attachment_upload_state_builder.dart index 1a0ba989..bd0aacc3 100644 --- a/packages/stream_chat_flutter/lib/src/attachment/attachment_upload_state_builder.dart +++ b/packages/stream_chat_flutter/lib/src/attachment/attachment_upload_state_builder.dart @@ -141,7 +141,7 @@ class _PreparingState extends StatelessWidget { uploaded: 0, total: double.maxFinite.toInt(), ), - ) + ), ], ); } @@ -181,7 +181,7 @@ class _InProgressState extends StatelessWidget { uploaded: sent, total: total, ), - ) + ), ], ); } @@ -234,7 +234,7 @@ class _FailedState extends StatelessWidget { ), ), ), - ) + ), ], ); } diff --git a/packages/stream_chat_flutter/lib/src/attachment/attachment_widget.dart b/packages/stream_chat_flutter/lib/src/attachment/attachment_widget.dart index e92087b5..7a5c891b 100644 --- a/packages/stream_chat_flutter/lib/src/attachment/attachment_widget.dart +++ b/packages/stream_chat_flutter/lib/src/attachment/attachment_widget.dart @@ -78,7 +78,7 @@ class AttachmentError extends StatelessWidget { color: StreamChatTheme.of(context) .colorTheme .accentError - .withOpacity(.1), + .withOpacity(0.1), child: Center( child: Icon( Icons.error_outline, diff --git a/packages/stream_chat_flutter/lib/src/attachment/file_attachment.dart b/packages/stream_chat_flutter/lib/src/attachment/file_attachment.dart index 4d2e8825..0b5d580f 100644 --- a/packages/stream_chat_flutter/lib/src/attachment/file_attachment.dart +++ b/packages/stream_chat_flutter/lib/src/attachment/file_attachment.dart @@ -253,7 +253,8 @@ class FileAttachment extends AttachmentWidget { if (message.status == MessageSendingStatus.sent) { trailingWidget = IconButton( icon: StreamSvgIcon.cloudDownload( - color: theme.colorTheme.textHighEmphasis), + color: theme.colorTheme.textHighEmphasis, + ), visualDensity: VisualDensity.compact, splashRadius: 16, onPressed: () { diff --git a/packages/stream_chat_flutter/lib/src/attachment/giphy_attachment.dart b/packages/stream_chat_flutter/lib/src/attachment/giphy_attachment.dart index 8272a962..46786f88 100644 --- a/packages/stream_chat_flutter/lib/src/attachment/giphy_attachment.dart +++ b/packages/stream_chat_flutter/lib/src/attachment/giphy_attachment.dart @@ -297,7 +297,7 @@ class GiphyAttachment extends AttachmentWidget { color: StreamChatTheme.of(context) .colorTheme .textHighEmphasis - .withOpacity(.5), + .withOpacity(0.5), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), diff --git a/packages/stream_chat_flutter/lib/src/attachment_actions_modal.dart b/packages/stream_chat_flutter/lib/src/attachment_actions_modal.dart index b5a3cc87..f49561aa 100644 --- a/packages/stream_chat_flutter/lib/src/attachment_actions_modal.dart +++ b/packages/stream_chat_flutter/lib/src/attachment_actions_modal.dart @@ -99,12 +99,14 @@ class AttachmentActionsModal extends StatelessWidget { () { final attachment = message.attachments[currentIndex]; final isImage = attachment.type == 'image'; - final Future Function(Attachment, - {void Function(int, int) progressCallback}) - saveFile = fileDownloader ?? _downloadAttachment; - final Future Function(Attachment, - {void Function(int, int) progressCallback}) - saveImage = imageDownloader ?? _downloadAttachment; + final Future Function( + Attachment, { + void Function(int, int) progressCallback, + }) saveFile = fileDownloader ?? _downloadAttachment; + final Future Function( + Attachment, { + void Function(int, int) progressCallback, + }) saveImage = imageDownloader ?? _downloadAttachment; final downloader = isImage ? saveImage : saveFile; final progressNotifier = @@ -183,7 +185,7 @@ class AttachmentActionsModal extends StatelessWidget { ), ), ), - ) + ), ], ); } diff --git a/packages/stream_chat_flutter/lib/src/back_button.dart b/packages/stream_chat_flutter/lib/src/back_button.dart index 6bd3e0cc..b0b04b8d 100644 --- a/packages/stream_chat_flutter/lib/src/back_button.dart +++ b/packages/stream_chat_flutter/lib/src/back_button.dart @@ -4,6 +4,7 @@ import 'package:stream_chat_flutter/src/unread_indicator.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; /// Back button implementation +// ignore: prefer-match-file-name class StreamBackButton extends StatelessWidget { /// Constructor for creating back button const StreamBackButton({ diff --git a/packages/stream_chat_flutter/lib/src/channel_bottom_sheet.dart b/packages/stream_chat_flutter/lib/src/channel_bottom_sheet.dart index f4be36e1..74661c08 100644 --- a/packages/stream_chat_flutter/lib/src/channel_bottom_sheet.dart +++ b/packages/stream_chat_flutter/lib/src/channel_bottom_sheet.dart @@ -77,7 +77,8 @@ class _ChannelBottomSheetState extends State { UserAvatar( user: members .firstWhere( - (e) => e.user?.id != userAsMember.user?.id) + (e) => e.user?.id != userAsMember.user?.id, + ) .user!, constraints: const BoxConstraints( maxHeight: 64, @@ -93,7 +94,8 @@ class _ChannelBottomSheetState extends State { Text( members .firstWhere( - (e) => e.user?.id != userAsMember.user?.id) + (e) => e.user?.id != userAsMember.user?.id, + ) .user ?.name ?? '', diff --git a/packages/stream_chat_flutter/lib/src/channel_list_header.dart b/packages/stream_chat_flutter/lib/src/channel_list_header.dart index 2dfc1ffb..3ebd9001 100644 --- a/packages/stream_chat_flutter/lib/src/channel_list_header.dart +++ b/packages/stream_chat_flutter/lib/src/channel_list_header.dart @@ -185,7 +185,7 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { ), onPressed: onNewChatButtonTap, ), - ) + ), ], title: Column( children: [ diff --git a/packages/stream_chat_flutter/lib/src/channel_list_view.dart b/packages/stream_chat_flutter/lib/src/channel_list_view.dart index 96b27823..fd59489a 100644 --- a/packages/stream_chat_flutter/lib/src/channel_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/channel_list_view.dart @@ -565,7 +565,8 @@ class _ChannelListViewState extends State { 'owner', ].contains(channel.state!.members .firstWhereOrNull( - (m) => m.userId == channel.client.state.currentUser?.id) + (m) => m.userId == channel.client.state.currentUser?.id, + ) ?.role)) IconSlideAction( color: backgroundColor, diff --git a/packages/stream_chat_flutter/lib/src/channel_preview.dart b/packages/stream_chat_flutter/lib/src/channel_preview.dart index 09cbfcc4..6e3e5363 100644 --- a/packages/stream_chat_flutter/lib/src/channel_preview.dart +++ b/packages/stream_chat_flutter/lib/src/channel_preview.dart @@ -72,85 +72,82 @@ class ChannelPreview extends StatelessWidget { final channelPreviewTheme = ChannelPreviewTheme.of(context); final streamChatState = StreamChat.of(context); return BetterStreamBuilder( - stream: channel.isMutedStream, - initialData: channel.isMuted, - builder: (context, data) => AnimatedOpacity( - opacity: data ? 0.5 : 1, - duration: const Duration(milliseconds: 300), - child: ListTile( - visualDensity: VisualDensity.compact, - contentPadding: const EdgeInsets.symmetric( - horizontal: 8, - ), - onTap: () => onTap?.call(channel), - onLongPress: () => onLongPress?.call(channel), - leading: leading ?? ChannelAvatar(onTap: onImageTap), - title: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Flexible( - child: title ?? - ChannelName( - textStyle: channelPreviewTheme.titleStyle, - ), + stream: channel.isMutedStream, + initialData: channel.isMuted, + builder: (context, data) => AnimatedOpacity( + opacity: data ? 0.5 : 1, + duration: const Duration(milliseconds: 300), + child: ListTile( + visualDensity: VisualDensity.compact, + contentPadding: const EdgeInsets.symmetric( + horizontal: 8, + ), + onTap: () => onTap?.call(channel), + onLongPress: () => onLongPress?.call(channel), + leading: leading ?? ChannelAvatar(onTap: onImageTap), + title: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Flexible( + child: title ?? + ChannelName( + textStyle: channelPreviewTheme.titleStyle, ), - BetterStreamBuilder>( - stream: channel.state?.membersStream, - initialData: channel.state?.members, - comparator: const ListEquality().equals, - builder: (context, members) { - if (members.isEmpty || - members.any((Member e) => - e.user!.id == - channel.client.state.currentUser?.id) != - true) { - return const SizedBox(); - } - return UnreadIndicator( - cid: channel.cid, - ); - }, - ), - ], - ), - subtitle: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Flexible(child: subtitle ?? _buildSubtitle(context)), - sendingIndicator ?? - Builder( - builder: (context) { - final lastMessage = - channel.state?.messages.lastWhereOrNull( - (m) => !m.isDeleted && m.shadowed != true, - ); - if (lastMessage?.user?.id == - streamChatState.currentUser?.id) { - return Padding( - padding: const EdgeInsets.only(right: 4), - child: SendingIndicator( - message: lastMessage!, - size: channelPreviewTheme.indicatorIconSize, - isMessageRead: channel.state!.read - .where((element) => - element.user.id != - channel - .client.state.currentUser!.id) - .where((element) => element.lastRead - .isAfter(lastMessage.createdAt)) - .isNotEmpty == - true, - ), - ); - } - return const SizedBox(); - }, - ), - trailing ?? _buildDate(context), - ], - ), ), - )); + BetterStreamBuilder>( + stream: channel.state?.membersStream, + initialData: channel.state?.members, + comparator: const ListEquality().equals, + builder: (context, members) { + if (members.isEmpty || + !members.any((Member e) => + e.user!.id == channel.client.state.currentUser?.id)) { + return const SizedBox(); + } + return UnreadIndicator( + cid: channel.cid, + ); + }, + ), + ], + ), + subtitle: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Flexible(child: subtitle ?? _buildSubtitle(context)), + sendingIndicator ?? + Builder( + builder: (context) { + final lastMessage = + channel.state?.messages.lastWhereOrNull( + (m) => !m.isDeleted && !m.shadowed, + ); + if (lastMessage?.user?.id == + streamChatState.currentUser?.id) { + return Padding( + padding: const EdgeInsets.only(right: 4), + child: SendingIndicator( + message: lastMessage!, + size: channelPreviewTheme.indicatorIconSize, + isMessageRead: channel.state!.read + .where((element) => + element.user.id != + channel.client.state.currentUser!.id) + .where((element) => element.lastRead + .isAfter(lastMessage.createdAt)) + .isNotEmpty, + ), + ); + } + return const SizedBox(); + }, + ), + trailing ?? _buildDate(context), + ], + ), + ), + ), + ); } Widget _buildDate(BuildContext context) => BetterStreamBuilder( @@ -246,10 +243,11 @@ class ChannelPreview extends StatelessWidget { lastMessage.mentionedUsers, lastMessage.attachments, channelPreviewTheme.subtitleStyle?.copyWith( - color: channelPreviewTheme.subtitleStyle?.color, - fontStyle: (lastMessage.isSystem || lastMessage.isDeleted) - ? FontStyle.italic - : FontStyle.normal), + color: channelPreviewTheme.subtitleStyle?.color, + fontStyle: (lastMessage.isSystem || lastMessage.isDeleted) + ? FontStyle.italic + : FontStyle.normal, + ), channelPreviewTheme.subtitleStyle?.copyWith( color: channelPreviewTheme.subtitleStyle?.color, fontStyle: (lastMessage.isSystem || lastMessage.isDeleted) diff --git a/packages/stream_chat_flutter/lib/src/commands_overlay.dart b/packages/stream_chat_flutter/lib/src/commands_overlay.dart index ffaec928..9f8aca1e 100644 --- a/packages/stream_chat_flutter/lib/src/commands_overlay.dart +++ b/packages/stream_chat_flutter/lib/src/commands_overlay.dart @@ -49,8 +49,9 @@ class CommandsOverlay extends StatelessWidget { child: Container( constraints: BoxConstraints.loose(size), decoration: BoxDecoration( - color: _streamChatTheme.colorTheme.barsBg, - borderRadius: BorderRadius.circular(8)), + color: _streamChatTheme.colorTheme.barsBg, + borderRadius: BorderRadius.circular(8), + ), child: ListView( padding: const EdgeInsets.all(0), shrinkWrap: true, @@ -72,9 +73,9 @@ class CommandsOverlay extends StatelessWidget { context.translations.instantCommandsLabel, style: TextStyle( color: _streamChatTheme.colorTheme.textHighEmphasis - .withOpacity(.5), + .withOpacity(0.5), ), - ) + ), ], ), ), @@ -102,7 +103,8 @@ class CommandsOverlay extends StatelessWidget { TextSpan( text: c.name.capitalize(), style: const TextStyle( - fontWeight: FontWeight.bold), + fontWeight: FontWeight.bold, + ), children: [ TextSpan( text: ' /${c.name} ${c.args}', @@ -132,7 +134,9 @@ class CommandsOverlay extends StatelessWidget { } Widget _buildCommandIcon( - StreamChatThemeData _streamChatTheme, String iconType) { + StreamChatThemeData _streamChatTheme, + String iconType, + ) { switch (iconType) { case 'giphy': return CircleAvatar( diff --git a/packages/stream_chat_flutter/lib/src/date_divider.dart b/packages/stream_chat_flutter/lib/src/date_divider.dart index 7c977f60..c3b48158 100644 --- a/packages/stream_chat_flutter/lib/src/date_divider.dart +++ b/packages/stream_chat_flutter/lib/src/date_divider.dart @@ -21,25 +21,16 @@ class DateDivider extends StatelessWidget { @override Widget build(BuildContext context) { final createdAt = Jiffy(dateTime); - final now = DateTime.now(); + final now = Jiffy(DateTime.now()); - String dayInfo; - if (Jiffy(createdAt).isSame(now, Units.DAY)) { + var dayInfo = createdAt.MMMd; + if (createdAt.isSame(now, Units.DAY)) { dayInfo = context.translations.todayLabel; - } else if (Jiffy(createdAt) - .isSame(now.subtract(const Duration(days: 1)), Units.DAY)) { + } else if (createdAt.isSame(now.subtract(days: 1), Units.DAY)) { dayInfo = context.translations.yesterdayLabel; - } else if (Jiffy(createdAt).isAfter( - now.subtract(const Duration(days: 7)), - Units.DAY, - )) { + } else if (createdAt.isAfter(now.subtract(days: 7), Units.DAY)) { dayInfo = createdAt.EEEE; - } else if (Jiffy(createdAt).isAfter( - Jiffy(now).subtract(years: 1), - Units.DAY, - )) { - dayInfo = createdAt.MMMd; - } else { + } else if (createdAt.isAfter(now.subtract(years: 1), Units.DAY)) { dayInfo = createdAt.MMMd; } diff --git a/packages/stream_chat_flutter/lib/src/emoji_overlay.dart b/packages/stream_chat_flutter/lib/src/emoji_overlay.dart index c37dd687..0a3cb634 100644 --- a/packages/stream_chat_flutter/lib/src/emoji_overlay.dart +++ b/packages/stream_chat_flutter/lib/src/emoji_overlay.dart @@ -81,10 +81,10 @@ class EmojiOverlay extends StatelessWidget { ), style: TextStyle( color: _streamChatTheme.colorTheme.textHighEmphasis - .withOpacity(.5), + .withOpacity(0.5), ), ), - ) + ), ], ), ); diff --git a/packages/stream_chat_flutter/lib/src/extension.dart b/packages/stream_chat_flutter/lib/src/extension.dart index 0072a811..92590de1 100644 --- a/packages/stream_chat_flutter/lib/src/extension.dart +++ b/packages/stream_chat_flutter/lib/src/extension.dart @@ -127,7 +127,8 @@ extension FlipBorder on BorderRadius { topLeft: topRight, topRight: topLeft, bottomLeft: bottomRight, - bottomRight: bottomLeft) + bottomRight: bottomLeft, + ) : this; } diff --git a/packages/stream_chat_flutter/lib/src/full_screen_media.dart b/packages/stream_chat_flutter/lib/src/full_screen_media.dart index a959229c..0c47383c 100644 --- a/packages/stream_chat_flutter/lib/src/full_screen_media.dart +++ b/packages/stream_chat_flutter/lib/src/full_screen_media.dart @@ -87,7 +87,7 @@ class _FullScreenMediaState extends State await Future.wait(videoPackages.values.map( (it) => it.initialize(), )); - setState(() {}); + setState(() {}); // ignore: no-empty-block } @override @@ -96,83 +96,83 @@ class _FullScreenMediaState extends State body: Stack( children: [ AnimatedBuilder( - animation: _controller, - builder: (context, snapshot) => PageView.builder( - controller: _pageController, - onPageChanged: (val) { + animation: _controller, + builder: (context, snapshot) => PageView.builder( + controller: _pageController, + onPageChanged: (val) { + setState(() { + _currentPage = val; + }); + }, + itemBuilder: (context, index) { + final attachment = widget.mediaAttachments[index]; + if (attachment.type == 'image' || + attachment.type == 'giphy') { + final imageUrl = attachment.imageUrl ?? + attachment.assetUrl ?? + attachment.thumbUrl; + return PhotoView( + loadingBuilder: (context, image) => const Offstage(), + imageProvider: (imageUrl == null && + attachment.localUri != null && + attachment.file?.bytes != null) + ? Image.memory(attachment.file!.bytes!).image + : CachedNetworkImageProvider(imageUrl!), + maxScale: PhotoViewComputedScale.covered, + minScale: PhotoViewComputedScale.contained, + heroAttributes: PhotoViewHeroAttributes( + tag: widget.mediaAttachments, + ), + backgroundDecoration: BoxDecoration( + color: ColorTween( + begin: ChannelHeaderTheme.of(context).color, + end: Colors.black, + ).lerp(_controller.value), + ), + onTapUp: (a, b, c) { setState(() { - _currentPage = val; + _optionsShown = !_optionsShown; }); - }, - itemBuilder: (context, index) { - final attachment = widget.mediaAttachments[index]; - if (attachment.type == 'image' || - attachment.type == 'giphy') { - final imageUrl = attachment.imageUrl ?? - attachment.assetUrl ?? - attachment.thumbUrl; - return PhotoView( - loadingBuilder: (context, image) => - const Offstage(), - imageProvider: (imageUrl == null && - attachment.localUri != null && - attachment.file?.bytes != null) - ? Image.memory(attachment.file!.bytes!).image - : CachedNetworkImageProvider(imageUrl!), - maxScale: PhotoViewComputedScale.covered, - minScale: PhotoViewComputedScale.contained, - heroAttributes: PhotoViewHeroAttributes( - tag: widget.mediaAttachments, - ), - backgroundDecoration: BoxDecoration( - color: ColorTween( - begin: ChannelHeaderTheme.of(context).color, - end: Colors.black, - ).lerp(_controller.value), - ), - onTapUp: (a, b, c) { - setState(() { - _optionsShown = !_optionsShown; - }); - if (_controller.isCompleted) { - _controller.reverse(); - } else { - _controller.forward(); - } - }, - ); - } else if (attachment.type == 'video') { - final controller = videoPackages[attachment.id]!; - if (!controller.initialized) { - return const Center( - child: CircularProgressIndicator(), - ); - } - return InkWell( - onTap: () { - setState(() { - _optionsShown = !_optionsShown; - }); - if (_controller.isCompleted) { - _controller.reverse(); - } else { - _controller.forward(); - } - }, - child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 50, - ), - child: Chewie( - controller: controller.chewieController!, - ), - ), - ); + if (_controller.isCompleted) { + _controller.reverse(); + } else { + _controller.forward(); } - return Container(); }, - itemCount: widget.mediaAttachments.length, - )), + ); + } else if (attachment.type == 'video') { + final controller = videoPackages[attachment.id]!; + if (!controller.initialized) { + return const Center( + child: CircularProgressIndicator(), + ); + } + return InkWell( + onTap: () { + setState(() { + _optionsShown = !_optionsShown; + }); + if (_controller.isCompleted) { + _controller.reverse(); + } else { + _controller.forward(); + } + }, + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 50, + ), + child: Chewie( + controller: controller.chewieController!, + ), + ), + ); + } + return Container(); + }, + itemCount: widget.mediaAttachments.length, + ), + ), AnimatedOpacity( opacity: _optionsShown ? 1.0 : 0.0, duration: const Duration(milliseconds: 300), diff --git a/packages/stream_chat_flutter/lib/src/gallery_footer.dart b/packages/stream_chat_flutter/lib/src/gallery_footer.dart index eaa03fb7..dcfa0e29 100644 --- a/packages/stream_chat_flutter/lib/src/gallery_footer.dart +++ b/packages/stream_chat_flutter/lib/src/gallery_footer.dart @@ -1,4 +1,3 @@ -import 'dart:async'; import 'dart:io'; import 'package:cached_network_image/cached_network_image.dart'; @@ -67,19 +66,6 @@ class GalleryFooter extends StatefulWidget implements PreferredSizeWidget { } class _GalleryFooterState extends State { - final TextEditingController _messageController = TextEditingController(); - final FocusNode _messageFocusNode = FocusNode(); - - final List _selectedChannels = []; - - @override - void initState() { - super.initState(); - _messageFocusNode.addListener(() { - setState(() {}); - }); - } - @override Widget build(BuildContext context) { const showShareButton = !kIsWeb; @@ -143,8 +129,9 @@ class _GalleryFooterState extends State { children: [ Text( context.translations.galleryPaginationText( - currentPage: widget.currentPage, - totalPages: widget.totalPages), + currentPage: widget.currentPage, + totalPages: widget.totalPages, + ), style: galleryFooterThemeData.titleTextStyle, ), ], @@ -267,6 +254,7 @@ class _GalleryFooterState extends State { Padding( padding: const EdgeInsets.all(8), child: Container( + padding: const EdgeInsets.all(2), clipBehavior: Clip.antiAlias, decoration: BoxDecoration( shape: BoxShape.circle, @@ -280,7 +268,6 @@ class _GalleryFooterState extends State { ), ], ), - padding: const EdgeInsets.all(2), child: UserAvatar( user: widget.message.user!, constraints: @@ -301,25 +288,4 @@ class _GalleryFooterState extends State { }, ); } - - /// Sends the current message - Future sendMessage() async { - final text = _messageController.text.trim(); - - final attachments = widget.message.attachments; - - _messageController.clear(); - - for (final channel in _selectedChannels) { - final message = Message( - text: text, - attachments: [attachments[widget.currentPage]], - ); - - await channel.sendMessage(message); - } - - _selectedChannels.clear(); - Navigator.pop(context); - } } diff --git a/packages/stream_chat_flutter/lib/src/gradient_avatar.dart b/packages/stream_chat_flutter/lib/src/gradient_avatar.dart index 3a6aba10..a02976c8 100644 --- a/packages/stream_chat_flutter/lib/src/gradient_avatar.dart +++ b/packages/stream_chat_flutter/lib/src/gradient_avatar.dart @@ -106,7 +106,8 @@ class DemoPainter extends CustomPainter { final p4 = pointsList.indexOf(off4); squares.add( - Offset4(p1, p2, p3, p4, i, j, rowCount, columnCount, gradient)); + Offset4(p1, p2, p3, p4, i, j, rowCount, columnCount, gradient), + ); } } @@ -123,17 +124,18 @@ class DemoPainter extends CustomPainter { final fontSize = username.length == 2 ? textSize : textSize * 1.5; TextPainter( - text: TextSpan( - text: username, - style: TextStyle( - fontFamily: fontFamily, - fontSize: fontSize, - fontWeight: FontWeight.w500, - color: Colors.white.withOpacity(0.7), - ), + text: TextSpan( + text: username, + style: TextStyle( + fontFamily: fontFamily, + fontSize: fontSize, + fontWeight: FontWeight.w500, + color: Colors.white.withOpacity(0.7), ), - textAlign: TextAlign.center, - textDirection: TextDirection.ltr) + ), + textAlign: TextAlign.center, + textDirection: TextDirection.ltr, + ) ..layout(maxWidth: size.width) ..paint( canvas, @@ -168,8 +170,8 @@ class DemoPainter extends CustomPainter { final sign1 = rand.nextInt(2) == 1 ? 1 : -1; final sign2 = rand.nextInt(2) == 1 ? 1 : -1; - final dx = 0.6 * sign1 * rand.nextInt(size.width ~/ columnCount); - final dy = 0.6 * sign2 * rand.nextInt(size.height ~/ rowCount); + final dx = sign1 * 0.6 * rand.nextInt(size.width ~/ columnCount); + final dy = sign2 * 0.6 * rand.nextInt(size.height ~/ rowCount); transformedList.add(Offset(orgDx + dx, orgDy + dy)); } @@ -223,8 +225,12 @@ class Offset4 { /// Draw the polygon on canvas void draw(Canvas canvas, List points) { final paint = Paint() - ..color = Color.fromARGB(255, Random().nextInt(255), - Random().nextInt(255), Random().nextInt(255)) + ..color = Color.fromARGB( + 255, + Random().nextInt(255), + Random().nextInt(255), + Random().nextInt(255), + ) ..shader = ui.Gradient.linear( points[p1], points[p3], diff --git a/packages/stream_chat_flutter/lib/src/localization/translations.dart b/packages/stream_chat_flutter/lib/src/localization/translations.dart index 246cd9bf..8aa8d071 100644 --- a/packages/stream_chat_flutter/lib/src/localization/translations.dart +++ b/packages/stream_chat_flutter/lib/src/localization/translations.dart @@ -300,8 +300,10 @@ abstract class Translations { String get youText; /// Gallery footer pagination text - String galleryPaginationText( - {required int currentPage, required int totalPages}); + String galleryPaginationText({ + required int currentPage, + required int totalPages, + }); /// The text shown for "File" String get fileText; @@ -665,8 +667,10 @@ class DefaultTranslations implements Translations { String get youText => 'You'; @override - String galleryPaginationText( - {required int currentPage, required int totalPages}) => + String galleryPaginationText({ + required int currentPage, + required int totalPages, + }) => '${currentPage + 1} of $totalPages'; @override diff --git a/packages/stream_chat_flutter/lib/src/media_list_view.dart b/packages/stream_chat_flutter/lib/src/media_list_view.dart index 77359f8b..4c845529 100644 --- a/packages/stream_chat_flutter/lib/src/media_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/media_list_view.dart @@ -129,7 +129,7 @@ class _MediaListViewState extends State { ), ), ), - ] + ], ], ), ), @@ -144,9 +144,9 @@ class _MediaListViewState extends State { _getMedia(); } - void _getMedia() async { + Future _getMedia() async { final assetList = await PhotoManager.getAssetPathList().then((value) { - if (value.isNotEmpty == true) { + if (value.isNotEmpty) { return value.singleWhere((element) => element.isAll); } }); @@ -178,7 +178,9 @@ class MediaThumbnailProvider extends ImageProvider { @override ImageStreamCompleter load( - MediaThumbnailProvider key, DecoderCallback decode) => + MediaThumbnailProvider key, + DecoderCallback decode, + ) => MultiFrameImageStreamCompleter( codec: _loadAsync(key, decode), scale: 1, @@ -188,7 +190,9 @@ class MediaThumbnailProvider extends ImageProvider { ); Future _loadAsync( - MediaThumbnailProvider key, DecoderCallback decode) async { + MediaThumbnailProvider key, + DecoderCallback decode, + ) async { assert(key == this, 'Checks MediaThumbnailProvider'); final bytes = await media.thumbData; diff --git a/packages/stream_chat_flutter/lib/src/message_actions_modal.dart b/packages/stream_chat_flutter/lib/src/message_actions_modal.dart index 387e31a1..a67004af 100644 --- a/packages/stream_chat_flutter/lib/src/message_actions_modal.dart +++ b/packages/stream_chat_flutter/lib/src/message_actions_modal.dart @@ -104,7 +104,7 @@ class _MessageActionsModalState extends State { final size = mediaQueryData.size; final user = StreamChat.of(context).currentUser; - final roughMaxSize = 2 * size.width / 3; + final roughMaxSize = size.width * 2 / 3; var messageTextLength = widget.message.text!.length; if (widget.message.quotedMessage != null) { var quotedMessageLength = @@ -119,7 +119,7 @@ class _MessageActionsModalState extends State { final roughSentenceSize = messageTextLength * (widget.messageTheme.messageTextStyle?.fontSize ?? 1) * 1.2; - final divFactor = widget.message.attachments.isNotEmpty == true + final divFactor = widget.message.attachments.isNotEmpty ? 1 : (roughSentenceSize == 0 ? 1 : (roughSentenceSize / roughMaxSize)); @@ -142,14 +142,15 @@ class _MessageActionsModalState extends State { (widget.message.status == MessageSendingStatus.sent)) Align( alignment: Alignment( - user?.id == widget.message.user?.id - ? (divFactor >= 1.0 - ? -0.2 - shiftFactor - : (1.2 - divFactor)) - : (divFactor >= 1.0 - ? 0.2 + shiftFactor - : -(1.2 - divFactor)), - 0), + user?.id == widget.message.user?.id + ? (divFactor >= 1.0 + ? -0.2 - shiftFactor + : (1.2 - divFactor)) + : (divFactor >= 1.0 + ? shiftFactor + 0.2 + : -(1.2 - divFactor)), + 0, + ), child: ReactionPicker( message: widget.message, ), @@ -194,7 +195,7 @@ class _MessageActionsModalState extends State { .map((action) => _buildCustomAction( context, action, - )) + )), ].insertBetween( Container( height: 1, diff --git a/packages/stream_chat_flutter/lib/src/message_input.dart b/packages/stream_chat_flutter/lib/src/message_input.dart index fed1cc4e..08fc2a7b 100644 --- a/packages/stream_chat_flutter/lib/src/message_input.dart +++ b/packages/stream_chat_flutter/lib/src/message_input.dart @@ -17,7 +17,7 @@ import 'package:stream_chat_flutter/src/emoji_overlay.dart'; import 'package:stream_chat_flutter/src/extension.dart'; import 'package:stream_chat_flutter/src/media_list_view.dart'; import 'package:stream_chat_flutter/src/message_list_view.dart'; -import 'package:stream_chat_flutter/src/overlays.dart'; +import 'package:stream_chat_flutter/src/multi_overlay.dart'; import 'package:stream_chat_flutter/src/quoted_message_widget.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; @@ -373,11 +373,13 @@ class MessageInputState extends State { _parseExistingMessage(widget.editMessage ?? widget.initialMessage!); } textEditingController.addListener(_onChangedDebounced); - _focusNode.addListener(() { - if (_focusNode.hasFocus) { - _openFilePickerSection = false; - } - }); + _focusNode.addListener(_focusNodeListener); + } + + void _focusNodeListener() { + if (_focusNode.hasFocus) { + _openFilePickerSection = false; + } } int _timeOut = 0; @@ -536,7 +538,7 @@ class MessageInputState extends State { ? null : Border.all( color: _streamChatTheme.colorTheme.textHighEmphasis - .withOpacity(.5), + .withOpacity(0.5), width: 2, ), borderRadius: BorderRadius.circular(3), @@ -640,7 +642,7 @@ class MessageInputState extends State { ), secondChild: widget.disableAttachments && !widget.showCommandsButton && - widget.actions.isNotEmpty != true + !widget.actions.isNotEmpty ? const Offstage() : Wrap( children: [ @@ -706,7 +708,7 @@ class MessageInputState extends State { decoration: _getInputDecoration(context), textCapitalization: TextCapitalization.sentences, ), - ) + ), ], ), ), @@ -827,6 +829,7 @@ class MessageInputState extends State { final channel = StreamChannel.of(context).channel; if (value.isNotEmpty) { + // ignore: no-empty-block channel.keyStroke(widget.parentMessage?.id).catchError((e) {}); } @@ -1028,8 +1031,10 @@ class MessageInputState extends State { _attachments.isNotEmpty) ? null : () { - pickFile(DefaultAttachmentTypes.image, - camera: true); + pickFile( + DefaultAttachmentTypes.image, + camera: true, + ); }, ), IconButton( @@ -1042,8 +1047,10 @@ class MessageInputState extends State { _attachments.isNotEmpty) ? null : () { - pickFile(DefaultAttachmentTypes.video, - camera: true); + pickFile( + DefaultAttachmentTypes.video, + camera: true, + ); }, ), ], @@ -1195,8 +1202,9 @@ class MessageInputState extends State { textEditingController.value = TextEditingValue( text: rejoin + - textEditingController.text - .substring(textEditingController.selection.start), + textEditingController.text.substring( + textEditingController.selection.start, + ), selection: TextSelection.collapsed( offset: rejoin.length, ), @@ -1254,8 +1262,7 @@ class MessageInputState extends State { Widget _buildReplyToMessage() { if (!_hasQuotedMessage) return const Offstage(); final containsUrl = widget.quotedMessage!.attachments - .any((element) => element.titleLink != null) == - true; + .any((element) => element.titleLink != null); return QuotedMessageWidget( reverse: true, showBorder: !containsUrl, @@ -1360,7 +1367,7 @@ class MessageInputState extends State { setState(() => _attachments.remove(attachment.id)); }, fillColor: - _streamChatTheme.colorTheme.textHighEmphasis.withOpacity(.5), + _streamChatTheme.colorTheme.textHighEmphasis.withOpacity(0.5), child: Center( child: StreamSvgIcon.close( size: 24, @@ -1839,10 +1846,11 @@ class MessageInputState extends State { backgroundColor: _streamChatTheme.colorTheme.barsBg, context: context, shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.only( - topLeft: Radius.circular(16), - topRight: Radius.circular(16), - )), + borderRadius: BorderRadius.only( + topLeft: Radius.circular(16), + topRight: Radius.circular(16), + ), + ), builder: (context) => Column( mainAxisSize: MainAxisSize.min, children: [ @@ -1875,7 +1883,7 @@ class MessageInputState extends State { ), Container( color: - _streamChatTheme.colorTheme.textHighEmphasis.withOpacity(.08), + _streamChatTheme.colorTheme.textHighEmphasis.withOpacity(0.08), height: 1, ), Row( @@ -1908,6 +1916,7 @@ class MessageInputState extends State { @override void dispose() { textEditingController.dispose(); + _focusNode.removeListener(_focusNodeListener); _stopSlowMode(); _onChangedDebounced.cancel(); super.dispose(); @@ -2018,7 +2027,8 @@ class _PickerWidgetState extends State<_PickerWidget> { Text( context.translations.enablePhotoAndVideoAccessMessage, style: widget.streamChatTheme.textTheme.body.copyWith( - color: widget.streamChatTheme.colorTheme.textLowEmphasis), + color: widget.streamChatTheme.colorTheme.textLowEmphasis, + ), textAlign: TextAlign.center, ), const SizedBox(height: 6), diff --git a/packages/stream_chat_flutter/lib/src/message_list_view.dart b/packages/stream_chat_flutter/lib/src/message_list_view.dart index 56c17270..ad2ff455 100644 --- a/packages/stream_chat_flutter/lib/src/message_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/message_list_view.dart @@ -60,6 +60,7 @@ typedef OnMessageTap = void Function(Message); typedef ReplyTapCallback = void Function(Message); /// Class for message details +// ignore: prefer-match-file-name class MessageDetails { /// Constructor for creating [MessageDetails] MessageDetails( @@ -358,8 +359,9 @@ class _MessageListViewState extends State { child: Text( context.translations.emptyChatMessagesText, style: _streamTheme.textTheme.footnote.copyWith( - color: _streamTheme.colorTheme.textHighEmphasis - .withOpacity(.5)), + color: _streamTheme.colorTheme.textHighEmphasis + .withOpacity(0.5), + ), ), ), messageListBuilder: widget.messageListBuilder ?? @@ -371,8 +373,9 @@ class _MessageListViewState extends State { child: Text( context.translations.genericErrorText, style: _streamTheme.textTheme.footnote.copyWith( - color: _streamTheme.colorTheme.textHighEmphasis - .withOpacity(.5)), + color: _streamTheme.colorTheme.textHighEmphasis + .withOpacity(0.5), + ), ), ), ); @@ -383,7 +386,7 @@ class _MessageListViewState extends State { if (_messageListLength != null) { if (_bottomPaginationActive || (_inBetweenList && _upToDate)) { - if (_itemPositionListener.itemPositions.value.isNotEmpty == true) { + if (_itemPositionListener.itemPositions.value.isNotEmpty) { final first = _itemPositionListener.itemPositions.value.first; final diff = newMessagesListLength - _messageListLength!; if (diff > 0) { @@ -674,7 +677,8 @@ class _MessageListViewState extends State { child: BetterStreamBuilder>( initialData: _itemPositionListener.itemPositions.value, stream: _valueListenableToStreamAdapter( - _itemPositionListener.itemPositions), + _itemPositionListener.itemPositions, + ), comparator: (a, b) { if (a == null || b == null) { return false; @@ -984,7 +988,7 @@ class _MessageListViewState extends State { final allRead = readList.length >= (channel.memberCount ?? 0) - 1; final hasFileAttachment = - message.attachments.any((it) => it.type == 'file') == true; + message.attachments.any((it) => it.type == 'file'); final isThreadMessage = message.parentId != null && message.showInChannel == true; @@ -1016,7 +1020,7 @@ class _MessageListViewState extends State { final isOnlyEmoji = message.text?.isOnlyEmoji ?? false; final hasUrlAttachment = - message.attachments.any((it) => it.titleLink != null) == true; + message.attachments.any((it) => it.titleLink != null); final borderSide = isOnlyEmoji || hasUrlAttachment || (isMyMessage && !hasFileAttachment) @@ -1259,10 +1263,11 @@ class _MessageListViewState extends State { if (widget.onThreadTap != null) { _onThreadTap = (Message message) { widget.onThreadTap!( - message, - widget.threadBuilder != null - ? widget.threadBuilder!(context, message) - : null); + message, + widget.threadBuilder != null + ? widget.threadBuilder!(context, message) + : null, + ); }; } else if (widget.threadBuilder != null) { _onThreadTap = (Message message) { @@ -1271,7 +1276,8 @@ class _MessageListViewState extends State { MaterialPageRoute( builder: (_) => BetterStreamBuilder( stream: streamChannel!.channel.state!.messagesStream.map( - (messages) => messages.firstWhere((m) => m.id == message.id)), + (messages) => messages.firstWhere((m) => m.id == message.id), + ), initialData: message, builder: (_, data) => StreamChannel( channel: streamChannel!.channel, @@ -1320,7 +1326,7 @@ class _LoadingIndicator extends StatelessWidget { stream: stream, initialData: false, errorBuilder: (context, error) => Container( - color: streamTheme.colorTheme.accentError.withOpacity(.2), + color: streamTheme.colorTheme.accentError.withOpacity(0.2), child: Center( child: Text(context.translations.loadingMessagesError), ), diff --git a/packages/stream_chat_flutter/lib/src/message_reactions_modal.dart b/packages/stream_chat_flutter/lib/src/message_reactions_modal.dart index e9f2e55e..6a73c439 100644 --- a/packages/stream_chat_flutter/lib/src/message_reactions_modal.dart +++ b/packages/stream_chat_flutter/lib/src/message_reactions_modal.dart @@ -46,11 +46,11 @@ class MessageReactionsModal extends StatelessWidget { final size = MediaQuery.of(context).size; final user = StreamChat.of(context).currentUser; - final roughMaxSize = 2 * size.width / 3; + final roughMaxSize = size.width * 2 / 3; var messageTextLength = message.text!.length; if (message.quotedMessage != null) { var quotedMessageLength = message.quotedMessage!.text!.length + 40; - if (message.quotedMessage!.attachments.isNotEmpty == true) { + if (message.quotedMessage!.attachments.isNotEmpty) { quotedMessageLength += 40; } if (quotedMessageLength > messageTextLength) { @@ -60,7 +60,7 @@ class MessageReactionsModal extends StatelessWidget { final roughSentenceSize = messageTextLength * (messageTheme.messageTextStyle?.fontSize ?? 1) * 1.2; - final divFactor = message.attachments.isNotEmpty == true + final divFactor = message.attachments.isNotEmpty ? 1 : (roughSentenceSize == 0 ? 1 : (roughSentenceSize / roughMaxSize)); @@ -80,14 +80,15 @@ class MessageReactionsModal extends StatelessWidget { (message.status == MessageSendingStatus.sent)) Align( alignment: Alignment( - user!.id == message.user!.id - ? (divFactor >= 1.0 - ? -0.2 - shiftFactor - : (1.2 - divFactor)) - : (divFactor >= 1.0 - ? 0.2 + shiftFactor - : -(1.2 - divFactor)), - 0), + user!.id == message.user!.id + ? (divFactor >= 1.0 + ? -0.2 - shiftFactor + : (1.2 - divFactor)) + : (divFactor >= 1.0 + ? shiftFactor + 0.2 + : -(1.2 - divFactor)), + 0, + ), child: ReactionPicker( message: message, ), @@ -102,7 +103,7 @@ class MessageReactionsModal extends StatelessWidget { context, user, ), - ] + ], ], ), ), diff --git a/packages/stream_chat_flutter/lib/src/message_search_item.dart b/packages/stream_chat_flutter/lib/src/message_search_item.dart index 89d43531..07f9f1c4 100644 --- a/packages/stream_chat_flutter/lib/src/message_search_item.dart +++ b/packages/stream_chat_flutter/lib/src/message_search_item.dart @@ -146,11 +146,12 @@ class MessageSearchItem extends StatelessWidget { } TextSpan _getDisplayText( - String text, - List mentions, - List attachments, - TextStyle? normalTextStyle, - TextStyle? mentionsTextStyle) { + String text, + List mentions, + List attachments, + TextStyle? normalTextStyle, + TextStyle? mentionsTextStyle, + ) { final textList = text.split(' '); final resList = []; for (final e in textList) { diff --git a/packages/stream_chat_flutter/lib/src/message_search_list_view.dart b/packages/stream_chat_flutter/lib/src/message_search_list_view.dart index daf34ff4..a5edc203 100644 --- a/packages/stream_chat_flutter/lib/src/message_search_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/message_search_list_view.dart @@ -217,7 +217,9 @@ class _MessageSearchListViewState extends State { ); Widget _listItemBuilder( - BuildContext context, GetMessageResponse getMessageResponse) { + BuildContext context, + GetMessageResponse getMessageResponse, + ) { if (widget.itemBuilder != null) { return widget.itemBuilder!(context, getMessageResponse); } @@ -231,33 +233,34 @@ class _MessageSearchListViewState extends State { final messageSearchBloc = MessageSearchBloc.of(context); return StreamBuilder( - stream: messageSearchBloc.queryMessagesLoading, - initialData: false, - builder: (context, snapshot) { - if (snapshot.hasError) { - return Container( - color: StreamChatTheme.of(context) - .colorTheme - .accentError - .withOpacity(.2), - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 16), - child: Center( - child: Text(context.translations.loadingMessagesError), - ), - ), - ); - } + stream: messageSearchBloc.queryMessagesLoading, + initialData: false, + builder: (context, snapshot) { + if (snapshot.hasError) { return Container( - height: 100, - padding: const EdgeInsets.all(32), - child: Center( - child: snapshot.data! - ? const CircularProgressIndicator() - : Container(), + color: StreamChatTheme.of(context) + .colorTheme + .accentError + .withOpacity(0.2), + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 16), + child: Center( + child: Text(context.translations.loadingMessagesError), + ), ), ); - }); + } + return Container( + height: 100, + padding: const EdgeInsets.all(32), + child: Center( + child: snapshot.data! + ? const CircularProgressIndicator() + : Container(), + ), + ); + }, + ); } Widget _buildListView(List data) { diff --git a/packages/stream_chat_flutter/lib/src/message_text.dart b/packages/stream_chat_flutter/lib/src/message_text.dart index c1aad231..6cdcd760 100644 --- a/packages/stream_chat_flutter/lib/src/message_text.dart +++ b/packages/stream_chat_flutter/lib/src/message_text.dart @@ -88,7 +88,9 @@ class MessageText extends StatelessWidget { for (final user in message.mentionedUsers.toSet()) { final userName = user.name; messageTextToRender = messageTextToRender.replaceAll( - '@$userName', '[@$userName](@${userName.replaceAll(' ', '')})'); + '@$userName', + '[@$userName](@${userName.replaceAll(' ', '')})', + ); } return messageTextToRender; } diff --git a/packages/stream_chat_flutter/lib/src/message_widget.dart b/packages/stream_chat_flutter/lib/src/message_widget.dart index 4422cdf9..45ea8122 100644 --- a/packages/stream_chat_flutter/lib/src/message_widget.dart +++ b/packages/stream_chat_flutter/lib/src/message_widget.dart @@ -575,8 +575,7 @@ class _MessageWidgetState extends State bool get isFailedState => isSendFailed || isUpdateFailed || isDeleteFailed; bool get isGiphy => - widget.message.attachments.any((element) => element.type == 'giphy') == - true; + widget.message.attachments.any((element) => element.type == 'giphy'); bool get isOnlyEmoji => widget.message.text?.isOnlyEmoji == true; @@ -596,7 +595,7 @@ class _MessageWidgetState extends State isDeleted; @override - bool get wantKeepAlive => widget.message.attachments.isNotEmpty == true; + bool get wantKeepAlive => widget.message.attachments.isNotEmpty; late StreamChatThemeData _streamChatTheme; late StreamChatState _streamChat; @@ -674,7 +673,10 @@ class _MessageWidgetState extends State child: PortalEntry( portal: Container( transform: Matrix4.translationValues( - widget.reverse ? 12 : -12, 0, 0), + widget.reverse ? 12 : -12, + 0, + 0, + ), constraints: const BoxConstraints( maxWidth: 22 * 6.0, ), @@ -704,13 +706,15 @@ class _MessageWidgetState extends State ? Container( // ignore: lines_longer_than_80_chars margin: EdgeInsets.symmetric( - horizontal: - // ignore: lines_longer_than_80_chars - widget.showUserAvatar == - // ignore: lines_longer_than_80_chars - DisplayWidget.gone - ? 0 - : 4.0), + horizontal: + // ignore: lines_longer_than_80_chars + widget.showUserAvatar == + // ignore: lines_longer_than_80_chars + DisplayWidget + .gone + ? 0 + : 4.0, + ), child: DeletedMessage( borderRadiusGeometry: widget .borderRadiusGeometry, @@ -794,7 +798,7 @@ class _MessageWidgetState extends State widget.message.user != null) ...[ _buildUserAvatar(), const SizedBox(width: 4), - ] + ], ], ), if (showBottomRow) @@ -856,7 +860,11 @@ class _MessageWidgetState extends State : chatThemeData.ownMessageTheme, reverse: widget.reverse, padding: EdgeInsets.only( - right: 8, left: 8, top: 8, bottom: hasNonUrlAttachments ? 8 : 0), + right: 8, + left: 8, + top: 8, + bottom: hasNonUrlAttachments ? 8 : 0, + ), ); } @@ -1054,64 +1062,64 @@ class _MessageWidgetState extends State final channel = StreamChannel.of(context).channel; showDialog( - useRootNavigator: false, - context: context, - barrierColor: _streamChatTheme.colorTheme.overlay, - builder: (context) => StreamChannel( - channel: channel, - child: MessageActionsModal( - messageWidget: widget.copyWith( - key: const Key('MessageWidget'), - message: widget.message.copyWith( - text: (widget.message.text?.length ?? 0) > 200 - ? '${widget.message.text!.substring(0, 200)}...' - : widget.message.text, - ), - showReactions: false, - showUsername: false, - showTimestamp: false, - translateUserAvatar: false, - showSendingIndicator: false, - padding: const EdgeInsets.all(0), - showReactionPickerIndicator: widget.showReactions && - (widget.message.status == MessageSendingStatus.sent), - showPinHighlight: false, - showUserAvatar: widget.message.user!.id == - channel.client.state.currentUser!.id - ? DisplayWidget.gone - : DisplayWidget.show, - ), - onCopyTap: (message) => - Clipboard.setData(ClipboardData(text: message.text)), - messageTheme: widget.messageTheme, - reverse: widget.reverse, - showDeleteMessage: widget.showDeleteMessage || isDeleteFailed, - message: widget.message, - editMessageInputBuilder: widget.editMessageInputBuilder, - onReplyTap: widget.onReplyTap, - onThreadReplyTap: widget.onThreadTap, - showResendMessage: widget.showResendMessage && - (isSendFailed || isUpdateFailed), - showCopyMessage: widget.showCopyMessage && - !isFailedState && - widget.message.text?.trim().isNotEmpty == true, - showEditMessage: widget.showEditMessage && - !isDeleteFailed && - widget.message.attachments - .any((element) => element.type == 'giphy') != - true, - showReactions: widget.showReactions, - showReplyMessage: widget.showReplyMessage && - !isFailedState && - widget.onReplyTap != null, - showThreadReplyMessage: widget.showThreadReplyMessage && - !isFailedState && - widget.onThreadTap != null, - showFlagButton: widget.showFlagButton, - showPinButton: widget.showPinButton, - customActions: widget.customActions, - ), - )); + useRootNavigator: false, + context: context, + barrierColor: _streamChatTheme.colorTheme.overlay, + builder: (context) => StreamChannel( + channel: channel, + child: MessageActionsModal( + messageWidget: widget.copyWith( + key: const Key('MessageWidget'), + message: widget.message.copyWith( + text: (widget.message.text?.length ?? 0) > 200 + ? '${widget.message.text!.substring(0, 200)}...' + : widget.message.text, + ), + showReactions: false, + showUsername: false, + showTimestamp: false, + translateUserAvatar: false, + showSendingIndicator: false, + padding: const EdgeInsets.all(0), + showReactionPickerIndicator: widget.showReactions && + (widget.message.status == MessageSendingStatus.sent), + showPinHighlight: false, + showUserAvatar: + widget.message.user!.id == channel.client.state.currentUser!.id + ? DisplayWidget.gone + : DisplayWidget.show, + ), + onCopyTap: (message) => + Clipboard.setData(ClipboardData(text: message.text)), + messageTheme: widget.messageTheme, + reverse: widget.reverse, + showDeleteMessage: widget.showDeleteMessage || isDeleteFailed, + message: widget.message, + editMessageInputBuilder: widget.editMessageInputBuilder, + onReplyTap: widget.onReplyTap, + onThreadReplyTap: widget.onThreadTap, + showResendMessage: + widget.showResendMessage && (isSendFailed || isUpdateFailed), + showCopyMessage: widget.showCopyMessage && + !isFailedState && + widget.message.text?.trim().isNotEmpty == true, + showEditMessage: widget.showEditMessage && + !isDeleteFailed && + !widget.message.attachments + .any((element) => element.type == 'giphy'), + showReactions: widget.showReactions, + showReplyMessage: widget.showReplyMessage && + !isFailedState && + widget.onReplyTap != null, + showThreadReplyMessage: widget.showThreadReplyMessage && + !isFailedState && + widget.onThreadTap != null, + showFlagButton: widget.showFlagButton, + showPinButton: widget.showPinButton, + customActions: widget.customActions, + ), + ), + ); } void _showMessageReactionsModalBottomSheet(BuildContext context) { @@ -1291,8 +1299,9 @@ class _MessageWidgetState extends State ? widget.messageTheme.copyWith( messageTextStyle: widget.messageTheme.messageTextStyle!.copyWith( - fontSize: 42, - )) + fontSize: 42, + ), + ) : widget.messageTheme, ), ), @@ -1326,7 +1335,7 @@ class _MessageWidgetState extends State fontSize: 13, fontWeight: FontWeight.w400, ), - ) + ), ], ), ); @@ -1432,8 +1441,12 @@ class _ThreadReplyPainter extends CustomPainter { final path = Path() ..moveTo(reverse ? size.width : 0, 0) - ..quadraticBezierTo(reverse ? size.width : 0, size.height * 0.38, - reverse ? size.width : 0, size.height * 0.50) + ..quadraticBezierTo( + reverse ? size.width : 0, + size.height * 0.38, + reverse ? size.width : 0, + size.height * 0.5, + ) ..quadraticBezierTo( reverse ? size.width : 0, size.height, diff --git a/packages/stream_chat_flutter/lib/src/overlays.dart b/packages/stream_chat_flutter/lib/src/multi_overlay.dart similarity index 100% rename from packages/stream_chat_flutter/lib/src/overlays.dart rename to packages/stream_chat_flutter/lib/src/multi_overlay.dart index 8d36be50..31b9d5e9 100644 --- a/packages/stream_chat_flutter/lib/src/overlays.dart +++ b/packages/stream_chat_flutter/lib/src/multi_overlay.dart @@ -2,23 +2,6 @@ import 'package:collection/collection.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_portal/flutter_portal.dart'; -/// Class that contains the parameters for building an overlay entry -class OverlayOptions { - /// Constructs a new overlay options object - /// [visible] - the visibility of the overlay - /// [widget] - the widget to be displayed - OverlayOptions({ - required this.visible, - required this.widget, - }); - - /// the visibility of the overlay - final bool visible; - - /// the widget to be displayed - final Widget widget; -} - /// Widget that renders a single overlay widget from a list of [overlayOptions] /// It shows the first one that is visible class MultiOverlay extends StatelessWidget { @@ -61,3 +44,20 @@ class MultiOverlay extends StatelessWidget { ); } } + +/// Class that contains the parameters for building an overlay entry +class OverlayOptions { + /// Constructs a new overlay options object + /// [visible] - the visibility of the overlay + /// [widget] - the widget to be displayed + OverlayOptions({ + required this.visible, + required this.widget, + }); + + /// the visibility of the overlay + final bool visible; + + /// the widget to be displayed + final Widget widget; +} diff --git a/packages/stream_chat_flutter/lib/src/quoted_message_widget.dart b/packages/stream_chat_flutter/lib/src/quoted_message_widget.dart index f1dc9711..14abc121 100644 --- a/packages/stream_chat_flutter/lib/src/quoted_message_widget.dart +++ b/packages/stream_chat_flutter/lib/src/quoted_message_widget.dart @@ -35,6 +35,7 @@ class _VideoAttachmentThumbnailState extends State<_VideoAttachmentThumbnail> { super.initState(); _controller = VideoPlayerController.network(widget.attachment.assetUrl!) ..initialize().then((_) { + // ignore: no-empty-block setState(() {}); //when your thumbnail will show. }); } @@ -95,10 +96,10 @@ class QuotedMessageWidget extends StatelessWidget { /// Callback for tap on widget final GestureTapCallback? onTap; - bool get _hasAttachments => message.attachments.isNotEmpty == true; + bool get _hasAttachments => message.attachments.isNotEmpty; bool get _containsLinkAttachment => - message.attachments.any((element) => element.titleLink != null) == true; + message.attachments.any((element) => element.titleLink != null); bool get _containsText => message.text?.isNotEmpty == true; @@ -140,12 +141,14 @@ class QuotedMessageWidget extends StatelessWidget { messageTheme: isOnlyEmoji && _containsText ? messageTheme.copyWith( messageTextStyle: messageTheme.messageTextStyle?.copyWith( - fontSize: 32, - )) + fontSize: 32, + ), + ) : messageTheme.copyWith( messageTextStyle: messageTheme.messageTextStyle?.copyWith( - fontSize: 12, - )), + fontSize: 12, + ), + ), ), ), ].insertBetween(const SizedBox(width: 8)); @@ -186,7 +189,7 @@ class QuotedMessageWidget extends StatelessWidget { image: DecorationImage( fit: BoxFit.cover, image: CachedNetworkImageProvider( - attachment.imageUrl!, + attachment.thumbUrl!, ), ), ), @@ -275,7 +278,8 @@ class QuotedMessageWidget extends StatelessWidget { height: 32, width: 32, child: getFileTypeImage( - attachment.extraData['mime_type'] as String?), + attachment.extraData['mime_type'] as String?, + ), ), }; diff --git a/packages/stream_chat_flutter/lib/src/reaction_bubble.dart b/packages/stream_chat_flutter/lib/src/reaction_bubble.dart index ecc2b27a..203b8481 100644 --- a/packages/stream_chat_flutter/lib/src/reaction_bubble.dart +++ b/packages/stream_chat_flutter/lib/src/reaction_bubble.dart @@ -142,7 +142,7 @@ class ReactionBubble extends StatelessWidget { size: 16, color: (!highlightOwnReactions || reaction.user?.id == userId) ? chatThemeData.colorTheme.accentPrimary - : chatThemeData.colorTheme.textHighEmphasis.withOpacity(.5), + : chatThemeData.colorTheme.textHighEmphasis.withOpacity(0.5), ), ); } diff --git a/packages/stream_chat_flutter/lib/src/reaction_picker.dart b/packages/stream_chat_flutter/lib/src/reaction_picker.dart index b5a685bd..2991a1bb 100644 --- a/packages/stream_chat_flutter/lib/src/reaction_picker.dart +++ b/packages/stream_chat_flutter/lib/src/reaction_picker.dart @@ -62,10 +62,11 @@ class _ReactionPickerState extends State mainAxisSize: MainAxisSize.min, children: reactionIcons .map((reactionIcon) { - final ownReactionIndex = widget.message.ownReactions - ?.indexWhere( - (reaction) => reaction.type == reactionIcon.type) ?? - -1; + final ownReactionIndex = + widget.message.ownReactions?.indexWhere( + (reaction) => reaction.type == reactionIcon.type, + ) ?? + -1; final index = reactionIcons.indexOf(reactionIcon); final child = reactionIcon.builder( diff --git a/packages/stream_chat_flutter/lib/src/stream_chat.dart b/packages/stream_chat_flutter/lib/src/stream_chat.dart index af617d34..ba8bcf64 100644 --- a/packages/stream_chat_flutter/lib/src/stream_chat.dart +++ b/packages/stream_chat_flutter/lib/src/stream_chat.dart @@ -75,7 +75,8 @@ class StreamChat extends StatefulWidget { if (streamChatState == null) { throw Exception( - 'You must have a StreamChat widget at the top of your widget tree'); + 'You must have a StreamChat widget at the top of your widget tree', + ); } return streamChatState; diff --git a/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart b/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart index 3fb13238..23d913cb 100644 --- a/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart +++ b/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart @@ -145,7 +145,7 @@ class StreamChatThemeData { ) { final accentColor = colorTheme.accentPrimary; final iconTheme = - IconThemeData(color: colorTheme.textHighEmphasis.withOpacity(.5)); + IconThemeData(color: colorTheme.textHighEmphasis.withOpacity(0.5)); final channelHeaderTheme = ChannelHeaderThemeData( avatarTheme: AvatarThemeData( borderRadius: BorderRadius.circular(20), @@ -174,7 +174,7 @@ class StreamChatThemeData { color: const Color(0xff7A7A7A), ), lastMessageAtStyle: textTheme.footnote.copyWith( - color: colorTheme.textHighEmphasis.withOpacity(.5), + color: colorTheme.textHighEmphasis.withOpacity(0.5), ), indicatorIconSize: 16, ); @@ -280,7 +280,7 @@ class StreamChatThemeData { return StreamSvgIcon.loveReaction( color: highlighted ? theme.colorTheme.accentPrimary - : theme.primaryIconTheme.color!.withOpacity(.5), + : theme.primaryIconTheme.color!.withOpacity(0.5), size: size, ); }, @@ -292,7 +292,7 @@ class StreamChatThemeData { return StreamSvgIcon.thumbsUpReaction( color: highlighted ? theme.colorTheme.accentPrimary - : theme.primaryIconTheme.color!.withOpacity(.5), + : theme.primaryIconTheme.color!.withOpacity(0.5), size: size, ); }, @@ -304,7 +304,7 @@ class StreamChatThemeData { return StreamSvgIcon.thumbsDownReaction( color: highlighted ? theme.colorTheme.accentPrimary - : theme.primaryIconTheme.color!.withOpacity(.5), + : theme.primaryIconTheme.color!.withOpacity(0.5), size: size, ); }, @@ -316,7 +316,7 @@ class StreamChatThemeData { return StreamSvgIcon.lolReaction( color: highlighted ? theme.colorTheme.accentPrimary - : theme.primaryIconTheme.color!.withOpacity(.5), + : theme.primaryIconTheme.color!.withOpacity(0.5), size: size, ); }, @@ -328,7 +328,7 @@ class StreamChatThemeData { return StreamSvgIcon.wutReaction( color: highlighted ? theme.colorTheme.accentPrimary - : theme.primaryIconTheme.color!.withOpacity(.5), + : theme.primaryIconTheme.color!.withOpacity(0.5), size: size, ); }, diff --git a/packages/stream_chat_flutter/lib/src/theme/avatar_theme.dart b/packages/stream_chat_flutter/lib/src/theme/avatar_theme.dart index 6c287638..738fa0de 100644 --- a/packages/stream_chat_flutter/lib/src/theme/avatar_theme.dart +++ b/packages/stream_chat_flutter/lib/src/theme/avatar_theme.dart @@ -2,6 +2,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; /// A style that overrides the default appearance of various avatar widgets. +// ignore: prefer-match-file-name class AvatarThemeData with Diagnosticable { /// Creates an [AvatarThemeData]. const AvatarThemeData({ diff --git a/packages/stream_chat_flutter/lib/src/theme/color_theme.dart b/packages/stream_chat_flutter/lib/src/theme/color_theme.dart index d021c6cf..b32c023f 100644 --- a/packages/stream_chat_flutter/lib/src/theme/color_theme.dart +++ b/packages/stream_chat_flutter/lib/src/theme/color_theme.dart @@ -25,13 +25,33 @@ class ColorTheme { stops: [0, 1], ), this.borderTop = const Effect( - sigmaX: 0, sigmaY: -1, color: Color(0xff000000), blur: 0, alpha: 0.08), + sigmaX: 0, + sigmaY: -1, + color: Color(0xff000000), + blur: 0, + alpha: 0.08, + ), this.borderBottom = const Effect( - sigmaX: 0, sigmaY: 1, color: Color(0xff000000), blur: 0, alpha: 0.08), + sigmaX: 0, + sigmaY: 1, + color: Color(0xff000000), + blur: 0, + alpha: 0.08, + ), this.shadowIconButton = const Effect( - sigmaX: 0, sigmaY: 2, color: Color(0xff000000), alpha: 0.5, blur: 4), + sigmaX: 0, + sigmaY: 2, + color: Color(0xff000000), + alpha: 0.5, + blur: 4, + ), this.modalShadow = const Effect( - sigmaX: 0, sigmaY: 0, color: Color(0xff000000), alpha: 1, blur: 8), + sigmaX: 0, + sigmaY: 0, + color: Color(0xff000000), + alpha: 1, + blur: 8, + ), }) : brightness = Brightness.light; /// Initialise with dark theme diff --git a/packages/stream_chat_flutter/lib/src/theme/gallery_footer_theme.dart b/packages/stream_chat_flutter/lib/src/theme/gallery_footer_theme.dart index bdf273e7..a227b830 100644 --- a/packages/stream_chat_flutter/lib/src/theme/gallery_footer_theme.dart +++ b/packages/stream_chat_flutter/lib/src/theme/gallery_footer_theme.dart @@ -151,11 +151,20 @@ class GalleryFooterThemeData with Diagnosticable { bottomSheetBarrierColor: Color.lerp(a.bottomSheetBarrierColor, b.bottomSheetBarrierColor, t), bottomSheetBackgroundColor: Color.lerp( - a.bottomSheetBackgroundColor, b.bottomSheetBackgroundColor, t), + a.bottomSheetBackgroundColor, + b.bottomSheetBackgroundColor, + t, + ), bottomSheetPhotosTextStyle: TextStyle.lerp( - a.bottomSheetPhotosTextStyle, b.bottomSheetPhotosTextStyle, t), + a.bottomSheetPhotosTextStyle, + b.bottomSheetPhotosTextStyle, + t, + ), bottomSheetCloseIconColor: Color.lerp( - a.bottomSheetCloseIconColor, b.bottomSheetCloseIconColor, t), + a.bottomSheetCloseIconColor, + b.bottomSheetCloseIconColor, + t, + ), ); /// Merges one [GalleryFooterThemeData] with another. @@ -208,10 +217,16 @@ class GalleryFooterThemeData with Diagnosticable { ..add(ColorProperty('gridIconButtonColor', gridIconButtonColor)) ..add(ColorProperty('bottomSheetBarrierColor', bottomSheetBarrierColor)) ..add(ColorProperty( - 'bottomSheetBackgroundColor', bottomSheetBackgroundColor)) + 'bottomSheetBackgroundColor', + bottomSheetBackgroundColor, + )) ..add(DiagnosticsProperty( - 'bottomSheetPhotosTextStyle', bottomSheetPhotosTextStyle)) + 'bottomSheetPhotosTextStyle', + bottomSheetPhotosTextStyle, + )) ..add(ColorProperty( - 'bottomSheetCloseIconColor', bottomSheetCloseIconColor)); + 'bottomSheetCloseIconColor', + bottomSheetCloseIconColor, + )); } } diff --git a/packages/stream_chat_flutter/lib/src/theme/message_theme.dart b/packages/stream_chat_flutter/lib/src/theme/message_theme.dart index 7bed2ceb..386a312f 100644 --- a/packages/stream_chat_flutter/lib/src/theme/message_theme.dart +++ b/packages/stream_chat_flutter/lib/src/theme/message_theme.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/src/theme/avatar_theme.dart'; /// Class for getting message theme +// ignore: prefer-match-file-name class MessageThemeData with Diagnosticable { /// Creates a [MessageThemeData]. const MessageThemeData({ @@ -105,7 +106,10 @@ class MessageThemeData with Diagnosticable { messageTextStyle: TextStyle.lerp(a.messageTextStyle, b.messageTextStyle, t), reactionsBackgroundColor: Color.lerp( - a.reactionsBackgroundColor, b.reactionsBackgroundColor, t), + a.reactionsBackgroundColor, + b.reactionsBackgroundColor, + t, + ), reactionsBorderColor: Color.lerp(a.messageBorderColor, b.reactionsBorderColor, t), reactionsMaskColor: diff --git a/packages/stream_chat_flutter/lib/src/typing_indicator.dart b/packages/stream_chat_flutter/lib/src/typing_indicator.dart index 5d425e58..d961a8ff 100644 --- a/packages/stream_chat_flutter/lib/src/typing_indicator.dart +++ b/packages/stream_chat_flutter/lib/src/typing_indicator.dart @@ -48,7 +48,7 @@ class TypingIndicator extends StatelessWidget { .map((e) => e.key)), builder: (context, data) => AnimatedSwitcher( duration: const Duration(milliseconds: 300), - child: data.isNotEmpty == true + child: data.isNotEmpty ? Padding( key: const Key('main'), padding: padding, diff --git a/packages/stream_chat_flutter/lib/src/user_avatar.dart b/packages/stream_chat_flutter/lib/src/user_avatar.dart index a923011c..86b34ea7 100644 --- a/packages/stream_chat_flutter/lib/src/user_avatar.dart +++ b/packages/stream_chat_flutter/lib/src/user_avatar.dart @@ -92,7 +92,9 @@ class UserAvatar extends StatelessWidget { streamChatTheme .ownMessageTheme.avatarTheme?.borderRadius, image: DecorationImage( - image: imageProvider, fit: BoxFit.cover), + image: imageProvider, + fit: BoxFit.cover, + ), ), ), ) diff --git a/packages/stream_chat_flutter/lib/src/user_item.dart b/packages/stream_chat_flutter/lib/src/user_item.dart index a2622385..cbaa0820 100644 --- a/packages/stream_chat_flutter/lib/src/user_item.dart +++ b/packages/stream_chat_flutter/lib/src/user_item.dart @@ -90,12 +90,13 @@ class UserItem extends StatelessWidget { Widget _buildLastActive(BuildContext context) { final chatTheme = StreamChatTheme.of(context); return Text( - user.online == true + user.online ? context.translations.userOnlineText : '${context.translations.userLastOnlineText} ' '${Jiffy(user.lastActive).fromNow()}', style: chatTheme.textTheme.footnote.copyWith( - color: chatTheme.colorTheme.textHighEmphasis.withOpacity(.5)), + color: chatTheme.colorTheme.textHighEmphasis.withOpacity(0.5), + ), ); } } diff --git a/packages/stream_chat_flutter/lib/src/user_list_view.dart b/packages/stream_chat_flutter/lib/src/user_list_view.dart index f7c9fa72..8697381a 100644 --- a/packages/stream_chat_flutter/lib/src/user_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/user_list_view.dart @@ -73,7 +73,7 @@ class UserListView extends StatefulWidget { this.listBuilder, this.userListController, }) : assert( - crossAxisCount == 1 || groupAlphabetically == false, + crossAxisCount == 1 || !groupAlphabetically, 'Cannot group alphabetically when crossAxisCount > 1', ), limit = limit ?? pagination?.limit ?? 30, @@ -407,33 +407,34 @@ class _UserListViewState extends State Widget _buildQueryProgressIndicator(context, UsersBlocState usersProvider) => StreamBuilder( - stream: usersProvider.queryUsersLoading, - initialData: false, - builder: (context, snapshot) { - if (snapshot.hasError) { - return Container( - color: StreamChatTheme.of(context) - .colorTheme - .accentError - .withOpacity(.2), - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 16), - child: Center( - child: Text(context.translations.loadingUsersError), - ), - ), - ); - } + stream: usersProvider.queryUsersLoading, + initialData: false, + builder: (context, snapshot) { + if (snapshot.hasError) { return Container( - height: 100, - padding: const EdgeInsets.all(32), - child: Center( - child: snapshot.data! - ? const CircularProgressIndicator() - : Container(), + color: StreamChatTheme.of(context) + .colorTheme + .accentError + .withOpacity(0.2), + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 16), + child: Center( + child: Text(context.translations.loadingUsersError), + ), ), ); - }); + } + return Container( + height: 100, + padding: const EdgeInsets.all(32), + child: Center( + child: snapshot.data! + ? const CircularProgressIndicator() + : Container(), + ), + ); + }, + ); Widget _separatorBuilder(context, i) => Container( height: 1, diff --git a/packages/stream_chat_flutter/lib/src/user_reaction_display.dart b/packages/stream_chat_flutter/lib/src/user_reaction_display.dart deleted file mode 100644 index b5ef623e..00000000 --- a/packages/stream_chat_flutter/lib/src/user_reaction_display.dart +++ /dev/null @@ -1,60 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:stream_chat_flutter/src/user_avatar.dart'; -import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; - -/// Displays a list of users who reacted -class UserReactionDisplay extends StatelessWidget { - /// Constructor for creating a [UserReactionDisplay] - const UserReactionDisplay({ - Key? key, - required this.reactionToEmoji, - required this.message, - this.size = 30, - }) : super(key: key); - - /// Reaction map - final Map reactionToEmoji; - - /// Message which is reacted to - final Message message; - - /// Size of Icon - final double size; - - @override - Widget build(BuildContext context) => Container( - color: Colors.black87, - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.center, - mainAxisSize: MainAxisSize.min, - children: reactionToEmoji.keys.map((reactionType) { - final firstUserReaction = message.latestReactions! - .firstWhere((element) => element.type == reactionType, - //ignore: unnecessary_parenthesis - orElse: (() => null) as Reaction Function()?); - - if (firstUserReaction.user == null) { - return IconButton( - iconSize: size, - icon: Container(), - onPressed: null, - ); - } - - return IconButton( - iconSize: size, - icon: UserAvatar( - user: firstUserReaction.user!, - constraints: BoxConstraints( - maxHeight: size - 5, - maxWidth: size - 5, - ), - onTap: (user) {}, - ), - onPressed: () {}, - ); - }).toList(), - ), - ); -} diff --git a/packages/stream_chat_flutter/lib/src/utils.dart b/packages/stream_chat_flutter/lib/src/utils.dart index 9b85e8c2..b4ca48f0 100644 --- a/packages/stream_chat_flutter/lib/src/utils.dart +++ b/packages/stream_chat_flutter/lib/src/utils.dart @@ -29,78 +29,82 @@ Future showConfirmationDialog( }) { final chatThemeData = StreamChatTheme.of(context); return showModalBottomSheet( - useRootNavigator: false, - backgroundColor: chatThemeData.colorTheme.barsBg, - context: context, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.only( + useRootNavigator: false, + backgroundColor: chatThemeData.colorTheme.barsBg, + context: context, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.only( topLeft: Radius.circular(16), topRight: Radius.circular(16), - )), - builder: (context) { - final effect = chatThemeData.colorTheme.borderTop; - return SafeArea( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - const SizedBox(height: 26), - if (icon != null) icon, - const SizedBox(height: 26), + ), + ), + builder: (context) { + final effect = chatThemeData.colorTheme.borderTop; + return SafeArea( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const SizedBox(height: 26), + if (icon != null) icon, + const SizedBox(height: 26), + Text( + title, + style: chatThemeData.textTheme.headlineBold, + ), + const SizedBox(height: 7), + if (question != null) Text( - title, - style: chatThemeData.textTheme.headlineBold, + question, + textAlign: TextAlign.center, ), - const SizedBox(height: 7), - if (question != null) - Text( - question, - textAlign: TextAlign.center, - ), - const SizedBox(height: 36), - Container( - color: effect.color!.withOpacity(effect.alpha ?? 1), - height: 1, - ), - Row( - children: [ - if (cancelText != null) - Flexible( - child: Container( - alignment: Alignment.center, - child: TextButton( - onPressed: () { - Navigator.of(context).pop(false); - }, - child: Text( - cancelText, - style: chatThemeData.textTheme.bodyBold.copyWith( - color: chatThemeData.colorTheme.textHighEmphasis - .withOpacity(0.5)), - ), - ), - ), - ), + const SizedBox(height: 36), + Container( + color: effect.color!.withOpacity(effect.alpha ?? 1), + height: 1, + ), + Row( + children: [ + if (cancelText != null) Flexible( child: Container( alignment: Alignment.center, child: TextButton( onPressed: () { - Navigator.pop(context, true); + Navigator.of(context).pop(false); }, child: Text( - okText, + cancelText, style: chatThemeData.textTheme.bodyBold.copyWith( - color: chatThemeData.colorTheme.accentError), + color: chatThemeData.colorTheme.textHighEmphasis + .withOpacity(0.5), + ), ), ), ), ), - ], - ), - ], - ), - ); - }); + Flexible( + child: Container( + alignment: Alignment.center, + child: TextButton( + onPressed: () { + Navigator.pop(context, true); + }, + child: Text( + okText, + style: chatThemeData.textTheme.bodyBold.copyWith( + color: chatThemeData.colorTheme.accentError, + ), + ), + ), + ), + ), + ], + ), + ], + ), + ); + }, + ); } /// Shows info dialog @@ -119,10 +123,11 @@ Future showInfoDialog( theme?.colorTheme.barsBg ?? chatThemeData.colorTheme.barsBg, context: context, shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.only( - topLeft: Radius.circular(16), - topRight: Radius.circular(16), - )), + borderRadius: BorderRadius.only( + topLeft: Radius.circular(16), + topRight: Radius.circular(16), + ), + ), builder: (context) => SafeArea( child: Column( mainAxisSize: MainAxisSize.min, @@ -147,8 +152,8 @@ Future showInfoDialog( height: 36, ), Container( - color: theme?.colorTheme.textHighEmphasis.withOpacity(.08) ?? - chatThemeData.colorTheme.textHighEmphasis.withOpacity(.08), + color: theme?.colorTheme.textHighEmphasis.withOpacity(0.08) ?? + chatThemeData.colorTheme.textHighEmphasis.withOpacity(0.08), height: 1, ), Center( diff --git a/packages/stream_chat_flutter/lib/src/video_service.dart b/packages/stream_chat_flutter/lib/src/video_service.dart index e914f466..a50a43c8 100644 --- a/packages/stream_chat_flutter/lib/src/video_service.dart +++ b/packages/stream_chat_flutter/lib/src/video_service.dart @@ -6,11 +6,12 @@ import 'package:video_compress/video_compress.dart'; import 'package:video_thumbnail/video_thumbnail.dart'; /// -class IVideoService { - IVideoService._(); +// ignore: prefer-match-file-name +class _IVideoService { + _IVideoService._(); - /// Singleton instance of [IVideoService] - static final IVideoService instance = IVideoService._(); + /// Singleton instance of [_IVideoService] + static final _IVideoService instance = _IVideoService._(); final _lock = Lock(); /// compress video from [path] @@ -64,6 +65,6 @@ class IVideoService { ); } -/// Get instance of [IVideoService] +/// Get instance of [_IVideoService] // ignore: non_constant_identifier_names -IVideoService get VideoService => IVideoService.instance; +_IVideoService get VideoService => _IVideoService.instance; diff --git a/packages/stream_chat_flutter/pubspec.yaml b/packages/stream_chat_flutter/pubspec.yaml index 6d067ed0..a36baba9 100644 --- a/packages/stream_chat_flutter/pubspec.yaml +++ b/packages/stream_chat_flutter/pubspec.yaml @@ -55,10 +55,9 @@ flutter: uses-material-design: true dev_dependencies: + dart_code_metrics: ^4.4.0 flutter_test: sdk: flutter golden_toolkit: ^0.10.0 mocktail: ^0.1.2 path: ^1.8.0 - pedantic: ^1.11.0 - diff --git a/packages/stream_chat_flutter/test/src/theme/channel_preview_theme_test.dart b/packages/stream_chat_flutter/test/src/theme/channel_preview_theme_test.dart index 3be39952..dc5c0529 100644 --- a/packages/stream_chat_flutter/test/src/theme/channel_preview_theme_test.dart +++ b/packages/stream_chat_flutter/test/src/theme/channel_preview_theme_test.dart @@ -59,7 +59,7 @@ final _channelPreviewThemeControl = ChannelPreviewThemeData( color: const Color(0xff7A7A7A), ), lastMessageAtStyle: TextTheme.light().footnote.copyWith( - color: ColorTheme.light().textHighEmphasis.withOpacity(.5), + color: ColorTheme.light().textHighEmphasis.withOpacity(0.5), ), indicatorIconSize: 16, ); @@ -83,7 +83,7 @@ final _channelPreviewThemeControlMidLerp = ChannelPreviewThemeData( fontSize: 12, ), lastMessageAtStyle: TextTheme.light().footnote.copyWith( - color: const Color(0x807f7f7f).withOpacity(.5), + color: const Color(0x807f7f7f).withOpacity(0.5), ), indicatorIconSize: 16, ); @@ -102,7 +102,7 @@ final _channelPreviewThemeControlDark = ChannelPreviewThemeData( color: const Color(0xff7A7A7A), ), lastMessageAtStyle: TextTheme.dark().footnote.copyWith( - color: ColorTheme.dark().textHighEmphasis.withOpacity(.5), + color: ColorTheme.dark().textHighEmphasis.withOpacity(0.5), ), indicatorIconSize: 16, ); diff --git a/packages/stream_chat_flutter_core/example/pubspec.yaml b/packages/stream_chat_flutter_core/example/pubspec.yaml index 6390abc4..4b0e27fb 100644 --- a/packages/stream_chat_flutter_core/example/pubspec.yaml +++ b/packages/stream_chat_flutter_core/example/pubspec.yaml @@ -1,4 +1,4 @@ -name: example +name: stream_chat_flutter_core_example description: Example app for testing stream_chat_flutter_core # The following line prevents the package from being accidentally published to @@ -26,9 +26,7 @@ dependencies: cupertino_icons: ^1.0.3 flutter: sdk: flutter - stream_chat_flutter_core: - path: ../ - + stream_chat_flutter_core: ^2.2.1 dev_dependencies: flutter_test: diff --git a/packages/stream_chat_flutter_core/lib/src/better_stream_builder.dart b/packages/stream_chat_flutter_core/lib/src/better_stream_builder.dart index 3c456246..2a2a5ab7 100644 --- a/packages/stream_chat_flutter_core/lib/src/better_stream_builder.dart +++ b/packages/stream_chat_flutter_core/lib/src/better_stream_builder.dart @@ -94,6 +94,7 @@ class _BetterStreamBuilderState if (widget.errorBuilder != null && error != _lastError) { _lastError = error; if (mounted) { + // ignore: no-empty-block setState(() {}); } } @@ -106,7 +107,7 @@ class _BetterStreamBuilderState if (!isEqual) { _lastEvent = event; if (mounted) { - setState(() {}); + setState(() {}); // ignore: no-empty-block } } } diff --git a/packages/stream_chat_flutter_core/lib/src/channels_bloc.dart b/packages/stream_chat_flutter_core/lib/src/channels_bloc.dart index 1aed7198..0e8d48bc 100644 --- a/packages/stream_chat_flutter_core/lib/src/channels_bloc.dart +++ b/packages/stream_chat_flutter_core/lib/src/channels_bloc.dart @@ -111,8 +111,7 @@ class ChannelsBlocState extends State _paginationEnded = false; } - if ((!clear && _paginationEnded) || - _queryChannelsLoadingController.value == true) { + if ((!clear && _paginationEnded) || _queryChannelsLoadingController.value) { return; } @@ -221,7 +220,8 @@ class ChannelsBlocState extends State .listen((e) { final channel = e.channel; _channelsController.add(List.from( - (channels ?? [])..removeWhere((c) => c.cid == channel?.cid))); + (channels ?? [])..removeWhere((c) => c.cid == channel?.cid), + )); })); } diff --git a/packages/stream_chat_flutter_core/lib/src/message_search_bloc.dart b/packages/stream_chat_flutter_core/lib/src/message_search_bloc.dart index 6477dfcd..e247a1cf 100644 --- a/packages/stream_chat_flutter_core/lib/src/message_search_bloc.dart +++ b/packages/stream_chat_flutter_core/lib/src/message_search_bloc.dart @@ -90,8 +90,7 @@ class MessageSearchBlocState extends State _paginationEnded = false; } - if ((!clear && _paginationEnded) || - _queryMessagesLoadingController.value == true) { + if ((!clear && _paginationEnded) || _queryMessagesLoadingController.value) { return; } diff --git a/packages/stream_chat_flutter_core/lib/src/stream_channel.dart b/packages/stream_chat_flutter_core/lib/src/stream_channel.dart index 443529ac..8117a26e 100644 --- a/packages/stream_chat_flutter_core/lib/src/stream_channel.dart +++ b/packages/stream_chat_flutter_core/lib/src/stream_channel.dart @@ -88,7 +88,7 @@ class StreamChannelState extends State { bool preferOffline = false, }) async { if (_topPaginationEnded || - _queryTopMessagesController.value == true || + _queryTopMessagesController.value || channel.state == null) { return; } @@ -120,9 +120,9 @@ class StreamChannelState extends State { bool preferOffline = false, }) async { if (_bottomPaginationEnded || - _queryBottomMessagesController.value == true || + _queryBottomMessagesController.value || channel.state == null || - channel.state!.isUpToDate == true) return; + channel.state!.isUpToDate) return; _queryBottomMessagesController.add(true); if (channel.state!.messages.isEmpty) { @@ -164,7 +164,7 @@ class StreamChannelState extends State { bool preferOffline = false, }) async { if (_topPaginationEnded || - _queryTopMessagesController.value == true || + _queryTopMessagesController.value || channel.state == null) return; _queryTopMessagesController.add(true); diff --git a/packages/stream_chat_flutter_core/lib/src/users_bloc.dart b/packages/stream_chat_flutter_core/lib/src/users_bloc.dart index d112961d..fc791cd8 100644 --- a/packages/stream_chat_flutter_core/lib/src/users_bloc.dart +++ b/packages/stream_chat_flutter_core/lib/src/users_bloc.dart @@ -77,8 +77,7 @@ class UsersBlocState extends State _paginationEnded = false; } - if ((!clear && _paginationEnded) || - _queryUsersLoadingController.value == true) { + if ((!clear && _paginationEnded) || _queryUsersLoadingController.value) { return; } diff --git a/packages/stream_chat_flutter_core/pubspec.yaml b/packages/stream_chat_flutter_core/pubspec.yaml index 128c58fb..1bc8a1f9 100644 --- a/packages/stream_chat_flutter_core/pubspec.yaml +++ b/packages/stream_chat_flutter_core/pubspec.yaml @@ -19,6 +19,7 @@ dependencies: stream_chat: ^3.1.1 dev_dependencies: + dart_code_metrics: ^4.4.0 fake_async: ^1.2.0 flutter_test: sdk: flutter diff --git a/packages/stream_chat_localizations/example/pubspec.yaml b/packages/stream_chat_localizations/example/pubspec.yaml index a139831e..9aaa23c6 100644 --- a/packages/stream_chat_localizations/example/pubspec.yaml +++ b/packages/stream_chat_localizations/example/pubspec.yaml @@ -1,4 +1,4 @@ -name: example +name: stream_chat_localizations_example description: A new Flutter project. publish_to: 'none' @@ -11,12 +11,8 @@ dependencies: cupertino_icons: ^1.0.3 flutter: sdk: flutter - stream_chat_localizations: - path: ../ - -dependency_overrides: - stream_chat_flutter: - path: ../../stream_chat_flutter + stream_chat_flutter: ^2.2.1 + stream_chat_localizations: ^1.1.0 dev_dependencies: flutter_test: diff --git a/packages/stream_chat_localizations/lib/src/stream_chat_localizations.dart b/packages/stream_chat_localizations/lib/src/stream_chat_localizations.dart index 4094dcaa..b9ac541e 100644 --- a/packages/stream_chat_localizations/lib/src/stream_chat_localizations.dart +++ b/packages/stream_chat_localizations/lib/src/stream_chat_localizations.dart @@ -32,7 +32,7 @@ const kStreamChatSupportedLanguages = { 'it', 'es', 'ja', - 'ko' + 'ko', }; /// Creates a [GlobalStreamChatLocalizations] instance for the given `locale`. diff --git a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_en.dart b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_en.dart index 5cb59755..c1106cab 100644 --- a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_en.dart +++ b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_en.dart @@ -350,8 +350,10 @@ class StreamChatLocalizationsEn extends GlobalStreamChatLocalizations { String get youText => 'You'; @override - String galleryPaginationText( - {required int currentPage, required int totalPages}) => + String galleryPaginationText({ + required int currentPage, + required int totalPages, + }) => '${currentPage + 1} of $totalPages'; @override diff --git a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_es.dart b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_es.dart index 69ee9237..49e66184 100644 --- a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_es.dart +++ b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_es.dart @@ -355,8 +355,10 @@ class StreamChatLocalizationsEs extends GlobalStreamChatLocalizations { String get youText => 'Usted'; @override - String galleryPaginationText( - {required int currentPage, required int totalPages}) => + String galleryPaginationText({ + required int currentPage, + required int totalPages, + }) => '${currentPage + 1} de $totalPages'; @override diff --git a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_fr.dart b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_fr.dart index 0727075a..0057b7cc 100644 --- a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_fr.dart +++ b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_fr.dart @@ -354,8 +354,10 @@ class StreamChatLocalizationsFr extends GlobalStreamChatLocalizations { String get youText => 'Vous'; @override - String galleryPaginationText( - {required int currentPage, required int totalPages}) => + String galleryPaginationText({ + required int currentPage, + required int totalPages, + }) => '${currentPage + 1} de $totalPages'; @override diff --git a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_hi.dart b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_hi.dart index ea1738de..0d7e1ec0 100644 --- a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_hi.dart +++ b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_hi.dart @@ -349,8 +349,10 @@ class StreamChatLocalizationsHi extends GlobalStreamChatLocalizations { String get youText => 'आप'; @override - String galleryPaginationText( - {required int currentPage, required int totalPages}) => + String galleryPaginationText({ + required int currentPage, + required int totalPages, + }) => '${currentPage + 1} ऑफ़ $totalPages'; @override diff --git a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_it.dart b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_it.dart index e60d4afe..18e961d6 100644 --- a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_it.dart +++ b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_it.dart @@ -351,8 +351,10 @@ Il file è troppo grande per essere caricato. Il limite è di $limitInMB MB.'''; String get youText => 'te'; @override - String galleryPaginationText( - {required int currentPage, required int totalPages}) => + String galleryPaginationText({ + required int currentPage, + required int totalPages, + }) => '${currentPage + 1} di $totalPages'; @override diff --git a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ko.dart b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ko.dart index a52a914f..3693bc11 100644 --- a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ko.dart +++ b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ko.dart @@ -334,9 +334,12 @@ class StreamChatLocalizationsKo extends GlobalStreamChatLocalizations { String get youText => '당신'; @override - String galleryPaginationText( - {required int currentPage, required int totalPages}) => + String galleryPaginationText({ + required int currentPage, + required int totalPages, + }) => '${currentPage + 1} / $totalPages'; + //3 / 11 @override diff --git a/packages/stream_chat_localizations/pubspec.yaml b/packages/stream_chat_localizations/pubspec.yaml index 552ee5ec..aaa4c56b 100644 --- a/packages/stream_chat_localizations/pubspec.yaml +++ b/packages/stream_chat_localizations/pubspec.yaml @@ -17,5 +17,6 @@ dependencies: stream_chat_flutter: ^3.0.0 dev_dependencies: + dart_code_metrics: ^4.4.0 flutter_test: sdk: flutter diff --git a/packages/stream_chat_persistence/example/pubspec.yaml b/packages/stream_chat_persistence/example/pubspec.yaml index 8dd6a719..6c6e8c6d 100644 --- a/packages/stream_chat_persistence/example/pubspec.yaml +++ b/packages/stream_chat_persistence/example/pubspec.yaml @@ -1,4 +1,4 @@ -name: example +name: stream_chat_persistence_example description: A new Flutter project. publish_to: 'none' @@ -11,12 +11,8 @@ dependencies: cupertino_icons: ^1.0.3 flutter: sdk: flutter - stream_chat_persistence: - path: ../ - -dependency_overrides: - stream_chat: - path: ../../stream_chat + stream_chat: ^2.2.1 + stream_chat_persistence: ^2.2.0 dev_dependencies: flutter_test: diff --git a/packages/stream_chat_persistence/lib/src/dao/message_dao.dart b/packages/stream_chat_persistence/lib/src/dao/message_dao.dart index ef140239..ddaafdc5 100644 --- a/packages/stream_chat_persistence/lib/src/dao/message_dao.dart +++ b/packages/stream_chat_persistence/lib/src/dao/message_dao.dart @@ -62,8 +62,10 @@ class MessageDao extends DatabaseAccessor Future getMessageById(String id) async => await (select(messages).join([ leftOuterJoin(_users, messages.userId.equalsExp(_users.id)), - leftOuterJoin(_pinnedByUsers, - messages.pinnedByUserId.equalsExp(_pinnedByUsers.id)), + leftOuterJoin( + _pinnedByUsers, + messages.pinnedByUserId.equalsExp(_pinnedByUsers.id), + ), ]) ..where(messages.id.equals(id))) .map(_messageFromJoinRow) @@ -74,8 +76,10 @@ class MessageDao extends DatabaseAccessor Future> getThreadMessages(String cid) async => Future.wait(await (select(messages).join([ leftOuterJoin(_users, messages.userId.equalsExp(_users.id)), - leftOuterJoin(_pinnedByUsers, - messages.pinnedByUserId.equalsExp(_pinnedByUsers.id)), + leftOuterJoin( + _pinnedByUsers, + messages.pinnedByUserId.equalsExp(_pinnedByUsers.id), + ), ]) ..where(messages.channelCid.equals(cid)) ..where(messages.parentId.isNotNull()) @@ -92,7 +96,9 @@ class MessageDao extends DatabaseAccessor final msgList = await Future.wait(await (select(messages).join([ leftOuterJoin(_users, messages.userId.equalsExp(_users.id)), leftOuterJoin( - _pinnedByUsers, messages.pinnedByUserId.equalsExp(_pinnedByUsers.id)), + _pinnedByUsers, + messages.pinnedByUserId.equalsExp(_pinnedByUsers.id), + ), ]) ..where(messages.parentId.isNotNull()) ..where(messages.parentId.equals(parentId)) @@ -134,7 +140,9 @@ class MessageDao extends DatabaseAccessor final msgList = await Future.wait(await (select(messages).join([ leftOuterJoin(_users, messages.userId.equalsExp(_users.id)), leftOuterJoin( - _pinnedByUsers, messages.pinnedByUserId.equalsExp(_pinnedByUsers.id)), + _pinnedByUsers, + messages.pinnedByUserId.equalsExp(_pinnedByUsers.id), + ), ]) ..where(messages.channelCid.equals(cid)) ..where( diff --git a/packages/stream_chat_persistence/lib/src/dao/pinned_message_dao.dart b/packages/stream_chat_persistence/lib/src/dao/pinned_message_dao.dart index 9bc0fa64..bac52aa6 100644 --- a/packages/stream_chat_persistence/lib/src/dao/pinned_message_dao.dart +++ b/packages/stream_chat_persistence/lib/src/dao/pinned_message_dao.dart @@ -64,8 +64,10 @@ class PinnedMessageDao extends DatabaseAccessor Future getMessageById(String id) async => await (select(pinnedMessages).join([ leftOuterJoin(_users, pinnedMessages.userId.equalsExp(_users.id)), - leftOuterJoin(_pinnedByUsers, - pinnedMessages.pinnedByUserId.equalsExp(_pinnedByUsers.id)), + leftOuterJoin( + _pinnedByUsers, + pinnedMessages.pinnedByUserId.equalsExp(_pinnedByUsers.id), + ), ]) ..where(pinnedMessages.id.equals(id))) .map(_messageFromJoinRow) @@ -76,8 +78,10 @@ class PinnedMessageDao extends DatabaseAccessor Future> getThreadMessages(String cid) async => Future.wait(await (select(pinnedMessages).join([ leftOuterJoin(_users, pinnedMessages.userId.equalsExp(_users.id)), - leftOuterJoin(_pinnedByUsers, - pinnedMessages.pinnedByUserId.equalsExp(_pinnedByUsers.id)), + leftOuterJoin( + _pinnedByUsers, + pinnedMessages.pinnedByUserId.equalsExp(_pinnedByUsers.id), + ), ]) ..where(pinnedMessages.channelCid.equals(cid)) ..where(pinnedMessages.parentId.isNotNull()) @@ -93,8 +97,10 @@ class PinnedMessageDao extends DatabaseAccessor }) async { final msgList = await Future.wait(await (select(pinnedMessages).join([ leftOuterJoin(_users, pinnedMessages.userId.equalsExp(_users.id)), - leftOuterJoin(_pinnedByUsers, - pinnedMessages.pinnedByUserId.equalsExp(_pinnedByUsers.id)), + leftOuterJoin( + _pinnedByUsers, + pinnedMessages.pinnedByUserId.equalsExp(_pinnedByUsers.id), + ), ]) ..where(pinnedMessages.parentId.isNotNull()) ..where(pinnedMessages.parentId.equals(parentId)) @@ -134,8 +140,10 @@ class PinnedMessageDao extends DatabaseAccessor }) async { final msgList = await Future.wait(await (select(pinnedMessages).join([ leftOuterJoin(_users, pinnedMessages.userId.equalsExp(_users.id)), - leftOuterJoin(_pinnedByUsers, - pinnedMessages.pinnedByUserId.equalsExp(_pinnedByUsers.id)), + leftOuterJoin( + _pinnedByUsers, + pinnedMessages.pinnedByUserId.equalsExp(_pinnedByUsers.id), + ), ]) ..where(pinnedMessages.channelCid.equals(cid)) ..where(pinnedMessages.parentId.isNull() | diff --git a/packages/stream_chat_persistence/lib/src/db/moor_chat_database.dart b/packages/stream_chat_persistence/lib/src/db/moor_chat_database.dart index 85f7b2de..35befbc1 100644 --- a/packages/stream_chat_persistence/lib/src/db/moor_chat_database.dart +++ b/packages/stream_chat_persistence/lib/src/db/moor_chat_database.dart @@ -10,29 +10,32 @@ export 'shared/shared_db.dart'; part 'moor_chat_database.g.dart'; /// A chat database implemented using moor -@UseMoor(tables: [ - Channels, - Messages, - PinnedMessages, - PinnedMessageReactions, - Reactions, - Users, - Members, - Reads, - ChannelQueries, - ConnectionEvents, -], daos: [ - UserDao, - ChannelDao, - MessageDao, - PinnedMessageDao, - PinnedMessageReactionDao, - MemberDao, - ReactionDao, - ReadDao, - ChannelQueryDao, - ConnectionEventDao, -]) +@UseMoor( + tables: [ + Channels, + Messages, + PinnedMessages, + PinnedMessageReactions, + Reactions, + Users, + Members, + Reads, + ChannelQueries, + ConnectionEvents, + ], + daos: [ + UserDao, + ChannelDao, + MessageDao, + PinnedMessageDao, + PinnedMessageReactionDao, + MemberDao, + ReactionDao, + ReadDao, + ChannelQueryDao, + ConnectionEventDao, + ], +) class MoorChatDatabase extends _$MoorChatDatabase { /// Creates a new moor chat database instance MoorChatDatabase( diff --git a/packages/stream_chat_persistence/lib/src/stream_chat_persistence_client.dart b/packages/stream_chat_persistence/lib/src/stream_chat_persistence_client.dart index d7db7924..9d81fecd 100644 --- a/packages/stream_chat_persistence/lib/src/stream_chat_persistence_client.dart +++ b/packages/stream_chat_persistence/lib/src/stream_chat_persistence_client.dart @@ -229,7 +229,7 @@ class StreamChatPersistenceClient extends ChatPersistenceClient { final parentId = message.parentId!; messageByParentIdDictionary[parentId] = [ ...messageByParentIdDictionary[parentId] ?? [], - message + message, ]; } return messageByParentIdDictionary; diff --git a/packages/stream_chat_persistence/pubspec.yaml b/packages/stream_chat_persistence/pubspec.yaml index f6409fa2..3e24da27 100644 --- a/packages/stream_chat_persistence/pubspec.yaml +++ b/packages/stream_chat_persistence/pubspec.yaml @@ -7,6 +7,7 @@ issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues environment: sdk: ">=2.12.0 <3.0.0" + flutter: ">=1.17.0" dependencies: flutter: @@ -22,8 +23,8 @@ dependencies: dev_dependencies: build_runner: ^2.0.1 + dart_code_metrics: ^4.4.0 flutter_test: sdk: flutter mocktail: ^0.1.1 - moor_generator: ^4.2.1 - pedantic: ^1.11.0 + moor_generator: ^4.2.1 \ No newline at end of file diff --git a/packages/stream_chat_persistence/test/src/dao/channel_query_dao_test.dart b/packages/stream_chat_persistence/test/src/dao/channel_query_dao_test.dart index 2ea1e73a..bc07919a 100644 --- a/packages/stream_chat_persistence/test/src/dao/channel_query_dao_test.dart +++ b/packages/stream_chat_persistence/test/src/dao/channel_query_dao_test.dart @@ -82,9 +82,9 @@ void main() { cid: cids[index], createdBy: users[index], config: ChannelConfig(), - extraData: {'test_custom_field': 3 + index}, + extraData: {'test_custom_field': index + 3}, createdAt: now, - memberCount: 3 + index, + memberCount: index + 3, lastMessageAt: now.add(Duration(hours: index)), ), ).reversed.toList(growable: false);