trying thumbor integration

improving quoted status support
This commit is contained in:
Mariotaku Lee 2015-04-07 23:43:03 +08:00
parent 5288fe34e9
commit b181bbe38f
62 changed files with 1687 additions and 1778 deletions

View File

@ -30,275 +30,281 @@ import static org.mariotaku.twidere.annotation.Preference.Type.STRING;
public interface SharedPreferenceConstants {
public static final String FORMAT_PATTERN_TITLE = "[TITLE]";
public static final String FORMAT_PATTERN_TEXT = "[TEXT]";
public static final String FORMAT_PATTERN_NAME = "[NAME]";
public static final String FORMAT_PATTERN_LINK = "[LINK]";
String FORMAT_PATTERN_TITLE = "[TITLE]";
String FORMAT_PATTERN_TEXT = "[TEXT]";
String FORMAT_PATTERN_NAME = "[NAME]";
String FORMAT_PATTERN_LINK = "[LINK]";
public static final String VALUE_NONE = "none";
public static final String VALUE_LINK_HIGHLIGHT_OPTION_NONE = VALUE_NONE;
public static final String VALUE_LINK_HIGHLIGHT_OPTION_HIGHLIGHT = "highlight";
public static final String VALUE_LINK_HIGHLIGHT_OPTION_UNDERLINE = "underline";
public static final String VALUE_LINK_HIGHLIGHT_OPTION_BOTH = "both";
public static final int VALUE_LINK_HIGHLIGHT_OPTION_CODE_NONE = 0x0;
public static final int VALUE_LINK_HIGHLIGHT_OPTION_CODE_HIGHLIGHT = 0x1;
public static final int VALUE_LINK_HIGHLIGHT_OPTION_CODE_UNDERLINE = 0x2;
public static final int VALUE_LINK_HIGHLIGHT_OPTION_CODE_BOTH = VALUE_LINK_HIGHLIGHT_OPTION_CODE_HIGHLIGHT
String VALUE_NONE = "none";
String VALUE_LINK_HIGHLIGHT_OPTION_NONE = VALUE_NONE;
String VALUE_LINK_HIGHLIGHT_OPTION_HIGHLIGHT = "highlight";
String VALUE_LINK_HIGHLIGHT_OPTION_UNDERLINE = "underline";
String VALUE_LINK_HIGHLIGHT_OPTION_BOTH = "both";
int VALUE_LINK_HIGHLIGHT_OPTION_CODE_NONE = 0x0;
int VALUE_LINK_HIGHLIGHT_OPTION_CODE_HIGHLIGHT = 0x1;
int VALUE_LINK_HIGHLIGHT_OPTION_CODE_UNDERLINE = 0x2;
int VALUE_LINK_HIGHLIGHT_OPTION_CODE_BOTH = VALUE_LINK_HIGHLIGHT_OPTION_CODE_HIGHLIGHT
| VALUE_LINK_HIGHLIGHT_OPTION_CODE_UNDERLINE;
public static final String VALUE_MEDIA_PREVIEW_STYLE_CROP = "crop";
public static final String VALUE_MEDIA_PREVIEW_STYLE_SCALE = "scale";
public static final String VALUE_MEDIA_PREVIEW_STYLE_NONE = VALUE_NONE;
String VALUE_MEDIA_PREVIEW_STYLE_CROP = "crop";
String VALUE_MEDIA_PREVIEW_STYLE_SCALE = "scale";
String VALUE_MEDIA_PREVIEW_STYLE_NONE = VALUE_NONE;
public static final int VALUE_MEDIA_PREVIEW_STYLE_CODE_CROP = 1;
public static final int VALUE_MEDIA_PREVIEW_STYLE_CODE_SCALE = 2;
public static final int VALUE_MEDIA_PREVIEW_STYLE_CODE_NONE = 0;
int VALUE_MEDIA_PREVIEW_STYLE_CODE_CROP = 1;
int VALUE_MEDIA_PREVIEW_STYLE_CODE_SCALE = 2;
int VALUE_MEDIA_PREVIEW_STYLE_CODE_NONE = 0;
public static final String VALUE_THEME_FONT_FAMILY_REGULAR = "sans-serif";
public static final String VALUE_THEME_FONT_FAMILY_CONDENSED = "sans-serif-condensed";
public static final String VALUE_THEME_FONT_FAMILY_LIGHT = "sans-serif-light";
public static final String VALUE_THEME_FONT_FAMILY_THIN = "sans-serif-thin";
String VALUE_THEME_FONT_FAMILY_REGULAR = "sans-serif";
String VALUE_THEME_FONT_FAMILY_CONDENSED = "sans-serif-condensed";
String VALUE_THEME_FONT_FAMILY_LIGHT = "sans-serif-light";
String VALUE_THEME_FONT_FAMILY_THIN = "sans-serif-thin";
public static final int VALUE_NOTIFICATION_FLAG_NONE = 0x0;
public static final int VALUE_NOTIFICATION_FLAG_RINGTONE = 0x1;
public static final int VALUE_NOTIFICATION_FLAG_VIBRATION = 0x2;
public static final int VALUE_NOTIFICATION_FLAG_LIGHT = 0x4;
int VALUE_NOTIFICATION_FLAG_NONE = 0x0;
int VALUE_NOTIFICATION_FLAG_RINGTONE = 0x1;
int VALUE_NOTIFICATION_FLAG_VIBRATION = 0x2;
int VALUE_NOTIFICATION_FLAG_LIGHT = 0x4;
public static final String VALUE_COMPOSE_QUIT_ACTION_ASK = "ask";
public static final String VALUE_COMPOSE_QUIT_ACTION_SAVE = "save";
public static final String VALUE_COMPOSE_QUIT_ACTION_DISCARD = "discard";
String VALUE_COMPOSE_QUIT_ACTION_ASK = "ask";
String VALUE_COMPOSE_QUIT_ACTION_SAVE = "save";
String VALUE_COMPOSE_QUIT_ACTION_DISCARD = "discard";
public static final String VALUE_TAB_DIPLAY_OPTION_ICON = "icon";
public static final String VALUE_TAB_DIPLAY_OPTION_LABEL = "label";
public static final String VALUE_TAB_DIPLAY_OPTION_BOTH = "both";
public static final int VALUE_TAB_DIPLAY_OPTION_CODE_ICON = 0x1;
public static final int VALUE_TAB_DIPLAY_OPTION_CODE_LABEL = 0x2;
public static final int VALUE_TAB_DIPLAY_OPTION_CODE_BOTH = VALUE_TAB_DIPLAY_OPTION_CODE_ICON
String VALUE_TAB_DIPLAY_OPTION_ICON = "icon";
String VALUE_TAB_DIPLAY_OPTION_LABEL = "label";
String VALUE_TAB_DIPLAY_OPTION_BOTH = "both";
int VALUE_TAB_DIPLAY_OPTION_CODE_ICON = 0x1;
int VALUE_TAB_DIPLAY_OPTION_CODE_LABEL = 0x2;
int VALUE_TAB_DIPLAY_OPTION_CODE_BOTH = VALUE_TAB_DIPLAY_OPTION_CODE_ICON
| VALUE_TAB_DIPLAY_OPTION_CODE_LABEL;
public static final String VALUE_THEME_BACKGROUND_DEFAULT = "default";
public static final String VALUE_THEME_BACKGROUND_SOLID = "solid";
public static final String VALUE_THEME_BACKGROUND_TRANSPARENT = "transparent";
String VALUE_THEME_BACKGROUND_DEFAULT = "default";
String VALUE_THEME_BACKGROUND_SOLID = "solid";
String VALUE_THEME_BACKGROUND_TRANSPARENT = "transparent";
public static final String VALUE_THEME_NAME_TWIDERE = "twidere";
public static final String VALUE_THEME_NAME_DARK = "dark";
public static final String VALUE_THEME_NAME_LIGHT = "light";
String VALUE_THEME_NAME_TWIDERE = "twidere";
String VALUE_THEME_NAME_DARK = "dark";
String VALUE_THEME_NAME_LIGHT = "light";
public static final String VALUE_PROFILE_IMAGE_STYLE_ROUND = "round";
public static final String VALUE_PROFILE_IMAGE_STYLE_SQUARE = "square";
String VALUE_PROFILE_IMAGE_STYLE_ROUND = "round";
String VALUE_PROFILE_IMAGE_STYLE_SQUARE = "square";
public static final String VALUE_COMPOSE_NOW_ACTION_COMPOSE = "compose";
public static final String VALUE_COMPOSE_NOW_ACTION_TAKE_PHOTO = "take_photo";
public static final String VALUE_COMPOSE_NOW_ACTION_PICK_IMAGE = "pick_image";
String VALUE_COMPOSE_NOW_ACTION_COMPOSE = "compose";
String VALUE_COMPOSE_NOW_ACTION_TAKE_PHOTO = "take_photo";
String VALUE_COMPOSE_NOW_ACTION_PICK_IMAGE = "pick_image";
public static final String VALUE_CARD_HIGHLIGHT_OPTION_NONE = VALUE_NONE;
public static final String VALUE_CARD_HIGHLIGHT_OPTION_BACKGROUND = "background";
public static final String VALUE_CARD_HIGHLIGHT_OPTION_LINE = "line";
String VALUE_CARD_HIGHLIGHT_OPTION_NONE = VALUE_NONE;
String VALUE_CARD_HIGHLIGHT_OPTION_BACKGROUND = "background";
String VALUE_CARD_HIGHLIGHT_OPTION_LINE = "line";
public static final int VALUE_CARD_HIGHLIGHT_OPTION_CODE_NONE = 0x0;
public static final int VALUE_CARD_HIGHLIGHT_OPTION_CODE_BACKGROUND = 0x1;
public static final int VALUE_CARD_HIGHLIGHT_OPTION_CODE_LINE = 0x2;
int VALUE_CARD_HIGHLIGHT_OPTION_CODE_NONE = 0x0;
int VALUE_CARD_HIGHLIGHT_OPTION_CODE_BACKGROUND = 0x1;
int VALUE_CARD_HIGHLIGHT_OPTION_CODE_LINE = 0x2;
public static final String DEFAULT_THEME = VALUE_THEME_NAME_TWIDERE;
public static final String DEFAULT_THEME_BACKGROUND = VALUE_THEME_BACKGROUND_DEFAULT;
public static final String DEFAULT_THEME_FONT_FAMILY = VALUE_THEME_FONT_FAMILY_REGULAR;
public static final int DEFAULT_THEME_BACKGROUND_ALPHA = 160;
String DEFAULT_THEME = VALUE_THEME_NAME_TWIDERE;
String DEFAULT_THEME_BACKGROUND = VALUE_THEME_BACKGROUND_DEFAULT;
String DEFAULT_THEME_FONT_FAMILY = VALUE_THEME_FONT_FAMILY_REGULAR;
int DEFAULT_THEME_BACKGROUND_ALPHA = 160;
public static final String DEFAULT_QUOTE_FORMAT = "RT @" + FORMAT_PATTERN_NAME + ": " + FORMAT_PATTERN_TEXT;
public static final String DEFAULT_SHARE_FORMAT = FORMAT_PATTERN_TITLE + " - " + FORMAT_PATTERN_TEXT;
public static final String DEFAULT_IMAGE_UPLOAD_FORMAT = FORMAT_PATTERN_TEXT + " " + FORMAT_PATTERN_LINK;
String DEFAULT_QUOTE_FORMAT = "RT @" + FORMAT_PATTERN_NAME + ": " + FORMAT_PATTERN_TEXT;
String DEFAULT_SHARE_FORMAT = FORMAT_PATTERN_TITLE + " - " + FORMAT_PATTERN_TEXT;
String DEFAULT_IMAGE_UPLOAD_FORMAT = FORMAT_PATTERN_TEXT + " " + FORMAT_PATTERN_LINK;
public static final String DEFAULT_REFRESH_INTERVAL = "15";
public static final boolean DEFAULT_AUTO_REFRESH = true;
public static final boolean DEFAULT_AUTO_REFRESH_HOME_TIMELINE = false;
public static final boolean DEFAULT_AUTO_REFRESH_MENTIONS = true;
public static final boolean DEFAULT_AUTO_REFRESH_DIRECT_MESSAGES = true;
public static final boolean DEFAULT_AUTO_REFRESH_TRENDS = false;
public static final boolean DEFAULT_NOTIFICATION = true;
public static final int DEFAULT_NOTIFICATION_TYPE_HOME = VALUE_NOTIFICATION_FLAG_NONE;
public static final int DEFAULT_NOTIFICATION_TYPE_MENTIONS = VALUE_NOTIFICATION_FLAG_VIBRATION
String DEFAULT_REFRESH_INTERVAL = "15";
boolean DEFAULT_AUTO_REFRESH = true;
boolean DEFAULT_AUTO_REFRESH_HOME_TIMELINE = false;
boolean DEFAULT_AUTO_REFRESH_MENTIONS = true;
boolean DEFAULT_AUTO_REFRESH_DIRECT_MESSAGES = true;
boolean DEFAULT_AUTO_REFRESH_TRENDS = false;
boolean DEFAULT_NOTIFICATION = true;
int DEFAULT_NOTIFICATION_TYPE_HOME = VALUE_NOTIFICATION_FLAG_NONE;
int DEFAULT_NOTIFICATION_TYPE_MENTIONS = VALUE_NOTIFICATION_FLAG_VIBRATION
| VALUE_NOTIFICATION_FLAG_LIGHT;
public static final int DEFAULT_NOTIFICATION_TYPE_DIRECT_MESSAGES = VALUE_NOTIFICATION_FLAG_RINGTONE
int DEFAULT_NOTIFICATION_TYPE_DIRECT_MESSAGES = VALUE_NOTIFICATION_FLAG_RINGTONE
| VALUE_NOTIFICATION_FLAG_VIBRATION | VALUE_NOTIFICATION_FLAG_LIGHT;
public static final boolean DEFAULT_HOME_TIMELINE_NOTIFICATION = false;
public static final boolean DEFAULT_MENTIONS_NOTIFICATION = true;
public static final boolean DEFAULT_DIRECT_MESSAGES_NOTIFICATION = true;
boolean DEFAULT_HOME_TIMELINE_NOTIFICATION = false;
boolean DEFAULT_MENTIONS_NOTIFICATION = true;
boolean DEFAULT_DIRECT_MESSAGES_NOTIFICATION = true;
public static final int DEFAULT_DATABASE_ITEM_LIMIT = 100;
public static final int DEFAULT_LOAD_ITEM_LIMIT = 20;
public static final String DEFAULT_CARD_HIGHLIGHT_OPTION = VALUE_CARD_HIGHLIGHT_OPTION_BACKGROUND;
int DEFAULT_DATABASE_ITEM_LIMIT = 100;
int DEFAULT_LOAD_ITEM_LIMIT = 20;
String DEFAULT_CARD_HIGHLIGHT_OPTION = VALUE_CARD_HIGHLIGHT_OPTION_BACKGROUND;
@Preference(type = INT, hasDefault = true, defaultInt = DEFAULT_DATABASE_ITEM_LIMIT)
public static final String KEY_DATABASE_ITEM_LIMIT = "database_item_limit";
String KEY_DATABASE_ITEM_LIMIT = "database_item_limit";
@Preference(type = INT, hasDefault = true, defaultInt = DEFAULT_LOAD_ITEM_LIMIT)
public static final String KEY_LOAD_ITEM_LIMIT = "load_item_limit";
String KEY_LOAD_ITEM_LIMIT = "load_item_limit";
@Preference(type = INT, hasDefault = true, defaultInt = 15)
public static final String KEY_TEXT_SIZE = "text_size_int";
String KEY_TEXT_SIZE = "text_size_int";
@Preference(type = STRING, hasDefault = true, defaultString = DEFAULT_THEME)
public static final String KEY_THEME = "theme";
String KEY_THEME = "theme";
@Preference(type = STRING, hasDefault = true, defaultString = DEFAULT_THEME_BACKGROUND)
public static final String KEY_THEME_BACKGROUND = "theme_background";
String KEY_THEME_BACKGROUND = "theme_background";
@Preference(type = INT, hasDefault = true, defaultInt = DEFAULT_THEME_BACKGROUND_ALPHA)
public static final String KEY_THEME_BACKGROUND_ALPHA = "theme_background_alpha";
String KEY_THEME_BACKGROUND_ALPHA = "theme_background_alpha";
@Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = true)
public static final String KEY_THEME_DARK_ACTIONBAR = "theme_dark_actionbar";
String KEY_THEME_DARK_ACTIONBAR = "theme_dark_actionbar";
@Preference(type = INT)
public static final String KEY_THEME_COLOR = "theme_color";
String KEY_THEME_COLOR = "theme_color";
@Preference(type = STRING, hasDefault = true, defaultString = DEFAULT_THEME_FONT_FAMILY)
public static final String KEY_THEME_FONT_FAMILY = "theme_font_family";
String KEY_THEME_FONT_FAMILY = "theme_font_family";
@Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = true)
public static final String KEY_DISPLAY_PROFILE_IMAGE = "display_profile_image";
String KEY_DISPLAY_PROFILE_IMAGE = "display_profile_image";
@Preference(type = BOOLEAN)
public static final String KEY_LEFTSIDE_COMPOSE_BUTTON = "leftside_compose_button";
String KEY_LEFTSIDE_COMPOSE_BUTTON = "leftside_compose_button";
@Preference(type = BOOLEAN)
public static final String KEY_ATTACH_LOCATION = "attach_location";
String KEY_ATTACH_LOCATION = "attach_location";
@Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = true)
public static final String KEY_GZIP_COMPRESSING = "gzip_compressing";
String KEY_GZIP_COMPRESSING = "gzip_compressing";
@Preference(type = BOOLEAN)
public static final String KEY_IGNORE_SSL_ERROR = "ignore_ssl_error";
String KEY_IGNORE_SSL_ERROR = "ignore_ssl_error";
@Preference(type = BOOLEAN)
public static final String KEY_LOAD_MORE_AUTOMATICALLY = "load_more_automatically";
String KEY_LOAD_MORE_AUTOMATICALLY = "load_more_automatically";
@Preference(type = STRING)
public static final String KEY_QUOTE_FORMAT = "quote_format";
String KEY_QUOTE_FORMAT = "quote_format";
@Preference(type = BOOLEAN)
public static final String KEY_REMEMBER_POSITION = "remember_position";
String KEY_REMEMBER_POSITION = "remember_position";
@Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = false)
public static final String KEY_READ_FROM_BOTTOM = "read_from_bottom";
String KEY_READ_FROM_BOTTOM = "read_from_bottom";
@Preference(type = INT, exportable = false)
public static final String KEY_SAVED_TAB_POSITION = "saved_tab_position";
String KEY_SAVED_TAB_POSITION = "saved_tab_position";
@Preference(type = BOOLEAN)
public static final String KEY_ENABLE_PROXY = "enable_proxy";
String KEY_ENABLE_PROXY = "enable_proxy";
@Preference(type = STRING)
public static final String KEY_PROXY_HOST = "proxy_host";
String KEY_PROXY_HOST = "proxy_host";
@Preference(type = STRING)
public static final String KEY_PROXY_PORT = "proxy_port";
String KEY_PROXY_PORT = "proxy_port";
@Preference(type = BOOLEAN)
public static final String KEY_REFRESH_ON_START = "refresh_on_start";
String KEY_REFRESH_ON_START = "refresh_on_start";
@Preference(type = BOOLEAN)
public static final String KEY_REFRESH_AFTER_TWEET = "refresh_after_tweet";
String KEY_REFRESH_AFTER_TWEET = "refresh_after_tweet";
@Preference(type = BOOLEAN)
public static final String KEY_AUTO_REFRESH = "auto_refresh";
String KEY_AUTO_REFRESH = "auto_refresh";
@Preference(type = STRING)
public static final String KEY_REFRESH_INTERVAL = "refresh_interval";
String KEY_REFRESH_INTERVAL = "refresh_interval";
@Preference(type = BOOLEAN)
public static final String KEY_AUTO_REFRESH_HOME_TIMELINE = "auto_refresh_home_timeline";
String KEY_AUTO_REFRESH_HOME_TIMELINE = "auto_refresh_home_timeline";
@Preference(type = BOOLEAN)
public static final String KEY_AUTO_REFRESH_MENTIONS = "auto_refresh_mentions";
String KEY_AUTO_REFRESH_MENTIONS = "auto_refresh_mentions";
@Preference(type = BOOLEAN)
public static final String KEY_AUTO_REFRESH_DIRECT_MESSAGES = "auto_refresh_direct_messages";
String KEY_AUTO_REFRESH_DIRECT_MESSAGES = "auto_refresh_direct_messages";
@Preference(type = BOOLEAN)
public static final String KEY_AUTO_REFRESH_TRENDS = "auto_refresh_trends";
String KEY_AUTO_REFRESH_TRENDS = "auto_refresh_trends";
@Preference(type = BOOLEAN)
public static final String KEY_HOME_TIMELINE_NOTIFICATION = "home_timeline_notification";
String KEY_HOME_TIMELINE_NOTIFICATION = "home_timeline_notification";
@Preference(type = BOOLEAN)
public static final String KEY_MENTIONS_NOTIFICATION = "mentions_notification";
String KEY_MENTIONS_NOTIFICATION = "mentions_notification";
@Preference(type = BOOLEAN)
public static final String KEY_DIRECT_MESSAGES_NOTIFICATION = "direct_messages_notification";
String KEY_DIRECT_MESSAGES_NOTIFICATION = "direct_messages_notification";
@Preference(type = INT)
public static final String KEY_LOCAL_TRENDS_WOEID = "local_trends_woeid";
public static final String KEY_NOTIFICATION_RINGTONE = "notification_ringtone";
public static final String KEY_NOTIFICATION_LIGHT_COLOR = "notification_light_color";
public static final String KEY_SHARE_FORMAT = "share_format";
public static final String KEY_HOME_REFRESH_MENTIONS = "home_refresh_mentions";
public static final String KEY_HOME_REFRESH_DIRECT_MESSAGES = "home_refresh_direct_messages";
public static final String KEY_HOME_REFRESH_TRENDS = "home_refresh_trends";
public static final String KEY_IMAGE_UPLOAD_FORMAT = "image_upload_format";
public static final String KEY_STATUS_SHORTENER = "status_shortener";
public static final String KEY_MEDIA_UPLOADER = "media_uploader";
String KEY_LOCAL_TRENDS_WOEID = "local_trends_woeid";
String KEY_NOTIFICATION_RINGTONE = "notification_ringtone";
String KEY_NOTIFICATION_LIGHT_COLOR = "notification_light_color";
String KEY_SHARE_FORMAT = "share_format";
String KEY_HOME_REFRESH_MENTIONS = "home_refresh_mentions";
String KEY_HOME_REFRESH_DIRECT_MESSAGES = "home_refresh_direct_messages";
String KEY_HOME_REFRESH_TRENDS = "home_refresh_trends";
String KEY_IMAGE_UPLOAD_FORMAT = "image_upload_format";
String KEY_STATUS_SHORTENER = "status_shortener";
String KEY_MEDIA_UPLOADER = "media_uploader";
@Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = false)
public static final String KEY_SHOW_ABSOLUTE_TIME = "show_absolute_time";
String KEY_SHOW_ABSOLUTE_TIME = "show_absolute_time";
@Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = false)
public static final String KEY_QUICK_SEND = "quick_send";
String KEY_QUICK_SEND = "quick_send";
@Preference(type = STRING, exportable = false)
public static final String KEY_COMPOSE_ACCOUNTS = "compose_accounts";
String KEY_COMPOSE_ACCOUNTS = "compose_accounts";
@Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = false)
public static final String KEY_TCP_DNS_QUERY = "tcp_dns_query";
String KEY_TCP_DNS_QUERY = "tcp_dns_query";
@Preference(type = STRING, hasDefault = true, defaultString = "8.8.8.8")
public static final String KEY_DNS_SERVER = "dns_server";
public static final String KEY_CONNECTION_TIMEOUT = "connection_timeout";
String KEY_DNS_SERVER = "dns_server";
String KEY_CONNECTION_TIMEOUT = "connection_timeout";
@Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = true)
public static final String KEY_NAME_FIRST = "name_first";
public static final String KEY_STOP_AUTO_REFRESH_WHEN_BATTERY_LOW = "stop_auto_refresh_when_battery_low";
String KEY_NAME_FIRST = "name_first";
String KEY_STOP_AUTO_REFRESH_WHEN_BATTERY_LOW = "stop_auto_refresh_when_battery_low";
@Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = false)
public static final String KEY_DISPLAY_SENSITIVE_CONTENTS = "display_sensitive_contents";
String KEY_DISPLAY_SENSITIVE_CONTENTS = "display_sensitive_contents";
@Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = true)
public static final String KEY_PHISHING_LINK_WARNING = "phishing_link_warning";
String KEY_PHISHING_LINK_WARNING = "phishing_link_warning";
@Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = false)
public static final String KEY_FAST_SCROLL_THUMB = "fast_scroll_thumb";
public static final String KEY_LINK_HIGHLIGHT_OPTION = "link_highlight_option";
String KEY_FAST_SCROLL_THUMB = "fast_scroll_thumb";
String KEY_LINK_HIGHLIGHT_OPTION = "link_highlight_option";
@Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = true)
public static final String KEY_INDICATE_MY_STATUS = "indicate_my_status";
public static final String KEY_PRELOAD_PROFILE_IMAGES = "preload_profile_images";
public static final String KEY_PRELOAD_PREVIEW_IMAGES = "preload_preview_images";
String KEY_INDICATE_MY_STATUS = "indicate_my_status";
String KEY_PRELOAD_PROFILE_IMAGES = "preload_profile_images";
String KEY_PRELOAD_PREVIEW_IMAGES = "preload_preview_images";
@Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = true)
public static final String KEY_PRELOAD_WIFI_ONLY = "preload_wifi_only";
String KEY_PRELOAD_WIFI_ONLY = "preload_wifi_only";
@Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = true)
public static final String KEY_LINK_TO_QUOTED_TWEET = "link_to_quoted_tweet";
String KEY_LINK_TO_QUOTED_TWEET = "link_to_quoted_tweet";
@Preference(type = BOOLEAN)
public static final String KEY_BACKGROUND_TOAST_NOTIFICATION = "background_toast_notification";
String KEY_BACKGROUND_TOAST_NOTIFICATION = "background_toast_notification";
@Preference(type = STRING)
public static final String KEY_COMPOSE_QUIT_ACTION = "compose_quit_action";
String KEY_COMPOSE_QUIT_ACTION = "compose_quit_action";
@Preference(type = BOOLEAN)
public static final String KEY_NO_CLOSE_AFTER_TWEET_SENT = "no_close_after_tweet_sent";
String KEY_NO_CLOSE_AFTER_TWEET_SENT = "no_close_after_tweet_sent";
@Preference(type = BOOLEAN)
public static final String KEY_FAST_IMAGE_LOADING = "fast_image_loading";
String KEY_FAST_IMAGE_LOADING = "fast_image_loading";
@Preference(type = STRING, hasDefault = false)
public static final String KEY_API_URL_FORMAT = "api_url_format";
String KEY_API_URL_FORMAT = "api_url_format";
@Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = false)
public static final String KEY_SAME_OAUTH_SIGNING_URL = "same_oauth_signing_url";
String KEY_SAME_OAUTH_SIGNING_URL = "same_oauth_signing_url";
@Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = false)
public static final String KEY_NO_VERSION_SUFFIX = "no_version_suffix";
String KEY_NO_VERSION_SUFFIX = "no_version_suffix";
@Preference(type = INT, hasDefault = true, defaultInt = Accounts.AUTH_TYPE_OAUTH)
public static final String KEY_AUTH_TYPE = "auth_type";
String KEY_AUTH_TYPE = "auth_type";
@Preference(type = STRING, hasDefault = true, defaultString = TwidereConstants.TWITTER_CONSUMER_KEY_3)
public static final String KEY_CONSUMER_KEY = "consumer_key";
String KEY_CONSUMER_KEY = "consumer_key";
@Preference(type = STRING, hasDefault = true, defaultString = TwidereConstants.TWITTER_CONSUMER_SECRET_3)
public static final String KEY_CONSUMER_SECRET = "consumer_secret";
public static final String KEY_FILTERS_IN_HOME_TIMELINE = "filters_in_home_timeline";
public static final String KEY_FILTERS_IN_MENTIONS_TIMELINE = "filters_in_mentions";
public static final String KEY_FILTERS_FOR_RTS = "filters_for_rts";
public static final String KEY_SETTINGS_WIZARD_COMPLETED = "settings_wizard_completed";
String KEY_CONSUMER_SECRET = "consumer_secret";
String KEY_FILTERS_IN_HOME_TIMELINE = "filters_in_home_timeline";
String KEY_FILTERS_IN_MENTIONS_TIMELINE = "filters_in_mentions";
String KEY_FILTERS_FOR_RTS = "filters_for_rts";
String KEY_SETTINGS_WIZARD_COMPLETED = "settings_wizard_completed";
@Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = true)
public static final String KEY_CARD_ANIMATION = "card_animation";
public static final String KEY_UNREAD_COUNT = "unread_count";
public static final String KEY_NOTIFICATION = "notification";
public static final String KEY_NOTIFICATION_TYPE_HOME = "notification_type_home";
public static final String KEY_NOTIFICATION_TYPE_MENTIONS = "notification_type_mentions";
public static final String KEY_NOTIFICATION_TYPE_DIRECT_MESSAGES = "notification_type_direct_messages";
public static final String KEY_NOTIFICATION_FOLLOWING_ONLY = "notification_following_only";
String KEY_CARD_ANIMATION = "card_animation";
String KEY_UNREAD_COUNT = "unread_count";
String KEY_NOTIFICATION = "notification";
String KEY_NOTIFICATION_TYPE_HOME = "notification_type_home";
String KEY_NOTIFICATION_TYPE_MENTIONS = "notification_type_mentions";
String KEY_NOTIFICATION_TYPE_DIRECT_MESSAGES = "notification_type_direct_messages";
String KEY_NOTIFICATION_FOLLOWING_ONLY = "notification_following_only";
@Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = false)
public static final String KEY_COMPACT_CARDS = "compact_cards";
String KEY_COMPACT_CARDS = "compact_cards";
@Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = false)
public static final String KEY_FORCE_USING_PRIVATE_APIS = "force_using_private_apis";
String KEY_FORCE_USING_PRIVATE_APIS = "force_using_private_apis";
@Preference(type = STRING, hasDefault = true, defaultString = "140")
public static final String KEY_STATUS_TEXT_LIMIT = "status_text_limit";
String KEY_STATUS_TEXT_LIMIT = "status_text_limit";
@Preference(type = STRING, hasDefault = true, defaultString = VALUE_COMPOSE_NOW_ACTION_COMPOSE)
public static final String KEY_COMPOSE_NOW_ACTION = "compose_now_action";
public static final String KEY_FALLBACK_TWITTER_LINK_HANDLER = "fallback_twitter_link_handler";
String KEY_COMPOSE_NOW_ACTION = "compose_now_action";
String KEY_FALLBACK_TWITTER_LINK_HANDLER = "fallback_twitter_link_handler";
@Preference(type = STRING, hasDefault = true, defaultString = VALUE_MEDIA_PREVIEW_STYLE_CROP)
public static final String KEY_MEDIA_PREVIEW_STYLE = "media_preview_style";
String KEY_MEDIA_PREVIEW_STYLE = "media_preview_style";
@Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = false)
public static final String KEY_MEDIA_PREVIEW = "media_preview";
String KEY_MEDIA_PREVIEW = "media_preview";
@Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = false)
public static final String KEY_SORT_TIMELINE_BY_ID = "sort_timeline_by_id";
String KEY_SORT_TIMELINE_BY_ID = "sort_timeline_by_id";
@Preference(type = STRING, hasDefault = true)
public static final String KEY_PROFILE_IMAGE_STYLE = "profile_image_style";
String KEY_PROFILE_IMAGE_STYLE = "profile_image_style";
public static final String KEY_QUICK_MENU_EXPANDED = "quick_menu_expanded";
String KEY_QUICK_MENU_EXPANDED = "quick_menu_expanded";
@Preference(type = STRING)
public static final String KEY_TRANSLATION_DESTINATION = "translation_destination";
String KEY_TRANSLATION_DESTINATION = "translation_destination";
@Preference(type = STRING)
public static final String KEY_TAB_DISPLAY_OPTION = "tab_display_option";
String KEY_TAB_DISPLAY_OPTION = "tab_display_option";
@Preference(type = STRING)
public static final String KEY_CARD_HIGHLIGHT_OPTION = "card_highlight_option";
String KEY_CARD_HIGHLIGHT_OPTION = "card_highlight_option";
@Preference(type = INT, exportable = false)
public static final String KEY_LIVE_WALLPAPER_SCALE = "live_wallpaper_scale";
String KEY_LIVE_WALLPAPER_SCALE = "live_wallpaper_scale";
@Preference(type = LONG, exportable = false)
public static final String KEY_API_LAST_CHANGE = "api_last_change";
String KEY_API_LAST_CHANGE = "api_last_change";
@Preference(type = LONG, exportable = false)
public static final String KEY_DEFAULT_ACCOUNT_ID = "default_account_id";
String KEY_DEFAULT_ACCOUNT_ID = "default_account_id";
@Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = false)
String KEY_THUMBOR_ENABLED = "thumbor_enabled";
String KEY_THUMBOR_ADDRESS = "thumbor_address";
String KEY_THUMBOR_SECURITY_KEY = "thumbor_security_key";
}

View File

@ -92,7 +92,7 @@ public class ParcelableStatus implements TwidereParcelable, Comparable<Parcelabl
};
public final long id, account_id, timestamp, user_id, retweet_id, retweeted_by_id, retweet_timestamp,
retweet_count, favorite_count, reply_count, descendent_reply_count, in_reply_to_status_id,
in_reply_to_user_id, my_retweet_id;
in_reply_to_user_id, my_retweet_id, quote_id, quote_timestamp, quoted_by_user_id;
public static final Comparator<ParcelableStatus> REVERSE_ID_COMPARATOR = new Comparator<ParcelableStatus>() {
@Override
@ -104,11 +104,12 @@ public class ParcelableStatus implements TwidereParcelable, Comparable<Parcelabl
}
};
public final boolean is_gap, is_retweet, is_favorite, is_possibly_sensitive, user_is_following, user_is_protected,
user_is_verified;
user_is_verified, is_quote;
public final String retweeted_by_name, retweeted_by_screen_name, retweeted_by_profile_image,
text_html, text_plain, user_name, user_screen_name, in_reply_to_name, in_reply_to_screen_name,
source, user_profile_image_url, text_unescaped, card_name;
source, user_profile_image_url, text_unescaped, card_name, quote_text_html, quote_text_plain,
quote_text_unescaped, quoted_by_user_name, quoted_by_user_screen_name, quoted_by_user_profile_image;
public final ParcelableLocation location;
@ -159,6 +160,16 @@ public class ParcelableStatus implements TwidereParcelable, Comparable<Parcelabl
mentions = SimpleValueSerializer.fromSerializedString(values.getAsString(Statuses.MENTIONS_LIST), ParcelableUserMention.SIMPLE_CREATOR);
card = ParcelableCardEntity.fromJSONString(values.getAsString(Statuses.CARD));
place_full_name = values.getAsString(Statuses.PLACE_FULL_NAME);
is_quote = ContentValuesUtils.getAsBoolean(values, Statuses.IS_QUOTE, false);
quote_id = ContentValuesUtils.getAsLong(values, Statuses.QUOTE_ID, -1);
quote_timestamp = ContentValuesUtils.getAsLong(values, Statuses.QUOTE_TIMESTAMP, -1);
quote_text_html = values.getAsString(Statuses.QUOTE_TEXT_HTML);
quote_text_plain = values.getAsString(Statuses.QUOTE_TEXT_PLAIN);
quote_text_unescaped = values.getAsString(Statuses.QUOTE_TEXT_UNESCAPED);
quoted_by_user_id = ContentValuesUtils.getAsLong(values, Statuses.QUOTED_BY_USER_ID, -1);
quoted_by_user_name = values.getAsString(Statuses.QUOTED_BY_USER_NAME);
quoted_by_user_screen_name = values.getAsString(Statuses.QUOTED_BY_USER_SCREEN_NAME);
quoted_by_user_profile_image = values.getAsString(Statuses.QUOTED_BY_USER_PROFILE_IMAGE);
card_name = card != null ? card.name : null;
}
@ -204,6 +215,16 @@ public class ParcelableStatus implements TwidereParcelable, Comparable<Parcelabl
mentions = idx.mentions != -1 ? ParcelableUserMention.fromJSONString(c.getString(idx.mentions)) : null;
card = idx.card != -1 ? ParcelableCardEntity.fromJSONString(c.getString(idx.card)) : null;
place_full_name = idx.place_full_name != -1 ? c.getString(idx.place_full_name) : null;
is_quote = idx.is_quote != -1 && c.getShort(idx.is_quote) == 1;
quote_id = idx.quote_id != -1 ? c.getLong(idx.quote_id) : -1;
quote_timestamp = idx.quote_timestamp != -1 ? c.getLong(idx.quote_timestamp) : -1;
quoted_by_user_id = idx.quoted_by_user_id != -1 ? c.getLong(idx.quoted_by_user_id) : -1;
quote_text_html = idx.quote_text_html != -1 ? c.getString(idx.quote_text_html) : null;
quote_text_plain = idx.quote_text_plain != -1 ? c.getString(idx.quote_text_plain) : null;
quote_text_unescaped = idx.quote_text_unescaped != -1 ? c.getString(idx.quote_text_unescaped) : null;
quoted_by_user_name = idx.quoted_by_user_name != -1 ? c.getString(idx.quoted_by_user_name) : null;
quoted_by_user_screen_name = idx.quoted_by_user_screen_name != -1 ? c.getString(idx.quoted_by_user_screen_name) : null;
quoted_by_user_profile_image = idx.quoted_by_user_profile_image != -1 ? c.getString(idx.quoted_by_user_profile_image) : null;
card_name = card != null ? card.name : null;
}
@ -246,6 +267,16 @@ public class ParcelableStatus implements TwidereParcelable, Comparable<Parcelabl
mentions = in.readParcelableArray("mentions", ParcelableUserMention.JSON_CREATOR);
card = in.readParcelable("card", ParcelableCardEntity.JSON_CREATOR);
place_full_name = in.readString("place_full_name");
is_quote = in.readBoolean("is_quote");
quote_id = in.readLong("quote_id");
quote_text_html = in.readString("quote_text_html");
quote_text_plain = in.readString("quote_text_plain");
quote_text_unescaped = in.readString("quote_text_unescaped");
quote_timestamp = in.readLong("quote_timestamp");
quoted_by_user_id = in.readLong("quoted_by_user_id");
quoted_by_user_name = in.readString("quoted_by_user_name");
quoted_by_user_screen_name = in.readString("quoted_by_user_screen_name");
quoted_by_user_profile_image = in.readString("quoted_by_user_profile_image");
card_name = card != null ? card.name : null;
}
@ -262,11 +293,11 @@ public class ParcelableStatus implements TwidereParcelable, Comparable<Parcelabl
reply_count = in.readLong();
descendent_reply_count = in.readLong();
in_reply_to_status_id = in.readLong();
is_gap = in.readInt() == 1;
is_retweet = in.readInt() == 1;
is_favorite = in.readInt() == 1;
user_is_protected = in.readInt() == 1;
user_is_verified = in.readInt() == 1;
is_gap = in.readByte() == 1;
is_retweet = in.readByte() == 1;
is_favorite = in.readByte() == 1;
user_is_protected = in.readByte() == 1;
user_is_verified = in.readByte() == 1;
retweeted_by_name = in.readString();
retweeted_by_screen_name = in.readString();
retweeted_by_profile_image = in.readString();
@ -280,14 +311,24 @@ public class ParcelableStatus implements TwidereParcelable, Comparable<Parcelabl
media = in.createTypedArray(ParcelableMedia.CREATOR);
location = in.readParcelable(ParcelableLocation.class.getClassLoader());
my_retweet_id = in.readLong();
is_possibly_sensitive = in.readInt() == 1;
user_is_following = in.readInt() == 1;
is_possibly_sensitive = in.readByte() == 1;
user_is_following = in.readByte() == 1;
text_unescaped = in.readString();
in_reply_to_user_id = in.readLong();
in_reply_to_name = in.readString();
mentions = in.createTypedArray(ParcelableUserMention.CREATOR);
card = in.readParcelable(ParcelableCardEntity.class.getClassLoader());
place_full_name = in.readString();
is_quote = in.readByte() == 1;
quote_id = in.readLong();
quote_text_html = in.readString();
quote_text_plain = in.readString();
quote_text_unescaped = in.readString();
quote_timestamp = in.readLong();
quoted_by_user_id = in.readLong();
quoted_by_user_name = in.readString();
quoted_by_user_screen_name = in.readString();
quoted_by_user_profile_image = in.readString();
card_name = card != null ? card.name : null;
}
@ -331,9 +372,119 @@ public class ParcelableStatus implements TwidereParcelable, Comparable<Parcelabl
mentions = orig.mentions;
card = orig.card;
place_full_name = orig.place_full_name;
is_quote = orig.is_quote;
quote_id = orig.quote_id;
quote_timestamp = orig.quote_timestamp;
quoted_by_user_id = orig.quoted_by_user_id;
quoted_by_user_name = orig.quoted_by_user_name;
quoted_by_user_screen_name = orig.quoted_by_user_screen_name;
quoted_by_user_profile_image = orig.quoted_by_user_profile_image;
quote_text_html = orig.quote_text_html;
quote_text_plain = orig.quote_text_plain;
quote_text_unescaped = orig.quote_text_unescaped;
card_name = card != null ? card.name : null;
}
public ParcelableStatus(final Status orig, final long account_id, final boolean is_gap) {
this.is_gap = is_gap;
this.account_id = account_id;
id = orig.getId();
timestamp = getTime(orig.getCreatedAt());
final Status retweeted = orig.getRetweetedStatus();
final User retweet_user = retweeted != null ? orig.getUser() : null;
is_retweet = orig.isRetweet();
retweet_id = retweeted != null ? retweeted.getId() : -1;
retweet_timestamp = retweeted != null ? getTime(retweeted.getCreatedAt()) : -1;
retweeted_by_id = retweet_user != null ? retweet_user.getId() : -1;
retweeted_by_name = retweet_user != null ? retweet_user.getName() : null;
retweeted_by_screen_name = retweet_user != null ? retweet_user.getScreenName() : null;
retweeted_by_profile_image = retweet_user != null ?
ParseUtils.parseString(retweet_user.getProfileImageUrlHttps()) : null;
final Status quoted = orig.getQuotedStatus();
final User quote_user = quoted != null ? orig.getUser() : null;
is_quote = orig.isQuote();
quote_id = quoted != null ? quoted.getId() : -1;
quote_text_html = TwitterContentUtils.formatStatusText(orig);
quote_text_plain = orig.getText();
quote_text_unescaped = HtmlEscapeHelper.toPlainText(quote_text_html);
quote_timestamp = quoted != null ? quoted.getCreatedAt().getTime() : -1;
quoted_by_user_id = quote_user != null ? quote_user.getId() : -1;
quoted_by_user_name = quote_user != null ? quote_user.getName() : null;
quoted_by_user_screen_name = quote_user != null ? quote_user.getScreenName() : null;
quoted_by_user_profile_image = quote_user != null ? ParseUtils.parseString(quote_user.getProfileImageUrlHttps()) : null;
final Status status;
if (quoted != null) {
status = quoted;
} else if (retweeted != null) {
status = retweeted;
} else {
status = orig;
}
final User user = status.getUser();
user_id = user.getId();
user_name = user.getName();
user_screen_name = user.getScreenName();
user_profile_image_url = ParseUtils.parseString(user.getProfileImageUrlHttps());
user_is_protected = user.isProtected();
user_is_verified = user.isVerified();
user_is_following = user.isFollowing();
text_html = TwitterContentUtils.formatStatusText(status);
media = ParcelableMedia.fromEntities(status);
text_plain = status.getText();
retweet_count = status.getRetweetCount();
favorite_count = status.getFavoriteCount();
reply_count = status.getReplyCount();
descendent_reply_count = status.getDescendentReplyCount();
in_reply_to_name = TwitterContentUtils.getInReplyToName(status);
in_reply_to_screen_name = status.getInReplyToScreenName();
in_reply_to_status_id = status.getInReplyToStatusId();
in_reply_to_user_id = status.getInReplyToUserId();
source = status.getSource();
location = ParcelableLocation.fromGeoLocation(status.getGeoLocation());
is_favorite = status.isFavorited();
text_unescaped = HtmlEscapeHelper.toPlainText(text_html);
my_retweet_id = retweeted_by_id == account_id ? id : status.getCurrentUserRetweet();
is_possibly_sensitive = status.isPossiblySensitive();
mentions = ParcelableUserMention.fromUserMentionEntities(status.getUserMentionEntities());
card = ParcelableCardEntity.fromCardEntity(status.getCard(), account_id);
place_full_name = getPlaceFullName(status.getPlace());
card_name = card != null ? card.name : null;
}
@Override
public int compareTo(@NonNull final ParcelableStatus another) {
final long diff = another.id - id;
if (diff > Integer.MAX_VALUE) return Integer.MAX_VALUE;
if (diff < Integer.MIN_VALUE) return Integer.MIN_VALUE;
return (int) diff;
}
@Override
public int describeContents() {
return 0;
}
@Override
public boolean equals(final Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (!(obj instanceof ParcelableStatus)) return false;
final ParcelableStatus other = (ParcelableStatus) obj;
return account_id == other.account_id && id == other.id;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) (account_id ^ account_id >>> 32);
result = prime * result + (int) (id ^ id >>> 32);
return result;
}
@Override
public String toString() {
return "ParcelableStatus{" +
@ -378,90 +529,6 @@ public class ParcelableStatus implements TwidereParcelable, Comparable<Parcelabl
'}';
}
public ParcelableStatus(final Status orig, final long account_id, final boolean is_gap) {
this.is_gap = is_gap;
this.account_id = account_id;
id = orig.getId();
timestamp = getTime(orig.getCreatedAt());
is_retweet = orig.isRetweet();
final Status retweeted = orig.getRetweetedStatus();
final User retweet_user = retweeted != null ? orig.getUser() : null;
retweet_id = retweeted != null ? retweeted.getId() : -1;
retweet_timestamp = retweeted != null ? getTime(retweeted.getCreatedAt()) : -1;
retweeted_by_id = retweet_user != null ? retweet_user.getId() : -1;
retweeted_by_name = retweet_user != null ? retweet_user.getName() : null;
retweeted_by_screen_name = retweet_user != null ? retweet_user.getScreenName() : null;
retweeted_by_profile_image = retweet_user != null ?
ParseUtils.parseString(retweet_user.getProfileImageUrlHttps()) : null;
final Status status = retweeted != null ? retweeted : orig;
final User user = status.getUser();
user_id = user.getId();
user_name = user.getName();
user_screen_name = user.getScreenName();
user_profile_image_url = ParseUtils.parseString(user.getProfileImageUrlHttps());
user_is_protected = user.isProtected();
user_is_verified = user.isVerified();
user_is_following = user.isFollowing();
text_html = TwitterContentUtils.formatStatusText(status);
media = ParcelableMedia.fromEntities(status);
text_plain = status.getText();
retweet_count = status.getRetweetCount();
favorite_count = status.getFavoriteCount();
reply_count = status.getReplyCount();
descendent_reply_count = status.getDescendentReplyCount();
in_reply_to_name = TwitterContentUtils.getInReplyToName(status);
in_reply_to_screen_name = status.getInReplyToScreenName();
in_reply_to_status_id = status.getInReplyToStatusId();
in_reply_to_user_id = status.getInReplyToUserId();
source = status.getSource();
location = ParcelableLocation.fromGeoLocation(status.getGeoLocation());
is_favorite = status.isFavorited();
text_unescaped = HtmlEscapeHelper.toPlainText(text_html);
my_retweet_id = retweeted_by_id == account_id ? id : status.getCurrentUserRetweet();
is_possibly_sensitive = status.isPossiblySensitive();
mentions = ParcelableUserMention.fromUserMentionEntities(status.getUserMentionEntities());
card = ParcelableCardEntity.fromCardEntity(status.getCard(), account_id);
place_full_name = getPlaceFullName(status.getPlace());
card_name = card != null ? card.name : null;
}
@Nullable
private static String getPlaceFullName(@Nullable Place place) {
if (place == null) return null;
return place.getFullName();
}
@Override
public int compareTo(@NonNull final ParcelableStatus another) {
final long diff = another.id - id;
if (diff > Integer.MAX_VALUE) return Integer.MAX_VALUE;
if (diff < Integer.MIN_VALUE) return Integer.MIN_VALUE;
return (int) diff;
}
@Override
public int describeContents() {
return 0;
}
@Override
public boolean equals(final Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (!(obj instanceof ParcelableStatus)) return false;
final ParcelableStatus other = (ParcelableStatus) obj;
return account_id == other.account_id && id == other.id;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) (account_id ^ account_id >>> 32);
result = prime * result + (int) (id ^ id >>> 32);
return result;
}
@Override
public void writeToParcel(final JSONParcel out) {
out.writeLong("status_id", id);
@ -502,6 +569,22 @@ public class ParcelableStatus implements TwidereParcelable, Comparable<Parcelabl
out.writeParcelableArray("mentions", mentions);
out.writeParcelable("card", card);
out.writeString("place_full_name", place_full_name);
out.writeBoolean("is_quote", is_quote);
out.writeLong("quote_id", quote_id);
out.writeString("quote_text_html", quote_text_html);
out.writeString("quote_text_plain", quote_text_plain);
out.writeString("quote_text_unescaped", quote_text_unescaped);
out.writeLong("quote_timestamp", quote_timestamp);
out.writeLong("quoted_by_user_id", quoted_by_user_id);
out.writeString("quoted_by_user_name", quoted_by_user_name);
out.writeString("quoted_by_user_screen_name", quoted_by_user_screen_name);
out.writeString("quoted_by_user_profile_image", quoted_by_user_profile_image);
}
@Nullable
private static String getPlaceFullName(@Nullable Place place) {
if (place == null) return null;
return place.getFullName();
}
private static long getTime(final Date date) {
@ -516,8 +599,63 @@ public class ParcelableStatus implements TwidereParcelable, Comparable<Parcelabl
in_reply_to_user_name, in_reply_to_user_screen_name, my_retweet_id, retweeted_by_user_name,
retweeted_by_user_screen_name, retweeted_by_user_profile_image, retweet_id, retweet_timestamp,
retweeted_by_user_id, user_id, source, retweet_count, favorite_count, reply_count,
descendent_reply_count, is_possibly_sensitive, is_following, media, mentions,
card_name, card, place_full_name;
descendent_reply_count, is_possibly_sensitive, is_following, media, mentions, card_name,
card, place_full_name, is_quote, quote_id, quote_text_html, quote_text_plain, quote_text_unescaped,
quote_timestamp, quoted_by_user_id, quoted_by_user_name, quoted_by_user_screen_name,
quoted_by_user_profile_image;
public CursorIndices(final Cursor cursor) {
_id = cursor.getColumnIndex(Statuses._ID);
account_id = cursor.getColumnIndex(Statuses.ACCOUNT_ID);
status_id = cursor.getColumnIndex(Statuses.STATUS_ID);
status_timestamp = cursor.getColumnIndex(Statuses.STATUS_TIMESTAMP);
user_name = cursor.getColumnIndex(Statuses.USER_NAME);
user_screen_name = cursor.getColumnIndex(Statuses.USER_SCREEN_NAME);
text_html = cursor.getColumnIndex(Statuses.TEXT_HTML);
text_plain = cursor.getColumnIndex(Statuses.TEXT_PLAIN);
text_unescaped = cursor.getColumnIndex(Statuses.TEXT_UNESCAPED);
user_profile_image_url = cursor.getColumnIndex(Statuses.USER_PROFILE_IMAGE_URL);
is_favorite = cursor.getColumnIndex(Statuses.IS_FAVORITE);
is_retweet = cursor.getColumnIndex(Statuses.IS_RETWEET);
is_quote = cursor.getColumnIndex(Statuses.IS_QUOTE);
is_gap = cursor.getColumnIndex(Statuses.IS_GAP);
location = cursor.getColumnIndex(Statuses.LOCATION);
is_protected = cursor.getColumnIndex(Statuses.IS_PROTECTED);
is_verified = cursor.getColumnIndex(Statuses.IS_VERIFIED);
in_reply_to_status_id = cursor.getColumnIndex(Statuses.IN_REPLY_TO_STATUS_ID);
in_reply_to_user_id = cursor.getColumnIndex(Statuses.IN_REPLY_TO_USER_ID);
in_reply_to_user_name = cursor.getColumnIndex(Statuses.IN_REPLY_TO_USER_NAME);
in_reply_to_user_screen_name = cursor.getColumnIndex(Statuses.IN_REPLY_TO_USER_SCREEN_NAME);
my_retweet_id = cursor.getColumnIndex(Statuses.MY_RETWEET_ID);
retweet_id = cursor.getColumnIndex(Statuses.RETWEET_ID);
retweet_timestamp = cursor.getColumnIndex(Statuses.RETWEET_TIMESTAMP);
retweeted_by_user_id = cursor.getColumnIndex(Statuses.RETWEETED_BY_USER_ID);
retweeted_by_user_name = cursor.getColumnIndex(Statuses.RETWEETED_BY_USER_NAME);
retweeted_by_user_screen_name = cursor.getColumnIndex(Statuses.RETWEETED_BY_USER_SCREEN_NAME);
retweeted_by_user_profile_image = cursor.getColumnIndex(Statuses.RETWEETED_BY_USER_PROFILE_IMAGE);
quote_id = cursor.getColumnIndex(Statuses.QUOTE_ID);
quote_text_html = cursor.getColumnIndex(Statuses.QUOTE_TEXT_HTML);
quote_text_plain = cursor.getColumnIndex(Statuses.QUOTE_TEXT_PLAIN);
quote_text_unescaped = cursor.getColumnIndex(Statuses.QUOTE_TEXT_UNESCAPED);
quote_timestamp = cursor.getColumnIndex(Statuses.QUOTE_TIMESTAMP);
quoted_by_user_id = cursor.getColumnIndex(Statuses.QUOTED_BY_USER_ID);
quoted_by_user_name = cursor.getColumnIndex(Statuses.QUOTED_BY_USER_NAME);
quoted_by_user_screen_name = cursor.getColumnIndex(Statuses.QUOTED_BY_USER_SCREEN_NAME);
quoted_by_user_profile_image = cursor.getColumnIndex(Statuses.QUOTED_BY_USER_PROFILE_IMAGE);
user_id = cursor.getColumnIndex(Statuses.USER_ID);
source = cursor.getColumnIndex(Statuses.SOURCE);
retweet_count = cursor.getColumnIndex(Statuses.RETWEET_COUNT);
favorite_count = cursor.getColumnIndex(Statuses.FAVORITE_COUNT);
reply_count = cursor.getColumnIndex(Statuses.REPLY_COUNT);
descendent_reply_count = cursor.getColumnIndex(Statuses.DESCENDENT_REPLY_COUNT);
is_possibly_sensitive = cursor.getColumnIndex(Statuses.IS_POSSIBLY_SENSITIVE);
is_following = cursor.getColumnIndex(Statuses.IS_FOLLOWING);
media = cursor.getColumnIndex(Statuses.MEDIA_LIST);
mentions = cursor.getColumnIndex(Statuses.MENTIONS_LIST);
card = cursor.getColumnIndex(Statuses.CARD);
card_name = cursor.getColumnIndex(Statuses.CARD_NAME);
place_full_name = cursor.getColumnIndex(Statuses.PLACE_FULL_NAME);
}
@Override
public String toString() {
@ -565,93 +703,9 @@ public class ParcelableStatus implements TwidereParcelable, Comparable<Parcelabl
'}';
}
public CursorIndices(final Cursor cursor) {
_id = cursor.getColumnIndex(Statuses._ID);
account_id = cursor.getColumnIndex(Statuses.ACCOUNT_ID);
status_id = cursor.getColumnIndex(Statuses.STATUS_ID);
status_timestamp = cursor.getColumnIndex(Statuses.STATUS_TIMESTAMP);
user_name = cursor.getColumnIndex(Statuses.USER_NAME);
user_screen_name = cursor.getColumnIndex(Statuses.USER_SCREEN_NAME);
text_html = cursor.getColumnIndex(Statuses.TEXT_HTML);
text_plain = cursor.getColumnIndex(Statuses.TEXT_PLAIN);
text_unescaped = cursor.getColumnIndex(Statuses.TEXT_UNESCAPED);
user_profile_image_url = cursor.getColumnIndex(Statuses.USER_PROFILE_IMAGE_URL);
is_favorite = cursor.getColumnIndex(Statuses.IS_FAVORITE);
is_retweet = cursor.getColumnIndex(Statuses.IS_RETWEET);
is_gap = cursor.getColumnIndex(Statuses.IS_GAP);
location = cursor.getColumnIndex(Statuses.LOCATION);
is_protected = cursor.getColumnIndex(Statuses.IS_PROTECTED);
is_verified = cursor.getColumnIndex(Statuses.IS_VERIFIED);
in_reply_to_status_id = cursor.getColumnIndex(Statuses.IN_REPLY_TO_STATUS_ID);
in_reply_to_user_id = cursor.getColumnIndex(Statuses.IN_REPLY_TO_USER_ID);
in_reply_to_user_name = cursor.getColumnIndex(Statuses.IN_REPLY_TO_USER_NAME);
in_reply_to_user_screen_name = cursor.getColumnIndex(Statuses.IN_REPLY_TO_USER_SCREEN_NAME);
my_retweet_id = cursor.getColumnIndex(Statuses.MY_RETWEET_ID);
retweet_id = cursor.getColumnIndex(Statuses.RETWEET_ID);
retweet_timestamp = cursor.getColumnIndex(Statuses.RETWEET_TIMESTAMP);
retweeted_by_user_id = cursor.getColumnIndex(Statuses.RETWEETED_BY_USER_ID);
retweeted_by_user_name = cursor.getColumnIndex(Statuses.RETWEETED_BY_USER_NAME);
retweeted_by_user_screen_name = cursor.getColumnIndex(Statuses.RETWEETED_BY_USER_SCREEN_NAME);
retweeted_by_user_profile_image = cursor.getColumnIndex(Statuses.RETWEETED_BY_USER_PROFILE_IMAGE);
user_id = cursor.getColumnIndex(Statuses.USER_ID);
source = cursor.getColumnIndex(Statuses.SOURCE);
retweet_count = cursor.getColumnIndex(Statuses.RETWEET_COUNT);
favorite_count = cursor.getColumnIndex(Statuses.FAVORITE_COUNT);
reply_count = cursor.getColumnIndex(Statuses.REPLY_COUNT);
descendent_reply_count = cursor.getColumnIndex(Statuses.DESCENDENT_REPLY_COUNT);
is_possibly_sensitive = cursor.getColumnIndex(Statuses.IS_POSSIBLY_SENSITIVE);
is_following = cursor.getColumnIndex(Statuses.IS_FOLLOWING);
media = cursor.getColumnIndex(Statuses.MEDIA_LIST);
mentions = cursor.getColumnIndex(Statuses.MENTIONS_LIST);
card = cursor.getColumnIndex(Statuses.CARD);
card_name = cursor.getColumnIndex(Statuses.CARD_NAME);
place_full_name = cursor.getColumnIndex(Statuses.PLACE_FULL_NAME);
}
}
@Override
public void writeToParcel(final Parcel out, final int flags) {
out.writeLong(id);
out.writeLong(account_id);
out.writeLong(timestamp);
out.writeLong(user_id);
out.writeLong(retweet_id);
out.writeLong(retweet_timestamp);
out.writeLong(retweeted_by_id);
out.writeLong(retweet_count);
out.writeLong(favorite_count);
out.writeLong(reply_count);
out.writeLong(descendent_reply_count);
out.writeLong(in_reply_to_status_id);
out.writeInt(is_gap ? 1 : 0);
out.writeInt(is_retweet ? 1 : 0);
out.writeInt(is_favorite ? 1 : 0);
out.writeInt(user_is_protected ? 1 : 0);
out.writeInt(user_is_verified ? 1 : 0);
out.writeString(retweeted_by_name);
out.writeString(retweeted_by_screen_name);
out.writeString(retweeted_by_profile_image);
out.writeString(text_html);
out.writeString(text_plain);
out.writeString(user_name);
out.writeString(user_screen_name);
out.writeString(in_reply_to_screen_name);
out.writeString(source);
out.writeString(user_profile_image_url);
out.writeTypedArray(media, flags);
out.writeParcelable(location, flags);
out.writeLong(my_retweet_id);
out.writeInt(is_possibly_sensitive ? 1 : 0);
out.writeInt(user_is_following ? 1 : 0);
out.writeString(text_unescaped);
out.writeLong(in_reply_to_user_id);
out.writeString(in_reply_to_name);
out.writeTypedArray(mentions, flags);
out.writeParcelable(card, flags);
out.writeString(place_full_name);
}
public static final class ParcelableCardEntity implements TwidereParcelable {
public static final Parcelable.Creator<ParcelableCardEntity> CREATOR = new Parcelable.Creator<ParcelableCardEntity>() {
@ -687,15 +741,6 @@ public class ParcelableStatus implements TwidereParcelable, Comparable<Parcelabl
users = src.createTypedArray(ParcelableUser.CREATOR);
}
@Override
public String toString() {
return "ParcelableCardEntity{" +
"name='" + name + '\'' +
", users=" + Arrays.toString(users) +
", values=" + Arrays.toString(values) +
'}';
}
public ParcelableCardEntity(JSONParcel src) {
name = src.readString("name");
values = src.readParcelableArray("values", ParcelableValueItem.JSON_CREATOR);
@ -716,6 +761,15 @@ public class ParcelableStatus implements TwidereParcelable, Comparable<Parcelabl
}
}
@Override
public String toString() {
return "ParcelableCardEntity{" +
"name='" + name + '\'' +
", users=" + Arrays.toString(users) +
", values=" + Arrays.toString(values) +
'}';
}
public static ParcelableCardEntity fromCardEntity(CardEntity card, long account_id) {
if (card == null) return null;
return new ParcelableCardEntity(card, account_id);
@ -803,11 +857,6 @@ public class ParcelableStatus implements TwidereParcelable, Comparable<Parcelabl
}
}
@Override
public int describeContents() {
return 0;
}
public static final class ParcelableUserValue implements TwidereParcelable {
public static final Parcelable.Creator<ParcelableUserValue> CREATOR = new Parcelable.Creator<ParcelableUserValue>() {
@ -969,6 +1018,13 @@ public class ParcelableStatus implements TwidereParcelable, Comparable<Parcelabl
}
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
@ -985,4 +1041,56 @@ public class ParcelableStatus implements TwidereParcelable, Comparable<Parcelabl
}
@Override
public void writeToParcel(final Parcel out, final int flags) {
out.writeLong(id);
out.writeLong(account_id);
out.writeLong(timestamp);
out.writeLong(user_id);
out.writeLong(retweet_id);
out.writeLong(retweet_timestamp);
out.writeLong(retweeted_by_id);
out.writeLong(retweet_count);
out.writeLong(favorite_count);
out.writeLong(reply_count);
out.writeLong(descendent_reply_count);
out.writeLong(in_reply_to_status_id);
out.writeByte((byte) (is_gap ? 1 : 0));
out.writeByte((byte) (is_retweet ? 1 : 0));
out.writeByte((byte) (is_favorite ? 1 : 0));
out.writeByte((byte) (user_is_protected ? 1 : 0));
out.writeByte((byte) (user_is_verified ? 1 : 0));
out.writeString(retweeted_by_name);
out.writeString(retweeted_by_screen_name);
out.writeString(retweeted_by_profile_image);
out.writeString(text_html);
out.writeString(text_plain);
out.writeString(user_name);
out.writeString(user_screen_name);
out.writeString(in_reply_to_screen_name);
out.writeString(source);
out.writeString(user_profile_image_url);
out.writeTypedArray(media, flags);
out.writeParcelable(location, flags);
out.writeLong(my_retweet_id);
out.writeByte((byte) (is_possibly_sensitive ? 1 : 0));
out.writeByte((byte) (user_is_following ? 1 : 0));
out.writeString(text_unescaped);
out.writeLong(in_reply_to_user_id);
out.writeString(in_reply_to_name);
out.writeTypedArray(mentions, flags);
out.writeParcelable(card, flags);
out.writeString(place_full_name);
out.writeByte((byte) (is_quote ? 1 : 0));
out.writeLong(quote_id);
out.writeString(quote_text_html);
out.writeString(quote_text_plain);
out.writeString(quote_text_unescaped);
out.writeLong(quote_timestamp);
out.writeLong(quoted_by_user_id);
out.writeString(quoted_by_user_name);
out.writeString(quoted_by_user_screen_name);
out.writeString(quoted_by_user_profile_image);
}
}

View File

@ -307,10 +307,9 @@ public final class ContentValuesCreator implements TwidereConstants {
values.put(Statuses.ACCOUNT_ID, accountId);
values.put(Statuses.STATUS_ID, orig.getId());
values.put(Statuses.STATUS_TIMESTAMP, orig.getCreatedAt().getTime());
final boolean isRetweet = orig.isRetweet();
final Status status;
final Status retweetedStatus = isRetweet ? orig.getRetweetedStatus() : null;
if (retweetedStatus != null) {
if (orig.isRetweet()) {
final Status retweetedStatus = orig.getRetweetedStatus();
final User retweetUser = orig.getUser();
final long retweetedById = retweetUser.getId();
values.put(Statuses.RETWEET_ID, retweetedStatus.getId());
@ -319,12 +318,34 @@ public final class ContentValuesCreator implements TwidereConstants {
values.put(Statuses.RETWEETED_BY_USER_NAME, retweetUser.getName());
values.put(Statuses.RETWEETED_BY_USER_SCREEN_NAME, retweetUser.getScreenName());
values.put(Statuses.RETWEETED_BY_USER_PROFILE_IMAGE, ParseUtils.parseString(retweetUser.getProfileImageUrlHttps()));
values.put(Statuses.IS_RETWEET, true);
if (retweetedById == accountId) {
values.put(Statuses.MY_RETWEET_ID, orig.getId());
} else {
values.put(Statuses.MY_RETWEET_ID, orig.getCurrentUserRetweet());
}
status = retweetedStatus;
} else if (orig.isQuote()) {
final Status quotedStatus = orig.getQuotedStatus();
final User quoteUser = orig.getUser();
final long quotedById = quoteUser.getId();
values.put(Statuses.QUOTE_ID, quotedStatus.getId());
final String textHtml = TwitterContentUtils.formatStatusText(orig);
values.put(Statuses.QUOTE_TEXT_HTML, textHtml);
values.put(Statuses.QUOTE_TEXT_PLAIN, orig.getText());
values.put(Statuses.QUOTE_TEXT_UNESCAPED, toPlainText(textHtml));
values.put(Statuses.QUOTE_TIMESTAMP, quotedStatus.getCreatedAt().getTime());
values.put(Statuses.QUOTED_BY_USER_ID, quotedById);
values.put(Statuses.QUOTED_BY_USER_NAME, quoteUser.getName());
values.put(Statuses.QUOTED_BY_USER_SCREEN_NAME, quoteUser.getScreenName());
values.put(Statuses.QUOTED_BY_USER_PROFILE_IMAGE, ParseUtils.parseString(quoteUser.getProfileImageUrlHttps()));
values.put(Statuses.IS_QUOTE, true);
if (quotedById == accountId) {
values.put(Statuses.MY_QUOTE_ID, orig.getId());
// } else {
// values.put(Statuses.MY_QUOTE_ID, orig.getCurrentUserRetweet());
}
status = quotedStatus;
} else {
values.put(Statuses.MY_RETWEET_ID, orig.getCurrentUserRetweet());
status = orig;
@ -340,10 +361,10 @@ public final class ContentValuesCreator implements TwidereConstants {
values.put(Statuses.IS_VERIFIED, user.isVerified());
values.put(Statuses.USER_PROFILE_IMAGE_URL, profileImageUrl);
values.put(CachedUsers.IS_FOLLOWING, user.isFollowing());
final String text_html = TwitterContentUtils.formatStatusText(status);
values.put(Statuses.TEXT_HTML, text_html);
final String textHtml = TwitterContentUtils.formatStatusText(status);
values.put(Statuses.TEXT_HTML, textHtml);
values.put(Statuses.TEXT_PLAIN, status.getText());
values.put(Statuses.TEXT_UNESCAPED, toPlainText(text_html));
values.put(Statuses.TEXT_UNESCAPED, toPlainText(textHtml));
values.put(Statuses.RETWEET_COUNT, status.getRetweetCount());
values.put(Statuses.REPLY_COUNT, status.getReplyCount());
values.put(Statuses.FAVORITE_COUNT, status.getFavoriteCount());
@ -362,7 +383,6 @@ public final class ContentValuesCreator implements TwidereConstants {
if (place != null) {
values.put(Statuses.PLACE_FULL_NAME, place.getFullName());
}
values.put(Statuses.IS_RETWEET, isRetweet);
values.put(Statuses.IS_FAVORITE, status.isFavorited());
final ParcelableMedia[] media = ParcelableMedia.fromEntities(status);
if (media != null) {

View File

@ -114,6 +114,8 @@ public interface Status extends Comparable<Status>, TwitterResponse, ExtendedEnt
*/
Status getRetweetedStatus();
Status getQuotedStatus();
/**
* returns the source of the tweet
*
@ -151,6 +153,8 @@ public interface Status extends Comparable<Status>, TwitterResponse, ExtendedEnt
*/
boolean isRetweet();
boolean isQuote();
/**
* Returns true if the authenticating user has retweeted this tweet, or
* false when the tweet was created before this feature was enabled.

View File

@ -95,7 +95,7 @@ public final class HttpClientWrapper {
}
public HttpResponse get(final String url, final String signUrl) throws TwitterException {
return get(url, signUrl, null, null);
return get(url, signUrl, null, null, null);
}
public HttpResponse get(final String url, final String signUrl, final Authorization authorization)
@ -105,12 +105,37 @@ public final class HttpClientWrapper {
public HttpResponse get(final String url, final String signUrl, final HttpParameter[] parameters)
throws TwitterException {
return get(url, signUrl, parameters, null);
return get(url, signUrl, parameters, null, null);
}
public HttpResponse get(final String url, final String signUrl, final HttpParameter[] parameters,
final Authorization authorization) throws TwitterException {
return request(new HttpRequest(GET, url, signUrl, parameters, authorization, requestHeaders));
return get(url, signUrl, parameters, authorization, null);
}
public HttpResponse get(final String url, final String signUrl, final HttpParameter[] parameters,
final Map<String, List<String>> requestHeaders) throws TwitterException {
return get(url, signUrl, parameters, null, requestHeaders);
}
public HttpResponse get(final String url, final String signUrl, final Map<String, List<String>> requestHeaders)
throws TwitterException {
return get(url, signUrl, null, null, requestHeaders);
}
public HttpResponse get(final String url, final String signUrl, final Authorization authorization,
final Map<String, List<String>> requestHeaders) throws TwitterException {
return get(url, signUrl, null, authorization, requestHeaders);
}
public HttpResponse get(final String url, final String signUrl, final HttpParameter[] parameters,
final Authorization authorization, final Map<String, List<String>> requestHeaders)
throws TwitterException {
final Map<String, List<String>> headers = new HashMap<>(this.requestHeaders);
if (requestHeaders != null) {
headers.putAll(requestHeaders);
}
return request(new HttpRequest(GET, url, signUrl, parameters, authorization, headers));
}
@Override

View File

@ -92,6 +92,7 @@ final class StatusJSONImpl extends TwitterResponseImpl implements Status {
private long[] contributorsIDs;
private Status retweetedStatus;
private Status quotedStatus;
private UserMentionEntity[] userMentionEntities;
private URLEntity[] urlEntities;
private HashtagEntity[] hashtagEntities;
@ -252,6 +253,11 @@ final class StatusJSONImpl extends TwitterResponseImpl implements Status {
return retweetedStatus;
}
@Override
public Status getQuotedStatus() {
return quotedStatus;
}
/**
* {@inheritDoc}
*/
@ -318,6 +324,11 @@ final class StatusJSONImpl extends TwitterResponseImpl implements Status {
return retweetedStatus != null;
}
@Override
public boolean isQuote() {
return quotedStatus != null;
}
/**
* {@inheritDoc}
*/
@ -395,6 +406,16 @@ final class StatusJSONImpl extends TwitterResponseImpl implements Status {
logger.warn("failed to parse retweeted_status:" + json);
}
}
if (!json.isNull("quoted_status")) {
try {
quotedStatus = new StatusJSONImpl(json.getJSONObject("quoted_status"));
} catch (final JSONException ignore) {
ignore.printStackTrace();
logger.warn("failed to parse retweeted_status:" + json);
}
}
if (!json.isNull("contributors")) {
try {
final JSONArray contributorsArray = json.getJSONArray("contributors");

View File

@ -55,6 +55,7 @@ repositories {
jcenter()
mavenCentral()
maven { url 'https://repo.commonsware.com.s3.amazonaws.com' }
maven { url 'https://github.com/suckgamony/RapidDecoder/raw/master/repository' }
maven { url "https://jitpack.io" }
}
@ -75,16 +76,18 @@ dependencies {
compile 'com.squareup:otto:1.3.6'
compile 'dnsjava:dnsjava:2.1.7'
compile 'com.commonsware.cwac:merge:1.1.1'
compile 'com.diegocarloslima:byakugallery:0.1.0'
compile 'com.davemorrissey.labs:subsampling-scale-image-view:3.1.3'
compile 'com.rengwuxian.materialedittext:library:2.0.3'
compile 'com.pnikosis:materialish-progress:1.5'
compile 'com.squareup.okhttp:okhttp:2.3.0'
compile 'pl.droidsonroids.gif:android-gif-drawable:1.1.3'
// Disabled temporarilly due to attribute clash with subsampling-scale-image-view
// compile 'pl.droidsonroids.gif:android-gif-drawable:1.1.3'
compile 'com.github.mariotaku:MessageBubbleView:1.0'
compile 'com.github.mariotaku:DragSortListView:0.6.1'
compile 'com.github.mariotaku:SlidingMenu:1.3'
compile 'com.github.uucky:ColorPicker-Android:0.9.1'
compile 'com.sprylab.android.texturevideoview:texturevideoview:1.0.0'
compile 'com.squareup:pollexor:2.0.2'
googleCompile 'com.google.android.gms:play-services-maps:7.0.0'
googleCompile 'com.google.maps.android:android-maps-utils:0.3.4'
fdroidCompile 'org.osmdroid:osmdroid-android:4.3'

View File

@ -33,7 +33,7 @@ import static org.mariotaku.twidere.annotation.Preference.Type.STRING;
public interface Constants extends TwidereConstants {
String DATABASES_NAME = "twidere.sqlite";
int DATABASES_VERSION = 93;
int DATABASES_VERSION = 94;
int MENU_GROUP_STATUS_EXTENSION = 10;
int MENU_GROUP_COMPOSE_EXTENSION = 11;

View File

@ -17,7 +17,6 @@
package org.mariotaku.twidere.activity.support;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.AsyncTask.Status;
import android.os.Bundle;
@ -39,12 +38,9 @@ import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLayoutChangeListener;
import android.view.ViewGroup;
import android.webkit.WebView;
import android.widget.Toast;
import android.widget.VideoView;
import com.diegocarloslima.byakugallery.lib.TileBitmapDrawable;
import com.diegocarloslima.byakugallery.lib.TileBitmapDrawable.OnInitializeListener;
import com.davemorrissey.labs.subscaleview.ImageSource;
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView;
import com.pnikosis.materialishprogress.ProgressWheel;
import com.sprylab.android.widget.TextureVideoView;
@ -66,15 +62,9 @@ import org.mariotaku.twidere.util.ThemeUtils;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.util.VideoLoader;
import org.mariotaku.twidere.util.VideoLoader.VideoLoadingListener;
import org.mariotaku.twidere.view.TouchImageView;
import org.mariotaku.twidere.view.TouchImageView.ZoomListener;
import java.io.File;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.RandomAccessFile;
import pl.droidsonroids.gif.GifDrawable;
public final class MediaViewerActivity extends ThemedActionBarActivity implements Constants, OnPageChangeListener {
@ -284,9 +274,9 @@ public final class MediaViewerActivity extends ThemedActionBarActivity implement
}
public static final class ImagePageFragment extends BaseSupportFragment
implements DownloadListener, LoaderCallbacks<Result>, OnLayoutChangeListener, OnClickListener, ZoomListener {
implements DownloadListener, LoaderCallbacks<Result>, OnLayoutChangeListener, OnClickListener {
private TouchImageView mImageView;
private SubsamplingScaleImageView mImageView;
private ProgressWheel mProgressBar;
private boolean mLoaderInitialized;
private float mContentLength;
@ -295,7 +285,7 @@ public final class MediaViewerActivity extends ThemedActionBarActivity implement
@Override
public void onBaseViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onBaseViewCreated(view, savedInstanceState);
mImageView = (TouchImageView) view.findViewById(R.id.image_view);
mImageView = (SubsamplingScaleImageView) view.findViewById(R.id.image_view);
mProgressBar = (ProgressWheel) view.findViewById(R.id.progress);
}
@ -326,40 +316,24 @@ public final class MediaViewerActivity extends ThemedActionBarActivity implement
mImageView.setVisibility(View.VISIBLE);
mImageView.setTag(data.file);
if (data.useDecoder) {
TileBitmapDrawable.attachTileBitmapDrawable(mImageView, data.file.getAbsolutePath(),
null, new OnInitializeListener() {
@Override
public void onStartInitialization() {
}
@Override
public void onEndInitialization() {
mImageView.post(new Runnable() {
@Override
public void run() {
updateScaleLimit();
}
});
}
});
mImageView.setImage(ImageSource.uri(Uri.fromFile(data.file)));
} else if ("image/gif".equals(data.options.outMimeType)) {
try {
final FileDescriptor fd = new RandomAccessFile(data.file, "r").getFD();
mImageView.setImageDrawable(new GifDrawable(fd));
} catch (IOException e) {
mImageView.setImageDrawable(null);
mImageView.setTag(null);
mImageView.setVisibility(View.GONE);
Utils.showErrorMessage(getActivity(), null, e, true);
}
// try {
// final FileDescriptor fd = new RandomAccessFile(data.file, "r").getFD();
// mImageView.setImageDrawable(new GifDrawable(fd));
// } catch (IOException e) {
// mImageView.setImage(null);
// mImageView.setTag(null);
// mImageView.setVisibility(View.GONE);
// Utils.showErrorMessage(getActivity(), null, e, true);
// }
updateScaleLimit();
} else {
mImageView.setImageBitmap(data.bitmap);
mImageView.setImage(ImageSource.bitmap(data.bitmap));
updateScaleLimit();
}
} else {
mImageView.setImageDrawable(null);
mImageView.setImage(null);
mImageView.setTag(null);
mImageView.setVisibility(View.GONE);
Utils.showErrorMessage(getActivity(), null, data.exception, true);
@ -371,10 +345,10 @@ public final class MediaViewerActivity extends ThemedActionBarActivity implement
@Override
public void onLoaderReset(final Loader<TileImageLoader.Result> loader) {
final Drawable drawable = mImageView.getDrawable();
if (drawable instanceof GifDrawable) {
((GifDrawable) drawable).recycle();
}
// final Drawable drawable = mImageView.getDrawable();
// if (drawable instanceof GifDrawable) {
// ((GifDrawable) drawable).recycle();
// }
}
@Override
@ -462,7 +436,6 @@ public final class MediaViewerActivity extends ThemedActionBarActivity implement
super.onActivityCreated(savedInstanceState);
setHasOptionsMenu(true);
mImageView.setOnClickListener(this);
mImageView.setZoomListener(this);
loadImage();
}
@ -510,13 +483,11 @@ public final class MediaViewerActivity extends ThemedActionBarActivity implement
}
@Override
public void onZoomOut() {
final MediaViewerActivity activity = (MediaViewerActivity) getActivity();
activity.setBarVisibility(true);
}
@Override
public void onZoomIn() {
final MediaViewerActivity activity = (MediaViewerActivity) getActivity();
activity.setBarVisibility(false);
@ -533,16 +504,16 @@ public final class MediaViewerActivity extends ThemedActionBarActivity implement
}
private void updateScaleLimit() {
final int viewWidth = mImageView.getWidth(), viewHeight = mImageView.getHeight();
final Drawable drawable = mImageView.getDrawable();
if (drawable == null || viewWidth <= 0 || viewHeight <= 0) return;
final int drawableWidth = drawable.getIntrinsicWidth();
final int drawableHeight = drawable.getIntrinsicHeight();
if (drawableWidth <= 0 || drawableHeight <= 0) return;
final float widthRatio = viewWidth / (float) drawableWidth;
final float heightRatio = viewHeight / (float) drawableHeight;
mImageView.setMaxScale(Math.max(1, Math.max(heightRatio, widthRatio)));
mImageView.resetScale();
// final int viewWidth = mImageView.getWidth(), viewHeight = mImageView.getHeight();
// final Drawable drawable = mImageView.getDrawable();
// if (drawable == null || viewWidth <= 0 || viewHeight <= 0) return;
// final int drawableWidth = drawable.getIntrinsicWidth();
// final int drawableHeight = drawable.getIntrinsicHeight();
// if (drawableWidth <= 0 || drawableHeight <= 0) return;
// final float widthRatio = viewWidth / (float) drawableWidth;
// final float heightRatio = viewHeight / (float) drawableHeight;
// mImageView.setMaxScale(Math.max(1, Math.max(heightRatio, widthRatio)));
// mImageView.resetScale();
}
}

View File

@ -38,9 +38,9 @@ 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_STATUS = 0;
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_LOAD_INDICATOR = 2;
public static final int ITEM_VIEW_TYPE_STATUS = 2;
private final Context mContext;
private final LayoutInflater mInflater;

View File

@ -114,7 +114,7 @@ public class TwidereApplication extends MultiDexApplication implements Constants
public ImageDownloader getFullImageDownloader() {
if (mFullImageDownloader != null) return mFullImageDownloader;
return mFullImageDownloader = new TwidereImageDownloader(this, true);
return mFullImageDownloader = new TwidereImageDownloader(this, true, true);
}
public Handler getHandler() {
@ -133,7 +133,7 @@ public class TwidereApplication extends MultiDexApplication implements Constants
public ImageDownloader getImageDownloader() {
if (mImageDownloader != null) return mImageDownloader;
return mImageDownloader = new TwidereImageDownloader(this, false);
return mImageDownloader = new TwidereImageDownloader(this, false, true);
}
public ImageLoader getImageLoader() {
@ -274,7 +274,8 @@ public class TwidereApplication extends MultiDexApplication implements Constants
startUsageStatisticsServiceIfNeeded(this);
//end
} else if (KEY_CONSUMER_KEY.equals(key) || KEY_CONSUMER_SECRET.equals(key) || KEY_API_URL_FORMAT.equals(key)
|| KEY_AUTH_TYPE.equals(key) || KEY_SAME_OAUTH_SIGNING_URL.equals(key)) {
|| KEY_AUTH_TYPE.equals(key) || KEY_SAME_OAUTH_SIGNING_URL.equals(key) || KEY_THUMBOR_ENABLED.equals(key)
|| KEY_THUMBOR_ADDRESS.equals(key) || KEY_THUMBOR_SECURITY_KEY.equals(key)) {
final SharedPreferences.Editor editor = preferences.edit();
editor.putLong(KEY_API_LAST_CHANGE, System.currentTimeMillis());
editor.apply();

View File

@ -68,7 +68,6 @@ import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.webkit.URLUtil;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Space;
import android.widget.TextView;
@ -106,6 +105,7 @@ import org.mariotaku.twidere.util.TwitterCardUtils;
import org.mariotaku.twidere.util.UserColorNameUtils;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.util.Utils.OnMediaClickListener;
import org.mariotaku.twidere.view.CardMediaContainer;
import org.mariotaku.twidere.view.ShapedImageView;
import org.mariotaku.twidere.view.StatusTextView;
import org.mariotaku.twidere.view.TwitterCardContainer;
@ -525,7 +525,7 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
private final View retweetedByContainer;
private final View mediaPreviewContainer;
private final View mediaPreviewLoad;
private final LinearLayout mediaPreviewGrid;
private final CardMediaContainer mediaPreview;
private final TextView locationView;
private final TwitterCardContainer twitterCard;
@ -549,9 +549,9 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
repliesCountView = (TextView) itemView.findViewById(R.id.replies_count);
retweetsCountView = (TextView) itemView.findViewById(R.id.retweets_count);
favoritesCountView = (TextView) itemView.findViewById(R.id.favorites_count);
mediaPreviewContainer = itemView.findViewById(R.id.media_preview);
mediaPreviewContainer = itemView.findViewById(R.id.media_preview_container);
mediaPreviewLoad = itemView.findViewById(R.id.media_preview_load);
mediaPreviewGrid = (LinearLayout) itemView.findViewById(R.id.media_preview_grid);
mediaPreview = (CardMediaContainer) itemView.findViewById(R.id.media_preview);
locationView = (TextView) itemView.findViewById(R.id.location_view);
profileContainer = itemView.findViewById(R.id.profile_container);
twitterCard = (TwitterCardContainer) itemView.findViewById(R.id.twitter_card);
@ -640,16 +640,13 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
} else if (adapter.isDetailMediaExpanded()) {
mediaPreviewContainer.setVisibility(View.VISIBLE);
mediaPreviewLoad.setVisibility(View.GONE);
mediaPreviewGrid.setVisibility(View.VISIBLE);
mediaPreviewGrid.removeAllViews();
final int maxColumns = resources.getInteger(R.integer.grid_column_image_preview);
Utils.addToLinearLayout(mediaPreviewGrid, loader, status.media, status.account_id,
maxColumns, adapter.getFragment());
mediaPreview.setVisibility(View.VISIBLE);
mediaPreview.displayMedia(status.media, loader, status.account_id,
adapter.getFragment(), adapter.getImageLoadingHandler());
} else {
mediaPreviewContainer.setVisibility(View.VISIBLE);
mediaPreviewLoad.setVisibility(View.VISIBLE);
mediaPreviewGrid.setVisibility(View.GONE);
mediaPreviewGrid.removeAllViews();
mediaPreview.setVisibility(View.GONE);
}
if (TwitterCardUtils.isCardSupported(status.card)) {

View File

@ -0,0 +1,86 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.preference;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Bundle;
import android.preference.SwitchPreference;
import android.support.annotation.NonNull;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Switch;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.fragment.SettingsDetailsFragment;
/**
* Created by mariotaku on 15/4/7.
*/
public class SwitchSettingsDetailsPreference extends SwitchPreference implements Constants {
public SwitchSettingsDetailsPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
final TypedArray a = context.obtainStyledAttributes(attrs, new int[]{android.R.attr.src});
setFragment(SettingsDetailsFragment.class.getName());
final Bundle extras = getExtras();
extras.putInt(EXTRA_RESID, a.getResourceId(0, 0));
a.recycle();
}
public SwitchSettingsDetailsPreference(Context context, AttributeSet attrs) {
this(context, attrs, android.R.attr.switchPreferenceStyle);
}
public SwitchSettingsDetailsPreference(Context context) {
this(context, null);
}
@Override
protected void onBindView(@NonNull View view) {
super.onBindView(view);
if (view instanceof ViewGroup) {
((ViewGroup) view).setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
}
final Switch switchView = (Switch) findViewByType(view, Switch.class);
if (switchView != null) {
switchView.setClickable(true);
switchView.setFocusable(true);
}
}
private static View findViewByType(View view, Class<? extends View> cls) {
if (cls.isAssignableFrom(view.getClass())) return view;
if (view instanceof ViewGroup) {
for (int i = 0, j = ((ViewGroup) view).getChildCount(); i < j; i++) {
final View found = findViewByType(((ViewGroup) view).getChildAt(i), cls);
if (found != null) return found;
}
}
return null;
}
@Override
protected void onClick() {
}
}

View File

@ -407,7 +407,6 @@ public class BackgroundOperationService extends IntentService implements Constan
final ContentLengthInputStream is = new ContentLengthInputStream(file);
is.setReadListener(new MessageMediaUploadListener(this, mNotificationManager, builder, text));
final MediaUploadResponse uploadResp = twitter.uploadMedia(file.getName(), is, o.outMimeType);
// final MediaUploadResponse uploadResp = twitter.uploadMediaBase64(is);
directMessage = new ParcelableDirectMessage(twitter.sendDirectMessage(recipientId, text,
uploadResp.getId()), accountId, true);
if (!file.delete()) {

View File

@ -20,7 +20,10 @@
package org.mariotaku.twidere.util;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.support.v4.content.res.ResourcesCompat;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.ImageView;
import android.widget.ProgressBar;
@ -30,6 +33,8 @@ import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
import com.nostra13.universalimageloader.core.listener.ImageLoadingProgressListener;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.model.ParcelableMedia;
import org.mariotaku.twidere.view.ForegroundImageView;
import java.util.HashMap;
import java.util.Map;
@ -55,6 +60,9 @@ public class ImageLoadingHandler implements ImageLoadingListener, ImageLoadingPr
public void onLoadingCancelled(final String imageUri, final View view) {
if (view == null || imageUri == null || imageUri.equals(mLoadingUris.get(view))) return;
mLoadingUris.remove(view);
if (view instanceof ForegroundImageView) {
((ForegroundImageView) view).setForeground(null);
}
final ProgressBar progress = findProgressBar(view.getParent());
if (progress != null) {
progress.setVisibility(View.GONE);
@ -65,18 +73,38 @@ public class ImageLoadingHandler implements ImageLoadingListener, ImageLoadingPr
public void onLoadingComplete(final String imageUri, final View view, final Bitmap bitmap) {
if (view == null) return;
mLoadingUris.remove(view);
final ProgressBar progress = findProgressBar(view.getParent());
final ViewGroup parent = (ViewGroup) view.getParent();
if (view instanceof ForegroundImageView) {
final Drawable foreground;
if (isVideoItem(parent)) {
foreground = ResourcesCompat.getDrawable(view.getResources(), R.drawable.ic_card_media_play, null);
} else {
foreground = null;
}
((ForegroundImageView) view).setForeground(foreground);
}
final ProgressBar progress = findProgressBar(parent);
if (progress != null) {
progress.setVisibility(View.GONE);
}
}
private static boolean isVideoItem(ViewGroup parent) {
final Object tag = parent.getTag();
if (tag instanceof ParcelableMedia) {
return ((ParcelableMedia) tag).type == ParcelableMedia.TYPE_VIDEO;
}
return false;
}
@Override
public void onLoadingFailed(final String imageUri, final View view, final FailReason reason) {
if (view == null) return;
if (view instanceof ImageView) {
if (view instanceof ForegroundImageView) {
((ImageView) view).setImageDrawable(null);
view.setBackgroundResource(R.drawable.image_preview_refresh);
final Drawable foreground = ResourcesCompat.getDrawable(view.getResources(),
R.drawable.image_preview_refresh, null);
((ForegroundImageView) view).setForeground(foreground);
}
mLoadingUris.remove(view);
final ProgressBar progress = findProgressBar(view.getParent());
@ -88,8 +116,8 @@ public class ImageLoadingHandler implements ImageLoadingListener, ImageLoadingPr
@Override
public void onLoadingStarted(final String imageUri, final View view) {
if (view == null || imageUri == null || imageUri.equals(mLoadingUris.get(view))) return;
if (view instanceof ImageView) {
view.setBackgroundResource(0);
if (view instanceof ForegroundImageView) {
((ForegroundImageView) view).setForeground(null);
}
mLoadingUris.put(view, imageUri);
final ProgressBar progress = findProgressBar(view.getParent());

View File

@ -73,7 +73,7 @@ public class OAuthPasswordAuthenticator implements Constants {
final String oauthToken = requestToken.getToken();
final String authorizationUrl = requestToken.getAuthorizationURL();
final HashMap<String, String> inputMap = new HashMap<>();
final HttpResponse authorizePage = client.get(authorizationUrl, authorizationUrl, null, null);
final HttpResponse authorizePage = client.get(authorizationUrl, authorizationUrl, null, null, null);
final List<String> cookieHeaders = authorizePage.getResponseHeaders("Set-Cookie");
readInputFromHtml(authorizePage.asReader(),
inputMap, INPUT_AUTHENTICITY_TOKEN, INPUT_REDIRECT_AFTER_LOGIN);

View File

@ -95,7 +95,6 @@ import android.util.TypedValue;
import android.view.Gravity;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
@ -106,8 +105,6 @@ import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.webkit.MimeTypeMap;
import android.widget.AbsListView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.TextView;
@ -233,8 +230,8 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Locale;
import java.util.Map.Entry;
import java.util.regex.Matcher;
@ -486,52 +483,6 @@ public final class Utils implements Constants, TwitterConstants {
}
}
public static void addToLinearLayout(final LinearLayout container, final MediaLoaderWrapper loader,
final List<ParcelableMedia> mediaList, final long accountId,
final int maxColumnCount, final OnMediaClickListener mediaClickListener) {
if (container.getOrientation() != LinearLayout.VERTICAL)
throw new IllegalArgumentException();
final Context context = container.getContext();
final ImageLoadingHandler loadingHandler = new ImageLoadingHandler(R.id.media_preview_progress);
final LayoutInflater inflater = LayoutInflater.from(context);
final ListIterator<ParcelableMedia> iterator = mediaList.listIterator();
final int imageCount = mediaList.size();
final double imageCountSqrt = Math.sqrt(imageCount);
final int bestColumnCount = imageCountSqrt % 1 == 0 ? (int) imageCountSqrt : maxColumnCount;
final int firstColumn = imageCount % bestColumnCount, fullRowCount = imageCount / bestColumnCount;
final int rowCount = fullRowCount + (firstColumn > 0 ? 1 : 0);
final View.OnClickListener clickListener = new ImageGridClickListener(mediaClickListener, accountId);
container.setMotionEventSplittingEnabled(false);
for (int currentRow = 0; currentRow < rowCount; currentRow++) {
final LinearLayout rowContainer = new LinearLayout(context);
rowContainer.setOrientation(LinearLayout.HORIZONTAL);
rowContainer.setMotionEventSplittingEnabled(false);
container.addView(rowContainer, LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
final int columnCount = currentRow == 0 && firstColumn > 0 ? firstColumn : bestColumnCount;
for (int currentColumn = 0; currentColumn < columnCount; currentColumn++) {
final ParcelableMedia media = iterator.next();
final View item = inflater.inflate(R.layout.grid_item_media_preview, rowContainer, false);
item.setTag(media);
if (mediaClickListener != null) {
item.setOnClickListener(clickListener);
}
final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) item.getLayoutParams();
lp.weight = 1.0f;
rowContainer.addView(item, lp);
final ImageView imageView = (ImageView) item.findViewById(R.id.media_preview_item);
loader.displayPreviewImage(imageView, media.page_url, loadingHandler);
}
}
}
public static void addToLinearLayout(final LinearLayout container, final MediaLoaderWrapper loader,
final ParcelableMedia[] mediaArray, final long accountId,
final int maxColumnCount, final OnMediaClickListener listener) {
addToLinearLayout(container, loader, Arrays.asList(mediaArray), accountId, maxColumnCount,
listener);
}
public static void announceForAccessibilityCompat(final Context context, final View view, final CharSequence text,
final Class<?> cls) {
final AccessibilityManager accessibilityManager = (AccessibilityManager) context
@ -2194,13 +2145,15 @@ public final class Utils implements Constants, TwitterConstants {
}
public static HttpResponse getRedirectedHttpResponse(final HttpClientWrapper client, final String url,
final String signUrl, final Authorization auth) throws TwitterException {
final String signUrl, final Authorization auth,
final HashMap<String, List<String>> additionalHeaders)
throws TwitterException {
if (url == null) return null;
final ArrayList<String> urls = new ArrayList<>();
urls.add(url);
HttpResponse resp;
try {
resp = client.get(url, signUrl, auth);
resp = client.get(url, signUrl, auth, additionalHeaders);
} catch (final TwitterException te) {
if (isRedirected(te.getStatusCode())) {
resp = te.getHttpResponse();
@ -2213,7 +2166,7 @@ public final class Utils implements Constants, TwitterConstants {
if (urls.contains(request_url)) throw new TwitterException("Too many redirects");
urls.add(request_url);
try {
resp = client.get(request_url, request_url);
resp = client.get(request_url, request_url, additionalHeaders);
} catch (final TwitterException te) {
if (isRedirected(te.getStatusCode())) {
resp = te.getHttpResponse();

View File

@ -30,6 +30,7 @@ import com.squareup.otto.Bus;
import org.mariotaku.twidere.app.TwidereApplication;
import org.mariotaku.twidere.model.SingleResponse;
import org.mariotaku.twidere.task.ManagedAsyncTask;
import org.mariotaku.twidere.util.imageloader.TwidereImageDownloader;
import org.mariotaku.twidere.util.message.VideoLoadFinishedEvent;
import java.io.File;
@ -52,7 +53,7 @@ public class VideoLoader {
final TwidereApplication app = TwidereApplication.getInstance(context);
mContext = context;
mDiskCache = app.getDiskCache();
mImageDownloader = app.getImageDownloader();
mImageDownloader = new TwidereImageDownloader(context, false, false);
mTaskManager = app.getAsyncTaskManager();
mBus = app.getMessageBus();
}

View File

@ -21,17 +21,23 @@ package org.mariotaku.twidere.util.imageloader;
import android.content.Context;
import android.net.Uri;
import android.os.Build;
import android.text.TextUtils;
import android.webkit.URLUtil;
import com.nostra13.universalimageloader.core.assist.ContentLengthInputStream;
import com.nostra13.universalimageloader.core.download.BaseImageDownloader;
import com.squareup.pollexor.Thumbor;
import com.squareup.pollexor.ThumborUrlBuilder;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.constant.SharedPreferenceConstants;
import org.mariotaku.twidere.model.ParcelableAccount;
import org.mariotaku.twidere.model.ParcelableAccount.ParcelableCredentials;
import org.mariotaku.twidere.model.ParcelableMedia;
import org.mariotaku.twidere.util.MediaPreviewUtils;
import org.mariotaku.twidere.util.SharedPreferencesWrapper;
import org.mariotaku.twidere.util.Utils;
import java.io.IOException;
@ -40,6 +46,7 @@ import java.util.Locale;
import twitter4j.TwitterException;
import twitter4j.auth.Authorization;
import twitter4j.http.HeaderMap;
import twitter4j.http.HttpClientWrapper;
import twitter4j.http.HttpResponse;
@ -52,106 +59,134 @@ import static org.mariotaku.twidere.util.Utils.getTwitterProfileImageOfSize;
public class TwidereImageDownloader extends BaseImageDownloader implements Constants {
private final Context mContext;
private HttpClientWrapper mClient;
private boolean mFastImageLoading;
private final boolean mFullImage;
private final String mTwitterProfileImageSize;
private final Context mContext;
private final SharedPreferencesWrapper mPreferences;
private final boolean mUseThumbor;
private Thumbor mThumbor;
private HttpClientWrapper mClient;
private boolean mFastImageLoading;
private final boolean mFullImage;
private final String mTwitterProfileImageSize;
public TwidereImageDownloader(final Context context, final boolean fullImage) {
super(context);
mContext = context;
mFullImage = fullImage;
mTwitterProfileImageSize = context.getString(R.string.profile_image_size);
reloadConnectivitySettings();
}
public TwidereImageDownloader(final Context context, final boolean fullImage, final boolean useThumbor) {
super(context);
mContext = context;
mPreferences = SharedPreferencesWrapper.getInstance(context, SHARED_PREFERENCES_NAME,
Context.MODE_PRIVATE, SharedPreferenceConstants.class);
mFullImage = fullImage;
mTwitterProfileImageSize = context.getString(R.string.profile_image_size);
mUseThumbor = useThumbor;
reloadConnectivitySettings();
public void reloadConnectivitySettings() {
mClient = getImageLoaderHttpClient(mContext);
mFastImageLoading = mContext.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE).getBoolean(
KEY_FAST_IMAGE_LOADING, true);
}
}
@Override
protected InputStream getStreamFromNetwork(final String uriString, final Object extras) throws IOException {
if (uriString == null) return null;
final ParcelableMedia media = MediaPreviewUtils.getAllAvailableImage(uriString, mFullImage, mFullImage
|| !mFastImageLoading ? mClient : null);
try {
final String mediaUrl = media != null ? media.media_url : uriString;
if (isTwitterProfileImage(uriString)) {
final String replaced = getTwitterProfileImageOfSize(mediaUrl, mTwitterProfileImageSize);
return getStreamFromNetworkInternal(replaced, extras);
} else
return getStreamFromNetworkInternal(mediaUrl, extras);
} catch (final TwitterException e) {
final int statusCode = e.getStatusCode();
if (statusCode != -1 && isTwitterProfileImage(uriString) && !uriString.contains("_normal.")) {
try {
return getStreamFromNetworkInternal(getNormalTwitterProfileImage(uriString), extras);
} catch (final TwitterException e2) {
public void reloadConnectivitySettings() {
mClient = getImageLoaderHttpClient(mContext);
mFastImageLoading = mPreferences.getBoolean(KEY_FAST_IMAGE_LOADING);
if (mUseThumbor && mPreferences.getBoolean(KEY_THUMBOR_ENABLED)) {
final String address = mPreferences.getString(KEY_THUMBOR_ADDRESS, null);
final String securityKey = mPreferences.getString(KEY_THUMBOR_SECURITY_KEY, null);
if (URLUtil.isValidUrl(address)) {
if (TextUtils.isEmpty(securityKey)) {
mThumbor = Thumbor.create(address);
} else {
mThumbor = Thumbor.create(address, securityKey);
}
} else {
mThumbor = null;
}
} else {
mThumbor = null;
}
}
}
}
throw new IOException(String.format(Locale.US, "Error downloading image %s, error code: %d", uriString,
statusCode));
}
}
@Override
protected InputStream getStreamFromNetwork(final String uriString, final Object extras) throws IOException {
if (uriString == null) return null;
final ParcelableMedia media = MediaPreviewUtils.getAllAvailableImage(uriString, mFullImage, mFullImage
|| !mFastImageLoading ? mClient : null);
try {
final String mediaUrl = media != null ? media.media_url : uriString;
if (isTwitterProfileImage(uriString)) {
final String replaced = getTwitterProfileImageOfSize(mediaUrl, mTwitterProfileImageSize);
return getStreamFromNetworkInternal(replaced, extras);
} else
return getStreamFromNetworkInternal(mediaUrl, extras);
} catch (final TwitterException e) {
final int statusCode = e.getStatusCode();
if (statusCode != -1 && isTwitterProfileImage(uriString) && !uriString.contains("_normal.")) {
try {
return getStreamFromNetworkInternal(getNormalTwitterProfileImage(uriString), extras);
} catch (final TwitterException e2) {
private String getReplacedUri(final Uri uri, final String apiUrlFormat) {
if (uri == null) return null;
if (apiUrlFormat == null) return uri.toString();
if (isTwitterUri(uri)) {
final StringBuilder sb = new StringBuilder();
final String domain = uri.getHost().replaceAll("\\.?twitter.com", "");
final String path = uri.getPath();
sb.append(Utils.getApiUrl(apiUrlFormat, domain, path));
final String query = uri.getQuery();
if (!TextUtils.isEmpty(query)) {
sb.append("?");
sb.append(query);
}
final String fragment = uri.getFragment();
if (!TextUtils.isEmpty(fragment)) {
sb.append("#");
sb.append(fragment);
}
return sb.toString();
}
return uri.toString();
}
}
}
throw new IOException(String.format(Locale.US, "Error downloading image %s, error code: %d", uriString,
statusCode));
}
}
private ContentLengthInputStream getStreamFromNetworkInternal(final String uriString, final Object extras)
throws IOException, TwitterException {
final Uri uri = Uri.parse(uriString);
final Authorization auth;
final ParcelableCredentials account;
if (isTwitterAuthRequired(uri) && extras instanceof AccountExtra) {
final AccountExtra accountExtra = (AccountExtra) extras;
account = ParcelableAccount.getCredentials(mContext, accountExtra.account_id);
auth = getTwitterAuthorization(mContext, accountExtra.account_id);
} else {
account = null;
auth = null;
}
final String modifiedUri = getReplacedUri(uri, account != null ? account.api_url_format : null);
final HttpResponse resp = getRedirectedHttpResponse(mClient, modifiedUri, uriString, auth);
return new ContentLengthInputStream(resp.asStream(), (int) resp.getContentLength());
}
private String getReplacedUri(final Uri uri, final String apiUrlFormat) {
if (uri == null) return null;
if (apiUrlFormat == null) return uri.toString();
if (isTwitterUri(uri)) {
final StringBuilder sb = new StringBuilder();
final String domain = uri.getHost().replaceAll("\\.?twitter.com", "");
final String path = uri.getPath();
sb.append(Utils.getApiUrl(apiUrlFormat, domain, path));
final String query = uri.getQuery();
if (!TextUtils.isEmpty(query)) {
sb.append("?");
sb.append(query);
}
final String fragment = uri.getFragment();
if (!TextUtils.isEmpty(fragment)) {
sb.append("#");
sb.append(fragment);
}
return sb.toString();
}
return uri.toString();
}
private boolean isTwitterAuthRequired(final Uri uri) {
if (uri == null) return false;
return "ton.twitter.com".equalsIgnoreCase(uri.getHost());
}
private ContentLengthInputStream getStreamFromNetworkInternal(final String uriString, final Object extras)
throws IOException, TwitterException {
final Uri uri = Uri.parse(uriString);
final Authorization auth;
final ParcelableCredentials account;
if (isTwitterAuthRequired(uri) && extras instanceof AccountExtra) {
final AccountExtra accountExtra = (AccountExtra) extras;
account = ParcelableAccount.getCredentials(mContext, accountExtra.account_id);
auth = getTwitterAuthorization(mContext, accountExtra.account_id);
} else {
account = null;
auth = null;
}
String modifiedUri = getReplacedUri(uri, account != null ? account.api_url_format : null);
if (mThumbor != null) {
modifiedUri = mThumbor.buildImage(modifiedUri).filter(ThumborUrlBuilder.quality(85)).toUrl();
}
final HeaderMap additionalHeaders = new HeaderMap();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
additionalHeaders.addHeader("Accept", "image/webp, */*");
}
final HttpResponse resp = getRedirectedHttpResponse(mClient, modifiedUri, uriString, auth, additionalHeaders);
return new ContentLengthInputStream(resp.asStream(), (int) resp.getContentLength());
}
private boolean isTwitterProfileImage(final String uriString) {
if (TextUtils.isEmpty(uriString)) return false;
return PATTERN_TWITTER_PROFILE_IMAGES.matcher(uriString).matches();
}
private boolean isTwitterAuthRequired(final Uri uri) {
if (uri == null) return false;
return "ton.twitter.com".equalsIgnoreCase(uri.getHost());
}
private boolean isTwitterUri(final Uri uri) {
if (uri == null) return false;
return "ton.twitter.com".equalsIgnoreCase(uri.getHost());
}
private boolean isTwitterProfileImage(final String uriString) {
if (TextUtils.isEmpty(uriString)) return false;
return PATTERN_TWITTER_PROFILE_IMAGES.matcher(uriString).matches();
}
private boolean isTwitterUri(final Uri uri) {
if (uri == null) return false;
return "ton.twitter.com".equalsIgnoreCase(uri.getHost());
}
}

View File

@ -25,22 +25,18 @@ import android.util.AttributeSet;
import android.view.View;
public class MediaViewPager extends ViewPager {
public MediaViewPager(Context context) {
this(context, null);
}
public MediaViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
if (v instanceof TouchImageView) {
return v.canScrollHorizontally(dx);
} else {
return super.canScroll(v, checkV, dx, x, y);
}
}
public MediaViewPager(Context context) {
this(context, null);
}
public MediaViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
return super.canScroll(v, checkV, dx, x, y);
}
}

View File

@ -1,533 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.view;
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.animation.Animation;
import android.view.animation.LinearInterpolator;
import android.view.animation.Transformation;
import android.widget.ImageView;
import com.diegocarloslima.byakugallery.lib.FlingScroller;
import com.diegocarloslima.byakugallery.lib.TouchGestureDetector;
public class TouchImageView extends ImageView {
private static final int DOUBLE_TAP_ANIMATION_DURATION = 300;
private static final int SCALE_END_ANIMATION_DURATION = 200;
private Drawable mDrawable;
private int mDrawableIntrinsicWidth;
private int mDrawableIntrinsicHeight;
private final TouchGestureDetector mTouchGestureDetector;
private final Matrix mMatrix = new Matrix();
private final float[] mMatrixValues = new float[9];
private float mScale;
private float mMaxScale = 1;
private float mTranslationX;
private float mTranslationY;
private Float mLastFocusX;
private Float mLastFocusY;
private final FlingScroller mFlingScroller = new FlingScroller();
private boolean mIsAnimatingBack;
private ZoomListener mZoomListener;
public TouchImageView(Context context) {
this(context, null);
}
public TouchImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public TouchImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
final TouchGestureDetector.OnTouchGestureListener listener = new TouchGestureDetector.OnTouchGestureListener() {
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
return performClick();
}
@Override
public void onLongPress(MotionEvent e) {
performLongClick();
}
@Override
public boolean onDoubleTap(MotionEvent e) {
loadMatrixValues();
final float minScale = getMinScale();
// If we have already zoomed in, we should return to our initial scale value (minScale). Otherwise, scale to full size
final boolean shouldZoomOut = mScale > minScale;
final float targetScale = shouldZoomOut ? minScale : mMaxScale;
// First, we try to keep the focused point in the same position when the animation ends
final float desiredTranslationX = e.getX() - (e.getX() - mTranslationX) * (targetScale / mScale);
final float desiredTranslationY = e.getY() - (e.getY() - mTranslationY) * (targetScale / mScale);
// Here, we apply a correction to avoid unwanted blank spaces
final float targetTranslationX = desiredTranslationX + computeTranslation(getMeasuredWidth(), mDrawableIntrinsicWidth * targetScale, desiredTranslationX, 0);
final float targetTranslationY = desiredTranslationY + computeTranslation(getMeasuredHeight(), mDrawableIntrinsicHeight * targetScale, desiredTranslationY, 0);
clearAnimation();
final Animation animation = new TouchAnimation(targetScale, targetTranslationX, targetTranslationY);
animation.setDuration(DOUBLE_TAP_ANIMATION_DURATION);
startAnimation(animation);
if (mZoomListener != null) {
if (shouldZoomOut) {
mZoomListener.onZoomOut();
} else {
mZoomListener.onZoomIn();
}
}
return true;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
// Sometimes, this method is called just after an onScaleEnd event. In this case, we want to wait until we animate back our image
if (mIsAnimatingBack) {
return false;
}
loadMatrixValues();
final float currentDrawableWidth = mDrawableIntrinsicWidth * mScale;
final float currentDrawableHeight = mDrawableIntrinsicHeight * mScale;
final float dx = computeTranslation(getMeasuredWidth(), currentDrawableWidth, mTranslationX, -distanceX);
final float dy = computeTranslation(getMeasuredHeight(), currentDrawableHeight, mTranslationY, -distanceY);
mMatrix.postTranslate(dx, dy);
clearAnimation();
ViewCompat.postInvalidateOnAnimation(TouchImageView.this);
return true;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
// Sometimes, this method is called just after an onScaleEnd event. In this case, we want to wait until we animate back our image
if (mIsAnimatingBack) {
return false;
}
loadMatrixValues();
final float horizontalSideFreeSpace = (getMeasuredWidth() - mDrawableIntrinsicWidth * mScale) / 2F;
final float minTranslationX = horizontalSideFreeSpace > 0 ? horizontalSideFreeSpace : getMeasuredWidth() - mDrawableIntrinsicWidth * mScale;
final float maxTranslationX = horizontalSideFreeSpace > 0 ? horizontalSideFreeSpace : 0;
final float verticalSideFreeSpace = (getMeasuredHeight() - mDrawableIntrinsicHeight * mScale) / 2F;
final float minTranslationY = verticalSideFreeSpace > 0 ? verticalSideFreeSpace : getMeasuredHeight() - mDrawableIntrinsicHeight * mScale;
final float maxTranslationY = verticalSideFreeSpace > 0 ? verticalSideFreeSpace : 0;
// Using FlingScroller here. The results were better than the Scroller class
// https://android.googlesource.com/platform/packages/apps/Gallery2/+/master/src/com/android/gallery3d/ui/FlingScroller.java
mFlingScroller.fling(Math.round(mTranslationX), Math.round(mTranslationY), Math.round(velocityX), Math.round(velocityY), Math.round(minTranslationX), Math.round(maxTranslationX), Math.round(minTranslationY), Math.round(maxTranslationY));
clearAnimation();
final Animation animation = new FlingAnimation();
animation.setDuration(mFlingScroller.getDuration());
animation.setInterpolator(new LinearInterpolator());
startAnimation(animation);
return true;
}
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
mLastFocusX = null;
mLastFocusY = null;
return true;
}
@Override
public boolean onScale(ScaleGestureDetector detector) {
loadMatrixValues();
float currentDrawableWidth = mDrawableIntrinsicWidth * mScale;
float currentDrawableHeight = mDrawableIntrinsicHeight * mScale;
final float focusX = computeFocus(getMeasuredWidth(), currentDrawableWidth, mTranslationX, detector.getFocusX());
final float focusY = computeFocus(getMeasuredHeight(), currentDrawableHeight, mTranslationY, detector.getFocusY());
// Here, we provide the ability to scroll while scaling
if (mLastFocusX != null && mLastFocusY != null) {
final float dx = computeScaleTranslation(getMeasuredWidth(), currentDrawableWidth, mTranslationX, focusX - mLastFocusX);
final float dy = computeScaleTranslation(getMeasuredHeight(), currentDrawableHeight, mTranslationY, focusY - mLastFocusY);
if (dx != 0 || dy != 0) {
mMatrix.postTranslate(dx, dy);
}
}
final float scale = computeScale(getMinScale(), mMaxScale, mScale, detector.getScaleFactor());
mMatrix.postScale(scale, scale, focusX, focusY);
mLastFocusX = focusX;
mLastFocusY = focusY;
clearAnimation();
ViewCompat.postInvalidateOnAnimation(TouchImageView.this);
return true;
}
@Override
public void onScaleEnd(ScaleGestureDetector detector) {
loadMatrixValues();
final float currentDrawableWidth = mDrawableIntrinsicWidth * mScale;
final float currentDrawableHeight = mDrawableIntrinsicHeight * mScale;
final float dx = computeTranslation(getMeasuredWidth(), currentDrawableWidth, mTranslationX, 0);
final float dy = computeTranslation(getMeasuredHeight(), currentDrawableHeight, mTranslationY, 0);
if (Math.abs(dx) < 1 && Math.abs(dy) < 1) {
return;
}
final float targetTranslationX = mTranslationX + dx;
final float targetTranslationY = mTranslationY + dy;
clearAnimation();
final Animation animation = new TouchAnimation(mScale, targetTranslationX, targetTranslationY);
animation.setDuration(SCALE_END_ANIMATION_DURATION);
startAnimation(animation);
mIsAnimatingBack = true;
}
};
mTouchGestureDetector = new TouchGestureDetector(context, listener);
super.setScaleType(ScaleType.MATRIX);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int oldMeasuredWidth = getMeasuredWidth();
final int oldMeasuredHeight = getMeasuredHeight();
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (oldMeasuredWidth != getMeasuredWidth() || oldMeasuredHeight != getMeasuredHeight()) {
resetToInitialState();
}
}
@Override
protected void onDraw(Canvas canvas) {
super.setImageMatrix(mMatrix);
super.onDraw(canvas);
}
@Override
public void setImageMatrix(Matrix matrix) {
if (matrix == null) {
matrix = new Matrix();
}
if (!mMatrix.equals(matrix)) {
mMatrix.set(matrix);
invalidate();
}
}
@Override
public Matrix getImageMatrix() {
return mMatrix;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
mTouchGestureDetector.onTouchEvent(event);
return true;
}
@Override
public void clearAnimation() {
super.clearAnimation();
mIsAnimatingBack = false;
}
@Override
public void setImageDrawable(Drawable drawable) {
super.setImageDrawable(drawable);
if (mDrawable != drawable) {
mDrawable = drawable;
if (drawable != null) {
mDrawableIntrinsicWidth = drawable.getIntrinsicWidth();
mDrawableIntrinsicHeight = drawable.getIntrinsicHeight();
resetToInitialState();
} else {
mDrawableIntrinsicWidth = 0;
mDrawableIntrinsicHeight = 0;
}
}
}
@Override
public void setScaleType(ScaleType scaleType) {
if (scaleType != ScaleType.MATRIX) {
throw new IllegalArgumentException("Unsupported scaleType. Only ScaleType.MATRIX is allowed.");
}
super.setScaleType(scaleType);
}
@Override
public boolean canScrollHorizontally(int direction) {
loadMatrixValues();
return canScroll(getMeasuredWidth(), mDrawableIntrinsicWidth * mScale, mTranslationX, direction);
}
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
@Override
public boolean canScrollVertically(int direction) {
loadMatrixValues();
return canScroll(getMeasuredHeight(), mDrawableIntrinsicHeight * mScale, mTranslationY, direction);
}
public void setMaxScale(float maxScale) {
mMaxScale = maxScale;
}
public void resetScale() {
loadMatrixValues();
// If we have already zoomed in, we should return to our initial scale value (minScale). Otherwise, scale to full size
final float targetScale = getMinScale();
// First, we try to keep the focused point in the same position when the animation ends
final float desiredTranslationX = getWidth() / 2;
final float desiredTranslationY = getHeight() / 2;
// Here, we apply a correction to avoid unwanted blank spaces
final float targetTranslationX = desiredTranslationX + computeTranslation(getMeasuredWidth(), mDrawableIntrinsicWidth * targetScale, desiredTranslationX, 0);
final float targetTranslationY = desiredTranslationY + computeTranslation(getMeasuredHeight(), mDrawableIntrinsicHeight * targetScale, desiredTranslationY, 0);
clearAnimation();
final Animation animation = new TouchAnimation(targetScale, targetTranslationX, targetTranslationY);
animation.setDuration(0);
startAnimation(animation);
}
private void resetToInitialState() {
mMatrix.reset();
final float minScale = getMinScale();
mMatrix.postScale(minScale, minScale);
final float[] values = new float[9];
mMatrix.getValues(values);
final float freeSpaceHorizontal = (getMeasuredWidth() - (mDrawableIntrinsicWidth * minScale)) / 2F;
final float freeSpaceVertical = (getMeasuredHeight() - (mDrawableIntrinsicHeight * minScale)) / 2F;
mMatrix.postTranslate(freeSpaceHorizontal, freeSpaceVertical);
invalidate();
}
private void loadMatrixValues() {
mMatrix.getValues(mMatrixValues);
mScale = mMatrixValues[Matrix.MSCALE_X];
mTranslationX = mMatrixValues[Matrix.MTRANS_X];
mTranslationY = mMatrixValues[Matrix.MTRANS_Y];
}
private float getMinScale() {
float minScale = Math.min(getMeasuredWidth() / (float) mDrawableIntrinsicWidth, getMeasuredHeight() / (float) mDrawableIntrinsicHeight);
if (minScale > mMaxScale) {
minScale = mMaxScale;
}
return minScale;
}
private static boolean canScroll(float viewSize, float drawableSize, float currentTranslation, int direction) {
if (direction > 0) {
return Math.round(currentTranslation) < 0;
} else if (direction < 0) {
return Math.round(currentTranslation) > viewSize - Math.round(drawableSize);
}
return false;
}
// The translation values must be in [0, viewSize - drawableSize], except if we have free space. In that case we will translate to half of the free space
private static float computeTranslation(float viewSize, float drawableSize, float currentTranslation, float delta) {
final float sideFreeSpace = (viewSize - drawableSize) / 2F;
if (sideFreeSpace > 0) {
return sideFreeSpace - currentTranslation;
} else if (currentTranslation + delta > 0) {
return -currentTranslation;
} else if (currentTranslation + delta < viewSize - drawableSize) {
return viewSize - drawableSize - currentTranslation;
}
return delta;
}
private static float computeScaleTranslation(float viewSize, float drawableSize, float currentTranslation, float delta) {
final float minTranslation = viewSize > drawableSize ? 0 : viewSize - drawableSize;
final float maxTranslation = viewSize > drawableSize ? viewSize - drawableSize : 0;
if (currentTranslation < minTranslation && delta > 0) {
if (currentTranslation + delta > maxTranslation) {
return maxTranslation - currentTranslation;
} else {
return delta;
}
} else if (currentTranslation > maxTranslation && delta < 0) {
if (currentTranslation + delta < minTranslation) {
return minTranslation - currentTranslation;
} else {
return delta;
}
} else if (currentTranslation > minTranslation && currentTranslation < maxTranslation) {
if (currentTranslation + delta < minTranslation) {
return minTranslation - currentTranslation;
} else if (currentTranslation + delta > maxTranslation) {
return maxTranslation - currentTranslation;
} else {
return delta;
}
}
return 0;
}
// If our focal point is outside the image, we will project it to our image bounds
private static float computeFocus(float viewSize, float drawableSize, float currentTranslation, float focusCoordinate) {
if (currentTranslation > 0 && focusCoordinate < currentTranslation) {
return currentTranslation;
} else if (currentTranslation < viewSize - drawableSize && focusCoordinate > currentTranslation + drawableSize) {
return drawableSize + currentTranslation;
}
return focusCoordinate;
}
// The scale values must be in [minScale, maxScale]
private static float computeScale(float minScale, float maxScale, float currentScale, float delta) {
if (currentScale * delta < minScale) {
return minScale / currentScale;
} else if (currentScale * delta > maxScale) {
return maxScale / currentScale;
}
return delta;
}
private class FlingAnimation extends Animation {
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
mFlingScroller.computeScrollOffset(interpolatedTime);
loadMatrixValues();
final float dx = mFlingScroller.getCurrX() - mTranslationX;
final float dy = mFlingScroller.getCurrY() - mTranslationY;
mMatrix.postTranslate(dx, dy);
ViewCompat.postInvalidateOnAnimation(TouchImageView.this);
}
}
private class TouchAnimation extends Animation {
private float initialScale;
private float initialTranslationX;
private float initialTranslationY;
private float targetScale;
private float targetTranslationX;
private float targetTranslationY;
TouchAnimation(float targetScale, float targetTranslationX, float targetTranslationY) {
loadMatrixValues();
this.initialScale = mScale;
this.initialTranslationX = mTranslationX;
this.initialTranslationY = mTranslationY;
this.targetScale = targetScale;
this.targetTranslationX = targetTranslationX;
this.targetTranslationY = targetTranslationY;
}
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
loadMatrixValues();
if (interpolatedTime >= 1) {
mMatrix.getValues(mMatrixValues);
mMatrixValues[Matrix.MSCALE_X] = this.targetScale;
mMatrixValues[Matrix.MSCALE_Y] = this.targetScale;
mMatrixValues[Matrix.MTRANS_X] = this.targetTranslationX;
mMatrixValues[Matrix.MTRANS_Y] = this.targetTranslationY;
mMatrix.setValues(mMatrixValues);
} else {
final float scaleFactor = (this.initialScale + interpolatedTime * (this.targetScale - this.initialScale)) / mScale;
mMatrix.postScale(scaleFactor, scaleFactor);
mMatrix.getValues(mMatrixValues);
final float currentTranslationX = mMatrixValues[Matrix.MTRANS_X];
final float currentTranslationY = mMatrixValues[Matrix.MTRANS_Y];
final float dx = this.initialTranslationX + interpolatedTime * (this.targetTranslationX - this.initialTranslationX) - currentTranslationX;
final float dy = this.initialTranslationY + interpolatedTime * (this.targetTranslationY - this.initialTranslationY) - currentTranslationY;
mMatrix.postTranslate(dx, dy);
}
ViewCompat.postInvalidateOnAnimation(TouchImageView.this);
}
}
public void setZoomListener(ZoomListener listener) {
mZoomListener = listener;
}
public static interface ZoomListener {
void onZoomOut();
void onZoomIn();
}
}

View File

@ -2,7 +2,6 @@ package org.mariotaku.twidere.view.holder;
import android.content.Context;
import android.database.Cursor;
import android.graphics.PorterDuff.Mode;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.widget.CardView;
@ -35,6 +34,7 @@ import org.mariotaku.twidere.util.UserColorNameUtils;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.util.Utils.OnMediaClickListener;
import org.mariotaku.twidere.view.CardMediaContainer;
import org.mariotaku.twidere.view.ForegroundColorView;
import org.mariotaku.twidere.view.ShapedImageView;
import org.mariotaku.twidere.view.ShortTimeView;
import org.mariotaku.twidere.view.iface.IColorLabelView;
@ -62,12 +62,16 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements Constan
private final ImageView profileTypeView;
private final ImageView extraTypeView;
private final TextView textView;
private final TextView quoteTextView;
private final TextView nameView, screenNameView;
private final TextView quotedNameView, quotedScreenNameView;
private final TextView replyRetweetView;
private final ShortTimeView timeView;
private final CardMediaContainer mediaPreviewContainer;
private final CardMediaContainer mediaPreview;
private final TextView replyCountView, retweetCountView, favoriteCountView;
private final View quotedNameContainer;
private final IColorLabelView itemContent;
private final ForegroundColorView quoteIndicator;
private StatusClickListener statusClickListener;
@ -79,13 +83,19 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements Constan
profileTypeView = (ImageView) itemView.findViewById(R.id.profile_type);
extraTypeView = (ImageView) itemView.findViewById(R.id.extra_type);
textView = (TextView) itemView.findViewById(R.id.text);
quoteTextView = (TextView) itemView.findViewById(R.id.quote_text);
nameView = (TextView) itemView.findViewById(R.id.name);
screenNameView = (TextView) itemView.findViewById(R.id.screen_name);
quotedNameView = (TextView) itemView.findViewById(R.id.quoted_name);
quotedScreenNameView = (TextView) itemView.findViewById(R.id.quoted_screen_name);
replyRetweetIcon = (ImageView) itemView.findViewById(R.id.reply_retweet_icon);
replyRetweetView = (TextView) itemView.findViewById(R.id.reply_retweet_status);
timeView = (ShortTimeView) itemView.findViewById(R.id.time);
mediaPreviewContainer = (CardMediaContainer) itemView.findViewById(R.id.media_preview_container);
mediaPreview = (CardMediaContainer) itemView.findViewById(R.id.media_preview);
quotedNameContainer = itemView.findViewById(R.id.quoted_name_container);
quoteIndicator = (ForegroundColorView) itemView.findViewById(R.id.quote_indicator);
replyCountView = (TextView) itemView.findViewById(R.id.reply_count);
retweetCountView = (TextView) itemView.findViewById(R.id.retweet_count);
@ -100,7 +110,7 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements Constan
screenNameView.setText("@" + TWIDERE_PREVIEW_SCREEN_NAME);
textView.setText(toPlainText(TWIDERE_PREVIEW_TEXT_HTML));
timeView.setTime(System.currentTimeMillis());
mediaPreviewContainer.displayMedia(R.drawable.nyan_stars_background);
mediaPreview.displayMedia(R.drawable.nyan_stars_background);
}
public void displayStatus(final ParcelableStatus status, final boolean displayInReplyTo) {
@ -109,42 +119,35 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements Constan
public void displayStatus(@NonNull final ParcelableStatus status, @Nullable final TranslationResult translation,
final boolean displayInReplyTo, final boolean shouldDisplayExtraType) {
final Context context = adapter.getContext();
final MediaLoaderWrapper loader = adapter.getImageLoader();
final ImageLoadingHandler handler = adapter.getImageLoadingHandler();
final AsyncTwitterWrapper twitter = adapter.getTwitterWrapper();
final TwidereLinkify linkify = adapter.getTwidereLinkify();
final boolean displayProfileImage = adapter.isProfileImageEnabled();
final boolean displayMediaPreview = adapter.isMediaPreviewEnabled();
final boolean displayAccountsColor = adapter.shouldShowAccountsColor();
final Context context = adapter.getContext();
final boolean nameFirst = adapter.isNameFirst();
final int profileImageStyle = adapter.getProfileImageStyle();
final int mediaPreviewStyle = adapter.getMediaPreviewStyle();
final int linkHighlightingStyle = adapter.getLinkHighlightingStyle();
final ParcelableMedia[] media = status.media;
replyRetweetIcon.setColorFilter(replyRetweetView.getCurrentTextColor(), Mode.SRC_ATOP);
final long reply_count = status.reply_count;
final long retweet_count;
final long favorite_count;
if (status.retweet_id > 0) {
replyRetweetView.setVisibility(View.VISIBLE);
replyRetweetIcon.setVisibility(View.VISIBLE);
final String retweetedBy = UserColorNameUtils.getDisplayName(context, status.retweeted_by_id,
status.retweeted_by_name, status.retweeted_by_screen_name, nameFirst);
replyRetweetView.setText(context.getString(R.string.name_retweeted, retweetedBy));
replyRetweetIcon.setImageResource(R.drawable.ic_activity_action_retweet);
} else if (status.in_reply_to_status_id > 0 && status.in_reply_to_user_id > 0 && displayInReplyTo) {
replyRetweetView.setVisibility(View.VISIBLE);
replyRetweetIcon.setVisibility(View.VISIBLE);
} else if (status.in_reply_to_status_id > 0 && status.in_reply_to_user_id > 0 && displayInReplyTo) {
final String inReplyTo = UserColorNameUtils.getDisplayName(context, status.in_reply_to_user_id,
status.in_reply_to_name, status.in_reply_to_screen_name, nameFirst);
replyRetweetView.setText(context.getString(R.string.in_reply_to_name, inReplyTo));
replyRetweetIcon.setImageResource(R.drawable.ic_activity_action_reply);
replyRetweetView.setVisibility(View.VISIBLE);
replyRetweetIcon.setVisibility(View.VISIBLE);
} else {
replyRetweetView.setVisibility(View.GONE);
replyRetweetIcon.setVisibility(View.GONE);
replyRetweetView.setText(null);
}
final int typeIconRes = getUserTypeIconRes(status.user_is_verified, status.user_is_protected);
if (typeIconRes != 0) {
profileTypeView.setImageResource(typeIconRes);
@ -154,64 +157,102 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements Constan
profileTypeView.setVisibility(View.GONE);
}
nameView.setText(status.user_name);
screenNameView.setText("@" + status.user_screen_name);
timeView.setTime(status.timestamp);
if (status.is_quote) {
quotedNameView.setText(status.user_name);
quotedScreenNameView.setText("@" + status.user_screen_name);
timeView.setTime(status.quote_timestamp);
nameView.setText(status.quoted_by_user_name);
screenNameView.setText("@" + status.quoted_by_user_screen_name);
final int userColor = UserColorNameUtils.getUserColor(context, status.user_id);
itemContent.drawStart(userColor);
if (adapter.getLinkHighlightingStyle() == VALUE_LINK_HIGHLIGHT_OPTION_CODE_NONE) {
quoteTextView.setText(status.quote_text_unescaped);
} else {
quoteTextView.setText(Html.fromHtml(status.quote_text_html));
linkify.applyAllLinks(quoteTextView, status.account_id, getLayoutPosition(),
status.is_possibly_sensitive, adapter.getLinkHighlightingStyle());
quoteTextView.setMovementMethod(null);
}
if (displayAccountsColor) {
quotedNameContainer.setVisibility(View.VISIBLE);
quoteTextView.setVisibility(View.VISIBLE);
quoteIndicator.setVisibility(View.VISIBLE);
quoteIndicator.setColor(UserColorNameUtils.getUserColor(context, status.user_id));
if (adapter.isProfileImageEnabled()) {
profileTypeView.setVisibility(View.VISIBLE);
profileImageView.setVisibility(View.VISIBLE);
loader.displayProfileImage(profileImageView, status.quoted_by_user_profile_image);
} else {
profileTypeView.setVisibility(View.GONE);
profileImageView.setVisibility(View.GONE);
loader.cancelDisplayTask(profileImageView);
}
final int userColor = UserColorNameUtils.getUserColor(context, status.quoted_by_user_id);
itemContent.drawStart(userColor);
} else {
nameView.setText(status.user_name);
screenNameView.setText("@" + status.user_screen_name);
timeView.setTime(status.timestamp);
quotedNameContainer.setVisibility(View.GONE);
quoteTextView.setVisibility(View.GONE);
quoteIndicator.setVisibility(View.GONE);
if (adapter.isProfileImageEnabled()) {
final String user_profile_image_url = status.user_profile_image_url;
profileTypeView.setVisibility(View.VISIBLE);
profileImageView.setVisibility(View.VISIBLE);
loader.displayProfileImage(profileImageView, user_profile_image_url);
} else {
profileTypeView.setVisibility(View.GONE);
profileImageView.setVisibility(View.GONE);
loader.cancelDisplayTask(profileImageView);
}
final int userColor = UserColorNameUtils.getUserColor(context, status.user_id);
itemContent.drawStart(userColor);
}
if (adapter.shouldShowAccountsColor()) {
itemContent.drawEnd(Utils.getAccountColor(context, status.account_id));
} else {
itemContent.drawEnd();
}
profileImageView.setStyle(profileImageStyle);
if (displayProfileImage) {
profileTypeView.setVisibility(View.VISIBLE);
profileImageView.setVisibility(View.VISIBLE);
loader.displayProfileImage(profileImageView, status.user_profile_image_url);
} else {
profileTypeView.setVisibility(View.GONE);
profileImageView.setVisibility(View.GONE);
loader.cancelDisplayTask(profileImageView);
}
if (displayMediaPreview) {
mediaPreviewContainer.setStyle(mediaPreviewStyle);
if (media != null && media.length > 0) {
mediaPreviewContainer.setVisibility(View.VISIBLE);
} else {
mediaPreviewContainer.setVisibility(View.GONE);
}
mediaPreviewContainer.displayMedia(media, loader, status.account_id, this, handler);
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());
} else {
mediaPreviewContainer.setVisibility(View.GONE);
mediaPreview.setVisibility(View.GONE);
}
if (translation != null) {
textView.setText(translation.getText());
} else if (linkHighlightingStyle == VALUE_LINK_HIGHLIGHT_OPTION_CODE_NONE) {
if (adapter.getLinkHighlightingStyle() == VALUE_LINK_HIGHLIGHT_OPTION_CODE_NONE) {
textView.setText(status.text_unescaped);
} else {
textView.setText(Html.fromHtml(status.text_html));
linkify.applyAllLinks(textView, status.account_id, getLayoutPosition(),
status.is_possibly_sensitive, linkHighlightingStyle);
status.is_possibly_sensitive,
adapter.getLinkHighlightingStyle());
textView.setMovementMethod(null);
}
if (status.reply_count > 0) {
replyCountView.setText(Utils.getLocalizedNumber(Locale.getDefault(), status.reply_count));
if (reply_count > 0) {
replyCountView.setText(Utils.getLocalizedNumber(Locale.getDefault(), reply_count));
} else {
replyCountView.setText(null);
}
final long retweet_count;
if (twitter.isDestroyingStatus(status.account_id, status.my_retweet_id)) {
retweetCountView.setActivated(false);
retweet_count = Math.max(0, status.favorite_count - 1);
retweet_count = Math.max(0, status.retweet_count - 1);
} else {
final boolean creatingRetweet = twitter.isCreatingRetweet(status.account_id, status.id);
retweetCountView.setActivated(creatingRetweet || Utils.isMyRetweet(status));
retweetCountView.setActivated(creatingRetweet || Utils.isMyRetweet(status.account_id,
status.retweeted_by_id, status.my_retweet_id));
retweet_count = status.retweet_count + (creatingRetweet ? 1 : 0);
}
if (retweet_count > 0) {
@ -219,9 +260,6 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements Constan
} else {
retweetCountView.setText(null);
}
retweetCountView.setEnabled(!status.user_is_protected);
final long favorite_count;
if (twitter.isDestroyingFavorite(status.account_id, status.id)) {
favoriteCountView.setActivated(false);
favorite_count = Math.max(0, status.favorite_count - 1);
@ -255,7 +293,6 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements Constan
final long favorite_count;
final long account_id = cursor.getLong(indices.account_id);
final long timestamp = cursor.getLong(indices.status_timestamp);
final long user_id = cursor.getLong(indices.user_id);
final long status_id = cursor.getLong(indices.status_id);
final long retweet_id = cursor.getLong(indices.retweet_id);
@ -264,15 +301,8 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements Constan
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);
final boolean user_is_protected = cursor.getInt(indices.is_protected) == 1;
final String user_name = cursor.getString(indices.user_name);
final String user_screen_name = cursor.getString(indices.user_screen_name);
final String user_profile_image_url = cursor.getString(indices.user_profile_image_url);
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 in_reply_to_name = cursor.getString(indices.in_reply_to_user_name);
final String in_reply_to_screen_name = cursor.getString(indices.in_reply_to_user_screen_name);
final String card_name = cursor.getString(indices.card_name);
final String place_full_name = cursor.getString(indices.place_full_name);
@ -282,6 +312,8 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements Constan
cursor.getString(indices.location));
if (retweet_id > 0) {
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,
retweeted_by_name, retweeted_by_screen_name, nameFirst);
replyRetweetView.setText(context.getString(R.string.name_retweeted, retweetedBy));
@ -289,6 +321,8 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements Constan
replyRetweetView.setVisibility(View.VISIBLE);
replyRetweetIcon.setVisibility(View.VISIBLE);
} else if (in_reply_to_status_id > 0 && in_reply_to_user_id > 0 && displayInReplyTo) {
final String in_reply_to_name = cursor.getString(indices.in_reply_to_user_name);
final String in_reply_to_screen_name = cursor.getString(indices.in_reply_to_user_screen_name);
final String inReplyTo = UserColorNameUtils.getDisplayName(context, in_reply_to_user_id,
in_reply_to_name, in_reply_to_screen_name, nameFirst);
replyRetweetView.setText(context.getString(R.string.in_reply_to_name, inReplyTo));
@ -300,8 +334,8 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements Constan
replyRetweetIcon.setVisibility(View.GONE);
}
final int typeIconRes = getUserTypeIconRes(cursor.getInt(indices.is_verified) == 1,
user_is_protected);
final int typeIconRes = getUserTypeIconRes(cursor.getShort(indices.is_verified) == 1,
cursor.getShort(indices.is_protected) == 1);
if (typeIconRes != 0) {
profileTypeView.setImageResource(typeIconRes);
profileTypeView.setVisibility(View.VISIBLE);
@ -310,12 +344,64 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements Constan
profileTypeView.setVisibility(View.GONE);
}
nameView.setText(user_name);
screenNameView.setText("@" + user_screen_name);
timeView.setTime(timestamp);
if (cursor.getShort(indices.is_quote) == 1) {
quotedNameView.setText(user_name);
quotedScreenNameView.setText("@" + user_screen_name);
timeView.setTime(cursor.getLong(indices.quote_timestamp));
nameView.setText(cursor.getString(indices.quoted_by_user_name));
screenNameView.setText("@" + cursor.getString(indices.quoted_by_user_screen_name));
if (adapter.getLinkHighlightingStyle() == VALUE_LINK_HIGHLIGHT_OPTION_CODE_NONE) {
quoteTextView.setText(cursor.getString(indices.quote_text_unescaped));
} else {
quoteTextView.setText(Html.fromHtml(cursor.getString(indices.quote_text_html)));
linkify.applyAllLinks(quoteTextView, account_id, getLayoutPosition(),
cursor.getShort(indices.is_possibly_sensitive) == 1,
adapter.getLinkHighlightingStyle());
quoteTextView.setMovementMethod(null);
}
quotedNameContainer.setVisibility(View.VISIBLE);
quoteTextView.setVisibility(View.VISIBLE);
quoteIndicator.setVisibility(View.VISIBLE);
quoteIndicator.setColor(UserColorNameUtils.getUserColor(context, user_id));
if (adapter.isProfileImageEnabled()) {
profileTypeView.setVisibility(View.VISIBLE);
profileImageView.setVisibility(View.VISIBLE);
loader.displayProfileImage(profileImageView, cursor.getString(indices.quoted_by_user_profile_image));
} else {
profileTypeView.setVisibility(View.GONE);
profileImageView.setVisibility(View.GONE);
loader.cancelDisplayTask(profileImageView);
}
final int userColor = UserColorNameUtils.getUserColor(context, cursor.getLong(indices.quoted_by_user_id));
itemContent.drawStart(userColor);
} else {
nameView.setText(user_name);
screenNameView.setText("@" + user_screen_name);
timeView.setTime(cursor.getLong(indices.status_timestamp));
quotedNameContainer.setVisibility(View.GONE);
quoteTextView.setVisibility(View.GONE);
quoteIndicator.setVisibility(View.GONE);
if (adapter.isProfileImageEnabled()) {
final String user_profile_image_url = cursor.getString(indices.user_profile_image_url);
profileTypeView.setVisibility(View.VISIBLE);
profileImageView.setVisibility(View.VISIBLE);
loader.displayProfileImage(profileImageView, user_profile_image_url);
} else {
profileTypeView.setVisibility(View.GONE);
profileImageView.setVisibility(View.GONE);
loader.cancelDisplayTask(profileImageView);
}
final int userColor = UserColorNameUtils.getUserColor(context, user_id);
itemContent.drawStart(userColor);
}
final int userColor = UserColorNameUtils.getUserColor(context, user_id);
itemContent.drawStart(userColor);
if (adapter.shouldShowAccountsColor()) {
itemContent.drawEnd(Utils.getAccountColor(context, account_id));
@ -323,25 +409,14 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements Constan
itemContent.drawEnd();
}
profileImageView.setStyle(adapter.getProfileImageStyle());
if (adapter.isProfileImageEnabled()) {
profileTypeView.setVisibility(View.VISIBLE);
profileImageView.setVisibility(View.VISIBLE);
loader.displayProfileImage(profileImageView, user_profile_image_url);
} else {
profileTypeView.setVisibility(View.GONE);
profileImageView.setVisibility(View.GONE);
loader.cancelDisplayTask(profileImageView);
}
if (adapter.isMediaPreviewEnabled()) {
mediaPreviewContainer.setStyle(adapter.getMediaPreviewStyle());
mediaPreviewContainer.setVisibility(media != null && media.length > 0 ? View.VISIBLE : View.GONE);
mediaPreviewContainer.displayMedia(media, loader, account_id, this,
mediaPreview.setStyle(adapter.getMediaPreviewStyle());
mediaPreview.setVisibility(media != null && media.length > 0 ? View.VISIBLE : View.GONE);
mediaPreview.displayMedia(media, loader, account_id, this,
adapter.getImageLoadingHandler());
} else {
mediaPreviewContainer.setVisibility(View.GONE);
mediaPreview.setVisibility(View.GONE);
}
if (adapter.getLinkHighlightingStyle() == VALUE_LINK_HIGHLIGHT_OPTION_CODE_NONE) {
textView.setText(cursor.getString(indices.text_unescaped));
@ -350,6 +425,7 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements Constan
linkify.applyAllLinks(textView, account_id, getLayoutPosition(),
cursor.getShort(indices.is_possibly_sensitive) == 1,
adapter.getLinkHighlightingStyle());
textView.setMovementMethod(null);
}
if (reply_count > 0) {
@ -372,15 +448,12 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements Constan
} else {
retweetCountView.setText(null);
}
retweetCountView.setEnabled(!user_is_protected);
favoriteCountView.setActivated(cursor.getInt(indices.is_favorite) == 1);
if (twitter.isDestroyingFavorite(account_id, status_id)) {
favoriteCountView.setActivated(false);
favorite_count = Math.max(0, cursor.getLong(indices.favorite_count) - 1);
} else {
final boolean creatingFavorite = twitter.isCreatingFavorite(account_id, status_id);
favoriteCountView.setActivated(creatingFavorite || cursor.getInt(indices.is_favorite) == 1);
favoriteCountView.setActivated(creatingFavorite || cursor.getShort(indices.is_favorite) == 1);
favorite_count = cursor.getLong(indices.favorite_count) + (creatingFavorite ? 1 : 0);
}
if (favorite_count > 0) {
@ -454,8 +527,11 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements Constan
public void setTextSize(final float textSize) {
nameView.setTextSize(textSize);
quotedNameView.setTextSize(textSize);
textView.setTextSize(textSize);
quoteTextView.setTextSize(textSize);
screenNameView.setTextSize(textSize * 0.85f);
quotedScreenNameView.setTextSize(textSize * 0.85f);
timeView.setTextSize(textSize * 0.85f);
replyRetweetView.setTextSize(textSize * 0.75f);
replyCountView.setTextSize(textSize);
@ -465,7 +541,8 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements Constan
public void setupViewOptions() {
setTextSize(adapter.getTextSize());
mediaPreviewContainer.setStyle(adapter.getMediaPreviewStyle());
mediaPreview.setStyle(adapter.getMediaPreviewStyle());
profileImageView.setStyle(adapter.getProfileImageStyle());
}
private void displayExtraTypeIcon(String cardName, ParcelableMedia[] media, ParcelableLocation location, String placeFullName) {

View File

@ -96,32 +96,35 @@ public interface IForegroundView {
}
public void dispatchOnDraw(final Canvas canvas) {
if (mForeground != null) {
final Drawable foreground = mForeground;
draw(canvas);
}
if (mForegroundBoundsChanged) {
mForegroundBoundsChanged = false;
final Rect selfBounds = mSelfBounds;
final Rect overlayBounds = mOverlayBounds;
public void draw(Canvas canvas) {
final Drawable foreground = mForeground;
if (foreground == null) return;
final int w = mView.getRight() - mView.getLeft();
final int h = mView.getBottom() - mView.getTop();
if (mForegroundBoundsChanged) {
mForegroundBoundsChanged = false;
final Rect selfBounds = mSelfBounds;
final Rect overlayBounds = mOverlayBounds;
if (mForegroundInPadding) {
selfBounds.set(0, 0, w, h);
} else {
selfBounds.set(mView.getPaddingLeft(), mView.getPaddingTop(), w - mView.getPaddingRight(), h
- mView.getPaddingBottom());
}
final int w = mView.getRight() - mView.getLeft();
final int h = mView.getBottom() - mView.getTop();
final int layoutDirection = ViewCompat.getLayoutDirection(mView);
GravityCompat.apply(mForegroundGravity, foreground.getIntrinsicWidth(),
foreground.getIntrinsicHeight(), selfBounds, overlayBounds, layoutDirection);
foreground.setBounds(overlayBounds);
if (mForegroundInPadding) {
selfBounds.set(0, 0, w, h);
} else {
selfBounds.set(mView.getPaddingLeft(), mView.getPaddingTop(), w - mView.getPaddingRight(), h
- mView.getPaddingBottom());
}
foreground.draw(canvas);
final int layoutDirection = ViewCompat.getLayoutDirection(mView);
GravityCompat.apply(mForegroundGravity, foreground.getIntrinsicWidth(),
foreground.getIntrinsicHeight(), selfBounds, overlayBounds, layoutDirection);
foreground.setBounds(overlayBounds);
}
foreground.draw(canvas);
}
public void dispatchOnLayout(final boolean changed, final int left, final int top, final int right,
@ -133,35 +136,6 @@ public interface IForegroundView {
mForegroundBoundsChanged = true;
}
public void draw(final Canvas canvas) {
if (mForeground != null) {
final Drawable foreground = mForeground;
if (mForegroundBoundsChanged) {
mForegroundBoundsChanged = false;
final Rect selfBounds = mSelfBounds;
final Rect overlayBounds = mOverlayBounds;
final int w = mView.getRight() - mView.getLeft();
final int h = mView.getBottom() - mView.getTop();
if (mForegroundInPadding) {
selfBounds.set(0, 0, w, h);
} else {
selfBounds.set(mView.getPaddingLeft(), mView.getPaddingTop(), w - mView.getPaddingRight(), h
- mView.getPaddingBottom());
}
final int layoutDirection = ViewCompat.getLayoutDirection(mView);
GravityCompat.apply(mForegroundGravity, foreground.getIntrinsicWidth(),
foreground.getIntrinsicHeight(), selfBounds, overlayBounds, layoutDirection);
foreground.setBounds(overlayBounds);
}
foreground.draw(canvas);
}
}
public void drawableStateChanged() {
if (mForeground != null && mForeground.isStateful()) {
mForeground.setState(mView.getDrawableState());

View File

@ -263,8 +263,8 @@
<string name="Nitems_selected_quantity_other"><xliff:g id="items">%d</xliff:g> العناصر المحددة</string>
<string name="view">عرض</string>
<string name="custom_host_mapping">تعيين المضيف مخصص</string>
<string name="host">المضيف</string>
<string name="address">العنوان (يمكن أن يكون عنوان مضيف آخر)</string>
<string name="host_mapping_host">المضيف</string>
<string name="host_mapping_address">العنوان (يمكن أن يكون عنوان مضيف آخر)</string>
<string name="dns_server">خادم DNS</string>
<string name="activities_about_me">الاحداث المتعلقة بي</string>
<string name="activities_by_friends">أنشطة الأصدقاء</string>

View File

@ -271,8 +271,8 @@
<string name="view">Mostra</string>
<string name="custom_host_mapping">Associacions de servidors personalitzades</string>
<string name="custom_host_mapping_summary">Associa servidors com el fitxer /etc/hosts sense requerir permisos addicionals.</string>
<string name="host">Servidor</string>
<string name="address">Adreça (pot ser una altra adreça de servidor)</string>
<string name="host_mapping_host">Servidor</string>
<string name="host_mapping_address">Adreça (pot ser una altra adreça de servidor)</string>
<string name="add_host_mapping">Afegeix una associació de servidor</string>
<string name="tcp_dns_query">Petició DNS per TCP</string>
<string name="tcp_dns_query_summary">Utilitza el protocol TCP per fer peticions DNS per evitar l\'«Enverinament de la Memòria Cau de DNS».</string>

View File

@ -271,8 +271,8 @@
<string name="view">Ansicht</string>
<string name="custom_host_mapping">Individuelles Host-Mapping</string>
<string name="custom_host_mapping_summary">Host-Mapping wie /ect/hosts, ohne zusätzlich erforderliche Rechte.</string>
<string name="host">Host</string>
<string name="address">Adresse(Kann auch eine andere Host-Adresse sein)</string>
<string name="host_mapping_host">Host</string>
<string name="host_mapping_address">Adresse(Kann auch eine andere Host-Adresse sein)</string>
<string name="add_host_mapping">Füge host mapping hinzu</string>
<string name="tcp_dns_query">TCP DNS-Abfrage</string>
<string name="tcp_dns_query_summary">Benutze TCP für DNS Anfragen, um DNS Cache Poisoning zu vermeiden.</string>

View File

@ -273,8 +273,8 @@
<string name="view">Vista</string>
<string name="custom_host_mapping">Asignación de host personalizado</string>
<string name="custom_host_mapping_summary">Funciona como \"/etc/hosts\", pero no requiere permisos adicionales.</string>
<string name="host">Host</string>
<string name="address">Dirección (puede ser otra dirección de host)</string>
<string name="host_mapping_host">Host</string>
<string name="host_mapping_address">Dirección (puede ser otra dirección de host)</string>
<string name="add_host_mapping">Añadir asignación de host</string>
<string name="tcp_dns_query">Consulta DNS usando TCP</string>
<string name="tcp_dns_query_summary">Utilizar el protocolo TCP para las peticiones DNS, puede evitar envenenamiento de caché DNS.</string>

View File

@ -270,8 +270,8 @@
<string name="view">Näytä</string>
<string name="custom_host_mapping">Mukautettu Host Mapping -määrittely</string>
<string name="custom_host_mapping_summary">Verkkonimet määritellään kuten /etc/hosts -tiedostossa, mutta ylimääräisiä oikeuksia ei tarvita.</string>
<string name="host">Host</string>
<string name="address">Osoite (voi olla toinen host-osoite)</string>
<string name="host_mapping_host">Host</string>
<string name="host_mapping_address">Osoite (voi olla toinen host-osoite)</string>
<string name="add_host_mapping">Lisää host mapping</string>
<string name="tcp_dns_query">TCP DNS -kysely</string>
<string name="tcp_dns_query_summary">Käytä TCP-yhteyskäytäntöä DNS-pyyntöihin, jotta vältyttäisiin DNS Cache Poisoning -verkkohuijauksilta.</string>

View File

@ -271,8 +271,8 @@
<string name="view">Voir</string>
<string name="custom_host_mapping">Mappage d\'hôte personnalisée</string>
<string name="custom_host_mapping_summary">Mappage d\'hôte comme /etc/hosts, mais n\'exige pas de permissions supplémentaires.</string>
<string name="host">Hôte</string>
<string name="address">Adresse (peut-être une autre adresse hôte)</string>
<string name="host_mapping_host">Hôte</string>
<string name="host_mapping_address">Adresse (peut-être une autre adresse hôte)</string>
<string name="add_host_mapping">Ajouter un hôte personnalisé</string>
<string name="tcp_dns_query">Requête DNS TCP</string>
<string name="tcp_dns_query_summary">Utiliser le protocole TCP pour faire des requêtes DNS, cela peut éviter un empoisonnement du cache DNS.</string>

View File

@ -243,8 +243,8 @@
<string name="view">Nézet</string>
<string name="custom_host_mapping">Egyedi host hozzárendelés</string>
<string name="custom_host_mapping_summary">Host hozzárendelés, mint a /etc/hosts, de nem kell hozzá plusz jog.</string>
<string name="host">Host</string>
<string name="address">Cím (Lehet egy másik host címe)</string>
<string name="host_mapping_host">Host</string>
<string name="host_mapping_address">Cím (Lehet egy másik host címe)</string>
<string name="add_host_mapping">Host hozzárendelés hozzáadása</string>
<string name="tcp_dns_query">TCP DNS lekérdezés</string>
<string name="tcp_dns_query_summary">DNS lekérdezések TCP protokoll felett, ezzel elkerülhető a DNS gyorsítótár mérgezés.</string>

View File

@ -273,8 +273,8 @@
<string name="view">Lihat</string>
<string name="custom_host_mapping">Kustom host mapping</string>
<string name="custom_host_mapping_summary">Host pemetaan sperti /etc/hosts, tanpa butuh permisi tambahan.</string>
<string name="host">Host</string>
<string name="address">Alamat (dapat berupa alamat host lain)</string>
<string name="host_mapping_host">Host</string>
<string name="host_mapping_address">Alamat (dapat berupa alamat host lain)</string>
<string name="add_host_mapping">Tambah pemetaan host</string>
<string name="tcp_dns_query">TCP DNS Query</string>
<string name="tcp_dns_query_summary">Gunakan protokol TCP untuk permintaan DNS dan menghindari DNS Cache Posioning.</string>

View File

@ -273,8 +273,8 @@
<string name="view">Visualizza</string>
<string name="custom_host_mapping">Mappatura host personalizzata</string>
<string name="custom_host_mapping_summary">Mappa gli host come in /etc/hosts, ma non richiede permessi aggiuntivi.</string>
<string name="host">Host</string>
<string name="address">Indirizzo (può essere un altro indirizzo host)</string>
<string name="host_mapping_host">Host</string>
<string name="host_mapping_address">Indirizzo (può essere un altro indirizzo host)</string>
<string name="add_host_mapping">Aggiungi mappatura host</string>
<string name="tcp_dns_query">TCP DNS Query</string>
<string name="tcp_dns_query_summary">Usa il protocollo TCP per effettuare le richieste DNS, utile per evitare il DNS Cache Poisoning.</string>

View File

@ -264,8 +264,8 @@
<string name="view">表示</string>
<string name="custom_host_mapping">ホストマッピングの設定</string>
<string name="custom_host_mapping_summary">rootedでなくても/etc/hostsのようにホストマッピングができます。</string>
<string name="host">ホスト</string>
<string name="address">アドレス (他のホストアドレスも可)</string>
<string name="host_mapping_host">ホスト</string>
<string name="host_mapping_address">アドレス (他のホストアドレスも可)</string>
<string name="add_host_mapping">ホストマッピングを追加</string>
<string name="tcp_dns_query">TCP DNS クエリー</string>
<string name="tcp_dns_query_summary">TCP プロトコルでDNS リクエストを通信し、DNSキャッシュ汚染を回避できます。</string>

View File

@ -270,8 +270,8 @@
<string name="view">보기</string>
<string name="custom_host_mapping">커스텀 호스트 매핑</string>
<string name="custom_host_mapping_summary">/etc/hosts 에 지정하는 것처럼 호스트를 매핑합니다. 다른 권한은 전혀 필요 없습니다.</string>
<string name="host">호스트</string>
<string name="address">주소 (대체 호스트 주소가 될 수 있음)</string>
<string name="host_mapping_host">호스트</string>
<string name="host_mapping_address">주소 (대체 호스트 주소가 될 수 있음)</string>
<string name="add_host_mapping">호스트 매핑 추가</string>
<string name="tcp_dns_query">TCP DNS 쿼리</string>
<string name="tcp_dns_query_summary">TCP 프로토콜로 DNS 요청을 통신하고 DNS 캐시의 오염을 막습니다.</string>

View File

@ -35,8 +35,8 @@
<string name="show_absolute_time">Tunjukkan masa mutlak</string>
<string name="show_absolute_time_summary">Tunjukkan masa mutlak di tweet</string>
<string name="user_mentions">Sebutan pengguna</string>
<string name="host">Hos</string>
<string name="address">Alamat (Boleh jadi sebagai alamat host yang lain)</string>
<string name="host_mapping_host">Hos</string>
<string name="host_mapping_address">Alamat (Boleh jadi sebagai alamat host yang lain)</string>
<string name="add_host_mapping">Tambah pemetaan hos</string>
<string name="tcp_dns_query">TCP DNS Query</string>
<string name="dns_server_summary">Tetapkan pelayan DNS untuk permintaan API.</string>

View File

@ -254,8 +254,8 @@
<string name="view">Bekijk</string>
<string name="custom_host_mapping">Aangepaste host toewijzingen</string>
<string name="custom_host_mapping_summary">Host toewijzingen zoals /etc/hosts, maar heeft geen aanvullende rechten nodig.</string>
<string name="host">Host</string>
<string name="address">Adres (Kan een ander host adres zijn)</string>
<string name="host_mapping_host">Host</string>
<string name="host_mapping_address">Adres (Kan een ander host adres zijn)</string>
<string name="add_host_mapping">Voeg host toewijzing toe</string>
<string name="tcp_dns_query">TCP DNS Query</string>
<string name="tcp_dns_query_summary">Gebruik TCP Protocol om DNS aanvragen te doen. Dit kan DNS Cache Poisoning vermijden.</string>

View File

@ -269,8 +269,8 @@
<string name="view">Wyświetl</string>
<string name="custom_host_mapping">Ustawianie mapowania hosta</string>
<string name="custom_host_mapping_summary">Mapowanie hostów, nie wymaga żadnych dodatkowych uprawnień.</string>
<string name="host">Host</string>
<string name="address">Adres (może być inny adres hosta)</string>
<string name="host_mapping_host">Host</string>
<string name="host_mapping_address">Adres (może być inny adres hosta)</string>
<string name="add_host_mapping">Dodaj mapowanie hosta</string>
<string name="tcp_dns_query">TCP DNS Query</string>
<string name="tcp_dns_query_summary">Używa protokołu TCP do zapytań DNS, może pozwolić uniknąć zatrucia DNS.</string>

View File

@ -256,8 +256,8 @@
<string name="view">Ver</string>
<string name="custom_host_mapping">Mapeamento de hosts personalizado</string>
<string name="custom_host_mapping_summary">Mapear hosts tais como /etc/hosts, mas não requer outras permissões adicionais.</string>
<string name="host">Host</string>
<string name="address">Endereço (pode ser outro endereço de host)</string>
<string name="host_mapping_host">Host</string>
<string name="host_mapping_address">Endereço (pode ser outro endereço de host)</string>
<string name="add_host_mapping">Adicionar mapeamento de hosts</string>
<string name="tcp_dns_query">Consultar TCP DNS</string>
<string name="tcp_dns_query_summary">Usar protocolo de TCP para solicitar DNS, isso pode evitar interrupções na Cache DNS.</string>

View File

@ -271,8 +271,8 @@
<string name="view">Вид</string>
<string name="custom_host_mapping">Перенаправление узлов</string>
<string name="custom_host_mapping_summary">Перенаправление узлов, как с помощью /etc/hosts, но не требующее дополнительных разрешений.</string>
<string name="host">Хост</string>
<string name="address">Адрес (Может быть указан другой адрес)</string>
<string name="host_mapping_host">Хост</string>
<string name="host_mapping_address">Адрес (Может быть указан другой адрес)</string>
<string name="add_host_mapping">Добавить перенаправление узлов</string>
<string name="tcp_dns_query">TCP DNS-запрос</string>
<string name="tcp_dns_query_summary">Использовать протокол TCP для запросов DNS в целях предотвращения DNS Cache Poisoning.</string>

View File

@ -244,8 +244,8 @@
<string name="view">เปิดดู</string>
<string name="custom_host_mapping">กำหนดที่อยู่ host เอง</string>
<string name="custom_host_mapping_summary">กำหนดที่อยู่ host เอง (เหมือนในไฟล์ /etc/hosts) ซึ่งการกระทำนี้ไม่ต้องการสิทธิ์ใดๆ เพิ่มเติม</string>
<string name="host">โฮสต์</string>
<string name="address">ที่อยู่ (สามารถใช้ที่อยู่โฮสต์อื่นได้)</string>
<string name="host_mapping_host">โฮสต์</string>
<string name="host_mapping_address">ที่อยู่ (สามารถใช้ที่อยู่โฮสต์อื่นได้)</string>
<string name="add_host_mapping">เพิ่มการกำหนดโฮสต์</string>
<string name="tcp_dns_query">การสืบค้น DNS ทาง TCP</string>
<string name="tcp_dns_query_summary">ใช้โปรโตคอล TCP เพื่อร้องขอ DNS ซึ่งสามารถหลบเลี่ยงการโจมตีแบบ DNS Cache Poisoning ได้</string>

View File

@ -273,8 +273,8 @@
<string name="view">Görüntüle</string>
<string name="custom_host_mapping">Özel sunucu haritalama</string>
<string name="custom_host_mapping_summary">/etc/hosts şeklinde sunucu haritalama, ancak ekstra izin gerektirmez.</string>
<string name="host">Sunucu</string>
<string name="address">Adres (başka bir sunucu adresi olabilir)</string>
<string name="host_mapping_host">Sunucu</string>
<string name="host_mapping_address">Adres (başka bir sunucu adresi olabilir)</string>
<string name="add_host_mapping">Sunucu haritalama ekle</string>
<string name="tcp_dns_query">TCP DNS sorgualama</string>
<string name="dns_server">DNS Sunucusu</string>

View File

@ -244,8 +244,8 @@
<string name="view">Вигляд</string>
<string name="custom_host_mapping">Перенаправлення вузлів</string>
<string name="custom_host_mapping_summary">Перенаправлення вузлів, як за допомогою /etc/hosts, але не потребує додаткових дозволів.</string>
<string name="host">Хост</string>
<string name="address">Адреса (може бути інша адреса)</string>
<string name="host_mapping_host">Хост</string>
<string name="host_mapping_address">Адреса (може бути інша адреса)</string>
<string name="add_host_mapping">Додати перенаправлення вузлів</string>
<string name="tcp_dns_query">TCP DNS запит</string>
<string name="tcp_dns_query_summary">Використовувати протокол TCP для DNS-запитів, це допоможе уникнути DNS Cache Poisoning.</string>

View File

@ -273,8 +273,8 @@
<string name="view">查看</string>
<string name="custom_host_mapping">自定义主机映射</string>
<string name="custom_host_mapping_summary">如同/etc/hosts的主机映射但不需要任何额外的权限</string>
<string name="host">主机名</string>
<string name="address">地址(可以是另一个主机名)</string>
<string name="host_mapping_host">主机名</string>
<string name="host_mapping_address">地址(可以是另一个主机名)</string>
<string name="add_host_mapping">添加主机名映射</string>
<string name="tcp_dns_query">TCP DNS查询方式</string>
<string name="tcp_dns_query_summary">使用TCP协议进行DNS查询这可以避免DNS缓存投毒</string>

View File

@ -273,8 +273,8 @@
<string name="view">檢視</string>
<string name="custom_host_mapping">自訂主機對應</string>
<string name="custom_host_mapping_summary">如同/etc/hosts的主機對應但不需要任何額外的權限</string>
<string name="host">主機名</string>
<string name="address">地址(可以是另一個主機名)</string>
<string name="host_mapping_host">主機名</string>
<string name="host_mapping_address">地址(可以是另一個主機名)</string>
<string name="add_host_mapping">新增主機名對應</string>
<string name="tcp_dns_query">TCP DNS 查詢方式</string>
<string name="tcp_dns_query_summary">使用 TCP 協議進行 DNS 查詢,這可以避免 DNS 快取污染</string>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

View File

@ -2,7 +2,7 @@
<!--
~ Twidere - Twitter client for Android
~
~ Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
~ Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
@ -164,20 +164,82 @@
style="?cardActionButtonStyle"
android:layout_width="@dimen/element_size_normal"
android:layout_height="@dimen/element_size_normal"
android:focusable="false"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:focusable="false"
android:src="@drawable/ic_action_more_vertical"/>
</RelativeLayout>
<org.mariotaku.twidere.view.CardMediaContainer
android:id="@+id/media_preview_container"
<org.mariotaku.twidere.view.HandleSpanClickTextView
android:id="@+id/quote_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/profile_container"
android:layout_below="@id/profile_container"
android:layout_marginBottom="@dimen/element_spacing_small"
android:layout_marginTop="@dimen/element_spacing_normal"
android:paddingLeft="@dimen/element_spacing_normal"
android:paddingRight="@dimen/element_spacing_normal"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorPrimary"
android:visibility="gone"
tools:text="@string/sample_status_text"
tools:visibility="visible"/>
<org.mariotaku.twidere.view.ForegroundColorView
android:id="@+id/quote_indicator"
android:layout_width="@dimen/element_spacing_small"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/text"
android:layout_alignTop="@+id/quoted_name_container"
android:layout_marginLeft="@dimen/element_spacing_normal"
android:background="?android:dividerHorizontal"
android:visibility="gone"
tools:visibility="visible"/>
<LinearLayout
android:id="@+id/quoted_name_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/quote_text"
android:layout_toRightOf="@+id/quote_indicator"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingLeft="@dimen/element_spacing_normal"
android:paddingRight="@dimen/element_spacing_normal"
android:visibility="gone"
tools:visibility="visible">
<org.mariotaku.twidere.view.themed.ThemedTextView
android:id="@+id/quoted_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:textAppearance="?android:textAppearanceSmall"
android:textColor="?android:textColorPrimary"
android:textStyle="bold"
tools:text="User"/>
<org.mariotaku.twidere.view.themed.ThemedTextView
android:id="@+id/quoted_screen_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/element_spacing_small"
android:singleLine="true"
android:textAppearance="?android:textAppearanceSmall"
android:textColor="?android:textColorSecondary"
android:textSize="10sp"
tools:text="\@user"/>
</LinearLayout>
<org.mariotaku.twidere.view.CardMediaContainer
android:id="@+id/media_preview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/quoted_name_container"
android:layout_marginTop="@dimen/element_spacing_normal"
android:layout_toRightOf="@+id/quote_indicator"
android:horizontalSpacing="@dimen/element_spacing_xsmall"
android:verticalSpacing="@dimen/element_spacing_xsmall">
@ -189,10 +251,10 @@
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/profile_container"
android:layout_below="@id/media_preview_container"
android:layout_below="@id/media_preview"
android:layout_marginBottom="@dimen/element_spacing_small"
android:layout_marginTop="@dimen/element_spacing_normal"
android:layout_toRightOf="@+id/quote_indicator"
android:paddingLeft="@dimen/element_spacing_normal"
android:paddingRight="@dimen/element_spacing_normal"
android:textAppearance="?android:attr/textAppearanceSmall"

View File

@ -98,7 +98,7 @@
android:layout_marginRight="@dimen/element_spacing_minus_small"
android:scaleType="fitCenter"/>
<LinearLayout
<RelativeLayout
android:id="@+id/status_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -108,6 +108,7 @@
android:orientation="vertical">
<LinearLayout
android:id="@+id/profile_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
@ -160,11 +161,71 @@
</LinearLayout>
<org.mariotaku.twidere.view.CardMediaContainer
android:id="@+id/media_preview_container"
<org.mariotaku.twidere.view.HandleSpanClickTextView
android:id="@+id/quote_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/profile_container"
android:layout_below="@id/profile_container"
android:layout_marginBottom="@dimen/element_spacing_small"
android:layout_marginTop="@dimen/element_spacing_normal"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorPrimary"
android:visibility="gone"
tools:text="@string/sample_status_text"
tools:visibility="visible"/>
<org.mariotaku.twidere.view.ForegroundColorView
android:id="@+id/quote_indicator"
android:layout_width="@dimen/element_spacing_small"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/text"
android:layout_alignTop="@+id/quoted_name_container"
android:layout_marginRight="@dimen/element_spacing_normal"
android:background="?android:dividerHorizontal"
android:visibility="gone"
tools:visibility="visible"/>
<LinearLayout
android:id="@+id/quoted_name_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/quote_text"
android:layout_toRightOf="@+id/quote_indicator"
android:gravity="center_vertical"
android:orientation="horizontal"
android:visibility="gone"
tools:visibility="visible">
<org.mariotaku.twidere.view.themed.ThemedTextView
android:id="@+id/quoted_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:textAppearance="?android:textAppearanceSmall"
android:textColor="?android:textColorPrimary"
android:textStyle="bold"
tools:text="User"/>
<org.mariotaku.twidere.view.themed.ThemedTextView
android:id="@+id/quoted_screen_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/element_spacing_small"
android:singleLine="true"
android:textAppearance="?android:textAppearanceSmall"
android:textColor="?android:textColorSecondary"
android:textSize="10sp"
tools:text="\@user"/>
</LinearLayout>
<org.mariotaku.twidere.view.CardMediaContainer
android:id="@+id/media_preview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/quoted_name_container"
android:layout_marginTop="@dimen/element_spacing_small"
android:layout_toRightOf="@+id/quote_indicator"
android:horizontalSpacing="@dimen/element_spacing_xsmall"
android:verticalSpacing="@dimen/element_spacing_xsmall">
@ -176,12 +237,14 @@
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/media_preview"
android:layout_marginTop="@dimen/element_spacing_small"
android:layout_toRightOf="@+id/quote_indicator"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorPrimary"
tools:text="@string/sample_status_text"/>
</LinearLayout>
</RelativeLayout>
<LinearLayout

View File

@ -35,7 +35,7 @@
android:id="@+id/host"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/host"
android:hint="@string/host_mapping_host"
android:inputType="text|textUri"
android:singleLine="true"/>
@ -44,7 +44,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:hint="@string/address"
android:hint="@string/host_mapping_address"
android:inputType="text|textUri"
android:singleLine="true"/>

View File

@ -23,7 +23,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<org.mariotaku.twidere.view.TouchImageView
<com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
android:id="@+id/image_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>

View File

@ -1,45 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Twidere - Twitter client for Android
~
~ Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<org.mariotaku.twidere.view.SquareRelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<org.mariotaku.twidere.view.HighlightImageView
android:id="@+id/media_preview_item"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentBottom="true"
android:layout_alignParentTop="true"
android:layout_centerInParent="true"
android:scaleType="centerCrop"/>
<ProgressBar
android:id="@+id/media_preview_progress"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_centerInParent="true"
android:layout_margin="16dp"/>
</org.mariotaku.twidere.view.SquareRelativeLayout>

View File

@ -20,7 +20,6 @@
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="?android:actionBarSize"
android:layout_height="wrap_content"
android:background="?android:activatedBackgroundIndicator"

View File

@ -182,7 +182,6 @@
android:layout_height="wrap_content"
android:visibility="gone"/>
<org.mariotaku.twidere.view.themed.ThemedTextView
android:id="@+id/location_view"
android:layout_width="match_parent"

View File

@ -27,7 +27,6 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@string/media"
android:foreground="@drawable/ic_action_play_circle"
android:foregroundGravity="center"
android:scaleType="centerCrop"/>

View File

@ -19,16 +19,23 @@
-->
<FrameLayout
android:id="@+id/media_preview"
android:id="@+id/media_preview_container"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/media_preview_grid"
<org.mariotaku.twidere.view.CardMediaContainer
android:id="@+id/media_preview"
android:layout_width="match_parent"
android:gravity="center"
android:layout_height="wrap_content"
android:orientation="vertical"/>
android:layout_marginTop="@dimen/element_spacing_normal"
android:horizontalSpacing="@dimen/element_spacing_xsmall"
android:verticalSpacing="@dimen/element_spacing_xsmall">
<include layout="@layout/layout_card_media_preview"/>
</org.mariotaku.twidere.view.CardMediaContainer>
<LinearLayout
android:id="@+id/media_preview_load"

View File

@ -23,21 +23,16 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:descendantFocusability="blocksDescendants"
android:divider="?android:dividerHorizontal"
android:gravity="center"
android:orientation="horizontal">
android:orientation="horizontal"
android:showDividers="middle">
<Switch
android:id="@android:id/toggle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<View
android:layout_width="1dp"
android:layout_height="@dimen/element_size_normal"
android:layout_marginLeft="@dimen/element_spacing_small"
android:layout_marginRight="@dimen/element_spacing_small"
android:background="?android:dividerHorizontal"/>
<org.mariotaku.twidere.view.ActionIconButton
android:id="@+id/settings"
android:layout_width="@dimen/element_size_normal"

View File

@ -273,8 +273,8 @@
<string name="view">View</string>
<string name="custom_host_mapping">Custom host mapping</string>
<string name="custom_host_mapping_summary">Host mapping like /etc/hosts, but does not require any additional permissions.</string>
<string name="host">Host</string>
<string name="address">Address (Can be another host address)</string>
<string name="host_mapping_host">Host</string>
<string name="host_mapping_address">Address (Can be another host address)</string>
<string name="add_host_mapping">Add host mapping</string>
<string name="tcp_dns_query">TCP DNS Query</string>
<string name="tcp_dns_query_summary">Use TCP Protocol to make DNS requests, which can avoid DNS Cache Poisoning.</string>
@ -739,6 +739,9 @@
<string name="permission_label_shorten_status">Shorten tweet</string>
<string name="permission_label_upload_media">Upload media</string>
<string name="permission_label_sync_timeline">Sync timeline</string>
<string name="thumbor_integration">Thumbor integration</string>
<string name="server_address">Server address</string>
<string name="security_key">Security key</string>
</resources>

View File

@ -64,6 +64,12 @@
<org.mariotaku.twidere.preference.DefaultAPIPreference
android:summary="@string/default_api_settings_summary"
android:title="@string/default_api_settings"/>
<org.mariotaku.twidere.preference.SwitchSettingsDetailsPreference
android:defaultValue="false"
android:key="thumbor_enabled"
android:src="@xml/preferences_thumbor"
android:title="@string/thumbor_integration"/>
</PreferenceCategory>
</PreferenceScreen>

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Twidere - Twitter client for Android
~
~ Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
android:title="@string/thumbor_integration">
<org.mariotaku.twidere.preference.AutoFixEditTextPreference
android:inputType="textUri"
android:key="thumbor_address"
android:title="@string/server_address"/>
<org.mariotaku.twidere.preference.AutoFixEditTextPreference
android:inputType="textVisiblePassword"
android:key="thumbor_security_key"
android:title="@string/security_key"/>
</PreferenceScreen>