package org.mercury_im.messenger.android.ui.roster.contacts.detail; import android.graphics.drawable.Drawable; import android.util.Log; import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.ViewModel; import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.packet.Presence; import org.jivesoftware.smack.roster.PresenceEventListener; import org.jivesoftware.smack.roster.Roster; import org.jivesoftware.smack.roster.RosterEntry; import org.jivesoftware.smack.roster.RosterGroup; import org.jxmpp.jid.BareJid; import org.jxmpp.jid.Jid; import org.jxmpp.jid.impl.JidCreate; import org.mercury_im.messenger.android.MercuryImApplication; import org.mercury_im.messenger.core.Messenger; import org.mercury_im.messenger.core.SchedulersFacade; import org.mercury_im.messenger.core.data.repository.OpenPgpRepository; import org.mercury_im.messenger.core.data.repository.PeerRepository; import org.mercury_im.messenger.entity.contact.Peer; import org.mercury_im.messenger.android.ui.avatar.AvatarDrawable; import org.mercury_im.messenger.core.util.CombinedPresenceListener; import org.pgpainless.key.OpenPgpV4Fingerprint; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.UUID; import javax.inject.Inject; import io.reactivex.Completable; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.CompositeDisposable; import io.reactivex.schedulers.Schedulers; public class ContactDetailViewModel extends ViewModel { @Inject PeerRepository peerRepository; @Inject OpenPgpRepository openPgpRepository; @Inject SchedulersFacade schedulers; @Inject Messenger messenger; private MutableLiveData contactAccountId = new MutableLiveData<>(UUID.randomUUID()); private MutableLiveData contactAddress = new MutableLiveData<>("alice@wonderland.lit"); private MutableLiveData contactAvatar = new MutableLiveData<>(new AvatarDrawable("Alice Wonderland", "alice@wonderland.lit")); private MutableLiveData contactPresenceMode = new MutableLiveData<>(Presence.Mode.available); private MutableLiveData contactPresenceStatus = new MutableLiveData<>("Going down the rabbit hole."); private MutableLiveData contactName = new MutableLiveData<>("Alice Wonderland"); private MutableLiveData contactAccountAddress = new MutableLiveData<>("mad@hatter.lit"); private MutableLiveData> contactGroups = new MutableLiveData<>(Collections.emptyList()); private MutableLiveData> contactFingerprints = new MutableLiveData<>(Collections.singletonList(new OpenPgpV4Fingerprint("1234567890ABCDEF1234567890ABCDEF01234567"))); private Roster roster; private CompositeDisposable disposable = new CompositeDisposable(); public ContactDetailViewModel() { super(); MercuryImApplication.getApplication().getAppComponent().inject(this); } public void bind(UUID accountId, String peerAddress) { Log.d("MMMMMM", "Bind!"); roster = Roster.getInstanceFor(messenger.getConnectionManager().getConnection(accountId).getConnection()); roster.addPresenceEventListener(presenceEventListener); contactAddress.setValue(peerAddress); contactAccountId.setValue(accountId); disposable.add(peerRepository.observePeerByAddress(accountId, peerAddress) .subscribeOn(schedulers.getIoScheduler()) .observeOn(schedulers.getUiScheduler()) .subscribe(peerOptional -> { if (!peerOptional.isPresent()) { return; } Peer peer = peerOptional.getItem(); contactAccountAddress.setValue(peer.getAccount().getAddress()); contactAvatar.setValue(new AvatarDrawable(peer.getDisplayName(), peer.getAddress())); contactName.setValue(peer.getDisplayName()); RosterEntry entry = roster.getEntry(JidCreate.entityBareFromOrThrowUnchecked(peerAddress)); if (entry != null) { List groups = entry.getGroups(); List groupNames = new ArrayList<>(groups.size()); for (RosterGroup g : groups) { groupNames.add(g.getName()); } contactGroups.postValue(groupNames); } })); BareJid jid = JidCreate.entityBareFromOrThrowUnchecked(peerAddress); Presence presence = roster.getPresence(jid); if (presence != null) { contactPresenceMode.postValue(presence.getMode()); contactPresenceStatus.postValue(presence.getStatus()); } disposable.add(openPgpRepository.observeFingerprintsOf(accountId, peerAddress) .subscribeOn(schedulers.getIoScheduler()) .observeOn(schedulers.getUiScheduler()) .subscribe(list -> contactFingerprints.setValue(list))); } public LiveData getContactAddress() { return contactAddress; } @Override protected void onCleared() { super.onCleared(); disposable.dispose(); if (roster != null) { roster.removePresenceEventListener(presenceEventListener); } } public LiveData getAccountId() { return contactAccountId; } public LiveData getContactAvatar() { return contactAvatar; } public LiveData getContactPresenceMode() { return contactPresenceMode; } public LiveData getContactName() { return contactName; } public LiveData getContactPresenceStatus() { return contactPresenceStatus; } public LiveData getContactAccountAddress() { return contactAccountAddress; } public LiveData> getContactGroups() { return contactGroups; } private final PresenceEventListener presenceEventListener = new CombinedPresenceListener() { @Override public void presenceReceived(Jid address, Presence presence) { if (presence.getFrom().asBareJid().toString().equals(getContactAddress().getValue())) { contactPresenceMode.postValue(presence.getMode()); contactPresenceStatus.postValue(presence.getStatus()); } } }; public void changeContactName(String newName) throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException { if (!newName.trim().isEmpty()) { RosterEntry entry = roster.getEntry(JidCreate.entityBareFromOrThrowUnchecked(getContactAddress().getValue())); entry.setName(newName); } } public Completable addContactToRosterGroup() { return Completable.fromAction(() -> doAddContactToRosterGroup()); } private void doAddContactToRosterGroup() throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException { String groupName = "Mercury Seven"; RosterGroup group = roster.getGroup(groupName); if (group == null) { group = roster.createGroup(groupName); } BareJid jid = JidCreate.entityBareFromOrThrowUnchecked(getContactAddress().getValue()); if (group.contains(jid)) { return; } RosterEntry entry = roster.getEntry(jid); group.addEntry(entry); } public Completable removeContactFromRosterGroup(String group) { return Completable.fromAction(() -> roster.getGroup(group).removeEntry(roster.getEntry(JidCreate.entityBareFromOrThrowUnchecked(getContactAddress().getValue())))); } public LiveData> getContactFingerprints() { return contactFingerprints; } }