improved support for sensitive content

This commit is contained in:
Mariotaku Lee 2015-04-08 21:26:44 +08:00
parent 31171ad05e
commit be7dffff16
9 changed files with 104 additions and 30 deletions

View File

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

View File

@ -23,6 +23,8 @@ public interface IStatusesAdapter<Data> extends IContentCardAdapter, StatusClick
boolean isNameFirst();
boolean isSensitiveContentEnabled();
void setData(Data data);
boolean shouldShowAccountsColor();

View File

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

View File

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

View File

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

BIN
twidere/src/main/res/drawable-hdpi/ic_action_warning.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 322 B

After

Width:  |  Height:  |  Size: 639 B

BIN
twidere/src/main/res/drawable-mdpi/ic_action_warning.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 251 B

After

Width:  |  Height:  |  Size: 454 B

BIN
twidere/src/main/res/drawable-xhdpi/ic_action_warning.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 460 B

After

Width:  |  Height:  |  Size: 967 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 474 B

After

Width:  |  Height:  |  Size: 1.0 KiB