should work on god damn MIUI
This commit is contained in:
parent
c34c00087d
commit
af0030a15d
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue