Starting to Materialize the Share dialog.
TODO(rosswang): hella animations. Also, I have not tested discovery yet.
Change-Id: I2551a483a272dc263db03765e825eb82e8697add
diff --git a/app/build.gradle b/app/build.gradle
index 0393b7f..119d275 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -75,7 +75,7 @@
'com.android.support:appcompat-v7:23.1.1',
'com.android.support:design:23.1.1',
'com.android.support:cardview-v7:23.1.1',
- 'com.android.support:recyclerview-v7:23.1.1',
+ 'com.android.support:recyclerview-v7:23.2.1',
'com.google.guava:guava:19.0'
)
firebaseCompile 'com.firebase:firebase-client-android:2.5.2'
diff --git a/app/src/main/res/layout/task_row.xml b/app/src/main/res/layout/task_row.xml
index 21415bd..cca2ed9 100644
--- a/app/src/main/res/layout/task_row.xml
+++ b/app/src/main/res/layout/task_row.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/swipe_right"
diff --git a/app/src/main/res/layout/todo_list_row.xml b/app/src/main/res/layout/todo_list_row.xml
index 4dd003b..756dc05 100644
--- a/app/src/main/res/layout/todo_list_row.xml
+++ b/app/src/main/res/layout/todo_list_row.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/swipe_right"
android:layout_width="match_parent"
diff --git a/app/src/syncbase/java/io/v/todos/sharing/ContactAdapter.java b/app/src/syncbase/java/io/v/todos/sharing/ContactAdapter.java
new file mode 100644
index 0000000..2bab5c9
--- /dev/null
+++ b/app/src/syncbase/java/io/v/todos/sharing/ContactAdapter.java
@@ -0,0 +1,311 @@
+// Copyright 2016 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package io.v.todos.sharing;
+
+import android.support.annotation.StringRes;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import com.google.common.collect.HashMultiset;
+import com.google.common.collect.Multiset;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+import io.v.todos.R;
+
+public class ContactAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
+ public static final int
+ VIEW_TYPE_SUBHEADER = 0,
+ VIEW_TYPE_CONTACT = 1;
+
+ public interface ContactTouchListener {
+ void onContactTouch(RecyclerView.ViewHolder viewHolder);
+ }
+
+ private static class SubheaderViewHolder extends RecyclerView.ViewHolder {
+ public final TextView category;
+
+ public SubheaderViewHolder(ViewGroup parent) {
+ super(LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.sharing_subheader, parent, false));
+ category = (TextView) itemView.findViewById(R.id.category);
+ }
+ }
+
+ private static class ContactViewHolder extends RecyclerView.ViewHolder {
+ public final TextView name;
+
+ public ContactViewHolder(ViewGroup parent) {
+ super(LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.sharing_entry, parent, false));
+ name = (TextView) itemView.findViewById(R.id.name);
+ }
+ }
+
+ // TODO(rosswang): Save expanded state, and/or manage more intelligently.
+ // TODO(rosswang): Potentially show condensed avatars in collapsed state.
+ private static class Sublist {
+ @StringRes
+ public final int header;
+ public final List<String> items = new ArrayList<>();
+
+ public Sublist(@StringRes int header) {
+ this.header = header;
+ }
+
+ public int getEffectiveSize() {
+ return 1 + items.size();
+ }
+ }
+
+ private final Sublist
+ mSharingAlready = new Sublist(R.string.sharing_already),
+ mSharingPossible = new Sublist(R.string.sharing_possible);
+
+ private final Sublist[] mSections = new Sublist[]{
+ mSharingAlready,
+ mSharingPossible
+ };
+
+ private Collection<String> mSharedAlready;
+ private final Set<String> mSharesAdded, mSharesRemoved, mSharesRecent;
+ private final Multiset<String> mDiscoCounter = HashMultiset.create();
+ private ContactTouchListener mContactTouchListener;
+
+ public ContactAdapter(Collection<String> sharedAlready, Set<String> sharesAdded,
+ Set<String> sharesRemoved, Set<String> sharesRecent) {
+ mSharesAdded = sharesAdded;
+ mSharesRemoved = sharesRemoved;
+ mSharesRecent = sharesRecent;
+
+ Set<String> recentUnaccountedFor = new HashSet<>(sharesRecent);
+ recentUnaccountedFor.removeAll(sharedAlready);
+ recentUnaccountedFor.removeAll(sharesAdded);
+ recentUnaccountedFor.removeAll(sharesRemoved);
+ mSharingPossible.items.addAll(recentUnaccountedFor);
+ mSharingPossible.items.addAll(sharesRemoved);
+ Collections.sort(mSharingPossible.items);
+
+ setSharedAlreadyData(sharedAlready);
+ }
+
+ private void setSharedAlreadyData(Collection<String> sharedAlready) {
+ mSharedAlready = sharedAlready;
+ mSharingAlready.items.clear();
+ mSharingAlready.items.addAll(sharedAlready);
+ mSharingAlready.items.removeAll(mSharesRemoved);
+ mSharingAlready.items.addAll(mSharesAdded);
+ Collections.sort(mSharingAlready.items);
+ }
+
+ public void filterDeltas() {
+ mSharesAdded.removeAll(mSharedAlready);
+ mSharesRemoved.retainAll(mSharedAlready);
+ }
+
+ private static class SublistEntry {
+ public final Sublist sublist;
+ public final int itemPosition;
+ public final String item;
+
+ public SublistEntry(Sublist sublist, int itemPosition, String item) {
+ this.sublist = sublist;
+ this.itemPosition = itemPosition;
+ this.item = item;
+ }
+ }
+
+ private SublistEntry getSublistItemPosition(int position) {
+ for (Sublist section : mSections) {
+ if (position == 0) {
+ return new SublistEntry(section, -1, null);
+ }
+ position--;
+ if (position < section.items.size()) {
+ return new SublistEntry(section, position, section.items.get(position));
+ }
+ position -= section.items.size();
+ }
+ throw new IndexOutOfBoundsException("No sublist at position " + position);
+ }
+
+ /**
+ * Inverse of {@link #getSublistItemPosition(int)}.
+ */
+ private int getViewPosition(Sublist section, int itemPosition) {
+ int offset = 1;
+ for (Sublist cursor: mSections) {
+ if (cursor == section) {
+ return offset + itemPosition;
+ } else {
+ offset += cursor.getEffectiveSize();
+ }
+ }
+ throw new NoSuchElementException("Section is not in list");
+ }
+
+ @Override
+ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ if (viewType == VIEW_TYPE_SUBHEADER) {
+ return new SubheaderViewHolder(parent);
+ } else {
+ final ContactViewHolder cvh = new ContactViewHolder(parent);
+ cvh.itemView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mContactTouchListener.onContactTouch(cvh);
+ }
+ });
+ return cvh;
+ }
+ }
+
+ @Override
+ public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
+ final SublistEntry entry = getSublistItemPosition(position);
+ if (entry.item == null) {
+ final SubheaderViewHolder svh = (SubheaderViewHolder) holder;
+ svh.category.setText(entry.sublist.header);
+ } else {
+ final ContactViewHolder cvh = (ContactViewHolder) holder;
+ cvh.name.setText(entry.item);
+ }
+ }
+
+ @Override
+ public int getItemCount() {
+ int count = 0;
+ for (Sublist section : mSections) {
+ count += section.getEffectiveSize();
+ }
+ return count;
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ return getSublistItemPosition(position).item == null ?
+ VIEW_TYPE_SUBHEADER : VIEW_TYPE_CONTACT;
+ }
+
+ public void setContactTouchListener(ContactTouchListener listener) {
+ mContactTouchListener = listener;
+ }
+
+ public void onNearbyDeviceLost(String email) {
+ // short-circuit note; remove must happen
+ if (mDiscoCounter.remove(email, 1) > 1 ||
+ Collections.binarySearch(mSharingAlready.items, email) >= 0) {
+ return;
+ }
+ int i = Collections.binarySearch(mSharingPossible.items, email);
+ if (i >= 0) {
+ mSharingPossible.items.remove(i);
+ notifyItemRemoved(getViewPosition(mSharingPossible, i));
+ }
+ }
+
+ public void onNearbyDeviceDiscovered(String email) {
+ // short-circuit note; add must happen
+ if (mDiscoCounter.add(email, 1) > 0 ||
+ Collections.binarySearch(mSharingAlready.items, email) >= 0) {
+ return;
+ }
+ int i = Collections.binarySearch(mSharingPossible.items, email);
+ if (i < 0) {
+ i = ~i;
+ mSharingPossible.items.add(i, email);
+ notifyItemInserted(getViewPosition(mSharingPossible, i));
+ }
+ }
+
+ private int shareWithPossible(int i) {
+ String email = mSharingPossible.items.remove(i);
+ // Animate movement by moving the item.
+ int j = ~Collections.binarySearch(mSharingAlready.items, email);
+ int oldPosition = getViewPosition(mSharingPossible, i);
+ int newPosition = getViewPosition(mSharingAlready, j);
+ mSharingAlready.items.add(j, email);
+ notifyItemMoved(oldPosition, newPosition);
+ registerShare(email);
+ return newPosition;
+ }
+
+ private void unshare(int i) {
+ String email = mSharingAlready.items.remove(i);
+ int j = ~Collections.binarySearch(mSharingPossible.items, email);
+ mSharingPossible.items.add(j, email);
+ registerUnshare(email);
+
+ // animate movement
+ int oldPosition = getViewPosition(mSharingAlready, i);
+ int newPosition = getViewPosition(mSharingPossible, j);
+ notifyItemMoved(oldPosition, newPosition);
+ }
+
+ private int insertShare(String email) {
+ int i = Collections.binarySearch(mSharingAlready.items, email);
+ if (i >= 0) {
+ return getViewPosition(mSharingAlready, i);
+ } else {
+ i = ~i;
+ mSharingAlready.items.add(i, email);
+ i = getViewPosition(mSharingAlready, i);
+ notifyItemInserted(i);
+ registerShare(email);
+ return i;
+ }
+ }
+
+ private void registerShare(String email) {
+ mSharesRecent.add(email);
+ if (!mSharesRemoved.remove(email)) {
+ mSharesAdded.add(email);
+ }
+ }
+
+ private void registerUnshare(String email) {
+ if (!mSharesAdded.remove(email)) {
+ mSharesRemoved.add(email);
+ }
+ }
+
+ /**
+ * @return the position of the e-mail in the adapter
+ */
+ public int onCustomShare(String email) {
+ int i = Collections.binarySearch(mSharingPossible.items, email);
+ if (i >= 0) {
+ return shareWithPossible(i);
+ } else {
+ return insertShare(email);
+ }
+ }
+
+ public void setSharedTo(Collection<String> sharedAlready) {
+ setSharedAlreadyData(sharedAlready);
+ // TODO(rosswang): list differ
+
+ notifyDataSetChanged();
+ }
+
+ // TODO(rosswang): this is a hacky abstraction
+ public void toggleContact(int position) {
+ SublistEntry entry = getSublistItemPosition(position);
+ if (entry.sublist == mSharingAlready) {
+ unshare(entry.itemPosition);
+ } else {
+ shareWithPossible(entry.itemPosition);
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/syncbase/java/io/v/todos/sharing/ShareListDialogFragment.java b/app/src/syncbase/java/io/v/todos/sharing/ShareListDialogFragment.java
index e380e05..cd654a4 100644
--- a/app/src/syncbase/java/io/v/todos/sharing/ShareListDialogFragment.java
+++ b/app/src/syncbase/java/io/v/todos/sharing/ShareListDialogFragment.java
@@ -8,13 +8,12 @@
import android.app.DialogFragment;
import android.app.FragmentManager;
import android.content.DialogInterface;
-import android.graphics.Paint;
import android.os.Bundle;
import android.support.v7.app.AlertDialog;
+import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.RecyclerView;
import android.view.KeyEvent;
import android.view.View;
-import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.widget.EditText;
import android.widget.TextView;
@@ -25,11 +24,7 @@
import com.google.common.util.concurrent.ListenableFuture;
import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
import java.util.Set;
import javax.annotation.Nullable;
@@ -48,24 +43,23 @@
* allow entry of any value. Confirming this dialog sends the set of added and removed emails. Tap
* to add/remove.
*/
-public class ShareListDialogFragment extends DialogFragment {
+public class ShareListDialogFragment extends DialogFragment
+ implements ContactAdapter.ContactTouchListener {
public static final String FRAGMENT_TAG = ShareListDialogFragment.class.getSimpleName();
public static ShareListDialogFragment find(FragmentManager fragmentManager) {
return (ShareListDialogFragment) fragmentManager.findFragmentByTag(FRAGMENT_TAG);
}
- private Set<String> mRemoved;
- private List<String> mNearby = new ArrayList<>();
- private ArrayList<String> mTyped;
- private Set<String> mAdded;
+ private RecyclerView mContacts;
+ private Set<String> mRemoved, mAdded, mRecent;
private static final String
REMOVED_KEY = "removedShares",
- TYPED_KEY = "explicitShares",
- ADDED_KEY = "addedShares";
+ ADDED_KEY = "addedShares",
+ RECENT_KEY = "recentShares";
- private ContactAdapter mAlreadyAdapter, mPossibleAdapter;
+ private ContactAdapter mAdapter;
private VContext mScanContext;
@@ -84,8 +78,8 @@
super.onSaveInstanceState(outState);
outState.putStringArrayList(REMOVED_KEY, new ArrayList<>(mRemoved));
- outState.putStringArrayList(TYPED_KEY, mTyped);
outState.putStringArrayList(ADDED_KEY, new ArrayList<>(mAdded));
+ outState.putStringArrayList(RECENT_KEY, new ArrayList<>(mRecent));
}
@Override
@@ -95,20 +89,30 @@
if (savedInstanceState == null) {
mRemoved = new HashSet<>();
mAdded = new HashSet<>();
- mTyped = new ArrayList<>();
+ mRecent = new HashSet<>();
} else {
mRemoved = new HashSet<>(savedInstanceState.getStringArrayList(REMOVED_KEY));
mAdded = new HashSet<>(savedInstanceState.getStringArrayList(ADDED_KEY));
- mTyped = savedInstanceState.getStringArrayList(TYPED_KEY);
+ mRecent = new HashSet<>(savedInstanceState.getStringArrayList(RECENT_KEY));
}
- mAlreadyAdapter = new ContactAdapter(getParent().getSharedTo(), mRemoved, true);
- RecyclerView rvAlready = (RecyclerView) view.findViewById(R.id.recycler_already);
- rvAlready.setAdapter(mAlreadyAdapter);
- mNearby.clear();
- final RecyclerView rvPossible = (RecyclerView) view.findViewById(R.id.recycler_possible);
- mPossibleAdapter = new ContactAdapter(mNearby, mTyped, mAdded, false);
- rvPossible.setAdapter(mPossibleAdapter);
+ mAdapter = new ContactAdapter(getParent().getSharedTo(), mAdded, mRemoved, mRecent);
+ mAdapter.setContactTouchListener(this);
+ mContacts = (RecyclerView) view.findViewById(R.id.recycler);
+ mContacts.setAdapter(mAdapter);
+ mContacts.setItemAnimator(new DefaultItemAnimator() {
+ @Override
+ public boolean animateAdd(RecyclerView.ViewHolder holder) {
+ dispatchAddFinished(holder);
+ return false;
+ }
+
+ @Override
+ public boolean animateRemove(RecyclerView.ViewHolder holder) {
+ dispatchRemoveFinished(holder);
+ return false;
+ }
+ });
mScanContext = SyncbasePersistence.getAppVContext().withCancel();
try {
@@ -116,39 +120,17 @@
Sharing.getDiscovery().scan(mScanContext,
"v.InterfaceName = \"" + Sharing.getPresenceInterface() + "\""),
new InputChannelCallback<Update>() {
- private final Map<String, Integer> counterMap = new HashMap<>();
-
@Override
public ListenableFuture<Void> onNext(Update result) {
final String email = Iterables.getOnlyElement(result.getAddresses());
- if (email == null) {
+ if (email == null ||
+ email.equals(SyncbasePersistence.getPersonalEmail())) {
return null;
}
- // Note: binarySearch returns -|correct insert index| - 1 if it fails
- // to find a match. For Java ints, this is the bitwise complement of the
- // "correct" insertion index.
- int searchIndex = Collections.binarySearch(mNearby, email);
if (result.isLost()) {
- Integer old = counterMap.get(email);
- counterMap.put(email, old == null ? 0 : Math.max(0, counterMap
- .get(email) - 1));
- // Remove the email if the counter indicates that we should.
- if (counterMap.get(email) == 0 && searchIndex >= 0) {
- mNearby.remove(searchIndex);
- mPossibleAdapter.notifyItemRemoved(searchIndex);
- }
+ mAdapter.onNearbyDeviceLost(email);
} else {
- Integer old = counterMap.get(email);
- counterMap.put(email, old == null ? 1 : counterMap.get(email) + 1);
- // Show the email if it's a new one and not equal to our email.
- // TODO(alexfandrianto): This still lets you see emails of those
- // nearby who you've already invited.
- if (searchIndex < 0 && !email.equals(getParent().getEmail())) {
- int insertIndex = ~searchIndex;
- mNearby.add(insertIndex, email);
- //mNearby.add(email);
- mPossibleAdapter.notifyItemInserted(insertIndex);
- }
+ mAdapter.onNearbyDeviceDiscovered(email);
}
return null;
}
@@ -174,11 +156,7 @@
boolean handled = false;
if (actionId == EditorInfo.IME_ACTION_SEND) {
String email = editText.getText().toString();
- if (!mTyped.contains(email)) {
- mTyped.add(email);
- }
- mAdded.add(email);
- rvPossible.getAdapter().notifyDataSetChanged();
+ mAdapter.onCustomShare(email);
editText.setText("");
handled = true;
}
@@ -190,6 +168,7 @@
.setView(view)
.setPositiveButton("Save", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
+ mAdapter.filterDeltas();
getParent().persistence.shareTodoList(mAdded);
// TODO(alexfandrianto/rosswang): removal
}
@@ -207,90 +186,16 @@
}
public void onSharedToChanged() {
- //TODO(rosswang)
- }
-
- private static class ContactAdapter extends RecyclerView.Adapter<ContactViewHolder> {
- private final List<String> backup;
- private final List<String> bonus;
- private final Set<String> toggledOn;
- private final boolean strikethrough; // If false, then bold.
-
- public ContactAdapter(List<String> backup, Set<String> toggledOn, boolean strikethrough) {
- super();
- this.backup = backup;
- this.bonus = null;
- this.toggledOn = toggledOn;
- this.strikethrough = strikethrough;
- }
-
- public ContactAdapter(List<String> backup, List<String> bonus, Set<String> toggledOn,
- boolean strikethrough) {
- super();
- this.backup = backup;
- this.bonus = bonus;
- this.toggledOn = toggledOn;
- this.strikethrough = strikethrough;
- }
-
- @Override
- public ContactViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- return new ContactViewHolder(new TextView(parent.getContext()));
- }
-
- @Override
- public void onBindViewHolder(final ContactViewHolder holder, int position) {
- final String name = position < backup.size() ? backup.get(position) :
- bonus.get(position - backup.size());
- final boolean present = toggledOn.contains(name);
- holder.bindString(name, present, strikethrough, new View.OnClickListener() {
-
- @Override
- public void onClick(View view) {
- if (present) {
- toggledOn.remove(name);
- } else {
- toggledOn.add(name);
- }
- notifyItemChanged(holder.getAdapterPosition());
- }
- });
- }
-
- @Override
- public int getItemCount() {
- int extra = bonus == null ? 0 : bonus.size();
- return backup.size() + extra;
- }
- }
-
- private static class ContactViewHolder extends RecyclerView.ViewHolder {
- public ContactViewHolder(View itemView) {
- super(itemView);
- }
-
- public void bindString(String name, boolean isActive, boolean strikethrough, View
- .OnClickListener listener) {
- TextView text = (TextView) itemView;
-
- text.setText(name);
- text.setTextSize(18);
- if (strikethrough) {
- if (isActive) {
- text.setPaintFlags(text.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
- } else {
- text.setPaintFlags(text.getPaintFlags() & ~Paint.STRIKE_THRU_TEXT_FLAG);
- }
- } else {
- // We should bold!
- if (isActive) {
- text.setTypeface(null, 1); // 1 is bold
- } else {
- text.setTypeface(null, 0); // 0 is default text style
- }
+ mContacts.post(new Runnable() {
+ @Override
+ public void run() {
+ mAdapter.setSharedTo(getParent().getSharedTo());
}
+ });
+ }
- text.setOnClickListener(listener);
- }
+ @Override
+ public void onContactTouch(RecyclerView.ViewHolder viewHolder) {
+ mAdapter.toggleContact(viewHolder.getAdapterPosition());
}
}
diff --git a/app/src/syncbase/res/drawable-hdpi/ic_expand_less_black_24dp.png b/app/src/syncbase/res/drawable-hdpi/ic_expand_less_black_24dp.png
new file mode 100644
index 0000000..57139a7
--- /dev/null
+++ b/app/src/syncbase/res/drawable-hdpi/ic_expand_less_black_24dp.png
Binary files differ
diff --git a/app/src/syncbase/res/drawable-hdpi/ic_expand_more_black_24dp.png b/app/src/syncbase/res/drawable-hdpi/ic_expand_more_black_24dp.png
new file mode 100644
index 0000000..9625f14
--- /dev/null
+++ b/app/src/syncbase/res/drawable-hdpi/ic_expand_more_black_24dp.png
Binary files differ
diff --git a/app/src/syncbase/res/drawable-mdpi/ic_expand_less_black_24dp.png b/app/src/syncbase/res/drawable-mdpi/ic_expand_less_black_24dp.png
new file mode 100644
index 0000000..08c16a3
--- /dev/null
+++ b/app/src/syncbase/res/drawable-mdpi/ic_expand_less_black_24dp.png
Binary files differ
diff --git a/app/src/syncbase/res/drawable-mdpi/ic_expand_more_black_24dp.png b/app/src/syncbase/res/drawable-mdpi/ic_expand_more_black_24dp.png
new file mode 100644
index 0000000..feb85a7
--- /dev/null
+++ b/app/src/syncbase/res/drawable-mdpi/ic_expand_more_black_24dp.png
Binary files differ
diff --git a/app/src/syncbase/res/drawable-xhdpi/ic_expand_less_black_24dp.png b/app/src/syncbase/res/drawable-xhdpi/ic_expand_less_black_24dp.png
new file mode 100644
index 0000000..323360e
--- /dev/null
+++ b/app/src/syncbase/res/drawable-xhdpi/ic_expand_less_black_24dp.png
Binary files differ
diff --git a/app/src/syncbase/res/drawable-xhdpi/ic_expand_more_black_24dp.png b/app/src/syncbase/res/drawable-xhdpi/ic_expand_more_black_24dp.png
new file mode 100644
index 0000000..d3ee65e
--- /dev/null
+++ b/app/src/syncbase/res/drawable-xhdpi/ic_expand_more_black_24dp.png
Binary files differ
diff --git a/app/src/syncbase/res/drawable-xxhdpi/ic_expand_less_black_24dp.png b/app/src/syncbase/res/drawable-xxhdpi/ic_expand_less_black_24dp.png
new file mode 100644
index 0000000..ee92f4e
--- /dev/null
+++ b/app/src/syncbase/res/drawable-xxhdpi/ic_expand_less_black_24dp.png
Binary files differ
diff --git a/app/src/syncbase/res/drawable-xxhdpi/ic_expand_more_black_24dp.png b/app/src/syncbase/res/drawable-xxhdpi/ic_expand_more_black_24dp.png
new file mode 100644
index 0000000..5cd142c
--- /dev/null
+++ b/app/src/syncbase/res/drawable-xxhdpi/ic_expand_more_black_24dp.png
Binary files differ
diff --git a/app/src/syncbase/res/drawable-xxxhdpi/ic_expand_less_black_24dp.png b/app/src/syncbase/res/drawable-xxxhdpi/ic_expand_less_black_24dp.png
new file mode 100644
index 0000000..99c6e3e
--- /dev/null
+++ b/app/src/syncbase/res/drawable-xxxhdpi/ic_expand_less_black_24dp.png
Binary files differ
diff --git a/app/src/syncbase/res/drawable-xxxhdpi/ic_expand_more_black_24dp.png b/app/src/syncbase/res/drawable-xxxhdpi/ic_expand_more_black_24dp.png
new file mode 100644
index 0000000..ad852e3
--- /dev/null
+++ b/app/src/syncbase/res/drawable-xxxhdpi/ic_expand_more_black_24dp.png
Binary files differ
diff --git a/app/src/syncbase/res/layout/sharing.xml b/app/src/syncbase/res/layout/sharing.xml
index 584e60e..af1fffe 100644
--- a/app/src/syncbase/res/layout/sharing.xml
+++ b/app/src/syncbase/res/layout/sharing.xml
@@ -1,51 +1,35 @@
<?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"
- android:orientation="vertical" android:layout_width="match_parent"
- android:layout_height="wrap_content">
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
- <TextView
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:gravity="center_vertical"
- android:textStyle="bold"
- android:textSize="22sp"
- android:textColor="#000000"
- android:layout_margin="5dp"
- android:text="@string/sharing_already" />
-
- <android.support.v7.widget.RecyclerView android:id="@+id/recycler_already"
+ <android.support.v7.widget.RecyclerView
+ android:id="@+id/recycler"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_weight="1"
- app:layoutManager="LinearLayoutManager" />
-
- <TextView
- android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:gravity="center_vertical"
- android:textStyle="bold"
- android:textSize="22sp"
- android:textColor="#000000"
- android:layout_margin="5dp"
- android:text="@string/sharing_possible" />
+ android:paddingTop="8dp"
+ app:layoutManager="LinearLayoutManager"/>
- <android.support.v7.widget.RecyclerView android:id="@+id/recycler_possible"
+ <android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_weight="1"
- app:layoutManager="LinearLayoutManager" />
-
- <EditText android:id="@+id/custom_email"
- android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:gravity="center_vertical"
- android:textStyle="bold"
- android:textSize="22sp"
- android:textColor="#000000"
- android:hint="@string/sharing_custom_hint"
- android:layout_margin="5dp"
- android:inputType="text"
- android:imeOptions="actionSend" />
+ android:paddingEnd="20dp"
+ android:paddingStart="20dp"
+ android:paddingTop="8dp">
+
+ <EditText
+ android:id="@+id/custom_email"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom"
+ android:hint="@string/sharing_custom_hint"
+ android:imeOptions="actionSend"
+ android:inputType="textEmailAddress"
+ android:textColor="#000000"
+ android:textSize="22sp"
+ android:textStyle="bold"/>
+ </android.support.design.widget.TextInputLayout>
</LinearLayout>
\ No newline at end of file
diff --git a/app/src/syncbase/res/layout/sharing_entry.xml b/app/src/syncbase/res/layout/sharing_entry.xml
new file mode 100644
index 0000000..a2eb525
--- /dev/null
+++ b/app/src/syncbase/res/layout/sharing_entry.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="48dp"
+ android:paddingEnd="24dp"
+ android:paddingStart="24dp">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:id="@+id/name"
+ android:layout_gravity="center_vertical"
+ android:textSize="16sp"/>
+</FrameLayout>
\ No newline at end of file
diff --git a/app/src/syncbase/res/layout/sharing_subheader.xml b/app/src/syncbase/res/layout/sharing_subheader.xml
new file mode 100644
index 0000000..50c81c0
--- /dev/null
+++ b/app/src/syncbase/res/layout/sharing_subheader.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="48dp"
+ android:orientation="horizontal"
+ android:paddingEnd="24dp"
+ android:paddingStart="24dp">
+
+ <TextView
+ android:id="@+id/category"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_weight="1"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textSize="14sp"
+ android:textStyle="bold"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/app/src/syncbase/res/values/strings.xml b/app/src/syncbase/res/values/strings.xml
index bc20f9d..b0e644b 100644
--- a/app/src/syncbase/res/values/strings.xml
+++ b/app/src/syncbase/res/values/strings.xml
@@ -2,9 +2,9 @@
<string name="app_name">Syncbase Todos</string>
<string name="share_location">Share Presence</string>
<!-- For Sharing Menu -->
- <string name="sharing_already">Sharing With</string>
- <string name="sharing_possible">Nearby</string>
- <string name="sharing_custom_hint">Add an email address...</string>
+ <string name="sharing_already">Shared With</string>
+ <string name="sharing_possible">Available</string>
+ <string name="sharing_custom_hint">Add an email address…</string>
<!-- Errors -->
<string name="err_share_location">Could not share location</string>
<string name="err_scan_nearby">Unable to scan for nearby users</string>