Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions example/lib/chat_view_list_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ class _ChatViewListScreenState extends State<ChatViewListScreen> {
),
config: ChatViewListConfig(
tileConfig: ListTileConfig(
pinIconConfig: const PinIconConfig(),
muteIconConfig: const MuteIconConfig(),
typingStatusConfig: const TypingStatusConfig(
showUserNames: true,
),
Expand Down
10 changes: 5 additions & 5 deletions lib/src/extensions/extensions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ extension ChatViewStateTitleExtension on String? {
}

extension type const TypingStatusConfigExtension(TypingStatusConfig config) {
String toTypingStatus(List<String> users) {
String toTypingStatus(List<ChatUser> users) {
final prefix = config.prefix ?? '';
final suffix = config.suffix ?? '';
final showUserNames = config.showUserNames;
Expand All @@ -163,20 +163,20 @@ extension type const TypingStatusConfigExtension(TypingStatusConfig config) {

final count = users.length;

final firstName = users[0];
final firstName = users[0].name;

if (count == 1) {
return '$firstName ${locale.isVerb} $text';
} else if (count == 2) {
final newText = showUserNames
? '$firstName & ${users[1]} ${locale.areVerb}'
? '$firstName & ${users[1].name} ${locale.areVerb}'
: '$firstName & 1 ${locale.other} ${locale.isVerb}';
return '$newText $text';
} else if (showUserNames && count == 3) {
return '${users[0]}, ${users[1]} & ${users[2]} ${locale.areVerb} $text';
return '$firstName, ${users[1].name} & ${users[2].name} ${locale.areVerb} $text';
} else {
final newText = showUserNames
? '$firstName, ${users[1]} & ${count - 2}'
? '$firstName, ${users[1].name} & ${count - 2}'
: '$firstName & ${count - 1}';
return '$newText ${locale.others} ${locale.areVerb} $text';
}
Expand Down
16 changes: 11 additions & 5 deletions lib/src/models/chat_view_list_item.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import 'package:chatview_utils/chatview_utils.dart';

import '../values/enumeration.dart';
import '../values/typedefs.dart';
import 'config_models/chat_view_list/chat_settings.dart';
import 'omit.dart';

/// Model class representing a user or group in the chat list.
Expand All @@ -32,8 +33,9 @@ class ChatViewListItem {
required this.id,
required this.name,
this.chatType = ChatType.user,
this.typingUsers = const <String>{},
this.typingUsers = const <ChatUser>{},
this.userActiveStatus = UserActiveStatus.offline,
this.settings = const ChatSettings(),
this.lastMessage,
this.imageUrl,
this.unreadCount,
Expand Down Expand Up @@ -64,16 +66,19 @@ class ChatViewListItem {
/// Defaults to [UserActiveStatus.offline].
final UserActiveStatus userActiveStatus;

// TODO(YASH): Switch to User Object instead of string.
/// Set of users currently typing in the chat.
final Set<String> typingUsers;
final Set<ChatUser> typingUsers;

/// Settings for the chat list view.
final ChatSettings settings;

ChatViewListItem copyWith({
Defaulted<String> id = const Omit(),
Defaulted<String> name = const Omit(),
Defaulted<ChatType> chatType = const Omit(),
Defaulted<Set<String>> typingUsers = const Omit(),
Defaulted<Set<ChatUser>> typingUsers = const Omit(),
Defaulted<UserActiveStatus> userActiveStatus = const Omit(),
Defaulted<ChatSettings> settings = const Omit(),
Defaulted<Message>? lastMessage = const Omit(),
Defaulted<String>? imageUrl = const Omit(),
Defaulted<int>? unreadCount = const Omit(),
Expand All @@ -83,10 +88,11 @@ class ChatViewListItem {
name: name is Omit ? this.name : name as String,
chatType: chatType is Omit ? this.chatType : chatType as ChatType,
typingUsers:
typingUsers is Omit ? this.typingUsers : typingUsers as Set<String>,
typingUsers is Omit ? this.typingUsers : typingUsers as Set<ChatUser>,
userActiveStatus: userActiveStatus is Omit
? this.userActiveStatus
: userActiveStatus as UserActiveStatus,
settings: settings is Omit ? this.settings : settings as ChatSettings,
lastMessage:
lastMessage is Omit ? this.lastMessage : lastMessage as Message?,
imageUrl: imageUrl is Omit ? this.imageUrl : imageUrl as String?,
Expand Down
28 changes: 28 additions & 0 deletions lib/src/models/config_models/chat_view_list/chat_settings.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import '../../../values/enumeration.dart';
import '../../../values/typedefs.dart';
import '../../omit.dart';

class ChatSettings {
const ChatSettings({
this.muteStatus = MuteStatus.unmute,
this.pinStatus = PinStatus.unpinned,
this.pinTime,
});

final MuteStatus muteStatus;
final PinStatus pinStatus;
final DateTime? pinTime;

ChatSettings copyWith({
Defaulted<MuteStatus> muteStatus = const Omit(),
Defaulted<PinStatus> pinStatus = const Omit(),
Defaulted<DateTime>? pinTime = const Omit(),
}) {
return ChatSettings(
muteStatus:
muteStatus is Omit ? this.muteStatus : muteStatus as MuteStatus,
pinStatus: pinStatus is Omit ? this.pinStatus : pinStatus as PinStatus,
pinTime: pinTime is Omit ? this.pinTime : pinTime as DateTime?,
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import 'package:flutter/material.dart';

import '../../../utils/constants/constants.dart';
import '../../../values/typedefs.dart';

class LastMessageTimeConfig {
const LastMessageTimeConfig({
Expand All @@ -30,6 +31,7 @@ class LastMessageTimeConfig {
this.dateFormatPattern = defaultDateFormat,
this.spaceBetweenTimeAndUnreadCount = 5,
this.textStyle,
this.timeBuilder,
});

/// Maximum number of lines for the last message time in the chat list.
Expand All @@ -54,4 +56,6 @@ class LastMessageTimeConfig {
///
/// Defaults to `5.0`.
final double spaceBetweenTimeAndUnreadCount;

final LastMessageTimeBuilder? timeBuilder;
}
18 changes: 18 additions & 0 deletions lib/src/models/config_models/chat_view_list/list_tile_config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import '../../../values/typedefs.dart';
import '../../chat_view_list_item.dart';
import 'last_message_time_config.dart';
import 'list_type_indicator_config.dart';
import 'mute_icon_config.dart';
import 'pin_icon_config.dart';
import 'unread_count_config.dart';
import 'user_active_status_config.dart';
import 'user_avatar_config.dart';
Expand All @@ -34,6 +36,8 @@ class ListTileConfig {
/// Creates a configuration object for the user widget in the chat list UI.
const ListTileConfig({
this.showOnlineStatus = true,
this.muteIconConfig = const MuteIconConfig(),
this.pinIconConfig = const PinIconConfig(),
this.timeConfig = const LastMessageTimeConfig(),
this.userAvatarConfig = const UserAvatarConfig(),
this.unreadCountConfig = const UnreadCountConfig(),
Expand All @@ -50,13 +54,21 @@ class ListTileConfig {
this.onTap,
this.onLongPress,
this.lastMessageTileBuilder,
this.userNameBuilder,
this.trailingBuilder,
});

/// Padding around the widget in the chat list.
///
/// Defaults to `EdgeInsets.symmetric(vertical: 6, horizontal: 8)`.
final EdgeInsets padding;

/// Custom widget builder for the user name in the chat list.
final UserNameBuilder? userNameBuilder;

/// Custom widget builder for the trailing widget in the chat list.
final TrailingBuilder? trailingBuilder;

/// Text styles for various text elements in the user widget.
final TextStyle? userNameTextStyle;

Expand Down Expand Up @@ -119,4 +131,10 @@ class ListTileConfig {

/// Configuration for the typing status indicator in the chat list.
final TypingStatusConfig typingStatusConfig;

/// Configuration for the mute icon in the chat list.
final MuteIconConfig muteIconConfig;

/// Configuration for the pin icon in the chat list.
final PinIconConfig pinIconConfig;
}
3 changes: 3 additions & 0 deletions lib/src/models/config_models/chat_view_list/models.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,14 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
export 'chat_settings.dart';
export 'chat_view_list_config.dart';
export 'list_tile_config.dart';
export 'last_message_time_config.dart';
export 'list_type_indicator_config.dart';
export 'load_more_config.dart';
export 'mute_icon_config.dart';
export 'pin_icon_config.dart';
export 'search_config.dart';
export 'unread_count_config.dart';
export 'user_active_status_config.dart';
Expand Down
13 changes: 13 additions & 0 deletions lib/src/models/config_models/chat_view_list/mute_icon_config.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import 'package:flutter/widgets.dart';

class MuteIconConfig {
const MuteIconConfig({
this.size = 18,
this.widget,
this.color,
});

final Widget? widget;
final double? size;
final Color? color;
}
13 changes: 13 additions & 0 deletions lib/src/models/config_models/chat_view_list/pin_icon_config.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import 'package:flutter/widgets.dart';

class PinIconConfig {
const PinIconConfig({
this.size = 18,
this.widget,
this.color,
});

final Widget? widget;
final double? size;
final Color? color;
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class UserAvatarConfig {
this.backgroundColor,
this.onBackgroundImageError,
this.onProfileTap,
this.avatarBuilder,
});

/// Radius for the circle avatar in the profile widget.
Expand All @@ -27,4 +28,7 @@ class UserAvatarConfig {

/// Callback function that is called when the profile widget is tapped.
final ValueSetter<ChatViewListItem>? onProfileTap;

/// Builder function to create a custom avatar widget.
final UserAvatarBuilder? avatarBuilder;
}
18 changes: 17 additions & 1 deletion lib/src/utils/chat_view_locale.dart
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,13 @@ final class ChatViewLocale {
required this.areVerb,
required this.other,
required this.others,
required this.mute,
required this.unmute,
required this.pin,
required this.unpin,
});

/// Create from Map
/// Create from `Map<String, String>`
factory ChatViewLocale.fromMap(Map<String, String> map) {
return ChatViewLocale(
today: map['today']?.toString() ?? '',
Expand Down Expand Up @@ -80,6 +84,10 @@ final class ChatViewLocale {
areVerb: map['areVerb']?.toString() ?? '',
other: map['other']?.toString() ?? '',
others: map['others']?.toString() ?? '',
mute: map['mute']?.toString() ?? '',
unmute: map['unmute']?.toString() ?? '',
pin: map['pin']?.toString() ?? '',
unpin: map['unpin']?.toString() ?? '',
);
}

Expand Down Expand Up @@ -109,6 +117,10 @@ final class ChatViewLocale {
final String areVerb;
final String other;
final String others;
final String mute;
final String unmute;
final String pin;
final String unpin;

/// English defaults
static const en = ChatViewLocale(
Expand Down Expand Up @@ -138,5 +150,9 @@ final class ChatViewLocale {
isVerb: 'is',
other: 'other',
others: 'others',
mute: 'Mute',
unmute: 'Unmute',
pin: 'Pin',
unpin: 'Unpin',
);
}
52 changes: 52 additions & 0 deletions lib/src/values/enumeration.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
import 'package:chatview_utils/chatview_utils.dart';
import 'package:flutter/material.dart';

import '../utils/package_strings.dart';

enum ShowReceiptsIn { all, lastMessage }

enum SuggestionListAlignment {
Expand Down Expand Up @@ -131,3 +133,53 @@ enum UserActiveStatus {
/// is user active
bool get isOffline => this == offline;
}

/// An enumeration representing mute status options.
enum MuteStatus {
/// The chat is muted.
muted,

/// The chat is not muted.
unmute;

/// Returns true if the chat is muted.
bool get isMuted => this == muted;

/// Returns true if the chat is unmuted.
bool get isUnmute => this == unmute;

String get menuName => switch (this) {
muted => PackageStrings.currentLocale.mute,
unmute => PackageStrings.currentLocale.unmute,
};

IconData get iconData => switch (this) {
muted => Icons.notifications_off,
unmute => Icons.notifications,
};
}

/// An enumeration representing the status of a chat pinning operation.
enum PinStatus {
/// The chat is pinned.
pinned,

/// The chat is unpinned.
unpinned;

/// Returns true if the chat is pinned.
bool get isPinned => this == pinned;

/// Returns true if the chat is unpinned.
bool get isNone => this == unpinned;

String get menuName => switch (this) {
pinned => PackageStrings.currentLocale.pin,
unpinned => PackageStrings.currentLocale.unpin,
};

IconData get iconData => switch (this) {
pinned => Icons.push_pin,
unpinned => Icons.push_pin_outlined,
};
}
12 changes: 12 additions & 0 deletions lib/src/values/typedefs.dart
Original file line number Diff line number Diff line change
Expand Up @@ -120,3 +120,15 @@ typedef UpdateChatCallback = ChatViewListItem Function(
ChatViewListItem previousChat,
);
typedef UnreadCountWidgetBuilder = Widget Function(int count);
typedef ChatStatusCallback<T> = void Function(
({ChatViewListItem chat, T status}) result,
);
typedef StatusTrailingIcon<T> = IconData Function(T status);
typedef LastMessageTimeBuilder = Widget Function(DateTime time);
typedef ChatViewListTileBuilder = Widget Function(
BuildContext context,
ChatViewListItem chat,
);
typedef UserAvatarBuilder = Widget Function(ChatViewListItem chat);
typedef UserNameBuilder = Widget Function(ChatViewListItem chat);
typedef TrailingBuilder = Widget Function(ChatViewListItem chat);
Loading