mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-17 21:29:54 +01:00
Refactor ContactListAdapter to be reusable for other use cases.
This commit introduces an abstract `BaseContactListAdapter` which provides most of the adapter logic. The original `ContactListAdapter` extends it to show date and online status of the contacts. The new `ContactChooserAdapter` which is used for introductions extends the `ContactListAdapter` and adds logic for graying out contacts from different identities than the currently used one. A new `ContactSelectorAdapter` extends the `BaseContactListAdapter` and allows to select multiple contacts. It offers a method to return a collection of all selected `ContactId`s. This commit also sneaks in an animation when the 'Share Forum' button is clicked. Closes #292
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
package org.briarproject.android.forum;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.CheckBox;
|
||||
|
||||
import org.briarproject.R;
|
||||
import org.briarproject.android.contact.BaseContactListAdapter;
|
||||
import org.briarproject.android.contact.ContactListItem;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
public class ContactSelectorAdapter
|
||||
extends
|
||||
BaseContactListAdapter<ContactSelectorAdapter.SelectableContactHolder> {
|
||||
|
||||
public ContactSelectorAdapter(Context context,
|
||||
OnItemClickListener listener) {
|
||||
|
||||
super(context, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SelectableContactHolder onCreateViewHolder(ViewGroup viewGroup,
|
||||
int i) {
|
||||
View v = LayoutInflater.from(ctx)
|
||||
.inflate(R.layout.list_item_selectable_contact, viewGroup,
|
||||
false);
|
||||
|
||||
return new SelectableContactHolder(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(final SelectableContactHolder ui,
|
||||
final int position) {
|
||||
super.onBindViewHolder(ui, position);
|
||||
|
||||
final SelectableContactListItem item =
|
||||
(SelectableContactListItem) getItem(position);
|
||||
|
||||
if (item.isSelected()) {
|
||||
ui.checkBox.setChecked(true);
|
||||
} else {
|
||||
ui.checkBox.setChecked(false);
|
||||
}
|
||||
}
|
||||
|
||||
public Collection<ContactId> getSelectedContactIds() {
|
||||
Collection<ContactId> selected = new ArrayList<ContactId>();
|
||||
|
||||
for (int i = 0; i < contacts.size(); i++) {
|
||||
SelectableContactListItem item =
|
||||
(SelectableContactListItem) contacts.get(i);
|
||||
if (item.isSelected()) selected.add(item.getContact().getId());
|
||||
}
|
||||
|
||||
return selected;
|
||||
}
|
||||
|
||||
protected static class SelectableContactHolder
|
||||
extends BaseContactListAdapter.BaseContactHolder {
|
||||
|
||||
private final CheckBox checkBox;
|
||||
|
||||
public SelectableContactHolder(View v) {
|
||||
super(v);
|
||||
|
||||
checkBox = (CheckBox) v.findViewById(R.id.checkBox);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareContactListItems(ContactListItem c1, ContactListItem c2) {
|
||||
return compareByName(c1, c2);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,6 +2,8 @@ package org.briarproject.android.forum;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.ActivityCompat;
|
||||
import android.support.v4.app.ActivityOptionsCompat;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
@@ -42,6 +44,8 @@ import java.util.logging.Logger;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
|
||||
import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP;
|
||||
import static android.view.Gravity.CENTER;
|
||||
import static android.view.Gravity.CENTER_HORIZONTAL;
|
||||
import static android.view.View.GONE;
|
||||
@@ -152,9 +156,13 @@ public class ForumActivity extends BriarActivity implements EventListener,
|
||||
return true;
|
||||
case R.id.action_forum_share:
|
||||
Intent i2 = new Intent(this, ShareForumActivity.class);
|
||||
i2.setFlags(FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP);
|
||||
i2.putExtra(GROUP_ID, groupId.getBytes());
|
||||
i2.putExtra(FORUM_NAME, forum.getName());
|
||||
startActivity(i2);
|
||||
ActivityOptionsCompat options = ActivityOptionsCompat
|
||||
.makeCustomAnimation(this, android.R.anim.slide_in_left,
|
||||
android.R.anim.slide_out_right);
|
||||
ActivityCompat.startActivity(this, i2, options.toBundle());
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
package org.briarproject.android.forum;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
|
||||
import org.briarproject.R;
|
||||
|
||||
public class NoContactsDialog {
|
||||
|
||||
private Listener listener = null;
|
||||
|
||||
public void setListener(Listener listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
public Dialog build(Context ctx) {
|
||||
if (listener == null) throw new IllegalStateException();
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(ctx,
|
||||
R.style.BriarDialogTheme);
|
||||
builder.setMessage(R.string.no_contacts_prompt);
|
||||
builder.setPositiveButton(R.string.add_button,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
listener.contactCreationSelected();
|
||||
}
|
||||
});
|
||||
builder.setNegativeButton(R.string.cancel_button,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
listener.contactCreationCancelled();
|
||||
}
|
||||
});
|
||||
return builder.create();
|
||||
}
|
||||
|
||||
public interface Listener {
|
||||
|
||||
void contactCreationSelected();
|
||||
|
||||
void contactCreationCancelled();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package org.briarproject.android.forum;
|
||||
|
||||
import org.briarproject.android.contact.ContactListItem;
|
||||
import org.briarproject.android.contact.ConversationItem;
|
||||
import org.briarproject.api.contact.Contact;
|
||||
import org.briarproject.api.identity.LocalAuthor;
|
||||
import org.briarproject.api.sync.GroupId;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
// This class is not thread-safe
|
||||
public class SelectableContactListItem extends ContactListItem {
|
||||
|
||||
private boolean selected;
|
||||
|
||||
public SelectableContactListItem(Contact contact, LocalAuthor localAuthor,
|
||||
GroupId groupId, boolean selected) {
|
||||
|
||||
super(contact, localAuthor, false, groupId, Collections.<ConversationItem>emptyList());
|
||||
|
||||
this.selected = selected;
|
||||
}
|
||||
|
||||
public void setSelected(boolean selected) {
|
||||
this.selected = selected;
|
||||
}
|
||||
|
||||
public boolean isSelected() {
|
||||
return selected;
|
||||
}
|
||||
|
||||
public void toggleSelected() {
|
||||
selected = !selected;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,67 +2,59 @@ package org.briarproject.android.forum;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.widget.Button;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.RadioButton;
|
||||
import android.widget.RadioGroup;
|
||||
|
||||
import org.briarproject.R;
|
||||
import org.briarproject.android.AndroidComponent;
|
||||
import org.briarproject.android.BriarActivity;
|
||||
import org.briarproject.android.contact.SelectContactsDialog;
|
||||
import org.briarproject.android.invitation.AddContactActivity;
|
||||
import org.briarproject.android.util.LayoutUtils;
|
||||
import org.briarproject.android.contact.BaseContactListAdapter;
|
||||
import org.briarproject.android.contact.ContactListItem;
|
||||
import org.briarproject.android.util.BriarRecyclerView;
|
||||
import org.briarproject.api.contact.Contact;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.contact.ContactManager;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.forum.ForumSharingManager;
|
||||
import org.briarproject.api.identity.IdentityManager;
|
||||
import org.briarproject.api.identity.LocalAuthor;
|
||||
import org.briarproject.api.sync.GroupId;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static android.view.Gravity.CENTER_HORIZONTAL;
|
||||
import static android.view.View.GONE;
|
||||
import static android.view.View.VISIBLE;
|
||||
import static android.widget.LinearLayout.VERTICAL;
|
||||
import static java.util.logging.Level.INFO;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
import static org.briarproject.android.forum.ForumActivity.FORUM_NAME;
|
||||
import static org.briarproject.android.util.CommonLayoutParams.MATCH_MATCH;
|
||||
import static org.briarproject.android.util.CommonLayoutParams.WRAP_WRAP;
|
||||
|
||||
public class ShareForumActivity extends BriarActivity
|
||||
implements OnClickListener, NoContactsDialog.Listener,
|
||||
SelectContactsDialog.Listener {
|
||||
public class ShareForumActivity extends BriarActivity implements
|
||||
BaseContactListAdapter.OnItemClickListener {
|
||||
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(ShareForumActivity.class.getName());
|
||||
|
||||
private RadioGroup radioGroup = null;
|
||||
private RadioButton shareWithAll = null, shareWithSome = null;
|
||||
private Button shareButton = null;
|
||||
private ProgressBar progress = null;
|
||||
private boolean changed = false;
|
||||
private ContactSelectorAdapter adapter;
|
||||
|
||||
// Fields that are accessed from background threads must be volatile
|
||||
@Inject protected volatile IdentityManager identityManager;
|
||||
@Inject protected volatile ContactManager contactManager;
|
||||
@Inject protected volatile ForumSharingManager forumSharingManager;
|
||||
private volatile GroupId groupId = null;
|
||||
private volatile Collection<Contact> contacts = null;
|
||||
private volatile Collection<ContactId> selected = null;
|
||||
private volatile GroupId groupId;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle state) {
|
||||
super.onCreate(state);
|
||||
|
||||
setContentView(R.layout.introduction_contact_chooser);
|
||||
|
||||
Intent i = getIntent();
|
||||
byte[] b = i.getByteArrayExtra(GROUP_ID);
|
||||
if (b == null) throw new IllegalStateException();
|
||||
@@ -71,44 +63,43 @@ SelectContactsDialog.Listener {
|
||||
if (forumName == null) throw new IllegalStateException();
|
||||
setTitle(forumName);
|
||||
|
||||
LinearLayout layout = new LinearLayout(this);
|
||||
layout.setLayoutParams(MATCH_MATCH);
|
||||
layout.setOrientation(VERTICAL);
|
||||
layout.setGravity(CENTER_HORIZONTAL);
|
||||
int pad = LayoutUtils.getPadding(this);
|
||||
layout.setPadding(pad, pad, pad, pad);
|
||||
adapter = new ContactSelectorAdapter(this, this);
|
||||
BriarRecyclerView list =
|
||||
(BriarRecyclerView) findViewById(R.id.contactList);
|
||||
list.setLayoutManager(new LinearLayoutManager(this));
|
||||
list.setAdapter(adapter);
|
||||
list.setEmptyText(getString(R.string.no_contacts));
|
||||
}
|
||||
|
||||
radioGroup = new RadioGroup(this);
|
||||
radioGroup.setOrientation(VERTICAL);
|
||||
radioGroup.setPadding(0, 0, 0, pad);
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
shareWithAll = new RadioButton(this);
|
||||
shareWithAll.setId(2);
|
||||
shareWithAll.setText(R.string.forum_share_with_all);
|
||||
shareWithAll.setOnClickListener(this);
|
||||
radioGroup.addView(shareWithAll);
|
||||
loadContactsAndVisibility();
|
||||
}
|
||||
|
||||
shareWithSome = new RadioButton(this);
|
||||
shareWithSome.setId(3);
|
||||
shareWithSome.setText(R.string.forum_share_with_some);
|
||||
shareWithSome.setOnClickListener(this);
|
||||
radioGroup.addView(shareWithSome);
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
// Inflate the menu items for use in the action bar
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
inflater.inflate(R.menu.forum_share_actions, menu);
|
||||
|
||||
layout.addView(radioGroup);
|
||||
return super.onCreateOptionsMenu(menu);
|
||||
}
|
||||
|
||||
shareButton = new Button(this);
|
||||
shareButton.setLayoutParams(WRAP_WRAP);
|
||||
shareButton.setText(R.string.forum_share_button);
|
||||
shareButton.setOnClickListener(this);
|
||||
layout.addView(shareButton);
|
||||
|
||||
progress = new ProgressBar(this);
|
||||
progress.setLayoutParams(WRAP_WRAP);
|
||||
progress.setIndeterminate(true);
|
||||
progress.setVisibility(GONE);
|
||||
layout.addView(progress);
|
||||
|
||||
setContentView(layout);
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(final MenuItem item) {
|
||||
// Handle presses on the action bar items
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
onBackPressed();
|
||||
return true;
|
||||
case R.id.action_share_forum:
|
||||
storeVisibility();
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -116,41 +107,29 @@ SelectContactsDialog.Listener {
|
||||
component.inject(this);
|
||||
}
|
||||
|
||||
public void onClick(View view) {
|
||||
if (view == shareWithAll) {
|
||||
changed = true;
|
||||
} else if (view == shareWithSome) {
|
||||
changed = true;
|
||||
if (contacts == null) loadVisibility();
|
||||
else displayVisibility();
|
||||
} else if (view == shareButton) {
|
||||
if (changed) {
|
||||
share();
|
||||
} else {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void share() {
|
||||
// Replace the button with a progress bar
|
||||
shareButton.setVisibility(GONE);
|
||||
progress.setVisibility(VISIBLE);
|
||||
// Update the group in a background thread
|
||||
storeVisibility(shareWithAll.isChecked());
|
||||
}
|
||||
|
||||
private void loadVisibility() {
|
||||
private void loadContactsAndVisibility() {
|
||||
runOnDbThread(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
long now = System.currentTimeMillis();
|
||||
contacts = contactManager.getActiveContacts();
|
||||
selected = forumSharingManager.getSharedWith(groupId);
|
||||
List<ContactListItem> contacts =
|
||||
new ArrayList<ContactListItem>();
|
||||
Collection<ContactId> selectedContacts =
|
||||
new HashSet<ContactId>(
|
||||
forumSharingManager.getSharedWith(groupId));
|
||||
|
||||
for (Contact c : contactManager.getActiveContacts()) {
|
||||
LocalAuthor localAuthor = identityManager
|
||||
.getLocalAuthor(c.getLocalAuthorId());
|
||||
boolean selected = selectedContacts.contains(c.getId());
|
||||
contacts.add(
|
||||
new SelectableContactListItem(c, localAuthor,
|
||||
groupId, selected));
|
||||
}
|
||||
long duration = System.currentTimeMillis() - now;
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Load took " + duration + " ms");
|
||||
displayVisibility();
|
||||
displayContacts(contacts);
|
||||
} catch (DbException e) {
|
||||
if (LOG.isLoggable(WARNING))
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
@@ -159,32 +138,22 @@ SelectContactsDialog.Listener {
|
||||
});
|
||||
}
|
||||
|
||||
private void displayVisibility() {
|
||||
private void displayContacts(final List<ContactListItem> contact) {
|
||||
runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
if (contacts.isEmpty()) {
|
||||
NoContactsDialog builder = new NoContactsDialog();
|
||||
builder.setListener(ShareForumActivity.this);
|
||||
builder.build(ShareForumActivity.this).show();
|
||||
} else {
|
||||
SelectContactsDialog builder = new SelectContactsDialog();
|
||||
builder.setListener(ShareForumActivity.this);
|
||||
builder.setContacts(contacts);
|
||||
builder.setSelected(selected);
|
||||
builder.build(ShareForumActivity.this).show();
|
||||
}
|
||||
adapter.addAll(contact);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void storeVisibility(final boolean all) {
|
||||
private void storeVisibility() {
|
||||
runOnDbThread(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
long now = System.currentTimeMillis();
|
||||
if (all) forumSharingManager.setSharedWithAll(groupId);
|
||||
else forumSharingManager.setSharedWith(groupId,
|
||||
selected);
|
||||
Collection<ContactId> selected =
|
||||
adapter.getSelectedContactIds();
|
||||
forumSharingManager.setSharedWith(groupId, selected);
|
||||
long duration = System.currentTimeMillis() - now;
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Update took " + duration + " ms");
|
||||
@@ -197,20 +166,10 @@ SelectContactsDialog.Listener {
|
||||
});
|
||||
}
|
||||
|
||||
public void contactCreationSelected() {
|
||||
startActivity(new Intent(this, AddContactActivity.class));
|
||||
@Override
|
||||
public void onItemClick(View view, ContactListItem item) {
|
||||
((SelectableContactListItem) item).toggleSelected();
|
||||
adapter.notifyItemChanged(adapter.findItemPosition(item), item);
|
||||
}
|
||||
|
||||
public void contactCreationCancelled() {
|
||||
radioGroup.clearCheck();
|
||||
}
|
||||
|
||||
public void contactsSelected(Collection<ContactId> selected) {
|
||||
this.selected = Collections.unmodifiableCollection(selected);
|
||||
share();
|
||||
}
|
||||
|
||||
public void contactSelectionCancelled() {
|
||||
radioGroup.clearCheck();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user