Wip: Implement local contact search
This commit is contained in:
parent
4e1585a4bb
commit
47ab78ba60
|
@ -4,11 +4,12 @@ import org.mercury_im.messenger.android.MercuryImApplication;
|
|||
import org.mercury_im.messenger.android.di.module.AndroidDatabaseModule;
|
||||
import org.mercury_im.messenger.android.di.module.AndroidSchedulersModule;
|
||||
import org.mercury_im.messenger.android.ui.account.AndroidAccountDetailsViewModel;
|
||||
import org.mercury_im.messenger.android.ui.ox.AndroidOxSecretKeyBackupRestoreViewModel;
|
||||
import org.mercury_im.messenger.android.ui.roster.contacts.AndroidContactListViewModel;
|
||||
import org.mercury_im.messenger.core.di.module.RxMercuryMessageStoreFactoryModule;
|
||||
import org.mercury_im.messenger.core.di.module.RxMercuryRosterStoreFactoryModule;
|
||||
import org.mercury_im.messenger.core.di.module.XmppTcpConnectionFactoryModule;
|
||||
import org.mercury_im.messenger.core.viewmodel.accounts.AccountDetailsViewModel;
|
||||
import org.mercury_im.messenger.core.viewmodel.chat.ChatViewModel;
|
||||
import org.mercury_im.messenger.data.di.RepositoryModule;
|
||||
import org.mercury_im.messenger.android.di.module.AppModule;
|
||||
import org.mercury_im.messenger.core.di.module.ViewModelModule;
|
||||
|
@ -22,7 +23,6 @@ import org.mercury_im.messenger.android.ui.chat.ChatInputFragment;
|
|||
import org.mercury_im.messenger.android.ui.chat.ChatInputViewModel;
|
||||
import org.mercury_im.messenger.android.ui.chat.AndroidChatViewModel;
|
||||
import org.mercury_im.messenger.android.ui.chatlist.ChatListViewModel;
|
||||
import org.mercury_im.messenger.android.ui.roster.contacts.ContactListViewModel;
|
||||
import org.mercury_im.messenger.android.ui.roster.contacts.detail.ContactDetailActivity;
|
||||
import org.mercury_im.messenger.android.ui.roster.contacts.detail.ContactDetailViewModel;
|
||||
import org.mercury_im.messenger.core.viewmodel.accounts.AccountsViewModel;
|
||||
|
@ -69,10 +69,12 @@ public interface AppComponent {
|
|||
|
||||
// ViewModels
|
||||
|
||||
void inject(ContactListViewModel contactListViewModel);
|
||||
void inject(AndroidContactListViewModel contactListViewModel);
|
||||
|
||||
void inject(AndroidChatViewModel androidChatViewModel);
|
||||
|
||||
void inject(ChatViewModel chatViewModel);
|
||||
|
||||
void inject(ChatInputViewModel chatInputViewModel);
|
||||
|
||||
void inject(AndroidLoginViewModel androidLoginViewModel);
|
||||
|
|
|
@ -7,6 +7,7 @@ import android.view.MenuItem;
|
|||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.SearchView;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
|
||||
|
@ -40,6 +41,8 @@ public class MainActivity extends AppCompatActivity
|
|||
@BindView(R.id.bottom_navigation)
|
||||
BottomNavigationView bottomNavigationView;
|
||||
|
||||
private SearchView searchView;
|
||||
|
||||
private ChatListFragment chatListFragment = new ChatListFragment();
|
||||
private RosterFragment rosterFragment = new RosterFragment();
|
||||
private AccountsFragment accountsFragment = new AccountsFragment();
|
||||
|
@ -63,6 +66,10 @@ public class MainActivity extends AppCompatActivity
|
|||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
// Inflate the menu; this adds items to the action bar if it is present.
|
||||
getMenuInflater().inflate(R.menu.menu_main, menu);
|
||||
|
||||
final MenuItem searchItem = menu.findItem(R.id.action_search);
|
||||
searchView = (SearchView) searchItem.getActionView();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -91,6 +98,7 @@ public class MainActivity extends AppCompatActivity
|
|||
|
||||
case R.id.entry_contacts:
|
||||
transaction.replace(R.id.fragment, rosterFragment).commit();
|
||||
searchView.setOnQueryTextListener(rosterFragment);
|
||||
return true;
|
||||
|
||||
case R.id.entry_accounts:
|
||||
|
@ -102,7 +110,8 @@ public class MainActivity extends AppCompatActivity
|
|||
|
||||
@Override
|
||||
public void onAccountListItemClick(Account item) {
|
||||
getSupportFragmentManager().beginTransaction().replace(R.id.fragment, new AccountDetailsFragment(item.getId())).commit();
|
||||
getSupportFragmentManager().beginTransaction().addToBackStack("Test")
|
||||
.replace(R.id.fragment, new AccountDetailsFragment(item.getId())).commit();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -16,9 +16,11 @@ import androidx.fragment.app.Fragment;
|
|||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.google.android.material.card.MaterialCardView;
|
||||
|
||||
import org.mercury_im.messenger.R;
|
||||
import org.mercury_im.messenger.android.MercuryImApplication;
|
||||
import org.mercury_im.messenger.android.util.OpenPgpFingerprintColorizer;
|
||||
import org.mercury_im.messenger.android.util.OpenPgpV4FingerprintFormatter;
|
||||
import org.mercury_im.messenger.core.viewmodel.accounts.AccountFingerprintViewItem;
|
||||
import org.pgpainless.key.OpenPgpV4Fingerprint;
|
||||
|
||||
|
@ -47,7 +49,10 @@ public class AccountDetailsFragment extends Fragment {
|
|||
TextView localFingerprint;
|
||||
|
||||
@BindView(R.id.fingerprint_list)
|
||||
RecyclerView externalFingerprintList;
|
||||
RecyclerView externalFingerprintRecyclerView;
|
||||
|
||||
@BindView(R.id.other_fingerprints_card)
|
||||
MaterialCardView otherFingerprintsLayout;
|
||||
|
||||
private final UUID accountId;
|
||||
private ToggleableFingerprintsAdapter adapter;
|
||||
|
@ -70,33 +75,30 @@ public class AccountDetailsFragment extends Fragment {
|
|||
.get(AndroidAccountDetailsViewModel.class);
|
||||
|
||||
this.adapter = new ToggleableFingerprintsAdapter(viewModel);
|
||||
observe();
|
||||
}
|
||||
|
||||
private void observe() {
|
||||
viewModel.getLocalFingerprint().observe(this,
|
||||
f -> localFingerprint.setText(OpenPgpFingerprintColorizer.formatOpenPgpV4Fingerprint(f)));
|
||||
viewModel.getLocalFingerprint().observe(getViewLifecycleOwner(),
|
||||
f -> localFingerprint.setText(OpenPgpV4FingerprintFormatter.formatOpenPgpV4Fingerprint(f)));
|
||||
|
||||
viewModel.getRemoteFingerprints().observe(this, adapter::setItems);
|
||||
|
||||
//viewModel.getJid().observe(this, jid::setText);
|
||||
|
||||
/*
|
||||
localFingerprintShareButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Intent sendIntent = new Intent();
|
||||
sendIntent.setAction(Intent.ACTION_SEND);
|
||||
sendIntent.putExtra(Intent.EXTRA_TEXT, viewModel.getLocalFingerprint().getValue());
|
||||
sendIntent.setType("text/plain");
|
||||
|
||||
Intent shareIntent = Intent.createChooser(sendIntent, null);
|
||||
startActivity(shareIntent);
|
||||
|
||||
}
|
||||
viewModel.getRemoteFingerprints().observe(getViewLifecycleOwner(), items -> {
|
||||
otherFingerprintsLayout.setVisibility(items.isEmpty() ? View.GONE : View.VISIBLE);
|
||||
adapter.setItems(items);
|
||||
});
|
||||
|
||||
*/
|
||||
viewModel.getJid().observe(getViewLifecycleOwner(), accountJid -> jid.setText(accountJid.toString()));
|
||||
|
||||
localFingerprintShareButton.setOnClickListener(v -> {
|
||||
OpenPgpV4Fingerprint fingerprint = viewModel.getLocalFingerprint().getValue();
|
||||
Intent sendIntent = new Intent();
|
||||
sendIntent.setAction(Intent.ACTION_SEND);
|
||||
sendIntent.putExtra(Intent.EXTRA_TEXT, "openpgp4fpr:" + fingerprint);
|
||||
sendIntent.setType("text/plain");
|
||||
|
||||
Intent shareIntent = Intent.createChooser(sendIntent, "Share OpenPGP Fingerprint");
|
||||
startActivity(shareIntent);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
@ -105,7 +107,9 @@ public class AccountDetailsFragment extends Fragment {
|
|||
View view = inflater.inflate(R.layout.fragment_account_details, container, false);
|
||||
ButterKnife.bind(this, view);
|
||||
|
||||
externalFingerprintList.setAdapter(adapter);
|
||||
externalFingerprintRecyclerView.setAdapter(adapter);
|
||||
|
||||
observe();
|
||||
|
||||
return view;
|
||||
}
|
||||
|
@ -142,12 +146,13 @@ public class AccountDetailsFragment extends Fragment {
|
|||
|
||||
final OpenPgpV4Fingerprint fingerprint = f.getFingerprint();
|
||||
|
||||
holder.fingerprint.setText(OpenPgpFingerprintColorizer.formatOpenPgpV4Fingerprint(fingerprint));
|
||||
holder.fingerprint.setText(OpenPgpV4FingerprintFormatter.formatOpenPgpV4Fingerprint(fingerprint));
|
||||
holder.fingerprintTimestamp.setText(dateFormat.format(f.getAnnouncementDate()));
|
||||
|
||||
holder.trustSwitch.setChecked(f.isTrusted());
|
||||
holder.trustSwitch.setOnCheckedChangeListener(
|
||||
(buttonView, isChecked) -> viewModel.markFingerprintTrusted(fingerprint, isChecked));
|
||||
holder.divider.setVisibility(position == fingerprints.size() - 1 ? View.GONE : View.VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -161,12 +166,14 @@ public class AccountDetailsFragment extends Fragment {
|
|||
private final Switch trustSwitch;
|
||||
private final TextView fingerprintTimestamp;
|
||||
private final TextView fingerprint;
|
||||
private final View divider;
|
||||
|
||||
public ViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
this.fingerprint = itemView.findViewById(R.id.fingerprint);
|
||||
this.trustSwitch = itemView.findViewById(R.id.fingerprint_toggle);
|
||||
this.fingerprintTimestamp = itemView.findViewById(R.id.fingerprint_timestamp);
|
||||
this.divider = itemView.findViewById(R.id.divider);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ import androidx.recyclerview.widget.RecyclerView;
|
|||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.mercury_im.messenger.R;
|
||||
import org.mercury_im.messenger.android.util.OpenPgpFingerprintColorizer;
|
||||
import org.mercury_im.messenger.core.viewmodel.accounts.AccountViewItem;
|
||||
import org.mercury_im.messenger.entity.Account;
|
||||
import org.mercury_im.messenger.android.ui.avatar.AvatarDrawable;
|
||||
|
|
|
@ -10,6 +10,7 @@ import androidx.lifecycle.ViewModel;
|
|||
import androidx.lifecycle.ViewModelProvider;
|
||||
|
||||
import org.jxmpp.jid.EntityBareJid;
|
||||
import org.jxmpp.jid.impl.JidCreate;
|
||||
import org.mercury_im.messenger.android.MercuryImApplication;
|
||||
import org.mercury_im.messenger.android.ui.MercuryAndroidViewModel;
|
||||
import org.mercury_im.messenger.core.SchedulersFacade;
|
||||
|
@ -19,13 +20,18 @@ import org.mercury_im.messenger.core.viewmodel.accounts.AccountFingerprintViewIt
|
|||
import org.pgpainless.key.OpenPgpV4Fingerprint;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
public class AndroidAccountDetailsViewModel extends AndroidViewModel implements MercuryAndroidViewModel<AccountDetailsViewModel> {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(AndroidAccountDetailsViewModel.class.getName());
|
||||
|
||||
@Inject
|
||||
SchedulersFacade schedulers;
|
||||
|
||||
|
@ -33,27 +39,33 @@ public class AndroidAccountDetailsViewModel extends AndroidViewModel implements
|
|||
AccountDetailsViewModel commonViewModel;
|
||||
|
||||
private final UUID accountId;
|
||||
private MutableLiveData<OpenPgpV4Fingerprint> localFingerprint = new MutableLiveData<>();
|
||||
private MutableLiveData<OpenPgpV4Fingerprint> localFingerprint = new MutableLiveData<>(new OpenPgpV4Fingerprint("09858F60046289311743B90F3152226EB43287C5"));
|
||||
private MutableLiveData<List<AccountFingerprintViewItem>> remoteFingerprints = new MutableLiveData<>(new ArrayList<>());
|
||||
private MutableLiveData<EntityBareJid> jid;
|
||||
private MutableLiveData<EntityBareJid> jid = new MutableLiveData<>(JidCreate.entityBareFromOrThrowUnchecked("placeholder@place.holder"));
|
||||
|
||||
public AndroidAccountDetailsViewModel(@NonNull Application application, UUID accountId) {
|
||||
super(application);
|
||||
this.accountId = accountId;
|
||||
|
||||
LOGGER.log(Level.INFO, "Creating AndroidAccountDetailsViewModel");
|
||||
((MercuryImApplication) application).getAppComponent().inject(this);
|
||||
|
||||
addDisposable(getCommonViewModel().observeLocalFingerprint(accountId)
|
||||
.compose(schedulers.executeUiSafeObservable())
|
||||
.filter(Optional::isPresent)
|
||||
.map(Optional::getItem)
|
||||
.subscribe(localFingerprint::setValue));
|
||||
.subscribe(localFingerprint::postValue));
|
||||
|
||||
addDisposable(getCommonViewModel().observeRemoteFingerprints(accountId)
|
||||
.compose(schedulers.executeUiSafeObservable())
|
||||
.subscribe(list -> remoteFingerprints.setValue(list)));
|
||||
.subscribe(list -> {
|
||||
LOGGER.log(Level.INFO, "Set remote fingerprints to list: " + Arrays.toString(list.toArray()));
|
||||
remoteFingerprints.postValue(list);
|
||||
},
|
||||
e -> LOGGER.log(Level.SEVERE, "Error observing remote fingerprints.", e),
|
||||
() -> LOGGER.log(Level.INFO, "observing remote fingerprint onComplete.")));
|
||||
|
||||
//addDisposable(getCommonViewModel().getJid(accountId).subscribe(jid::setValue));
|
||||
addDisposable(getCommonViewModel().getJid(accountId).subscribe(jid::postValue));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -12,6 +12,7 @@ import org.mercury_im.messenger.core.SchedulersFacade;
|
|||
import org.mercury_im.messenger.core.data.repository.DirectChatRepository;
|
||||
import org.mercury_im.messenger.core.data.repository.MessageRepository;
|
||||
import org.mercury_im.messenger.core.data.repository.PeerRepository;
|
||||
import org.mercury_im.messenger.core.util.Optional;
|
||||
import org.mercury_im.messenger.core.viewmodel.chat.ChatViewModel;
|
||||
import org.mercury_im.messenger.data.repository.RxMessageRepository;
|
||||
import org.mercury_im.messenger.entity.chat.DirectChat;
|
||||
|
@ -29,6 +30,7 @@ import io.reactivex.Completable;
|
|||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
||||
public class AndroidChatViewModel extends ViewModel implements MercuryAndroidViewModel<ChatViewModel> {
|
||||
|
@ -36,7 +38,7 @@ public class AndroidChatViewModel extends ViewModel implements MercuryAndroidVie
|
|||
private final CompositeDisposable disposable = new CompositeDisposable();
|
||||
private static final Logger LOGGER = Logger.getLogger(AndroidChatViewModel.class.getName());
|
||||
|
||||
//@Inject
|
||||
@Inject
|
||||
ChatViewModel commonViewModel;
|
||||
|
||||
@Inject
|
||||
|
@ -74,30 +76,22 @@ public class AndroidChatViewModel extends ViewModel implements MercuryAndroidVie
|
|||
public void init(DirectChat chat) {
|
||||
this.chat.setValue(chat);
|
||||
this.contact.setValue(chat.getPeer());
|
||||
this.commonViewModel.init(chat);
|
||||
|
||||
// Subscribe peer
|
||||
disposable.add(contactRepository.observePeer(chat.getPeer().getId())
|
||||
.subscribe(peer -> {
|
||||
if (peer.isPresent()) {
|
||||
contactDisplayName.setValue(peer.getItem().getName());
|
||||
}
|
||||
},
|
||||
disposable.add(commonViewModel.getPeer()
|
||||
.subscribe(peer -> contactDisplayName.setValue(peer.getName()),
|
||||
error -> LOGGER.log(Level.SEVERE, "Error subscribing display name to peer", error)));
|
||||
|
||||
// Subscribe messages
|
||||
disposable.add(messageRepository.observeMessages(chat)
|
||||
.doOnNext(m -> LOGGER.log(Level.INFO, "NEW MESSAGES."))
|
||||
.subscribe(messageList -> {
|
||||
|
||||
AndroidChatViewModel.this.messages.postValue(messageList);
|
||||
},
|
||||
addDisposable(commonViewModel.getMessages()
|
||||
.subscribe(messageList -> AndroidChatViewModel.this.messages.postValue(messageList),
|
||||
error -> LOGGER.log(Level.SEVERE, "Error subscribing to messages", error)));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCleared() {
|
||||
super.onCleared();
|
||||
LOGGER.log(Level.INFO, "CLEAR");
|
||||
disposable.clear();
|
||||
}
|
||||
|
||||
|
@ -114,12 +108,7 @@ public class AndroidChatViewModel extends ViewModel implements MercuryAndroidVie
|
|||
}
|
||||
|
||||
public void queryTextChanged(String query) {
|
||||
Observable<List<Message>> observable = query.isEmpty() ?
|
||||
messageRepository.observeMessages(chat.getValue()) :
|
||||
messageRepository.findMessagesWithBody(chat.getValue(), query);
|
||||
|
||||
disposable.add(observable.subscribe(messages ->
|
||||
AndroidChatViewModel.this.messages.setValue(messages)));
|
||||
commonViewModel.onQueryTextChanged(query);
|
||||
}
|
||||
|
||||
public void deleteContact() {
|
||||
|
@ -127,9 +116,9 @@ public class AndroidChatViewModel extends ViewModel implements MercuryAndroidVie
|
|||
disposable.add(messenger.deleteContact(contact)
|
||||
.subscribeOn(schedulers.getIoScheduler())
|
||||
.observeOn(schedulers.getUiScheduler())
|
||||
.subscribe(() -> LOGGER.log(Level.INFO, "Contact deleted."), e -> {
|
||||
LOGGER.log(Level.SEVERE, e.getMessage(), e);
|
||||
}));
|
||||
.subscribe(
|
||||
() -> LOGGER.log(Level.INFO, "Contact deleted."),
|
||||
e -> LOGGER.log(Level.SEVERE, e.getMessage(), e)));
|
||||
}
|
||||
|
||||
public void sendMessage(String body) {
|
||||
|
|
|
@ -7,6 +7,7 @@ import android.view.ViewGroup;
|
|||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.widget.SearchView;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentPagerAdapter;
|
||||
|
@ -21,7 +22,7 @@ import org.mercury_im.messenger.android.ui.roster.contacts.ContactListFragment;
|
|||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
|
||||
public class RosterFragment extends Fragment {
|
||||
public class RosterFragment extends Fragment implements SearchView.OnQueryTextListener {
|
||||
|
||||
@BindView(R.id.tab_layout)
|
||||
TabLayout tabLayout;
|
||||
|
@ -29,6 +30,9 @@ public class RosterFragment extends Fragment {
|
|||
@BindView(R.id.viewpager)
|
||||
ViewPager viewPager;
|
||||
|
||||
private ContactListFragment contactListFragment = new ContactListFragment();
|
||||
private BookmarkListFragment bookmarkListFragment = new BookmarkListFragment();
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
|
@ -44,6 +48,17 @@ public class RosterFragment extends Fragment {
|
|||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onQueryTextSubmit(String query) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onQueryTextChange(String newText) {
|
||||
contactListFragment.onQueryTextChange(newText);
|
||||
return false;
|
||||
}
|
||||
|
||||
private class RosterFragmentPagerAdapter extends FragmentPagerAdapter {
|
||||
|
||||
final int PAGE_COUNT = 2;
|
||||
|
@ -52,8 +67,8 @@ public class RosterFragment extends Fragment {
|
|||
getString(R.string.tab_bookmarks)
|
||||
};
|
||||
final Fragment[] PAGES = new Fragment[] {
|
||||
new ContactListFragment(),
|
||||
new BookmarkListFragment()
|
||||
contactListFragment,
|
||||
bookmarkListFragment
|
||||
};
|
||||
|
||||
public RosterFragmentPagerAdapter(@NonNull FragmentManager fm, int behavior) {
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
package org.mercury_im.messenger.android.ui.roster.contacts;
|
||||
|
||||
import android.util.Log;
|
||||
import android.app.Application;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.AndroidViewModel;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
import androidx.lifecycle.ViewModel;
|
||||
|
||||
import org.mercury_im.messenger.android.MercuryImApplication;
|
||||
import org.mercury_im.messenger.android.ui.MercuryAndroidViewModel;
|
||||
import org.mercury_im.messenger.core.Messenger;
|
||||
import org.mercury_im.messenger.data.repository.RxAccountRepository;
|
||||
import org.mercury_im.messenger.data.repository.RxPeerRepository;
|
||||
import org.mercury_im.messenger.core.viewmodel.roster.ContactListViewModel;
|
||||
import org.mercury_im.messenger.entity.Account;
|
||||
import org.mercury_im.messenger.entity.contact.Peer;
|
||||
|
||||
|
@ -21,13 +22,11 @@ import io.reactivex.disposables.CompositeDisposable;
|
|||
import lombok.Getter;
|
||||
|
||||
|
||||
public class ContactListViewModel extends ViewModel {
|
||||
public class AndroidContactListViewModel extends AndroidViewModel
|
||||
implements MercuryAndroidViewModel<ContactListViewModel> {
|
||||
|
||||
@Inject
|
||||
RxPeerRepository xmppContactRepository;
|
||||
|
||||
@Inject
|
||||
RxAccountRepository accountRepository;
|
||||
ContactListViewModel commonViewModel;
|
||||
|
||||
@Inject
|
||||
@Getter
|
||||
|
@ -37,14 +36,13 @@ public class ContactListViewModel extends ViewModel {
|
|||
private final MutableLiveData<List<Account>> accounts = new MutableLiveData<>();
|
||||
private final CompositeDisposable compositeDisposable = new CompositeDisposable();
|
||||
|
||||
public ContactListViewModel() {
|
||||
super();
|
||||
MercuryImApplication.getApplication().getAppComponent().inject(this);
|
||||
Log.d("ContactListViewModel", "Start observing database");
|
||||
public AndroidContactListViewModel(@NonNull Application application) {
|
||||
super(application);
|
||||
((MercuryImApplication) application).getAppComponent().inject(this);
|
||||
// Subscribe to changes to the contacts table and update the LiveData object for the UI.
|
||||
compositeDisposable.add(xmppContactRepository.observeAllPeers()
|
||||
compositeDisposable.add(getCommonViewModel().getContacts()
|
||||
.subscribe(rosterEntryList::postValue));
|
||||
compositeDisposable.add(accountRepository.observeAllAccounts()
|
||||
compositeDisposable.add(getCommonViewModel().getAccounts()
|
||||
.subscribe(accounts::postValue));
|
||||
}
|
||||
|
||||
|
@ -61,4 +59,13 @@ public class ContactListViewModel extends ViewModel {
|
|||
public LiveData<List<Account>> getAccounts() {
|
||||
return accounts;
|
||||
}
|
||||
|
||||
public void onContactSearchQueryTextChanged(String query) {
|
||||
getCommonViewModel().onContactSearchQueryChanged(query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContactListViewModel getCommonViewModel() {
|
||||
return commonViewModel;
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@ import android.view.LayoutInflater;
|
|||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.appcompat.widget.SearchView;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
@ -23,9 +24,9 @@ import static androidx.constraintlayout.widget.Constraints.TAG;
|
|||
/**
|
||||
* A placeholder fragment containing a simple view.
|
||||
*/
|
||||
public class ContactListFragment extends Fragment {
|
||||
public class ContactListFragment extends Fragment implements SearchView.OnQueryTextListener {
|
||||
|
||||
private ContactListViewModel contactListViewModel;
|
||||
private AndroidContactListViewModel viewModel;
|
||||
|
||||
@BindView(R.id.roster_entry_list__recycler_view)
|
||||
RecyclerView recyclerView;
|
||||
|
@ -51,18 +52,18 @@ public class ContactListFragment extends Fragment {
|
|||
}
|
||||
|
||||
private void displayAddContactDialog() {
|
||||
AddContactDialogFragment addContactDialogFragment = new AddContactDialogFragment(contactListViewModel.getAccounts().getValue(), contactListViewModel.getMessenger());
|
||||
AddContactDialogFragment addContactDialogFragment = new AddContactDialogFragment(viewModel.getAccounts().getValue(), viewModel.getMessenger());
|
||||
addContactDialogFragment.show(this.getParentFragmentManager(), "add");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
contactListViewModel = new ViewModelProvider(this).get(ContactListViewModel.class);
|
||||
observeViewModel(contactListViewModel);
|
||||
viewModel = new ViewModelProvider(this).get(AndroidContactListViewModel.class);
|
||||
observeViewModel(viewModel);
|
||||
}
|
||||
|
||||
private void observeViewModel(ContactListViewModel viewModel) {
|
||||
private void observeViewModel(AndroidContactListViewModel viewModel) {
|
||||
viewModel.getRosterEntryList().observe(this, rosterEntries -> {
|
||||
if (rosterEntries == null) {
|
||||
Log.d(TAG, "Displaying null roster entries");
|
||||
|
@ -72,4 +73,15 @@ public class ContactListFragment extends Fragment {
|
|||
Log.d(TAG, "Displaying " + rosterEntries.size() + " roster entries");
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onQueryTextSubmit(String query) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onQueryTextChange(String newText) {
|
||||
viewModel.onContactSearchQueryTextChanged(newText);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,8 +23,7 @@ import com.google.android.material.chip.Chip;
|
|||
import com.google.android.material.chip.ChipGroup;
|
||||
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton;
|
||||
|
||||
import org.jivesoftware.smackx.colors.ConsistentColor;
|
||||
import org.mercury_im.messenger.android.util.OpenPgpFingerprintColorizer;
|
||||
import org.mercury_im.messenger.android.util.OpenPgpV4FingerprintFormatter;
|
||||
import org.mercury_im.messenger.core.Messenger;
|
||||
import org.mercury_im.messenger.R;
|
||||
import org.mercury_im.messenger.android.ui.chat.ChatActivity;
|
||||
|
@ -176,6 +175,6 @@ public class ContactDetailFragment extends Fragment {
|
|||
if (fingerprints.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
fingerprint.setText(OpenPgpFingerprintColorizer.formatOpenPgpV4Fingerprint(fingerprints.get(0)));
|
||||
fingerprint.setText(OpenPgpV4FingerprintFormatter.formatOpenPgpV4Fingerprint(fingerprints.get(0)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ import android.text.style.ForegroundColorSpan;
|
|||
import org.jivesoftware.smackx.colors.ConsistentColor;
|
||||
import org.pgpainless.key.OpenPgpV4Fingerprint;
|
||||
|
||||
public class OpenPgpFingerprintColorizer {
|
||||
public class OpenPgpV4FingerprintFormatter {
|
||||
|
||||
/**
|
||||
* Split an OpenPGP fingerprint into 10 blocks of length 4.
|
|
@ -1,16 +1,20 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<ScrollView 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"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:orientation="vertical">
|
||||
|
||||
<de.hdodenhof.circleimageview.CircleImageView
|
||||
android:id="@+id/avatar"
|
||||
android:layout_width="196dp"
|
||||
android:layout_height="196dp"
|
||||
android:layout_marginTop="60dp"
|
||||
android:paddingTop="12dp"
|
||||
android:src="@drawable/aldrin"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
|
@ -52,6 +56,7 @@
|
|||
android:layout_marginBottom="8dp"/>
|
||||
|
||||
<include layout="@layout/view_fingerprints_card_toggleable"
|
||||
android:id="@+id/other_fingerprints_card"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_marginTop="8dp"
|
||||
|
@ -60,4 +65,5 @@
|
|||
</LinearLayout>
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</ScrollView>
|
|
@ -40,7 +40,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="?android:attr/listDivider"
|
||||
app:layout_constraintTop_toBottomOf="@id/fingerprint" />
|
||||
app:layout_constraintTop_toBottomOf="@id/fingerprint_timestamp" />
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -14,7 +14,8 @@
|
|||
android:orientation="vertical"
|
||||
android:paddingStart="12dp"
|
||||
android:paddingEnd="12dp"
|
||||
android:paddingTop="12dp">
|
||||
android:paddingTop="12dp"
|
||||
android:paddingBottom="12dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
|
@ -31,6 +32,7 @@
|
|||
tools:listitem="@layout/view_fingerprint_toggleable"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginTop="8dp"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
|
|
|
@ -34,6 +34,7 @@ public class MessageMapping extends AbstractMapping<Message, MessageModel> {
|
|||
model.setStanzaId(entity.getStanzaId());
|
||||
model.setOriginId(entity.getOriginId());
|
||||
model.setLegacyId(entity.getLegacyStanzaId());
|
||||
model.setXml(entity.getXml());
|
||||
|
||||
return model;
|
||||
}
|
||||
|
@ -49,6 +50,7 @@ public class MessageMapping extends AbstractMapping<Message, MessageModel> {
|
|||
entity.setStanzaId(model.getStanzaId());
|
||||
entity.setOriginId(model.getOriginId());
|
||||
entity.setLegacyStanzaId(model.getLegacyId());
|
||||
entity.setXml(model.getXml());
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,6 +42,9 @@ public abstract class AbstractMessageModel implements Persistable {
|
|||
@Column(length = 65536)
|
||||
String body;
|
||||
|
||||
@Column(length = 65536)
|
||||
String xml;
|
||||
|
||||
@Column
|
||||
String legacyId;
|
||||
|
||||
|
|
|
@ -110,7 +110,7 @@ public class RxMessageRepository
|
|||
public Observable<List<Message>> findMessagesWithBody(String body) {
|
||||
return data().select(MessageModel.class)
|
||||
.from(MessageModel.class)
|
||||
.where(MessageModel.BODY.eq(body))
|
||||
.where(MessageModel.BODY.like("%" + body + "%"))
|
||||
.get().observableResult()
|
||||
.map(ResultDelegate::toList)
|
||||
.map(this::messageModelsToEntities);
|
||||
|
@ -121,7 +121,7 @@ public class RxMessageRepository
|
|||
return data().select(MessageModel.class)
|
||||
|
||||
.from(MessageModel.class)
|
||||
.where(MessageModel.BODY.eq(body)
|
||||
.where(MessageModel.BODY.like("%" + body + "%")
|
||||
.and(MessageModel.CHAT_ID.eq(chat.getId())))
|
||||
.get().observableResult()
|
||||
.map(ResultDelegate::toList)
|
||||
|
@ -133,7 +133,7 @@ public class RxMessageRepository
|
|||
return data().select(MessageModel.class)
|
||||
|
||||
.from(MessageModel.class)
|
||||
.where(MessageModel.BODY.eq(body)
|
||||
.where(MessageModel.BODY.like("%" + body + "%")
|
||||
.and(MessageModel.CHAT_ID.eq(chat.getId())))
|
||||
.get().observableResult()
|
||||
.map(ResultDelegate::toList)
|
||||
|
|
|
@ -170,10 +170,11 @@ public class RxOpenPgpRepository implements OpenPgpRepository {
|
|||
.where(AnnouncedOpenPgpContactKey.ACCOUNT_ID.eq(accountId)
|
||||
.and(AnnouncedOpenPgpContactKey.OWNER.eq(owner))
|
||||
.and(AnnouncedOpenPgpContactKey.FINGERPRINT.eq(fingerprint)))
|
||||
.get().observableResult()
|
||||
.map(ResultDelegate::first)
|
||||
.map(AnnouncedOpenPgpContactKey::getModificationDate)
|
||||
.singleOrError();
|
||||
.limit(1)
|
||||
.get()
|
||||
.maybe()
|
||||
.toSingle()
|
||||
.map(AnnouncedOpenPgpContactKey::getModificationDate);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -256,27 +257,18 @@ public class RxOpenPgpRepository implements OpenPgpRepository {
|
|||
|
||||
@Override
|
||||
public Observable<List<OpenPgpV4Fingerprint>> observeRemoteFingerprintsOfAccount(UUID accountId) {
|
||||
return observeLocalFingerprintOf(accountId)
|
||||
.flatMap(localFingerprint -> data.select(OpenPgpPublicKeyRing.class)
|
||||
.where(OpenPgpPublicKeyRing.ACCOUNT_ID.eq(accountId))
|
||||
return accountRepository.getAccount(accountId).toSingle()
|
||||
.flatMapObservable(account -> data.select(AnnouncedOpenPgpContactKey.class)
|
||||
.where(AnnouncedOpenPgpContactKey.ACCOUNT_ID.eq(accountId)
|
||||
.and(AnnouncedOpenPgpContactKey.OWNER.eq(account.getJid())))
|
||||
.get().observableResult()
|
||||
.map(result -> {
|
||||
OpenPgpPublicKeyRing ring = new ResultDelegate<>(result).firstOrNull();
|
||||
if (ring == null) {
|
||||
return Collections.emptyList();
|
||||
} else {
|
||||
Iterator<PGPPublicKeyRing> iterator = PGPainless.readKeyRing().publicKeyRingCollection(ring.getBytes()).iterator();
|
||||
List<OpenPgpV4Fingerprint> fingerprints = new ArrayList<>();
|
||||
while (iterator.hasNext()) {
|
||||
PGPPublicKeyRing r = iterator.next();
|
||||
OpenPgpV4Fingerprint f = new OpenPgpV4Fingerprint(r);
|
||||
fingerprints.add(f);
|
||||
}
|
||||
if (localFingerprint.isPresent()) {
|
||||
fingerprints.remove(localFingerprint.getItem());
|
||||
}
|
||||
return fingerprints;
|
||||
.map(ResultDelegate::toList)
|
||||
.map(list -> {
|
||||
ArrayList<OpenPgpV4Fingerprint> fingerprints = new ArrayList<>();
|
||||
for (AnnouncedOpenPgpContactKey key : list) {
|
||||
fingerprints.add(key.getFingerprint());
|
||||
}
|
||||
return fingerprints;
|
||||
}));
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ import org.mercury_im.messenger.entity.Account;
|
|||
import org.mercury_im.messenger.entity.contact.Peer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
|
@ -174,4 +175,25 @@ public class RxPeerRepository
|
|||
.where(PeerModel.ACCOUNT_ID.eq(accountId))
|
||||
.get().single().ignoreElement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Observable<List<Peer>> findPeers(String query) {
|
||||
return data().select(PeerModel.class)
|
||||
.where(PeerModel.ADDRESS.like("%" + query + "%")
|
||||
.or(PeerModel.NAME.like("%" + query + "%")))
|
||||
.get().observableResult()
|
||||
.map(ResultDelegate::toList)
|
||||
.map(this::peerModelsToEntities);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Observable<List<Peer>> findPeers(UUID accountId, String query) {
|
||||
return data().select(PeerModel.class)
|
||||
.where(PeerModel.ACCOUNT_ID.eq(accountId)
|
||||
.and(PeerModel.ADDRESS.like("%" + query + "%")
|
||||
.or(PeerModel.NAME.like("%" + query + "%"))))
|
||||
.get().observableResult()
|
||||
.map(ResultDelegate::toList)
|
||||
.map(this::peerModelsToEntities);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
|
|||
import org.jivesoftware.smackx.ox.store.definition.OpenPgpTrustStore;
|
||||
import org.jxmpp.jid.EntityBareJid;
|
||||
import org.mercury_im.messenger.core.util.Optional;
|
||||
import org.mercury_im.messenger.entity.Account;
|
||||
import org.pgpainless.key.OpenPgpV4Fingerprint;
|
||||
|
||||
import java.util.Date;
|
||||
|
|
|
@ -61,4 +61,8 @@ public interface PeerRepository {
|
|||
}
|
||||
|
||||
Completable deleteAllPeers(UUID accountId);
|
||||
|
||||
Observable<List<Peer>> findPeers(String query);
|
||||
|
||||
Observable<List<Peer>> findPeers(UUID accountId, String query);
|
||||
}
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
package org.mercury_im.messenger.core.di.component;
|
||||
|
||||
import org.mercury_im.messenger.core.di.scope.AccountScope;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import dagger.BindsInstance;
|
||||
import dagger.Component;
|
||||
|
||||
@Component
|
||||
public interface ConnectionComponent {
|
||||
|
||||
ConnectionComponent getComponent();
|
||||
|
||||
@Component.Builder
|
||||
interface Builder {
|
||||
|
||||
@BindsInstance Builder withAccount(@AccountScope UUID accountId);
|
||||
|
||||
ConnectionComponent build();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package org.mercury_im.messenger.core.di.component;
|
||||
|
||||
import org.mercury_im.messenger.core.viewmodel.accounts.AccountDetailsViewModel;
|
||||
import org.mercury_im.messenger.core.viewmodel.accounts.AccountsViewModel;
|
||||
import org.mercury_im.messenger.core.viewmodel.accounts.LoginViewModel;
|
||||
import org.mercury_im.messenger.core.viewmodel.chat.ChatViewModel;
|
||||
import org.mercury_im.messenger.core.viewmodel.ox.OxSecretKeyBackupRestoreViewModel;
|
||||
|
||||
import dagger.Component;
|
||||
|
||||
@Component
|
||||
public interface CoreComponent {
|
||||
|
||||
void inject(LoginViewModel viewModel);
|
||||
|
||||
void inject(AccountsViewModel viewModel);
|
||||
|
||||
void inject(AccountDetailsViewModel viewModel);
|
||||
|
||||
void inject(ChatViewModel viewModel);
|
||||
|
||||
void inject(OxSecretKeyBackupRestoreViewModel viewModel);
|
||||
}
|
|
@ -1,11 +1,14 @@
|
|||
package org.mercury_im.messenger.core.di.module;
|
||||
|
||||
import org.mercury_im.messenger.core.Messenger;
|
||||
import org.mercury_im.messenger.core.SchedulersFacade;
|
||||
import org.mercury_im.messenger.core.data.repository.AccountRepository;
|
||||
import org.mercury_im.messenger.core.data.repository.OpenPgpRepository;
|
||||
import org.mercury_im.messenger.core.data.repository.Repositories;
|
||||
import org.mercury_im.messenger.core.viewmodel.accounts.AccountDetailsViewModel;
|
||||
import org.mercury_im.messenger.core.viewmodel.accounts.AccountsViewModel;
|
||||
import org.mercury_im.messenger.core.viewmodel.accounts.LoginViewModel;
|
||||
import org.mercury_im.messenger.core.viewmodel.chat.ChatViewModel;
|
||||
import org.mercury_im.messenger.core.xmpp.MercuryConnectionManager;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
@ -41,6 +44,11 @@ public class ViewModelModule {
|
|||
return new AccountDetailsViewModel(openPgpRepository, accountRepository, schedulers);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
static ChatViewModel provideChatViewModel(Messenger messenger, Repositories repositories, SchedulersFacade schedulers) {
|
||||
return new ChatViewModel(messenger, repositories, schedulers);
|
||||
}
|
||||
/*
|
||||
@Provides
|
||||
@Singleton
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
package org.mercury_im.messenger.core.di.scope;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
import javax.inject.Scope;
|
||||
|
||||
@Scope
|
||||
@Documented
|
||||
@Retention(value = RetentionPolicy.RUNTIME)
|
||||
public @interface AccountScope {
|
||||
}
|
|
@ -68,6 +68,7 @@ public class MercuryMessageStore implements IncomingChatMessageListener, Outgoin
|
|||
message.setTimestamp(delayInformation != null ? delayInformation.getStamp() : new Date());
|
||||
message.setSender(from.asEntityBareJidString());
|
||||
message.setRecipient(smackMessage.getTo().asBareJid().toString());
|
||||
message.setXml(smackMessage.toXML().toString());
|
||||
if (smackMessage.getBody() != null) {
|
||||
message.setBody(smackMessage.getBody());
|
||||
}
|
||||
|
@ -86,6 +87,7 @@ public class MercuryMessageStore implements IncomingChatMessageListener, Outgoin
|
|||
message.setTimestamp(new Date());
|
||||
message.setSender(account.getAddress());
|
||||
message.setRecipient(to.asBareJid().toString());
|
||||
message.setXml(smackMessage.build().toXML().toString());
|
||||
if (smackMessage.getBody() != null) {
|
||||
message.setBody(smackMessage.getBody());
|
||||
}
|
||||
|
@ -111,6 +113,7 @@ public class MercuryMessageStore implements IncomingChatMessageListener, Outgoin
|
|||
message.setTimestamp(delayInformation != null ? delayInformation.getStamp() : new Date());
|
||||
message.setSender(contact.getJid().toString());
|
||||
message.setRecipient(smackMessage.getTo().asBareJid().toString());
|
||||
message.setXml(smackMessage.toXML().toString());
|
||||
org.jivesoftware.smack.packet.Message.Body body = decryptedPayload.getExtension(org.jivesoftware.smack.packet.Message.Body.ELEMENT,
|
||||
org.jivesoftware.smack.packet.Message.Body.NAMESPACE);
|
||||
if (body != null) {
|
||||
|
|
|
@ -6,9 +6,11 @@ import java.util.Date;
|
|||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@ToString
|
||||
public class AccountFingerprintViewItem {
|
||||
OpenPgpV4Fingerprint fingerprint;
|
||||
Date announcementDate;
|
||||
|
|
|
@ -3,6 +3,7 @@ package org.mercury_im.messenger.core.viewmodel.chat;
|
|||
import org.mercury_im.messenger.core.Messenger;
|
||||
import org.mercury_im.messenger.core.SchedulersFacade;
|
||||
import org.mercury_im.messenger.core.data.repository.Repositories;
|
||||
import org.mercury_im.messenger.core.util.Optional;
|
||||
import org.mercury_im.messenger.core.viewmodel.MercuryViewModel;
|
||||
import org.mercury_im.messenger.entity.chat.DirectChat;
|
||||
import org.mercury_im.messenger.entity.contact.Peer;
|
||||
|
@ -11,6 +12,7 @@ import org.mercury_im.messenger.entity.message.Message;
|
|||
import java.util.List;
|
||||
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.subjects.BehaviorSubject;
|
||||
import lombok.Getter;
|
||||
|
||||
public class ChatViewModel implements MercuryViewModel {
|
||||
|
@ -18,6 +20,7 @@ public class ChatViewModel implements MercuryViewModel {
|
|||
private final Messenger messenger;
|
||||
private final Repositories repositories;
|
||||
private final SchedulersFacade schedulers;
|
||||
private DirectChat chat;
|
||||
|
||||
@Getter
|
||||
private Observable<Peer> peer;
|
||||
|
@ -28,23 +31,35 @@ public class ChatViewModel implements MercuryViewModel {
|
|||
@Getter
|
||||
private Observable<String> contactDisplayName;
|
||||
|
||||
private final BehaviorSubject<Observable<List<Message>>> messageQueryObservable = BehaviorSubject.create();
|
||||
|
||||
|
||||
public ChatViewModel(Messenger messenger,
|
||||
Repositories repositories,
|
||||
SchedulersFacade schedulers,
|
||||
DirectChat chat) {
|
||||
SchedulersFacade schedulers) {
|
||||
this.messenger = messenger;
|
||||
this.repositories = repositories;
|
||||
this.schedulers = schedulers;
|
||||
}
|
||||
|
||||
public void init(DirectChat directChat) {
|
||||
this.chat = directChat;
|
||||
//peer = repositories.getPeerRepository().observePeer(chat.getPeer());
|
||||
messages = repositories.getMessageRepository().observeMessages(chat);
|
||||
messageQueryObservable.onNext(repositories.getMessageRepository().observeMessages(chat));
|
||||
messages = Observable.switchOnNext(messageQueryObservable);
|
||||
|
||||
peer = repositories.getPeerRepository().observePeer(chat.getPeer().getId())
|
||||
.filter(Optional::isPresent).map(Optional::getItem);
|
||||
|
||||
contactDisplayName = repositories.getPeerRepository().observePeer(chat.getPeer())
|
||||
.map(optional -> optional.isPresent() ? optional.getItem().getDisplayName() : "DELETED");
|
||||
}
|
||||
|
||||
public void sendMessage(String body) {
|
||||
//addDisposable(messenger.sendMessage());
|
||||
public void onQueryTextChanged(String query) {
|
||||
if (query.trim().isEmpty()) {
|
||||
messageQueryObservable.onNext(repositories.getMessageRepository().observeMessages(chat));
|
||||
} else {
|
||||
messageQueryObservable.onNext(repositories.getMessageRepository().findMessagesWithBody(chat, query));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
package org.mercury_im.messenger.core.viewmodel.roster;
|
||||
|
||||
import org.mercury_im.messenger.core.data.repository.AccountRepository;
|
||||
import org.mercury_im.messenger.core.data.repository.PeerRepository;
|
||||
import org.mercury_im.messenger.core.viewmodel.MercuryViewModel;
|
||||
import org.mercury_im.messenger.entity.Account;
|
||||
import org.mercury_im.messenger.entity.contact.Peer;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.subjects.BehaviorSubject;
|
||||
import lombok.Getter;
|
||||
|
||||
public class ContactListViewModel implements MercuryViewModel {
|
||||
|
||||
private final PeerRepository peerRepository;
|
||||
private final AccountRepository accountRepository;
|
||||
|
||||
@Getter
|
||||
private Observable<List<Peer>> contacts;
|
||||
|
||||
@Getter
|
||||
private Observable<List<Account>> accounts;
|
||||
|
||||
private BehaviorSubject<Observable<List<Peer>>> queryResultObservables = BehaviorSubject.create();
|
||||
|
||||
@Inject
|
||||
public ContactListViewModel(PeerRepository peerRepository, AccountRepository accountRepository) {
|
||||
this.peerRepository = peerRepository;
|
||||
this.accountRepository = accountRepository;
|
||||
|
||||
queryResultObservables.onNext(peerRepository.observeAllPeers());
|
||||
this.contacts = Observable.switchOnNext(queryResultObservables);
|
||||
this.accounts = accountRepository.observeAllAccounts();
|
||||
}
|
||||
|
||||
public void onContactSearchQueryChanged(String query) {
|
||||
if (query.trim().isEmpty()) {
|
||||
queryResultObservables.onNext(peerRepository.observeAllPeers());
|
||||
} else {
|
||||
queryResultObservables.onNext(peerRepository.findPeers(query));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,6 +16,7 @@ import org.mercury_im.messenger.core.xmpp.state.ConnectionState;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
|
@ -27,6 +28,7 @@ import lombok.Getter;
|
|||
public class MercuryConnection {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(MercuryConnection.class.getName());
|
||||
private AtomicBoolean connecting = new AtomicBoolean(false);
|
||||
|
||||
@Getter
|
||||
private XMPPConnection connection;
|
||||
|
@ -59,20 +61,25 @@ public class MercuryConnection {
|
|||
}
|
||||
|
||||
private synchronized void doConnect() throws ServerUnreachableException {
|
||||
AbstractXMPPConnection connection = (AbstractXMPPConnection) getConnection();
|
||||
if (connection.isConnected()) {
|
||||
return;
|
||||
if (connecting.compareAndSet(false, true)) {
|
||||
AbstractXMPPConnection connection = (AbstractXMPPConnection) getConnection();
|
||||
if (connection.isConnected()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
connection.connect();
|
||||
connecting.set(false);
|
||||
} catch (SmackException.EndpointConnectionException e) {
|
||||
connection.disconnect();
|
||||
throw new ServerUnreachableException("Cannot connect to server " + connection.getXMPPServiceDomain().asUnescapedString(), e);
|
||||
} catch (IOException | InterruptedException | XMPPException | SmackException e) {
|
||||
throw new AssertionError("Unexpected exception.", e);
|
||||
}
|
||||
stateObservable.onNext(stateObservable.getValue().withConnectivity(ConnectivityState.connecting));
|
||||
LOGGER.log(Level.INFO, "Connected!");
|
||||
} else {
|
||||
LOGGER.log(Level.INFO, "Already connecting.");
|
||||
}
|
||||
try {
|
||||
connection.connect();
|
||||
} catch (SmackException.EndpointConnectionException e) {
|
||||
connection.disconnect();
|
||||
throw new ServerUnreachableException("Cannot connect to server " + connection.getXMPPServiceDomain().asUnescapedString(), e);
|
||||
} catch (IOException | InterruptedException | XMPPException | SmackException e) {
|
||||
throw new AssertionError("Unexpected exception.", e);
|
||||
}
|
||||
stateObservable.onNext(stateObservable.getValue().withConnectivity(ConnectivityState.connecting));
|
||||
LOGGER.log(Level.INFO, "Connected!");
|
||||
}
|
||||
|
||||
public Completable login() {
|
||||
|
@ -109,6 +116,7 @@ public class MercuryConnection {
|
|||
private final ConnectionListener connectionListener = new ConnectionListener() {
|
||||
@Override
|
||||
public void connected(XMPPConnection connection) {
|
||||
connecting.set(false);
|
||||
stateObservable.onNext(stateObservable.getValue()
|
||||
.withConnectivity(ConnectivityState.connected)
|
||||
.withAuthenticated(false));
|
||||
|
@ -127,6 +135,7 @@ public class MercuryConnection {
|
|||
|
||||
@Override
|
||||
public void connectionClosed() {
|
||||
connecting.set(false);
|
||||
stateObservable.onNext(stateObservable.getValue()
|
||||
.withConnectivity(ConnectivityState.disconnected)
|
||||
.withAuthenticated(false));
|
||||
|
@ -134,6 +143,7 @@ public class MercuryConnection {
|
|||
|
||||
@Override
|
||||
public void connectionClosedOnError(Exception e) {
|
||||
connecting.set(false);
|
||||
stateObservable.onNext(stateObservable.getValue()
|
||||
.withConnectivity(ConnectivityState.disconnected)
|
||||
.withAuthenticated(false));
|
||||
|
|
|
@ -18,6 +18,7 @@ public class Message {
|
|||
String legacyStanzaId;
|
||||
String originId;
|
||||
String stanzaId;
|
||||
String xml;
|
||||
boolean encrypted;
|
||||
boolean received;
|
||||
boolean read;
|
||||
|
|
Loading…
Reference in New Issue