mirror of
https://codeberg.org/Mercury-IM/Mercury-IM
synced 2024-06-12 22:54:53 +02:00
Experiements
This commit is contained in:
parent
aa75aea180
commit
b9eb37e387
|
@ -18,6 +18,7 @@ import com.google.android.material.navigation.NavigationView;
|
||||||
import org.mercury_im.messenger.MercuryImApplication;
|
import org.mercury_im.messenger.MercuryImApplication;
|
||||||
import org.mercury_im.messenger.R;
|
import org.mercury_im.messenger.R;
|
||||||
import org.mercury_im.messenger.persistence.model.AccountModel;
|
import org.mercury_im.messenger.persistence.model.AccountModel;
|
||||||
|
import org.mercury_im.messenger.persistence.repository.ChatRepository;
|
||||||
import org.mercury_im.messenger.ui.chatlist.ChatListFragment;
|
import org.mercury_im.messenger.ui.chatlist.ChatListFragment;
|
||||||
import org.mercury_im.messenger.ui.login.AccountsActivity;
|
import org.mercury_im.messenger.ui.login.AccountsActivity;
|
||||||
import org.mercury_im.messenger.ui.login.AccountsFragment;
|
import org.mercury_im.messenger.ui.login.AccountsFragment;
|
||||||
|
@ -25,6 +26,8 @@ import org.mercury_im.messenger.ui.login.LoginActivity;
|
||||||
import org.mercury_im.messenger.ui.roster.RosterFragment;
|
import org.mercury_im.messenger.ui.roster.RosterFragment;
|
||||||
import org.mercury_im.messenger.ui.settings.SettingsActivity;
|
import org.mercury_im.messenger.ui.settings.SettingsActivity;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import butterknife.BindView;
|
import butterknife.BindView;
|
||||||
import butterknife.ButterKnife;
|
import butterknife.ButterKnife;
|
||||||
|
|
||||||
|
@ -32,6 +35,9 @@ public class MainActivity extends AppCompatActivity
|
||||||
implements NavigationView.OnNavigationItemSelectedListener,
|
implements NavigationView.OnNavigationItemSelectedListener,
|
||||||
AccountsFragment.OnAccountListItemClickListener {
|
AccountsFragment.OnAccountListItemClickListener {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
ChatRepository chatRepository;
|
||||||
|
|
||||||
@BindView(R.id.toolbar)
|
@BindView(R.id.toolbar)
|
||||||
Toolbar toolbar;
|
Toolbar toolbar;
|
||||||
|
|
||||||
|
|
|
@ -21,12 +21,16 @@ import org.jxmpp.jid.impl.JidCreate;
|
||||||
import org.mercury_im.messenger.MercuryImApplication;
|
import org.mercury_im.messenger.MercuryImApplication;
|
||||||
import org.mercury_im.messenger.R;
|
import org.mercury_im.messenger.R;
|
||||||
import org.mercury_im.messenger.core.centers.ConnectionCenter;
|
import org.mercury_im.messenger.core.centers.ConnectionCenter;
|
||||||
|
import org.mercury_im.messenger.persistence.repository.ChatRepository;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import butterknife.BindView;
|
import butterknife.BindView;
|
||||||
import butterknife.ButterKnife;
|
import butterknife.ButterKnife;
|
||||||
|
import io.reactivex.Scheduler;
|
||||||
|
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||||
import io.reactivex.disposables.CompositeDisposable;
|
import io.reactivex.disposables.CompositeDisposable;
|
||||||
|
import io.reactivex.schedulers.Schedulers;
|
||||||
|
|
||||||
public class ChatActivity extends AppCompatActivity
|
public class ChatActivity extends AppCompatActivity
|
||||||
implements ChatInputFragment.OnChatInputActionListener, SearchView.OnQueryTextListener {
|
implements ChatInputFragment.OnChatInputActionListener, SearchView.OnQueryTextListener {
|
||||||
|
@ -43,6 +47,9 @@ public class ChatActivity extends AppCompatActivity
|
||||||
@BindView(R.id.recyclerView)
|
@BindView(R.id.recyclerView)
|
||||||
RecyclerView recyclerView;
|
RecyclerView recyclerView;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
ChatRepository chatRepository;
|
||||||
|
|
||||||
private final ChatRecyclerViewAdapter recyclerViewAdapter = new ChatRecyclerViewAdapter();
|
private final ChatRecyclerViewAdapter recyclerViewAdapter = new ChatRecyclerViewAdapter();
|
||||||
|
|
||||||
private ChatViewModel chatViewModel;
|
private ChatViewModel chatViewModel;
|
||||||
|
@ -118,6 +125,13 @@ public class ChatActivity extends AppCompatActivity
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
switch (item.getItemId()) {
|
switch (item.getItemId()) {
|
||||||
|
case R.id.action_debug:
|
||||||
|
chatRepository.getOrCreateChatWith(accountId, JidCreate.entityBareFromOrThrowUnchecked("alice@wonderland.lit"))
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe();
|
||||||
|
break;
|
||||||
|
|
||||||
// menu_chat
|
// menu_chat
|
||||||
case R.id.action_call:
|
case R.id.action_call:
|
||||||
case R.id.action_clear_history:
|
case R.id.action_clear_history:
|
||||||
|
|
|
@ -60,7 +60,7 @@ public class ChatListFragment extends Fragment {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Log.d(TAG, "Displaying " + chatModels.size() + " chats");
|
Log.d(TAG, "Displaying " + chatModels.size() + " chats");
|
||||||
recyclerViewAdapter.setItems(chatModels);
|
recyclerViewAdapter.setModels(chatModels);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,69 +1,43 @@
|
||||||
package org.mercury_im.messenger.ui.chatlist;
|
package org.mercury_im.messenger.ui.chatlist;
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
|
||||||
import androidx.core.app.ActivityOptionsCompat;
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import org.jivesoftware.smackx.colors.ConsistentColor;
|
|
||||||
import org.jxmpp.jid.EntityBareJid;
|
|
||||||
import org.mercury_im.messenger.R;
|
import org.mercury_im.messenger.R;
|
||||||
import org.mercury_im.messenger.persistence.model.ChatModel;
|
import org.mercury_im.messenger.persistence.model.ChatModel;
|
||||||
import org.mercury_im.messenger.persistence.room.model.RoomChatModel;
|
import org.mercury_im.messenger.ui.util.AbstractRecyclerViewAdapter;
|
||||||
import org.mercury_im.messenger.persistence.room.model.RoomContactModel;
|
|
||||||
import org.mercury_im.messenger.ui.chat.ChatActivity;
|
|
||||||
import org.mercury_im.messenger.util.ColorUtil;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import butterknife.BindView;
|
import butterknife.BindView;
|
||||||
import butterknife.ButterKnife;
|
import butterknife.ButterKnife;
|
||||||
import de.hdodenhof.circleimageview.CircleImageView;
|
import de.hdodenhof.circleimageview.CircleImageView;
|
||||||
|
|
||||||
public class ChatListRecyclerViewAdapter
|
public class ChatListRecyclerViewAdapter
|
||||||
extends RecyclerView.Adapter<ChatListRecyclerViewAdapter.ChatListItemViewHolder> {
|
extends AbstractRecyclerViewAdapter<ChatModel, ChatListRecyclerViewAdapter.ChatHolder> {
|
||||||
|
|
||||||
private List<ChatModel> chatModelList;
|
|
||||||
|
|
||||||
public ChatListRecyclerViewAdapter() {
|
public ChatListRecyclerViewAdapter() {
|
||||||
this.chatModelList = new ArrayList<>();
|
super(new ChatMessageDiffCallback(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public ChatListItemViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
public ChatHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||||
return new ChatListItemViewHolder(parent.getContext(), LayoutInflater.from(parent.getContext())
|
View view = LayoutInflater.from(parent.getContext())
|
||||||
.inflate(R.layout.recycler_view_item_chat_list, parent, false));
|
.inflate(R.layout.recycler_view_item_chat_list, parent, false);
|
||||||
|
return new ChatHolder(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(@NonNull ChatListItemViewHolder holder, int position) {
|
public void onBindViewHolder(@NonNull ChatHolder holder, int position) {
|
||||||
ChatModel model = chatModelList.get(position);
|
ChatModel model = getModelAt(position);
|
||||||
holder.bind(model);
|
// TODO: Better bindable model pls
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public static class ChatHolder extends RecyclerView.ViewHolder {
|
||||||
public int getItemCount() {
|
|
||||||
return chatModelList.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setItems(List<ChatModel> chatModels) {
|
|
||||||
this.chatModelList = chatModels;
|
|
||||||
notifyDataSetChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ChatListItemViewHolder extends RecyclerView.ViewHolder {
|
|
||||||
|
|
||||||
private View view;
|
|
||||||
|
|
||||||
@BindView(R.id.chat_name)
|
@BindView(R.id.chat_name)
|
||||||
TextView nameView;
|
TextView nameView;
|
||||||
|
@ -77,18 +51,26 @@ public class ChatListRecyclerViewAdapter
|
||||||
@BindView(R.id.chat_avatar)
|
@BindView(R.id.chat_avatar)
|
||||||
CircleImageView avatarView;
|
CircleImageView avatarView;
|
||||||
|
|
||||||
Context context;
|
public ChatHolder(@NonNull View itemView) {
|
||||||
|
|
||||||
public ChatListItemViewHolder(Context context, View itemView) {
|
|
||||||
super(itemView);
|
super(itemView);
|
||||||
this.context = context;
|
ButterKnife.bind(this, itemView);
|
||||||
this.view = itemView;
|
}
|
||||||
ButterKnife.bind(this, view);
|
}
|
||||||
|
|
||||||
|
private static class ChatMessageDiffCallback extends AbstractDiffCallback<ChatModel> {
|
||||||
|
|
||||||
|
public ChatMessageDiffCallback(boolean detectMoves) {
|
||||||
|
super(detectMoves);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bind(ChatModel chatModel) {
|
@Override
|
||||||
String name = chatModel.getPeerEntityId() + "";
|
public boolean areItemsTheSame(ChatModel oldItem, ChatModel newItem) {
|
||||||
nameView.setText(name);
|
return oldItem.getId() == newItem.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean areContentsTheSame(ChatModel oldItem, ChatModel newItem) {
|
||||||
|
return areItemsTheSame(oldItem, newItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,9 @@ import androidx.lifecycle.ViewModel;
|
||||||
|
|
||||||
import org.mercury_im.messenger.MercuryImApplication;
|
import org.mercury_im.messenger.MercuryImApplication;
|
||||||
import org.mercury_im.messenger.persistence.model.ChatModel;
|
import org.mercury_im.messenger.persistence.model.ChatModel;
|
||||||
|
import org.mercury_im.messenger.persistence.model.MessageModel;
|
||||||
import org.mercury_im.messenger.persistence.repository.ChatRepository;
|
import org.mercury_im.messenger.persistence.repository.ChatRepository;
|
||||||
|
import org.mercury_im.messenger.persistence.repository.MessageRepository;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -22,6 +24,9 @@ public class ChatListViewModel extends ViewModel {
|
||||||
@Inject
|
@Inject
|
||||||
ChatRepository chatRepository;
|
ChatRepository chatRepository;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
MessageRepository messageRepository;
|
||||||
|
|
||||||
private CompositeDisposable disposable = new CompositeDisposable();
|
private CompositeDisposable disposable = new CompositeDisposable();
|
||||||
|
|
||||||
private final MutableLiveData<List<ChatModel>> chats = new MutableLiveData<>();
|
private final MutableLiveData<List<ChatModel>> chats = new MutableLiveData<>();
|
||||||
|
@ -32,7 +37,21 @@ public class ChatListViewModel extends ViewModel {
|
||||||
disposable.add(chatRepository.getAllChats()
|
disposable.add(chatRepository.getAllChats()
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe((Consumer<List<ChatModel>>) chats::setValue));
|
.subscribe((Consumer<List<ChatModel>>) chatModels -> {
|
||||||
|
chats.setValue(chatModels);
|
||||||
|
//for (ChatModel chat : chatModels) {
|
||||||
|
// messageRepository.getLastMessageFrom(chat.ge)
|
||||||
|
//}
|
||||||
|
}));
|
||||||
|
|
||||||
|
disposable.add(messageRepository.getAllMessages()
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe((Consumer<List<MessageModel>>) messageModels -> {
|
||||||
|
for (MessageModel message : messageModels) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
public LiveData<List<ChatModel>> getChats() {
|
public LiveData<List<ChatModel>> getChats() {
|
||||||
|
|
|
@ -69,7 +69,6 @@ public class AccountsRecyclerViewAdapter extends RecyclerView.Adapter<AccountsRe
|
||||||
mValues.clear();
|
mValues.clear();
|
||||||
mValues.addAll(values);
|
mValues.addAll(values);
|
||||||
diffResult.dispatchUpdatesTo(this);
|
diffResult.dispatchUpdatesTo(this);
|
||||||
// notifyDataSetChanged(); TODO: Not needed?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -59,7 +59,7 @@ public class RosterFragment extends Fragment {
|
||||||
Log.d(TAG, "Displaying null roster entries");
|
Log.d(TAG, "Displaying null roster entries");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
recyclerViewAdapter.setItems(rosterEntries);
|
recyclerViewAdapter.setModels(rosterEntries);
|
||||||
Log.d(TAG, "Displaying " + rosterEntries.size() + " roster entries");
|
Log.d(TAG, "Displaying " + rosterEntries.size() + " roster entries");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,24 +16,25 @@ import androidx.recyclerview.widget.RecyclerView;
|
||||||
import org.jivesoftware.smackx.colors.ConsistentColor;
|
import org.jivesoftware.smackx.colors.ConsistentColor;
|
||||||
import org.jxmpp.jid.EntityBareJid;
|
import org.jxmpp.jid.EntityBareJid;
|
||||||
import org.mercury_im.messenger.R;
|
import org.mercury_im.messenger.R;
|
||||||
|
import org.mercury_im.messenger.persistence.model.ContactModel;
|
||||||
import org.mercury_im.messenger.persistence.room.model.RoomContactModel;
|
import org.mercury_im.messenger.persistence.room.model.RoomContactModel;
|
||||||
import org.mercury_im.messenger.ui.chat.ChatActivity;
|
import org.mercury_im.messenger.ui.chat.ChatActivity;
|
||||||
|
import org.mercury_im.messenger.ui.util.AbstractRecyclerViewAdapter;
|
||||||
import org.mercury_im.messenger.util.ColorUtil;
|
import org.mercury_im.messenger.util.ColorUtil;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import butterknife.BindView;
|
import butterknife.BindView;
|
||||||
import butterknife.ButterKnife;
|
import butterknife.ButterKnife;
|
||||||
import de.hdodenhof.circleimageview.CircleImageView;
|
import de.hdodenhof.circleimageview.CircleImageView;
|
||||||
|
|
||||||
public class RosterRecyclerViewAdapter
|
public class RosterRecyclerViewAdapter
|
||||||
extends RecyclerView.Adapter<RosterRecyclerViewAdapter.RosterItemViewHolder> {
|
extends AbstractRecyclerViewAdapter<RoomContactModel, RosterRecyclerViewAdapter.RosterItemViewHolder> {
|
||||||
|
|
||||||
private List<RoomContactModel> entryModelList;
|
|
||||||
|
|
||||||
public RosterRecyclerViewAdapter() {
|
public RosterRecyclerViewAdapter() {
|
||||||
this.entryModelList = new ArrayList<>();
|
super(new ContactDiffCallback());
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
|
@ -45,20 +46,10 @@ public class RosterRecyclerViewAdapter
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(@NonNull RosterItemViewHolder holder, int position) {
|
public void onBindViewHolder(@NonNull RosterItemViewHolder holder, int position) {
|
||||||
RoomContactModel model = entryModelList.get(position);
|
RoomContactModel model = getModelAt(position);
|
||||||
holder.bind(model);
|
holder.bind(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getItemCount() {
|
|
||||||
return entryModelList.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setItems(List<RoomContactModel> rosterEntryModels) {
|
|
||||||
this.entryModelList = rosterEntryModels;
|
|
||||||
notifyDataSetChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
public class RosterItemViewHolder extends RecyclerView.ViewHolder {
|
public class RosterItemViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
|
||||||
private View view;
|
private View view;
|
||||||
|
@ -87,24 +78,32 @@ public class RosterRecyclerViewAdapter
|
||||||
EntityBareJid jid = contactModel.getEntity().getJid();
|
EntityBareJid jid = contactModel.getEntity().getJid();
|
||||||
jidView.setText(jid.toString());
|
jidView.setText(jid.toString());
|
||||||
jidView.setTextColor(ColorUtil.consistentColor(jid.toString(), new ConsistentColor.ConsistentColorSettings(ConsistentColor.Deficiency.none)));
|
jidView.setTextColor(ColorUtil.consistentColor(jid.toString(), new ConsistentColor.ConsistentColorSettings(ConsistentColor.Deficiency.none)));
|
||||||
view.setOnClickListener(new View.OnClickListener() {
|
view.setOnClickListener(view -> {
|
||||||
@Override
|
|
||||||
public void onClick(View view) {
|
|
||||||
|
|
||||||
Intent intent = new Intent(context, ChatActivity.class);
|
Intent intent = new Intent(context, ChatActivity.class);
|
||||||
intent.putExtra("JID", jid.toString());
|
intent.putExtra("JID", jid.toString());
|
||||||
intent.putExtra("ACCOUNT", contactModel.getEntity().getAccountId());
|
intent.putExtra("ACCOUNT", contactModel.getEntity().getAccountId());
|
||||||
|
|
||||||
// Animation
|
context.startActivity(intent);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class ContactDiffCallback extends AbstractDiffCallback<RoomContactModel> {
|
||||||
|
|
||||||
|
public ContactDiffCallback() {
|
||||||
|
super(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean areItemsTheSame(RoomContactModel oldItem, RoomContactModel newItem) {
|
||||||
|
return oldItem.getId() == newItem.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean areContentsTheSame(RoomContactModel oldItem, RoomContactModel newItem) {
|
||||||
|
return areItemsTheSame(oldItem, newItem) &&
|
||||||
|
Objects.equals(oldItem.getRosterName(), newItem.getRosterName());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,86 @@
|
||||||
|
package org.mercury_im.messenger.ui.util;
|
||||||
|
|
||||||
|
import androidx.recyclerview.widget.DiffUtil;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public abstract class AbstractRecyclerViewAdapter<M, VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<VH> {
|
||||||
|
|
||||||
|
private final List<M> models = new ArrayList<>();
|
||||||
|
private final AbstractDiffCallback<M> diffCallback;
|
||||||
|
|
||||||
|
public AbstractRecyclerViewAdapter(AbstractDiffCallback<M> diffCallback) {
|
||||||
|
this.diffCallback = diffCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setModels(List<M> newModels) {
|
||||||
|
diffCallback.setData(this.models, newModels);
|
||||||
|
DiffUtil.DiffResult delta = DiffUtil.calculateDiff(diffCallback, diffCallback.detectMoves);
|
||||||
|
this.models.clear();
|
||||||
|
this.models.addAll(newModels);
|
||||||
|
delta.dispatchUpdatesTo(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<M> getModels() {
|
||||||
|
return models;
|
||||||
|
}
|
||||||
|
|
||||||
|
public M getModelAt(int position) {
|
||||||
|
return getModels().get(position);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemCount() {
|
||||||
|
return models.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static abstract class AbstractDiffCallback<I> extends DiffUtil.Callback {
|
||||||
|
|
||||||
|
private List<I> oldData;
|
||||||
|
private List<I> newData;
|
||||||
|
private boolean detectMoves;
|
||||||
|
|
||||||
|
public AbstractDiffCallback(boolean detectMoves) {
|
||||||
|
this.detectMoves = detectMoves;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setData(List<I> oldData, List<I> newData) {
|
||||||
|
this.oldData = oldData;
|
||||||
|
this.newData = newData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public I oldItemAt(int index) {
|
||||||
|
return oldData.get(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
public I newItemAt(int index) {
|
||||||
|
return newData.get(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOldListSize() {
|
||||||
|
return oldData.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNewListSize() {
|
||||||
|
return newData.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
|
||||||
|
return areItemsTheSame(oldItemAt(oldItemPosition), newItemAt(newItemPosition));
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract boolean areItemsTheSame(I oldItem, I newItem);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
|
||||||
|
return areContentsTheSame(oldItemAt(oldItemPosition), newItemAt(newItemPosition));
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract boolean areContentsTheSame(I oldItem, I newItem);
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,7 +5,6 @@
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:menu="@menu/menu_chat"
|
|
||||||
tools:context=".ui.chat.ChatActivity">
|
tools:context=".ui.chat.ChatActivity">
|
||||||
|
|
||||||
<com.google.android.material.appbar.AppBarLayout
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
|
@ -18,15 +17,8 @@
|
||||||
android:id="@+id/toolbar"
|
android:id="@+id/toolbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?attr/actionBarSize"
|
android:layout_height="?attr/actionBarSize"
|
||||||
android:background="?attr/colorPrimary">
|
android:background="?attr/colorPrimary"
|
||||||
|
tools:menu="@menu/menu_chat"/>
|
||||||
<de.hdodenhof.circleimageview.CircleImageView
|
|
||||||
android:layout_width="40dp"
|
|
||||||
android:layout_height="40dp"
|
|
||||||
android:src="@drawable/aldrin"
|
|
||||||
android:transitionName="avatar"/>
|
|
||||||
|
|
||||||
</androidx.appcompat.widget.Toolbar>
|
|
||||||
|
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
|
|
|
@ -14,9 +14,7 @@
|
||||||
android:id="@+id/toolbar"
|
android:id="@+id/toolbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?attr/actionBarSize"
|
android:layout_height="?attr/actionBarSize"
|
||||||
android:background="?attr/colorPrimary">
|
android:background="?attr/colorPrimary" />
|
||||||
|
|
||||||
</androidx.appcompat.widget.Toolbar>
|
|
||||||
|
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
|
@ -27,7 +25,7 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="bottom"
|
android:layout_gravity="bottom"
|
||||||
android:background="@color/colorPrimary"
|
android:background="@color/colorAccent"
|
||||||
app:menu="@menu/bottom_menu_main" />
|
app:menu="@menu/bottom_menu_main" />
|
||||||
|
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
|
@ -31,4 +31,8 @@
|
||||||
android:orderInCategory="400"
|
android:orderInCategory="400"
|
||||||
android:title="@string/action_delete_chat"
|
android:title="@string/action_delete_chat"
|
||||||
app:showAsAction="never" />
|
app:showAsAction="never" />
|
||||||
|
|
||||||
|
<item android:id="@+id/action_debug"
|
||||||
|
android:orderInCategory="1000"
|
||||||
|
android:title="DEBUG" />
|
||||||
</menu>
|
</menu>
|
|
@ -2,7 +2,7 @@
|
||||||
"formatVersion": 1,
|
"formatVersion": 1,
|
||||||
"database": {
|
"database": {
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"identityHash": "fdd5152ff14dba77ae4dba978fc0bb11",
|
"identityHash": "343b0cb91d977d378c17c577a4dc231d",
|
||||||
"entities": [
|
"entities": [
|
||||||
{
|
{
|
||||||
"tableName": "accounts",
|
"tableName": "accounts",
|
||||||
|
@ -59,7 +59,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"tableName": "entities",
|
"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 )",
|
"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": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"fieldPath": "id",
|
"fieldPath": "id",
|
||||||
|
@ -78,12 +78,6 @@
|
||||||
"columnName": "jid",
|
"columnName": "jid",
|
||||||
"affinity": "TEXT",
|
"affinity": "TEXT",
|
||||||
"notNull": true
|
"notNull": true
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "avatarFile",
|
|
||||||
"columnName": "avatar",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"primaryKey": {
|
"primaryKey": {
|
||||||
|
@ -531,7 +525,7 @@
|
||||||
"views": [],
|
"views": [],
|
||||||
"setupQueries": [
|
"setupQueries": [
|
||||||
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
||||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'fdd5152ff14dba77ae4dba978fc0bb11')"
|
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '343b0cb91d977d378c17c577a4dc231d')"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -37,8 +37,8 @@ public class RoomRepositoryModule {
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@Provides
|
@Provides
|
||||||
ChatRepository provideChatRepository(ChatDao dao) {
|
ChatRepository provideChatRepository(ChatDao chatDao, EntityDao entityDao) {
|
||||||
return new IChatRepository(dao);
|
return new IChatRepository(chatDao, entityDao);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
|
|
|
@ -6,6 +6,7 @@ import androidx.room.TypeConverters;
|
||||||
|
|
||||||
import org.jxmpp.jid.EntityBareJid;
|
import org.jxmpp.jid.EntityBareJid;
|
||||||
import org.mercury_im.messenger.persistence.room.model.RoomChatModel;
|
import org.mercury_im.messenger.persistence.room.model.RoomChatModel;
|
||||||
|
import org.mercury_im.messenger.persistence.room.pojo.Chat;
|
||||||
import org.mercury_im.messenger.persistence.room.type_converter.EntityBareJidConverter;
|
import org.mercury_im.messenger.persistence.room.type_converter.EntityBareJidConverter;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -31,4 +32,16 @@ public interface ChatDao extends BaseDao<RoomChatModel> {
|
||||||
|
|
||||||
@Query("SELECT chats.* FROM chats JOIN contacts WHERE contacts.pk_contact_id = :contactId")
|
@Query("SELECT chats.* FROM chats JOIN contacts WHERE contacts.pk_contact_id = :contactId")
|
||||||
Maybe<RoomChatModel> getChatWithContact(long contactId);
|
Maybe<RoomChatModel> getChatWithContact(long contactId);
|
||||||
|
|
||||||
|
@Query("SELECT chats.* FROM chats JOIN entities WHERE fk_account_id = :accountId AND jid = :jid")
|
||||||
|
Observable<RoomChatModel> getObservableChatWithJid(long accountId, EntityBareJid jid);
|
||||||
|
|
||||||
|
@Query("SELECT " +
|
||||||
|
"pk_chat_id as chatId, " +
|
||||||
|
"fk_entity_id as entityId, " +
|
||||||
|
"active, " +
|
||||||
|
"jid " +
|
||||||
|
"FROM chats INNER JOIN entities")
|
||||||
|
Observable<Chat> getChat();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,9 @@ import io.reactivex.Observable;
|
||||||
@TypeConverters(EntityBareJidConverter.class)
|
@TypeConverters(EntityBareJidConverter.class)
|
||||||
public interface MessageDao extends BaseDao<RoomMessageModel> {
|
public interface MessageDao extends BaseDao<RoomMessageModel> {
|
||||||
|
|
||||||
|
@Query("SELECT * FROM messages")
|
||||||
|
Observable<List<RoomMessageModel>> getAllMessages();
|
||||||
|
|
||||||
@Query("SELECT * FROM messages " +
|
@Query("SELECT * FROM messages " +
|
||||||
"WHERE fk_account_id = :accountId " +
|
"WHERE fk_account_id = :accountId " +
|
||||||
"ORDER BY send_date ASC")
|
"ORDER BY send_date ASC")
|
||||||
|
@ -47,4 +50,7 @@ public interface MessageDao extends BaseDao<RoomMessageModel> {
|
||||||
"AND body LIKE :query " +
|
"AND body LIKE :query " +
|
||||||
"COLLATE utf8_general_ci") // case insensitive
|
"COLLATE utf8_general_ci") // case insensitive
|
||||||
Observable<List<RoomMessageModel>> findMessageByQuery(long accountId, EntityBareJid peer, String query);
|
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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,10 +52,6 @@ public class RoomEntityModel implements EntityModel {
|
||||||
@ColumnInfo(name = KEY_JID)
|
@ColumnInfo(name = KEY_JID)
|
||||||
protected EntityBareJid jid;
|
protected EntityBareJid jid;
|
||||||
|
|
||||||
@TypeConverters(FileConverter.class)
|
|
||||||
@ColumnInfo(name = KEY_AVATAR)
|
|
||||||
protected File avatarFile;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getId() {
|
public long getId() {
|
||||||
return id;
|
return id;
|
||||||
|
@ -86,15 +82,4 @@ public class RoomEntityModel implements EntityModel {
|
||||||
public void setAccountId(long accountId) {
|
public void setAccountId(long accountId) {
|
||||||
this.accountId = accountId;
|
this.accountId = accountId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public File getAvatarFile() {
|
|
||||||
return avatarFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setAvatarFile(File file) {
|
|
||||||
this.avatarFile = file;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
package org.mercury_im.messenger.persistence.room.pojo;
|
||||||
|
|
||||||
|
import org.jxmpp.jid.EntityBareJid;
|
||||||
|
|
||||||
|
public class Chat {
|
||||||
|
public long chatId;
|
||||||
|
public long entityId;
|
||||||
|
public EntityBareJid jid;
|
||||||
|
|
||||||
|
}
|
|
@ -1,6 +1,5 @@
|
||||||
package org.mercury_im.messenger.persistence.room.repository;
|
package org.mercury_im.messenger.persistence.room.repository;
|
||||||
|
|
||||||
import org.mercury_im.messenger.persistence.model.AccountModel;
|
|
||||||
import org.mercury_im.messenger.persistence.repository.AccountRepository;
|
import org.mercury_im.messenger.persistence.repository.AccountRepository;
|
||||||
import org.mercury_im.messenger.persistence.room.dao.AccountDao;
|
import org.mercury_im.messenger.persistence.room.dao.AccountDao;
|
||||||
import org.mercury_im.messenger.persistence.room.model.RoomAccountModel;
|
import org.mercury_im.messenger.persistence.room.model.RoomAccountModel;
|
||||||
|
|
|
@ -2,11 +2,14 @@ package org.mercury_im.messenger.persistence.room.repository;
|
||||||
|
|
||||||
import org.jxmpp.jid.EntityBareJid;
|
import org.jxmpp.jid.EntityBareJid;
|
||||||
import org.mercury_im.messenger.persistence.model.AccountModel;
|
import org.mercury_im.messenger.persistence.model.AccountModel;
|
||||||
|
import org.mercury_im.messenger.persistence.model.ChatModel;
|
||||||
import org.mercury_im.messenger.persistence.model.ContactModel;
|
import org.mercury_im.messenger.persistence.model.ContactModel;
|
||||||
import org.mercury_im.messenger.persistence.model.EntityModel;
|
import org.mercury_im.messenger.persistence.model.EntityModel;
|
||||||
import org.mercury_im.messenger.persistence.repository.ChatRepository;
|
import org.mercury_im.messenger.persistence.repository.ChatRepository;
|
||||||
import org.mercury_im.messenger.persistence.room.dao.ChatDao;
|
import org.mercury_im.messenger.persistence.room.dao.ChatDao;
|
||||||
|
import org.mercury_im.messenger.persistence.room.dao.EntityDao;
|
||||||
import org.mercury_im.messenger.persistence.room.model.RoomChatModel;
|
import org.mercury_im.messenger.persistence.room.model.RoomChatModel;
|
||||||
|
import org.mercury_im.messenger.persistence.room.model.RoomEntityModel;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -15,14 +18,21 @@ import javax.inject.Inject;
|
||||||
import io.reactivex.Completable;
|
import io.reactivex.Completable;
|
||||||
import io.reactivex.Maybe;
|
import io.reactivex.Maybe;
|
||||||
import io.reactivex.Observable;
|
import io.reactivex.Observable;
|
||||||
|
import io.reactivex.Scheduler;
|
||||||
|
import io.reactivex.SingleTransformer;
|
||||||
|
import io.reactivex.disposables.Disposable;
|
||||||
|
import io.reactivex.functions.Consumer;
|
||||||
|
import io.reactivex.schedulers.Schedulers;
|
||||||
|
|
||||||
public class IChatRepository implements ChatRepository<RoomChatModel> {
|
public class IChatRepository implements ChatRepository<RoomChatModel> {
|
||||||
|
|
||||||
private final ChatDao chatDao;
|
private final ChatDao chatDao;
|
||||||
|
private final EntityDao entityDao;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public IChatRepository(ChatDao dao) {
|
public IChatRepository(ChatDao chatDao, EntityDao entityDao) {
|
||||||
this.chatDao = dao;
|
this.chatDao = chatDao;
|
||||||
|
this.entityDao = entityDao;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -30,6 +40,11 @@ public class IChatRepository implements ChatRepository<RoomChatModel> {
|
||||||
return new RoomChatModel();
|
return new RoomChatModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Observable<RoomChatModel> getOrCreateChatWith(long accountId, EntityBareJid jid) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Observable<List<RoomChatModel>> getAllChats() {
|
public Observable<List<RoomChatModel>> getAllChats() {
|
||||||
return chatDao.getAllChats();
|
return chatDao.getAllChats();
|
||||||
|
|
|
@ -37,6 +37,16 @@ public class IMessageRepository implements MessageRepository<RoomMessageModel> {
|
||||||
return messageDao.insert(message);
|
return messageDao.insert(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Observable<RoomMessageModel> getLastMessageFrom(long accountId, EntityBareJid peer) {
|
||||||
|
return messageDao.getLastMessageFrom(accountId, peer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Observable<List<RoomMessageModel>> getAllMessages() {
|
||||||
|
return messageDao.getAllMessages();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Observable<List<RoomMessageModel>> getAllMessagesOf(long accountId) {
|
public Observable<List<RoomMessageModel>> getAllMessagesOf(long accountId) {
|
||||||
return messageDao.getAllMessagesOf(accountId);
|
return messageDao.getAllMessagesOf(accountId);
|
||||||
|
|
|
@ -7,8 +7,7 @@ import java.io.File;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An {@link EntityModel} represents an XMPP user as seen by an account.
|
* An {@link EntityModel} represents an XMPP user as seen by an account.
|
||||||
* Its primary key should be composited of its {@link EntityBareJid} and the primary key of the
|
* The pair (account_id, jid) MUST be unique.
|
||||||
* {@link AccountModel} which is communicating with the user.
|
|
||||||
*/
|
*/
|
||||||
public interface EntityModel {
|
public interface EntityModel {
|
||||||
|
|
||||||
|
@ -16,15 +15,12 @@ public interface EntityModel {
|
||||||
|
|
||||||
void setId(long id);
|
void setId(long id);
|
||||||
|
|
||||||
EntityBareJid getJid();
|
|
||||||
|
|
||||||
void setJid(EntityBareJid jid);
|
|
||||||
|
|
||||||
long getAccountId();
|
long getAccountId();
|
||||||
|
|
||||||
void setAccountId(long accountId);
|
void setAccountId(long accountId);
|
||||||
|
|
||||||
File getAvatarFile();
|
EntityBareJid getJid();
|
||||||
|
|
||||||
|
void setJid(EntityBareJid jid);
|
||||||
|
|
||||||
void setAvatarFile(File file);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,8 @@ public interface ChatRepository<E extends ChatModel> {
|
||||||
|
|
||||||
Observable<List<E>> getAllChatsOf(AccountModel account);
|
Observable<List<E>> getAllChatsOf(AccountModel account);
|
||||||
|
|
||||||
|
Observable<E> getOrCreateChatWith(long accountId, EntityBareJid jid);
|
||||||
|
|
||||||
Maybe<E> getChatWith(AccountModel account, EntityBareJid jid);
|
Maybe<E> getChatWith(AccountModel account, EntityBareJid jid);
|
||||||
|
|
||||||
Maybe<E> getChatWith(EntityModel identity);
|
Maybe<E> getChatWith(EntityModel identity);
|
||||||
|
|
|
@ -17,6 +17,8 @@ public interface MessageRepository<E extends MessageModel> {
|
||||||
|
|
||||||
Single<Long> insertMessage(E message);
|
Single<Long> insertMessage(E message);
|
||||||
|
|
||||||
|
Observable<List<E>> getAllMessages();
|
||||||
|
|
||||||
Observable<List<E>> getAllMessagesOf(long accountId);
|
Observable<List<E>> getAllMessagesOf(long accountId);
|
||||||
|
|
||||||
Observable<List<E>> getAllMessagesOfChat(long accountId, EntityBareJid peer);
|
Observable<List<E>> getAllMessagesOfChat(long accountId, EntityBareJid peer);
|
||||||
|
@ -28,4 +30,6 @@ public interface MessageRepository<E extends MessageModel> {
|
||||||
Observable<List<E>> findMessageByQuery(long accountId, String query);
|
Observable<List<E>> findMessageByQuery(long accountId, String query);
|
||||||
|
|
||||||
Observable<List<E>> findMessageByQuery(long accountId, EntityBareJid peer, String query);
|
Observable<List<E>> findMessageByQuery(long accountId, EntityBareJid peer, String query);
|
||||||
|
|
||||||
|
Observable<E> getLastMessageFrom(long accountId, EntityBareJid peer);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue