improved support for sensitive content
|
@ -38,6 +38,7 @@ import org.mariotaku.twidere.view.holder.StatusViewHolder;
|
|||
*/
|
||||
public abstract class AbsStatusesAdapter<D> extends Adapter<ViewHolder> implements Constants,
|
||||
IStatusesAdapter<D> {
|
||||
|
||||
public static final int ITEM_VIEW_TYPE_LOAD_INDICATOR = 0;
|
||||
public static final int ITEM_VIEW_TYPE_GAP = 1;
|
||||
public static final int ITEM_VIEW_TYPE_STATUS = 2;
|
||||
|
@ -60,11 +61,11 @@ public abstract class AbsStatusesAdapter<D> extends Adapter<ViewHolder> implemen
|
|||
private final boolean mNameFirst;
|
||||
private final boolean mDisplayMediaPreview;
|
||||
private final boolean mDisplayProfileImage;
|
||||
private final boolean mSensitiveContentEnabled;
|
||||
private final TwidereLinkify mLinkify;
|
||||
|
||||
private boolean mLoadMoreSupported;
|
||||
private boolean mLoadMoreIndicatorVisible;
|
||||
|
||||
private StatusAdapterListener mStatusAdapterListener;
|
||||
private boolean mShowInReplyTo;
|
||||
private boolean mShowAccountsColor;
|
||||
|
@ -87,6 +88,7 @@ public abstract class AbsStatusesAdapter<D> extends Adapter<ViewHolder> implemen
|
|||
mNameFirst = preferences.getBoolean(KEY_NAME_FIRST, true);
|
||||
mDisplayProfileImage = preferences.getBoolean(KEY_DISPLAY_PROFILE_IMAGE, true);
|
||||
mDisplayMediaPreview = preferences.getBoolean(KEY_MEDIA_PREVIEW, false);
|
||||
mSensitiveContentEnabled = preferences.getBoolean(KEY_DISPLAY_SENSITIVE_CONTENTS, false);
|
||||
mLinkify = new TwidereLinkify(new StatusAdapterLinkClickHandler<>(this));
|
||||
setShowInReplyTo(true);
|
||||
}
|
||||
|
@ -181,6 +183,11 @@ public abstract class AbsStatusesAdapter<D> extends Adapter<ViewHolder> implemen
|
|||
return mNameFirst;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSensitiveContentEnabled() {
|
||||
return mSensitiveContentEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isProfileImageEnabled() {
|
||||
return mDisplayProfileImage;
|
||||
|
|
|
@ -23,6 +23,8 @@ public interface IStatusesAdapter<Data> extends IContentCardAdapter, StatusClick
|
|||
|
||||
boolean isNameFirst();
|
||||
|
||||
boolean isSensitiveContentEnabled();
|
||||
|
||||
void setData(Data data);
|
||||
|
||||
boolean shouldShowAccountsColor();
|
||||
|
|
|
@ -20,7 +20,10 @@
|
|||
package org.mariotaku.twidere.fragment.support;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Color;
|
||||
|
@ -33,6 +36,7 @@ import android.nfc.NfcEvent;
|
|||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
|
@ -54,7 +58,6 @@ import android.support.v7.widget.RecyclerView.ViewHolder;
|
|||
import android.text.Html;
|
||||
import android.text.SpannableString;
|
||||
import android.text.TextUtils;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
import android.text.style.URLSpan;
|
||||
import android.view.ActionMode;
|
||||
import android.view.ActionMode.Callback;
|
||||
|
@ -742,14 +745,19 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
|
|||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
final ParcelableStatus status = adapter.getStatus(getAdapterPosition());
|
||||
final StatusFragment fragment = adapter.getFragment();
|
||||
switch (v.getId()) {
|
||||
case R.id.media_preview_load: {
|
||||
adapter.setDetailMediaExpanded(true);
|
||||
if (adapter.isSensitiveContentEnabled() || !status.is_possibly_sensitive) {
|
||||
adapter.setDetailMediaExpanded(true);
|
||||
} else {
|
||||
final LoadSensitiveImageConfirmDialogFragment f = new LoadSensitiveImageConfirmDialogFragment();
|
||||
f.show(fragment.getChildFragmentManager(), "load_sensitive_image_confirm");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case R.id.profile_container: {
|
||||
final ParcelableStatus status = adapter.getStatus(getPosition());
|
||||
final Fragment fragment = adapter.getFragment();
|
||||
final FragmentActivity activity = fragment.getActivity();
|
||||
final Bundle activityOption = Utils.makeSceneTransitionOption(activity,
|
||||
new Pair<View, String>(profileImageView, UserFragment.TRANSITION_NAME_PROFILE_IMAGE),
|
||||
|
@ -759,14 +767,11 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
|
|||
break;
|
||||
}
|
||||
case R.id.retweets_container: {
|
||||
final ParcelableStatus status = adapter.getStatus(getPosition());
|
||||
final Fragment fragment = adapter.getFragment();
|
||||
final FragmentActivity activity = fragment.getActivity();
|
||||
Utils.openStatusRetweeters(activity, status.account_id, status.id);
|
||||
break;
|
||||
}
|
||||
case R.id.retweeted_by_container: {
|
||||
final ParcelableStatus status = adapter.getStatus(getPosition());
|
||||
if (status.retweet_id > 0) {
|
||||
Utils.openUserProfile(adapter.getContext(), status.account_id, status.user_id,
|
||||
status.user_screen_name, null);
|
||||
|
@ -774,7 +779,6 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
|
|||
break;
|
||||
}
|
||||
case R.id.location_view: {
|
||||
final ParcelableStatus status = adapter.getStatus(getAdapterPosition());
|
||||
final ParcelableLocation location = status.location;
|
||||
if (!ParcelableLocation.isValidLocation(location)) return;
|
||||
Utils.openMap(adapter.getContext(), location.latitude, location.longitude);
|
||||
|
@ -884,6 +888,41 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
|
|||
}
|
||||
}
|
||||
|
||||
public static final class LoadSensitiveImageConfirmDialogFragment extends BaseSupportDialogFragment implements
|
||||
DialogInterface.OnClickListener {
|
||||
|
||||
@Override
|
||||
public void onClick(final DialogInterface dialog, final int which) {
|
||||
switch (which) {
|
||||
case DialogInterface.BUTTON_POSITIVE: {
|
||||
final Fragment f = getParentFragment();
|
||||
if (f instanceof StatusFragment) {
|
||||
final StatusAdapter adapter = ((StatusFragment) f).getAdapter();
|
||||
adapter.setDetailMediaExpanded(true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(final Bundle savedInstanceState) {
|
||||
final Context wrapped = ThemeUtils.getDialogThemedContext(getActivity());
|
||||
final AlertDialog.Builder builder = new AlertDialog.Builder(wrapped);
|
||||
builder.setTitle(android.R.string.dialog_alert_title);
|
||||
builder.setMessage(R.string.sensitive_content_warning);
|
||||
builder.setPositiveButton(android.R.string.ok, this);
|
||||
builder.setNegativeButton(android.R.string.cancel, null);
|
||||
return builder.create();
|
||||
}
|
||||
}
|
||||
|
||||
private StatusAdapter getAdapter() {
|
||||
return mStatusAdapter;
|
||||
}
|
||||
|
||||
static class LoadConversationTask extends AsyncTask<ParcelableStatus, ParcelableStatus,
|
||||
ListResponse<ParcelableStatus>> {
|
||||
|
||||
|
@ -971,6 +1010,7 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
|
|||
private final int mLinkHighligingStyle;
|
||||
private final boolean mDisplayMediaPreview;
|
||||
private final boolean mDisplayProfileImage;
|
||||
private final boolean mSensitiveContentEnabled;
|
||||
|
||||
private boolean mLoadMoreSupported;
|
||||
private boolean mLoadMoreIndicatorVisible;
|
||||
|
@ -1001,6 +1041,7 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
|
|||
mIsCompact = compact;
|
||||
mDisplayProfileImage = preferences.getBoolean(KEY_DISPLAY_PROFILE_IMAGE, true);
|
||||
mDisplayMediaPreview = preferences.getBoolean(KEY_MEDIA_PREVIEW, false);
|
||||
mSensitiveContentEnabled = preferences.getBoolean(KEY_DISPLAY_SENSITIVE_CONTENTS, false);
|
||||
if (compact) {
|
||||
mCardLayoutResource = R.layout.card_item_status_compact;
|
||||
} else {
|
||||
|
@ -1131,6 +1172,11 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
|
|||
return mNameFirst;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSensitiveContentEnabled() {
|
||||
return mSensitiveContentEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setData(List<ParcelableStatus> data) {
|
||||
|
||||
|
|
|
@ -214,6 +214,7 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
|
|||
private ActionBarDrawable mActionBarBackground;
|
||||
private Fragment mCurrentVisibleFragment;
|
||||
private int mCardBackgroundColor;
|
||||
private int mUserUiColor;
|
||||
|
||||
|
||||
@Subscribe
|
||||
|
@ -1250,6 +1251,7 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
|
|||
}
|
||||
|
||||
private void setUserUiColor(int color) {
|
||||
mUserUiColor = color;
|
||||
if (mActionBarBackground == null) {
|
||||
setupBaseActionBar();
|
||||
}
|
||||
|
@ -1335,8 +1337,6 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
|
|||
setCompatToolbarOverlayAlpha(activity, factor * tabOutlineAlphaFactor);
|
||||
}
|
||||
|
||||
final int color = mActionBarBackground.getColor();
|
||||
|
||||
if (activity instanceof IThemedActivity) {
|
||||
final Drawable drawable = mPagerIndicator.getBackground();
|
||||
final int stackedTabColor;
|
||||
|
@ -1345,9 +1345,9 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
|
|||
final int contrastColor = ColorUtils.getContrastYIQ(stackedTabColor, 192);
|
||||
mPagerIndicator.setIconColor(contrastColor);
|
||||
mPagerIndicator.setLabelColor(contrastColor);
|
||||
mPagerIndicator.setStripColor(color);
|
||||
mPagerIndicator.setStripColor(mUserUiColor);
|
||||
} else if (drawable instanceof ColorDrawable) {
|
||||
stackedTabColor = color;
|
||||
stackedTabColor = mUserUiColor;
|
||||
final int tabColor = (Integer) sArgbEvaluator.evaluate(tabOutlineAlphaFactor, stackedTabColor, mCardBackgroundColor);
|
||||
((ColorDrawable) drawable).setColor(tabColor);
|
||||
final int contrastColor = ColorUtils.getContrastYIQ(tabColor, 192);
|
||||
|
@ -1356,7 +1356,7 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
|
|||
mPagerIndicator.setStripColor(contrastColor);
|
||||
}
|
||||
} else {
|
||||
final int contrastColor = ColorUtils.getContrastYIQ(color, 192);
|
||||
final int contrastColor = ColorUtils.getContrastYIQ(mUserUiColor, 192);
|
||||
mPagerIndicator.setIconColor(contrastColor);
|
||||
mPagerIndicator.setLabelColor(contrastColor);
|
||||
mPagerIndicator.setStripColor(contrastColor);
|
||||
|
|
|
@ -225,9 +225,14 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements Constan
|
|||
|
||||
if (adapter.isMediaPreviewEnabled()) {
|
||||
mediaPreview.setStyle(adapter.getMediaPreviewStyle());
|
||||
mediaPreview.setVisibility(status.media != null && status.media.length > 0 ? View.VISIBLE : View.GONE);
|
||||
mediaPreview.displayMedia(status.media, loader, status.account_id, this,
|
||||
adapter.getImageLoadingHandler());
|
||||
final boolean hasMedia = status.media != null && status.media.length > 0;
|
||||
if (hasMedia && (adapter.isSensitiveContentEnabled() || !status.is_possibly_sensitive)) {
|
||||
mediaPreview.setVisibility(hasMedia ? View.VISIBLE : View.GONE);
|
||||
mediaPreview.displayMedia(status.media, loader, status.account_id, this,
|
||||
adapter.getImageLoadingHandler());
|
||||
} else {
|
||||
mediaPreview.setVisibility(View.GONE);
|
||||
}
|
||||
} else {
|
||||
mediaPreview.setVisibility(View.GONE);
|
||||
}
|
||||
|
@ -275,7 +280,8 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements Constan
|
|||
favoriteCountView.setText(null);
|
||||
}
|
||||
if (shouldDisplayExtraType) {
|
||||
displayExtraTypeIcon(status.card_name, status.media, status.location, status.place_full_name);
|
||||
displayExtraTypeIcon(status.card_name, status.media, status.location, status.place_full_name,
|
||||
status.is_possibly_sensitive);
|
||||
} else {
|
||||
extraTypeView.setVisibility(View.GONE);
|
||||
}
|
||||
|
@ -298,7 +304,6 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements Constan
|
|||
final long status_id = cursor.getLong(indices.status_id);
|
||||
final long retweet_id = cursor.getLong(indices.retweet_id);
|
||||
final long my_retweet_id = cursor.getLong(indices.my_retweet_id);
|
||||
final long retweeted_by_id = cursor.getLong(indices.retweeted_by_user_id);
|
||||
final long in_reply_to_status_id = cursor.getLong(indices.in_reply_to_status_id);
|
||||
final long in_reply_to_user_id = cursor.getLong(indices.in_reply_to_user_id);
|
||||
|
||||
|
@ -307,12 +312,15 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements Constan
|
|||
final String card_name = cursor.getString(indices.card_name);
|
||||
final String place_full_name = cursor.getString(indices.place_full_name);
|
||||
|
||||
final boolean sensitive = cursor.getShort(indices.is_possibly_sensitive) == 1;
|
||||
|
||||
final ParcelableMedia[] media = SimpleValueSerializer.fromSerializedString(
|
||||
cursor.getString(indices.media), ParcelableMedia.SIMPLE_CREATOR);
|
||||
final ParcelableLocation location = ParcelableLocation.fromString(
|
||||
cursor.getString(indices.location));
|
||||
|
||||
if (retweet_id > 0) {
|
||||
final long retweeted_by_id = cursor.getLong(indices.retweeted_by_user_id);
|
||||
final String retweeted_by_name = cursor.getString(indices.retweeted_by_user_name);
|
||||
final String retweeted_by_screen_name = cursor.getString(indices.retweeted_by_user_screen_name);
|
||||
final String retweetedBy = UserColorNameUtils.getDisplayName(context, retweeted_by_id,
|
||||
|
@ -417,10 +425,13 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements Constan
|
|||
|
||||
|
||||
if (adapter.isMediaPreviewEnabled()) {
|
||||
mediaPreview.setStyle(adapter.getMediaPreviewStyle());
|
||||
mediaPreview.setVisibility(media != null && media.length > 0 ? View.VISIBLE : View.GONE);
|
||||
mediaPreview.displayMedia(media, loader, account_id, this,
|
||||
adapter.getImageLoadingHandler());
|
||||
final boolean hasMedia = media != null && media.length > 0;
|
||||
if (hasMedia && (adapter.isSensitiveContentEnabled() || !sensitive)) {
|
||||
mediaPreview.setVisibility(hasMedia ? View.VISIBLE : View.GONE);
|
||||
mediaPreview.displayMedia(media, loader, account_id, this, adapter.getImageLoadingHandler());
|
||||
} else {
|
||||
mediaPreview.setVisibility(View.GONE);
|
||||
}
|
||||
} else {
|
||||
mediaPreview.setVisibility(View.GONE);
|
||||
}
|
||||
|
@ -445,6 +456,7 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements Constan
|
|||
retweet_count = Math.max(0, cursor.getLong(indices.retweet_count) - 1);
|
||||
} else {
|
||||
final boolean creatingRetweet = twitter.isCreatingRetweet(account_id, status_id);
|
||||
final long retweeted_by_id = cursor.getLong(indices.retweeted_by_user_id);
|
||||
retweetCountView.setActivated(creatingRetweet || Utils.isMyRetweet(account_id,
|
||||
retweeted_by_id, my_retweet_id));
|
||||
retweet_count = cursor.getLong(indices.retweet_count) + (creatingRetweet ? 1 : 0);
|
||||
|
@ -467,7 +479,7 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements Constan
|
|||
} else {
|
||||
favoriteCountView.setText(null);
|
||||
}
|
||||
displayExtraTypeIcon(card_name, media, location, place_full_name);
|
||||
displayExtraTypeIcon(card_name, media, location, place_full_name, sensitive);
|
||||
}
|
||||
|
||||
public CardView getCardView() {
|
||||
|
@ -551,21 +563,21 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements Constan
|
|||
profileImageView.setStyle(adapter.getProfileImageStyle());
|
||||
}
|
||||
|
||||
private void displayExtraTypeIcon(String cardName, ParcelableMedia[] media, ParcelableLocation location, String placeFullName) {
|
||||
private void displayExtraTypeIcon(String cardName, ParcelableMedia[] media, ParcelableLocation location, String placeFullName, boolean sensitive) {
|
||||
if (TwitterCardUtils.CARD_NAME_AUDIO.equals(cardName)) {
|
||||
extraTypeView.setImageResource(R.drawable.ic_action_music);
|
||||
extraTypeView.setImageResource(sensitive ? R.drawable.ic_action_warning : R.drawable.ic_action_music);
|
||||
extraTypeView.setVisibility(View.VISIBLE);
|
||||
} else if (TwitterCardUtils.CARD_NAME_ANIMATED_GIF.equals(cardName)) {
|
||||
extraTypeView.setImageResource(R.drawable.ic_action_movie);
|
||||
extraTypeView.setImageResource(sensitive ? R.drawable.ic_action_warning : R.drawable.ic_action_movie);
|
||||
extraTypeView.setVisibility(View.VISIBLE);
|
||||
} else if (TwitterCardUtils.CARD_NAME_PLAYER.equals(cardName)) {
|
||||
extraTypeView.setImageResource(R.drawable.ic_action_play_circle);
|
||||
extraTypeView.setImageResource(sensitive ? R.drawable.ic_action_warning : R.drawable.ic_action_play_circle);
|
||||
extraTypeView.setVisibility(View.VISIBLE);
|
||||
} else if (media != null && media.length > 0) {
|
||||
if (hasVideo(media)) {
|
||||
extraTypeView.setImageResource(R.drawable.ic_action_movie);
|
||||
extraTypeView.setImageResource(sensitive ? R.drawable.ic_action_warning : R.drawable.ic_action_movie);
|
||||
} else {
|
||||
extraTypeView.setImageResource(R.drawable.ic_action_gallery);
|
||||
extraTypeView.setImageResource(sensitive ? R.drawable.ic_action_warning : R.drawable.ic_action_gallery);
|
||||
}
|
||||
extraTypeView.setVisibility(View.VISIBLE);
|
||||
} else if (ParcelableLocation.isValidLocation(location) || !TextUtils.isEmpty(placeFullName)) {
|
||||
|
@ -604,6 +616,7 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements Constan
|
|||
private final int profileImageStyle, mediaPreviewStyle;
|
||||
private final boolean nameFirst;
|
||||
private final boolean displayProfileImage;
|
||||
private final boolean sensitiveContentEnabled;
|
||||
private boolean displayMediaPreview;
|
||||
|
||||
public DummyStatusHolderAdapter(Context context) {
|
||||
|
@ -622,6 +635,7 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements Constan
|
|||
nameFirst = preferences.getBoolean(KEY_NAME_FIRST, true);
|
||||
displayProfileImage = preferences.getBoolean(KEY_DISPLAY_PROFILE_IMAGE, true);
|
||||
displayMediaPreview = preferences.getBoolean(KEY_MEDIA_PREVIEW, false);
|
||||
sensitiveContentEnabled = preferences.getBoolean(KEY_DISPLAY_SENSITIVE_CONTENTS, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -759,6 +773,11 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements Constan
|
|||
return nameFirst;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSensitiveContentEnabled() {
|
||||
return sensitiveContentEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setData(Object o) {
|
||||
|
||||
|
|
Before Width: | Height: | Size: 322 B After Width: | Height: | Size: 639 B |
Before Width: | Height: | Size: 251 B After Width: | Height: | Size: 454 B |
Before Width: | Height: | Size: 460 B After Width: | Height: | Size: 967 B |
Before Width: | Height: | Size: 474 B After Width: | Height: | Size: 1.0 KiB |