Add conversation media photo rail to recipient preferences

// FREEBIE
This commit is contained in:
Moxie Marlinspike 2017-09-20 18:14:28 -07:00
parent a1c276f70b
commit 4828a8a274
14 changed files with 375 additions and 108 deletions

View File

@ -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 @@
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:id="@+id/scroll_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
android:descendantFocusability="blocksDescendants"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<FrameLayout android:id="@+id/preference_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<LinearLayout android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView android:id="@+id/rail_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="16dp"
android:text="Shared media"
android:visibility="gone"
android:textColor="?attr/colorPrimary"/>
<org.thoughtcrime.securesms.components.ThreadPhotoRailView
android:id="@+id/recent_photos"
android:layout_width="match_parent"
android:layout_height="90dp"
android:visibility="visible"
android:layout_marginBottom="16dp"/>
<include layout="@layout/preference_divider"/>
<FrameLayout android:id="@+id/preference_fragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>

View File

@ -0,0 +1,13 @@
<?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:paddingLeft="16dp"
android:paddingStart="16dp"
android:clipToPadding="false"
android:nestedScrollingEnabled="true"
android:scrollbars="none"/>
</merge>

View File

@ -0,0 +1,17 @@
<?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">
<org.thoughtcrime.securesms.components.ThumbnailView
android:id="@+id/thumbnail"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"/>
</org.thoughtcrime.securesms.components.SquareFrameLayout>

View File

@ -998,6 +998,8 @@
<string name="recipient_preferences__color">Color</string>
<string name="recipient_preferences__color_for_this_contact">Color for this contact</string>
<string name="recipient_preferences__view_safety_number">View safety number</string>
<string name="recipient_preferences__chat_settings">Chat settings</string>
<string name="recipient_preferences__privacy">Privacy</string>
<!--- redphone_call_controls -->
<string name="redphone_call_card__signal_call">Signal Call</string>

View File

@ -2,48 +2,55 @@
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<org.thoughtcrime.securesms.components.SwitchPreferenceCompat
android:key="pref_key_recipient_mute"
android:title="@string/recipient_preferences__mute_conversation"
android:defaultValue="false"
android:disableDependentsState="true"
android:persistent="false" />
<PreferenceCategory android:key="notification_settings" android:title="@string/recipient_preferences__chat_settings">
<org.thoughtcrime.securesms.components.SwitchPreferenceCompat
android:key="pref_key_recipient_mute"
android:title="@string/recipient_preferences__mute_conversation"
android:defaultValue="false"
android:disableDependentsState="true"
android:persistent="false" />
<org.thoughtcrime.securesms.preferences.SignalRingtonePreference
android:dependency="pref_key_recipient_mute"
android:key="pref_key_recipient_ringtone"
android:title="@string/recipient_preferences__notification_sound"
android:ringtoneType="notification"
android:showSilent="true"
android:showDefault="true"
android:persistent="false"/>
<org.thoughtcrime.securesms.preferences.SignalRingtonePreference
android:dependency="pref_key_recipient_mute"
android:key="pref_key_recipient_ringtone"
android:title="@string/recipient_preferences__notification_sound"
android:ringtoneType="notification"
android:showSilent="true"
android:showDefault="true"
android:persistent="false"/>
<org.thoughtcrime.securesms.preferences.SignalListPreference
android:dependency="pref_key_recipient_mute"
android:key="pref_key_recipient_vibrate"
android:title="@string/recipient_preferences__vibrate"
android:entries="@array/recipient_vibrate_entries"
android:entryValues="@array/recipient_vibrate_values"
android:defaultValue="0"
android:persistent="false"/>
<org.thoughtcrime.securesms.preferences.ColorPreference
android:key="pref_key_recipient_color"
android:title="@string/recipient_preferences__color"
android:defaultValue="@android:color/black"
android:negativeButtonText="@null"
android:positiveButtonText="@null"
android:persistent="false"
app:numColumns="5" />
<Preference android:key="pref_key_recipient_identity"
android:title="@string/recipient_preferences__view_safety_number"
android:persistent="false"
android:enabled="false"/>
<Preference android:key="pref_key_recipient_block"
android:title="@string/recipient_preferences__block"
<org.thoughtcrime.securesms.preferences.SignalListPreference
android:dependency="pref_key_recipient_mute"
android:key="pref_key_recipient_vibrate"
android:title="@string/recipient_preferences__vibrate"
android:entries="@array/recipient_vibrate_entries"
android:entryValues="@array/recipient_vibrate_values"
android:defaultValue="0"
android:persistent="false"/>
<org.thoughtcrime.securesms.preferences.ColorPickerPreference
android:key="pref_key_recipient_color"
android:title="@string/recipient_preferences__color"
android:defaultValue="@android:color/black"
android:negativeButtonText="@null"
android:positiveButtonText="@null"
android:persistent="false"
app:numColumns="5" />
</PreferenceCategory>
<PreferenceCategory android:layout="@layout/preference_divider"/>
<PreferenceCategory android:key="privacy_settings" android:title="@string/recipient_preferences__privacy">
<Preference android:key="pref_key_recipient_identity"
android:title="@string/recipient_preferences__view_safety_number"
android:persistent="false"
android:enabled="false"/>
<Preference android:key="pref_key_recipient_block"
android:title="@string/recipient_preferences__block"
android:persistent="false"/>
</PreferenceCategory>
</PreferenceScreen>

View File

@ -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);
}

View File

@ -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) {

View File

@ -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<ViewHolder> {
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<ViewHolder> {
}
}
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<ViewHolder> {
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());

View File

@ -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<SaveAttachmentTask.Attachment> doInBackground(Void... params) {
long threadId = DatabaseFactory.getThreadDatabase(c).getThreadIdFor(recipient);
Cursor cursor = DatabaseFactory.getMediaDatabase(c).getMediaForThread(threadId);
List<SaveAttachmentTask.Attachment> 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<Cursor> onCreateLoader(int i, Bundle bundle) {
return new ThreadMediaLoader(this, threadId);
return new ThreadMediaLoader(this, masterSecret, recipient.getAddress());
}
@Override
public void onLoadFinished(Loader<Cursor> 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);
}
}
}

View File

@ -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;
}

View File

@ -123,7 +123,7 @@ public abstract class PassphraseRequiredActionBarActivity extends BaseActionBarA
fragment.setArguments(args);
getSupportFragmentManager().beginTransaction()
.replace(target, fragment)
.commit();
.commitAllowingStateLoss();
return fragment;
}

View File

@ -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<Cursor>
{
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<Cursor> onCreateLoader(int id, Bundle args) {
return new ThreadMediaLoader(this, masterSecret, address);
}
@Override
public void onLoadFinished(Loader<Cursor> 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<Cursor> 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<Optional<IdentityRecord>>() {
@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<Uri, Void, Void>() {
@ -347,7 +401,7 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
.setRingtone(recipient, params[0]);
return null;
}
}.execute(uri);
}.execute(value);
return false;
}

View File

@ -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<ThreadPhotoRailAdapter.ThreadPhotoViewHolder> {
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);
}
}

View File

@ -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;
}
}