diff --git a/res/layout/recipient_preference_activity.xml b/res/layout/recipient_preference_activity.xml index a6b67bccad..5a5337147d 100644 --- a/res/layout/recipient_preference_activity.xml +++ b/res/layout/recipient_preference_activity.xml @@ -4,6 +4,8 @@ xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" + android:layout_marginLeft="0dp" + android:layout_marginRight="0dp" android:background="@color/transparent" xmlns:tools="http://schemas.android.com/tools"> @@ -58,14 +60,39 @@ - + + + + + + + + + + + diff --git a/res/layout/recipient_preference_photo_rail.xml b/res/layout/recipient_preference_photo_rail.xml new file mode 100644 index 0000000000..bb3f365f58 --- /dev/null +++ b/res/layout/recipient_preference_photo_rail.xml @@ -0,0 +1,13 @@ + + + + + \ No newline at end of file diff --git a/res/layout/recipient_preference_photo_rail_item.xml b/res/layout/recipient_preference_photo_rail_item.xml new file mode 100644 index 0000000000..71b1d962d8 --- /dev/null +++ b/res/layout/recipient_preference_photo_rail_item.xml @@ -0,0 +1,17 @@ + + + + + + + diff --git a/res/values/strings.xml b/res/values/strings.xml index f87b6caef3..6a9e364e55 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -998,6 +998,8 @@ Color Color for this contact View safety number + Chat settings + Privacy Signal Call diff --git a/res/xml/recipient_preferences.xml b/res/xml/recipient_preferences.xml index 6726a26f17..2fd341041d 100644 --- a/res/xml/recipient_preferences.xml +++ b/res/xml/recipient_preferences.xml @@ -2,48 +2,55 @@ - + + - + - - - - - - - + + + + + + + + + + + + \ No newline at end of file diff --git a/src/org/thoughtcrime/securesms/ConversationActivity.java b/src/org/thoughtcrime/securesms/ConversationActivity.java index c42953f3f8..6c022e2a29 100644 --- a/src/org/thoughtcrime/securesms/ConversationActivity.java +++ b/src/org/thoughtcrime/securesms/ConversationActivity.java @@ -719,7 +719,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity private void handleViewMedia() { Intent intent = new Intent(this, MediaOverviewActivity.class); - intent.putExtra(MediaOverviewActivity.THREAD_ID_EXTRA, threadId); intent.putExtra(MediaOverviewActivity.ADDRESS_EXTRA, recipient.getAddress()); startActivity(intent); } diff --git a/src/org/thoughtcrime/securesms/ConversationItem.java b/src/org/thoughtcrime/securesms/ConversationItem.java index e45fbbfec3..899699a48f 100644 --- a/src/org/thoughtcrime/securesms/ConversationItem.java +++ b/src/org/thoughtcrime/securesms/ConversationItem.java @@ -605,10 +605,9 @@ public class ConversationItem extends LinearLayout Intent intent = new Intent(context, MediaPreviewActivity.class); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); intent.setDataAndType(slide.getUri(), slide.getContentType()); - if (!messageRecord.isOutgoing()) intent.putExtra(MediaPreviewActivity.ADDRESS_EXTRA, recipient.getAddress()); + intent.putExtra(MediaPreviewActivity.ADDRESS_EXTRA, conversationRecipient.getAddress()); intent.putExtra(MediaPreviewActivity.DATE_EXTRA, messageRecord.getTimestamp()); intent.putExtra(MediaPreviewActivity.SIZE_EXTRA, slide.asAttachment().getSize()); - intent.putExtra(MediaPreviewActivity.THREAD_ID_EXTRA, messageRecord.getThreadId()); context.startActivity(intent); } else if (slide.getUri() != null) { diff --git a/src/org/thoughtcrime/securesms/MediaAdapter.java b/src/org/thoughtcrime/securesms/MediaAdapter.java index b18d561619..4d2392ff50 100644 --- a/src/org/thoughtcrime/securesms/MediaAdapter.java +++ b/src/org/thoughtcrime/securesms/MediaAdapter.java @@ -29,6 +29,7 @@ import android.view.ViewGroup; 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.mms.Slide; @@ -38,7 +39,7 @@ public class MediaAdapter extends CursorRecyclerViewAdapter { private static final String TAG = MediaAdapter.class.getSimpleName(); private final MasterSecret masterSecret; - private final long threadId; + private final Address address; public static class ViewHolder extends RecyclerView.ViewHolder { public ThumbnailView imageView; @@ -49,10 +50,10 @@ public class MediaAdapter extends CursorRecyclerViewAdapter { } } - public MediaAdapter(Context context, MasterSecret masterSecret, Cursor c, long threadId) { + public MediaAdapter(Context context, MasterSecret masterSecret, Cursor c, Address address) { super(context, c); this.masterSecret = masterSecret; - this.threadId = threadId; + this.address = address; } @Override @@ -88,7 +89,7 @@ public class MediaAdapter extends CursorRecyclerViewAdapter { Intent intent = new Intent(getContext(), MediaPreviewActivity.class); intent.putExtra(MediaPreviewActivity.DATE_EXTRA, mediaRecord.getDate()); intent.putExtra(MediaPreviewActivity.SIZE_EXTRA, mediaRecord.getAttachment().getSize()); - intent.putExtra(MediaPreviewActivity.THREAD_ID_EXTRA, threadId); + intent.putExtra(MediaPreviewActivity.ADDRESS_EXTRA, address); if (mediaRecord.getAddress() != null) { intent.putExtra(MediaPreviewActivity.ADDRESS_EXTRA, mediaRecord.getAddress()); diff --git a/src/org/thoughtcrime/securesms/MediaOverviewActivity.java b/src/org/thoughtcrime/securesms/MediaOverviewActivity.java index 081ebb31f8..73ad46f2dc 100644 --- a/src/org/thoughtcrime/securesms/MediaOverviewActivity.java +++ b/src/org/thoughtcrime/securesms/MediaOverviewActivity.java @@ -42,9 +42,9 @@ 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.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientModifiedListener; -import org.thoughtcrime.securesms.util.AbstractCursorLoader; import org.thoughtcrime.securesms.util.DynamicLanguage; import org.thoughtcrime.securesms.util.SaveAttachmentTask; import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask; @@ -59,7 +59,6 @@ public class MediaOverviewActivity extends PassphraseRequiredActionBarActivity i private final static String TAG = MediaOverviewActivity.class.getSimpleName(); public static final String ADDRESS_EXTRA = "address"; - public static final String THREAD_ID_EXTRA = "thread_id"; private final DynamicLanguage dynamicLanguage = new DynamicLanguage(); @@ -69,7 +68,6 @@ public class MediaOverviewActivity extends PassphraseRequiredActionBarActivity i private GridLayoutManager gridManager; private TextView noImages; private Recipient recipient; - private long threadId; @Override protected void onPreCreate() { @@ -124,8 +122,6 @@ public class MediaOverviewActivity extends PassphraseRequiredActionBarActivity i } private void initializeResources() { - threadId = getIntent().getLongExtra(THREAD_ID_EXTRA, -1); - 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)); @@ -136,8 +132,6 @@ public class MediaOverviewActivity extends PassphraseRequiredActionBarActivity i if (address != null) { recipient = Recipient.from(this, address, true); - } else if (threadId > -1) { - recipient = DatabaseFactory.getThreadDatabase(this).getRecipientForThreadId(threadId); } else { recipient = null; } @@ -163,10 +157,11 @@ public class MediaOverviewActivity extends PassphraseRequiredActionBarActivity i R.string.please_wait) { @Override protected List doInBackground(Void... params) { + long threadId = DatabaseFactory.getThreadDatabase(c).getThreadIdFor(recipient); Cursor cursor = DatabaseFactory.getMediaDatabase(c).getMediaForThread(threadId); List attachments = new ArrayList<>(cursor.getCount()); - while (cursor != null && cursor.moveToNext()) { + while (cursor.moveToNext()) { MediaRecord record = MediaRecord.from(c, masterSecret, cursor); attachments.add(new SaveAttachmentTask.Attachment(record.getAttachment().getDataUri(), record.getContentType(), @@ -174,6 +169,8 @@ public class MediaOverviewActivity extends PassphraseRequiredActionBarActivity i null)); } + cursor.close(); + return attachments; } @@ -216,13 +213,13 @@ public class MediaOverviewActivity extends PassphraseRequiredActionBarActivity i @Override public Loader onCreateLoader(int i, Bundle bundle) { - return new ThreadMediaLoader(this, threadId); + return new ThreadMediaLoader(this, masterSecret, recipient.getAddress()); } @Override public void onLoadFinished(Loader cursorLoader, Cursor cursor) { Log.w(TAG, "onLoadFinished()"); - gridView.setAdapter(new MediaAdapter(this, masterSecret, cursor, threadId)); + gridView.setAdapter(new MediaAdapter(this, masterSecret, cursor, recipient.getAddress())); noImages.setVisibility(gridView.getAdapter().getItemCount() > 0 ? View.GONE : View.VISIBLE); invalidateOptionsMenu(); } @@ -232,17 +229,4 @@ public class MediaOverviewActivity extends PassphraseRequiredActionBarActivity i ((CursorRecyclerViewAdapter)gridView.getAdapter()).changeCursor(null); } - public static class ThreadMediaLoader extends AbstractCursorLoader { - private final long threadId; - - public ThreadMediaLoader(Context context, long threadId) { - super(context); - this.threadId = threadId; - } - - @Override - public Cursor getCursor() { - return DatabaseFactory.getMediaDatabase(getContext()).getMediaForThread(threadId); - } - } } diff --git a/src/org/thoughtcrime/securesms/MediaPreviewActivity.java b/src/org/thoughtcrime/securesms/MediaPreviewActivity.java index 1fd13b1188..244f422dd7 100644 --- a/src/org/thoughtcrime/securesms/MediaPreviewActivity.java +++ b/src/org/thoughtcrime/securesms/MediaPreviewActivity.java @@ -54,7 +54,6 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity im private final static String TAG = MediaPreviewActivity.class.getSimpleName(); public static final String ADDRESS_EXTRA = "address"; - public static final String THREAD_ID_EXTRA = "thread_id"; public static final String DATE_EXTRA = "date"; public static final String SIZE_EXTRA = "size"; @@ -68,7 +67,6 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity im private Uri mediaUri; private String mediaType; private Recipient recipient; - private long threadId; private long date; private long size; @@ -150,7 +148,6 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity im mediaType = getIntent().getType(); date = getIntent().getLongExtra(DATE_EXTRA, -1); size = getIntent().getLongExtra(SIZE_EXTRA, 0); - threadId = getIntent().getLongExtra(THREAD_ID_EXTRA, -1); if (address != null) { recipient = Recipient.from(this, address, true); @@ -194,7 +191,7 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity im private void showOverview() { Intent intent = new Intent(this, MediaOverviewActivity.class); - intent.putExtra(MediaOverviewActivity.THREAD_ID_EXTRA, threadId); + intent.putExtra(MediaOverviewActivity.ADDRESS_EXTRA, recipient.getAddress()); startActivity(intent); } @@ -223,7 +220,7 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity im menu.clear(); MenuInflater inflater = this.getMenuInflater(); inflater.inflate(R.menu.media_preview, menu); - if (threadId == -1) menu.findItem(R.id.media_preview__overview).setVisible(false); + if (recipient == null) menu.findItem(R.id.media_preview__overview).setVisible(false); return true; } diff --git a/src/org/thoughtcrime/securesms/PassphraseRequiredActionBarActivity.java b/src/org/thoughtcrime/securesms/PassphraseRequiredActionBarActivity.java index cfa9321735..1ceff5808c 100644 --- a/src/org/thoughtcrime/securesms/PassphraseRequiredActionBarActivity.java +++ b/src/org/thoughtcrime/securesms/PassphraseRequiredActionBarActivity.java @@ -123,7 +123,7 @@ public abstract class PassphraseRequiredActionBarActivity extends BaseActionBarA fragment.setArguments(args); getSupportFragmentManager().beginTransaction() .replace(target, fragment) - .commit(); + .commitAllowingStateLoss(); return fragment; } diff --git a/src/org/thoughtcrime/securesms/RecipientPreferenceActivity.java b/src/org/thoughtcrime/securesms/RecipientPreferenceActivity.java index 97dbb9eedd..7ccb4b4507 100644 --- a/src/org/thoughtcrime/securesms/RecipientPreferenceActivity.java +++ b/src/org/thoughtcrime/securesms/RecipientPreferenceActivity.java @@ -5,6 +5,7 @@ import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; +import android.database.Cursor; import android.graphics.Color; import android.media.Ringtone; import android.media.RingtoneManager; @@ -12,23 +13,28 @@ import android.net.Uri; import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; -import android.preference.CheckBoxPreference; -import android.preference.ListPreference; -import android.preference.Preference; import android.provider.Settings; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.support.design.widget.CollapsingToolbarLayout; import android.support.v4.app.Fragment; -import android.support.v4.preference.PreferenceFragment; +import android.support.v4.app.LoaderManager; +import android.support.v4.content.Loader; import android.support.v7.app.AlertDialog; +import android.support.v7.preference.CheckBoxPreference; +import android.support.v7.preference.ListPreference; +import android.support.v7.preference.Preference; import android.support.v7.widget.Toolbar; import android.util.Log; import android.view.MenuItem; +import android.view.View; import android.view.WindowManager; import android.widget.ImageView; +import android.widget.TextView; import org.thoughtcrime.securesms.color.MaterialColor; import org.thoughtcrime.securesms.color.MaterialColors; +import org.thoughtcrime.securesms.components.ThreadPhotoRailView; import org.thoughtcrime.securesms.crypto.IdentityKeyParcelable; import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.database.Address; @@ -38,10 +44,12 @@ import org.thoughtcrime.securesms.database.IdentityDatabase; import org.thoughtcrime.securesms.database.IdentityDatabase.IdentityRecord; import org.thoughtcrime.securesms.database.RecipientDatabase; import org.thoughtcrime.securesms.database.RecipientDatabase.VibrateState; +import org.thoughtcrime.securesms.database.loaders.ThreadMediaLoader; import org.thoughtcrime.securesms.jobs.MultiDeviceBlockedUpdateJob; import org.thoughtcrime.securesms.jobs.MultiDeviceContactUpdateJob; import org.thoughtcrime.securesms.preferences.AdvancedRingtonePreference; -import org.thoughtcrime.securesms.preferences.ColorPreference; +import org.thoughtcrime.securesms.preferences.ColorPickerPreference; +import org.thoughtcrime.securesms.preferences.CorrectedPreferenceFragment; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientModifiedListener; import org.thoughtcrime.securesms.util.DynamicLanguage; @@ -55,7 +63,7 @@ import org.whispersystems.libsignal.util.guava.Optional; import java.util.concurrent.ExecutionException; -public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActivity implements RecipientModifiedListener +public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActivity implements RecipientModifiedListener, LoaderManager.LoaderCallbacks { private static final String TAG = RecipientPreferenceActivity.class.getSimpleName(); @@ -73,6 +81,10 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi private final DynamicLanguage dynamicLanguage = new DynamicLanguage(); private ImageView avatar; + private MasterSecret masterSecret; + private Address address; + private TextView threadPhotoRailLabel; + private ThreadPhotoRailView threadPhotoRailView; private CollapsingToolbarLayout toolbarLayout; private BroadcastReceiver staleReceiver; @@ -85,8 +97,9 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi @Override public void onCreate(Bundle instanceState, @NonNull MasterSecret masterSecret) { setContentView(R.layout.recipient_preference_activity); + this.masterSecret = masterSecret; + this.address = getIntent().getParcelableExtra(ADDRESS_EXTRA); - Address address = getIntent().getParcelableExtra(ADDRESS_EXTRA); Recipient recipient = Recipient.from(this, address, true); initializeToolbar(); @@ -94,9 +107,7 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi setHeader(recipient); recipient.addListener(this); - Bundle bundle = new Bundle(); - bundle.putParcelable(ADDRESS_EXTRA, address); - initFragment(R.id.preference_fragment, new RecipientPreferenceFragment(), masterSecret, null, bundle); + getSupportLoaderManager().initLoader(0, null, this); } @Override @@ -138,12 +149,29 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi } private void initializeToolbar() { - this.toolbarLayout = ViewUtil.findById(this, R.id.collapsing_toolbar); - this.avatar = ViewUtil.findById(this, R.id.avatar); + this.toolbarLayout = ViewUtil.findById(this, R.id.collapsing_toolbar); + this.avatar = ViewUtil.findById(this, R.id.avatar); + this.threadPhotoRailView = ViewUtil.findById(this, R.id.recent_photos); + this.threadPhotoRailLabel = ViewUtil.findById(this, R.id.rail_label); this.toolbarLayout.setExpandedTitleColor(getResources().getColor(R.color.white)); this.toolbarLayout.setCollapsedTitleTextColor(getResources().getColor(R.color.white)); + this.threadPhotoRailView.setListener(mediaRecord -> { + Intent intent = new Intent(RecipientPreferenceActivity.this, MediaPreviewActivity.class); + intent.putExtra(MediaPreviewActivity.ADDRESS_EXTRA, address); + intent.putExtra(MediaPreviewActivity.DATE_EXTRA, mediaRecord.getDate()); + intent.putExtra(MediaPreviewActivity.SIZE_EXTRA, mediaRecord.getAttachment().getSize()); + intent.setDataAndType(mediaRecord.getAttachment().getDataUri(), mediaRecord.getContentType()); + startActivity(intent); + }); + + this.threadPhotoRailLabel.setOnClickListener(v -> { + Intent intent = new Intent(this, MediaOverviewActivity.class); + intent.putExtra(MediaOverviewActivity.ADDRESS_EXTRA, address); + startActivity(intent); + }); + Toolbar toolbar = ViewUtil.findById(this, R.id.toolbar); setSupportActionBar(toolbar); getSupportActionBar().setDisplayHomeAsUpEnabled(true); @@ -183,23 +211,48 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi Util.runOnMain(() -> setHeader(recipient)); } + @Override + public Loader onCreateLoader(int id, Bundle args) { + return new ThreadMediaLoader(this, masterSecret, address); + } + + @Override + public void onLoadFinished(Loader loader, Cursor data) { + if (data != null && data.getCount() > 0) { + this.threadPhotoRailLabel.setVisibility(View.VISIBLE); + this.threadPhotoRailView.setVisibility(View.VISIBLE); + } else { + this.threadPhotoRailLabel.setVisibility(View.GONE); + this.threadPhotoRailView.setVisibility(View.GONE); + } + + this.threadPhotoRailView.setCursor(data, masterSecret); + + Bundle bundle = new Bundle(); + bundle.putParcelable(ADDRESS_EXTRA, address); + initFragment(R.id.preference_fragment, new RecipientPreferenceFragment(), masterSecret, null, bundle); + } + + @Override + public void onLoaderReset(Loader loader) { + this.threadPhotoRailView.setCursor(null, masterSecret); + } + public static class RecipientPreferenceFragment - extends PreferenceFragment + extends CorrectedPreferenceFragment implements RecipientModifiedListener { private Recipient recipient; private BroadcastReceiver staleReceiver; - private MasterSecret masterSecret; private boolean canHaveSafetyNumber; @Override public void onCreate(Bundle icicle) { + Log.w(TAG, "onCreate (fragment)"); super.onCreate(icicle); - addPreferencesFromResource(R.xml.recipient_preferences); initializeRecipients(); - this.masterSecret = getArguments().getParcelable("master_secret"); this.canHaveSafetyNumber = getActivity().getIntent() .getBooleanExtra(RecipientPreferenceActivity.CAN_HAVE_SAFETY_NUMBER_EXTRA, false); @@ -213,7 +266,12 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi .setOnPreferenceClickListener(new BlockClickedListener()); this.findPreference(PREFERENCE_COLOR) .setOnPreferenceChangeListener(new ColorChangeListener()); - } + } + + @Override + public void onCreatePreferences(@Nullable Bundle savedInstanceState, String rootKey) { + addPreferencesFromResource(R.xml.recipient_preferences); + } @Override public void onResume() { @@ -255,9 +313,9 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi CheckBoxPreference mutePreference = (CheckBoxPreference) this.findPreference(PREFERENCE_MUTED); AdvancedRingtonePreference ringtonePreference = (AdvancedRingtonePreference) this.findPreference(PREFERENCE_TONE); ListPreference vibratePreference = (ListPreference) this.findPreference(PREFERENCE_VIBRATE); - ColorPreference colorPreference = (ColorPreference) this.findPreference(PREFERENCE_COLOR); + ColorPickerPreference colorPreference = (ColorPickerPreference) this.findPreference(PREFERENCE_COLOR); Preference blockPreference = this.findPreference(PREFERENCE_BLOCK); - final Preference identityPreference = this.findPreference(PREFERENCE_IDENTITY); + Preference identityPreference = this.findPreference(PREFERENCE_IDENTITY); mutePreference.setChecked(recipient.isMuted()); @@ -294,11 +352,11 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi if (blockPreference != null) getPreferenceScreen().removePreference(blockPreference); if (identityPreference != null) getPreferenceScreen().removePreference(identityPreference); } else { - colorPreference.setChoices(MaterialColors.CONVERSATION_PALETTE.asConversationColorArray(getActivity())); - colorPreference.setValue(recipient.getColor().toActionBarColor(getActivity())); + colorPreference.setColors(MaterialColors.CONVERSATION_PALETTE.asConversationColorArray(getActivity())); + colorPreference.setColor(recipient.getColor().toActionBarColor(getActivity())); if (recipient.isBlocked()) blockPreference.setTitle(R.string.RecipientPreferenceActivity_unblock); - else blockPreference.setTitle(R.string.RecipientPreferenceActivity_block); + else blockPreference.setTitle(R.string.RecipientPreferenceActivity_block); IdentityUtil.getRemoteIdentityKey(getActivity(), recipient).addListener(new ListenableFuture.Listener>() { @Override @@ -330,14 +388,10 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi private class RingtoneChangeListener implements Preference.OnPreferenceChangeListener { @Override public boolean onPreferenceChange(Preference preference, Object newValue) { - String value = (String)newValue; + Uri value = (Uri)newValue; - final Uri uri; - - if (Settings.System.DEFAULT_NOTIFICATION_URI.toString().equals(value)) { - uri = null; - } else { - uri = Uri.parse(value); + if (Settings.System.DEFAULT_NOTIFICATION_URI.equals(value)) { + value = null; } new AsyncTask() { @@ -347,7 +401,7 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi .setRingtone(recipient, params[0]); return null; } - }.execute(uri); + }.execute(value); return false; } diff --git a/src/org/thoughtcrime/securesms/components/ThreadPhotoRailView.java b/src/org/thoughtcrime/securesms/components/ThreadPhotoRailView.java new file mode 100644 index 0000000000..d5a821d1f3 --- /dev/null +++ b/src/org/thoughtcrime/securesms/components/ThreadPhotoRailView.java @@ -0,0 +1,129 @@ +package org.thoughtcrime.securesms.components; + + +import android.content.Context; +import android.database.Cursor; +import android.os.Bundle; +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 org.thoughtcrime.securesms.R; +import org.thoughtcrime.securesms.crypto.MasterSecret; +import org.thoughtcrime.securesms.database.Address; +import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter; +import org.thoughtcrime.securesms.database.MediaDatabase; +import org.thoughtcrime.securesms.database.loaders.ThreadMediaLoader; +import org.thoughtcrime.securesms.mms.Slide; +import org.thoughtcrime.securesms.util.MediaUtil; +import org.thoughtcrime.securesms.util.ViewUtil; + +public class ThreadPhotoRailView extends FrameLayout { + + public static final String ADDRESS_EXTRA = "address"; + public static final String MASTER_SECRET_EXTRA = "master_secret"; + + @NonNull private final RecyclerView recyclerView; + @Nullable private OnItemClickedListener listener; + + public ThreadPhotoRailView(Context context) { + this(context, null); + } + + public ThreadPhotoRailView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public ThreadPhotoRailView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + + inflate(context, R.layout.recipient_preference_photo_rail, this); + + this.recyclerView = ViewUtil.findById(this, R.id.photo_list); + this.recyclerView.setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)); + this.recyclerView.setItemAnimator(new DefaultItemAnimator()); + this.recyclerView.setNestedScrollingEnabled(true); + } + + public void setListener(@Nullable OnItemClickedListener listener) { + this.listener = listener; + + if (this.recyclerView.getAdapter() != null) { + ((ThreadPhotoRailAdapter)this.recyclerView.getAdapter()).setListener(listener); + } + } + + public void setCursor(@Nullable Cursor cursor, @NonNull MasterSecret masterSecret) { + this.recyclerView.setAdapter(new ThreadPhotoRailAdapter(getContext(), masterSecret, cursor, this.listener)); + } + + private static class ThreadPhotoRailAdapter extends CursorRecyclerViewAdapter { + + private static final String TAG = ThreadPhotoRailAdapter.class.getName(); + + private final MasterSecret masterSecret; + + @Nullable private OnItemClickedListener clickedListener; + + private ThreadPhotoRailAdapter(@NonNull Context context, + @NonNull MasterSecret masterSecret, + @NonNull Cursor cursor, + @Nullable OnItemClickedListener listener) + { + super(context, cursor); + this.masterSecret = masterSecret; + this.clickedListener = listener; + } + + @Override + public ThreadPhotoViewHolder onCreateItemViewHolder(ViewGroup parent, int viewType) { + View itemView = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.recipient_preference_photo_rail_item, parent, false); + + return new ThreadPhotoViewHolder(itemView); + } + + @Override + public void onBindItemViewHolder(ThreadPhotoViewHolder viewHolder, @NonNull Cursor cursor) { + ThumbnailView imageView = viewHolder.imageView; + MediaDatabase.MediaRecord mediaRecord = MediaDatabase.MediaRecord.from(getContext(), masterSecret, cursor); + Slide slide = MediaUtil.getSlideForAttachment(getContext(), mediaRecord.getAttachment()); + + if (slide != null) { + imageView.setImageResource(masterSecret, slide, false, false); + } + + imageView.setOnClickListener(v -> { + if (clickedListener != null) clickedListener.onItemClicked(mediaRecord); + }); + } + + public void setListener(@Nullable OnItemClickedListener listener) { + this.clickedListener = listener; + } + + static class ThreadPhotoViewHolder extends RecyclerView.ViewHolder { + + ThumbnailView imageView; + + ThreadPhotoViewHolder(View itemView) { + super(itemView); + + this.imageView = ViewUtil.findById(itemView, R.id.thumbnail); + } + } + } + + public interface OnItemClickedListener { + public void onItemClicked(MediaDatabase.MediaRecord mediaRecord); + } +} diff --git a/src/org/thoughtcrime/securesms/database/loaders/ThreadMediaLoader.java b/src/org/thoughtcrime/securesms/database/loaders/ThreadMediaLoader.java new file mode 100644 index 0000000000..57f37d3ee3 --- /dev/null +++ b/src/org/thoughtcrime/securesms/database/loaders/ThreadMediaLoader.java @@ -0,0 +1,38 @@ +package org.thoughtcrime.securesms.database.loaders; + + +import android.content.Context; +import android.database.Cursor; +import android.support.annotation.NonNull; + +import org.thoughtcrime.securesms.crypto.MasterSecret; +import org.thoughtcrime.securesms.database.Address; +import org.thoughtcrime.securesms.database.DatabaseFactory; +import org.thoughtcrime.securesms.recipients.Recipient; +import org.thoughtcrime.securesms.util.AbstractCursorLoader; + +public class ThreadMediaLoader extends AbstractCursorLoader { + + private final Address address; + private final MasterSecret masterSecret; + + public ThreadMediaLoader(@NonNull Context context, @NonNull MasterSecret masterSecret, @NonNull Address address) { + super(context); + this.masterSecret = masterSecret; + this.address = address; + } + + @Override + public Cursor getCursor() { + long threadId = DatabaseFactory.getThreadDatabase(getContext()).getThreadIdFor(Recipient.from(getContext(), address, true)); + return DatabaseFactory.getMediaDatabase(getContext()).getMediaForThread(threadId); + } + + public Address getAddress() { + return address; + } + + public MasterSecret getMasterSecret() { + return masterSecret; + } +}