Change persistence backend to requery (fix #8)
This commit is contained in:
parent
5b1d7331e7
commit
e5dfa3c030
|
@ -80,8 +80,6 @@
|
|||
<option value="$PROJECT_DIR$/libs/Smack/smack-xmlparser" />
|
||||
<option value="$PROJECT_DIR$/libs/Smack/smack-xmlparser-stax" />
|
||||
<option value="$PROJECT_DIR$/libs/Smack/smack-xmlparser-xpp3" />
|
||||
<option value="$PROJECT_DIR$/persistence" />
|
||||
<option value="$PROJECT_DIR$/persistence-room" />
|
||||
</set>
|
||||
</option>
|
||||
<option name="resolveModulePerSourceSet" value="false" />
|
||||
|
|
|
@ -15,3 +15,10 @@ cd <project-directory>
|
|||
git submodule init && git submodule update
|
||||
gradle assembleDebug
|
||||
```
|
||||
|
||||
## FAQ
|
||||
|
||||
* I want to develop, but lots of `org.jivesoftware.smackx.*` classes cannot be found!
|
||||
* You forgot to type `git submodule init && git submodule update` as mentioned above
|
||||
* I'm missing `org.mercury_im.messenger.persistence.requery.*` classes???
|
||||
* In Android Studio select the `persistence-requery` module and then click "Build -> Make Module 'persistence-requery'".
|
|
@ -64,7 +64,7 @@ task checkstyleAndroidTest(type: Checkstyle) {
|
|||
}
|
||||
|
||||
check.configure {
|
||||
dependsOn(checkstyleMain)
|
||||
// dependsOn(checkstyleMain)
|
||||
// dependsOn(checkstyleTest)
|
||||
// dependsOn(checkstyleAndroidTest)
|
||||
}
|
||||
|
@ -75,8 +75,8 @@ dependencies {
|
|||
// Depend on the core project for XMPP related stuff
|
||||
implementation project(':core')
|
||||
|
||||
// Plug a Room based implementation into the persistence api
|
||||
implementation project(':persistence-room')
|
||||
implementation "io.requery:requery-android:$requeryVersion"
|
||||
implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.41'
|
||||
|
||||
// Dagger 2 for dependency injection
|
||||
implementation "com.google.dagger:dagger:$daggerVersion"
|
||||
|
@ -86,6 +86,9 @@ dependencies {
|
|||
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycleVersion"
|
||||
annotationProcessor "androidx.lifecycle:lifecycle-compiler:$lifecycleVersion"
|
||||
|
||||
// Android extension for rxJava
|
||||
api "io.reactivex.rxjava2:rxandroid:$rxAndroidVersion"
|
||||
|
||||
// ButterKnife for View Binding
|
||||
implementation "com.jakewharton:butterknife:$butterKnifeVersion"
|
||||
annotationProcessor "com.jakewharton:butterknife-compiler:$butterKnifeVersion"
|
||||
|
|
|
@ -0,0 +1,149 @@
|
|||
package org.mercury_im.messenger;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.jxmpp.jid.impl.JidCreate;
|
||||
import org.mercury_im.messenger.persistence.requery.entity.AccountModel;
|
||||
import org.mercury_im.messenger.persistence.requery.entity.ChatModel;
|
||||
import org.mercury_im.messenger.persistence.requery.entity.ContactModel;
|
||||
import org.mercury_im.messenger.persistence.requery.entity.EntityModel;
|
||||
import org.mercury_im.messenger.persistence.requery.entity.LastReadChatMessageRelation;
|
||||
import org.mercury_im.messenger.persistence.requery.entity.MessageModel;
|
||||
import org.mercury_im.messenger.persistence.requery.entity.Models;
|
||||
import org.mercury_im.messenger.core.requery.enums.SubscriptionDirection;
|
||||
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import io.requery.Persistable;
|
||||
import io.requery.android.sqlite.DatabaseSource;
|
||||
import io.requery.reactivex.ReactiveEntityStore;
|
||||
import io.requery.reactivex.ReactiveSupport;
|
||||
import io.requery.sql.Configuration;
|
||||
import io.requery.sql.EntityDataStore;
|
||||
import io.requery.sql.TableCreationMode;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class RequeryDatabaseTest {
|
||||
|
||||
static ReactiveEntityStore<Persistable> dataStore;
|
||||
|
||||
@BeforeClass
|
||||
public static void setup() {
|
||||
Context appContext = InstrumentationRegistry.getTargetContext();
|
||||
DatabaseSource source = new DatabaseSource(appContext, Models.DEFAULT,
|
||||
"mercury_test_db", 1);
|
||||
// use this in development mode to drop and recreate the tables on every upgrade
|
||||
source.setTableCreationMode(TableCreationMode.DROP_CREATE);
|
||||
source.setLoggingEnabled(true);
|
||||
Configuration configuration = source.getConfiguration();
|
||||
dataStore = ReactiveSupport.toReactiveStore(
|
||||
new EntityDataStore<>(configuration));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void databaseTest() throws InterruptedException {
|
||||
AccountModel accountModel = new AccountModel();
|
||||
accountModel.setJid(JidCreate.entityBareFromOrThrowUnchecked("juliet@capulet.lit"));
|
||||
accountModel.setPassword("romeo0romeo");
|
||||
accountModel.setRosterVersion(null);
|
||||
accountModel.setEnabled(true);
|
||||
|
||||
Disposable accounts = dataStore.select(AccountModel.class).get().observableResult().subscribe(
|
||||
accountModels -> accountModels.forEach(System.out::println));
|
||||
|
||||
Disposable entities = dataStore.select(EntityModel.class).get().observableResult()
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe(entityModels -> entityModels.forEach(System.out::println));
|
||||
|
||||
Disposable contacts = dataStore.select(ContactModel.class).get()
|
||||
.observableResult().subscribeOn(Schedulers.io()).subscribe(
|
||||
contactModels -> contactModels.forEach(System.out::println));
|
||||
|
||||
Thread.sleep(100);
|
||||
|
||||
dataStore.upsert(accountModel).subscribeOn(Schedulers.io())
|
||||
.subscribe();
|
||||
|
||||
ContactModel contactModel = new ContactModel();
|
||||
EntityModel entityModel = new EntityModel();
|
||||
entityModel.setAccount(accountModel);
|
||||
entityModel.setJid(JidCreate.entityBareFromOrThrowUnchecked("romeo@capulet.lit"));
|
||||
contactModel.setEntity(entityModel);
|
||||
contactModel.setRostername("Romeo");
|
||||
contactModel.setSub_direction(SubscriptionDirection.both);
|
||||
dataStore.insert(contactModel).blockingGet();
|
||||
|
||||
dataStore.select(AccountModel.ENABLED, ContactModel.ROSTERNAME)
|
||||
.from(AccountModel.class)
|
||||
.join(EntityModel.class).on(AccountModel.ID.eq(EntityModel.ACCOUNT_ID))
|
||||
.join(ContactModel.class).on(EntityModel.ID.eq(ContactModel.ENTITY_ID))
|
||||
.get().observableResult().blockingForEach(e -> e.forEach(System.out::println));
|
||||
|
||||
Thread.sleep(10000);
|
||||
accounts.dispose();
|
||||
entities.dispose();
|
||||
contacts.dispose();
|
||||
}
|
||||
|
||||
public static class ContactDetail {
|
||||
private boolean enabled;
|
||||
private String rostername;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test2() {
|
||||
AccountModel account = new AccountModel();
|
||||
account.setJid(JidCreate.entityBareFromOrThrowUnchecked("omemouser@jabberhead.tk"));
|
||||
account.setEnabled(true);
|
||||
account.setPassword("nöö");
|
||||
|
||||
EntityModel entity = new EntityModel();
|
||||
entity.setJid(JidCreate.entityBareFromOrThrowUnchecked("jabbertest@test.test"));
|
||||
entity.setAccount(account);
|
||||
|
||||
ContactModel contact = new ContactModel();
|
||||
contact.setEntity(entity);
|
||||
contact.setRostername("Olaf");
|
||||
contact.setSub_direction(SubscriptionDirection.both);
|
||||
contact.setSub_approved(false);
|
||||
contact.setSub_pending(true);
|
||||
|
||||
dataStore.upsert(contact).blockingGet();
|
||||
|
||||
ChatModel chat = new ChatModel();
|
||||
chat.setPeer(entity);
|
||||
chat.setDisplayed(true);
|
||||
|
||||
dataStore.upsert(chat).blockingGet();
|
||||
|
||||
MessageModel message = new MessageModel();
|
||||
message.setBody("Hallo Welt!");
|
||||
message.setChat(chat);
|
||||
|
||||
dataStore.upsert(message).blockingGet();
|
||||
|
||||
LastReadChatMessageRelation lastRead = new LastReadChatMessageRelation();
|
||||
lastRead.setChat(chat);
|
||||
lastRead.setMessage(message);
|
||||
|
||||
dataStore.upsert(lastRead).blockingGet();
|
||||
|
||||
MessageModel message2 = new MessageModel();
|
||||
message2.setChat(chat);
|
||||
message2.setBody("How are you?");
|
||||
|
||||
dataStore.upsert(message2).blockingGet();
|
||||
|
||||
LastReadChatMessageRelation lastRead2 = new LastReadChatMessageRelation();
|
||||
lastRead2.setChat(chat);
|
||||
lastRead2.setMessage(message2);
|
||||
|
||||
dataStore.upsert(lastRead2).blockingGet();
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package org.mercury_im.messenger;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.app.Application;
|
||||
import android.app.NotificationChannel;
|
||||
|
@ -10,12 +11,11 @@ import android.os.Build;
|
|||
|
||||
import org.mercury_im.messenger.core.centers.ConnectionCenter;
|
||||
import org.mercury_im.messenger.core.connection.MercuryConfiguration;
|
||||
import org.mercury_im.messenger.persistence.util.ChatAndPossiblyContact;
|
||||
import org.mercury_im.messenger.core.util.ContactNameUtil;
|
||||
import org.mercury_im.messenger.di.component.AppComponent;
|
||||
import org.mercury_im.messenger.di.component.DaggerAppComponent;
|
||||
import org.mercury_im.messenger.di.module.AppModule;
|
||||
import org.mercury_im.messenger.persistence.pojo.Chat;
|
||||
import org.mercury_im.messenger.persistence.room.RoomModule;
|
||||
import org.mercury_im.messenger.persistence.room.RoomRepositoryModule;
|
||||
import org.mercury_im.messenger.service.XmppConnectionService;
|
||||
import org.mercury_im.messenger.util.AbstractActivityLifecycleCallbacks;
|
||||
|
||||
|
@ -38,6 +38,7 @@ public class MercuryImApplication extends Application implements org.mercury_im.
|
|||
|
||||
// Keep track of activities in "started" state.
|
||||
// This will come in handy for CSI
|
||||
// see https://medium.com/@iamsadesh/android-how-to-detect-when-app-goes-background-foreground-fd5a4d331f8a
|
||||
private AtomicInteger activityReferences = new AtomicInteger(0);
|
||||
private AtomicBoolean isActivityChangingConfiguration = new AtomicBoolean(false);
|
||||
|
||||
|
@ -78,8 +79,6 @@ public class MercuryImApplication extends Application implements org.mercury_im.
|
|||
public AppComponent createAppComponent() {
|
||||
AppComponent appComponent = DaggerAppComponent.builder()
|
||||
.appModule(new AppModule(this))
|
||||
.roomModule(new RoomModule(this))
|
||||
.roomRepositoryModule(new RoomRepositoryModule())
|
||||
.build();
|
||||
|
||||
appComponent.inject(this);
|
||||
|
@ -100,6 +99,7 @@ public class MercuryImApplication extends Application implements org.mercury_im.
|
|||
String fName = getResources().getString(R.string.channel_name_foreground);
|
||||
String fDescription = getResources().getString(R.string.channel_description_foreground);
|
||||
|
||||
@SuppressLint("WrongConstant")
|
||||
NotificationChannel foreground = new NotificationChannel(Notifications.NOTIFICATION_CHANNEL__FOREGROUND_SERVICE,
|
||||
fName, NotificationManager.IMPORTANCE_MIN);
|
||||
foreground.setDescription(fDescription);
|
||||
|
@ -110,6 +110,7 @@ public class MercuryImApplication extends Application implements org.mercury_im.
|
|||
String mName = getResources().getString(R.string.channel_name_message);
|
||||
String mDescription = getResources().getString(R.string.channel_description_message);
|
||||
|
||||
@SuppressLint("WrongConstant")
|
||||
NotificationChannel messages = new NotificationChannel(Notifications.NOTIFICATION_CHANNEL__NEW_MESSAGE,
|
||||
mName, NotificationManager.IMPORTANCE_DEFAULT);
|
||||
messages.setDescription(mDescription);
|
||||
|
@ -117,8 +118,10 @@ public class MercuryImApplication extends Application implements org.mercury_im.
|
|||
}
|
||||
|
||||
@Override
|
||||
public int chatMessageReceived(Chat chat, String contactName, String body) {
|
||||
return Notifications.chatMessageReceived(this, chat, contactName, body);
|
||||
public int chatMessageReceived(ChatAndPossiblyContact chatAndPossiblyContact, String body) {
|
||||
return Notifications.chatMessageReceived(this,
|
||||
chatAndPossiblyContact.getChat(),
|
||||
ContactNameUtil.displayableNameFrom(chatAndPossiblyContact.getContact()), body);
|
||||
}
|
||||
|
||||
public AppComponent getAppComponent() {
|
||||
|
|
|
@ -7,7 +7,7 @@ import android.content.Intent;
|
|||
import androidx.core.app.NotificationCompat;
|
||||
import androidx.core.app.NotificationManagerCompat;
|
||||
|
||||
import org.mercury_im.messenger.persistence.pojo.Chat;
|
||||
import org.mercury_im.messenger.persistence.entity.ChatModel;
|
||||
import org.mercury_im.messenger.ui.chat.ChatActivity;
|
||||
|
||||
public class Notifications {
|
||||
|
@ -20,14 +20,14 @@ public class Notifications {
|
|||
// Notification IDs
|
||||
public static final int FOREGROUND_SERVICE_ID = 1; // must not be 0
|
||||
|
||||
public static int chatMessageReceived(Context context, Chat chat, String contactName, String body) {
|
||||
public static int chatMessageReceived(Context context, ChatModel chat, String contactName, String body) {
|
||||
NotificationManagerCompat notificationManagerCompat = NotificationManagerCompat.from(context);
|
||||
int id = (chat.accountId + " " + chat.jid.toString()).hashCode();
|
||||
int id = (int) chat.getId();
|
||||
|
||||
Intent tapAction = new Intent(context, ChatActivity.class);
|
||||
tapAction.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
tapAction.putExtra(ChatActivity.EXTRA_JID, chat.jid.toString());
|
||||
tapAction.putExtra(ChatActivity.EXTRA_ACCOUNT, chat.accountId);
|
||||
tapAction.putExtra(ChatActivity.EXTRA_JID, chat.getPeer().getJid().toString());
|
||||
tapAction.putExtra(ChatActivity.EXTRA_ACCOUNT, chat.getPeer().getAccount().getId());
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, tapAction, 0);
|
||||
|
||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(context,
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
package org.mercury_im.messenger.di.component;
|
||||
|
||||
import org.mercury_im.messenger.MercuryImApplication;
|
||||
import org.mercury_im.messenger.core.di.XmppComponent;
|
||||
import org.mercury_im.messenger.core.stores.PlainMessageStore;
|
||||
import org.mercury_im.messenger.di.module.AppModule;
|
||||
import org.mercury_im.messenger.persistence.room.RoomModule;
|
||||
import org.mercury_im.messenger.di.module.AndroidPersistenceModule;
|
||||
import org.mercury_im.messenger.service.XmppConnectionService;
|
||||
import org.mercury_im.messenger.ui.MainActivity;
|
||||
import org.mercury_im.messenger.ui.chat.ChatActivity;
|
||||
|
@ -25,10 +26,11 @@ import dagger.Component;
|
|||
* application.
|
||||
*/
|
||||
@Singleton
|
||||
@Component(modules = {
|
||||
AppModule.class,
|
||||
RoomModule.class
|
||||
})
|
||||
@Component(
|
||||
modules = {
|
||||
AppModule.class,
|
||||
AndroidPersistenceModule.class
|
||||
})
|
||||
public interface AppComponent {
|
||||
|
||||
// Application
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
package org.mercury_im.messenger.di.module;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
import org.mercury_im.messenger.BuildConfig;
|
||||
import org.mercury_im.messenger.persistence.entity.Models;
|
||||
import org.mercury_im.messenger.thread_utils.ThreadUtils;
|
||||
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import io.reactivex.Scheduler;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import io.requery.Persistable;
|
||||
import io.requery.android.sqlite.DatabaseSource;
|
||||
import io.requery.reactivex.ReactiveEntityStore;
|
||||
import io.requery.reactivex.ReactiveSupport;
|
||||
import io.requery.sql.Configuration;
|
||||
import io.requery.sql.EntityDataStore;
|
||||
import io.requery.sql.TableCreationMode;
|
||||
|
||||
@Module
|
||||
public class AndroidPersistenceModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
static ReactiveEntityStore<Persistable> provideDatabase(Application application) {
|
||||
// override onUpgrade to handle migrating to a new version
|
||||
DatabaseSource source = new DatabaseSource(application, Models.DEFAULT,
|
||||
"mercury_req_db", 1);
|
||||
if (BuildConfig.DEBUG) {
|
||||
// use this in development mode to drop and recreate the tables on every upgrade
|
||||
source.setTableCreationMode(TableCreationMode.DROP_CREATE);
|
||||
}
|
||||
Configuration configuration = source.getConfiguration();
|
||||
ReactiveEntityStore<Persistable> dataStore = ReactiveSupport.toReactiveStore(
|
||||
new EntityDataStore<>(configuration));
|
||||
return dataStore;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Named(value = ThreadUtils.SCHEDULER_IO)
|
||||
@Singleton
|
||||
static Scheduler provideDatabaseThread() {
|
||||
return Schedulers.io();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Named(value = ThreadUtils.SCHEDULER_UI)
|
||||
@Singleton
|
||||
static Scheduler providerUIThread() {
|
||||
return AndroidSchedulers.mainThread();
|
||||
}
|
||||
}
|
|
@ -8,10 +8,14 @@ import dagger.Provides;
|
|||
import org.mercury_im.messenger.MercuryImApplication;
|
||||
import org.mercury_im.messenger.core.NotificationManager;
|
||||
import org.mercury_im.messenger.core.di.CenterModule;
|
||||
import org.mercury_im.messenger.persistence.di.RequeryModule;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
@Module(includes = CenterModule.class)
|
||||
@Module(includes = {
|
||||
CenterModule.class,
|
||||
RequeryModule.class
|
||||
})
|
||||
public class AppModule {
|
||||
|
||||
private MercuryImApplication mApplication;
|
||||
|
|
|
@ -15,11 +15,10 @@ import com.google.android.material.navigation.NavigationView;
|
|||
|
||||
import org.mercury_im.messenger.MercuryImApplication;
|
||||
import org.mercury_im.messenger.R;
|
||||
import org.mercury_im.messenger.persistence.model.AccountModel;
|
||||
import org.mercury_im.messenger.persistence.entity.AccountModel;
|
||||
import org.mercury_im.messenger.persistence.repository.ChatRepository;
|
||||
import org.mercury_im.messenger.ui.chatlist.ChatListFragment;
|
||||
import org.mercury_im.messenger.ui.login.AccountsFragment;
|
||||
import org.mercury_im.messenger.ui.login.LoginActivity;
|
||||
import org.mercury_im.messenger.ui.roster.RosterFragment;
|
||||
import org.mercury_im.messenger.ui.settings.SettingsActivity;
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ import androidx.annotation.NonNull;
|
|||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.SearchView;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.lifecycle.ViewModelProviders;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
@ -22,6 +23,7 @@ import io.reactivex.schedulers.Schedulers;
|
|||
|
||||
import org.jivesoftware.smack.SmackException;
|
||||
import org.jivesoftware.smack.chat2.ChatManager;
|
||||
import org.jivesoftware.smack.packet.Message;
|
||||
import org.jxmpp.jid.EntityBareJid;
|
||||
import org.jxmpp.jid.impl.JidCreate;
|
||||
|
||||
|
@ -91,7 +93,7 @@ public class ChatActivity extends AppCompatActivity
|
|||
getSupportActionBar().setSubtitle(jid.asUnescapedString());
|
||||
accountId = savedInstanceState.getLong(EXTRA_ACCOUNT);
|
||||
|
||||
chatViewModel = ViewModelProviders.of(this).get(ChatViewModel.class);
|
||||
chatViewModel = new ViewModelProvider(this).get(ChatViewModel.class);
|
||||
chatViewModel.init(accountId, jid);
|
||||
// Listen for updates to contact information and messages
|
||||
observeViewModel(chatViewModel);
|
||||
|
|
|
@ -4,19 +4,13 @@ import androidx.lifecycle.LiveData;
|
|||
import androidx.lifecycle.MutableLiveData;
|
||||
import androidx.lifecycle.ViewModel;
|
||||
|
||||
import io.reactivex.Completable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import io.reactivex.functions.Consumer;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
||||
import org.jxmpp.jid.EntityBareJid;
|
||||
import org.mercury_im.messenger.MercuryImApplication;
|
||||
import org.mercury_im.messenger.core.centers.ConnectionCenter;
|
||||
import org.mercury_im.messenger.core.util.ContactNameUtil;
|
||||
import org.mercury_im.messenger.persistence.model.ChatModel;
|
||||
import org.mercury_im.messenger.persistence.model.ContactModel;
|
||||
import org.mercury_im.messenger.persistence.model.MessageModel;
|
||||
import org.mercury_im.messenger.persistence.entity.ChatModel;
|
||||
import org.mercury_im.messenger.persistence.entity.ContactModel;
|
||||
import org.mercury_im.messenger.persistence.entity.EntityModel;
|
||||
import org.mercury_im.messenger.persistence.entity.MessageModel;
|
||||
import org.mercury_im.messenger.persistence.repository.ChatRepository;
|
||||
import org.mercury_im.messenger.persistence.repository.MessageRepository;
|
||||
import org.mercury_im.messenger.persistence.repository.RosterRepository;
|
||||
|
@ -25,6 +19,10 @@ import java.util.List;
|
|||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import io.reactivex.Completable;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import io.reactivex.functions.Consumer;
|
||||
|
||||
public class ChatViewModel extends ViewModel {
|
||||
|
||||
private final CompositeDisposable disposable = new CompositeDisposable();
|
||||
|
@ -41,9 +39,7 @@ public class ChatViewModel extends ViewModel {
|
|||
@Inject
|
||||
ConnectionCenter connectionCenter;
|
||||
|
||||
private long accountId;
|
||||
private EntityBareJid jid;
|
||||
|
||||
private MutableLiveData<EntityModel> entity = new MutableLiveData<>();
|
||||
private MutableLiveData<ContactModel> contact = new MutableLiveData<>();
|
||||
private MutableLiveData<List<MessageModel>> messages = new MutableLiveData<>();
|
||||
private MutableLiveData<String> contactDisplayName = new MutableLiveData<>();
|
||||
|
@ -55,29 +51,24 @@ public class ChatViewModel extends ViewModel {
|
|||
}
|
||||
|
||||
public void init(long accountId, EntityBareJid jid) {
|
||||
this.accountId = accountId;
|
||||
this.jid = jid;
|
||||
disposable.add(rosterRepository.getOrCreateEntity(accountId, jid)
|
||||
.subscribe((Consumer<EntityModel>) this::init));
|
||||
}
|
||||
|
||||
disposable.add(rosterRepository.getContact(accountId, jid)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe((Consumer<ContactModel>)
|
||||
contactModel -> {
|
||||
ChatViewModel.this.contact.setValue(contactModel);
|
||||
contactDisplayName.setValue(ContactNameUtil.displayableNameFrom(contactModel));
|
||||
public void init(EntityModel entityModel) {
|
||||
|
||||
disposable.add(rosterRepository.getContact(entityModel.getAccount().getId(), entityModel.getJid())
|
||||
.subscribe(reactiveResult -> {
|
||||
ContactModel model = reactiveResult.first();
|
||||
ChatViewModel.this.contact.setValue(model);
|
||||
contactDisplayName.setValue(model.getRostername());
|
||||
}));
|
||||
|
||||
disposable.add(messageRepository.getAllMessagesOfChat(accountId, jid)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe((Consumer<List<MessageModel>>)
|
||||
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)));
|
||||
disposable.add(messageRepository.getAllMessagesOfEntity(entityModel)
|
||||
.subscribe(reactiveResult -> {
|
||||
List<MessageModel> messages = reactiveResult.toList();
|
||||
ChatViewModel.this.messages.setValue(messages);
|
||||
}));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -99,6 +90,7 @@ public class ChatViewModel extends ViewModel {
|
|||
}
|
||||
|
||||
public void queryTextChanged(String query) {
|
||||
/*
|
||||
if (query.isEmpty()) {
|
||||
disposable.add(messageRepository.getAllMessagesOfChat(accountId, jid)
|
||||
.subscribeOn(Schedulers.io())
|
||||
|
@ -112,6 +104,8 @@ public class ChatViewModel extends ViewModel {
|
|||
.subscribe((Consumer<List<MessageModel>>) o -> {
|
||||
messages.setValue(o);
|
||||
}));
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
public Completable requestMamMessages() {
|
||||
|
|
|
@ -10,7 +10,7 @@ import androidx.annotation.NonNull;
|
|||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import org.mercury_im.messenger.R;
|
||||
import org.mercury_im.messenger.persistence.model.MessageModel;
|
||||
import org.mercury_im.messenger.persistence.entity.MessageModel;
|
||||
import org.mercury_im.messenger.ui.util.MessageBackgroundDrawable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
|
|
@ -3,16 +3,20 @@ package org.mercury_im.messenger.ui.chatlist;
|
|||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.view.ActionMode;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import org.mercury_im.messenger.R;
|
||||
import org.mercury_im.messenger.persistence.pojo.Chat;
|
||||
import org.mercury_im.messenger.persistence.entity.ChatModel;
|
||||
import org.mercury_im.messenger.ui.chat.ChatActivity;
|
||||
import org.mercury_im.messenger.ui.util.AbstractRecyclerViewAdapter;
|
||||
import org.mercury_im.messenger.util.ColorUtil;
|
||||
|
@ -21,7 +25,7 @@ import butterknife.BindView;
|
|||
import butterknife.ButterKnife;
|
||||
|
||||
public class ChatListRecyclerViewAdapter
|
||||
extends AbstractRecyclerViewAdapter<Chat, ChatListRecyclerViewAdapter.ChatHolder> {
|
||||
extends AbstractRecyclerViewAdapter<ChatModel, ChatListRecyclerViewAdapter.ChatHolder> {
|
||||
|
||||
public ChatListRecyclerViewAdapter() {
|
||||
super(new ChatMessageDiffCallback(true));
|
||||
|
@ -37,20 +41,24 @@ public class ChatListRecyclerViewAdapter
|
|||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ChatHolder holder, int position) {
|
||||
Chat model = getModelAt(position);
|
||||
holder.nameView.setText(model.contactName != null ?
|
||||
model.contactName : model.jid.toString());
|
||||
holder.avatarView.setColorFilter(ColorUtil.consistentColor(model.jid.toString()));
|
||||
ChatModel model = getModelAt(position);
|
||||
holder.nameView.setText(model.getPeer().getJid() != null ?
|
||||
model.getPeer().getJid() : model.toString());
|
||||
holder.avatarView.setColorFilter(ColorUtil.consistentColor(model.getPeer().getJid().toString()));
|
||||
|
||||
holder.itemView.setOnClickListener(view -> {
|
||||
|
||||
Intent intent = new Intent(holder.context, ChatActivity.class);
|
||||
intent.putExtra(ChatActivity.EXTRA_JID, model.jid.toString());
|
||||
intent.putExtra(ChatActivity.EXTRA_ACCOUNT, model.accountId);
|
||||
intent.putExtra(ChatActivity.EXTRA_JID, model.getPeer().getJid().toString());
|
||||
intent.putExtra(ChatActivity.EXTRA_ACCOUNT, model.getPeer().getAccount().getId());
|
||||
|
||||
holder.context.startActivity(intent);
|
||||
});
|
||||
// TODO: Better bindable model pls
|
||||
|
||||
holder.itemView.setOnLongClickListener(v -> {
|
||||
((AppCompatActivity) v.getContext()).startSupportActionMode(actionModeCallback);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public static class ChatHolder extends RecyclerView.ViewHolder {
|
||||
|
@ -76,20 +84,49 @@ public class ChatListRecyclerViewAdapter
|
|||
}
|
||||
}
|
||||
|
||||
private static class ChatMessageDiffCallback extends AbstractDiffCallback<Chat> {
|
||||
private static class ChatMessageDiffCallback extends AbstractDiffCallback<ChatModel> {
|
||||
|
||||
ChatMessageDiffCallback(boolean detectMoves) {
|
||||
super(detectMoves);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areItemsTheSame(Chat oldItem, Chat newItem) {
|
||||
return oldItem.chatId == newItem.chatId;
|
||||
public boolean areItemsTheSame(ChatModel oldItem, ChatModel newItem) {
|
||||
return oldItem.getId() == newItem.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(Chat oldItem, Chat newItem) {
|
||||
public boolean areContentsTheSame(ChatModel oldItem, ChatModel newItem) {
|
||||
return areItemsTheSame(oldItem, newItem);
|
||||
}
|
||||
}
|
||||
|
||||
private androidx.appcompat.view.ActionMode.Callback actionModeCallback = new androidx.appcompat.view.ActionMode.Callback() {
|
||||
private boolean multiSelect = false;
|
||||
|
||||
@Override
|
||||
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
|
||||
mode.getMenuInflater().inflate(R.menu.actionmode_chatlist, menu);
|
||||
multiSelect = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
|
||||
|
||||
mode.finish();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyActionMode(ActionMode mode) {
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -4,14 +4,8 @@ import androidx.lifecycle.LiveData;
|
|||
import androidx.lifecycle.MutableLiveData;
|
||||
import androidx.lifecycle.ViewModel;
|
||||
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import io.reactivex.functions.Consumer;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
||||
import org.mercury_im.messenger.MercuryImApplication;
|
||||
import org.mercury_im.messenger.persistence.model.MessageModel;
|
||||
import org.mercury_im.messenger.persistence.pojo.Chat;
|
||||
import org.mercury_im.messenger.persistence.entity.ChatModel;
|
||||
import org.mercury_im.messenger.persistence.repository.ChatRepository;
|
||||
import org.mercury_im.messenger.persistence.repository.MessageRepository;
|
||||
|
||||
|
@ -19,6 +13,8 @@ import java.util.List;
|
|||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
|
||||
public class ChatListViewModel extends ViewModel {
|
||||
|
||||
@Inject
|
||||
|
@ -29,27 +25,16 @@ public class ChatListViewModel extends ViewModel {
|
|||
|
||||
private CompositeDisposable disposable = new CompositeDisposable();
|
||||
|
||||
private final MutableLiveData<List<Chat>> chats = new MutableLiveData<>();
|
||||
private final MutableLiveData<List<ChatModel>> chats = new MutableLiveData<>();
|
||||
|
||||
public ChatListViewModel() {
|
||||
MercuryImApplication.getApplication().getAppComponent().inject(this);
|
||||
|
||||
disposable.add(chatRepository.getDisplayableChats()
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe((Consumer<List<Chat>>) chats::setValue));
|
||||
|
||||
disposable.add(messageRepository.getAllMessages()
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe((Consumer<List<MessageModel>>) messageModels -> {
|
||||
for (MessageModel message : messageModels) {
|
||||
|
||||
}
|
||||
}));
|
||||
disposable.add(chatRepository.getVisibleChats()
|
||||
.subscribe(result -> chats.setValue(result.toList())));
|
||||
}
|
||||
|
||||
public LiveData<List<Chat>> getChats() {
|
||||
public LiveData<List<ChatModel>> getChats() {
|
||||
return chats;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ import com.google.android.material.floatingactionbutton.ExtendedFloatingActionBu
|
|||
|
||||
import org.mercury_im.messenger.MercuryImApplication;
|
||||
import org.mercury_im.messenger.R;
|
||||
import org.mercury_im.messenger.persistence.model.AccountModel;
|
||||
import org.mercury_im.messenger.persistence.entity.AccountModel;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
|
|
|
@ -11,11 +11,9 @@ import android.widget.TextView;
|
|||
import androidx.recyclerview.widget.DiffUtil;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import de.hdodenhof.circleimageview.CircleImageView;
|
||||
|
||||
import org.mercury_im.messenger.MercuryImApplication;
|
||||
import org.mercury_im.messenger.R;
|
||||
import org.mercury_im.messenger.persistence.model.AccountModel;
|
||||
import org.mercury_im.messenger.persistence.entity.AccountModel;
|
||||
import org.mercury_im.messenger.ui.login.AccountsFragment.OnAccountListItemClickListener;
|
||||
import org.mercury_im.messenger.util.AbstractDiffCallback;
|
||||
import org.mercury_im.messenger.util.ColorUtil;
|
||||
|
@ -47,9 +45,8 @@ public class AccountsRecyclerViewAdapter extends RecyclerView.Adapter<AccountsRe
|
|||
AccountModel account = mValues.get(position);
|
||||
holder.jid.setText(account.getJid());
|
||||
holder.avatar.setColorFilter(ColorUtil.consistentColor(account.getJid().toString()));
|
||||
holder.enabled.setChecked(account.getEnabled());
|
||||
holder.enabled.setChecked(account.isEnabled());
|
||||
holder.accountModel = account;
|
||||
holder.status.setText(account.getState());
|
||||
holder.enabled.setOnCheckedChangeListener((compoundButton, b) -> {
|
||||
viewModel.toggleAccountEnabled(account);
|
||||
});
|
||||
|
|
|
@ -6,25 +6,19 @@ import android.widget.Toast;
|
|||
import androidx.lifecycle.AndroidViewModel;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
import androidx.lifecycle.ViewModel;
|
||||
|
||||
import io.reactivex.Scheduler;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import io.reactivex.functions.Consumer;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
||||
import org.jivesoftware.smack.XMPPConnection;
|
||||
import org.mercury_im.messenger.MercuryImApplication;
|
||||
import org.mercury_im.messenger.core.centers.ConnectionCenter;
|
||||
import org.mercury_im.messenger.core.connection.MercuryConnection;
|
||||
import org.mercury_im.messenger.persistence.model.AccountModel;
|
||||
import org.mercury_im.messenger.persistence.entity.AccountModel;
|
||||
import org.mercury_im.messenger.persistence.repository.AccountRepository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
|
||||
public class AccountsViewModel extends AndroidViewModel {
|
||||
|
||||
@Inject
|
||||
|
@ -40,10 +34,8 @@ public class AccountsViewModel extends AndroidViewModel {
|
|||
public AccountsViewModel(Application application) {
|
||||
super(application);
|
||||
MercuryImApplication.getApplication().getAppComponent().inject(this);
|
||||
compositeDisposable.add(repository.getAllAccounts()
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe((Consumer<List<AccountModel>>) accounts::setValue));
|
||||
compositeDisposable.add(repository.getAll()
|
||||
.subscribe(accountModels -> accounts.setValue(accountModels.toList())));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -63,9 +55,8 @@ public class AccountsViewModel extends AndroidViewModel {
|
|||
return;
|
||||
}
|
||||
|
||||
accountModel.setEnabled(!accountModel.getEnabled());
|
||||
repository.updateAccount(accountModel)
|
||||
.subscribeOn(Schedulers.io())
|
||||
accountModel.setEnabled(!accountModel.isEnabled());
|
||||
repository.upsert(accountModel)
|
||||
.subscribe();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,18 +9,18 @@ import android.widget.TextView;
|
|||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.ViewModelProviders;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
|
||||
import com.google.android.material.textfield.TextInputEditText;
|
||||
|
||||
import org.mercury_im.messenger.MercuryImApplication;
|
||||
import org.mercury_im.messenger.R;
|
||||
import org.mercury_im.messenger.persistence.model.AccountModel;
|
||||
import org.mercury_im.messenger.persistence.entity.AccountModel;
|
||||
import org.mercury_im.messenger.util.TextChangedListener;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
|
||||
|
||||
/**
|
||||
* A login screen that offers login via email/password.
|
||||
|
@ -49,7 +49,7 @@ public class LoginActivity extends AppCompatActivity implements TextView.OnEdito
|
|||
// Set up the login form.
|
||||
ButterKnife.bind(this);
|
||||
|
||||
viewModel = ViewModelProviders.of(this).get(LoginViewModel.class);
|
||||
viewModel = new ViewModelProvider(this).get(LoginViewModel.class);
|
||||
|
||||
observeViewModel(viewModel);
|
||||
displayCredentials(viewModel.getAccount());
|
||||
|
@ -121,7 +121,7 @@ public class LoginActivity extends AppCompatActivity implements TextView.OnEdito
|
|||
});
|
||||
}
|
||||
|
||||
private void displayCredentials(LiveData<? extends AccountModel> account) {
|
||||
private void displayCredentials(LiveData<AccountModel> account) {
|
||||
account.observe(this, accountModel -> {
|
||||
if (accountModel == null) {
|
||||
return;
|
||||
|
|
|
@ -11,17 +11,14 @@ import androidx.lifecycle.MutableLiveData;
|
|||
import androidx.lifecycle.ViewModel;
|
||||
|
||||
import io.reactivex.Single;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.observers.DisposableSingleObserver;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
||||
import org.jxmpp.jid.EntityBareJid;
|
||||
import org.jxmpp.jid.impl.JidCreate;
|
||||
import org.mercury_im.messenger.MercuryImApplication;
|
||||
import org.mercury_im.messenger.core.centers.ConnectionCenter;
|
||||
import org.mercury_im.messenger.persistence.model.AccountModel;
|
||||
import org.mercury_im.messenger.persistence.entity.AccountModel;
|
||||
import org.mercury_im.messenger.persistence.repository.AccountRepository;
|
||||
import org.mercury_im.messenger.persistence.room.model.RoomAccountModel;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
|
@ -46,7 +43,7 @@ public class LoginViewModel extends ViewModel {
|
|||
public LoginViewModel() {
|
||||
super();
|
||||
MercuryImApplication.getApplication().getAppComponent().inject(this);
|
||||
init(accountRepository.newAccountModel());
|
||||
init(new AccountModel());
|
||||
}
|
||||
|
||||
public LiveData<Boolean> getSigninSuccessful() {
|
||||
|
@ -109,7 +106,7 @@ public class LoginViewModel extends ViewModel {
|
|||
public void login() {
|
||||
AccountModel account = getAccount().getValue();
|
||||
if (account != null && account.getJid() != null && !TextUtils.isEmpty(account.getPassword())) {
|
||||
accountRepository.insertAccount(account);
|
||||
accountRepository.upsert(account);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -132,18 +129,15 @@ public class LoginViewModel extends ViewModel {
|
|||
}
|
||||
|
||||
if (loginIntact) {
|
||||
RoomAccountModel accountModel = new RoomAccountModel();
|
||||
AccountModel accountModel = new AccountModel();
|
||||
accountModel.setEnabled(true);
|
||||
accountModel.setJid(bareJid);
|
||||
accountModel.setPassword(password);
|
||||
Single<Long> id = accountRepository.insertAccount(accountModel);
|
||||
id.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new DisposableSingleObserver<Long>() {
|
||||
Single<AccountModel> insert = accountRepository.upsert(accountModel);
|
||||
insert.subscribe(new DisposableSingleObserver<AccountModel>() {
|
||||
@Override
|
||||
public void onSuccess(Long aLong) {
|
||||
accountModel.setId(aLong);
|
||||
Log.d(MercuryImApplication.TAG, "LoginActivity.loginDetailsEntered: Account " + aLong + " inserted.");
|
||||
public void onSuccess(AccountModel inserted) {
|
||||
Log.d(MercuryImApplication.TAG, "LoginActivity.loginDetailsEntered: Account " + inserted.getId() + " inserted.");
|
||||
connectionCenter.createConnection(accountModel);
|
||||
signinSuccessful.setValue(true);
|
||||
}
|
||||
|
|
|
@ -6,17 +6,17 @@ import androidx.annotation.NonNull;
|
|||
import androidx.lifecycle.AndroidViewModel;
|
||||
import androidx.lifecycle.LiveData;
|
||||
|
||||
import org.mercury_im.messenger.persistence.room.model.RoomContactModel;
|
||||
import org.mercury_im.messenger.persistence.room.repository.IRosterRepository;
|
||||
import org.mercury_im.messenger.persistence.entity.ContactModel;
|
||||
import org.mercury_im.messenger.persistence.repository.RosterRepository;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
public class ContactListItemViewModel extends AndroidViewModel {
|
||||
|
||||
@Inject
|
||||
IRosterRepository contactRepository;
|
||||
RosterRepository contactRepository;
|
||||
|
||||
private LiveData<RoomContactModel> contact;
|
||||
private LiveData<ContactModel> contact;
|
||||
|
||||
@Inject
|
||||
public ContactListItemViewModel(@NonNull Application application) {
|
||||
|
|
|
@ -11,22 +11,20 @@ import android.widget.TextView;
|
|||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import de.hdodenhof.circleimageview.CircleImageView;
|
||||
|
||||
import org.jivesoftware.smackx.colors.ConsistentColor;
|
||||
import org.jxmpp.jid.EntityBareJid;
|
||||
import org.mercury_im.messenger.R;
|
||||
import org.mercury_im.messenger.persistence.room.model.RoomContactModel;
|
||||
import org.mercury_im.messenger.persistence.entity.ContactModel;
|
||||
import org.mercury_im.messenger.ui.chat.ChatActivity;
|
||||
import org.mercury_im.messenger.ui.util.AbstractRecyclerViewAdapter;
|
||||
import org.mercury_im.messenger.util.ColorUtil;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
|
||||
public class ContactListRecyclerViewAdapter
|
||||
extends AbstractRecyclerViewAdapter<RoomContactModel, ContactListRecyclerViewAdapter.RosterItemViewHolder> {
|
||||
extends AbstractRecyclerViewAdapter<ContactModel, ContactListRecyclerViewAdapter.RosterItemViewHolder> {
|
||||
|
||||
public ContactListRecyclerViewAdapter() {
|
||||
super(new ContactDiffCallback());
|
||||
|
@ -41,7 +39,7 @@ public class ContactListRecyclerViewAdapter
|
|||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull RosterItemViewHolder holder, int position) {
|
||||
RoomContactModel model = getModelAt(position);
|
||||
ContactModel model = getModelAt(position);
|
||||
holder.bind(model);
|
||||
}
|
||||
|
||||
|
@ -67,8 +65,8 @@ public class ContactListRecyclerViewAdapter
|
|||
ButterKnife.bind(this, view);
|
||||
}
|
||||
|
||||
void bind(RoomContactModel contactModel) {
|
||||
String name = contactModel.getRosterName();
|
||||
void bind(ContactModel contactModel) {
|
||||
String name = contactModel.getRostername();
|
||||
nameView.setText(name != null ? name : contactModel.getEntity().getJid().getLocalpart().asUnescapedString());
|
||||
EntityBareJid jid = contactModel.getEntity().getJid();
|
||||
jidView.setText(jid.toString());
|
||||
|
@ -77,28 +75,28 @@ public class ContactListRecyclerViewAdapter
|
|||
|
||||
Intent intent = new Intent(context, ChatActivity.class);
|
||||
intent.putExtra(ChatActivity.EXTRA_JID, jid.toString());
|
||||
intent.putExtra(ChatActivity.EXTRA_ACCOUNT, contactModel.getEntity().getAccountId());
|
||||
intent.putExtra(ChatActivity.EXTRA_ACCOUNT, contactModel.getEntity().getAccount().getId());
|
||||
|
||||
context.startActivity(intent);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static class ContactDiffCallback extends AbstractDiffCallback<RoomContactModel> {
|
||||
private static class ContactDiffCallback extends AbstractDiffCallback<ContactModel> {
|
||||
|
||||
ContactDiffCallback() {
|
||||
super(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areItemsTheSame(RoomContactModel oldItem, RoomContactModel newItem) {
|
||||
public boolean areItemsTheSame(ContactModel oldItem, ContactModel newItem) {
|
||||
return oldItem.getId() == newItem.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(RoomContactModel oldItem, RoomContactModel newItem) {
|
||||
public boolean areContentsTheSame(ContactModel oldItem, ContactModel newItem) {
|
||||
return areItemsTheSame(oldItem, newItem) &&
|
||||
Objects.equals(oldItem.getRosterName(), newItem.getRosterName());
|
||||
Objects.equals(oldItem.getRostername(), newItem.getRostername());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,27 +6,25 @@ import androidx.lifecycle.LiveData;
|
|||
import androidx.lifecycle.MutableLiveData;
|
||||
import androidx.lifecycle.ViewModel;
|
||||
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import io.reactivex.functions.Consumer;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
||||
import org.mercury_im.messenger.MercuryImApplication;
|
||||
import org.mercury_im.messenger.persistence.model.ContactModel;
|
||||
import org.mercury_im.messenger.persistence.entity.ContactModel;
|
||||
import org.mercury_im.messenger.persistence.repository.RosterRepository;
|
||||
import org.mercury_im.messenger.persistence.room.model.RoomContactModel;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
||||
|
||||
public class ContactListViewModel extends ViewModel {
|
||||
|
||||
@Inject
|
||||
RosterRepository rosterRepository;
|
||||
|
||||
private final MutableLiveData<List<RoomContactModel>> rosterEntryList = new MutableLiveData<>();
|
||||
private final MutableLiveData<List<ContactModel>> rosterEntryList = new MutableLiveData<>();
|
||||
private final CompositeDisposable compositeDisposable = new CompositeDisposable();
|
||||
|
||||
public ContactListViewModel() {
|
||||
|
@ -37,9 +35,10 @@ public class ContactListViewModel extends ViewModel {
|
|||
compositeDisposable.add(rosterRepository.getAllContacts()
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe((Consumer<List<? extends ContactModel>>) o -> {
|
||||
Log.d("ContactListViewModel", "Room changed contacts: " + o.size());
|
||||
rosterEntryList.setValue((List<RoomContactModel>) o);
|
||||
.subscribe(o -> {
|
||||
List<ContactModel> list = o.toList();
|
||||
Log.d("ContactListViewModel", "Room changed contacts: " + list.size());
|
||||
rosterEntryList.setValue(list);
|
||||
}));
|
||||
}
|
||||
|
||||
|
@ -49,7 +48,7 @@ public class ContactListViewModel extends ViewModel {
|
|||
compositeDisposable.clear();
|
||||
}
|
||||
|
||||
public LiveData<List<RoomContactModel>> getRosterEntryList() {
|
||||
public LiveData<List<ContactModel>> getRosterEntryList() {
|
||||
return rosterEntryList;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<item android:id="@+id/action_copy"
|
||||
android:title="@string/action_copy"
|
||||
android:icon="@drawable/ic_content_copy_black_24dp" />
|
||||
|
||||
<item android:id="@+id/action_reply_message"
|
||||
android:title="@string/action_reply_message"
|
||||
android:icon="@drawable/ic_reply_black_24dp" />
|
||||
</menu>
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<item android:id="@+id/action_close_chat"
|
||||
android:title="@string/action_close_chat"
|
||||
android:icon="@drawable/ic_delete_black_24dp" />
|
||||
|
||||
</menu>
|
|
@ -129,4 +129,6 @@
|
|||
<string name="action_add_account">Add Account</string>
|
||||
<string name="action_add_contact">Add Contact</string>
|
||||
<string name="action_add_bookmark">Add Bookmark</string>
|
||||
<string name="action_close_chat">Close Chat</string>
|
||||
<string name="action_copy">Copy</string>
|
||||
</resources>
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
<item name="messageBubbleColor">@color/white</item>
|
||||
<item name="messageTextColor">@color/textBlack</item>
|
||||
|
||||
<item name="windowActionModeOverlay">true</item>
|
||||
</style>
|
||||
|
||||
<!-- Light Theme -->
|
||||
|
|
|
@ -7,7 +7,7 @@ buildscript {
|
|||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.5.0'
|
||||
classpath 'com.android.tools.build:gradle:3.5.1'
|
||||
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
|
|
|
@ -1,7 +1,14 @@
|
|||
apply plugin: 'java-library'
|
||||
|
||||
// Add the generated folder to the source directories so that we can work with generated classes
|
||||
// This is apparently necessary for use with requery.
|
||||
sourceSets {
|
||||
main.java.srcDirs += "${buildDir}/generated/sources/annotationProcessor/java/main/"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
api project(":thread_utils")
|
||||
api project(":persistence")
|
||||
|
||||
// Smack
|
||||
|
@ -17,10 +24,19 @@ dependencies {
|
|||
// api "org.igniterealtime.smack:smack-openpgp:$smackOpenpgpVersion"
|
||||
// api "org.igniterealtime.smack:smack-resolver-minidns:$smackResolverMiniDnsVersion"
|
||||
|
||||
|
||||
// RxJava2
|
||||
api "io.reactivex.rxjava2:rxjava:$rxJava2Version"
|
||||
|
||||
// Dagger 2 for dependency injection
|
||||
implementation "com.google.dagger:dagger:$daggerVersion"
|
||||
annotationProcessor "com.google.dagger:dagger-compiler:$daggerVersion"
|
||||
|
||||
// Requery ORM
|
||||
api "io.requery:requery:$requeryVersion"
|
||||
annotationProcessor "io.requery:requery-processor:$requeryVersion"
|
||||
|
||||
// JUnit for testing
|
||||
testImplementation "junit:junit:$junitVersion"
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
package org.mercury_im.messenger.core;
|
||||
|
||||
import org.mercury_im.messenger.persistence.pojo.Chat;
|
||||
|
||||
import org.mercury_im.messenger.persistence.util.ChatAndPossiblyContact;
|
||||
|
||||
public interface NotificationManager {
|
||||
|
||||
int chatMessageReceived(Chat chat, String contactName, String body);
|
||||
int chatMessageReceived(ChatAndPossiblyContact chatAndPossiblyContact, String body);
|
||||
|
||||
}
|
||||
|
|
|
@ -3,26 +3,25 @@ package org.mercury_im.messenger.core.centers;
|
|||
import org.jivesoftware.smack.AbstractXMPPConnection;
|
||||
import org.jivesoftware.smack.SmackException;
|
||||
import org.jivesoftware.smack.XMPPConnection;
|
||||
import org.jivesoftware.smack.XMPPException;
|
||||
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
|
||||
import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration;
|
||||
import org.jivesoftware.smackx.caps.EntityCapsManager;
|
||||
import org.jivesoftware.smackx.csi.ClientStateIndicationManager;
|
||||
import org.jivesoftware.smackx.mam.MamManager;
|
||||
import org.mercury_im.messenger.core.stores.EntityCapsStore;
|
||||
import org.mercury_im.messenger.core.connection.MercuryConfiguration;
|
||||
import org.mercury_im.messenger.core.connection.MercuryConnection;
|
||||
import org.mercury_im.messenger.core.stores.PlainMessageStore;
|
||||
import org.mercury_im.messenger.core.stores.RosterStore;
|
||||
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.entity.AccountModel;
|
||||
import org.mercury_im.messenger.persistence.entity.ChatModel;
|
||||
import org.mercury_im.messenger.persistence.repository.AccountRepository;
|
||||
import org.mercury_im.messenger.persistence.repository.RosterRepository;
|
||||
import org.mercury_im.messenger.core.stores.EntityCapsStore;
|
||||
import org.mercury_im.messenger.core.stores.PlainMessageStore;
|
||||
import org.mercury_im.messenger.core.stores.RosterStore;
|
||||
|
||||
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;
|
||||
|
@ -34,7 +33,6 @@ import javax.inject.Singleton;
|
|||
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.functions.Consumer;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
||||
@Singleton
|
||||
|
@ -44,9 +42,9 @@ public class ConnectionCenter {
|
|||
|
||||
// Injected
|
||||
private final AccountRepository accountRepository;
|
||||
private final RosterRepository rosterRepository;
|
||||
private final PlainMessageStore messageStore;
|
||||
private final EntityCapsStore entityCapsStore;
|
||||
private final RosterRepository rosterRepository;
|
||||
|
||||
// Connections
|
||||
private final Map<Long, MercuryConnection> connectionMap =
|
||||
|
@ -86,15 +84,14 @@ public class ConnectionCenter {
|
|||
}
|
||||
|
||||
// otherwise subscribe to accounts and create connections.
|
||||
Disposable allAccounts = accountRepository.getAllAccounts()
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribeOn(Schedulers.computation())
|
||||
.subscribe((Consumer<List<? extends AccountModel>>) accounts -> {
|
||||
Disposable allAccounts = accountRepository.getAll()
|
||||
.observeOn(Schedulers.newThread())
|
||||
.subscribe(accounts -> {
|
||||
LOGGER.log(Level.INFO, "Accounts changed.");
|
||||
Set<Long> accountIds = new HashSet<>();
|
||||
|
||||
// Add missing connections to the map
|
||||
for (AccountModel account : accounts) {
|
||||
for (AccountModel account : accounts.toList()) {
|
||||
accountIds.add(account.getId());
|
||||
if (connectionMap.get(account.getId()) != null) {
|
||||
continue;
|
||||
|
@ -121,7 +118,7 @@ public class ConnectionCenter {
|
|||
|
||||
for (AccountModel account : accounts) {
|
||||
MercuryConnection connection = connectionMap.get(account.getId());
|
||||
if (account.getEnabled()) {
|
||||
if (account.isEnabled()) {
|
||||
if (connection.getConnection().isConnected()) {
|
||||
continue;
|
||||
}
|
||||
|
@ -139,7 +136,6 @@ public class ConnectionCenter {
|
|||
});
|
||||
|
||||
disposable.add(allAccounts);
|
||||
|
||||
}
|
||||
|
||||
public MercuryConnection getConnection(AccountModel account) {
|
||||
|
@ -179,15 +175,13 @@ public class ConnectionCenter {
|
|||
|
||||
public void initializeConnection(MercuryConnection connection) {
|
||||
// Register roster store
|
||||
RosterStore rosterStore = new RosterStore(rosterRepository);
|
||||
RosterStore rosterStore = new RosterStore(rosterRepository, accountRepository);
|
||||
rosterStore.setAccountId(connection.getAccountId());
|
||||
rosterStore.subscribe();
|
||||
connection.getRoster().setRosterStore(rosterStore);
|
||||
|
||||
// Register message store
|
||||
messageStore.registerForMercuryConnection(connection);
|
||||
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -229,21 +223,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);
|
||||
}));
|
||||
|
||||
MercuryConnection connection = connectionMap.get(chat.getPeer().getAccount().getId());
|
||||
if (connection == null) return;
|
||||
MamManager mamManager = MamManager.getInstanceFor(connection.getConnection());
|
||||
MamManager.MamQuery query;
|
||||
//if (chat.getEarliestMamMessageId() == null) {
|
||||
try {
|
||||
query = mamManager.queryMostRecentPage(chat.getPeer().getJid(), 100);
|
||||
messageStore.handleMamResult(chat.getPeer().getAccount().getId(), chat.getPeer().getJid(), query);
|
||||
} catch (SmackException.NoResponseException | XMPPException.XMPPErrorException | SmackException.NotConnectedException | SmackException.NotLoggedInException | InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
//} else {
|
||||
//MamManager.MamQueryArgs queryArgs = MamManager.MamQueryArgs.builder()
|
||||
// .beforeUid()
|
||||
// .build();
|
||||
//query = mamManager.queryArchive()
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,12 +2,13 @@ package org.mercury_im.messenger.core.di;
|
|||
|
||||
import org.mercury_im.messenger.core.NotificationManager;
|
||||
import org.mercury_im.messenger.core.centers.ConnectionCenter;
|
||||
import org.mercury_im.messenger.core.stores.EntityCapsStore;
|
||||
import org.mercury_im.messenger.core.stores.PlainMessageStore;
|
||||
import org.mercury_im.messenger.persistence.repository.AccountRepository;
|
||||
import org.mercury_im.messenger.persistence.repository.ChatRepository;
|
||||
import org.mercury_im.messenger.persistence.repository.EntityCapsRepository;
|
||||
import org.mercury_im.messenger.persistence.repository.MessageRepository;
|
||||
import org.mercury_im.messenger.persistence.repository.RosterRepository;
|
||||
import org.mercury_im.messenger.persistence.repository.EntityCapsRepository;
|
||||
import org.mercury_im.messenger.core.stores.EntityCapsStore;
|
||||
import org.mercury_im.messenger.core.stores.PlainMessageStore;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
|
@ -19,20 +20,26 @@ public class CenterModule {
|
|||
|
||||
@Singleton
|
||||
@Provides
|
||||
static ConnectionCenter provideConnectionCenter(EntityCapsStore capsStore, PlainMessageStore messageStore, AccountRepository accountRepository, RosterRepository rosterRepository) {
|
||||
static ConnectionCenter provideConnectionCenter(EntityCapsStore capsStore,
|
||||
PlainMessageStore messageStore,
|
||||
AccountRepository accountRepository,
|
||||
RosterRepository rosterRepository) {
|
||||
return new ConnectionCenter(capsStore, messageStore, accountRepository, rosterRepository);
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
static EntityCapsStore providerEntityCapsStore(EntityCapsRepository capsRepository) {
|
||||
return new EntityCapsStore(capsRepository);
|
||||
static EntityCapsStore providerEntityCapsStore(EntityCapsRepository entityCapsRepository) {
|
||||
return new EntityCapsStore(entityCapsRepository);
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
static PlainMessageStore provideMessageStore(MessageRepository messageRepository, NotificationManager notificationManager) {
|
||||
return new PlainMessageStore(messageRepository, notificationManager);
|
||||
static PlainMessageStore provideMessageStore(RosterRepository rosterRepository,
|
||||
ChatRepository chatRepository,
|
||||
MessageRepository messageRepository,
|
||||
NotificationManager notificationManager) {
|
||||
return new PlainMessageStore(rosterRepository, chatRepository, messageRepository, notificationManager);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,11 +1,16 @@
|
|||
package org.mercury_im.messenger.core.di;
|
||||
|
||||
import org.mercury_im.messenger.persistence.di.RequeryModule;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import dagger.Component;
|
||||
|
||||
@Singleton
|
||||
@Component(modules = CenterModule.class)
|
||||
@Component(modules = {
|
||||
CenterModule.class,
|
||||
RequeryModule.class
|
||||
})
|
||||
public interface XmppComponent {
|
||||
|
||||
}
|
||||
|
|
|
@ -4,24 +4,21 @@ import org.jivesoftware.smack.util.PacketParserUtils;
|
|||
import org.jivesoftware.smack.xml.XmlPullParser;
|
||||
import org.jivesoftware.smackx.caps.cache.EntityCapsPersistentCache;
|
||||
import org.jivesoftware.smackx.disco.packet.DiscoverInfo;
|
||||
import org.mercury_im.messenger.persistence.model.EntityCapsModel;
|
||||
import org.mercury_im.messenger.persistence.entity.EntityCapsModel;
|
||||
import org.mercury_im.messenger.persistence.repository.EntityCapsRepository;
|
||||
|
||||
|
||||
import java.io.StringReader;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.Single;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import io.reactivex.functions.Consumer;
|
||||
import io.reactivex.observers.DisposableSingleObserver;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
||||
public class EntityCapsStore implements EntityCapsPersistentCache {
|
||||
|
||||
|
@ -31,56 +28,75 @@ public class EntityCapsStore implements EntityCapsPersistentCache {
|
|||
private final Map<String, DiscoverInfo> discoverInfoMap = new HashMap<>();
|
||||
|
||||
private final CompositeDisposable disposable = new CompositeDisposable();
|
||||
private Observable<List<EntityCapsModel>> allEntityCaps;
|
||||
|
||||
@Inject
|
||||
public EntityCapsStore(EntityCapsRepository repository) {
|
||||
this.entityCapsRepository = repository;
|
||||
public EntityCapsStore(EntityCapsRepository entityCapsRepository) {
|
||||
this.entityCapsRepository = entityCapsRepository;
|
||||
populateFromDatabase();
|
||||
}
|
||||
|
||||
/*
|
||||
* Since nodeVers are - if ever - only deleted all at once but added one by one and never
|
||||
* modified, we can simply determine the set of newly added nodeVers, process those and add
|
||||
* them to the database.
|
||||
*/
|
||||
private void populateFromDatabase() {
|
||||
allEntityCaps = entityCapsRepository.getAllEntityCaps();
|
||||
disposable.add(allEntityCaps.subscribeOn(Schedulers.io())
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribe(entityCapsModels -> {
|
||||
discoverInfoMap.clear();
|
||||
for (EntityCapsModel c : entityCapsModels) {
|
||||
DiscoverInfo info;
|
||||
try {
|
||||
XmlPullParser parser = PacketParserUtils.getParserFor(new StringReader(c.getXml()));
|
||||
info = (DiscoverInfo) PacketParserUtils.parseIQ(parser);
|
||||
discoverInfoMap.put(c.getNodeVer(), info);
|
||||
} catch (Exception e) {
|
||||
LOGGER.log(Level.SEVERE, "Error parsing EntityCaps: ", e);
|
||||
}
|
||||
}
|
||||
}, throwable -> LOGGER.log(Level.SEVERE, "Error accessing database", throwable)));
|
||||
disposable.add(entityCapsRepository.getAll()
|
||||
.subscribe(
|
||||
entityCapsModels -> {
|
||||
Map<String, EntityCapsModel> nextEntityCaps = entityCapsModels.toMap(EntityCapsModel.NODE_VER);
|
||||
|
||||
// New set of nodeVers
|
||||
Set<String> nextKeys = nextEntityCaps.keySet();
|
||||
// Old set of nodeVers
|
||||
Set<String> previousKeys = discoverInfoMap.keySet();
|
||||
|
||||
// Added nodeVers
|
||||
nextKeys.removeAll(previousKeys);
|
||||
|
||||
for (String key : nextKeys) {
|
||||
// Only add new items. Items itself cannot change, so we don't have to deal
|
||||
// with changed items.
|
||||
EntityCapsModel addedModel = nextEntityCaps.get(key);
|
||||
DiscoverInfo info;
|
||||
try {
|
||||
XmlPullParser parser = PacketParserUtils.getParserFor(new StringReader(addedModel.getXml()));
|
||||
info = (DiscoverInfo) PacketParserUtils.parseIQ(parser);
|
||||
discoverInfoMap.put(addedModel.getNodeVer(), info);
|
||||
} catch (Exception e) {
|
||||
LOGGER.log(Level.SEVERE, "Error parsing EntityCaps: ", e);
|
||||
}
|
||||
}
|
||||
},
|
||||
error -> LOGGER.log(Level.WARNING, "An error occurred while updating the EntityCaps cache.", error)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addDiscoverInfoByNodePersistent(String nodeVer, DiscoverInfo info) {
|
||||
EntityCapsModel model = entityCapsRepository.newEntityCapsModel(nodeVer);
|
||||
EntityCapsModel model = new EntityCapsModel();
|
||||
model.setNodeVer(nodeVer);
|
||||
CharSequence xml = info.toXML();
|
||||
String string = xml.toString();
|
||||
model.setXml(string);
|
||||
disposable.add(entityCapsRepository.insertOrReplaceEntityCaps(model)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe());
|
||||
disposable.add(entityCapsRepository.upsert(model).subscribe(
|
||||
success -> LOGGER.log(Level.FINE, "Upserted EntityCaps model " + success),
|
||||
error -> LOGGER.log(Level.WARNING, "An error occurred upserting EntityCaps model", error)
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
public DiscoverInfo lookup(String nodeVer) {
|
||||
LOGGER.log(Level.INFO, "Looking up caps for " + nodeVer + " in cache...");
|
||||
LOGGER.log(Level.FINE, "Looking up caps for " + nodeVer + " in cache...");
|
||||
DiscoverInfo info = discoverInfoMap.get(nodeVer);
|
||||
LOGGER.log(Level.INFO, "Entry found: " + (info != null ? info.toXML().toString() : "null"));
|
||||
LOGGER.log(Level.FINE, "Entry found: " + (info != null ? info.toXML().toString() : "null"));
|
||||
return info;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void emptyCache() {
|
||||
entityCapsRepository.deleteAllEntityCaps()
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe();
|
||||
disposable.add(entityCapsRepository.deleteAll().subscribe(
|
||||
success -> LOGGER.log(Level.FINE, "EntityCaps table cleared successfully."),
|
||||
error -> LOGGER.log(Level.WARNING, "An error occurred while clearing EntityCaps table.", error)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,13 +5,24 @@ import org.jivesoftware.smack.chat2.ChatManager;
|
|||
import org.jivesoftware.smack.packet.Message;
|
||||
import org.jivesoftware.smackx.carbons.CarbonManager;
|
||||
import org.jivesoftware.smackx.carbons.packet.CarbonExtension;
|
||||
import org.jivesoftware.smackx.delay.DelayInformationManager;
|
||||
import org.jivesoftware.smackx.delay.packet.DelayInformation;
|
||||
import org.jivesoftware.smackx.mam.MamManager;
|
||||
import org.jivesoftware.smackx.sid.element.OriginIdElement;
|
||||
import org.jivesoftware.smackx.sid.element.StanzaIdElement;
|
||||
import org.jxmpp.jid.EntityBareJid;
|
||||
import org.jxmpp.jid.impl.JidCreate;
|
||||
import org.mercury_im.messenger.core.NotificationManager;
|
||||
import org.mercury_im.messenger.core.connection.MercuryConnection;
|
||||
import org.mercury_im.messenger.persistence.model.MessageModel;
|
||||
import org.mercury_im.messenger.persistence.entity.ChatModel;
|
||||
import org.mercury_im.messenger.persistence.entity.ContactModel;
|
||||
import org.mercury_im.messenger.persistence.entity.EntityModel;
|
||||
import org.mercury_im.messenger.persistence.entity.LastChatMessageRelation;
|
||||
import org.mercury_im.messenger.persistence.entity.MessageModel;
|
||||
import org.mercury_im.messenger.persistence.repository.ChatRepository;
|
||||
import org.mercury_im.messenger.persistence.repository.MessageRepository;
|
||||
import org.mercury_im.messenger.persistence.repository.RosterRepository;
|
||||
import org.mercury_im.messenger.persistence.util.ChatAndPossiblyContact;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
|
@ -19,8 +30,8 @@ import java.util.List;
|
|||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import io.reactivex.Completable;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import io.reactivex.functions.Consumer;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
||||
public class PlainMessageStore {
|
||||
|
@ -28,75 +39,95 @@ public class PlainMessageStore {
|
|||
private static final Logger LOGGER = Logger.getLogger(PlainMessageStore.class.getName());
|
||||
private static final CompositeDisposable disposable = new CompositeDisposable();
|
||||
|
||||
private final RosterRepository rosterRepository;
|
||||
private final ChatRepository chatRepository;
|
||||
private final MessageRepository messageRepository;
|
||||
|
||||
private final NotificationManager notificationManager;
|
||||
|
||||
public PlainMessageStore(MessageRepository messageRepository, NotificationManager notificationManager) {
|
||||
public PlainMessageStore(RosterRepository rosterRepository, ChatRepository chatRepository, MessageRepository messageRepository, NotificationManager notificationManager) {
|
||||
this.rosterRepository = rosterRepository;
|
||||
this.chatRepository = chatRepository;
|
||||
this.messageRepository = messageRepository;
|
||||
this.notificationManager = notificationManager;
|
||||
}
|
||||
|
||||
public void newIncomingMessage(long accountId, EntityBareJid from, Message message, Chat chat) {
|
||||
public void handleIncomingMessage(long accountId, EntityBareJid from, Message message, Chat chat) {
|
||||
if (message.getBody() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
org.mercury_im.messenger.persistence.pojo.Chat chatPojo = new org.mercury_im.messenger.persistence.pojo.Chat();
|
||||
chatPojo.jid = from;
|
||||
chatPojo.accountId = accountId;
|
||||
chatPojo.contactName = null;
|
||||
notificationManager.chatMessageReceived(chatPojo, null, message.getBody());
|
||||
Completable.fromAction(() -> {
|
||||
EntityModel entityModel = rosterRepository.getOrCreateEntity(accountId, from)
|
||||
.blockingGet();
|
||||
ContactModel contactModel = rosterRepository.getContact(accountId, entityModel.getJid()).blockingFirst().firstOrNull();
|
||||
ChatModel chatModel = chatRepository.getChatWith(entityModel).blockingFirst().firstOr(() -> {
|
||||
ChatModel freshChatModel = new ChatModel();
|
||||
freshChatModel.setPeer(entityModel);
|
||||
freshChatModel.setDisplayed(true);
|
||||
return freshChatModel;
|
||||
});
|
||||
|
||||
MessageModel messageModel = messageRepository.newMessageModel();
|
||||
messageModel.setAccountId(accountId);
|
||||
messageModel.setFrom(chat.getXmppAddressOfChatPartner());
|
||||
messageModel.setTo(message.getTo().asEntityBareJidIfPossible());
|
||||
messageModel.setIncoming(true);
|
||||
messageModel.setBody(message.getBody());
|
||||
messageModel.setSendDate(new Date());
|
||||
chatModel = chatRepository.upsert(chatModel).blockingGet();
|
||||
|
||||
disposable.add(
|
||||
messageRepository.insertMessage(messageModel)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe(messageId ->
|
||||
LOGGER.log(Level.INFO, "Inserted incoming message " + messageId)));
|
||||
MessageModel messageModel = setCommonMessageAttributes(message, chatModel);
|
||||
messageModel.setSender(from);
|
||||
messageModel.setIncoming(true);
|
||||
|
||||
final ChatModel fChatModel = chatModel;
|
||||
disposable.add(messageRepository.insert(messageModel)
|
||||
.subscribe(insertedMessageModel -> {
|
||||
if (message.getBody() != null) {
|
||||
notificationManager.chatMessageReceived(new ChatAndPossiblyContact(fChatModel, contactModel), message.getBody());
|
||||
}
|
||||
|
||||
LastChatMessageRelation lastMessage = new LastChatMessageRelation();
|
||||
lastMessage.setChat(fChatModel);
|
||||
lastMessage.setMessage(insertedMessageModel);
|
||||
}));
|
||||
}).subscribeOn(Schedulers.io())
|
||||
.subscribe();
|
||||
}
|
||||
|
||||
public void newOutgoingMessage(long accountId, EntityBareJid to, Message message, Chat chat) {
|
||||
MessageModel messageModel = messageRepository.newMessageModel();
|
||||
messageModel.setAccountId(accountId);
|
||||
messageModel.setFrom(message.getFrom() != null ? message.getFrom().asEntityBareJidIfPossible() : null);
|
||||
messageModel.setTo(chat.getXmppAddressOfChatPartner());
|
||||
messageModel.setIncoming(false);
|
||||
messageModel.setBody(message.getBody());
|
||||
messageModel.setSendDate(new Date());
|
||||
public void handleOutgoingMessage(long accountId, EntityBareJid to, Message message, Chat chat) {
|
||||
MessageModel model = setCommonMessageAttributes(message, null);
|
||||
EntityModel entityModel = rosterRepository.getOrCreateEntity(accountId, to).blockingGet();
|
||||
|
||||
disposable.add(
|
||||
messageRepository.insertMessage(messageModel)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe(messageId ->
|
||||
LOGGER.log(Level.INFO, "Inserted outgoing message " + messageId)));
|
||||
model.setIncoming(false);
|
||||
model.setTimestamp(new Date());
|
||||
model.setSender(entityModel.getAccount().getJid());
|
||||
model.setRecipient(to);
|
||||
|
||||
ChatModel chatModel = chatRepository.getChatWith(entityModel).blockingFirst().firstOr(() -> {
|
||||
ChatModel freshChatModel = new ChatModel();
|
||||
freshChatModel.setPeer(entityModel);
|
||||
freshChatModel.setDisplayed(true);
|
||||
return freshChatModel;
|
||||
});
|
||||
|
||||
model.setChat(chatModel);
|
||||
|
||||
disposable.add(messageRepository.upsert(model)
|
||||
.subscribe(messageId ->
|
||||
LOGGER.log(Level.INFO, "Inserted outgoing message " + messageId)));
|
||||
}
|
||||
|
||||
public void onCarbonCopyReceived(long accountId, CarbonExtension.Direction direction, Message carbonCopy, Message wrappingMessage) {
|
||||
public void handleCarbonCopy(long accountId, CarbonExtension.Direction direction, Message carbonCopy, Message wrappingMessage) {
|
||||
if (carbonCopy.getBody() == null) {
|
||||
return;
|
||||
}
|
||||
MessageModel messageModel = messageRepository.newMessageModel();
|
||||
messageModel.setAccountId(accountId);
|
||||
messageModel.setFrom(carbonCopy.getFrom() != null ? carbonCopy.getFrom().asEntityBareJidIfPossible() : null);
|
||||
messageModel.setTo(carbonCopy.getTo() != null ? carbonCopy.getTo().asEntityBareJidIfPossible() : null);
|
||||
MessageModel messageModel = new MessageModel();
|
||||
messageModel.setSender(carbonCopy.getFrom() != null ? carbonCopy.getFrom().asEntityBareJidIfPossible() : null);
|
||||
messageModel.setRecipient(carbonCopy.getTo() != null ? carbonCopy.getTo().asEntityBareJidIfPossible() : null);
|
||||
|
||||
messageModel.setIncoming(direction == CarbonExtension.Direction.received);
|
||||
|
||||
messageModel.setBody(carbonCopy.getBody());
|
||||
messageModel.setSendDate(new Date());
|
||||
disposable.add(
|
||||
messageRepository.insertMessage(messageModel)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe(messageId ->
|
||||
LOGGER.log(Level.INFO, "Inserted carbon message " + messageId)));
|
||||
messageModel.setTimestamp(new Date());
|
||||
|
||||
disposable.add(messageRepository.upsert(messageModel)
|
||||
.subscribe(messageId ->
|
||||
LOGGER.log(Level.INFO, "Inserted carbon message " + messageId)));
|
||||
}
|
||||
|
||||
public void registerForMercuryConnection(MercuryConnection connection) {
|
||||
|
@ -105,13 +136,15 @@ public class PlainMessageStore {
|
|||
|
||||
// Add account ID to
|
||||
chatManager.addIncomingListener((from, message, chat) ->
|
||||
PlainMessageStore.this.newIncomingMessage(
|
||||
PlainMessageStore.this.handleIncomingMessage(
|
||||
connection.getAccountId(), from, message, chat));
|
||||
|
||||
chatManager.addOutgoingListener((to, message, chat) ->
|
||||
PlainMessageStore.this.newOutgoingMessage(
|
||||
PlainMessageStore.this.handleOutgoingMessage(
|
||||
connection.getAccountId(), to, message, chat));
|
||||
|
||||
carbonManager.addCarbonCopyReceivedListener((direction, carbonCopy, wrappingMessage) ->
|
||||
PlainMessageStore.this.onCarbonCopyReceived(
|
||||
PlainMessageStore.this.handleCarbonCopy(
|
||||
connection.getAccountId(), direction, carbonCopy, wrappingMessage));
|
||||
}
|
||||
|
||||
|
@ -119,7 +152,7 @@ public class PlainMessageStore {
|
|||
disposable.clear();
|
||||
}
|
||||
|
||||
public void onMamResult(long accountId, EntityBareJid peerJid, MamManager.MamQuery query) {
|
||||
public void handleMamResult(long accountId, EntityBareJid peerJid, MamManager.MamQuery query) {
|
||||
List<MessageModel> messageModels = new ArrayList<>();
|
||||
for (Message message : query.getMessages()) {
|
||||
Date date = new Date();
|
||||
|
@ -128,19 +161,42 @@ public class PlainMessageStore {
|
|||
date = delay.getStamp();
|
||||
}
|
||||
|
||||
MessageModel messageModel = messageRepository.newMessageModel();
|
||||
messageModel.setAccountId(accountId);
|
||||
MessageModel messageModel = new MessageModel();
|
||||
messageModel.setBody(message.getBody());
|
||||
messageModel.setFrom(message.getFrom().asEntityBareJidOrThrow());
|
||||
messageModel.setTo(message.getTo().asEntityBareJidOrThrow());
|
||||
messageModel.setSender(message.getFrom().asEntityBareJidOrThrow());
|
||||
messageModel.setRecipient(message.getTo().asEntityBareJidOrThrow());
|
||||
messageModel.setIncoming(peerJid.equals(message.getFrom().asEntityBareJidOrThrow()));
|
||||
messageModel.setSendDate(date);
|
||||
messageModel.setTimestamp(date);
|
||||
messageModels.add(messageModel);
|
||||
}
|
||||
|
||||
disposable.add(
|
||||
messageRepository.insertMessages(messageModels)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe());
|
||||
disposable.add(messageRepository.upsert(messageModels).subscribe());
|
||||
}
|
||||
|
||||
private MessageModel incomingMessageToModel(Message message, ChatModel chat) {
|
||||
MessageModel model = setCommonMessageAttributes(message, chat);
|
||||
model.setIncoming(true);
|
||||
return model;
|
||||
}
|
||||
|
||||
private MessageModel setCommonMessageAttributes(Message message, ChatModel chat) {
|
||||
MessageModel model = new MessageModel();
|
||||
|
||||
model.setBody(message.getBody());
|
||||
Date timestamp = DelayInformationManager.getDelayTimestamp(message);
|
||||
model.setTimestamp(timestamp == null ? new Date() : timestamp);
|
||||
model.setThread(message.getThread());
|
||||
model.setLegacyId(message.getStanzaId());
|
||||
model.setChat(chat);
|
||||
model.setRecipient(message.getTo().asEntityBareJidOrThrow());
|
||||
model.setSender(message.getFrom() != null ? message.getFrom().asEntityBareJidIfPossible() : null);
|
||||
OriginIdElement originId = OriginIdElement.getOriginId(message);
|
||||
model.setOriginId(originId != null ? originId.getId() : null);
|
||||
StanzaIdElement stanzaId = StanzaIdElement.getStanzaId(message);
|
||||
model.setStanzaId(stanzaId != null ? stanzaId.getId() : null);
|
||||
model.setStanzaIdBy(stanzaId != null ? JidCreate.entityBareFromOrThrowUnchecked(stanzaId.getBy()) : null);
|
||||
|
||||
|
||||
return model;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,10 +2,12 @@ package org.mercury_im.messenger.core.stores;
|
|||
|
||||
import org.jivesoftware.smack.roster.packet.RosterPacket;
|
||||
import org.jxmpp.jid.Jid;
|
||||
import org.mercury_im.messenger.persistence.model.ContactModel;
|
||||
import org.mercury_im.messenger.persistence.model.EntityModel;
|
||||
import org.mercury_im.messenger.persistence.model.RosterInformationModel;
|
||||
import org.mercury_im.messenger.persistence.entity.AccountModel;
|
||||
import org.mercury_im.messenger.persistence.entity.ContactModel;
|
||||
import org.mercury_im.messenger.persistence.entity.EntityModel;
|
||||
import org.mercury_im.messenger.persistence.repository.AccountRepository;
|
||||
import org.mercury_im.messenger.persistence.repository.RosterRepository;
|
||||
import org.mercury_im.messenger.persistence.enums.SubscriptionDirection;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
@ -18,8 +20,9 @@ import java.util.logging.Logger;
|
|||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import io.reactivex.Scheduler;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import io.reactivex.functions.Consumer;
|
||||
import io.reactivex.functions.Action;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
||||
public class RosterStore implements org.jivesoftware.smack.roster.rosterstore.RosterStore {
|
||||
|
@ -27,16 +30,17 @@ public class RosterStore implements org.jivesoftware.smack.roster.rosterstore.Ro
|
|||
private static final Logger LOGGER = Logger.getLogger(RosterStore.class.getName());
|
||||
|
||||
private final RosterRepository rosterRepository;
|
||||
private long accountId;
|
||||
|
||||
private final AccountRepository accountRepository;
|
||||
private AccountModel account;
|
||||
private CompositeDisposable disposable = null;
|
||||
|
||||
private final Map<Jid, RosterPacket.Item> itemMap = new HashMap<>();
|
||||
private String rosterVersion;
|
||||
|
||||
@Inject
|
||||
public RosterStore(RosterRepository rosterRepository) {
|
||||
public RosterStore(RosterRepository rosterRepository, AccountRepository accountRepository) {
|
||||
this.rosterRepository = rosterRepository;
|
||||
this.accountRepository = accountRepository;
|
||||
}
|
||||
|
||||
public void subscribe() {
|
||||
|
@ -46,30 +50,23 @@ public class RosterStore implements org.jivesoftware.smack.roster.rosterstore.Ro
|
|||
}
|
||||
disposable = new CompositeDisposable();
|
||||
|
||||
disposable.add(rosterRepository.getAllContactsOfAccount(accountId)
|
||||
.subscribeOn(Schedulers.io())
|
||||
disposable.add(rosterRepository.getAllContactsOfAccount(account)
|
||||
.observeOn(Schedulers.computation())
|
||||
.subscribe((Consumer<List<? extends ContactModel>>) contactsList -> {
|
||||
itemMap.clear();
|
||||
for (ContactModel contactModel : contactsList) {
|
||||
rosterRepository.getEntityForContact(contactModel.getId())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe((Consumer<EntityModel>) entityModel -> {
|
||||
RosterPacket.Item item = fromModel(contactModel);
|
||||
itemMap.put(entityModel.getJid(), item);
|
||||
});
|
||||
LOGGER.log(Level.INFO, "Populate itemMap with " + contactsList.size() + " items");
|
||||
.subscribe(contactsList -> {
|
||||
itemMap.clear();
|
||||
for (ContactModel contactModel : contactsList) {
|
||||
itemMap.put(contactModel.getEntity().getJid(), fromModel(contactModel));
|
||||
LOGGER.log(Level.INFO, "Populate itemMap with " + contactsList.toList().size() + " items");
|
||||
|
||||
}
|
||||
}));
|
||||
}
|
||||
},
|
||||
error -> LOGGER.log(Level.WARNING, "An error occurred while updating roster cache", error)));
|
||||
|
||||
disposable.add(rosterRepository.getRosterInformationForAccount(accountId)
|
||||
.subscribeOn(Schedulers.io())
|
||||
disposable.add(rosterRepository.getRosterVersion(account)
|
||||
.observeOn(Schedulers.computation())
|
||||
.subscribe((Consumer<RosterInformationModel>) s -> {
|
||||
LOGGER.log(Level.INFO, "Set rosterVer = " + s.getRosterVersion());
|
||||
rosterVersion = s.getRosterVersion();
|
||||
}));
|
||||
.subscribe(
|
||||
result -> setRosterVersion(result),
|
||||
error -> LOGGER.log(Level.WARNING, "An error occurred updating cached roster version", error)));
|
||||
}
|
||||
|
||||
public void unsubscribe() {
|
||||
|
@ -81,7 +78,13 @@ public class RosterStore implements org.jivesoftware.smack.roster.rosterstore.Ro
|
|||
}
|
||||
|
||||
public void setAccountId(long accountId) {
|
||||
this.accountId = accountId;
|
||||
this.account = accountRepository.getAccount(accountId)
|
||||
.doOnSubscribe(subscribe -> LOGGER.log(Level.FINE, "Fetching account " + accountId))
|
||||
.blockingFirst().first();
|
||||
}
|
||||
|
||||
private void setRosterVersion(String rosterVersion) {
|
||||
this.rosterVersion = rosterVersion;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -104,14 +107,16 @@ public class RosterStore implements org.jivesoftware.smack.roster.rosterstore.Ro
|
|||
LOGGER.log(Level.INFO, "Add entry " + item.toXML().toString());
|
||||
// Update database
|
||||
ContactModel contact = toModel(item);
|
||||
rosterRepository.upsertContact(contact)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(Schedulers.computation())
|
||||
.subscribe();
|
||||
rosterRepository.updateRosterVersionForAccount(accountId, version)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(Schedulers.computation())
|
||||
.subscribe();
|
||||
disposable.add(rosterRepository.upsertContact(contact)
|
||||
.subscribe(
|
||||
success -> LOGGER.log(Level.FINE, "Upserted contact model " + success + " successfully"),
|
||||
error -> LOGGER.log(Level.WARNING, "An error occurred upserting contact " + contact, error)
|
||||
));
|
||||
disposable.add(rosterRepository.updateRosterVersion(account, version)
|
||||
.subscribe(
|
||||
success -> LOGGER.log(Level.FINE, "Upserted roster version to " + rosterVersion + " successfully"),
|
||||
error -> LOGGER.log(Level.WARNING, "An error occurred upserting roster version", error)
|
||||
));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -120,15 +125,21 @@ public class RosterStore implements org.jivesoftware.smack.roster.rosterstore.Ro
|
|||
public boolean resetEntries(Collection<RosterPacket.Item> items, String version) {
|
||||
LOGGER.log(Level.INFO, "Reset Entries: " + Arrays.toString(items.toArray()));
|
||||
// Update database
|
||||
// TODO: Delete other contacts
|
||||
for (RosterPacket.Item item : items) {
|
||||
ContactModel model = toModel(item);
|
||||
rosterRepository.upsertContact(model)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe();
|
||||
disposable.add(rosterRepository.upsertContact(model)
|
||||
.subscribe(
|
||||
success -> LOGGER.log(Level.FINE, "Upserted contact model " + success + " successfully"),
|
||||
error -> LOGGER.log(Level.WARNING, "An error occurred upserting contact " + model, error)
|
||||
));
|
||||
}
|
||||
rosterRepository.updateRosterVersionForAccount(accountId, version)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe();
|
||||
|
||||
disposable.add(rosterRepository.updateRosterVersion(account, version)
|
||||
.subscribe(
|
||||
success -> LOGGER.log(Level.FINE, "Upserted roster version to " + rosterVersion + " successfully"),
|
||||
error -> LOGGER.log(Level.WARNING, "An error occurred upserting roster version", error)
|
||||
));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -136,54 +147,60 @@ public class RosterStore implements org.jivesoftware.smack.roster.rosterstore.Ro
|
|||
@Override
|
||||
public boolean removeEntry(Jid bareJid, String version) {
|
||||
LOGGER.log(Level.INFO, "Remove entry " + bareJid.toString());
|
||||
rosterRepository.deleteContact(accountId, bareJid.asEntityBareJidOrThrow())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(Schedulers.computation())
|
||||
.subscribe();
|
||||
rosterRepository.updateRosterVersionForAccount(accountId, version)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(Schedulers.computation())
|
||||
.subscribe();
|
||||
|
||||
disposable.add(rosterRepository.deleteContact(account.getId(), bareJid.asEntityBareJidOrThrow())
|
||||
.subscribe(
|
||||
() -> LOGGER.log(Level.FINE, "Deletion of contact " + bareJid.toString() + " successful"),
|
||||
error -> LOGGER.log(Level.WARNING, "An error occurred deleting contact " + bareJid.toString(), error)
|
||||
));
|
||||
disposable.add(rosterRepository.updateRosterVersion(account, version)
|
||||
.subscribe(
|
||||
success -> LOGGER.log(Level.FINE, "Upserted roster version to " + rosterVersion + " successfully"),
|
||||
error -> LOGGER.log(Level.WARNING, "An error occurred upserting roster version", error)
|
||||
));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetStore() {
|
||||
LOGGER.log(Level.INFO, "Reset Store");
|
||||
rosterRepository.deleteAllContactsOfAccount(accountId)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(Schedulers.computation())
|
||||
.subscribe();
|
||||
rosterRepository.updateRosterVersionForAccount(accountId, "")
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(Schedulers.computation())
|
||||
.subscribe();
|
||||
|
||||
disposable.add(rosterRepository.deleteAllContactsOfAccount(account)
|
||||
.subscribe(
|
||||
success -> LOGGER.log(Level.FINE, "Successfully reset store."),
|
||||
error -> LOGGER.log(Level.WARNING, "An error occurred resetting store", error)
|
||||
));
|
||||
disposable.add(rosterRepository.updateRosterVersion(account, "")
|
||||
.subscribe(
|
||||
success -> LOGGER.log(Level.FINE, "Successfully reset roster version"),
|
||||
error -> LOGGER.log(Level.WARNING, "An error occurred resetting roster version", error)
|
||||
));
|
||||
}
|
||||
|
||||
public RosterPacket.Item fromModel(ContactModel contactModel) {
|
||||
RosterPacket.Item item = new RosterPacket.Item(
|
||||
contactModel.getEntity().getJid(),
|
||||
contactModel.getRosterName());
|
||||
if (contactModel.getDirection() != null) {
|
||||
item.setItemType(convert(contactModel.getDirection()));
|
||||
contactModel.getRostername());
|
||||
if (contactModel.getSub_direction() != null) {
|
||||
item.setItemType(convert(contactModel.getSub_direction()));
|
||||
}
|
||||
item.setApproved(contactModel.isApproved());
|
||||
item.setSubscriptionPending(contactModel.isSubscriptionPending());
|
||||
item.setApproved(contactModel.isSub_approved());
|
||||
item.setSubscriptionPending(contactModel.isSub_pending());
|
||||
return item;
|
||||
}
|
||||
|
||||
public ContactModel toModel(RosterPacket.Item item) {
|
||||
ContactModel contact = rosterRepository.newContactModel();
|
||||
ContactModel contact = new ContactModel();
|
||||
|
||||
contact.setRosterName(item.getName());
|
||||
contact.setRostername(item.getName());
|
||||
if (item.getItemType() != null) {
|
||||
contact.setDirection(convert(item.getItemType()));
|
||||
contact.setSub_direction(convert(item.getItemType()));
|
||||
}
|
||||
contact.setApproved(item.isApproved());
|
||||
contact.setSubscriptionPending(item.isSubscriptionPending());
|
||||
contact.setSub_approved(item.isApproved());
|
||||
contact.setSub_pending(item.isSubscriptionPending());
|
||||
|
||||
EntityModel entity = rosterRepository.newEntityModel();
|
||||
entity.setAccountId(accountId);
|
||||
EntityModel entity = new EntityModel();
|
||||
entity.setAccount(account);
|
||||
entity.setJid(item.getJid().asEntityBareJidOrThrow());
|
||||
|
||||
contact.setEntity(entity);
|
||||
|
@ -191,11 +208,12 @@ public class RosterStore implements org.jivesoftware.smack.roster.rosterstore.Ro
|
|||
return contact;
|
||||
}
|
||||
|
||||
public ContactModel.DIRECTION convert(RosterPacket.ItemType type) {
|
||||
return ContactModel.DIRECTION.valueOf(type.toString());
|
||||
public SubscriptionDirection convert(RosterPacket.ItemType type) {
|
||||
return SubscriptionDirection.valueOf(type.toString());
|
||||
|
||||
}
|
||||
|
||||
public RosterPacket.ItemType convert(ContactModel.DIRECTION direction) {
|
||||
public RosterPacket.ItemType convert(SubscriptionDirection direction) {
|
||||
return RosterPacket.ItemType.fromString(direction.toString());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,16 +1,28 @@
|
|||
package org.mercury_im.messenger.core.util;
|
||||
|
||||
import org.mercury_im.messenger.persistence.model.ContactModel;
|
||||
import org.mercury_im.messenger.persistence.entity.ContactModel;
|
||||
import org.mercury_im.messenger.persistence.entity.EntityModel;
|
||||
|
||||
public class ContactNameUtil {
|
||||
|
||||
public static String displayableNameFrom(ContactModel contactModel) {
|
||||
if (contactModel.getRosterName() != null) {
|
||||
return contactModel.getRosterName();
|
||||
if (contactModel == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (contactModel.getRostername() != null) {
|
||||
return contactModel.getRostername();
|
||||
}
|
||||
if (contactModel.getEntity() != null) {
|
||||
return contactModel.getEntity().getJid().getLocalpart().asUnescapedString();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String displayableNameFrom(ContactModel contact, EntityModel entity) {
|
||||
if (contact == null) {
|
||||
return entity.getJid().getLocalpart().asUnescapedString();
|
||||
} return displayableNameFrom(contact);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
/build
|
||||
*.iml
|
||||
/schemas
|
|
@ -1,31 +0,0 @@
|
|||
# Room Persistence Layer of Mercury
|
||||
|
||||
This Android Module contains an implementation of the interfaces of the `persistence` module.
|
||||
In particular it defines SQL schemes and provides DAOs as well as implementations of Model classes
|
||||
and Repositories that utilize the [Room Database Framework](https://developer.android.com/topic/libraries/architecture/room).
|
||||
|
||||
## Packages and Classes
|
||||
|
||||
### `AppDatabase`
|
||||
defines what makes up the database itself. It lists all available entities and provides dao classes.
|
||||
|
||||
### `dao` package
|
||||
Contains data access objects (DAOs) which provide CRUD methods (Create, Read, Update, Delete) for
|
||||
all the models.
|
||||
|
||||
Note, that the `BaseDao` interface already defines methods for creating, updating and deleting
|
||||
entities and is extended by most DAO classes.
|
||||
|
||||
### `model` package
|
||||
Contains classes that represent the data itself in form of models.
|
||||
|
||||
### `repository` package
|
||||
Contains implementations of data repositories. Repositories are single sources of truth and provide
|
||||
a user-friendly separation layer between the application and the DAOs.
|
||||
|
||||
Ideally this layer would also provide access to the XMPP domain, but this is still subject to
|
||||
discussion.
|
||||
|
||||
### `type_converter` package
|
||||
Contains Room specific type converter that convert non-basic data types into basic data types which
|
||||
can be handled by the database and vice versa.
|
|
@ -1,56 +0,0 @@
|
|||
apply plugin: 'com.android.library'
|
||||
|
||||
android {
|
||||
compileSdkVersion 29
|
||||
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 19
|
||||
targetSdkVersion 28
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
javaCompileOptions {
|
||||
annotationProcessorOptions {
|
||||
arguments = ["room.schemaLocation": "$projectDir/schemas".toString()]
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility 1.8
|
||||
targetCompatibility 1.8
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api project(":persistence")
|
||||
|
||||
// Dagger 2 for dependency injection
|
||||
implementation "com.google.dagger:dagger:$daggerVersion"
|
||||
annotationProcessor "com.google.dagger:dagger-compiler:$daggerVersion"
|
||||
|
||||
// Room
|
||||
api "androidx.room:room-runtime:$roomVersion"
|
||||
annotationProcessor "androidx.room:room-compiler:$roomVersion"
|
||||
implementation "androidx.room:room-rxjava2:$roomRxJavaVersion"
|
||||
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"
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
|
@ -1,518 +0,0 @@
|
|||
{
|
||||
"formatVersion": 1,
|
||||
"database": {
|
||||
"version": 1,
|
||||
"identityHash": "6322b5b46e09460ae6f30134786c9221",
|
||||
"entities": [
|
||||
{
|
||||
"tableName": "accounts",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`pk_account_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `jid` TEXT, `password` TEXT, `enabled` INTEGER NOT NULL, `state` TEXT)",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "pk_account_id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "jid",
|
||||
"columnName": "jid",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "password",
|
||||
"columnName": "password",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "enabled",
|
||||
"columnName": "enabled",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "state",
|
||||
"columnName": "state",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"columnNames": [
|
||||
"pk_account_id"
|
||||
],
|
||||
"autoGenerate": true
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "index_accounts_pk_account_id",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"pk_account_id"
|
||||
],
|
||||
"createSql": "CREATE INDEX `index_accounts_pk_account_id` ON `${TABLE_NAME}` (`pk_account_id`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "entities",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`pk_entity_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `fk_account_id` INTEGER NOT NULL, `jid` TEXT NOT NULL, FOREIGN KEY(`fk_account_id`) REFERENCES `accounts`(`pk_account_id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "pk_entity_id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "accountId",
|
||||
"columnName": "fk_account_id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "jid",
|
||||
"columnName": "jid",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"columnNames": [
|
||||
"pk_entity_id"
|
||||
],
|
||||
"autoGenerate": true
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "index_entities_pk_entity_id",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"pk_entity_id"
|
||||
],
|
||||
"createSql": "CREATE INDEX `index_entities_pk_entity_id` ON `${TABLE_NAME}` (`pk_entity_id`)"
|
||||
},
|
||||
{
|
||||
"name": "index_entities_fk_account_id_jid",
|
||||
"unique": true,
|
||||
"columnNames": [
|
||||
"fk_account_id",
|
||||
"jid"
|
||||
],
|
||||
"createSql": "CREATE UNIQUE INDEX `index_entities_fk_account_id_jid` ON `${TABLE_NAME}` (`fk_account_id`, `jid`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"table": "accounts",
|
||||
"onDelete": "CASCADE",
|
||||
"onUpdate": "NO ACTION",
|
||||
"columns": [
|
||||
"fk_account_id"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"pk_account_id"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tableName": "contacts",
|
||||
"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, `sub_direction` TEXT, `sub_pending` INTEGER NOT NULL, `sub_approved` INTEGER NOT NULL, FOREIGN KEY(`fk_entity_id`) REFERENCES `entities`(`pk_entity_id`) ON UPDATE NO ACTION ON DELETE RESTRICT )",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "pk_contact_id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "entityId",
|
||||
"columnName": "fk_entity_id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "rosterName",
|
||||
"columnName": "rostername",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "direction",
|
||||
"columnName": "sub_direction",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "subscriptionPending",
|
||||
"columnName": "sub_pending",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "approved",
|
||||
"columnName": "sub_approved",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"columnNames": [
|
||||
"pk_contact_id"
|
||||
],
|
||||
"autoGenerate": true
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "index_contacts_pk_contact_id",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"pk_contact_id"
|
||||
],
|
||||
"createSql": "CREATE INDEX `index_contacts_pk_contact_id` ON `${TABLE_NAME}` (`pk_contact_id`)"
|
||||
},
|
||||
{
|
||||
"name": "index_contacts_fk_entity_id",
|
||||
"unique": true,
|
||||
"columnNames": [
|
||||
"fk_entity_id"
|
||||
],
|
||||
"createSql": "CREATE UNIQUE INDEX `index_contacts_fk_entity_id` ON `${TABLE_NAME}` (`fk_entity_id`)"
|
||||
},
|
||||
{
|
||||
"name": "index_contacts_pk_contact_id_fk_entity_id",
|
||||
"unique": true,
|
||||
"columnNames": [
|
||||
"pk_contact_id",
|
||||
"fk_entity_id"
|
||||
],
|
||||
"createSql": "CREATE UNIQUE INDEX `index_contacts_pk_contact_id_fk_entity_id` ON `${TABLE_NAME}` (`pk_contact_id`, `fk_entity_id`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"table": "entities",
|
||||
"onDelete": "RESTRICT",
|
||||
"onUpdate": "NO ACTION",
|
||||
"columns": [
|
||||
"fk_entity_id"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"pk_entity_id"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tableName": "roster_information",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`pk_account_id` INTEGER NOT NULL, `roster_version` TEXT, PRIMARY KEY(`pk_account_id`))",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "accountId",
|
||||
"columnName": "pk_account_id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "rosterVersion",
|
||||
"columnName": "roster_version",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"columnNames": [
|
||||
"pk_account_id"
|
||||
],
|
||||
"autoGenerate": false
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "index_roster_information_pk_account_id",
|
||||
"unique": true,
|
||||
"columnNames": [
|
||||
"pk_account_id"
|
||||
],
|
||||
"createSql": "CREATE UNIQUE INDEX `index_roster_information_pk_account_id` ON `${TABLE_NAME}` (`pk_account_id`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"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, `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": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "pk_chat_id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "peerEntityId",
|
||||
"columnName": "fk_entity_id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "isActive",
|
||||
"columnName": "active",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "lastReadMessageId",
|
||||
"columnName": "last_read_message",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "mostRecentMamMessageId",
|
||||
"columnName": "most_recent_mam_msg",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "earliestMamMessageId",
|
||||
"columnName": "earliest_mam_msg",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"columnNames": [
|
||||
"pk_chat_id"
|
||||
],
|
||||
"autoGenerate": true
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "index_chats_pk_chat_id",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"pk_chat_id"
|
||||
],
|
||||
"createSql": "CREATE INDEX `index_chats_pk_chat_id` ON `${TABLE_NAME}` (`pk_chat_id`)"
|
||||
},
|
||||
{
|
||||
"name": "index_chats_fk_entity_id",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"fk_entity_id"
|
||||
],
|
||||
"createSql": "CREATE INDEX `index_chats_fk_entity_id` ON `${TABLE_NAME}` (`fk_entity_id`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"table": "entities",
|
||||
"onDelete": "CASCADE",
|
||||
"onUpdate": "NO ACTION",
|
||||
"columns": [
|
||||
"fk_entity_id"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"pk_entity_id"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tableName": "messages",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`pk_message_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `fk_account_id` INTEGER NOT NULL, `body` TEXT, `send_date` INTEGER, `from` TEXT, `to` TEXT, `incoming` INTEGER NOT NULL, FOREIGN KEY(`fk_account_id`) REFERENCES `accounts`(`pk_account_id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "pk_message_id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "accountId",
|
||||
"columnName": "fk_account_id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "body",
|
||||
"columnName": "body",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "sendDate",
|
||||
"columnName": "send_date",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "from",
|
||||
"columnName": "from",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "to",
|
||||
"columnName": "to",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "incoming",
|
||||
"columnName": "incoming",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"columnNames": [
|
||||
"pk_message_id"
|
||||
],
|
||||
"autoGenerate": true
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "index_messages_pk_message_id",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"pk_message_id"
|
||||
],
|
||||
"createSql": "CREATE INDEX `index_messages_pk_message_id` ON `${TABLE_NAME}` (`pk_message_id`)"
|
||||
},
|
||||
{
|
||||
"name": "index_messages_fk_account_id",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"fk_account_id"
|
||||
],
|
||||
"createSql": "CREATE INDEX `index_messages_fk_account_id` ON `${TABLE_NAME}` (`fk_account_id`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"table": "accounts",
|
||||
"onDelete": "CASCADE",
|
||||
"onUpdate": "NO ACTION",
|
||||
"columns": [
|
||||
"fk_account_id"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"pk_account_id"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tableName": "avatars",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`pk_avatar_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `fk_entity_id` INTEGER NOT NULL, `sha1sum` TEXT, `bytes` BLOB, FOREIGN KEY(`fk_entity_id`) REFERENCES `entities`(`pk_entity_id`) ON UPDATE NO ACTION ON DELETE RESTRICT )",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "avatarId",
|
||||
"columnName": "pk_avatar_id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "entityId",
|
||||
"columnName": "fk_entity_id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "sha1Sum",
|
||||
"columnName": "sha1sum",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "bytes",
|
||||
"columnName": "bytes",
|
||||
"affinity": "BLOB",
|
||||
"notNull": false
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"columnNames": [
|
||||
"pk_avatar_id"
|
||||
],
|
||||
"autoGenerate": true
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "index_avatars_pk_avatar_id",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"pk_avatar_id"
|
||||
],
|
||||
"createSql": "CREATE INDEX `index_avatars_pk_avatar_id` ON `${TABLE_NAME}` (`pk_avatar_id`)"
|
||||
},
|
||||
{
|
||||
"name": "index_avatars_fk_entity_id",
|
||||
"unique": true,
|
||||
"columnNames": [
|
||||
"fk_entity_id"
|
||||
],
|
||||
"createSql": "CREATE UNIQUE INDEX `index_avatars_fk_entity_id` ON `${TABLE_NAME}` (`fk_entity_id`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"table": "entities",
|
||||
"onDelete": "RESTRICT",
|
||||
"onUpdate": "NO ACTION",
|
||||
"columns": [
|
||||
"fk_entity_id"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"pk_entity_id"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tableName": "entity_caps",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`pk_node_ver` TEXT NOT NULL, `xml` TEXT, PRIMARY KEY(`pk_node_ver`))",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "nodeVer",
|
||||
"columnName": "pk_node_ver",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "xml",
|
||||
"columnName": "xml",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"columnNames": [
|
||||
"pk_node_ver"
|
||||
],
|
||||
"autoGenerate": false
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "index_entity_caps_pk_node_ver",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"pk_node_ver"
|
||||
],
|
||||
"createSql": "CREATE INDEX `index_entity_caps_pk_node_ver` ON `${TABLE_NAME}` (`pk_node_ver`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": []
|
||||
}
|
||||
],
|
||||
"views": [],
|
||||
"setupQueries": [
|
||||
"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, '6322b5b46e09460ae6f30134786c9221')"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -1,382 +0,0 @@
|
|||
{
|
||||
"formatVersion": 1,
|
||||
"database": {
|
||||
"version": 2,
|
||||
"identityHash": "1149b7d295726ec2043486e660dcf75d",
|
||||
"entities": [
|
||||
{
|
||||
"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, 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 )",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "pk_contact_id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "accountId",
|
||||
"columnName": "fk_account_id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "entityId",
|
||||
"columnName": "fk_entity_id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "rosterName",
|
||||
"columnName": "rostername",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "nickname",
|
||||
"columnName": "nickname",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"columnNames": [
|
||||
"pk_contact_id"
|
||||
],
|
||||
"autoGenerate": true
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "index_contacts_pk_contact_id",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"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",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"fk_entity_id"
|
||||
],
|
||||
"createSql": "CREATE INDEX `index_contacts_fk_entity_id` ON `${TABLE_NAME}` (`fk_entity_id`)"
|
||||
},
|
||||
{
|
||||
"name": "index_contacts_pk_contact_id_fk_entity_id",
|
||||
"unique": true,
|
||||
"columnNames": [
|
||||
"pk_contact_id",
|
||||
"fk_entity_id"
|
||||
],
|
||||
"createSql": "CREATE UNIQUE INDEX `index_contacts_pk_contact_id_fk_entity_id` ON `${TABLE_NAME}` (`pk_contact_id`, `fk_entity_id`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"table": "accounts",
|
||||
"onDelete": "CASCADE",
|
||||
"onUpdate": "NO ACTION",
|
||||
"columns": [
|
||||
"fk_account_id"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"pk_account_id"
|
||||
]
|
||||
},
|
||||
{
|
||||
"table": "entities",
|
||||
"onDelete": "RESTRICT",
|
||||
"onUpdate": "NO ACTION",
|
||||
"columns": [
|
||||
"fk_entity_id"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"pk_entity_id"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tableName": "accounts",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`pk_account_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `jid` TEXT, `password` TEXT, `enabled` INTEGER NOT NULL, `state` TEXT)",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "pk_account_id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "jid",
|
||||
"columnName": "jid",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "password",
|
||||
"columnName": "password",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "enabled",
|
||||
"columnName": "enabled",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "state",
|
||||
"columnName": "state",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"columnNames": [
|
||||
"pk_account_id"
|
||||
],
|
||||
"autoGenerate": true
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "index_accounts_pk_account_id",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"pk_account_id"
|
||||
],
|
||||
"createSql": "CREATE INDEX `index_accounts_pk_account_id` ON `${TABLE_NAME}` (`pk_account_id`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"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 )",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "pk_chat_id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "peerEntityId",
|
||||
"columnName": "fk_entity_id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "isActive",
|
||||
"columnName": "active",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"columnNames": [
|
||||
"pk_chat_id"
|
||||
],
|
||||
"autoGenerate": true
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "index_chats_pk_chat_id",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"pk_chat_id"
|
||||
],
|
||||
"createSql": "CREATE INDEX `index_chats_pk_chat_id` ON `${TABLE_NAME}` (`pk_chat_id`)"
|
||||
},
|
||||
{
|
||||
"name": "index_chats_fk_entity_id",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"fk_entity_id"
|
||||
],
|
||||
"createSql": "CREATE INDEX `index_chats_fk_entity_id` ON `${TABLE_NAME}` (`fk_entity_id`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"table": "entities",
|
||||
"onDelete": "CASCADE",
|
||||
"onUpdate": "NO ACTION",
|
||||
"columns": [
|
||||
"fk_entity_id"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"pk_entity_id"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tableName": "messages",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`pk_message_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `fk_account_id` INTEGER NOT NULL, `body` TEXT, `send_date` INTEGER, `from` TEXT, `to` TEXT, `incoming` INTEGER NOT NULL, FOREIGN KEY(`fk_account_id`) REFERENCES `accounts`(`pk_account_id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "pk_message_id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "accountId",
|
||||
"columnName": "fk_account_id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "body",
|
||||
"columnName": "body",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "sendDate",
|
||||
"columnName": "send_date",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "from",
|
||||
"columnName": "from",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "to",
|
||||
"columnName": "to",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "incoming",
|
||||
"columnName": "incoming",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"columnNames": [
|
||||
"pk_message_id"
|
||||
],
|
||||
"autoGenerate": true
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "index_messages_pk_message_id",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"pk_message_id"
|
||||
],
|
||||
"createSql": "CREATE INDEX `index_messages_pk_message_id` ON `${TABLE_NAME}` (`pk_message_id`)"
|
||||
},
|
||||
{
|
||||
"name": "index_messages_fk_account_id",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"fk_account_id"
|
||||
],
|
||||
"createSql": "CREATE INDEX `index_messages_fk_account_id` ON `${TABLE_NAME}` (`fk_account_id`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"table": "accounts",
|
||||
"onDelete": "CASCADE",
|
||||
"onUpdate": "NO ACTION",
|
||||
"columns": [
|
||||
"fk_account_id"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"pk_account_id"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tableName": "entities",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`pk_entity_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `fk_account_id` INTEGER NOT NULL, `jid` TEXT NOT NULL, `avatar` TEXT, FOREIGN KEY(`fk_account_id`) REFERENCES `accounts`(`pk_account_id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "pk_entity_id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "accountId",
|
||||
"columnName": "fk_account_id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "jid",
|
||||
"columnName": "jid",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "avatarFile",
|
||||
"columnName": "avatar",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"columnNames": [
|
||||
"pk_entity_id"
|
||||
],
|
||||
"autoGenerate": true
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "index_entities_pk_entity_id",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"pk_entity_id"
|
||||
],
|
||||
"createSql": "CREATE INDEX `index_entities_pk_entity_id` ON `${TABLE_NAME}` (`pk_entity_id`)"
|
||||
},
|
||||
{
|
||||
"name": "index_entities_fk_account_id_jid",
|
||||
"unique": true,
|
||||
"columnNames": [
|
||||
"fk_account_id",
|
||||
"jid"
|
||||
],
|
||||
"createSql": "CREATE UNIQUE INDEX `index_entities_fk_account_id_jid` ON `${TABLE_NAME}` (`fk_account_id`, `jid`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"table": "accounts",
|
||||
"onDelete": "CASCADE",
|
||||
"onUpdate": "NO ACTION",
|
||||
"columns": [
|
||||
"fk_account_id"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"pk_account_id"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"views": [],
|
||||
"setupQueries": [
|
||||
"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, '1149b7d295726ec2043486e660dcf75d')"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
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,111 +0,0 @@
|
|||
package org.mercury_im.messenger.persistence.room;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mercury_im.messenger.persistence.room.model.RoomAccountModel;
|
||||
import org.mercury_im.messenger.persistence.room.model.RoomChatModel;
|
||||
import org.mercury_im.messenger.persistence.room.model.RoomContactModel;
|
||||
import org.mercury_im.messenger.persistence.room.model.RoomEntityModel;
|
||||
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ExampleInstrumentedTest extends AbstractDatabaseTest {
|
||||
|
||||
@Test
|
||||
public void testUpsertContact1() {
|
||||
RoomAccountModel accountModel = new RoomAccountModel();
|
||||
accountModel.setJid(TEST_JID_JULIET);
|
||||
accountRepository.insertAccount(accountModel).test().assertValue(1L).dispose();
|
||||
|
||||
RoomContactModel contactModel = new RoomContactModel();
|
||||
RoomEntityModel entityModel = new RoomEntityModel();
|
||||
entityModel.setAccountId(1);
|
||||
entityModel.setJid(TEST_JID_ROMEO);
|
||||
contactModel.setEntity(entityModel);
|
||||
|
||||
rosterRepository.upsertContact(contactModel).test().assertValue(1L).dispose();
|
||||
rosterRepository.maybeGetContact(1L).subscribe(contact -> {
|
||||
System.out.println(contact.getEntity().getAccountId() + " " + contact.getEntity().getJid().toString());
|
||||
}).dispose();
|
||||
|
||||
rosterRepository.upsertContact(contactModel).test().assertValue(1L).dispose();
|
||||
rosterRepository.maybeGetContact(1L).subscribe(contact -> {
|
||||
System.out.println(contact.getEntity().getAccountId() + " " + contact.getEntity().getJid().toString());
|
||||
}).dispose();
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpsertContact() throws InterruptedException {
|
||||
RoomAccountModel accountModel = new RoomAccountModel();
|
||||
accountModel.setJid(TEST_JID_ROMEO);
|
||||
accountRepository.insertAccount(accountModel).test().assertValue(1L).dispose();
|
||||
|
||||
RoomContactModel contact = new RoomContactModel();
|
||||
contact.setRosterName("A");
|
||||
RoomEntityModel entity = new RoomEntityModel();
|
||||
entity.setJid(TEST_JID_JULIET);
|
||||
entity.setAccountId(1L);
|
||||
contact.setEntity(entity);
|
||||
rosterRepository.upsertContact(contact).test().assertValue(1L).dispose();
|
||||
Thread.sleep(100);
|
||||
contact.setId(0);
|
||||
contact.setRosterName("B");
|
||||
contact.getEntity().setId(0);
|
||||
contact.setEntityId(0);
|
||||
rosterRepository.upsertContact(contact).test().assertValue(1L).dispose();
|
||||
|
||||
rosterRepository.getAllContacts().subscribe(System.out::println);
|
||||
|
||||
Thread.sleep(200);
|
||||
}
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.mercury_im.messenger.persistence.room" />
|
|
@ -1,112 +0,0 @@
|
|||
package org.mercury_im.messenger.persistence.room;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.room.Database;
|
||||
import androidx.room.Room;
|
||||
import androidx.room.RoomDatabase;
|
||||
|
||||
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.ChatDao;
|
||||
import org.mercury_im.messenger.persistence.room.dao.ContactDao;
|
||||
import org.mercury_im.messenger.persistence.room.dao.EntityCapsDao;
|
||||
import org.mercury_im.messenger.persistence.room.dao.EntityDao;
|
||||
import org.mercury_im.messenger.persistence.room.dao.MessageDao;
|
||||
import org.mercury_im.messenger.persistence.room.dao.RosterInformationDao;
|
||||
import org.mercury_im.messenger.persistence.room.model.RoomAccountModel;
|
||||
import org.mercury_im.messenger.persistence.room.model.RoomAvatarModel;
|
||||
import org.mercury_im.messenger.persistence.room.model.RoomChatModel;
|
||||
import org.mercury_im.messenger.persistence.room.model.RoomContactModel;
|
||||
import org.mercury_im.messenger.persistence.room.model.RoomEntityCapsModel;
|
||||
import org.mercury_im.messenger.persistence.room.model.RoomEntityModel;
|
||||
import org.mercury_im.messenger.persistence.room.model.RoomMessageModel;
|
||||
import org.mercury_im.messenger.persistence.room.model.RoomRosterInformationModel;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@Database(version = 1,
|
||||
entities = {
|
||||
RoomAccountModel.class,
|
||||
RoomEntityModel.class,
|
||||
RoomContactModel.class,
|
||||
RoomRosterInformationModel.class,
|
||||
RoomChatModel.class,
|
||||
RoomMessageModel.class,
|
||||
RoomAvatarModel.class,
|
||||
RoomEntityCapsModel.class
|
||||
})
|
||||
public abstract class AppDatabase extends RoomDatabase {
|
||||
|
||||
private static final String DB_NAME = "mercury_db";
|
||||
private static AppDatabase INSTANCE;
|
||||
|
||||
public static final String TAG = "PERSISTENCE_ROOM";
|
||||
|
||||
public static synchronized AppDatabase getDatabase(final Context context) {
|
||||
if (INSTANCE == null) {
|
||||
Logger.getLogger("DATABASE").log(Level.INFO, context.getApplicationContext().getDatabasePath(DB_NAME).getAbsolutePath());
|
||||
INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
|
||||
AppDatabase.class, DB_NAME)
|
||||
.build();
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an instance of {@link AccountDao}.
|
||||
*
|
||||
* @return accountDao
|
||||
*/
|
||||
public abstract AccountDao accountDao();
|
||||
|
||||
/**
|
||||
* Return an instance of {@link EntityDao}.
|
||||
*
|
||||
* @return entityDao
|
||||
*/
|
||||
public abstract EntityDao entityDao();
|
||||
|
||||
/**
|
||||
* Return an instance of {@link ContactDao}.
|
||||
*
|
||||
* @return contactDao
|
||||
*/
|
||||
public abstract ContactDao contactDao();
|
||||
|
||||
/**
|
||||
* Return an instance of {@link RosterInformationDao}.
|
||||
*
|
||||
* @return rosterInformationDao
|
||||
*/
|
||||
public abstract RosterInformationDao rosterInformationDao();
|
||||
|
||||
/**
|
||||
* Return an instance of {@link ChatDao}.
|
||||
*
|
||||
* @return chatDao
|
||||
*/
|
||||
public abstract ChatDao chatDao();
|
||||
|
||||
/**
|
||||
* Return an instance of {@link MessageDao}.
|
||||
*
|
||||
* @return messageDao
|
||||
*/
|
||||
public abstract MessageDao messageDao();
|
||||
|
||||
/**
|
||||
* Return an instance of {@link AvatarDao}.
|
||||
*
|
||||
* @return avatarDao
|
||||
*/
|
||||
public abstract AvatarDao avatarDao();
|
||||
|
||||
/**
|
||||
* Return an instance of {@link EntityCapsDao}.
|
||||
*
|
||||
* @return entityCapsDao
|
||||
*/
|
||||
public abstract EntityCapsDao entityCapsDao();
|
||||
}
|
|
@ -1,86 +0,0 @@
|
|||
package org.mercury_im.messenger.persistence.room;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
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.ChatDao;
|
||||
import org.mercury_im.messenger.persistence.room.dao.ContactDao;
|
||||
import org.mercury_im.messenger.persistence.room.dao.EntityCapsDao;
|
||||
import org.mercury_im.messenger.persistence.room.dao.EntityDao;
|
||||
import org.mercury_im.messenger.persistence.room.dao.MessageDao;
|
||||
import org.mercury_im.messenger.persistence.room.dao.RosterInformationDao;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
|
||||
/**
|
||||
* Provides the {@link AppDatabase}, DAOs and Repositories.
|
||||
*/
|
||||
@Module(includes = RoomRepositoryModule.class)
|
||||
public class RoomModule {
|
||||
|
||||
private AppDatabase mAppDatabase;
|
||||
|
||||
@Inject
|
||||
public RoomModule(Application application) {
|
||||
mAppDatabase = AppDatabase.getDatabase(application);
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
AppDatabase provideAppDatabase() {
|
||||
return mAppDatabase;
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
AccountDao provideAccountDao() {
|
||||
return mAppDatabase.accountDao();
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
ContactDao provideContactDao() {
|
||||
return mAppDatabase.contactDao();
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
ChatDao provideChatDao() {
|
||||
return mAppDatabase.chatDao();
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
MessageDao provideMessageDao() {
|
||||
return mAppDatabase.messageDao();
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
EntityDao provideEntityDao() {
|
||||
return mAppDatabase.entityDao();
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
AvatarDao providerAvatarDao() {
|
||||
return mAppDatabase.avatarDao();
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
RosterInformationDao provideRosterInformationDao() {
|
||||
return mAppDatabase.rosterInformationDao();
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
EntityCapsDao provideEntityCapsDao() {
|
||||
return mAppDatabase.entityCapsDao();
|
||||
}
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
package org.mercury_im.messenger.persistence.room;
|
||||
|
||||
import org.mercury_im.messenger.persistence.repository.AccountRepository;
|
||||
import org.mercury_im.messenger.persistence.repository.AvatarRepository;
|
||||
import org.mercury_im.messenger.persistence.repository.ChatRepository;
|
||||
import org.mercury_im.messenger.persistence.repository.EntityCapsRepository;
|
||||
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.AvatarDao;
|
||||
import org.mercury_im.messenger.persistence.room.dao.ChatDao;
|
||||
import org.mercury_im.messenger.persistence.room.dao.ContactDao;
|
||||
import org.mercury_im.messenger.persistence.room.dao.EntityCapsDao;
|
||||
import org.mercury_im.messenger.persistence.room.dao.EntityDao;
|
||||
import org.mercury_im.messenger.persistence.room.dao.MessageDao;
|
||||
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.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;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
|
||||
@Module
|
||||
public class RoomRepositoryModule {
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
AccountRepository provideAccountRepository(AccountDao dao) {
|
||||
return new IAccountRepository(dao);
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
ChatRepository provideChatRepository(ChatDao chatDao, RosterRepository rosterRepository) {
|
||||
return new IChatRepository(chatDao, rosterRepository);
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
MessageRepository provideMessageRepository(MessageDao dao) {
|
||||
return new IMessageRepository(dao);
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
RosterRepository provideContactRepository(EntityDao entityDao, ContactDao contactDao, RosterInformationDao rosterInformationDao) {
|
||||
return new IRosterRepository(entityDao, contactDao, rosterInformationDao);
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
AvatarRepository provideAvatarRepository(AvatarDao avatarDao) {
|
||||
return new IAvatarRepository(avatarDao);
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
EntityCapsRepository providerEntityCapsRepository(EntityCapsDao entityCapsDao) {
|
||||
return new IEntityCapsRepository(entityCapsDao);
|
||||
}
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
package org.mercury_im.messenger.persistence.room.dao;
|
||||
|
||||
import androidx.annotation.WorkerThread;
|
||||
import androidx.room.Dao;
|
||||
import androidx.room.Query;
|
||||
import androidx.room.TypeConverters;
|
||||
|
||||
import org.jxmpp.jid.EntityBareJid;
|
||||
import org.mercury_im.messenger.persistence.room.model.RoomAccountModel;
|
||||
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;
|
||||
|
||||
@Dao
|
||||
@TypeConverters(EntityBareJidConverter.class)
|
||||
@WorkerThread
|
||||
public interface AccountDao extends BaseDao<RoomAccountModel> {
|
||||
|
||||
/**
|
||||
* Return an {@link Observable} wrapping a {@link List} which contains all
|
||||
* {@link RoomAccountModel Accounts} which are currently stored in the database.
|
||||
*
|
||||
* @return live updating account list
|
||||
*/
|
||||
@Query("select * from accounts")
|
||||
Observable<List<RoomAccountModel>> getAllAccounts();
|
||||
|
||||
/**
|
||||
* Return the {@link RoomAccountModel Account} which is identified by the given id.
|
||||
*
|
||||
* @param id id of the account
|
||||
* @return account or null
|
||||
*/
|
||||
@Query("select * from accounts where pk_account_id = :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")
|
||||
Maybe<RoomAccountModel> getAccountByJid(EntityBareJid jid);
|
||||
|
||||
@Query("update accounts set state = :state where pk_account_id = :accountId")
|
||||
Completable updateConnectionState(long accountId, String state);
|
||||
|
||||
@Query("DELETE FROM accounts WHERE pk_account_id = :accountId")
|
||||
Completable deleteAccount(long accountId);
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
package org.mercury_im.messenger.persistence.room.dao;
|
||||
|
||||
import androidx.annotation.WorkerThread;
|
||||
import androidx.room.Dao;
|
||||
import androidx.room.Query;
|
||||
import androidx.room.TypeConverters;
|
||||
|
||||
import org.jxmpp.jid.EntityBareJid;
|
||||
import org.mercury_im.messenger.persistence.room.model.RoomAvatarModel;
|
||||
import org.mercury_im.messenger.persistence.room.type_converter.EntityBareJidConverter;
|
||||
|
||||
import io.reactivex.Maybe;
|
||||
|
||||
@Dao
|
||||
@TypeConverters(EntityBareJidConverter.class)
|
||||
@WorkerThread
|
||||
public interface AvatarDao extends BaseDao<RoomAvatarModel> {
|
||||
|
||||
@Query("SELECT * FROM avatars WHERE pk_avatar_id = :avatarId")
|
||||
Maybe<RoomAvatarModel> getAvatarById(long avatarId);
|
||||
|
||||
@Query("SELECT * FROM avatars WHERE fk_entity_id = :entityId")
|
||||
Maybe<RoomAvatarModel> getAvatarByEntityId(long entityId);
|
||||
|
||||
@Query("SELECT avatars.* " +
|
||||
"FROM avatars INNER JOIN entities ON avatars.fk_entity_id = entities.pk_entity_id " +
|
||||
"WHERE entities.jid = :jid")
|
||||
Maybe<RoomAvatarModel> getAvatarByJid(EntityBareJid jid);
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
package org.mercury_im.messenger.persistence.room.dao;
|
||||
|
||||
import androidx.room.Delete;
|
||||
import androidx.room.Insert;
|
||||
import androidx.room.OnConflictStrategy;
|
||||
import androidx.room.Transaction;
|
||||
import androidx.room.Update;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import io.reactivex.Completable;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.Single;
|
||||
|
||||
public interface BaseDao<T> {
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||
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
|
||||
Completable update(T entity);
|
||||
|
||||
@Update
|
||||
Completable update(T[] entities);
|
||||
|
||||
@Delete
|
||||
Completable delete(T entity);
|
||||
|
||||
@Delete
|
||||
Completable delete(T[] entities);
|
||||
|
||||
@Delete
|
||||
Completable delete(List<T> entities);
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
package org.mercury_im.messenger.persistence.room.dao;
|
||||
|
||||
import androidx.room.Dao;
|
||||
import androidx.room.Query;
|
||||
import androidx.room.TypeConverters;
|
||||
|
||||
import org.jxmpp.jid.EntityBareJid;
|
||||
import org.mercury_im.messenger.persistence.room.model.RoomChatModel;
|
||||
import org.mercury_im.messenger.persistence.pojo.Chat;
|
||||
import org.mercury_im.messenger.persistence.room.type_converter.EntityBareJidConverter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import io.reactivex.Maybe;
|
||||
import io.reactivex.Observable;
|
||||
|
||||
@Dao
|
||||
@TypeConverters(EntityBareJidConverter.class)
|
||||
public interface ChatDao extends BaseDao<RoomChatModel> {
|
||||
|
||||
@Query("SELECT * FROM chats")
|
||||
Observable<List<RoomChatModel>> getAllChats();
|
||||
|
||||
@Query("SELECT chats.* FROM chats JOIN entities WHERE fk_account_id = :accountId")
|
||||
Observable<List<RoomChatModel>> getAllChatsOfAccount(long accountId);
|
||||
|
||||
@Query("SELECT * FROM chats WHERE fk_entity_id = :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")
|
||||
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")
|
||||
Maybe<RoomChatModel> maybeGetChatWithContact(long contactId);
|
||||
|
||||
@Query("SELECT chats.* FROM chats JOIN contacts WHERE contacts.pk_contact_id = :contactId")
|
||||
Observable<RoomChatModel> getChatWithContact(long contactId);
|
||||
|
||||
@Query("SELECT chats.pk_chat_id as chatId, " +
|
||||
"chats.fk_entity_id as entityId, " +
|
||||
"contacts.rostername as contactName, " +
|
||||
"entities.fk_account_id as accountId, " +
|
||||
"jid, active " +
|
||||
"from chats " +
|
||||
"LEFT JOIN entities " +
|
||||
"ON chats.fk_entity_id = entities.pk_entity_id " +
|
||||
"LEFT JOIN contacts " +
|
||||
"ON entities.pk_entity_id = contacts.fk_entity_id")
|
||||
Observable<List<Chat>> getChatPojos();
|
||||
}
|
|
@ -1,79 +0,0 @@
|
|||
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.type_converter.EntityBareJidConverter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import io.reactivex.Completable;
|
||||
import io.reactivex.Maybe;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.Single;
|
||||
|
||||
import static androidx.room.OnConflictStrategy.REPLACE;
|
||||
|
||||
@Dao
|
||||
@TypeConverters(EntityBareJidConverter.class)
|
||||
public interface ContactDao extends BaseDao<RoomContactModel> {
|
||||
|
||||
@Override
|
||||
@Insert(onConflict = REPLACE)
|
||||
Single<Long> insert(RoomContactModel entity);
|
||||
|
||||
@Query("SELECT * FROM contacts WHERE pk_contact_id = :id")
|
||||
Observable<RoomContactModel> getContact(long id);
|
||||
|
||||
@Query("SELECT * FROM contacts WHERE pk_contact_id = :id")
|
||||
Maybe<RoomContactModel> maybeGetContact(long id);
|
||||
|
||||
@Query("SELECT * FROM contacts WHERE fk_entity_id = :entityId")
|
||||
Maybe<RoomContactModel> getContactForEntityId(long entityId);
|
||||
|
||||
@Query("SELECT * FROM contacts")
|
||||
Observable<List<RoomContactModel>> getAllContacts();
|
||||
|
||||
@Query("SELECT contacts.* FROM contacts JOIN entities " +
|
||||
"ON contacts.fk_entity_id = entities.pk_entity_id " +
|
||||
"WHERE entities.fk_account_id = :accountId AND jid = :jid")
|
||||
Maybe<RoomContactModel> maybeGetContactByJid(long accountId, EntityBareJid jid);
|
||||
|
||||
@Query("SELECT contacts.* FROM contacts JOIN entities " +
|
||||
"ON contacts.fk_entity_id = entities.pk_entity_id " +
|
||||
"WHERE entities.fk_account_id = :accountId AND jid = :jid")
|
||||
Observable<RoomContactModel> getContactByJid(long accountId, EntityBareJid jid);
|
||||
|
||||
@Query("SELECT contacts.* FROM contacts JOIN entities " +
|
||||
"ON contacts.fk_entity_id = entities.pk_entity_id " +
|
||||
"WHERE entities.fk_account_id = :accountId")
|
||||
Observable<List<RoomContactModel>> getContactsForAccount(long accountId);
|
||||
|
||||
@Query("DELETE FROM contacts WHERE pk_contact_id = :id")
|
||||
Completable deleteContact(long id);
|
||||
|
||||
@Query("DELETE FROM contacts WHERE fk_entity_id = :entityId")
|
||||
Completable deleteContactForEntity(long entityId);
|
||||
|
||||
@Query("DELETE FROM contacts")
|
||||
Completable deleteAll();
|
||||
|
||||
@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);
|
||||
|
||||
@Query("DELETE FROM contacts WHERE pk_contact_id IN(: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")
|
||||
Single<RoomEntityModel> getEntityForContactId(long contactId);
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
package org.mercury_im.messenger.persistence.room.dao;
|
||||
|
||||
import androidx.annotation.WorkerThread;
|
||||
import androidx.room.Dao;
|
||||
import androidx.room.Query;
|
||||
|
||||
import org.mercury_im.messenger.persistence.room.model.RoomEntityCapsModel;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import io.reactivex.Completable;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.Single;
|
||||
|
||||
@Dao
|
||||
@WorkerThread
|
||||
public interface EntityCapsDao extends BaseDao<RoomEntityCapsModel> {
|
||||
|
||||
@Query("SELECT * FROM entity_caps WHERE pk_node_ver = :nodeVer")
|
||||
Single<RoomEntityCapsModel> getEntityCapsForNodeVer(String nodeVer);
|
||||
|
||||
@Query("SELECT * FROM entity_caps")
|
||||
Observable<List<RoomEntityCapsModel>> getAllEntityCaps();
|
||||
|
||||
@Query("DELETE FROM entity_caps")
|
||||
Completable deleteAllEntityCaps();
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
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.RoomEntityModel;
|
||||
import org.mercury_im.messenger.persistence.room.type_converter.EntityBareJidConverter;
|
||||
|
||||
import io.reactivex.Maybe;
|
||||
import io.reactivex.Single;
|
||||
|
||||
import static androidx.room.OnConflictStrategy.REPLACE;
|
||||
|
||||
@Dao
|
||||
@TypeConverters(EntityBareJidConverter.class)
|
||||
public interface EntityDao extends BaseDao<RoomEntityModel> {
|
||||
|
||||
@Query("SELECT * FROM entities WHERE pk_entity_id = :id")
|
||||
Maybe<RoomEntityModel> getEntity(long id);
|
||||
|
||||
@Query("SELECT * FROM entities WHERE fk_account_id = :accountId AND jid = :jid")
|
||||
Maybe<RoomEntityModel> getEntityFor(long accountId, EntityBareJid jid);
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
package org.mercury_im.messenger.persistence.room.dao;
|
||||
|
||||
import androidx.room.Dao;
|
||||
import androidx.room.Query;
|
||||
import androidx.room.TypeConverters;
|
||||
|
||||
import org.jxmpp.jid.EntityBareJid;
|
||||
import org.mercury_im.messenger.persistence.room.model.RoomMessageModel;
|
||||
import org.mercury_im.messenger.persistence.room.type_converter.EntityBareJidConverter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import io.reactivex.Observable;
|
||||
|
||||
@Dao
|
||||
@TypeConverters(EntityBareJidConverter.class)
|
||||
public interface MessageDao extends BaseDao<RoomMessageModel> {
|
||||
|
||||
@Query("SELECT * FROM messages")
|
||||
Observable<List<RoomMessageModel>> getAllMessages();
|
||||
|
||||
@Query("SELECT * FROM messages " +
|
||||
"WHERE fk_account_id = :accountId " +
|
||||
"ORDER BY send_date ASC")
|
||||
Observable<List<RoomMessageModel>> getAllMessagesOf(long accountId);
|
||||
|
||||
@Query("SELECT * FROM messages " +
|
||||
"WHERE fk_account_id = :accountId AND `from` = :sender " +
|
||||
"ORDER BY send_date ASC")
|
||||
Observable<List<RoomMessageModel>> getAllMessagesFrom(long accountId, EntityBareJid sender);
|
||||
|
||||
@Query("SELECT * FROM messages " +
|
||||
"WHERE fk_account_id = :accountId AND (`from` = :peer OR `to` = :peer) " +
|
||||
"ORDER BY send_date ASC")
|
||||
Observable<List<RoomMessageModel>> getAllMessagesInConversation(long accountId, EntityBareJid peer);
|
||||
|
||||
@Query("SELECT * FROM messages " +
|
||||
"WHERE body LIKE :query " +
|
||||
"COLLATE utf8_general_ci") // case insensitive
|
||||
Observable<List<RoomMessageModel>> findMessageByQuery(String query);
|
||||
|
||||
@Query("SELECT * FROM messages " +
|
||||
"WHERE fk_account_id = :accountId AND body LIKE :query " +
|
||||
"COLLATE utf8_general_ci") // case insensitive
|
||||
Observable<List<RoomMessageModel>> findMessageByQuery(long accountId, String query);
|
||||
|
||||
@Query("SELECT * FROM messages " +
|
||||
"WHERE fk_account_id = :accountId " +
|
||||
"AND (`from` = :peer OR `to` = :peer) " +
|
||||
"AND body LIKE :query " +
|
||||
"COLLATE utf8_general_ci") // case insensitive
|
||||
Observable<List<RoomMessageModel>> findMessageByQuery(long accountId, EntityBareJid peer, String query);
|
||||
|
||||
@Query("SELECT * FROM messages WHERE fk_account_id = :accountId AND (`from` = :peer OR `to` = :peer) ORDER BY send_date DESC LIMIT 1")
|
||||
Observable<RoomMessageModel> getLastMessageFrom(long accountId, EntityBareJid peer);
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
package org.mercury_im.messenger.persistence.room.dao;
|
||||
|
||||
import androidx.room.Dao;
|
||||
import androidx.room.Insert;
|
||||
import androidx.room.Query;
|
||||
|
||||
import org.mercury_im.messenger.persistence.room.model.RoomRosterInformationModel;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.Single;
|
||||
|
||||
import static androidx.room.OnConflictStrategy.REPLACE;
|
||||
|
||||
@Dao
|
||||
public interface RosterInformationDao extends BaseDao<RoomRosterInformationModel> {
|
||||
|
||||
@Query("SELECT * FROM roster_information")
|
||||
Observable<List<RoomRosterInformationModel>> getAllRosterInformation();
|
||||
|
||||
@Query("SELECT * FROM roster_information WHERE pk_account_id = :accountId")
|
||||
Observable<RoomRosterInformationModel> getRosterInformation(long accountId);
|
||||
|
||||
@Insert(onConflict = REPLACE)
|
||||
Single<Long> insertRosterInformation(RoomRosterInformationModel information);
|
||||
}
|
|
@ -1,107 +0,0 @@
|
|||
package org.mercury_im.messenger.persistence.room.model;
|
||||
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.room.ColumnInfo;
|
||||
import androidx.room.Entity;
|
||||
import androidx.room.Index;
|
||||
import androidx.room.PrimaryKey;
|
||||
import androidx.room.TypeConverters;
|
||||
|
||||
import org.jxmpp.jid.EntityBareJid;
|
||||
import org.mercury_im.messenger.persistence.model.AbstractAccountModel;
|
||||
import org.mercury_im.messenger.persistence.model.AccountModel;
|
||||
import org.mercury_im.messenger.persistence.room.type_converter.EntityBareJidConverter;
|
||||
|
||||
import static org.mercury_im.messenger.persistence.room.model.RoomAccountModel.KEY_ID;
|
||||
import static org.mercury_im.messenger.persistence.room.model.RoomAccountModel.TABLE;
|
||||
|
||||
@Entity(tableName = TABLE, indices = {@Index(KEY_ID)})
|
||||
public class RoomAccountModel extends AbstractAccountModel {
|
||||
|
||||
public static final String TABLE = "accounts";
|
||||
public static final String KEY_ID = "pk_account_id";
|
||||
public static final String KEY_JID = "jid";
|
||||
public static final String KEY_PASSWORD = "password";
|
||||
public static final String KEY_ENABLED = "enabled";
|
||||
public static final String KEY_STATE = "state";
|
||||
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
@ColumnInfo(name = KEY_ID)
|
||||
public long id;
|
||||
|
||||
@TypeConverters(EntityBareJidConverter.class)
|
||||
@ColumnInfo(name = KEY_JID)
|
||||
private EntityBareJid jid;
|
||||
|
||||
@ColumnInfo(name = KEY_PASSWORD)
|
||||
private String password;
|
||||
|
||||
@ColumnInfo(name = KEY_ENABLED)
|
||||
private boolean enabled;
|
||||
|
||||
@ColumnInfo(name = KEY_STATE)
|
||||
private String state;
|
||||
|
||||
@Override
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setId(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityBareJid getJid() {
|
||||
return jid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setJid(EntityBareJid jid) {
|
||||
this.jid = jid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setState(String 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,87 +0,0 @@
|
|||
package org.mercury_im.messenger.persistence.room.model;
|
||||
|
||||
import androidx.room.ColumnInfo;
|
||||
import androidx.room.Entity;
|
||||
import androidx.room.ForeignKey;
|
||||
import androidx.room.Index;
|
||||
import androidx.room.PrimaryKey;
|
||||
|
||||
import org.mercury_im.messenger.persistence.model.AvatarModel;
|
||||
|
||||
import static androidx.room.ForeignKey.RESTRICT;
|
||||
import static org.mercury_im.messenger.persistence.room.model.RoomAvatarModel.KEY_ENTITY_ID;
|
||||
import static org.mercury_im.messenger.persistence.room.model.RoomAvatarModel.KEY_ID;
|
||||
import static org.mercury_im.messenger.persistence.room.model.RoomAvatarModel.TABLE;
|
||||
|
||||
@Entity(tableName = TABLE,
|
||||
indices = {
|
||||
@Index(value = KEY_ID),
|
||||
@Index(value = KEY_ENTITY_ID, unique = true)
|
||||
},
|
||||
foreignKeys = {
|
||||
@ForeignKey(entity = RoomEntityModel.class,
|
||||
parentColumns = RoomEntityModel.KEY_ID,
|
||||
childColumns = KEY_ENTITY_ID,
|
||||
onDelete = RESTRICT)
|
||||
})
|
||||
public class RoomAvatarModel implements AvatarModel {
|
||||
|
||||
public static final String TABLE = "avatars";
|
||||
public static final String KEY_ID = "pk_avatar_id";
|
||||
public static final String KEY_ENTITY_ID = "fk_entity_id";
|
||||
public static final String KEY_SHA1_SUM = "sha1sum";
|
||||
public static final String KEY_BYTES = "bytes";
|
||||
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
@ColumnInfo(name = KEY_ID)
|
||||
private long avatarId;
|
||||
|
||||
@ColumnInfo(name = KEY_ENTITY_ID)
|
||||
private long entityId;
|
||||
|
||||
@ColumnInfo(name = KEY_SHA1_SUM)
|
||||
private String sha1Sum;
|
||||
|
||||
@ColumnInfo(name = KEY_BYTES)
|
||||
private byte[] bytes;
|
||||
|
||||
@Override
|
||||
public long getAvatarId() {
|
||||
return avatarId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAvatarId(long id) {
|
||||
this.avatarId = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long entityId() {
|
||||
return entityId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEntityId(long entityId) {
|
||||
this.entityId = entityId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSha1Sum() {
|
||||
return sha1Sum;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSha1Sum(String sha1Sum) {
|
||||
this.sha1Sum = sha1Sum;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getBytes() {
|
||||
return bytes.clone();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBytes(byte[] bytes) {
|
||||
this.bytes = bytes;
|
||||
}
|
||||
}
|
|
@ -1,126 +0,0 @@
|
|||
package org.mercury_im.messenger.persistence.room.model;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.room.ColumnInfo;
|
||||
import androidx.room.Entity;
|
||||
import androidx.room.ForeignKey;
|
||||
import androidx.room.Index;
|
||||
import androidx.room.PrimaryKey;
|
||||
|
||||
import org.mercury_im.messenger.persistence.model.ChatModel;
|
||||
|
||||
import static androidx.room.ForeignKey.CASCADE;
|
||||
import static org.mercury_im.messenger.persistence.room.model.RoomChatModel.KEY_ID;
|
||||
import static org.mercury_im.messenger.persistence.room.model.RoomChatModel.KEY_ENTITY;
|
||||
import static org.mercury_im.messenger.persistence.room.model.RoomChatModel.TABLE;
|
||||
|
||||
@Entity(tableName = TABLE,
|
||||
indices = {
|
||||
@Index(KEY_ID), @Index(KEY_ENTITY)
|
||||
},
|
||||
foreignKeys = {
|
||||
@ForeignKey(entity = RoomEntityModel.class,
|
||||
parentColumns = RoomEntityModel.KEY_ID,
|
||||
childColumns = KEY_ENTITY,
|
||||
onDelete = CASCADE)
|
||||
})
|
||||
public class RoomChatModel implements ChatModel {
|
||||
|
||||
public static final String TABLE = "chats";
|
||||
public static final String KEY_ID = "pk_chat_id";
|
||||
|
||||
public static final String KEY_ENTITY = "fk_entity_id";
|
||||
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)
|
||||
@ColumnInfo(name = KEY_ID)
|
||||
private long id;
|
||||
|
||||
@ColumnInfo(name = KEY_ENTITY)
|
||||
private long peerEntityId;
|
||||
|
||||
@ColumnInfo(name = KEY_ACTIVE)
|
||||
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
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setId(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getPeerEntityId() {
|
||||
return peerEntityId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPeerEntityId(long id) {
|
||||
this.peerEntityId = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive() {
|
||||
return isActive;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setActive(boolean 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,153 +0,0 @@
|
|||
package org.mercury_im.messenger.persistence.room.model;
|
||||
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.room.ColumnInfo;
|
||||
import androidx.room.Entity;
|
||||
import androidx.room.ForeignKey;
|
||||
import androidx.room.Ignore;
|
||||
import androidx.room.Index;
|
||||
import androidx.room.PrimaryKey;
|
||||
import androidx.room.TypeConverters;
|
||||
|
||||
import org.mercury_im.messenger.persistence.model.ContactModel;
|
||||
import org.mercury_im.messenger.persistence.model.EntityModel;
|
||||
import org.mercury_im.messenger.persistence.room.type_converter.DirectionConverter;
|
||||
|
||||
import static androidx.room.ForeignKey.RESTRICT;
|
||||
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.TABLE;
|
||||
|
||||
@Entity(tableName = TABLE,
|
||||
indices = {
|
||||
@Index(value = KEY_ID),
|
||||
@Index(value = KEY_ENTITY_ID, unique = true),
|
||||
@Index(value = {KEY_ID, KEY_ENTITY_ID}, unique = true)
|
||||
},
|
||||
foreignKeys = {
|
||||
@ForeignKey(entity = RoomEntityModel.class,
|
||||
parentColumns = RoomEntityModel.KEY_ID,
|
||||
childColumns = KEY_ENTITY_ID,
|
||||
onDelete = RESTRICT)})
|
||||
public class RoomContactModel implements ContactModel {
|
||||
|
||||
public static final String TABLE = "contacts";
|
||||
public static final String KEY_ID = "pk_contact_id";
|
||||
public static final String KEY_ENTITY_ID = "fk_entity_id";
|
||||
public static final String KEY_ROSTER_NAME = "rostername";
|
||||
public static final String KEY_SUB_DIRECTION = "sub_direction";
|
||||
public static final String KEY_SUB_PENDING = "sub_pending";
|
||||
public static final String KEY_SUB_APPROVED = "sub_approved";
|
||||
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
@ColumnInfo(name = KEY_ID)
|
||||
private long id;
|
||||
|
||||
@ColumnInfo(name = KEY_ENTITY_ID)
|
||||
private long entityId;
|
||||
|
||||
@ColumnInfo(name = KEY_ROSTER_NAME)
|
||||
private String rosterName;
|
||||
|
||||
@ColumnInfo(name = KEY_SUB_DIRECTION)
|
||||
@TypeConverters(DirectionConverter.class)
|
||||
private DIRECTION direction;
|
||||
|
||||
@ColumnInfo(name = KEY_SUB_PENDING)
|
||||
private boolean subscriptionPending;
|
||||
|
||||
@ColumnInfo(name = KEY_SUB_APPROVED)
|
||||
private boolean approved;
|
||||
|
||||
/**
|
||||
* This field is ignored by room and must instead be populated manually by calling
|
||||
* {@link #setEntity(EntityModel)}.
|
||||
*/
|
||||
@Ignore
|
||||
private EntityModel entityModel;
|
||||
|
||||
@Override
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setId(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getEntityId() {
|
||||
return entityId;
|
||||
}
|
||||
|
||||
@Override
|
||||
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 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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityModel getEntity() {
|
||||
return entityModel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEntity(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_SUB_DIRECTION + ": " + getDirection() + ", " +
|
||||
KEY_SUB_PENDING + ": " + isSubscriptionPending() + ", " +
|
||||
KEY_SUB_APPROVED + ": " + isApproved() +
|
||||
"]";
|
||||
}
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
package org.mercury_im.messenger.persistence.room.model;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.room.ColumnInfo;
|
||||
import androidx.room.Entity;
|
||||
import androidx.room.PrimaryKey;
|
||||
|
||||
import org.mercury_im.messenger.persistence.model.EntityCapsModel;
|
||||
|
||||
import static org.mercury_im.messenger.persistence.room.model.RoomEntityCapsModel.TABLE;
|
||||
|
||||
@Entity(tableName = TABLE)
|
||||
public class RoomEntityCapsModel implements EntityCapsModel {
|
||||
|
||||
public static final String TABLE = "entity_caps";
|
||||
public static final String KEY_NODE_VER = "pk_node_ver";
|
||||
public static final String KEY_XML = "xml";
|
||||
|
||||
@PrimaryKey
|
||||
@NonNull
|
||||
@ColumnInfo(name = KEY_NODE_VER, index = true)
|
||||
private String nodeVer;
|
||||
|
||||
@ColumnInfo(name = KEY_XML)
|
||||
private String xml;
|
||||
|
||||
public RoomEntityCapsModel(@NonNull String nodeVer) {
|
||||
this.nodeVer = nodeVer;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public String getNodeVer() {
|
||||
return nodeVer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNodeVer(@NonNull String nodeVer) {
|
||||
this.nodeVer = nodeVer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getXml() {
|
||||
return xml;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setXml(String xml) {
|
||||
this.xml = xml;
|
||||
}
|
||||
}
|
|
@ -1,94 +0,0 @@
|
|||
package org.mercury_im.messenger.persistence.room.model;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.room.ColumnInfo;
|
||||
import androidx.room.Entity;
|
||||
import androidx.room.ForeignKey;
|
||||
import androidx.room.Index;
|
||||
import androidx.room.PrimaryKey;
|
||||
import androidx.room.TypeConverters;
|
||||
|
||||
import org.jxmpp.jid.EntityBareJid;
|
||||
import org.mercury_im.messenger.persistence.model.EntityModel;
|
||||
import org.mercury_im.messenger.persistence.room.type_converter.EntityBareJidConverter;
|
||||
import org.mercury_im.messenger.persistence.room.type_converter.FileConverter;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import static androidx.room.ForeignKey.CASCADE;
|
||||
import static org.mercury_im.messenger.persistence.room.model.RoomEntityModel.KEY_ACCOUNT_ID;
|
||||
import static org.mercury_im.messenger.persistence.room.model.RoomEntityModel.KEY_ID;
|
||||
import static org.mercury_im.messenger.persistence.room.model.RoomEntityModel.KEY_JID;
|
||||
import static org.mercury_im.messenger.persistence.room.model.RoomEntityModel.TABLE;
|
||||
|
||||
@Entity(tableName = TABLE,
|
||||
indices = {
|
||||
@Index(value = KEY_ID),
|
||||
@Index(value = {KEY_ACCOUNT_ID, KEY_JID}, unique = true)
|
||||
},
|
||||
foreignKeys = {
|
||||
@ForeignKey(entity = RoomAccountModel.class,
|
||||
parentColumns = RoomAccountModel.KEY_ID,
|
||||
childColumns = KEY_ACCOUNT_ID,
|
||||
onDelete = CASCADE)
|
||||
})
|
||||
public class RoomEntityModel implements EntityModel {
|
||||
|
||||
public static final String TABLE = "entities";
|
||||
public static final String KEY_ID = "pk_entity_id";
|
||||
public static final String KEY_ACCOUNT_ID = "fk_account_id";
|
||||
public static final String KEY_JID = "jid";
|
||||
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
@ColumnInfo(name = KEY_ID)
|
||||
protected long id;
|
||||
|
||||
@ColumnInfo(name = KEY_ACCOUNT_ID)
|
||||
protected long accountId;
|
||||
|
||||
@NonNull
|
||||
@TypeConverters(EntityBareJidConverter.class)
|
||||
@ColumnInfo(name = KEY_JID)
|
||||
protected EntityBareJid jid;
|
||||
|
||||
@Override
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setId(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public EntityBareJid getJid() {
|
||||
return jid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setJid(@NonNull EntityBareJid jid) {
|
||||
this.jid = jid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getAccountId() {
|
||||
return accountId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAccountId(long accountId) {
|
||||
this.accountId = accountId;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public String toString() {
|
||||
return "EntityModel[" +
|
||||
KEY_ID + ": " + getId() + ", " +
|
||||
KEY_ACCOUNT_ID + ": " + getAccountId() + ", " +
|
||||
KEY_JID + ": " + getJid().toString() +
|
||||
"]";
|
||||
}
|
||||
}
|
|
@ -1,141 +0,0 @@
|
|||
package org.mercury_im.messenger.persistence.room.model;
|
||||
|
||||
import androidx.room.ColumnInfo;
|
||||
import androidx.room.Entity;
|
||||
import androidx.room.ForeignKey;
|
||||
import androidx.room.Index;
|
||||
import androidx.room.PrimaryKey;
|
||||
import androidx.room.TypeConverters;
|
||||
|
||||
import org.jxmpp.jid.EntityBareJid;
|
||||
import org.mercury_im.messenger.persistence.model.MessageModel;
|
||||
import org.mercury_im.messenger.persistence.room.type_converter.DateConverter;
|
||||
import org.mercury_im.messenger.persistence.room.type_converter.EntityBareJidConverter;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import static androidx.room.ForeignKey.CASCADE;
|
||||
import static org.mercury_im.messenger.persistence.room.model.RoomMessageModel.KEY_ACCOUNT_ID;
|
||||
import static org.mercury_im.messenger.persistence.room.model.RoomMessageModel.KEY_ID;
|
||||
import static org.mercury_im.messenger.persistence.room.model.RoomMessageModel.TABLE;
|
||||
|
||||
@Entity(tableName = TABLE,
|
||||
foreignKeys = {
|
||||
@ForeignKey(entity = RoomAccountModel.class,
|
||||
parentColumns = RoomAccountModel.KEY_ID,
|
||||
childColumns = KEY_ACCOUNT_ID,
|
||||
onDelete = CASCADE)},
|
||||
indices = {
|
||||
@Index(KEY_ID),
|
||||
@Index(KEY_ACCOUNT_ID)
|
||||
})
|
||||
public class RoomMessageModel implements MessageModel {
|
||||
|
||||
public static final String TABLE = "messages";
|
||||
public static final String KEY_ID = "pk_message_id";
|
||||
public static final String KEY_ACCOUNT_ID = "fk_account_id";
|
||||
public static final String KEY_BODY = "body";
|
||||
public static final String KEY_SEND_DATE = "send_date";
|
||||
public static final String KEY_FROM = "from";
|
||||
public static final String KEY_TO = "to";
|
||||
public static final String KEY_INCOMING = "incoming";
|
||||
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
@ColumnInfo(name = KEY_ID)
|
||||
private long id;
|
||||
|
||||
@ColumnInfo(name = KEY_ACCOUNT_ID)
|
||||
private long accountId;
|
||||
|
||||
@ColumnInfo(name = KEY_BODY)
|
||||
private String body;
|
||||
|
||||
@TypeConverters(DateConverter.class)
|
||||
@ColumnInfo(name = KEY_SEND_DATE)
|
||||
private Date sendDate;
|
||||
|
||||
@TypeConverters(EntityBareJidConverter.class)
|
||||
@ColumnInfo(name = KEY_FROM)
|
||||
private EntityBareJid from;
|
||||
|
||||
@TypeConverters(EntityBareJidConverter.class)
|
||||
@ColumnInfo(name = KEY_TO)
|
||||
private EntityBareJid to;
|
||||
|
||||
@ColumnInfo(name = KEY_INCOMING)
|
||||
private boolean incoming;
|
||||
|
||||
public RoomMessageModel() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setId(long val) {
|
||||
this.id = val;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getAccountId() {
|
||||
return accountId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAccountId(long accountId) {
|
||||
this.accountId = accountId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBody() {
|
||||
return body;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBody(String body) {
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getSendDate() {
|
||||
return sendDate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSendDate(Date date) {
|
||||
this.sendDate = date;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityBareJid getFrom() {
|
||||
return from;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFrom(EntityBareJid sender) {
|
||||
this.from = sender;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityBareJid getTo() {
|
||||
return to;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTo(EntityBareJid recipient) {
|
||||
this.to = recipient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isIncoming() {
|
||||
return incoming;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIncoming(boolean isIncoming) {
|
||||
this.incoming = isIncoming;
|
||||
}
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
package org.mercury_im.messenger.persistence.room.model;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
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.RoomRosterInformationModel.KEY_ID;
|
||||
import static org.mercury_im.messenger.persistence.room.model.RoomRosterInformationModel.TABLE;
|
||||
|
||||
@Entity(tableName = TABLE, indices = {
|
||||
@Index(value = KEY_ID, unique = true)
|
||||
})
|
||||
public class RoomRosterInformationModel 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;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public String toString() {
|
||||
return "RosterInformationModel[" +
|
||||
KEY_ID + ": " + getAccountId() + ", " +
|
||||
KEY_ROSTER_VERSION + ": " + getRosterVersion() +
|
||||
"]";
|
||||
}
|
||||
}
|
|
@ -1,77 +0,0 @@
|
|||
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.room.dao.AccountDao;
|
||||
import org.mercury_im.messenger.persistence.room.model.RoomAccountModel;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import io.reactivex.Completable;
|
||||
import io.reactivex.Maybe;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.Single;
|
||||
|
||||
import static org.mercury_im.messenger.persistence.room.AppDatabase.TAG;
|
||||
|
||||
public class IAccountRepository implements AccountRepository<RoomAccountModel> {
|
||||
|
||||
private final AccountDao accountDao;
|
||||
|
||||
@Inject
|
||||
public IAccountRepository(AccountDao accountDao) {
|
||||
this.accountDao = accountDao;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RoomAccountModel newAccountModel() {
|
||||
return new RoomAccountModel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Observable<RoomAccountModel> getAccount(long accountId) {
|
||||
return accountDao.getAccountById(accountId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Maybe<RoomAccountModel> maybeGetAccount(long accountId) {
|
||||
return accountDao.maybeGetAccountById(accountId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Observable<List<RoomAccountModel>> getAllAccounts() {
|
||||
return accountDao.getAllAccounts();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Single<Long> insertAccount(@NonNull RoomAccountModel accountModel) {
|
||||
return accountDao.insert(accountModel)
|
||||
.map(accountId -> {
|
||||
accountModel.setId(accountId);
|
||||
return accountId;
|
||||
})
|
||||
.doOnSubscribe(ignore -> Log.v(TAG, "Insert " + accountModel))
|
||||
.doAfterSuccess(accountId -> Log.v(TAG, "AccountModel has new ID " + accountId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Completable updateAccount(RoomAccountModel accountModel) {
|
||||
return accountDao.update(accountModel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Completable deleteAccount(long accountId) {
|
||||
return accountDao.deleteAccount(accountId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Completable deleteAccount(RoomAccountModel item) {
|
||||
return accountDao.delete(item);
|
||||
}
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
package org.mercury_im.messenger.persistence.room.repository;
|
||||
|
||||
import org.jxmpp.jid.EntityBareJid;
|
||||
import org.mercury_im.messenger.persistence.repository.AvatarRepository;
|
||||
import org.mercury_im.messenger.persistence.room.dao.AvatarDao;
|
||||
import org.mercury_im.messenger.persistence.room.model.RoomAvatarModel;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import io.reactivex.Maybe;
|
||||
import io.reactivex.Single;
|
||||
|
||||
public class IAvatarRepository implements AvatarRepository<RoomAvatarModel> {
|
||||
|
||||
private final AvatarDao dao;
|
||||
|
||||
@Inject
|
||||
public IAvatarRepository(AvatarDao dao) {
|
||||
this.dao = dao;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RoomAvatarModel newAvatarModel() {
|
||||
return new RoomAvatarModel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Maybe<RoomAvatarModel> getAvatarById(long avatarId) {
|
||||
return dao.getAvatarById(avatarId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Maybe<RoomAvatarModel> getAvatarByEntityId(long entityId) {
|
||||
return dao.getAvatarByEntityId(entityId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Maybe<RoomAvatarModel> getAvatarByJid(EntityBareJid jid) {
|
||||
return dao.getAvatarByJid(jid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Single<Long> updateOrInsertAvatar(RoomAvatarModel avatarModel) {
|
||||
return dao.insert(avatarModel);
|
||||
}
|
||||
}
|
|
@ -1,120 +0,0 @@
|
|||
package org.mercury_im.messenger.persistence.room.repository;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import org.jxmpp.jid.EntityBareJid;
|
||||
import org.mercury_im.messenger.persistence.model.EntityModel;
|
||||
import org.mercury_im.messenger.persistence.pojo.Chat;
|
||||
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.model.RoomChatModel;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import io.reactivex.Completable;
|
||||
import io.reactivex.Maybe;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.Single;
|
||||
|
||||
import static org.mercury_im.messenger.persistence.room.AppDatabase.TAG;
|
||||
|
||||
public class IChatRepository implements ChatRepository<RoomChatModel> {
|
||||
|
||||
private final ChatDao chatDao;
|
||||
private final RosterRepository rosterRepository;
|
||||
|
||||
@Inject
|
||||
public IChatRepository(ChatDao chatDao, RosterRepository rosterRepository) {
|
||||
this.chatDao = chatDao;
|
||||
this.rosterRepository = rosterRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RoomChatModel newChatModel() {
|
||||
return new RoomChatModel();
|
||||
}
|
||||
|
||||
@Override
|
||||
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
|
||||
public Observable<List<RoomChatModel>> getAllChats() {
|
||||
return chatDao.getAllChats();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Observable<List<RoomChatModel>> getAllChatsOfAccount(long accountId) {
|
||||
return chatDao.getAllChatsOfAccount(accountId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Maybe<RoomChatModel> maybeGetChatWith(long accountId, EntityBareJid jid) {
|
||||
return chatDao.maybeGetChatWithJid(accountId, jid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Maybe<RoomChatModel> maybeGetChatWithEntity(long entityId) {
|
||||
return chatDao.maybeGetChatWithEntity(entityId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Maybe<RoomChatModel> maybeGetChatWithContact(long contactId) {
|
||||
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
|
||||
public Completable closeChat(RoomChatModel chat) {
|
||||
return chatDao.delete(chat);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Observable<List<Chat>> getDisplayableChats() {
|
||||
return chatDao.getChatPojos();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
package org.mercury_im.messenger.persistence.room.repository;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.mercury_im.messenger.persistence.repository.EntityCapsRepository;
|
||||
import org.mercury_im.messenger.persistence.room.dao.EntityCapsDao;
|
||||
import org.mercury_im.messenger.persistence.room.model.RoomEntityCapsModel;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import io.reactivex.Completable;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.Single;
|
||||
|
||||
|
||||
public class IEntityCapsRepository implements EntityCapsRepository<RoomEntityCapsModel> {
|
||||
|
||||
private final EntityCapsDao dao;
|
||||
|
||||
@Inject
|
||||
public IEntityCapsRepository(EntityCapsDao dao) {
|
||||
this.dao = dao;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RoomEntityCapsModel newEntityCapsModel(@NonNull String nodeVer) {
|
||||
return new RoomEntityCapsModel(nodeVer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Observable<List<RoomEntityCapsModel>> getAllEntityCaps() {
|
||||
return dao.getAllEntityCaps();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Single<RoomEntityCapsModel> getEntityCapsForNodeVer(String nodeVer) {
|
||||
return dao.getEntityCapsForNodeVer(nodeVer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Single<List<Long>> insertOrReplaceEntityCaps(List<RoomEntityCapsModel> entityCaps) {
|
||||
return dao.insert(entityCaps);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Single<Long> 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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Completable deleteAllEntityCaps() {
|
||||
return dao.deleteAllEntityCaps();
|
||||
}
|
||||
}
|
|
@ -1,84 +0,0 @@
|
|||
package org.mercury_im.messenger.persistence.room.repository;
|
||||
|
||||
import org.jxmpp.jid.EntityBareJid;
|
||||
import org.mercury_im.messenger.persistence.repository.MessageRepository;
|
||||
import org.mercury_im.messenger.persistence.room.dao.MessageDao;
|
||||
import org.mercury_im.messenger.persistence.room.model.RoomMessageModel;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import io.reactivex.Maybe;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.Single;
|
||||
|
||||
public class IMessageRepository implements MessageRepository<RoomMessageModel> {
|
||||
|
||||
private final MessageDao messageDao;
|
||||
|
||||
@Inject
|
||||
public IMessageRepository(MessageDao messageDao) {
|
||||
this.messageDao = messageDao;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RoomMessageModel newMessageModel() {
|
||||
return new RoomMessageModel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Maybe<RoomMessageModel> getMessage(long accountId, long chatId, long messageId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Single<Long> insertMessage(RoomMessageModel message) {
|
||||
return messageDao.insert(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Single<List<Long>> insertMessages(List<RoomMessageModel> messages) {
|
||||
return messageDao.insert(messages);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Observable<RoomMessageModel> getLastMessageFrom(long accountId, EntityBareJid peer) {
|
||||
return messageDao.getLastMessageFrom(accountId, peer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Observable<List<RoomMessageModel>> getAllMessages() {
|
||||
return messageDao.getAllMessages();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Observable<List<RoomMessageModel>> getAllMessagesOf(long accountId) {
|
||||
return messageDao.getAllMessagesOf(accountId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Observable<List<RoomMessageModel>> getAllMessagesFrom(long accountId, EntityBareJid contact) {
|
||||
return messageDao.getAllMessagesFrom(accountId, contact);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Observable<List<RoomMessageModel>> getAllMessagesOfChat(long accountId, EntityBareJid peer) {
|
||||
return messageDao.getAllMessagesInConversation(accountId, peer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Observable<List<RoomMessageModel>> findMessageByQuery(String query) {
|
||||
return messageDao.findMessageByQuery("%" + query + "%");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Observable<List<RoomMessageModel>> findMessageByQuery(long accountId, String query) {
|
||||
return messageDao.findMessageByQuery(accountId, "%" + query + "%");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Observable<List<RoomMessageModel>> findMessageByQuery(long accountId, EntityBareJid peer, String query) {
|
||||
return messageDao.findMessageByQuery(accountId, peer, "%" + query + "%");
|
||||
}
|
||||
}
|
|
@ -1,263 +0,0 @@
|
|||
package org.mercury_im.messenger.persistence.room.repository;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import org.jxmpp.jid.EntityBareJid;
|
||||
import org.mercury_im.messenger.persistence.repository.RosterRepository;
|
||||
import org.mercury_im.messenger.persistence.room.dao.ContactDao;
|
||||
import org.mercury_im.messenger.persistence.room.dao.EntityDao;
|
||||
import org.mercury_im.messenger.persistence.room.dao.RosterInformationDao;
|
||||
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.RoomRosterInformationModel;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import io.reactivex.Completable;
|
||||
import io.reactivex.Maybe;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.Single;
|
||||
|
||||
import static org.mercury_im.messenger.persistence.room.AppDatabase.TAG;
|
||||
|
||||
public class IRosterRepository extends RosterRepository<RoomEntityModel, RoomContactModel, RoomRosterInformationModel> {
|
||||
|
||||
private final EntityDao entityDao;
|
||||
|
||||
@Override
|
||||
public Observable<RoomContactModel> getContact(long accountId, EntityBareJid jid) {
|
||||
return contactDao.getContactByJid(accountId, jid);
|
||||
}
|
||||
|
||||
private final ContactDao contactDao;
|
||||
private final RosterInformationDao rosterInformationDao;
|
||||
|
||||
@Inject
|
||||
public IRosterRepository(EntityDao entityDao, ContactDao contactDao, RosterInformationDao rosterInformationDao) {
|
||||
this.contactDao = contactDao;
|
||||
this.entityDao = entityDao;
|
||||
this.rosterInformationDao = rosterInformationDao;
|
||||
}
|
||||
|
||||
/*
|
||||
RoomContactModel
|
||||
*/
|
||||
|
||||
@Override
|
||||
public RoomContactModel newContactModel() {
|
||||
return new RoomContactModel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Observable<List<RoomContactModel>> getAllContacts() {
|
||||
return contactDao.getAllContacts()
|
||||
.flatMap(list -> {
|
||||
for (RoomContactModel contact : list) {
|
||||
RoomEntityModel entity = getEntityForContact(contact).blockingGet();
|
||||
contact.setEntity(entity);
|
||||
}
|
||||
return Observable.just(list);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Observable<List<RoomContactModel>> getAllContactsOfAccount(long accountId) {
|
||||
return contactDao.getContactsForAccount(accountId)
|
||||
.flatMap(list -> {
|
||||
for (RoomContactModel contact : list) {
|
||||
RoomEntityModel entity = getEntityForContact(contact).blockingGet();
|
||||
contact.setEntity(entity);
|
||||
}
|
||||
return Observable.just(list);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Single<Long> upsertContact(RoomContactModel contact) {
|
||||
|
||||
return Single.fromCallable(() -> {
|
||||
RoomEntityModel existingEntityModel = entityDao
|
||||
.getEntityFor(contact.getEntity().getAccountId(), contact.getEntity().getJid())
|
||||
.blockingGet();
|
||||
if (existingEntityModel == null) {
|
||||
// Insert missing entity
|
||||
existingEntityModel = (RoomEntityModel) contact.getEntity();
|
||||
long entityId = insertEntity(existingEntityModel).blockingGet();
|
||||
existingEntityModel.setId(entityId);
|
||||
contact.setEntity(existingEntityModel);
|
||||
} else {
|
||||
contact.getEntity().setId(existingEntityModel.getId());
|
||||
contact.setEntityId(existingEntityModel.getId());
|
||||
entityDao.update((RoomEntityModel) contact.getEntity())
|
||||
.doOnSubscribe(ignore -> Log.v(TAG, "Updating entity " + contact.getEntity()))
|
||||
.blockingAwait();
|
||||
}
|
||||
|
||||
RoomContactModel existingContactModel = contactDao.getContactForEntityId(existingEntityModel.getId()).blockingGet();
|
||||
if (existingContactModel == null) {
|
||||
// Insert missing contact
|
||||
existingContactModel = contact;
|
||||
return insertContact(existingContactModel).blockingGet();
|
||||
} else {
|
||||
contact.setId(existingContactModel.getId());
|
||||
contactDao.update(contact)
|
||||
.doOnSubscribe(ignore -> Log.v(TAG, "Updating contact " + contact))
|
||||
.doOnComplete(() -> Log.v(TAG, "Update complete"))
|
||||
.blockingAwait();
|
||||
}
|
||||
|
||||
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
|
||||
public Single<RoomEntityModel> getEntityForContact(long contactId) {
|
||||
Single<RoomEntityModel> s = contactDao.getEntityForContactId(contactId);
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Observable<RoomContactModel> getContact(long contactId) {
|
||||
return contactDao.getContact(contactId)
|
||||
.map(contact -> {
|
||||
contact.setEntity(getEntityForContact(contactId).toMaybe().blockingGet());
|
||||
contact.setEntityId(contact.getEntity().getId());
|
||||
return contact;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Maybe<RoomContactModel> maybeGetContact(long id) {
|
||||
return contactDao.maybeGetContact(id)
|
||||
// Set the entity
|
||||
.zipWith(getEntityForContact(id).toMaybe(),
|
||||
(contact, entity) -> {
|
||||
contact.setEntity(entity);
|
||||
contact.setEntityId(entity.getId());
|
||||
return contact;
|
||||
});
|
||||
}
|
||||
|
||||
@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
|
||||
public Maybe<RoomContactModel> getContactForEntity(long entityId) {
|
||||
return contactDao.getContactForEntityId(entityId)
|
||||
// Set the entity
|
||||
.zipWith(getEntity(entityId),
|
||||
(contact, entity) -> {
|
||||
contact.setEntity(entity);
|
||||
contact.setEntityId(entityId);
|
||||
return contact;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Completable deleteContact(long id) {
|
||||
return contactDao.deleteContact(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Completable deleteContact(RoomContactModel contact) {
|
||||
return contactDao.delete(contact);
|
||||
}
|
||||
|
||||
@Override
|
||||
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
|
||||
// entity for the jid first and then delete by using its entityId
|
||||
final Maybe<RoomEntityModel> entity = getEntityForAccountAndJid(accountId, jid.asEntityBareJidOrThrow());
|
||||
return entity.flatMapCompletable(entityModel -> contactDao.deleteContactForEntity(entityModel.getId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Completable deleteAllContacts() {
|
||||
return contactDao.deleteAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Completable deleteAllContactsOfAccount(long accountId) {
|
||||
return contactDao.deleteAllForAccount(accountId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Completable deleteContacts(long[] ids) {
|
||||
return contactDao.deleteContacts(ids);
|
||||
}
|
||||
|
||||
/*
|
||||
RoomRosterInformationModel
|
||||
*/
|
||||
|
||||
@Override
|
||||
public RoomRosterInformationModel newRosterInformationModel() {
|
||||
return new RoomRosterInformationModel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Observable<RoomRosterInformationModel> getRosterInformationForAccount(long accountId) {
|
||||
return rosterInformationDao.getRosterInformation(accountId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Single<Long> updateRosterInformation(RoomRosterInformationModel rosterInformation) {
|
||||
return rosterInformationDao.insertRosterInformation(rosterInformation)
|
||||
.doOnSubscribe(ignore -> Log.v(TAG, "Insert " + rosterInformation));
|
||||
}
|
||||
|
||||
/*
|
||||
RoomEntityModel
|
||||
*/
|
||||
|
||||
@Override
|
||||
public RoomEntityModel newEntityModel() {
|
||||
return new RoomEntityModel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Maybe<RoomEntityModel> getEntity(long id) {
|
||||
return entityDao.getEntity(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Maybe<RoomEntityModel> getEntityForAccountAndJid(long accountId, EntityBareJid jid) {
|
||||
return entityDao.getEntityFor(accountId, jid);
|
||||
}
|
||||
|
||||
public Single<Long> insertEntity(RoomEntityModel entityModel) {
|
||||
return entityDao.insert(entityModel)
|
||||
.map(entityId -> {
|
||||
entityModel.setId(entityId);
|
||||
return entityId;
|
||||
})
|
||||
.doOnSubscribe(ignore -> Log.v(TAG, "Insert " + entityModel))
|
||||
.doAfterSuccess(entityId -> Log.v(TAG, "Assign ID " + entityId + " to " + entityModel));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
package org.mercury_im.messenger.persistence.room.type_converter;
|
||||
|
||||
import androidx.room.TypeConverter;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class DateConverter {
|
||||
|
||||
@TypeConverter
|
||||
public static long toLong(Date date) {
|
||||
return date != null ? date.getTime() : -1;
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
public static Date toDate(long lon) {
|
||||
return lon != -1 ? new Date(lon) : null;
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
package org.mercury_im.messenger.persistence.room.type_converter;
|
||||
|
||||
import androidx.room.TypeConverter;
|
||||
|
||||
import org.mercury_im.messenger.persistence.model.ContactModel;
|
||||
|
||||
public class DirectionConverter {
|
||||
|
||||
@TypeConverter
|
||||
public static String toString(ContactModel.DIRECTION direction) {
|
||||
return direction != null ? direction.toString() : null;
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
public static ContactModel.DIRECTION fromString(String string) {
|
||||
return string != null ? ContactModel.DIRECTION.valueOf(string) : null;
|
||||
}
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
package org.mercury_im.messenger.persistence.room.type_converter;
|
||||
|
||||
import androidx.room.TypeConverter;
|
||||
|
||||
import org.jxmpp.jid.EntityBareJid;
|
||||
import org.jxmpp.jid.impl.JidCreate;
|
||||
import org.jxmpp.stringprep.XmppStringprepException;
|
||||
|
||||
public class EntityBareJidConverter {
|
||||
|
||||
@TypeConverter
|
||||
public static String toString(EntityBareJid jid) {
|
||||
return jid != null ? jid.toString() : null;
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
public static EntityBareJid toEntityBareJid(String string) {
|
||||
try {
|
||||
return string != null ? JidCreate.entityBareFrom(string) : null;
|
||||
} catch (XmppStringprepException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
package org.mercury_im.messenger.persistence.room.type_converter;
|
||||
|
||||
import androidx.room.TypeConverter;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class FileConverter {
|
||||
|
||||
@TypeConverter
|
||||
public static String toString(File file) {
|
||||
if (file == null) {
|
||||
return null;
|
||||
}
|
||||
return file.getAbsolutePath();
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
public static File toFile(String string) {
|
||||
if (string == null) {
|
||||
return null;
|
||||
}
|
||||
return new File(string);
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
<resources>
|
||||
<string name="app_name">RoomDatabase</string>
|
||||
</resources>
|
|
@ -1,17 +0,0 @@
|
|||
package org.mercury_im.messenger.persistence.room;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
public class ExampleUnitTest {
|
||||
@Test
|
||||
public void addition_isCorrect() {
|
||||
assertEquals(4, 2 + 2);
|
||||
}
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
# Abstract Persistence Layer of Mercury
|
||||
|
||||
This Android module defines interfaces for a persistence backend.
|
||||
|
||||
Ideally this module would at some point be a plain java (non-Android) module to allow for
|
||||
non-Android implementations. This is currently being blocked by [LiveData](https://developer.android.com/topic/libraries/architecture/livedata)
|
||||
being an Android library. We could fix this by replacing LiveData with RxJava, but this would
|
||||
require us to manually handle LifeCycles of ViewModels etc. so for now we stick with LiveData.
|
||||
|
||||
## Packages
|
||||
|
||||
### `model` package
|
||||
Contains interfaces that define the structure of data classes.
|
||||
|
||||
### `repository` package
|
||||
Repositories build a user-friendly interface to query and modify data in the backend.
|
||||
|
||||
## Implementations
|
||||
Currently the module is only being implemented by the `persistence-room` Android module.
|
|
@ -1,12 +1,15 @@
|
|||
apply plugin: 'java-library'
|
||||
|
||||
// Add the generated folder to the source directories so that we can work with generated classes
|
||||
// This is apparently necessary for use with requery.
|
||||
sourceSets {
|
||||
main.java.srcDirs += "${buildDir}/generated/sources/annotationProcessor/java/main/"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
api('org.jxmpp:jxmpp-jid') {
|
||||
version {
|
||||
prefer 'latest.release'
|
||||
}
|
||||
}
|
||||
// JXMPP for Jid types. Version comes from smacks version.gradle
|
||||
api("org.jxmpp:jxmpp-jid:$jxmppVersion")
|
||||
|
||||
// RxJava2
|
||||
api "io.reactivex.rxjava2:rxjava:$rxJava2Version"
|
||||
|
@ -15,5 +18,14 @@ dependencies {
|
|||
implementation "com.google.dagger:dagger:$daggerVersion"
|
||||
annotationProcessor "com.google.dagger:dagger-compiler:$daggerVersion"
|
||||
|
||||
// Requery ORM
|
||||
api "io.requery:requery:$requeryVersion"
|
||||
annotationProcessor "io.requery:requery-processor:$requeryVersion"
|
||||
|
||||
// JUnit for testing
|
||||
testImplementation "junit:junit:$junitVersion"
|
||||
implementation project(':thread_utils')
|
||||
}
|
||||
|
||||
sourceCompatibility = "8"
|
||||
targetCompatibility = "8"
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
|
@ -1,27 +0,0 @@
|
|||
package org.mercury_im.messenger.persistence;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ExampleInstrumentedTest {
|
||||
@Test
|
||||
public void useAppContext() {
|
||||
// Context of the app under test.
|
||||
Context appContext = InstrumentationRegistry.getTargetContext();
|
||||
|
||||
assertEquals("org.mercury_im.messenger.persistence.test", appContext.getPackageName());
|
||||
}
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.mercury_im.messenger.persistence" />
|
|
@ -0,0 +1,33 @@
|
|||
package org.mercury_im.messenger.persistence.converter;
|
||||
|
||||
import org.jxmpp.jid.EntityBareJid;
|
||||
import org.jxmpp.jid.impl.JidCreate;
|
||||
|
||||
import io.requery.Converter;
|
||||
|
||||
public class EntityBareJidConverter implements Converter<EntityBareJid, String> {
|
||||
@Override
|
||||
public Class<EntityBareJid> getMappedType() {
|
||||
return EntityBareJid.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<String> getPersistedType() {
|
||||
return String.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getPersistedSize() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String convertToPersisted(EntityBareJid jid) {
|
||||
return jid == null ? null : jid.asUnescapedString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityBareJid convertToMapped(Class<? extends EntityBareJid> aClass, String string) {
|
||||
return string == null ? null : JidCreate.entityBareFromOrThrowUnchecked(string);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package org.mercury_im.messenger.persistence.converter;
|
||||
|
||||
import org.mercury_im.messenger.persistence.enums.SaslCondition;
|
||||
|
||||
import io.requery.Converter;
|
||||
|
||||
public class SaslConditionConverter implements Converter<SaslCondition, String> {
|
||||
@Override
|
||||
public Class<SaslCondition> getMappedType() {
|
||||
return SaslCondition.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<String> getPersistedType() {
|
||||
return String.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getPersistedSize() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String convertToPersisted(SaslCondition value) {
|
||||
return value != null ? value.toString() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SaslCondition convertToMapped(Class<? extends SaslCondition> type, String value) {
|
||||
return value != null ? SaslCondition.valueOf(value) : null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package org.mercury_im.messenger.persistence.converter;
|
||||
|
||||
import org.mercury_im.messenger.persistence.enums.SubscriptionDirection;
|
||||
|
||||
import io.requery.Converter;
|
||||
|
||||
public class SubscriptionDirectionConverter implements Converter<SubscriptionDirection, String> {
|
||||
@Override
|
||||
public Class<SubscriptionDirection> getMappedType() {
|
||||
return SubscriptionDirection.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<String> getPersistedType() {
|
||||
return String.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getPersistedSize() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String convertToPersisted(SubscriptionDirection subscriptionDirection) {
|
||||
return subscriptionDirection == null ? null : subscriptionDirection.name();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubscriptionDirection convertToMapped(Class<? extends SubscriptionDirection> aClass, String string) {
|
||||
return string == null ? null : SubscriptionDirection.valueOf(string);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
package org.mercury_im.messenger.persistence.di;
|
||||
|
||||
import org.mercury_im.messenger.persistence.repository.AccountRepository;
|
||||
import org.mercury_im.messenger.persistence.repository.ChatRepository;
|
||||
import org.mercury_im.messenger.persistence.repository.EntityCapsRepository;
|
||||
import org.mercury_im.messenger.persistence.repository.RosterRepository;
|
||||
import org.mercury_im.messenger.thread_utils.ThreadUtils;
|
||||
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import io.reactivex.Scheduler;
|
||||
import io.requery.Persistable;
|
||||
import io.requery.reactivex.ReactiveEntityStore;
|
||||
|
||||
@Module
|
||||
public class RequeryModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
public static AccountRepository provideAccountRepository(ReactiveEntityStore<Persistable> data,
|
||||
@Named(value = ThreadUtils.SCHEDULER_IO) Scheduler ioScheduler,
|
||||
@Named(value = ThreadUtils.SCHEDULER_UI) Scheduler uiScheduler) {
|
||||
return new AccountRepository(data, ioScheduler, uiScheduler);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
public static ChatRepository provideChatRepository(ReactiveEntityStore<Persistable> data,
|
||||
@Named(value = ThreadUtils.SCHEDULER_IO) Scheduler ioScheduler,
|
||||
@Named(value = ThreadUtils.SCHEDULER_UI) Scheduler uiScheduler) {
|
||||
return new ChatRepository(data, ioScheduler, uiScheduler);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
public static EntityCapsRepository provideCapsRepository(ReactiveEntityStore<Persistable> data,
|
||||
@Named(value = ThreadUtils.SCHEDULER_IO) Scheduler ioScheduler,
|
||||
@Named(value = ThreadUtils.SCHEDULER_UI) Scheduler uiScheduler) {
|
||||
return new EntityCapsRepository(data, ioScheduler, uiScheduler);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
public static RosterRepository provideRosterRepository(ReactiveEntityStore<Persistable> data,
|
||||
@Named(value = ThreadUtils.SCHEDULER_IO) Scheduler ioScheduler,
|
||||
@Named(value = ThreadUtils.SCHEDULER_UI) Scheduler uiScheduler) {
|
||||
return new RosterRepository(data, ioScheduler, uiScheduler);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package org.mercury_im.messenger.persistence.entity;
|
||||
|
||||
import org.jxmpp.jid.EntityBareJid;
|
||||
import org.mercury_im.messenger.persistence.converter.EntityBareJidConverter;
|
||||
|
||||
import io.requery.Column;
|
||||
import io.requery.Convert;
|
||||
import io.requery.Entity;
|
||||
import io.requery.Generated;
|
||||
import io.requery.Key;
|
||||
import io.requery.Persistable;
|
||||
import io.requery.Table;
|
||||
|
||||
@Table(name = "accounts")
|
||||
@Entity
|
||||
public abstract class AbstractAccountModel implements Persistable {
|
||||
|
||||
@Key @Generated
|
||||
long id;
|
||||
|
||||
@Column(nullable = false)
|
||||
@Convert(EntityBareJidConverter.class)
|
||||
EntityBareJid jid;
|
||||
|
||||
@Column(nullable = false)
|
||||
String password;
|
||||
|
||||
boolean enabled;
|
||||
|
||||
String rosterVersion;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Account[" + id + ", " +
|
||||
jid + ", " +
|
||||
(enabled ? "enabled" : "disabled") + "]";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package org.mercury_im.messenger.persistence.entity;
|
||||
|
||||
import io.requery.Entity;
|
||||
import io.requery.ForeignKey;
|
||||
import io.requery.Generated;
|
||||
import io.requery.Key;
|
||||
import io.requery.OneToOne;
|
||||
import io.requery.Persistable;
|
||||
import io.requery.Table;
|
||||
|
||||
@Entity
|
||||
@Table(name = "chats")
|
||||
public abstract class AbstractChatModel implements Persistable {
|
||||
|
||||
@Key @Generated
|
||||
long id;
|
||||
|
||||
@OneToOne
|
||||
@ForeignKey
|
||||
EntityModel peer;
|
||||
|
||||
boolean displayed;
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package org.mercury_im.messenger.persistence.entity;
|
||||
|
||||
import org.mercury_im.messenger.persistence.converter.SubscriptionDirectionConverter;
|
||||
import org.mercury_im.messenger.persistence.enums.SubscriptionDirection;
|
||||
|
||||
import io.requery.Convert;
|
||||
import io.requery.Entity;
|
||||
import io.requery.ForeignKey;
|
||||
import io.requery.Generated;
|
||||
import io.requery.Key;
|
||||
import io.requery.OneToOne;
|
||||
import io.requery.Persistable;
|
||||
import io.requery.Table;
|
||||
|
||||
@Entity
|
||||
@Table(name = "contacts")
|
||||
public abstract class AbstractContactModel implements Persistable {
|
||||
|
||||
@Key @Generated
|
||||
long id;
|
||||
|
||||
@OneToOne
|
||||
@ForeignKey(referencedColumn = "id")
|
||||
EntityModel entity;
|
||||
|
||||
String rostername;
|
||||
|
||||
@Convert(SubscriptionDirectionConverter.class)
|
||||
SubscriptionDirection sub_direction;
|
||||
|
||||
boolean sub_pending;
|
||||
|
||||
boolean sub_approved;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Contact[" + id + ", " +
|
||||
rostername + ", " +
|
||||
entity + ", " +
|
||||
sub_direction + ", " +
|
||||
(sub_pending ? "pending" : "not pending") + ", " +
|
||||
(sub_approved ? "approved" : "not approved") + "]";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package org.mercury_im.messenger.persistence.entity;
|
||||
|
||||
import io.requery.Column;
|
||||
import io.requery.Entity;
|
||||
import io.requery.Key;
|
||||
import io.requery.Persistable;
|
||||
import io.requery.Table;
|
||||
|
||||
@Table(name = "entity_caps")
|
||||
@Entity
|
||||
public abstract class AbstractEntityCapsModel implements Persistable {
|
||||
|
||||
@Key
|
||||
String nodeVer;
|
||||
|
||||
@Column(nullable = false)
|
||||
String xml;
|
||||
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package org.mercury_im.messenger.persistence.entity;
|
||||
|
||||
import org.jxmpp.jid.EntityBareJid;
|
||||
import org.mercury_im.messenger.persistence.converter.EntityBareJidConverter;
|
||||
|
||||
import io.requery.Column;
|
||||
import io.requery.Convert;
|
||||
import io.requery.Entity;
|
||||
import io.requery.Generated;
|
||||
import io.requery.Key;
|
||||
import io.requery.ManyToOne;
|
||||
import io.requery.Persistable;
|
||||
import io.requery.Table;
|
||||
|
||||
@Entity
|
||||
@Table(name = "entities")
|
||||
public abstract class AbstractEntityModel implements Persistable {
|
||||
|
||||
@Key @Generated
|
||||
long id;
|
||||
|
||||
@ManyToOne
|
||||
AccountModel account;
|
||||
|
||||
@Convert(EntityBareJidConverter.class)
|
||||
@Column(nullable = false)
|
||||
EntityBareJid jid;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Entity[" + id + ", " +
|
||||
jid + ", " +
|
||||
account + "]";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package org.mercury_im.messenger.persistence.entity;
|
||||
|
||||
import io.requery.Entity;
|
||||
import io.requery.ForeignKey;
|
||||
import io.requery.Key;
|
||||
import io.requery.OneToOne;
|
||||
import io.requery.Persistable;
|
||||
import io.requery.Table;
|
||||
|
||||
@Entity
|
||||
@Table(name = "last_messages")
|
||||
public abstract class AbstractLastChatMessageRelation implements Persistable {
|
||||
|
||||
@Key
|
||||
@OneToOne
|
||||
@ForeignKey
|
||||
ChatModel chat;
|
||||
|
||||
@OneToOne
|
||||
@ForeignKey
|
||||
MessageModel message;
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package org.mercury_im.messenger.persistence.entity;
|
||||
|
||||
import io.requery.Entity;
|
||||
import io.requery.ForeignKey;
|
||||
import io.requery.Key;
|
||||
import io.requery.OneToOne;
|
||||
import io.requery.Persistable;
|
||||
import io.requery.Table;
|
||||
|
||||
@Entity
|
||||
@Table(name = "last_read_messages")
|
||||
public abstract class AbstractLastReadChatMessageRelation implements Persistable {
|
||||
|
||||
@Key
|
||||
@OneToOne
|
||||
@ForeignKey
|
||||
ChatModel chat;
|
||||
|
||||
@OneToOne
|
||||
@ForeignKey
|
||||
MessageModel message;
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package org.mercury_im.messenger.persistence.entity;
|
||||
|
||||
import org.jxmpp.jid.EntityBareJid;
|
||||
import org.mercury_im.messenger.persistence.converter.EntityBareJidConverter;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import io.requery.Column;
|
||||
import io.requery.Convert;
|
||||
import io.requery.Entity;
|
||||
import io.requery.ForeignKey;
|
||||
import io.requery.Generated;
|
||||
import io.requery.Key;
|
||||
import io.requery.ManyToOne;
|
||||
import io.requery.Persistable;
|
||||
import io.requery.Table;
|
||||
|
||||
@Entity
|
||||
@Table(name = "messages")
|
||||
public abstract class AbstractMessageModel implements Persistable {
|
||||
|
||||
@Key @Generated
|
||||
long id;
|
||||
|
||||
@ForeignKey(referencedColumn = "id")
|
||||
@ManyToOne
|
||||
ChatModel chat;
|
||||
|
||||
String body;
|
||||
|
||||
@Column(name = "\"timestamp\"", nullable = false)
|
||||
Date timestamp;
|
||||
|
||||
@Convert(EntityBareJidConverter.class)
|
||||
@Column(nullable = false)
|
||||
EntityBareJid sender;
|
||||
|
||||
@Convert(EntityBareJidConverter.class)
|
||||
@Column(nullable = false)
|
||||
EntityBareJid recipient;
|
||||
|
||||
boolean incoming;
|
||||
|
||||
String thread;
|
||||
|
||||
@Column(nullable = false)
|
||||
String legacyId;
|
||||
|
||||
String originId;
|
||||
|
||||
String stanzaId;
|
||||
|
||||
@Convert(EntityBareJidConverter.class)
|
||||
EntityBareJid stanzaIdBy;
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package org.mercury_im.messenger.persistence.entity;
|
||||
|
||||
import org.mercury_im.messenger.persistence.enums.SaslCondition;
|
||||
|
||||
import io.requery.Entity;
|
||||
import io.requery.Key;
|
||||
import io.requery.ManyToOne;
|
||||
import io.requery.Persistable;
|
||||
import io.requery.Table;
|
||||
|
||||
@Entity
|
||||
@Table(name = "sasl_auth")
|
||||
public abstract class AbstractSaslAuthenticationResultModel implements Persistable {
|
||||
|
||||
@Key
|
||||
@ManyToOne
|
||||
AccountModel account;
|
||||
|
||||
SaslCondition saslCondition;
|
||||
|
||||
String descriptiveText;
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
package org.mercury_im.messenger.persistence.enums;
|
||||
|
||||
public enum SaslCondition {
|
||||
|
||||
// Success
|
||||
|
||||
/**
|
||||
* The SASL handshake is considered successful.
|
||||
*
|
||||
* @see <a href="https://xmpp.org/rfcs/rfc6120.html#sasl-process-neg-success">rfc6120 $6.4.6: SASL Success</a>
|
||||
*/
|
||||
success,
|
||||
|
||||
// Failure
|
||||
|
||||
/**
|
||||
* The receiving entity acknowledges that the authentication handshake has been aborted by the
|
||||
* initiating entity; sent in reply to the <pre><abort/></pre> element.
|
||||
*
|
||||
* @see <a href="https://xmpp.org/rfcs/rfc6120.html#sasl-errors-aborted">rfc6120 §6.5.1: aborted</a>
|
||||
*/
|
||||
aborted,
|
||||
|
||||
/**
|
||||
* The account of the initiating entity has been temporarily disabled; sent in reply to an
|
||||
* <pre><auth/></pre> element (with or without initial response data) or a
|
||||
* <pre><response/></pre> element.
|
||||
*
|
||||
* @see <a href="https://xmpp.org/rfcs/rfc6120.html#sasl-errors-account-disabled">rfc6120 §6.5.2: account-disabled</a>
|
||||
*/
|
||||
account_disabled,
|
||||
|
||||
/**
|
||||
* The authentication failed because the initiating entity provided credentials that have
|
||||
* expired; sent in reply to a <pre><response/></pre> element or an <pre><auth/></pre> element
|
||||
* with initial response data.
|
||||
*
|
||||
* @see <a href="https://xmpp.org/rfcs/rfc6120.html#sasl-errors-credentials-expired">rfc6120 §6.5.3: credentials-expired</a>
|
||||
*/
|
||||
credentials_expired,
|
||||
|
||||
/**
|
||||
* The mechanism requested by the initiating entity cannot be used unless the confidentiality
|
||||
* and integrity of the underlying stream are protected (typically via TLS);
|
||||
* sent in reply to an <pre><auth/></pre> element (with or without initial response data).
|
||||
*
|
||||
* @see <a href="https://xmpp.org/rfcs/rfc6120.html#sasl-errors-encryption-required">rfc6120 §6.5.4: encryption-required</a>
|
||||
*/
|
||||
encryption_required,
|
||||
|
||||
/**
|
||||
* The data provided by the initiating entity could not be processed because the base 64
|
||||
* encoding is incorrect (e.g., because the encoding does not adhere to the definition in
|
||||
* Section 4 of [BASE64]); sent in reply to a <pre><response/></pre> element or an
|
||||
* <pre><auth/></pre> element with initial response data.
|
||||
*
|
||||
* @see <a href="https://xmpp.org/rfcs/rfc6120.html#sasl-errors-incorrect-encoding">rfc6120 §6.5.5: incorrect-encoding</a>
|
||||
*/
|
||||
incorrect_encoding,
|
||||
|
||||
/**
|
||||
* The authzid provided by the initiating entity is invalid, either because it is incorrectly
|
||||
* formatted or because the initiating entity does not have permissions to authorize that ID;
|
||||
* sent in reply to a <pre><response/></pre> element or an <pre><auth/></pre> element with
|
||||
* initial response data.
|
||||
*
|
||||
* @see <a href="https://xmpp.org/rfcs/rfc6120.html#sasl-errors-invalid-authzid">rfc6120 §6.5.6: invalid-authzid</a>
|
||||
*/
|
||||
invalid_authzid,
|
||||
|
||||
/**
|
||||
* The initiating entity did not specify a mechanism, or requested a mechanism that is not
|
||||
* supported by the receiving entity; sent in reply to an <pre><auth/></pre> element.
|
||||
*
|
||||
* @see <a href="https://xmpp.org/rfcs/rfc6120.html#sasl-errors-invalid-mechanism">rfc6120 §6.5.7: invalid-mechanism</a>
|
||||
*/
|
||||
invalid_mechanism,
|
||||
|
||||
/**
|
||||
* The request is malformed (e.g., the <pre><auth/></pre> element includes initial response
|
||||
* data but the mechanism does not allow that, or the data sent violates the syntax for the
|
||||
* specified SASL mechanism);
|
||||
* sent in reply to an <pre><abort/></pre>, <pre><auth/></pre>, <pre><challenge/></pre>,
|
||||
* or <pre><response/></pre> element.
|
||||
*
|
||||
* @see <a href="https://xmpp.org/rfcs/rfc6120.html#sasl-errors-malformed-request">rfc6120 §6.5.8: malformed-request</a>
|
||||
*/
|
||||
malformed_request,
|
||||
|
||||
/**
|
||||
* The mechanism requested by the initiating entity is weaker than server policy permits for
|
||||
* that initiating entity; sent in reply to an <pre><auth/></pre> element (with or without
|
||||
* initial response data).
|
||||
*
|
||||
* @see <a href="https://xmpp.org/rfcs/rfc6120.html#sasl-errors-mechanism-too-weak">rfc6120 §6.5.9: mechanism-too-weak</a>
|
||||
*/
|
||||
mechanism_too_weak,
|
||||
|
||||
/**
|
||||
* The authentication failed because the initiating entity did not provide proper credentials,
|
||||
* or because some generic authentication failure has occurred but the receiving entity does
|
||||
* not wish to disclose specific information about the cause of the failure;
|
||||
* sent in reply to a <pre><response/></pre> element or an <pre><auth/></pre> element with
|
||||
* initial response data.
|
||||
*
|
||||
* @see <a href="https://xmpp.org/rfcs/rfc6120.html#sasl-errors-not-authorized">rfc6120 §6.5.10: not-authorized</a>
|
||||
*/
|
||||
not_authorized,
|
||||
|
||||
/**
|
||||
* The authentication failed because of a temporary error condition within the receiving entity,
|
||||
* and it is advisable for the initiating entity to try again later;
|
||||
* sent in reply to an <pre><auth/></pre> element or a <pre><response/></pre> element.
|
||||
*
|
||||
* @see <a href="https://xmpp.org/rfcs/rfc6120.html#sasl-errors-temporary-auth-failure">rfc6120 §6.5.11: temporary-auth-failure</a>
|
||||
*/
|
||||
temporary_auth_failure
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package org.mercury_im.messenger.persistence.enums;
|
||||
|
||||
public enum SubscriptionDirection {
|
||||
none,
|
||||
to,
|
||||
from,
|
||||
both,
|
||||
remove
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
package org.mercury_im.messenger.persistence.model;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public abstract class AbstractAccountModel implements AccountModel {
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other == null) return false;
|
||||
if (this == other) return true;
|
||||
if (!(other instanceof AccountModel)) {
|
||||
return false;
|
||||
}
|
||||
AccountModel o = (AccountModel) other;
|
||||
|
||||
return o.getId() == getId() &&
|
||||
Objects.equals(o.getJid(), getJid()) &&
|
||||
Objects.equals(o.getEnabled(), getEnabled()) &&
|
||||
Objects.equals(o.getPassword(), getPassword()) &&
|
||||
Objects.equals(o.getState(), getState());
|
||||
}
|
||||
}
|
|
@ -1,74 +0,0 @@
|
|||
package org.mercury_im.messenger.persistence.model;
|
||||
|
||||
import org.jxmpp.jid.EntityBareJid;
|
||||
|
||||
/**
|
||||
* Interface representing an account database entity.
|
||||
*/
|
||||
public interface AccountModel {
|
||||
|
||||
/**
|
||||
* Primary key.
|
||||
*
|
||||
* @return account id
|
||||
*/
|
||||
long getId();
|
||||
|
||||
/**
|
||||
* Set the primary key.
|
||||
*
|
||||
* @param id account id
|
||||
*/
|
||||
void setId(long id);
|
||||
|
||||
/**
|
||||
* Return the password of the XMPP account.
|
||||
*
|
||||
* @return password
|
||||
*/
|
||||
String getPassword();
|
||||
|
||||
/**
|
||||
* Set the password of the XMPP account.
|
||||
*
|
||||
* @param password password
|
||||
*/
|
||||
void setPassword(String password);
|
||||
|
||||
/**
|
||||
* Return the JID of the XMPP account.
|
||||
*
|
||||
* @return XMPP address
|
||||
*/
|
||||
EntityBareJid getJid();
|
||||
|
||||
/**
|
||||
* Set the JID of the XMPP account.
|
||||
*
|
||||
* @param jid XMPP address
|
||||
*/
|
||||
void setJid(EntityBareJid jid);
|
||||
|
||||
/**
|
||||
* Is the account enabled (should it be online).
|
||||
*
|
||||
* @return account enabled?
|
||||
*/
|
||||
boolean getEnabled();
|
||||
|
||||
/**
|
||||
* Set whether or not the account is enabled and active.
|
||||
*
|
||||
* @param enabled enabled
|
||||
*/
|
||||
void setEnabled(boolean enabled);
|
||||
|
||||
/**
|
||||
* Return the state of the connection.
|
||||
*
|
||||
* @return state
|
||||
*/
|
||||
String getState();
|
||||
|
||||
void setState(String state);
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue