Poc: Add/Remove roster groups

This commit is contained in:
Paul Schaub 2020-06-05 13:45:53 +02:00
parent 441cf7c902
commit 206fd1c8da
Signed by: vanitasvitae
GPG Key ID: 62BEE9264BF17311
7 changed files with 103 additions and 7 deletions

View File

@ -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<String> 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);
}
}
}

View File

@ -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<String> contactPresenceStatus = new MutableLiveData<>("Going down the rabbit hole.");
private MutableLiveData<String> contactName = new MutableLiveData<>("Alice Wonderland");
private MutableLiveData<String> contactAccountAddress = new MutableLiveData<>("mad@hatter.lit");
private MutableLiveData<List<String>> 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<RosterGroup> groups = entry.getGroups();
List<String> 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<List<String>> 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()))));
}
}

View File

@ -143,6 +143,12 @@
android:text="Dungeons n' Dragons"/>
</com.google.android.material.chip.ChipGroup>
<Button
android:id="@+id/button_add_to_group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Mark Mercury Seven"/>
</LinearLayout>
</androidx.cardview.widget.CardView>

View File

@ -3,6 +3,7 @@ package org.mercury_im.messenger.data.model;
import org.mercury_im.messenger.data.converter.SubscriptionDirectionConverter;
import org.mercury_im.messenger.entity.contact.SubscriptionDirection;
import java.util.List;
import java.util.UUID;
import io.requery.CascadeAction;
@ -42,6 +43,9 @@ public abstract class AbstractPeerModel implements Persistable {
@Convert(SubscriptionDirectionConverter.class)
SubscriptionDirection subscriptionDirection;
@Column
List<String> groupNames;
boolean subscriptionPending;
boolean subscriptionPreApproved;

View File

@ -198,6 +198,9 @@ public class MercuryRosterStore implements RosterStore {
}
item.setApproved(contactModel.isSubscriptionApproved());
item.setSubscriptionPending(contactModel.isSubscriptionPending());
for (String groupName : contactModel.getGroupNames()) {
item.addGroupName(groupName);
}
return item;
}
@ -210,7 +213,7 @@ public class MercuryRosterStore implements RosterStore {
}
peer.setSubscriptionApproved(item.isApproved());
peer.setSubscriptionPending(item.isSubscriptionPending());
peer.setGroupNames(new ArrayList<>(item.getGroupNames()));
return peer;
}

View File

@ -36,7 +36,7 @@ public class CsiManager implements ClientStateListener {
private void tryCsiActive(MercuryConnection connection) {
try {
ClientStateIndicationManager.active(connection.getConnection());
} catch (SmackException.NotConnectedException | InterruptedException e) {
} catch (SmackException.NotConnectedException | InterruptedException | IllegalArgumentException e) {
LOGGER.log(Level.WARNING, "Sending CSI state 'active' failed.", e);
}
}
@ -44,7 +44,7 @@ public class CsiManager implements ClientStateListener {
private void tryCsiInactive(MercuryConnection connection) {
try {
ClientStateIndicationManager.inactive(connection.getConnection());
} catch (SmackException.NotConnectedException | InterruptedException e) {
} catch (SmackException.NotConnectedException | InterruptedException | IllegalArgumentException e) {
LOGGER.log(Level.WARNING, "Sending CSI state 'inactive' failed.", e);
}
}

View File

@ -2,6 +2,7 @@ package org.mercury_im.messenger.entity.contact;
import org.mercury_im.messenger.entity.Account;
import java.util.List;
import java.util.UUID;
import lombok.Data;
@ -19,6 +20,7 @@ public class Peer {
SubscriptionDirection subscriptionDirection;
boolean subscriptionPending;
boolean subscriptionApproved;
List<String> groupNames;
public Peer() {
this.id = UUID.randomUUID();