parent
e8ae6d67b1
commit
8b342ee18b
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<android.support.v7.widget.RecyclerView
|
||||
android:id="@+id/photo_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:scrollbars="none"/>
|
||||
</merge>
|
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<org.thoughtcrime.securesms.components.SquareFrameLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginRight="2dp"
|
||||
app:square_height="true">
|
||||
|
||||
<ImageView android:id="@+id/thumbnail"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
</org.thoughtcrime.securesms.components.SquareFrameLayout>
|
||||
|
@ -0,0 +1,146 @@
|
||||
package org.thoughtcrime.securesms.components;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.provider.MediaStore;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.LoaderManager;
|
||||
import android.support.v4.content.Loader;
|
||||
import android.support.v7.widget.DefaultItemAnimator;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.load.Key;
|
||||
import com.bumptech.glide.signature.MediaStoreSignature;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter;
|
||||
import org.thoughtcrime.securesms.database.loaders.RecentPhotosLoader;
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
|
||||
public class RecentPhotoViewRail extends FrameLayout implements LoaderManager.LoaderCallbacks<Cursor> {
|
||||
|
||||
@NonNull private final RecyclerView recyclerView;
|
||||
@Nullable private OnItemClickedListener listener;
|
||||
|
||||
public RecentPhotoViewRail(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public RecentPhotoViewRail(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public RecentPhotoViewRail(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
|
||||
inflate(context, R.layout.recent_photo_view, this);
|
||||
|
||||
this.recyclerView = ViewUtil.findById(this, R.id.photo_list);
|
||||
this.recyclerView.setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false));
|
||||
this.recyclerView.setItemAnimator(new DefaultItemAnimator());
|
||||
}
|
||||
|
||||
public void setListener(@Nullable OnItemClickedListener listener) {
|
||||
this.listener = listener;
|
||||
|
||||
if (this.recyclerView.getAdapter() != null) {
|
||||
((RecentPhotoAdapter)this.recyclerView.getAdapter()).setListener(listener);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
|
||||
return new RecentPhotosLoader(getContext());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
|
||||
this.recyclerView.setAdapter(new RecentPhotoAdapter(getContext(), data, RecentPhotosLoader.BASE_URL, listener));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoaderReset(Loader<Cursor> loader) {
|
||||
((CursorRecyclerViewAdapter)this.recyclerView.getAdapter()).changeCursor(null);
|
||||
}
|
||||
|
||||
private static class RecentPhotoAdapter extends CursorRecyclerViewAdapter<RecentPhotoAdapter.RecentPhotoViewHolder> {
|
||||
|
||||
@NonNull private final Uri baseUri;
|
||||
@Nullable private OnItemClickedListener clickedListener;
|
||||
|
||||
private RecentPhotoAdapter(@NonNull Context context, @NonNull Cursor cursor, @NonNull Uri baseUri, @Nullable OnItemClickedListener listener) {
|
||||
super(context, cursor);
|
||||
this.baseUri = baseUri;
|
||||
this.clickedListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecentPhotoViewHolder onCreateItemViewHolder(ViewGroup parent, int viewType) {
|
||||
View itemView = LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.recent_photo_view_item, parent, false);
|
||||
|
||||
return new RecentPhotoViewHolder(itemView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindItemViewHolder(RecentPhotoViewHolder viewHolder, @NonNull Cursor cursor) {
|
||||
viewHolder.imageView.setImageDrawable(null);
|
||||
|
||||
long id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Images.ImageColumns._ID));
|
||||
long dateTaken = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Images.ImageColumns.DATE_TAKEN));
|
||||
long dateModified = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Images.ImageColumns.DATE_MODIFIED));
|
||||
String mimeType = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.ImageColumns.MIME_TYPE));
|
||||
int orientation = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Images.ImageColumns.ORIENTATION));
|
||||
|
||||
final Uri uri = Uri.withAppendedPath(baseUri, Long.toString(id));
|
||||
|
||||
Key signature = new MediaStoreSignature(mimeType, dateModified, orientation);
|
||||
|
||||
Glide.with(getContext())
|
||||
.fromMediaStore()
|
||||
.load(uri)
|
||||
.signature(signature)
|
||||
.centerCrop()
|
||||
.into(viewHolder.imageView);
|
||||
|
||||
viewHolder.imageView.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (clickedListener != null) clickedListener.onItemClicked(uri);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public void setListener(@Nullable OnItemClickedListener listener) {
|
||||
this.clickedListener = listener;
|
||||
}
|
||||
|
||||
static class RecentPhotoViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
ImageView imageView;
|
||||
|
||||
RecentPhotoViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
|
||||
this.imageView = ViewUtil.findById(itemView, R.id.thumbnail);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public interface OnItemClickedListener {
|
||||
public void onItemClicked(Uri uri);
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package org.thoughtcrime.securesms.database.loaders;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.provider.MediaStore;
|
||||
import android.support.v4.content.CursorLoader;
|
||||
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
|
||||
public class RecentPhotosLoader extends CursorLoader {
|
||||
|
||||
public static Uri BASE_URL = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
|
||||
|
||||
private static final String[] PROJECTION = new String[] {
|
||||
MediaStore.Images.ImageColumns._ID,
|
||||
MediaStore.Images.ImageColumns.DATE_TAKEN,
|
||||
MediaStore.Images.ImageColumns.DATE_MODIFIED,
|
||||
MediaStore.Images.ImageColumns.ORIENTATION,
|
||||
MediaStore.Images.ImageColumns.MIME_TYPE
|
||||
};
|
||||
|
||||
private final Context context;
|
||||
|
||||
public RecentPhotosLoader(Context context) {
|
||||
super(context);
|
||||
this.context = context.getApplicationContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cursor loadInBackground() {
|
||||
return context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
|
||||
PROJECTION, null, null,
|
||||
MediaStore.Images.ImageColumns.DATE_MODIFIED + " DESC");
|
||||
}
|
||||
|
||||
|
||||
}
|
Loading…
Reference in New Issue