mirror of
https://codeberg.org/Mercury-IM/Mercury-IM
synced 2024-06-30 07:24:50 +02:00
experimental MAM and improved rx repos
This commit is contained in:
parent
93bcda8480
commit
939ce748ef
|
@ -8,11 +8,9 @@ import android.view.MenuItem;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
import androidx.appcompat.widget.Toolbar;
|
import androidx.appcompat.widget.Toolbar;
|
||||||
import androidx.fragment.app.FragmentManager;
|
|
||||||
import androidx.fragment.app.FragmentTransaction;
|
import androidx.fragment.app.FragmentTransaction;
|
||||||
|
|
||||||
import com.google.android.material.bottomnavigation.BottomNavigationView;
|
import com.google.android.material.bottomnavigation.BottomNavigationView;
|
||||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
|
||||||
import com.google.android.material.navigation.NavigationView;
|
import com.google.android.material.navigation.NavigationView;
|
||||||
|
|
||||||
import org.mercury_im.messenger.MercuryImApplication;
|
import org.mercury_im.messenger.MercuryImApplication;
|
||||||
|
|
|
@ -126,9 +126,9 @@ public class ChatActivity extends AppCompatActivity
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
switch (item.getItemId()) {
|
switch (item.getItemId()) {
|
||||||
case R.id.action_debug:
|
case R.id.action_debug:
|
||||||
chatRepository.getOrCreateChatWith(accountId, JidCreate.entityBareFromOrThrowUnchecked("alice@wonderland.lit"))
|
Log.d("CHATACTIVITY", "Fetch MAM messages!");
|
||||||
|
chatViewModel.requestMamMessages()
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.subscribe();
|
.subscribe();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,11 @@ import androidx.lifecycle.ViewModel;
|
||||||
|
|
||||||
import org.jxmpp.jid.EntityBareJid;
|
import org.jxmpp.jid.EntityBareJid;
|
||||||
import org.mercury_im.messenger.MercuryImApplication;
|
import org.mercury_im.messenger.MercuryImApplication;
|
||||||
|
import org.mercury_im.messenger.core.centers.ConnectionCenter;
|
||||||
|
import org.mercury_im.messenger.persistence.model.ChatModel;
|
||||||
import org.mercury_im.messenger.persistence.model.ContactModel;
|
import org.mercury_im.messenger.persistence.model.ContactModel;
|
||||||
import org.mercury_im.messenger.persistence.model.MessageModel;
|
import org.mercury_im.messenger.persistence.model.MessageModel;
|
||||||
|
import org.mercury_im.messenger.persistence.repository.ChatRepository;
|
||||||
import org.mercury_im.messenger.persistence.repository.MessageRepository;
|
import org.mercury_im.messenger.persistence.repository.MessageRepository;
|
||||||
import org.mercury_im.messenger.persistence.repository.RosterRepository;
|
import org.mercury_im.messenger.persistence.repository.RosterRepository;
|
||||||
|
|
||||||
|
@ -15,9 +18,10 @@ import java.util.List;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import io.reactivex.Scheduler;
|
import io.reactivex.Completable;
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||||
import io.reactivex.disposables.CompositeDisposable;
|
import io.reactivex.disposables.CompositeDisposable;
|
||||||
|
import io.reactivex.functions.Action;
|
||||||
import io.reactivex.functions.Consumer;
|
import io.reactivex.functions.Consumer;
|
||||||
import io.reactivex.schedulers.Schedulers;
|
import io.reactivex.schedulers.Schedulers;
|
||||||
|
|
||||||
|
@ -31,12 +35,19 @@ public class ChatViewModel extends ViewModel {
|
||||||
@Inject
|
@Inject
|
||||||
RosterRepository rosterRepository;
|
RosterRepository rosterRepository;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
ChatRepository chatRepository;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
ConnectionCenter connectionCenter;
|
||||||
|
|
||||||
private long accountId;
|
private long accountId;
|
||||||
private EntityBareJid jid;
|
private EntityBareJid jid;
|
||||||
|
|
||||||
private MutableLiveData<ContactModel> contact = new MutableLiveData<>();
|
private MutableLiveData<ContactModel> contact = new MutableLiveData<>();
|
||||||
private MutableLiveData<List<MessageModel>> messages = new MutableLiveData<>();
|
private MutableLiveData<List<MessageModel>> messages = new MutableLiveData<>();
|
||||||
private MutableLiveData<String> contactDisplayName = new MutableLiveData<>();
|
private MutableLiveData<String> contactDisplayName = new MutableLiveData<>();
|
||||||
|
private MutableLiveData<ChatModel> chat = new MutableLiveData<>();
|
||||||
|
|
||||||
public ChatViewModel() {
|
public ChatViewModel() {
|
||||||
super();
|
super();
|
||||||
|
@ -66,6 +77,12 @@ public class ChatViewModel extends ViewModel {
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe((Consumer<List<MessageModel>>)
|
.subscribe((Consumer<List<MessageModel>>)
|
||||||
messages -> ChatViewModel.this.messages.setValue(messages)));
|
messages -> ChatViewModel.this.messages.setValue(messages)));
|
||||||
|
|
||||||
|
disposable.add(chatRepository.getOrCreateChatWith(accountId, jid)
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe((Consumer<ChatModel>)
|
||||||
|
chatModel -> this.chat.setValue(chatModel)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -101,4 +118,18 @@ public class ChatViewModel extends ViewModel {
|
||||||
messages.setValue(o);
|
messages.setValue(o);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Completable requestMamMessages() {
|
||||||
|
return Completable.fromAction(new Action() {
|
||||||
|
@Override
|
||||||
|
public void run() throws Exception {
|
||||||
|
ChatModel chatModel = ChatViewModel.this.chat.getValue();
|
||||||
|
if (chatModel == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
connectionCenter.requestMamMessagesFor(chatModel);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package org.mercury_im.messenger;
|
package org.mercury_im.messenger;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
import org.mercury_im.messenger.core.connection.ConnectionState;
|
import org.mercury_im.messenger.core.connection.ConnectionState;
|
||||||
|
|
||||||
import io.reactivex.observers.TestObserver;
|
import io.reactivex.observers.TestObserver;
|
||||||
|
|
|
@ -7,12 +7,16 @@ import org.jivesoftware.smack.tcp.XMPPTCPConnection;
|
||||||
import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration;
|
import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration;
|
||||||
import org.jivesoftware.smackx.caps.EntityCapsManager;
|
import org.jivesoftware.smackx.caps.EntityCapsManager;
|
||||||
import org.jivesoftware.smackx.csi.ClientStateIndicationManager;
|
import org.jivesoftware.smackx.csi.ClientStateIndicationManager;
|
||||||
|
import org.jivesoftware.smackx.mam.MamManager;
|
||||||
|
import org.jxmpp.jid.EntityBareJid;
|
||||||
import org.mercury_im.messenger.core.stores.EntityCapsStore;
|
import org.mercury_im.messenger.core.stores.EntityCapsStore;
|
||||||
import org.mercury_im.messenger.core.connection.MercuryConfiguration;
|
import org.mercury_im.messenger.core.connection.MercuryConfiguration;
|
||||||
import org.mercury_im.messenger.core.connection.MercuryConnection;
|
import org.mercury_im.messenger.core.connection.MercuryConnection;
|
||||||
import org.mercury_im.messenger.core.stores.PlainMessageStore;
|
import org.mercury_im.messenger.core.stores.PlainMessageStore;
|
||||||
import org.mercury_im.messenger.core.stores.RosterStore;
|
import org.mercury_im.messenger.core.stores.RosterStore;
|
||||||
import org.mercury_im.messenger.persistence.model.AccountModel;
|
import org.mercury_im.messenger.persistence.model.AccountModel;
|
||||||
|
import org.mercury_im.messenger.persistence.model.ChatModel;
|
||||||
|
import org.mercury_im.messenger.persistence.model.EntityModel;
|
||||||
import org.mercury_im.messenger.persistence.repository.AccountRepository;
|
import org.mercury_im.messenger.persistence.repository.AccountRepository;
|
||||||
import org.mercury_im.messenger.persistence.repository.RosterRepository;
|
import org.mercury_im.messenger.persistence.repository.RosterRepository;
|
||||||
|
|
||||||
|
@ -213,4 +217,23 @@ public class ConnectionCenter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void requestMamMessagesFor(ChatModel chat) {
|
||||||
|
disposable.add(rosterRepository.getEntity(chat.getPeerEntityId())
|
||||||
|
.subscribe((Consumer<EntityModel>) entity -> {
|
||||||
|
MercuryConnection connection = connectionMap.get(entity.getAccountId());
|
||||||
|
if (connection == null) return;
|
||||||
|
MamManager mamManager = MamManager.getInstanceFor(connection.getConnection());
|
||||||
|
MamManager.MamQuery query;
|
||||||
|
//if (chat.getEarliestMamMessageId() == null) {
|
||||||
|
query = mamManager.queryMostRecentPage(entity.getJid(), 100);
|
||||||
|
//} else {
|
||||||
|
//MamManager.MamQueryArgs queryArgs = MamManager.MamQueryArgs.builder()
|
||||||
|
// .beforeUid()
|
||||||
|
// .build();
|
||||||
|
//query = mamManager.queryArchive()
|
||||||
|
//}
|
||||||
|
messageStore.onMamResult(entity.getAccountId(), entity.getJid(), query);
|
||||||
|
}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,12 +2,12 @@ package org.mercury_im.messenger.core.centers;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
public class NotificationCenter {
|
public class MessageCenter {
|
||||||
|
|
||||||
private final ConnectionCenter connectionCenter;
|
private final ConnectionCenter connectionCenter;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public NotificationCenter(ConnectionCenter connectionCenter) {
|
public MessageCenter(ConnectionCenter connectionCenter) {
|
||||||
this.connectionCenter = connectionCenter;
|
this.connectionCenter = connectionCenter;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -13,6 +13,7 @@ import org.jivesoftware.smackx.carbons.CarbonManager;
|
||||||
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
|
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
|
||||||
import org.jivesoftware.smackx.disco.packet.DiscoverInfo;
|
import org.jivesoftware.smackx.disco.packet.DiscoverInfo;
|
||||||
import org.jivesoftware.smackx.iqversion.VersionManager;
|
import org.jivesoftware.smackx.iqversion.VersionManager;
|
||||||
|
import org.jivesoftware.smackx.mam.MamManager;
|
||||||
import org.jivesoftware.smackx.sid.StableUniqueStanzaIdManager;
|
import org.jivesoftware.smackx.sid.StableUniqueStanzaIdManager;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -36,6 +37,7 @@ public class MercuryConnection {
|
||||||
protected final CarbonManager carbonManager;
|
protected final CarbonManager carbonManager;
|
||||||
protected final StableUniqueStanzaIdManager stanzaIdManager;
|
protected final StableUniqueStanzaIdManager stanzaIdManager;
|
||||||
protected final ServiceDiscoveryManager serviceDiscoveryManager;
|
protected final ServiceDiscoveryManager serviceDiscoveryManager;
|
||||||
|
protected final MamManager mamManager;
|
||||||
|
|
||||||
BehaviorSubject<ConnectionState> state = BehaviorSubject.createDefault(ConnectionState.DISCONNECTED);
|
BehaviorSubject<ConnectionState> state = BehaviorSubject.createDefault(ConnectionState.DISCONNECTED);
|
||||||
|
|
||||||
|
@ -59,6 +61,8 @@ public class MercuryConnection {
|
||||||
VersionManager.setAutoAppendSmackVersion(false);
|
VersionManager.setAutoAppendSmackVersion(false);
|
||||||
VersionManager.getInstanceFor(connection).setVersion("Mercury", "0.0.1-stealth", "Android");
|
VersionManager.getInstanceFor(connection).setVersion("Mercury", "0.0.1-stealth", "Android");
|
||||||
serviceDiscoveryManager.setIdentity(new DiscoverInfo.Identity("client", "Mercury", "phone"));
|
serviceDiscoveryManager.setIdentity(new DiscoverInfo.Identity("client", "Mercury", "phone"));
|
||||||
|
|
||||||
|
mamManager = MamManager.getInstanceFor(connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void connect() {
|
public void connect() {
|
||||||
|
@ -120,6 +124,8 @@ public class MercuryConnection {
|
||||||
exception.printStackTrace();
|
exception.printStackTrace();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -16,8 +16,10 @@ import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import io.reactivex.Observable;
|
||||||
import io.reactivex.Single;
|
import io.reactivex.Single;
|
||||||
import io.reactivex.disposables.CompositeDisposable;
|
import io.reactivex.disposables.CompositeDisposable;
|
||||||
|
import io.reactivex.functions.Consumer;
|
||||||
import io.reactivex.observers.DisposableSingleObserver;
|
import io.reactivex.observers.DisposableSingleObserver;
|
||||||
import io.reactivex.schedulers.Schedulers;
|
import io.reactivex.schedulers.Schedulers;
|
||||||
|
|
||||||
|
@ -29,7 +31,7 @@ public class EntityCapsStore implements EntityCapsPersistentCache {
|
||||||
private final Map<String, DiscoverInfo> discoverInfoMap = new HashMap<>();
|
private final Map<String, DiscoverInfo> discoverInfoMap = new HashMap<>();
|
||||||
|
|
||||||
private final CompositeDisposable disposable = new CompositeDisposable();
|
private final CompositeDisposable disposable = new CompositeDisposable();
|
||||||
private Single<List<EntityCapsModel>> allEntityCaps;
|
private Observable<List<EntityCapsModel>> allEntityCaps;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public EntityCapsStore(EntityCapsRepository repository) {
|
public EntityCapsStore(EntityCapsRepository repository) {
|
||||||
|
@ -41,9 +43,7 @@ public class EntityCapsStore implements EntityCapsPersistentCache {
|
||||||
allEntityCaps = entityCapsRepository.getAllEntityCaps();
|
allEntityCaps = entityCapsRepository.getAllEntityCaps();
|
||||||
disposable.add(allEntityCaps.subscribeOn(Schedulers.io())
|
disposable.add(allEntityCaps.subscribeOn(Schedulers.io())
|
||||||
.observeOn(Schedulers.io())
|
.observeOn(Schedulers.io())
|
||||||
.subscribeWith(new DisposableSingleObserver<List<? extends EntityCapsModel>>() {
|
.subscribe(entityCapsModels -> {
|
||||||
@Override
|
|
||||||
public void onSuccess(List<? extends EntityCapsModel> entityCapsModels) {
|
|
||||||
discoverInfoMap.clear();
|
discoverInfoMap.clear();
|
||||||
for (EntityCapsModel c : entityCapsModels) {
|
for (EntityCapsModel c : entityCapsModels) {
|
||||||
DiscoverInfo info;
|
DiscoverInfo info;
|
||||||
|
@ -55,26 +55,18 @@ public class EntityCapsStore implements EntityCapsPersistentCache {
|
||||||
LOGGER.log(Level.SEVERE, "Error parsing EntityCaps: ", e);
|
LOGGER.log(Level.SEVERE, "Error parsing EntityCaps: ", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}, throwable -> LOGGER.log(Level.SEVERE, "Error accessing database", throwable)));
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(Throwable e) {
|
|
||||||
LOGGER.log(Level.SEVERE, "Error processing Caps update from store.", e);
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addDiscoverInfoByNodePersistent(String nodeVer, DiscoverInfo info) {
|
public void addDiscoverInfoByNodePersistent(String nodeVer, DiscoverInfo info) {
|
||||||
discoverInfoMap.put(nodeVer, info);
|
|
||||||
EntityCapsModel model = entityCapsRepository.newEntityCapsModel(nodeVer);
|
EntityCapsModel model = entityCapsRepository.newEntityCapsModel(nodeVer);
|
||||||
CharSequence xml = info.toXML();
|
CharSequence xml = info.toXML();
|
||||||
LOGGER.log(Level.INFO, "Persisting entry:" + xml);
|
|
||||||
String string = xml.toString();
|
String string = xml.toString();
|
||||||
model.setXml(string);
|
model.setXml(string);
|
||||||
entityCapsRepository.insertOrReplaceEntityCaps(model)
|
disposable.add(entityCapsRepository.insertOrReplaceEntityCaps(model)
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.subscribe();
|
.subscribe());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -5,16 +5,21 @@ import org.jivesoftware.smack.chat2.ChatManager;
|
||||||
import org.jivesoftware.smack.packet.Message;
|
import org.jivesoftware.smack.packet.Message;
|
||||||
import org.jivesoftware.smackx.carbons.CarbonManager;
|
import org.jivesoftware.smackx.carbons.CarbonManager;
|
||||||
import org.jivesoftware.smackx.carbons.packet.CarbonExtension;
|
import org.jivesoftware.smackx.carbons.packet.CarbonExtension;
|
||||||
|
import org.jivesoftware.smackx.delay.packet.DelayInformation;
|
||||||
|
import org.jivesoftware.smackx.mam.MamManager;
|
||||||
import org.jxmpp.jid.EntityBareJid;
|
import org.jxmpp.jid.EntityBareJid;
|
||||||
import org.mercury_im.messenger.core.connection.MercuryConnection;
|
import org.mercury_im.messenger.core.connection.MercuryConnection;
|
||||||
import org.mercury_im.messenger.persistence.model.MessageModel;
|
import org.mercury_im.messenger.persistence.model.MessageModel;
|
||||||
import org.mercury_im.messenger.persistence.repository.MessageRepository;
|
import org.mercury_im.messenger.persistence.repository.MessageRepository;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import io.reactivex.disposables.CompositeDisposable;
|
import io.reactivex.disposables.CompositeDisposable;
|
||||||
|
import io.reactivex.functions.Consumer;
|
||||||
import io.reactivex.schedulers.Schedulers;
|
import io.reactivex.schedulers.Schedulers;
|
||||||
|
|
||||||
public class PlainMessageStore {
|
public class PlainMessageStore {
|
||||||
|
@ -102,4 +107,29 @@ public class PlainMessageStore {
|
||||||
public void dispose() {
|
public void dispose() {
|
||||||
disposable.clear();
|
disposable.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void onMamResult(long accountId, EntityBareJid peerJid, MamManager.MamQuery query) {
|
||||||
|
List<MessageModel> messageModels = new ArrayList<>();
|
||||||
|
for (Message message : query.getMessages()) {
|
||||||
|
Date date = new Date();
|
||||||
|
DelayInformation delay = DelayInformation.from(message);
|
||||||
|
if (delay != null) {
|
||||||
|
date = delay.getStamp();
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageModel messageModel = messageRepository.newMessageModel();
|
||||||
|
messageModel.setAccountId(accountId);
|
||||||
|
messageModel.setBody(message.getBody());
|
||||||
|
messageModel.setFrom(message.getFrom().asEntityBareJidOrThrow());
|
||||||
|
messageModel.setTo(message.getTo().asEntityBareJidOrThrow());
|
||||||
|
messageModel.setIncoming(peerJid.equals(message.getFrom().asEntityBareJidOrThrow()));
|
||||||
|
messageModel.setSendDate(date);
|
||||||
|
messageModels.add(messageModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
disposable.add(
|
||||||
|
messageRepository.insertMessages(messageModels)
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.subscribe());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,7 +104,7 @@ public class RosterStore implements org.jivesoftware.smack.roster.rosterstore.Ro
|
||||||
LOGGER.log(Level.INFO, "Add entry " + item.toXML().toString());
|
LOGGER.log(Level.INFO, "Add entry " + item.toXML().toString());
|
||||||
// Update database
|
// Update database
|
||||||
ContactModel contact = toModel(item);
|
ContactModel contact = toModel(item);
|
||||||
rosterRepository.updateOrInsertContact(contact)
|
rosterRepository.upsertContact(contact)
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(Schedulers.computation())
|
.observeOn(Schedulers.computation())
|
||||||
.subscribe();
|
.subscribe();
|
||||||
|
@ -122,7 +122,7 @@ public class RosterStore implements org.jivesoftware.smack.roster.rosterstore.Ro
|
||||||
// Update database
|
// Update database
|
||||||
for (RosterPacket.Item item : items) {
|
for (RosterPacket.Item item : items) {
|
||||||
ContactModel model = toModel(item);
|
ContactModel model = toModel(item);
|
||||||
rosterRepository.updateOrInsertContact(model)
|
rosterRepository.upsertContact(model)
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.subscribe();
|
.subscribe();
|
||||||
}
|
}
|
||||||
|
@ -174,7 +174,6 @@ public class RosterStore implements org.jivesoftware.smack.roster.rosterstore.Ro
|
||||||
|
|
||||||
public ContactModel toModel(RosterPacket.Item item) {
|
public ContactModel toModel(RosterPacket.Item item) {
|
||||||
ContactModel contact = rosterRepository.newContactModel();
|
ContactModel contact = rosterRepository.newContactModel();
|
||||||
contact.setAccountId(accountId);
|
|
||||||
|
|
||||||
contact.setRosterName(item.getName());
|
contact.setRosterName(item.getName());
|
||||||
if (item.getItemType() != null) {
|
if (item.getItemType() != null) {
|
||||||
|
|
|
@ -41,15 +41,16 @@ dependencies {
|
||||||
implementation "com.google.dagger:dagger:$daggerVersion"
|
implementation "com.google.dagger:dagger:$daggerVersion"
|
||||||
annotationProcessor "com.google.dagger:dagger-compiler:$daggerVersion"
|
annotationProcessor "com.google.dagger:dagger-compiler:$daggerVersion"
|
||||||
|
|
||||||
testImplementation "junit:junit:$junitVersion"
|
|
||||||
androidTestImplementation "androidx.test:runner:$andxTestRunnerVersion"
|
|
||||||
androidTestImplementation "androidx.test.espresso:espresso-core:$andxTestEspressoVersion"
|
|
||||||
androidTestImplementation "androidx.test:core:$andxTestCoreVersion"
|
|
||||||
androidTestImplementation "androidx.test.ext:junit:$andxTestJunitVersion"
|
|
||||||
|
|
||||||
// Room
|
// Room
|
||||||
api "androidx.room:room-runtime:$roomVersion"
|
api "androidx.room:room-runtime:$roomVersion"
|
||||||
annotationProcessor "androidx.room:room-compiler:$roomVersion"
|
annotationProcessor "androidx.room:room-compiler:$roomVersion"
|
||||||
implementation "androidx.room:room-rxjava2:$roomRxJavaVersion"
|
implementation "androidx.room:room-rxjava2:$roomRxJavaVersion"
|
||||||
api "io.reactivex.rxjava2:rxandroid:$rxAndroidVersion"
|
api "io.reactivex.rxjava2:rxandroid:$rxAndroidVersion"
|
||||||
|
|
||||||
|
// Test
|
||||||
|
testImplementation "junit:junit:$junitVersion"
|
||||||
|
androidTestImplementation "androidx.test:runner:$andxTestRunnerVersion"
|
||||||
|
androidTestImplementation "androidx.test.espresso:espresso-core:$andxTestEspressoVersion"
|
||||||
|
androidTestImplementation "androidx.test:core:$andxTestCoreVersion"
|
||||||
|
androidTestImplementation "androidx.test.ext:junit:$andxTestJunitVersion"
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"formatVersion": 1,
|
"formatVersion": 1,
|
||||||
"database": {
|
"database": {
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"identityHash": "343b0cb91d977d378c17c577a4dc231d",
|
"identityHash": "aa41a1d6727ebded374388bdd6cf8456",
|
||||||
"entities": [
|
"entities": [
|
||||||
{
|
{
|
||||||
"tableName": "accounts",
|
"tableName": "accounts",
|
||||||
|
@ -121,7 +121,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"tableName": "contacts",
|
"tableName": "contacts",
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`pk_contact_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `fk_account_id` INTEGER NOT NULL, `fk_entity_id` INTEGER NOT NULL, `rostername` TEXT, `nickname` TEXT, `direction` TEXT, `sub_pending` INTEGER NOT NULL, `approved` INTEGER NOT NULL, FOREIGN KEY(`fk_account_id`) REFERENCES `accounts`(`pk_account_id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`fk_entity_id`) REFERENCES `entities`(`pk_entity_id`) ON UPDATE NO ACTION ON DELETE RESTRICT )",
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`pk_contact_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `fk_entity_id` INTEGER NOT NULL, `rostername` TEXT, `nickname` TEXT, `direction` TEXT, `sub_pending` INTEGER NOT NULL, `approved` INTEGER NOT NULL, FOREIGN KEY(`fk_entity_id`) REFERENCES `entities`(`pk_entity_id`) ON UPDATE NO ACTION ON DELETE RESTRICT )",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"fieldPath": "id",
|
"fieldPath": "id",
|
||||||
|
@ -129,12 +129,6 @@
|
||||||
"affinity": "INTEGER",
|
"affinity": "INTEGER",
|
||||||
"notNull": true
|
"notNull": true
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"fieldPath": "accountId",
|
|
||||||
"columnName": "fk_account_id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"fieldPath": "entityId",
|
"fieldPath": "entityId",
|
||||||
"columnName": "fk_entity_id",
|
"columnName": "fk_entity_id",
|
||||||
|
@ -187,14 +181,6 @@
|
||||||
],
|
],
|
||||||
"createSql": "CREATE INDEX `index_contacts_pk_contact_id` ON `${TABLE_NAME}` (`pk_contact_id`)"
|
"createSql": "CREATE INDEX `index_contacts_pk_contact_id` ON `${TABLE_NAME}` (`pk_contact_id`)"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "index_contacts_fk_account_id",
|
|
||||||
"unique": false,
|
|
||||||
"columnNames": [
|
|
||||||
"fk_account_id"
|
|
||||||
],
|
|
||||||
"createSql": "CREATE INDEX `index_contacts_fk_account_id` ON `${TABLE_NAME}` (`fk_account_id`)"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "index_contacts_fk_entity_id",
|
"name": "index_contacts_fk_entity_id",
|
||||||
"unique": true,
|
"unique": true,
|
||||||
|
@ -214,17 +200,6 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"foreignKeys": [
|
"foreignKeys": [
|
||||||
{
|
|
||||||
"table": "accounts",
|
|
||||||
"onDelete": "CASCADE",
|
|
||||||
"onUpdate": "NO ACTION",
|
|
||||||
"columns": [
|
|
||||||
"fk_account_id"
|
|
||||||
],
|
|
||||||
"referencedColumns": [
|
|
||||||
"pk_account_id"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"table": "entities",
|
"table": "entities",
|
||||||
"onDelete": "RESTRICT",
|
"onDelete": "RESTRICT",
|
||||||
|
@ -275,7 +250,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"tableName": "chats",
|
"tableName": "chats",
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`pk_chat_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `fk_entity_id` INTEGER NOT NULL, `active` INTEGER NOT NULL, FOREIGN KEY(`fk_entity_id`) REFERENCES `entities`(`pk_entity_id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`pk_chat_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `fk_entity_id` INTEGER NOT NULL, `active` INTEGER NOT NULL, `last_read_message` INTEGER NOT NULL, `most_recent_mam_msg` TEXT, `earliest_mam_msg` TEXT, FOREIGN KEY(`fk_entity_id`) REFERENCES `entities`(`pk_entity_id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"fieldPath": "id",
|
"fieldPath": "id",
|
||||||
|
@ -294,6 +269,24 @@
|
||||||
"columnName": "active",
|
"columnName": "active",
|
||||||
"affinity": "INTEGER",
|
"affinity": "INTEGER",
|
||||||
"notNull": true
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastReadMessageId",
|
||||||
|
"columnName": "last_read_message",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "mostRecentMamMessage",
|
||||||
|
"columnName": "most_recent_mam_msg",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "earliestMamMsg",
|
||||||
|
"columnName": "earliest_mam_msg",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"primaryKey": {
|
"primaryKey": {
|
||||||
|
@ -525,7 +518,7 @@
|
||||||
"views": [],
|
"views": [],
|
||||||
"setupQueries": [
|
"setupQueries": [
|
||||||
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
||||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '343b0cb91d977d378c17c577a4dc231d')"
|
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'aa41a1d6727ebded374388bdd6cf8456')"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
package org.mercury_im.messenger.persistence.room;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import androidx.room.Room;
|
||||||
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.jxmpp.jid.EntityBareJid;
|
||||||
|
import org.jxmpp.jid.impl.JidCreate;
|
||||||
|
import org.mercury_im.messenger.persistence.room.repository.IAccountRepository;
|
||||||
|
import org.mercury_im.messenger.persistence.room.repository.IAvatarRepository;
|
||||||
|
import org.mercury_im.messenger.persistence.room.repository.IChatRepository;
|
||||||
|
import org.mercury_im.messenger.persistence.room.repository.IEntityCapsRepository;
|
||||||
|
import org.mercury_im.messenger.persistence.room.repository.IMessageRepository;
|
||||||
|
import org.mercury_im.messenger.persistence.room.repository.IRosterRepository;
|
||||||
|
|
||||||
|
public abstract class AbstractDatabaseTest {
|
||||||
|
|
||||||
|
protected AppDatabase db;
|
||||||
|
protected IAccountRepository accountRepository;
|
||||||
|
protected IRosterRepository rosterRepository;
|
||||||
|
protected IMessageRepository messageRepository;
|
||||||
|
protected IChatRepository chatRepository;
|
||||||
|
protected IEntityCapsRepository capsRepository;
|
||||||
|
protected IAvatarRepository avatarRepository;
|
||||||
|
|
||||||
|
protected final EntityBareJid TEST_JID_JULIET = JidCreate.entityBareFromOrThrowUnchecked("juliet@capulet.lit");
|
||||||
|
protected final EntityBareJid TEST_JID_ROMEO = JidCreate.entityBareFromOrThrowUnchecked("romeo@montague.lit");
|
||||||
|
protected final EntityBareJid TEST_JID_MERCUTIO = JidCreate.entityBareFromOrThrowUnchecked("mercutio@montague.lit");
|
||||||
|
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void createDb() {
|
||||||
|
Context context = ApplicationProvider.getApplicationContext();
|
||||||
|
db = Room.inMemoryDatabaseBuilder(context, AppDatabase.class).build();
|
||||||
|
accountRepository = new IAccountRepository(db.accountDao());
|
||||||
|
rosterRepository = new IRosterRepository(
|
||||||
|
db.entityDao(), db.contactDao(), db.rosterInformationDao());
|
||||||
|
messageRepository = new IMessageRepository(db.messageDao());
|
||||||
|
chatRepository = new IChatRepository(db.chatDao(), rosterRepository);
|
||||||
|
capsRepository = new IEntityCapsRepository(db.entityCapsDao());
|
||||||
|
avatarRepository = new IAvatarRepository(db.avatarDao());
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void closeDb() {
|
||||||
|
db.close();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,24 +1,18 @@
|
||||||
package org.mercury_im.messenger.persistence.room;
|
package org.mercury_im.messenger.persistence.room;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.jxmpp.jid.impl.JidCreate;
|
|
||||||
import org.mercury_im.messenger.persistence.room.model.RoomAccountModel;
|
import org.mercury_im.messenger.persistence.room.model.RoomAccountModel;
|
||||||
import org.mercury_im.messenger.persistence.room.repository.IAccountRepository;
|
import org.mercury_im.messenger.persistence.room.model.RoomChatModel;
|
||||||
import org.mercury_im.messenger.persistence.room.repository.IRosterRepository;
|
import org.mercury_im.messenger.persistence.room.model.RoomContactModel;
|
||||||
import org.mercury_im.messenger.persistence.room.repository.IMessageRepository;
|
import org.mercury_im.messenger.persistence.room.model.RoomEntityModel;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import io.reactivex.Observable;
|
import io.reactivex.Observable;
|
||||||
import io.reactivex.functions.Predicate;
|
import io.reactivex.disposables.Disposable;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instrumented test, which will execute on an Android device.
|
* Instrumented test, which will execute on an Android device.
|
||||||
|
@ -26,33 +20,67 @@ import static org.junit.Assert.assertEquals;
|
||||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||||
*/
|
*/
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
public class ExampleInstrumentedTest {
|
public class ExampleInstrumentedTest extends AbstractDatabaseTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void useAppContext() {
|
public void testUpsertContact() {
|
||||||
// Context of the app under test
|
RoomAccountModel accountModel = new RoomAccountModel();
|
||||||
|
accountModel.setJid(TEST_JID_JULIET);
|
||||||
|
accountRepository.insertAccount(accountModel).test().assertValue(1L).dispose();
|
||||||
|
|
||||||
Context context = ApplicationProvider.getApplicationContext();
|
RoomContactModel contactModel = new RoomContactModel();
|
||||||
|
RoomEntityModel entityModel = new RoomEntityModel();
|
||||||
|
entityModel.setAccountId(1);
|
||||||
|
entityModel.setJid(TEST_JID_ROMEO);
|
||||||
|
contactModel.setEntity(entityModel);
|
||||||
|
|
||||||
AppDatabase appDatabase = AppDatabase.getDatabase(context);
|
rosterRepository.upsertContact(contactModel).test().assertValue(1L).dispose();
|
||||||
IAccountRepository accountRepository = new IAccountRepository(appDatabase.accountDao());
|
rosterRepository.getContact(1L).subscribe(contact -> {
|
||||||
IRosterRepository rosterRepository = new IRosterRepository(appDatabase.rosterEntryDao());
|
System.out.println(contact.getEntity().getAccountId() + " " + contact.getEntity().getJid().toString());
|
||||||
IMessageRepository messageRepository = new IMessageRepository(appDatabase.messageDao());
|
}).dispose();
|
||||||
|
|
||||||
Observable<List<RoomAccountModel>> accounts = accountRepository.getAllAccounts();
|
rosterRepository.upsertContact(contactModel).test().assertValue(1L).dispose();
|
||||||
|
rosterRepository.getContact(1L).subscribe(contact -> {
|
||||||
final RoomAccountModel a1 = new RoomAccountModel();
|
System.out.println(contact.getEntity().getAccountId() + " " + contact.getEntity().getJid().toString());
|
||||||
a1.setJid(JidCreate.entityBareFromOrThrowUnchecked("alice@wonderland.lit"));
|
}).dispose();
|
||||||
a1.setPassword("5w0rdf1sh");
|
|
||||||
a1.setEnabled(false);
|
|
||||||
accountRepository.insertAccount(a1);
|
|
||||||
|
|
||||||
accounts.test()
|
|
||||||
.assertValue(new Predicate<List<RoomAccountModel>>() {
|
|
||||||
@Override
|
|
||||||
public boolean test(List<RoomAccountModel> roomAccountModels) throws Exception {
|
|
||||||
return roomAccountModels.size() == 1;
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
@Test
|
||||||
|
public void testGetOrCreateEntity() {
|
||||||
|
RoomAccountModel accountModel = new RoomAccountModel();
|
||||||
|
accountModel.setJid(TEST_JID_JULIET);
|
||||||
|
accountRepository.insertAccount(accountModel).test().assertValue(1L).dispose();
|
||||||
|
|
||||||
|
RoomEntityModel romeo = rosterRepository.getOrCreateEntityForAccountAndJid(accountModel, TEST_JID_ROMEO).blockingGet();
|
||||||
|
RoomEntityModel mercu = rosterRepository.getOrCreateEntityForAccountAndJid(accountModel, TEST_JID_MERCUTIO).blockingGet();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testObservabilityOfChat() throws InterruptedException {
|
||||||
|
RoomAccountModel accountModel = new RoomAccountModel();
|
||||||
|
accountModel.setJid(TEST_JID_JULIET);
|
||||||
|
accountRepository.insertAccount(accountModel).test().assertValue(1L).dispose();
|
||||||
|
|
||||||
|
Observable<RoomChatModel> chat = chatRepository.getOrCreateChatWith(accountModel.getId(), TEST_JID_ROMEO);
|
||||||
|
Disposable disposable = chat.subscribe(chatModel -> Log.d(AppDatabase.TAG, "onNext: " + chatModel));
|
||||||
|
|
||||||
|
|
||||||
|
RoomChatModel chatModel = chatRepository.newChatModel();
|
||||||
|
chatModel.setId(1L);
|
||||||
|
chatModel.setPeerEntityId(1L);
|
||||||
|
chatModel.setActive(true);
|
||||||
|
chatRepository.updateChat(chatModel).blockingAwait();
|
||||||
|
|
||||||
|
chatModel.setActive(false);
|
||||||
|
chatRepository.updateChat(chatModel).blockingAwait();
|
||||||
|
|
||||||
|
chatModel.setActive(true);
|
||||||
|
chatRepository.updateChat(chatModel).blockingAwait();
|
||||||
|
|
||||||
|
Thread.sleep(100);
|
||||||
|
|
||||||
|
disposable.dispose();
|
||||||
|
|
||||||
|
Thread.sleep(100);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package org.mercury_im.messenger.persistence.room;
|
package org.mercury_im.messenger.persistence.room;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import androidx.room.Database;
|
import androidx.room.Database;
|
||||||
import androidx.room.Room;
|
import androidx.room.Room;
|
||||||
|
@ -43,6 +42,8 @@ public abstract class AppDatabase extends RoomDatabase {
|
||||||
private static final String DB_NAME = "mercury_db";
|
private static final String DB_NAME = "mercury_db";
|
||||||
private static AppDatabase INSTANCE;
|
private static AppDatabase INSTANCE;
|
||||||
|
|
||||||
|
public static final String TAG = "PERSISTENCE_ROOM";
|
||||||
|
|
||||||
public static AppDatabase getDatabase(final Context context) {
|
public static AppDatabase getDatabase(final Context context) {
|
||||||
if (INSTANCE == null) {
|
if (INSTANCE == null) {
|
||||||
Logger.getLogger("DATABASE").log(Level.INFO, context.getApplicationContext().getDatabasePath(DB_NAME).getAbsolutePath());
|
Logger.getLogger("DATABASE").log(Level.INFO, context.getApplicationContext().getDatabasePath(DB_NAME).getAbsolutePath());
|
||||||
|
|
|
@ -3,9 +3,9 @@ package org.mercury_im.messenger.persistence.room;
|
||||||
import org.mercury_im.messenger.persistence.repository.AccountRepository;
|
import org.mercury_im.messenger.persistence.repository.AccountRepository;
|
||||||
import org.mercury_im.messenger.persistence.repository.AvatarRepository;
|
import org.mercury_im.messenger.persistence.repository.AvatarRepository;
|
||||||
import org.mercury_im.messenger.persistence.repository.ChatRepository;
|
import org.mercury_im.messenger.persistence.repository.ChatRepository;
|
||||||
import org.mercury_im.messenger.persistence.repository.RosterRepository;
|
|
||||||
import org.mercury_im.messenger.persistence.repository.EntityCapsRepository;
|
import org.mercury_im.messenger.persistence.repository.EntityCapsRepository;
|
||||||
import org.mercury_im.messenger.persistence.repository.MessageRepository;
|
import org.mercury_im.messenger.persistence.repository.MessageRepository;
|
||||||
|
import org.mercury_im.messenger.persistence.repository.RosterRepository;
|
||||||
import org.mercury_im.messenger.persistence.room.dao.AccountDao;
|
import org.mercury_im.messenger.persistence.room.dao.AccountDao;
|
||||||
import org.mercury_im.messenger.persistence.room.dao.AvatarDao;
|
import org.mercury_im.messenger.persistence.room.dao.AvatarDao;
|
||||||
import org.mercury_im.messenger.persistence.room.dao.ChatDao;
|
import org.mercury_im.messenger.persistence.room.dao.ChatDao;
|
||||||
|
@ -17,9 +17,9 @@ import org.mercury_im.messenger.persistence.room.dao.RosterInformationDao;
|
||||||
import org.mercury_im.messenger.persistence.room.repository.IAccountRepository;
|
import org.mercury_im.messenger.persistence.room.repository.IAccountRepository;
|
||||||
import org.mercury_im.messenger.persistence.room.repository.IAvatarRepository;
|
import org.mercury_im.messenger.persistence.room.repository.IAvatarRepository;
|
||||||
import org.mercury_im.messenger.persistence.room.repository.IChatRepository;
|
import org.mercury_im.messenger.persistence.room.repository.IChatRepository;
|
||||||
import org.mercury_im.messenger.persistence.room.repository.IRosterRepository;
|
|
||||||
import org.mercury_im.messenger.persistence.room.repository.IEntityCapsRepository;
|
import org.mercury_im.messenger.persistence.room.repository.IEntityCapsRepository;
|
||||||
import org.mercury_im.messenger.persistence.room.repository.IMessageRepository;
|
import org.mercury_im.messenger.persistence.room.repository.IMessageRepository;
|
||||||
|
import org.mercury_im.messenger.persistence.room.repository.IRosterRepository;
|
||||||
|
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
@ -37,8 +37,8 @@ public class RoomRepositoryModule {
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@Provides
|
@Provides
|
||||||
ChatRepository provideChatRepository(ChatDao chatDao, EntityDao entityDao) {
|
ChatRepository provideChatRepository(ChatDao chatDao, RosterRepository rosterRepository) {
|
||||||
return new IChatRepository(chatDao, entityDao);
|
return new IChatRepository(chatDao, rosterRepository);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
|
|
|
@ -36,7 +36,10 @@ public interface AccountDao extends BaseDao<RoomAccountModel> {
|
||||||
* @return account or null
|
* @return account or null
|
||||||
*/
|
*/
|
||||||
@Query("select * from accounts where pk_account_id = :id")
|
@Query("select * from accounts where pk_account_id = :id")
|
||||||
Maybe<RoomAccountModel> getAccountById(long id);
|
Maybe<RoomAccountModel> maybeGetAccountById(long id);
|
||||||
|
|
||||||
|
@Query("select * from accounts where pk_account_id = :id")
|
||||||
|
Observable<RoomAccountModel> getAccountById(long id);
|
||||||
|
|
||||||
@Query("select * from accounts where jid = :jid")
|
@Query("select * from accounts where jid = :jid")
|
||||||
Maybe<RoomAccountModel> getAccountByJid(EntityBareJid jid);
|
Maybe<RoomAccountModel> getAccountByJid(EntityBareJid jid);
|
||||||
|
|
|
@ -2,16 +2,27 @@ package org.mercury_im.messenger.persistence.room.dao;
|
||||||
|
|
||||||
import androidx.room.Delete;
|
import androidx.room.Delete;
|
||||||
import androidx.room.Insert;
|
import androidx.room.Insert;
|
||||||
|
import androidx.room.OnConflictStrategy;
|
||||||
|
import androidx.room.Transaction;
|
||||||
import androidx.room.Update;
|
import androidx.room.Update;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import io.reactivex.Completable;
|
import io.reactivex.Completable;
|
||||||
|
import io.reactivex.Observable;
|
||||||
import io.reactivex.Single;
|
import io.reactivex.Single;
|
||||||
|
|
||||||
public interface BaseDao<T> {
|
public interface BaseDao<T> {
|
||||||
|
|
||||||
@Insert
|
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||||
Single<Long> insert(T entity);
|
Single<Long> insert(T entity);
|
||||||
|
|
||||||
|
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||||
|
Single<Long[]> insert(T[] entities);
|
||||||
|
|
||||||
|
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||||
|
Single<List<Long>> insert(List<T> entities);
|
||||||
|
|
||||||
@Update
|
@Update
|
||||||
Completable update(T entity);
|
Completable update(T entity);
|
||||||
|
|
||||||
|
@ -23,4 +34,7 @@ public interface BaseDao<T> {
|
||||||
|
|
||||||
@Delete
|
@Delete
|
||||||
Completable delete(T[] entities);
|
Completable delete(T[] entities);
|
||||||
|
|
||||||
|
@Delete
|
||||||
|
Completable delete(List<T> entities);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import java.util.List;
|
||||||
|
|
||||||
import io.reactivex.Maybe;
|
import io.reactivex.Maybe;
|
||||||
import io.reactivex.Observable;
|
import io.reactivex.Observable;
|
||||||
|
import io.reactivex.Single;
|
||||||
|
|
||||||
@Dao
|
@Dao
|
||||||
@TypeConverters(EntityBareJidConverter.class)
|
@TypeConverters(EntityBareJidConverter.class)
|
||||||
|
@ -22,26 +23,23 @@ public interface ChatDao extends BaseDao<RoomChatModel> {
|
||||||
Observable<List<RoomChatModel>> getAllChats();
|
Observable<List<RoomChatModel>> getAllChats();
|
||||||
|
|
||||||
@Query("SELECT chats.* FROM chats JOIN entities WHERE fk_account_id = :accountId")
|
@Query("SELECT chats.* FROM chats JOIN entities WHERE fk_account_id = :accountId")
|
||||||
Observable<List<RoomChatModel>> getAllChatsOf(long accountId);
|
Observable<List<RoomChatModel>> getAllChatsOfAccount(long accountId);
|
||||||
|
|
||||||
@Query("SELECT * FROM chats WHERE fk_entity_id = :entityId")
|
@Query("SELECT * FROM chats WHERE fk_entity_id = :entityId")
|
||||||
Maybe<RoomChatModel> getChatWithIdentity(long entityId);
|
Maybe<RoomChatModel> maybeGetChatWithEntity(long entityId);
|
||||||
|
|
||||||
|
@Query("SELECT * FROM chats WHERE fk_entity_id = :entityId")
|
||||||
|
Observable<RoomChatModel> getChatWithEntity(long entityId);
|
||||||
|
|
||||||
@Query("SELECT chats.* FROM chats JOIN entities WHERE fk_account_id = :accountId AND jid = :jid")
|
@Query("SELECT chats.* FROM chats JOIN entities WHERE fk_account_id = :accountId AND jid = :jid")
|
||||||
Maybe<RoomChatModel> getChatWithJid(long accountId, EntityBareJid jid);
|
Maybe<RoomChatModel> maybeGetChatWithJid(long accountId, EntityBareJid jid);
|
||||||
|
|
||||||
|
@Query("SELECT chats.* FROM chats JOIN entities WHERE fk_account_id = :accountId AND jid = :jid")
|
||||||
|
Observable<RoomChatModel> getChatWithJid(long accountId, EntityBareJid jid);
|
||||||
|
|
||||||
@Query("SELECT chats.* FROM chats JOIN contacts WHERE contacts.pk_contact_id = :contactId")
|
@Query("SELECT chats.* FROM chats JOIN contacts WHERE contacts.pk_contact_id = :contactId")
|
||||||
Maybe<RoomChatModel> getChatWithContact(long contactId);
|
Maybe<RoomChatModel> maybeGetChatWithContact(long contactId);
|
||||||
|
|
||||||
@Query("SELECT chats.* FROM chats JOIN entities WHERE fk_account_id = :accountId AND jid = :jid")
|
|
||||||
Observable<RoomChatModel> getObservableChatWithJid(long accountId, EntityBareJid jid);
|
|
||||||
|
|
||||||
@Query("SELECT " +
|
|
||||||
"pk_chat_id as chatId, " +
|
|
||||||
"fk_entity_id as entityId, " +
|
|
||||||
"active, " +
|
|
||||||
"jid " +
|
|
||||||
"FROM chats INNER JOIN entities")
|
|
||||||
Observable<Chat> getChat();
|
|
||||||
|
|
||||||
|
@Query("SELECT chats.* FROM chats JOIN contacts WHERE contacts.pk_contact_id = :contactId")
|
||||||
|
Observable<RoomChatModel> getChatWithContact(long contactId);
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,10 +37,11 @@ public interface ContactDao extends BaseDao<RoomContactModel> {
|
||||||
Observable<List<RoomContactModel>> getAllContacts();
|
Observable<List<RoomContactModel>> getAllContacts();
|
||||||
|
|
||||||
@Query("SELECT contacts.* FROM contacts JOIN entities " +
|
@Query("SELECT contacts.* FROM contacts JOIN entities " +
|
||||||
"WHERE contacts.fk_account_id = :accountId AND jid = :jid")
|
"WHERE entities.fk_account_id = :accountId AND jid = :jid")
|
||||||
Maybe<RoomContactModel> getContactByJid(long accountId, EntityBareJid jid);
|
Maybe<RoomContactModel> getContactByJid(long accountId, EntityBareJid jid);
|
||||||
|
|
||||||
@Query("SELECT * FROM contacts WHERE fk_account_id = :accountId")
|
@Query("SELECT contacts.* FROM contacts JOIN entities " +
|
||||||
|
"WHERE entities.fk_account_id = :accountId")
|
||||||
Observable<List<RoomContactModel>> getContactsForAccount(long accountId);
|
Observable<List<RoomContactModel>> getContactsForAccount(long accountId);
|
||||||
|
|
||||||
@Query("DELETE FROM contacts WHERE pk_contact_id = :id")
|
@Query("DELETE FROM contacts WHERE pk_contact_id = :id")
|
||||||
|
@ -52,12 +53,15 @@ public interface ContactDao extends BaseDao<RoomContactModel> {
|
||||||
@Query("DELETE FROM contacts")
|
@Query("DELETE FROM contacts")
|
||||||
Completable deleteAll();
|
Completable deleteAll();
|
||||||
|
|
||||||
@Query("DELETE FROM contacts WHERE fk_account_id = :accountId")
|
@Query("DELETE FROM contacts WHERE fk_entity_id IN " +
|
||||||
|
"(SELECT pk_entity_id FROM entities " +
|
||||||
|
"WHERE entities.fk_account_id = :accountId)")
|
||||||
Completable deleteAllForAccount(long accountId);
|
Completable deleteAllForAccount(long accountId);
|
||||||
|
|
||||||
@Query("DELETE FROM contacts WHERE pk_contact_id IN(:ids)")
|
@Query("DELETE FROM contacts WHERE pk_contact_id IN(:ids)")
|
||||||
Completable deleteContacts(long[] ids);
|
Completable deleteContacts(long[] ids);
|
||||||
|
|
||||||
@Query("SELECT entities.* FROM contacts INNER JOIN entities ON contacts.fk_entity_id = entities.pk_entity_id WHERE contacts.pk_contact_id = :contactId")
|
@Query("SELECT entities.* FROM contacts INNER JOIN entities ON contacts.fk_entity_id = entities.pk_entity_id " +
|
||||||
|
"WHERE contacts.pk_contact_id = :contactId")
|
||||||
Single<RoomEntityModel> getEntityForContactId(long contactId);
|
Single<RoomEntityModel> getEntityForContactId(long contactId);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,6 @@ package org.mercury_im.messenger.persistence.room.dao;
|
||||||
|
|
||||||
import androidx.annotation.WorkerThread;
|
import androidx.annotation.WorkerThread;
|
||||||
import androidx.room.Dao;
|
import androidx.room.Dao;
|
||||||
import androidx.room.Delete;
|
|
||||||
import androidx.room.Insert;
|
|
||||||
import androidx.room.Query;
|
import androidx.room.Query;
|
||||||
|
|
||||||
import org.mercury_im.messenger.persistence.room.model.RoomEntityCapsModel;
|
import org.mercury_im.messenger.persistence.room.model.RoomEntityCapsModel;
|
||||||
|
@ -11,31 +9,18 @@ import org.mercury_im.messenger.persistence.room.model.RoomEntityCapsModel;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import io.reactivex.Completable;
|
import io.reactivex.Completable;
|
||||||
|
import io.reactivex.Observable;
|
||||||
import io.reactivex.Single;
|
import io.reactivex.Single;
|
||||||
|
|
||||||
import static androidx.room.OnConflictStrategy.REPLACE;
|
|
||||||
|
|
||||||
@Dao
|
@Dao
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
public interface EntityCapsDao {
|
public interface EntityCapsDao extends BaseDao<RoomEntityCapsModel> {
|
||||||
|
|
||||||
@Query("SELECT * FROM entity_caps WHERE pk_node_ver = :nodeVer")
|
@Query("SELECT * FROM entity_caps WHERE pk_node_ver = :nodeVer")
|
||||||
Single<RoomEntityCapsModel> getEntityCapsForNodeVer(String nodeVer);
|
Single<RoomEntityCapsModel> getEntityCapsForNodeVer(String nodeVer);
|
||||||
|
|
||||||
@Query("SELECT * FROM entity_caps")
|
@Query("SELECT * FROM entity_caps")
|
||||||
Single<List<RoomEntityCapsModel>> getAllEntityCaps();
|
Observable<List<RoomEntityCapsModel>> getAllEntityCaps();
|
||||||
|
|
||||||
@Insert(onConflict = REPLACE)
|
|
||||||
Completable insert(List<RoomEntityCapsModel> models);
|
|
||||||
|
|
||||||
@Insert(onConflict = REPLACE)
|
|
||||||
Completable insert(RoomEntityCapsModel model);
|
|
||||||
|
|
||||||
@Delete
|
|
||||||
Completable delete(List<RoomEntityCapsModel> models);
|
|
||||||
|
|
||||||
@Delete
|
|
||||||
Completable delete(RoomEntityCapsModel model);
|
|
||||||
|
|
||||||
@Query("DELETE FROM entity_caps")
|
@Query("DELETE FROM entity_caps")
|
||||||
Completable deleteAllEntityCaps();
|
Completable deleteAllEntityCaps();
|
||||||
|
|
|
@ -18,10 +18,6 @@ import static androidx.room.OnConflictStrategy.REPLACE;
|
||||||
@TypeConverters(EntityBareJidConverter.class)
|
@TypeConverters(EntityBareJidConverter.class)
|
||||||
public interface EntityDao extends BaseDao<RoomEntityModel> {
|
public interface EntityDao extends BaseDao<RoomEntityModel> {
|
||||||
|
|
||||||
@Override
|
|
||||||
@Insert(onConflict = REPLACE)
|
|
||||||
Single<Long> insert(RoomEntityModel entity);
|
|
||||||
|
|
||||||
@Query("SELECT * FROM entities WHERE pk_entity_id = :id")
|
@Query("SELECT * FROM entities WHERE pk_entity_id = :id")
|
||||||
Maybe<RoomEntityModel> getEntity(long id);
|
Maybe<RoomEntityModel> getEntity(long id);
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package org.mercury_im.messenger.persistence.room.model;
|
package org.mercury_im.messenger.persistence.room.model;
|
||||||
|
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.room.ColumnInfo;
|
import androidx.room.ColumnInfo;
|
||||||
import androidx.room.Entity;
|
import androidx.room.Entity;
|
||||||
import androidx.room.Index;
|
import androidx.room.Index;
|
||||||
|
@ -48,8 +49,9 @@ public class RoomAccountModel extends AbstractAccountModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setId(long id) {
|
public RoomAccountModel setId(long id) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -91,4 +93,16 @@ public class RoomAccountModel extends AbstractAccountModel {
|
||||||
public void setState(String state) {
|
public void setState(String state) {
|
||||||
this.state = state;
|
this.state = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NonNull
|
||||||
|
public String toString() {
|
||||||
|
return "AccountModel[" +
|
||||||
|
KEY_ID + ": " + getId() + ", " +
|
||||||
|
KEY_JID + ": " + (getJid() != null ? getJid().toString() : "null") + ", " +
|
||||||
|
KEY_PASSWORD + ": " + getPassword() + ", " +
|
||||||
|
KEY_ENABLED + ": " + getEnabled() + ", " +
|
||||||
|
KEY_STATE + ": " +getState() +
|
||||||
|
"]";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package org.mercury_im.messenger.persistence.room.model;
|
package org.mercury_im.messenger.persistence.room.model;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.room.ColumnInfo;
|
import androidx.room.ColumnInfo;
|
||||||
import androidx.room.Entity;
|
import androidx.room.Entity;
|
||||||
import androidx.room.ForeignKey;
|
import androidx.room.ForeignKey;
|
||||||
|
@ -30,6 +31,9 @@ public class RoomChatModel implements ChatModel {
|
||||||
|
|
||||||
public static final String KEY_ENTITY = "fk_entity_id";
|
public static final String KEY_ENTITY = "fk_entity_id";
|
||||||
public static final String KEY_ACTIVE = "active";
|
public static final String KEY_ACTIVE = "active";
|
||||||
|
public static final String KEY_LAST_READ_MSG = "last_read_message";
|
||||||
|
public static final String KEY_MOST_RECENT_MAM_MSG = "most_recent_mam_msg";
|
||||||
|
public static final String KEY_EARLIEST_MAM_MSG = "earliest_mam_msg";
|
||||||
|
|
||||||
@PrimaryKey(autoGenerate = true)
|
@PrimaryKey(autoGenerate = true)
|
||||||
@ColumnInfo(name = KEY_ID)
|
@ColumnInfo(name = KEY_ID)
|
||||||
|
@ -41,6 +45,15 @@ public class RoomChatModel implements ChatModel {
|
||||||
@ColumnInfo(name = KEY_ACTIVE)
|
@ColumnInfo(name = KEY_ACTIVE)
|
||||||
private boolean isActive;
|
private boolean isActive;
|
||||||
|
|
||||||
|
@ColumnInfo(name = KEY_LAST_READ_MSG)
|
||||||
|
private long lastReadMessageId;
|
||||||
|
|
||||||
|
@ColumnInfo(name = KEY_MOST_RECENT_MAM_MSG)
|
||||||
|
private String mostRecentMamMessageId;
|
||||||
|
|
||||||
|
@ColumnInfo(name = KEY_EARLIEST_MAM_MSG)
|
||||||
|
private String earliestMamMessageId;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getId() {
|
public long getId() {
|
||||||
return id;
|
return id;
|
||||||
|
@ -70,4 +83,44 @@ public class RoomChatModel implements ChatModel {
|
||||||
public void setActive(boolean active) {
|
public void setActive(boolean active) {
|
||||||
this.isActive = active;
|
this.isActive = active;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getLastReadMessageId() {
|
||||||
|
return lastReadMessageId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setLastReadMessageId(long messageId) {
|
||||||
|
this.lastReadMessageId = messageId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMostRecentMamMessageId() {
|
||||||
|
return mostRecentMamMessageId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setMostRecentMamMessageId(String uid) {
|
||||||
|
this.mostRecentMamMessageId = uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getEarliestMamMessageId() {
|
||||||
|
return earliestMamMessageId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setEarliestMamMessageId(String uid) {
|
||||||
|
this.earliestMamMessageId = uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NonNull
|
||||||
|
public String toString() {
|
||||||
|
return "ChatModel[" +
|
||||||
|
KEY_ID + ": " + getId() + ", " +
|
||||||
|
KEY_ENTITY + ": " + getPeerEntityId() + ", " +
|
||||||
|
KEY_ACTIVE + ": " + isActive() +
|
||||||
|
"]";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package org.mercury_im.messenger.persistence.room.model;
|
package org.mercury_im.messenger.persistence.room.model;
|
||||||
|
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.room.ColumnInfo;
|
import androidx.room.ColumnInfo;
|
||||||
import androidx.room.Entity;
|
import androidx.room.Entity;
|
||||||
import androidx.room.ForeignKey;
|
import androidx.room.ForeignKey;
|
||||||
|
@ -13,9 +14,7 @@ import org.mercury_im.messenger.persistence.model.ContactModel;
|
||||||
import org.mercury_im.messenger.persistence.model.EntityModel;
|
import org.mercury_im.messenger.persistence.model.EntityModel;
|
||||||
import org.mercury_im.messenger.persistence.room.type_converter.DirectionConverter;
|
import org.mercury_im.messenger.persistence.room.type_converter.DirectionConverter;
|
||||||
|
|
||||||
import static androidx.room.ForeignKey.CASCADE;
|
|
||||||
import static androidx.room.ForeignKey.RESTRICT;
|
import static androidx.room.ForeignKey.RESTRICT;
|
||||||
import static org.mercury_im.messenger.persistence.room.model.RoomContactModel.KEY_ACCOUNT_ID;
|
|
||||||
import static org.mercury_im.messenger.persistence.room.model.RoomContactModel.KEY_ID;
|
import static org.mercury_im.messenger.persistence.room.model.RoomContactModel.KEY_ID;
|
||||||
import static org.mercury_im.messenger.persistence.room.model.RoomContactModel.KEY_ENTITY_ID;
|
import static org.mercury_im.messenger.persistence.room.model.RoomContactModel.KEY_ENTITY_ID;
|
||||||
import static org.mercury_im.messenger.persistence.room.model.RoomContactModel.TABLE;
|
import static org.mercury_im.messenger.persistence.room.model.RoomContactModel.TABLE;
|
||||||
|
@ -23,15 +22,10 @@ import static org.mercury_im.messenger.persistence.room.model.RoomContactModel.T
|
||||||
@Entity(tableName = TABLE,
|
@Entity(tableName = TABLE,
|
||||||
indices = {
|
indices = {
|
||||||
@Index(value = KEY_ID),
|
@Index(value = KEY_ID),
|
||||||
@Index(value = KEY_ACCOUNT_ID),
|
|
||||||
@Index(value = KEY_ENTITY_ID, unique = true),
|
@Index(value = KEY_ENTITY_ID, unique = true),
|
||||||
@Index(value = {KEY_ID, KEY_ENTITY_ID}, unique = true)
|
@Index(value = {KEY_ID, KEY_ENTITY_ID}, unique = true)
|
||||||
},
|
},
|
||||||
foreignKeys = {
|
foreignKeys = {
|
||||||
@ForeignKey(entity = RoomAccountModel.class,
|
|
||||||
parentColumns = RoomAccountModel.KEY_ID,
|
|
||||||
childColumns = KEY_ACCOUNT_ID,
|
|
||||||
onDelete = CASCADE),
|
|
||||||
@ForeignKey(entity = RoomEntityModel.class,
|
@ForeignKey(entity = RoomEntityModel.class,
|
||||||
parentColumns = RoomEntityModel.KEY_ID,
|
parentColumns = RoomEntityModel.KEY_ID,
|
||||||
childColumns = KEY_ENTITY_ID,
|
childColumns = KEY_ENTITY_ID,
|
||||||
|
@ -40,21 +34,17 @@ public class RoomContactModel implements ContactModel {
|
||||||
|
|
||||||
public static final String TABLE = "contacts";
|
public static final String TABLE = "contacts";
|
||||||
public static final String KEY_ID = "pk_contact_id";
|
public static final String KEY_ID = "pk_contact_id";
|
||||||
public static final String KEY_ACCOUNT_ID = "fk_account_id";
|
|
||||||
public static final String KEY_ENTITY_ID = "fk_entity_id";
|
public static final String KEY_ENTITY_ID = "fk_entity_id";
|
||||||
public static final String KEY_ROSTER_NAME = "rostername";
|
public static final String KEY_ROSTER_NAME = "rostername";
|
||||||
public static final String KEY_NICKNAME = "nickname";
|
public static final String KEY_NICKNAME = "nickname";
|
||||||
public static final String KEY_DIRECTION = "direction";
|
public static final String KEY_SUB_DIRECTION = "direction";
|
||||||
public static final String KEY_SUB_PENDING = "sub_pending";
|
public static final String KEY_SUB_PENDING = "sub_pending";
|
||||||
public static final String KEY_APPROVED = "approved";
|
public static final String KEY_SUB_APPROVED = "approved";
|
||||||
|
|
||||||
@PrimaryKey(autoGenerate = true)
|
@PrimaryKey(autoGenerate = true)
|
||||||
@ColumnInfo(name = KEY_ID)
|
@ColumnInfo(name = KEY_ID)
|
||||||
private long id;
|
private long id;
|
||||||
|
|
||||||
@ColumnInfo(name = KEY_ACCOUNT_ID)
|
|
||||||
private long accountId;
|
|
||||||
|
|
||||||
@ColumnInfo(name = KEY_ENTITY_ID)
|
@ColumnInfo(name = KEY_ENTITY_ID)
|
||||||
private long entityId;
|
private long entityId;
|
||||||
|
|
||||||
|
@ -64,14 +54,14 @@ public class RoomContactModel implements ContactModel {
|
||||||
@ColumnInfo(name = KEY_NICKNAME)
|
@ColumnInfo(name = KEY_NICKNAME)
|
||||||
private String nickname;
|
private String nickname;
|
||||||
|
|
||||||
@ColumnInfo(name = KEY_DIRECTION)
|
@ColumnInfo(name = KEY_SUB_DIRECTION)
|
||||||
@TypeConverters(DirectionConverter.class)
|
@TypeConverters(DirectionConverter.class)
|
||||||
private DIRECTION direction;
|
private DIRECTION direction;
|
||||||
|
|
||||||
@ColumnInfo(name = KEY_SUB_PENDING)
|
@ColumnInfo(name = KEY_SUB_PENDING)
|
||||||
private boolean subscriptionPending;
|
private boolean subscriptionPending;
|
||||||
|
|
||||||
@ColumnInfo(name = KEY_APPROVED)
|
@ColumnInfo(name = KEY_SUB_APPROVED)
|
||||||
private boolean approved;
|
private boolean approved;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -91,16 +81,6 @@ public class RoomContactModel implements ContactModel {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getAccountId() {
|
|
||||||
return accountId;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setAccountId(long accountId) {
|
|
||||||
this.accountId = accountId;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getEntityId() {
|
public long getEntityId() {
|
||||||
return entityId;
|
return entityId;
|
||||||
|
@ -169,5 +149,20 @@ public class RoomContactModel implements ContactModel {
|
||||||
@Override
|
@Override
|
||||||
public void setEntity(EntityModel entity) {
|
public void setEntity(EntityModel entity) {
|
||||||
this.entityModel = entity;
|
this.entityModel = entity;
|
||||||
|
this.entityId = entity.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NonNull
|
||||||
|
public String toString() {
|
||||||
|
return "ContactModel[" +
|
||||||
|
KEY_ID + ": " + getId() + ", " +
|
||||||
|
KEY_ENTITY_ID + ": " + getEntityId() + ", " +
|
||||||
|
KEY_ROSTER_NAME + ": " + getRosterName() + ", " +
|
||||||
|
KEY_NICKNAME + ": " + getNickname() + ", " +
|
||||||
|
KEY_SUB_DIRECTION + ": " + getDirection() + ", " +
|
||||||
|
KEY_SUB_PENDING + ": " + isSubscriptionPending() + ", " +
|
||||||
|
KEY_SUB_APPROVED + ": " + isApproved() +
|
||||||
|
"]";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,6 @@ public class RoomEntityModel implements EntityModel {
|
||||||
public static final String KEY_ID = "pk_entity_id";
|
public static final String KEY_ID = "pk_entity_id";
|
||||||
public static final String KEY_ACCOUNT_ID = "fk_account_id";
|
public static final String KEY_ACCOUNT_ID = "fk_account_id";
|
||||||
public static final String KEY_JID = "jid";
|
public static final String KEY_JID = "jid";
|
||||||
public static final String KEY_AVATAR = "avatar";
|
|
||||||
|
|
||||||
@PrimaryKey(autoGenerate = true)
|
@PrimaryKey(autoGenerate = true)
|
||||||
@ColumnInfo(name = KEY_ID)
|
@ColumnInfo(name = KEY_ID)
|
||||||
|
@ -82,4 +81,14 @@ public class RoomEntityModel implements EntityModel {
|
||||||
public void setAccountId(long accountId) {
|
public void setAccountId(long accountId) {
|
||||||
this.accountId = accountId;
|
this.accountId = accountId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NonNull
|
||||||
|
public String toString() {
|
||||||
|
return "EntityModel[" +
|
||||||
|
KEY_ID + ": " + getId() + ", " +
|
||||||
|
KEY_ACCOUNT_ID + ": " + getAccountId() + ", " +
|
||||||
|
KEY_JID + ": " + getJid().toString() +
|
||||||
|
"]";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package org.mercury_im.messenger.persistence.room.model;
|
package org.mercury_im.messenger.persistence.room.model;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.room.ColumnInfo;
|
import androidx.room.ColumnInfo;
|
||||||
import androidx.room.Entity;
|
import androidx.room.Entity;
|
||||||
import androidx.room.Index;
|
import androidx.room.Index;
|
||||||
|
@ -45,4 +46,13 @@ public class RoomRosterInformationModel implements RosterInformationModel {
|
||||||
public void setRosterVersion(String rosterVersion) {
|
public void setRosterVersion(String rosterVersion) {
|
||||||
this.rosterVersion = rosterVersion;
|
this.rosterVersion = rosterVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NonNull
|
||||||
|
public String toString() {
|
||||||
|
return "RosterInformationModel[" +
|
||||||
|
KEY_ID + ": " + getAccountId() + ", " +
|
||||||
|
KEY_ROSTER_VERSION + ": " + getRosterVersion() +
|
||||||
|
"]";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,5 +6,5 @@ public class Chat {
|
||||||
public long chatId;
|
public long chatId;
|
||||||
public long entityId;
|
public long entityId;
|
||||||
public EntityBareJid jid;
|
public EntityBareJid jid;
|
||||||
|
public boolean active;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
package org.mercury_im.messenger.persistence.room.repository;
|
package org.mercury_im.messenger.persistence.room.repository;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import org.mercury_im.messenger.persistence.repository.AccountRepository;
|
import org.mercury_im.messenger.persistence.repository.AccountRepository;
|
||||||
import org.mercury_im.messenger.persistence.room.dao.AccountDao;
|
import org.mercury_im.messenger.persistence.room.dao.AccountDao;
|
||||||
import org.mercury_im.messenger.persistence.room.model.RoomAccountModel;
|
import org.mercury_im.messenger.persistence.room.model.RoomAccountModel;
|
||||||
|
@ -13,6 +17,8 @@ import io.reactivex.Maybe;
|
||||||
import io.reactivex.Observable;
|
import io.reactivex.Observable;
|
||||||
import io.reactivex.Single;
|
import io.reactivex.Single;
|
||||||
|
|
||||||
|
import static org.mercury_im.messenger.persistence.room.AppDatabase.TAG;
|
||||||
|
|
||||||
public class IAccountRepository implements AccountRepository<RoomAccountModel> {
|
public class IAccountRepository implements AccountRepository<RoomAccountModel> {
|
||||||
|
|
||||||
private final AccountDao accountDao;
|
private final AccountDao accountDao;
|
||||||
|
@ -28,10 +34,15 @@ public class IAccountRepository implements AccountRepository<RoomAccountModel> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Maybe<RoomAccountModel> getAccount(long accountId) {
|
public Observable<RoomAccountModel> getAccount(long accountId) {
|
||||||
return accountDao.getAccountById(accountId);
|
return accountDao.getAccountById(accountId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Maybe<RoomAccountModel> maybeGetAccount(long accountId) {
|
||||||
|
return accountDao.maybeGetAccountById(accountId);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Observable<List<RoomAccountModel>> getAllAccounts() {
|
public Observable<List<RoomAccountModel>> getAllAccounts() {
|
||||||
return accountDao.getAllAccounts();
|
return accountDao.getAllAccounts();
|
||||||
|
@ -39,13 +50,16 @@ public class IAccountRepository implements AccountRepository<RoomAccountModel> {
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Single<Long> insertAccount(RoomAccountModel accountModel) {
|
public Single<Long> insertAccount(@NonNull RoomAccountModel accountModel) {
|
||||||
return accountDao.insert(accountModel);
|
return accountDao.insert(accountModel)
|
||||||
|
.map(accountId -> accountModel.setId(accountId).getId())
|
||||||
|
.doOnSubscribe(ignore -> Log.v(TAG, "Insert " + accountModel))
|
||||||
|
.doAfterSuccess(accountId -> Log.v(TAG, "AccountModel has new ID " + accountId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Completable updateState(long accountId, String state) {
|
public Completable updateAccount(RoomAccountModel accountModel) {
|
||||||
return accountDao.updateConnectionState(accountId, state);
|
return accountDao.update(accountModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,15 +1,13 @@
|
||||||
package org.mercury_im.messenger.persistence.room.repository;
|
package org.mercury_im.messenger.persistence.room.repository;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import org.jxmpp.jid.EntityBareJid;
|
import org.jxmpp.jid.EntityBareJid;
|
||||||
import org.mercury_im.messenger.persistence.model.AccountModel;
|
|
||||||
import org.mercury_im.messenger.persistence.model.ChatModel;
|
|
||||||
import org.mercury_im.messenger.persistence.model.ContactModel;
|
|
||||||
import org.mercury_im.messenger.persistence.model.EntityModel;
|
import org.mercury_im.messenger.persistence.model.EntityModel;
|
||||||
import org.mercury_im.messenger.persistence.repository.ChatRepository;
|
import org.mercury_im.messenger.persistence.repository.ChatRepository;
|
||||||
|
import org.mercury_im.messenger.persistence.repository.RosterRepository;
|
||||||
import org.mercury_im.messenger.persistence.room.dao.ChatDao;
|
import org.mercury_im.messenger.persistence.room.dao.ChatDao;
|
||||||
import org.mercury_im.messenger.persistence.room.dao.EntityDao;
|
|
||||||
import org.mercury_im.messenger.persistence.room.model.RoomChatModel;
|
import org.mercury_im.messenger.persistence.room.model.RoomChatModel;
|
||||||
import org.mercury_im.messenger.persistence.room.model.RoomEntityModel;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -18,21 +16,19 @@ import javax.inject.Inject;
|
||||||
import io.reactivex.Completable;
|
import io.reactivex.Completable;
|
||||||
import io.reactivex.Maybe;
|
import io.reactivex.Maybe;
|
||||||
import io.reactivex.Observable;
|
import io.reactivex.Observable;
|
||||||
import io.reactivex.Scheduler;
|
import io.reactivex.Single;
|
||||||
import io.reactivex.SingleTransformer;
|
|
||||||
import io.reactivex.disposables.Disposable;
|
import static org.mercury_im.messenger.persistence.room.AppDatabase.TAG;
|
||||||
import io.reactivex.functions.Consumer;
|
|
||||||
import io.reactivex.schedulers.Schedulers;
|
|
||||||
|
|
||||||
public class IChatRepository implements ChatRepository<RoomChatModel> {
|
public class IChatRepository implements ChatRepository<RoomChatModel> {
|
||||||
|
|
||||||
private final ChatDao chatDao;
|
private final ChatDao chatDao;
|
||||||
private final EntityDao entityDao;
|
private final RosterRepository rosterRepository;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public IChatRepository(ChatDao chatDao, EntityDao entityDao) {
|
public IChatRepository(ChatDao chatDao, RosterRepository rosterRepository) {
|
||||||
this.chatDao = chatDao;
|
this.chatDao = chatDao;
|
||||||
this.entityDao = entityDao;
|
this.rosterRepository = rosterRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -42,7 +38,36 @@ public class IChatRepository implements ChatRepository<RoomChatModel> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Observable<RoomChatModel> getOrCreateChatWith(long accountId, EntityBareJid jid) {
|
public Observable<RoomChatModel> getOrCreateChatWith(long accountId, EntityBareJid jid) {
|
||||||
|
return Observable.fromCallable(() -> {
|
||||||
|
EntityModel entity = (EntityModel) rosterRepository.getOrCreateEntityForAccountAndJid(accountId, jid).blockingGet();
|
||||||
|
RoomChatModel chat = maybeGetChatWithEntity(entity).blockingGet();
|
||||||
|
if (chat == null) {
|
||||||
|
chat = newChatModel();
|
||||||
|
chat.setPeerEntityId(entity.getId());
|
||||||
|
chat.setId(insertChat(chat).blockingGet());
|
||||||
|
}
|
||||||
|
return chat;
|
||||||
|
}).concatWith(getChatWith(accountId, jid).skip(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Observable<RoomChatModel> getChatWith(long accountId, EntityBareJid jid) {
|
||||||
|
return chatDao.getChatWithJid(accountId, jid);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Observable<RoomChatModel> getChatWithEntity(long entityId) {
|
||||||
|
return chatDao.getChatWithEntity(entityId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Completable updateChat(RoomChatModel chat) {
|
||||||
|
return chatDao.update(chat);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Observable<RoomChatModel> getChatWithContact(long contactId) {
|
||||||
|
return chatDao.getChatWithContact(contactId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -51,27 +76,39 @@ public class IChatRepository implements ChatRepository<RoomChatModel> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Observable<List<RoomChatModel>> getAllChatsOf(AccountModel accountModel) {
|
public Observable<List<RoomChatModel>> getAllChatsOfAccount(long accountId) {
|
||||||
return chatDao.getAllChatsOf(accountModel.getId());
|
return chatDao.getAllChatsOfAccount(accountId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Maybe<RoomChatModel> getChatWith(EntityModel identity) {
|
public Maybe<RoomChatModel> maybeGetChatWith(long accountId, EntityBareJid jid) {
|
||||||
return chatDao.getChatWithIdentity(identity.getId());
|
return chatDao.maybeGetChatWithJid(accountId, jid);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Maybe<RoomChatModel> getChatWith(AccountModel account, EntityBareJid jid) {
|
public Maybe<RoomChatModel> maybeGetChatWithEntity(long entityId) {
|
||||||
return chatDao.getChatWithJid(account.getId(), jid);
|
return chatDao.maybeGetChatWithEntity(entityId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Maybe<RoomChatModel> getChatWith(ContactModel contact) {
|
public Maybe<RoomChatModel> maybeGetChatWithContact(long contactId) {
|
||||||
return chatDao.getChatWithContact(contact.getId());
|
return chatDao.maybeGetChatWithContact(contactId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Single<Long> insertChat(RoomChatModel chat) {
|
||||||
|
return chatDao.insert(chat)
|
||||||
|
.map(chatId -> {
|
||||||
|
chat.setId(chatId);
|
||||||
|
return chatId;
|
||||||
|
})
|
||||||
|
.doOnSubscribe(ignore -> Log.v(TAG, "Insert " + chat))
|
||||||
|
.doAfterSuccess(chatId -> Log.v(TAG, "Assign ID " + chatId + " to " + chat));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Completable closeChat(RoomChatModel chat) {
|
public Completable closeChat(RoomChatModel chat) {
|
||||||
return chatDao.delete(chat);
|
return chatDao.delete(chat);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import java.util.List;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import io.reactivex.Completable;
|
import io.reactivex.Completable;
|
||||||
|
import io.reactivex.Observable;
|
||||||
import io.reactivex.Single;
|
import io.reactivex.Single;
|
||||||
|
|
||||||
|
|
||||||
|
@ -29,7 +30,7 @@ public class IEntityCapsRepository implements EntityCapsRepository<RoomEntityCap
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Single<List<RoomEntityCapsModel>> getAllEntityCaps() {
|
public Observable<List<RoomEntityCapsModel>> getAllEntityCaps() {
|
||||||
return dao.getAllEntityCaps();
|
return dao.getAllEntityCaps();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,12 +40,12 @@ public class IEntityCapsRepository implements EntityCapsRepository<RoomEntityCap
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Completable insertOrReplaceEntityCaps(List<RoomEntityCapsModel> entityCaps) {
|
public Single<List<Long>> insertOrReplaceEntityCaps(List<RoomEntityCapsModel> entityCaps) {
|
||||||
return dao.insert(entityCaps);
|
return dao.insert(entityCaps);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Completable insertOrReplaceEntityCaps(RoomEntityCapsModel entityCaps) {
|
public Single<Long> insertOrReplaceEntityCaps(RoomEntityCapsModel entityCaps) {
|
||||||
return dao.insert(entityCaps);
|
return dao.insert(entityCaps);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,11 @@ public class IMessageRepository implements MessageRepository<RoomMessageModel> {
|
||||||
return messageDao.insert(message);
|
return messageDao.insert(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Single<List<Long>> insertMessages(List<RoomMessageModel> messages) {
|
||||||
|
return messageDao.insert(messages);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Observable<RoomMessageModel> getLastMessageFrom(long accountId, EntityBareJid peer) {
|
public Observable<RoomMessageModel> getLastMessageFrom(long accountId, EntityBareJid peer) {
|
||||||
return messageDao.getLastMessageFrom(accountId, peer);
|
return messageDao.getLastMessageFrom(accountId, peer);
|
||||||
|
|
|
@ -12,18 +12,16 @@ import org.mercury_im.messenger.persistence.room.model.RoomEntityModel;
|
||||||
import org.mercury_im.messenger.persistence.room.model.RoomRosterInformationModel;
|
import org.mercury_im.messenger.persistence.room.model.RoomRosterInformationModel;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import io.reactivex.Completable;
|
import io.reactivex.Completable;
|
||||||
import io.reactivex.CompletableSource;
|
|
||||||
import io.reactivex.Maybe;
|
import io.reactivex.Maybe;
|
||||||
import io.reactivex.Observable;
|
import io.reactivex.Observable;
|
||||||
import io.reactivex.Single;
|
import io.reactivex.Single;
|
||||||
import io.reactivex.SingleObserver;
|
|
||||||
import io.reactivex.SingleSource;
|
import static org.mercury_im.messenger.persistence.room.AppDatabase.TAG;
|
||||||
import io.reactivex.functions.Consumer;
|
|
||||||
import io.reactivex.functions.Function;
|
|
||||||
|
|
||||||
public class IRosterRepository extends RosterRepository<RoomEntityModel, RoomContactModel, RoomRosterInformationModel> {
|
public class IRosterRepository extends RosterRepository<RoomEntityModel, RoomContactModel, RoomRosterInformationModel> {
|
||||||
|
|
||||||
|
@ -72,23 +70,45 @@ public class IRosterRepository extends RosterRepository<RoomEntityModel, RoomCon
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Single<Long> updateOrInsertContact(RoomContactModel contact) {
|
public Single<Long> upsertContact(RoomContactModel contact) {
|
||||||
//noinspection unchecked
|
|
||||||
return entityDao.getEntityFor(contact.getAccountId(), contact.getEntity().getJid())
|
return Single.fromCallable(() -> {
|
||||||
.switchIfEmpty(insertOrReplaceEntity((RoomEntityModel) contact.getEntity())
|
RoomEntityModel existingEntityModel = entityDao
|
||||||
.flatMap(entityId -> {
|
.getEntityFor(contact.getEntity().getAccountId(), contact.getEntity().getJid())
|
||||||
Log.d("Mercury", "Insert entity since maybe did not emit: " + entityId);
|
.blockingGet();
|
||||||
contact.getEntity().setId(entityId);
|
if (existingEntityModel == null) {
|
||||||
return (SingleSource<RoomEntityModel>) observer ->
|
// Insert missing entity
|
||||||
observer.onSuccess((RoomEntityModel) contact.getEntity());
|
existingEntityModel = (RoomEntityModel) contact.getEntity();
|
||||||
}))
|
long entityId = insertEntity(existingEntityModel).blockingGet();
|
||||||
.flatMap(entityModel -> {
|
existingEntityModel.setId(entityId);
|
||||||
contact.setEntityId(entityModel.getId());
|
contact.setEntity(existingEntityModel);
|
||||||
contact.setEntity(entityModel);
|
}
|
||||||
return contactDao.insert(contact);
|
|
||||||
|
RoomContactModel existingContactModel = contactDao.getContactForEntityId(existingEntityModel.getId()).blockingGet();
|
||||||
|
if (existingContactModel == null) {
|
||||||
|
// Insert missing contact
|
||||||
|
existingContactModel = contact;
|
||||||
|
return insertContact(existingContactModel).blockingGet();
|
||||||
|
} else {
|
||||||
|
contactDao.update(contact);
|
||||||
|
}
|
||||||
|
|
||||||
|
return existingContactModel.getId();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Single<Long> insertContact(RoomContactModel contact) {
|
||||||
|
return contactDao.insert(contact)
|
||||||
|
.map(contactId -> {
|
||||||
|
contact.setId(contactId);
|
||||||
|
return contactId;
|
||||||
|
})
|
||||||
|
.doOnSubscribe(ignore -> Log.v(TAG, "Insert " + contact))
|
||||||
|
.doAfterSuccess(cid -> Log.v(TAG, "Assigned ID " + cid + " to " + contact));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Single<RoomEntityModel> getEntityForContact(long contactId) {
|
public Single<RoomEntityModel> getEntityForContact(long contactId) {
|
||||||
Single<RoomEntityModel> s = contactDao.getEntityForContactId(contactId);
|
Single<RoomEntityModel> s = contactDao.getEntityForContactId(contactId);
|
||||||
|
@ -107,6 +127,20 @@ public class IRosterRepository extends RosterRepository<RoomEntityModel, RoomCon
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Single<RoomEntityModel> getOrCreateEntityForAccountAndJid(long accountId, EntityBareJid jid) {
|
||||||
|
return Single.fromCallable(() -> {
|
||||||
|
RoomEntityModel existing = getEntityForAccountAndJid(accountId, jid).blockingGet();
|
||||||
|
if (existing == null) {
|
||||||
|
existing = newEntityModel();
|
||||||
|
existing.setAccountId(accountId);
|
||||||
|
existing.setJid(jid);
|
||||||
|
existing.setId(insertEntity(existing).blockingGet());
|
||||||
|
}
|
||||||
|
return existing;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Maybe<RoomContactModel> getContactForEntity(long entityId) {
|
public Maybe<RoomContactModel> getContactForEntity(long entityId) {
|
||||||
return contactDao.getContactForEntityId(entityId)
|
return contactDao.getContactForEntityId(entityId)
|
||||||
|
@ -133,13 +167,8 @@ public class IRosterRepository extends RosterRepository<RoomEntityModel, RoomCon
|
||||||
public Completable deleteContact(long accountId, EntityBareJid jid) {
|
public Completable deleteContact(long accountId, EntityBareJid jid) {
|
||||||
// Since Room does not support "DELETE x FROM X x INNER JOIN Y...", we have to get the
|
// Since Room does not support "DELETE x FROM X x INNER JOIN Y...", we have to get the
|
||||||
// entity for the jid first and then delete by using its entityId
|
// entity for the jid first and then delete by using its entityId
|
||||||
final Maybe<RoomEntityModel> entity = getEntity(accountId, jid.asEntityBareJidOrThrow());
|
final Maybe<RoomEntityModel> entity = getEntityForAccountAndJid(accountId, jid.asEntityBareJidOrThrow());
|
||||||
return entity.flatMapCompletable(new Function<RoomEntityModel, CompletableSource>() {
|
return entity.flatMapCompletable(entityModel -> contactDao.deleteContactForEntity(entityModel.getId()));
|
||||||
@Override
|
|
||||||
public CompletableSource apply(RoomEntityModel entityModel) {
|
|
||||||
return contactDao.deleteContactForEntity(entityModel.getId());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -173,7 +202,8 @@ public class IRosterRepository extends RosterRepository<RoomEntityModel, RoomCon
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Single<Long> updateRosterInformation(RoomRosterInformationModel rosterInformation) {
|
public Single<Long> updateRosterInformation(RoomRosterInformationModel rosterInformation) {
|
||||||
return rosterInformationDao.insertRosterInformation(rosterInformation);
|
return rosterInformationDao.insertRosterInformation(rosterInformation)
|
||||||
|
.doOnSubscribe(ignore -> Log.v(TAG, "Insert " + rosterInformation));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -191,13 +221,18 @@ public class IRosterRepository extends RosterRepository<RoomEntityModel, RoomCon
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Maybe<RoomEntityModel> getEntity(long accountId, EntityBareJid jid) {
|
public Maybe<RoomEntityModel> getEntityForAccountAndJid(long accountId, EntityBareJid jid) {
|
||||||
return entityDao.getEntityFor(accountId, jid);
|
return entityDao.getEntityFor(accountId, jid);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public Single<Long> insertEntity(RoomEntityModel entityModel) {
|
||||||
public Single<Long> insertOrReplaceEntity(RoomEntityModel entity) {
|
return entityDao.insert(entityModel)
|
||||||
return entityDao.insert(entity);
|
.map(entityId -> {
|
||||||
|
entityModel.setId(entityId);
|
||||||
|
return entityId;
|
||||||
|
})
|
||||||
|
.doOnSubscribe(ignore -> Log.v(TAG, "Insert " + entityModel))
|
||||||
|
.doAfterSuccess(entityId -> Log.v(TAG, "Assign ID " + entityId + " to " + entityModel));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ public interface AccountModel {
|
||||||
*
|
*
|
||||||
* @param id account id
|
* @param id account id
|
||||||
*/
|
*/
|
||||||
void setId(long id);
|
AccountModel setId(long id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the password of the XMPP account.
|
* Return the password of the XMPP account.
|
||||||
|
|
|
@ -13,4 +13,16 @@ public interface ChatModel {
|
||||||
boolean isActive();
|
boolean isActive();
|
||||||
|
|
||||||
void setActive(boolean opened);
|
void setActive(boolean opened);
|
||||||
|
|
||||||
|
long getLastReadMessageId();
|
||||||
|
|
||||||
|
void setLastReadMessageId(long messageId);
|
||||||
|
|
||||||
|
String getMostRecentMamMessageId();
|
||||||
|
|
||||||
|
void setMostRecentMamMessageId(String uid);
|
||||||
|
|
||||||
|
String getEarliestMamMessageId();
|
||||||
|
|
||||||
|
void setEarliestMamMessageId(String uid);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,10 +6,6 @@ public interface ContactModel<E extends EntityModel> {
|
||||||
|
|
||||||
void setId(long id);
|
void setId(long id);
|
||||||
|
|
||||||
long getAccountId();
|
|
||||||
|
|
||||||
void setAccountId(long id);
|
|
||||||
|
|
||||||
long getEntityId();
|
long getEntityId();
|
||||||
|
|
||||||
void setEntityId(long id);
|
void setEntityId(long id);
|
||||||
|
|
|
@ -13,13 +13,15 @@ public interface AccountRepository<E extends AccountModel> {
|
||||||
|
|
||||||
E newAccountModel();
|
E newAccountModel();
|
||||||
|
|
||||||
Maybe<E> getAccount(long accountId);
|
Observable<E> getAccount(long accountId);
|
||||||
|
|
||||||
|
Maybe<E> maybeGetAccount(long accountId);
|
||||||
|
|
||||||
Observable<List<E>> getAllAccounts();
|
Observable<List<E>> getAllAccounts();
|
||||||
|
|
||||||
Single<Long> insertAccount(E accountModel);
|
Single<Long> insertAccount(E accountModel);
|
||||||
|
|
||||||
Completable updateState(long accountId, String state);
|
Completable updateAccount(E accountModel);
|
||||||
|
|
||||||
Completable deleteAccount(E item);
|
Completable deleteAccount(E item);
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ import java.util.List;
|
||||||
import io.reactivex.Completable;
|
import io.reactivex.Completable;
|
||||||
import io.reactivex.Maybe;
|
import io.reactivex.Maybe;
|
||||||
import io.reactivex.Observable;
|
import io.reactivex.Observable;
|
||||||
|
import io.reactivex.Single;
|
||||||
|
|
||||||
public interface ChatRepository<E extends ChatModel> {
|
public interface ChatRepository<E extends ChatModel> {
|
||||||
|
|
||||||
|
@ -18,15 +19,60 @@ public interface ChatRepository<E extends ChatModel> {
|
||||||
|
|
||||||
Observable<List<E>> getAllChats();
|
Observable<List<E>> getAllChats();
|
||||||
|
|
||||||
Observable<List<E>> getAllChatsOf(AccountModel account);
|
Observable<List<E>> getAllChatsOfAccount(long accountId);
|
||||||
|
|
||||||
|
default Observable<List<E>> getAllChatsOfAccount(AccountModel account) {
|
||||||
|
return getAllChatsOfAccount(account.getId());
|
||||||
|
}
|
||||||
|
|
||||||
Observable<E> getOrCreateChatWith(long accountId, EntityBareJid jid);
|
Observable<E> getOrCreateChatWith(long accountId, EntityBareJid jid);
|
||||||
|
|
||||||
Maybe<E> getChatWith(AccountModel account, EntityBareJid jid);
|
Observable<E> getChatWith(long accountId, EntityBareJid jid);
|
||||||
|
|
||||||
Maybe<E> getChatWith(EntityModel identity);
|
default Observable<E> getChatWith(AccountModel accountModel, EntityBareJid jid) {
|
||||||
|
return getChatWith(accountModel.getId(), jid);
|
||||||
|
}
|
||||||
|
|
||||||
Maybe<E> getChatWith(ContactModel contact);
|
Observable<E> getChatWithEntity(long entityId);
|
||||||
|
|
||||||
|
default Observable<E> getChatWithEntity(EntityModel entity) {
|
||||||
|
return getChatWithEntity(entity.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
Observable<E> getChatWithContact(long contactId);
|
||||||
|
|
||||||
|
default Observable<E> getChatWithContact(ContactModel contact) {
|
||||||
|
return getChatWithContact(contact.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
Maybe<E> maybeGetChatWith(long accountId, EntityBareJid jid);
|
||||||
|
|
||||||
|
default Maybe<E> maybeGetChatWith(AccountModel account, EntityBareJid jid) {
|
||||||
|
return maybeGetChatWith(account.getId(), jid);
|
||||||
|
}
|
||||||
|
|
||||||
|
Maybe<E> maybeGetChatWithContact(long contactId);
|
||||||
|
|
||||||
|
default Maybe<E> maybeGetChatWithContact(ContactModel contact) {
|
||||||
|
return maybeGetChatWithContact(contact.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
Maybe<E> maybeGetChatWithEntity(long entityId);
|
||||||
|
|
||||||
|
default Maybe<E> maybeGetChatWithEntity(EntityModel entity) {
|
||||||
|
return maybeGetChatWithEntity(entity.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
Completable updateChat(E chat);
|
||||||
|
|
||||||
|
Single<Long> insertChat(E chat);
|
||||||
|
|
||||||
Completable closeChat(E chat);
|
Completable closeChat(E chat);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,19 +5,20 @@ import org.mercury_im.messenger.persistence.model.EntityCapsModel;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import io.reactivex.Completable;
|
import io.reactivex.Completable;
|
||||||
|
import io.reactivex.Observable;
|
||||||
import io.reactivex.Single;
|
import io.reactivex.Single;
|
||||||
|
|
||||||
public interface EntityCapsRepository<E extends EntityCapsModel> {
|
public interface EntityCapsRepository<E extends EntityCapsModel> {
|
||||||
|
|
||||||
E newEntityCapsModel(String nodeVer);
|
E newEntityCapsModel(String nodeVer);
|
||||||
|
|
||||||
Single<List<E>> getAllEntityCaps();
|
Observable<List<E>> getAllEntityCaps();
|
||||||
|
|
||||||
Single<E> getEntityCapsForNodeVer(String nodeVer);
|
Single<E> getEntityCapsForNodeVer(String nodeVer);
|
||||||
|
|
||||||
Completable insertOrReplaceEntityCaps(List<E> entityCaps);
|
Single<List<Long>> insertOrReplaceEntityCaps(List<E> entityCaps);
|
||||||
|
|
||||||
Completable insertOrReplaceEntityCaps(E entityCaps);
|
Single<Long> insertOrReplaceEntityCaps(E entityCaps);
|
||||||
|
|
||||||
Completable deleteOrReplaceEntityCaps(List<E> entityCaps);
|
Completable deleteOrReplaceEntityCaps(List<E> entityCaps);
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,8 @@ public interface MessageRepository<E extends MessageModel> {
|
||||||
|
|
||||||
Single<Long> insertMessage(E message);
|
Single<Long> insertMessage(E message);
|
||||||
|
|
||||||
|
Single<List<Long>> insertMessages(List<E> messages);
|
||||||
|
|
||||||
Observable<List<E>> getAllMessages();
|
Observable<List<E>> getAllMessages();
|
||||||
|
|
||||||
Observable<List<E>> getAllMessagesOf(long accountId);
|
Observable<List<E>> getAllMessagesOf(long accountId);
|
||||||
|
|
|
@ -12,7 +12,6 @@ import io.reactivex.Completable;
|
||||||
import io.reactivex.Maybe;
|
import io.reactivex.Maybe;
|
||||||
import io.reactivex.Observable;
|
import io.reactivex.Observable;
|
||||||
import io.reactivex.Single;
|
import io.reactivex.Single;
|
||||||
import io.reactivex.functions.Consumer;
|
|
||||||
|
|
||||||
public abstract class RosterRepository<E extends EntityModel, C extends ContactModel, V extends RosterInformationModel> {
|
public abstract class RosterRepository<E extends EntityModel, C extends ContactModel, V extends RosterInformationModel> {
|
||||||
|
|
||||||
|
@ -64,7 +63,15 @@ public abstract class RosterRepository<E extends EntityModel, C extends ContactM
|
||||||
* @param contact contact
|
* @param contact contact
|
||||||
* @return single wrapping the contacts ID
|
* @return single wrapping the contacts ID
|
||||||
*/
|
*/
|
||||||
public abstract Single<Long> updateOrInsertContact(C contact);
|
public abstract Single<Long> upsertContact(C contact);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert a contact.
|
||||||
|
*
|
||||||
|
* @param contact contact
|
||||||
|
* @return single wrapping the contacts ID
|
||||||
|
*/
|
||||||
|
public abstract Single<Long> insertContact(C contact);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the {@link ContactModel} corresponding to the given ID wrapped in a {@link Maybe}.
|
* Return the {@link ContactModel} corresponding to the given ID wrapped in a {@link Maybe}.
|
||||||
|
@ -75,7 +82,7 @@ public abstract class RosterRepository<E extends EntityModel, C extends ContactM
|
||||||
public abstract Maybe<C> getContact(long id);
|
public abstract Maybe<C> getContact(long id);
|
||||||
|
|
||||||
public Maybe<C> getContact(long accountId, EntityBareJid jid) {
|
public Maybe<C> getContact(long accountId, EntityBareJid jid) {
|
||||||
return getEntity(accountId, jid).flatMap(this::getContactForEntity);
|
return getEntityForAccountAndJid(accountId, jid).flatMap(this::getContactForEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -223,7 +230,7 @@ public abstract class RosterRepository<E extends EntityModel, C extends ContactM
|
||||||
* @param jid {@link EntityBareJid} of the {@link EntityModel}
|
* @param jid {@link EntityBareJid} of the {@link EntityModel}
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public abstract Maybe<E> getEntity(long accountId, EntityBareJid jid);
|
public abstract Maybe<E> getEntityForAccountAndJid(long accountId, EntityBareJid jid);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the {@link EntityModel} which has foreign keys pointing to the {@link AccountModel}
|
* Return the {@link EntityModel} which has foreign keys pointing to the {@link AccountModel}
|
||||||
|
@ -233,22 +240,21 @@ public abstract class RosterRepository<E extends EntityModel, C extends ContactM
|
||||||
* @param jid {@link EntityBareJid}
|
* @param jid {@link EntityBareJid}
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Maybe<E> getEntity(AccountModel account, EntityBareJid jid) {
|
public Maybe<E> getEntityForAccountAndJid(AccountModel account, EntityBareJid jid) {
|
||||||
return getEntity(account.getId(), jid);
|
return getEntityForAccountAndJid(account.getId(), jid);
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract Single<E> getEntityForContact(long contactId);
|
public abstract Single<E> getEntityForContact(long contactId);
|
||||||
|
|
||||||
|
public Single<E> getOrCreateEntityForAccountAndJid(AccountModel accountModel, EntityBareJid jid) {
|
||||||
|
return getOrCreateEntityForAccountAndJid(accountModel.getId(), jid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract Single<E> getOrCreateEntityForAccountAndJid(long accountId, EntityBareJid jid);
|
||||||
|
|
||||||
public Single<E> getEntityForContact(C contact) {
|
public Single<E> getEntityForContact(C contact) {
|
||||||
return getEntityForContact(contact.getId());
|
return getEntityForContact(contact.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Insert or replace a {@link EntityModel} in the database.
|
|
||||||
*
|
|
||||||
* @param entity {@link EntityModel} which we want to insert or replace in the database
|
|
||||||
* @return {@link Single} which wraps the ID assigned to the entity
|
|
||||||
*/
|
|
||||||
public abstract Single<Long> insertOrReplaceEntity(E entity);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue