2017-09-25 15:32:45 +00:00
|
|
|
/*
|
2015-01-19 02:11:30 +00:00
|
|
|
* Copyright (C) 2015 Open Whisper Systems
|
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
package org.thoughtcrime.securesms;
|
|
|
|
|
|
|
|
import android.content.res.Configuration;
|
|
|
|
import android.database.Cursor;
|
|
|
|
import android.os.Bundle;
|
2014-12-15 20:25:55 +00:00
|
|
|
import android.support.annotation.NonNull;
|
2017-09-25 15:32:45 +00:00
|
|
|
import android.support.design.widget.TabLayout;
|
|
|
|
import android.support.v4.app.Fragment;
|
|
|
|
import android.support.v4.app.FragmentManager;
|
|
|
|
import android.support.v4.app.FragmentStatePagerAdapter;
|
2015-01-19 02:11:30 +00:00
|
|
|
import android.support.v4.app.LoaderManager;
|
|
|
|
import android.support.v4.content.Loader;
|
2017-09-25 15:32:45 +00:00
|
|
|
import android.support.v4.view.ViewPager;
|
|
|
|
import android.support.v7.widget.DividerItemDecoration;
|
|
|
|
import android.support.v7.widget.LinearLayoutManager;
|
2015-01-19 02:11:30 +00:00
|
|
|
import android.support.v7.widget.RecyclerView;
|
2017-09-25 15:32:45 +00:00
|
|
|
import android.support.v7.widget.Toolbar;
|
|
|
|
import android.view.LayoutInflater;
|
2015-01-19 02:11:30 +00:00
|
|
|
import android.view.MenuItem;
|
|
|
|
import android.view.View;
|
2017-09-25 15:32:45 +00:00
|
|
|
import android.view.ViewGroup;
|
2015-01-19 02:11:30 +00:00
|
|
|
import android.widget.TextView;
|
|
|
|
|
2017-09-24 04:30:00 +00:00
|
|
|
import com.codewaves.stickyheadergrid.StickyHeaderGridLayoutManager;
|
|
|
|
|
2015-01-19 02:11:30 +00:00
|
|
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
2017-07-26 16:59:15 +00:00
|
|
|
import org.thoughtcrime.securesms.database.Address;
|
2017-09-25 15:32:45 +00:00
|
|
|
import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter;
|
2017-09-24 04:30:00 +00:00
|
|
|
import org.thoughtcrime.securesms.database.loaders.BucketedThreadMediaLoader;
|
|
|
|
import org.thoughtcrime.securesms.database.loaders.BucketedThreadMediaLoader.BucketedThreadMedia;
|
2017-09-25 15:32:45 +00:00
|
|
|
import org.thoughtcrime.securesms.database.loaders.ThreadMediaLoader;
|
2017-10-16 20:11:42 +00:00
|
|
|
import org.thoughtcrime.securesms.mms.GlideApp;
|
2017-08-01 15:56:00 +00:00
|
|
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
2015-01-19 02:11:30 +00:00
|
|
|
import org.thoughtcrime.securesms.util.DynamicLanguage;
|
2017-09-25 15:32:45 +00:00
|
|
|
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
|
2017-09-24 04:30:00 +00:00
|
|
|
import org.thoughtcrime.securesms.util.DynamicTheme;
|
2017-09-25 15:32:45 +00:00
|
|
|
import org.thoughtcrime.securesms.util.StickyHeaderDecoration;
|
2017-09-24 04:30:00 +00:00
|
|
|
import org.thoughtcrime.securesms.util.ViewUtil;
|
2015-08-22 11:03:07 +00:00
|
|
|
|
2017-09-25 15:32:45 +00:00
|
|
|
import java.util.Locale;
|
2015-01-19 02:11:30 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Activity for displaying media attachments in-app
|
|
|
|
*/
|
2017-09-25 15:32:45 +00:00
|
|
|
public class MediaOverviewActivity extends PassphraseRequiredActionBarActivity {
|
2017-12-05 20:07:37 +00:00
|
|
|
|
|
|
|
@SuppressWarnings("unused")
|
2015-01-19 02:11:30 +00:00
|
|
|
private final static String TAG = MediaOverviewActivity.class.getSimpleName();
|
|
|
|
|
2017-08-01 15:56:00 +00:00
|
|
|
public static final String ADDRESS_EXTRA = "address";
|
2015-01-19 02:11:30 +00:00
|
|
|
|
2017-09-25 15:32:45 +00:00
|
|
|
private final DynamicTheme dynamicTheme = new DynamicNoActionBarTheme();
|
2015-01-19 02:11:30 +00:00
|
|
|
private final DynamicLanguage dynamicLanguage = new DynamicLanguage();
|
|
|
|
|
2017-09-25 15:32:45 +00:00
|
|
|
private Toolbar toolbar;
|
|
|
|
private TabLayout tabLayout;
|
|
|
|
private ViewPager viewPager;
|
2015-01-19 02:11:30 +00:00
|
|
|
private MasterSecret masterSecret;
|
2017-09-25 15:32:45 +00:00
|
|
|
private Recipient recipient;
|
2015-01-19 02:11:30 +00:00
|
|
|
|
|
|
|
@Override
|
2014-12-15 20:25:55 +00:00
|
|
|
protected void onPreCreate() {
|
2017-09-24 04:30:00 +00:00
|
|
|
dynamicTheme.onCreate(this);
|
2015-01-19 02:11:30 +00:00
|
|
|
dynamicLanguage.onCreate(this);
|
2014-12-15 20:25:55 +00:00
|
|
|
}
|
2015-01-19 02:11:30 +00:00
|
|
|
|
2014-12-15 20:25:55 +00:00
|
|
|
@Override
|
|
|
|
protected void onCreate(Bundle bundle, @NonNull MasterSecret masterSecret) {
|
2015-01-19 02:11:30 +00:00
|
|
|
setContentView(R.layout.media_overview_activity);
|
2017-09-25 15:32:45 +00:00
|
|
|
this.masterSecret = masterSecret;
|
2015-01-19 02:11:30 +00:00
|
|
|
|
|
|
|
initializeResources();
|
2017-09-25 15:32:45 +00:00
|
|
|
initializeToolbar();
|
2015-01-19 02:11:30 +00:00
|
|
|
|
2017-09-25 15:32:45 +00:00
|
|
|
this.tabLayout.setupWithViewPager(viewPager);
|
|
|
|
this.viewPager.setAdapter(new MediaOverviewPagerAdapter(getSupportFragmentManager()));
|
2015-01-19 02:11:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onResume() {
|
|
|
|
super.onResume();
|
2017-09-24 04:30:00 +00:00
|
|
|
dynamicTheme.onResume(this);
|
2015-01-19 02:11:30 +00:00
|
|
|
dynamicLanguage.onResume(this);
|
|
|
|
}
|
|
|
|
|
2017-09-25 15:32:45 +00:00
|
|
|
@Override
|
|
|
|
public boolean onOptionsItemSelected(MenuItem item) {
|
|
|
|
super.onOptionsItemSelected(item);
|
|
|
|
|
|
|
|
switch (item.getItemId()) {
|
|
|
|
case android.R.id.home: finish(); return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2015-01-19 02:11:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private void initializeResources() {
|
2017-08-01 15:56:00 +00:00
|
|
|
Address address = getIntent().getParcelableExtra(ADDRESS_EXTRA);
|
2017-07-26 16:59:15 +00:00
|
|
|
|
2017-09-25 15:32:45 +00:00
|
|
|
this.viewPager = ViewUtil.findById(this, R.id.pager);
|
|
|
|
this.toolbar = ViewUtil.findById(this, R.id.toolbar);
|
|
|
|
this.tabLayout = ViewUtil.findById(this, R.id.tab_layout);
|
2017-09-24 04:30:00 +00:00
|
|
|
this.recipient = Recipient.from(this, address, true);
|
2015-01-19 02:11:30 +00:00
|
|
|
}
|
|
|
|
|
2017-09-25 15:32:45 +00:00
|
|
|
private void initializeToolbar() {
|
|
|
|
setSupportActionBar(this.toolbar);
|
|
|
|
getSupportActionBar().setTitle(recipient.toShortString());
|
|
|
|
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
|
|
|
this.recipient.addListener(recipient -> getSupportActionBar().setTitle(recipient.toShortString()));
|
2015-08-22 11:03:07 +00:00
|
|
|
}
|
|
|
|
|
2017-09-25 15:32:45 +00:00
|
|
|
private class MediaOverviewPagerAdapter extends FragmentStatePagerAdapter {
|
2015-08-22 11:03:07 +00:00
|
|
|
|
2017-09-25 15:32:45 +00:00
|
|
|
MediaOverviewPagerAdapter(FragmentManager fragmentManager) {
|
|
|
|
super(fragmentManager);
|
2015-08-22 11:03:07 +00:00
|
|
|
}
|
|
|
|
|
2017-09-25 15:32:45 +00:00
|
|
|
@Override
|
|
|
|
public Fragment getItem(int position) {
|
|
|
|
Fragment fragment;
|
2015-08-22 11:03:07 +00:00
|
|
|
|
2017-09-25 15:32:45 +00:00
|
|
|
if (position == 0) fragment = new MediaOverviewGalleryFragment();
|
|
|
|
else if (position == 1) fragment = new MediaOverviewDocumentsFragment();
|
|
|
|
else throw new AssertionError();
|
2015-01-19 02:11:30 +00:00
|
|
|
|
2017-09-25 15:32:45 +00:00
|
|
|
Bundle args = new Bundle();
|
|
|
|
args.putString(MediaOverviewGalleryFragment.ADDRESS_EXTRA, recipient.getAddress().serialize());
|
|
|
|
args.putParcelable(MediaOverviewGalleryFragment.MASTER_SECRET_EXTRA, masterSecret);
|
|
|
|
args.putSerializable(MediaOverviewGalleryFragment.LOCALE_EXTRA, dynamicLanguage.getCurrentLocale());
|
|
|
|
|
|
|
|
fragment.setArguments(args);
|
|
|
|
|
|
|
|
return fragment;
|
2015-01-19 02:11:30 +00:00
|
|
|
}
|
|
|
|
|
2017-09-25 15:32:45 +00:00
|
|
|
@Override
|
|
|
|
public int getCount() {
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public CharSequence getPageTitle(int position) {
|
|
|
|
if (position == 0) return getString(R.string.MediaOverviewActivity_Media);
|
|
|
|
else if (position == 1) return getString(R.string.MediaOverviewActivity_Documents);
|
|
|
|
else throw new AssertionError();
|
|
|
|
}
|
2015-01-19 02:11:30 +00:00
|
|
|
}
|
|
|
|
|
2017-09-25 15:32:45 +00:00
|
|
|
public static abstract class MediaOverviewFragment<T> extends Fragment implements LoaderManager.LoaderCallbacks<T> {
|
|
|
|
|
|
|
|
public static final String ADDRESS_EXTRA = "address";
|
|
|
|
public static final String MASTER_SECRET_EXTRA = "master_secret";
|
|
|
|
public static final String LOCALE_EXTRA = "locale_extra";
|
|
|
|
|
|
|
|
protected TextView noMedia;
|
|
|
|
protected Recipient recipient;
|
|
|
|
protected MasterSecret masterSecret;
|
|
|
|
protected RecyclerView recyclerView;
|
|
|
|
protected Locale locale;
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onCreate(Bundle bundle) {
|
|
|
|
super.onCreate(bundle);
|
|
|
|
|
|
|
|
String address = getArguments().getString(ADDRESS_EXTRA);
|
|
|
|
MasterSecret masterSecret = getArguments().getParcelable(MASTER_SECRET_EXTRA);
|
|
|
|
Locale locale = (Locale)getArguments().getSerializable(LOCALE_EXTRA);
|
|
|
|
|
|
|
|
if (address == null) throw new AssertionError();
|
|
|
|
if (masterSecret == null) throw new AssertionError();
|
|
|
|
if (locale == null) throw new AssertionError();
|
|
|
|
|
|
|
|
this.recipient = Recipient.from(getContext(), Address.fromSerialized(address), true);
|
|
|
|
this.masterSecret = masterSecret;
|
|
|
|
this.locale = locale;
|
|
|
|
|
|
|
|
getLoaderManager().initLoader(0, null, this);
|
|
|
|
}
|
2015-01-19 02:11:30 +00:00
|
|
|
}
|
|
|
|
|
2017-09-25 15:32:45 +00:00
|
|
|
public static class MediaOverviewGalleryFragment extends MediaOverviewFragment<BucketedThreadMedia> {
|
|
|
|
|
|
|
|
private StickyHeaderGridLayoutManager gridManager;
|
2017-09-24 04:30:00 +00:00
|
|
|
|
2017-09-25 15:32:45 +00:00
|
|
|
@Override
|
2017-12-05 20:07:37 +00:00
|
|
|
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
2017-09-25 15:32:45 +00:00
|
|
|
View view = inflater.inflate(R.layout.media_overview_gallery_fragment, container, false);
|
|
|
|
|
|
|
|
this.recyclerView = ViewUtil.findById(view, R.id.media_grid);
|
|
|
|
this.noMedia = ViewUtil.findById(view, R.id.no_images);
|
|
|
|
this.gridManager = new StickyHeaderGridLayoutManager(getResources().getInteger(R.integer.media_overview_cols));
|
|
|
|
|
2017-10-16 20:11:42 +00:00
|
|
|
this.recyclerView.setAdapter(new MediaGalleryAdapter(getContext(), masterSecret, GlideApp.with(this), new BucketedThreadMedia(getContext()), locale, recipient.getAddress()));
|
2017-09-25 15:32:45 +00:00
|
|
|
this.recyclerView.setLayoutManager(gridManager);
|
|
|
|
this.recyclerView.setHasFixedSize(true);
|
|
|
|
|
|
|
|
return view;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onConfigurationChanged(Configuration newConfig) {
|
|
|
|
super.onConfigurationChanged(newConfig);
|
|
|
|
if (gridManager != null) {
|
|
|
|
this.gridManager = new StickyHeaderGridLayoutManager(getResources().getInteger(R.integer.media_overview_cols));
|
|
|
|
this.recyclerView.setLayoutManager(gridManager);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Loader<BucketedThreadMedia> onCreateLoader(int i, Bundle bundle) {
|
|
|
|
return new BucketedThreadMediaLoader(getContext(), masterSecret, recipient.getAddress());
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onLoadFinished(Loader<BucketedThreadMedia> loader, BucketedThreadMedia bucketedThreadMedia) {
|
|
|
|
((MediaGalleryAdapter) recyclerView.getAdapter()).setMedia(bucketedThreadMedia);
|
|
|
|
((MediaGalleryAdapter) recyclerView.getAdapter()).notifyAllSectionsDataSetChanged();
|
|
|
|
|
|
|
|
noMedia.setVisibility(recyclerView.getAdapter().getItemCount() > 0 ? View.GONE : View.VISIBLE);
|
|
|
|
getActivity().invalidateOptionsMenu();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onLoaderReset(Loader<BucketedThreadMedia> cursorLoader) {
|
|
|
|
((MediaGalleryAdapter) recyclerView.getAdapter()).setMedia(new BucketedThreadMedia(getContext()));
|
|
|
|
}
|
2015-01-19 02:11:30 +00:00
|
|
|
}
|
|
|
|
|
2017-09-25 15:32:45 +00:00
|
|
|
public static class MediaOverviewDocumentsFragment extends MediaOverviewFragment<Cursor> {
|
|
|
|
|
|
|
|
@Override
|
2017-12-05 20:07:37 +00:00
|
|
|
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
2017-09-25 15:32:45 +00:00
|
|
|
View view = inflater.inflate(R.layout.media_overview_documents_fragment, container, false);
|
|
|
|
MediaDocumentsAdapter adapter = new MediaDocumentsAdapter(getContext(), masterSecret, null, locale);
|
|
|
|
|
|
|
|
this.recyclerView = ViewUtil.findById(view, R.id.recycler_view);
|
|
|
|
this.noMedia = ViewUtil.findById(view, R.id.no_documents);
|
|
|
|
|
|
|
|
this.recyclerView.setAdapter(adapter);
|
|
|
|
this.recyclerView.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false));
|
|
|
|
this.recyclerView.addItemDecoration(new StickyHeaderDecoration(adapter, false, true));
|
|
|
|
this.recyclerView.addItemDecoration(new DividerItemDecoration(getContext(), DividerItemDecoration.VERTICAL));
|
|
|
|
|
|
|
|
return view;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
|
|
|
|
return new ThreadMediaLoader(getContext(), masterSecret, recipient.getAddress(), false);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
|
|
|
|
((CursorRecyclerViewAdapter)this.recyclerView.getAdapter()).changeCursor(data);
|
|
|
|
getActivity().invalidateOptionsMenu();
|
|
|
|
|
|
|
|
this.noMedia.setVisibility(data.getCount() > 0 ? View.GONE : View.VISIBLE);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onLoaderReset(Loader<Cursor> loader) {
|
|
|
|
((CursorRecyclerViewAdapter)this.recyclerView.getAdapter()).changeCursor(null);
|
|
|
|
getActivity().invalidateOptionsMenu();
|
|
|
|
}
|
2015-01-19 02:11:30 +00:00
|
|
|
}
|
|
|
|
}
|