This commit is contained in:
Paul Schaub 2019-08-12 17:05:30 +02:00
parent d80099b2cf
commit 41b116719f
Signed by: vanitasvitae
GPG Key ID: 62BEE9264BF17311
34 changed files with 492 additions and 98 deletions

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="JDK" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/classes" />
</component>
</project>

0
app/.attach_pid15269 Normal file
View File

View File

@ -2,7 +2,6 @@ package org.mercury_im.messenger.di.component;
import org.mercury_im.messenger.MercuryImApplication;
import org.mercury_im.messenger.di.module.AppModule;
import org.mercury_im.messenger.handler.AvatarHandler;
import org.mercury_im.messenger.handler.RoomPlainMessageHandler;
import org.mercury_im.messenger.persistence.room.RoomModule;
import org.mercury_im.messenger.service.XmppConnectionService;
@ -71,6 +70,4 @@ public interface AppComponent {
// Connectors
void inject(RoomPlainMessageHandler messageHandler);
void inject(AvatarHandler avatarHandler);
}

View File

@ -1,33 +0,0 @@
package org.mercury_im.messenger.handler;
import org.jivesoftware.smackx.avatar.UserAvatarManager;
import org.jivesoftware.smackx.avatar.element.MetadataExtension;
import org.jivesoftware.smackx.avatar.listener.AvatarListener;
import org.jxmpp.jid.EntityBareJid;
import org.mercury_im.messenger.MercuryImApplication;
import org.mercury_im.messenger.persistence.repository.AvatarRepository;
import org.mercury_im.messenger.persistence.room.model.RoomAvatarModel;
import javax.inject.Inject;
public class AvatarHandler implements AvatarListener {
private final long accountId;
@Inject
AvatarRepository avatarRepository;
private UserAvatarManager avatarManager;
public AvatarHandler(long accountId, UserAvatarManager avatarManager) {
this.accountId = accountId;
this.avatarManager = avatarManager;
MercuryImApplication.getApplication().getAppComponent().inject(this);
}
@Override
public void onAvatarUpdateReceived(EntityBareJid user, MetadataExtension metadata) {
}
}

View File

@ -29,7 +29,6 @@ public class RoomPlainMessageHandler implements PlainMessageHandler {
public RoomPlainMessageHandler(long accountId) {
this.accountId = accountId;
MercuryImApplication.getApplication().getAppComponent().inject(this);
}

View File

@ -7,6 +7,7 @@ import android.view.MenuItem;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.FragmentManager;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
@ -14,6 +15,7 @@ import org.mercury_im.messenger.MercuryImApplication;
import org.mercury_im.messenger.R;
import org.mercury_im.messenger.ui.login.AccountsActivity;
import org.mercury_im.messenger.ui.login.LoginActivity;
import org.mercury_im.messenger.ui.roster.RosterFragment;
import org.mercury_im.messenger.ui.settings.SettingsActivity;
public class MainActivity extends AppCompatActivity {
@ -27,6 +29,11 @@ public class MainActivity extends AppCompatActivity {
MercuryImApplication.getApplication().getAppComponent().inject(this);
FragmentManager fm = getSupportFragmentManager();
fm.beginTransaction()
.replace(R.id.fragment, new RosterFragment())
.commit();
FloatingActionButton fab = findViewById(R.id.fab);
}

View File

@ -1,8 +1,15 @@
package org.mercury_im.messenger;
import org.junit.Test;
import org.mercury_im.messenger.core.ConnectionState;
import static org.junit.Assert.*;
import io.reactivex.Observable;
import io.reactivex.disposables.Disposable;
import io.reactivex.observers.TestObserver;
import io.reactivex.schedulers.TestScheduler;
import io.reactivex.subjects.BehaviorSubject;
import static org.junit.Assert.assertEquals;
/**
* Example local unit test, which will execute on the development machine (host).
@ -14,4 +21,16 @@ public class ExampleUnitTest {
public void addition_isCorrect() {
assertEquals(4, 2 + 2);
}
@Test
public void test() {
TestScheduler testScheduler = new TestScheduler();
BehaviorSubject<ConnectionState> state = BehaviorSubject.createDefault(ConnectionState.DISCONNECTED);
TestObserver<ConnectionState> observable = state.test();
assertEquals(ConnectionState.DISCONNECTED, state.getValue());
state.onNext(ConnectionState.CONNECTING);
assertEquals(ConnectionState.CONNECTING, state.getValue());
observable.assertValues(ConnectionState.DISCONNECTED, ConnectionState.CONNECTING).dispose();
}
}

View File

@ -9,9 +9,13 @@ import org.mercury_im.messenger.persistence.repository.AccountRepository;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.inject.Inject;
import javax.inject.Singleton;
@ -23,6 +27,8 @@ import io.reactivex.schedulers.Schedulers;
@Singleton
public class ConnectionCenter {
private static final Logger LOGGER = Logger.getLogger(ConnectionCenter.class.getName());
// Injected
private final AccountRepository accountRepository;
private final EntityCapsStore entityCapsStore;
@ -38,10 +44,12 @@ public class ConnectionCenter {
@Inject
public ConnectionCenter(EntityCapsStore capsStore, AccountRepository accountRepository) {
LOGGER.log(Level.INFO, "ConnectionCenter initialized");
this.accountRepository = accountRepository;
this.entityCapsStore = capsStore;
EntityCapsManager.setPersistentCache(capsStore);
startUp();
}
/**
@ -62,12 +70,29 @@ public class ConnectionCenter {
.observeOn(Schedulers.io())
.subscribeOn(Schedulers.computation())
.subscribe((Consumer<List<? extends AccountModel>>) accounts -> {
Set<Long> accountIds = new HashSet<>();
// Add missing connections to the map
for (AccountModel account : accounts) {
accountIds.add(account.getId());
if (connectionMap.get(account.getId()) != null) {
continue;
}
MercuryConnection connection = createConnection(account);
connectionMap.put(account.getId(), connection);
if (account.getEnabled()) {
connection.connect();
}
}
// Remove unwanted connections from the map
for (long connectionId : connectionMap.keySet()) {
if (!accountIds.contains(connectionId)) {
AbstractXMPPConnection con =
(AbstractXMPPConnection) connectionMap.get(connectionId).getConnection();
con.disconnect();
connectionMap.remove(connectionId);
}
}
}));
}
@ -85,12 +110,13 @@ public class ConnectionCenter {
}
public MercuryConnection createConnection(AccountModel accountModel) {
LOGGER.log(Level.INFO, "Create Connection for " + accountModel.getJid().toString());
XMPPTCPConnectionConfiguration configuration = XMPPTCPConnectionConfiguration.builder()
.setHost(accountModel.getJid().getDomain().toString())
.setXmppAddressAndPassword(accountModel.getJid(), accountModel.getPassword())
.setConnectTimeout(2 * 60 * 1000)
.setEnabledSSLCiphers(MercuryConfiguration.enabledCiphers)
.setEnabledSSLProtocols(MercuryConfiguration.enabledProtocols)
//.setEnabledSSLCiphers(MercuryConfiguration.enabledCiphers)
//.setEnabledSSLProtocols(MercuryConfiguration.enabledProtocols)
.build();
AbstractXMPPConnection tcpConnection = new XMPPTCPConnection(configuration);

View File

@ -21,10 +21,15 @@ public enum ConnectionState {
/**
* The connection is successfully connected to the server and the stream has been initiated.
* In this state the connection is ready to send and receive stanzas.
*/
CONNECTED,
/**
* THe connection is authenticated.
* In this state the connection is ready to send and receive stanzas.
*/
AUTHENTICATED,
/**
* The connection is in the process of shutting down.
*/

View File

@ -3,23 +3,25 @@ package org.mercury_im.messenger.core;
import org.jivesoftware.smack.AbstractXMPPConnection;
import org.jivesoftware.smack.ConnectionListener;
import org.jivesoftware.smack.ReconnectionManager;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.chat2.ChatManager;
import org.jivesoftware.smack.iqrequest.AbstractIqRequestHandler;
import org.jivesoftware.smack.iqrequest.IQRequestHandler;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.roster.Roster;
import org.jivesoftware.smackx.caps.EntityCapsManager;
import org.jivesoftware.smackx.carbons.CarbonManager;
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
import org.jivesoftware.smackx.disco.packet.DiscoverInfo;
import org.jivesoftware.smackx.iqversion.VersionManager;
import org.jivesoftware.smackx.iqversion.packet.Version;
import org.jivesoftware.smackx.sid.StableUniqueStanzaIdManager;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
public class MercuryConnection implements ConnectionListener {
import io.reactivex.subjects.BehaviorSubject;
public class MercuryConnection {
public static final String TAG = "Mercury";
@ -35,9 +37,12 @@ public class MercuryConnection implements ConnectionListener {
protected final StableUniqueStanzaIdManager stanzaIdManager;
protected final ServiceDiscoveryManager serviceDiscoveryManager;
BehaviorSubject<ConnectionState> state = BehaviorSubject.createDefault(ConnectionState.DISCONNECTED);
public MercuryConnection(AbstractXMPPConnection connection, long accountId) {
this.connection = connection;
connection.addConnectionListener(this);
connection.addConnectionListener(connectionListener);
this.accountId = accountId;
reconnectionManager = ReconnectionManager.getInstanceFor(connection);
@ -55,6 +60,34 @@ public class MercuryConnection implements ConnectionListener {
roster.setRosterLoadedAtLogin(true);
}
public void connect() {
LOGGER.log(Level.INFO, "Connecting...");
state.onNext(ConnectionState.CONNECTING);
AbstractXMPPConnection con = (AbstractXMPPConnection) getConnection();
try {
con.connect().login();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (SmackException e) {
e.printStackTrace();
} catch (XMPPException e) {
e.printStackTrace();
}
}
public void disconnect() {
AbstractXMPPConnection con = (AbstractXMPPConnection) getConnection();
state.onNext(ConnectionState.DISCONNECTING);
try {
con.disconnect(new Presence(Presence.Type.unavailable));
} catch (SmackException.NotConnectedException e) {
e.printStackTrace();
}
state.onNext(ConnectionState.DISCONNECTED);
}
public XMPPConnection getConnection() {
return connection;
}
@ -73,31 +106,35 @@ public class MercuryConnection implements ConnectionListener {
return roster;
}
@Override
public void connected(XMPPConnection connection) {
LOGGER.info("Connection " + getAccountId() + " connected.");
}
@Override
public void authenticated(XMPPConnection connection, boolean resumed) {
LOGGER.info("Connection " + getAccountId() + " authenticated (" + (resumed ? "resumed" : "first time") + ")");
if (connection == this.connection && !resumed) {
LOGGER.info("Enabling carbons!");
carbonManager.enableCarbonsAsync(exception -> {
LOGGER.severe("Could not enable carbons for connection " + accountId + ": " + exception.getMessage());
exception.printStackTrace();
});
private final ConnectionListener connectionListener = new ConnectionListener() {
@Override
public void connected(XMPPConnection connection) {
state.onNext(ConnectionState.CONNECTED);
}
}
@Override
public void connectionClosed() {
LOGGER.fine("Connection " + accountId + " closed.");
}
@Override
public void authenticated(XMPPConnection connection, boolean resumed) {
state.onNext(ConnectionState.AUTHENTICATED);
LOGGER.info("Connection " + getAccountId() + " authenticated (" + (resumed ? "resumed" : "initially") + ")");
if (!resumed) {
LOGGER.info("Enabling carbons!");
carbonManager.enableCarbonsAsync(exception -> {
LOGGER.severe("Could not enable carbons for connection " + accountId + ": " + exception.getMessage());
exception.printStackTrace();
});
}
}
@Override
public void connectionClosedOnError(Exception e) {
LOGGER.severe("Connection " + accountId + " closed on error: " + e.getMessage());
}
@Override
public void connectionClosed() {
state.onNext(ConnectionState.DISCONNECTED);
}
@Override
public void connectionClosedOnError(Exception e) {
state.onNext(ConnectionState.DISCONNECTED);
}
};
}

View File

@ -0,0 +1,110 @@
package org.mercury_im.messenger.core;
import org.jivesoftware.smack.roster.packet.RosterPacket;
import org.jxmpp.jid.Jid;
import org.mercury_im.messenger.persistence.model.ContactAttributes;
import org.mercury_im.messenger.persistence.model.ContactModel;
import org.mercury_im.messenger.persistence.model.EntityModel;
import org.mercury_im.messenger.persistence.repository.ContactRepository;
import java.util.Collection;
import java.util.List;
import javax.inject.Inject;
import io.reactivex.MaybeObserver;
import io.reactivex.Observer;
import io.reactivex.Scheduler;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.schedulers.Schedulers;
public class RosterStore implements org.jivesoftware.smack.roster.rosterstore.RosterStore {
private final ContactRepository contactRepository;
private long accountId;
@Inject
public RosterStore(ContactRepository contactRepository) {
this.contactRepository = contactRepository;
contactRepository.getAllContactsOfAccount(accountId)
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.computation())
.subscribe();
}
public void setAccountId(long accountId) {
this.accountId = accountId;
}
@Override
public List<RosterPacket.Item> getEntries() {
}
@Override
public RosterPacket.Item getEntry(Jid bareJid) {
return null;
}
@Override
public String getRosterVersion() {
return null;
}
@Override
public boolean addEntry(RosterPacket.Item item, String version) {
return false;
}
@Override
public boolean resetEntries(Collection<RosterPacket.Item> items, String version) {
return false;
}
@Override
public boolean removeEntry(Jid bareJid, String version) {
return false;
}
@Override
public void resetStore() {
}
public RosterPacket.Item fromModel(ContactModel contactModel) {
RosterPacket.Item item = new RosterPacket.Item(contactModel.getEntity().getJid(), contactModel.getContact().getRosterName());
item.setItemType(convert(contactModel.getContact().getDirection()));
item.setApproved(contactModel.getContact().isApproved());
item.setSubscriptionPending(contactModel.getContact().isSubscriptionPending());
return item;
}
public ContactModel toModel(RosterPacket.Item item) {
ContactModel contact = contactRepository.newContactModel();
ContactAttributes attributes = contactRepository.newAttributesModel();
attributes.setRosterName(item.getName());
attributes.setDirection(convert(item.getItemType()));
attributes.setApproved(item.isApproved());
attributes.setSubscriptionPending(item.isSubscriptionPending());
EntityModel entity = contactRepository.newEntityModel();
entity.setJid(item.getJid().asEntityBareJidOrThrow());
contact.setContact(attributes);
contact.setEntity(entity);
return contact;
}
public ContactAttributes.DIRECTION convert(RosterPacket.ItemType type) {
return ContactAttributes.DIRECTION.valueOf(type.toString());
}
public RosterPacket.ItemType convert(ContactAttributes.DIRECTION direction) {
return RosterPacket.ItemType.fromString(direction.toString());
}
}

View File

@ -2,6 +2,7 @@ package org.mercury_im.messenger.core.di;
import org.mercury_im.messenger.core.ConnectionCenter;
import org.mercury_im.messenger.core.EntityCapsStore;
import org.mercury_im.messenger.persistence.repository.AccountRepository;
import org.mercury_im.messenger.persistence.repository.EntityCapsRepository;
import javax.inject.Inject;
@ -15,8 +16,8 @@ public class CenterModule {
@Singleton
@Provides
static ConnectionCenter provideConnectionCenter(EntityCapsStore capsStore) {
return new ConnectionCenter(capsStore);
static ConnectionCenter provideConnectionCenter(EntityCapsStore capsStore, AccountRepository accountRepository) {
return new ConnectionCenter(capsStore, accountRepository);
}
@Singleton

View File

@ -1,19 +1,23 @@
package org.mercury_im.messenger.persistence.room.dao;
import androidx.room.Dao;
import androidx.room.Insert;
import androidx.room.Query;
import androidx.room.TypeConverters;
import org.jxmpp.jid.EntityBareJid;
import org.mercury_im.messenger.persistence.room.model.RoomContactModel;
import org.mercury_im.messenger.persistence.room.model.RoomEntityModel;
import org.mercury_im.messenger.persistence.room.model.RoomRosterInformation;
import org.mercury_im.messenger.persistence.room.type_converter.EntityBareJidConverter;
import java.util.List;
import io.reactivex.Completable;
import io.reactivex.Maybe;
import io.reactivex.Observable;
import static androidx.room.OnConflictStrategy.REPLACE;
import static org.mercury_im.messenger.persistence.room.model.RoomContactModel.PREFIX;
@Dao
@ -45,4 +49,13 @@ public interface ContactDao {
"entities." + RoomEntityModel.KEY_AVATAR + " AS " + PREFIX + RoomEntityModel.KEY_AVATAR + " " +
"FROM contacts INNER JOIN entities ON contacts.fk_entity_id = entities.pk_entity_id")
Observable<List<RoomContactModel>> getAllContactAndEntities();
@Query("SELECT * FROM roster_information")
Observable<List<RoomRosterInformation>> getAllRosterInformation();
@Query("SELECT * FROM roster_information WHERE pk_account_id = :accountId")
Maybe<RoomRosterInformation> getRosterInformation(long accountId);
@Insert(onConflict = REPLACE)
Completable insertRosterInformation(RoomRosterInformation information);
}

View File

@ -26,8 +26,14 @@ public interface EntityCapsDao {
Single<List<RoomEntityCapsModel>> getAllEntityCaps();
@Insert(onConflict = REPLACE)
Completable insert(RoomEntityCapsModel... models);
Completable insert(List<RoomEntityCapsModel> models);
@Insert(onConflict = REPLACE)
Completable insert(RoomEntityCapsModel model);
@Delete
Completable delete(RoomEntityCapsModel... models);
Completable delete(List<RoomEntityCapsModel> models);
@Delete
Completable delete(RoomEntityCapsModel model);
}

View File

@ -6,8 +6,11 @@ import androidx.room.Entity;
import androidx.room.ForeignKey;
import androidx.room.Index;
import androidx.room.PrimaryKey;
import androidx.room.TypeConverter;
import androidx.room.TypeConverters;
import org.mercury_im.messenger.persistence.model.ContactAttributes;
import org.mercury_im.messenger.persistence.room.type_converter.DirectionConverter;
import static androidx.room.ForeignKey.CASCADE;
import static androidx.room.ForeignKey.RESTRICT;
@ -40,6 +43,9 @@ public class RoomContactAttributes implements ContactAttributes {
public static final String KEY_ENTITY_ID = "fk_entity_id";
public static final String KEY_ROSTER_NAME = "rostername";
public static final String KEY_NICKNAME = "nickname";
public static final String KEY_DIRECTION = "direction";
public static final String KEY_SUB_PENDING = "sub_pending";
public static final String KEY_APPROVED = "approved";
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = KEY_ID)
@ -57,25 +63,15 @@ public class RoomContactAttributes implements ContactAttributes {
@ColumnInfo(name = KEY_NICKNAME)
private String nickname;
@Override
public String getRosterName() {
return rosterName;
}
@ColumnInfo(name = KEY_DIRECTION)
@TypeConverters(DirectionConverter.class)
private DIRECTION direction;
@Override
public void setRosterName(String rosterName) {
this.rosterName = rosterName;
}
@ColumnInfo(name = KEY_SUB_PENDING)
private boolean subscriptionPending;
@Override
public String getNickname() {
return nickname;
}
@Override
public void setNickname(String nickname) {
this.nickname = nickname;
}
@ColumnInfo(name = KEY_APPROVED)
private boolean approved;
@Override
public long getId() {
@ -106,4 +102,54 @@ public class RoomContactAttributes implements ContactAttributes {
public void setEntityId(long id) {
this.entityId = id;
}
@Override
public String getRosterName() {
return rosterName;
}
@Override
public void setRosterName(String rosterName) {
this.rosterName = rosterName;
}
@Override
public String getNickname() {
return nickname;
}
@Override
public void setNickname(String nickname) {
this.nickname = nickname;
}
@Override
public DIRECTION getDirection() {
return direction;
}
@Override
public void setDirection(DIRECTION direction) {
this.direction = direction;
}
@Override
public boolean isSubscriptionPending() {
return subscriptionPending;
}
@Override
public void setSubscriptionPending(boolean pending) {
this.subscriptionPending = pending;
}
@Override
public boolean isApproved() {
return approved;
}
@Override
public void setApproved(boolean approved) {
this.approved = approved;
}
}

View File

@ -0,0 +1,48 @@
package org.mercury_im.messenger.persistence.room.model;
import androidx.room.ColumnInfo;
import androidx.room.Entity;
import androidx.room.Index;
import androidx.room.PrimaryKey;
import org.mercury_im.messenger.persistence.model.RosterInformationModel;
import static org.mercury_im.messenger.persistence.room.model.RoomRosterInformation.KEY_ID;
import static org.mercury_im.messenger.persistence.room.model.RoomRosterInformation.TABLE;
@Entity(tableName = TABLE, indices = {
@Index(value = KEY_ID, unique = true)
})
public class RoomRosterInformation implements RosterInformationModel {
public static final String TABLE = "roster_information";
public static final String KEY_ID = "pk_account_id";
public static final String KEY_ROSTER_VERSION = "roster_version";
@PrimaryKey
@ColumnInfo(name = KEY_ID)
private long accountId;
@ColumnInfo(name = KEY_ROSTER_VERSION)
private String rosterVersion;
@Override
public long getAccountId() {
return accountId;
}
@Override
public void setAccountId(long accountId) {
this.accountId = accountId;
}
@Override
public String getRosterVersion() {
return rosterVersion;
}
@Override
public void setRosterVersion(String rosterVersion) {
this.rosterVersion = rosterVersion;
}
}

View File

@ -1,19 +1,25 @@
package org.mercury_im.messenger.persistence.room.repository;
import org.jxmpp.jid.EntityBareJid;
import org.mercury_im.messenger.persistence.model.ContactAttributes;
import org.mercury_im.messenger.persistence.model.EntityModel;
import org.mercury_im.messenger.persistence.model.RosterInformationModel;
import org.mercury_im.messenger.persistence.repository.ContactRepository;
import org.mercury_im.messenger.persistence.room.dao.ContactDao;
import org.mercury_im.messenger.persistence.room.model.RoomContactAttributes;
import org.mercury_im.messenger.persistence.room.model.RoomContactModel;
import org.mercury_im.messenger.persistence.room.model.RoomEntityModel;
import org.mercury_im.messenger.persistence.room.model.RoomRosterInformation;
import java.util.List;
import javax.inject.Inject;
import io.reactivex.Completable;
import io.reactivex.Maybe;
import io.reactivex.Observable;
public class IContactRepository implements ContactRepository<RoomContactModel> {
public class IContactRepository implements ContactRepository<RoomContactModel, RoomRosterInformation> {
private final ContactDao dao;
@ -27,6 +33,16 @@ public class IContactRepository implements ContactRepository<RoomContactModel> {
return new RoomContactModel();
}
@Override
public ContactAttributes newAttributesModel() {
return new RoomContactAttributes();
}
@Override
public EntityModel newEntityModel() {
return new RoomEntityModel();
}
@Override
public Maybe<RoomContactModel> getContact(long accountId, EntityBareJid jid) {
return dao.getContactAndEntity(accountId, jid);
@ -46,4 +62,19 @@ public class IContactRepository implements ContactRepository<RoomContactModel> {
public Observable<List<RoomContactModel>> getAllContacts() {
return dao.getAllContactAndEntities();
}
@Override
public Observable<List<RoomRosterInformation>> getAllRosterInformation() {
return dao.getAllRosterInformation();
}
@Override
public Completable insertRosterInformation(RoomRosterInformation rosterInfo) {
return dao.insertRosterInformation(rosterInfo);
}
@Override
public Maybe<RoomRosterInformation> getRosterInformation(long accountId) {
return dao.getRosterInformation(accountId);
}
}

View File

@ -39,12 +39,22 @@ public class IEntityCapsRepository implements EntityCapsRepository<RoomEntityCap
}
@Override
public Completable insertOrReplaceEntityCaps(RoomEntityCapsModel... entityCaps) {
public Completable insertOrReplaceEntityCaps(List<RoomEntityCapsModel> entityCaps) {
return dao.insert(entityCaps);
}
@Override
public Completable deleteOrReplaceEntityCaps(RoomEntityCapsModel... entityCaps) {
public Completable insertOrReplaceEntityCaps(RoomEntityCapsModel entityCaps) {
return dao.insert(entityCaps);
}
@Override
public Completable deleteOrReplaceEntityCaps(List<RoomEntityCapsModel> entityCaps) {
return dao.delete(entityCaps);
}
@Override
public Completable deleteOrReplaceEntityCaps(RoomEntityCapsModel entityCaps) {
return dao.delete(entityCaps);
}
}

View File

@ -0,0 +1,18 @@
package org.mercury_im.messenger.persistence.room.type_converter;
import androidx.room.TypeConverter;
import org.mercury_im.messenger.persistence.model.ContactAttributes;
public class DirectionConverter {
@TypeConverter
public static String toString(ContactAttributes.DIRECTION direction) {
return direction.toString();
}
@TypeConverter
public static ContactAttributes.DIRECTION fromString(String string) {
return ContactAttributes.DIRECTION.valueOf(string);
}
}

View File

@ -21,4 +21,24 @@ public interface ContactAttributes {
String getNickname();
void setNickname(String nickname);
DIRECTION getDirection();
void setDirection(DIRECTION direction);
boolean isSubscriptionPending();
void setSubscriptionPending(boolean pending);
boolean isApproved();
void setApproved(boolean approved);
enum DIRECTION {
none,
to,
from,
both,
remove
}
}

View File

@ -4,5 +4,9 @@ public interface ContactModel<C extends ContactAttributes, E extends EntityModel
C getContact();
void setContact(C contact);
E getEntity();
void setEntity(E entity);
}

View File

@ -0,0 +1,12 @@
package org.mercury_im.messenger.persistence.model;
public interface RosterInformationModel {
long getAccountId();
void setAccountId(long accountId);
String getRosterVersion();
void setRosterVersion(String rosterVersion);
}

View File

@ -4,16 +4,22 @@ import org.jxmpp.jid.EntityBareJid;
import org.mercury_im.messenger.persistence.model.ContactModel;
import org.mercury_im.messenger.persistence.model.ContactAttributes;
import org.mercury_im.messenger.persistence.model.EntityModel;
import org.mercury_im.messenger.persistence.model.RosterInformationModel;
import java.util.List;
import io.reactivex.Completable;
import io.reactivex.Maybe;
import io.reactivex.Observable;
public interface ContactRepository<CE extends ContactModel<? extends ContactAttributes, ? extends EntityModel>> {
public interface ContactRepository<CE extends ContactModel<? extends ContactAttributes, ? extends EntityModel>, I extends RosterInformationModel> {
CE newContactModel();
ContactAttributes newAttributesModel();
EntityModel newEntityModel();
Maybe<CE> getContact(long accountId, EntityBareJid jid);
Maybe<CE> getContactForEntity(EntityModel entityModel);
@ -21,4 +27,10 @@ public interface ContactRepository<CE extends ContactModel<? extends ContactAttr
Observable<List<CE>> getAllContactsOfAccount(long accountId);
Observable<List<CE>> getAllContacts();
Observable<List<I>> getAllRosterInformation();
Maybe<I> getRosterInformation(long accountId);
Completable insertRosterInformation(I rosterInfo);
}

View File

@ -15,7 +15,11 @@ public interface EntityCapsRepository<E extends EntityCapsModel> {
Single<E> getEntityCapsForNodeVer(String nodeVer);
Completable insertOrReplaceEntityCaps(E... entityCaps);
Completable insertOrReplaceEntityCaps(List<E> entityCaps);
Completable deleteOrReplaceEntityCaps(E... entityCaps);
Completable insertOrReplaceEntityCaps(E entityCaps);
Completable deleteOrReplaceEntityCaps(List<E> entityCaps);
Completable deleteOrReplaceEntityCaps(E entityCaps);
}

Binary file not shown.

View File

@ -0,0 +1,2 @@
Manifest-Version: 1.0