mirror of
https://codeberg.org/Mercury-IM/Mercury-IM
synced 2024-11-14 20:02:05 +01:00
Work on contact list - wip!
This commit is contained in:
parent
ff04832614
commit
687288e697
25 changed files with 420 additions and 190 deletions
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 -> )
|
||||
*/
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package org.mercury_im.messenger.data.enums;
|
||||
package org.mercury_im.messenger.entity.contact;
|
||||
|
||||
public enum SubscriptionDirection {
|
||||
none,
|
|
@ -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
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
package org.mercury_im.messenger.entity.message;
|
||||
|
||||
public enum MessageDirection {
|
||||
incoming,
|
||||
outgoing
|
||||
}
|
Loading…
Reference in a new issue