Skip to content

Commit

Permalink
refactor!: initial attachments refactor.
Browse files Browse the repository at this point in the history
Signed-off-by: xsahil03x <[email protected]>
  • Loading branch information
xsahil03x committed Jul 13, 2023
1 parent b8eeb2d commit 4699e65
Show file tree
Hide file tree
Showing 61 changed files with 3,613 additions and 1,696 deletions.
45 changes: 41 additions & 4 deletions packages/stream_chat/lib/src/core/models/attachment.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,24 @@ import 'package:uuid/uuid.dart';

part 'attachment.g.dart';

mixin AttachmentType {
/// Backend specified types.
static const image = 'image';
static const file = 'file';
static const giphy = 'giphy';
static const video = 'video';

/// Application custom types.
static const urlPreview = 'url_preview';
}

/// The class that contains the information about an attachment
@JsonSerializable(includeIfNull: false)
class Attachment extends Equatable {
/// Constructor used for json serialization
Attachment({
String? id,
this.type,
String? type,
this.titleLink,
String? title,
this.thumbUrl,
Expand All @@ -33,14 +44,16 @@ class Attachment extends Equatable {
this.authorLink,
this.authorIcon,
this.assetUrl,
List<Action>? actions,
this.actions = const [],
this.originalWidth,
this.originalHeight,
Map<String, Object?> extraData = const {},
this.file,
UploadState? uploadState,
}) : id = id ?? const Uuid().v4(),
_type = type,
title = title ?? file?.name,
localUri = file?.path != null ? Uri.parse(file!.path!) : null,
actions = actions ?? [],
// For backwards compatibility,
// set 'file_size', 'mime_type' in [extraData].
extraData = {
Expand Down Expand Up @@ -84,7 +97,15 @@ class Attachment extends Equatable {

///The attachment type based on the URL resource. This can be: audio,
///image or video
final String? type;
String? get type {
if (_type == AttachmentType.image && titleLink != null) {
return AttachmentType.urlPreview;
}

return _type;
}

final String? _type;

///The link to which the attachment message points to.
final String? titleLink;
Expand Down Expand Up @@ -126,6 +147,12 @@ class Attachment extends Equatable {
/// Actions from a command
final List<Action>? actions;

/// The original width of the attached image.
final int? originalWidth;

/// The original height of the attached image.
final int? originalHeight;

final Uri? localUri;

/// The file present inside this attachment.
Expand Down Expand Up @@ -175,6 +202,8 @@ class Attachment extends Equatable {
'author_icon',
'asset_url',
'actions',
'original_width',
'original_height',
];

/// Known db specific top level fields.
Expand Down Expand Up @@ -214,6 +243,8 @@ class Attachment extends Equatable {
String? authorIcon,
String? assetUrl,
List<Action>? actions,
int? originalWidth,
int? originalHeight,
AttachmentFile? file,
UploadState? uploadState,
Map<String, Object?>? extraData,
Expand All @@ -238,6 +269,8 @@ class Attachment extends Equatable {
authorIcon: authorIcon ?? this.authorIcon,
assetUrl: assetUrl ?? this.assetUrl,
actions: actions ?? this.actions,
originalWidth: originalWidth ?? this.originalWidth,
originalHeight: originalHeight ?? this.originalHeight,
file: file ?? this.file,
uploadState: uploadState ?? this.uploadState,
extraData: extraData ?? this.extraData,
Expand All @@ -264,6 +297,8 @@ class Attachment extends Equatable {
authorIcon: other.authorIcon,
assetUrl: other.assetUrl,
actions: other.actions,
originalWidth: other.originalWidth,
originalHeight: other.originalHeight,
file: other.file,
uploadState: other.uploadState,
extraData: other.extraData,
Expand Down Expand Up @@ -291,6 +326,8 @@ class Attachment extends Equatable {
authorIcon,
assetUrl,
actions,
originalWidth,
originalHeight,
file,
uploadState,
extraData,
Expand Down
4 changes: 4 additions & 0 deletions packages/stream_chat/lib/src/core/models/attachment.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import 'package:stream_chat/src/core/models/attachment.dart';

/// {@template giphy_info_type}
/// The different types of quality for a Giphy attachment.
/// {@endtemplate}
enum GiphyInfoType {
/// Original quality giphy, the largest size to load.
original('original'),

/// Lower quality with a fixed height, adjusts width according to the
/// Giphy aspect ratio. Lower size than [original].
fixedHeight('fixed_height'),

/// Still image of the [fixedHeight] giphy.
fixedHeightStill('fixed_height_still'),

/// Lower quality with a fixed height with width adjusted according to the
/// aspect ratio and played at a lower frame rate. Significantly lower size,
/// but visually less appealing.
fixedHeightDownsampled('fixed_height_downsampled');

/// {@macro giphy_info_type}
const GiphyInfoType(this.value);

/// The value of the [GiphyInfoType].
final String value;
}

/// {@template giphy_info}
/// A class that contains extra information about a Giphy attachment.
/// {@endtemplate}
class GiphyInfo {
/// {@macro giphy_info}
const GiphyInfo({
required this.url,
required this.width,
required this.height,
});

/// The url for the Giphy image.
final String url;

/// The width of the Giphy image.
final double width;

/// The height of the Giphy image.
final double height;

@override
String toString() => 'GiphyInfo{url: $url, width: $width, height: $height}';
}

/// GiphyInfo extension on [Attachment] class.
extension GiphyInfoX on Attachment {
/// Returns the [GiphyInfo] for the given [type].
GiphyInfo? giphyInfo(GiphyInfoType type) {
final giphy = extraData['giphy'] as Map<String, Object?>?;
if (giphy == null) return null;

final info = giphy[type.value] as Map<String, Object?>?;
if (info == null) return null;

return GiphyInfo(
url: info['url']! as String,
width: double.parse(info['width']! as String),
height: double.parse(info['height']! as String),
);
}
}
3 changes: 3 additions & 0 deletions packages/stream_chat/lib/src/core/models/message.dart
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,9 @@ class Message extends Equatable {
/// Message custom extraData.
final Map<String, Object?> extraData;

/// True if the message is a error.
bool get isError => type == 'error';

/// True if the message is a system info.
bool get isSystem => type == 'system';

Expand Down
1 change: 1 addition & 0 deletions packages/stream_chat/lib/stream_chat.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export 'src/core/http/interceptor/logging_interceptor.dart';
export 'src/core/models/action.dart';
export 'src/core/models/attachment.dart';
export 'src/core/models/attachment_file.dart';
export 'src/core/models/attachment_giphy_info.dart';
export 'src/core/models/channel_config.dart';
export 'src/core/models/channel_model.dart';
export 'src/core/models/channel_mute.dart';
Expand Down
2 changes: 1 addition & 1 deletion packages/stream_chat/test/src/client/client_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -805,7 +805,7 @@ void main() {
emits(ConnectionStatus.disconnected),
);

await client.disconnectUser();
await client.disconnectUser(flushChatPersistence: true);

expect(client.state.currentUser, isNull);
expect(client.wsConnectionStatus, ConnectionStatus.disconnected);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
export 'attachment_error.dart';
export 'attachment_upload_state_builder.dart';
export 'attachment_widget.dart' show AttachmentSource;
export 'file_attachment.dart';
export 'giphy_attachment.dart';
export 'image_attachment.dart';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ class _FailedState extends StatelessWidget {
children: [
_IconButton(
icon: StreamSvgIcon.retry(
size: 14,
color: theme.colorTheme.barsBg,
),
onPressed: () {
Expand All @@ -217,6 +218,7 @@ class _FailedState extends StatelessWidget {
),
child: Text(
context.translations.uploadErrorLabel,
textAlign: TextAlign.center,
style: theme.textTheme.footnote.copyWith(
color: theme.colorTheme.barsBg,
),
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import 'package:collection/collection.dart';
import 'package:flutter/widgets.dart';
import 'package:stream_chat_flutter/src/attachment/builder/attachment_widget_builder.dart';
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';

/// {@template attachmentWidgetCatalog}
/// A widget catalog which determines which attachment widget should be build
/// for a given [Message] and [Attachment] based on the list of [builders].
///
/// This is used by the [MessageWidget] to build the widget for the
/// [Message.attachments]. If you want to customize the widget used to show
/// attachments, you can use this to add your own attachment builder.
/// {@endtemplate}
///
/// See also:
///
/// * [StreamAttachmentWidgetBuilder], which is used to build a widget for a
/// given [Message] and [Attachment].
/// * [MessageWidget] which uses the [AttachmentWidgetCatalog] to build the
/// widget for the [Message.attachments].
class AttachmentWidgetCatalog {
/// {@macro attachmentWidgetCatalog}
const AttachmentWidgetCatalog({required this.builders});

/// The list of builders to use to build the widget.
///
/// The order of the builders is important. The first builder that can handle
/// the message and attachments will be used to build the widget.
final List<StreamAttachmentWidgetBuilder> builders;

/// Builds a widget for the given [message] and [attachments].
///
/// It iterates through the list of builders and uses the first builder
/// that can handle the message and attachments.
///
/// Throws an [Exception] if no builder is found for the message.
Widget build(BuildContext context, Message message) {
assert(!message.isDeleted, 'Cannot build attachment for deleted message');

assert(
message.attachments.isNotEmpty,
'Cannot build attachment for message without attachments',
);

// The list of attachments to build the widget for.
final attachments = message.attachments.grouped;
for (final builder in builders) {
if (builder.canHandle(message, attachments)) {
return builder.build(context, message, attachments);
}
}

throw Exception('No builder found for $message and $attachments');
}
}

extension on List<Attachment> {
/// Groups the attachments by their type.
Map<String, List<Attachment>> get grouped {
return groupBy(this, (attachment) => attachment.type!);
}
}
Loading

0 comments on commit 4699e65

Please sign in to comment.