mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-25 19:29:54 +01:00
Use the image editor for avatars.
This commit is contained in:
@@ -0,0 +1,223 @@
|
||||
package org.thoughtcrime.securesms.mediasend;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
import androidx.lifecycle.ViewModelProviders;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.TransportOptions;
|
||||
import org.thoughtcrime.securesms.imageeditor.model.EditorModel;
|
||||
import org.thoughtcrime.securesms.providers.BlobProvider;
|
||||
import org.thoughtcrime.securesms.scribbles.ImageEditorFragment;
|
||||
import org.thoughtcrime.securesms.util.MediaUtil;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.util.Collections;
|
||||
|
||||
public class AvatarSelectionActivity extends AppCompatActivity implements CameraFragment.Controller, ImageEditorFragment.Controller, MediaPickerFolderFragment.Controller, MediaPickerItemFragment.Controller {
|
||||
|
||||
private static final String IMAGE_CAPTURE = "IMAGE_CAPTURE";
|
||||
private static final String IMAGE_EDITOR = "IMAGE_EDITOR";
|
||||
private static final String ARG_GALLERY = "ARG_GALLERY";
|
||||
|
||||
public static final String EXTRA_MEDIA = "avatar.media";
|
||||
|
||||
private Media currentMedia;
|
||||
|
||||
public static Intent getIntentForCameraCapture(@NonNull Context context) {
|
||||
return new Intent(context, AvatarSelectionActivity.class);
|
||||
}
|
||||
|
||||
public static Intent getIntentForGallery(@NonNull Context context) {
|
||||
Intent intent = getIntentForCameraCapture(context);
|
||||
|
||||
intent.putExtra(ARG_GALLERY, true);
|
||||
|
||||
return intent;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.avatar_selection_activity);
|
||||
|
||||
MediaSendViewModel viewModel = ViewModelProviders.of(this, new MediaSendViewModel.Factory(getApplication(), new MediaRepository())).get(MediaSendViewModel.class);
|
||||
viewModel.setTransport(TransportOptions.getPushTransportOption(this));
|
||||
|
||||
if (isGalleryFirst()) {
|
||||
onGalleryClicked();
|
||||
} else {
|
||||
onCameraSelected();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCameraError() {
|
||||
Toast.makeText(this, R.string.error, Toast.LENGTH_SHORT).show();
|
||||
finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onImageCaptured(@NonNull byte[] data, int width, int height) {
|
||||
Uri blobUri = BlobProvider.getInstance()
|
||||
.forData(data)
|
||||
.withMimeType(MediaUtil.IMAGE_JPEG)
|
||||
.createForSingleSessionInMemory();
|
||||
|
||||
onMediaSelected(new Media(blobUri,
|
||||
MediaUtil.IMAGE_JPEG,
|
||||
System.currentTimeMillis(),
|
||||
width,
|
||||
height,
|
||||
data.length,
|
||||
0,
|
||||
Optional.of(Media.ALL_MEDIA_BUCKET_ID),
|
||||
Optional.absent(),
|
||||
Optional.absent()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onVideoCaptured(@NonNull FileDescriptor fd) {
|
||||
throw new UnsupportedOperationException("Cannot set profile as video");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onVideoCaptureError() {
|
||||
throw new AssertionError("This should never happen");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGalleryClicked() {
|
||||
if (isGalleryFirst() && popToRoot()) {
|
||||
return;
|
||||
}
|
||||
|
||||
MediaPickerFolderFragment fragment = MediaPickerFolderFragment.newInstance(this, null);
|
||||
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction()
|
||||
.replace(R.id.fragment_container, fragment);
|
||||
|
||||
if (isCameraFirst()) {
|
||||
transaction.addToBackStack(null);
|
||||
}
|
||||
|
||||
transaction.commit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDisplayRotation() {
|
||||
return getWindowManager().getDefaultDisplay().getRotation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCameraCountButtonClicked() {
|
||||
throw new UnsupportedOperationException("Cannot select more than one photo");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTouchEventsNeeded(boolean needed) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestFullScreen(boolean fullScreen, boolean hideKeyboard) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFolderSelected(@NonNull MediaFolder folder) {
|
||||
getSupportFragmentManager().beginTransaction()
|
||||
.replace(R.id.fragment_container, MediaPickerItemFragment.newInstance(folder.getBucketId(), folder.getTitle(), 1, false))
|
||||
.addToBackStack(null)
|
||||
.commit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMediaSelected(@NonNull Media media) {
|
||||
currentMedia = media;
|
||||
|
||||
getSupportFragmentManager().beginTransaction()
|
||||
.replace(R.id.fragment_container, ImageEditorFragment.newInstanceForAvatar(media.getUri()), IMAGE_EDITOR)
|
||||
.addToBackStack(IMAGE_EDITOR)
|
||||
.commit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCameraSelected() {
|
||||
if (isCameraFirst() && popToRoot()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Fragment fragment = CameraFragment.newInstanceForAvatarCapture();
|
||||
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction()
|
||||
.replace(R.id.fragment_container, fragment, IMAGE_CAPTURE);
|
||||
|
||||
if (isGalleryFirst()) {
|
||||
transaction.addToBackStack(null);
|
||||
}
|
||||
|
||||
transaction.commit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDoneEditing() {
|
||||
handleSave();
|
||||
}
|
||||
|
||||
public boolean popToRoot() {
|
||||
final int backStackCount = getSupportFragmentManager().getBackStackEntryCount();
|
||||
if (backStackCount == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < backStackCount; i++) {
|
||||
getSupportFragmentManager().popBackStack();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isGalleryFirst() {
|
||||
return getIntent().getBooleanExtra(ARG_GALLERY, false);
|
||||
}
|
||||
|
||||
private boolean isCameraFirst() {
|
||||
return !isGalleryFirst();
|
||||
}
|
||||
|
||||
private void handleSave() {
|
||||
ImageEditorFragment fragment = (ImageEditorFragment) getSupportFragmentManager().findFragmentByTag(IMAGE_EDITOR);
|
||||
if (fragment == null) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
ImageEditorFragment.Data data = (ImageEditorFragment.Data) fragment.saveState();
|
||||
if (data == null) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
EditorModel model = data.readModel();
|
||||
if (model == null) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
MediaRepository.transformMedia(this,
|
||||
Collections.singletonList(currentMedia),
|
||||
Collections.singletonMap(currentMedia, new ImageEditorModelRenderMediaTransform(model)),
|
||||
output -> {
|
||||
Media transformed = output.get(currentMedia);
|
||||
|
||||
Intent result = new Intent();
|
||||
result.putExtra(EXTRA_MEDIA, transformed);
|
||||
setResult(RESULT_OK, result);
|
||||
finish();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
package org.thoughtcrime.securesms.mediasend;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.AttrRes;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.appcompat.widget.AppCompatTextView;
|
||||
import androidx.core.util.Consumer;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.annimon.stream.Stream;
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.util.ThemeUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class AvatarSelectionBottomSheetDialogFragment extends BottomSheetDialogFragment {
|
||||
|
||||
private static final String ARG_OPTIONS = "options";
|
||||
private static final String ARG_REQUEST_CODE = "request_code";
|
||||
|
||||
public static DialogFragment create(boolean includeClear, boolean includeCamera, short resultCode) {
|
||||
DialogFragment fragment = new AvatarSelectionBottomSheetDialogFragment();
|
||||
List<SelectionOption> selectionOptions = new ArrayList<>(3);
|
||||
Bundle args = new Bundle();
|
||||
|
||||
if (includeCamera) {
|
||||
selectionOptions.add(SelectionOption.CAPTURE);
|
||||
}
|
||||
|
||||
selectionOptions.add(SelectionOption.GALLERY);
|
||||
|
||||
if (includeClear) {
|
||||
selectionOptions.add(SelectionOption.DELETE);
|
||||
}
|
||||
|
||||
String[] options = Stream.of(selectionOptions)
|
||||
.map(SelectionOption::getCode)
|
||||
.toArray(String[]::new);
|
||||
|
||||
args.putStringArray(ARG_OPTIONS, options);
|
||||
args.putShort(ARG_REQUEST_CODE, resultCode);
|
||||
fragment.setArguments(args);
|
||||
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
setStyle(DialogFragment.STYLE_NORMAL,
|
||||
ThemeUtil.isDarkTheme(requireContext()) ? R.style.Theme_Design_BottomSheetDialog_Fixed
|
||||
: R.style.Theme_Design_Light_BottomSheetDialog_Fixed);
|
||||
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
if (getOptionsCount() == 1) {
|
||||
launchOptionAndDismiss(getOptionsFromArguments().get(0));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
return inflater.inflate(R.layout.avatar_selection_bottom_sheet_dialog_fragment, container, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
RecyclerView recyclerView = view.findViewById(R.id.avatar_selection_bottom_sheet_dialog_fragment_recycler);
|
||||
recyclerView.setAdapter(new SelectionOptionAdapter(getOptionsFromArguments(), this::launchOptionAndDismiss));
|
||||
}
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
private int getOptionsCount() {
|
||||
return requireArguments().getStringArray(ARG_OPTIONS).length;
|
||||
}
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
private List<SelectionOption> getOptionsFromArguments() {
|
||||
String[] optionCodes = requireArguments().getStringArray(ARG_OPTIONS);
|
||||
|
||||
return Stream.of(optionCodes).map(SelectionOption::fromCode).toList();
|
||||
}
|
||||
|
||||
private void launchOptionAndDismiss(@NonNull SelectionOption option) {
|
||||
Intent intent = createIntent(requireContext(), option);
|
||||
|
||||
int requestCode = requireArguments().getShort(ARG_REQUEST_CODE);
|
||||
if (getParentFragment() != null) {
|
||||
requireParentFragment().startActivityForResult(intent, requestCode);
|
||||
} else {
|
||||
requireActivity().startActivityForResult(intent, requestCode);
|
||||
}
|
||||
|
||||
dismiss();
|
||||
}
|
||||
|
||||
private static Intent createIntent(@NonNull Context context, @NonNull SelectionOption selectionOption) {
|
||||
switch (selectionOption) {
|
||||
case CAPTURE:
|
||||
return AvatarSelectionActivity.getIntentForCameraCapture(context);
|
||||
case GALLERY:
|
||||
return AvatarSelectionActivity.getIntentForGallery(context);
|
||||
case DELETE:
|
||||
return new Intent("org.thoughtcrime.securesms.action.CLEAR_PROFILE_PHOTO");
|
||||
default:
|
||||
throw new IllegalStateException("Unknown option: " + selectionOption);
|
||||
}
|
||||
}
|
||||
|
||||
private enum SelectionOption {
|
||||
CAPTURE("capture", R.string.AvatarSelectionBottomSheetDialogFragment__take_photo, R.attr.avatar_selection_take_photo),
|
||||
GALLERY("gallery", R.string.AvatarSelectionBottomSheetDialogFragment__choose_from_gallery, R.attr.avatar_selection_pick_photo),
|
||||
DELETE("delete", R.string.AvatarSelectionBottomSheetDialogFragment__remove_photo, R.attr.avatar_selection_remove_photo);
|
||||
|
||||
private final String code;
|
||||
private final @StringRes int label;
|
||||
private final @AttrRes int icon;
|
||||
|
||||
SelectionOption(@NonNull String code, @StringRes int label, @AttrRes int icon) {
|
||||
this.code = code;
|
||||
this.label = label;
|
||||
this.icon = icon;
|
||||
}
|
||||
|
||||
public @NonNull String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
static SelectionOption fromCode(@NonNull String code) {
|
||||
for (SelectionOption option : values()) {
|
||||
if (option.code.equals(code)) {
|
||||
return option;
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalStateException("Unknown option: " + code);
|
||||
}
|
||||
}
|
||||
|
||||
private static class SelectionOptionViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
private final AppCompatTextView optionView;
|
||||
|
||||
SelectionOptionViewHolder(@NonNull View itemView, @NonNull Consumer<Integer> onClick) {
|
||||
super(itemView);
|
||||
itemView.setOnClickListener(v -> {
|
||||
if (getAdapterPosition() != RecyclerView.NO_POSITION) {
|
||||
onClick.accept(getAdapterPosition());
|
||||
}
|
||||
});
|
||||
|
||||
optionView = (AppCompatTextView) itemView;
|
||||
}
|
||||
|
||||
void bind(@NonNull SelectionOption selectionOption) {
|
||||
optionView.setCompoundDrawablesWithIntrinsicBounds(ThemeUtil.getThemedDrawable(optionView.getContext(), selectionOption.icon), null, null, null);
|
||||
optionView.setText(selectionOption.label);
|
||||
}
|
||||
}
|
||||
|
||||
private static class SelectionOptionAdapter extends RecyclerView.Adapter<SelectionOptionViewHolder> {
|
||||
|
||||
private final List<SelectionOption> options;
|
||||
private final Consumer<SelectionOption> onOptionClicked;
|
||||
|
||||
private SelectionOptionAdapter(@NonNull List<SelectionOption> options, @NonNull Consumer<SelectionOption> onOptionClicked) {
|
||||
this.options = options;
|
||||
this.onOptionClicked = onOptionClicked;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public SelectionOptionViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.avatar_selection_bottom_sheet_dialog_fragment_option, parent, false);
|
||||
return new SelectionOptionViewHolder(view, (position) -> onOptionClicked.accept(options.get(position)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull SelectionOptionViewHolder holder, int position) {
|
||||
holder.bind(options.get(position));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return options.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
package org.thoughtcrime.securesms.mediasend;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.os.Build;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.camera.core.CameraX;
|
||||
@@ -10,8 +9,6 @@ import androidx.fragment.app.Fragment;
|
||||
import org.thoughtcrime.securesms.mediasend.camerax.CameraXUtil;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public interface CameraFragment {
|
||||
|
||||
@@ -24,6 +21,15 @@ public interface CameraFragment {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("RestrictedApi")
|
||||
static Fragment newInstanceForAvatarCapture() {
|
||||
if (CameraXUtil.isSupported() && CameraX.isInitialized()) {
|
||||
return CameraXFragment.newInstanceForAvatarCapture();
|
||||
} else {
|
||||
return Camera1Fragment.newInstance();
|
||||
}
|
||||
}
|
||||
|
||||
interface Controller {
|
||||
void onCameraError();
|
||||
void onImageCaptured(@NonNull byte[] data, int width, int height);
|
||||
|
||||
@@ -25,7 +25,6 @@ import androidx.annotation.RequiresApi;
|
||||
import androidx.camera.core.CameraX;
|
||||
import androidx.camera.core.ImageCapture;
|
||||
import androidx.camera.core.ImageProxy;
|
||||
import androidx.camera.core.impl.utils.executor.CameraXExecutors;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.lifecycle.ViewModelProviders;
|
||||
@@ -45,7 +44,6 @@ import org.thoughtcrime.securesms.util.MemoryFileDescriptor;
|
||||
import org.thoughtcrime.securesms.util.Stopwatch;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.ThemeUtil;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
|
||||
import org.thoughtcrime.securesms.video.VideoUtil;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
@@ -60,7 +58,8 @@ import java.io.IOException;
|
||||
@RequiresApi(21)
|
||||
public class CameraXFragment extends Fragment implements CameraFragment {
|
||||
|
||||
private static final String TAG = Log.tag(CameraXFragment.class);
|
||||
private static final String TAG = Log.tag(CameraXFragment.class);
|
||||
private static final String IS_VIDEO_ENABLED = "is_video_enabled";
|
||||
|
||||
private CameraXView camera;
|
||||
private ViewGroup controlsContainer;
|
||||
@@ -69,8 +68,22 @@ public class CameraXFragment extends Fragment implements CameraFragment {
|
||||
private View selfieFlash;
|
||||
private MemoryFileDescriptor videoFileDescriptor;
|
||||
|
||||
public static CameraXFragment newInstanceForAvatarCapture() {
|
||||
CameraXFragment fragment = new CameraXFragment();
|
||||
Bundle args = new Bundle();
|
||||
|
||||
args.putBoolean(IS_VIDEO_ENABLED, false);
|
||||
fragment.setArguments(args);
|
||||
|
||||
return fragment;
|
||||
}
|
||||
|
||||
public static CameraXFragment newInstance() {
|
||||
return new CameraXFragment();
|
||||
CameraXFragment fragment = new CameraXFragment();
|
||||
|
||||
fragment.setArguments(new Bundle());
|
||||
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -282,9 +295,10 @@ public class CameraXFragment extends Fragment implements CameraFragment {
|
||||
}
|
||||
|
||||
private boolean isVideoRecordingSupported(@NonNull Context context) {
|
||||
return Build.VERSION.SDK_INT >= 26 &&
|
||||
MediaConstraints.isVideoTranscodeAvailable() &&
|
||||
CameraXUtil.isMixedModeSupported(context) &&
|
||||
return Build.VERSION.SDK_INT >= 26 &&
|
||||
requireArguments().getBoolean(IS_VIDEO_ENABLED, true) &&
|
||||
MediaConstraints.isVideoTranscodeAvailable() &&
|
||||
CameraXUtil.isMixedModeSupported(context) &&
|
||||
VideoUtil.getMaxVideoDurationInSeconds(context, viewModel.getMediaConstraints()) > 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
package org.thoughtcrime.securesms.mediasend;
|
||||
|
||||
import androidx.lifecycle.ViewModelProviders;
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Point;
|
||||
import android.os.Bundle;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.lifecycle.ViewModelProviders;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.mms.GlideApp;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
@@ -32,9 +32,10 @@ import java.util.List;
|
||||
*/
|
||||
public class MediaPickerItemFragment extends Fragment implements MediaPickerItemAdapter.EventListener {
|
||||
|
||||
private static final String KEY_BUCKET_ID = "bucket_id";
|
||||
private static final String KEY_FOLDER_TITLE = "folder_title";
|
||||
private static final String KEY_MAX_SELECTION = "max_selection";
|
||||
private static final String KEY_BUCKET_ID = "bucket_id";
|
||||
private static final String KEY_FOLDER_TITLE = "folder_title";
|
||||
private static final String KEY_MAX_SELECTION = "max_selection";
|
||||
private static final String KEY_FORCE_MULTI_SELECT = "force_multi_select";
|
||||
|
||||
private String bucketId;
|
||||
private String folderTitle;
|
||||
@@ -45,10 +46,15 @@ public class MediaPickerItemFragment extends Fragment implements MediaPickerItem
|
||||
private GridLayoutManager layoutManager;
|
||||
|
||||
public static MediaPickerItemFragment newInstance(@NonNull String bucketId, @NonNull String folderTitle, int maxSelection) {
|
||||
return newInstance(bucketId, folderTitle, maxSelection, true);
|
||||
}
|
||||
|
||||
public static MediaPickerItemFragment newInstance(@NonNull String bucketId, @NonNull String folderTitle, int maxSelection, boolean forceMultiSelect) {
|
||||
Bundle args = new Bundle();
|
||||
args.putString(KEY_BUCKET_ID, bucketId);
|
||||
args.putString(KEY_FOLDER_TITLE, folderTitle);
|
||||
args.putInt(KEY_MAX_SELECTION, maxSelection);
|
||||
args.putBoolean(KEY_FORCE_MULTI_SELECT, forceMultiSelect);
|
||||
|
||||
MediaPickerItemFragment fragment = new MediaPickerItemFragment();
|
||||
fragment.setArguments(args);
|
||||
@@ -110,8 +116,10 @@ public class MediaPickerItemFragment extends Fragment implements MediaPickerItem
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
viewModel.onItemPickerStarted();
|
||||
adapter.setForcedMultiSelect(true);
|
||||
viewModel.onMultiSelectStarted();
|
||||
if (requireArguments().getBoolean(KEY_FORCE_MULTI_SELECT)) {
|
||||
adapter.setForcedMultiSelect(true);
|
||||
viewModel.onMultiSelectStarted();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -470,6 +470,10 @@ public class MediaSendActivity extends PassphraseRequiredActionBarActivity imple
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDoneEditing() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGlobalLayout() {
|
||||
hud.getRootView().getWindowVisibleDisplayFrame(visibleBounds);
|
||||
|
||||
Reference in New Issue
Block a user