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