aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Schneppe <christian@pix-art.de>2019-01-27 14:56:20 +0100
committerChristian Schneppe <christian@pix-art.de>2019-01-27 14:56:20 +0100
commit71f8e656db044a3b3e28cb82a954521699fe9602 (patch)
treec65950352826fad22fa90e03773f9f72c5007391
parent712c6d32d205fb12bf8b61b3ee544a451dd117ca (diff)
refactored group chat members into seperate screen
-rw-r--r--src/main/AndroidManifest.xml5
-rw-r--r--src/main/java/de/pixart/messenger/entities/MucOptions.java31
-rw-r--r--src/main/java/de/pixart/messenger/services/AvatarService.java5
-rw-r--r--src/main/java/de/pixart/messenger/ui/ConferenceDetailsActivity.java232
-rw-r--r--src/main/java/de/pixart/messenger/ui/EditAccountActivity.java2
-rw-r--r--src/main/java/de/pixart/messenger/ui/MucUsersActivity.java71
-rw-r--r--src/main/java/de/pixart/messenger/ui/adapter/UserAdapter.java146
-rw-r--r--src/main/java/de/pixart/messenger/ui/adapter/UserPreviewAdapter.java72
-rw-r--r--src/main/java/de/pixart/messenger/ui/util/GridManager.java3
-rw-r--r--src/main/res/layout/account_row.xml2
-rw-r--r--src/main/res/layout/activity_muc_details.xml38
-rw-r--r--src/main/res/layout/activity_muc_users.xml33
-rw-r--r--src/main/res/layout/contact.xml2
-rw-r--r--src/main/res/layout/user_preview.xml17
-rw-r--r--src/main/res/values/dimens.xml1
-rw-r--r--src/main/res/values/strings.xml2
16 files changed, 452 insertions, 210 deletions
diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml
index 2edfdbf67..d5dcd8dd6 100644
--- a/src/main/AndroidManifest.xml
+++ b/src/main/AndroidManifest.xml
@@ -305,9 +305,12 @@
android:name=".ui.EnterNameActivity"
android:label="@string/enter_your_name"
android:launchMode="singleTask" />
+ <activity
+ android:name=".ui.MucUsersActivity"
+ android:label="@string/group_chat_members" />
<service android:name=".services.ExportBackupService" />
- <service android:name=".services.ImportBackupService"/>
+ <service android:name=".services.ImportBackupService" />
<service
android:name=".services.ContactChooserTargetService"
android:permission="android.permission.BIND_CHOOSER_TARGET_SERVICE">
diff --git a/src/main/java/de/pixart/messenger/entities/MucOptions.java b/src/main/java/de/pixart/messenger/entities/MucOptions.java
index 01daad1bf..c1b776b9a 100644
--- a/src/main/java/de/pixart/messenger/entities/MucOptions.java
+++ b/src/main/java/de/pixart/messenger/entities/MucOptions.java
@@ -14,6 +14,7 @@ import java.util.Set;
import de.pixart.messenger.Config;
import de.pixart.messenger.R;
+import de.pixart.messenger.services.AvatarService;
import de.pixart.messenger.services.MessageArchiveService;
import de.pixart.messenger.utils.JidHelper;
import de.pixart.messenger.utils.UIHelper;
@@ -45,6 +46,7 @@ public class MucOptions {
private User self;
private String password = null;
private boolean tookProposedNickFromBookmark = false;
+
public MucOptions(Conversation conversation) {
this.account = conversation.getAccount();
this.conversation = conversation;
@@ -102,7 +104,7 @@ public class MucOptions {
}
void notifyOfBookmarkNick(final String nick) {
- final String normalized = normalize(account.getJid(),nick);
+ final String normalized = normalize(account.getJid(), nick);
if (normalized != null && normalized.equals(getSelf().getFullJid().getResource())) {
this.tookProposedNickFromBookmark = true;
}
@@ -381,6 +383,21 @@ public class MucOptions {
return subset;
}
+ public static List<User> sub(List<User> users, int max) {
+ ArrayList<User> subset = new ArrayList<>();
+ HashSet<Jid> jids = new HashSet<>();
+ for (User user : users) {
+ jids.add(user.getAccount().getJid().asBareJid());
+ if (user.getRealJid() == null || (user.getRealJid().getLocal() != null && jids.add(user.getRealJid()))) {
+ subset.add(user);
+ }
+ if (subset.size() >= max) {
+ break;
+ }
+ }
+ return subset;
+ }
+
public int getUserCount() {
synchronized (users) {
return users.size();
@@ -602,6 +619,7 @@ public class MucOptions {
private int resId;
private int rank;
+
Affiliation(int rank, int resId) {
this.resId = resId;
this.rank = rank;
@@ -644,6 +662,7 @@ public class MucOptions {
private int resId;
private int rank;
+
Role(int resId, int rank) {
this.resId = resId;
this.rank = rank;
@@ -702,7 +721,7 @@ public class MucOptions {
}
- public static class User implements Comparable<User> {
+ public static class User implements Comparable<User>, AvatarService.Avatarable {
private Role role = Role.NONE;
private Affiliation affiliation = Affiliation.NONE;
private Jid realJid;
@@ -838,7 +857,7 @@ public class MucOptions {
}
}
- private String getComparableName() {
+ public String getComparableName() {
Contact contact = getContact();
if (contact != null) {
return contact.getDisplayName();
@@ -863,5 +882,11 @@ public class MucOptions {
this.chatState = chatState;
return true;
}
+
+ @Override
+ public int getAvatarBackgroundColor() {
+ final String seed = realJid != null ? realJid.asBareJid().toString() : null;
+ return UIHelper.getColorForName(seed == null ? getName() : seed);
+ }
}
}
diff --git a/src/main/java/de/pixart/messenger/services/AvatarService.java b/src/main/java/de/pixart/messenger/services/AvatarService.java
index 4ed01c42a..da5c449f9 100644
--- a/src/main/java/de/pixart/messenger/services/AvatarService.java
+++ b/src/main/java/de/pixart/messenger/services/AvatarService.java
@@ -39,6 +39,7 @@ import de.pixart.messenger.entities.Conversational;
import de.pixart.messenger.entities.ListItem;
import de.pixart.messenger.entities.Message;
import de.pixart.messenger.entities.MucOptions;
+import de.pixart.messenger.ui.ConferenceDetailsActivity;
import de.pixart.messenger.utils.UIHelper;
import de.pixart.messenger.xmpp.OnAdvancedStreamFeaturesLoaded;
import de.pixart.messenger.xmpp.XmppConnection;
@@ -75,13 +76,15 @@ public class AvatarService implements OnAdvancedStreamFeaturesLoaded {
public Bitmap get(final Avatarable avatarable, final int size, final boolean cachedOnly) {
if (avatarable instanceof Account) {
- return get((Account) avatarable,size,cachedOnly);
+ return get((Account) avatarable, size, cachedOnly);
} else if (avatarable instanceof Conversation) {
return get((Conversation) avatarable, size, cachedOnly);
} else if (avatarable instanceof Message) {
return get((Message) avatarable, size, cachedOnly);
} else if (avatarable instanceof ListItem) {
return get((ListItem) avatarable, size, cachedOnly);
+ } else if (avatarable instanceof MucOptions.User) {
+ return get((MucOptions.User) avatarable, size, cachedOnly);
}
throw new AssertionError("AvatarService does not know how to generate avatar from "+avatarable.getClass().getName());
}
diff --git a/src/main/java/de/pixart/messenger/ui/ConferenceDetailsActivity.java b/src/main/java/de/pixart/messenger/ui/ConferenceDetailsActivity.java
index 3508fef7c..92192de69 100644
--- a/src/main/java/de/pixart/messenger/ui/ConferenceDetailsActivity.java
+++ b/src/main/java/de/pixart/messenger/ui/ConferenceDetailsActivity.java
@@ -54,6 +54,7 @@ import de.pixart.messenger.services.XmppConnectionService;
import de.pixart.messenger.services.XmppConnectionService.OnConversationUpdate;
import de.pixart.messenger.services.XmppConnectionService.OnMucRosterUpdate;
import de.pixart.messenger.ui.adapter.MediaAdapter;
+import de.pixart.messenger.ui.adapter.UserPreviewAdapter;
import de.pixart.messenger.ui.interfaces.OnMediaLoaded;
import de.pixart.messenger.ui.util.Attachment;
import de.pixart.messenger.ui.util.AvatarWorkerTask;
@@ -78,15 +79,7 @@ import static de.pixart.messenger.utils.StringUtils.changed;
public class ConferenceDetailsActivity extends XmppActivity implements OnConversationUpdate, OnMucRosterUpdate, XmppConnectionService.OnAffiliationChanged, XmppConnectionService.OnRoleChanged, XmppConnectionService.OnConfigurationPushed, TextWatcher, OnMediaLoaded {
public static final String ACTION_VIEW_MUC = "view_muc";
- private static final float INACTIVE_ALPHA = 0.4684f; //compromise between dark and light theme
private Conversation mConversation;
- private OnClickListener inviteListener = new OnClickListener() {
-
- @Override
- public void onClick(View v) {
- inviteToConversation(mConversation);
- }
- };
private OnClickListener destroyListener = new OnClickListener() {
@Override
public void onClick(View v) {
@@ -109,8 +102,8 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
};
private ActivityMucDetailsBinding binding;
private MediaAdapter mMediaAdapter;
+ private UserPreviewAdapter mUserPreviewAdapter;
private String uuid = null;
- private User mSelectedUser = null;
private boolean mAdvancedMode = false;
@@ -247,31 +240,6 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
}
};
- public static boolean cancelPotentialWork(User user, ImageView imageView) {
- final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
-
- if (bitmapWorkerTask != null) {
- final User old = bitmapWorkerTask.o;
- if (old == null || user != old) {
- bitmapWorkerTask.cancel(true);
- } else {
- return false;
- }
- }
- return true;
- }
-
- private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) {
- if (imageView != null) {
- final Drawable drawable = imageView.getDrawable();
- if (drawable instanceof AsyncDrawable) {
- final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
- return asyncDrawable.getBitmapWorkerTask();
- }
- }
- return null;
- }
-
@Override
public void onConversationUpdate() {
refreshUi();
@@ -292,14 +260,10 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
super.onCreate(savedInstanceState);
this.binding = DataBindingUtil.setContentView(this, R.layout.activity_muc_details);
this.binding.changeConferenceButton.setOnClickListener(this.mChangeConferenceSettings);
- this.binding.invite.setOnClickListener(inviteListener);
- this.binding.invite.setVisibility(View.GONE);
- this.binding.invite.setOnClickListener(inviteListener);
this.binding.destroy.setVisibility(View.GONE);
this.binding.destroy.setOnClickListener(destroyListener);
this.binding.leaveMuc.setVisibility(View.GONE);
this.binding.addContactButton.setVisibility(View.GONE);
- this.binding.mucMoreDetails.setVisibility(View.GONE);
setSupportActionBar((Toolbar) binding.toolbar);
configureActionBar(getSupportActionBar());
this.binding.editNickButton.setOnClickListener(v -> quickEdit(mConversation.getMucOptions().getActualNick(),
@@ -342,9 +306,18 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
}
}
});
- mMediaAdapter = new MediaAdapter(this, R.dimen.media_size);
+ this.mMediaAdapter = new MediaAdapter(this, R.dimen.media_size);
+ this.mUserPreviewAdapter = new UserPreviewAdapter();
this.binding.media.setAdapter(mMediaAdapter);
+ this.binding.users.setAdapter(mUserPreviewAdapter);
GridManager.setupLayoutManager(this, this.binding.media, R.dimen.media_size);
+ GridManager.setupLayoutManager(this, this.binding.users, R.dimen.media_size);
+ this.binding.invite.setOnClickListener(v -> inviteToConversation(mConversation));
+ this.binding.showUsers.setOnClickListener(v -> {
+ Intent intent = new Intent(this, MucUsersActivity.class);
+ intent.putExtra("uuid", mConversation.getUuid());
+ startActivity(intent);
+ });
}
@Override
@@ -470,36 +443,6 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
}
@Override
- public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
- Object tag = v.getTag();
- if (tag instanceof User) {
- getMenuInflater().inflate(R.menu.muc_details_context, menu);
- final User user = (User) tag;
- this.mSelectedUser = user;
- String name;
- final Contact contact = user.getContact();
- if (contact != null && contact.showInContactList()) {
- name = contact.getDisplayName();
- } else if (user.getRealJid() != null) {
- name = user.getRealJid().asBareJid().toString();
- } else {
- name = user.getName();
- }
- menu.setHeaderTitle(name);
- MucDetailsContextMenuHelper.configureMucDetailsContextMenu(this, menu, mConversation, user);
- }
- super.onCreateContextMenu(menu, v, menuInfo);
- }
-
- @Override
- public boolean onContextItemSelected(MenuItem item) {
- if (!MucDetailsContextMenuHelper.onContextItemSelected(item, mSelectedUser, mConversation, this)) {
- return super.onContextItemSelected(item);
- }
- return true;
- }
-
- @Override
public void onMediaLoaded(List<Attachment> attachments) {
runOnUiThread(() -> {
int limit = GridManager.getCurrentColumnCount(binding.media);
@@ -578,8 +521,8 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
} else {
this.binding.detailsAccount.setVisibility(View.GONE);
}
- AvatarWorkerTask.loadAvatar(mConversation, binding.detailsMucAvatar, getPixel(Config.AVATAR_SIZE));
- AvatarWorkerTask.loadAvatar(mConversation, binding.yourPhoto, R.dimen.avatar_on_details_screen_size);
+ AvatarWorkerTask.loadAvatar(mConversation, binding.detailsMucAvatar, R.dimen.avatar_big);
+ AvatarWorkerTask.loadAvatar(mConversation.getAccount(), binding.yourPhoto, R.dimen.avatar_on_details_screen_size);
String roomName = mucOptions.getName();
String subject = mucOptions.getSubject();
@@ -609,7 +552,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
}
this.binding.mucYourNick.setText(EmojiWrapper.transform(mucOptions.getActualNick()));
if (mucOptions.online()) {
- this.binding.mucMoreDetails.setVisibility(View.VISIBLE);
+ this.binding.usersWrapper.setVisibility(View.VISIBLE);
this.binding.mucSettings.setVisibility(View.VISIBLE);
this.binding.mucInfoMore.setVisibility(this.mAdvancedMode ? View.VISIBLE : View.GONE);
this.binding.jid.setVisibility(this.mAdvancedMode ? View.VISIBLE : View.GONE);
@@ -686,7 +629,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
});
}
} else {
- this.binding.mucMoreDetails.setVisibility(View.GONE);
+ this.binding.usersWrapper.setVisibility(View.GONE);
this.binding.mucInfoMore.setVisibility(View.GONE);
this.binding.mucSettings.setVisibility(View.GONE);
}
@@ -710,71 +653,36 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
this.binding.notificationStatusButton.setImageResource(ic_notifications_none);
}
- final LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- this.binding.mucMembers.removeAllViews();
- if (inflater == null) {
- return;
- }
- final ArrayList<User> users = mucOptions.getUsers();
- Collections.sort(users);
- for (final User user : users) {
- ContactBinding binding = DataBindingUtil.inflate(inflater, R.layout.contact, this.binding.mucMembers, false);
- this.setListItemBackgroundOnView(binding.getRoot());
- binding.getRoot().setOnClickListener(view1 -> highlightInMuc(mConversation, user.getName()));
- registerForContextMenu(binding.getRoot());
- binding.getRoot().setTag(user);
- if (mAdvancedMode && user.getPgpKeyId() != 0) {
- binding.key.setVisibility(View.VISIBLE);
- binding.key.setOnClickListener(v -> viewPgpKey(user));
- binding.key.setText(OpenPgpUtils.convertKeyIdToHex(user.getPgpKeyId()));
- }
- Contact contact = user.getContact();
- String name = user.getName();
- if (contact != null) {
- binding.contactDisplayName.setText(EmojiWrapper.transform(contact.getDisplayName()));
- binding.contactJid.setText((name != null ? EmojiWrapper.transform(name) + " \u2022 " : "") + getStatus(user));
+ List<User> users = mucOptions.getUsers();
+ Collections.sort(users, (a, b) -> {
+ if (b.getAffiliation().outranks(a.getAffiliation())) {
+ return 1;
+ } else if (a.getAffiliation().outranks(b.getAffiliation())) {
+ return -1;
} else {
- binding.contactDisplayName.setText(name == null ? "" : EmojiWrapper.transform(name));
- binding.contactJid.setText(getStatus(user));
-
- }
- loadAvatar(user, binding.contactPhoto);
- if (user.getRole() == MucOptions.Role.NONE) {
- binding.contactJid.setAlpha(INACTIVE_ALPHA);
- binding.key.setAlpha(INACTIVE_ALPHA);
- binding.contactDisplayName.setAlpha(INACTIVE_ALPHA);
- binding.contactPhoto.setAlpha(INACTIVE_ALPHA);
+ if (a.getAvatar() != null && b.getAvatar() == null) {
+ return -1;
+ } else if (a.getAvatar() == null && b.getAvatar() != null) {
+ return 1;
+ } else {
+ return a.getComparableName().compareToIgnoreCase(b.getComparableName());
+ }
}
- this.binding.mucMembers.addView(binding.getRoot());
- }
- if (mConversation.getMucOptions().canInvite()) {
- this.binding.invite.setVisibility(View.VISIBLE);
- } else {
- this.binding.invite.setVisibility(View.GONE);
- }
+ });
+ this.mUserPreviewAdapter.setUserList(MucOptions.sub(users, GridManager.getCurrentColumnCount(binding.users)));
+ this.binding.invite.setVisibility(mucOptions.canInvite() ? View.VISIBLE : View.GONE);
}
- private String getStatus(User user) {
- if (mAdvancedMode) {
- return getString(user.getAffiliation().getResId()) +
- " (" + getString(user.getRole().getResId()) + ')';
+ public static String getStatus(Context context, User user, final boolean advanced) {
+ if (advanced) {
+ return String.format("%s (%s)", context.getString(user.getAffiliation().getResId()), context.getString(user.getRole().getResId()));
} else {
- return getString(user.getAffiliation().getResId());
+ return context.getString(user.getAffiliation().getResId());
}
}
- private void viewPgpKey(User user) {
- PgpEngine pgp = xmppConnectionService.getPgpEngine();
- if (pgp != null) {
- PendingIntent intent = pgp.getIntentForKey(user.getPgpKeyId());
- if (intent != null) {
- try {
- startIntentSenderForResult(intent.getIntentSender(), 0, null, 0, 0, 0);
- } catch (SendIntentException ignored) {
-
- }
- }
- }
+ private String getStatus(User user) {
+ return getStatus(this, user, mAdvancedMode);
}
@Override
@@ -816,28 +724,6 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
});
}
- public void loadAvatar(User user, ImageView imageView) {
- if (cancelPotentialWork(user, imageView)) {
- final Bitmap bm = avatarService().get(user, getPixel(48), true);
- if (bm != null) {
- cancelPotentialWork(user, imageView);
- imageView.setImageBitmap(bm);
- imageView.setBackgroundColor(0x00000000);
- } else {
- String seed = user.getRealJid() != null ? user.getRealJid().asBareJid().toString() : null;
- imageView.setBackgroundColor(UIHelper.getColorForName(seed == null ? user.getName() : seed));
- imageView.setImageDrawable(null);
- final BitmapWorkerTask task = new BitmapWorkerTask(imageView);
- final AsyncDrawable asyncDrawable = new AsyncDrawable(getResources(), null, task);
- imageView.setImageDrawable(asyncDrawable);
- try {
- task.execute(user);
- } catch (final RejectedExecutionException ignored) {
- }
- }
- }
- }
-
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
@@ -864,46 +750,4 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
}
}
}
-
- static class AsyncDrawable extends BitmapDrawable {
- private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference;
-
- AsyncDrawable(Resources res, Bitmap bitmap, BitmapWorkerTask bitmapWorkerTask) {
- super(res, bitmap);
- bitmapWorkerTaskReference = new WeakReference<>(bitmapWorkerTask);
- }
-
- BitmapWorkerTask getBitmapWorkerTask() {
- return bitmapWorkerTaskReference.get();
- }
- }
-
- class BitmapWorkerTask extends AsyncTask<User, Void, Bitmap> {
- private final WeakReference<ImageView> imageViewReference;
- private User o = null;
-
- private BitmapWorkerTask(ImageView imageView) {
- imageViewReference = new WeakReference<>(imageView);
- }
-
- @Override
- protected Bitmap doInBackground(User... params) {
- this.o = params[0];
- if (imageViewReference.get() == null) {
- return null;
- }
- return avatarService().get(this.o, getPixel(48), isCancelled());
- }
-
- @Override
- protected void onPostExecute(Bitmap bitmap) {
- if (bitmap != null && !isCancelled()) {
- final ImageView imageView = imageViewReference.get();
- if (imageView != null) {
- imageView.setImageBitmap(bitmap);
- imageView.setBackgroundColor(0x00000000);
- }
- }
- }
- }
}
diff --git a/src/main/java/de/pixart/messenger/ui/EditAccountActivity.java b/src/main/java/de/pixart/messenger/ui/EditAccountActivity.java
index 34330236f..47a7b2173 100644
--- a/src/main/java/de/pixart/messenger/ui/EditAccountActivity.java
+++ b/src/main/java/de/pixart/messenger/ui/EditAccountActivity.java
@@ -1058,7 +1058,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
if (!mInitMode) {
binding.avater.setVisibility(View.VISIBLE);
- AvatarWorkerTask.loadAvatar(mAccount, binding.avater, getPixel(Config.AVATAR_SIZE));
+ AvatarWorkerTask.loadAvatar(mAccount, binding.avater, R.dimen.avatar_big);
this.binding.accountJid.setEnabled(false);
} else {
binding.avater.setVisibility(View.GONE);
diff --git a/src/main/java/de/pixart/messenger/ui/MucUsersActivity.java b/src/main/java/de/pixart/messenger/ui/MucUsersActivity.java
new file mode 100644
index 000000000..ffefedc80
--- /dev/null
+++ b/src/main/java/de/pixart/messenger/ui/MucUsersActivity.java
@@ -0,0 +1,71 @@
+package de.pixart.messenger.ui;
+
+import android.content.Intent;
+import android.databinding.DataBindingUtil;
+import android.os.Bundle;
+import android.support.v7.widget.Toolbar;
+import android.view.MenuItem;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+import de.pixart.messenger.R;
+import de.pixart.messenger.databinding.ActivityMucUsersBinding;
+import de.pixart.messenger.entities.Conversation;
+import de.pixart.messenger.entities.MucOptions;
+import de.pixart.messenger.services.XmppConnectionService;
+import de.pixart.messenger.ui.adapter.UserAdapter;
+import de.pixart.messenger.ui.util.MucDetailsContextMenuHelper;
+
+public class MucUsersActivity extends XmppActivity implements XmppConnectionService.OnRosterUpdate {
+
+ private UserAdapter userAdapter;
+
+ private Conversation mConversation = null;
+
+ @Override
+ protected void refreshUiReal() {
+ }
+
+ @Override
+ void onBackendConnected() {
+ final Intent intent = getIntent();
+ final String uuid = intent == null ? null : intent.getStringExtra("uuid");
+ if (uuid != null) {
+ mConversation = xmppConnectionService.findConversationByUuid(uuid);
+ }
+ loadAndSubmitUsers();
+ }
+
+ private void loadAndSubmitUsers() {
+ if (mConversation != null) {
+ ArrayList<MucOptions.User> users = mConversation.getMucOptions().getUsers();
+ Collections.sort(users);
+ userAdapter.submitList(users);
+ }
+ }
+
+ @Override
+ public boolean onContextItemSelected(MenuItem item) {
+ if (!MucDetailsContextMenuHelper.onContextItemSelected(item, userAdapter.getSelectedUser(), mConversation, this)) {
+ return super.onContextItemSelected(item);
+ }
+ return true;
+ }
+
+ @Override
+ protected void onCreate(final Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ ActivityMucUsersBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_muc_users);
+ setSupportActionBar((Toolbar) binding.toolbar);
+ configureActionBar(getSupportActionBar(), true);
+ this.userAdapter = new UserAdapter(true);
+ binding.list.setAdapter(this.userAdapter);
+ }
+
+
+ @Override
+ public void onRosterUpdate() {
+ loadAndSubmitUsers();
+ }
+} \ No newline at end of file
diff --git a/src/main/java/de/pixart/messenger/ui/adapter/UserAdapter.java b/src/main/java/de/pixart/messenger/ui/adapter/UserAdapter.java
new file mode 100644
index 000000000..f6a15aff4
--- /dev/null
+++ b/src/main/java/de/pixart/messenger/ui/adapter/UserAdapter.java
@@ -0,0 +1,146 @@
+package de.pixart.messenger.ui.adapter;
+
+import android.app.PendingIntent;
+import android.content.IntentSender;
+import android.databinding.DataBindingUtil;
+import android.support.annotation.NonNull;
+import android.support.v7.recyclerview.extensions.ListAdapter;
+import android.support.v7.util.DiffUtil;
+import android.support.v7.widget.RecyclerView;
+import android.view.ContextMenu;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.PopupMenu;
+
+import org.openintents.openpgp.util.OpenPgpUtils;
+
+import java.util.List;
+
+import de.pixart.messenger.R;
+import de.pixart.messenger.crypto.PgpEngine;
+import de.pixart.messenger.databinding.ContactBinding;
+import de.pixart.messenger.entities.Contact;
+import de.pixart.messenger.entities.MucOptions;
+import de.pixart.messenger.services.XmppConnectionService;
+import de.pixart.messenger.ui.ConferenceDetailsActivity;
+import de.pixart.messenger.ui.XmppActivity;
+import de.pixart.messenger.ui.util.AvatarWorkerTask;
+import de.pixart.messenger.ui.util.MucDetailsContextMenuHelper;
+
+public class UserAdapter extends ListAdapter<MucOptions.User, UserAdapter.ViewHolder> implements View.OnCreateContextMenuListener {
+
+ private MucOptions.User selectedUser = null;
+
+ static final DiffUtil.ItemCallback<MucOptions.User> DIFF = new DiffUtil.ItemCallback<MucOptions.User>() {
+ @Override
+ public boolean areItemsTheSame(@NonNull MucOptions.User a, @NonNull MucOptions.User b) {
+ return a == b;
+ }
+
+ @Override
+ public boolean areContentsTheSame(@NonNull MucOptions.User a, @NonNull MucOptions.User b) {
+ return a.equals(b);
+ }
+ };
+ private final boolean advancedMode;
+
+ public UserAdapter(final boolean advancedMode) {
+ super(DIFF);
+ this.advancedMode = advancedMode;
+ }
+
+ @NonNull
+ @Override
+ public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int position) {
+ return new ViewHolder(DataBindingUtil.inflate(LayoutInflater.from(viewGroup.getContext()), R.layout.contact, viewGroup, false));
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull ViewHolder viewHolder, int position) {
+ final MucOptions.User user = getItem(position);
+ AvatarWorkerTask.loadAvatar(user, viewHolder.binding.contactPhoto, R.dimen.avatar);
+ viewHolder.binding.getRoot().setOnClickListener(v -> {
+ final XmppActivity activity = XmppActivity.find(v);
+ if (activity != null) {
+ activity.highlightInMuc(user.getConversation(), user.getName());
+ }
+ });
+ viewHolder.binding.getRoot().setTag(user);
+ viewHolder.binding.getRoot().setOnCreateContextMenuListener(this);
+ viewHolder.binding.getRoot().setOnLongClickListener(v -> {
+ selectedUser = user;
+ return false;
+ });
+ final String name = user.getName();
+ final Contact contact = user.getContact();
+ if (contact != null) {
+ viewHolder.binding.contactDisplayName.setText(contact.getDisplayName());
+ if (name != null) {
+ viewHolder.binding.contactJid.setText(String.format("%s \u2022 %s", name, ConferenceDetailsActivity.getStatus(viewHolder.binding.getRoot().getContext(), user, advancedMode)));
+ } else {
+ viewHolder.binding.contactJid.setText(ConferenceDetailsActivity.getStatus(viewHolder.binding.getRoot().getContext(), user, advancedMode));
+ }
+ } else {
+ viewHolder.binding.contactDisplayName.setText(name == null ? "" : name);
+ viewHolder.binding.contactJid.setText(ConferenceDetailsActivity.getStatus(viewHolder.binding.getRoot().getContext(), user, advancedMode));
+ }
+ if (advancedMode && user.getPgpKeyId() != 0) {
+ viewHolder.binding.key.setVisibility(View.VISIBLE);
+ viewHolder.binding.key.setOnClickListener(v -> {
+ final XmppActivity activity = XmppActivity.find(v);
+ final XmppConnectionService service = activity == null ? null : activity.xmppConnectionService;
+ final PgpEngine pgpEngine = service == null ? null : service.getPgpEngine();
+ if (pgpEngine != null) {
+ PendingIntent intent = pgpEngine.getIntentForKey(user.getPgpKeyId());
+ if (intent != null) {
+ try {
+ activity.startIntentSenderForResult(intent.getIntentSender(), 0, null, 0, 0, 0);
+ } catch (IntentSender.SendIntentException ignored) {
+
+ }
+ }
+ }
+ });
+ viewHolder.binding.key.setText(OpenPgpUtils.convertKeyIdToHex(user.getPgpKeyId()));
+ }
+
+
+ }
+
+ public MucOptions.User getSelectedUser() {
+ return selectedUser;
+ }
+
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
+ final XmppActivity activity = XmppActivity.find(v);
+ final Object tag = v.getTag();
+ if (tag instanceof MucOptions.User && activity != null) {
+ activity.getMenuInflater().inflate(R.menu.muc_details_context, menu);
+ final MucOptions.User user = (MucOptions.User) tag;
+ String name;
+ final Contact contact = user.getContact();
+ if (contact != null && contact.showInContactList()) {
+ name = contact.getDisplayName();
+ } else if (user.getRealJid() != null) {
+ name = user.getRealJid().asBareJid().toString();
+ } else {
+ name = user.getName();
+ }
+ menu.setHeaderTitle(name);
+ MucDetailsContextMenuHelper.configureMucDetailsContextMenu(activity, menu, user.getConversation(), user);
+ }
+ }
+
+ class ViewHolder extends RecyclerView.ViewHolder {
+
+ private final ContactBinding binding;
+
+ private ViewHolder(ContactBinding binding) {
+ super(binding.getRoot());
+ this.binding = binding;
+ }
+ }
+} \ No newline at end of file
diff --git a/src/main/java/de/pixart/messenger/ui/adapter/UserPreviewAdapter.java b/src/main/java/de/pixart/messenger/ui/adapter/UserPreviewAdapter.java
new file mode 100644
index 000000000..5104ef86c
--- /dev/null
+++ b/src/main/java/de/pixart/messenger/ui/adapter/UserPreviewAdapter.java
@@ -0,0 +1,72 @@
+package de.pixart.messenger.ui.adapter;
+
+import android.databinding.DataBindingUtil;
+import android.support.annotation.NonNull;
+import android.support.v7.recyclerview.extensions.ListAdapter;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.ViewGroup;
+import android.widget.PopupMenu;
+
+import java.util.List;
+
+import de.pixart.messenger.R;
+import de.pixart.messenger.databinding.UserPreviewBinding;
+import de.pixart.messenger.entities.MucOptions;
+import de.pixart.messenger.ui.XmppActivity;
+import de.pixart.messenger.ui.util.AvatarWorkerTask;
+import de.pixart.messenger.ui.util.MucDetailsContextMenuHelper;
+
+public class UserPreviewAdapter extends ListAdapter<MucOptions.User, UserPreviewAdapter.ViewHolder> {
+
+ public UserPreviewAdapter() {
+ super(UserAdapter.DIFF);
+ }
+
+ @NonNull
+ @Override
+ public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int position) {
+ return new ViewHolder(DataBindingUtil.inflate(LayoutInflater.from(viewGroup.getContext()), R.layout.user_preview, viewGroup, false));
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull ViewHolder viewHolder, int position) {
+ final MucOptions.User user = getItem(position);
+ AvatarWorkerTask.loadAvatar(user, viewHolder.binding.avatar, R.dimen.media_size);
+ viewHolder.binding.getRoot().setOnClickListener(v -> {
+ final XmppActivity activity = XmppActivity.find(v);
+ if (activity != null) {
+ activity.highlightInMuc(user.getConversation(), user.getName());
+ }
+ });
+ viewHolder.binding.getRoot().setOnLongClickListener(v -> {
+ final XmppActivity activity = XmppActivity.find(v);
+ if (activity == null) {
+ return true;
+ }
+ final PopupMenu popupMenu = new PopupMenu(activity, v);
+ popupMenu.inflate(R.menu.muc_details_context);
+ final Menu menu = popupMenu.getMenu();
+ MucDetailsContextMenuHelper.configureMucDetailsContextMenu(activity, menu, user.getConversation(), user);
+ popupMenu.setOnMenuItemClickListener(menuItem -> MucDetailsContextMenuHelper.onContextItemSelected(menuItem, user, user.getConversation(), activity));
+ popupMenu.show();
+ return true;
+ });
+ }
+
+ public void setUserList(List<MucOptions.User> users) {
+ submitList(users);
+ }
+
+
+ class ViewHolder extends RecyclerView.ViewHolder {
+
+ private final UserPreviewBinding binding;
+
+ private ViewHolder(UserPreviewBinding binding) {
+ super(binding.getRoot());
+ this.binding = binding;
+ }
+ }
+} \ No newline at end of file
diff --git a/src/main/java/de/pixart/messenger/ui/util/GridManager.java b/src/main/java/de/pixart/messenger/ui/util/GridManager.java
index 0b445f3ec..9cad626ff 100644
--- a/src/main/java/de/pixart/messenger/ui/util/GridManager.java
+++ b/src/main/java/de/pixart/messenger/ui/util/GridManager.java
@@ -29,7 +29,8 @@ public class GridManager {
}
final ColumnInfo columnInfo = calculateColumnCount(context, recyclerView.getMeasuredWidth(), desiredSize);
Log.d(Config.LOGTAG, "final count " + columnInfo.count);
- if (recyclerView.getAdapter().getItemCount() != 0) {
+ final RecyclerView.Adapter adapter = recyclerView.getAdapter();
+ if (adapter != null && adapter.getItemCount() != 0) {
Log.e(Config.LOGTAG, "adapter already has items; just go with it now");
return;
}
diff --git a/src/main/res/layout/account_row.xml b/src/main/res/layout/account_row.xml
index f99f6c0dd..e3f3d99e1 100644
--- a/src/main/res/layout/account_row.xml
+++ b/src/main/res/layout/account_row.xml
@@ -5,7 +5,7 @@
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:background="?android:selectableItemBackground"
+ android:background="?selectableItemBackground"
android:paddingStart="8dp"
android:paddingLeft="8dp"
android:paddingTop="8dp"
diff --git a/src/main/res/layout/activity_muc_details.xml b/src/main/res/layout/activity_muc_details.xml
index c29d78c26..b8da6f213 100644
--- a/src/main/res/layout/activity_muc_details.xml
+++ b/src/main/res/layout/activity_muc_details.xml
@@ -463,8 +463,8 @@
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
- android:id="@+id/muc_more_details"
- android:layout_width="match_parent"
+ android:id="@+id/users_wrapper"
+ android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/activity_horizontal_margin"
android:layout_marginLeft="@dimen/activity_horizontal_margin"
@@ -489,16 +489,40 @@
android:layout_marginBottom="24dp"
android:text="@string/invite_contact" />
- <LinearLayout
- android:id="@+id/muc_members"
+ <android.support.v7.widget.RecyclerView
+ android:id="@+id/users"
android:layout_width="fill_parent"
android:layout_height="0dp"
+ android:layout_marginStart="-2dp"
+ android:layout_marginEnd="-2dp"
android:layout_weight="1"
android:divider="?android:dividerHorizontal"
- android:orientation="vertical"
- android:showDividers="middle" />
- </LinearLayout>
+ android:orientation="horizontal"
+ android:paddingStart="@dimen/card_padding_regular"
+ android:paddingTop="@dimen/card_padding_regular"
+ android:paddingEnd="@dimen/card_padding_regular"
+ android:paddingBottom="@dimen/card_padding_list" />
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_gravity="end"
+ android:orientation="horizontal">
+ <Button
+ android:id="@+id/show_users"
+ style="@style/Widget.Conversations.Button.Borderless"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:minWidth="0dp"
+ android:paddingStart="16dp"
+ android:paddingLeft="16dp"
+ android:paddingEnd="16dp"
+ android:paddingRight="16dp"
+ android:text="@string/view_users"
+ android:textColor="?attr/colorAccent" />
+ </LinearLayout>
+ </LinearLayout>
</android.support.v7.widget.CardView>
</LinearLayout>
</ScrollView>
diff --git a/src/main/res/layout/activity_muc_users.xml b/src/main/res/layout/activity_muc_users.xml
new file mode 100644
index 000000000..d6bdf8435
--- /dev/null
+++ b/src/main/res/layout/activity_muc_users.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
+
+
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:background="?attr/color_background_tertiary"
+ android:orientation="vertical">
+
+ <include
+ android:id="@+id/toolbar"
+ layout="@layout/toolbar" />
+
+
+ <android.support.design.widget.CoordinatorLayout
+ android:id="@+id/coordinator"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="?attr/color_background_tertiary">
+
+ <android.support.v7.widget.RecyclerView
+ android:id="@+id/list"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="?attr/color_background_tertiary"
+ android:orientation="vertical"
+ app:layoutManager="android.support.v7.widget.LinearLayoutManager" />
+ </android.support.design.widget.CoordinatorLayout>
+
+ </LinearLayout>
+</layout> \ No newline at end of file
diff --git a/src/main/res/layout/contact.xml b/src/main/res/layout/contact.xml
index d7d8956ec..e5b71d743 100644
--- a/src/main/res/layout/contact.xml
+++ b/src/main/res/layout/contact.xml
@@ -5,7 +5,7 @@
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:background="?attr/list_item_background"
+ android:background="?selectableItemBackground"
android:padding="@dimen/list_padding">
<com.makeramen.roundedimageview.RoundedImageView
diff --git a/src/main/res/layout/user_preview.xml b/src/main/res/layout/user_preview.xml
new file mode 100644
index 000000000..ecc05e623
--- /dev/null
+++ b/src/main/res/layout/user_preview.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <de.pixart.messenger.ui.widget.SquareFrameLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="?selectableItemBackground"
+ android:padding="2dp">
+
+ <ImageView
+ android:id="@+id/avatar"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@color/black54"
+ android:scaleType="centerInside" />
+ </de.pixart.messenger.ui.widget.SquareFrameLayout>
+</layout> \ No newline at end of file
diff --git a/src/main/res/values/dimens.xml b/src/main/res/values/dimens.xml
index 969d1c8c2..211066fd6 100644
--- a/src/main/res/values/dimens.xml
+++ b/src/main/res/values/dimens.xml
@@ -31,4 +31,5 @@
<dimen name="avatar">48dp</dimen>
<dimen name="avatar_on_conversation_overview">56dp</dimen>
<dimen name="avatar_on_status_message">32dp</dimen>
+ <dimen name="avatar_big">480dp</dimen>
</resources>
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index 188fc764c..3920b7eeb 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -870,4 +870,6 @@
<string name="unable_to_decrypt_backup">Unable to decrypt backup. Is the password correct?</string>
<string name="pref_prefer_xmpp_avatar_summary">Prefer the users XMPP avatar instead of the one from your address book</string>
<string name="pref_prefer_xmpp_avatar">Prefer XMPP avatar</string>
+ <string name="view_users">View members</string>
+ <string name="group_chat_members">Group chat members</string>
</resources>