Work on contact list - wip!

This commit is contained in:
Paul Schaub 2019-12-21 05:34:19 +01:00
parent ff04832614
commit 687288e697
Signed by: vanitasvitae
GPG Key ID: 62BEE9264BF17311
25 changed files with 420 additions and 190 deletions

View File

@ -18,8 +18,11 @@ import java.util.List;
import javax.inject.Inject;
import io.reactivex.Completable;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.functions.Consumer;
import io.reactivex.schedulers.Schedulers;
public class ChatViewModel extends ViewModel {
@ -85,22 +88,12 @@ public class ChatViewModel extends ViewModel {
}
public void queryTextChanged(String query) {
/*
if (query.isEmpty()) {
disposable.add(messageRepository.getAllMessagesOfChat(accountId, jid)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe((Consumer<List<MessageModel>>)
messages -> ChatViewModel.this.messages.setValue(messages)));
}
disposable.add(messageRepository.findMessageByQuery(accountId, jid, query)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe((Consumer<List<MessageModel>>) o -> {
messages.setValue(o);
}));
Observable<List<Message>> observable = query.isEmpty() ?
messageRepository.observeMessages(chat.getValue()) :
messageRepository.findMessagesWithBody(chat.getValue(), query);
*/
disposable.add(observable.subscribe(messages ->
ChatViewModel.this.messages.setValue(messages)));
}
public Completable requestMamMessages() {

View File

@ -1,6 +1,6 @@
package org.mercury_im.messenger.ui.chat;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -20,7 +20,7 @@ import java.util.List;
public class MessagesRecyclerViewAdapter extends RecyclerView.Adapter<MessagesRecyclerViewAdapter.MessageViewHolder> {
private List<Message> messages = new ArrayList<>();
private SparseArray<Boolean> checkedItems = new SparseArray<>();
private SparseBooleanArray checkedItems = new SparseBooleanArray();
public MessagesRecyclerViewAdapter() {
@ -50,22 +50,22 @@ public class MessagesRecyclerViewAdapter extends RecyclerView.Adapter<MessagesRe
public void onBindViewHolder(@NonNull MessageViewHolder holder, int position) {
Message message = messages.get(position);
MessageBackgroundDrawable background = getBackgroundDrawable(position);
// if (message.isIncoming()) {
if (message.isIncoming()) {
holder.body.setBackgroundResource(background.getIncomingDrawable());
// } else {
// holder.body.setBackgroundResource(background.getOutgoingDrawable());
// }
} else {
holder.body.setBackgroundResource(background.getOutgoingDrawable());
}
holder.body.setText(((TextPayload) message.getMessagePayloads().get(0).getMessageContents().get(0)).getBody());
holder.body.requestLayout();
}
@Override
public int getItemViewType(int position) {
// if (messages.get(position).isIncoming()) {
if (messages.get(position).isIncoming()) {
return R.layout.view_message_text_in;
// } else {
// return R.layout.view_message_text_out;
// }
} else {
return R.layout.view_message_text_out;
}
}
@Override
@ -89,22 +89,22 @@ public class MessagesRecyclerViewAdapter extends RecyclerView.Adapter<MessagesRe
Message predecessor = pos != 0 ? messages.get(pos - 1) : null;
Message successor = pos != messages.size() - 1 ? messages.get(pos + 1) : null;
// if (predecessor == null || predecessor.isIncoming() != subject.isIncoming()) {
// if (successor == null || successor.isIncoming() != subject.isIncoming()) {
if (predecessor == null || predecessor.isIncoming() != subject.isIncoming()) {
if (successor == null || successor.isIncoming() != subject.isIncoming()) {
// This is a single message
return MessageBackgroundDrawable.SINGLE;
// } else {
} else {
// This is the first message of a group
// return MessageBackgroundDrawable.FIRST;
// }
// } else {
// if (successor == null || successor.isIncoming() != subject.isIncoming()) {
return MessageBackgroundDrawable.FIRST;
}
} else {
if (successor == null || successor.isIncoming() != subject.isIncoming()) {
// This is the last message of a group
// return MessageBackgroundDrawable.LAST;
// } else {
return MessageBackgroundDrawable.LAST;
} else {
// This message is in the middle of a group
// return MessageBackgroundDrawable.MID;
// }
// }
return MessageBackgroundDrawable.MID;
}
}
}
}

View File

@ -23,6 +23,8 @@ import butterknife.ButterKnife;
import org.mercury_im.messenger.Messenger;
import org.mercury_im.messenger.R;
import java.util.ArrayList;
public class ChatListFragment extends Fragment {
private ChatListViewModel viewModel;
@ -63,10 +65,6 @@ public class ChatListFragment extends Fragment {
super.onAttach(context);
viewModel = new ViewModelProvider(getActivity()).get(ChatListViewModel.class);
viewModel.getChats().observe(this, chatModels -> {
if (chatModels == null) {
Log.d(Messenger.TAG, "Displaying null chats");
return;
}
Log.d(Messenger.TAG, "Displaying " + chatModels.size() + " chats");
recyclerViewAdapter.setModels(chatModels);
});

View File

@ -8,6 +8,7 @@ import org.mercury_im.messenger.MercuryImApplication;
import org.mercury_im.messenger.data.repository.DirectChatRepository;
import org.mercury_im.messenger.entity.chat.DirectChat;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
@ -21,7 +22,7 @@ public class ChatListViewModel extends ViewModel {
private CompositeDisposable disposable = new CompositeDisposable();
private final MutableLiveData<List<DirectChat>> chats = new MutableLiveData<>();
private final MutableLiveData<List<DirectChat>> chats = new MutableLiveData<>(new ArrayList<>());
public ChatListViewModel() {
MercuryImApplication.getApplication().getAppComponent().inject(this);

View File

@ -31,10 +31,7 @@ public class ContactListViewModel extends ViewModel {
Log.d("ContactListViewModel", "Start observing database");
// Subscribe to changes to the contacts table and update the LiveData object for the UI.
compositeDisposable.add(xmppContactRepository.observeAllPeers()
.subscribe(list -> {
Log.d("ContactListViewModel", "Room changed contacts: " + list.size());
rosterEntryList.setValue(list);
}));
.subscribe(rosterEntryList::setValue));
}
@Override

View File

@ -0,0 +1,44 @@
package org.mercury_im.messenger.data.converter;
import org.mercury_im.messenger.entity.message.MessageDirection;
import io.requery.Converter;
public class MessageDirectionConverter implements Converter<MessageDirection, Integer> {
@Override
public Class<MessageDirection> getMappedType() {
return MessageDirection.class;
}
@Override
public Class<Integer> getPersistedType() {
return Integer.class;
}
@Override
public Integer getPersistedSize() {
return null;
}
@Override
public Integer convertToPersisted(MessageDirection value) {
switch (value) {
case outgoing:
return 0;
case incoming:
return 1;
default: return 1;
}
}
@Override
public MessageDirection convertToMapped(Class<? extends MessageDirection> type, Integer value) {
switch (value) {
case 0:
return MessageDirection.outgoing;
case 1:
return MessageDirection.incoming;
default: return MessageDirection.incoming;
}
}
}

View File

@ -1,6 +1,6 @@
package org.mercury_im.messenger.data.converter;
import org.mercury_im.messenger.data.enums.SubscriptionDirection;
import org.mercury_im.messenger.entity.contact.SubscriptionDirection;
import io.requery.Converter;

View File

@ -35,6 +35,7 @@ public class MessageMapping extends AbstractMapping<Message, MessageModel> {
model.setSender(entity.getSender());
model.setRecipient(entity.getRecipient());
model.setTimestamp(entity.getTimestamp());
model.setDirection(entity.getDirection());
model.getPayloads().clear();
for (PayloadContainer payload : entity.getMessagePayloads()) {
@ -52,6 +53,7 @@ public class MessageMapping extends AbstractMapping<Message, MessageModel> {
entity.setSender(model.getSender());
entity.setRecipient(model.getRecipient());
entity.setTimestamp(model.getTimestamp());
entity.setDirection(model.getDirection());
List<PayloadContainer> payloadContainers = new ArrayList<>(entity.getMessagePayloads().size());
for (MessagePayloadContainerModel containerModel : model.getPayloads()) {

View File

@ -1,6 +1,5 @@
package org.mercury_im.messenger.data.mapping;
import org.mercury_im.messenger.data.enums.SubscriptionDirection;
import org.mercury_im.messenger.data.model.PeerModel;
import org.mercury_im.messenger.entity.contact.IPeer;
import org.mercury_im.messenger.entity.contact.Peer;
@ -32,7 +31,9 @@ public class PeerMapping extends AbstractMapping<Peer, PeerModel> {
model.setAddress(entity.getAddress());
model.setName(entity.getName());
// TODO: sub direction
model.setSubscriptionDirection(entity.getSubscriptionDirection());
model.setSubscriptionPending(entity.isSubscriptionPending());
model.setSubscriptionPreApproved(entity.isSubscriptionApproved());
return model;
}
@ -43,75 +44,10 @@ public class PeerMapping extends AbstractMapping<Peer, PeerModel> {
entity.setAddress(model.getAddress());
entity.setId(model.getId());
// TODO: Sub direction
entity.setSubscriptionDirection(model.getSubscriptionDirection());
entity.setSubscriptionPending(model.isSubscriptionPending());
entity.setSubscriptionApproved(model.isSubscriptionPreApproved());
return entity;
}
private void setSubscriptionDirectionInModel(PeerModel model, Peer entity) {
switch (entity.getSubscriptionMode()) {
case NONE:
model.setSubscriptionDirection(SubscriptionDirection.none);
model.setSubscriptionPreApproved(false);
model.setSubscriptionPending(false);
break;
case NONE_PREAPPROVED:
model.setSubscriptionDirection(SubscriptionDirection.none);
model.setSubscriptionPreApproved(true);
model.setSubscriptionPending(false);
break;
case TO_THEM_PENDING:
model.setSubscriptionDirection(SubscriptionDirection.to);
model.setSubscriptionPending(true);
model.setSubscriptionPreApproved(false);
break;
case TO_THEM_PENDING_PREAPPROVED:
model.setSubscriptionDirection(SubscriptionDirection.to);
model.setSubscriptionPending(true);
model.setSubscriptionPreApproved(true);
break;
case TO_THEM_ACCEPTED:
model.setSubscriptionDirection(SubscriptionDirection.to);
model.setSubscriptionPending(false);
model.setSubscriptionPreApproved(false);
break;
case TO_THEM_ACCEPTED_PREAPPROVED:
model.setSubscriptionDirection(SubscriptionDirection.to);
model.setSubscriptionPending(false);
model.setSubscriptionPreApproved(true);
break;
case FROM_THEM_PENDING:
model.setSubscriptionDirection(SubscriptionDirection.from);
model.setSubscriptionPending(true);
model.setSubscriptionPreApproved(false);
break;
case FROM_THEM_ACCEPTED:
model.setSubscriptionDirection(SubscriptionDirection.from);
model.setSubscriptionPending(false);
model.setSubscriptionPreApproved(false);
break;
case BIDIRECTIONAL:
model.setSubscriptionDirection(SubscriptionDirection.both);
model.setSubscriptionPending(false);
model.setSubscriptionPreApproved(false);
break;
}
}
private void setSubscriptionDirectionInEntity(Peer entity, PeerModel model) {
switch (model.getSubscriptionDirection()) {
case none:
break;
case to:
break;
case from:
break;
case both:
break;
case remove:
break;
}
}
}

View File

@ -1,9 +1,13 @@
package org.mercury_im.messenger.data.model;
import org.mercury_im.messenger.data.converter.MessageDirectionConverter;
import org.mercury_im.messenger.entity.message.MessageDirection;
import java.util.Date;
import java.util.Set;
import io.requery.Column;
import io.requery.Convert;
import io.requery.Entity;
import io.requery.Generated;
import io.requery.Key;
@ -27,6 +31,10 @@ public abstract class AbstractMessageModel implements Persistable {
@Column(name = "\"timestamp\"", nullable = false)
Date timestamp;
@Column(nullable = false)
@Convert(MessageDirectionConverter.class)
MessageDirection direction;
@OneToMany
Set<MessagePayloadContainerModel> payloads;

View File

@ -1,7 +1,7 @@
package org.mercury_im.messenger.data.model;
import org.mercury_im.messenger.data.converter.SubscriptionDirectionConverter;
import org.mercury_im.messenger.data.enums.SubscriptionDirection;
import org.mercury_im.messenger.entity.contact.SubscriptionDirection;
import io.requery.Column;
import io.requery.Convert;

View File

@ -180,7 +180,7 @@ public class XmppMessageRepository
.and(DirectMessagesRelation.MESSAGE_ID.eq(message.getId()))
.get().maybe()
.switchIfEmpty(Single.just(message)
.map(messageMapping::toModel)
.map(messageMapping::toEntity)
.flatMap(messageModel -> )
*/
}

View File

@ -2,6 +2,7 @@ package org.mercury_im.messenger.data.repository;
import org.mercury_im.messenger.data.mapping.PeerMapping;
import org.mercury_im.messenger.data.model.PeerModel;
import org.mercury_im.messenger.entity.contact.SubscriptionDirection;
import org.mercury_im.messenger.util.Optional;
import org.mercury_im.messenger.entity.Account;
import org.mercury_im.messenger.entity.contact.IPeer;
@ -9,6 +10,8 @@ import org.mercury_im.messenger.entity.contact.Peer;
import org.mercury_im.messenger.util.ThreadUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import javax.inject.Inject;
@ -130,6 +133,25 @@ public class XmppPeerRepository
.observeOn(observerScheduler());
}
@Override
public Observable<List<Peer>> observeAllContactsOfAccount(long accountId) {
return data().select(PeerModel.class)
.where(PeerModel.ACCOUNT_ID.eq(accountId))
.and(PeerModel.SUBSCRIPTION_DIRECTION.in(
Arrays.asList(SubscriptionDirection.both, SubscriptionDirection.to)))
.get().observableResult()
.map(ResultDelegate::toList)
.map(peerModels -> {
List<Peer> peerEntities = new ArrayList<>(peerModels.size());
for (PeerModel model : peerModels) {
peerEntities.add(peerMapping.toEntity(model));
}
return peerEntities;
})
.subscribeOn(subscriberScheduler())
.observeOn(observerScheduler());
}
@Override
public Single<Peer> updatePeer(Peer peer) {
// In order to update, we fetch the model, update it and write it back.
@ -170,4 +192,9 @@ public class XmppPeerRepository
.subscribeOn(subscriberScheduler())
.observeOn(observerScheduler());
}
@Override
public Completable deletePeer(long accountId, String address) {
return null;
}
}

View File

@ -6,7 +6,6 @@ import org.mercury_im.messenger.data.model.AccountModel;
import org.mercury_im.messenger.data.model.PeerModel;
import org.mercury_im.messenger.entity.contact.IPeer;
import org.mercury_im.messenger.entity.contact.Peer;
import org.mercury_im.messenger.entity.contact.SubscriptionMode;
import javax.inject.Inject;
@ -25,7 +24,7 @@ public class PeerMappingTest {
PEER_GORDO.setId(1);
PEER_GORDO.setAddress("gordo@big.joe");
PEER_GORDO.setName("Gordo");
PEER_GORDO.setSubscriptionMode(SubscriptionMode.TO_THEM_ACCEPTED_PREAPPROVED);
PEER_GORDO.setSubscriptionDirection(SubscriptionMode.TO_THEM_ACCEPTED_PREAPPROVED);
}
public PeerMappingTest() {

View File

@ -47,7 +47,7 @@ public class AccountRepositoryTest {
Account a1 = new IAccount();
a1.setAddress("a1@example.com");
a1.setAuthentication(new PasswordAuthentication("a1a1a1"));
a1.setPassword("a1a1a1");
a1.setEnabled(true);
d.add(accountRepository.insertAccount(a1).subscribe());
@ -57,7 +57,7 @@ public class AccountRepositoryTest {
Account a2 = new IAccount();
a2.setAddress("a2@example.com");
a2.setAuthentication(new PasswordAuthentication("a2a2a2"));
a2.setPassword("a2a2a2");
a2.setEnabled(false);
d.add(accountRepository.insertAccount(a2).subscribe());
@ -66,7 +66,7 @@ public class AccountRepositoryTest {
Account a3 = new IAccount();
a3.setAddress("a3@example.com");
a3.setAuthentication(new PasswordAuthentication("a3a3a3"));
a3.setPassword("a3a3a3");
a3.setEnabled(false);
d.add(accountRepository.insertAccount(a3).subscribe());

View File

@ -2,9 +2,11 @@ package org.mercury_im.messenger;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.roster.Roster;
import org.jivesoftware.smackx.csi.ClientStateIndicationManager;
import org.mercury_im.messenger.data.repository.Repositories;
import org.mercury_im.messenger.entity.Account;
import org.mercury_im.messenger.store.MercuryRosterStore;
import org.mercury_im.messenger.usecase.AddAccount;
import org.mercury_im.messenger.xmpp.MercuryConnection;
@ -30,6 +32,13 @@ public class Messenger implements ClientStateListener {
public void addConnection(MercuryConnection connection) {
connections.put(connection.getAccount().getId(), connection);
initRosterStore(connection);
}
private void initRosterStore(MercuryConnection connection) {
Roster.getInstanceFor(connection.getConnection())
.setRosterStore(new MercuryRosterStore(connection.getAccount(),
repositories.getPeerRepository(), repositories.getAccountRepository()));
}
public MercuryConnection getConnection(Account account) {

View File

@ -41,9 +41,17 @@ public interface PeerRepository {
Observable<List<Peer>> observeAllPeers();
default Observable<List<Peer>> observeAllContactsOfAccount(Account account) {
return observeAllContactsOfAccount(account.getId());
}
Observable<List<Peer>> observeAllContactsOfAccount(long accountId);
Single<Peer> updatePeer(Peer Peer);
Single<Peer> upsertPeer(Peer Peer);
Completable deletePeer(Peer Peer);
Completable deletePeer(long accountId, String address);
}

View File

@ -0,0 +1,207 @@
package org.mercury_im.messenger.store;
import org.jivesoftware.smack.roster.packet.RosterPacket;
import org.jivesoftware.smack.roster.rosterstore.RosterStore;
import org.jxmpp.jid.Jid;
import org.jxmpp.jid.impl.JidCreate;
import org.mercury_im.messenger.data.repository.AccountRepository;
import org.mercury_im.messenger.data.repository.PeerRepository;
import org.mercury_im.messenger.entity.Account;
import org.mercury_im.messenger.entity.contact.IPeer;
import org.mercury_im.messenger.entity.contact.Peer;
import org.mercury_im.messenger.entity.contact.SubscriptionDirection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.schedulers.Schedulers;
public class MercuryRosterStore implements RosterStore {
private static final Logger LOGGER = Logger.getLogger(RosterStore.class.getName());
private final PeerRepository peerRepository;
private final AccountRepository accountRepository;
private Account account;
private final CompositeDisposable disposable = new CompositeDisposable();
private final Map<String, RosterPacket.Item> itemMap = new HashMap<>();
private String rosterVersion;
public MercuryRosterStore(Account account, PeerRepository rosterRepository, AccountRepository accountRepository) {
this.account = account;
this.peerRepository = rosterRepository;
this.accountRepository = accountRepository;
}
public void subscribe() {
disposable.add(peerRepository.observeAllContactsOfAccount(account)
.observeOn(Schedulers.computation())
.subscribe(contactsList -> {
itemMap.clear();
for (Peer contactModel : contactsList) {
itemMap.put(contactModel.getAddress(), fromEntity(contactModel));
LOGGER.log(Level.INFO, "Populate itemMap with " + contactsList.size() + " items");
}
},
error -> LOGGER.log(Level.WARNING, "An error occurred while updating roster cache", error)));
/*
disposable.add(peerRepository.getRosterVersion(account)
.observeOn(Schedulers.computation())
.subscribe(
result -> setRosterVersion(result),
error -> LOGGER.log(Level.WARNING, "An error occurred updating cached roster version", error)));
*/
}
public void unsubscribe() {
disposable.dispose();
}
private void setRosterVersion(String rosterVersion) {
this.rosterVersion = rosterVersion;
}
@Override
public List<RosterPacket.Item> getEntries() {
return new ArrayList<>(itemMap.values());
}
@Override
public RosterPacket.Item getEntry(Jid bareJid) {
return itemMap.get(bareJid);
}
@Override
public String getRosterVersion() {
return rosterVersion != null ? rosterVersion : "";
}
@Override
public boolean addEntry(RosterPacket.Item item, String version) {
LOGGER.log(Level.INFO, "Add entry " + item.toXML().toString());
// Update database
Peer contact = toEntity(item);
disposable.add(peerRepository.upsertPeer(contact)
.subscribe(
success -> LOGGER.log(Level.FINE, "Upserted contact model " + success + " successfully"),
error -> LOGGER.log(Level.WARNING, "An error occurred upserting contact " + contact, error)
));
/*
disposable.add(peerRepository.updateRosterVersion(account, version)
.subscribe(
success -> LOGGER.log(Level.FINE, "Upserted roster version to " + rosterVersion + " successfully"),
error -> LOGGER.log(Level.WARNING, "An error occurred upserting roster version", error)
));
*/
return true;
}
@Override
public boolean resetEntries(Collection<RosterPacket.Item> items, String version) {
LOGGER.log(Level.INFO, "Reset Entries: " + Arrays.toString(items.toArray()));
// Update database
// TODO: Delete other contacts
for (RosterPacket.Item item : items) {
Peer model = toEntity(item);
disposable.add(peerRepository.upsertPeer(model)
.subscribe(
success -> LOGGER.log(Level.FINE, "Upserted contact model " + success + " successfully"),
error -> LOGGER.log(Level.WARNING, "An error occurred upserting contact " + model, error)
));
}
/*
disposable.add(peerRepository.updateRosterVersion(account, version)
.subscribe(
success -> LOGGER.log(Level.FINE, "Upserted roster version to " + rosterVersion + " successfully"),
error -> LOGGER.log(Level.WARNING, "An error occurred upserting roster version", error)
));
*/
return true;
}
@Override
public boolean removeEntry(Jid bareJid, String version) {
LOGGER.log(Level.INFO, "Remove entry " + bareJid.toString());
disposable.add(peerRepository.deletePeer(account.getId(), bareJid.asEntityBareJidOrThrow().asEntityBareJidString())
.subscribe(
() -> LOGGER.log(Level.FINE, "Deletion of contact " + bareJid.toString() + " successful"),
error -> LOGGER.log(Level.WARNING, "An error occurred deleting contact " + bareJid.toString(), error)
));
/*
disposable.add(peerRepository.updateRosterVersion(account, version)
.subscribe(
success -> LOGGER.log(Level.FINE, "Upserted roster version to " + rosterVersion + " successfully"),
error -> LOGGER.log(Level.WARNING, "An error occurred upserting roster version", error)
));
*/
return true;
}
@Override
public void resetStore() {
LOGGER.log(Level.INFO, "Reset Store");
/*
disposable.add(peerRepository.deleteAllContactsOfAccount(account)
.subscribe(
success -> LOGGER.log(Level.FINE, "Successfully reset store."),
error -> LOGGER.log(Level.WARNING, "An error occurred resetting store", error)
));
disposable.add(peerRepository.updateRosterVersion(account, "")
.subscribe(
success -> LOGGER.log(Level.FINE, "Successfully reset roster version"),
error -> LOGGER.log(Level.WARNING, "An error occurred resetting roster version", error)
));
*/
}
public RosterPacket.Item fromEntity(Peer contactModel) {
RosterPacket.Item item = new RosterPacket.Item(
JidCreate.entityBareFromOrThrowUnchecked(contactModel.getAddress()),
contactModel.getName());
if (contactModel.getSubscriptionDirection() != null) {
item.setItemType(convert(contactModel.getSubscriptionDirection()));
}
item.setApproved(contactModel.isSubscriptionApproved());
item.setSubscriptionPending(contactModel.isSubscriptionPending());
return item;
}
public Peer toEntity(RosterPacket.Item item) {
Peer peer = new IPeer();
peer.setAccount(account);
peer.setAddress(item.getJid().asEntityBareJidOrThrow().asEntityBareJidString());
peer.setName(item.getName());
if (item.getItemType() != null) {
peer.setSubscriptionDirection(convert(item.getItemType()));
}
peer.setSubscriptionApproved(item.isApproved());
peer.setSubscriptionPending(item.isSubscriptionPending());
return peer;
}
public SubscriptionDirection convert(RosterPacket.ItemType type) {
return SubscriptionDirection.valueOf(type.toString());
}
public RosterPacket.ItemType convert(SubscriptionDirection direction) {
return RosterPacket.ItemType.fromString(direction.toString());
}
}

View File

@ -8,7 +8,9 @@ public class IPeer implements Peer {
protected Account account;
protected String address;
protected String name;
protected SubscriptionMode subscriptionMode;
protected SubscriptionDirection subscriptionDirection;
protected boolean pending;
protected boolean approved;
@Override
public long getId() {
@ -51,18 +53,38 @@ public class IPeer implements Peer {
}
@Override
public SubscriptionMode getSubscriptionMode() {
return subscriptionMode;
public SubscriptionDirection getSubscriptionDirection() {
return subscriptionDirection;
}
@Override
public void setSubscriptionMode(SubscriptionMode mode) {
this.subscriptionMode = mode;
public void setSubscriptionDirection(SubscriptionDirection mode) {
this.subscriptionDirection = mode;
}
@Override
public boolean isSubscriptionPending() {
return pending;
}
@Override
public void setSubscriptionPending(boolean pending) {
this.pending = pending;
}
@Override
public boolean isSubscriptionApproved() {
return approved;
}
@Override
public void setSubscriptionApproved(boolean approved) {
this.approved = approved;
}
@Override
public boolean isContact() {
return subscriptionMode != SubscriptionMode.NONE
&& subscriptionMode != SubscriptionMode.FROM_THEM_PENDING;
return subscriptionDirection != SubscriptionDirection.none
&& subscriptionDirection != SubscriptionDirection.from;
}
}

View File

@ -26,9 +26,17 @@ public interface Peer {
void setName(String name);
SubscriptionMode getSubscriptionMode();
SubscriptionDirection getSubscriptionDirection();
void setSubscriptionMode(SubscriptionMode mode);
void setSubscriptionDirection(SubscriptionDirection mode);
boolean isSubscriptionPending();
void setSubscriptionPending(boolean pending);
boolean isSubscriptionApproved();
void setSubscriptionApproved(boolean approved);
boolean isContact();
}

View File

@ -1,4 +1,4 @@
package org.mercury_im.messenger.data.enums;
package org.mercury_im.messenger.entity.contact;
public enum SubscriptionDirection {
none,

View File

@ -1,55 +0,0 @@
package org.mercury_im.messenger.entity.contact;
/**
* Enum describing the relationship between the user and another entity.
*/
public enum SubscriptionMode {
/**
* No subscription between us an them.
*/
NONE,
/**
* No subscription between us and them.
* However, we pre-approved their subscription, should they decide to subscribe to us.
*/
NONE_PREAPPROVED,
/**
* We sent a subscription request, which is now pending to be accepted.
* We do not pre-approve their subscription to us.
*/
TO_THEM_PENDING,
/**
* We sent a subscription request, which is now pending to be accepted.
* Also, we pre-approved their subscription to us.
*/
TO_THEM_PENDING_PREAPPROVED,
/**
* We sent a subscription request and they approved it.
*/
TO_THEM_ACCEPTED,
/**
* We sent a subscription request and they approved it.
* Also, we pre-approved their subscription, should they decide to subscribe back.
*/
TO_THEM_ACCEPTED_PREAPPROVED,
/**
* They sent us a subscription request, but we did not yet accept it.
*/
FROM_THEM_PENDING,
/**
* They sent us a subscription request and we accepted it.
*/
FROM_THEM_ACCEPTED,
/**
* They accepted us and we accepted them.
*/
BIDIRECTIONAL
}

View File

@ -12,6 +12,8 @@ public class IMessage implements Message {
protected List<PayloadContainer> payloads;
protected MessageDeliveryState deliveryState;
protected MessageMetadata metadata;
protected MessageDirection direction;
@Override
public long getId() {
@ -53,6 +55,16 @@ public class IMessage implements Message {
this.timestamp = timestamp;
}
@Override
public MessageDirection getDirection() {
return direction;
}
@Override
public void setDirection(MessageDirection direction) {
this.direction = direction;
}
@Override
public List<PayloadContainer> getMessagePayloads() {
return payloads;

View File

@ -21,6 +21,14 @@ public interface Message {
void setTimestamp(Date timestamp);
MessageDirection getDirection();
void setDirection(MessageDirection direction);
default boolean isIncoming() {
return getDirection() == MessageDirection.incoming;
}
List<PayloadContainer> getMessagePayloads();
void setMessagePayloads(List<PayloadContainer> payloadContainers);

View File

@ -0,0 +1,6 @@
package org.mercury_im.messenger.entity.message;
public enum MessageDirection {
incoming,
outgoing
}