Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix!: 🐛 json parsing issue #178

Merged
merged 2 commits into from
Jun 6, 2024
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
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
## [2.0.0] (Unreleased)

* **Breaking**: [177](https://github.com/SimformSolutionsPvtLtd/flutter_chatview/pull/177) Fixed
json serializable of models and added copyWith method (Message, Reaction and Reply Message).
* **Fix**: [182](https://github.com/SimformSolutionsPvtLtd/flutter_chatview/issues/182) Fix
send message not working when user start texting after newLine.
* **Feat**: [156](https://github.com/SimformSolutionsPvtLtd/flutter_chatview/pull/156) Added
Expand Down Expand Up @@ -41,7 +43,6 @@
* **Feat**: [161](https://github.com/SimformSolutionsPvtLtd/flutter_chatview/pull/161) Added
field to set top padding of chat text field.


## [1.3.1]

* **Feat**: [105](https://github.com/SimformSolutionsPvtLtd/flutter_chatview/pull/105) Allow user
Expand Down
23 changes: 21 additions & 2 deletions lib/src/models/chat_user.dart
Original file line number Diff line number Diff line change
Expand Up @@ -67,15 +67,34 @@ class ChatUser {
id: json["id"],
name: json["name"],
profilePhoto: json["profilePhoto"],
imageType: json["imageType"],
imageType: ImageType.tryParse(json['imageType']?.toString()) ??
ImageType.network,
defaultAvatarImage: json["defaultAvatarImage"],
);

Map<String, dynamic> toJson() => {
'id': id,
'name': name,
'profilePhoto': profilePhoto,
'imageType': imageType,
'imageType': imageType.name,
'defaultAvatarImage': defaultAvatarImage,
};

ChatUser copyWith({
String? id,
String? name,
String? profilePhoto,
ImageType? imageType,
String? defaultAvatarImage,
bool forceNullValue = false,
}) {
return ChatUser(
id: id ?? this.id,
name: name ?? this.name,
imageType: imageType ?? this.imageType,
profilePhoto:
forceNullValue ? profilePhoto : profilePhoto ?? this.profilePhoto,
defaultAvatarImage: defaultAvatarImage ?? this.defaultAvatarImage,
);
}
}
65 changes: 52 additions & 13 deletions lib/src/models/message.dart
Original file line number Diff line number Diff line change
Expand Up @@ -91,25 +91,64 @@ class Message {
}

factory Message.fromJson(Map<String, dynamic> json) => Message(
id: json["id"],
message: json["message"],
createdAt: json["createdAt"],
sendBy: json["sendBy"],
replyMessage: ReplyMessage.fromJson(json["reply_message"]),
reaction: Reaction.fromJson(json["reaction"]),
messageType: json["message_type"],
voiceMessageDuration: json["voice_message_duration"],
status: json['status']);
id: json['id']?.toString() ?? '',
message: json['message']?.toString() ?? '',
createdAt:
DateTime.tryParse(json['createdAt'].toString()) ?? DateTime.now(),
sendBy: json['sendBy']?.toString() ?? '',
replyMessage: json['reply_message'] is Map<String, dynamic>
? ReplyMessage.fromJson(json['reply_message'])
: const ReplyMessage(),
reaction: json['reaction'] is Map<String, dynamic>
aditya-css marked this conversation as resolved.
Show resolved Hide resolved
? Reaction.fromJson(json['reaction'])
: null,
messageType: MessageType.tryParse(json['message_type']?.toString()) ??
MessageType.text,
voiceMessageDuration: Duration(
microseconds:
int.tryParse(json['voice_message_duration'].toString()) ?? 0,
),
status: MessageStatus.tryParse(json['status']?.toString()) ??
MessageStatus.pending,
);

Map<String, dynamic> toJson() => {
'id': id,
'message': message,
'createdAt': createdAt,
'createdAt': createdAt.toIso8601String(),
'sendBy': sendBy,
'reply_message': replyMessage.toJson(),
'reaction': reaction.toJson(),
'message_type': messageType,
'voice_message_duration': voiceMessageDuration,
'status': status.name
'message_type': messageType.name,
'voice_message_duration': voiceMessageDuration?.inMicroseconds,
'status': status.name,
};

Message copyWith({
String? id,
GlobalKey? key,
String? message,
DateTime? createdAt,
String? sendBy,
ReplyMessage? replyMessage,
Reaction? reaction,
MessageType? messageType,
Duration? voiceMessageDuration,
MessageStatus? status,
bool forceNullValue = false,
}) {
return Message(
id: id ?? this.message,
message: message ?? this.message,
createdAt: createdAt ?? this.createdAt,
sendBy: sendBy ?? this.sendBy,
messageType: messageType ?? this.messageType,
voiceMessageDuration: forceNullValue
? voiceMessageDuration
: voiceMessageDuration ?? this.voiceMessageDuration,
reaction: reaction ?? this.reaction,
replyMessage: replyMessage ?? this.replyMessage,
status: status ?? this.status,
);
}
}
40 changes: 36 additions & 4 deletions lib/src/models/reaction.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,32 @@ class Reaction {
required this.reactedUserIds,
});

factory Reaction.fromJson(Map<String, dynamic> json) => Reaction(
reactions: json['reactions'],
reactedUserIds: json['reactedUserIds'],
);
factory Reaction.fromJson(Map<String, dynamic> json) {
final reactionsList = json['reactions'] is List<dynamic>
? json['reactions'] as List<dynamic>
: <dynamic>[];

final reactions = <String>[
for (var i = 0; i < reactionsList.length; i++)
if (reactionsList[i]?.toString().isNotEmpty ?? false)
reactionsList[i]!.toString()
];

final reactedUserIdList = json['reactedUserIds'] is List<dynamic>
? json['reactedUserIds'] as List<dynamic>
: <dynamic>[];

final reactedUserIds = <String>[
for (var i = 0; i < reactedUserIdList.length; i++)
if (reactedUserIdList[i]?.toString().isNotEmpty ?? false)
reactedUserIdList[i]!.toString()
];

return Reaction(
reactions: reactions,
reactedUserIds: reactedUserIds,
);
}

/// Provides list of reaction in single message.
final List<String> reactions;
Expand All @@ -19,4 +41,14 @@ class Reaction {
'reactions': reactions,
'reactedUserIds': reactedUserIds,
};

Reaction copyWith({
List<String>? reactions,
List<String>? reactedUserIds,
}) {
return Reaction(
reactions: reactions ?? this.reactions,
reactedUserIds: reactedUserIds ?? this.reactedUserIds,
);
}
}
41 changes: 33 additions & 8 deletions lib/src/models/reply_message.dart
Original file line number Diff line number Diff line change
Expand Up @@ -48,20 +48,45 @@ class ReplyMessage {
});

factory ReplyMessage.fromJson(Map<String, dynamic> json) => ReplyMessage(
message: json['message'],
replyBy: json['replyBy'],
replyTo: json['replyTo'],
messageType: json["message_type"],
messageId: json["id"],
voiceMessageDuration: json["voiceMessageDuration"],
message: json['message']?.toString() ?? '',
replyBy: json['replyBy']?.toString() ?? '',
replyTo: json['replyTo']?.toString() ?? '',
messageType: MessageType.tryParse(json['message_type']?.toString()) ??
MessageType.text,
messageId: json['id']?.toString() ?? '',
voiceMessageDuration: Duration(
microseconds:
int.tryParse(json['voiceMessageDuration'].toString()) ?? 0,
),
);

Map<String, dynamic> toJson() => {
'message': message,
'replyBy': replyBy,
'replyTo': replyTo,
'message_type': messageType,
'message_type': messageType.name,
'id': messageId,
'voiceMessageDuration': voiceMessageDuration,
'voiceMessageDuration': voiceMessageDuration?.inMicroseconds,
};

ReplyMessage copyWith({
String? messageId,
String? message,
String? replyTo,
String? replyBy,
MessageType? messageType,
Duration? voiceMessageDuration,
bool forceNullValue = false,
}) {
return ReplyMessage(
messageId: messageId ?? this.messageId,
message: message ?? this.message,
replyTo: replyTo ?? this.replyTo,
replyBy: replyBy ?? this.replyBy,
messageType: messageType ?? this.messageType,
voiceMessageDuration: forceNullValue
? voiceMessageDuration
: voiceMessageDuration ?? this.voiceMessageDuration,
);
}
}
52 changes: 50 additions & 2 deletions lib/src/values/enumeration.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,22 @@ enum MessageType {

/// Only supported on android and ios
voice,
custom
custom;

static MessageType? tryParse(String? value) {
final type = value?.trim().toLowerCase();
if (type?.isEmpty ?? true) return null;
if (type == image.name) {
return image;
} else if (type == text.name) {
return text;
} else if (type == voice.name) {
return voice;
} else if (type == custom.name) {
return custom;
}
return null;
}
}

/// Events, Wheter the user is still typing a message or has
Expand All @@ -36,7 +51,27 @@ enum TypeWriterStatus { typing, typed }

/// [MessageStatus] defines the current state of the message
/// if you are sender sending a message then, the
enum MessageStatus { read, delivered, undelivered, pending }
enum MessageStatus {
read,
delivered,
undelivered,
pending;

static MessageStatus? tryParse(String? value) {
final status = value?.trim().toLowerCase();
if (status?.isEmpty ?? true) return null;
if (status == read.name) {
return read;
} else if (status == delivered.name) {
return delivered;
} else if (status == undelivered.name) {
return undelivered;
} else if (status == pending.name) {
return pending;
}
return null;
}
}

/// Types of states
enum ChatViewState { hasMessages, noData, loading, error }
Expand All @@ -53,6 +88,19 @@ enum ImageType {
bool get isAsset => this == ImageType.asset;

bool get isBase64 => this == ImageType.base64;

static ImageType? tryParse(String? value) {
final type = value?.trim().toLowerCase();
if (type?.isEmpty ?? true) return null;
if (type == asset.name) {
return asset;
} else if (type == network.name) {
return network;
} else if (type == base64.name) {
return base64;
}
return null;
}
}

extension ChatViewStateExtension on ChatViewState {
Expand Down