From ae51e89a41309af211500903def99c78f867a0ee Mon Sep 17 00:00:00 2001 From: kollerlukas Date: Sun, 29 Jan 2017 23:59:45 -0800 Subject: [PATCH] - improvements in Loading speed - bug fixes --- .idea/misc.xml | 2 +- app/build.gradle | 6 +- .../adapter/album/RecyclerViewAdapter.java | 53 ++-- .../album/ViewHolder/VideoViewHolder.java | 51 ++-- .../item/ViewHolder/GifViewHolder.java | 13 +- .../item/ViewHolder/PhotoViewHolder.java | 20 +- .../item/ViewHolder/VideoViewHolder.java | 54 ++++ .../adapter/item/ViewHolder/ViewHolder.java | 8 +- .../adapter/item/ViewPagerAdapter.java | 15 +- .../adapter/main/ViewHolder/AlbumHolder.java | 20 +- .../us/koller/cameraroll/data/AlbumItem.java | 3 +- .../data/{ => MediaLoader}/MediaLoader.java | 255 ++++++++---------- .../data/MediaLoader/MediaLoaderThread.java | 91 +++++++ .../koller/cameraroll/ui/AlbumActivity.java | 47 ++-- .../us/koller/cameraroll/ui/ItemActivity.java | 56 ++-- .../us/koller/cameraroll/ui/MainActivity.java | 62 +++-- .../ui/widget/SwipeBackCoordinatorLayout.java | 124 ++++----- .../util/{ViewUtil.java => ItemViewUtil.java} | 62 ++++- .../us/koller/cameraroll/util/SortUtil.java | 4 +- .../java/us/koller/cameraroll/util/Util.java | 48 ++++ app/src/main/res/drawable/gif_indicator.png | Bin 0 -> 719 bytes .../ic_play_circle_filled_white_24dp.png | Bin 0 -> 883 bytes .../main/res/drawable/ic_sort_white_24dp.png | Bin 0 -> 505 bytes app/src/main/res/drawable/video_indicator.png | Bin 0 -> 508 bytes app/src/main/res/layout/activity_about.xml | 4 +- app/src/main/res/layout/activity_album.xml | 2 +- app/src/main/res/layout/albumitem_cover.xml | 3 +- 27 files changed, 613 insertions(+), 390 deletions(-) create mode 100644 app/src/main/java/us/koller/cameraroll/adapter/item/ViewHolder/VideoViewHolder.java rename app/src/main/java/us/koller/cameraroll/data/{ => MediaLoader}/MediaLoader.java (53%) create mode 100644 app/src/main/java/us/koller/cameraroll/data/MediaLoader/MediaLoaderThread.java rename app/src/main/java/us/koller/cameraroll/util/{ViewUtil.java => ItemViewUtil.java} (74%) create mode 100644 app/src/main/res/drawable/gif_indicator.png create mode 100644 app/src/main/res/drawable/ic_play_circle_filled_white_24dp.png create mode 100644 app/src/main/res/drawable/ic_sort_white_24dp.png create mode 100644 app/src/main/res/drawable/video_indicator.png diff --git a/.idea/misc.xml b/.idea/misc.xml index 7158618b..cca2cdae 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -37,7 +37,7 @@ - + diff --git a/app/build.gradle b/app/build.gradle index db59ab6b..abb278aa 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -7,12 +7,13 @@ android { applicationId "us.koller.cameraroll" minSdkVersion 21 targetSdkVersion 25 - versionCode 1 + versionCode 3 versionName "v1.0" renderscriptTargetApi 25 renderscriptSupportModeEnabled true testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } + buildTypes { release { minifyEnabled true @@ -30,6 +31,7 @@ android { dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) + androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { exclude group: 'com.android.support', module: 'support-annotations' }) @@ -46,4 +48,4 @@ dependencies { compile 'com.github.chrisbanes:PhotoView:1.3.1' compile 'com.github.MFlisar:DragSelectRecyclerView:0.2' -} +} \ No newline at end of file diff --git a/app/src/main/java/us/koller/cameraroll/adapter/album/RecyclerViewAdapter.java b/app/src/main/java/us/koller/cameraroll/adapter/album/RecyclerViewAdapter.java index 8d14a8a1..bea3f928 100644 --- a/app/src/main/java/us/koller/cameraroll/adapter/album/RecyclerViewAdapter.java +++ b/app/src/main/java/us/koller/cameraroll/adapter/album/RecyclerViewAdapter.java @@ -1,11 +1,11 @@ package us.koller.cameraroll.adapter.album; +import android.animation.ObjectAnimator; +import android.animation.PropertyValuesHolder; import android.app.Activity; -import android.content.ActivityNotFoundException; import android.content.Intent; -import android.net.Uri; +import android.graphics.drawable.Drawable; import android.support.v4.app.ActivityOptionsCompat; -import android.support.v4.content.FileProvider; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; @@ -14,7 +14,6 @@ import com.michaelflisar.dragselectrecyclerview.DragSelectTouchListener; -import java.io.File; import java.util.ArrayList; import us.koller.cameraroll.R; @@ -26,6 +25,7 @@ import us.koller.cameraroll.data.AlbumItem; import us.koller.cameraroll.data.Gif; import us.koller.cameraroll.data.Photo; +import us.koller.cameraroll.data.Video; import us.koller.cameraroll.ui.ItemActivity; public class RecyclerViewAdapter extends RecyclerView.Adapter { @@ -114,7 +114,11 @@ public void onClick(View view) { if (selector_mode) { onItemSelected((AlbumItemHolder) holder); - } else if (albumItem instanceof Photo || albumItem instanceof Gif) { + + //notify DragSelectTouchListener + int position = album.getAlbumItems().indexOf(albumItem); + dragSelectTouchListener.startDragSelection(position); + } else if (albumItem instanceof Photo || albumItem instanceof Gif || albumItem instanceof Video) { Intent intent = new Intent(holder.itemView.getContext(), ItemActivity.class); intent.putExtra(ItemActivity.ALBUM_ITEM, albumItem); intent.putExtra(ItemActivity.ALBUM, album); @@ -126,21 +130,11 @@ public void onClick(View view) { holder.itemView.findViewById(R.id.image), albumItem.getPath()); holder.itemView.getContext().startActivity(intent, options.toBundle()); - } else { - File file = new File(albumItem.getPath()); - Uri uri = FileProvider.getUriForFile(holder.itemView.getContext(), - holder.itemView.getContext().getApplicationContext().getPackageName() + ".provider", file); - - Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setDataAndType(uri, "video/*"); - intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - try { - holder.itemView.getContext().startActivity(intent); - } catch (ActivityNotFoundException e) { - Toast.makeText(holder.itemView.getContext(), "No App found to play your video", Toast.LENGTH_SHORT).show(); - e.printStackTrace(); - } } + + /*else if (albumItem instanceof Video){ + AlbumActivity.videoOnClick((Activity) holder.itemView.getContext(), albumItem); + }*/ } }); @@ -157,13 +151,15 @@ public boolean onLongClick(View view) { //notify AlbumActivity callback.onSelectorModeEnter(); + } - //notify DragSelectTouchListener + onItemSelected((AlbumItemHolder) holder); + + //notify DragSelectTouchListener + if (selected_items[album.getAlbumItems().indexOf(((AlbumItemHolder) holder).albumItem)]) { int position = album.getAlbumItems().indexOf(albumItem); dragSelectTouchListener.startDragSelection(position); } - - onItemSelected((AlbumItemHolder) holder); return true; } }); @@ -195,6 +191,19 @@ private void onItemSelected(AlbumItemHolder holder) { = !selected_items[album.getAlbumItems().indexOf(holder.albumItem)]; holder.itemView.findViewById(R.id.image) .setSelected(selected_items[album.getAlbumItems().indexOf(holder.albumItem)]); + + //fade selected indicator + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) { + boolean selected = selected_items[album.getAlbumItems().indexOf(holder.albumItem)]; + Drawable foreground = holder.itemView.findViewById(R.id.image).getForeground(); + + ObjectAnimator + .ofPropertyValuesHolder(foreground, + PropertyValuesHolder.ofInt("alpha", + selected ? 0 : 255, + selected ? 255 : 0)).start(); + } + callback.onItemSelected(getSelectedItemCount()); checkForNoSelectedItems(); } diff --git a/app/src/main/java/us/koller/cameraroll/adapter/album/ViewHolder/VideoViewHolder.java b/app/src/main/java/us/koller/cameraroll/adapter/album/ViewHolder/VideoViewHolder.java index 55b8d30f..d32393e6 100644 --- a/app/src/main/java/us/koller/cameraroll/adapter/album/ViewHolder/VideoViewHolder.java +++ b/app/src/main/java/us/koller/cameraroll/adapter/album/ViewHolder/VideoViewHolder.java @@ -12,7 +12,6 @@ import us.koller.cameraroll.R; import us.koller.cameraroll.data.AlbumItem; -import us.koller.cameraroll.data.Video; import us.koller.cameraroll.util.Util; public class VideoViewHolder extends AlbumItemHolder { @@ -34,32 +33,30 @@ void loadImage(ImageView imageView, final AlbumItem albumItem) { (int) ((float) screenWidth / columnCount), (int) ((float) screenWidth / columnCount)}; - if (albumItem instanceof Video) { - Glide.with(context) - .load(albumItem.getPath()) - .asBitmap() - .thumbnail(0.1f) - .skipMemoryCache(true) - .override(imageDimens[0], imageDimens[1]) - .listener(new RequestListener() { - @Override - public boolean onException(Exception e, String model, - Target target, boolean isFirstResource) { - return false; + Glide.with(context) + .load(albumItem.getPath()) + .asBitmap() + .thumbnail(0.1f) + .skipMemoryCache(true) + .override(imageDimens[0], imageDimens[1]) + .listener(new RequestListener() { + @Override + public boolean onException(Exception e, String model, + Target target, boolean isFirstResource) { + return false; + } + + @Override + public boolean onResourceReady(Bitmap resource, String model, + Target target, boolean isFromMemoryCache, + boolean isFirstResource) { + if (!albumItem.hasFadedIn) { + fadeIn(); } - - @Override - public boolean onResourceReady(Bitmap resource, String model, - Target target, boolean isFromMemoryCache, - boolean isFirstResource) { - if (!albumItem.hasFadedIn) { - fadeIn(); - } - return false; - } - }) - .error(R.drawable.error_placeholder) - .into(imageView); - } + return false; + } + }) + .error(R.drawable.error_placeholder) + .into(imageView); } } diff --git a/app/src/main/java/us/koller/cameraroll/adapter/item/ViewHolder/GifViewHolder.java b/app/src/main/java/us/koller/cameraroll/adapter/item/ViewHolder/GifViewHolder.java index 2b57504d..15d03e8c 100644 --- a/app/src/main/java/us/koller/cameraroll/adapter/item/ViewHolder/GifViewHolder.java +++ b/app/src/main/java/us/koller/cameraroll/adapter/item/ViewHolder/GifViewHolder.java @@ -1,5 +1,6 @@ package us.koller.cameraroll.adapter.item.ViewHolder; +import android.os.Handler; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; @@ -8,7 +9,8 @@ import us.koller.cameraroll.R; import us.koller.cameraroll.data.AlbumItem; -import us.koller.cameraroll.util.ViewUtil; +import us.koller.cameraroll.ui.ItemActivity; +import us.koller.cameraroll.util.ItemViewUtil; public class GifViewHolder extends ViewHolder { @@ -24,16 +26,16 @@ public View getView(ViewGroup container) { v.removeView(v.findViewById(R.id.subsampling)); View view = v.findViewById(R.id.image); if (albumItem.isSharedElement) { - ViewUtil.bindTransitionView((ImageView) view, albumItem); + ItemViewUtil.bindTransitionView((ImageView) view, albumItem); } else { - ViewUtil.bindGif(this, (ImageView) view, albumItem); + ItemViewUtil.bindGif(this, (ImageView) view, albumItem); } return v; } public void reloadGif() { View view = itemView.findViewById(R.id.image); - ViewUtil.bindGif(this, (ImageView) view, albumItem); + ItemViewUtil.bindGif(this, (ImageView) view, albumItem); } public void setAttacher(ImageView imageView) { @@ -51,9 +53,10 @@ public void onViewTap(View view, float x, float y) { } @Override - public void onSharedElement() { + public void onSharedElement(final ItemActivity.Callback callback) { if (attacher != null) { attacher.cleanup(); } + callback.callback(); } } diff --git a/app/src/main/java/us/koller/cameraroll/adapter/item/ViewHolder/PhotoViewHolder.java b/app/src/main/java/us/koller/cameraroll/adapter/item/ViewHolder/PhotoViewHolder.java index 5401dc57..389804cc 100644 --- a/app/src/main/java/us/koller/cameraroll/adapter/item/ViewHolder/PhotoViewHolder.java +++ b/app/src/main/java/us/koller/cameraroll/adapter/item/ViewHolder/PhotoViewHolder.java @@ -1,6 +1,5 @@ package us.koller.cameraroll.adapter.item.ViewHolder; -import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; @@ -11,7 +10,7 @@ import us.koller.cameraroll.data.AlbumItem; import us.koller.cameraroll.data.Photo; import us.koller.cameraroll.ui.ItemActivity; -import us.koller.cameraroll.util.ViewUtil; +import us.koller.cameraroll.util.ItemViewUtil; public class PhotoViewHolder extends ViewHolder { @@ -26,12 +25,12 @@ public View getView(ViewGroup container) { super.setOnClickListener(view); final View transitionView = itemView.findViewById(R.id.image); - ViewUtil.bindTransitionView((ImageView) transitionView, albumItem); + ItemViewUtil.bindTransitionView((ImageView) transitionView, albumItem); if (albumItem.isSharedElement) { view.setVisibility(View.INVISIBLE); } else { transitionView.setVisibility(View.INVISIBLE); - ViewUtil.bindSubsamplingImageView( + ItemViewUtil.bindSubsamplingImageView( (SubsamplingScaleImageView) view, (Photo) albumItem, transitionView); } @@ -43,7 +42,7 @@ public void swapView(final boolean isReturning) { final View transitionView = itemView.findViewById(R.id.image); if (!isReturning) { view.setVisibility(View.VISIBLE); - ViewUtil.bindSubsamplingImageView( + ItemViewUtil.bindSubsamplingImageView( (SubsamplingScaleImageView) view, (Photo) albumItem, transitionView); } else { @@ -52,7 +51,7 @@ public void swapView(final boolean isReturning) { } } - public void scaleDown(final ItemActivity.Callback callback) { + private void scaleDown(final ItemActivity.Callback callback) { final SubsamplingScaleImageView imageView = (SubsamplingScaleImageView) itemView.findViewById(R.id.subsampling); if (imageView != null) { try { @@ -75,7 +74,12 @@ public void onComplete() { } @Override - public void onSharedElement() { - + public void onSharedElement(final ItemActivity.Callback callback) { + scaleDown(new ItemActivity.Callback() { + @Override + public void callback() { + callback.callback(); + } + }); } } diff --git a/app/src/main/java/us/koller/cameraroll/adapter/item/ViewHolder/VideoViewHolder.java b/app/src/main/java/us/koller/cameraroll/adapter/item/ViewHolder/VideoViewHolder.java new file mode 100644 index 00000000..9dc70436 --- /dev/null +++ b/app/src/main/java/us/koller/cameraroll/adapter/item/ViewHolder/VideoViewHolder.java @@ -0,0 +1,54 @@ +package us.koller.cameraroll.adapter.item.ViewHolder; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.app.Activity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; + +import us.koller.cameraroll.R; +import us.koller.cameraroll.data.AlbumItem; +import us.koller.cameraroll.ui.AlbumActivity; +import us.koller.cameraroll.ui.ItemActivity; +import us.koller.cameraroll.util.ItemViewUtil; + +public class VideoViewHolder extends ViewHolder { + + public VideoViewHolder(AlbumItem albumItem, int position) { + super(albumItem, position); + } + + @Override + public View getView(ViewGroup container) { + ViewGroup v = super.inflateView(container); + v.removeView(v.findViewById(R.id.subsampling)); + View view = v.findViewById(R.id.image); + if (albumItem.isSharedElement) { + ItemViewUtil.bindTransitionView((ImageView) view, albumItem); + } else { + itemView = v; + bindView(); + } + return v; + } + + public void bindView() { + View view = itemView.findViewById(R.id.image); + ViewGroup v = ItemViewUtil.bindImageViewForVideo((ImageView) view, albumItem); + View playButton = v.findViewWithTag(ItemViewUtil.VIDEO_PLAY_BUTTON_TAG); + playButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + AlbumActivity.videoOnClick((Activity) view.getContext(), albumItem); + } + }); + playButton.setAlpha(0.0f); + playButton.animate().alpha(0.54f).start(); + } + + @Override + public void onSharedElement(final ItemActivity.Callback callback) { + callback.callback(); + } +} diff --git a/app/src/main/java/us/koller/cameraroll/adapter/item/ViewHolder/ViewHolder.java b/app/src/main/java/us/koller/cameraroll/adapter/item/ViewHolder/ViewHolder.java index 5de3dfb3..27fd80c7 100644 --- a/app/src/main/java/us/koller/cameraroll/adapter/item/ViewHolder/ViewHolder.java +++ b/app/src/main/java/us/koller/cameraroll/adapter/item/ViewHolder/ViewHolder.java @@ -5,7 +5,7 @@ import us.koller.cameraroll.data.AlbumItem; import us.koller.cameraroll.ui.ItemActivity; -import us.koller.cameraroll.util.ViewUtil; +import us.koller.cameraroll.util.ItemViewUtil; public abstract class ViewHolder { @@ -13,7 +13,7 @@ public abstract class ViewHolder { public AlbumItem albumItem; private int position; - ViewHolder(AlbumItem albumItem, int position) { + public ViewHolder(AlbumItem albumItem, int position) { this.albumItem = albumItem; this.position = position; } @@ -23,7 +23,7 @@ public int getPosition() { } ViewGroup inflateView(ViewGroup container) { - ViewGroup v = ViewUtil.inflateView(container); + ViewGroup v = ItemViewUtil.inflateView(container); v.setTag(albumItem.getPath()); this.itemView = v; return v; @@ -58,5 +58,5 @@ public String getTag() { return albumItem.getPath(); } - public abstract void onSharedElement(); + public abstract void onSharedElement(ItemActivity.Callback callback); } diff --git a/app/src/main/java/us/koller/cameraroll/adapter/item/ViewPagerAdapter.java b/app/src/main/java/us/koller/cameraroll/adapter/item/ViewPagerAdapter.java index 0c8eb78a..4c5caa3e 100644 --- a/app/src/main/java/us/koller/cameraroll/adapter/item/ViewPagerAdapter.java +++ b/app/src/main/java/us/koller/cameraroll/adapter/item/ViewPagerAdapter.java @@ -1,7 +1,6 @@ package us.koller.cameraroll.adapter.item; import android.support.v4.view.PagerAdapter; -import android.util.Log; import android.view.View; import android.view.ViewGroup; @@ -9,10 +8,12 @@ import us.koller.cameraroll.adapter.item.ViewHolder.GifViewHolder; import us.koller.cameraroll.adapter.item.ViewHolder.PhotoViewHolder; +import us.koller.cameraroll.adapter.item.ViewHolder.VideoViewHolder; import us.koller.cameraroll.adapter.item.ViewHolder.ViewHolder; import us.koller.cameraroll.data.Album; import us.koller.cameraroll.data.AlbumItem; -import us.koller.cameraroll.data.Photo; +import us.koller.cameraroll.data.Gif; +import us.koller.cameraroll.data.Video; public class ViewPagerAdapter extends PagerAdapter { @@ -40,10 +41,12 @@ public Object instantiateItem(final ViewGroup container, int position) { AlbumItem albumItem = album.getAlbumItems().get(position); ViewHolder viewHolder; - if (albumItem instanceof Photo) { - viewHolder = new PhotoViewHolder(albumItem, position); - } else { + if (albumItem instanceof Video) { + viewHolder = new VideoViewHolder(albumItem, position); + } else if (albumItem instanceof Gif) { viewHolder = new GifViewHolder(albumItem, position); + } else { + viewHolder = new PhotoViewHolder(albumItem, position); } viewHolders.add(viewHolder); @@ -62,7 +65,7 @@ public void destroyItem(ViewGroup container, int position, Object object) { } } - public ViewHolder findViewHolderByPosition(int position) { + private ViewHolder findViewHolderByPosition(int position) { for (int i = 0; i < viewHolders.size(); i++) { if (position == viewHolders.get(i).getPosition()) { return viewHolders.get(i); diff --git a/app/src/main/java/us/koller/cameraroll/adapter/main/ViewHolder/AlbumHolder.java b/app/src/main/java/us/koller/cameraroll/adapter/main/ViewHolder/AlbumHolder.java index 5655e03b..00eb5715 100644 --- a/app/src/main/java/us/koller/cameraroll/adapter/main/ViewHolder/AlbumHolder.java +++ b/app/src/main/java/us/koller/cameraroll/adapter/main/ViewHolder/AlbumHolder.java @@ -1,13 +1,14 @@ package us.koller.cameraroll.adapter.main.ViewHolder; import android.app.Activity; +import android.graphics.Bitmap; import android.support.v7.widget.RecyclerView; import android.view.View; import android.widget.ImageView; import android.widget.TextView; import com.bumptech.glide.Glide; -import com.bumptech.glide.load.resource.drawable.GlideDrawable; +import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.bumptech.glide.request.RequestListener; import com.bumptech.glide.request.target.Target; @@ -45,7 +46,6 @@ private void loadImage() { final AlbumItem coverImage = album.getAlbumItems().get(0); final ImageView image = (ImageView) itemView.findViewById(R.id.image); - if (image instanceof ParallaxImageView) { ((ParallaxImageView) image).setParallaxTranslation(); } @@ -59,26 +59,30 @@ private void loadImage() { Glide.with(itemView.getContext()) .load(coverImage.getPath()) + .asBitmap() .error(R.drawable.error_placeholder) - .listener(new RequestListener() { + .listener(new RequestListener() { @Override public boolean onException(Exception e, String model, - Target target, boolean isFirstResource) { + Target target, boolean isFirstResource) { coverImage.error = true; return false; } @Override - public boolean onResourceReady(GlideDrawable resource, String model, - Target target, boolean isFromMemoryCache, + public boolean onResourceReady(Bitmap resource, String model, + Target target, boolean isFromMemoryCache, boolean isFirstResource) { if (!coverImage.hasFadedIn) { coverImage.hasFadedIn = true; ColorFade.fadeSaturation(image); } + + if (image instanceof ParallaxImageView) { + ((ParallaxImageView) image).setParallaxTranslation(); + } return false; } - }) - .into(image); + }).into(image); } } diff --git a/app/src/main/java/us/koller/cameraroll/data/AlbumItem.java b/app/src/main/java/us/koller/cameraroll/data/AlbumItem.java index f501ac50..e308bccd 100644 --- a/app/src/main/java/us/koller/cameraroll/data/AlbumItem.java +++ b/app/src/main/java/us/koller/cameraroll/data/AlbumItem.java @@ -12,6 +12,7 @@ import us.koller.cameraroll.util.MediaType; import us.koller.cameraroll.util.SortUtil; +import us.koller.cameraroll.util.Util; public abstract class AlbumItem implements Parcelable, SortUtil.Sortable { private static final int PHOTO = 1; @@ -78,7 +79,7 @@ public String getPath() { @Override public long getDate(Activity context) { - return MediaLoader.getDateAdded(context, getPath()); + return Util.getDateAdded(context, getPath()); } public Uri getUri(Context context) { diff --git a/app/src/main/java/us/koller/cameraroll/data/MediaLoader.java b/app/src/main/java/us/koller/cameraroll/data/MediaLoader/MediaLoader.java similarity index 53% rename from app/src/main/java/us/koller/cameraroll/data/MediaLoader.java rename to app/src/main/java/us/koller/cameraroll/data/MediaLoader/MediaLoader.java index 6f691e8d..abca72ee 100644 --- a/app/src/main/java/us/koller/cameraroll/data/MediaLoader.java +++ b/app/src/main/java/us/koller/cameraroll/data/MediaLoader/MediaLoader.java @@ -1,8 +1,7 @@ -package us.koller.cameraroll.data; +package us.koller.cameraroll.data.MediaLoader; import android.Manifest; import android.app.Activity; -import android.content.ContentResolver; import android.content.pm.PackageManager; import android.database.Cursor; import android.net.Uri; @@ -19,21 +18,30 @@ import java.io.FileFilter; import java.util.ArrayList; +import us.koller.cameraroll.data.Album; +import us.koller.cameraroll.data.AlbumItem; +import us.koller.cameraroll.ui.MainActivity; import us.koller.cameraroll.util.MediaType; import us.koller.cameraroll.util.SortUtil; import us.koller.cameraroll.util.Util; -public class MediaLoader { +public class MediaLoader implements MainActivity.ActivityListener { public interface MediaLoaderCallback { void onMediaLoaded(ArrayList albums, boolean wasStorageSearched); } - private String[] projection = new String[]{ + private interface Callback { + void callback(ArrayList albums); + } + + private static final String FILE_TYPE_NO_MEDIA = ".nomedia"; + public static final int PERMISSION_REQUEST_CODE = 16; + private static final String[] projection = new String[]{ MediaStore.Files.FileColumns.DATA, MediaStore.Files.FileColumns.PARENT}; - public static final int PERMISSION_REQUEST_CODE = 16; + private ArrayList mediaLoaderThreads; public MediaLoader() { @@ -41,6 +49,8 @@ public MediaLoader() { public void loadAlbums(final Activity context, final boolean hiddenFolders, final MediaLoaderCallback callback) { + final long startTime = System.currentTimeMillis(); + if (!checkPermission(context)) { return; } @@ -73,12 +83,17 @@ public void loadAlbums(final Activity context, final boolean hiddenFolders, return; } + //search hiddenFolders + if (hiddenFolders) { + ArrayList hiddenAlbums = loadHiddenFolders(context); + albums.addAll(hiddenAlbums); + } + AsyncTask.execute(new Runnable() { @Override public void run() { if (cursor.moveToFirst()) { String path; - int pathColumn = cursor.getColumnIndex(MediaStore.Files.FileColumns.DATA); do { @@ -108,141 +123,93 @@ public void run() { } cursor.close(); - if (hiddenFolders) { - ArrayList hiddenAlbums = loadHiddenFolders(context); - for (int i = 0; i < hiddenAlbums.size(); i++) { - albums.add(hiddenAlbums.get(i)); - } - } //done loading media with content resolver SortUtil.sortAlbums(context, albums, SortUtil.BY_NAME); callback.onMediaLoaded(albums, false); - } - }); + Log.d("MediaLoader", "onMediaLoaded(..., false): " + String.valueOf(System.currentTimeMillis() - startTime)); - //load storage albums asynchronous - AsyncTask.execute(new Runnable() { - @Override - public void run() { - ArrayList albumsWithStorage = searchStorage(context, albums); - if (!hiddenFolders) { - for (int i = albumsWithStorage.size() - 1; i >= 0; i--) { - if (albumsWithStorage.get(i).hiddenAlbum) { - albumsWithStorage.remove(i); + //load media from storage + searchStorage(context, albums, new Callback() { + @Override + public void callback(ArrayList albums) { + if (!hiddenFolders) { + for (int i = albums.size() - 1; i >= 0; i--) { + if (albums.get(i).hiddenAlbum) { + albums.remove(i); + } + } } - } - } - //done loading media from storage - SortUtil.sortAlbums(context, albumsWithStorage, SortUtil.BY_NAME); - callback.onMediaLoaded(albumsWithStorage, true); + //done loading media from storage + SortUtil.sortAlbums(context, albums, SortUtil.BY_NAME); + callback.onMediaLoaded(albums, true); + Log.d("MediaLoader", "onMediaLoaded(..., true): " + String.valueOf(System.currentTimeMillis() - startTime)); + } + }); } }); } - private ArrayList searchStorage(final Activity context, final ArrayList albums) { - File file = Environment.getExternalStorageDirectory(); //new File("/storage/emulated/0"); - File[] files = file.listFiles(); - for (int i = 0; i < files.length; i++) { - if (!files[i].getPath().equals("/storage/emulated/0/Android")) { - recursivelySearchStorage(context, files[i], albums); - } - } - return albums; - } - - private void recursivelySearchStorage(Activity context, File file, ArrayList albums) { - if (file == null) { - return; - } - - if (!file.isDirectory()) { - return; - } - - Log.d("MediaLoader", file.getPath()); + private void searchStorage(final Activity context, final ArrayList albums, final Callback callback) { + final long startTime = System.currentTimeMillis(); - Album album = checkDirForMedia(context, file.getPath()); - if (album != null) { - boolean alreadyExists = false; - for (int k = 0; k < albums.size(); k++) { - if (file.getPath().equals(albums.get(k).getPath())) { - alreadyExists = true; - break; - } - } - - if (!alreadyExists) { - albums.add(album); - } - } - - File[] files = file.listFiles(new FileFilter() { + File dir = Environment.getExternalStorageDirectory(); //new File("/storage/emulated/0"); + File[] dirs = dir.listFiles(new FileFilter() { @Override public boolean accept(File file) { - return file.isDirectory(); + return !file.getName().equals("Android"); } }); - for (int i = 0; i < files.length; i++) { - Log.d("MediaLoader", file.getPath()); - recursivelySearchStorage(context, files[i], albums); + mediaLoaderThreads = new ArrayList<>(); + + for (int i = 0; i < dirs.length; i++) { + final File file = dirs[i]; + MediaLoaderThread mediaLoaderThread + = new MediaLoaderThread(context, file, new MediaLoaderThread.Callback() { + @Override + public void done(MediaLoaderThread thread, ArrayList albumsToAdd) { + mergeAlbums(albums, albumsToAdd); + mediaLoaderThreads.remove(thread); + thread.cancel(); + if (mediaLoaderThreads.size() == 0) { + callback.callback(albums); + mediaLoaderThreads = null; + + Log.d("MediaLoader", "searchStorage(): " + String.valueOf(System.currentTimeMillis() - startTime)); + } + } + }); + mediaLoaderThread.start(); + mediaLoaderThreads.add(mediaLoaderThread); } } - private AlbumItem loadMediaItem(Activity context, Uri uri) { - // Make the query. - ContentResolver resolver = context.getContentResolver(); - Cursor cursor = resolver.query(uri, - projection, // Which columns to return - null, // Which rows to return (all rows) - null, // Selection arguments (none) - null // Ordering - ); - - if (cursor == null) { - return AlbumItem.getInstance(context, uri.toString()); + private void mergeAlbums(ArrayList albums, ArrayList albumsToAdd) { + for (int i = albumsToAdd.size() - 1; i >= 0; i--) { + for (int k = 0; k < albums.size(); k++) { + if (albumsToAdd.get(i).getPath() + .equals(albums.get(k).getPath())) { + albumsToAdd.remove(i); + break; + } + } } - - cursor.moveToFirst(); - String path = cursor.getString(cursor.getColumnIndex(MediaStore.Files.FileColumns.DATA)); - cursor.close(); - - return AlbumItem.getInstance(context, path != null ? path : uri.toString()); + albums.addAll(albumsToAdd); } - static long getDateAdded(Activity context, String path) { - - long dateAdded = new File(path).lastModified(); - - String[] projection = {MediaStore.Images.Media.DATE_TAKEN}; - - // Make the query. - ContentResolver resolver = context.getContentResolver(); - Cursor cursor = resolver.query(Uri.parse(path), - projection, // Which columns to return - null, // Which rows to return (all rows) - null, // Selection arguments (none) - MediaStore.Images.Media.DATE_TAKEN // Ordering - ); - - if (cursor == null) { - return dateAdded; + @Override + public void onDestroy() { + //cancel all mediaLoaderThreads when Activity is being destroyed + if (mediaLoaderThreads != null) { + for (int i = 0; i < mediaLoaderThreads.size(); i++) { + mediaLoaderThreads.get(i).cancel(); + } } - - cursor.moveToFirst(); - String dateTaken = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATE_TAKEN)); - cursor.close(); - - dateAdded = Long.parseLong(dateTaken); - - return dateAdded; } - private static final String FILE_TYPE_NO_MEDIA = ".nomedia"; - - private ArrayList loadHiddenFolders(Activity context) { + private ArrayList loadHiddenFolders(final Activity context) { ArrayList hiddenAlbums = new ArrayList<>(); @@ -251,7 +218,7 @@ private ArrayList loadHiddenFolders(Activity context) { + "=" + MediaStore.Files.FileColumns.MEDIA_TYPE_NONE; // Files with name contain .nomedia - String where = nonMediaCondition + " AND " + String selection = nonMediaCondition + " AND " + MediaStore.Files.FileColumns.TITLE + " LIKE ?"; String[] params = new String[]{"%" + FILE_TYPE_NO_MEDIA + "%"}; @@ -260,8 +227,8 @@ private ArrayList loadHiddenFolders(Activity context) { // text on External Media URI Cursor cursor = context.getContentResolver().query( MediaStore.Files.getContentUri("external"), - projection, - where, + new String[]{MediaStore.Files.FileColumns.DATA}, + selection, params, MediaStore.Images.Media.DATE_TAKEN); @@ -271,9 +238,29 @@ private ArrayList loadHiddenFolders(Activity context) { if (cursor.moveToFirst()) { int pathColumn = cursor.getColumnIndex(MediaStore.Files.FileColumns.DATA); + do { - Album album = checkDirForMedia(context, cursor.getString(pathColumn)); - if (album != null) { + String path = cursor.getString(pathColumn); + Log.d("MediaLoader", path); + + path = path.replace(FILE_TYPE_NO_MEDIA, ""); + File folder = new File(path); + final Album album = new Album().setPath(folder.getPath()); + album.hiddenAlbum = true; + + folder.listFiles(new FileFilter() { + @Override + public boolean accept(File file) { + if (MediaType.isMedia(context, file.getPath())) { + AlbumItem albumItem = AlbumItem.getInstance(context, file.getPath()); + album.getAlbumItems().add(albumItem); + return true; + } + return false; + } + }); + + if (album.getAlbumItems().size() > 0) { hiddenAlbums.add(album); } } while (cursor.moveToNext()); @@ -283,34 +270,6 @@ private ArrayList loadHiddenFolders(Activity context) { return hiddenAlbums; } - private Album checkDirForMedia(final Activity context, String path) { - path = path.replace(FILE_TYPE_NO_MEDIA, ""); - File folder = new File(path); - Album album = new Album().setPath(folder.getPath()); - album.hiddenAlbum = folder.isHidden(); - - File[] files = folder.listFiles(new FileFilter() { - @Override - public boolean accept(File file) { - return MediaType.isMedia(context, file.getPath()); - } - }); - - if (files != null) { - for (int i = 0; i < files.length; i++) { - if (MediaType.isMedia(context, files[i].getPath())) { - AlbumItem albumItem = loadMediaItem(context, Uri.parse(files[i].getPath())); - album.getAlbumItems().add(albumItem); - } - } - } - - if (album.getAlbumItems().size() == 0) { - return null; - } - return album; - } - public static boolean checkPermission(Activity context) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { int permissionCheck = ContextCompat.checkSelfPermission(context, Manifest.permission.READ_EXTERNAL_STORAGE); diff --git a/app/src/main/java/us/koller/cameraroll/data/MediaLoader/MediaLoaderThread.java b/app/src/main/java/us/koller/cameraroll/data/MediaLoader/MediaLoaderThread.java new file mode 100644 index 00000000..245213a0 --- /dev/null +++ b/app/src/main/java/us/koller/cameraroll/data/MediaLoader/MediaLoaderThread.java @@ -0,0 +1,91 @@ +package us.koller.cameraroll.data.MediaLoader; + +import android.app.Activity; +import android.os.Looper; +import android.util.Log; + +/*import org.lukhnos.nnio.file.DirectoryStream; +import org.lukhnos.nnio.file.FileSystems; +import org.lukhnos.nnio.file.Files; +import org.lukhnos.nnio.file.Path;*/ + +import java.io.File; +import java.io.FileFilter; +import java.util.ArrayList; + +import us.koller.cameraroll.data.Album; +import us.koller.cameraroll.data.AlbumItem; +import us.koller.cameraroll.util.MediaType; + +class MediaLoaderThread extends java.lang.Thread { + + interface Callback { + void done(MediaLoaderThread mediaLoaderThread, ArrayList albums); + } + + private Activity context; + private Callback callback; + + private File dir; + + MediaLoaderThread(Activity context, File dir, Callback callback) { + this.context = context; + this.callback = callback; + this.dir = dir; + + + } + + @Override + public void run() { + super.run(); + + Looper.prepare(); + + ArrayList albums = new ArrayList<>(); + + if (dir != null) { + recursivelySearchStorage(context, dir, albums); + } + + if (callback != null) { + callback.done(this, albums); + } + } + + private void recursivelySearchStorage(final Activity context, + final File file, + final ArrayList albums) { + if (interrupted() || file == null) { + return; + } + + if (!file.isDirectory()) { + return; + } + + final Album album = new Album().setPath(file.getPath()); + album.hiddenAlbum = file.isHidden(); + + File[] files = file.listFiles(); + for (int i = 0; i < files.length; i++) { + if (file.isDirectory()) { + recursivelySearchStorage(context, files[i], albums); + } else if (MediaType.isMedia(context, files[i].getPath())) { + AlbumItem albumItem = AlbumItem + .getInstance(context, files[i].getPath()); + album.getAlbumItems().add(albumItem); + } + } + + if (album.getAlbumItems().size() > 0) { + albums.add(album); + } + } + + void cancel() { + context = null; + callback = null; + interrupt(); + } +} diff --git a/app/src/main/java/us/koller/cameraroll/ui/AlbumActivity.java b/app/src/main/java/us/koller/cameraroll/ui/AlbumActivity.java index 06ee4c30..17d347c4 100644 --- a/app/src/main/java/us/koller/cameraroll/ui/AlbumActivity.java +++ b/app/src/main/java/us/koller/cameraroll/ui/AlbumActivity.java @@ -1,6 +1,8 @@ package us.koller.cameraroll.ui; +import android.app.Activity; import android.app.ActivityManager; +import android.content.ActivityNotFoundException; import android.content.ClipData; import android.content.Intent; import android.content.pm.PackageManager; @@ -19,13 +21,13 @@ import android.support.graphics.drawable.AnimatedVectorDrawableCompat; import android.support.v4.app.SharedElementCallback; import android.support.v4.content.ContextCompat; +import android.support.v4.content.FileProvider; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.Toolbar; import android.transition.Fade; import android.transition.Slide; -import android.transition.Transition; import android.transition.TransitionSet; import android.view.Gravity; import android.view.View; @@ -43,12 +45,12 @@ import us.koller.cameraroll.adapter.album.RecyclerViewAdapter; import us.koller.cameraroll.data.Album; import us.koller.cameraroll.data.AlbumItem; -import us.koller.cameraroll.data.MediaLoader; +import us.koller.cameraroll.data.MediaLoader.MediaLoader; +import us.koller.cameraroll.data.Video; import us.koller.cameraroll.ui.widget.GridMarginDecoration; import us.koller.cameraroll.ui.widget.SwipeBackCoordinatorLayout; import us.koller.cameraroll.util.ColorFade; import us.koller.cameraroll.util.MediaType; -import us.koller.cameraroll.util.TransitionListenerAdapter; import us.koller.cameraroll.util.Util; public class AlbumActivity extends AppCompatActivity implements SwipeBackCoordinatorLayout.OnSwipeListener, RecyclerViewAdapter.Callback { @@ -137,9 +139,10 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { return; } - final SwipeBackCoordinatorLayout swipeBackView - = (SwipeBackCoordinatorLayout) findViewById(R.id.root_view); - swipeBackView.setOnSwipeListener(this); + final ViewGroup rootView = (ViewGroup) findViewById(R.id.root_view); + if (rootView instanceof SwipeBackCoordinatorLayout) { + ((SwipeBackCoordinatorLayout) rootView).setOnSwipeListener(this); + } final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); @@ -206,7 +209,7 @@ public void onScrolled(RecyclerView recyclerView, int dx, int dy) { fab.setScaleX(0.0f); fab.setScaleY(0.0f); - swipeBackView.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() { + rootView.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() { @Override public WindowInsets onApplyWindowInsets(View view, WindowInsets insets) { toolbar.setPadding(toolbar.getPaddingStart(), @@ -231,7 +234,7 @@ public WindowInsets onApplyWindowInsets(View view, WindowInsets insets) { fabParams.bottomMargin += insets.getSystemWindowInsetBottom(); fab.setLayoutParams(fabParams); - swipeBackView.setOnApplyWindowInsetsListener(null); + rootView.setOnApplyWindowInsetsListener(null); return insets.consumeSystemWindowInsets(); } }); @@ -357,7 +360,6 @@ public void onDismissed(Snackbar snackbar, int event) { } } }); - //snackbar.show(); Util.showSnackbar(snackbar); if (VIEW_ONLY) { @@ -405,7 +407,6 @@ public void onDismissed(Snackbar snackbar, int event) { } } }); - //snackbar.show(); Util.showSnackbar(snackbar); } @@ -436,9 +437,6 @@ public void deleteAlbumItems(AlbumItem[] selected_items, int[] indices) { if (refreshMainActivityAfterItemWasDeleted) { setResult(RESULT_OK, new Intent(MainActivity.REFRESH_MEDIA)); onBackPressed(); - /*Intent intent = new Intent(AlbumActivity.this, MainActivity.class); - intent.setAction(MainActivity.REFRESH_MEDIA); - startActivity(intent);*/ } Toast.makeText(AlbumActivity.this, getString(R.string.successfully_deleted) + successfully_deleted + " / " + selected_items.length, Toast.LENGTH_SHORT).show(); @@ -545,6 +543,26 @@ public void onItemSelected(int selectedItemCount) { } } + public static void videoOnClick(Activity context, AlbumItem albumItem) { + if (!(albumItem instanceof Video)) { + return; + } + + File file = new File(albumItem.getPath()); + Uri uri = FileProvider.getUriForFile(context, + context.getApplicationContext().getPackageName() + ".provider", file); + + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setDataAndType(uri, "video/*"); + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + try { + context.startActivity(intent); + } catch (ActivityNotFoundException e) { + Toast.makeText(context, "No App found to play your video", Toast.LENGTH_SHORT).show(); + e.printStackTrace(); + } + } + public void fabClicked() { animateFab(false, true); new Handler().postDelayed(new Runnable() { @@ -640,8 +658,7 @@ private void setupTaskDescription() { @Override public boolean canSwipeBack(int dir) { - return !((RecyclerViewAdapter) recyclerView.getAdapter()).isSelectorModeActive() - && SwipeBackCoordinatorLayout.canSwipeBackForThisView(recyclerView, dir) && !pick_photos; + return SwipeBackCoordinatorLayout.canSwipeBackForThisView(recyclerView, dir) && !pick_photos; } @Override diff --git a/app/src/main/java/us/koller/cameraroll/ui/ItemActivity.java b/app/src/main/java/us/koller/cameraroll/ui/ItemActivity.java index f8ca346c..f73c06cb 100644 --- a/app/src/main/java/us/koller/cameraroll/ui/ItemActivity.java +++ b/app/src/main/java/us/koller/cameraroll/ui/ItemActivity.java @@ -34,7 +34,6 @@ import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; -import android.view.ViewTreeObserver; import android.view.WindowInsets; import android.view.animation.AccelerateDecelerateInterpolator; import android.widget.ImageView; @@ -52,12 +51,12 @@ import us.koller.cameraroll.R; import us.koller.cameraroll.adapter.item.ViewHolder.GifViewHolder; import us.koller.cameraroll.adapter.item.ViewHolder.PhotoViewHolder; +import us.koller.cameraroll.adapter.item.ViewHolder.VideoViewHolder; import us.koller.cameraroll.adapter.item.ViewHolder.ViewHolder; import us.koller.cameraroll.adapter.item.ViewPagerAdapter; import us.koller.cameraroll.data.Album; import us.koller.cameraroll.data.AlbumItem; -import us.koller.cameraroll.data.Gif; -import us.koller.cameraroll.data.MediaLoader; +import us.koller.cameraroll.data.MediaLoader.MediaLoader; import us.koller.cameraroll.data.Photo; import us.koller.cameraroll.data.Video; import us.koller.cameraroll.util.MediaType; @@ -122,12 +121,15 @@ public void onTransitionEnd(Transition transition) { if (viewHolder == null) { return; } - if (!isReturning && albumItem instanceof Photo) { - ((PhotoViewHolder) viewHolder).swapView(false); - Log.d("ItemActivity", "swapView()"); - } else if (!isReturning && albumItem instanceof Gif - && viewHolder instanceof GifViewHolder) { - ((GifViewHolder) viewHolder).reloadGif(); + + if (!isReturning) { + if (viewHolder instanceof PhotoViewHolder) { + ((PhotoViewHolder) viewHolder).swapView(false); + } else if (viewHolder instanceof GifViewHolder) { + ((GifViewHolder) viewHolder).reloadGif(); + } else if (viewHolder instanceof VideoViewHolder) { + ((VideoViewHolder) viewHolder).bindView(); + } } if (transition != null) { @@ -199,7 +201,7 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { if (actionBar != null) { actionBar.setTitle(albumItem.getName() != null && !view_only ? albumItem.getName() : ""); - actionBar.setDisplayHomeAsUpEnabled(true/*!view_only*/); + actionBar.setDisplayHomeAsUpEnabled(true); } viewPager = (ViewPager) findViewById(R.id.view_pager); @@ -271,12 +273,6 @@ public WindowInsets onApplyWindowInsets(View view, WindowInsets insets) { } } - @Override - protected void onResume() { - super.onResume(); - Log.d("ItemActivity", "onResume() called; " + this); - } - @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); @@ -341,10 +337,6 @@ public void setPhotoAs() { } public void sharePhoto() { - if (albumItem instanceof Video) { - return; - } - Uri uri = albumItem.getUri(this); Intent shareIntent = ShareCompat.IntentBuilder.from(this) @@ -420,7 +412,6 @@ public void showInfoDialog() { if (exif == null) { snackbar = Snackbar.make(findViewById(R.id.root_view), R.string.error, Snackbar.LENGTH_LONG); - //snackbar.show(); Util.showSnackbar(snackbar); return; } @@ -435,7 +426,9 @@ public void showInfoDialog() { int[] imageDimens = null; if (!exifSupported) { - imageDimens = Util.getImageDimensions(albumItem.getPath()); + imageDimens = albumItem instanceof Video ? + Util.getVideoDimensions(albumItem.getPath()) : + Util.getImageDimensions(albumItem.getPath()); } String height = exifSupported ? exif.getAttribute(ExifInterface.TAG_IMAGE_LENGTH) : String.valueOf(imageDimens[1]); @@ -610,6 +603,7 @@ public void onSaveInstanceState(Bundle outState) { SubsamplingScaleImageView imageView = (SubsamplingScaleImageView) view; ImageViewState state = imageView.getState(); if (state != null) { + Log.d("ItemActivity", "saving state..."); outState.putSerializable(IMAGE_VIEW_SAVED_STATE, imageView.getState()); } } @@ -628,19 +622,15 @@ public void onBackPressed() { showUI(false); if (view_only) { this.finishAffinity(); - } else if (albumItem instanceof Photo) { + } else { ViewHolder viewHolder = ((ViewPagerAdapter) viewPager.getAdapter()).findViewHolderByTag(albumItem.getPath()); - if (viewHolder instanceof PhotoViewHolder) { - ((PhotoViewHolder) viewHolder).scaleDown(new Callback() { - @Override - public void callback() { - setResultAndFinish(); - } - }); - } - } else { - setResultAndFinish(); + viewHolder.onSharedElement(new ItemActivity.Callback() { + @Override + public void callback() { + setResultAndFinish(); + } + }); } } diff --git a/app/src/main/java/us/koller/cameraroll/ui/MainActivity.java b/app/src/main/java/us/koller/cameraroll/ui/MainActivity.java index 8c062922..ca369984 100644 --- a/app/src/main/java/us/koller/cameraroll/ui/MainActivity.java +++ b/app/src/main/java/us/koller/cameraroll/ui/MainActivity.java @@ -5,7 +5,6 @@ import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.graphics.BitmapFactory; -import android.os.AsyncTask; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.design.widget.Snackbar; @@ -28,13 +27,16 @@ import us.koller.cameraroll.R; import us.koller.cameraroll.adapter.main.RecyclerViewAdapter; import us.koller.cameraroll.data.Album; -import us.koller.cameraroll.data.MediaLoader; +import us.koller.cameraroll.data.MediaLoader.MediaLoader; import us.koller.cameraroll.ui.widget.ParallaxImageView; -import us.koller.cameraroll.util.SortUtil; import us.koller.cameraroll.util.Util; public class MainActivity extends AppCompatActivity { + public static interface ActivityListener { + public void onDestroy(); + } + public static final String ALBUMS = "ALBUMS"; public static final String REFRESH_MEDIA = "REFRESH_MEDIA"; public static final String SHARED_PREF_NAME = "CAMERA_ROLL_SETTINGS"; @@ -50,6 +52,8 @@ public class MainActivity extends AppCompatActivity { private Snackbar snackbar; + private MediaLoader mediaLoader; + private boolean hiddenFolders = false; private boolean pick_photos; private boolean allowMultiple; @@ -102,7 +106,6 @@ public void onClick(View view) { recyclerView.setLayoutManager(new LinearLayoutManager(this)); recyclerViewAdapter = new RecyclerViewAdapter(pick_photos).setAlbums(albums); recyclerView.setAdapter(recyclerViewAdapter); - recyclerView.setHasFixedSize(true); recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override @@ -168,20 +171,12 @@ public boolean onPreDraw() { setupTaskDescription(); - //loading media + //load media if (savedInstanceState == null) { refreshPhotos(); } } - @Override - protected void onNewIntent(Intent intent) { - super.onNewIntent(intent); - if (intent.getAction().equals(REFRESH_MEDIA)) { - //refreshPhotos(); - } - } - @Override public void onActivityReenter(int resultCode, Intent intent) { super.onActivityReenter(resultCode, intent); @@ -216,7 +211,6 @@ private void setSystemUiFlags() { public void refreshPhotos() { final Snackbar snackbar = Snackbar.make(findViewById(R.id.root_view), R.string.loading, Snackbar.LENGTH_INDEFINITE); - //snackbar.show(); Util.showSnackbar(snackbar); final MediaLoader.MediaLoaderCallback callback @@ -224,24 +218,40 @@ public void refreshPhotos() { @Override public void onMediaLoaded(final ArrayList albums, final boolean wasStorageSearched) { - final int oldAlbumsSize = MainActivity.this.albums.size(); - MainActivity.this.albums = albums; recyclerView.post(new Runnable() { @Override public void run() { recyclerViewAdapter.setAlbums(albums); - if (!wasStorageSearched) { - recyclerViewAdapter.notifyDataSetChanged(); - } else { + + if (wasStorageSearched) { + if (albums.size() > 0 + && MainActivity.this.albums.size() > 0 + && albums.size() > MainActivity.this.albums.size()) { + int i = 0, k = 0; + while (i < albums.size()) { + if (!albums.get(i).equals(MainActivity.this.albums.get(k))) { + recyclerViewAdapter.notifyItemInserted(i); + } else if (k < MainActivity.this.albums.size() - 1) { + k++; + } + i++; + } + } + snackbar.dismiss(); - recyclerViewAdapter.notifyItemRangeInserted(oldAlbumsSize, albums.size()); + mediaLoader = null; + } else { + recyclerViewAdapter.notifyDataSetChanged(); } + + MainActivity.this.albums = albums; } }); } }; - new MediaLoader().loadAlbums(MainActivity.this, hiddenFolders, callback); + mediaLoader = new MediaLoader(); + mediaLoader.loadAlbums(MainActivity.this, hiddenFolders, callback); } @Override @@ -294,7 +304,7 @@ public void onRequestPermissionsResult(int requestCode, @NonNull String permissi } } else { // permission denied - Snackbar snackbar = Util.getPermissionDeniedSnackbar(findViewById(R.id.root_view)); + snackbar = Util.getPermissionDeniedSnackbar(findViewById(R.id.root_view)); snackbar.setAction(R.string.retry, new View.OnClickListener() { @Override public void onClick(View view) { @@ -325,4 +335,12 @@ protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putParcelableArrayList(ALBUMS, albums); } + + @Override + protected void onDestroy() { + super.onDestroy(); + if (mediaLoader != null) { + mediaLoader.onDestroy(); + } + } } diff --git a/app/src/main/java/us/koller/cameraroll/ui/widget/SwipeBackCoordinatorLayout.java b/app/src/main/java/us/koller/cameraroll/ui/widget/SwipeBackCoordinatorLayout.java index a3e3c744..0c09f100 100644 --- a/app/src/main/java/us/koller/cameraroll/ui/widget/SwipeBackCoordinatorLayout.java +++ b/app/src/main/java/us/koller/cameraroll/ui/widget/SwipeBackCoordinatorLayout.java @@ -4,7 +4,6 @@ import android.support.design.widget.CoordinatorLayout; import android.support.v4.view.ViewCompat; import android.util.AttributeSet; -import android.view.MotionEvent; import android.view.View; import android.view.animation.Animation; import android.view.animation.Transformation; @@ -20,19 +19,11 @@ public class SwipeBackCoordinatorLayout extends CoordinatorLayout { private static float SWIPE_TRIGGER = 100; private static final float SWIPE_RADIO = 2.5F; - private float touchSlop; - private float oldX; - private float oldY; - private int swipeDir = NULL_DIR; public static final int NULL_DIR = 0; public static final int UP_DIR = 1; public static final int DOWN_DIR = -1; - /** - *
life cycle. - */ - public SwipeBackCoordinatorLayout(Context context) { super(context); this.initialize(); @@ -53,85 +44,76 @@ private void initialize() { } @Override - public boolean dispatchTouchEvent(MotionEvent ev) { - super.dispatchTouchEvent(ev); - if (ev.getAction() == MotionEvent.ACTION_DOWN) { - oldX = ev.getX(); - oldY = ev.getY(); - } - return isEnabled() && listener != null; + public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) { + return super.onStartNestedScroll(child, target, nestedScrollAxes) + || ((nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0); } @Override - public boolean onInterceptTouchEvent(MotionEvent ev) { - super.onInterceptTouchEvent(ev); - switch (ev.getAction()) { - case MotionEvent.ACTION_MOVE: - if (Math.abs(ev.getY() - oldY) < touchSlop) { - oldX = ev.getX(); - oldY = ev.getY(); - return false; - } else if (ev.getY() > oldY - && Math.abs(ev.getX() - oldX) < Math.abs(ev.getY() - oldY)) { - // swipe down. - if (swipeDistance == 0 && !listener.canSwipeBack(DOWN_DIR)) { - oldX = ev.getX(); - oldY = ev.getY(); - return false; - } else { - return true; - } - } else if (ev.getY() < oldY - && Math.abs(ev.getX() - oldX) < Math.abs(ev.getY() - oldY)) { - // swipe up. - if (swipeDistance == 0 && !listener.canSwipeBack(UP_DIR)) { - oldX = ev.getX(); - oldY = ev.getY(); - return false; - } else { - return true; - } - } - break; - case MotionEvent.ACTION_UP: - return swipeDistance != 0; + public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) { + int dyConsumed = 0; + if (swipeDistance != 0) { + dyConsumed = onPreScroll(dy); } - return false; + + int[] newConsumed = new int[]{0, 0}; + super.onNestedPreScroll(target, dx, dy - dyConsumed, newConsumed); + + consumed[0] = newConsumed[0]; + consumed[1] = newConsumed[1] + dyConsumed; } @Override - public boolean onTouchEvent(MotionEvent ev) { - super.onTouchEvent(ev); - switch (ev.getAction()) { - case MotionEvent.ACTION_MOVE: - onSwipe(ev.getY()); - return true; - case MotionEvent.ACTION_UP: - if (Math.abs(swipeDistance) >= SWIPE_TRIGGER) { - swipeBack(); - } else { - reset(); - } - return true; + public void onNestedScroll(View target, int dxConsumed, int dyConsumed, + int dxUnconsumed, int dyUnconsumed) { + int newDyConsumed = dyConsumed; + int newDyUnconsumed = dyUnconsumed; + if (swipeDistance == 0) { + int dir = dyUnconsumed < 0 ? DOWN_DIR : UP_DIR; + if (listener.canSwipeBack(dir)) { + onScroll(dyUnconsumed); + newDyConsumed = dyConsumed + dyUnconsumed; + newDyUnconsumed = 0; + } } - return false; + + super.onNestedScroll(target, dxConsumed, newDyConsumed, dxUnconsumed, newDyUnconsumed); } - private void onSwipe(float newY) { - if (swipeDistance * (newY - oldY) < 0) { - swipeDistance = 0; - swipeDir = NULL_DIR; + @Override + public void onStopNestedScroll(View child) { + super.onStopNestedScroll(child); + if (Math.abs(swipeDistance) >= SWIPE_TRIGGER) { + swipeBack(); } else { - swipeDistance = (int) (newY - oldY); + reset(); } - if (swipeDistance != 0) { - swipeDir = swipeDistance > 0 ? DOWN_DIR : UP_DIR; - } else { + } + + private int onPreScroll(int dy) { + int consumed; + if (swipeDistance * (swipeDistance - dy) < 0) { swipeDir = NULL_DIR; + consumed = swipeDistance; + swipeDistance = 0; + } else { + consumed = dy; + swipeDistance -= dy; } + setSwipeTranslation(); + + return consumed; } + private void onScroll(int dy) { + swipeDistance = -dy; + swipeDir = swipeDistance > 0 ? DOWN_DIR : UP_DIR; + + setSwipeTranslation(); + } + + private void swipeBack() { if (listener != null) { listener.onSwipeFinish(swipeDir); diff --git a/app/src/main/java/us/koller/cameraroll/util/ViewUtil.java b/app/src/main/java/us/koller/cameraroll/util/ItemViewUtil.java similarity index 74% rename from app/src/main/java/us/koller/cameraroll/util/ViewUtil.java rename to app/src/main/java/us/koller/cameraroll/util/ItemViewUtil.java index b596c5fb..2c5e6971 100644 --- a/app/src/main/java/us/koller/cameraroll/util/ViewUtil.java +++ b/app/src/main/java/us/koller/cameraroll/util/ItemViewUtil.java @@ -5,12 +5,12 @@ import android.net.Uri; import android.os.Handler; import android.provider.MediaStore; -import android.support.design.widget.Snackbar; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; +import android.widget.RelativeLayout; import com.bumptech.glide.Glide; import com.bumptech.glide.load.engine.DiskCacheStrategy; @@ -21,18 +21,16 @@ import com.davemorrissey.labs.subscaleview.ImageViewState; import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView; -import uk.co.senab.photoview.PhotoViewAttacher; - import java.io.IOException; import us.koller.cameraroll.R; import us.koller.cameraroll.adapter.item.ViewHolder.GifViewHolder; import us.koller.cameraroll.data.AlbumItem; -import us.koller.cameraroll.data.Gif; import us.koller.cameraroll.data.Photo; +import us.koller.cameraroll.data.Video; import us.koller.cameraroll.ui.ItemActivity; -public class ViewUtil { +public class ItemViewUtil { public static ViewGroup inflateView(ViewGroup container) { return (ViewGroup) LayoutInflater.from(container.getContext()) @@ -50,7 +48,7 @@ public static View bindSubsamplingImageView(SubsamplingScaleImageView imageView, if (!photo.contentUri) { if (imageViewState != null) { imageView.setImage(ImageSource.uri(photo.getPath()), imageViewState); - Log.d("ViewUtil", "restored state..."); + Log.d("ItemViewUtil", "restored state..."); } else { imageView.setImage(ImageSource.uri(photo.getPath())); } @@ -60,7 +58,7 @@ public static View bindSubsamplingImageView(SubsamplingScaleImageView imageView, imageView.getContext().getContentResolver(), Uri.parse(photo.getPath())); if (imageViewState != null) { imageView.setImage(ImageSource.bitmap(bmp), imageViewState); - Log.d("ViewUtil", "restored state..."); + Log.d("ItemViewUtil", "restored state..."); } else { imageView.setImage(ImageSource.bitmap(bmp)); } @@ -85,12 +83,15 @@ public void onImageLoaded() { public static View bindTransitionView(final ImageView imageView, final AlbumItem albumItem) { - int[] imageDimens = Util.getImageDimensions(albumItem.getPath()); + int[] imageDimens = albumItem instanceof Video ? + Util.getVideoDimensions(albumItem.getPath()) : + Util.getImageDimensions(albumItem.getPath()); + int screenWidth = Util.getScreenWidth((Activity) imageView.getContext()); float scale = ((float) screenWidth) / (float) imageDimens[0]; scale = scale > 1.0f ? 1.0f : scale == 0.0f ? 1.0f : scale; - imageDimens[0] = (int) (imageDimens[0] * scale); - imageDimens[1] = (int) (imageDimens[1] * scale); + imageDimens[0] = (int) (imageDimens[0] * scale * 0.5f); + imageDimens[1] = (int) (imageDimens[1] * scale * 0.5f); Glide.with(imageView.getContext()) .load(albumItem.getPath()) @@ -138,7 +139,7 @@ public static View bindGif(final GifViewHolder gifViewHolder, .load(albumItem.getPath()) .asGif() .skipMemoryCache(true) - .diskCacheStrategy(DiskCacheStrategy.RESULT) + .diskCacheStrategy(DiskCacheStrategy.SOURCE) .error(R.drawable.error_placeholder) .listener(new RequestListener() { @Override @@ -161,4 +162,43 @@ public boolean onResourceReady(GifDrawable resource, String model, imageView.setTransitionName(albumItem.getPath()); return imageView; } + + public static final String VIDEO_PLAY_BUTTON_TAG = "VIDEO_PLAY_BUTTON_TAG"; + + public static ViewGroup bindImageViewForVideo(final ImageView imageView, + final AlbumItem albumItem) { + int[] imageDimens = albumItem instanceof Video ? + Util.getVideoDimensions(albumItem.getPath()) : + Util.getImageDimensions(albumItem.getPath()); + + int screenWidth = Util.getScreenWidth((Activity) imageView.getContext()); + float scale = ((float) screenWidth) / (float) imageDimens[0]; + scale = scale > 1.0f ? 1.0f : scale == 0.0f ? 1.0f : scale; + imageDimens[0] = (int) (imageDimens[0] * scale); + imageDimens[1] = (int) (imageDimens[1] * scale); + + Glide.with(imageView.getContext()) + .load(albumItem.getPath()) + .asBitmap() + .override(imageDimens[0], imageDimens[1]) + .skipMemoryCache(true) + .error(R.drawable.error_placeholder) + .into(imageView); + imageView.setTransitionName(albumItem.getPath()); + + ImageView playButton = new ImageView(imageView.getContext()); + playButton.setTag(VIDEO_PLAY_BUTTON_TAG); + playButton.setImageResource(R.drawable.ic_play_circle_filled_white_24dp); + playButton.setAlpha(0.54f); + RelativeLayout.LayoutParams params + = new RelativeLayout.LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT); + params.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE); + playButton.setLayoutParams(params); + + ViewGroup v = (ViewGroup) imageView.getParent(); + v.addView(playButton); + return v; + } } diff --git a/app/src/main/java/us/koller/cameraroll/util/SortUtil.java b/app/src/main/java/us/koller/cameraroll/util/SortUtil.java index d3e13938..9e769ad7 100644 --- a/app/src/main/java/us/koller/cameraroll/util/SortUtil.java +++ b/app/src/main/java/us/koller/cameraroll/util/SortUtil.java @@ -21,9 +21,9 @@ public interface Sortable { public static ArrayList sortAlbums(Activity context, ArrayList albums, int by) { //sort each individual album - for (int i = 0; i < albums.size(); i++) { + /*for (int i = 0; i < albums.size(); i++) { sort(context, albums, BY_DATE); - } + }*/ //sort albums arrayList sort(context, albums, by); diff --git a/app/src/main/java/us/koller/cameraroll/util/Util.java b/app/src/main/java/us/koller/cameraroll/util/Util.java index c84bc716..4f470c67 100644 --- a/app/src/main/java/us/koller/cameraroll/util/Util.java +++ b/app/src/main/java/us/koller/cameraroll/util/Util.java @@ -1,10 +1,16 @@ package us.koller.cameraroll.util; import android.app.Activity; +import android.content.ContentResolver; import android.content.Context; +import android.database.Cursor; +import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Typeface; +import android.media.MediaMetadataRetriever; +import android.net.Uri; import android.os.Build; +import android.provider.MediaStore; import android.support.design.widget.Snackbar; import android.util.DisplayMetrics; import android.view.View; @@ -39,6 +45,20 @@ public static int[] getImageDimensions(String path) { return dimensions; } + public static int[] getVideoDimensions(String path) { + MediaMetadataRetriever retriever = new MediaMetadataRetriever(); + + retriever.setDataSource(path); + Bitmap bitmap = retriever.getFrameAtTime(); + + int[] dimensions = new int[2]; + + dimensions[0] = bitmap.getWidth() > 0 ? bitmap.getWidth() : 1; + dimensions[1] = bitmap.getHeight() > 0 ? bitmap.getHeight() : 1; + return dimensions; + + } + public static void setDarkStatusBarIcons(final View v) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { v.post(new Runnable() { @@ -85,4 +105,32 @@ public boolean onLongClick(View view) { }); return snackbar; } + + public static long getDateAdded(Activity context, String path) { + + long dateAdded = new File(path).lastModified(); + + String[] projection = {MediaStore.Images.Media.DATE_TAKEN}; + + // Make the query. + ContentResolver resolver = context.getContentResolver(); + Cursor cursor = resolver.query(Uri.parse(path), + projection, // Which columns to return + null, // Which rows to return (all rows) + null, // Selection arguments (none) + MediaStore.Images.Media.DATE_TAKEN // Ordering + ); + + if (cursor == null) { + return dateAdded; + } + + cursor.moveToFirst(); + String dateTaken = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATE_TAKEN)); + cursor.close(); + + dateAdded = Long.parseLong(dateTaken); + + return dateAdded; + } } diff --git a/app/src/main/res/drawable/gif_indicator.png b/app/src/main/res/drawable/gif_indicator.png new file mode 100644 index 0000000000000000000000000000000000000000..28705ed019cb475ba6c8220e72c4687819a7f090 GIT binary patch literal 719 zcmV;=0xgXt=Y~ThXD}OCN3f#ef`QDYgUP#)e36Pfe?mj1K(~`Wl zlq9WE000000000000000003~)%;)p_)oL|Zuh-Ko%Vwl9eQ7fl16dIb?;mNiC=$eG zTPmGeDVnRKjnA*zZad~n(O)1`=>D`2@?ejN^nyQ+1I5ZxH#vUN#g zsfI{dhtyXUi0nv73Xr|qXZ<2dH`EXT4m<_)R0BkUYt#(^^&5ZWdZRKjbX-Qi{E%8g0>)Ct$g^2~x7)p#%ehW(HUYNsWyxxe6sk)JkcKwPN<-O}wGGwDQ4n&Zx%T$D z0({E*L|sCF>}j^LWgoCMVT;A$4*?AX$R(LsP7Z0`G9Hb9fMRUt zAi$?9qN)csNdfZ3ODbN-qe@6X=e~$#)tyy61Vj>`-~78-uEvNF0%8fU^={VaFGoNu z0doCr8-gs110dj>0wgk^VwTPO`1>|twyPop1PCa*DNT!bIDUVtW-#)^unfcGG6`1cl!3TbBCbQR4az#Z&MMXt1K#o;*Iio^@SKfK& zl?D|~*ndW&kOE z<`WV$Xn z5mr^ck_L=(N0{9*CJ7kj4j^R0h!o&UYM7`>p9CPm1*SSD?jP_QCfoK4Sip4iegMNX zG2Js6?|>6*sN@wehb`s308-pwOLda&0Y70=Kez>S^B>;&o)+?bB<&7Rz-x+cC?nsJ z8^9OTd;k9y{0}cfM@>AN^1*G{b0Fa;33rRh|EQkQ)r!=hx z*b)NBPiaFBP!$5mPw8(RzyOE=JFu=%`1 z-tU2@ZA|tH$}b?!Ii~uPPX7Q!A5~0rNsrXA%Moq~yBji+2VciRCj86S(npU+xC(JR znIH~-_j4Z7pKec3$M56p5Of=K273Wwo@avUk$f0eP%@MPdgmDo?-Ed+I+9)UA?#~d zNq*!b5;Z80Fmn+u%@SAmsmdZL(^nC*?DK-#n(Xl{9kyHsO)|{}|DaQab*8jOBM)$R z@ta_UBFB`ur^Op@w793t5t|gq(rf-YuK6bdM1Tko0V06Z^FN`6oF-LpM=}5a002ov JPDHLkV1l`OfX)B_ literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/ic_sort_white_24dp.png b/app/src/main/res/drawable/ic_sort_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..9953803cd81cfcff57deb08d6b089d64afa7d971 GIT binary patch literal 505 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGoY)RhkE(}8pX7+2iB`GtXjvBlHHF{I+w+dF6T4l9VT1;%{cTYUe{-5I_r z;s(c>&&;V!`qaC~?3BOPBo$8(TH^M5U;Ve*{}-M|Tr#XnYf-Q5&2Lek+XEy-j+r0w znEF^cvE|su-AXY#&V{5&{x4#wIjL&Sp;a~Zx{sGndDPZ-QR?B@RZMp* zfMz%w9%%Szth~gjq49D0X?F|W4+nnSyd=2op0&o`rT4e3{VkOr_BVdQF$0D(3YaGB(8jVo)`muOpH9<+r3Aa{^m~Btsg*3`Q`+?C^1`ipSzdE%6BZk4#)z4*}Q$iB}u_MKE literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/video_indicator.png b/app/src/main/res/drawable/video_indicator.png new file mode 100644 index 0000000000000000000000000000000000000000..e3aeb354adea27e4a8f1744ccd7d2175094f6729 GIT binary patch literal 508 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7Ro>U_9*U;uuoF`1X#a-w_7^hl_lk zoSr+G6g8hGIGs>XQGL2axsqFEhMtOY@*a~d*{g2<^IyfYu<$SA$?i8YKvSUL!G&|r zKbHoIoDU7%J3aO1!8PYR%bsmh*xzyVe{D+oY?leMcFL4wDgQT(Su=;vV(Y~HOyb(h znf(eu+-VFvj2s698o<;N;RWknZ(o*~H`lN}t*ZRx>nOczV)9C@Prv_3ujKf1XZ>!@ z2SQ5mZ4;iB$CkS?urf04o2GB?&A_V7xNo{X$ASdK1N~3AnKWi_e#rjW#K5J-(3J&%iKY Zt^eQR%QK&~J$VEY^mO%eS?83{1OQ;Q!4&`i literal 0 HcmV?d00001 diff --git a/app/src/main/res/layout/activity_about.xml b/app/src/main/res/layout/activity_about.xml index 27dcb5b2..d72497c1 100644 --- a/app/src/main/res/layout/activity_about.xml +++ b/app/src/main/res/layout/activity_about.xml @@ -5,7 +5,7 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - @@ -55,7 +55,7 @@ android:padding="16dp" android:background="@color/dark_bg"/> - + diff --git a/app/src/main/res/layout/albumitem_cover.xml b/app/src/main/res/layout/albumitem_cover.xml index 82940864..7fab7a65 100644 --- a/app/src/main/res/layout/albumitem_cover.xml +++ b/app/src/main/res/layout/albumitem_cover.xml @@ -2,7 +2,8 @@ + android:layout_width="wrap_content" + android:clickable="true">