Sending and receiving works!

This commit is contained in:
Paul Schaub 2019-06-21 03:45:33 +02:00
parent 9477059b0b
commit 8ceeef70b0
Signed by: vanitasvitae
GPG Key ID: 62BEE9264BF17311
23 changed files with 491 additions and 35 deletions

View File

@ -4,9 +4,10 @@ import org.mercury_im.messenger.MercuryImApplication;
import org.mercury_im.messenger.di.module.AppModule;
import org.mercury_im.messenger.di.module.RepositoryModule;
import org.mercury_im.messenger.di.module.RoomModule;
import org.mercury_im.messenger.handler.RoomPlainMessageHandler;
import org.mercury_im.messenger.service.XmppConnectionService;
import org.mercury_im.messenger.ui.MainActivity;
import org.mercury_im.messenger.ui.RoomRosterHandler;
import org.mercury_im.messenger.handler.RoomRosterHandler;
import org.mercury_im.messenger.ui.chat.ChatActivity;
import org.mercury_im.messenger.ui.chat.ChatInputFragment;
import org.mercury_im.messenger.ui.chat.ChatInputViewModel;
@ -64,4 +65,6 @@ public interface AppComponent {
// Connectors
void inject(RoomRosterHandler roomRosterHandler);
void inject(RoomPlainMessageHandler messageHandler);
}

View File

@ -2,16 +2,19 @@ package org.mercury_im.messenger.di.module;
import org.mercury_im.messenger.persistence.repository.AccountRepository;
import org.mercury_im.messenger.persistence.repository.ChatRepository;
import org.mercury_im.messenger.persistence.repository.ContactAndEntityRepository;
import org.mercury_im.messenger.persistence.repository.ContactRepository;
import org.mercury_im.messenger.persistence.repository.EntityRepository;
import org.mercury_im.messenger.persistence.repository.MessageRepository;
import org.mercury_im.messenger.persistence.room.dao.AccountDao;
import org.mercury_im.messenger.persistence.room.dao.ChatDao;
import org.mercury_im.messenger.persistence.room.dao.ContactAndEntityDao;
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.MessageDao;
import org.mercury_im.messenger.persistence.room.repository.IAccountRepository;
import org.mercury_im.messenger.persistence.room.repository.IChatRepository;
import org.mercury_im.messenger.persistence.room.repository.IContactAndEntityRepository;
import org.mercury_im.messenger.persistence.room.repository.IContactRepository;
import org.mercury_im.messenger.persistence.room.repository.IEntityRepository;
import org.mercury_im.messenger.persistence.room.repository.IMessageRepository;
@ -54,4 +57,10 @@ public class RepositoryModule {
return new IMessageRepository(dao);
}
@Singleton
@Provides
ContactAndEntityRepository provideContactAndEntityRepository(ContactAndEntityDao dao) {
return new IContactAndEntityRepository(dao);
}
}

View File

@ -3,6 +3,7 @@ package org.mercury_im.messenger.di.module;
import org.mercury_im.messenger.MercuryImApplication;
import org.mercury_im.messenger.persistence.room.AppDatabase;
import org.mercury_im.messenger.persistence.room.dao.AccountDao;
import org.mercury_im.messenger.persistence.room.dao.ContactAndEntityDao;
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.ContactDao;
@ -56,4 +57,10 @@ public class RoomModule {
EntityDao provideEntityDao() {
return mAppDatabase.entityDao();
}
@Singleton
@Provides
ContactAndEntityDao provideContactAndEntityDao() {
return mAppDatabase.contactAndEntityDao();
}
}

View File

@ -0,0 +1,69 @@
package org.mercury_im.messenger.handler;
import android.util.Log;
import org.jivesoftware.smack.chat2.Chat;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smackx.carbons.packet.CarbonExtension;
import org.jxmpp.jid.EntityBareJid;
import org.mercury_im.messenger.MercuryImApplication;
import org.mercury_im.messenger.persistence.model.MessageModel;
import org.mercury_im.messenger.persistence.repository.MessageRepository;
import org.mercury_im.messenger.persistence.room.model.RoomMessageModel;
import org.mercury_im.messenger.xmpp_core.PlainMessageHandler;
import javax.inject.Inject;
import static org.mercury_im.messenger.MercuryImApplication.TAG;
public class RoomPlainMessageHandler implements PlainMessageHandler {
private final long accountId;
@Inject
MessageRepository messageRepository;
public RoomPlainMessageHandler(long accountId) {
this.accountId = accountId;
MercuryImApplication.getApplication().getAppComponent().inject(this);
}
@Override
public void newIncomingMessage(EntityBareJid from, Message message, Chat chat) {
MessageModel messageModel = new RoomMessageModel();
messageModel.setAccountId(accountId);
messageModel.setFrom(chat.getXmppAddressOfChatPartner());
messageModel.setTo(message.getTo().asEntityBareJidIfPossible());
messageModel.setIncoming(true);
messageModel.setBody(message.getBody());
long messageId = messageRepository.insertMessage(messageModel);
Log.d(TAG, "Inserted incoming message " + messageId);
}
@Override
public void newOutgoingMessage(EntityBareJid to, Message message, Chat chat) {
MessageModel messageModel = new RoomMessageModel();
messageModel.setAccountId(accountId);
messageModel.setFrom(message.getFrom() != null ? message.getFrom().asEntityBareJidIfPossible() : null);
messageModel.setTo(chat.getXmppAddressOfChatPartner());
messageModel.setIncoming(false);
messageModel.setBody(message.getBody());
long messageId = messageRepository.insertMessage(messageModel);
Log.d(TAG, "Inserted outgoing message " + messageId);
}
@Override
public void onCarbonCopyReceived(CarbonExtension.Direction direction, Message carbonCopy, Message wrappingMessage) {
MessageModel messageModel = new RoomMessageModel();
messageModel.setAccountId(accountId);
messageModel.setFrom(carbonCopy.getFrom() != null ? carbonCopy.getFrom().asEntityBareJidIfPossible() : null);
messageModel.setTo(carbonCopy.getTo() != null ? carbonCopy.getTo().asEntityBareJidIfPossible() : null);
messageModel.setIncoming(direction == CarbonExtension.Direction.received);
messageModel.setBody(carbonCopy.getBody());
long messageId = messageRepository.insertMessage(messageModel);
Log.d(TAG, "Inserted carbon message " + messageId);
}
}

View File

@ -1,4 +1,4 @@
package org.mercury_im.messenger.ui;
package org.mercury_im.messenger.handler;
import android.util.Log;

View File

@ -1,16 +1,86 @@
package org.mercury_im.messenger.ui.chat;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.chat2.ChatManager;
import org.jxmpp.jid.EntityBareJid;
import org.jxmpp.jid.impl.JidCreate;
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.model.MessageModel;
import org.mercury_im.messenger.persistence.repository.AccountRepository;
import org.mercury_im.messenger.persistence.repository.MessageRepository;
import org.mercury_im.messenger.ui.BindingActivity;
public class ChatActivity extends AppCompatActivity implements ChatInputFragment.OnChatInputActionListener {
import java.util.List;
import javax.inject.Inject;
public class ChatActivity extends BindingActivity implements ChatInputFragment.OnChatInputActionListener {
@Inject
AccountRepository accountRepository;
@Inject
MessageRepository messageRepository;
private EntityBareJid jid;
private long accountId;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chat);
MercuryImApplication.getApplication().getAppComponent().inject(this);
RecyclerView recyclerView = findViewById(R.id.recyclerView);
ChatRecyclerViewAdapter adapter = new ChatRecyclerViewAdapter();
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
if (savedInstanceState == null) {
savedInstanceState = getIntent().getExtras();
}
String jidString = savedInstanceState.getString("JID");
if (jidString != null) {
jid = JidCreate.entityBareFromOrThrowUnchecked(jidString);
accountId = savedInstanceState.getLong("ACCOUNT");
LiveData<AccountModel> accountModel = accountRepository.getAccount(accountId);
ChatViewModel viewModel = ViewModelProviders.of(this).get(ChatViewModel.class);
accountModel.observe(this, new Observer<AccountModel>() {
@Override
public void onChanged(AccountModel accountModel) {
viewModel.init(accountModel, jid);
}
});
LiveData<List<MessageModel>> messages = messageRepository.getAllMessagesFrom(accountId, jid);
messages.observe(this, new Observer<List<MessageModel>>() {
@Override
public void onChanged(List<MessageModel> messageModels) {
Log.d(MercuryImApplication.TAG, "Updating messages: " + messageModels.size());
adapter.updateMessages(messageModels);
}
});
getSupportFragmentManager().beginTransaction().replace(R.id.fab, ChatInputFragment.newInstance())
.commitAllowingStateLoss();
}
}
@Override
@ -25,6 +95,19 @@ public class ChatActivity extends AppCompatActivity implements ChatInputFragment
@Override
public void onComposingBodySend(String body) {
new Thread() {
@Override
public void run() {
try {
ChatManager.getInstanceFor(connectionService.getConnection(accountId).getConnection())
.chatWith(jid).send(body);
} catch (SmackException.NotConnectedException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
}

View File

@ -7,6 +7,8 @@ import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -17,8 +19,11 @@ import android.widget.Toast;
import org.mercury_im.messenger.R;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import static org.mercury_im.messenger.MercuryImApplication.TAG;
public class ChatInputFragment extends Fragment implements View.OnClickListener {
@BindView(R.id.text_body)
@ -42,7 +47,10 @@ public class ChatInputFragment extends Fragment implements View.OnClickListener
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.content_chat, container, false);
Log.d(TAG, "onCreateView");
View view = inflater.inflate(R.layout.view_chat_field, container, false);
ButterKnife.bind(this, view);
return view;
}
@Override
@ -58,7 +66,7 @@ public class ChatInputFragment extends Fragment implements View.OnClickListener
* @param viewModel ViewModel
*/
private void observeViewModel(ChatInputViewModel viewModel) {
viewModel.getDraft().observe(ChatInputFragment.this, draft -> textInput.setText(draft));
//viewModel.getDraft().observe(ChatInputFragment.this, draft -> textInput.setText(draft));
}
/**
@ -88,6 +96,7 @@ public class ChatInputFragment extends Fragment implements View.OnClickListener
@Override
@OnClick({R.id.btn_send, R.id.btn_media})
public void onClick(View view) {
Log.d(TAG, "onClick!");
switch (view.getId()) {
// Add media
case R.id.btn_media:

View File

@ -0,0 +1,58 @@
package org.mercury_im.messenger.ui.chat;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import org.mercury_im.messenger.R;
import org.mercury_im.messenger.persistence.model.MessageModel;
import java.util.ArrayList;
import java.util.List;
public class ChatRecyclerViewAdapter extends RecyclerView.Adapter<ChatRecyclerViewAdapter.ChatItemViewHolder> {
private List<MessageModel> messages = new ArrayList<>();
public ChatRecyclerViewAdapter() {
}
public void updateMessages(List<MessageModel> messages) {
this.messages.clear();
this.messages.addAll(messages);
notifyDataSetChanged();
}
@NonNull
@Override
public ChatItemViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new ChatItemViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.view_message_text_in, parent, false));
}
@Override
public void onBindViewHolder(@NonNull ChatItemViewHolder holder, int position) {
MessageModel message = messages.get(position);
holder.body.setText(message.getBody());
}
@Override
public int getItemCount() {
return messages.size();
}
public class ChatItemViewHolder extends RecyclerView.ViewHolder {
private TextView body;
public ChatItemViewHolder(@NonNull View itemView) {
super(itemView);
body = itemView.findViewById(R.id.msg_body);
}
}
}

View File

@ -3,10 +3,7 @@ package org.mercury_im.messenger.ui.login;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.ViewModelProviders;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import android.util.Log;
import android.view.KeyEvent;
@ -27,12 +24,12 @@ import org.jxmpp.jid.impl.JidCreate;
import org.jxmpp.stringprep.XmppStringprepException;
import org.mercury_im.messenger.MercuryImApplication;
import org.mercury_im.messenger.R;
import org.mercury_im.messenger.handler.RoomPlainMessageHandler;
import org.mercury_im.messenger.persistence.model.AccountModel;
import org.mercury_im.messenger.persistence.room.model.RoomAccountModel;
import org.mercury_im.messenger.persistence.repository.AccountRepository;
import org.mercury_im.messenger.service.XmppConnectionService;
import org.mercury_im.messenger.ui.BindingActivity;
import org.mercury_im.messenger.ui.RoomRosterHandler;
import org.mercury_im.messenger.handler.RoomRosterHandler;
import org.mercury_im.messenger.xmpp_core.MercuryConnection;
import java.io.IOException;
@ -156,11 +153,12 @@ public class LoginActivity extends BindingActivity implements TextView.OnEditorA
XMPPTCPConnection connection = new XMPPTCPConnection(accountModel.getJid().getLocalpart().asUnescapedString(),
accountModel.getPassword(), accountModel.getJid().getDomain().toString());
MercuryConnection mercuryConnection = new MercuryConnection(connection, accountModel.getId());
connectionService.putConnection(accountModel.getId(), mercuryConnection);
mercuryConnection.setRosterHandler(new RoomRosterHandler(accountModel.getId(), Roster.getInstanceFor(connection)));
mercuryConnection.setPlainMessageHandler(new RoomPlainMessageHandler(accountModel.getId()));
connection.connect().login();
if (bound) {
connectionService.putConnection(accountModel.getId(), mercuryConnection);
}
Log.d(MercuryImApplication.TAG, "Logged in for " + accountModel.getJid().toString());
} catch (XmppStringprepException e) {
e.printStackTrace();
} catch (InterruptedException e) {

View File

@ -2,13 +2,19 @@ package org.mercury_im.messenger.ui.roster;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import android.content.Context;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import org.jxmpp.jid.EntityBareJid;
import org.mercury_im.messenger.R;
import org.mercury_im.messenger.persistence.room.model.RoomContactAndEntityModel;
import org.mercury_im.messenger.persistence.room.model.RoomContactModel;
import org.mercury_im.messenger.ui.chat.ChatActivity;
import java.util.List;
@ -18,22 +24,22 @@ import butterknife.ButterKnife;
public class RosterRecyclerViewAdapter
extends RecyclerView.Adapter<RosterRecyclerViewAdapter.RosterItemViewHolder> {
private List<RoomContactModel> entryModelList;
private List<RoomContactAndEntityModel> entryModelList;
public RosterRecyclerViewAdapter(List<RoomContactModel> entryModelList) {
public RosterRecyclerViewAdapter(List<RoomContactAndEntityModel> entryModelList) {
this.entryModelList = entryModelList;
}
@NonNull
@Override
public RosterItemViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new RosterItemViewHolder(LayoutInflater.from(parent.getContext())
return new RosterItemViewHolder(parent.getContext(), LayoutInflater.from(parent.getContext())
.inflate(R.layout.recycler_view_item_roster_entry, parent, false));
}
@Override
public void onBindViewHolder(@NonNull RosterItemViewHolder holder, int position) {
RoomContactModel model = entryModelList.get(position);
RoomContactAndEntityModel model = entryModelList.get(position);
holder.bind(model);
}
@ -42,7 +48,7 @@ public class RosterRecyclerViewAdapter
return entryModelList.size();
}
public void setItems(List<RoomContactModel> rosterEntryModels) {
public void setItems(List<RoomContactAndEntityModel> rosterEntryModels) {
this.entryModelList = rosterEntryModels;
notifyDataSetChanged();
}
@ -55,18 +61,32 @@ public class RosterRecyclerViewAdapter
TextView nicknameView;
public RosterItemViewHolder(View itemView) {
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);
}
void bind(RoomContactModel contactModel) {
// jidView.setText("" + contactModel.getEntityId());
String nick = contactModel.getNickname();
void bind(RoomContactAndEntityModel contactModel) {
String nick = contactModel.getContact().getNickname();
nicknameView.setText(nick != null ? nick : "");
EntityBareJid jid = contactModel.getEntity().getJid();
jidView.setText(jid.toString());
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);
}
});
}
}
}

View File

@ -6,7 +6,9 @@ import androidx.lifecycle.LiveData;
import androidx.annotation.NonNull;
import org.mercury_im.messenger.MercuryImApplication;
import org.mercury_im.messenger.persistence.repository.ContactAndEntityRepository;
import org.mercury_im.messenger.persistence.repository.ContactRepository;
import org.mercury_im.messenger.persistence.room.model.RoomContactAndEntityModel;
import org.mercury_im.messenger.persistence.room.model.RoomContactModel;
import java.util.List;
@ -16,18 +18,18 @@ import javax.inject.Inject;
public class RosterViewModel extends AndroidViewModel {
@Inject
ContactRepository contactRepository;
ContactAndEntityRepository contactAndEntityRepository;
private final LiveData<List<RoomContactModel>> rosterEntryList;
private final LiveData<List<RoomContactAndEntityModel>> rosterEntryList;
@Inject
public RosterViewModel(@NonNull Application application) {
super(application);
MercuryImApplication.getApplication().getAppComponent().inject(this);
this.rosterEntryList = contactRepository.getAllContacts();
this.rosterEntryList = contactAndEntityRepository.getAllContactAndEntities();
}
public LiveData<List<RoomContactModel>> getRosterEntryList() {
public LiveData<List<RoomContactAndEntityModel>> getRosterEntryList() {
return rosterEntryList;
}
}

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/chat"
@ -16,7 +15,7 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:listitem="@layout/recycler_view_item_1">
tools:listitem="@layout/view_message_text_in">
</androidx.recyclerview.widget.RecyclerView>

View File

@ -3,7 +3,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="wrap_content">
<de.hdodenhof.circleimageview.CircleImageView
android:id="@+id/msg_avatar"

View File

@ -7,6 +7,7 @@ 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.ContactAndEntityDao;
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.ContactDao;
@ -42,4 +43,6 @@ public abstract class AppDatabase extends RoomDatabase {
public abstract AccountDao accountDao();
public abstract EntityDao entityDao();
public abstract ContactAndEntityDao contactAndEntityDao();
}

View File

@ -0,0 +1,46 @@
package org.mercury_im.messenger.persistence.room.dao;
import androidx.lifecycle.LiveData;
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.RoomContactAndEntityModel;
import org.mercury_im.messenger.persistence.room.model.RoomEntityModel;
import org.mercury_im.messenger.persistence.room.type_converter.EntityBareJidConverter;
import java.util.List;
import static org.mercury_im.messenger.persistence.room.model.RoomContactAndEntityModel.PREFIX;
@Dao
@TypeConverters(EntityBareJidConverter.class)
public interface ContactAndEntityDao {
@Query("SELECT contacts.*, " +
"entities." + RoomEntityModel.KEY_ID + " AS " + PREFIX + RoomEntityModel.KEY_ID + ", " +
"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")
LiveData<RoomContactAndEntityModel> getContactAndEntity(long accountId, EntityBareJid bareJid);
@Query("SELECT contacts.*, " +
"entities." + RoomEntityModel.KEY_ID + " AS " + PREFIX + RoomEntityModel.KEY_ID + ", " +
"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")
LiveData<List<RoomContactAndEntityModel>> getAllContactAndEntities(long accountId);
@Query("SELECT contacts.*, " +
"entities." + RoomEntityModel.KEY_ID + " AS " + PREFIX + RoomEntityModel.KEY_ID + ", " +
"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")
LiveData<List<RoomContactAndEntityModel>> getAllContactAndEntities();
}

View File

@ -0,0 +1,34 @@
package org.mercury_im.messenger.persistence.room.model;
import androidx.room.Embedded;
import org.mercury_im.messenger.persistence.model.ContactAndEntityModel;
public class RoomContactAndEntityModel implements ContactAndEntityModel<RoomContactModel, RoomEntityModel> {
public static final String PREFIX = "e_";
@Embedded(prefix = PREFIX)
private RoomEntityModel entity;
@Embedded()
private RoomContactModel contact;
@Override
public RoomContactModel getContact() {
return contact;
}
public void setContact(RoomContactModel contact) {
this.contact = contact;
}
@Override
public RoomEntityModel getEntity() {
return entity;
}
public void setEntity(RoomEntityModel entity) {
this.entity = entity;
}
}

View File

@ -0,0 +1,37 @@
package org.mercury_im.messenger.persistence.room.repository;
import androidx.lifecycle.LiveData;
import org.jxmpp.jid.EntityBareJid;
import org.mercury_im.messenger.persistence.repository.ContactAndEntityRepository;
import org.mercury_im.messenger.persistence.room.dao.ContactAndEntityDao;
import org.mercury_im.messenger.persistence.room.model.RoomContactAndEntityModel;
import java.util.List;
import javax.inject.Inject;
public class IContactAndEntityRepository implements ContactAndEntityRepository<RoomContactAndEntityModel> {
private final ContactAndEntityDao dao;
@Inject
public IContactAndEntityRepository(ContactAndEntityDao dao) {
this.dao = dao;
}
@Override
public LiveData<RoomContactAndEntityModel> getContactAndEntity(long accountId, EntityBareJid jid) {
return dao.getContactAndEntity(accountId, jid);
}
@Override
public LiveData<List<RoomContactAndEntityModel>> getAllContactAndEntities(long accountId) {
return dao.getAllContactAndEntities(accountId);
}
@Override
public LiveData<List<RoomContactAndEntityModel>> getAllContactAndEntities() {
return dao.getAllContactAndEntities();
}
}

View File

@ -8,11 +8,11 @@ public class DateConverter {
@TypeConverter
public static long toLong(Date date) {
return date.getTime();
return date != null ? date.getTime() : -1;
}
@TypeConverter
public static Date toDate(long lon) {
return new Date(lon);
return lon != -1 ? new Date(lon) : null;
}
}

View File

@ -0,0 +1,8 @@
package org.mercury_im.messenger.persistence.model;
public interface ContactAndEntityModel<C extends ContactModel, E extends EntityModel> {
C getContact();
E getEntity();
}

View File

@ -0,0 +1,19 @@
package org.mercury_im.messenger.persistence.repository;
import androidx.lifecycle.LiveData;
import org.jxmpp.jid.EntityBareJid;
import org.mercury_im.messenger.persistence.model.ContactAndEntityModel;
import org.mercury_im.messenger.persistence.model.ContactModel;
import org.mercury_im.messenger.persistence.model.EntityModel;
import java.util.List;
public interface ContactAndEntityRepository<CE extends ContactAndEntityModel<? extends ContactModel, ? extends EntityModel>> {
LiveData<CE> getContactAndEntity(long accountId, EntityBareJid jid);
LiveData<List<CE>> getAllContactAndEntities(long accountId);
LiveData<List<CE>> getAllContactAndEntities();
}

View File

@ -1,19 +1,32 @@
package org.mercury_im.messenger.xmpp_core;
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;
public class MercuryConnection {
public class MercuryConnection implements ConnectionListener {
public static final String TAG = "Mercury";
protected final XMPPConnection connection;
protected final long accountId;
protected final Roster roster;
protected final ChatManager chatManager;
protected final CarbonManager carbonManager;
public MercuryConnection(XMPPConnection connection, long accountId) {
this.connection = connection;
this.accountId = accountId;
this.roster = Roster.getInstanceFor(connection);
this.chatManager = ChatManager.getInstanceFor(connection);
this.carbonManager = CarbonManager.getInstanceFor(connection);
roster.setRosterLoadedAtLogin(true);
}
@ -26,6 +39,12 @@ public class MercuryConnection {
roster.addRosterLoadedListener(handler);
}
public void setPlainMessageHandler(PlainMessageHandler plainMessageHandler) {
carbonManager.addCarbonCopyReceivedListener(plainMessageHandler);
chatManager.addIncomingListener(plainMessageHandler);
chatManager.addOutgoingListener(plainMessageHandler);
}
public long getAccountId() {
return accountId;
}
@ -33,4 +52,27 @@ public class MercuryConnection {
public Roster getRoster() {
return roster;
}
@Override
public void connected(XMPPConnection connection) {
}
@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));
}
}
@Override
public void connectionClosed() {
Log.i(TAG, "Connection closed.");
}
@Override
public void connectionClosedOnError(Exception e) {
Log.e(TAG, "Connection closed on error.", e);
}
}

View File

@ -0,0 +1,9 @@
package org.mercury_im.messenger.xmpp_core;
import org.jivesoftware.smack.chat2.IncomingChatMessageListener;
import org.jivesoftware.smack.chat2.OutgoingChatMessageListener;
import org.jivesoftware.smackx.carbons.CarbonCopyReceivedListener;
public interface PlainMessageHandler extends IncomingChatMessageListener, OutgoingChatMessageListener, CarbonCopyReceivedListener {
}