From eb1dd58a0b2d8e90b80798532958244411c0a815 Mon Sep 17 00:00:00 2001 From: Greyson Parrelli Date: Fri, 1 Mar 2019 10:50:48 -0800 Subject: [PATCH] Persistent media in multi-send. --- res/anim/slide_from_left.xml | 9 ++ res/anim/slide_to_left.xml | 9 ++ res/drawable-hdpi/ic_arrow_right.png | Bin 0 -> 260 bytes res/drawable-hdpi/ic_select_off.png | Bin 0 -> 1847 bytes res/drawable-hdpi/ic_select_on.png | Bin 0 -> 2118 bytes res/drawable-mdpi/ic_arrow_right.png | Bin 0 -> 238 bytes res/drawable-mdpi/ic_select_off.png | Bin 0 -> 923 bytes res/drawable-mdpi/ic_select_on.png | Bin 0 -> 1410 bytes .../media_count_button_background.xml | 12 ++ res/drawable-xhdpi/ic_arrow_right.png | Bin 0 -> 344 bytes res/drawable-xhdpi/ic_select_off.png | Bin 0 -> 2579 bytes res/drawable-xhdpi/ic_select_on.png | Bin 0 -> 3235 bytes res/drawable-xxhdpi/ic_arrow_right.png | Bin 0 -> 508 bytes res/drawable-xxhdpi/ic_select_off.png | Bin 0 -> 4687 bytes res/drawable-xxhdpi/ic_select_on.png | Bin 0 -> 5315 bytes res/drawable-xxxhdpi/ic_arrow_right.png | Bin 0 -> 652 bytes res/drawable-xxxhdpi/ic_select_off.png | Bin 0 -> 8534 bytes res/drawable-xxxhdpi/ic_select_on.png | Bin 0 -> 8067 bytes .../media_count_button_background.xml | 5 + .../media_count_number_background.xml | 5 + res/drawable/pill.xml | 5 + res/layout/mediapicker_activity.xml | 13 -- res/layout/mediapicker_media_item.xml | 39 ++++-- res/layout/mediasend_activity.xml | 54 ++++++++ .../mediasend/MediaPickerFolderFragment.java | 9 ++ .../mediasend/MediaPickerItemAdapter.java | 30 ++-- .../mediasend/MediaPickerItemFragment.java | 92 +++---------- .../mediasend/MediaSendActivity.java | 90 +++++++----- .../mediasend/MediaSendFragment.java | 30 ++-- .../MediaSendFragmentPagerAdapter.java | 10 ++ .../mediasend/MediaSendViewModel.java | 128 +++++++++++++----- .../securesms/scribbles/ScribbleFragment.java | 4 + .../scribbles/widget/ScribbleView.java | 2 + 33 files changed, 359 insertions(+), 187 deletions(-) create mode 100644 res/anim/slide_from_left.xml create mode 100644 res/anim/slide_to_left.xml create mode 100644 res/drawable-hdpi/ic_arrow_right.png create mode 100644 res/drawable-hdpi/ic_select_off.png create mode 100644 res/drawable-hdpi/ic_select_on.png create mode 100644 res/drawable-mdpi/ic_arrow_right.png create mode 100644 res/drawable-mdpi/ic_select_off.png create mode 100644 res/drawable-mdpi/ic_select_on.png create mode 100644 res/drawable-v21/media_count_button_background.xml create mode 100644 res/drawable-xhdpi/ic_arrow_right.png create mode 100644 res/drawable-xhdpi/ic_select_off.png create mode 100644 res/drawable-xhdpi/ic_select_on.png create mode 100644 res/drawable-xxhdpi/ic_arrow_right.png create mode 100644 res/drawable-xxhdpi/ic_select_off.png create mode 100644 res/drawable-xxhdpi/ic_select_on.png create mode 100644 res/drawable-xxxhdpi/ic_arrow_right.png create mode 100644 res/drawable-xxxhdpi/ic_select_off.png create mode 100644 res/drawable-xxxhdpi/ic_select_on.png create mode 100644 res/drawable/media_count_button_background.xml create mode 100644 res/drawable/media_count_number_background.xml create mode 100644 res/drawable/pill.xml delete mode 100644 res/layout/mediapicker_activity.xml create mode 100644 res/layout/mediasend_activity.xml diff --git a/res/anim/slide_from_left.xml b/res/anim/slide_from_left.xml new file mode 100644 index 0000000000..8ad83d09ed --- /dev/null +++ b/res/anim/slide_from_left.xml @@ -0,0 +1,9 @@ + + + + + \ No newline at end of file diff --git a/res/anim/slide_to_left.xml b/res/anim/slide_to_left.xml new file mode 100644 index 0000000000..698746867a --- /dev/null +++ b/res/anim/slide_to_left.xml @@ -0,0 +1,9 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi/ic_arrow_right.png b/res/drawable-hdpi/ic_arrow_right.png new file mode 100644 index 0000000000000000000000000000000000000000..bbc68bf0f6ae2d42b08a2a82c83a76393d17e8ed GIT binary patch literal 260 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbBI14-?iy0UMW`i(eN#`7Ipx`!7 z7srr@*0(bPxf&D%T+*#Q-9JAooy@zCKT*kOisYhJ)e2RcGevh#_*fiGO8p$Bp%m8C zyeL{jiL2r5p1%HFZS&L`tc-7_yp;T}@|&F@b(sj`RsyK;W>EO~Et%m9CO%A$pLuoB zwqI}7*7bx%w_kmh6K1+Zku>ygb(M!#ZO- b;{%3A4DPx*@kvBMRA>e5nQds5Wf;fLw6*sa-R4U=x1%;^l1n2kkjR-WqP}F1BGHFIf%riX z_E8c^@WY@$zceC3OVq`N#)!>o$kY{X=%%O;Tbo8(Zsp5f&eY@S|9d*u;n_>a7sPk%|swrp>)@+KdRCUMfI>AGG{4g z2s6i&w3$3m1^CC5M#xCn_=w7A37F$J_*4*2t287A+vsO3&f)xh;hu2U1=;}pMn=`h zBpL$d6iy}y$wDfqsHk|htgLKpR#w)$jEs!D^z`(cKp>DXFfh=6>(;Hln>TOvo;Y!$ zW&i&DziGTr7z%>=hyXbwtLoGWWO1HZ&JgAbOZV*A^KM&P+ritnZ~rc5BNCD6YH4XX zymRNy52RxidV>1Ui+-CVRi{R9p8RIEXA1?}wrzW(v$L~K9{b&14-F0V_w@9%cXV|8 zeE$6T>I)Yx9Mia;dV71@hKGmy++%t6>eZ_an>TNMPdZD`8`O^->_w9ydTg|q^Q1|h zQe##+1V~ zUaxnf`f$8ZVAe7P#*@dk6WK1sZ`$c+9ODaDtXQ$;(xppBOs^Jt*Ve6D-&Y^en{!($dxDyuy9==+UE7gB^+VS#`@`1MdhDGGCT?ATGN8F6--bLY<0s*T0UjARSuysDEHBZ1x} zmoHyF3<+#++O%nl+E@>40@!?L6i^1+MO|H8-=m1#rl6qUEw!PDoSaJMrOpu}k*l3( zmF-R<^P_s%nimQ9#kl_!*pX|qDl04BW)dJ!U0wZ|+ANf*s)tpg{%8fg=wHy-*ti?p z694w?+soCqTwtw)T?;5+QOy_guXvh6DmgiMgW8q}ggC4M^-o4@0<(2s7Ax}I_@G1X zn3OVs^Mz46(%6|q0sD4xet!OIDm}XAH2HkKK~=$sz;&1lS1bg*=pWHZJ)rAI14fFA zi`h6h4{#p;LhE260*ShyEz?O^sDYm2$B&;@!L5-SV=SGQdPj_e@6@SN^|a`An_pgD z?o|~6VKacv+_PuTI$IeRGyQ&DC=%G_BHG3@ZnA=h~cH%Oz}+S|+oVL>&Sj*1N<{U5rp@|Pw7!;HQ~F>;SPXjP6(o&SNL>z<~p+l9G~~4Mm@0TGhsu9`-QhLEe(QTK%0IAWcn8NA#Q9 zATz;n?v9#%PPw2TI}7#k;7fc^`gH5}tAba+Km2rLtTRM_F!`=syVl4Ez1pqQWiCxs zkR-%13O4&mT7T(_7cbr@d!8#-uKc26Sl~K?fB5OhL<9(tudc4{JCzTl=$S)@4!xr~ zFXE73Jzyvnf?o8eDP^|kK+RYEf$aaFazKDU*c4K~lOi}8moGFBU>4YU;`Wsi6685i zh|8CH2v{!0?PnE8u)x{>;_l-v1Q3e^B;xM#y2HRl zf;AC$e{i@-u&_BJG6Y^br~NM`(&JGD61L59HzF#e*R=e}7YzaV>JZ>r$Z&55M8?2< zhBhP1<%^dPE@FJ)nAX2pWj`d4FyJiPuDhge0s+8f%w0mxpz5PZv=Nxdis>>!jIlQA lb_I4jYi;yDk+__Je*wldi^(%~B_RL+002ovPDHLkV1k(nnA`vW literal 0 HcmV?d00001 diff --git a/res/drawable-hdpi/ic_select_on.png b/res/drawable-hdpi/ic_select_on.png new file mode 100644 index 0000000000000000000000000000000000000000..e50fcbdea75d345893ed7b6bb83cfabfe750ee87 GIT binary patch literal 2118 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 + + + + + + + + + \ No newline at end of file diff --git a/res/drawable-xhdpi/ic_arrow_right.png b/res/drawable-xhdpi/ic_arrow_right.png new file mode 100644 index 0000000000000000000000000000000000000000..510690366d5b622791e4eb47841a2ce5ed91819a GIT binary patch literal 344 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTC&H|6fVg?2=RS;(M3{v^Pz`)4m z>EalY(fD>2H`gHp0T=ao3(Qx#e|RBx@ZJ$=7cnNbWslTNA3Cy$o!Zh;>w7sZJosE> z%G?V#{Tmidxg?aRZnZ*kfl6Jk1e0L*kLwdeIPWLT5GvfWrRQg^%-)Xc?~E^2v6rPS zeC;#CvDu)REs>4)5RX)gqzQ*{hCtc{g)<8ru}id-sTQ3p_Z0VxPIV6~+14GOu`M(z z#FXV)){M0_Zu2wW@0`{B!*@aa;urjqRoadB&Me%1`9%|3Y|x_as*-5dyEmM+i(Nb$ zTT(6im-+aMC!giLPHDL5Ee(0I=-Ga$kkF}B>g$ymzO)3qe^M%Pz~k(?BLSXO3^Ts> Vdw-MW>Hr26gQu&X%Q~loCII+ih2sDK literal 0 HcmV?d00001 diff --git a/res/drawable-xhdpi/ic_select_off.png b/res/drawable-xhdpi/ic_select_off.png new file mode 100644 index 0000000000000000000000000000000000000000..2368c9e3d6ade25d017ed9d7f7287ebde656d53b GIT binary patch literal 2579 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 V+Don2q7wiB002ovPDHLkV1kowHe>(* literal 0 HcmV?d00001 diff --git a/res/drawable-xxxhdpi/ic_arrow_right.png b/res/drawable-xxxhdpi/ic_arrow_right.png new file mode 100644 index 0000000000000000000000000000000000000000..f7ce1009b801a59f0e747fcc1920a120ec02ff06 GIT binary patch literal 652 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 g=0G8q?ciQcF}V^uvpnn}Py+BuMN_##$s+830fp literal 0 HcmV?d00001 diff --git a/res/drawable-xxxhdpi/ic_select_on.png b/res/drawable-xxxhdpi/ic_select_on.png new file mode 100644 index 0000000000000000000000000000000000000000..177ce2507211f16676ee9f64faa52b099fc0bcbc GIT binary patch literal 8067 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 + + + + diff --git a/res/drawable/media_count_number_background.xml b/res/drawable/media_count_number_background.xml new file mode 100644 index 0000000000..1ffe671559 --- /dev/null +++ b/res/drawable/media_count_number_background.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/pill.xml b/res/drawable/pill.xml new file mode 100644 index 0000000000..be4d965cfc --- /dev/null +++ b/res/drawable/pill.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/res/layout/mediapicker_activity.xml b/res/layout/mediapicker_activity.xml deleted file mode 100644 index b7068b063a..0000000000 --- a/res/layout/mediapicker_activity.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/res/layout/mediapicker_media_item.xml b/res/layout/mediapicker_media_item.xml index bc9c28bd19..e5aa0150a8 100644 --- a/res/layout/mediapicker_media_item.xml +++ b/res/layout/mediapicker_media_item.xml @@ -6,14 +6,16 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginRight="2dp" - android:layout_marginBottom="2dp"> + android:layout_marginBottom="2dp" + android:animateLayoutChanges="true"> + android:scaleType="centerCrop" + tools:src="@drawable/empty_inbox_1"/> + tools:visibility="gone"> - - + android:background="@color/transparent_black_90" /> - + - + \ No newline at end of file diff --git a/res/layout/mediasend_activity.xml b/res/layout/mediasend_activity.xml new file mode 100644 index 0000000000..f279426812 --- /dev/null +++ b/res/layout/mediasend_activity.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/org/thoughtcrime/securesms/mediasend/MediaPickerFolderFragment.java b/src/org/thoughtcrime/securesms/mediasend/MediaPickerFolderFragment.java index 9215cddf5a..08c47a7399 100644 --- a/src/org/thoughtcrime/securesms/mediasend/MediaPickerFolderFragment.java +++ b/src/org/thoughtcrime/securesms/mediasend/MediaPickerFolderFragment.java @@ -15,6 +15,7 @@ import android.support.v7.widget.Toolbar; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.view.WindowManager; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.mms.GlideApp; @@ -88,6 +89,14 @@ public class MediaPickerFolderFragment extends Fragment implements MediaPickerFo initToolbar(view.findViewById(R.id.mediapicker_toolbar)); } + @Override + public void onResume() { + super.onResume(); + + requireActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN); + requireActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); + } + @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); diff --git a/src/org/thoughtcrime/securesms/mediasend/MediaPickerItemAdapter.java b/src/org/thoughtcrime/securesms/mediasend/MediaPickerItemAdapter.java index 651c8c4874..c7217b8976 100644 --- a/src/org/thoughtcrime/securesms/mediasend/MediaPickerItemAdapter.java +++ b/src/org/thoughtcrime/securesms/mediasend/MediaPickerItemAdapter.java @@ -17,6 +17,7 @@ import org.thoughtcrime.securesms.util.StableIdGenerator; import java.util.ArrayList; import java.util.Collection; +import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import java.util.TreeSet; @@ -38,11 +39,7 @@ public class MediaPickerItemAdapter extends RecyclerView.Adapter(); this.maxSelection = maxSelection; this.stableIdGenerator = new StableIdGenerator<>(); - this.selected = new TreeSet<>((m1, m2) -> { - if (m1.equals(m2)) return 0; - else if (Long.compare(m2.getDate(), m1.getDate()) == 0) return m2.getUri().compareTo(m1.getUri()); - else return Long.compare(m2.getDate(), m1.getDate()); - }); + this.selected = new LinkedHashSet<>(); setHasStableIds(true); } @@ -97,13 +94,17 @@ public class MediaPickerItemAdapter extends RecyclerView.Adapter selected, int maxSelection, @NonNull GlideRequests glideRequests, @NonNull EventListener eventListener) { @@ -113,10 +114,13 @@ public class MediaPickerItemAdapter extends RecyclerView.Adapter eventListener.onMediaChosen(media)); + selectOn.setVisibility(View.GONE); + selectOff.setVisibility(View.GONE); + selectOverlay.setVisibility(View.GONE); + if (maxSelection > 1) { itemView.setOnLongClickListener(v -> { selected.add(media); @@ -125,11 +129,17 @@ public class MediaPickerItemAdapter extends RecyclerView.Adapter { selected.remove(media); eventListener.onMediaSelectionChanged(new ArrayList<>(selected)); }); } else { + selectOff.setVisibility(View.VISIBLE); + selectOn.setVisibility(View.GONE); + selectOverlay.setVisibility(View.GONE); itemView.setOnClickListener(v -> { if (selected.size() < maxSelection) { selected.add(media); diff --git a/src/org/thoughtcrime/securesms/mediasend/MediaPickerItemFragment.java b/src/org/thoughtcrime/securesms/mediasend/MediaPickerItemFragment.java index e76bc62a03..5927e50a48 100644 --- a/src/org/thoughtcrime/securesms/mediasend/MediaPickerItemFragment.java +++ b/src/org/thoughtcrime/securesms/mediasend/MediaPickerItemFragment.java @@ -50,8 +50,6 @@ public class MediaPickerItemFragment extends Fragment implements MediaPickerItem private MediaPickerItemAdapter adapter; private Controller controller; private GridLayoutManager layoutManager; - private ActionMode actionMode; - private ActionMode.Callback actionModeCallback; public static MediaPickerItemFragment newInstance(@NonNull String bucketId, @NonNull String folderTitle, int maxSelection) { Bundle args = new Bundle(); @@ -70,11 +68,10 @@ public class MediaPickerItemFragment extends Fragment implements MediaPickerItem super.onCreate(savedInstanceState); setHasOptionsMenu(true); - bucketId = getArguments().getString(KEY_BUCKET_ID); - folderTitle = getArguments().getString(KEY_FOLDER_TITLE); - maxSelection = getArguments().getInt(KEY_MAX_SELECTION); - viewModel = ViewModelProviders.of(requireActivity(), new MediaSendViewModel.Factory(new MediaRepository())).get(MediaSendViewModel.class); - actionModeCallback = new ActionModeCallback(); + bucketId = getArguments().getString(KEY_BUCKET_ID); + folderTitle = getArguments().getString(KEY_FOLDER_TITLE); + maxSelection = getArguments().getInt(KEY_MAX_SELECTION); + viewModel = ViewModelProviders.of(requireActivity(), new MediaSendViewModel.Factory(new MediaRepository())).get(MediaSendViewModel.class); } @Override @@ -114,6 +111,8 @@ public class MediaPickerItemFragment extends Fragment implements MediaPickerItem } viewModel.getMediaInBucket(requireContext(), bucketId).observe(this, adapter::setMedia); + + initMediaObserver(viewModel); } @Override @@ -125,16 +124,19 @@ public class MediaPickerItemFragment extends Fragment implements MediaPickerItem } @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - inflater.inflate(R.menu.mediapicker_default, menu); + public void onPrepareOptionsMenu(Menu menu) { + requireActivity().getMenuInflater().inflate(R.menu.mediapicker_default, menu); + + MenuItem beginSelectionButton = menu.findItem(R.id.mediapicker_menu_add); + + beginSelectionButton.setVisible(!viewModel.getCountButtonState().getValue().getVisibility()); } @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == R.id.mediapicker_menu_add) { adapter.setForcedMultiSelect(true); - actionMode = ((AppCompatActivity) requireActivity()).startSupportActionMode(actionModeCallback); - actionMode.setTitle(getResources().getString(R.string.MediaPickerItemFragment_tap_to_select)); + viewModel.onMultiSelectStarted(); return true; } return false; @@ -148,23 +150,13 @@ public class MediaPickerItemFragment extends Fragment implements MediaPickerItem @Override public void onMediaChosen(@NonNull Media media) { - controller.onMediaSelected(bucketId, Collections.singleton(media)); viewModel.onSelectedMediaChanged(requireContext(), Collections.singletonList(media)); + controller.onMediaSelected(bucketId); } @Override public void onMediaSelectionChanged(@NonNull List selected) { adapter.notifyDataSetChanged(); - - if (actionMode == null && !selected.isEmpty()) { - actionMode = ((AppCompatActivity) requireActivity()).startSupportActionMode(actionModeCallback); - actionMode.setTitle(String.valueOf(selected.size())); - } else if (actionMode != null && selected.isEmpty()) { - actionMode.finish(); - } else if (actionMode != null) { - actionMode.setTitle(String.valueOf(selected.size())); - } - viewModel.onSelectedMediaChanged(requireContext(), selected); } @@ -181,6 +173,12 @@ public class MediaPickerItemFragment extends Fragment implements MediaPickerItem toolbar.setNavigationOnClickListener(v -> requireActivity().onBackPressed()); } + private void initMediaObserver(@NonNull MediaSendViewModel viewModel) { + viewModel.getCountButtonState().observe(this, media -> { + requireActivity().invalidateOptionsMenu(); + }); + } + private void onScreenWidthChanged(int newWidth) { if (layoutManager != null) { layoutManager.setSpanCount(newWidth / getResources().getDimensionPixelSize(R.dimen.media_picker_item_width)); @@ -193,55 +191,7 @@ public class MediaPickerItemFragment extends Fragment implements MediaPickerItem return size.x; } - private class ActionModeCallback implements ActionMode.Callback { - - private int statusBarColor; - - @Override - public boolean onCreateActionMode(ActionMode mode, Menu menu) { - MenuInflater inflater = mode.getMenuInflater(); - inflater.inflate(R.menu.mediapicker_multiselect, menu); - - if (Build.VERSION.SDK_INT >= 21) { - Window window = requireActivity().getWindow(); - statusBarColor = window.getStatusBarColor(); - window.setStatusBarColor(getResources().getColor(R.color.action_mode_status_bar)); - } - - return true; - } - - @Override - public boolean onPrepareActionMode(ActionMode mode, Menu menu) { - return false; - } - - @Override - public boolean onActionItemClicked(ActionMode mode, MenuItem menuItem) { - if (menuItem.getItemId() == R.id.mediapicker_menu_confirm) { - List selected = new ArrayList<>(adapter.getSelected()); - actionMode.finish(); - viewModel.onSelectedMediaChanged(requireContext(), selected); - controller.onMediaSelected(bucketId, selected); - return true; - } - return false; - } - - @Override - public void onDestroyActionMode(ActionMode mode) { - actionMode = null; - adapter.setSelected(Collections.emptySet()); - viewModel.onSelectedMediaChanged(requireContext(), Collections.emptyList()); - - if (Build.VERSION.SDK_INT >= 21) { - requireActivity().getWindow().setStatusBarColor(statusBarColor); - } - } - } - - public interface Controller { - void onMediaSelected(@NonNull String bucketId, @NonNull Collection media); + void onMediaSelected(@NonNull String bucketId); } } diff --git a/src/org/thoughtcrime/securesms/mediasend/MediaSendActivity.java b/src/org/thoughtcrime/securesms/mediasend/MediaSendActivity.java index 3441cccf5b..115aabbc23 100644 --- a/src/org/thoughtcrime/securesms/mediasend/MediaSendActivity.java +++ b/src/org/thoughtcrime/securesms/mediasend/MediaSendActivity.java @@ -6,11 +6,18 @@ import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.support.annotation.NonNull; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentTransaction; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.TransportOption; import org.thoughtcrime.securesms.database.Address; +import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.mms.MediaConstraints; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.scribbles.ScribbleFragment; @@ -23,6 +30,7 @@ import org.whispersystems.libsignal.util.guava.Optional; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.Locale; /** * Encompasses the entire flow of sending media, starting from the selection process to the actual @@ -56,10 +64,12 @@ public class MediaSendActivity extends PassphraseRequiredActionBarActivity imple private final DynamicLanguage dynamicLanguage = new DynamicLanguage(); private Recipient recipient; - private String body; private TransportOption transport; private MediaSendViewModel viewModel; + private View countButton; + private TextView countButtonText; + /** * Get an intent to launch the media send flow starting with the picker. */ @@ -94,28 +104,42 @@ public class MediaSendActivity extends PassphraseRequiredActionBarActivity imple @Override protected void onCreate(Bundle savedInstanceState, boolean ready) { - setContentView(R.layout.mediapicker_activity); + setContentView(R.layout.mediasend_activity); setResult(RESULT_CANCELED); if (savedInstanceState != null) { return; } + countButton = findViewById(R.id.mediasend_count_button); + countButtonText = findViewById(R.id.mediasend_count_button_text); + viewModel = ViewModelProviders.of(this, new MediaSendViewModel.Factory(new MediaRepository())).get(MediaSendViewModel.class); recipient = Recipient.from(this, Address.fromSerialized(getIntent().getStringExtra(KEY_ADDRESS)), true); - body = getIntent().getStringExtra(KEY_BODY); transport = getIntent().getParcelableExtra(KEY_TRANSPORT); viewModel.setMediaConstraints(transport.isSms() ? MediaConstraints.getMmsMediaConstraints(transport.getSimSubscriptionId().or(-1)) : MediaConstraints.getPushMediaConstraints()); + viewModel.onBodyChanged(getIntent().getStringExtra(KEY_BODY)); + List media = getIntent().getParcelableArrayListExtra(KEY_MEDIA); if (!Util.isEmpty(media)) { - navigateToMediaSend(media, body, transport); + viewModel.onSelectedMediaChanged(this, media); + + Fragment fragment = MediaSendFragment.newInstance(transport, dynamicLanguage.getCurrentLocale()); + getSupportFragmentManager().beginTransaction() + .replace(R.id.mediasend_fragment_container, fragment, TAG_SEND) + .commit(); } else { - navigateToFolderPicker(recipient); + MediaPickerFolderFragment fragment = MediaPickerFolderFragment.newInstance(recipient); + getSupportFragmentManager().beginTransaction() + .replace(R.id.mediasend_fragment_container, fragment, TAG_FOLDER_PICKER) + .commit(); } + + initializeCountButtonObserver(transport, dynamicLanguage.getCurrentLocale()); } @Override @@ -137,41 +161,34 @@ public class MediaSendActivity extends PassphraseRequiredActionBarActivity imple public void onFolderSelected(@NonNull MediaFolder folder) { viewModel.onFolderSelected(folder.getBucketId()); - MediaPickerItemFragment fragment = MediaPickerItemFragment.newInstance(folder.getBucketId(), - folder.getTitle(), - transport.isSms() ? MAX_SMS : MAX_PUSH); - + MediaPickerItemFragment fragment = MediaPickerItemFragment.newInstance(folder.getBucketId(), folder.getTitle(), transport.isSms() ? MAX_SMS :MAX_PUSH); getSupportFragmentManager().beginTransaction() - .setCustomAnimations(R.anim.fade_in, R.anim.fade_out, R.anim.fade_in, R.anim.fade_out) - .replace(R.id.mediapicker_fragment_container, fragment, TAG_ITEM_PICKER) + .setCustomAnimations(R.anim.slide_from_right, R.anim.slide_to_left, R.anim.slide_from_left, R.anim.slide_to_right) + .replace(R.id.mediasend_fragment_container, fragment, TAG_ITEM_PICKER) .addToBackStack(null) .commit(); } @Override - public void onMediaSelected(@NonNull String bucketId, @NonNull Collection media) { - MediaSendFragment fragment = MediaSendFragment.newInstance(body, transport, dynamicLanguage.getCurrentLocale()); - getSupportFragmentManager().beginTransaction() - .setCustomAnimations(R.anim.fade_in, R.anim.fade_out, R.anim.fade_in, R.anim.fade_out) - .replace(R.id.mediapicker_fragment_container, fragment, TAG_SEND) - .addToBackStack(null) - .commit(); + public void onMediaSelected(@NonNull String bucketId) { + navigateToMediaSend(transport, dynamicLanguage.getCurrentLocale()); } @Override public void onAddMediaClicked(@NonNull String bucketId) { + // TODO: Get actual folder title somehow MediaPickerFolderFragment folderFragment = MediaPickerFolderFragment.newInstance(recipient); - MediaPickerItemFragment itemFragment = MediaPickerItemFragment.newInstance(bucketId, - "", - transport.isSms() ? MAX_SMS : MAX_PUSH); + MediaPickerItemFragment itemFragment = MediaPickerItemFragment.newInstance(bucketId, "", transport.isSms() ? MAX_SMS : MAX_PUSH); getSupportFragmentManager().beginTransaction() - .replace(R.id.mediapicker_fragment_container, folderFragment, TAG_FOLDER_PICKER) + .setCustomAnimations(R.anim.stationary, R.anim.slide_to_left, R.anim.slide_from_left, R.anim.slide_to_right) + .replace(R.id.mediasend_fragment_container, folderFragment, TAG_FOLDER_PICKER) .addToBackStack(null) .commit(); getSupportFragmentManager().beginTransaction() - .replace(R.id.mediapicker_fragment_container, itemFragment, TAG_ITEM_PICKER) + .setCustomAnimations(R.anim.slide_from_right, R.anim.stationary, R.anim.slide_from_left, R.anim.slide_to_right) + .replace(R.id.mediasend_fragment_container, itemFragment, TAG_ITEM_PICKER) .addToBackStack(null) .commit(); } @@ -214,20 +231,29 @@ public class MediaSendActivity extends PassphraseRequiredActionBarActivity imple } } - private void navigateToMediaSend(List media, String body, TransportOption transport) { - viewModel.setInitialSelectedMedia(this, media); + private void initializeCountButtonObserver(@NonNull TransportOption transport, @NonNull Locale locale) { + viewModel.getCountButtonState().observe(this, buttonState -> { + if (buttonState == null) return; - MediaSendFragment sendFragment = MediaSendFragment.newInstance(body, transport, dynamicLanguage.getCurrentLocale()); - getSupportFragmentManager().beginTransaction() - .replace(R.id.mediapicker_fragment_container, sendFragment, TAG_SEND) - .commit(); + countButton.setVisibility(buttonState.getVisibility() ? View.VISIBLE : View.GONE); + countButton.setOnClickListener(v -> navigateToMediaSend(transport, locale)); + countButtonText.setText(String.valueOf(buttonState.getCount())); + }); } - private void navigateToFolderPicker(@NonNull Recipient recipient) { - MediaPickerFolderFragment folderFragment = MediaPickerFolderFragment.newInstance(recipient); + private void navigateToMediaSend(@NonNull TransportOption transport, @NonNull Locale locale) { + MediaSendFragment fragment = MediaSendFragment.newInstance(transport, locale); + String backstackTag = null; + + if (getSupportFragmentManager().findFragmentByTag(TAG_SEND) != null) { + getSupportFragmentManager().popBackStack(TAG_SEND, FragmentManager.POP_BACK_STACK_INCLUSIVE); + backstackTag = TAG_SEND; + } getSupportFragmentManager().beginTransaction() - .replace(R.id.mediapicker_fragment_container, folderFragment, TAG_FOLDER_PICKER) + .setCustomAnimations(R.anim.slide_from_right, R.anim.slide_to_left, R.anim.slide_from_left, R.anim.slide_to_right) + .replace(R.id.mediasend_fragment_container, fragment, TAG_SEND) + .addToBackStack(backstackTag) .commit(); } } diff --git a/src/org/thoughtcrime/securesms/mediasend/MediaSendFragment.java b/src/org/thoughtcrime/securesms/mediasend/MediaSendFragment.java index c96ad9f069..dc81b83c1b 100644 --- a/src/org/thoughtcrime/securesms/mediasend/MediaSendFragment.java +++ b/src/org/thoughtcrime/securesms/mediasend/MediaSendFragment.java @@ -72,7 +72,6 @@ public class MediaSendFragment extends Fragment implements ViewTreeObserver.OnGl private static final String TAG = MediaSendFragment.class.getSimpleName(); - private static final String KEY_BODY = "body"; private static final String KEY_TRANSPORT = "transport"; private static final String KEY_LOCALE = "locale"; @@ -99,9 +98,8 @@ public class MediaSendFragment extends Fragment implements ViewTreeObserver.OnGl private final Rect visibleBounds = new Rect(); - public static MediaSendFragment newInstance(@NonNull String body, @NonNull TransportOption transport, @NonNull Locale locale) { + public static MediaSendFragment newInstance(@NonNull TransportOption transport, @NonNull Locale locale) { Bundle args = new Bundle(); - args.putString(KEY_BODY, body); args.putParcelable(KEY_TRANSPORT, transport); args.putSerializable(KEY_LOCALE, locale); @@ -134,9 +132,6 @@ public class MediaSendFragment extends Fragment implements ViewTreeObserver.OnGl locale = (Locale) getArguments().getSerializable(KEY_LOCALE); initViewModel(); - - requireActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); - requireActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN); } @Override @@ -181,7 +176,7 @@ public class MediaSendFragment extends Fragment implements ViewTreeObserver.OnGl captionText.clearFocus(); composeText.requestFocus(); - fragmentPagerAdapter = new MediaSendFragmentPagerAdapter(requireActivity().getSupportFragmentManager(), locale); + fragmentPagerAdapter = new MediaSendFragmentPagerAdapter(getChildFragmentManager(), locale); fragmentPager.setAdapter(fragmentPagerAdapter); FragmentPageChangeListener pageChangeListener = new FragmentPageChangeListener(); @@ -208,7 +203,7 @@ public class MediaSendFragment extends Fragment implements ViewTreeObserver.OnGl sendButton.setTransport(transportOption); sendButton.disableTransport(transportOption.getType() == TransportOption.Type.SMS ? TransportOption.Type.TEXTSECURE : TransportOption.Type.SMS); - composeText.append(getArguments().getString(KEY_BODY)); + composeText.append(viewModel.getBody()); if (TextSecurePreferences.isSystemEmojiPreferred(getContext())) { @@ -221,13 +216,25 @@ public class MediaSendFragment extends Fragment implements ViewTreeObserver.OnGl @Override public void onStart() { super.onStart(); + fragmentPagerAdapter.restoreState(viewModel.getDrawState()); + viewModel.onImageEditorStarted(); + + requireActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); + requireActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN); + } + + @Override + public void onHiddenChanged(boolean hidden) { + super.onHiddenChanged(hidden); } @Override public void onStop() { super.onStop(); + fragmentPagerAdapter.saveAllState(); viewModel.saveDrawState(fragmentPagerAdapter.getSavedState()); + viewModel.onImageEditorEnded(); } @Override @@ -328,11 +335,13 @@ public class MediaSendFragment extends Fragment implements ViewTreeObserver.OnGl }); viewModel.getBucketId().observe(this, bucketId -> { - if (bucketId == null || !bucketId.isPresent() || sendButton.getSelectedTransport().isSms()) { + if (bucketId == null) return; + + if (sendButton.getSelectedTransport().isSms()) { addButton.setVisibility(View.GONE); } else { addButton.setVisibility(View.VISIBLE); - addButton.setOnClickListener(v -> controller.onAddMediaClicked(bucketId.get())); + addButton.setOnClickListener(v -> controller.onAddMediaClicked(bucketId)); } }); @@ -505,6 +514,7 @@ public class MediaSendFragment extends Fragment implements ViewTreeObserver.OnGl @Override public void afterTextChanged(Editable s) { presentCharactersRemaining(); + viewModel.onBodyChanged(s); } @Override diff --git a/src/org/thoughtcrime/securesms/mediasend/MediaSendFragmentPagerAdapter.java b/src/org/thoughtcrime/securesms/mediasend/MediaSendFragmentPagerAdapter.java index d85eba9f1f..2283504fb8 100644 --- a/src/org/thoughtcrime/securesms/mediasend/MediaSendFragmentPagerAdapter.java +++ b/src/org/thoughtcrime/securesms/mediasend/MediaSendFragmentPagerAdapter.java @@ -9,6 +9,7 @@ import android.support.v4.app.FragmentStatePagerAdapter; import android.view.View; import android.view.ViewGroup; +import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.scribbles.ScribbleFragment; import org.thoughtcrime.securesms.util.MediaUtil; import org.whispersystems.libsignal.util.guava.Optional; @@ -106,6 +107,15 @@ class MediaSendFragmentPagerAdapter extends FragmentStatePagerAdapter { return new HashMap<>(savedState); } + void saveAllState() { + for (MediaSendPageFragment fragment : fragments.values()) { + Object state = fragment.saveState(); + if (state != null) { + savedState.put(fragment.getUri(), state); + } + } + } + void restoreState(@NonNull Map state) { savedState.clear(); savedState.putAll(state); diff --git a/src/org/thoughtcrime/securesms/mediasend/MediaSendViewModel.java b/src/org/thoughtcrime/securesms/mediasend/MediaSendViewModel.java index 7bf95e6337..9212e1cdb6 100644 --- a/src/org/thoughtcrime/securesms/mediasend/MediaSendViewModel.java +++ b/src/org/thoughtcrime/securesms/mediasend/MediaSendViewModel.java @@ -15,7 +15,6 @@ import org.thoughtcrime.securesms.mms.MediaConstraints; import org.thoughtcrime.securesms.util.MediaUtil; import org.thoughtcrime.securesms.util.SingleLiveEvent; import org.thoughtcrime.securesms.util.Util; -import org.whispersystems.libsignal.util.guava.Optional; import java.util.Collections; import java.util.HashMap; @@ -31,31 +30,37 @@ class MediaSendViewModel extends ViewModel { private final MutableLiveData> selectedMedia; private final MutableLiveData> bucketMedia; private final MutableLiveData position; - private final MutableLiveData> bucketId; + private final MutableLiveData bucketId; private final MutableLiveData> folders; + private final MutableLiveData countButtonState; private final SingleLiveEvent error; private final Map savedDrawState; - private MediaConstraints mediaConstraints; + private MediaConstraints mediaConstraints; + private CharSequence body; + private CountButtonState.Visibility countButtonVisibility; private MediaSendViewModel(@NonNull MediaRepository repository) { - this.repository = repository; - this.selectedMedia = new MutableLiveData<>(); - this.bucketMedia = new MutableLiveData<>(); - this.position = new MutableLiveData<>(); - this.bucketId = new MutableLiveData<>(); - this.folders = new MutableLiveData<>(); - this.error = new SingleLiveEvent<>(); - this.savedDrawState = new HashMap<>(); + this.repository = repository; + this.selectedMedia = new MutableLiveData<>(); + this.bucketMedia = new MutableLiveData<>(); + this.position = new MutableLiveData<>(); + this.bucketId = new MutableLiveData<>(); + this.folders = new MutableLiveData<>(); + this.countButtonState = new MutableLiveData<>(); + this.error = new SingleLiveEvent<>(); + this.savedDrawState = new HashMap<>(); + this.countButtonVisibility = CountButtonState.Visibility.CONDITIONAL; position.setValue(-1); + countButtonState.setValue(new CountButtonState(0, CountButtonState.Visibility.CONDITIONAL)); } void setMediaConstraints(@NonNull MediaConstraints mediaConstraints) { this.mediaConstraints = mediaConstraints; } - void setInitialSelectedMedia(@NonNull Context context, @NonNull List newMedia) { + void onSelectedMediaChanged(@NonNull Context context, @NonNull List newMedia) { repository.getPopulatedMedia(context, newMedia, populatedMedia -> { List filteredMedia = getFilteredMedia(context, populatedMedia, mediaConstraints); @@ -63,26 +68,48 @@ class MediaSendViewModel extends ViewModel { error.postValue(Error.ITEM_TOO_LARGE); } - boolean allBucketsPopulated = Stream.of(filteredMedia).reduce(true, (populated, m) -> populated && m.getBucketId().isPresent()); + if (filteredMedia.size() > 0) { + String computedId = Stream.of(filteredMedia) + .skip(1) + .reduce(filteredMedia.get(0).getBucketId().orNull(), (id, m) -> { + if (Util.equals(id, m.getBucketId().orNull())) { + return id; + } else { + return Media.ALL_MEDIA_BUCKET_ID; + } + }); + bucketId.postValue(computedId); + } else { + bucketId.postValue(Media.ALL_MEDIA_BUCKET_ID); + countButtonVisibility = CountButtonState.Visibility.CONDITIONAL; + } selectedMedia.postValue(filteredMedia); - bucketId.postValue(allBucketsPopulated ? computeBucketId(filteredMedia) : Optional.absent()); + countButtonState.postValue(new CountButtonState(filteredMedia.size(), countButtonVisibility)); }); } - void onSelectedMediaChanged(@NonNull Context context, @NonNull List newMedia) { - List filteredMedia = getFilteredMedia(context, newMedia, mediaConstraints); + void onMultiSelectStarted() { + countButtonVisibility = CountButtonState.Visibility.FORCED_ON; + countButtonState.postValue(new CountButtonState(getSelectedMediaOrDefault().size(), countButtonVisibility)); + } - if (filteredMedia.size() != newMedia.size()) { - error.setValue(Error.ITEM_TOO_LARGE); - } + void onImageEditorStarted() { + countButtonVisibility = CountButtonState.Visibility.FORCED_OFF; + countButtonState.postValue(new CountButtonState(getSelectedMediaOrDefault().size(), countButtonVisibility)); + } + + void onImageEditorEnded() { + countButtonVisibility = CountButtonState.Visibility.CONDITIONAL; + countButtonState.postValue(new CountButtonState(getSelectedMediaOrDefault().size(), countButtonVisibility)); + } - selectedMedia.setValue(filteredMedia); - position.setValue(filteredMedia.isEmpty() ? -1 : 0); + void onBodyChanged(@NonNull CharSequence body) { + this.body = body; } void onFolderSelected(@NonNull String bucketId) { - this.bucketId.setValue(Optional.of(bucketId)); + this.bucketId.setValue(bucketId); bucketMedia.setValue(Collections.emptyList()); } @@ -91,7 +118,7 @@ class MediaSendViewModel extends ViewModel { } void onMediaItemRemoved(int position) { - selectedMedia.getValue().remove(position); + getSelectedMediaOrDefault().remove(position); selectedMedia.setValue(selectedMedia.getValue()); } @@ -110,11 +137,11 @@ class MediaSendViewModel extends ViewModel { return savedDrawState; } - LiveData> getSelectedMedia() { + @NonNull LiveData> getSelectedMedia() { return selectedMedia; } - LiveData> getMediaInBucket(@NonNull Context context, @NonNull String bucketId) { + @NonNull LiveData> getMediaInBucket(@NonNull Context context, @NonNull String bucketId) { repository.getMediaInBucket(context, bucketId, bucketMedia::postValue); return bucketMedia; } @@ -124,11 +151,19 @@ class MediaSendViewModel extends ViewModel { return folders; } + @NonNull LiveData getCountButtonState() { + return countButtonState; + } + + CharSequence getBody() { + return body; + } + LiveData getPosition() { return position; } - LiveData> getBucketId() { + LiveData getBucketId() { return bucketId; } @@ -136,17 +171,9 @@ class MediaSendViewModel extends ViewModel { return error; } - private Optional computeBucketId(@NonNull List media) { - if (media.isEmpty() || !media.get(0).getBucketId().isPresent()) return Optional.absent(); - - String candidate = media.get(0).getBucketId().get(); - for (int i = 1; i < media.size(); i++) { - if (!Util.equals(candidate, media.get(i).getBucketId().orNull())) { - return Optional.of(Media.ALL_MEDIA_BUCKET_ID); - } - } - - return Optional.of(candidate); + private @NonNull List getSelectedMediaOrDefault() { + return selectedMedia.getValue() == null ? Collections.emptyList() + : selectedMedia.getValue(); } private @NonNull List getFilteredMedia(@NonNull Context context, @NonNull List media, @NonNull MediaConstraints mediaConstraints) { @@ -165,6 +192,33 @@ class MediaSendViewModel extends ViewModel { ITEM_TOO_LARGE } + static class CountButtonState { + private final int count; + private final Visibility visibility; + + private CountButtonState(int count, @NonNull Visibility visibility) { + this.count = count; + this.visibility = visibility; + } + + int getCount() { + return count; + } + + boolean getVisibility() { + switch (visibility) { + case FORCED_ON: return true; + case FORCED_OFF: return false; + case CONDITIONAL: return count > 0; + default: return false; + } + } + + enum Visibility { + CONDITIONAL, FORCED_ON, FORCED_OFF + } + } + static class Factory extends ViewModelProvider.NewInstanceFactory { private final MediaRepository repository; diff --git a/src/org/thoughtcrime/securesms/scribbles/ScribbleFragment.java b/src/org/thoughtcrime/securesms/scribbles/ScribbleFragment.java index 9c8dd215df..a5b08f8eed 100644 --- a/src/org/thoughtcrime/securesms/scribbles/ScribbleFragment.java +++ b/src/org/thoughtcrime/securesms/scribbles/ScribbleFragment.java @@ -147,6 +147,10 @@ public class ScribbleFragment extends Fragment implements ScribbleHud.EventListe public void restoreState(@NonNull Object state) { if (state instanceof ScribbleView.SavedState) { savedState = (ScribbleView.SavedState) state; + + if (scribbleView != null) { + scribbleView.restoreState(savedState); + } } else { Log.w(TAG, "Received a bad saved state. Received class: " + state.getClass().getName()); } diff --git a/src/org/thoughtcrime/securesms/scribbles/widget/ScribbleView.java b/src/org/thoughtcrime/securesms/scribbles/widget/ScribbleView.java index 2986dc1f8b..a7453e24de 100644 --- a/src/org/thoughtcrime/securesms/scribbles/widget/ScribbleView.java +++ b/src/org/thoughtcrime/securesms/scribbles/widget/ScribbleView.java @@ -33,6 +33,7 @@ import android.widget.FrameLayout; import android.widget.ImageView; import com.bumptech.glide.load.engine.DiskCacheStrategy; +import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions; import com.bumptech.glide.request.target.SimpleTarget; import com.bumptech.glide.request.target.Target; import com.bumptech.glide.request.transition.Transition; @@ -87,6 +88,7 @@ public class ScribbleView extends FrameLayout { glideRequests.load(new DecryptableUri(uri)) .diskCacheStrategy(DiskCacheStrategy.NONE) + .transition(DrawableTransitionOptions.withCrossFade()) .fitCenter() .into(imageView); }