| // 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.app.Dialog; |
| import android.app.DialogFragment; |
| import android.app.FragmentManager; |
| import android.content.DialogInterface; |
| import android.os.Bundle; |
| import android.support.v7.app.AlertDialog; |
| import android.support.v7.widget.RecyclerView; |
| import android.view.KeyEvent; |
| import android.view.View; |
| import android.view.inputmethod.EditorInfo; |
| import android.widget.EditText; |
| import android.widget.TextView; |
| |
| import com.google.common.collect.Iterables; |
| import com.google.common.util.concurrent.FutureCallback; |
| import com.google.common.util.concurrent.Futures; |
| import com.google.common.util.concurrent.ListenableFuture; |
| |
| import java.util.ArrayList; |
| import java.util.HashSet; |
| import java.util.Set; |
| |
| import javax.annotation.Nullable; |
| |
| import io.v.todos.R; |
| import io.v.todos.persistence.syncbase.SyncbasePersistence; |
| import io.v.v23.InputChannelCallback; |
| import io.v.v23.InputChannels; |
| import io.v.v23.context.VContext; |
| import io.v.v23.discovery.Update; |
| import io.v.v23.verror.VException; |
| |
| /** |
| * The share dialog contains two recycler views. The top one shows the existing items, and the |
| * bottom shows ones that are nearby but not shared to yet. There's also a freeform text box to |
| * 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 |
| 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 RecyclerView mContacts; |
| private Set<String> mRemoved, mAdded, mRecent; |
| |
| private static final String |
| REMOVED_KEY = "removedShares", |
| ADDED_KEY = "addedShares", |
| RECENT_KEY = "recentShares"; |
| |
| private ContactAdapter mAdapter; |
| |
| private VContext mScanContext; |
| |
| private ShareListMenuFragment getParent() { |
| return ((ShareListMenuFragment) getParentFragment()); |
| } |
| |
| @Override |
| public void onDestroyView() { |
| mScanContext.cancel(); |
| super.onDestroyView(); |
| } |
| |
| @Override |
| public void onSaveInstanceState(Bundle outState) { |
| super.onSaveInstanceState(outState); |
| |
| outState.putStringArrayList(REMOVED_KEY, new ArrayList<>(mRemoved)); |
| outState.putStringArrayList(ADDED_KEY, new ArrayList<>(mAdded)); |
| outState.putStringArrayList(RECENT_KEY, new ArrayList<>(mRecent)); |
| } |
| |
| @Override |
| public Dialog onCreateDialog(Bundle savedInstanceState) { |
| View view = getActivity().getLayoutInflater().inflate(R.layout.sharing, null); |
| |
| if (savedInstanceState == null) { |
| mRemoved = new HashSet<>(); |
| mAdded = new HashSet<>(); |
| mRecent = new HashSet<>(); |
| } else { |
| mRemoved = new HashSet<>(savedInstanceState.getStringArrayList(REMOVED_KEY)); |
| mAdded = new HashSet<>(savedInstanceState.getStringArrayList(ADDED_KEY)); |
| mRecent = new HashSet<>(savedInstanceState.getStringArrayList(RECENT_KEY)); |
| } |
| |
| mAdapter = new ContactAdapter(getParent().getSharedTo(), mAdded, mRemoved, mRecent); |
| mAdapter.setContactTouchListener(this); |
| mContacts = (RecyclerView) view.findViewById(R.id.recycler); |
| mContacts.setAdapter(mAdapter); |
| |
| mScanContext = SyncbasePersistence.getAppVContext().withCancel(); |
| try { |
| ListenableFuture<Void> scan = InputChannels.withCallback( |
| Sharing.getDiscovery().scan(mScanContext, |
| "v.InterfaceName = \"" + Sharing.getPresenceInterface() + "\""), |
| new InputChannelCallback<Update>() { |
| @Override |
| public ListenableFuture<Void> onNext(Update result) { |
| final String email = Iterables.getOnlyElement(result.getAddresses()); |
| if (email == null || |
| email.equals(SyncbasePersistence.getPersonalEmail())) { |
| return null; |
| } |
| if (result.isLost()) { |
| mAdapter.onNearbyDeviceLost(email); |
| } else { |
| mAdapter.onNearbyDeviceDiscovered(email); |
| } |
| return null; |
| } |
| }); |
| Futures.addCallback(scan, new FutureCallback<Void>() { |
| @Override |
| public void onSuccess(@Nullable Void result) { |
| } |
| |
| @Override |
| public void onFailure(Throwable t) { |
| handleScanningError(t); |
| } |
| }); |
| } catch (VException e) { |
| handleScanningError(e); |
| } |
| |
| final EditText editText = (EditText) view.findViewById(R.id.custom_email); |
| editText.setOnEditorActionListener(new TextView.OnEditorActionListener() { |
| @Override |
| public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { |
| boolean handled = false; |
| if (actionId == EditorInfo.IME_ACTION_SEND) { |
| String email = editText.getText().toString(); |
| mAdapter.onCustomShare(email); |
| editText.setText(""); |
| handled = true; |
| } |
| return handled; |
| } |
| }); |
| |
| return new AlertDialog.Builder(getActivity()) |
| .setView(view) |
| .setPositiveButton("Save", new DialogInterface.OnClickListener() { |
| public void onClick(DialogInterface dialog, int whichButton) { |
| mAdapter.filterDeltas(); |
| getParent().persistence.shareTodoList(mAdded); |
| // TODO(alexfandrianto/rosswang): removal |
| } |
| }) |
| .setNegativeButton("Cancel", new DialogInterface.OnClickListener() { |
| public void onClick(DialogInterface dialog, int whichButton) { |
| } |
| }) |
| .create(); |
| } |
| |
| private void handleScanningError(Throwable t) { |
| //TODO(rosswang): indicate error in the view |
| SyncbasePersistence.getAppErrorReporter().onError(R.string.err_scan_nearby, t); |
| } |
| |
| public void onSharedToChanged() { |
| mContacts.post(new Runnable() { |
| @Override |
| public void run() { |
| mAdapter.setSharedTo(getParent().getSharedTo()); |
| } |
| }); |
| } |
| |
| @Override |
| public void onContactTouch(RecyclerView.ViewHolder viewHolder) { |
| mAdapter.toggleContact(viewHolder.getAdapterPosition()); |
| } |
| } |