changed 'favorite' to 'like' to comply twitter's new design spec
This commit is contained in:
Mariotaku Lee 2015-11-04 20:40:13 +08:00
parent 8d56b9b868
commit 3417fc68d4
35 changed files with 369 additions and 94 deletions

View File

@ -0,0 +1,60 @@
/*
* 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.util;
import android.support.annotation.NonNull;
/**
* Created by mariotaku on 15/11/4.
*/
public final class CodePointArray {
private final int[] codePoints;
public CodePointArray(@NonNull final CharSequence cs) {
final int inputLength = cs.length();
final int[] temp = new int[inputLength];
int codePointsLength = 0;
for (int offset = 0; offset < inputLength; ) {
final int codePoint = Character.codePointAt(cs, offset);
temp[codePointsLength++] = codePoint;
offset += Character.charCount(codePoint);
}
codePoints = new int[codePointsLength];
System.arraycopy(temp, 0, codePoints, 0, codePointsLength);
}
public int get(int pos) {
return codePoints[pos];
}
public int length() {
return codePoints.length;
}
@NonNull
public String substring(int start, int end) {
final StringBuilder sb = new StringBuilder();
for (int i = start; i < end; i++) {
sb.appendCodePoint(codePoints[i]);
}
return sb.toString();
}
}

View File

@ -22,7 +22,6 @@ package org.mariotaku.twidere.util;
import android.support.annotation.NonNull;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Locale;
@ -34,7 +33,7 @@ import static org.mariotaku.twidere.util.HtmlEscapeHelper.unescape;
public class HtmlBuilder {
private final String source;
private final int[] codePoints;
private final CodePointArray codePoints;
private final int codePointsLength;
private final boolean throwExceptions, sourceIsEscaped, shouldReEscape;
@ -44,20 +43,11 @@ public class HtmlBuilder {
final boolean shouldReEscape) {
if (source == null) throw new NullPointerException();
this.source = source;
final int length = source.length();
final int[] codepointsTemp = new int[length];
int codePointsLength = 0;
for (int offset = 0; offset < length; ) {
final int codepoint = source.codePointAt(offset);
codepointsTemp[codePointsLength++] = codepoint;
offset += Character.charCount(codepoint);
}
codePoints = new int[codePointsLength];
System.arraycopy(codepointsTemp, 0, codePoints, 0, codePointsLength);
throwExceptions = strict;
this.codePoints = new CodePointArray(source);
this.throwExceptions = strict;
this.sourceIsEscaped = sourceIsEscaped;
this.shouldReEscape = shouldReEscape;
this.codePointsLength = codePointsLength;
this.codePointsLength = codePoints.length();
}
public boolean addLink(final String link, final String display, final int start, final int end) {
@ -107,7 +97,7 @@ public class HtmlBuilder {
builder.append(spec.link);
builder.append("\">");
if (start >= 0 && start <= end && end <= codePointsLength) {
builder.append(!isEmpty(spec.display) ? spec.display_is_html ? spec.display : toHtml(spec.display)
builder.append(!isEmpty(spec.display) ? spec.displayIsHtml ? spec.display : toHtml(spec.display)
: spec.link);
}
builder.append("</a>");
@ -128,20 +118,26 @@ public class HtmlBuilder {
@Override
public String toString() {
return "HtmlBuilder{orig=" + source + ", codePoints=" + Arrays.toString(codePoints) + ", string_length="
+ codePointsLength + ", throw_exceptions=" + throwExceptions + ", source_is_escaped=" + sourceIsEscaped
+ ", should_re_escape=" + shouldReEscape + ", links=" + links + "}";
return "HtmlBuilder{" +
"source='" + source + '\'' +
", codePoints=" + codePoints +
", codePointsLength=" + codePointsLength +
", throwExceptions=" + throwExceptions +
", sourceIsEscaped=" + sourceIsEscaped +
", shouldReEscape=" + shouldReEscape +
", links=" + links +
'}';
}
private void appendSource(final StringBuilder builder, final int start, final int end) {
if (sourceIsEscaped == shouldReEscape) {
for (int i = start; i < end; i++) {
builder.appendCodePoint(codePoints[i]);
builder.appendCodePoint(codePoints.get(i));
}
} else if (shouldReEscape) {
builder.append(escape(subString(start, end)));
builder.append(escape(codePoints.substring(start, end)));
} else {
builder.append(unescape(subString(start, end)));
builder.append(unescape(codePoints.substring(start, end)));
}
}
@ -150,26 +146,18 @@ public class HtmlBuilder {
return shouldReEscape ? escape(source) : unescape(source);
}
private String subString(final int start, final int end) {
final StringBuilder sb = new StringBuilder();
for (int i = start; i < end; i++) {
sb.appendCodePoint(codePoints[i]);
}
return sb.toString();
}
static final class LinkSpec implements Comparable<LinkSpec> {
final String link, display;
final int start, end;
final boolean display_is_html;
final boolean displayIsHtml;
LinkSpec(final String link, final String display, final int start, final int end, final boolean display_is_html) {
LinkSpec(final String link, final String display, final int start, final int end, final boolean displayIsHtml) {
this.link = link;
this.display = display;
this.start = start;
this.end = end;
this.display_is_html = display_is_html;
this.displayIsHtml = displayIsHtml;
}
@Override
@ -186,7 +174,7 @@ public class HtmlBuilder {
if (display == null) {
if (other.display != null) return false;
} else if (!display.equals(other.display)) return false;
if (display_is_html != other.display_is_html) return false;
if (displayIsHtml != other.displayIsHtml) return false;
if (end != other.end) return false;
if (link == null) {
if (other.link != null) return false;
@ -200,7 +188,7 @@ public class HtmlBuilder {
final int prime = 31;
int result = 1;
result = prime * result + (display == null ? 0 : display.hashCode());
result = prime * result + (display_is_html ? 1231 : 1237);
result = prime * result + (displayIsHtml ? 1231 : 1237);
result = prime * result + end;
result = prime * result + (link == null ? 0 : link.hashCode());
result = prime * result + start;
@ -209,8 +197,13 @@ public class HtmlBuilder {
@Override
public String toString() {
return "LinkSpec{link=" + link + ", display=" + display + ", start=" + start + ", end=" + end
+ ", display_is_html=" + display_is_html + "}";
return "LinkSpec{" +
"link='" + link + '\'' +
", display='" + display + '\'' +
", start=" + start +
", end=" + end +
", displayIsHtml=" + displayIsHtml +
'}';
}
}

View File

@ -20,27 +20,51 @@
package org.mariotaku.twidere.util;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.text.translate.AggregateTranslator;
import org.apache.commons.lang3.text.translate.CodePointTranslator;
import java.io.IOException;
import java.io.Writer;
public class HtmlEscapeHelper {
public static String escape(final String string) {
if (string == null) return null;
return StringEscapeUtils.escapeHtml4(string);
}
public static final AggregateTranslator ESCAPE_HTML = new AggregateTranslator(StringEscapeUtils.ESCAPE_HTML4,
new UnicodeControlCharacterToHtmlTranslator());
public static String toHtml(final String string) {
if (string == null) return null;
return escape(string).replace("\n", "<br/>");
}
public static String escape(final CharSequence text) {
if (text == null) return null;
return ESCAPE_HTML.translate(text);
}
public static String toPlainText(final String string) {
if (string == null) return null;
return unescape(string.replace("<br/>", "\n").replaceAll("<!--.*?-->|<[^>]+>", ""));
}
public static String toHtml(final String string) {
if (string == null) return null;
return escape(string).replace("\n", "<br/>");
}
public static String unescape(final String string) {
if (string == null) return null;
return StringEscapeUtils.unescapeHtml4(string);
}
public static String toPlainText(final String string) {
if (string == null) return null;
return unescape(string.replace("<br/>", "\n").replaceAll("<!--.*?-->|<[^>]+>", ""));
}
public static String unescape(final String string) {
if (string == null) return null;
return StringEscapeUtils.unescapeHtml4(string);
}
private static class UnicodeControlCharacterToHtmlTranslator extends CodePointTranslator {
@Override
public boolean translate(int codePoint, Writer out) throws IOException {
if (Character.isISOControl(codePoint)) {
out.append("&#x");
final char[] chars = Character.toChars(codePoint);
for (char c : chars) {
out.append(Integer.toHexString(c));
}
out.append(';');
return true;
}
return false;
}
}
}

View File

@ -24,6 +24,9 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import org.apache.commons.lang3.text.translate.CharSequenceTranslator;
import org.apache.commons.lang3.text.translate.EntityArrays;
import org.apache.commons.lang3.text.translate.LookupTranslator;
import org.mariotaku.twidere.api.twitter.Twitter;
import org.mariotaku.twidere.api.twitter.TwitterException;
import org.mariotaku.twidere.api.twitter.model.DirectMessage;
@ -59,7 +62,7 @@ public class TwitterContentUtils {
if (message == null) return null;
final HtmlBuilder builder = new HtmlBuilder(message.getText(), false, true, true);
TwitterContentUtils.parseEntities(builder, message);
return builder.build().replace("\n", "<br/>");
return builder.build();
}
public static String formatExpandedUserDescription(final User user) {
@ -76,14 +79,14 @@ public class TwitterContentUtils {
}
}
}
return toPlainText(builder.build().replace("\n", "<br/>"));
return toPlainText(builder.build());
}
public static String formatStatusText(final Status status) {
if (status == null) return null;
final HtmlBuilder builder = new HtmlBuilder(status.getText(), false, true, true);
TwitterContentUtils.parseEntities(builder, status);
return builder.build().replace("\n", "<br/>");
return builder.build();
}
public static String formatUserDescription(final User user) {
@ -100,7 +103,7 @@ public class TwitterContentUtils {
}
}
}
return builder.build().replace("\n", "<br/>");
return builder.build();
}
@NonNull
@ -167,9 +170,11 @@ public class TwitterContentUtils {
return ConsumerKeyType.UNKNOWN;
}
public static String unescapeTwitterStatusText(final String str) {
if (str == null) return null;
return str.replace("&amp;", "&").replace("&lt;", "<").replace("&gt;", ">");
private static final CharSequenceTranslator UNESCAPE_TWITTER_RAW_TEXT = new LookupTranslator(EntityArrays.BASIC_UNESCAPE());
public static String unescapeTwitterStatusText(final CharSequence text) {
if (text == null) return null;
return UNESCAPE_TWITTER_RAW_TEXT.translate(text);
}
public static <T extends List<Status>> T getStatusesWithQuoteData(Twitter twitter, @NonNull T list) throws TwitterException {

View File

@ -96,6 +96,7 @@ dependencies {
compile 'com.diogobernardino:williamchart:2.0.1'
compile 'com.lnikkila:extendedtouchview:0.1.0'
compile 'com.google.dagger:dagger:2.0.1'
compile 'org.attoparser:attoparser:1.4.0.RELEASE'
googleCompile 'com.google.android.gms:play-services-maps:8.1.0'
googleCompile 'com.google.maps.android:android-maps-utils:0.4'
fdroidCompile 'org.osmdroid:osmdroid-android:4.3'

View File

@ -158,6 +158,7 @@
android:excludeFromRecents="true"
android:label="@string/compose"
android:launchMode="singleTop"
android:parentActivityName=".activity.support.HomeActivity"
android:theme="@style/Theme.Twidere.Dark.Dialog"
android:windowSoftInputMode="adjustResize">
<intent-filter android:label="@string/compose">
@ -222,6 +223,7 @@
<activity
android:name=".activity.SettingsActivity"
android:label="@string/settings"
android:parentActivityName=".activity.support.HomeActivity"
android:theme="@style/Theme.Twidere.Dark"
android:windowSoftInputMode="adjustResize">
<intent-filter>
@ -256,6 +258,7 @@
android:theme="@style/Theme.Twidere.Dark.NoDisplay" />
<activity
android:name=".activity.support.LinkHandlerActivity"
android:parentActivityName=".activity.support.HomeActivity"
android:theme="@style/Theme.Twidere.Dark.DialogWhenLarge.NoActionBar"
android:windowSoftInputMode="adjustResize">
<meta-data

View File

@ -19,8 +19,10 @@
package edu.tsinghua.hotmobi.model;
import android.app.KeyguardManager;
import android.content.Context;
import android.content.res.Configuration;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
@ -59,6 +61,9 @@ public class SessionEvent extends BaseEvent implements Parcelable {
@ParcelableThisPlease
@JsonField(name = "preferences")
HashMap<String, String> preferences;
@ParcelableThisPlease
@JsonField(name = "device_preferences")
HashMap<String, String> devicePreferences;
protected SessionEvent(Parcel in) {
super(in);
@ -90,6 +95,14 @@ public class SessionEvent extends BaseEvent implements Parcelable {
this.preferences = preferences;
}
public HashMap<String, String> getDevicePreferences() {
return devicePreferences;
}
public void setDevicePreferences(HashMap<String, String> devicePreferences) {
this.devicePreferences = devicePreferences;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
@ -104,6 +117,20 @@ public class SessionEvent extends BaseEvent implements Parcelable {
preferences.put("notification_" + accountId + "_interactions", String.valueOf(pref.isMentionsNotificationEnabled()));
}
setPreferences(preferences);
final HashMap<String, String> devicePreferences = new HashMap<>();
devicePreferences.put("device_secure", isDeviceSecure(context));
setDevicePreferences(devicePreferences);
}
private static String isDeviceSecure(Context context) {
KeyguardManager km = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
return String.valueOf(false);
} else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
return String.valueOf(km.isKeyguardSecure());
} else {
return String.valueOf(km.isDeviceSecure());
}
}
@Override

View File

@ -430,7 +430,7 @@ public class LinkHandlerActivity extends BaseAppCompatActivity implements System
break;
}
case LINK_ID_USER_FAVORITES: {
setTitle(R.string.favorites);
setTitle(R.string.likes);
break;
}
case LINK_ID_USER_FOLLOWERS: {

View File

@ -516,7 +516,7 @@ public class AccountsDashboardFragment extends BaseSupportFragment implements Lo
// if (accounts.length > 1) {
// mAccountOptionsAdapter.add(new OptionItem(R.string.compose, R.drawable.ic_action_status_compose, R.id.compose));
// }
mAccountOptionsAdapter.add(new OptionItem(R.string.favorites, R.drawable.ic_action_star, R.id.favorites));
mAccountOptionsAdapter.add(new OptionItem(R.string.likes, R.drawable.ic_action_heart, R.id.favorites));
mAccountOptionsAdapter.add(new OptionItem(R.string.lists, R.drawable.ic_action_list, R.id.lists));
}

View File

@ -96,6 +96,7 @@ import org.mariotaku.twidere.model.SingleResponse;
import org.mariotaku.twidere.util.AsyncTaskUtils;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
import org.mariotaku.twidere.util.CompareUtils;
import org.mariotaku.twidere.util.HtmlSpanBuilder;
import org.mariotaku.twidere.util.KeyboardShortcutsHandler;
import org.mariotaku.twidere.util.KeyboardShortcutsHandler.KeyboardShortcutCallback;
import org.mariotaku.twidere.util.LinkCreator;
@ -906,7 +907,7 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
}
timeSourceView.setMovementMethod(LinkMovementMethod.getInstance());
textView.setText(Html.fromHtml(status.text_html));
textView.setText(HtmlSpanBuilder.fromHtml(status.text_html));
linkify.applyAllLinks(textView, status.account_id, layoutPosition, status.is_possibly_sensitive);
ThemeUtils.applyParagraphSpacing(textView, 1.1f);

View File

@ -1449,7 +1449,7 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
if (Utils.isOfficialKeyAccount(context, accountId)) {
mPagerAdapter.addTab(UserMediaTimelineFragment.class, tabArgs, getString(R.string.media), R.drawable.ic_action_gallery, TAB_TYPE_MEDIA, TAB_POSITION_MEDIA, null);
}
mPagerAdapter.addTab(UserFavoritesFragment.class, tabArgs, getString(R.string.favorites), R.drawable.ic_action_star, TAB_TYPE_FAVORITES, TAB_POSITION_FAVORITES, null);
mPagerAdapter.addTab(UserFavoritesFragment.class, tabArgs, getString(R.string.likes), R.drawable.ic_action_heart, TAB_TYPE_FAVORITES, TAB_POSITION_FAVORITES, null);
}
private void updateFollowProgressState() {

View File

@ -81,7 +81,7 @@ public class CustomTabUtils implements Constants {
TrendsSuggestionsFragment.class, R.string.trends, R.drawable.ic_action_hashtag,
CustomTabConfiguration.ACCOUNT_NONE, CustomTabConfiguration.FIELD_TYPE_NONE, 3, true));
CUSTOM_TABS_CONFIGURATION_MAP.put(TAB_TYPE_FAVORITES, new CustomTabConfiguration(UserFavoritesFragment.class,
R.string.favorites, R.drawable.ic_action_star, CustomTabConfiguration.ACCOUNT_REQUIRED,
R.string.likes, R.drawable.ic_action_heart, CustomTabConfiguration.ACCOUNT_REQUIRED,
CustomTabConfiguration.FIELD_TYPE_USER, 4));
CUSTOM_TABS_CONFIGURATION_MAP.put(TAB_TYPE_USER_TIMELINE, new CustomTabConfiguration(
UserTimelineFragment.class, R.string.users_statuses, R.drawable.ic_action_quote,

View File

@ -0,0 +1,130 @@
/*
* 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.util;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.style.URLSpan;
import org.apache.commons.lang3.StringUtils;
import org.attoparser.AttoParseException;
import org.attoparser.IAttoParser;
import org.attoparser.markup.MarkupAttoParser;
import org.attoparser.markup.html.AbstractStandardNonValidatingHtmlAttoHandler;
import org.attoparser.markup.html.HtmlParsingConfiguration;
import org.attoparser.markup.html.elements.IHtmlElement;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Created by mariotaku on 15/11/4.
*/
public class HtmlSpanBuilder {
private static final IAttoParser PARSER = new MarkupAttoParser();
public static Spanned fromHtml(String html) {
final HtmlParsingConfiguration conf = new HtmlParsingConfiguration();
final HtmlSpanHandler handler = new HtmlSpanHandler(conf);
try {
PARSER.parse(html, handler);
} catch (AttoParseException e) {
throw new RuntimeException(e);
}
return handler.getText();
}
private static void applyTag(SpannableStringBuilder sb, int start, int end, TagInfo info) {
final Object span = createSpan(info);
if (span == null) return;
sb.setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
private static Object createSpan(TagInfo info) {
switch (info.name) {
case "a": {
return new URLSpan(info.getAttribute("href"));
}
}
return null;
}
private static int lastIndexOfTag(List<TagInfo> info, String name) {
for (int i = info.size() - 1; i >= 0; i--) {
if (StringUtils.equals(info.get(i).name, name)) {
return i;
}
}
return -1;
}
private static class TagInfo {
final int start;
final String name;
final Map<String, String> attributes;
public TagInfo(int start, String name, Map<String, String> attributes) {
this.start = start;
this.name = name;
this.attributes = attributes;
}
public String getAttribute(String attr) {
return attributes.get(attr);
}
}
private static class HtmlSpanHandler extends AbstractStandardNonValidatingHtmlAttoHandler {
private final SpannableStringBuilder sb;
List<TagInfo> tagInfo;
public HtmlSpanHandler(HtmlParsingConfiguration conf) {
super(conf);
this.sb = new SpannableStringBuilder();
tagInfo = new ArrayList<>();
}
@Override
public void handleText(char[] buffer, int offset, int len, int line, int col) throws AttoParseException {
sb.append(HtmlEscapeHelper.unescape(new String(buffer, offset, len)));
}
@Override
public void handleHtmlCloseElement(IHtmlElement element, String elementName, int line, int col) throws AttoParseException {
final int lastIndex = lastIndexOfTag(tagInfo, elementName);
if (lastIndex != -1) {
TagInfo info = tagInfo.get(lastIndex);
applyTag(sb, info.start, sb.length(), info);
tagInfo.remove(lastIndex);
}
}
@Override
public void handleHtmlOpenElement(IHtmlElement element, String elementName, Map<String, String> attributes, int line, int col) throws AttoParseException {
tagInfo.add(new TagInfo(sb.length(), elementName, attributes));
}
public Spanned getText() {
return sb;
}
}
}

View File

@ -41,7 +41,7 @@ public class KeyboardShortcutsHandler implements Constants, KeyboardShortcutCons
sActionLabelMap.put(ACTION_HOME_ACCOUNTS_DASHBOARD, R.string.open_accounts_dashboard);
sActionLabelMap.put(ACTION_STATUS_REPLY, R.string.reply);
sActionLabelMap.put(ACTION_STATUS_RETWEET, R.string.retweet);
sActionLabelMap.put(ACTION_STATUS_FAVORITE, R.string.favorite);
sActionLabelMap.put(ACTION_STATUS_FAVORITE, R.string.like);
sActionLabelMap.put(ACTION_NAVIGATION_PREVIOUS, R.string.previous_item);
sActionLabelMap.put(ACTION_NAVIGATION_NEXT, R.string.next_item);
sActionLabelMap.put(ACTION_NAVIGATION_PAGE_DOWN, R.string.page_down);

View File

@ -24,7 +24,7 @@ import android.support.annotation.NonNull;
/**
* Created by mariotaku on 14/12/23.
*/
public class StringUtils {
public class TwidereStringUtils {
public static boolean regionMatchesIgnoreCase(@NonNull final String string, final int thisStart,
@NonNull final String match, final int start,
final int length) {

View File

@ -74,6 +74,7 @@ import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.ListFragment;
import android.support.v4.content.ContextCompat;
import android.support.v4.util.LongSparseArray;
import android.support.v4.util.Pair;
import android.support.v4.view.ActionProvider;
@ -1727,13 +1728,13 @@ public final class Utils implements Constants {
return def;
}
public static int getCardHighlightColor(final Resources res, final boolean isMention, final boolean isFavorite,
final boolean isRetweet) {
public static int getCardHighlightColor(final Context context, final boolean isMention,
final boolean isFavorite, final boolean isRetweet) {
if (isMention)
return res.getColor(R.color.highlight_reply);
return ContextCompat.getColor(context, R.color.highlight_reply);
else if (isFavorite)
return res.getColor(R.color.highlight_favorite);
else if (isRetweet) res.getColor(R.color.highlight_retweet);
return ContextCompat.getColor(context, R.color.highlight_like);
else if (isRetweet) ContextCompat.getColor(context, R.color.highlight_retweet);
return Color.TRANSPARENT;
}
@ -1955,7 +1956,7 @@ public final class Utils implements Constants {
if (key == -1 || isEmpty(value)) {
continue;
}
if (StringUtils.startsWithIgnoreCase(value, str)) {
if (TwidereStringUtils.startsWithIgnoreCase(value, str)) {
list.add(key);
}
}
@ -3332,8 +3333,8 @@ public final class Utils implements Constants {
final ParcelableCredentials account) {
if (context == null || menu == null || status == null || account == null) return;
final Resources resources = context.getResources();
final int retweetHighlight = resources.getColor(R.color.highlight_retweet);
final int favoriteHighlight = resources.getColor(R.color.highlight_favorite);
final int retweetHighlight = ContextCompat.getColor(context, R.color.highlight_retweet);
final int likeHighlight = ContextCompat.getColor(context, R.color.highlight_like);
final boolean isMyRetweet = isMyRetweet(status);
final MenuItem delete = menu.findItem(R.id.delete);
if (delete != null) {
@ -3346,8 +3347,8 @@ public final class Utils implements Constants {
}
final MenuItem favorite = menu.findItem(R.id.favorite);
if (favorite != null) {
ActionIconDrawable.setMenuHighlight(favorite, new TwidereMenuInfo(status.is_favorite, favoriteHighlight));
favorite.setTitle(status.is_favorite ? R.string.unfavorite : R.string.favorite);
ActionIconDrawable.setMenuHighlight(favorite, new TwidereMenuInfo(status.is_favorite, likeHighlight));
favorite.setTitle(status.is_favorite ? R.string.undo_like : R.string.like);
}
final MenuItem translate = menu.findItem(R.id.translate);
if (translate != null) {

View File

@ -103,7 +103,7 @@ public class ActivityTitleSummaryViewHolder extends ViewHolder implements View.O
}
case Activity.ACTION_FAVORITE: {
activityTypeView.setImageResource(R.drawable.ic_activity_action_favorite);
activityTypeView.setColorFilter(ContextCompat.getColor(context, R.color.highlight_favorite), Mode.SRC_ATOP);
activityTypeView.setColorFilter(ContextCompat.getColor(context, R.color.highlight_like), Mode.SRC_ATOP);
if (byFriends) {
titleView.setText(getTitleStringByFriends(R.string.activity_by_friends_favorite,
R.string.activity_by_friends_favorite_multi, activity.sources, activity.target_statuses));
@ -136,7 +136,7 @@ public class ActivityTitleSummaryViewHolder extends ViewHolder implements View.O
return;
}
activityTypeView.setImageResource(R.drawable.ic_activity_action_favorite);
activityTypeView.setColorFilter(ContextCompat.getColor(context, R.color.highlight_favorite), Mode.SRC_ATOP);
activityTypeView.setColorFilter(ContextCompat.getColor(context, R.color.highlight_like), Mode.SRC_ATOP);
titleView.setText(getTitleStringAboutMe(R.string.activity_about_me_favorited_retweet,
R.string.activity_about_me_favorited_retweet_multi, activity.sources));
displayUserProfileImages(activity.sources);
@ -178,9 +178,9 @@ public class ActivityTitleSummaryViewHolder extends ViewHolder implements View.O
return;
}
activityTypeView.setImageResource(R.drawable.ic_activity_action_favorite);
activityTypeView.setColorFilter(ContextCompat.getColor(context, R.color.highlight_favorite), Mode.SRC_ATOP);
titleView.setText(getTitleStringAboutMe(R.string.activity_about_me_favorited_mention,
R.string.activity_about_me_favorited_mention_multi, activity.sources));
activityTypeView.setColorFilter(ContextCompat.getColor(context, R.color.highlight_like), Mode.SRC_ATOP);
titleView.setText(getTitleStringAboutMe(R.string.activity_about_me_liked_mention,
R.string.activity_about_me_liked_mention_multi, activity.sources));
displayUserProfileImages(activity.sources);
summaryView.setText(activity.target_statuses[0].text_unescaped);
summaryView.setVisibility(View.VISIBLE);

View File

@ -780,4 +780,6 @@
<string name="bug_reports">错误报告</string>
<string name="invalid_consumer_key">无效的Consumer key</string>
<string name="invalid_consumer_secret">无效的Consumer secret</string>
<string name="like">喜欢</string>
<string name="likes">喜欢</string>
</resources>

Binary file not shown.

After

Width:  |  Height:  |  Size: 686 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 510 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 865 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 329 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 240 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 459 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 478 B

View File

@ -288,14 +288,14 @@
style="?cardActionButtonStyle"
android:layout_width="wrap_content"
android:layout_height="@dimen/button_size_content_card"
android:drawableLeft="@drawable/ic_action_star"
android:drawableStart="@drawable/ic_action_star"
android:drawableLeft="@drawable/ic_action_heart"
android:drawableStart="@drawable/ic_action_heart"
android:focusable="false"
android:gravity="center"
android:paddingLeft="@dimen/element_spacing_normal"
android:paddingRight="@dimen/element_spacing_normal"
android:textAppearance="?android:textAppearanceSmall"
app:iabActivatedColor="@color/highlight_favorite"
app:iabActivatedColor="@color/highlight_like"
app:iabColor="?android:textColorTertiary" />
</LinearLayout>

View File

@ -272,14 +272,14 @@
android:layout_width="wrap_content"
android:layout_height="@dimen/button_size_content_card"
android:layout_weight="0"
android:drawableLeft="@drawable/ic_action_star"
android:drawableStart="@drawable/ic_action_star"
android:drawableLeft="@drawable/ic_action_heart"
android:drawableStart="@drawable/ic_action_heart"
android:focusable="false"
android:gravity="center"
android:paddingLeft="@dimen/element_spacing_normal"
android:paddingRight="@dimen/element_spacing_normal"
android:textAppearance="?android:textAppearanceSmall"
app:iabActivatedColor="@color/highlight_favorite"
app:iabActivatedColor="@color/highlight_like"
app:iabColor="?android:textColorTertiary" />
</LinearLayout>

View File

@ -434,7 +434,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:text="@string/favorites"
android:text="@string/likes"
android:textAppearance="?android:textAppearanceSmall"
android:textColor="?android:textColorSecondary" />
</LinearLayout>

View File

@ -1,6 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:ignore="AlwaysShowAction">
<item
android:id="@id/reply"
@ -14,8 +16,8 @@
app:showAsAction="always" />
<item
android:id="@id/favorite"
android:icon="@drawable/ic_action_star"
android:title="@string/favorite"
android:icon="@drawable/ic_action_heart"
android:title="@string/like"
app:showAsAction="always" />
<item
android:id="@id/share"

View File

@ -26,6 +26,7 @@
<color name="action_icon_light_disabled">#4DFFFFFF</color>
<color name="highlight_retweet">@color/material_light_green</color>
<color name="highlight_favorite">@color/material_amber</color>
<color name="highlight_like">@color/material_pink</color>
<color name="highlight_reply">@color/material_light_blue</color>
<color name="highlight_follow">@color/material_light_blue</color>
<color name="unread_color">@color/material_red</color>

View File

@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generated by crowdin.net -->
<?xml version="1.0" encoding="utf-8"?><!-- Generated by crowdin.net -->
<resources>
<plurals name="Nitems_selected">
@ -58,5 +57,9 @@
<item quantity="one">@string/N_favorites_quantity_one</item>
<item quantity="other">@string/N_favorites_quantity_other</item>
</plurals>
<plurals name="N_likes">
<item quantity="one">@string/N_likes_quantity_one</item>
<item quantity="other">@string/N_likes_quantity_other</item>
</plurals>
</resources>

View File

@ -55,6 +55,9 @@
<string name="cancel_retweet">Cancel retweet</string>
<string name="favorite">Favorite</string>
<string name="unfavorite">Unfavorite</string>
<!-- v. e.g. An action label on a tweet to like this tweet. Formerly Twitter's favorite. -->
<string name="like">Like</string>
<string name="undo_like">Undo like</string>
<string name="reply">Reply</string>
<string name="share">Share</string>
<string name="view_image">Image</string>
@ -98,6 +101,7 @@
<string name="retweeted_by_count">Retweeted by <xliff:g id="retweet_count">%d</xliff:g> users</string>
<string name="users_retweeted_this">Users retweeted this</string>
<string name="users_favorited_this">Users favorited this</string>
<string name="users_liked_this">Users liked this</string>
<string name="reply_to">Reply to <xliff:g id="user_name">%s</xliff:g></string>
<string name="quote_user">Quote <xliff:g id="user_name">%s</xliff:g></string>
<string name="time_source"><xliff:g id="time">%1$s</xliff:g> · <xliff:g id="source">%2$s</xliff:g></string>
@ -131,6 +135,8 @@
<string name="location">Location</string>
<string name="url">URL</string>
<string name="favorites">Favorites</string>
<!-- n. formerly Twitter's favorite, in the plural -->
<string name="likes">Likes</string>
<string name="name">Name</string>
<string name="refresh">Refresh</string>
<string name="retry">Retry</string>
@ -283,6 +289,8 @@
<string name="activity_about_me_retweeted_mention_multi"><xliff:g id="user">%s</xliff:g> and <xliff:g id="other">%2$s</xliff:g> retweeted a tweet mentioned you.</string>
<string name="activity_about_me_favorited_mention"><xliff:g id="user">%s</xliff:g> favorited a tweet mentioned you.</string>
<string name="activity_about_me_favorited_mention_multi"><xliff:g id="user">%s</xliff:g> and <xliff:g id="other">%2$s</xliff:g> favorited a tweet mentioned you.</string>
<string name="activity_about_me_liked_mention"><xliff:g id="user">%s</xliff:g> liked a tweet mentioned you.</string>
<string name="activity_about_me_liked_mention_multi"><xliff:g id="user">%s</xliff:g> and <xliff:g id="other">%2$s</xliff:g> liked a tweet mentioned you.</string>
<string name="activity_about_me_list_member_added"><xliff:g id="user">%s</xliff:g> added you to list.</string>
<string name="activity_about_me_list_member_added_with_name"><xliff:g id="user">%1$s</xliff:g> added you to list <xliff:g id="list">%2$s</xliff:g>".</string>
<string name="activity_about_me_list_member_added_multi"><xliff:g id="user">%1$s</xliff:g> and <xliff:g id="other">%2$s</xliff:g> added you to their lists.</string>
@ -731,8 +739,10 @@
<string name="hide_card_actions">Hide card actions</string>
<string name="N_statuses_quantity_one" tools:ignore="PluralsCandidate"><xliff:g id="count">%d</xliff:g> tweet</string>
<string name="N_statuses_quantity_other" tools:ignore="PluralsCandidate"><xliff:g id="count">%d</xliff:g> tweets</string>
<string name="N_favorites_quantity_one" tools:ignore="PluralsCandidate"><xliff:g id="count">%d</xliff:g> favorites</string>
<string name="N_favorites_quantity_one" tools:ignore="PluralsCandidate"><xliff:g id="count">%d</xliff:g> favorite</string>
<string name="N_favorites_quantity_other" tools:ignore="PluralsCandidate"><xliff:g id="count">%d</xliff:g> favorites</string>
<string name="N_likes_quantity_one" tools:ignore="PluralsCandidate"><xliff:g id="count">%d</xliff:g> like</string>
<string name="N_likes_quantity_other" tools:ignore="PluralsCandidate"><xliff:g id="count">%d</xliff:g> likes</string>
<string name="drafts_hint_messages">Your unsent tweets will save here</string>
<string name="keyboard_shortcuts">Keyboard shortcuts</string>
<string name="keyboard_shortcut_hint">Press keys</string>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="32px" height="32px" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<!-- Generator: Sketch 3.4 (15588) - http://www.bohemiancoding.com/sketch -->
<title>Artboard</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
<g id="Artboard" sketch:type="MSArtboardGroup" fill="#FFFFFF">
<path d="M16,24.5708333 L14.6708333,23.3608333 C9.95,19.08 6.83333333,16.2566667 6.83333333,12.7916667 C6.83333333,9.96833333 9.05166667,7.75 11.875,7.75 C13.47,7.75 15.0008333,8.4925 16,9.66583333 C16.9991667,8.4925 18.53,7.75 20.125,7.75 C22.9483333,7.75 25.1666667,9.96833333 25.1666667,12.7916667 C25.1666667,16.2566667 22.05,19.08 17.3291667,23.37 L16,24.5708333 L16,24.5708333 Z" id="Shape" sketch:type="MSShapeGroup"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB