diff --git a/app/src/main/java/org/mercury_im/messenger/ui/chat/ChatViewModel.java b/app/src/main/java/org/mercury_im/messenger/ui/chat/ChatViewModel.java index 388093c..74ceaa1 100644 --- a/app/src/main/java/org/mercury_im/messenger/ui/chat/ChatViewModel.java +++ b/app/src/main/java/org/mercury_im/messenger/ui/chat/ChatViewModel.java @@ -76,13 +76,17 @@ public class ChatViewModel extends ViewModel { // Subscribe messages disposable.add(messageRepository.observeMessages(chat) - .subscribe(ChatViewModel.this.messages::setValue, + .subscribe(messageList -> { + LOGGER.log(Level.INFO, "NEW MESSAGES."); + ChatViewModel.this.messages.setValue(messageList); + }, error -> LOGGER.log(Level.SEVERE, "Error subscribing to messages", error))); } @Override protected void onCleared() { super.onCleared(); + LOGGER.log(Level.INFO, "CLEAR"); disposable.clear(); } @@ -133,6 +137,6 @@ public class ChatViewModel extends ViewModel { public void sendMessage(String body) { disposable.add(messenger.sendMessage(getContact().getValue(), body) - .subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe()); + .subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe()); } } diff --git a/app/src/main/java/org/mercury_im/messenger/ui/chat/MessagesRecyclerViewAdapter.java b/app/src/main/java/org/mercury_im/messenger/ui/chat/MessagesRecyclerViewAdapter.java index 09da304..e9581e0 100644 --- a/app/src/main/java/org/mercury_im/messenger/ui/chat/MessagesRecyclerViewAdapter.java +++ b/app/src/main/java/org/mercury_im/messenger/ui/chat/MessagesRecyclerViewAdapter.java @@ -55,7 +55,7 @@ public class MessagesRecyclerViewAdapter extends RecyclerView.Adapter { + Account account = accounts.get(accountSelector.getSelectedItemPosition()); + String address = contactAddress.getText() != null ? contactAddress.getText().toString() : ""; + disposable.add(messenger.addContact(account.getId(), address) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( AddContactDialogFragment.this::dismiss, e -> { if (e instanceof SmackException.NotLoggedInException || e instanceof SmackException.NotConnectedException) { - contactAddressLayout.setError("Account not connected"); + contactAddressLayout.setError(getString(R.string.error_account_not_connected)); } else if (e instanceof ContactAlreadyAddedException) { - contactAddressLayout.setError("Contact already added"); + contactAddressLayout.setError(getString(R.string.error_contact_already_added)); } else if (e instanceof XmppStringprepException) { - contactAddressLayout.setError("Invalid address"); + contactAddressLayout.setError(getString(R.string.error_invalid_address)); } else { contactAddressLayout.setError(e.getClass().getName()); } } )); - } - }); - } + }); } @Override diff --git a/app/src/main/java/org/mercury_im/messenger/ui/roster/contacts/detail/ContactDetailFragment.java b/app/src/main/java/org/mercury_im/messenger/ui/roster/contacts/detail/ContactDetailFragment.java index 91bc0de..372f7c4 100644 --- a/app/src/main/java/org/mercury_im/messenger/ui/roster/contacts/detail/ContactDetailFragment.java +++ b/app/src/main/java/org/mercury_im/messenger/ui/roster/contacts/detail/ContactDetailFragment.java @@ -74,14 +74,11 @@ public class ContactDetailFragment extends Fragment { ButterKnife.bind(this, view); if (fab != null) { - fab.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - Intent intent = new Intent(getContext(), ChatActivity.class); - intent.putExtra(ChatActivity.EXTRA_JID, viewModel.getContactAddress().getValue()); - intent.putExtra(ChatActivity.EXTRA_ACCOUNT, viewModel.getAccountId().getValue().toString()); - startActivity(intent); - } + fab.setOnClickListener(v -> { + Intent intent = new Intent(getContext(), ChatActivity.class); + intent.putExtra(ChatActivity.EXTRA_JID, viewModel.getContactAddress().getValue()); + intent.putExtra(ChatActivity.EXTRA_ACCOUNT, viewModel.getAccountId().getValue().toString()); + startActivity(intent); }); } diff --git a/app/src/main/res/layout/dialog_add_contact.xml b/app/src/main/res/layout/dialog_add_contact.xml index b54de8a..bc10786 100644 --- a/app/src/main/res/layout/dialog_add_contact.xml +++ b/app/src/main/res/layout/dialog_add_contact.xml @@ -26,7 +26,7 @@ diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a26bc52..033a35d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -132,4 +132,10 @@ Close Chat Copy Remove Contact + Add Contact + Add + Cancel + Account not connected + Contact already added + Invalid address diff --git a/data/src/main/java/org/mercury_im/messenger/data/mapping/MessageMapping.java b/data/src/main/java/org/mercury_im/messenger/data/mapping/MessageMapping.java index e88fb33..7938d64 100644 --- a/data/src/main/java/org/mercury_im/messenger/data/mapping/MessageMapping.java +++ b/data/src/main/java/org/mercury_im/messenger/data/mapping/MessageMapping.java @@ -31,17 +31,15 @@ public class MessageMapping extends AbstractMapping { @Override public MessageModel mapToModel(Message entity, MessageModel model) { + model.setId(entity.getId()); model.setSender(entity.getSender()); model.setRecipient(entity.getRecipient()); model.setTimestamp(entity.getTimestamp()); model.setDirection(entity.getDirection()); - - model.getPayloads().clear(); - for (PayloadContainer payload : entity.getMessagePayloads()) { - MessagePayloadContainerModel payloadModel = messagePayloadContainerMapping.toModel(payload, new MessagePayloadContainerModel()); - payloadModel.setMessage(model); - model.getPayloads().add(payloadModel); - } + model.setBody(entity.getBody()); + model.setStanzaId(entity.getStanzaId()); + model.setOriginId(entity.getOriginId()); + model.setLegacyId(entity.getLegacyStanzaId()); return model; } @@ -53,12 +51,10 @@ public class MessageMapping extends AbstractMapping { entity.setRecipient(model.getRecipient()); entity.setTimestamp(model.getTimestamp()); entity.setDirection(model.getDirection()); - - List payloadContainers = new ArrayList<>(entity.getMessagePayloads().size()); - for (MessagePayloadContainerModel containerModel : model.getPayloads()) { - payloadContainers.add(messagePayloadContainerMapping.toEntity(containerModel)); - } - entity.setMessagePayloads(payloadContainers); + entity.setBody(model.getBody()); + entity.setStanzaId(model.getStanzaId()); + entity.setOriginId(model.getOriginId()); + entity.setLegacyStanzaId(model.getLegacyId()); return entity; } } diff --git a/data/src/main/java/org/mercury_im/messenger/data/model/AbstractMessageModel.java b/data/src/main/java/org/mercury_im/messenger/data/model/AbstractMessageModel.java index 279c07c..4b6fa4e 100644 --- a/data/src/main/java/org/mercury_im/messenger/data/model/AbstractMessageModel.java +++ b/data/src/main/java/org/mercury_im/messenger/data/model/AbstractMessageModel.java @@ -38,8 +38,8 @@ public abstract class AbstractMessageModel implements Persistable { @Convert(MessageDirectionConverter.class) MessageDirection direction; - @OneToMany - Set payloads; + @Column + String body; @Column String legacyId; diff --git a/data/src/main/java/org/mercury_im/messenger/data/repository/XmppMessageRepository.java b/data/src/main/java/org/mercury_im/messenger/data/repository/XmppMessageRepository.java index 9ef7259..640051d 100644 --- a/data/src/main/java/org/mercury_im/messenger/data/repository/XmppMessageRepository.java +++ b/data/src/main/java/org/mercury_im/messenger/data/repository/XmppMessageRepository.java @@ -8,8 +8,6 @@ import org.mercury_im.messenger.data.model.DirectMessagesRelation; import org.mercury_im.messenger.data.model.GroupChatModel; import org.mercury_im.messenger.data.model.GroupMessagesRelation; import org.mercury_im.messenger.data.model.MessageModel; -import org.mercury_im.messenger.data.model.MessagePayloadContainerModel; -import org.mercury_im.messenger.data.model.MessagePayloadModel; import org.mercury_im.messenger.data.repository.dao.DirectChatDao; import org.mercury_im.messenger.data.repository.dao.GroupChatDao; import org.mercury_im.messenger.data.repository.dao.MessageDao; @@ -92,6 +90,7 @@ public class XmppMessageRepository .from(MessageModel.class) .join(DirectMessagesRelation.class) .on(DirectMessagesRelation.MESSAGE_ID.eq(MessageModel.ID)) + .where(DirectMessagesRelation.CHAT_ID.eq(chat.getId())) .get().observableResult() .map(ResultDelegate::toList) .map(this::messageModelsToEntities) @@ -117,11 +116,7 @@ public class XmppMessageRepository public Observable> findMessagesWithBody(String body) { return data().select(MessageModel.class) .from(MessageModel.class) - .join(MessagePayloadContainerModel.class) - .on(MessagePayloadContainerModel.MESSAGE_ID.eq(MessageModel.ID)) - .join(MessagePayloadModel.class) - .on(MessagePayloadModel.PAYLOAD_CONTAINER_ID.eq(MessagePayloadContainerModel.ID)) - .where(MessagePayloadModel.BODY.eq(body)) + .where(MessageModel.BODY.eq(body)) .get().observableResult() .map(ResultDelegate::toList) .map(this::messageModelsToEntities) @@ -136,12 +131,8 @@ public class XmppMessageRepository .from(MessageModel.class) .join(DirectMessagesRelation.class) .on(DirectMessagesRelation.MESSAGE_ID.eq(MessageModel.ID)) - .join(MessagePayloadContainerModel.class) - .on(MessagePayloadContainerModel.MESSAGE_ID.eq(MessageModel.ID)) - .join(MessagePayloadModel.class) - .on(MessagePayloadModel.PAYLOAD_CONTAINER_ID.eq(MessagePayloadContainerModel.ID)) - .where(MessagePayloadModel.BODY.eq(body)) + .where(MessageModel.BODY.eq(body)) .and(DirectMessagesRelation.CHAT_ID.eq(chat.getId())) .get().observableResult() .map(ResultDelegate::toList) @@ -157,12 +148,8 @@ public class XmppMessageRepository .from(MessageModel.class) .join(GroupMessagesRelation.class) .on(GroupMessagesRelation.MESSAGE_ID.eq(MessageModel.ID)) - .join(MessagePayloadContainerModel.class) - .on(MessagePayloadContainerModel.MESSAGE_ID.eq(MessageModel.ID)) - .join(MessagePayloadModel.class) - .on(MessagePayloadModel.PAYLOAD_CONTAINER_ID.eq(MessagePayloadContainerModel.ID)) - .where(MessagePayloadModel.BODY.eq(body)) + .where(MessageModel.BODY.eq(body)) .and(GroupMessagesRelation.CHAT_ID.eq(chat.getId())) .get().observableResult() .map(ResultDelegate::toList) @@ -174,15 +161,6 @@ public class XmppMessageRepository @Override public Single upsertMessage(DirectChat chat, Message message) { return null; - /* - return data().select(DirectMessagesRelation.class) - .where(DirectMessagesRelation.CHAT_ID.eq(chat.getId())) - .and(DirectMessagesRelation.MESSAGE_ID.eq(message.getId())) - .get().maybe() - .switchIfEmpty(Single.just(message) - .map(messageMapping::toEntity) - .flatMap(messageModel -> ) - */ } @Override diff --git a/domain/src/main/java/org/mercury_im/messenger/store/MercuryMessageStore.java b/domain/src/main/java/org/mercury_im/messenger/store/MercuryMessageStore.java new file mode 100644 index 0000000..99c4580 --- /dev/null +++ b/domain/src/main/java/org/mercury_im/messenger/store/MercuryMessageStore.java @@ -0,0 +1,81 @@ +package org.mercury_im.messenger.store; + +import org.jivesoftware.smack.chat2.IncomingChatMessageListener; +import org.jivesoftware.smack.chat2.OutgoingChatMessageListener; +import org.jivesoftware.smack.packet.MessageBuilder; +import org.jivesoftware.smackx.delay.packet.DelayInformation; +import org.jxmpp.jid.EntityBareJid; +import org.mercury_im.messenger.data.repository.DirectChatRepository; +import org.mercury_im.messenger.data.repository.MessageRepository; +import org.mercury_im.messenger.data.repository.PeerRepository; +import org.mercury_im.messenger.entity.Account; +import org.mercury_im.messenger.entity.message.Message; +import org.mercury_im.messenger.entity.message.MessageDirection; + +import java.util.Date; +import java.util.logging.Level; +import java.util.logging.Logger; + +import io.reactivex.disposables.CompositeDisposable; +import io.reactivex.schedulers.Schedulers; + +public class MercuryMessageStore implements IncomingChatMessageListener, OutgoingChatMessageListener { + + private static final Logger LOGGER = Logger.getLogger(MercuryMessageStore.class.getName()); + + private final MessageRepository messageRepository; + private final DirectChatRepository directChatRepository; + private final PeerRepository peerRepository; + + private Account account; + + private CompositeDisposable disposable = new CompositeDisposable(); + + public MercuryMessageStore(Account account, + PeerRepository peerRepository, + DirectChatRepository directChatRepository, + MessageRepository messageRepository) { + this.account = account; + this.peerRepository = peerRepository; + this.directChatRepository = directChatRepository; + this.messageRepository = messageRepository; + } + + @Override + public void newIncomingMessage(EntityBareJid from, + org.jivesoftware.smack.packet.Message smackMessage, + org.jivesoftware.smack.chat2.Chat smackChat) { + Message message = new Message(); + message.setDirection(MessageDirection.incoming); + DelayInformation delayInformation = DelayInformation.from(smackMessage); + message.setTimestamp(delayInformation != null ? delayInformation.getStamp() : new Date()); + message.setSender(from.asEntityBareJidString()); + message.setRecipient(smackMessage.getTo().asBareJid().toString()); + if (smackMessage.getBody() != null) { + message.setBody(smackMessage.getBody()); + } + disposable.add(peerRepository.getOrCreatePeer(account, from.asEntityBareJidString()) + .flatMap(directChatRepository::getOrCreateChatWithPeer) + .flatMap(chat -> messageRepository.insertMessage(chat, message)) + .subscribeOn(Schedulers.io()) + .subscribe(m -> LOGGER.log(Level.INFO, "Message written"), e -> LOGGER.log(Level.SEVERE, "Error: ", e))); + } + + @Override + public void newOutgoingMessage(EntityBareJid to, + MessageBuilder smackMessage, + org.jivesoftware.smack.chat2.Chat smackChat) { + Message message = new Message(); + message.setDirection(MessageDirection.outgoing); + message.setTimestamp(new Date()); + message.setSender(account.getAddress()); + message.setRecipient(to.asBareJid().toString()); + if (smackMessage.getBody() != null) { + message.setBody(smackMessage.getBody().getMessage()); + } + disposable.add(peerRepository.getOrCreatePeer(account, to.asEntityBareJidString()) + .flatMap(directChatRepository::getOrCreateChatWithPeer) + .flatMap(chat -> messageRepository.insertMessage(chat, message)) + .subscribe(m -> LOGGER.log(Level.INFO, "Message written"), e -> LOGGER.log(Level.SEVERE, "Error: ", e))); + } +} diff --git a/domain/src/main/java/org/mercury_im/messenger/store/MercuryRosterStore.java b/domain/src/main/java/org/mercury_im/messenger/store/MercuryRosterStore.java index fb1025c..2d9da68 100644 --- a/domain/src/main/java/org/mercury_im/messenger/store/MercuryRosterStore.java +++ b/domain/src/main/java/org/mercury_im/messenger/store/MercuryRosterStore.java @@ -198,8 +198,11 @@ public class MercuryRosterStore implements RosterStore { } item.setApproved(contactModel.isSubscriptionApproved()); item.setSubscriptionPending(contactModel.isSubscriptionPending()); - for (String groupName : contactModel.getGroupNames()) { - item.addGroupName(groupName); + List groupNames = contactModel.getGroupNames(); + if (groupNames != null) { + for (String groupName : groupNames) { + item.addGroupName(groupName); + } } return item; } diff --git a/domain/src/main/java/org/mercury_im/messenger/xmpp/MercuryConnectionManager.java b/domain/src/main/java/org/mercury_im/messenger/xmpp/MercuryConnectionManager.java index cca611a..c8914d0 100644 --- a/domain/src/main/java/org/mercury_im/messenger/xmpp/MercuryConnectionManager.java +++ b/domain/src/main/java/org/mercury_im/messenger/xmpp/MercuryConnectionManager.java @@ -1,10 +1,15 @@ package org.mercury_im.messenger.xmpp; +import org.jivesoftware.smack.chat2.ChatManager; import org.jivesoftware.smackx.caps.EntityCapsManager; import org.mercury_im.messenger.data.repository.AccountRepository; +import org.mercury_im.messenger.data.repository.DirectChatRepository; +import org.mercury_im.messenger.data.repository.MessageRepository; +import org.mercury_im.messenger.data.repository.PeerRepository; import org.mercury_im.messenger.data.repository.Repositories; import org.mercury_im.messenger.entity.Account; import org.mercury_im.messenger.store.MercuryEntityCapsStore; +import org.mercury_im.messenger.store.MercuryMessageStore; import org.mercury_im.messenger.usecase.RosterStoreBinder; import org.mercury_im.messenger.util.Optional; import org.mercury_im.messenger.xmpp.state.ConnectionPoolState; @@ -36,6 +41,9 @@ public class MercuryConnectionManager { private final AccountRepository accountRepository; private final RosterStoreBinder rosterStoreBinder; private final MercuryEntityCapsStore entityCapsStore; + private final PeerRepository peerRepository; + private final DirectChatRepository directChatRepository; + private final MessageRepository messageRepository; private final Map connectionsMap = new ConcurrentHashMap<>(); private final Map connectionDisposables = new ConcurrentHashMap<>(); @@ -55,6 +63,9 @@ public class MercuryConnectionManager { this.accountRepository = repositories.getAccountRepository(); this.rosterStoreBinder = rosterStoreBinder; this.entityCapsStore = entityCapsStore; + this.peerRepository = repositories.getPeerRepository(); + this.directChatRepository = repositories.getDirectChatRepository(); + this.messageRepository = repositories.getMessageRepository(); EntityCapsManager.setPersistentCache(entityCapsStore); start(); @@ -121,6 +132,15 @@ public class MercuryConnectionManager { public void bindConnection(MercuryConnection connection) { rosterStoreBinder.setRosterStoreOn(connection); + accountRepository.getAccount(connection.getAccountId()) + .subscribeOn(Schedulers.io()) + .subscribe(account -> { + MercuryMessageStore mercuryMessageStore = new MercuryMessageStore(account, peerRepository, directChatRepository, messageRepository); + ChatManager chatManager = ChatManager.getInstanceFor(connection.getConnection()); + chatManager.addIncomingListener(mercuryMessageStore); + chatManager.addOutgoingListener(mercuryMessageStore); + }); + } private void handleOptionalAccountChangedEvent(MercuryConnection connection, Optional event) { diff --git a/domain/src/main/java/org/mercury_im/messenger/xmpp/XmppDirectMessageCenter.java b/domain/src/main/java/org/mercury_im/messenger/xmpp/XmppDirectMessageCenter.java index 7814046..d89e48b 100644 --- a/domain/src/main/java/org/mercury_im/messenger/xmpp/XmppDirectMessageCenter.java +++ b/domain/src/main/java/org/mercury_im/messenger/xmpp/XmppDirectMessageCenter.java @@ -81,12 +81,8 @@ public class XmppDirectMessageCenter String originId = OriginIdElement.addTo(messageBuilder).getId(); String legacyStanzaId = messageBuilder.getStanzaId(); - - MessageMetadata metadata = new MessageMetadata(); - metadata.setLegacyStanzaId(legacyStanzaId); - metadata.setOriginId(originId); - - message.setMetadata(metadata); + message.setLegacyStanzaId(legacyStanzaId); + message.setOriginId(originId); Chat smackChat = chatManager.chatWith(peerAddress); return messageRepository.insertMessage(chat, message) diff --git a/entity/src/main/java/org/mercury_im/messenger/entity/chat/DirectChat.java b/entity/src/main/java/org/mercury_im/messenger/entity/chat/DirectChat.java index 533a111..7a633da 100644 --- a/entity/src/main/java/org/mercury_im/messenger/entity/chat/DirectChat.java +++ b/entity/src/main/java/org/mercury_im/messenger/entity/chat/DirectChat.java @@ -12,4 +12,8 @@ import lombok.EqualsAndHashCode; @EqualsAndHashCode(callSuper = true) public class DirectChat extends Chat { Peer peer; + + public DirectChat() { + super(); + } } diff --git a/entity/src/main/java/org/mercury_im/messenger/entity/message/Message.java b/entity/src/main/java/org/mercury_im/messenger/entity/message/Message.java index 5120582..a4a2846 100644 --- a/entity/src/main/java/org/mercury_im/messenger/entity/message/Message.java +++ b/entity/src/main/java/org/mercury_im/messenger/entity/message/Message.java @@ -13,11 +13,17 @@ public class Message { String recipient; Date timestamp; MessageDirection direction; - List messagePayloads; + String body; MessageDeliveryState deliveryState; - MessageMetadata metadata; + String legacyStanzaId; + String originId; + String stanzaId; public boolean isIncoming() { return getDirection() == MessageDirection.incoming; } + + public Message() { + this.id = UUID.randomUUID(); + } } diff --git a/entity/src/main/java/org/mercury_im/messenger/entity/message/MessageMetadata.java b/entity/src/main/java/org/mercury_im/messenger/entity/message/MessageMetadata.java index b18b7c9..f24badf 100644 --- a/entity/src/main/java/org/mercury_im/messenger/entity/message/MessageMetadata.java +++ b/entity/src/main/java/org/mercury_im/messenger/entity/message/MessageMetadata.java @@ -9,7 +9,5 @@ import lombok.Data; @Data public class MessageMetadata { private long id; - private String legacyStanzaId; - private String originId; - private String stanzaId; + } \ No newline at end of file diff --git a/libs/Smack b/libs/Smack index e2a196f..219efa5 160000 --- a/libs/Smack +++ b/libs/Smack @@ -1 +1 @@ -Subproject commit e2a196fa52222a6816dd850ee8380335a90f7850 +Subproject commit 219efa564c222b7add06870bb51ba85dfe353cc7