should work on god damn MIUI

This commit is contained in:
Mariotaku Lee 2016-04-05 14:08:19 +08:00
parent c34c00087d
commit af0030a15d
7 changed files with 155 additions and 142 deletions

View File

@ -0,0 +1,102 @@
package org.mariotaku.twidere.api.twitter.util;
import android.support.annotation.NonNull;
import java.text.AttributedCharacterIterator;
import java.text.DateFormat;
import java.text.FieldPosition;
import java.text.NumberFormat;
import java.text.ParseException;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
/**
* Created by mariotaku on 16/4/5.
*/
public final class ThreadLocalSimpleDateFormat extends DateFormat {
private final ThreadLocal<SimpleDateFormat> threadLocal;
public ThreadLocalSimpleDateFormat(@NonNull final String pattern, final Locale locale) {
threadLocal = new ThreadLocal<SimpleDateFormat>() {
@Override
protected SimpleDateFormat initialValue() {
return new SimpleDateFormat(pattern, locale);
}
};
}
@Override
public void setTimeZone(TimeZone timezone) {
threadLocal.get().setTimeZone(timezone);
}
@Override
public void setNumberFormat(NumberFormat format) {
threadLocal.get().setNumberFormat(format);
}
@Override
public void setLenient(boolean value) {
threadLocal.get().setLenient(value);
}
@Override
public void setCalendar(Calendar cal) {
threadLocal.get().setCalendar(cal);
}
@Override
public Object parseObject(String string, @NonNull ParsePosition position) {
return threadLocal.get().parseObject(string, position);
}
@Override
public Date parse(String string) throws ParseException {
return threadLocal.get().parse(string);
}
@Override
public boolean isLenient() {
return threadLocal.get().isLenient();
}
@Override
public TimeZone getTimeZone() {
return threadLocal.get().getTimeZone();
}
@Override
public NumberFormat getNumberFormat() {
return threadLocal.get().getNumberFormat();
}
@Override
public Calendar getCalendar() {
return threadLocal.get().getCalendar();
}
@Override
public AttributedCharacterIterator formatToCharacterIterator(@NonNull Object object) {
return threadLocal.get().formatToCharacterIterator(object);
}
@Override
public Object parseObject(String string) throws ParseException {
return threadLocal.get().parseObject(string);
}
@Override
public StringBuffer format(Date date, StringBuffer buffer, FieldPosition field) {
return threadLocal.get().format(date, buffer, field);
}
@Override
public Date parse(String string, ParsePosition position) {
return threadLocal.get().parse(string, position);
}
}

View File

@ -19,143 +19,41 @@
package org.mariotaku.twidere.api.twitter.util;
import android.util.Log;
import com.bluelinelabs.logansquare.typeconverters.StringBasedTypeConverter;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Locale;
import java.util.SimpleTimeZone;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;
/**
* Created by mariotaku on 15/5/7.
*/
public class TwitterDateConverter extends StringBasedTypeConverter<Date> {
private static final String[] WEEK_NAMES = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
private static final String[] MONTH_NAMES = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
"Aug", "Sep", "Oct", "Nov", "Dec"};
static final DateFormat sFormat = new ThreadLocalSimpleDateFormat("EEE MMM dd HH:mm:ss ZZZZZ yyyy",
Locale.ENGLISH);
private static final TimeZone TIME_ZONE = TimeZone.getTimeZone("UTC");
private static final Locale LOCALE = Locale.ENGLISH;
private final DateFormat mDateFormat;
public TwitterDateConverter() {
mDateFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss ZZZZZ yyyy", LOCALE);
mDateFormat.setLenient(true);
mDateFormat.setTimeZone(TIME_ZONE);
static {
sFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
sFormat.setLenient(true);
}
@Override
public Date getFromString(String string) {
Date date = null;
public Date getFromString(final String string) {
if (string == null) return null;
try {
date = parseTwitterDate(string);
} catch (NumberFormatException e) {
Log.w("Twidere", e);
// Ignore
}
if (date != null) return date;
try {
date = mDateFormat.parse(string);
return sFormat.parse(string);
} catch (ParseException e) {
return null;
}
return date;
}
private Date parseTwitterDate(String string) {
final List<String> segs = split(string, " ");
if (segs.size() != 6) {
return null;
}
final List<String> timeSegs = split(segs.get(3), ":");
if (timeSegs.size() != 3) {
return null;
}
final GregorianCalendar calendar = new GregorianCalendar(TIME_ZONE, LOCALE);
calendar.clear();
final int monthIdx = indexOf(MONTH_NAMES, segs.get(1));
if (monthIdx < 0) {
return null;
}
calendar.set(Calendar.YEAR, Integer.parseInt(segs.get(5)));
calendar.set(Calendar.MONTH, monthIdx);
calendar.set(Calendar.DAY_OF_MONTH, Integer.parseInt(segs.get(2)));
calendar.set(Calendar.HOUR_OF_DAY, Integer.parseInt(timeSegs.get(0)));
calendar.set(Calendar.MINUTE, Integer.parseInt(timeSegs.get(1)));
calendar.set(Calendar.SECOND, Integer.parseInt(timeSegs.get(2)));
calendar.setTimeZone(SimpleTimeZone.getTimeZone(getTimezoneText(segs.get(4))));
final Date date = calendar.getTime();
if (!WEEK_NAMES[calendar.get(Calendar.DAY_OF_WEEK) - 1].equals(segs.get(0))) {
return null;
}
return date;
}
@Override
public String convertToString(Date date) {
final Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
final StringBuilder sb = new StringBuilder();
sb.append(WEEK_NAMES[calendar.get(Calendar.DAY_OF_WEEK) - 1]);
sb.append(' ');
sb.append(MONTH_NAMES[calendar.get(Calendar.MONTH)]);
sb.append(' ');
sb.append(calendar.get(Calendar.DAY_OF_MONTH));
sb.append(' ');
sb.append(calendar.get(Calendar.HOUR_OF_DAY));
sb.append(':');
sb.append(calendar.get(Calendar.MINUTE));
sb.append(':');
sb.append(calendar.get(Calendar.SECOND));
sb.append(' ');
final long offset = TimeUnit.MILLISECONDS.toMinutes(calendar.get(Calendar.ZONE_OFFSET));
sb.append(offset > 0 ? '+' : '-');
sb.append(String.format(Locale.ROOT, "%02d%02d", Math.abs(offset) / 60, Math.abs(offset) % 60));
sb.append(' ');
sb.append(calendar.get(Calendar.YEAR));
return sb.toString();
}
private String getTimezoneText(String seg) {
if (seg.startsWith("GMT") || seg.startsWith("UTC")) return seg;
return "GMT" + seg;
}
public static List<String> split(String input, String delim) {
List<String> l = new ArrayList<>();
int offset = 0;
while (true) {
int index = input.indexOf(delim, offset);
if (index == -1) {
l.add(input.substring(offset));
return l;
} else {
l.add(input.substring(offset, index));
offset = (index + delim.length());
}
}
}
private static int indexOf(String[] input, String find) {
for (int i = 0, inputLength = input.length; i < inputLength; i++) {
if (find == null) {
if (input[i] == null) return i;
} else if (find.equals(input[i])) return i;
}
return -1;
public String convertToString(final Date date) {
if (date == null) return null;
return sFormat.format(date);
}
}

View File

@ -10,8 +10,7 @@ import com.bluelinelabs.logansquare.annotation.JsonObject;
import com.hannesdorfmann.parcelableplease.annotation.ParcelablePlease;
import com.hannesdorfmann.parcelableplease.annotation.ParcelableThisPlease;
import org.mariotaku.twidere.api.twitter.util.TwitterDateConverter;
import java.util.ArrayList;
import java.util.List;
/**
@ -164,7 +163,7 @@ public class UserKey implements Comparable<UserKey>, Parcelable {
@Nullable
public static UserKey[] arrayOf(@Nullable String str) {
if (str == null) return null;
List<String> split = TwitterDateConverter.split(str, ",");
List<String> split = split(str, ",");
UserKey[] keys = new UserKey[split.size()];
for (int i = 0, splitLength = split.size(); i < splitLength; i++) {
keys[i] = valueOf(split.get(i));
@ -181,7 +180,6 @@ public class UserKey implements Comparable<UserKey>, Parcelable {
return result;
}
public static String escapeText(String host) {
final StringBuilder sb = new StringBuilder();
for (int i = 0, j = host.length(); i < j; i++) {
@ -194,6 +192,7 @@ public class UserKey implements Comparable<UserKey>, Parcelable {
return sb.toString();
}
private static boolean isSpecialChar(char ch) {
return ch == '\\' || ch == '@' || ch == ',';
}
@ -201,4 +200,20 @@ public class UserKey implements Comparable<UserKey>, Parcelable {
public boolean maybeEquals(@Nullable UserKey another) {
return another != null && another.getId().equals(id);
}
public static List<String> split(String input, String delim) {
List<String> l = new ArrayList<>();
int offset = 0;
while (true) {
int index = input.indexOf(delim, offset);
if (index == -1) {
l.add(input.substring(offset));
return l;
} else {
l.add(input.substring(offset, index));
offset = index + delim.length();
}
}
}
}

View File

@ -45,6 +45,8 @@ import android.widget.TableLayout;
import android.widget.TextView;
import org.apache.commons.lang3.math.NumberUtils;
import org.mariotaku.abstask.library.AbstractTask;
import org.mariotaku.abstask.library.TaskStarter;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.api.twitter.TwitterCaps;
import org.mariotaku.twidere.api.twitter.TwitterException;
@ -55,12 +57,11 @@ import org.mariotaku.twidere.model.ParcelableCardEntity;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.model.UserKey;
import org.mariotaku.twidere.model.util.ParcelableCardEntityUtils;
import org.mariotaku.abstask.library.AbstractTask;
import org.mariotaku.abstask.library.TaskStarter;
import org.mariotaku.twidere.util.TwitterAPIFactory;
import org.mariotaku.twidere.util.support.ViewSupport;
import java.util.Date;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -190,6 +191,7 @@ public class CardPollFragment extends BaseSupportFragment implements
return null;
}
};
task.setResultHandler(CardPollFragment.this);
task.setParams(cardData);
TaskStarter.execute(task);
}
@ -212,7 +214,7 @@ public class CardPollFragment extends BaseSupportFragment implements
if (label == null) throw new NullPointerException();
final float choicePercent = votesSum == 0 ? 0 : value / (float) votesSum;
choiceLabelView.setText(label);
choicePercentView.setText(String.format("%d%%", Math.round(choicePercent * 100)));
choicePercentView.setText(String.format(Locale.US, "%d%%", Math.round(choicePercent * 100)));
pollItem.setOnClickListener(clickListener);

View File

@ -8,18 +8,30 @@ import android.support.v4.util.ArrayMap;
import org.apache.commons.lang3.math.NumberUtils;
import org.mariotaku.twidere.TwidereConstants;
import org.mariotaku.twidere.api.twitter.model.CardEntity;
import org.mariotaku.twidere.api.twitter.util.ThreadLocalSimpleDateFormat;
import org.mariotaku.twidere.model.ParcelableCardEntity;
import org.mariotaku.twidere.model.UserKey;
import org.mariotaku.twidere.util.InternalParseUtils;
import java.text.DateFormat;
import java.text.ParseException;
import java.util.Date;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;
/**
* Created by mariotaku on 16/2/24.
*/
public class ParcelableCardEntityUtils implements TwidereConstants {
static final DateFormat sISOFormat = new ThreadLocalSimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'",
Locale.ENGLISH);
static {
sISOFormat.setLenient(true);
sISOFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
}
@Nullable
public static ParcelableCardEntity fromCardEntity(@Nullable CardEntity card, @Nullable UserKey accountKey) {
if (card == null) return null;
@ -74,8 +86,11 @@ public class ParcelableCardEntityUtils implements TwidereConstants {
public static Date getAsDate(@NonNull ParcelableCardEntity obj, @NonNull String key, Date def) {
final ParcelableCardEntity.ParcelableBindingValue value = obj.getValue(key);
if (value == null) return def;
final String str = value.value;
return InternalParseUtils.parseISODateTime(str, def);
try {
return sISOFormat.parse(value.value);
} catch (ParseException e) {
return def;
}
}
}

View File

@ -4,15 +4,11 @@ import android.os.Bundle;
import android.util.JsonWriter;
import android.util.Log;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.mariotaku.restfu.RestFuUtils;
import org.mariotaku.twidere.TwidereConstants;
import java.io.IOException;
import java.io.StringWriter;
import java.text.ParseException;
import java.util.Date;
import java.util.Locale;
import java.util.Set;
@ -71,18 +67,4 @@ public class InternalParseUtils {
return result.substring(0, i == dotIdx ? dotIdx : i + 1);
}
public static Date parseISODateTime(String str, Date def) {
try {
return DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.parse(str);
} catch (ParseException e) {
return def;
} catch (Error nsme) {
// Fuck Xiaomi http://crashes.to/s/a84a3d257dc
try {
return DateUtils.parseDate(str, Locale.ENGLISH, "yyyy-MM-dd'T'HH:mm:ssZZ");
} catch (ParseException e1) {
return def;
}
}
}
}

View File

@ -2303,7 +2303,6 @@ public final class Utils implements Constants {
public static boolean checkDeviceCompatible() {
try {
Menu.class.isAssignableFrom(MenuBuilder.class);
InternalParseUtils.parseISODateTime("2001-01-01T01:01:01Z", null);
} catch (Error e) {
TwidereBugReporter.logException(e);
return false;