diff --git a/briar-android/res/layout/list_item_contact.xml b/briar-android/res/layout/list_item_contact.xml index 624434e9a43a77ba7adc556422bc5a2165c5a983..732cb2109ed9b9af7e2dcf2140bd27e2b7c3624c 100644 --- a/briar-android/res/layout/list_item_contact.xml +++ b/briar-android/res/layout/list_item_contact.xml @@ -1,7 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" @@ -12,8 +11,7 @@ android:layout_height="wrap_content" android:background="?attr/selectableItemBackground" android:paddingBottom="@dimen/listitem_horizontal_margin" - android:paddingTop="@dimen/listitem_horizontal_margin" - > + android:paddingTop="@dimen/listitem_horizontal_margin"> <FrameLayout android:id="@+id/avatarFrameView" @@ -76,15 +74,6 @@ android:textSize="@dimen/text_size_small" tools:text="Dec 24"/> - <TextView - android:id="@+id/identityView" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:textColor="@android:color/tertiary_text_light" - android:textSize="@dimen/text_size_tiny" - android:visibility="gone" - tools:text="My Identity"/> - </LinearLayout> <ImageView diff --git a/briar-android/res/values/strings.xml b/briar-android/res/values/strings.xml index 132cea768dd5f12ffc8b3c4265d99fb5354eadeb..f69c03741706fa32928ad10b36a7985406973f94 100644 --- a/briar-android/res/values/strings.xml +++ b/briar-android/res/values/strings.xml @@ -127,8 +127,6 @@ <string name="introduction_sent">Your introduction has been sent.</string> <string name="introduction_error">There was an error making the introduction.</string> <string name="introduction_response_error">Error when responding to introduction</string> - <string name="introduction_warn_different_identities_title">Warning: Different Identities</string> - <string name="introduction_warn_different_identities_text">You are trying to introduce two contacts that you have added with different identities. This might reveal that both identities are yours.</string> <string name="dialog_button_introduce">Introduce</string> <string name="introduction_request_sent">You have asked to introduce %1$s to %2$s.</string> <string name="introduction_request_received">%1$s has asked to introduce you to %2$s. Do you want to add %2$s to your contact list?</string> diff --git a/briar-android/src/org/briarproject/android/contact/BaseContactListAdapter.java b/briar-android/src/org/briarproject/android/contact/BaseContactListAdapter.java index cd01ad1a426faa92757372bade5fe2db41005e7f..78af58b5b8938511b41a368a3b1c265f706d0b83 100644 --- a/briar-android/src/org/briarproject/android/contact/BaseContactListAdapter.java +++ b/briar-android/src/org/briarproject/android/contact/BaseContactListAdapter.java @@ -2,129 +2,61 @@ package org.briarproject.android.contact; import android.content.Context; import android.support.annotation.Nullable; -import android.support.v4.view.ViewCompat; -import android.support.v7.widget.RecyclerView; import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.TextView; -import org.briarproject.R; import org.briarproject.android.util.BriarAdapter; import org.briarproject.api.contact.ContactId; -import org.briarproject.api.identity.Author; -import org.briarproject.util.StringUtils; - -import im.delight.android.identicons.IdenticonDrawable; import static android.support.v7.util.SortedList.INVALID_POSITION; -public abstract class BaseContactListAdapter<VH extends BaseContactListAdapter.BaseContactHolder> - extends BriarAdapter<ContactListItem, VH> { +public abstract class BaseContactListAdapter<I extends ContactItem, VH extends ContactItemViewHolder<I>> + extends BriarAdapter<I, VH> { @Nullable - protected final OnItemClickListener listener; + protected final OnContactClickListener<I> listener; - public BaseContactListAdapter(Context ctx, - @Nullable OnItemClickListener listener) { - super(ctx, ContactListItem.class); + public BaseContactListAdapter(Context ctx, Class<I> c, + @Nullable OnContactClickListener<I> listener) { + super(ctx, c); this.listener = listener; } @Override public void onBindViewHolder(final VH ui, int position) { - final ContactListItem item = getItemAt(position); - if (item == null) return; - - Author author = item.getContact().getAuthor(); - ui.avatar.setImageDrawable( - new IdenticonDrawable(author.getId().getBytes())); - String contactName = author.getName(); - ui.name.setText(contactName); - - ui.layout.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (listener != null) listener.onItemClick(ui.avatar, item); - } - }); - - ViewCompat.setTransitionName(ui.avatar, "avatar" + - StringUtils.toHexString(item.getGroupId().getBytes())); + I item = items.get(position); + ui.bind(item, listener); } @Override - public int compare(ContactListItem c1, ContactListItem c2) { - return compareByName(c1, c2); + public int compare(I c1, I c2) { + return c1.getContact().getAuthor().getName() + .compareTo(c2.getContact().getAuthor().getName()); } @Override - public boolean areItemsTheSame(ContactListItem c1, ContactListItem c2) { + public boolean areItemsTheSame(I c1, I c2) { return c1.getContact().getId().equals(c2.getContact().getId()); } @Override - public boolean areContentsTheSame(ContactListItem c1, ContactListItem c2) { + public boolean areContentsTheSame(I c1, I c2) { // check for all properties that influence visual // representation of contact - if (c1.isConnected() != c2.isConnected()) { - return false; - } - if (c1.getUnreadCount() != c2.getUnreadCount()) { - return false; - } - if (c1.getTimestamp() != c2.getTimestamp()) { - return false; - } - return true; + return c1.isConnected() == c2.isConnected(); } int findItemPosition(ContactId c) { int count = getItemCount(); for (int i = 0; i < count; i++) { - ContactListItem item = getItemAt(i); + I item = getItemAt(i); if (item != null && item.getContact().getId().equals(c)) return i; } return INVALID_POSITION; // Not found } - public static class BaseContactHolder extends RecyclerView.ViewHolder { - - public final ViewGroup layout; - public final ImageView avatar; - public final TextView name; - - public BaseContactHolder(View v) { - super(v); - - layout = (ViewGroup) v; - avatar = (ImageView) v.findViewById(R.id.avatarView); - name = (TextView) v.findViewById(R.id.nameView); - } - } - - protected int compareByName(ContactListItem c1, ContactListItem c2) { - int authorCompare = c1.getLocalAuthor().getName() - .compareTo(c2.getLocalAuthor().getName()); - if (authorCompare == 0) { - // if names are equal, compare by time instead - return compareByTime(c1, c2); - } else { - return authorCompare; - } - } - - protected int compareByTime(ContactListItem c1, ContactListItem c2) { - long time1 = c1.getTimestamp(); - long time2 = c2.getTimestamp(); - if (time1 < time2) return 1; - if (time1 > time2) return -1; - return 0; - } - - public interface OnItemClickListener { - void onItemClick(View view, ContactListItem item); + public interface OnContactClickListener<I> { + void onItemClick(View view, I item); } } diff --git a/briar-android/src/org/briarproject/android/contact/ContactItem.java b/briar-android/src/org/briarproject/android/contact/ContactItem.java new file mode 100644 index 0000000000000000000000000000000000000000..9e92c8983aff2410cb4f77f6a51fc5dbbbb9e5f0 --- /dev/null +++ b/briar-android/src/org/briarproject/android/contact/ContactItem.java @@ -0,0 +1,32 @@ +package org.briarproject.android.contact; + +import org.briarproject.api.contact.Contact; +import org.briarproject.api.nullsafety.NotNullByDefault; + +import javax.annotation.concurrent.NotThreadSafe; + +@NotThreadSafe +@NotNullByDefault +public class ContactItem { + + private final Contact contact; + private boolean connected; + + public ContactItem(Contact contact, boolean connected) { + this.contact = contact; + this.connected = connected; + } + + public Contact getContact() { + return contact; + } + + boolean isConnected() { + return connected; + } + + void setConnected(boolean connected) { + this.connected = connected; + } + +} diff --git a/briar-android/src/org/briarproject/android/contact/ContactItemViewHolder.java b/briar-android/src/org/briarproject/android/contact/ContactItemViewHolder.java new file mode 100644 index 0000000000000000000000000000000000000000..46a81762b60f21b1473f5b0cc95dbfe55a53495b --- /dev/null +++ b/briar-android/src/org/briarproject/android/contact/ContactItemViewHolder.java @@ -0,0 +1,51 @@ +package org.briarproject.android.contact; + +import android.support.annotation.UiThread; +import android.support.v7.widget.RecyclerView; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import org.briarproject.R; +import org.briarproject.android.contact.BaseContactListAdapter.OnContactClickListener; +import org.briarproject.api.identity.Author; +import org.briarproject.api.nullsafety.NotNullByDefault; +import org.jetbrains.annotations.Nullable; + +import im.delight.android.identicons.IdenticonDrawable; + +@UiThread +@NotNullByDefault +public class ContactItemViewHolder<I extends ContactItem> + extends RecyclerView.ViewHolder { + + protected final ViewGroup layout; + protected final ImageView avatar; + protected final TextView name; + + public ContactItemViewHolder(View v) { + super(v); + + layout = (ViewGroup) v; + avatar = (ImageView) v.findViewById(R.id.avatarView); + name = (TextView) v.findViewById(R.id.nameView); + } + + protected void bind(final I item, + @Nullable final OnContactClickListener<I> listener) { + Author author = item.getContact().getAuthor(); + avatar.setImageDrawable( + new IdenticonDrawable(author.getId().getBytes())); + String contactName = author.getName(); + name.setText(contactName); + + layout.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (listener != null) listener.onItemClick(avatar, item); + } + }); + } + +} diff --git a/briar-android/src/org/briarproject/android/contact/ContactListAdapter.java b/briar-android/src/org/briarproject/android/contact/ContactListAdapter.java index a2cf8012d3eae990d857108fa282a63234822805..ae6c45b9aacb28b40004edf8d56c24920f5c2b91 100644 --- a/briar-android/src/org/briarproject/android/contact/ContactListAdapter.java +++ b/briar-android/src/org/briarproject/android/contact/ContactListAdapter.java @@ -1,87 +1,49 @@ package org.briarproject.android.contact; import android.content.Context; -import android.support.v4.view.ViewCompat; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.TextView; import org.briarproject.R; -import org.briarproject.android.util.AndroidUtils; -import org.briarproject.util.StringUtils; -public class ContactListAdapter - extends BaseContactListAdapter<ContactListAdapter.ContactHolder> { +public class ContactListAdapter extends + BaseContactListAdapter<ContactListItem, ContactListItemViewHolder> { - public ContactListAdapter(Context context, OnItemClickListener listener) { - super(context, listener); + public ContactListAdapter(Context context, + OnContactClickListener<ContactListItem> listener) { + super(context, ContactListItem.class, listener); } @Override - public ContactHolder onCreateViewHolder(ViewGroup viewGroup, int i) { + public ContactListItemViewHolder onCreateViewHolder(ViewGroup viewGroup, + int i) { View v = LayoutInflater.from(viewGroup.getContext()).inflate( R.layout.list_item_contact, viewGroup, false); - return new ContactHolder(v); + return new ContactListItemViewHolder(v); } @Override - public void onBindViewHolder(ContactHolder ui, int position) { - super.onBindViewHolder(ui, position); - - ContactListItem item = getItemAt(position); - if (item == null) return; - - // unread count - int unread = item.getUnreadCount(); - if (unread > 0) { - ui.unread.setText(String.valueOf(unread)); - ui.unread.setVisibility(View.VISIBLE); - } else { - ui.unread.setVisibility(View.INVISIBLE); + public boolean areContentsTheSame(ContactListItem c1, ContactListItem c2) { + // check for all properties that influence visual + // representation of contact + if (c1.getUnreadCount() != c2.getUnreadCount()) { + return false; } - - // date of last message - if (item.isEmpty()) { - ui.date.setText(R.string.date_no_private_messages); - } else { - long timestamp = item.getTimestamp(); - ui.date.setText(AndroidUtils.formatDate(ctx, timestamp)); - } - - // online/offline - if (item.isConnected()) { - ui.bulb.setImageResource(R.drawable.contact_connected); - } else { - ui.bulb.setImageResource(R.drawable.contact_disconnected); - } - - ViewCompat.setTransitionName(ui.bulb, - "bulb" + StringUtils.toHexString(item.getGroupId().getBytes())); - } - - protected static class ContactHolder - extends BaseContactListAdapter.BaseContactHolder { - - public final ImageView bulb; - private final TextView unread; - public final TextView date; - public final TextView identity; - - private ContactHolder(View v) { - super(v); - - bulb = (ImageView) v.findViewById(R.id.bulbView); - unread = (TextView) v.findViewById(R.id.unreadCountView); - date = (TextView) v.findViewById(R.id.dateView); - identity = (TextView) v.findViewById(R.id.identityView); + if (c1.getTimestamp() != c2.getTimestamp()) { + return false; } + return super.areContentsTheSame(c1, c2); } @Override public int compare(ContactListItem c1, ContactListItem c2) { - return compareByTime(c1, c2); + long time1 = c1.getTimestamp(); + long time2 = c2.getTimestamp(); + if (time1 < time2) return 1; + if (time1 > time2) return -1; + return 0; } + } diff --git a/briar-android/src/org/briarproject/android/contact/ContactListFragment.java b/briar-android/src/org/briarproject/android/contact/ContactListFragment.java index 9f5d23971e307f06a08e63055ab8c34aa957e530..2d2a098b37d8830f72037b66dbf5bc9bfcf853ae 100644 --- a/briar-android/src/org/briarproject/android/contact/ContactListFragment.java +++ b/briar-android/src/org/briarproject/android/contact/ContactListFragment.java @@ -7,7 +7,6 @@ import android.support.annotation.Nullable; import android.support.v4.app.ActivityCompat; import android.support.v4.app.ActivityOptionsCompat; import android.support.v4.util.Pair; -import android.support.v4.view.ViewCompat; import android.support.v7.widget.LinearLayoutManager; import android.view.LayoutInflater; import android.view.Menu; @@ -19,6 +18,7 @@ import android.view.ViewGroup; import org.briarproject.R; import org.briarproject.android.ActivityComponent; import org.briarproject.android.api.AndroidNotificationManager; +import org.briarproject.android.contact.BaseContactListAdapter.OnContactClickListener; import org.briarproject.android.fragment.BaseFragment; import org.briarproject.android.keyagreement.KeyAgreementActivity; import org.briarproject.android.view.BriarRecyclerView; @@ -41,8 +41,6 @@ import org.briarproject.api.event.IntroductionResponseReceivedEvent; import org.briarproject.api.event.InvitationRequestReceivedEvent; import org.briarproject.api.event.InvitationResponseReceivedEvent; import org.briarproject.api.event.PrivateMessageReceivedEvent; -import org.briarproject.api.identity.IdentityManager; -import org.briarproject.api.identity.LocalAuthor; import org.briarproject.api.introduction.IntroductionRequest; import org.briarproject.api.introduction.IntroductionResponse; import org.briarproject.api.messaging.ConversationManager; @@ -59,6 +57,7 @@ import java.util.logging.Logger; import javax.inject.Inject; import static android.support.v4.app.ActivityOptionsCompat.makeSceneTransitionAnimation; +import static android.support.v4.view.ViewCompat.getTransitionName; import static java.util.logging.Level.INFO; import static java.util.logging.Level.WARNING; import static org.briarproject.android.BriarActivity.GROUP_ID; @@ -82,8 +81,6 @@ public class ContactListFragment extends BaseFragment implements EventListener { @Inject volatile ContactManager contactManager; @Inject - volatile IdentityManager identityManager; - @Inject volatile ConversationManager conversationManager; public static ContactListFragment newInstance() { @@ -108,12 +105,10 @@ public class ContactListFragment extends BaseFragment implements EventListener { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View contentView = - inflater.inflate(R.layout.list, container, - false); + View contentView = inflater.inflate(R.layout.list, container, false); - BaseContactListAdapter.OnItemClickListener onItemClickListener = - new ContactListAdapter.OnItemClickListener() { + OnContactClickListener<ContactListItem> onContactClickListener = + new OnContactClickListener<ContactListItem>() { @Override public void onItemClick(View view, ContactListItem item) { GroupId groupId = item.getGroupId(); @@ -123,17 +118,17 @@ public class ContactListFragment extends BaseFragment implements EventListener { // work-around for android bug #224270 if (Build.VERSION.SDK_INT >= 23) { - ContactListAdapter.ContactHolder holder = - (ContactListAdapter.ContactHolder) list + ContactListItemViewHolder holder = + (ContactListItemViewHolder) list .getRecyclerView() .findViewHolderForAdapterPosition( adapter.findItemPosition( item)); Pair<View, String> avatar = - Pair.create((View) holder.avatar, ViewCompat - .getTransitionName(holder.avatar)); + Pair.create((View) holder.avatar, + getTransitionName(holder.avatar)); Pair<View, String> bulb = - Pair.create((View) holder.bulb, ViewCompat. + Pair.create((View) holder.bulb, getTransitionName(holder.bulb)); ActivityOptionsCompat options = makeSceneTransitionAnimation(getActivity(), @@ -145,8 +140,7 @@ public class ContactListFragment extends BaseFragment implements EventListener { } } }; - - adapter = new ContactListAdapter(getContext(), onItemClickListener); + adapter = new ContactListAdapter(getContext(), onContactClickListener); list = (BriarRecyclerView) contentView.findViewById(R.id.list); list.setLayoutManager(new LinearLayoutManager(getContext())); list.setAdapter(adapter); @@ -212,10 +206,8 @@ public class ContactListFragment extends BaseFragment implements EventListener { conversationManager.getGroupCount(id); boolean connected = connectionRegistry.isConnected(c.getId()); - LocalAuthor localAuthor = identityManager - .getLocalAuthor(c.getLocalAuthorId()); - contacts.add(new ContactListItem(c, localAuthor, - connected, groupId, count)); + contacts.add(new ContactListItem(c, connected, + groupId, count)); } catch (NoSuchContactException e) { // Continue } diff --git a/briar-android/src/org/briarproject/android/contact/ContactListItem.java b/briar-android/src/org/briarproject/android/contact/ContactListItem.java index e9c9e568b2e9c8853d0a17020ac7e4bf754ae646..19808d982bffd0c60c0d435f8b11cc28e6d68c58 100644 --- a/briar-android/src/org/briarproject/android/contact/ContactListItem.java +++ b/briar-android/src/org/briarproject/android/contact/ContactListItem.java @@ -2,63 +2,40 @@ package org.briarproject.android.contact; import org.briarproject.api.clients.MessageTracker.GroupCount; import org.briarproject.api.contact.Contact; -import org.briarproject.api.identity.LocalAuthor; +import org.briarproject.api.nullsafety.NotNullByDefault; import org.briarproject.api.sync.GroupId; -import org.jetbrains.annotations.NotNull; import javax.annotation.concurrent.NotThreadSafe; @NotThreadSafe -public class ContactListItem { +@NotNullByDefault +public class ContactListItem extends ContactItem { - private final Contact contact; - private final LocalAuthor localAuthor; private final GroupId groupId; - private boolean connected, empty; + private boolean empty; private long timestamp; private int unread; - public ContactListItem(@NotNull Contact contact, - @NotNull LocalAuthor localAuthor, boolean connected, - @NotNull GroupId groupId, @NotNull GroupCount count) { - this.contact = contact; - this.localAuthor = localAuthor; + public ContactListItem(Contact contact, boolean connected, GroupId groupId, + GroupCount count) { + super(contact, connected); this.groupId = groupId; - this.connected = connected; this.empty = count.getMsgCount() == 0; this.unread = count.getUnreadCount(); this.timestamp = count.getLatestMsgTime(); } void addMessage(ConversationItem message) { - empty = empty && message == null; - if (message != null) { - if (message.getTime() > timestamp) timestamp = message.getTime(); - if (!message.isRead()) - unread++; - } - } - - public Contact getContact() { - return contact; - } - - public LocalAuthor getLocalAuthor() { - return localAuthor; + empty = false; + if (message.getTime() > timestamp) timestamp = message.getTime(); + if (!message.isRead()) + unread++; } GroupId getGroupId() { return groupId; } - boolean isConnected() { - return connected; - } - - void setConnected(boolean connected) { - this.connected = connected; - } - boolean isEmpty() { return empty; } @@ -70,4 +47,5 @@ public class ContactListItem { int getUnreadCount() { return unread; } -} \ No newline at end of file + +} diff --git a/briar-android/src/org/briarproject/android/contact/ContactListItemViewHolder.java b/briar-android/src/org/briarproject/android/contact/ContactListItemViewHolder.java new file mode 100644 index 0000000000000000000000000000000000000000..6e46526182d120e633dd7c38cac8c68e661deea5 --- /dev/null +++ b/briar-android/src/org/briarproject/android/contact/ContactListItemViewHolder.java @@ -0,0 +1,74 @@ +package org.briarproject.android.contact; + +import android.support.annotation.UiThread; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import org.briarproject.R; +import org.briarproject.android.contact.BaseContactListAdapter.OnContactClickListener; +import org.briarproject.api.nullsafety.NotNullByDefault; +import org.briarproject.api.sync.GroupId; +import org.jetbrains.annotations.Nullable; + +import static android.support.v4.view.ViewCompat.setTransitionName; +import static org.briarproject.android.util.AndroidUtils.formatDate; +import static org.briarproject.util.StringUtils.toHexString; + +@UiThread +@NotNullByDefault +class ContactListItemViewHolder extends ContactItemViewHolder<ContactListItem> { + + protected final ImageView bulb; + private final TextView unread; + private final TextView date; + + public ContactListItemViewHolder(View v) { + super(v); + bulb = (ImageView) v.findViewById(R.id.bulbView); + unread = (TextView) v.findViewById(R.id.unreadCountView); + date = (TextView) v.findViewById(R.id.dateView); + } + + @Override + protected void bind(ContactListItem item, @Nullable + OnContactClickListener<ContactListItem> listener) { + super.bind(item, listener); + + // unread count + int unreadCount = item.getUnreadCount(); + if (unreadCount > 0) { + unread.setText(String.valueOf(unreadCount)); + unread.setVisibility(View.VISIBLE); + } else { + unread.setVisibility(View.INVISIBLE); + } + + // date of last message + if (item.isEmpty()) { + date.setText(R.string.date_no_private_messages); + } else { + long timestamp = item.getTimestamp(); + date.setText(formatDate(date.getContext(), timestamp)); + } + + // online/offline + if (item.isConnected()) { + bulb.setImageResource(R.drawable.contact_connected); + } else { + bulb.setImageResource(R.drawable.contact_disconnected); + } + + setTransitionName(avatar, getAvatarTransitionName(item.getGroupId())); + setTransitionName(bulb, getBulbTransitionName(item.getGroupId())); + } + + private String getAvatarTransitionName(GroupId g) { + return "avatar" + toHexString(g.getBytes()); + } + + private String getBulbTransitionName(GroupId g) { + return "bulb" + toHexString(g.getBytes()); + } + +} diff --git a/briar-android/src/org/briarproject/android/introduction/ContactChooserAdapter.java b/briar-android/src/org/briarproject/android/introduction/ContactChooserAdapter.java deleted file mode 100644 index e291302b8e6b86323bfbd8ff587bce6854fbc8ee..0000000000000000000000000000000000000000 --- a/briar-android/src/org/briarproject/android/introduction/ContactChooserAdapter.java +++ /dev/null @@ -1,63 +0,0 @@ -package org.briarproject.android.introduction; - -import android.content.Context; -import android.support.annotation.UiThread; -import android.view.View; - -import org.briarproject.android.contact.ContactListAdapter; -import org.briarproject.android.contact.ContactListItem; -import org.briarproject.api.identity.AuthorId; - -@UiThread -class ContactChooserAdapter extends ContactListAdapter { - - private AuthorId localAuthorId; - - ContactChooserAdapter(Context context, OnItemClickListener listener) { - super(context, listener); - } - - @Override - public void onBindViewHolder(final ContactHolder ui, final int position) { - super.onBindViewHolder(ui, position); - - final ContactListItem item = getItemAt(position); - if (item == null) return; - - ui.name.setText(item.getContact().getAuthor().getName()); - - ui.identity.setText(item.getLocalAuthor().getName()); - ui.identity.setVisibility(View.VISIBLE); - - if (!item.getLocalAuthor().getId().equals(localAuthorId)) { - grayOutItem(ui); - } - } - - @Override - public int compare(ContactListItem c1, ContactListItem c2) { - return compareByName(c1, c2); - } - - /** - * Set the identity from whose perspective the contact shall be chosen. - * Contacts that belong to a different author will be shown grayed out, - * but are still clickable. - * - * @param authorId The ID of the local Author - */ - void setLocalAuthor(AuthorId authorId) { - localAuthorId = authorId; - notifyDataSetChanged(); - } - - private void grayOutItem(final ContactHolder ui) { - float alpha = 0.25f; - ui.bulb.setAlpha(alpha); - ui.avatar.setAlpha(alpha); - ui.name.setAlpha(alpha); - ui.date.setAlpha(alpha); - ui.identity.setAlpha(alpha); - } - -} diff --git a/briar-android/src/org/briarproject/android/introduction/ContactChooserFragment.java b/briar-android/src/org/briarproject/android/introduction/ContactChooserFragment.java index 888cc61e79eb48b713a61ffeba6788c759f02abb..4e939d2b26b0a4ca26eea2184e28f8ad10f586b9 100644 --- a/briar-android/src/org/briarproject/android/introduction/ContactChooserFragment.java +++ b/briar-android/src/org/briarproject/android/introduction/ContactChooserFragment.java @@ -1,10 +1,8 @@ package org.briarproject.android.introduction; import android.content.Context; -import android.content.DialogInterface; import android.os.Build; import android.os.Bundle; -import android.support.v7.app.AlertDialog; import android.support.v7.widget.LinearLayoutManager; import android.transition.Fade; import android.view.LayoutInflater; @@ -13,6 +11,7 @@ import android.view.ViewGroup; import org.briarproject.R; import org.briarproject.android.ActivityComponent; +import org.briarproject.android.contact.BaseContactListAdapter.OnContactClickListener; import org.briarproject.android.contact.ContactListAdapter; import org.briarproject.android.contact.ContactListItem; import org.briarproject.android.fragment.BaseFragment; @@ -22,9 +21,6 @@ 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.identity.AuthorId; -import org.briarproject.api.identity.IdentityManager; -import org.briarproject.api.identity.LocalAuthor; import org.briarproject.api.messaging.ConversationManager; import org.briarproject.api.plugins.ConnectionRegistry; import org.briarproject.api.sync.GroupId; @@ -44,7 +40,7 @@ public class ContactChooserFragment extends BaseFragment { private IntroductionActivity introductionActivity; private BriarRecyclerView list; - private ContactChooserAdapter adapter; + private ContactListAdapter adapter; private ContactId contactId; // Fields that are accessed from background threads must be volatile @@ -52,8 +48,6 @@ public class ContactChooserFragment extends BaseFragment { @Inject volatile ContactManager contactManager; @Inject - volatile IdentityManager identityManager; - @Inject volatile ConversationManager conversationManager; @Inject volatile ConnectionRegistry connectionRegistry; @@ -83,22 +77,16 @@ public class ContactChooserFragment extends BaseFragment { setExitTransition(new Fade()); } - ContactListAdapter.OnItemClickListener onItemClickListener = - new ContactListAdapter.OnItemClickListener() { + OnContactClickListener<ContactListItem> onContactClickListener = + new OnContactClickListener<ContactListItem>() { @Override public void onItemClick(View view, ContactListItem item) { if (c1 == null) throw new IllegalStateException(); Contact c2 = item.getContact(); - if (!c1.getLocalAuthorId() - .equals(c2.getLocalAuthorId())) { - warnAboutDifferentIdentities(view, c1, c2); - } else { - introductionActivity.showMessageScreen(view, c1, - c2); - } + introductionActivity.showMessageScreen(view, c1, c2); } }; - adapter = new ContactChooserAdapter(getActivity(), onItemClickListener); + adapter = new ContactListAdapter(getActivity(), onContactClickListener); list = (BriarRecyclerView) contentView.findViewById(R.id.list); list.setLayoutManager(new LinearLayoutManager(getActivity())); @@ -139,8 +127,6 @@ public class ContactChooserFragment extends BaseFragment { public void run() { try { List<ContactListItem> contacts = new ArrayList<>(); - AuthorId localAuthorId = - identityManager.getLocalAuthor().getId(); for (Contact c : contactManager.getActiveContacts()) { if (c.getId().equals(contactId)) { c1 = c; @@ -152,13 +138,11 @@ public class ContactChooserFragment extends BaseFragment { conversationManager.getGroupCount(id); boolean connected = connectionRegistry.isConnected(c.getId()); - LocalAuthor localAuthor = identityManager - .getLocalAuthor(c.getLocalAuthorId()); - contacts.add(new ContactListItem(c, localAuthor, - connected, groupId, count)); + contacts.add(new ContactListItem(c, connected, + groupId, count)); } } - displayContacts(localAuthorId, contacts); + displayContacts(contacts); } catch (DbException e) { if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); @@ -167,37 +151,14 @@ public class ContactChooserFragment extends BaseFragment { }); } - private void displayContacts(final AuthorId localAuthorId, - final List<ContactListItem> contacts) { + private void displayContacts(final List<ContactListItem> contacts) { introductionActivity.runOnUiThreadUnlessDestroyed(new Runnable() { @Override public void run() { - adapter.setLocalAuthor(localAuthorId); if (contacts.isEmpty()) list.showData(); else adapter.addAll(contacts); } }); } - private void warnAboutDifferentIdentities(final View view, final Contact c1, - final Contact c2) { - - DialogInterface.OnClickListener okListener = - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - introductionActivity.showMessageScreen(view, c1, c2); - } - }; - AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(), - R.style.BriarDialogTheme); - builder.setTitle(getString( - R.string.introduction_warn_different_identities_title)); - builder.setMessage(getString( - R.string.introduction_warn_different_identities_text)); - builder.setPositiveButton(R.string.dialog_button_introduce, okListener); - builder.setNegativeButton(android.R.string.cancel, null); - builder.show(); - } - } diff --git a/briar-android/src/org/briarproject/android/introduction/IntroductionActivity.java b/briar-android/src/org/briarproject/android/introduction/IntroductionActivity.java index aeada3f1d1187b954a05a2b2b719bc5d8e559435..8e9d5c389ea53ef7bf6bc445eb684f73985a3e19 100644 --- a/briar-android/src/org/briarproject/android/introduction/IntroductionActivity.java +++ b/briar-android/src/org/briarproject/android/introduction/IntroductionActivity.java @@ -13,12 +13,12 @@ import org.briarproject.R; import org.briarproject.android.ActivityComponent; import org.briarproject.android.BriarActivity; import org.briarproject.android.fragment.BaseFragment; +import org.briarproject.android.fragment.BaseFragment.BaseFragmentListener; import org.briarproject.api.contact.Contact; import org.briarproject.api.contact.ContactId; -// TODO extend the BriarFragmentActivity ? -public class IntroductionActivity extends BriarActivity implements - BaseFragment.BaseFragmentListener { +public class IntroductionActivity extends BriarActivity + implements BaseFragmentListener { public static final String CONTACT_ID = "briar.CONTACT_ID"; diff --git a/briar-android/src/org/briarproject/android/sharing/ContactSelectorAdapter.java b/briar-android/src/org/briarproject/android/sharing/ContactSelectorAdapter.java index 0d4d68912f5754397e9d417b1a56b63403131021..9573c6398dc0d5fa030bc8c03016d30dbe15ca49 100644 --- a/briar-android/src/org/briarproject/android/sharing/ContactSelectorAdapter.java +++ b/briar-android/src/org/briarproject/android/sharing/ContactSelectorAdapter.java @@ -4,8 +4,6 @@ import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.CheckBox; -import android.widget.TextView; import org.briarproject.R; import org.briarproject.android.contact.BaseContactListAdapter; @@ -14,16 +12,12 @@ import org.briarproject.api.contact.ContactId; import java.util.ArrayList; import java.util.Collection; -import static android.view.View.GONE; -import static android.view.View.VISIBLE; - -class ContactSelectorAdapter - extends BaseContactListAdapter<ContactSelectorAdapter.SelectableContactHolder> { +class ContactSelectorAdapter extends + BaseContactListAdapter<SelectableContactItem, SelectableContactHolder> { ContactSelectorAdapter(Context context, - OnItemClickListener listener) { - - super(context, listener); + OnContactClickListener<SelectableContactItem> listener) { + super(context, SelectableContactItem.class, listener); } @Override @@ -31,66 +25,17 @@ class ContactSelectorAdapter int i) { View v = LayoutInflater.from(ctx).inflate( R.layout.list_item_selectable_contact, viewGroup, false); - return new SelectableContactHolder(v); } - @Override - public void onBindViewHolder(SelectableContactHolder ui, int position) { - super.onBindViewHolder(ui, position); - - SelectableContactListItem item = - (SelectableContactListItem) getItemAt(position); - if (item == null) return; - - if (item.isSelected()) { - ui.checkBox.setChecked(true); - } else { - ui.checkBox.setChecked(false); - } - - if (item.isDisabled()) { - // we share this forum already with that contact - ui.layout.setEnabled(false); - ui.shared.setVisibility(VISIBLE); - grayOutItem(ui, true); - } else { - ui.layout.setEnabled(true); - ui.shared.setVisibility(GONE); - grayOutItem(ui, false); - } - } - Collection<ContactId> getSelectedContactIds() { Collection<ContactId> selected = new ArrayList<>(); for (int i = 0; i < items.size(); i++) { - SelectableContactListItem item = - (SelectableContactListItem) items.get(i); + SelectableContactItem item = items.get(i); if (item.isSelected()) selected.add(item.getContact().getId()); } - return selected; } - static class SelectableContactHolder - extends BaseContactListAdapter.BaseContactHolder { - - private final CheckBox checkBox; - private final TextView shared; - - private SelectableContactHolder(View v) { - super(v); - - checkBox = (CheckBox) v.findViewById(R.id.checkBox); - shared = (TextView) v.findViewById(R.id.infoView); - } - } - - private void grayOutItem(SelectableContactHolder ui, boolean gray) { - float alpha = gray ? 0.25f : 1f; - ui.avatar.setAlpha(alpha); - ui.name.setAlpha(alpha); - ui.checkBox.setAlpha(alpha); - } } diff --git a/briar-android/src/org/briarproject/android/sharing/ContactSelectorFragment.java b/briar-android/src/org/briarproject/android/sharing/ContactSelectorFragment.java index 03e4da3979fc6de40030705c21b01e471f532ab1..cc8f46230b25d505000c71c67ffb96b60786b320 100644 --- a/briar-android/src/org/briarproject/android/sharing/ContactSelectorFragment.java +++ b/briar-android/src/org/briarproject/android/sharing/ContactSelectorFragment.java @@ -15,16 +15,14 @@ import android.view.ViewGroup; import org.briarproject.R; import org.briarproject.android.ActivityComponent; -import org.briarproject.android.contact.BaseContactListAdapter; -import org.briarproject.android.contact.ContactListItem; +import org.briarproject.android.contact.BaseContactListAdapter.OnContactClickListener; import org.briarproject.android.fragment.BaseFragment; import org.briarproject.android.view.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.identity.IdentityManager; -import org.briarproject.api.identity.LocalAuthor; +import org.briarproject.api.plugins.ConnectionRegistry; import org.briarproject.api.sync.GroupId; import java.util.ArrayList; @@ -41,8 +39,8 @@ import static org.briarproject.android.sharing.ShareActivity.getContactsFromIds; import static org.briarproject.android.sharing.ShareActivity.getContactsFromIntegers; import static org.briarproject.api.sharing.SharingConstants.GROUP_ID; -public class ContactSelectorFragment extends BaseFragment implements - BaseContactListAdapter.OnItemClickListener { +public class ContactSelectorFragment extends BaseFragment + implements OnContactClickListener<SelectableContactItem> { public static final String TAG = ContactSelectorFragment.class.getName(); private static final Logger LOG = Logger.getLogger(TAG); @@ -56,7 +54,7 @@ public class ContactSelectorFragment extends BaseFragment implements @Inject volatile ContactManager contactManager; @Inject - volatile IdentityManager identityManager; + volatile ConnectionRegistry connectionRegistry; private volatile GroupId groupId; private volatile ContactSelectorListener listener; @@ -115,7 +113,6 @@ public class ContactSelectorFragment extends BaseFragment implements selectedContacts = getContactsFromIntegers(intContacts); } } - return contentView; } @@ -170,8 +167,8 @@ public class ContactSelectorFragment extends BaseFragment implements } @Override - public void onItemClick(View view, ContactListItem item) { - ((SelectableContactListItem) item).toggleSelected(); + public void onItemClick(View view, SelectableContactItem item) { + item.toggleSelected(); adapter.notifyItemChanged(adapter.findItemPosition(item), item); updateMenuItem(); @@ -183,18 +180,19 @@ public class ContactSelectorFragment extends BaseFragment implements public void run() { try { long now = System.currentTimeMillis(); - List<ContactListItem> contacts = new ArrayList<>(); - + List<SelectableContactItem> contacts = + new ArrayList<>(); for (Contact c : contactManager.getActiveContacts()) { - LocalAuthor localAuthor = identityManager - .getLocalAuthor(c.getLocalAuthorId()); + // is this contact online? + boolean connected = + connectionRegistry.isConnected(c.getId()); // was this contact already selected? boolean selected = selection != null && selection.contains(c.getId()); // do we have already some sharing with that contact? boolean disabled = listener.isDisabled(groupId, c); - contacts.add(new SelectableContactListItem(c, - localAuthor, groupId, selected, disabled)); + contacts.add(new SelectableContactItem(c, connected, + selected, disabled)); } long duration = System.currentTimeMillis() - now; if (LOG.isLoggable(INFO)) @@ -208,7 +206,8 @@ public class ContactSelectorFragment extends BaseFragment implements }); } - private void displayContacts(final List<ContactListItem> contacts) { + private void displayContacts( + final List<SelectableContactItem> contacts) { listener.runOnUiThreadUnlessDestroyed(new Runnable() { @Override public void run() { diff --git a/briar-android/src/org/briarproject/android/sharing/SelectableContactHolder.java b/briar-android/src/org/briarproject/android/sharing/SelectableContactHolder.java new file mode 100644 index 0000000000000000000000000000000000000000..9f0eddfe8c1af47ca72d0f43d0167ba79600fed2 --- /dev/null +++ b/briar-android/src/org/briarproject/android/sharing/SelectableContactHolder.java @@ -0,0 +1,61 @@ +package org.briarproject.android.sharing; + +import android.support.annotation.UiThread; +import android.view.View; +import android.widget.CheckBox; +import android.widget.TextView; + +import org.briarproject.R; +import org.briarproject.android.contact.BaseContactListAdapter.OnContactClickListener; +import org.briarproject.android.contact.ContactItemViewHolder; +import org.briarproject.api.nullsafety.NotNullByDefault; +import org.jetbrains.annotations.Nullable; + +import static android.view.View.GONE; +import static android.view.View.VISIBLE; + +@UiThread +@NotNullByDefault +class SelectableContactHolder + extends ContactItemViewHolder<SelectableContactItem> { + + private final CheckBox checkBox; + private final TextView shared; + + SelectableContactHolder(View v) { + super(v); + checkBox = (CheckBox) v.findViewById(R.id.checkBox); + shared = (TextView) v.findViewById(R.id.infoView); + } + + @Override + protected void bind(SelectableContactItem item, @Nullable + OnContactClickListener<SelectableContactItem> listener) { + super.bind(item, listener); + + if (item.isSelected()) { + checkBox.setChecked(true); + } else { + checkBox.setChecked(false); + } + + if (item.isDisabled()) { + // we share this forum already with that contact + layout.setEnabled(false); + shared.setVisibility(VISIBLE); + grayOutItem(true); + } else { + layout.setEnabled(true); + shared.setVisibility(GONE); + grayOutItem(false); + } + } + + private void grayOutItem(boolean gray) { + float alpha = gray ? 0.25f : 1f; + avatar.setAlpha(alpha); + name.setAlpha(alpha); + checkBox.setAlpha(alpha); + } + +} diff --git a/briar-android/src/org/briarproject/android/sharing/SelectableContactItem.java b/briar-android/src/org/briarproject/android/sharing/SelectableContactItem.java new file mode 100644 index 0000000000000000000000000000000000000000..8bd5edf938b8a4b69d069b7dadf76597018cda9c --- /dev/null +++ b/briar-android/src/org/briarproject/android/sharing/SelectableContactItem.java @@ -0,0 +1,34 @@ +package org.briarproject.android.sharing; + +import org.briarproject.android.contact.ContactItem; +import org.briarproject.api.contact.Contact; +import org.briarproject.api.nullsafety.NotNullByDefault; + +import javax.annotation.concurrent.NotThreadSafe; + +@NotThreadSafe +@NotNullByDefault +public class SelectableContactItem extends ContactItem { + + private boolean selected, disabled; + + public SelectableContactItem(Contact contact, boolean connected, + boolean selected, boolean disabled) { + super(contact, connected); + this.selected = selected; + this.disabled = disabled; + } + + public boolean isSelected() { + return selected; + } + + public void toggleSelected() { + selected = !selected; + } + + public boolean isDisabled() { + return disabled; + } + +} diff --git a/briar-android/src/org/briarproject/android/sharing/SelectableContactListItem.java b/briar-android/src/org/briarproject/android/sharing/SelectableContactListItem.java deleted file mode 100644 index 8e76d39e705a562788528b93a0f900ed57940f89..0000000000000000000000000000000000000000 --- a/briar-android/src/org/briarproject/android/sharing/SelectableContactListItem.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.briarproject.android.sharing; - -import android.support.annotation.UiThread; - -import org.briarproject.android.contact.ContactListItem; -import org.briarproject.api.clients.MessageTracker.GroupCount; -import org.briarproject.api.contact.Contact; -import org.briarproject.api.identity.LocalAuthor; -import org.briarproject.api.sync.GroupId; - -// This class is NOT thread-safe -public class SelectableContactListItem extends ContactListItem { - - private boolean selected, disabled; - - public SelectableContactListItem(Contact contact, LocalAuthor localAuthor, - GroupId groupId, boolean selected, boolean disabled) { - - super(contact, localAuthor, false, groupId, new GroupCount(0, 0, 0)); - - this.selected = selected; - this.disabled = disabled; - } - - public void setSelected(boolean selected) { - this.selected = selected; - } - - public boolean isSelected() { - return selected; - } - - public void toggleSelected() { - selected = !selected; - } - - public boolean isDisabled() { - return disabled; - } -} diff --git a/briar-android/src/org/briarproject/android/sharing/SharingStatusActivity.java b/briar-android/src/org/briarproject/android/sharing/SharingStatusActivity.java index 377b10d71c52ead6583db71e6d44d92eb5048efa..f1a7bda25378d76a717d670558ddacc8370d97f4 100644 --- a/briar-android/src/org/briarproject/android/sharing/SharingStatusActivity.java +++ b/briar-android/src/org/briarproject/android/sharing/SharingStatusActivity.java @@ -7,13 +7,11 @@ import android.view.MenuItem; import org.briarproject.R; import org.briarproject.android.BriarActivity; -import org.briarproject.android.contact.ContactListItem; +import org.briarproject.android.contact.ContactItem; import org.briarproject.android.view.BriarRecyclerView; -import org.briarproject.api.clients.MessageTracker.GroupCount; import org.briarproject.api.contact.Contact; import org.briarproject.api.db.DbException; -import org.briarproject.api.identity.IdentityManager; -import org.briarproject.api.identity.LocalAuthor; +import org.briarproject.api.plugins.ConnectionRegistry; import org.briarproject.api.sync.GroupId; import java.util.ArrayList; @@ -36,7 +34,7 @@ abstract class SharingStatusActivity extends BriarActivity { // Fields that are accessed from background threads must be volatile @Inject - volatile IdentityManager identityManager; + volatile ConnectionRegistry connectionRegistry; @Override public void onCreate(Bundle savedInstanceState) { @@ -109,13 +107,11 @@ abstract class SharingStatusActivity extends BriarActivity { @Override public void run() { try { - List<ContactListItem> contactItems = new ArrayList<>(); + List<ContactItem> contactItems = new ArrayList<>(); for (Contact c : getSharedBy()) { - LocalAuthor localAuthor = identityManager - .getLocalAuthor(c.getLocalAuthorId()); - ContactListItem item = - new ContactListItem(c, localAuthor, false, - groupId, new GroupCount(0, 0, 0)); + boolean isConnected = + connectionRegistry.isConnected(c.getId()); + ContactItem item = new ContactItem(c, isConnected); contactItems.add(item); } displaySharedBy(contactItems); @@ -127,7 +123,7 @@ abstract class SharingStatusActivity extends BriarActivity { }); } - private void displaySharedBy(final List<ContactListItem> contacts) { + private void displaySharedBy(final List<ContactItem> contacts) { runOnUiThreadUnlessDestroyed(new Runnable() { @Override public void run() { @@ -142,13 +138,11 @@ abstract class SharingStatusActivity extends BriarActivity { @Override public void run() { try { - List<ContactListItem> contactItems = new ArrayList<>(); + List<ContactItem> contactItems = new ArrayList<>(); for (Contact c : getSharedWith()) { - LocalAuthor localAuthor = identityManager - .getLocalAuthor(c.getLocalAuthorId()); - ContactListItem item = - new ContactListItem(c, localAuthor, false, - groupId, new GroupCount(0, 0, 0)); + boolean isConnected = + connectionRegistry.isConnected(c.getId()); + ContactItem item = new ContactItem(c, isConnected); contactItems.add(item); } displaySharedWith(contactItems); @@ -160,7 +154,7 @@ abstract class SharingStatusActivity extends BriarActivity { }); } - private void displaySharedWith(final List<ContactListItem> contacts) { + private void displaySharedWith(final List<ContactItem> contacts) { runOnUiThreadUnlessDestroyed(new Runnable() { @Override public void run() { diff --git a/briar-android/src/org/briarproject/android/sharing/SharingStatusAdapter.java b/briar-android/src/org/briarproject/android/sharing/SharingStatusAdapter.java index 5f7dd803da443e0751b195d17a469fcff9ae1e41..539d9f81f237fc74dc38ac391c25bb1e92f3f25d 100644 --- a/briar-android/src/org/briarproject/android/sharing/SharingStatusAdapter.java +++ b/briar-android/src/org/briarproject/android/sharing/SharingStatusAdapter.java @@ -7,20 +7,22 @@ import android.view.ViewGroup; import org.briarproject.R; import org.briarproject.android.contact.BaseContactListAdapter; +import org.briarproject.android.contact.ContactItem; +import org.briarproject.android.contact.ContactItemViewHolder; -class SharingStatusAdapter - extends BaseContactListAdapter<BaseContactListAdapter.BaseContactHolder> { +class SharingStatusAdapter extends + BaseContactListAdapter<ContactItem, ContactItemViewHolder<ContactItem>> { SharingStatusAdapter(Context context) { - super(context, null); + super(context, ContactItem.class, null); } @Override - public BaseContactHolder onCreateViewHolder(ViewGroup viewGroup, int i) { + public ContactItemViewHolder<ContactItem> onCreateViewHolder( + ViewGroup viewGroup, int i) { View v = LayoutInflater.from(viewGroup.getContext()).inflate( R.layout.list_item_contact_small, viewGroup, false); - - return new BaseContactHolder(v); + return new ContactItemViewHolder<>(v); } }