mirror of
https://github.com/oxen-io/session-android.git
synced 2025-02-19 19:38:45 +00:00
Reorganize conversation media activity to have sticky headers
// FREEBIE
This commit is contained in:
parent
5189fbf686
commit
c6b2e785a5
@ -105,6 +105,7 @@ dependencies {
|
||||
exclude group: 'com.android.support', module: 'appcompat-v7'
|
||||
exclude group: 'com.android.support', module: 'recyclerview-v7'
|
||||
}
|
||||
compile 'com.codewaves.stickyheadergrid:stickyheadergrid:0.9.4'
|
||||
|
||||
|
||||
testCompile 'junit:junit:4.12'
|
||||
@ -171,6 +172,7 @@ dependencyVerification {
|
||||
'com.klinkerapps:android-smsmms:e7c3328a0f3a8dd44daa8129de4e99996f3057a4546e47891b036b81e0ebf1d1',
|
||||
'com.annimon:stream:5da6e2e3e0551d61a3ea7014f04312276549e3dd739cf637996e4cf43c5535b9',
|
||||
'com.takisoft.fix:colorpicker:f5d0dbabe406a1800498ca9c1faf34db36e021d8488bf10360f29961fe3ab0d1',
|
||||
'com.codewaves.stickyheadergrid:stickyheadergrid:5b4aa6a52a957cfd55f60f4220c11c0c371385a3cb9786cae03c260dcdef5794',
|
||||
'com.android.support:support-annotations:a774272036941b4e912eb426d70c848bde7f06a3bf5fb491f75a427dc6595270',
|
||||
'com.android.support:support-v4:ee44c481a1f4d6978568e223e8125379b52b2ececdd53450e09ebae144bd377d',
|
||||
'com.android.support:support-vector-drawable:077009d13882ee96f061e4bc2dbe7cce7ae1762d8297592a787ff741afbfb1f2',
|
||||
|
@ -4,7 +4,7 @@
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/gray95">
|
||||
android:background="@color/white">
|
||||
|
||||
<android.support.v7.widget.RecyclerView
|
||||
android:id="@+id/media_grid"
|
||||
@ -14,11 +14,9 @@
|
||||
|
||||
<TextView android:id="@+id/no_images"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@android:color/white"
|
||||
android:textStyle="italic"
|
||||
android:layout_height="match_parent"
|
||||
android:textSize="24sp"
|
||||
android:gravity="center_horizontal"
|
||||
android:gravity="center"
|
||||
android:paddingTop="30dp"
|
||||
android:visibility="gone"
|
||||
android:text="@string/media_overview_activity__no_media" />
|
||||
|
@ -2,7 +2,8 @@
|
||||
<org.thoughtcrime.securesms.components.SquareFrameLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="match_parent"
|
||||
android:padding="2dp">
|
||||
|
||||
<org.thoughtcrime.securesms.components.ThumbnailView
|
||||
android:id="@+id/image"
|
||||
|
18
res/layout/media_overview_item_header.xml
Normal file
18
res/layout/media_overview_item_header.xml
Normal file
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/white"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView android:id="@+id/text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="start|center_vertical"
|
||||
android:textColor="@color/gray50"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold"
|
||||
android:textAllCaps="true"
|
||||
tools:text="March 1, 2015" />
|
||||
</FrameLayout>
|
@ -1469,6 +1469,10 @@
|
||||
<string name="RingtonePreference_alarm_sound_default">Default alarm sound</string>
|
||||
<string name="RingtonePreference_add_ringtone_text">Add ringtone</string>
|
||||
<string name="RingtonePreference_unable_to_add_ringtone">Unable to add custom ringtone</string>
|
||||
<string name="BucketedThreadMedia_Today">Today</string>
|
||||
<string name="BucketedThreadMedia_Yesterday">Yesterday</string>
|
||||
<string name="BucketedThreadMedia_This_week">This week</string>
|
||||
<string name="BucketedThreadMedia_This_month">This month</string>
|
||||
|
||||
|
||||
<!-- EOF -->
|
||||
|
@ -18,65 +18,104 @@ package org.thoughtcrime.securesms;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.codewaves.stickyheadergrid.StickyHeaderGridAdapter;
|
||||
|
||||
import org.thoughtcrime.securesms.MediaAdapter.ViewHolder;
|
||||
import org.thoughtcrime.securesms.components.ThumbnailView;
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter;
|
||||
import org.thoughtcrime.securesms.database.MediaDatabase.MediaRecord;
|
||||
import org.thoughtcrime.securesms.database.loaders.BucketedThreadMediaLoader.BucketedThreadMedia;
|
||||
import org.thoughtcrime.securesms.mms.Slide;
|
||||
import org.thoughtcrime.securesms.util.MediaUtil;
|
||||
|
||||
public class MediaAdapter extends CursorRecyclerViewAdapter<ViewHolder> {
|
||||
import java.util.Locale;
|
||||
|
||||
public class MediaAdapter extends StickyHeaderGridAdapter {
|
||||
private static final String TAG = MediaAdapter.class.getSimpleName();
|
||||
|
||||
private final MasterSecret masterSecret;
|
||||
private final Address address;
|
||||
private final Context context;
|
||||
private final MasterSecret masterSecret;
|
||||
private final Locale locale;
|
||||
private final Address address;
|
||||
|
||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
public ThumbnailView imageView;
|
||||
private BucketedThreadMedia media;
|
||||
|
||||
public ViewHolder(View v) {
|
||||
private static class ViewHolder extends StickyHeaderGridAdapter.ItemViewHolder {
|
||||
ThumbnailView imageView;
|
||||
|
||||
ViewHolder(View v) {
|
||||
super(v);
|
||||
imageView = (ThumbnailView) v.findViewById(R.id.image);
|
||||
}
|
||||
}
|
||||
|
||||
public MediaAdapter(Context context, MasterSecret masterSecret, Cursor c, Address address) {
|
||||
super(context, c);
|
||||
private static class HeaderHolder extends StickyHeaderGridAdapter.HeaderViewHolder {
|
||||
TextView textView;
|
||||
|
||||
HeaderHolder(View itemView) {
|
||||
super(itemView);
|
||||
textView = (TextView) itemView.findViewById(R.id.text);
|
||||
}
|
||||
}
|
||||
|
||||
public MediaAdapter(Context context, MasterSecret masterSecret, BucketedThreadMedia media, Locale locale, Address address) {
|
||||
this.context = context;
|
||||
this.masterSecret = masterSecret;
|
||||
this.locale = locale;
|
||||
this.media = media;
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewHolder onCreateItemViewHolder(final ViewGroup viewGroup, final int i) {
|
||||
final View view = LayoutInflater.from(getContext()).inflate(R.layout.media_overview_item, viewGroup, false);
|
||||
return new ViewHolder(view);
|
||||
public void setMedia(BucketedThreadMedia media) {
|
||||
this.media = media;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindItemViewHolder(final ViewHolder viewHolder, final @NonNull Cursor cursor) {
|
||||
final ThumbnailView imageView = viewHolder.imageView;
|
||||
final MediaRecord mediaRecord = MediaRecord.from(getContext(), masterSecret, cursor);
|
||||
public StickyHeaderGridAdapter.HeaderViewHolder onCreateHeaderViewHolder(ViewGroup parent, int headerType) {
|
||||
return new HeaderHolder(LayoutInflater.from(context).inflate(R.layout.media_overview_item_header, parent, false));
|
||||
}
|
||||
|
||||
Slide slide = MediaUtil.getSlideForAttachment(getContext(), mediaRecord.getAttachment());
|
||||
@Override
|
||||
public ItemViewHolder onCreateItemViewHolder(ViewGroup parent, int itemType) {
|
||||
return new ViewHolder(LayoutInflater.from(context).inflate(R.layout.media_overview_item, parent, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindHeaderViewHolder(StickyHeaderGridAdapter.HeaderViewHolder viewHolder, int section) {
|
||||
((HeaderHolder)viewHolder).textView.setText(media.getName(section, locale));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindItemViewHolder(ItemViewHolder viewHolder, int section, int offset) {
|
||||
MediaRecord mediaRecord = media.get(section, offset);
|
||||
ThumbnailView thumbnailView = ((ViewHolder)viewHolder).imageView;
|
||||
|
||||
Slide slide = MediaUtil.getSlideForAttachment(context, mediaRecord.getAttachment());
|
||||
|
||||
if (slide != null) {
|
||||
imageView.setImageResource(masterSecret, slide, false, false);
|
||||
thumbnailView.setImageResource(masterSecret, slide, false, false);
|
||||
}
|
||||
|
||||
imageView.setOnClickListener(new OnMediaClickListener(mediaRecord));
|
||||
thumbnailView.setOnClickListener(new OnMediaClickListener(mediaRecord));
|
||||
}
|
||||
|
||||
private class OnMediaClickListener implements OnClickListener {
|
||||
@Override
|
||||
public int getSectionCount() {
|
||||
return media.getSectionCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSectionItemCount(int section) {
|
||||
return media.getSectionItemCount(section);
|
||||
}
|
||||
|
||||
private class OnMediaClickListener implements View.OnClickListener {
|
||||
|
||||
private final MediaRecord mediaRecord;
|
||||
|
||||
private OnMediaClickListener(MediaRecord mediaRecord) {
|
||||
@ -86,7 +125,7 @@ public class MediaAdapter extends CursorRecyclerViewAdapter<ViewHolder> {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (mediaRecord.getAttachment().getDataUri() != null) {
|
||||
Intent intent = new Intent(getContext(), MediaPreviewActivity.class);
|
||||
Intent intent = new Intent(context, MediaPreviewActivity.class);
|
||||
intent.putExtra(MediaPreviewActivity.DATE_EXTRA, mediaRecord.getDate());
|
||||
intent.putExtra(MediaPreviewActivity.SIZE_EXTRA, mediaRecord.getAttachment().getSize());
|
||||
intent.putExtra(MediaPreviewActivity.ADDRESS_EXTRA, address);
|
||||
@ -96,8 +135,9 @@ public class MediaAdapter extends CursorRecyclerViewAdapter<ViewHolder> {
|
||||
}
|
||||
|
||||
intent.setDataAndType(mediaRecord.getAttachment().getDataUri(), mediaRecord.getContentType());
|
||||
getContext().startActivity(intent);
|
||||
context.startActivity(intent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -16,37 +16,34 @@
|
||||
*/
|
||||
package org.thoughtcrime.securesms;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.res.Configuration;
|
||||
import android.database.Cursor;
|
||||
import android.os.Build.VERSION;
|
||||
import android.os.Build.VERSION_CODES;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.app.LoaderManager;
|
||||
import android.support.v4.content.Loader;
|
||||
import android.support.v7.widget.GridLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.codewaves.stickyheadergrid.StickyHeaderGridLayoutManager;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.MediaDatabase.MediaRecord;
|
||||
import org.thoughtcrime.securesms.database.loaders.ThreadMediaLoader;
|
||||
import org.thoughtcrime.securesms.database.loaders.BucketedThreadMediaLoader;
|
||||
import org.thoughtcrime.securesms.database.loaders.BucketedThreadMediaLoader.BucketedThreadMedia;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
|
||||
import org.thoughtcrime.securesms.util.DynamicLanguage;
|
||||
import org.thoughtcrime.securesms.util.DynamicTheme;
|
||||
import org.thoughtcrime.securesms.util.SaveAttachmentTask;
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@ -55,95 +52,73 @@ import java.util.List;
|
||||
/**
|
||||
* Activity for displaying media attachments in-app
|
||||
*/
|
||||
public class MediaOverviewActivity extends PassphraseRequiredActionBarActivity implements LoaderManager.LoaderCallbacks<Cursor> {
|
||||
public class MediaOverviewActivity extends PassphraseRequiredActionBarActivity implements LoaderManager.LoaderCallbacks<BucketedThreadMedia> {
|
||||
private final static String TAG = MediaOverviewActivity.class.getSimpleName();
|
||||
|
||||
public static final String ADDRESS_EXTRA = "address";
|
||||
|
||||
private final DynamicTheme dynamicTheme = new DynamicTheme();
|
||||
private final DynamicLanguage dynamicLanguage = new DynamicLanguage();
|
||||
|
||||
private MasterSecret masterSecret;
|
||||
|
||||
private RecyclerView gridView;
|
||||
private GridLayoutManager gridManager;
|
||||
private StickyHeaderGridLayoutManager gridManager;
|
||||
private TextView noImages;
|
||||
private Recipient recipient;
|
||||
|
||||
@Override
|
||||
protected void onPreCreate() {
|
||||
this.setTheme(R.style.TextSecure_DarkTheme);
|
||||
dynamicTheme.onCreate(this);
|
||||
dynamicLanguage.onCreate(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle bundle, @NonNull MasterSecret masterSecret) {
|
||||
this.masterSecret = masterSecret;
|
||||
setFullscreenIfPossible();
|
||||
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
setContentView(R.layout.media_overview_activity);
|
||||
|
||||
initializeResources();
|
||||
initializeActionBar();
|
||||
|
||||
getSupportLoaderManager().initLoader(0, null, MediaOverviewActivity.this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
if (gridManager != null) gridManager.setSpanCount(getResources().getInteger(R.integer.media_overview_cols));
|
||||
}
|
||||
|
||||
@TargetApi(VERSION_CODES.JELLY_BEAN)
|
||||
private void setFullscreenIfPossible() {
|
||||
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
|
||||
WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||
|
||||
if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) {
|
||||
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN);
|
||||
if (gridManager != null) {
|
||||
this.gridManager = new StickyHeaderGridLayoutManager(getResources().getInteger(R.integer.media_overview_cols));
|
||||
this.gridView.setLayoutManager(gridManager);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
dynamicTheme.onResume(this);
|
||||
dynamicLanguage.onResume(this);
|
||||
}
|
||||
|
||||
private void initializeActionBar() {
|
||||
getSupportActionBar().setTitle(recipient == null
|
||||
? getString(R.string.AndroidManifest__all_media)
|
||||
: getString(R.string.AndroidManifest__all_media_named, recipient.toShortString()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
getSupportActionBar().setTitle(recipient.toShortString());
|
||||
}
|
||||
|
||||
private void initializeResources() {
|
||||
noImages = (TextView ) findViewById(R.id.no_images );
|
||||
gridView = (RecyclerView) findViewById(R.id.media_grid);
|
||||
gridManager = new GridLayoutManager(this, getResources().getInteger(R.integer.media_overview_cols));
|
||||
gridView.setLayoutManager(gridManager);
|
||||
gridView.setHasFixedSize(true);
|
||||
this.noImages = ViewUtil.findById(this, R.id.no_images);
|
||||
this.gridView = ViewUtil.findById(this, R.id.media_grid);
|
||||
this.gridManager = new StickyHeaderGridLayoutManager(getResources().getInteger(R.integer.media_overview_cols));
|
||||
|
||||
Address address = getIntent().getParcelableExtra(ADDRESS_EXTRA);
|
||||
|
||||
if (address != null) {
|
||||
recipient = Recipient.from(this, address, true);
|
||||
} else {
|
||||
recipient = null;
|
||||
}
|
||||
this.recipient = Recipient.from(this, address, true);
|
||||
this.recipient.addListener(recipient -> initializeActionBar());
|
||||
|
||||
if (recipient != null) {
|
||||
recipient.addListener(new RecipientModifiedListener() {
|
||||
@Override
|
||||
public void onModified(Recipient recipients) {
|
||||
initializeActionBar();
|
||||
}
|
||||
});
|
||||
}
|
||||
this.gridView.setAdapter(new MediaAdapter(this, masterSecret, new BucketedThreadMedia(this), dynamicLanguage.getCurrentLocale(), address));
|
||||
this.gridView.setLayoutManager(gridManager);
|
||||
this.gridView.setHasFixedSize(true);
|
||||
}
|
||||
|
||||
private void saveToDisk() {
|
||||
@ -212,21 +187,21 @@ public class MediaOverviewActivity extends PassphraseRequiredActionBarActivity i
|
||||
}
|
||||
|
||||
@Override
|
||||
public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
|
||||
return new ThreadMediaLoader(this, masterSecret, recipient.getAddress());
|
||||
public Loader<BucketedThreadMedia> onCreateLoader(int i, Bundle bundle) {
|
||||
return new BucketedThreadMediaLoader(this, masterSecret, recipient.getAddress());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
|
||||
Log.w(TAG, "onLoadFinished()");
|
||||
gridView.setAdapter(new MediaAdapter(this, masterSecret, cursor, recipient.getAddress()));
|
||||
public void onLoadFinished(Loader<BucketedThreadMedia> loader, BucketedThreadMedia bucketedThreadMedia) {
|
||||
((MediaAdapter)gridView.getAdapter()).setMedia(bucketedThreadMedia);
|
||||
((MediaAdapter)gridView.getAdapter()).notifyAllSectionsDataSetChanged();
|
||||
|
||||
noImages.setVisibility(gridView.getAdapter().getItemCount() > 0 ? View.GONE : View.VISIBLE);
|
||||
invalidateOptionsMenu();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoaderReset(Loader<Cursor> cursorLoader) {
|
||||
((CursorRecyclerViewAdapter)gridView.getAdapter()).changeCursor(null);
|
||||
public void onLoaderReset(Loader<BucketedThreadMedia> cursorLoader) {
|
||||
((MediaAdapter)gridView.getAdapter()).setMedia(new BucketedThreadMedia(this));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,221 @@
|
||||
package org.thoughtcrime.securesms.database.loaders;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.content.AsyncTaskLoader;
|
||||
|
||||
import com.annimon.stream.Stream;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.MediaDatabase;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
public class BucketedThreadMediaLoader extends AsyncTaskLoader<BucketedThreadMediaLoader.BucketedThreadMedia> {
|
||||
|
||||
private static final String TAG = BucketedThreadMediaLoader.class.getSimpleName();
|
||||
|
||||
private final MasterSecret masterSecret;
|
||||
private final Address address;
|
||||
|
||||
public BucketedThreadMediaLoader(@NonNull Context context, @NonNull MasterSecret masterSecret, @NonNull Address address) {
|
||||
super(context);
|
||||
this.masterSecret = masterSecret;
|
||||
this.address = address;
|
||||
|
||||
onContentChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStartLoading() {
|
||||
if (takeContentChanged()) {
|
||||
forceLoad();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStopLoading() {
|
||||
cancelLoad();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BucketedThreadMedia loadInBackground() {
|
||||
BucketedThreadMedia result = new BucketedThreadMedia(getContext());
|
||||
long threadId = DatabaseFactory.getThreadDatabase(getContext()).getThreadIdFor(Recipient.from(getContext(), address, true));
|
||||
|
||||
try (Cursor cursor = DatabaseFactory.getMediaDatabase(getContext()).getMediaForThread(threadId)) {
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
result.add(MediaDatabase.MediaRecord.from(getContext(), masterSecret, cursor));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static class BucketedThreadMedia {
|
||||
|
||||
private final TimeBucket TODAY;
|
||||
private final TimeBucket YESTERDAY;
|
||||
private final TimeBucket THIS_WEEK;
|
||||
private final TimeBucket THIS_MONTH;
|
||||
private final MonthBuckets OLDER;
|
||||
|
||||
private final TimeBucket[] TIME_SECTIONS;
|
||||
|
||||
public BucketedThreadMedia(@NonNull Context context) {
|
||||
this.TODAY = new TimeBucket(context.getString(R.string.BucketedThreadMedia_Today), TimeBucket.addToCalendar(Calendar.DAY_OF_YEAR, -1), TimeBucket.addToCalendar(Calendar.DAY_OF_YEAR, 1000));
|
||||
this.YESTERDAY = new TimeBucket(context.getString(R.string.BucketedThreadMedia_Yesterday), TimeBucket.addToCalendar(Calendar.DAY_OF_YEAR, -2), TimeBucket.addToCalendar(Calendar.DAY_OF_YEAR, -1));
|
||||
this.THIS_WEEK = new TimeBucket(context.getString(R.string.BucketedThreadMedia_This_week), TimeBucket.addToCalendar(Calendar.DAY_OF_YEAR, -7), TimeBucket.addToCalendar(Calendar.DAY_OF_YEAR, -2));
|
||||
this.THIS_MONTH = new TimeBucket(context.getString(R.string.BucketedThreadMedia_This_month), TimeBucket.addToCalendar(Calendar.DAY_OF_YEAR, -30), TimeBucket.addToCalendar(Calendar.DAY_OF_YEAR, -7));
|
||||
this.TIME_SECTIONS = new TimeBucket[]{TODAY, YESTERDAY, THIS_WEEK, THIS_MONTH};
|
||||
this.OLDER = new MonthBuckets();
|
||||
}
|
||||
|
||||
|
||||
public void add(MediaDatabase.MediaRecord mediaRecord) {
|
||||
for (TimeBucket timeSection : TIME_SECTIONS) {
|
||||
if (timeSection.inRange(mediaRecord.getDate())) {
|
||||
timeSection.add(mediaRecord);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
OLDER.add(mediaRecord);
|
||||
}
|
||||
|
||||
public int getSectionCount() {
|
||||
return (int)Stream.of(TIME_SECTIONS)
|
||||
.filter(timeBucket -> !timeBucket.isEmpty())
|
||||
.count() +
|
||||
OLDER.getSectionCount();
|
||||
}
|
||||
|
||||
public int getSectionItemCount(int section) {
|
||||
List<TimeBucket> activeTimeBuckets = Stream.of(TIME_SECTIONS).filter(timeBucket -> !timeBucket.isEmpty()).toList();
|
||||
|
||||
if (section < activeTimeBuckets.size()) return activeTimeBuckets.get(section).getItemCount();
|
||||
else return OLDER.getSectionItemCount(section - activeTimeBuckets.size());
|
||||
}
|
||||
|
||||
public MediaDatabase.MediaRecord get(int section, int item) {
|
||||
List<TimeBucket> activeTimeBuckets = Stream.of(TIME_SECTIONS).filter(timeBucket -> !timeBucket.isEmpty()).toList();
|
||||
|
||||
if (section < activeTimeBuckets.size()) return activeTimeBuckets.get(section).getItem(item);
|
||||
else return OLDER.getItem(section - activeTimeBuckets.size(), item);
|
||||
}
|
||||
|
||||
public String getName(int section, Locale locale) {
|
||||
List<TimeBucket> activeTimeBuckets = Stream.of(TIME_SECTIONS).filter(timeBucket -> !timeBucket.isEmpty()).toList();
|
||||
|
||||
if (section < activeTimeBuckets.size()) return activeTimeBuckets.get(section).getName();
|
||||
else return OLDER.getName(section - activeTimeBuckets.size(), locale);
|
||||
}
|
||||
|
||||
private static class TimeBucket {
|
||||
|
||||
private final List<MediaDatabase.MediaRecord> records = new LinkedList<>();
|
||||
|
||||
private final long startTime;
|
||||
private final long endtime;
|
||||
private final String name;
|
||||
|
||||
TimeBucket(String name, long startTime, long endtime) {
|
||||
this.name = name;
|
||||
this.startTime = startTime;
|
||||
this.endtime = endtime;
|
||||
}
|
||||
|
||||
void add(MediaDatabase.MediaRecord record) {
|
||||
this.records.add(record);
|
||||
}
|
||||
|
||||
boolean inRange(long timestamp) {
|
||||
return timestamp > startTime && timestamp <= endtime;
|
||||
}
|
||||
|
||||
boolean isEmpty() {
|
||||
return records.isEmpty();
|
||||
}
|
||||
|
||||
int getItemCount() {
|
||||
return records.size();
|
||||
}
|
||||
|
||||
MediaDatabase.MediaRecord getItem(int position) {
|
||||
return records.get(position);
|
||||
}
|
||||
|
||||
String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
static long addToCalendar(int field, int amount) {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.add(field, amount);
|
||||
return calendar.getTimeInMillis();
|
||||
}
|
||||
}
|
||||
|
||||
private static class MonthBuckets {
|
||||
|
||||
private final Map<Date, List<MediaDatabase.MediaRecord>> months = new HashMap<>();
|
||||
|
||||
void add(MediaDatabase.MediaRecord record) {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTimeInMillis(record.getDate());
|
||||
|
||||
int year = calendar.get(Calendar.YEAR) - 1900;
|
||||
int month = calendar.get(Calendar.MONTH);
|
||||
Date date = new Date(year, month, 1);
|
||||
|
||||
if (months.containsKey(date)) {
|
||||
months.get(date).add(record);
|
||||
} else {
|
||||
List<MediaDatabase.MediaRecord> list = new LinkedList<>();
|
||||
list.add(record);
|
||||
months.put(date, list);
|
||||
}
|
||||
}
|
||||
|
||||
int getSectionCount() {
|
||||
return months.size();
|
||||
}
|
||||
|
||||
int getSectionItemCount(int section) {
|
||||
return months.get(getSection(section)).size();
|
||||
}
|
||||
|
||||
MediaDatabase.MediaRecord getItem(int section, int position) {
|
||||
return months.get(getSection(section)).get(position);
|
||||
}
|
||||
|
||||
Date getSection(int section) {
|
||||
ArrayList<Date> keys = new ArrayList<>(months.keySet());
|
||||
Collections.sort(keys, Collections.reverseOrder());
|
||||
|
||||
return keys.get(section);
|
||||
}
|
||||
|
||||
String getName(int section, Locale locale) {
|
||||
Date sectionDate = getSection(section);
|
||||
|
||||
return new SimpleDateFormat("MMMM, yyyy", locale).format(sectionDate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user