This commit is contained in:
Paul Schaub 2019-06-24 01:41:17 +02:00
parent e7eb6ff9e6
commit a82acb5777
Signed by: vanitasvitae
GPG Key ID: 62BEE9264BF17311
24 changed files with 237 additions and 195 deletions

View File

@ -104,7 +104,4 @@ dependencies {
// circular image viewer for avatars
implementation 'de.hdodenhof:circleimageview:2.2.0'
// Smack Android
implementation "org.igniterealtime.smack:smack-android-extensions:$smackAndroidExtensionsVersion"
}

View File

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.mercury_im.messenger">
<!-- To auto-complete the email text field in the login form with the user's emails -->
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.READ_PROFILE" />
@ -16,18 +15,18 @@
android:label="@string/app_name"
android:roundIcon="@drawable/ic_launcher"
android:supportsRtl="true"
android:theme="@style/AppTheme">
android:theme="@style/AppTheme.Light">
<activity
android:name=".ui.chat.ChatActivity"
android:label="Chat"
android:theme="@style/AppTheme.NoActionBar"/>
android:theme="@style/AppTheme.Light.NoActionBar" />
<activity
android:name=".ui.MainActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar">
android:theme="@style/AppTheme.Light.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

View File

@ -59,6 +59,7 @@ public class RoomPlainMessageHandler implements PlainMessageHandler {
@Override
public void onCarbonCopyReceived(CarbonExtension.Direction direction, Message carbonCopy, Message wrappingMessage) {
Log.d(TAG, "onCarbonReceived:" + carbonCopy.toXML());
MessageModel messageModel = new RoomMessageModel();
messageModel.setAccountId(accountId);
messageModel.setFrom(carbonCopy.getFrom() != null ? carbonCopy.getFrom().asEntityBareJidIfPossible() : null);

View File

@ -3,6 +3,8 @@ package org.mercury_im.messenger.ui.chat;
import android.os.Bundle;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import androidx.lifecycle.LiveData;
@ -29,14 +31,28 @@ import java.util.List;
import javax.inject.Inject;
import butterknife.BindView;
import butterknife.ButterKnife;
public class ChatActivity extends BindingActivity implements ChatInputFragment.OnChatInputActionListener {
public static final String EXTRA_JID = "JID";
public static final String EXTRA_ACCOUNT = "ACCOUNT";
@Inject
AccountRepository accountRepository;
@Inject
MessageRepository messageRepository;
@BindView(R.id.toolbar)
Toolbar toolbar;
@BindView(R.id.recyclerView)
RecyclerView recyclerView;
private ChatViewModel chatViewModel;
private EntityBareJid jid;
private long accountId;
@ -44,11 +60,13 @@ public class ChatActivity extends BindingActivity implements ChatInputFragment.O
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d("Mercury", "onCreate");
setContentView(R.layout.activity_chat);
ButterKnife.bind(this);
setSupportActionBar(toolbar);
MercuryImApplication.getApplication().getAppComponent().inject(this);
RecyclerView recyclerView = findViewById(R.id.recyclerView);
ChatRecyclerViewAdapter adapter = new ChatRecyclerViewAdapter();
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
@ -58,18 +76,19 @@ public class ChatActivity extends BindingActivity implements ChatInputFragment.O
if (savedInstanceState == null) return;
}
String jidString = savedInstanceState.getString("JID");
String jidString = savedInstanceState.getString(EXTRA_JID);
if (jidString != null) {
getSupportActionBar().setTitle(jidString);
jid = JidCreate.entityBareFromOrThrowUnchecked(jidString);
accountId = savedInstanceState.getLong("ACCOUNT");
accountId = savedInstanceState.getLong(EXTRA_ACCOUNT);
LiveData<AccountModel> accountModel = accountRepository.getAccount(accountId);
ChatViewModel viewModel = ViewModelProviders.of(this).get(ChatViewModel.class);
chatViewModel = ViewModelProviders.of(this).get(ChatViewModel.class);
accountModel.observe(this, new Observer<AccountModel>() {
@Override
public void onChanged(AccountModel accountModel) {
viewModel.init(accountModel, jid);
chatViewModel.init(accountModel, jid);
}
});
@ -88,6 +107,13 @@ public class ChatActivity extends BindingActivity implements ChatInputFragment.O
}
}
@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
outState.putString(EXTRA_JID, jid.toString());
outState.putLong(EXTRA_ACCOUNT, accountId);
super.onSaveInstanceState(outState);
}
@Override
public void onButtonMediaClicked() {

View File

@ -1,10 +1,13 @@
package org.mercury_im.messenger.ui.roster;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityOptionsCompat;
import androidx.recyclerview.widget.RecyclerView;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -20,6 +23,7 @@ import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
import de.hdodenhof.circleimageview.CircleImageView;
public class RosterRecyclerViewAdapter
extends RecyclerView.Adapter<RosterRecyclerViewAdapter.RosterItemViewHolder> {
@ -57,18 +61,22 @@ public class RosterRecyclerViewAdapter
private View view;
@BindView(R.id.roster_entry__jid)
TextView jidView;
@BindView(R.id.roster_entry__nickname)
TextView nicknameView;
@BindView(R.id.roster_entry__avatar)
CircleImageView avatarView;
Context context;
public RosterItemViewHolder(Context context, View itemView) {
super(itemView);
this.context = context;
this.view = itemView;
this.jidView = itemView.findViewById(R.id.roster_entry__jid);
this.nicknameView = itemView.findViewById(R.id.roster_entry__nickname);
ButterKnife.bind(this, view);
}
void bind(RoomContactAndEntityModel contactModel) {
@ -80,11 +88,19 @@ public class RosterRecyclerViewAdapter
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(context, ChatActivity.class);
intent.putExtra("JID", jid.toString());
intent.putExtra("ACCOUNT", contactModel.getEntity().getAccountId());
context.startActivity(intent);
// Animation
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
ActivityOptionsCompat options = ActivityOptionsCompat
.makeSceneTransitionAnimation((AppCompatActivity) context, avatarView, "avatar");
context.startActivity(intent, options.toBundle());
} else {
context.startActivity(intent);
}
}
});
}

View File

@ -11,20 +11,19 @@ tools:context=".ui.chat.ChatActivity">
android:id="@+id/appbar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay"
app:layout_constraintTop_toTopOf="parent">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay">
android:background="?attr/colorPrimary">
<de.hdodenhof.circleimageview.CircleImageView
android:layout_width="40dp"
android:layout_height="40dp"
android:src="@drawable/aldrin"/>
android:src="@drawable/aldrin"
android:transitionName="avatar"/>
</androidx.appcompat.widget.Toolbar>

View File

@ -8,15 +8,13 @@
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
android:layout_height="wrap_content">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay" />
android:background="?attr/colorPrimary" />
</com.google.android.material.appbar.AppBarLayout>

View File

@ -25,4 +25,10 @@
android:orderInCategory="130"
android:title="Accounts"
app:showAsAction="never" />
<item
android:id="@+id/action_emoji"
android:orderInCategory="150"
android:title="Emoji"
app:showAsAction="never" />
</menu>

View File

@ -1,42 +1,31 @@
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="android:colorBackground">@color/background</item>
<item name="editTextBackground">@null</item>
<item name="actionBarStyle">@style/AppTheme.AppBarOverlay</item>
<style name="AppTheme" parent="Theme.AppCompat">
</style>
<!-- Theme for Activities that either have their own, or no toolbar at all -->
<style name="AppTheme.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
<!-- Theme for the Toolbar -->
<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.ActionBar">
<item name="android:windowTitleStyle">@style/AppTheme.AppBarOverlay.TitleStyle</item>
</style>
<!-- Theme for menu entry popups of the toolbars menu -->
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat" />
<style name="AppTheme.AppBarOverlay.TitleStyle" parent="Theme.AppCompat.Light">
<item name="android:textColorPrimary">#fff</item>
</style>
<style name="AppTheme.ChatTextField" parent="Theme.AppCompat.NoActionBar">
<style name="AppTheme.Light" parent="Theme.AppCompat.Light">
</style>
<style name="AppTheme.ChatText" parent="AppTheme">
<style name="AppTheme.NoActionBar" parent="Theme.AppCompat.NoActionBar">
</style>
<style name="AppTheme.Light.NoActionBar" parent="Theme.AppCompat.Light.NoActionBar">
</style>
<style name="AppTheme.AppBarOverlay">
</style>
<style name="AppTheme.Light.AppBarOverlay">
</style>
<style name="AppTheme.Message">
</style>

View File

@ -2,33 +2,33 @@
"formatVersion": 1,
"database": {
"version": 1,
"identityHash": "63a5e8d6de4b6d8eb30e820be9ab9a69",
"identityHash": "c54702e8cd69b3410ca84bab6d4d3aa6",
"entities": [
{
"tableName": "contacts",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `accountId` INTEGER NOT NULL, `entityId` INTEGER NOT NULL, `rosterName` TEXT, `nickname` TEXT, PRIMARY KEY(`id`), FOREIGN KEY(`accountId`) REFERENCES `accounts`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`entityId`) REFERENCES `entities`(`id`) ON UPDATE NO ACTION ON DELETE RESTRICT )",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`pk_contact_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `fk_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": "id",
"columnName": "pk_contact_id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "accountId",
"columnName": "accountId",
"columnName": "fk_account_id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "entityId",
"columnName": "entityId",
"columnName": "fk_entity_id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "rosterName",
"columnName": "rosterName",
"columnName": "rostername",
"affinity": "TEXT",
"notNull": false
},
@ -41,43 +41,43 @@
],
"primaryKey": {
"columnNames": [
"id"
"pk_contact_id"
],
"autoGenerate": false
"autoGenerate": true
},
"indices": [
{
"name": "index_contacts_id",
"name": "index_contacts_pk_contact_id",
"unique": false,
"columnNames": [
"id"
"pk_contact_id"
],
"createSql": "CREATE INDEX `index_contacts_id` ON `${TABLE_NAME}` (`id`)"
"createSql": "CREATE INDEX `index_contacts_pk_contact_id` ON `${TABLE_NAME}` (`pk_contact_id`)"
},
{
"name": "index_contacts_accountId",
"name": "index_contacts_fk_account_id",
"unique": false,
"columnNames": [
"accountId"
"fk_account_id"
],
"createSql": "CREATE INDEX `index_contacts_accountId` ON `${TABLE_NAME}` (`accountId`)"
"createSql": "CREATE INDEX `index_contacts_fk_account_id` ON `${TABLE_NAME}` (`fk_account_id`)"
},
{
"name": "index_contacts_entityId",
"name": "index_contacts_fk_entity_id",
"unique": false,
"columnNames": [
"entityId"
"fk_entity_id"
],
"createSql": "CREATE INDEX `index_contacts_entityId` ON `${TABLE_NAME}` (`entityId`)"
"createSql": "CREATE INDEX `index_contacts_fk_entity_id` ON `${TABLE_NAME}` (`fk_entity_id`)"
},
{
"name": "index_contacts_id_entityId",
"name": "index_contacts_pk_contact_id_fk_entity_id",
"unique": true,
"columnNames": [
"id",
"entityId"
"pk_contact_id",
"fk_entity_id"
],
"createSql": "CREATE UNIQUE INDEX `index_contacts_id_entityId` ON `${TABLE_NAME}` (`id`, `entityId`)"
"createSql": "CREATE UNIQUE INDEX `index_contacts_pk_contact_id_fk_entity_id` ON `${TABLE_NAME}` (`pk_contact_id`, `fk_entity_id`)"
}
],
"foreignKeys": [
@ -86,10 +86,10 @@
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"accountId"
"fk_account_id"
],
"referencedColumns": [
"id"
"pk_account_id"
]
},
{
@ -97,21 +97,21 @@
"onDelete": "RESTRICT",
"onUpdate": "NO ACTION",
"columns": [
"entityId"
"fk_entity_id"
],
"referencedColumns": [
"id"
"pk_entity_id"
]
}
]
},
{
"tableName": "accounts",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `jid` TEXT, `password` TEXT, `enabled` INTEGER NOT NULL)",
"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)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"columnName": "pk_account_id",
"affinity": "INTEGER",
"notNull": true
},
@ -136,67 +136,67 @@
],
"primaryKey": {
"columnNames": [
"id"
"pk_account_id"
],
"autoGenerate": true
},
"indices": [
{
"name": "index_accounts_id",
"name": "index_accounts_pk_account_id",
"unique": false,
"columnNames": [
"id"
"pk_account_id"
],
"createSql": "CREATE INDEX `index_accounts_id` ON `${TABLE_NAME}` (`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}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `xmppId` INTEGER NOT NULL, `open` INTEGER NOT NULL, FOREIGN KEY(`xmppId`) REFERENCES `entities`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`pk_chat_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `fk_entity_id` INTEGER NOT NULL, `active` INTEGER NOT NULL, FOREIGN KEY(`fk_entity_id`) REFERENCES `entities`(`pk_entity_id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"columnName": "pk_chat_id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "peerIdentityId",
"columnName": "xmppId",
"fieldPath": "peerEntityId",
"columnName": "fk_entity_id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "isOpened",
"columnName": "open",
"fieldPath": "isActive",
"columnName": "active",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"id"
"pk_chat_id"
],
"autoGenerate": true
},
"indices": [
{
"name": "index_chats_id",
"name": "index_chats_pk_chat_id",
"unique": false,
"columnNames": [
"id"
"pk_chat_id"
],
"createSql": "CREATE INDEX `index_chats_id` ON `${TABLE_NAME}` (`id`)"
"createSql": "CREATE INDEX `index_chats_pk_chat_id` ON `${TABLE_NAME}` (`pk_chat_id`)"
},
{
"name": "index_chats_xmppId",
"name": "index_chats_fk_entity_id",
"unique": false,
"columnNames": [
"xmppId"
"fk_entity_id"
],
"createSql": "CREATE INDEX `index_chats_xmppId` ON `${TABLE_NAME}` (`xmppId`)"
"createSql": "CREATE INDEX `index_chats_fk_entity_id` ON `${TABLE_NAME}` (`fk_entity_id`)"
}
],
"foreignKeys": [
@ -205,27 +205,27 @@
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"xmppId"
"fk_entity_id"
],
"referencedColumns": [
"id"
"pk_entity_id"
]
}
]
},
{
"tableName": "messages",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `accountId` INTEGER NOT NULL, `body` TEXT, `sendDate` INTEGER, `from` TEXT, `to` TEXT, `incoming` INTEGER NOT NULL, FOREIGN KEY(`accountId`) REFERENCES `accounts`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"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": "id",
"columnName": "pk_message_id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "accountId",
"columnName": "accountId",
"columnName": "fk_account_id",
"affinity": "INTEGER",
"notNull": true
},
@ -237,7 +237,7 @@
},
{
"fieldPath": "sendDate",
"columnName": "sendDate",
"columnName": "send_date",
"affinity": "INTEGER",
"notNull": false
},
@ -262,26 +262,26 @@
],
"primaryKey": {
"columnNames": [
"id"
"pk_message_id"
],
"autoGenerate": true
},
"indices": [
{
"name": "index_messages_id",
"name": "index_messages_pk_message_id",
"unique": false,
"columnNames": [
"id"
"pk_message_id"
],
"createSql": "CREATE INDEX `index_messages_id` ON `${TABLE_NAME}` (`id`)"
"createSql": "CREATE INDEX `index_messages_pk_message_id` ON `${TABLE_NAME}` (`pk_message_id`)"
},
{
"name": "index_messages_accountId",
"name": "index_messages_fk_account_id",
"unique": false,
"columnNames": [
"accountId"
"fk_account_id"
],
"createSql": "CREATE INDEX `index_messages_accountId` ON `${TABLE_NAME}` (`accountId`)"
"createSql": "CREATE INDEX `index_messages_fk_account_id` ON `${TABLE_NAME}` (`fk_account_id`)"
}
],
"foreignKeys": [
@ -290,27 +290,27 @@
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"accountId"
"fk_account_id"
],
"referencedColumns": [
"id"
"pk_account_id"
]
}
]
},
{
"tableName": "entities",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `accountId` INTEGER NOT NULL, `jid` TEXT NOT NULL, `avatar` TEXT, PRIMARY KEY(`id`), FOREIGN KEY(`accountId`) REFERENCES `accounts`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"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": "id",
"columnName": "pk_entity_id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "accountId",
"columnName": "accountId",
"columnName": "fk_account_id",
"affinity": "INTEGER",
"notNull": true
},
@ -329,27 +329,27 @@
],
"primaryKey": {
"columnNames": [
"id"
"pk_entity_id"
],
"autoGenerate": false
"autoGenerate": true
},
"indices": [
{
"name": "index_entities_id",
"name": "index_entities_pk_entity_id",
"unique": false,
"columnNames": [
"id"
"pk_entity_id"
],
"createSql": "CREATE INDEX `index_entities_id` ON `${TABLE_NAME}` (`id`)"
"createSql": "CREATE INDEX `index_entities_pk_entity_id` ON `${TABLE_NAME}` (`pk_entity_id`)"
},
{
"name": "index_entities_accountId_jid",
"name": "index_entities_fk_account_id_jid",
"unique": true,
"columnNames": [
"accountId",
"fk_account_id",
"jid"
],
"createSql": "CREATE UNIQUE INDEX `index_entities_accountId_jid` ON `${TABLE_NAME}` (`accountId`, `jid`)"
"createSql": "CREATE UNIQUE INDEX `index_entities_fk_account_id_jid` ON `${TABLE_NAME}` (`fk_account_id`, `jid`)"
}
],
"foreignKeys": [
@ -358,10 +358,10 @@
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"accountId"
"fk_account_id"
],
"referencedColumns": [
"id"
"pk_account_id"
]
}
]
@ -370,7 +370,7 @@
"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, '63a5e8d6de4b6d8eb30e820be9ab9a69')"
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'c54702e8cd69b3410ca84bab6d4d3aa6')"
]
}
}

View File

@ -41,7 +41,7 @@ public interface AccountDao extends BaseDao<RoomAccountModel> {
* @param id id of the account
* @return account or null
*/
@Query("select * from accounts where id = :id")
@Query("select * from accounts where pk_account_id = :id")
LiveData<RoomAccountModel> getAccountById(long id);
@Query("select * from accounts where jid = :jid")

View File

@ -18,15 +18,15 @@ public interface ChatDao extends BaseDao<RoomChatModel> {
@Query("SELECT * FROM chats")
LiveData<List<RoomChatModel>> getAllChats();
@Query("SELECT chats.* FROM chats JOIN entities WHERE accountId = :accountId")
@Query("SELECT chats.* FROM chats JOIN entities WHERE fk_account_id = :accountId")
LiveData<List<RoomChatModel>> getAllChatsOf(long accountId);
@Query("SELECT * FROM chats WHERE xmppId = :identityId")
LiveData<RoomChatModel> getChatWithIdentity(long identityId);
@Query("SELECT * FROM chats WHERE fk_entity_id = :entityId")
LiveData<RoomChatModel> getChatWithIdentity(long entityId);
@Query("SELECT chats.* FROM chats JOIN entities WHERE accountId = :accountId AND jid = :jid")
@Query("SELECT chats.* FROM chats JOIN entities WHERE fk_account_id = :accountId AND jid = :jid")
LiveData<RoomChatModel> getChatWithJid(long accountId, EntityBareJid jid);
@Query("SELECT * FROM chats JOIN contacts WHERE contacts.id = :contactId")
@Query("SELECT * FROM chats JOIN contacts WHERE contacts.pk_contact_id = :contactId")
LiveData<RoomChatModel> getChatWithContact(long contactId);
}

View File

@ -23,8 +23,8 @@ public interface ContactAndEntityDao {
"entities." + RoomEntityModel.KEY_ACCOUNT_ID + " AS " + PREFIX + RoomEntityModel.KEY_ACCOUNT_ID + ", " +
"entities." + RoomEntityModel.KEY_JID + " AS " + PREFIX + RoomEntityModel.KEY_JID + ", " +
"entities." + RoomEntityModel.KEY_AVATAR + " AS " + PREFIX + RoomEntityModel.KEY_AVATAR + " " +
"FROM contacts INNER JOIN entities ON contacts.entityId = entities.id " +
"WHERE entities.accountId = :accountId AND entities.jid = :bareJid")
"FROM contacts INNER JOIN entities ON contacts.fk_entity_id = entities.pk_entity_id " +
"WHERE entities.fk_account_id = :accountId AND entities.jid = :bareJid")
LiveData<RoomContactAndEntityModel> getContactAndEntity(long accountId, EntityBareJid bareJid);
@Query("SELECT contacts.*, " +
@ -32,8 +32,8 @@ public interface ContactAndEntityDao {
"entities." + RoomEntityModel.KEY_ACCOUNT_ID + " AS " + PREFIX + RoomEntityModel.KEY_ACCOUNT_ID + ", " +
"entities." + RoomEntityModel.KEY_JID + " AS " + PREFIX + RoomEntityModel.KEY_JID + ", " +
"entities." + RoomEntityModel.KEY_AVATAR + " AS " + PREFIX + RoomEntityModel.KEY_AVATAR + " " +
"FROM contacts INNER JOIN entities ON contacts.entityId = entities.id " +
"WHERE entities.accountId = :accountId")
"FROM contacts INNER JOIN entities ON contacts.fk_entity_id = entities.pk_entity_id " +
"WHERE entities.fk_account_id = :accountId")
LiveData<List<RoomContactAndEntityModel>> getAllContactAndEntities(long accountId);
@Query("SELECT contacts.*, " +
@ -41,6 +41,6 @@ public interface ContactAndEntityDao {
"entities." + RoomEntityModel.KEY_ACCOUNT_ID + " AS " + PREFIX + RoomEntityModel.KEY_ACCOUNT_ID + ", " +
"entities." + RoomEntityModel.KEY_JID + " AS " + PREFIX + RoomEntityModel.KEY_JID + ", " +
"entities." + RoomEntityModel.KEY_AVATAR + " AS " + PREFIX + RoomEntityModel.KEY_AVATAR + " " +
"FROM contacts INNER JOIN entities ON contacts.entityId = entities.id")
"FROM contacts INNER JOIN entities ON contacts.fk_entity_id = entities.pk_entity_id")
LiveData<List<RoomContactAndEntityModel>> getAllContactAndEntities();
}

View File

@ -23,16 +23,16 @@ public interface ContactDao extends BaseDao<RoomContactModel> {
@Insert(onConflict = REPLACE)
long insert(RoomContactModel entity);
@Query("SELECT * FROM contacts WHERE id = :id")
@Query("SELECT * FROM contacts WHERE pk_contact_id = :id")
LiveData<RoomContactModel> getContact(long id);
@Query("SELECT * FROM contacts WHERE id = :id")
@Query("SELECT * FROM contacts WHERE pk_contact_id = :id")
RoomContactModel syncGetContact(long id);
@Query("SELECT * FROM contacts WHERE entityId = :entityId")
@Query("SELECT * FROM contacts WHERE fk_entity_id = :entityId")
LiveData<RoomContactModel> getContactForEntityId(long entityId);
@Query("SELECT * FROM contacts WHERE entityId = :entityId")
@Query("SELECT * FROM contacts WHERE fk_entity_id = :entityId")
RoomContactModel syncGetContactForEntityId(long entityId);
/**
@ -44,9 +44,9 @@ public interface ContactDao extends BaseDao<RoomContactModel> {
@Query("SELECT * FROM contacts")
LiveData<List<RoomContactModel>> getAllContacts();
@Query("SELECT contacts.* FROM contacts JOIN entities WHERE contacts.accountId = :accountId AND jid = :jid")
@Query("SELECT contacts.* FROM contacts JOIN entities WHERE contacts.fk_account_id = :accountId AND jid = :jid")
RoomContactModel getContactByJid(long accountId, EntityBareJid jid);
@Query("SELECT * FROM contacts WHERE accountId = :accountId")
@Query("SELECT * FROM contacts WHERE fk_account_id = :accountId")
LiveData<List<RoomContactModel>> getContactsForAccount(long accountId);
}

View File

@ -20,16 +20,16 @@ public interface EntityDao extends BaseDao<RoomEntityModel> {
@Insert(onConflict = REPLACE)
long insert(RoomEntityModel entity);
@Query("SELECT * FROM entities WHERE id = :id")
@Query("SELECT * FROM entities WHERE pk_entity_id = :id")
LiveData<RoomEntityModel> getEntity(long id);
@Query("SELECT * FROM entities WHERE id = :id")
@Query("SELECT * FROM entities WHERE pk_entity_id = :id")
RoomEntityModel getEntitySync(long id);
@Query("SELECT * FROM entities WHERE accountId = :accountId AND jid = :jid")
@Query("SELECT * FROM entities WHERE fk_account_id = :accountId AND jid = :jid")
LiveData<RoomEntityModel> getEntityFor(long accountId, EntityBareJid jid);
@Query("SELECT * FROM entities WHERE accountId = :accountId AND jid = :jid")
@Query("SELECT * FROM entities WHERE fk_account_id = :accountId AND jid = :jid")
RoomEntityModel getEntityForSync(long accountId, EntityBareJid jid);
}

View File

@ -17,13 +17,13 @@ import java.util.List;
@TypeConverters(EntityBareJidConverter.class)
public interface MessageDao extends BaseDao<RoomMessageModel> {
@Query("SELECT * FROM messages WHERE accountId=:accountId ORDER BY sendDate ASC")
@Query("SELECT * FROM messages WHERE fk_account_id = :accountId ORDER BY send_date ASC")
LiveData<List<RoomMessageModel>> getAllMessagesOf(long accountId);
@Query("SELECT * FROM messages WHERE accountId=:accountId AND `from`=:sender ORDER BY sendDate ASC")
@Query("SELECT * FROM messages WHERE fk_account_id = :accountId AND `from` = :sender ORDER BY send_date ASC")
LiveData<List<RoomMessageModel>> getAllMessagesFrom(long accountId, EntityBareJid sender);
@Query("SELECT * FROM messages WHERE accountId = :accountId AND (`from` = :peer OR `to` = :peer) ORDER BY sendDate ASC")
@Query("SELECT * FROM messages WHERE fk_account_id = :accountId AND (`from` = :peer OR `to` = :peer) ORDER BY send_date ASC")
LiveData<List<RoomMessageModel>> getAllMessagesInConversation(long accountId, EntityBareJid peer);
}

View File

@ -18,7 +18,7 @@ import static org.mercury_im.messenger.persistence.room.model.RoomAccountModel.T
public class RoomAccountModel implements AccountModel {
public static final String TABLE = "accounts";
public static final String KEY_ID = "id";
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";

View File

@ -7,35 +7,39 @@ import androidx.room.Index;
import androidx.room.PrimaryKey;
import org.mercury_im.messenger.persistence.model.ChatModel;
import org.mercury_im.messenger.persistence.model.EntityModel;
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_XMPPID;
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_XMPPID)},
indices = {
@Index(KEY_ID), @Index(KEY_ENTITY)
},
foreignKeys = {
@ForeignKey(entity = RoomEntityModel.class, parentColumns = "id", childColumns = "xmppId", onDelete = CASCADE)
@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_ID = "id";
public static final String KEY_XMPPID = "xmppId";
public static final String KEY_OPEN = "open";
public static final String KEY_ENTITY = "fk_entity_id";
public static final String KEY_ACTIVE = "active";
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = KEY_ID)
private long id;
@ColumnInfo(name = KEY_XMPPID)
private long peerIdentityId;
@ColumnInfo(name = KEY_ENTITY)
private long peerEntityId;
@ColumnInfo(name = KEY_OPEN)
private boolean isOpened;
@ColumnInfo(name = KEY_ACTIVE)
private boolean isActive;
@Override
public long getId() {
@ -48,22 +52,22 @@ public class RoomChatModel implements ChatModel {
}
@Override
public long getPeerIdentityId() {
return peerIdentityId;
public long getPeerEntityId() {
return peerEntityId;
}
@Override
public void setPeerIdentityId(long id) {
this.peerIdentityId = id;
public void setPeerEntityId(long id) {
this.peerEntityId = id;
}
@Override
public boolean isOpened() {
return isOpened;
public boolean isActive() {
return isActive;
}
@Override
public void setIsOpened(boolean opened) {
this.isOpened = opened;
public void setActive(boolean active) {
this.isActive = active;
}
}

View File

@ -35,13 +35,13 @@ import static org.mercury_im.messenger.persistence.room.model.RoomContactModel.T
public class RoomContactModel implements ContactModel {
public static final String TABLE = "contacts";
public static final String KEY_ID = "id";
public static final String KEY_ACCOUNT_ID = "accountId";
public static final String KEY_ENTITY_ID = "entityId";
public static final String KEY_ROSTER_NAME = "rosterName";
public static final String KEY_ID = "pk_contact_id";
public static final String KEY_ACCOUNT_ID = "fk_account_id";
public static final String KEY_ENTITY_ID = "fk_entity_id";
public static final String KEY_ROSTER_NAME = "rostername";
public static final String KEY_NICKNAME = "nickname";
@PrimaryKey
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = KEY_ID)
private long id;

View File

@ -35,12 +35,12 @@ import static org.mercury_im.messenger.persistence.room.model.RoomEntityModel.TA
public class RoomEntityModel implements EntityModel {
public static final String TABLE = "entities";
public static final String KEY_ID = "id";
public static final String KEY_ACCOUNT_ID = "accountId";
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";
public static final String KEY_AVATAR = "avatar";
@PrimaryKey
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = KEY_ID)
protected long id;

View File

@ -32,10 +32,10 @@ import static org.mercury_im.messenger.persistence.room.model.RoomMessageModel.T
public class RoomMessageModel implements MessageModel {
public static final String TABLE = "messages";
public static final String KEY_ID = "id";
public static final String KEY_ACCOUNT_ID = "accountId";
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 = "sendDate";
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";

View File

@ -6,11 +6,11 @@ public interface ChatModel {
void setId(long id);
long getPeerIdentityId();
long getPeerEntityId();
void setPeerIdentityId(long id);
void setPeerEntityId(long id);
boolean isOpened();
boolean isActive();
void setIsOpened(boolean opened);
void setActive(boolean opened);
}

View File

@ -8,9 +8,9 @@ dependencies {
api "org.igniterealtime.smack:smack-experimental:$smackExperimentalVersion"
api "org.igniterealtime.smack:smack-extensions:$smackExtensionsVersion"
api "org.igniterealtime.smack:smack-im:$smackImVersion"
api "org.igniterealtime.smack:smack-omemo:$smackOmemoVersion"
api "org.igniterealtime.smack:smack-omemo-signal:$smackOmemoSignalVersion"
api "org.igniterealtime.smack:smack-openpgp:$smackOpenpgpVersion"
//api "org.igniterealtime.smack:smack-omemo:$smackOmemoVersion"
//api "org.igniterealtime.smack:smack-omemo-signal:$smackOmemoSignalVersion"
//api "org.igniterealtime.smack:smack-openpgp:$smackOpenpgpVersion"
// api "org.igniterealtime.smack:smack-resolver-minidns:$smackResolverMiniDnsVersion"
api "org.igniterealtime.smack:smack-tcp:$smackTcpVersion"

View File

@ -4,14 +4,16 @@ import org.jivesoftware.smack.ConnectionListener;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.chat2.ChatManager;
import org.jivesoftware.smack.roster.Roster;
import org.jivesoftware.smack.util.ExceptionCallback;
import org.jivesoftware.smackx.carbons.CarbonManager;
import org.whispersystems.libsignal.logging.Log;
import java.util.logging.Logger;
public abstract class MercuryConnection implements ConnectionListener {
public static final String TAG = "Mercury";
private static final Logger LOGGER = Logger.getLogger(MercuryConnection.class.getName());
protected final XMPPConnection connection;
protected final long accountId;
@ -22,6 +24,7 @@ public abstract class MercuryConnection implements ConnectionListener {
public MercuryConnection(XMPPConnection connection, long accountId) {
this.connection = connection;
connection.addConnectionListener(this);
this.accountId = accountId;
this.roster = Roster.getInstanceFor(connection);
@ -64,21 +67,25 @@ public abstract class MercuryConnection implements ConnectionListener {
@Override
public void authenticated(XMPPConnection connection, boolean resumed) {
if (connection == this.connection && !resumed) {
carbonManager.enableCarbonsAsync(exception ->
Log.e("Mercury", "Could not enable carbons for connection " + accountId + ":", exception));
LOGGER.info("Enabling carbons!");
carbonManager.enableCarbonsAsync(exception -> {
LOGGER.severe("Could not enable carbons for connection " + accountId + ": " + exception.getMessage());
exception.printStackTrace();
});
}
getState().updateConnectionState(ConnectionState.CONNECTED);
}
@Override
public void connectionClosed() {
Log.i(TAG, "Connection closed.");
LOGGER.fine("Connection closed.");
getState().updateConnectionState(ConnectionState.DISCONNECTED);
}
@Override
public void connectionClosedOnError(Exception e) {
Log.e(TAG, "Connection closed on error.", e);
LOGGER.severe("Connection closed on error: " + e.getMessage());
e.printStackTrace();
getState().updateConnectionState(ConnectionState.DISCONNECTED);
}
}