it.auties.whatsapp.model.chat.Chat Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of whatsappweb4j Show documentation
Show all versions of whatsappweb4j Show documentation
Standalone fully-featured Whatsapp Web API for Java and Kotlin
package it.auties.whatsapp.model.chat;
import com.fasterxml.jackson.annotation.JsonSetter;
import it.auties.protobuf.base.ProtobufMessage;
import it.auties.protobuf.base.ProtobufName;
import it.auties.protobuf.base.ProtobufProperty;
import it.auties.whatsapp.api.Whatsapp;
import it.auties.whatsapp.listener.Listener;
import it.auties.whatsapp.model.contact.Contact;
import it.auties.whatsapp.model.contact.ContactJid;
import it.auties.whatsapp.model.contact.ContactJidProvider;
import it.auties.whatsapp.model.contact.ContactStatus;
import it.auties.whatsapp.model.info.MessageInfo;
import it.auties.whatsapp.model.message.model.MessageCategory;
import it.auties.whatsapp.model.sync.HistorySyncMessage;
import it.auties.whatsapp.util.Clock;
import lombok.*;
import lombok.Builder.Default;
import lombok.experimental.Accessors;
import lombok.extern.jackson.Jacksonized;
import java.time.ZonedDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import static it.auties.protobuf.base.ProtobufType.*;
import static java.util.Objects.requireNonNullElse;
/**
* A model class that represents a Chat. A chat can be of two types: a conversation with a contact
* or a group. This class is only a model, this means that changing its values will have no real
* effect on WhatsappWeb's servers. This class also offers a builder, accessible using
* {@link Chat#builder()}.
*/
@SuppressWarnings({"UnusedReturnValue", "unused"})
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@Data
@Builder
@Jacksonized
@Accessors(fluent = true)
@ProtobufName("Conversation")
public final class Chat implements ProtobufMessage, ContactJidProvider {
/**
* The unique id of this chat
*/
@NonNull
@Default
private final UUID uuid = UUID.randomUUID();
/**
* The non-null unique jid used to identify this chat
*/
@ProtobufProperty(index = 1, type = STRING)
@NonNull
private final ContactJid jid;
/**
* The nullable new unique jid for this Chat. This field is not null when a contact changes phone
* number and connects their new phone number with Whatsapp.
*/
@ProtobufProperty(index = 3, type = STRING)
private final ContactJid newJid;
/**
* The nullable old jid for this Chat. This field is not null when a contact changes phone number
* and connects their new phone number with Whatsapp.
*/
@ProtobufProperty(index = 4, type = STRING)
private final ContactJid oldJid;
/**
* The timestamp of this chat
* Usually refers to the time when it was last modified
* Doesn't necessarily match {@link Chat#newestMessage()}'s timestamp
*/
@ProtobufProperty(index = 12, type = UINT64)
private long timestampSeconds;
/**
* A non-null list of messages in this chat sorted chronologically
*/
@ProtobufProperty(index = 2, type = MESSAGE, implementation = HistorySyncMessage.class, repeated = true)
@NonNull
@Default
private final ConcurrentLinkedDeque historySyncMessages = new ConcurrentLinkedDeque<>();
/**
* The number of unread messages in this chat. If this field is negative, this chat is marked as
* unread.
*/
@ProtobufProperty(index = 6, type = UINT32)
private int unreadMessagesCount;
/**
* Whether this chat is read only
*/
@ProtobufProperty(index = 7, name = "readOnly", type = BOOL)
private boolean readOnly;
/**
* Whether this chat has been transferred completely
*/
@ProtobufProperty(index = 8, name = "endOfHistoryTransfer", type = BOOL)
private boolean endOfHistoryTransfer;
/**
* The seconds in seconds before a message is automatically deleted from this chat both locally
* and from WhatsappWeb's servers. If ephemeral messages aren't enabled, this field has a value of
* 0
*/
@ProtobufProperty(index = 9, type = UINT32)
@Default
private ChatEphemeralTimer ephemeralMessageDuration = ChatEphemeralTimer.OFF;
/**
* The seconds in seconds since {@link java.time.Instant#EPOCH} when ephemeral messages were
* turned on. If ephemeral messages aren't enabled, this field has a value of 0.
*/
@ProtobufProperty(index = 10, type = INT64)
private long ephemeralMessagesToggleTime;
/**
* The history sync status
*/
@ProtobufProperty(index = 11, name = "endOfHistoryTransferType", type = MESSAGE)
@Default
private EndOfHistoryTransferType endOfHistoryTransferType = EndOfHistoryTransferType.COMPLETE_BUT_MORE_MESSAGES_REMAIN_ON_PRIMARY;
/**
* The non-null display name of this chat
*/
@ProtobufProperty(index = 13, type = STRING)
private String name;
/**
* This field is used to determine whether a chat was marked as being spam or not.
*/
@ProtobufProperty(index = 15, type = BOOL)
private boolean notSpam;
/**
* This field is used to determine whether a chat is archived or not.
*/
@ProtobufProperty(index = 16, type = BOOL)
private boolean archived;
/**
* The initiator of disappearing chats
*/
@ProtobufProperty(index = 17, type = MESSAGE, implementation = ChatDisappear.class)
private ChatDisappear disappearInitiator;
/**
* Whether this chat was manually marked as unread
*/
@ProtobufProperty(index = 19, name = "markedAsUnread", type = BOOL)
private boolean markedAsUnread;
/**
* The participants of this chat, if it's a group
*/
@ProtobufProperty(implementation = GroupParticipant.class, index = 20, name = "participant", repeated = true, type = MESSAGE)
@Default
private Map participants = new ConcurrentHashMap<>();
/**
* The participants that used to be in this chat, if it's a group
*/
@Default
private Map pastParticipants = new ConcurrentHashMap<>();
/**
* The token of this chat
*/
@ProtobufProperty(index = 21, type = BYTES)
private byte[] token;
/**
* The timestamp of the token of this chat
*/
@ProtobufProperty(index = 22, type = UINT64)
private long tokenTimestampSeconds;
/**
* The public identity key of this chat
*/
@ProtobufProperty(index = 23, type = BYTES)
private byte[] identityKey;
/**
* The seconds in seconds since {@link java.time.Instant#EPOCH} when this chat was pinned to the
* top. If the chat isn't pinned, this field has a value of 0.
*/
@ProtobufProperty(index = 24, type = UINT32)
private int pinnedTimestampSeconds;
/**
* The mute status of this chat
*/
@ProtobufProperty(index = 25, type = UINT64)
@NonNull
@Default
private ChatMute mute = ChatMute.notMuted();
/**
* The wallpaper of this chat
*/
@ProtobufProperty(index = 26, type = MESSAGE, implementation = ChatWallpaper.class)
private ChatWallpaper wallpaper;
/**
* The type of this media visibility set for this chat
*/
@ProtobufProperty(index = 27, type = MESSAGE, implementation = ChatMediaVisibility.class)
@NonNull
@Default
private ChatMediaVisibility mediaVisibility = ChatMediaVisibility.OFF;
/**
* The timestamp of the sender of the token of this chat
*/
@ProtobufProperty(index = 28, type = UINT64)
private long tokenSenderTimestampSeconds;
/**
* Whether this chat was suspended and therefore cannot be accessed anymore
*/
@ProtobufProperty(index = 29, type = BOOL)
private boolean suspended;
/**
* Whether this chat was terminated
*/
@ProtobufProperty(index = 30, name = "terminated", type = BOOL)
private boolean terminated;
/**
* The timestamp at which the chat, if a group, was created
*/
@ProtobufProperty(index = 31, name = "createdAt", type = UINT64)
private long foundationTimestampSeconds;
/**
* The user who created this chat, if a group
*/
@ProtobufProperty(index = 32, name = "createdBy", type = STRING)
private ContactJid founder;
/**
* The description of this chat, if a group
*/
@ProtobufProperty(index = 33, name = "description", type = STRING)
private String description;
/**
* Whether this chat is an official support chat from Whatsapp
*/
@ProtobufProperty(index = 34, name = "support", type = BOOL)
private boolean support;
/**
* Whether this chat is a parent group
*/
@ProtobufProperty(index = 35, name = "isParentGroup", type = BOOL)
private boolean parentGroup;
/**
* Whether this chat is a default subgroup
*/
@ProtobufProperty(index = 36, name = "isDefaultSubgroup", type = BOOL)
private boolean defaultSubGroup;
/**
* The parent group's jid in a community
*/
@ProtobufProperty(index = 37, name = "parentGroupId", type = STRING)
private ContactJid parentGroupJid;
/**
* Experimental
*/
@ProtobufProperty(index = 38, name = "displayName", type = STRING)
private String displayName;
/**
* Experimental
*/
@ProtobufProperty(index = 39, name = "pnJid", type = STRING)
private ContactJid pnJid;
/**
* Experimental
*/
@ProtobufProperty(index = 40, name = "shareOwnPn", type = BOOL)
private boolean shareOwnPn;
/**
* Experimental
*/
@ProtobufProperty(index = 41, name = "pnhDuplicateLidThread", type = BOOL)
private boolean pnhDuplicateLidThread;
/**
* Experimental
*/
@ProtobufProperty(index = 42, name = "lidJid", type = STRING)
private ContactJid lidJid;
/**
* A map that holds the status of each participant, excluding yourself, for this chat. If the
* chat is not a group, this map's size will range from 0 to 1. Otherwise, it will range from 0
* to the number of participants - 1. It is important to remember that is not guaranteed that
* every participant will be present as a key. In this case, if this chat is a group, it can be
* safely assumed that the user is not available. Otherwise, it's recommended to use
* {@link Whatsapp#subscribeToPresence(ContactJidProvider)} to force Whatsapp to send updates
* regarding the status of the other participant. It's also possible to listen for updates to a
* contact's presence in a group or in a conversation by implementing
* {@link Listener#onContactPresence}. The presence that this map indicates might not line up
* with {@link Contact#lastKnownPresence()} if the contact is composing, recording or paused. This
* is because a contact can be online on Whatsapp and composing, recording or paused in a specific
* chat.
*/
@Default
@NonNull
private ConcurrentHashMap presences = new ConcurrentHashMap<>();
/**
* A set that hold all the jids of the participants in this chat that have received pre keys. This
* set is only used if the chat is a group chat. It's not important for anything other than
* message ciphering.
*/
@Default
@NonNull
private Set participantsPreKeys = new HashSet<>();
/**
* Constructs a chat from a jid
*
* @param jid the non-null jid
* @return a non-null chat
*/
public static Chat ofJid(@NonNull ContactJid jid) {
return Chat.builder().jid(jid).build();
}
/**
* Returns the name of this chat
*
* @return a non-null string
*/
public String name() {
return requireNonNullElse(name, requireNonNullElse(displayName, jid.user()));
}
/**
* Returns whether this chat has a name. If this method returns false, it doesn't imply that
* {@link Chat#name()} will return null.
*
* @return a boolean
*/
public boolean hasName() {
return name != null;
}
/**
* Returns a boolean to represent whether this chat is a group or not
*
* @return true if this chat is a group
*/
public boolean isGroup() {
return jid.type() == ContactJid.Type.GROUP;
}
/**
* Returns a boolean to represent whether this chat is pinned or not
*
* @return true if this chat is pinned
*/
public boolean isPinned() {
return pinnedTimestampSeconds != 0;
}
/**
* Returns a boolean to represent whether ephemeral messages are enabled for this chat
*
* @return true if ephemeral messages are enabled for this chat
*/
public boolean isEphemeral() {
return ephemeralMessageDuration != ChatEphemeralTimer.OFF && ephemeralMessagesToggleTime != 0;
}
/**
* Returns a boolean to represent whether this chat has a new jid
*
* @return true if this chat has a new jid
*/
public boolean hasNewJid() {
return newJid != null;
}
/**
* Returns a boolean to represent whether this chat has an old jid
*
* @return true if this chat has an old jid
*/
public boolean hasOldJid() {
return oldJid != null;
}
/**
* Returns all the unread messages in this chat
*
* @return a non-null collection
*/
public Collection unreadMessages() {
if (!hasUnreadMessages()) {
return List.of();
}
var iterator = historySyncMessages.iterator();
return historySyncMessages.stream()
.limit(unreadMessagesCount())
.map(HistorySyncMessage::messageInfo)
.toList();
}
/**
* Returns a boolean to represent whether this chat has unread messages
*
* @return true if this chat has unread messages
*/
public boolean hasUnreadMessages() {
return unreadMessagesCount > 0;
}
/**
* Returns an optional value containing the new jid of this chat
*
* @return a non-empty optional if the new jid is not null
*/
public Optional newJid() {
return Optional.ofNullable(newJid);
}
/**
* Returns an optional value containing the old jid of this chat
*
* @return a non-empty optional if the old jid is not null
*/
public Optional oldJid() {
return Optional.ofNullable(oldJid);
}
/**
* Returns an optional value containing the disappearing status of this chat
*
* @return a non-empty optional if the disappearing status of this chat is not null
*/
public Optional disappearInitiator() {
return Optional.ofNullable(disappearInitiator);
}
/**
* Returns an optional value containing the wallpaper of this chat, if any is set
*
* @return a non-empty optional if this chat has a custom wallpaper
*/
public Optional wallpaper() {
return Optional.ofNullable(wallpaper);
}
/**
* Returns an optional value containing the seconds this chat was pinned
*
* @return a non-empty optional if the chat is pinned
*/
public ZonedDateTime pinnedTimestamp() {
return Clock.parseSeconds(pinnedTimestampSeconds);
}
/**
* Returns the timestamp for the creation of this chat in seconds since
* {@link java.time.Instant#EPOCH}
*
* @return a non-empty optional if this field is populated
*/
public ZonedDateTime timestamp() {
return Clock.parseSeconds(timestampSeconds);
}
/**
* Returns an optional value containing the seconds in seconds since
* {@link java.time.Instant#EPOCH} when ephemeral messages were turned on
*
* @return a non-empty optional if ephemeral messages are enabled for this chat
*/
public ZonedDateTime ephemeralMessagesToggleTime() {
return Clock.parseSeconds(ephemeralMessagesToggleTime);
}
/**
* Returns an optional value containing the latest message in chronological terms for this chat
*
* @return an optional
*/
public Optional newestMessage() {
return Optional.ofNullable(historySyncMessages.peekLast())
.map(HistorySyncMessage::messageInfo);
}
/**
* Returns an optional value containing the first message in chronological terms for this chat
*
* @return an optional
*/
public Optional oldestMessage() {
return Optional.ofNullable(historySyncMessages.peekFirst())
.map(HistorySyncMessage::messageInfo);
}
/**
* Returns an optional value containing the latest message in chronological terms for this chat
* with type that isn't server
*
* @return an optional
*/
public Optional newestStandardMessage() {
return findMessageBy(this::isStandardMessage, true);
}
/**
* Returns an optional value containing the first message in chronological terms for this chat
* with type that isn't server
*
* @return an optional
*/
public Optional oldestStandardMessage() {
return findMessageBy(this::isStandardMessage, false);
}
private boolean isStandardMessage(MessageInfo info) {
return !info.message().hasCategory(MessageCategory.SERVER) && !info.hasStub();
}
/**
* Returns an optional value containing the latest message in chronological terms for this chat
* sent from you
*
* @return an optional
*/
public Optional newestMessageFromMe() {
return findMessageBy(this::isMessageFromMe, true);
}
/**
* Returns an optional value containing the first message in chronological terms for this chat
* sent from you
*
* @return an optional
*/
public Optional oldestMessageFromMe() {
return findMessageBy(this::isMessageFromMe, false);
}
private boolean isMessageFromMe(MessageInfo info) {
return !info.message().hasCategory(MessageCategory.SERVER) && !info.hasStub() && info.fromMe();
}
/**
* Returns an optional value containing the latest message in chronological terms for this chat
* with type server
*
* @return an optional
*/
public Optional newestServerMessage() {
return findMessageBy(this::isServerMessage, true);
}
/**
* Returns an optional value containing the first message in chronological terms for this chat
* with type server
*
* @return an optional
*/
public Optional oldestServerMessage() {
return findMessageBy(this::isServerMessage, false);
}
private boolean isServerMessage(MessageInfo info) {
return info.message().hasCategory(MessageCategory.SERVER) || info.hasStub();
}
private Optional findMessageBy(Function filter, boolean newest) {
var descendingIterator = newest ? historySyncMessages.descendingIterator() : historySyncMessages.iterator();
while (descendingIterator.hasNext()){
var info = descendingIterator.next().messageInfo();
if(filter.apply(info)){
return Optional.ofNullable(info);
}
}
return Optional.empty();
}
/**
* Returns all the starred messages in this chat
*
* @return a non-null list of messages
*/
public Collection starredMessages() {
return historySyncMessages.stream()
.map(HistorySyncMessage::messageInfo)
.filter(MessageInfo::starred)
.toList();
}
/**
* Returns the token for this chat
*
* @return a non-null optional value
*/
public Optional token() {
return Optional.ofNullable(token);
}
/**
* Returns the timestamp for the creation of this chat's token
*
* @return a non-null optional value
*/
public ZonedDateTime tokenTimestamp() {
return Clock.parseSeconds(tokenTimestampSeconds);
}
/**
* Returns the identity token for this chat
*
* @return a non-null optional value
*/
public Optional identityKey() {
return Optional.ofNullable(identityKey);
}
/**
* Returns the timestamp for the token sender creation of this chat
*
* @return a non-null optional value
*/
public ZonedDateTime tokenSenderTimestamp() {
return Clock.parseSeconds(tokenSenderTimestampSeconds);
}
/**
* Returns the timestamp for the creation of this chat if it's a group
*
* @return a non-null optional value
*/
public ZonedDateTime foundationTimestamp() {
return Clock.parseSeconds(foundationTimestampSeconds);
}
/**
* Returns the contact who created this chat if it's a group
* This method only works if {@link Whatsapp#queryGroupMetadata(ContactJidProvider)} has been called before on this chat.
* By default, all groups that have been used in the last two weeks wil be synced automatically
*
* @return a non-null optional value
*/
public Optional founder() {
return Optional.ofNullable(founder);
}
/**
* Returns the description of this chat if it's a group
* This method only works if {@link Whatsapp#queryGroupMetadata(ContactJidProvider)} has been called before on this chat.
* By default, all groups that have been used in the last two weeks wil be synced automatically
*
* @return a non-null optional value
*/
public Optional description() {
return Optional.ofNullable(description);
}
/**
* Returns the pn jid
* Experimental
*
* @return a non-null optional value
*/
public Optional pnJid() {
return Optional.ofNullable(pnJid);
}
/**
* Returns the lid jid
* Experimental
*
* @return a non-null optional value
*/
public Optional lidJid() {
return Optional.ofNullable(lidJid);
}
/**
* Adds a new unspecified amount of messages to this chat and sorts them accordingly
*
* @param newMessages the non-null messages to add
*/
public void addMessages(@NonNull Collection newMessages) {
historySyncMessages.addAll(newMessages);
}
/**
* Adds a new unspecified amount of messages to this chat and sorts them accordingly
*
* @param oldMessages the non-null messages to add
*/
public void addOldMessages(@NonNull Collection oldMessages) {
oldMessages.forEach(historySyncMessages::addFirst);
}
/**
* Adds a message to the chat in the most recent slot available
*
* @param info the message to add to the chat
* @return whether the message was added
*/
public boolean addNewMessage(@NonNull MessageInfo info) {
var sync = new HistorySyncMessage(info, historySyncMessages.size());
if (historySyncMessages.contains(sync)) {
return false;
}
historySyncMessages.add(sync);
updateChatTimestamp(info);
return true;
}
/**
* Adds a message to the chat in the oldest slot available
*
* @param info the message to add to the chat
* @return whether the message was added
*/
public boolean addOldMessage(@NonNull HistorySyncMessage info) {
historySyncMessages.addFirst(info);
return true;
}
/**
* Remove a message from the chat
*
* @param info the message to remove
* @return whether the message was removed
*/
public boolean removeMessage(@NonNull MessageInfo info) {
var result = historySyncMessages.removeIf(entry -> Objects.equals(entry.messageInfo().id(), info.id()));
refreshChatTimestamp();
return result;
}
/**
* Remove a message from the chat
*
* @param predicate the predicate that determines if a message should be removed
* @return whether the message was removed
*/
public boolean removeMessage(@NonNull Predicate super MessageInfo> predicate) {
var result = historySyncMessages.removeIf(entry -> predicate.test(entry.messageInfo()));
refreshChatTimestamp();
return result;
}
private void refreshChatTimestamp() {
var message = newestMessage();
if(message.isEmpty()){
return;
}
updateChatTimestamp(message.get());
}
private void updateChatTimestamp(MessageInfo info) {
var oldTimeStamp = newestMessage().map(MessageInfo::timestampSeconds).orElse(0L);
if(oldTimeStamp > info.timestampSeconds()){
return;
}
timestampSeconds(info.timestampSeconds());
}
/**
* Removes all messages from the chat
*/
public void removeMessages() {
historySyncMessages.clear();
}
/**
* Returns an immutable list of messages wrapped in history syncs
* This is useful for the proto
*
* @return a non-null collection
*/
public Collection messages(){
return Collections.unmodifiableCollection(historySyncMessages);
}
/**
* Returns an immutable list representing the participants of this chat if it's a group
*
* @return a non-null collection
*/
public Collection participants() {
return participants.values();
}
/**
* Adds a collection of participants to this chat
*
* @param participants the participants to add
*/
public void addParticipants(Collection participants) {
participants.forEach(this::addParticipant);
}
/**
* Adds a participant to this chat
*
* @param jid the non-null jid of the participant
* @param role the role of the participant
* @return the old value associated with the provided jid
*/
public Optional addParticipant(@NonNull ContactJid jid, GroupRole role){
return Optional.ofNullable(participants.put(jid, new GroupParticipant(jid, role)));
}
/**
* Adds a participant to this chat
*
* @param participant the non-null participant
* @return the old value associated with the provided jid
*/
public Optional addParticipant(@NonNull GroupParticipant participant){
return Optional.ofNullable(participants.put(participant.jid(), participant));
}
/**
* Removes a participant from this chat
*
* @param jid the non-null jid of the participant
* @return the old value associated with the provided jid
*/
public Optional removeParticipant(@NonNull ContactJid jid){
return Optional.ofNullable(participants.remove(jid));
}
/**
* Finds a participant by jid
* This method only works if {@link Whatsapp#queryGroupMetadata(ContactJidProvider)} has been called before on this chat.
* By default, all groups that have been used in the last two weeks wil be synced automatically
*
* @param jid the non-null jid of the participant
* @return the participant, if present
*/
public Optional findParticipant(@NonNull ContactJid jid){
return Optional.ofNullable(participants.get(jid));
}
/**
* Returns an immutable list representing the pastParticipants of this chat if it's a group
*
* @return a non-null collection
*/
public Collection pastParticipants() {
return pastParticipants.values();
}
/**
* Adds a past participant
*
* @param participant the non-null jid of the past participant
* @return the old value associated with the provided jid
*/
public Optional addPastParticipant(@NonNull PastParticipant participant){
return Optional.ofNullable(pastParticipants.put(participant.jid(), participant));
}
/**
* Adds a collection of past participants
*
* @param pastParticipants the non-null list of past participants
*/
public void addPastParticipants(List pastParticipants) {
for(var pastParticipant : pastParticipants){
this.pastParticipants.put(pastParticipant.jid(), pastParticipant);
}
}
/**
* Removes a past participant
*
* @param jid the non-null jid of the past participant
* @return the old value associated with the provided jid
*/
public Optional removePastParticipant(@NonNull ContactJid jid){
return Optional.ofNullable(pastParticipants.remove(jid));
}
/**
* Finds a past participant by jid
*
* @param jid the non-null jid of the past participant
* @return the past participant, if present
*/
public Optional findPastParticipant(@NonNull ContactJid jid){
return Optional.ofNullable(pastParticipants.get(jid));
}
/**
* Checks if this chat is equal to another chat
*
* @param other the chat
* @return a boolean
*/
public boolean equals(Object other) {
return (other instanceof Chat that) && Objects.equals(this.jid(), that.jid());
}
/**
* Returns this object as a jid
*
* @return a non-null jid
*/
@Override
@NonNull
public ContactJid toJid() {
return jid();
}
/**
* Returns the hash code for this chat
*
* @return an int
*/
@Override
public int hashCode() {
return Objects.hash(jid());
}
/**
* Returns the hash code for this chat using all fields.
* This is useful to check if two chats are exactly the same.
*
* @return an int
*/
public int fullHashCode() {
int result = Objects.hash(jid, newJid, oldJid, timestampSeconds, historySyncMessages, unreadMessagesCount, readOnly, endOfHistoryTransfer, ephemeralMessageDuration, ephemeralMessagesToggleTime, endOfHistoryTransferType, name, notSpam, archived, disappearInitiator, markedAsUnread, participants, pastParticipants, tokenTimestampSeconds, pinnedTimestampSeconds, mute, wallpaper, mediaVisibility, tokenSenderTimestampSeconds, suspended, terminated, foundationTimestampSeconds, founder, description, support, parentGroup, defaultSubGroup, parentGroupJid, displayName, pnJid, shareOwnPn, pnhDuplicateLidThread, lidJid, presences, participantsPreKeys);
result = 31 * result + Arrays.hashCode(token);
result = 31 * result + Arrays.hashCode(identityKey);
result = 31 * result + historySyncMessages.size();
return result;
}
@Override
public String toString() {
return "Chat{" + "uuid=" + uuid + ", jid=" + jid + ", newJid=" + newJid + ", oldJid=" + oldJid + ", timestampSeconds=" + timestampSeconds + ", messages=" + historySyncMessages + ", unreadMessagesCount=" + unreadMessagesCount + ", readOnly=" + readOnly + ", endOfHistoryTransfer=" + endOfHistoryTransfer + ", ephemeralMessageDuration=" + ephemeralMessageDuration + ", ephemeralMessagesToggleTime=" + ephemeralMessagesToggleTime + ", endOfHistoryTransferType=" + endOfHistoryTransferType + ", name='" + name + '\'' + ", notSpam=" + notSpam + ", archived=" + archived + ", disappearInitiator=" + disappearInitiator + ", markedAsUnread=" + markedAsUnread + ", participants=" + participants + ", pastParticipants=" + pastParticipants + ", token=" + Arrays.toString(token) + ", tokenTimestamp=" + tokenTimestampSeconds + ", identityKey=" + Arrays.toString(identityKey) + ", pinnedTimestampSeconds=" + pinnedTimestampSeconds + ", mute=" + mute + ", wallpaper=" + wallpaper + ", mediaVisibility=" + mediaVisibility + ", tokenSenderTimestamp=" + tokenSenderTimestampSeconds + ", suspended=" + suspended + ", terminated=" + terminated + ", createdAt=" + foundationTimestampSeconds + ", createdBy=" + founder + ", description='" + description + '\'' + ", support=" + support + ", parentGroup=" + parentGroup + ", defaultSubGroup=" + defaultSubGroup + ", parentGroupJid=" + parentGroupJid + ", displayName='" + displayName + '\'' + ", pnJid=" + pnJid + ", shareOwnPn=" + shareOwnPn + ", pnhDuplicateLidThread=" + pnhDuplicateLidThread + ", lidJid=" + lidJid + ", presences=" + presences + ", participantsPreKeys=" + participantsPreKeys + '}';
}
/**
* The constants of this enumerated type describe the various types of trasnfers that can regard a
* chat history sync
*/
@AllArgsConstructor
@Accessors(fluent = true)
public enum EndOfHistoryTransferType implements ProtobufMessage {
/**
* Complete, but more messages remain on the phone
*/
COMPLETE_BUT_MORE_MESSAGES_REMAIN_ON_PRIMARY(0),
/**
* Complete and no more messages remain on the phone
*/
COMPLETE_AND_NO_MORE_MESSAGE_REMAIN_ON_PRIMARY(1);
@Getter
private final int index;
}
/**
* Internal implementation to deserialize messages
*/
public static class ChatBuilder {
public ChatBuilder participants(Collection participants){
this.participants$set = true;
this.participants$value = participants.stream()
.collect(Collectors.toConcurrentMap(GroupParticipant::jid, Function.identity()));
return this;
}
@JsonSetter("participants")
public ChatBuilder participants(Map participants){
this.participants$set = true;
this.participants$value = participants;
return this;
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy