diff options
author | Stefan Niedermann <info@niedermann.it> | 2020-11-03 19:45:24 +0300 |
---|---|---|
committer | Stefan Niedermann <info@niedermann.it> | 2020-11-03 19:45:24 +0300 |
commit | ce54a71de9d40f994078cb93b7e2e411b77dffef (patch) | |
tree | 17b81ee0fabdbc3227b3878a4f3d035901c27045 /app/src/main/java/it/niedermann/nextcloud/deck/ui | |
parent | 704b8c48d1fdfeee3d900287347d24e79a72aef8 (diff) |
Allow actual image picking
Signed-off-by: Stefan Niedermann <info@niedermann.it>
Diffstat (limited to 'app/src/main/java/it/niedermann/nextcloud/deck/ui')
3 files changed, 87 insertions, 33 deletions
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/CardAttachmentsFragment.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/CardAttachmentsFragment.java index 9edcf7a33..2401a4829 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/CardAttachmentsFragment.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/CardAttachmentsFragment.java @@ -92,6 +92,7 @@ public class CardAttachmentsFragment extends BrandedFragment implements Attachme private CardAttachmentAdapter adapter; private ImageView[] brandedViews; + private GalleryAdapter galleryAdapter; private int clickedItemPosition; @@ -152,15 +153,30 @@ public class CardAttachmentsFragment extends BrandedFragment implements Attachme public void onStateChanged(@NonNull View bottomSheet, int newState) { switch (newState) { case STATE_HIDDEN: { + DeckLog.log("BottomSheet: HIDDEN"); hidePicker(); binding.fab.show(); break; } - case STATE_EXPANDED: + case STATE_EXPANDED: { + DeckLog.log("BottomSheet: EXPANDED"); + showPicker(); + break; + } case STATE_HALF_EXPANDED: { + DeckLog.log("BottomSheet: HALF_EXPANDED"); showPicker(); break; } + case BottomSheetBehavior.STATE_COLLAPSED: + DeckLog.log("BottomSheet: COLLAPSED"); + break; + case BottomSheetBehavior.STATE_DRAGGING: + DeckLog.log("BottomSheet: DRAGGING"); + break; + case BottomSheetBehavior.STATE_SETTLING: + DeckLog.log("BottomSheet: SETTLING"); + break; } } @@ -169,11 +185,6 @@ public class CardAttachmentsFragment extends BrandedFragment implements Attachme } }); - if (SDK_INT >= LOLLIPOP) { - GalleryAdapter galleryAdapter = new GalleryAdapter(requireContext()); - binding.pickerRecyclerView.setLayoutManager(new GridLayoutManager(requireContext(), 3)); - binding.pickerRecyclerView.setAdapter(galleryAdapter); - } final DisplayMetrics displayMetrics = getResources().getDisplayMetrics(); int spanCount = (int) ((displayMetrics.widthPixels / displayMetrics.density) / getResources().getInteger(R.integer.max_dp_attachment_column)); @@ -209,9 +220,15 @@ public class CardAttachmentsFragment extends BrandedFragment implements Attachme if (viewModel.canEdit()) { binding.fab.setOnClickListener(v -> { -// picker = CardAttachmentPicker.newInstance(); -// picker.show(getChildFragmentManager(), CardAttachmentPicker.class.getSimpleName()); - mBottomSheetBehaviour.setState(STATE_HALF_EXPANDED); + if (SDK_INT >= LOLLIPOP && galleryAdapter == null) { + galleryAdapter = new GalleryAdapter(requireContext(), uri -> { + // TODO show selected image in dialog and let it confirm first + onActivityResult(REQUEST_CODE_ADD_FILE, RESULT_OK, new Intent().setData(uri)); + }); + binding.pickerRecyclerView.setLayoutManager(new GridLayoutManager(requireContext(), 3)); + binding.pickerRecyclerView.setAdapter(galleryAdapter); + } + mBottomSheetBehaviour.setState(STATE_EXPANDED); showPicker(); binding.fab.hide(); }); @@ -314,6 +331,15 @@ public class CardAttachmentsFragment extends BrandedFragment implements Attachme } } + @Override + public void onDestroy() { + if (this.galleryAdapter != null) { + this.galleryAdapter.onDestroy(); + this.binding.pickerRecyclerView.setAdapter(null); + } + super.onDestroy(); + } + private void uploadNewAttachmentFromUri(@NonNull Uri sourceUri, String mimeType) throws UploadAttachmentFailedException, IOException { if (sourceUri == null) { throw new UploadAttachmentFailedException("sourceUri is null"); @@ -408,6 +434,14 @@ public class CardAttachmentsFragment extends BrandedFragment implements Attachme } } + @Override + public void onLowMemory() { + super.onLowMemory(); + if (galleryAdapter != null) { + galleryAdapter.onLowMemory(); + } + } + private void hidePicker() { binding.bottomNavigation .animate() diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/GalleryAdapter.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/GalleryAdapter.java index d123cee74..0b051ed58 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/GalleryAdapter.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/GalleryAdapter.java @@ -6,6 +6,7 @@ import android.content.ContentUris; import android.content.Context; import android.database.Cursor; import android.graphics.Bitmap; +import android.net.Uri; import android.os.Handler; import android.os.Looper; import android.provider.MediaStore; @@ -13,10 +14,8 @@ import android.util.Pair; import android.util.Size; import android.view.LayoutInflater; import android.view.ViewGroup; -import android.widget.Toast; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import androidx.recyclerview.widget.RecyclerView; import java.util.HashMap; @@ -27,8 +26,8 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.FutureTask; +import java.util.function.Consumer; -import it.niedermann.nextcloud.deck.DeckLog; import it.niedermann.nextcloud.deck.databinding.ItemAttachmentImageBinding; import static android.os.Build.VERSION.SDK_INT; @@ -37,38 +36,37 @@ import static androidx.recyclerview.widget.RecyclerView.NO_ID; public class GalleryAdapter extends RecyclerView.Adapter<GalleryItemViewHolder> { - @NonNull - private final Context context; private final int columnIndex; private final int count; - @Nullable + @NonNull + private final Consumer<Uri> onSelect; + @NonNull private final Cursor cursor; @NonNull private final ContentResolver contentResolver; @NonNull private final Map<Integer, Pair<Long, FutureTask<Bitmap>>> itemCache = new HashMap<>(); + @NonNull private final ExecutorService bitmapFetcherExecutor = Executors.newCachedThreadPool(); + @NonNull private final ExecutorService bitmapWaiterExecutor = Executors.newCachedThreadPool(); - public GalleryAdapter(@NonNull Context context) { - this.context = context; + public GalleryAdapter(@NonNull Context context, @NonNull Consumer<Uri> onSelect) { + this.onSelect = onSelect; this.contentResolver = context.getContentResolver(); - log("Start Query"); @SuppressLint("InlinedApi") final String sortOrder = (SDK_INT >= Q) ? MediaStore.Images.Media.DATE_TAKEN : MediaStore.Images.Media.DATE_ADDED; cursor = Objects.requireNonNull(contentResolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, new String[]{MediaStore.Images.Media._ID}, null, null, sortOrder + " DESC")); this.columnIndex = cursor.getColumnIndex(MediaStore.Images.Media._ID); this.count = cursor.getCount(); - - log("Cursor count = " + this.count); notifyItemRangeInserted(0, this.count); setHasStableIds(true); } @Override public long getItemId(int position) { - Pair<Long, ?> itemAtPosition = getImageId(position); + final Pair<Long, ?> itemAtPosition = getImageInformation(position); return itemAtPosition == null ? NO_ID : itemAtPosition.first; } @@ -80,14 +78,15 @@ public class GalleryAdapter extends RecyclerView.Adapter<GalleryItemViewHolder> @Override public void onBindViewHolder(@NonNull GalleryItemViewHolder holder, int position) { - FutureTask<Bitmap> imageFuture = getImageId(position).second; - bitmapFetcherExecutor.execute(imageFuture); + final Pair<Long, FutureTask<Bitmap>> imageInformation = getImageInformation(position); + bitmapFetcherExecutor.execute(imageInformation.second); bitmapWaiterExecutor.execute(() -> { try { - final Bitmap image = imageFuture.get(); - new Handler(Looper.getMainLooper()).post(() -> holder.bind(image)); + final Bitmap image = imageInformation.second.get(); + new Handler(Looper.getMainLooper()).post(() -> holder.bind(ContentUris.withAppendedId( + MediaStore.Images.Media.EXTERNAL_CONTENT_URI, imageInformation.first), image, onSelect)); } catch (ExecutionException | InterruptedException ignored) { - new Handler(Looper.getMainLooper()).post(() -> holder.bind(null)); + new Handler(Looper.getMainLooper()).post(holder::bindError); } }); } @@ -97,12 +96,12 @@ public class GalleryAdapter extends RecyclerView.Adapter<GalleryItemViewHolder> return count; } - private Pair<Long, FutureTask<Bitmap>> getImageId(int position) { + private Pair<Long, FutureTask<Bitmap>> getImageInformation(int position) { if (itemCache.containsKey(position)) { return itemCache.get(position); } else { - if (cursor == null) { - return new Pair<>(NO_ID, null); + if (cursor.isClosed()) { + throw new IllegalStateException("This adapter has already been destoryed and can no longer be used."); } if (cursor.moveToPosition(position)) { long id = cursor.getLong(columnIndex); @@ -122,8 +121,17 @@ public class GalleryAdapter extends RecyclerView.Adapter<GalleryItemViewHolder> } } - private void log(String msg) { - DeckLog.log(msg); - Toast.makeText(context, msg, Toast.LENGTH_SHORT).show(); + /** + * Call this method in case of low memory. It will clear the internally cached {@link Bitmap}s to free memory. + */ + public void onLowMemory() { + itemCache.clear(); + } + + /** + * Call this method when the {@link GalleryAdapter} is no longe need to free resources. + */ + public void onDestroy() { + cursor.close(); } } diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/GalleryItemViewHolder.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/GalleryItemViewHolder.java index 7c4cf4a5a..d83876f0e 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/GalleryItemViewHolder.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/picker/GalleryItemViewHolder.java @@ -1,6 +1,7 @@ package it.niedermann.nextcloud.deck.ui.card.attachments.picker; import android.graphics.Bitmap; +import android.net.Uri; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -10,7 +11,9 @@ import com.bumptech.glide.Glide; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.function.Consumer; +import it.niedermann.nextcloud.deck.R; import it.niedermann.nextcloud.deck.databinding.ItemAttachmentImageBinding; public class GalleryItemViewHolder extends RecyclerView.ViewHolder { @@ -23,9 +26,18 @@ public class GalleryItemViewHolder extends RecyclerView.ViewHolder { this.binding = binding; } - public void bind(@Nullable Bitmap image) { + public void bind(@NonNull Uri uri, @Nullable Bitmap image, @NonNull Consumer<Uri> onSelect) { + itemView.setOnClickListener((v) -> onSelect.accept(uri)); Glide.with(itemView.getContext()) .load(image) + .placeholder(R.drawable.ic_image_grey600_24dp) + .into(binding.preview); + } + + public void bindError() { + itemView.setOnClickListener(null); + Glide.with(itemView.getContext()) + .load(R.drawable.ic_image_grey600_24dp) .into(binding.preview); } } |