diff --git a/app/src/main/java/org/mercury_im/messenger/android/ui/chat/AndroidChatViewModel.java b/app/src/main/java/org/mercury_im/messenger/android/ui/chat/AndroidChatViewModel.java index be7b1d6..f8ea782 100644 --- a/app/src/main/java/org/mercury_im/messenger/android/ui/chat/AndroidChatViewModel.java +++ b/app/src/main/java/org/mercury_im/messenger/android/ui/chat/AndroidChatViewModel.java @@ -35,9 +35,6 @@ import io.reactivex.schedulers.Schedulers; public class AndroidChatViewModel extends ViewModel implements MercuryAndroidViewModel { - private final CompositeDisposable disposable = new CompositeDisposable(); - private static final Logger LOGGER = Logger.getLogger(AndroidChatViewModel.class.getName()); - @Inject ChatViewModel commonViewModel; @@ -57,28 +54,22 @@ public class AndroidChatViewModel extends ViewModel implements MercuryAndroidVie public void init(UUID accountId, EntityBareJid jid) { commonViewModel.init(accountId, jid); - } + addDisposable(commonViewModel.getPeer() + .filter(Optional::isPresent).map(Optional::getItem) + .compose(schedulers.executeUiSafeObservable()) + .subscribe(contact::setValue)); - public void init(DirectChat chat) { - this.chat.setValue(chat); - this.contact.setValue(chat.getPeer()); - this.commonViewModel.init(chat); - - // Subscribe peer - disposable.add(commonViewModel.getContactDisplayName() - .subscribe(name -> contactDisplayName.setValue(name), - error -> LOGGER.log(Level.SEVERE, "Error subscribing display name to peer", error))); - - // Subscribe messages addDisposable(commonViewModel.getMessages() - .subscribe(messageList -> AndroidChatViewModel.this.messages.postValue(messageList), - error -> LOGGER.log(Level.SEVERE, "Error subscribing to messages", error))); - } + .compose(schedulers.executeUiSafeObservable()) + .subscribe(messages::setValue)); - @Override - protected void onCleared() { - super.onCleared(); - disposable.clear(); + addDisposable(commonViewModel.getContactDisplayName() + .compose(schedulers.executeUiSafeObservable()) + .subscribe(contactDisplayName::setValue)); + + addDisposable(commonViewModel.getChat() + .compose(schedulers.executeUiSafeObservable()) + .subscribe(chat::setValue)); } public LiveData> getMessages() { diff --git a/app/src/main/java/org/mercury_im/messenger/android/ui/chatlist/AndroidChatListViewModel.java b/app/src/main/java/org/mercury_im/messenger/android/ui/chatlist/AndroidChatListViewModel.java index afa78e0..b4b468a 100644 --- a/app/src/main/java/org/mercury_im/messenger/android/ui/chatlist/AndroidChatListViewModel.java +++ b/app/src/main/java/org/mercury_im/messenger/android/ui/chatlist/AndroidChatListViewModel.java @@ -52,4 +52,8 @@ public class AndroidChatListViewModel extends AndroidViewModel implements Mercur public ChatListViewModel getCommonViewModel() { return commonViewModel; } + + public void onQueryTextChanged(String query) { + getCommonViewModel().onQueryTextChanged(query); + } } diff --git a/app/src/main/java/org/mercury_im/messenger/android/ui/chatlist/ChatListFragment.java b/app/src/main/java/org/mercury_im/messenger/android/ui/chatlist/ChatListFragment.java index 77ce06f..7a1bac8 100644 --- a/app/src/main/java/org/mercury_im/messenger/android/ui/chatlist/ChatListFragment.java +++ b/app/src/main/java/org/mercury_im/messenger/android/ui/chatlist/ChatListFragment.java @@ -74,6 +74,7 @@ public class ChatListFragment extends Fragment implements SearchView.OnQueryText @Override public boolean onQueryTextChange(String newText) { + viewModel.onQueryTextChanged(newText); return false; } } diff --git a/app/src/main/java/org/mercury_im/messenger/android/ui/roster/contacts/ContactListFragment.java b/app/src/main/java/org/mercury_im/messenger/android/ui/roster/contacts/ContactListFragment.java index 0afccc3..d185c1f 100644 --- a/app/src/main/java/org/mercury_im/messenger/android/ui/roster/contacts/ContactListFragment.java +++ b/app/src/main/java/org/mercury_im/messenger/android/ui/roster/contacts/ContactListFragment.java @@ -7,6 +7,7 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import androidx.annotation.Nullable; import androidx.appcompat.widget.SearchView; import androidx.fragment.app.Fragment; import androidx.lifecycle.ViewModelProvider; @@ -39,6 +40,12 @@ public class ContactListFragment extends Fragment implements SearchView.OnQueryT } + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + viewModel = new ViewModelProvider(this).get(AndroidContactListViewModel.class); + } + @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -57,9 +64,8 @@ public class ContactListFragment extends Fragment implements SearchView.OnQueryT } @Override - public void onAttach(Context context) { - super.onAttach(context); - viewModel = new ViewModelProvider(this).get(AndroidContactListViewModel.class); + public void onResume() { + super.onResume(); observeViewModel(viewModel); } diff --git a/data/src/main/java/org/mercury_im/messenger/data/repository/RxDirectChatRepository.java b/data/src/main/java/org/mercury_im/messenger/data/repository/RxDirectChatRepository.java index 06bd469..e86e954 100644 --- a/data/src/main/java/org/mercury_im/messenger/data/repository/RxDirectChatRepository.java +++ b/data/src/main/java/org/mercury_im/messenger/data/repository/RxDirectChatRepository.java @@ -4,6 +4,7 @@ import org.mercury_im.messenger.core.data.repository.DirectChatRepository; import org.mercury_im.messenger.core.util.Optional; import org.mercury_im.messenger.data.mapping.DirectChatMapping; import org.mercury_im.messenger.data.model.DirectChatModel; +import org.mercury_im.messenger.data.model.PeerModel; import org.mercury_im.messenger.data.repository.dao.DirectChatDao; import org.mercury_im.messenger.entity.chat.DirectChat; import org.mercury_im.messenger.entity.contact.Peer; @@ -124,4 +125,16 @@ public class RxDirectChatRepository return dao.delete(chatId) .ignoreElement(); } + + @Override + public Observable> findChatsByQuery(String query) { + return data().select(DirectChatModel.class) + .join(PeerModel.class) + .on(DirectChatModel.PEER_ID.eq(PeerModel.ID)) + .where(PeerModel.NAME.like("%" + query + "%") + .or(PeerModel.ADDRESS.like("%" + query + "%"))) + .get().observableResult() + .map(ResultDelegate::toList) + .map(this::chatModelsToEntities); + } } diff --git a/domain/src/main/java/org/mercury_im/messenger/core/data/repository/DirectChatRepository.java b/domain/src/main/java/org/mercury_im/messenger/core/data/repository/DirectChatRepository.java index 1057915..9272b2e 100644 --- a/domain/src/main/java/org/mercury_im/messenger/core/data/repository/DirectChatRepository.java +++ b/domain/src/main/java/org/mercury_im/messenger/core/data/repository/DirectChatRepository.java @@ -42,4 +42,5 @@ public interface DirectChatRepository { Completable deleteDirectChat(UUID chatId); + Observable> findChatsByQuery(String query); } diff --git a/domain/src/main/java/org/mercury_im/messenger/core/viewmodel/chat/ChatListViewModel.java b/domain/src/main/java/org/mercury_im/messenger/core/viewmodel/chat/ChatListViewModel.java index 671a044..2ba2bf2 100644 --- a/domain/src/main/java/org/mercury_im/messenger/core/viewmodel/chat/ChatListViewModel.java +++ b/domain/src/main/java/org/mercury_im/messenger/core/viewmodel/chat/ChatListViewModel.java @@ -10,19 +10,32 @@ import java.util.List; import javax.inject.Inject; import io.reactivex.Observable; +import io.reactivex.subjects.BehaviorSubject; public class ChatListViewModel implements MercuryViewModel { private final SchedulersFacade schedulers; private final DirectChatRepository directChatRepository; + private final BehaviorSubject>> chatSourceObservable; + @Inject public ChatListViewModel(DirectChatRepository directChatRepository, SchedulersFacade schedulers) { this.directChatRepository = directChatRepository; this.schedulers = schedulers; + + chatSourceObservable = BehaviorSubject.createDefault(directChatRepository.observeAllDirectChats()); } public Observable> observeAllDirectChats() { - return directChatRepository.observeAllDirectChats(); + return Observable.switchOnNext(chatSourceObservable); + } + + public void onQueryTextChanged(String query) { + if (query.trim().isEmpty()) { + chatSourceObservable.onNext(directChatRepository.observeAllDirectChats()); + } else { + chatSourceObservable.onNext(directChatRepository.findChatsByQuery(query)); + } } } diff --git a/domain/src/main/java/org/mercury_im/messenger/core/viewmodel/chat/ChatViewModel.java b/domain/src/main/java/org/mercury_im/messenger/core/viewmodel/chat/ChatViewModel.java index 2639eef..0eaee8d 100644 --- a/domain/src/main/java/org/mercury_im/messenger/core/viewmodel/chat/ChatViewModel.java +++ b/domain/src/main/java/org/mercury_im/messenger/core/viewmodel/chat/ChatViewModel.java @@ -19,6 +19,7 @@ import java.util.logging.Level; import java.util.logging.Logger; import io.reactivex.Observable; +import io.reactivex.Single; import io.reactivex.subjects.BehaviorSubject; import lombok.Getter; @@ -31,10 +32,14 @@ public class ChatViewModel implements MercuryViewModel { private final DirectChatRepository directChatRepository; private final MessageRepository messageRepository; private final SchedulersFacade schedulers; - private DirectChat chat; @Getter - private BehaviorSubject> peer = BehaviorSubject.createDefault(new Optional<>()); + private BehaviorSubject> peer = BehaviorSubject.create(); + + Single directChat; + + @Getter + private BehaviorSubject chat = BehaviorSubject.create(); @Getter private Observable> messages; @@ -58,28 +63,24 @@ public class ChatViewModel implements MercuryViewModel { } public void init(UUID accountId, EntityBareJid contactJid) { - addDisposable(contactRepository.getOrCreatePeer(accountId, contactJid) - .flatMap(directChatRepository::getOrCreateChatWithPeer) - .subscribe(this::init, - e -> LOGGER.log(Level.SEVERE, "Error subscribing to peer data", e))); - } + Single peerSingle = contactRepository.getOrCreatePeer(accountId, contactJid); + peerSingle.flatMapObservable(contactRepository::observePeer).subscribe(peer); + directChat = peerSingle.flatMap(directChatRepository::getOrCreateChatWithPeer); - public void init(DirectChat directChat) { - this.chat = directChat; + directChat.toObservable().compose(schedulers.executeUiSafeObservable()).subscribe(chat); - messageQueryObservable.onNext(messageRepository.observeMessages(chat)); + Observable> allMessagesObservable = directChat.flatMapObservable(messageRepository::observeMessages); + messageQueryObservable.onNext(allMessagesObservable); messages = Observable.switchOnNext(messageQueryObservable); - - contactRepository.observePeer(chat.getPeer().getId()).subscribe(peer); - - contactDisplayName = peer.map(optional -> optional.isPresent() ? optional.getItem().getDisplayName() : "DELETED"); + contactDisplayName = peer.filter(Optional::isPresent).map(Optional::getItem) + .map(Peer::getDisplayName); } public void onQueryTextChanged(String query) { if (query.trim().isEmpty()) { - messageQueryObservable.onNext(messageRepository.observeMessages(chat)); + messageQueryObservable.onNext(directChat.flatMapObservable(messageRepository::observeMessages)); } else { - messageQueryObservable.onNext(messageRepository.findMessagesWithBody(chat, query)); + messageQueryObservable.onNext(directChat.flatMapObservable(c -> messageRepository.findMessagesWithBody(c, query))); } } @@ -95,7 +96,7 @@ public class ChatViewModel implements MercuryViewModel { } public void sendMessage(String body) { - addDisposable(messenger.sendEncryptedMessage(getPeer().getValue().getItem(), body) + addDisposable(messenger.sendEncryptedMessage(peer.getValue().getItem(), body) .compose(schedulers.executeUiSafeCompletable()) .subscribe(() -> LOGGER.log(Level.INFO, "Successfully sent encrypted message."), e -> LOGGER.log(Level.SEVERE, "Error sending encrypted message.", e)));