diff --git a/app/src/main/java/org/mercury_im/messenger/ui/roster/contacts/detail/ContactDetailFragment.java b/app/src/main/java/org/mercury_im/messenger/ui/roster/contacts/detail/ContactDetailFragment.java index cc5d215..91bc0de 100644 --- a/app/src/main/java/org/mercury_im/messenger/ui/roster/contacts/detail/ContactDetailFragment.java +++ b/app/src/main/java/org/mercury_im/messenger/ui/roster/contacts/detail/ContactDetailFragment.java @@ -8,6 +8,7 @@ import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.Button; import android.widget.EditText; import android.widget.ImageView; import android.widget.TextView; @@ -18,6 +19,7 @@ import androidx.fragment.app.Fragment; import androidx.lifecycle.ViewModelProvider; import androidx.lifecycle.ViewModelStoreOwner; +import com.google.android.material.chip.Chip; import com.google.android.material.chip.ChipGroup; import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton; @@ -26,10 +28,11 @@ import org.mercury_im.messenger.R; import org.mercury_im.messenger.ui.chat.ChatActivity; import org.mercury_im.messenger.util.ColorUtil; +import java.util.List; + import butterknife.BindView; import butterknife.ButterKnife; import io.reactivex.Completable; -import io.reactivex.Observable; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.schedulers.Schedulers; @@ -59,6 +62,9 @@ public class ContactDetailFragment extends Fragment { @BindView(R.id.fab) ExtendedFloatingActionButton fab; + @BindView(R.id.button_add_to_group) + Button button; + private ContactDetailViewModel viewModel; @Nullable @@ -98,6 +104,15 @@ public class ContactDetailFragment extends Fragment { } }); + button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + viewModel.addContactToRosterGroup().subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(); + } + }); + return view; } @@ -132,5 +147,24 @@ public class ContactDetailFragment extends Fragment { viewModel.getContactAddress().observe(this, address -> contactAddress.setText(address)); viewModel.getContactPresenceStatus().observe(this, presenceText -> contactPresence.setText(presenceText)); viewModel.getContactAccountAddress().observe(this, address -> contactAccount.setText(address)); + viewModel.getContactGroups().observe(this, this::setRosterGroups); + } + + private void setRosterGroups(List groups) { + contactGroups.removeAllViews(); + for (String group : groups) { + Chip chip = new Chip(contactGroups.getContext()); + chip.setText(group); + chip.setOnLongClickListener(new View.OnLongClickListener() { + @Override + public boolean onLongClick(View v) { + viewModel.removeContactFromRosterGroup(group) + .subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()) + .subscribe(); + return true; + } + }); + contactGroups.addView(chip); + } } } diff --git a/app/src/main/java/org/mercury_im/messenger/ui/roster/contacts/detail/ContactDetailViewModel.java b/app/src/main/java/org/mercury_im/messenger/ui/roster/contacts/detail/ContactDetailViewModel.java index fe0c2be..db4524e 100644 --- a/app/src/main/java/org/mercury_im/messenger/ui/roster/contacts/detail/ContactDetailViewModel.java +++ b/app/src/main/java/org/mercury_im/messenger/ui/roster/contacts/detail/ContactDetailViewModel.java @@ -14,6 +14,8 @@ 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.MercuryImApplication; @@ -23,10 +25,15 @@ import org.mercury_im.messenger.entity.contact.Peer; import org.mercury_im.messenger.ui.avatar.AvatarDrawable; import org.mercury_im.messenger.util.CombinedPresenceListener; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import java.util.UUID; +import java.util.stream.Collectors; import javax.inject.Inject; +import io.reactivex.Completable; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.CompositeDisposable; import io.reactivex.schedulers.Schedulers; @@ -46,6 +53,7 @@ public class ContactDetailViewModel extends ViewModel { 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 Roster roster; @@ -58,6 +66,8 @@ public class ContactDetailViewModel extends ViewModel { 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) @@ -71,12 +81,21 @@ public class ContactDetailViewModel extends ViewModel { 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); + } })); - roster = Roster.getInstanceFor(messenger.getConnectionManager().getConnection(accountId).getConnection()); - roster.addPresenceEventListener(presenceEventListener); + BareJid jid = JidCreate.entityBareFromOrThrowUnchecked(peerAddress); - Presence presence = roster.getPresence(JidCreate.entityBareFromOrThrowUnchecked(peerAddress)); + Presence presence = roster.getPresence(jid); if (presence != null) { contactPresenceMode.postValue(presence.getMode()); contactPresenceStatus.postValue(presence.getStatus()); @@ -120,6 +139,10 @@ public class ContactDetailViewModel extends ViewModel { return contactAccountAddress; } + public LiveData> getContactGroups() { + return contactGroups; + } + private final PresenceEventListener presenceEventListener = new CombinedPresenceListener() { @Override public void presenceReceived(Jid address, Presence presence) { @@ -138,4 +161,28 @@ public class ContactDetailViewModel extends ViewModel { 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())))); + + } } diff --git a/app/src/main/res/layout/fragment_contact_details.xml b/app/src/main/res/layout/fragment_contact_details.xml index c59483c..f4110fd 100644 --- a/app/src/main/res/layout/fragment_contact_details.xml +++ b/app/src/main/res/layout/fragment_contact_details.xml @@ -143,6 +143,12 @@ android:text="Dungeons n' Dragons"/> + +