code cleanup
This commit is contained in:
parent
a4f3fd94f8
commit
8cddbb0dfc
|
@ -10,6 +10,7 @@ import org.mariotaku.microblog.library.twitter.model.User;
|
|||
/**
|
||||
* Created by mariotaku on 16/3/11.
|
||||
*/
|
||||
@SuppressWarnings("RedundantThrows")
|
||||
public interface BlocksResources {
|
||||
|
||||
@POST("/blocks/create.json")
|
||||
|
|
|
@ -8,6 +8,7 @@ import org.mariotaku.microblog.library.twitter.model.DirectMessage;
|
|||
/**
|
||||
* Created by mariotaku on 16/3/31.
|
||||
*/
|
||||
@SuppressWarnings("RedundantThrows")
|
||||
public interface DirectMessagesResources {
|
||||
|
||||
@POST("/direct_messages/new.json")
|
||||
|
|
|
@ -8,6 +8,7 @@ import org.mariotaku.microblog.library.twitter.model.Status;
|
|||
/**
|
||||
* Created by mariotaku on 16/3/11.
|
||||
*/
|
||||
@SuppressWarnings("RedundantThrows")
|
||||
public interface FavoritesResources {
|
||||
|
||||
@POST("/favorites/create/{id}.json")
|
||||
|
|
|
@ -12,6 +12,7 @@ import org.mariotaku.microblog.library.twitter.model.User;
|
|||
/**
|
||||
* Created by mariotaku on 16/3/11.
|
||||
*/
|
||||
@SuppressWarnings("RedundantThrows")
|
||||
public interface FriendshipsResources {
|
||||
|
||||
@POST("/friendships/create.json")
|
||||
|
|
|
@ -13,6 +13,7 @@ import org.mariotaku.microblog.library.twitter.model.User;
|
|||
/**
|
||||
* Created by mariotaku on 16/3/4.
|
||||
*/
|
||||
@SuppressWarnings("RedundantThrows")
|
||||
public interface GroupResources {
|
||||
|
||||
@GET("/statusnet/groups/timeline/{group_id}.json")
|
||||
|
|
|
@ -35,6 +35,7 @@ import org.mariotaku.restfu.annotation.param.Param;
|
|||
import org.mariotaku.restfu.annotation.param.Queries;
|
||||
import org.mariotaku.restfu.annotation.param.Query;
|
||||
|
||||
@SuppressWarnings("RedundantThrows")
|
||||
public interface ListResources {
|
||||
@POST("/lists/members/create.json")
|
||||
UserList addUserListMember(@Query("list_id") String listId, @Query("user_id") String userId) throws MicroBlogException;
|
||||
|
|
|
@ -29,8 +29,10 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Mapper for IDs object
|
||||
* Created by mariotaku on 15/10/21.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class IDs$$JsonObjectMapper extends JsonMapper<IDs> {
|
||||
|
||||
@SuppressWarnings("TryWithIdenticalCatches")
|
||||
|
|
|
@ -27,9 +27,9 @@ import org.mariotaku.twidere.util.model.AccountDetailsUtils;
|
|||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Object holding account info and credentials
|
||||
* Created by mariotaku on 2016/12/3.
|
||||
*/
|
||||
|
||||
@ParcelablePlease
|
||||
@JsonObject
|
||||
public class AccountDetails implements Parcelable, Comparable<AccountDetails> {
|
||||
|
|
|
@ -41,7 +41,6 @@ import org.mariotaku.twidere.model.util.UserKeyCursorFieldConverter;
|
|||
import org.mariotaku.twidere.provider.TwidereDataStore;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Statuses;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.Arrays;
|
||||
|
@ -445,11 +444,11 @@ public class ParcelableStatus implements Parcelable, Comparable<ParcelableStatus
|
|||
}
|
||||
|
||||
@OnJsonParseComplete
|
||||
void onParseComplete() throws IOException {
|
||||
void onParseComplete() {
|
||||
fixSortId();
|
||||
}
|
||||
|
||||
void fixSortId() {
|
||||
private void fixSortId() {
|
||||
if (sort_id <= 0) {
|
||||
try {
|
||||
sort_id = Long.parseLong(id);
|
||||
|
|
|
@ -1,53 +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.model.util;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.mariotaku.library.objectcursor.converter.CursorFieldConverter;
|
||||
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 15/11/27.
|
||||
*/
|
||||
public class JSONObjectConverter implements CursorFieldConverter<JSONObject> {
|
||||
@Override
|
||||
public JSONObject parseField(Cursor cursor, int columnIndex, ParameterizedType fieldType) {
|
||||
final String string = cursor.getString(columnIndex);
|
||||
if (TextUtils.isEmpty(string)) return null;
|
||||
try {
|
||||
return new JSONObject(string);
|
||||
} catch (JSONException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeField(ContentValues values, JSONObject object, String columnName, ParameterizedType fieldType) {
|
||||
if (object != null) {
|
||||
values.put(columnName, object.toString());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,54 +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.model.util;
|
||||
|
||||
import android.os.Parcel;
|
||||
|
||||
import com.hannesdorfmann.parcelableplease.ParcelBagger;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 15/11/28.
|
||||
*/
|
||||
public class JSONParcelBagger implements ParcelBagger<JSONObject> {
|
||||
@Override
|
||||
public void write(JSONObject value, Parcel out, int flags) {
|
||||
if (value != null) {
|
||||
out.writeString(value.toString());
|
||||
} else {
|
||||
out.writeString(null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject read(Parcel in) {
|
||||
final String s = in.readString();
|
||||
if (s != null) {
|
||||
try {
|
||||
return new JSONObject(s);
|
||||
} catch (JSONException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -1,85 +0,0 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.util;
|
||||
|
||||
import java.util.Vector;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class HtmlLinkExtractor {
|
||||
|
||||
private final Pattern patternTag, patternLink;
|
||||
|
||||
private static final String HTML_A_TAG_PATTERN = "(?i)<a([^>]+)>(.+?)</a>";
|
||||
private static final String HTML_A_HREF_TAG_PATTERN = "\\s*(?i)href\\s*=\\s*(\"([^\"]*\")|'[^']*'|([^'\">\\s]+))";
|
||||
|
||||
public HtmlLinkExtractor() {
|
||||
patternTag = Pattern.compile(HTML_A_TAG_PATTERN);
|
||||
patternLink = Pattern.compile(HTML_A_HREF_TAG_PATTERN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate html with regular expression
|
||||
*
|
||||
* @param html html content for validation
|
||||
* @return Vector links and link text
|
||||
*/
|
||||
public Vector<HtmlLink> grabLinks(final String html) {
|
||||
final Vector<HtmlLink> result = new Vector<>();
|
||||
final Matcher matcherTag = patternTag.matcher(html);
|
||||
while (matcherTag.find()) {
|
||||
final String href = matcherTag.group(1); // href
|
||||
final String linkText = matcherTag.group(2); // link text
|
||||
final Matcher matcherLink = patternLink.matcher(href);
|
||||
while (matcherLink.find()) {
|
||||
final String link = matcherLink.group(1); // link
|
||||
final HtmlLink obj = new HtmlLink(link, linkText);
|
||||
result.add(obj);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static class HtmlLink {
|
||||
|
||||
private final String link;
|
||||
private final String text;
|
||||
|
||||
private HtmlLink(final String link, final String text) {
|
||||
this.link = replaceInvalidChar(link);
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public String getLink() {
|
||||
return link;
|
||||
}
|
||||
|
||||
public String getLinkText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
private static String replaceInvalidChar(String link) {
|
||||
link = link.replaceAll("'", "");
|
||||
link = link.replaceAll("\"", "");
|
||||
return link;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,47 +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.util;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 15/11/25.
|
||||
*/
|
||||
public class Nullables {
|
||||
|
||||
private Nullables() {
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static <T> List<T> list(@Nullable List<T> list) {
|
||||
if (list == null) return Collections.emptyList();
|
||||
return list;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static <T> T assertNonNull(@Nullable T object) {
|
||||
if (object == null) throw new NullPointerException();
|
||||
return object;
|
||||
}
|
||||
}
|
|
@ -29,10 +29,6 @@ public final class ParseUtils implements TwidereConstants {
|
|||
private ParseUtils() {
|
||||
}
|
||||
|
||||
public static String parseString(final String object) {
|
||||
return object;
|
||||
}
|
||||
|
||||
public static String parseString(final Object object) {
|
||||
return parseString(object, null);
|
||||
}
|
||||
|
|
|
@ -35,5 +35,6 @@ android {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
compile "com.android.support:support-compat:$android_support_lib_version"
|
||||
compile fileTree(dir: 'libs', include: ['*.jar'])
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ import android.graphics.Shader.TileMode;
|
|||
import android.graphics.drawable.AnimationDrawable;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
|
@ -77,9 +78,9 @@ public class NyanDrawingHelper {
|
|||
} else {
|
||||
sakamotoRes = R.drawable.nyan_sakamoto;
|
||||
}
|
||||
mSakamotoHelper = new DrawableDrawingHelper(mResources.getDrawable(sakamotoRes));
|
||||
mSakamotoHelper = new DrawableDrawingHelper(ContextCompat.getDrawable(context, sakamotoRes));
|
||||
mDrawingHelpers = new IDrawingHelper[]{mStarsHelper, mRainbowHelper, mSakamotoHelper};
|
||||
mBackgroundColor = mResources.getColor(R.color.nyan_background);
|
||||
mBackgroundColor = ContextCompat.getColor(context, R.color.nyan_background);
|
||||
}
|
||||
|
||||
public final void dispatchDraw(final Canvas canvas) {
|
||||
|
|
|
@ -1,65 +0,0 @@
|
|||
package org.mariotaku.twidere.util
|
||||
|
||||
import org.junit.Test
|
||||
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 16/1/23.
|
||||
*/
|
||||
class TwidereMathUtilsTest {
|
||||
|
||||
@Throws(Exception::class)
|
||||
fun testClamp() {
|
||||
|
||||
}
|
||||
|
||||
@Throws(Exception::class)
|
||||
fun testClamp1() {
|
||||
|
||||
}
|
||||
|
||||
@Throws(Exception::class)
|
||||
fun testNextPowerOf2() {
|
||||
|
||||
}
|
||||
|
||||
@Throws(Exception::class)
|
||||
fun testPrevPowerOf2() {
|
||||
|
||||
}
|
||||
|
||||
@Throws(Exception::class)
|
||||
fun testSum() {
|
||||
|
||||
}
|
||||
|
||||
@Throws(Exception::class)
|
||||
fun testSum1() {
|
||||
|
||||
}
|
||||
|
||||
@Throws(Exception::class)
|
||||
fun testSum2() {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testInRange() {
|
||||
assertTrue(TwidereMathUtils.inRange(5, 0, 10, TwidereMathUtils.RANGE_INCLUSIVE_INCLUSIVE))
|
||||
assertFalse(TwidereMathUtils.inRange(0, 0, 10, TwidereMathUtils.RANGE_EXCLUSIVE_EXCLUSIVE))
|
||||
assertFalse(TwidereMathUtils.inRange(0, 5, 10, TwidereMathUtils.RANGE_INCLUSIVE_INCLUSIVE))
|
||||
assertFalse(TwidereMathUtils.inRange(5, 5, 10, TwidereMathUtils.RANGE_EXCLUSIVE_INCLUSIVE))
|
||||
assertFalse(TwidereMathUtils.inRange(10, 5, 10, TwidereMathUtils.RANGE_INCLUSIVE_EXCLUSIVE))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testInRange1() {
|
||||
assertTrue(TwidereMathUtils.inRange(5f, 0f, 10f, TwidereMathUtils.RANGE_INCLUSIVE_INCLUSIVE))
|
||||
assertFalse(TwidereMathUtils.inRange(0f, 0f, 10f, TwidereMathUtils.RANGE_EXCLUSIVE_EXCLUSIVE))
|
||||
assertFalse(TwidereMathUtils.inRange(0f, 5f, 10f, TwidereMathUtils.RANGE_INCLUSIVE_INCLUSIVE))
|
||||
assertFalse(TwidereMathUtils.inRange(5f, 5f, 10f, TwidereMathUtils.RANGE_EXCLUSIVE_INCLUSIVE))
|
||||
assertFalse(TwidereMathUtils.inRange(10f, 5f, 10f, TwidereMathUtils.RANGE_INCLUSIVE_EXCLUSIVE))
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
TwitterCardViewFactoryImpl
|
|
@ -56,6 +56,7 @@ public final class CRLFLineReader extends BufferedReader
|
|||
StringBuilder sb = new StringBuilder();
|
||||
int intch;
|
||||
boolean prevWasCR = false;
|
||||
//noinspection SynchronizeOnNonFinalField
|
||||
synchronized(lock) { // make thread-safe (hopefully!)
|
||||
while((intch = read()) != -1)
|
||||
{
|
||||
|
|
|
@ -1,135 +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.microblog.library.twitter.util;
|
||||
|
||||
import com.fasterxml.jackson.core.TreeNode;
|
||||
|
||||
/**
|
||||
* @author Dan Checkoway - dcheckoway at gmail.com
|
||||
* @since Twitter4J 2.1.9
|
||||
*/
|
||||
public final class JSONObjectType {
|
||||
private JSONObjectType() {
|
||||
}
|
||||
|
||||
public enum Type {
|
||||
SENDER,
|
||||
STATUS,
|
||||
DIRECT_MESSAGE,
|
||||
DELETE,
|
||||
LIMIT,
|
||||
STALL_WARNING,
|
||||
SCRUB_GEO,
|
||||
FRIENDS,
|
||||
FAVORITE,
|
||||
UNFAVORITE,
|
||||
FOLLOW,
|
||||
UNFOLLOW,
|
||||
USER_LIST_MEMBER_ADDED,
|
||||
USER_LIST_MEMBER_DELETED,
|
||||
USER_LIST_SUBSCRIBED,
|
||||
USER_LIST_UNSUBSCRIBED,
|
||||
USER_LIST_CREATED,
|
||||
USER_LIST_UPDATED,
|
||||
USER_LIST_DESTROYED,
|
||||
USER_UPDATE,
|
||||
USER_DELETE,
|
||||
USER_SUSPEND,
|
||||
BLOCK,
|
||||
UNBLOCK,
|
||||
DISCONNECTION,
|
||||
UNKNOWN
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine the respective object type for a given JSONObject. This
|
||||
* method inspects the object to figure out what type of object it
|
||||
* represents. This is useful when processing JSON events of mixed type
|
||||
* from a stream, in which case you may need to know what type of object
|
||||
* to construct, or how to handle the event properly.
|
||||
*
|
||||
* @param json the JSONObject whose type should be determined
|
||||
* @return the determined JSONObjectType, or null if not recognized
|
||||
*/
|
||||
public static Type determine(TreeNode json) {
|
||||
// This code originally lived in AbstractStreamImplementation.
|
||||
// I've moved it in here to expose it as a public encapsulation of
|
||||
// the object type determination logic.
|
||||
if (json.get("sender") != null) {
|
||||
return Type.SENDER;
|
||||
} else if (json.get("text") != null) {
|
||||
return Type.STATUS;
|
||||
} else if (json.get("direct_message") != null) {
|
||||
return Type.DIRECT_MESSAGE;
|
||||
} else if (json.get("delete") != null) {
|
||||
return Type.DELETE;
|
||||
} else if (json.get("limit") != null) {
|
||||
return Type.LIMIT;
|
||||
} else if (json.get("warning") != null) {
|
||||
return Type.STALL_WARNING;
|
||||
} else if (json.get("scrub_geo") != null) {
|
||||
return Type.SCRUB_GEO;
|
||||
} else if (json.get("friends") != null) {
|
||||
return Type.FRIENDS;
|
||||
} else if (json.get("event") != null) {
|
||||
String event;
|
||||
event = json.get("event").asToken().asString();
|
||||
if ("favorite".equals(event)) {
|
||||
return Type.FAVORITE;
|
||||
} else if ("unfavorite".equals(event)) {
|
||||
return Type.UNFAVORITE;
|
||||
} else if ("follow".equals(event)) {
|
||||
return Type.FOLLOW;
|
||||
} else if ("unfollow".equals(event)) {
|
||||
return Type.UNFOLLOW;
|
||||
} else if (event.startsWith("list")) {
|
||||
if ("list_member_added".equals(event)) {
|
||||
return Type.USER_LIST_MEMBER_ADDED;
|
||||
} else if ("list_member_removed".equals(event)) {
|
||||
return Type.USER_LIST_MEMBER_DELETED;
|
||||
} else if ("list_user_subscribed".equals(event)) {
|
||||
return Type.USER_LIST_SUBSCRIBED;
|
||||
} else if ("list_user_unsubscribed".equals(event)) {
|
||||
return Type.USER_LIST_UNSUBSCRIBED;
|
||||
} else if ("list_created".equals(event)) {
|
||||
return Type.USER_LIST_CREATED;
|
||||
} else if ("list_updated".equals(event)) {
|
||||
return Type.USER_LIST_UPDATED;
|
||||
} else if ("list_destroyed".equals(event)) {
|
||||
return Type.USER_LIST_DESTROYED;
|
||||
}
|
||||
} else if ("user_update".equals(event)) {
|
||||
return Type.USER_UPDATE;
|
||||
} else if ("user_delete".equals(event)) {
|
||||
return Type.USER_DELETE;
|
||||
} else if ("user_suspend".equals(event)) {
|
||||
return Type.USER_SUSPEND;
|
||||
} else if ("block".equals(event)) {
|
||||
return Type.BLOCK;
|
||||
} else if ("unblock".equals(event)) {
|
||||
return Type.UNBLOCK;
|
||||
}
|
||||
} else if (json.get("disconnect") != null) {
|
||||
return Type.DISCONNECTION;
|
||||
}
|
||||
return Type.UNKNOWN;
|
||||
}
|
||||
}
|
|
@ -51,7 +51,6 @@ import static org.mariotaku.twidere.constant.IntentConstants.EXTRA_TITLE;
|
|||
public final class DataExportImportTypeSelectorDialogFragment extends BaseDialogFragment implements
|
||||
OnMultiChoiceClickListener, OnClickListener, OnShowListener, OnItemClickListener {
|
||||
|
||||
private TypeAdapter mAdapter;
|
||||
private ListView mListView;
|
||||
|
||||
@Override
|
||||
|
@ -84,20 +83,20 @@ public final class DataExportImportTypeSelectorDialogFragment extends BaseDialog
|
|||
public final Dialog onCreateDialog(final Bundle savedInstanceState) {
|
||||
final Context context = getActivity();
|
||||
final int flags = getEnabledFlags();
|
||||
mAdapter = new TypeAdapter(context, flags);
|
||||
mListView = new ListView(context);
|
||||
mAdapter.add(new Type(R.string.settings, DataImportExportUtils.FLAG_PREFERENCES));
|
||||
mAdapter.add(new Type(R.string.title_nicknames, DataImportExportUtils.FLAG_NICKNAMES));
|
||||
mAdapter.add(new Type(R.string.title_user_colors, DataImportExportUtils.FLAG_USER_COLORS));
|
||||
mAdapter.add(new Type(R.string.custom_host_mapping, DataImportExportUtils.FLAG_HOST_MAPPING));
|
||||
mAdapter.add(new Type(R.string.keyboard_shortcuts, DataImportExportUtils.FLAG_KEYBOARD_SHORTCUTS));
|
||||
mAdapter.add(new Type(R.string.title_filters, DataImportExportUtils.FLAG_FILTERS));
|
||||
mAdapter.add(new Type(R.string.tabs, DataImportExportUtils.FLAG_TABS));
|
||||
mListView.setAdapter(mAdapter);
|
||||
final TypeAdapter adapter = new TypeAdapter(context, flags);
|
||||
adapter.add(new Type(R.string.settings, DataImportExportUtils.FLAG_PREFERENCES));
|
||||
adapter.add(new Type(R.string.title_nicknames, DataImportExportUtils.FLAG_NICKNAMES));
|
||||
adapter.add(new Type(R.string.title_user_colors, DataImportExportUtils.FLAG_USER_COLORS));
|
||||
adapter.add(new Type(R.string.custom_host_mapping, DataImportExportUtils.FLAG_HOST_MAPPING));
|
||||
adapter.add(new Type(R.string.keyboard_shortcuts, DataImportExportUtils.FLAG_KEYBOARD_SHORTCUTS));
|
||||
adapter.add(new Type(R.string.title_filters, DataImportExportUtils.FLAG_FILTERS));
|
||||
adapter.add(new Type(R.string.tabs, DataImportExportUtils.FLAG_TABS));
|
||||
mListView.setAdapter(adapter);
|
||||
mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
|
||||
mListView.setOnItemClickListener(this);
|
||||
for (int i = 0, j = mAdapter.getCount(); i < j; i++) {
|
||||
mListView.setItemChecked(i, mAdapter.isEnabled(i));
|
||||
for (int i = 0, j = adapter.getCount(); i < j; i++) {
|
||||
mListView.setItemChecked(i, adapter.isEnabled(i));
|
||||
}
|
||||
final AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
||||
builder.setTitle(getTitle());
|
||||
|
|
|
@ -1,97 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2010 Daniel Nilsson
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.graphic;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.ColorFilter;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
/**
|
||||
* This drawable that draws a simple white and gray chessboard pattern. It's
|
||||
* pattern you will often see as a background behind a partly transparent image
|
||||
* in many applications.
|
||||
*
|
||||
* @author Daniel Nilsson
|
||||
*/
|
||||
public class AlphaPatternDrawable extends Drawable {
|
||||
|
||||
private final int mAlphaPatternSize;
|
||||
|
||||
private int mNumRectanglesHorizontal;
|
||||
private int mNumRectanglesVertical;
|
||||
|
||||
private final Rect mRect = new Rect(), mBounds = new Rect();
|
||||
private final Paint mPaint = new Paint();
|
||||
|
||||
public AlphaPatternDrawable(final int alphaPatternSize) {
|
||||
mAlphaPatternSize = alphaPatternSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(@NonNull final Canvas canvas) {
|
||||
|
||||
boolean verticalStartWhite = true;
|
||||
for (int i = 0; i <= mNumRectanglesVertical; i++) {
|
||||
boolean horizontalStartWhite = verticalStartWhite;
|
||||
for (int j = 0; j <= mNumRectanglesHorizontal; j++) {
|
||||
mRect.setEmpty();
|
||||
mRect.top = i * mAlphaPatternSize + mBounds.top;
|
||||
mRect.left = j * mAlphaPatternSize + mBounds.left;
|
||||
mRect.bottom = Math.min(mRect.top + mAlphaPatternSize, mBounds.bottom);
|
||||
mRect.right = Math.min(mRect.left + mAlphaPatternSize, mBounds.right);
|
||||
|
||||
mPaint.setColor(horizontalStartWhite ? Color.WHITE : Color.LTGRAY);
|
||||
canvas.drawRect(mRect, mPaint);
|
||||
|
||||
horizontalStartWhite = !horizontalStartWhite;
|
||||
}
|
||||
verticalStartWhite = !verticalStartWhite;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOpacity() {
|
||||
return PixelFormat.OPAQUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAlpha(final int alpha) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setColorFilter(final ColorFilter cf) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onBoundsChange(final Rect bounds) {
|
||||
super.onBoundsChange(bounds);
|
||||
mBounds.set(bounds);
|
||||
final int height = bounds.height();
|
||||
final int width = bounds.width();
|
||||
mNumRectanglesHorizontal = (int) Math.ceil(width / mAlphaPatternSize);
|
||||
mNumRectanglesVertical = (int) Math.ceil(height / mAlphaPatternSize);
|
||||
invalidateSelf();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,69 +0,0 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.graphic;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Rect;
|
||||
|
||||
public class ColorPreviewDrawable extends AlphaPatternDrawable {
|
||||
|
||||
private final int mColor;
|
||||
private final Paint mPaint;
|
||||
private final float[] mPoints;
|
||||
|
||||
public ColorPreviewDrawable(final int alphaPatternSize, final int color) {
|
||||
super(alphaPatternSize);
|
||||
mPaint = new Paint();
|
||||
mPaint.setColor(Color.WHITE);
|
||||
mPaint.setStrokeWidth(2.0f);
|
||||
mColor = color;
|
||||
mPoints = new float[16];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(final Canvas canvas) {
|
||||
super.draw(canvas);
|
||||
canvas.drawColor(mColor);
|
||||
canvas.drawLines(mPoints, mPaint);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onBoundsChange(final Rect bounds) {
|
||||
super.onBoundsChange(bounds);
|
||||
mPoints[0] = bounds.top;
|
||||
mPoints[1] = bounds.top;
|
||||
mPoints[2] = bounds.right;
|
||||
mPoints[3] = bounds.top;
|
||||
mPoints[4] = bounds.top;
|
||||
mPoints[5] = bounds.top;
|
||||
mPoints[6] = bounds.top;
|
||||
mPoints[7] = bounds.bottom;
|
||||
mPoints[8] = bounds.right;
|
||||
mPoints[9] = bounds.top;
|
||||
mPoints[10] = bounds.right;
|
||||
mPoints[11] = bounds.bottom;
|
||||
mPoints[12] = bounds.top;
|
||||
mPoints[13] = bounds.bottom;
|
||||
mPoints[14] = bounds.right;
|
||||
mPoints[15] = bounds.bottom;
|
||||
}
|
||||
}
|
|
@ -1,451 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2012 Wireless Designs, LLC
|
||||
* <p>
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
* <p>
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
* <p>
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.graphic;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.ColorFilter;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.Typeface;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.text.Layout;
|
||||
import android.text.StaticLayout;
|
||||
import android.text.TextPaint;
|
||||
import android.util.TypedValue;
|
||||
|
||||
/**
|
||||
* A Drawable object that draws text. A TextDrawable accepts most of the same
|
||||
* parameters that can be applied to {@link android.widget.TextView} for
|
||||
* displaying and formatting text.
|
||||
*
|
||||
* Optionally, a {@link Path} may be supplied on which to draw the text.
|
||||
*
|
||||
* A TextDrawable has an intrinsic size equal to that required to draw all the
|
||||
* text it has been supplied, when possible. In cases where a {@link Path} has
|
||||
* been supplied, the caller must explicitly call
|
||||
* {@link #setBounds(android.graphics.Rect) setBounds()} to provide the Drawable
|
||||
* size based on the Path constraints.
|
||||
*/
|
||||
public class TextDrawable extends Drawable {
|
||||
|
||||
/* Platform XML constants for typeface */
|
||||
private static final int SANS = 1;
|
||||
private static final int SERIF = 2;
|
||||
private static final int MONOSPACE = 3;
|
||||
|
||||
/* Resources for scaling values to the given device */
|
||||
private final Resources mResources;
|
||||
/* Paint to hold most drawing primitives for the text */
|
||||
private final TextPaint mTextPaint;
|
||||
/* Layout is used to measure and draw the text */
|
||||
private StaticLayout mTextLayout;
|
||||
/* Alignment of the text inside its bounds */
|
||||
private Layout.Alignment mTextAlignment = Layout.Alignment.ALIGN_NORMAL;
|
||||
/* Optional path on which to draw the text */
|
||||
private Path mTextPath;
|
||||
/* Stateful text color list */
|
||||
private ColorStateList mTextColors;
|
||||
/* Container for the bounds to be reported to widgets */
|
||||
private final Rect mTextBounds;
|
||||
/* Text string to draw */
|
||||
private CharSequence mText = "";
|
||||
|
||||
/* Attribute lists to pull default values from the current theme */
|
||||
private static final int[] themeAttributes = {android.R.attr.textAppearance};
|
||||
private static final int[] appearanceAttributes = {android.R.attr.textSize, android.R.attr.typeface,
|
||||
android.R.attr.textStyle, android.R.attr.textColor};
|
||||
|
||||
public TextDrawable(final Context context) {
|
||||
super();
|
||||
// Used to load and scale resource items
|
||||
mResources = context.getResources();
|
||||
// Definition of this drawables size
|
||||
mTextBounds = new Rect();
|
||||
// Paint to use for the text
|
||||
mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
|
||||
mTextPaint.density = mResources.getDisplayMetrics().density;
|
||||
mTextPaint.setDither(true);
|
||||
|
||||
int textSize = 15;
|
||||
ColorStateList textColor = null;
|
||||
int styleIndex = -1;
|
||||
int typefaceIndex = -1;
|
||||
|
||||
// Set default parameters from the current theme
|
||||
final TypedArray a = context.getTheme().obtainStyledAttributes(themeAttributes);
|
||||
final int appearanceId = a.getResourceId(0, -1);
|
||||
a.recycle();
|
||||
|
||||
TypedArray ap = null;
|
||||
if (appearanceId != -1) {
|
||||
ap = context.obtainStyledAttributes(appearanceId, appearanceAttributes);
|
||||
}
|
||||
if (ap != null) {
|
||||
for (int i = 0; i < ap.getIndexCount(); i++) {
|
||||
final int attr = ap.getIndex(i);
|
||||
switch (attr) {
|
||||
case 0: // Text Size
|
||||
textSize = a.getDimensionPixelSize(attr, textSize);
|
||||
break;
|
||||
case 1: // Typeface
|
||||
typefaceIndex = a.getInt(attr, typefaceIndex);
|
||||
break;
|
||||
case 2: // Text Style
|
||||
styleIndex = a.getInt(attr, styleIndex);
|
||||
break;
|
||||
case 3: // Text Color
|
||||
textColor = a.getColorStateList(attr);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ap.recycle();
|
||||
}
|
||||
|
||||
setTextColor(textColor != null ? textColor : ColorStateList.valueOf(0xFF000000));
|
||||
setRawTextSize(textSize);
|
||||
|
||||
Typeface tf = null;
|
||||
switch (typefaceIndex) {
|
||||
case SANS:
|
||||
tf = Typeface.SANS_SERIF;
|
||||
break;
|
||||
|
||||
case SERIF:
|
||||
tf = Typeface.SERIF;
|
||||
break;
|
||||
|
||||
case MONOSPACE:
|
||||
tf = Typeface.MONOSPACE;
|
||||
break;
|
||||
}
|
||||
|
||||
setTypeface(tf, styleIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(@NonNull final Canvas canvas) {
|
||||
if (mTextPath == null) {
|
||||
// Allow the layout to draw the text
|
||||
mTextLayout.draw(canvas);
|
||||
} else {
|
||||
// Draw directly on the canvas using the supplied path
|
||||
canvas.drawTextOnPath(mText.toString(), mTextPath, 0, 0, mTextPaint);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIntrinsicHeight() {
|
||||
// Return the vertical bounds measured, or -1 if none
|
||||
if (mTextBounds.isEmpty())
|
||||
return -1;
|
||||
else
|
||||
return mTextBounds.bottom - mTextBounds.top;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIntrinsicWidth() {
|
||||
// Return the horizontal bounds measured, or -1 if none
|
||||
if (mTextBounds.isEmpty())
|
||||
return -1;
|
||||
else
|
||||
return mTextBounds.right - mTextBounds.left;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOpacity() {
|
||||
return PixelFormat.TRANSLUCENT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the text currently being displayed
|
||||
*/
|
||||
public CharSequence getText() {
|
||||
return mText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current text alignment setting
|
||||
*/
|
||||
public Layout.Alignment getTextAlign() {
|
||||
return mTextAlignment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the horizontal stretch factor of the text
|
||||
*/
|
||||
public float getTextScaleX() {
|
||||
return mTextPaint.getTextScaleX();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current text size, in pixels
|
||||
*/
|
||||
public float getTextSize() {
|
||||
return mTextPaint.getTextSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current typeface and style that the Paint using for display.
|
||||
*/
|
||||
public Typeface getTypeface() {
|
||||
return mTextPaint.getTypeface();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStateful() {
|
||||
/*
|
||||
* The drawable's ability to represent state is based on the text color
|
||||
* list set
|
||||
*/
|
||||
return mTextColors.isStateful();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAlpha(final int alpha) {
|
||||
if (mTextPaint.getAlpha() != alpha) {
|
||||
mTextPaint.setAlpha(alpha);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setColorFilter(final ColorFilter cf) {
|
||||
if (mTextPaint.getColorFilter() != cf) {
|
||||
mTextPaint.setColorFilter(cf);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the text that will be displayed
|
||||
*
|
||||
* @param text Text to display
|
||||
*/
|
||||
public void setText(CharSequence text) {
|
||||
if (text == null) {
|
||||
text = "";
|
||||
}
|
||||
|
||||
mText = text;
|
||||
|
||||
measureContent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the text alignment. The alignment itself is based on the text layout
|
||||
* direction. For LTR text NORMAL is left aligned and OPPOSITE is right
|
||||
* aligned. For RTL text, those alignments are reversed.
|
||||
*
|
||||
* @param align Text alignment value. Should be set to one of:
|
||||
*
|
||||
* {@link Layout.Alignment#ALIGN_NORMAL},
|
||||
* {@link Layout.Alignment#ALIGN_NORMAL},
|
||||
* {@link Layout.Alignment#ALIGN_OPPOSITE}.
|
||||
*/
|
||||
public void setTextAlign(final Layout.Alignment align) {
|
||||
if (mTextAlignment != align) {
|
||||
mTextAlignment = align;
|
||||
measureContent();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the text color as a state list
|
||||
*
|
||||
* @param colorStateList ColorStateList of text colors, such as inflated
|
||||
* from an R.color resource
|
||||
*/
|
||||
public void setTextColor(final ColorStateList colorStateList) {
|
||||
mTextColors = colorStateList;
|
||||
updateTextColors(getState());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a single text color for all states
|
||||
*
|
||||
* @param color Color value such as {@link Color#WHITE} or
|
||||
* {@link Color#argb(int, int, int, int)}
|
||||
*/
|
||||
public void setTextColor(final int color) {
|
||||
setTextColor(ColorStateList.valueOf(color));
|
||||
}
|
||||
|
||||
/**
|
||||
* Optional Path object on which to draw the text. If this is set,
|
||||
* TextDrawable cannot properly measure the bounds this drawable will need.
|
||||
* You must call {@link #setBounds(int, int, int, int) setBounds()} before
|
||||
* applying this TextDrawable to any View.
|
||||
*
|
||||
* Calling this method with <code>null</code> will remove any Path currently
|
||||
* attached.
|
||||
*/
|
||||
public void setTextPath(final Path path) {
|
||||
if (mTextPath != path) {
|
||||
mTextPath = path;
|
||||
measureContent();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the horizontal stretch factor of the text
|
||||
*
|
||||
* @param size Text scale factor
|
||||
*/
|
||||
public void setTextScaleX(final float size) {
|
||||
if (size != mTextPaint.getTextScaleX()) {
|
||||
mTextPaint.setTextScaleX(size);
|
||||
measureContent();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the text size. The value will be interpreted in "sp" units
|
||||
*
|
||||
* @param size Text size value, in sp
|
||||
*/
|
||||
public void setTextSize(final float size) {
|
||||
setTextSize(TypedValue.COMPLEX_UNIT_SP, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the text size, using the supplied complex units
|
||||
*
|
||||
* @param unit Units for the text size, such as dp or sp
|
||||
* @param size Text size value
|
||||
*/
|
||||
public void setTextSize(final int unit, final float size) {
|
||||
final float dimension = TypedValue.applyDimension(unit, size, mResources.getDisplayMetrics());
|
||||
setRawTextSize(dimension);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the typeface and style in which the text should be displayed. Note
|
||||
* that not all Typeface families actually have bold and italic variants, so
|
||||
* you may need to use {@link #setTypeface(Typeface, int)} to get the
|
||||
* appearance that you actually want.
|
||||
*/
|
||||
public void setTypeface(final Typeface tf) {
|
||||
if (mTextPaint.getTypeface() != tf) {
|
||||
mTextPaint.setTypeface(tf);
|
||||
|
||||
measureContent();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the typeface and style in which the text should be displayed, and
|
||||
* turns on the fake bold and italic bits in the Paint if the Typeface that
|
||||
* you provided does not have all the bits in the style that you specified.
|
||||
*
|
||||
*/
|
||||
public void setTypeface(Typeface tf, final int style) {
|
||||
if (style > 0) {
|
||||
if (tf == null) {
|
||||
tf = Typeface.defaultFromStyle(style);
|
||||
} else {
|
||||
tf = Typeface.create(tf, style);
|
||||
}
|
||||
|
||||
setTypeface(tf);
|
||||
// now compute what (if any) algorithmic styling is needed
|
||||
final int typefaceStyle = tf != null ? tf.getStyle() : 0;
|
||||
final int need = style & ~typefaceStyle;
|
||||
mTextPaint.setFakeBoldText((need & Typeface.BOLD) != 0);
|
||||
mTextPaint.setTextSkewX((need & Typeface.ITALIC) != 0 ? -0.25f : 0);
|
||||
} else {
|
||||
mTextPaint.setFakeBoldText(false);
|
||||
mTextPaint.setTextSkewX(0);
|
||||
setTypeface(tf);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onBoundsChange(final Rect bounds) {
|
||||
// Update the internal bounds in response to any external requests
|
||||
mTextBounds.set(bounds);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onStateChange(final int[] state) {
|
||||
// Upon state changes, grab the correct text color
|
||||
return updateTextColors(state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal method to take measurements of the current contents and apply
|
||||
* the correct bounds when possible.
|
||||
*/
|
||||
private void measureContent() {
|
||||
// If drawing to a path, we cannot measure intrinsic bounds
|
||||
// We must resly on setBounds being called externally
|
||||
if (mTextPath != null) {
|
||||
// Clear any previous measurement
|
||||
mTextLayout = null;
|
||||
mTextBounds.setEmpty();
|
||||
} else {
|
||||
// Measure text bounds
|
||||
final float desired = Layout.getDesiredWidth(mText, mTextPaint);
|
||||
mTextLayout = new StaticLayout(mText, mTextPaint, (int) desired, mTextAlignment, 1.0f, 0.0f, false);
|
||||
mTextBounds.set(0, 0, mTextLayout.getWidth(), mTextLayout.getHeight());
|
||||
}
|
||||
|
||||
// We may need to be redrawn
|
||||
invalidateSelf();
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the text size, in raw pixels
|
||||
*/
|
||||
private void setRawTextSize(final float size) {
|
||||
if (size != mTextPaint.getTextSize()) {
|
||||
mTextPaint.setTextSize(size);
|
||||
|
||||
measureContent();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal method to apply the correct text color based on the drawable's
|
||||
* state
|
||||
*/
|
||||
private boolean updateTextColors(final int[] stateSet) {
|
||||
final int newColor = mTextColors.getColorForState(stateSet, Color.WHITE);
|
||||
if (mTextPaint.getColor() != newColor) {
|
||||
mTextPaint.setColor(newColor);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,117 +0,0 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.loader;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.v4.content.AsyncTaskLoader;
|
||||
import android.util.Log;
|
||||
|
||||
import org.mariotaku.microblog.library.MicroBlog;
|
||||
import org.mariotaku.microblog.library.MicroBlogException;
|
||||
import org.mariotaku.microblog.library.statusnet.model.Group;
|
||||
import org.mariotaku.microblog.library.twitter.model.CursorSupport;
|
||||
import org.mariotaku.microblog.library.twitter.model.PageableResponseList;
|
||||
import org.mariotaku.twidere.TwidereConstants;
|
||||
import org.mariotaku.twidere.loader.iface.ICursorSupportLoader;
|
||||
import org.mariotaku.twidere.model.ParcelableGroup;
|
||||
import org.mariotaku.twidere.model.UserKey;
|
||||
import org.mariotaku.twidere.model.util.ParcelableGroupUtils;
|
||||
import org.mariotaku.twidere.util.MicroBlogAPIFactory;
|
||||
import org.mariotaku.twidere.util.collection.NoDuplicatesArrayList;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public abstract class BaseGroupsLoader extends AsyncTaskLoader<List<ParcelableGroup>>
|
||||
implements TwidereConstants, ICursorSupportLoader {
|
||||
|
||||
protected final NoDuplicatesArrayList<ParcelableGroup> mData = new NoDuplicatesArrayList<>();
|
||||
protected final UserKey mAccountId;
|
||||
private final long mCursor;
|
||||
|
||||
private long mNextCursor, mPrevCursor;
|
||||
|
||||
public BaseGroupsLoader(final Context context, final UserKey accountKey, final long cursor,
|
||||
final List<ParcelableGroup> data) {
|
||||
super(context);
|
||||
if (data != null) {
|
||||
mData.addAll(data);
|
||||
}
|
||||
mCursor = cursor;
|
||||
mAccountId = accountKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCursor() {
|
||||
return mCursor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getNextCursor() {
|
||||
return mNextCursor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getPrevCursor() {
|
||||
return mPrevCursor;
|
||||
}
|
||||
|
||||
public abstract List<Group> getGroups(final MicroBlog twitter) throws MicroBlogException;
|
||||
|
||||
@Override
|
||||
public List<ParcelableGroup> loadInBackground() {
|
||||
final MicroBlog twitter = MicroBlogAPIFactory.getInstance(getContext(), mAccountId);
|
||||
List<Group> listLoaded = null;
|
||||
try {
|
||||
listLoaded = getGroups(twitter);
|
||||
} catch (final MicroBlogException e) {
|
||||
Log.w(LOGTAG, e);
|
||||
}
|
||||
if (listLoaded != null) {
|
||||
final int listSize = listLoaded.size();
|
||||
if (listLoaded instanceof PageableResponseList) {
|
||||
mNextCursor = ((CursorSupport) listLoaded).getNextCursor();
|
||||
mPrevCursor = ((CursorSupport) listLoaded).getPreviousCursor();
|
||||
final int dataSize = mData.size();
|
||||
for (int i = 0; i < listSize; i++) {
|
||||
final Group group = listLoaded.get(i);
|
||||
mData.add(ParcelableGroupUtils.from(group, mAccountId, dataSize + i, isMember(group)));
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < listSize; i++) {
|
||||
final Group list = listLoaded.get(i);
|
||||
mData.add(ParcelableGroupUtils.from(listLoaded.get(i), mAccountId, i, isMember(list)));
|
||||
}
|
||||
}
|
||||
}
|
||||
Collections.sort(mData);
|
||||
return mData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartLoading() {
|
||||
forceLoad();
|
||||
}
|
||||
|
||||
protected boolean isMember(final Group list) {
|
||||
return list.isMember();
|
||||
}
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.loader;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import org.mariotaku.microblog.library.MicroBlog;
|
||||
import org.mariotaku.microblog.library.MicroBlogException;
|
||||
import org.mariotaku.microblog.library.statusnet.model.Group;
|
||||
import org.mariotaku.microblog.library.twitter.model.ResponseList;
|
||||
import org.mariotaku.twidere.model.ParcelableGroup;
|
||||
import org.mariotaku.twidere.model.UserKey;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class UserGroupsLoader extends BaseGroupsLoader {
|
||||
|
||||
private final UserKey mUserKey;
|
||||
private final String mScreenName;
|
||||
|
||||
public UserGroupsLoader(final Context context, final UserKey accountKey, final UserKey userKey,
|
||||
final String screenName, final List<ParcelableGroup> data) {
|
||||
super(context, accountKey, 0, data);
|
||||
mUserKey = userKey;
|
||||
mScreenName = screenName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseList<Group> getGroups(final MicroBlog twitter) throws MicroBlogException {
|
||||
if (twitter == null) return null;
|
||||
if (mUserKey != null) {
|
||||
return twitter.getGroups(mUserKey.getId());
|
||||
} else if (mScreenName != null) {
|
||||
return twitter.getGroups(mScreenName);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isMember(final Group list) {
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -14,6 +14,7 @@ import org.mariotaku.restfu.annotation.method.GET;
|
|||
import org.mariotaku.restfu.http.HttpRequest;
|
||||
import org.mariotaku.restfu.http.HttpResponse;
|
||||
import org.mariotaku.restfu.http.RestHttpClient;
|
||||
import org.mariotaku.twidere.util.Utils;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
@ -70,7 +71,7 @@ public class DefaultFeatures {
|
|||
jsonParser.skipChildren();
|
||||
}
|
||||
} finally {
|
||||
response.close();
|
||||
Utils.closeSilently(response);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1,63 +0,0 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.model;
|
||||
|
||||
import android.app.Fragment;
|
||||
import android.os.Bundle;
|
||||
|
||||
import static org.mariotaku.twidere.util.CompareUtils.bundleEquals;
|
||||
import static org.mariotaku.twidere.util.CompareUtils.objectEquals;
|
||||
|
||||
public class TabSpec {
|
||||
|
||||
public CharSequence name;
|
||||
public final Object icon;
|
||||
public final Class<? extends Fragment> cls;
|
||||
public final Bundle args;
|
||||
public final int position;
|
||||
|
||||
public TabSpec(final CharSequence name, final Object icon, final Class<? extends Fragment> cls, final Bundle args,
|
||||
final int position) {
|
||||
if (cls == null) throw new IllegalArgumentException("Fragment cannot be null!");
|
||||
if (name == null && icon == null)
|
||||
throw new IllegalArgumentException("You must specify a name or icon for this tab!");
|
||||
this.name = name;
|
||||
this.icon = icon;
|
||||
this.cls = cls;
|
||||
this.args = args;
|
||||
this.position = position;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (!(o instanceof TabSpec)) return false;
|
||||
final TabSpec spec = (TabSpec) o;
|
||||
return objectEquals(name, spec.name) && objectEquals(icon, spec.icon) && cls == spec.cls
|
||||
&& bundleEquals(args, spec.args) && position == spec.position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TabSpec{name=" + name + ", icon=" + icon + ", cls=" + cls + ", args=" + args + ", position=" + position
|
||||
+ "}";
|
||||
}
|
||||
|
||||
}
|
|
@ -19,14 +19,17 @@
|
|||
|
||||
package org.mariotaku.twidere.model.message;
|
||||
|
||||
import org.mariotaku.twidere.model.UserKey;
|
||||
|
||||
/**
|
||||
* Called when account changed
|
||||
* Created by mariotaku on 15/4/24.
|
||||
*/
|
||||
public class AccountChangedEvent {
|
||||
public final long[] account_ids, activated_ids;
|
||||
public final UserKey[] account_keys, activated_keys;
|
||||
|
||||
public AccountChangedEvent(long[] account_ids, long[] activated_ids) {
|
||||
this.account_ids = account_ids;
|
||||
this.activated_ids = activated_ids;
|
||||
public AccountChangedEvent(UserKey[] account_keys, UserKey[] activated_keys) {
|
||||
this.account_keys = account_keys;
|
||||
this.activated_keys = activated_keys;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ public class GetMessagesTaskEvent {
|
|||
@NonNull
|
||||
public final Uri uri;
|
||||
public final boolean running;
|
||||
private final Exception exception;
|
||||
public final Exception exception;
|
||||
|
||||
public GetMessagesTaskEvent(@NonNull Uri uri, boolean running, Exception exception) {
|
||||
this.uri = uri;
|
||||
|
|
|
@ -1,26 +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.model.message;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 15/3/23.
|
||||
*/
|
||||
public class VideoLoadFinishedEvent {
|
||||
}
|
|
@ -3,9 +3,9 @@ package org.mariotaku.twidere.model.tab.iface;
|
|||
import org.mariotaku.twidere.model.AccountDetails;
|
||||
|
||||
/**
|
||||
* Account callback for extra configurations
|
||||
* Created by mariotaku on 2016/11/30.
|
||||
*/
|
||||
|
||||
public interface AccountCallback {
|
||||
|
||||
AccountDetails getAccount();
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
package org.mariotaku.twidere.preference;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.PorterDuff.Mode;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v7.preference.Preference;
|
||||
import android.support.v7.preference.PreferenceViewHolder;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import org.mariotaku.twidere.R;
|
||||
import org.mariotaku.twidere.util.ThemeUtils;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 14-7-28.
|
||||
*/
|
||||
public class ForegroundColorIconPreference extends Preference {
|
||||
public ForegroundColorIconPreference(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull PreferenceViewHolder view) {
|
||||
super.onBindViewHolder(view);
|
||||
final int fgColor = ThemeUtils.getThemeForegroundColor(getContext());
|
||||
((ImageView) view.findViewById(android.R.id.icon)).setColorFilter(fgColor, Mode.SRC_ATOP);
|
||||
}
|
||||
|
||||
public ForegroundColorIconPreference(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, R.attr.preferenceStyle);
|
||||
}
|
||||
|
||||
public ForegroundColorIconPreference(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.text;
|
||||
|
||||
import android.text.TextPaint;
|
||||
import android.text.style.CharacterStyle;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 14/12/13.
|
||||
*/
|
||||
public class TextAlphaSpan extends CharacterStyle {
|
||||
|
||||
private int alpha;
|
||||
|
||||
public TextAlphaSpan(int alpha) {
|
||||
this.alpha = alpha;
|
||||
}
|
||||
|
||||
public void setAlpha(int alpha) {
|
||||
this.alpha = alpha;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDrawState(TextPaint tp) {
|
||||
tp.setAlpha(alpha);
|
||||
}
|
||||
}
|
|
@ -106,6 +106,7 @@ public abstract class AbsServiceInterface<I extends IInterface> implements IInte
|
|||
}
|
||||
|
||||
public interface CheckServiceAction {
|
||||
@SuppressWarnings("RedundantThrows")
|
||||
void check(@Nullable Bundle metaData) throws CheckServiceException;
|
||||
}
|
||||
|
||||
|
|
|
@ -513,6 +513,9 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
|
|||
public SingleResponse<Relationship> doLongOperation(Object param) {
|
||||
final MicroBlog microBlog = MicroBlogAPIFactory.getInstance(context, accountKey);
|
||||
try {
|
||||
if (microBlog == null) {
|
||||
throw new MicroBlogException("No account");
|
||||
}
|
||||
final Relationship relationship = microBlog.updateFriendship(userKey.getId(), update);
|
||||
if (!relationship.isSourceWantRetweetsFromTarget()) {
|
||||
// TODO remove cached retweets
|
||||
|
@ -555,6 +558,9 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
|
|||
MicroBlog microBlog = MicroBlogAPIFactory.getInstance(context, accountId);
|
||||
if (!Utils.isOfficialCredentials(context, accountId)) continue;
|
||||
try {
|
||||
if (microBlog == null) {
|
||||
throw new MicroBlogException("No account");
|
||||
}
|
||||
microBlog.setActivitiesAboutMeUnread(cursor);
|
||||
} catch (MicroBlogException e) {
|
||||
DebugLog.w(LOGTAG, null, e);
|
||||
|
@ -733,11 +739,6 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
|
|||
}
|
||||
|
||||
private void deleteCaches(final List<String> list) {
|
||||
for (final Uri uri : DataStoreUtils.STATUSES_URIS) {
|
||||
// TODO delete caches
|
||||
// ContentResolverUtils.bulkDelete(mResolver, uri, Statuses.USER_ID, list,
|
||||
// Statuses.ACCOUNT_ID + " = " + mAccountKey, false);
|
||||
}
|
||||
// I bet you don't want to see these users in your auto complete list.
|
||||
//TODO insert to blocked users data
|
||||
final ContentValues values = new ContentValues();
|
||||
|
|
|
@ -98,11 +98,7 @@ import org.mariotaku.twidere.util.content.ContentResolverUtils;
|
|||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static android.text.TextUtils.isEmpty;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 15/11/28.
|
||||
|
@ -115,8 +111,6 @@ public class DataStoreUtils implements Constants {
|
|||
public static final Uri[] ACTIVITIES_URIS = new Uri[]{Activities.AboutMe.CONTENT_URI};
|
||||
|
||||
private static final UriMatcher CONTENT_PROVIDER_URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
|
||||
private static Map<UserKey, String> sAccountScreenNames = new HashMap<>();
|
||||
private static Map<UserKey, String> sAccountNames = new HashMap<>();
|
||||
|
||||
static {
|
||||
CONTENT_PROVIDER_URI_MATCHER.addURI(TwidereDataStore.AUTHORITY, Statuses.CONTENT_PATH,
|
||||
|
@ -338,9 +332,6 @@ public class DataStoreUtils implements Constants {
|
|||
}
|
||||
|
||||
public static String getAccountName(@NonNull final Context context, final UserKey accountKey) {
|
||||
final String cached = sAccountNames.get(accountKey);
|
||||
if (!isEmpty(cached)) return cached;
|
||||
|
||||
AccountManager am = AccountManager.get(context);
|
||||
Account account = AccountUtils.findByAccountKey(am, accountKey);
|
||||
if (account == null) return null;
|
||||
|
@ -350,13 +341,9 @@ public class DataStoreUtils implements Constants {
|
|||
|
||||
public static String getAccountScreenName(final Context context, final UserKey accountKey) {
|
||||
if (context == null) return null;
|
||||
final String cached = sAccountScreenNames.get(accountKey);
|
||||
if (!isEmpty(cached)) return cached;
|
||||
|
||||
AccountManager am = AccountManager.get(context);
|
||||
Account account = AccountUtils.findByAccountKey(am, accountKey);
|
||||
if (account == null) return null;
|
||||
|
||||
return AccountExtensionsKt.getAccountUser(account, am).screen_name;
|
||||
}
|
||||
|
||||
|
@ -733,10 +720,6 @@ public class DataStoreUtils implements Constants {
|
|||
}
|
||||
}
|
||||
|
||||
public static void clearAccountName() {
|
||||
sAccountScreenNames.clear();
|
||||
}
|
||||
|
||||
public static boolean isFilteringUser(Context context, UserKey userKey) {
|
||||
return isFilteringUser(context, userKey.toString());
|
||||
}
|
||||
|
|
|
@ -42,11 +42,6 @@ public class HtmlEscapeHelper {
|
|||
return ESCAPE_HTML.translate(text);
|
||||
}
|
||||
|
||||
public static String toHtml(final String string) {
|
||||
if (string == null) return null;
|
||||
return escape(string).replace("\n", "<br/>");
|
||||
}
|
||||
|
||||
public static String toPlainText(final String string) {
|
||||
if (string == null) return null;
|
||||
return unescape(string.replace("<br/>", "\n").replaceAll("<!--.*?-->|<[^>]+>", ""));
|
||||
|
|
|
@ -1,119 +0,0 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.util;
|
||||
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.net.Uri;
|
||||
|
||||
import com.nostra13.universalimageloader.utils.IoUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class ImageValidator {
|
||||
|
||||
public static int INVALID = 0;
|
||||
public static int VALID_FOR_BITMAP_FACTORY = 0x1;
|
||||
public static int VALID_FOR_REGION_DECODER = 0x2;
|
||||
public static int VALID_FOR_ALL = VALID_FOR_BITMAP_FACTORY | VALID_FOR_REGION_DECODER;
|
||||
|
||||
private static final byte[] PNG_HEAD = {(byte) 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A};
|
||||
private static final byte[] PNG_TAIL = {0x49, 0x45, 0x4E, 0x44, (byte) 0xAE, 0x42, 0x60, (byte) 0x82};
|
||||
|
||||
private static final byte[] JPEG_HEAD = {(byte) 0xFF, (byte) 0xD8};
|
||||
private static final byte[] JPEG_TAIL = {(byte) 0xFF, (byte) 0xD9};
|
||||
|
||||
private ImageValidator() {
|
||||
}
|
||||
|
||||
public static boolean isValidForRegionDecoder(int validity) {
|
||||
return (validity & VALID_FOR_REGION_DECODER) != 0;
|
||||
}
|
||||
|
||||
public static boolean isValid(int validity) {
|
||||
return validity != 0;
|
||||
}
|
||||
|
||||
public static int checkImageValidity(final File file) {
|
||||
if (file == null) return INVALID;
|
||||
return checkImageValidity(file.getPath());
|
||||
}
|
||||
|
||||
public static int checkImageValidity(final String file) {
|
||||
final BitmapFactory.Options opts = new BitmapFactory.Options();
|
||||
opts.inJustDecodeBounds = true;
|
||||
BitmapFactory.decodeFile(file, opts);
|
||||
final String type = opts.outMimeType;
|
||||
if (type == null) return INVALID;
|
||||
if ("image/jpeg".equalsIgnoreCase(type))
|
||||
return checkJPEGValidity(file);
|
||||
else if ("image/png".equalsIgnoreCase(type)) return checkPNGValidity(file);
|
||||
return opts.outWidth > 0 && opts.outHeight > 0 ? VALID_FOR_BITMAP_FACTORY : INVALID;
|
||||
}
|
||||
|
||||
public static int checkImageValidity(final Uri uri) {
|
||||
if (uri == null) return INVALID;
|
||||
return checkImageValidity(uri.getPath());
|
||||
}
|
||||
|
||||
public static int checkJPEGValidity(final String file) {
|
||||
return checkHeadTailValidity(file, JPEG_HEAD, JPEG_TAIL);
|
||||
}
|
||||
|
||||
public static int checkPNGValidity(final String file) {
|
||||
return checkHeadTailValidity(file, PNG_HEAD, PNG_TAIL);
|
||||
}
|
||||
|
||||
private static int checkHeadTailValidity(final RandomAccessFile raf, final byte[] head, final byte[] tail) {
|
||||
if (raf == null) return INVALID;
|
||||
try {
|
||||
final long length = raf.length();
|
||||
// The file has 0-length, so it can't be a PNG file.
|
||||
if (length == 0) return INVALID;
|
||||
byte[] buffer;
|
||||
// Read head.
|
||||
buffer = new byte[head.length];
|
||||
raf.seek(0);
|
||||
if (raf.read(buffer) != buffer.length || !Arrays.equals(buffer, head)) return INVALID;
|
||||
// Read tail.
|
||||
buffer = new byte[tail.length];
|
||||
raf.seek(length - buffer.length);
|
||||
if (raf.read(buffer) != buffer.length || !Arrays.equals(buffer, tail))
|
||||
return VALID_FOR_BITMAP_FACTORY;
|
||||
} catch (final IOException e) {
|
||||
return INVALID;
|
||||
} finally {
|
||||
IoUtils.closeSilently(raf);
|
||||
}
|
||||
return VALID_FOR_ALL;
|
||||
}
|
||||
|
||||
private static int checkHeadTailValidity(final String file, final byte[] head, final byte[] tail) {
|
||||
try {
|
||||
return checkHeadTailValidity(new RandomAccessFile(file, "r"), head, tail);
|
||||
} catch (final FileNotFoundException e) {
|
||||
return INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,16 +1,6 @@
|
|||
package org.mariotaku.twidere.util;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.util.JsonWriter;
|
||||
import android.util.Log;
|
||||
|
||||
import org.mariotaku.restfu.RestFuUtils;
|
||||
import org.mariotaku.twidere.TwidereConstants;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 16/3/8.
|
||||
|
@ -19,46 +9,6 @@ public class InternalParseUtils {
|
|||
private InternalParseUtils() {
|
||||
}
|
||||
|
||||
public static String bundleToJSON(final Bundle args) {
|
||||
final Set<String> keys = args.keySet();
|
||||
final StringWriter sw = new StringWriter();
|
||||
final JsonWriter json = new JsonWriter(sw);
|
||||
try {
|
||||
json.beginObject();
|
||||
for (final String key : keys) {
|
||||
json.name(key);
|
||||
final Object value = args.get(key);
|
||||
if (value == null) {
|
||||
json.nullValue();
|
||||
} else if (value instanceof Boolean) {
|
||||
json.value((Boolean) value);
|
||||
} else if (value instanceof Integer) {
|
||||
json.value((Integer) value);
|
||||
} else if (value instanceof Long) {
|
||||
json.value((Long) value);
|
||||
} else if (value instanceof String) {
|
||||
json.value((String) value);
|
||||
} else if (value instanceof Float) {
|
||||
json.value((Float) value);
|
||||
} else if (value instanceof Double) {
|
||||
json.value((Double) value);
|
||||
} else {
|
||||
json.nullValue();
|
||||
Log.w(TwidereConstants.LOGTAG, "Unknown type " + value.getClass().getSimpleName() + " in arguments key " + key);
|
||||
}
|
||||
}
|
||||
json.endObject();
|
||||
json.flush();
|
||||
sw.flush();
|
||||
return sw.toString();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
} finally {
|
||||
RestFuUtils.closeSilently(json);
|
||||
}
|
||||
}
|
||||
|
||||
public static String parsePrettyDecimal(double num, int decimalDigits) {
|
||||
String result = String.format(Locale.US, "%." + decimalDigits + "f", num);
|
||||
int dotIdx = result.lastIndexOf('.');
|
||||
|
|
|
@ -1,56 +0,0 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.util;
|
||||
|
||||
import android.support.v4.util.LongSparseArray;
|
||||
|
||||
public class LongSparseArrayUtils {
|
||||
private LongSparseArrayUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A copy of all keys contained in the sparse array.
|
||||
*/
|
||||
public static <E> long[] getKeys(final LongSparseArray<E> array) {
|
||||
final int length = array.size();
|
||||
final long[] result = new long[length];
|
||||
for (int i = 0, j = length; i < j; i++) {
|
||||
result[i] = array.keyAt(i);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static <E> boolean hasKey(final LongSparseArray<E> array, final long key) {
|
||||
return array.indexOfKey(key) >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets all supplied keys to the given unique value.
|
||||
*
|
||||
* @param keys Keys to set
|
||||
* @param uniqueValue Value to set all supplied keys to
|
||||
*/
|
||||
public static <E> void setValues(final LongSparseArray<E> array, final long[] keys, final E uniqueValue) {
|
||||
final int length = keys.length;
|
||||
for (long key : keys) {
|
||||
array.put(key, uniqueValue);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
package org.mariotaku.twidere.util;
|
||||
|
||||
import org.mariotaku.microblog.library.MicroBlogException;
|
||||
import org.mariotaku.restfu.RestAPIFactory;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 16/5/27.
|
||||
*/
|
||||
public class MicroBlogBuilder {
|
||||
|
||||
final RestAPIFactory<MicroBlogException> factory;
|
||||
|
||||
public MicroBlogBuilder() {
|
||||
factory = new RestAPIFactory<>();
|
||||
}
|
||||
|
||||
|
||||
public <T> T build(Class<T> cls) {
|
||||
return factory.build(cls);
|
||||
}
|
||||
|
||||
}
|
|
@ -37,10 +37,6 @@ public final class ServiceUtils {
|
|||
private ServiceUtils() {
|
||||
}
|
||||
|
||||
public static ServiceToken bindToService(final Context context, final Intent intent) {
|
||||
return bindToService(context, intent, null);
|
||||
}
|
||||
|
||||
public static ServiceToken bindToService(final Context context, final Intent intent,
|
||||
final ServiceConnection callback) {
|
||||
|
||||
|
|
|
@ -24,7 +24,6 @@ import android.content.res.Resources;
|
|||
import android.content.res.TypedArray;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.PorterDuff.Mode;
|
||||
import android.graphics.Typeface;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
|
@ -165,10 +164,6 @@ public class ThemeUtils implements Constants {
|
|||
return TwidereColorUtils.YIQToColor(Color.alpha(accentColor), yiq);
|
||||
}
|
||||
|
||||
public static Resources getResources(final Context context) {
|
||||
return context.getResources();
|
||||
}
|
||||
|
||||
public static Drawable getSelectableItemBackgroundDrawable(final Context context) {
|
||||
return getDrawableFromThemeAttribute(context, android.R.attr.selectableItemBackground);
|
||||
}
|
||||
|
@ -304,15 +299,6 @@ public class ThemeUtils implements Constants {
|
|||
ThemeBackgroundPreference.MIN_ALPHA, ThemeBackgroundPreference.MAX_ALPHA);
|
||||
}
|
||||
|
||||
public static Typeface getUserTypeface(final Context context, final String fontFamily, final Typeface defTypeface) {
|
||||
if (context == null || Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN)
|
||||
return Typeface.DEFAULT;
|
||||
final int fontStyle = defTypeface != null ? defTypeface.getStyle() : Typeface.NORMAL;
|
||||
final Typeface tf = Typeface.create(fontFamily, fontStyle);
|
||||
if (tf != null) return tf;
|
||||
return Typeface.create(Typeface.DEFAULT, fontStyle);
|
||||
}
|
||||
|
||||
public static Drawable getWindowBackground(final Context context) {
|
||||
final TypedArray a = context.obtainStyledAttributes(new int[]{android.R.attr.windowBackground});
|
||||
try {
|
||||
|
|
|
@ -1,138 +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.util;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.TypeEvaluator;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.View;
|
||||
|
||||
/**
|
||||
* Static utility methods for Transitions.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class TransitionUtils {
|
||||
private static int MAX_IMAGE_SIZE = (1024 * 1024);
|
||||
|
||||
private TransitionUtils() {
|
||||
}
|
||||
|
||||
static Animator mergeAnimators(Animator animator1, Animator animator2) {
|
||||
if (animator1 == null) {
|
||||
return animator2;
|
||||
} else if (animator2 == null) {
|
||||
return animator1;
|
||||
} else {
|
||||
AnimatorSet animatorSet = new AnimatorSet();
|
||||
animatorSet.playTogether(animator1, animator2);
|
||||
return animatorSet;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a copy of bitmap of given drawable, return null if intrinsic size is zero
|
||||
*/
|
||||
public static Bitmap createDrawableBitmap(Drawable drawable) {
|
||||
int width = drawable.getIntrinsicWidth();
|
||||
int height = drawable.getIntrinsicHeight();
|
||||
if (width <= 0 || height <= 0) {
|
||||
return null;
|
||||
}
|
||||
float scale = Math.min(1f, ((float) MAX_IMAGE_SIZE) / (width * height));
|
||||
if (drawable instanceof BitmapDrawable && scale == 1f) {
|
||||
// return same bitmap if scale down not needed
|
||||
return ((BitmapDrawable) drawable).getBitmap();
|
||||
}
|
||||
int bitmapWidth = (int) (width * scale);
|
||||
int bitmapHeight = (int) (height * scale);
|
||||
Bitmap bitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888);
|
||||
Canvas canvas = new Canvas(bitmap);
|
||||
Rect existingBounds = drawable.getBounds();
|
||||
int left = existingBounds.left;
|
||||
int top = existingBounds.top;
|
||||
int right = existingBounds.right;
|
||||
int bottom = existingBounds.bottom;
|
||||
drawable.setBounds(0, 0, bitmapWidth, bitmapHeight);
|
||||
drawable.draw(canvas);
|
||||
drawable.setBounds(left, top, right, bottom);
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Bitmap of the given view, using the Matrix matrix to transform to the local
|
||||
* coordinates. <code>matrix</code> will be modified during the bitmap creation.
|
||||
* <p/>
|
||||
* <p>If the bitmap is large, it will be scaled uniformly down to at most 1MB size.</p>
|
||||
*
|
||||
* @param view The view to create a bitmap for.
|
||||
* @param matrix The matrix converting the view local coordinates to the coordinates that
|
||||
* the bitmap will be displayed in. <code>matrix</code> will be modified before
|
||||
* returning.
|
||||
* @param bounds The bounds of the bitmap in the destination coordinate system (where the
|
||||
* view should be presented. Typically, this is matrix.mapRect(viewBounds);
|
||||
* @return A bitmap of the given view or null if bounds has no width or height.
|
||||
*/
|
||||
public static Bitmap createViewBitmap(View view, Matrix matrix, RectF bounds) {
|
||||
Bitmap bitmap = null;
|
||||
int bitmapWidth = Math.round(bounds.width());
|
||||
int bitmapHeight = Math.round(bounds.height());
|
||||
if (bitmapWidth > 0 && bitmapHeight > 0) {
|
||||
float scale = Math.min(1f, ((float) MAX_IMAGE_SIZE) / (bitmapWidth * bitmapHeight));
|
||||
bitmapWidth *= scale;
|
||||
bitmapHeight *= scale;
|
||||
matrix.postTranslate(-bounds.left, -bounds.top);
|
||||
matrix.postScale(scale, scale);
|
||||
bitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888);
|
||||
Canvas canvas = new Canvas(bitmap);
|
||||
canvas.concat(matrix);
|
||||
view.draw(canvas);
|
||||
}
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
public static class MatrixEvaluator implements TypeEvaluator<Matrix> {
|
||||
|
||||
float[] mTempStartValues = new float[9];
|
||||
|
||||
float[] mTempEndValues = new float[9];
|
||||
|
||||
Matrix mTempMatrix = new Matrix();
|
||||
|
||||
@Override
|
||||
public Matrix evaluate(float fraction, Matrix startValue, Matrix endValue) {
|
||||
startValue.getValues(mTempStartValues);
|
||||
endValue.getValues(mTempEndValues);
|
||||
for (int i = 0; i < 9; i++) {
|
||||
float diff = mTempEndValues[i] - mTempStartValues[i];
|
||||
mTempEndValues[i] = mTempStartValues[i] + (fraction * diff);
|
||||
}
|
||||
mTempMatrix.setValues(mTempEndValues);
|
||||
return mTempMatrix;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -20,14 +20,10 @@
|
|||
package org.mariotaku.twidere.util;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public final class TwidereArrayUtils {
|
||||
|
||||
|
@ -43,15 +39,6 @@ public final class TwidereArrayUtils {
|
|||
return true;
|
||||
}
|
||||
|
||||
public static boolean contentMatch(final long[] array1, final long[] array2) {
|
||||
if (array1 == null || array2 == null) return array1 == array2;
|
||||
if (array1.length != array2.length) return false;
|
||||
for (long anArray1 : array1) {
|
||||
if (!ArrayUtils.contains(array2, anArray1)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean contentMatch(final Object[] array1, final Object[] array2) {
|
||||
if (array1 == null || array2 == null) return array1 == array2;
|
||||
if (array1.length != array2.length) return false;
|
||||
|
@ -61,40 +48,6 @@ public final class TwidereArrayUtils {
|
|||
return true;
|
||||
}
|
||||
|
||||
public static long[] fromList(final List<Long> list) {
|
||||
if (list == null) return null;
|
||||
final int count = list.size();
|
||||
final long[] array = new long[count];
|
||||
for (int i = 0; i < count; i++) {
|
||||
array[i] = list.get(i);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
|
||||
public static long[] intersection(final long[] array1, final long[] array2) {
|
||||
if (array1 == null || array2 == null) return new long[0];
|
||||
final List<Long> list1 = new ArrayList<>();
|
||||
for (final long item : array1) {
|
||||
list1.add(item);
|
||||
}
|
||||
final List<Long> list2 = new ArrayList<>();
|
||||
for (final long item : array2) {
|
||||
list2.add(item);
|
||||
}
|
||||
list1.retainAll(list2);
|
||||
return fromList(list1);
|
||||
}
|
||||
|
||||
public static <T> T[] intersection(@NonNull final T[] array1, @NonNull final T[] array2) {
|
||||
final List<T> list1 = new ArrayList<>();
|
||||
Collections.addAll(list1, array1);
|
||||
final List<T> list2 = new ArrayList<>();
|
||||
Collections.addAll(list2, array2);
|
||||
list1.retainAll(list2);
|
||||
//noinspection unchecked
|
||||
return list1.toArray((T[]) Array.newInstance(array1.getClass().getComponentType(), list1.size()));
|
||||
}
|
||||
|
||||
public static int arraysLength(@NonNull final Object... arrays) {
|
||||
int length = 0;
|
||||
|
@ -116,21 +69,6 @@ public final class TwidereArrayUtils {
|
|||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static long[] parseLongArray(final String string, final char token) {
|
||||
if (TextUtils.isEmpty(string)) return new long[0];
|
||||
final String[] itemsStringArray = string.split(String.valueOf(token));
|
||||
final long[] array = new long[itemsStringArray.length];
|
||||
for (int i = 0, j = itemsStringArray.length; i < j; i++) {
|
||||
try {
|
||||
array[i] = Long.parseLong(itemsStringArray[i]);
|
||||
} catch (final NumberFormatException e) {
|
||||
return new long[0];
|
||||
}
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
public static String toString(final long[] array, final char token, final boolean include_space) {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
final int length = array.length;
|
||||
|
@ -173,18 +111,6 @@ public final class TwidereArrayUtils {
|
|||
}
|
||||
|
||||
|
||||
public static String toStringForSQL(final String[] array) {
|
||||
final int size = array != null ? array.length : 0;
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (i > 0) {
|
||||
builder.append(',');
|
||||
}
|
||||
builder.append('?');
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public static void offset(long[] array, long offset) {
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
array[i] += offset;
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
package org.mariotaku.twidere.util;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 16/3/7.
|
||||
*/
|
||||
public class TwidereCollectionUtils {
|
||||
private TwidereCollectionUtils() {
|
||||
}
|
||||
|
||||
public static String[] toStringArray(final Collection<?> list) {
|
||||
if (list == null) return null;
|
||||
final int length = list.size();
|
||||
final String[] stringArray = new String[length];
|
||||
int idx = 0;
|
||||
for (Object o : list) {
|
||||
stringArray[idx++] = ParseUtils.parseString(o);
|
||||
}
|
||||
return stringArray;
|
||||
}
|
||||
}
|
|
@ -117,7 +117,4 @@ public class TwidereColorUtils {
|
|||
return (yiq >= threshold) ? colorDark : colorLight;
|
||||
}
|
||||
|
||||
public static int getYIQContrast(int color1, int color2) {
|
||||
return getYIQLuminance(color1) - getYIQLuminance(color2);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,54 +0,0 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class TwidereListUtils {
|
||||
|
||||
private TwidereListUtils() {
|
||||
}
|
||||
|
||||
public static List<Long> fromArray(final long[] array) {
|
||||
if (array == null) return null;
|
||||
final List<Long> list = new ArrayList<>();
|
||||
for (final long item : array) {
|
||||
list.add(item);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public static <T> String toString(final List<T> list, final char delimiter, final boolean includeSpace) {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
final int size = list.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (i > 0) {
|
||||
builder.append(delimiter);
|
||||
if (includeSpace) {
|
||||
builder.append(" ");
|
||||
}
|
||||
}
|
||||
builder.append(list.get(i));
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -19,24 +19,11 @@
|
|||
|
||||
package org.mariotaku.twidere.util;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
public class TwidereMathUtils {
|
||||
public static final int RANGE_EXCLUSIVE_EXCLUSIVE = 0b00;
|
||||
public static final int RANGE_EXCLUSIVE_INCLUSIVE = 0b01;
|
||||
public static final int RANGE_INCLUSIVE_EXCLUSIVE = 0b10;
|
||||
public static final int RANGE_INCLUSIVE_INCLUSIVE = 0b11;
|
||||
static final int MASK_LEFT_BOUND = 0b10;
|
||||
static final int MASK_RIGHT_BOUND = 0b01;
|
||||
|
||||
private TwidereMathUtils() {
|
||||
}
|
||||
|
||||
public static float clamp(final float num, final float bound1, final float bound2) {
|
||||
final float max = Math.max(bound1, bound2), min = Math.min(bound1, bound2);
|
||||
return Math.max(Math.min(num, max), min);
|
||||
}
|
||||
|
||||
public static int clamp(final int num, final int bound1, final int bound2) {
|
||||
final int max = Math.max(bound1, bound2), min = Math.min(bound1, bound2);
|
||||
return Math.max(Math.min(num, max), min);
|
||||
|
@ -57,43 +44,4 @@ public class TwidereMathUtils {
|
|||
return n + 1;
|
||||
}
|
||||
|
||||
// Returns the previous power of two.
|
||||
// Returns the input if it is already power of 2.
|
||||
// Throws IllegalArgumentException if the input is <= 0
|
||||
public static int prevPowerOf2(final int n) {
|
||||
if (n <= 0) throw new IllegalArgumentException();
|
||||
return Integer.highestOneBit(n);
|
||||
}
|
||||
|
||||
public static double sum(double... doubles) {
|
||||
double sum = 0;
|
||||
for (double d : doubles) {
|
||||
sum += d;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
public static int sum(@NonNull int[] array) {
|
||||
return sum(array, 0, array.length - 1);
|
||||
}
|
||||
|
||||
public static int sum(@NonNull int[] array, int start, int end) {
|
||||
int sum = 0;
|
||||
for (int i = start; i <= end; i++) {
|
||||
int num = array[i];
|
||||
sum += num;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
public static boolean inRange(int num, int from, int to, int flag) {
|
||||
return ((flag & MASK_LEFT_BOUND) == 0 ? num > from : num >= from)
|
||||
&& ((flag & MASK_RIGHT_BOUND) == 0 ? num < to : num <= to);
|
||||
}
|
||||
|
||||
public static boolean inRange(float num, float from, float to, int flag) {
|
||||
return ((flag & MASK_LEFT_BOUND) == 0 ? num > from : num >= from)
|
||||
&& ((flag & MASK_RIGHT_BOUND) == 0 ? num < to : num <= to);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -52,7 +52,6 @@ public class TwidereStringUtils {
|
|||
|
||||
/**
|
||||
* Fix to https://github.com/TwidereProject/Twidere-Android/issues/449
|
||||
* @param string
|
||||
*/
|
||||
public static void fixSHY(Spannable string) {
|
||||
for (int i = 0, j = string.length(); i < j; i++) {
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
package org.mariotaku.twidere.util;
|
||||
|
||||
import android.support.annotation.UiThread;
|
||||
import android.view.View;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 16/1/23.
|
||||
*/
|
||||
public class TwidereViewUtils {
|
||||
private TwidereViewUtils() {
|
||||
}
|
||||
|
||||
@UiThread
|
||||
public static boolean hitView(float x, float y, View view) {
|
||||
int[] location = new int[2];
|
||||
view.getLocationOnScreen(location);
|
||||
return TwidereMathUtils.inRange(x, location[0], location[0] + view.getWidth(), TwidereMathUtils.RANGE_INCLUSIVE_INCLUSIVE) &&
|
||||
TwidereMathUtils.inRange(y, location[1], location[1] + view.getHeight(), TwidereMathUtils.RANGE_INCLUSIVE_INCLUSIVE);
|
||||
}
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.util;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.UnreadCounts;
|
||||
|
||||
public class UnreadCountUtils {
|
||||
private UnreadCountUtils() {
|
||||
}
|
||||
|
||||
public static int getUnreadCount(final Context context, final int position) {
|
||||
if (context == null || position < 0) return 0;
|
||||
final ContentResolver resolver = context.getContentResolver();
|
||||
final Uri.Builder builder = TwidereDataStore.UnreadCounts.CONTENT_URI.buildUpon();
|
||||
builder.appendPath(ParseUtils.parseString(position));
|
||||
final Uri uri = builder.build();
|
||||
final Cursor c = resolver.query(uri, new String[] { UnreadCounts.COUNT }, null, null, null);
|
||||
if (c == null) return 0;
|
||||
try {
|
||||
if (c.getCount() == 0) return 0;
|
||||
c.moveToFirst();
|
||||
return c.getInt(c.getColumnIndex(UnreadCounts.COUNT));
|
||||
} finally {
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
|
||||
public static int getUnreadCount(final Context context, final String type) {
|
||||
if (context == null || type == null) return 0;
|
||||
final ContentResolver resolver = context.getContentResolver();
|
||||
final Uri.Builder builder = TwidereDataStore.UnreadCounts.ByType.CONTENT_URI.buildUpon();
|
||||
builder.appendPath(type);
|
||||
final Uri uri = builder.build();
|
||||
final Cursor c = resolver.query(uri, new String[] { UnreadCounts.COUNT }, null, null, null);
|
||||
if (c == null) return 0;
|
||||
try {
|
||||
if (c.getCount() == 0) return 0;
|
||||
c.moveToFirst();
|
||||
return c.getInt(c.getColumnIndex(UnreadCounts.COUNT));
|
||||
} finally {
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -48,10 +48,8 @@ public class UserColorNameManager {
|
|||
private final SharedPreferences colorPreferences, nicknamePreferences;
|
||||
private final LruCache<String, Integer> colorCache;
|
||||
private final LruCache<String, String> nicknameCache;
|
||||
private final Context context;
|
||||
|
||||
public UserColorNameManager(Context context) {
|
||||
this.context = context;
|
||||
colorPreferences = context.getSharedPreferences(USER_COLOR_PREFERENCES_NAME, Context.MODE_PRIVATE);
|
||||
nicknamePreferences = context.getSharedPreferences(USER_NICKNAME_PREFERENCES_NAME, Context.MODE_PRIVATE);
|
||||
colorCache = new LruCache<>(512);
|
||||
|
|
|
@ -21,7 +21,6 @@ package org.mariotaku.twidere.util;
|
|||
|
||||
import android.accounts.AccountManager;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.ActionBar;
|
||||
import android.app.Activity;
|
||||
import android.content.ContentResolver;
|
||||
|
@ -43,7 +42,6 @@ import android.graphics.drawable.Drawable;
|
|||
import android.location.Location;
|
||||
import android.location.LocationManager;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
import android.net.Uri;
|
||||
import android.nfc.NfcAdapter;
|
||||
import android.nfc.NfcAdapter.CreateNdefMessageCallback;
|
||||
|
@ -51,8 +49,6 @@ import android.os.BatteryManager;
|
|||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
import android.os.SystemClock;
|
||||
import android.provider.MediaStore;
|
||||
import android.support.annotation.DrawableRes;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
@ -63,12 +59,9 @@ import android.support.v4.view.GravityCompat;
|
|||
import android.support.v4.view.accessibility.AccessibilityEventCompat;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.view.menu.MenuBuilder;
|
||||
import android.system.ErrnoException;
|
||||
import android.text.TextUtils;
|
||||
import android.text.format.DateFormat;
|
||||
import android.text.format.DateUtils;
|
||||
import android.transition.Transition;
|
||||
import android.transition.TransitionInflater;
|
||||
import android.util.Log;
|
||||
import android.util.TypedValue;
|
||||
import android.view.Gravity;
|
||||
|
@ -76,13 +69,9 @@ import android.view.KeyCharacterMap;
|
|||
import android.view.KeyEvent;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
import android.widget.AbsListView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
|
@ -123,10 +112,7 @@ import org.mariotaku.twidere.provider.TwidereDataStore.CachedUsers;
|
|||
import org.mariotaku.twidere.provider.TwidereDataStore.DirectMessages;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.DirectMessages.ConversationEntries;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Statuses;
|
||||
import org.mariotaku.twidere.util.TwidereLinkify.HighlightStyle;
|
||||
import org.mariotaku.twidere.view.CardMediaContainer.PreviewStyle;
|
||||
import org.mariotaku.twidere.view.ShapedImageView;
|
||||
import org.mariotaku.twidere.view.ShapedImageView.ShapeStyle;
|
||||
import org.mariotaku.twidere.view.TabPagerIndicator;
|
||||
|
||||
import java.io.Closeable;
|
||||
|
@ -575,33 +561,6 @@ public final class Utils implements Constants {
|
|||
}
|
||||
|
||||
|
||||
public static String getImagePathFromUri(final Context context, final Uri uri) {
|
||||
if (context == null || uri == null) return null;
|
||||
|
||||
final String mediaUriStart = ParseUtils.parseString(MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
|
||||
|
||||
if (ParseUtils.parseString(uri).startsWith(mediaUriStart)) {
|
||||
|
||||
final String[] proj = {MediaStore.Images.Media.DATA};
|
||||
final Cursor cur = context.getContentResolver().query(uri, proj, null, null, null);
|
||||
|
||||
if (cur == null) return null;
|
||||
|
||||
final int idxData = cur.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
|
||||
|
||||
cur.moveToFirst();
|
||||
try {
|
||||
return cur.getString(idxData);
|
||||
} finally {
|
||||
cur.close();
|
||||
}
|
||||
} else {
|
||||
final String path = uri.getPath();
|
||||
if (path != null && new File(path).exists()) return path;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String getMediaUploadStatus(@NonNull final Context context,
|
||||
@Nullable final CharSequence[] links,
|
||||
@Nullable final CharSequence text) {
|
||||
|
@ -626,20 +585,6 @@ public final class Utils implements Constants {
|
|||
return new File(context.getCacheDir(), cacheDirName);
|
||||
}
|
||||
|
||||
@HighlightStyle
|
||||
public static int getLinkHighlightingStyleInt(final String option) {
|
||||
if (option == null) return VALUE_LINK_HIGHLIGHT_OPTION_CODE_NONE;
|
||||
switch (option) {
|
||||
case VALUE_LINK_HIGHLIGHT_OPTION_BOTH:
|
||||
return VALUE_LINK_HIGHLIGHT_OPTION_CODE_BOTH;
|
||||
case VALUE_LINK_HIGHLIGHT_OPTION_HIGHLIGHT:
|
||||
return VALUE_LINK_HIGHLIGHT_OPTION_CODE_HIGHLIGHT;
|
||||
case VALUE_LINK_HIGHLIGHT_OPTION_UNDERLINE:
|
||||
return VALUE_LINK_HIGHLIGHT_OPTION_CODE_UNDERLINE;
|
||||
}
|
||||
return VALUE_LINK_HIGHLIGHT_OPTION_CODE_NONE;
|
||||
}
|
||||
|
||||
public static String getLocalizedNumber(final Locale locale, final Number number) {
|
||||
final NumberFormat nf = NumberFormat.getInstance(locale);
|
||||
return nf.format(number);
|
||||
|
@ -692,14 +637,6 @@ public final class Utils implements Constants {
|
|||
return url;
|
||||
}
|
||||
|
||||
@ShapeStyle
|
||||
public static int getProfileImageStyle(String style) {
|
||||
if (VALUE_PROFILE_IMAGE_STYLE_SQUARE.equalsIgnoreCase(style)) {
|
||||
return ShapedImageView.SHAPE_RECTANGLE;
|
||||
}
|
||||
return ShapedImageView.SHAPE_CIRCLE;
|
||||
}
|
||||
|
||||
@PreviewStyle
|
||||
public static int getMediaPreviewStyle(String style) {
|
||||
if (VALUE_MEDIA_PREVIEW_STYLE_SCALE.equalsIgnoreCase(style)) {
|
||||
|
@ -873,16 +810,6 @@ public final class Utils implements Constants {
|
|||
return accountId.equals(retweetedById) || myRetweetId != null;
|
||||
}
|
||||
|
||||
public static boolean isNetworkAvailable(final Context context) {
|
||||
try {
|
||||
final ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
final NetworkInfo info = cm.getActiveNetworkInfo();
|
||||
return info != null && info.isConnected();
|
||||
} catch (SecurityException e) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static int matchTabCode(@Nullable final Uri uri) {
|
||||
if (uri == null) return UriMatcher.NO_MATCH;
|
||||
return HOME_TABS_URI_MATCHER.match(uri);
|
||||
|
@ -956,47 +883,11 @@ public final class Utils implements Constants {
|
|||
activity.overridePendingTransition(enterAnim, exitAnim);
|
||||
}
|
||||
|
||||
public static void scrollListToPosition(final AbsListView list, final int position) {
|
||||
scrollListToPosition(list, position, 0);
|
||||
}
|
||||
|
||||
public static void scrollListToPosition(final AbsListView absListView, final int position, final int offset) {
|
||||
if (absListView == null) return;
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
|
||||
if (absListView instanceof ListView) {
|
||||
final ListView listView = (ListView) absListView;
|
||||
listView.setSelectionFromTop(position, offset);
|
||||
} else {
|
||||
absListView.setSelection(position);
|
||||
}
|
||||
stopListView(absListView);
|
||||
} else {
|
||||
stopListView(absListView);
|
||||
if (absListView instanceof ListView) {
|
||||
final ListView listView = (ListView) absListView;
|
||||
listView.setSelectionFromTop(position, offset);
|
||||
} else {
|
||||
absListView.setSelection(position);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void scrollListToTop(final AbsListView list) {
|
||||
if (list == null) return;
|
||||
scrollListToPosition(list, 0);
|
||||
}
|
||||
|
||||
static boolean isMyStatus(ParcelableStatus status) {
|
||||
if (isMyRetweet(status)) return true;
|
||||
return status.account_key.maybeEquals(status.user_key);
|
||||
}
|
||||
|
||||
public static boolean shouldStopAutoRefreshOnBatteryLow(final Context context) {
|
||||
final SharedPreferences mPreferences = context.getSharedPreferences(SHARED_PREFERENCES_NAME,
|
||||
Context.MODE_PRIVATE);
|
||||
return mPreferences.getBoolean(KEY_STOP_AUTO_REFRESH_WHEN_BATTERY_LOW, true);
|
||||
}
|
||||
|
||||
public static void showErrorMessage(final Context context, final CharSequence message, final boolean longMessage) {
|
||||
if (context == null) return;
|
||||
final Toast toast = Toast.makeText(context, message, longMessage ? Toast.LENGTH_LONG : Toast.LENGTH_SHORT);
|
||||
|
@ -1122,19 +1013,6 @@ public final class Utils implements Constants {
|
|||
context.startActivity(Intent.createChooser(intent, context.getString(R.string.action_share)));
|
||||
}
|
||||
|
||||
public static void stopListView(final AbsListView list) {
|
||||
if (list == null) return;
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
|
||||
list.dispatchTouchEvent(MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(),
|
||||
MotionEvent.ACTION_CANCEL, 0, 0, 0));
|
||||
} else {
|
||||
list.dispatchTouchEvent(MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(),
|
||||
MotionEvent.ACTION_DOWN, 0, 0, 0));
|
||||
list.dispatchTouchEvent(MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(),
|
||||
MotionEvent.ACTION_UP, 0, 0, 0));
|
||||
}
|
||||
}
|
||||
|
||||
public static String trimLineBreak(final String orig) {
|
||||
if (orig == null) return null;
|
||||
return orig.replaceAll("\\n+", "\n");
|
||||
|
@ -1228,21 +1106,10 @@ public final class Utils implements Constants {
|
|||
return null;
|
||||
}
|
||||
|
||||
public static boolean isCustomConsumerKeySecret(String consumerKey, String consumerSecret) {
|
||||
if (TextUtils.isEmpty(consumerKey) || TextUtils.isEmpty(consumerSecret)) return false;
|
||||
return !TWITTER_CONSUMER_KEY.equals(consumerKey) && !TWITTER_CONSUMER_SECRET.equals(consumerKey)
|
||||
&& !TWITTER_CONSUMER_KEY_LEGACY.equals(consumerKey) && !TWITTER_CONSUMER_SECRET_LEGACY.equals(consumerSecret);
|
||||
}
|
||||
|
||||
public static boolean isStreamingEnabled() {
|
||||
return Boolean.parseBoolean("false");
|
||||
}
|
||||
|
||||
public static int getErrorNo(Throwable t) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) return 0;
|
||||
return UtilsL.getErrorNo(t);
|
||||
}
|
||||
|
||||
public static void logOpenNotificationFromUri(Context context, Uri uri) {
|
||||
if (!uri.getBooleanQueryParameter(QUERY_PARAM_FROM_NOTIFICATION, false)) return;
|
||||
final String type = uri.getQueryParameter(QUERY_PARAM_NOTIFICATION_TYPE);
|
||||
|
@ -1282,31 +1149,6 @@ public final class Utils implements Constants {
|
|||
return !ConnectivityManagerCompat.isActiveNetworkMetered(cm) || !preferences.getBoolean(KEY_BANDWIDTH_SAVING_MODE);
|
||||
}
|
||||
|
||||
static class UtilsL {
|
||||
|
||||
private UtilsL() {
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
static void setSharedElementTransition(Context context, Window window, int transitionRes) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) return;
|
||||
window.requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS);
|
||||
final TransitionInflater inflater = TransitionInflater.from(context);
|
||||
final Transition transition = inflater.inflateTransition(transitionRes);
|
||||
window.setSharedElementEnterTransition(transition);
|
||||
window.setSharedElementExitTransition(transition);
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
public static int getErrorNo(Throwable t) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) return 0;
|
||||
if (t instanceof ErrnoException) {
|
||||
return ((ErrnoException) t).errno;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send Notifications to Pebble smart watches
|
||||
*
|
||||
|
|
|
@ -24,47 +24,42 @@ import java.util.Collection;
|
|||
|
||||
public class NoDuplicatesArrayList<E> extends ArrayList<E> {
|
||||
|
||||
private static final long serialVersionUID = -7277301117508689125L;
|
||||
private static final long serialVersionUID = -7277301117508689125L;
|
||||
|
||||
public NoDuplicatesArrayList() {
|
||||
}
|
||||
public NoDuplicatesArrayList() {
|
||||
}
|
||||
|
||||
public NoDuplicatesArrayList(final Collection<? extends E> collection) {
|
||||
addAll(collection);
|
||||
}
|
||||
public NoDuplicatesArrayList(final Collection<? extends E> collection) {
|
||||
addAll(collection);
|
||||
}
|
||||
|
||||
public NoDuplicatesArrayList(final int capacity) {
|
||||
super(capacity);
|
||||
}
|
||||
public NoDuplicatesArrayList(final int capacity) {
|
||||
super(capacity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(final E e) {
|
||||
if (contains(e))
|
||||
return false;
|
||||
else
|
||||
return super.add(e);
|
||||
}
|
||||
@Override
|
||||
public boolean add(final E e) {
|
||||
if (contains(e)) return false;
|
||||
return super.add(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(final int index, final E element) {
|
||||
if (contains(element))
|
||||
return;
|
||||
else {
|
||||
super.add(index, element);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void add(final int index, final E element) {
|
||||
if (contains(element)) return;
|
||||
super.add(index, element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(final Collection<? extends E> collection) {
|
||||
final Collection<E> copy = new ArrayList<>(collection);
|
||||
copy.removeAll(this);
|
||||
return super.addAll(copy);
|
||||
}
|
||||
@Override
|
||||
public boolean addAll(final Collection<? extends E> collection) {
|
||||
final Collection<E> copy = new ArrayList<>(collection);
|
||||
copy.removeAll(this);
|
||||
return super.addAll(copy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(final int index, final Collection<? extends E> collection) {
|
||||
final Collection<E> copy = new ArrayList<>(collection);
|
||||
copy.removeAll(this);
|
||||
return super.addAll(index, copy);
|
||||
}
|
||||
@Override
|
||||
public boolean addAll(final int index, final Collection<? extends E> collection) {
|
||||
final Collection<E> copy = new ArrayList<>(collection);
|
||||
copy.removeAll(this);
|
||||
return super.addAll(index, copy);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,371 +0,0 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.util.content;
|
||||
|
||||
import android.accounts.AccountManager;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.os.Build;
|
||||
|
||||
import org.mariotaku.sqliteqb.library.Columns;
|
||||
import org.mariotaku.sqliteqb.library.Columns.Column;
|
||||
import org.mariotaku.sqliteqb.library.Constraint;
|
||||
import org.mariotaku.sqliteqb.library.Expression;
|
||||
import org.mariotaku.sqliteqb.library.NewColumn;
|
||||
import org.mariotaku.sqliteqb.library.OnConflict;
|
||||
import org.mariotaku.sqliteqb.library.RawSQLLang;
|
||||
import org.mariotaku.sqliteqb.library.SQLQuery;
|
||||
import org.mariotaku.sqliteqb.library.SQLQueryBuilder;
|
||||
import org.mariotaku.sqliteqb.library.SetValue;
|
||||
import org.mariotaku.sqliteqb.library.Table;
|
||||
import org.mariotaku.sqliteqb.library.query.SQLCreateIndexQuery;
|
||||
import org.mariotaku.sqliteqb.library.query.SQLCreateTableQuery;
|
||||
import org.mariotaku.sqliteqb.library.query.SQLCreateTriggerQuery.Event;
|
||||
import org.mariotaku.sqliteqb.library.query.SQLCreateTriggerQuery.Type;
|
||||
import org.mariotaku.sqliteqb.library.query.SQLDeleteQuery;
|
||||
import org.mariotaku.twidere.Constants;
|
||||
import org.mariotaku.twidere.annotation.CustomTabType;
|
||||
import org.mariotaku.twidere.model.Tab;
|
||||
import org.mariotaku.twidere.model.TabValuesCreator;
|
||||
import org.mariotaku.twidere.model.tab.TabConfiguration;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Accounts;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Activities;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.CachedHashtags;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.CachedRelationships;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.CachedStatuses;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.CachedTrends;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.CachedUsers;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.DirectMessages;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Drafts;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Filters;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.SavedSearches;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.SearchHistory;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Statuses;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Tabs;
|
||||
import org.mariotaku.twidere.util.AccountMigratorKt;
|
||||
import org.mariotaku.twidere.util.TwidereQueryBuilder.ConversationsEntryQueryBuilder;
|
||||
import org.mariotaku.twidere.util.TwidereQueryBuilder.DirectMessagesQueryBuilder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
|
||||
import static org.mariotaku.twidere.util.content.DatabaseUpgradeHelper.safeUpgrade;
|
||||
|
||||
public final class TwidereSQLiteOpenHelper extends SQLiteOpenHelper implements Constants {
|
||||
|
||||
private final Context mContext;
|
||||
|
||||
public TwidereSQLiteOpenHelper(final Context context, final String name, final int version) {
|
||||
super(context, name, null, version);
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(final SQLiteDatabase db) {
|
||||
db.beginTransaction();
|
||||
db.execSQL(createTable(Statuses.TABLE_NAME, Statuses.COLUMNS, Statuses.TYPES, true));
|
||||
db.execSQL(createTable(Activities.AboutMe.TABLE_NAME, Activities.AboutMe.COLUMNS, Activities.AboutMe.TYPES, true));
|
||||
db.execSQL(createTable(Activities.ByFriends.TABLE_NAME, Activities.ByFriends.COLUMNS, Activities.ByFriends.TYPES, true));
|
||||
db.execSQL(createTable(Drafts.TABLE_NAME, Drafts.COLUMNS, Drafts.TYPES, true));
|
||||
db.setTransactionSuccessful();
|
||||
db.endTransaction();
|
||||
|
||||
db.beginTransaction();
|
||||
db.execSQL(createTable(CachedUsers.TABLE_NAME, CachedUsers.COLUMNS, CachedUsers.TYPES, true,
|
||||
createConflictReplaceConstraint(CachedUsers.USER_KEY)));
|
||||
db.execSQL(createTable(CachedStatuses.TABLE_NAME, CachedStatuses.COLUMNS, CachedStatuses.TYPES, true));
|
||||
db.execSQL(createTable(CachedTrends.Local.TABLE_NAME, CachedTrends.Local.COLUMNS, CachedTrends.Local.TYPES,
|
||||
true));
|
||||
db.execSQL(createTable(CachedHashtags.TABLE_NAME, CachedHashtags.COLUMNS, CachedHashtags.TYPES, true));
|
||||
db.execSQL(createTable(CachedRelationships.TABLE_NAME, CachedRelationships.COLUMNS, CachedRelationships.TYPES, true,
|
||||
createConflictReplaceConstraint(CachedRelationships.ACCOUNT_KEY, CachedRelationships.USER_KEY)));
|
||||
db.setTransactionSuccessful();
|
||||
db.endTransaction();
|
||||
|
||||
|
||||
db.beginTransaction();
|
||||
db.execSQL(createTable(Filters.Users.TABLE_NAME, Filters.Users.COLUMNS, Filters.Users.TYPES, true));
|
||||
db.execSQL(createTable(Filters.Keywords.TABLE_NAME, Filters.Keywords.COLUMNS, Filters.Keywords.TYPES, true));
|
||||
db.execSQL(createTable(Filters.Sources.TABLE_NAME, Filters.Sources.COLUMNS, Filters.Sources.TYPES, true));
|
||||
db.execSQL(createTable(Filters.Links.TABLE_NAME, Filters.Links.COLUMNS, Filters.Links.TYPES, true));
|
||||
db.execSQL(createTable(Filters.Subscriptions.TABLE_NAME, Filters.Subscriptions.COLUMNS, Filters.Subscriptions.TYPES, true));
|
||||
db.setTransactionSuccessful();
|
||||
db.endTransaction();
|
||||
|
||||
db.beginTransaction();
|
||||
db.execSQL(createTable(DirectMessages.Inbox.TABLE_NAME, DirectMessages.Inbox.COLUMNS,
|
||||
DirectMessages.Inbox.TYPES, true));
|
||||
db.execSQL(createTable(DirectMessages.Outbox.TABLE_NAME, DirectMessages.Outbox.COLUMNS,
|
||||
DirectMessages.Outbox.TYPES, true));
|
||||
db.execSQL(createTable(Tabs.TABLE_NAME, Tabs.COLUMNS, Tabs.TYPES, true));
|
||||
db.execSQL(createTable(SavedSearches.TABLE_NAME, SavedSearches.COLUMNS, SavedSearches.TYPES, true));
|
||||
db.execSQL(createTable(SearchHistory.TABLE_NAME, SearchHistory.COLUMNS, SearchHistory.TYPES, true));
|
||||
db.setTransactionSuccessful();
|
||||
db.endTransaction();
|
||||
|
||||
db.beginTransaction();
|
||||
createViews(db);
|
||||
createTriggers(db);
|
||||
createIndices(db);
|
||||
db.setTransactionSuccessful();
|
||||
db.endTransaction();
|
||||
|
||||
setupDefaultTabs(db);
|
||||
}
|
||||
|
||||
private void setupDefaultTabs(SQLiteDatabase db) {
|
||||
db.beginTransaction();
|
||||
@CustomTabType
|
||||
String[] tabTypes = {CustomTabType.HOME_TIMELINE, CustomTabType.NOTIFICATIONS_TIMELINE,
|
||||
CustomTabType.TRENDS_SUGGESTIONS, CustomTabType.DIRECT_MESSAGES};
|
||||
for (int i = 0, j = tabTypes.length; i < j; i++) {
|
||||
@CustomTabType
|
||||
final String tabType = tabTypes[i];
|
||||
final TabConfiguration conf = TabConfiguration.ofType(tabType);
|
||||
final Tab tab = new Tab();
|
||||
tab.setType(tabType);
|
||||
tab.setIcon(conf.getIcon().getPersistentKey());
|
||||
tab.setPosition(i);
|
||||
try {
|
||||
db.insert(Tabs.TABLE_NAME, null, TabValuesCreator.create(tab));
|
||||
} catch (IOException e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
db.setTransactionSuccessful();
|
||||
db.endTransaction();
|
||||
}
|
||||
|
||||
private Constraint createConflictReplaceConstraint(String... columns) {
|
||||
return Constraint.unique(new Columns(columns), OnConflict.IGNORE);
|
||||
}
|
||||
|
||||
private void createIndices(SQLiteDatabase db) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) return;
|
||||
db.execSQL(createIndex("statuses_index", Statuses.TABLE_NAME, new String[]{Statuses.ACCOUNT_KEY}, true));
|
||||
db.execSQL(createIndex("messages_inbox_index", DirectMessages.Inbox.TABLE_NAME, new String[]{DirectMessages.ACCOUNT_KEY}, true));
|
||||
db.execSQL(createIndex("messages_outbox_index", DirectMessages.Outbox.TABLE_NAME, new String[]{DirectMessages.ACCOUNT_KEY}, true));
|
||||
}
|
||||
|
||||
private void createViews(SQLiteDatabase db) {
|
||||
db.execSQL(SQLQueryBuilder.dropView(true, DirectMessages.TABLE_NAME).getSQL());
|
||||
db.execSQL(SQLQueryBuilder.dropView(true, DirectMessages.ConversationEntries.TABLE_NAME).getSQL());
|
||||
|
||||
db.execSQL(SQLQueryBuilder.createView(true, DirectMessages.TABLE_NAME)
|
||||
.as(DirectMessagesQueryBuilder.build()).buildSQL());
|
||||
db.execSQL(SQLQueryBuilder.createView(true, DirectMessages.ConversationEntries.TABLE_NAME)
|
||||
.as(ConversationsEntryQueryBuilder.build()).buildSQL());
|
||||
}
|
||||
|
||||
private void createTriggers(SQLiteDatabase db) {
|
||||
db.execSQL(SQLQueryBuilder.dropTrigger(true, "delete_old_statuses").getSQL());
|
||||
db.execSQL(SQLQueryBuilder.dropTrigger(true, "delete_old_cached_statuses").getSQL());
|
||||
db.execSQL(SQLQueryBuilder.dropTrigger(true, "delete_old_received_messages").getSQL());
|
||||
db.execSQL(SQLQueryBuilder.dropTrigger(true, "delete_old_sent_messages").getSQL());
|
||||
db.execSQL(SQLQueryBuilder.dropTrigger(true, "on_user_cache_update_trigger").getSQL());
|
||||
db.execSQL(SQLQueryBuilder.dropTrigger(true, "delete_old_cached_hashtags").getSQL());
|
||||
db.execSQL(createDeleteDuplicateStatusTrigger("delete_old_statuses", Statuses.TABLE_NAME).getSQL());
|
||||
db.execSQL(createDeleteDuplicateStatusTrigger("delete_old_cached_statuses", CachedStatuses.TABLE_NAME).getSQL());
|
||||
db.execSQL(createDeleteDuplicateMessageTrigger("delete_old_received_messages", DirectMessages.Inbox.TABLE_NAME).getSQL());
|
||||
db.execSQL(createDeleteDuplicateMessageTrigger("delete_old_sent_messages", DirectMessages.Outbox.TABLE_NAME).getSQL());
|
||||
|
||||
// Update user info in filtered users
|
||||
final Table cachedUsersTable = new Table(CachedUsers.TABLE_NAME);
|
||||
final Table filteredUsersTable = new Table(Filters.Users.TABLE_NAME);
|
||||
db.execSQL(SQLQueryBuilder.createTrigger(false, true, "on_user_cache_update_trigger")
|
||||
.type(Type.BEFORE)
|
||||
.event(Event.INSERT)
|
||||
.on(cachedUsersTable)
|
||||
.forEachRow(true)
|
||||
.actions(SQLQueryBuilder.update(OnConflict.REPLACE, filteredUsersTable)
|
||||
.set(new SetValue(new Column(Filters.Users.NAME), new Column(Table.NEW, CachedUsers.NAME)),
|
||||
new SetValue(new Column(Filters.Users.SCREEN_NAME), new Column(Table.NEW, CachedUsers.SCREEN_NAME)))
|
||||
.where(Expression.equals(new Column(Filters.Users.USER_KEY), new Column(Table.NEW, CachedUsers.USER_KEY)))
|
||||
.build())
|
||||
.buildSQL());
|
||||
|
||||
// Delete duplicated hashtags ignoring case
|
||||
final Table cachedHashtagsTable = new Table(CachedHashtags.TABLE_NAME);
|
||||
db.execSQL(SQLQueryBuilder.createTrigger(false, true, "delete_old_cached_hashtags")
|
||||
.type(Type.BEFORE)
|
||||
.event(Event.INSERT)
|
||||
.on(cachedHashtagsTable)
|
||||
.forEachRow(true)
|
||||
.actions(SQLQueryBuilder.deleteFrom(cachedHashtagsTable)
|
||||
.where(Expression.like(new Column(CachedHashtags.NAME), new Column(Table.NEW, CachedHashtags.NAME)))
|
||||
.build())
|
||||
.buildSQL());
|
||||
|
||||
}
|
||||
|
||||
private SQLQuery createDeleteDuplicateStatusTrigger(String triggerName, String tableName) {
|
||||
final Table table = new Table(tableName);
|
||||
final SQLDeleteQuery deleteOld = SQLQueryBuilder.deleteFrom(table).where(Expression.and(
|
||||
Expression.equals(new Column(Statuses.ACCOUNT_KEY), new Column(Table.NEW, Statuses.ACCOUNT_KEY)),
|
||||
Expression.equals(new Column(Statuses.STATUS_ID), new Column(Table.NEW, Statuses.STATUS_ID))
|
||||
)).build();
|
||||
return SQLQueryBuilder.createTrigger(false, true, triggerName)
|
||||
.type(Type.BEFORE).event(Event.INSERT).on(table).forEachRow(true)
|
||||
.actions(deleteOld).build();
|
||||
}
|
||||
|
||||
|
||||
private SQLQuery createDeleteDuplicateMessageTrigger(String triggerName, String tableName) {
|
||||
final Table table = new Table(tableName);
|
||||
final SQLDeleteQuery deleteOld = SQLQueryBuilder.deleteFrom(table).where(Expression.and(
|
||||
Expression.equals(new Column(DirectMessages.ACCOUNT_KEY), new Column(Table.NEW, DirectMessages.ACCOUNT_KEY)),
|
||||
Expression.equals(new Column(DirectMessages.MESSAGE_ID), new Column(Table.NEW, DirectMessages.MESSAGE_ID))
|
||||
)).build();
|
||||
return SQLQueryBuilder.createTrigger(false, true, triggerName)
|
||||
.type(Type.BEFORE).event(Event.INSERT).on(table).forEachRow(true)
|
||||
.actions(deleteOld).build();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onDowngrade(final SQLiteDatabase db, final int oldVersion, final int newVersion) {
|
||||
handleVersionChange(db, oldVersion, newVersion);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpgrade(final SQLiteDatabase db, final int oldVersion, final int newVersion) {
|
||||
handleVersionChange(db, oldVersion, newVersion);
|
||||
if (oldVersion <= 43 && newVersion >= 44 && newVersion <= 153) {
|
||||
final ContentValues values = new ContentValues();
|
||||
final SharedPreferences prefs = mContext
|
||||
.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
|
||||
// Here I use old consumer key/secret because it's default key for
|
||||
// older versions
|
||||
final String prefConsumerKey = prefs.getString(KEY_CONSUMER_KEY, TWITTER_CONSUMER_KEY_LEGACY);
|
||||
final String prefConsumerSecret = prefs.getString(KEY_CONSUMER_SECRET, TWITTER_CONSUMER_SECRET_LEGACY);
|
||||
values.put(Accounts.CONSUMER_KEY, prefConsumerKey.trim());
|
||||
values.put(Accounts.CONSUMER_SECRET, prefConsumerSecret.trim());
|
||||
db.update(Accounts.TABLE_NAME, values, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleVersionChange(final SQLiteDatabase db, final int oldVersion, final int newVersion) {
|
||||
|
||||
if (oldVersion <= 153) {
|
||||
migrateLegacyAccounts(db);
|
||||
if (newVersion > 153) {
|
||||
AccountMigratorKt.migrateAccounts(AccountManager.get(mContext), db);
|
||||
db.execSQL(SQLQueryBuilder.dropTable(true, Accounts.TABLE_NAME).getSQL());
|
||||
}
|
||||
}
|
||||
|
||||
safeUpgrade(db, Statuses.TABLE_NAME, Statuses.COLUMNS, Statuses.TYPES, true, null);
|
||||
safeUpgrade(db, Activities.AboutMe.TABLE_NAME, Activities.AboutMe.COLUMNS,
|
||||
Activities.AboutMe.TYPES, true, null);
|
||||
safeUpgrade(db, Activities.ByFriends.TABLE_NAME, Activities.ByFriends.COLUMNS,
|
||||
Activities.ByFriends.TYPES, true, null);
|
||||
migrateDrafts(db);
|
||||
safeUpgrade(db, CachedUsers.TABLE_NAME, CachedUsers.COLUMNS, CachedUsers.TYPES, true, null,
|
||||
createConflictReplaceConstraint(CachedUsers.USER_KEY));
|
||||
safeUpgrade(db, CachedStatuses.TABLE_NAME, CachedStatuses.COLUMNS, CachedStatuses.TYPES, true, null);
|
||||
safeUpgrade(db, CachedHashtags.TABLE_NAME, CachedHashtags.COLUMNS, CachedHashtags.TYPES, true, null);
|
||||
safeUpgrade(db, CachedRelationships.TABLE_NAME, CachedRelationships.COLUMNS, CachedRelationships.TYPES, true, null,
|
||||
createConflictReplaceConstraint(CachedRelationships.ACCOUNT_KEY, CachedRelationships.USER_KEY));
|
||||
|
||||
migrateFilters(db, oldVersion);
|
||||
safeUpgrade(db, DirectMessages.Inbox.TABLE_NAME, DirectMessages.Inbox.COLUMNS,
|
||||
DirectMessages.Inbox.TYPES, true, null);
|
||||
safeUpgrade(db, DirectMessages.Outbox.TABLE_NAME, DirectMessages.Outbox.COLUMNS,
|
||||
DirectMessages.Outbox.TYPES, true, null);
|
||||
safeUpgrade(db, CachedTrends.Local.TABLE_NAME, CachedTrends.Local.COLUMNS,
|
||||
CachedTrends.Local.TYPES, true, null);
|
||||
safeUpgrade(db, Tabs.TABLE_NAME, Tabs.COLUMNS, Tabs.TYPES, false, null);
|
||||
safeUpgrade(db, SavedSearches.TABLE_NAME, SavedSearches.COLUMNS, SavedSearches.TYPES, true, null);
|
||||
safeUpgrade(db, SearchHistory.TABLE_NAME, SearchHistory.COLUMNS, SearchHistory.TYPES, true, null);
|
||||
|
||||
if (oldVersion < 131) {
|
||||
migrateFilteredUsers(db);
|
||||
}
|
||||
|
||||
db.beginTransaction();
|
||||
db.execSQL(SQLQueryBuilder.dropTable(true, "network_usages").getSQL());
|
||||
db.execSQL(SQLQueryBuilder.dropTable(true, "mentions").getSQL());
|
||||
createViews(db);
|
||||
createTriggers(db);
|
||||
createIndices(db);
|
||||
db.setTransactionSuccessful();
|
||||
db.endTransaction();
|
||||
}
|
||||
|
||||
private void migrateDrafts(SQLiteDatabase db) {
|
||||
final HashMap<String, String> draftsAlias = new HashMap<>();
|
||||
draftsAlias.put(Drafts.MEDIA, "medias");
|
||||
safeUpgrade(db, Drafts.TABLE_NAME, Drafts.COLUMNS, Drafts.TYPES, false, draftsAlias);
|
||||
}
|
||||
|
||||
private void migrateFilters(SQLiteDatabase db, int oldVersion) {
|
||||
safeUpgrade(db, Filters.Users.TABLE_NAME, Filters.Users.COLUMNS, Filters.Users.TYPES,
|
||||
oldVersion < 49, null);
|
||||
|
||||
final HashMap<String, String> filtersAlias = new HashMap<>();
|
||||
safeUpgrade(db, Filters.Keywords.TABLE_NAME, Filters.Keywords.COLUMNS, Filters.Keywords.TYPES,
|
||||
oldVersion < 49, filtersAlias);
|
||||
safeUpgrade(db, Filters.Sources.TABLE_NAME, Filters.Sources.COLUMNS, Filters.Sources.TYPES,
|
||||
oldVersion < 49, filtersAlias);
|
||||
safeUpgrade(db, Filters.Links.TABLE_NAME, Filters.Links.COLUMNS, Filters.Links.TYPES,
|
||||
oldVersion < 49, filtersAlias);
|
||||
safeUpgrade(db, Filters.Subscriptions.TABLE_NAME, Filters.Subscriptions.COLUMNS,
|
||||
Filters.Subscriptions.TYPES, false, null);
|
||||
}
|
||||
|
||||
private void migrateLegacyAccounts(SQLiteDatabase db) {
|
||||
final HashMap<String, String> accountsAlias = new HashMap<>();
|
||||
accountsAlias.put(Accounts.SCREEN_NAME, "username");
|
||||
accountsAlias.put(Accounts.NAME, "username");
|
||||
accountsAlias.put(Accounts.ACCOUNT_KEY, "user_id");
|
||||
accountsAlias.put(Accounts.COLOR, "user_color");
|
||||
accountsAlias.put(Accounts.OAUTH_TOKEN_SECRET, "token_secret");
|
||||
accountsAlias.put(Accounts.API_URL_FORMAT, "rest_base_url");
|
||||
safeUpgrade(db, Accounts.TABLE_NAME, Accounts.COLUMNS, Accounts.TYPES, false, accountsAlias);
|
||||
}
|
||||
|
||||
private void migrateFilteredUsers(SQLiteDatabase db) {
|
||||
db.execSQL(SQLQueryBuilder.update(OnConflict.REPLACE, Filters.Users.TABLE_NAME)
|
||||
.set(new SetValue(Filters.Users.USER_KEY, new RawSQLLang(Filters.Users.USER_KEY + "||?")))
|
||||
.where(Expression.notLikeArgs(new Column(Filters.Users.USER_KEY)))
|
||||
.buildSQL(),
|
||||
new Object[]{"@twitter.com", "%@%"});
|
||||
}
|
||||
|
||||
private static String createTable(final String tableName, final String[] columns, final String[] types,
|
||||
final boolean createIfNotExists, final Constraint... constraints) {
|
||||
final SQLCreateTableQuery.Builder qb = SQLQueryBuilder.createTable(createIfNotExists, tableName);
|
||||
qb.columns(NewColumn.createNewColumns(columns, types));
|
||||
qb.constraint(constraints);
|
||||
return qb.buildSQL();
|
||||
}
|
||||
|
||||
private static String createIndex(final String indexName, final String tableName, final String[] columns,
|
||||
final boolean createIfNotExists) {
|
||||
final SQLCreateIndexQuery.Builder qb = SQLQueryBuilder.createIndex(false, createIfNotExists);
|
||||
qb.name(indexName);
|
||||
qb.on(new Table(tableName), new Columns(columns));
|
||||
return qb.buildSQL();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,125 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2011-2013 Sergey Tarasevich
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*******************************************************************************/
|
||||
package org.mariotaku.twidere.util.imageloader;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapShader;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.ColorFilter;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.Shader;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import com.nostra13.universalimageloader.core.assist.LoadedFrom;
|
||||
import com.nostra13.universalimageloader.core.display.BitmapDisplayer;
|
||||
import com.nostra13.universalimageloader.core.imageaware.ImageAware;
|
||||
import com.nostra13.universalimageloader.core.imageaware.ImageViewAware;
|
||||
|
||||
/**
|
||||
* Can display bitmap with rounded corners. This implementation works only with ImageViews wrapped
|
||||
* in ImageViewAware.
|
||||
* <br />
|
||||
* This implementation is inspired by
|
||||
* <a href="http://www.curious-creature.org/2012/12/11/android-recipe-1-image-with-rounded-corners/">
|
||||
* Romain Guy's article</a>. It rounds images using custom drawable drawing. Original bitmap isn't changed.
|
||||
* <br />
|
||||
* <br />
|
||||
* If this implementation doesn't meet your needs then consider
|
||||
* <a href="https://github.com/vinc3m1/RoundedImageView">RoundedImageView</a> or
|
||||
* <a href="https://github.com/Pkmmte/CircularImageView">CircularImageView</a> projects for usage.
|
||||
*
|
||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
||||
* @since 1.5.6
|
||||
*/
|
||||
public class OvalBitmapDisplayer implements BitmapDisplayer {
|
||||
|
||||
protected final int margin;
|
||||
|
||||
public OvalBitmapDisplayer() {
|
||||
this(0);
|
||||
}
|
||||
|
||||
public OvalBitmapDisplayer(int marginPixels) {
|
||||
this.margin = marginPixels;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void display(Bitmap bitmap, ImageAware imageAware, LoadedFrom loadedFrom) {
|
||||
if (!(imageAware instanceof ImageViewAware)) {
|
||||
throw new IllegalArgumentException("ImageAware should wrap ImageView. ImageViewAware is expected.");
|
||||
}
|
||||
|
||||
imageAware.setImageDrawable(new OvalDrawable(bitmap, margin));
|
||||
}
|
||||
|
||||
public static class OvalDrawable extends Drawable {
|
||||
|
||||
protected final int margin;
|
||||
|
||||
protected final RectF mRect = new RectF(),
|
||||
mBitmapRect;
|
||||
protected final BitmapShader bitmapShader;
|
||||
protected final Paint paint;
|
||||
|
||||
public OvalDrawable(Bitmap bitmap, int margin) {
|
||||
this.margin = margin;
|
||||
|
||||
bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
|
||||
mBitmapRect = new RectF(margin, margin, bitmap.getWidth() - margin, bitmap.getHeight() - margin);
|
||||
|
||||
paint = new Paint();
|
||||
paint.setAntiAlias(true);
|
||||
paint.setShader(bitmapShader);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onBoundsChange(Rect bounds) {
|
||||
super.onBoundsChange(bounds);
|
||||
mRect.set(margin, margin, bounds.width() - margin, bounds.height() - margin);
|
||||
|
||||
// Resize the original bitmap to fit the new bound
|
||||
Matrix shaderMatrix = new Matrix();
|
||||
shaderMatrix.setRectToRect(mBitmapRect, mRect, Matrix.ScaleToFit.FILL);
|
||||
bitmapShader.setLocalMatrix(shaderMatrix);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(@NonNull Canvas canvas) {
|
||||
canvas.drawOval(mRect, paint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOpacity() {
|
||||
return PixelFormat.TRANSLUCENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAlpha(int alpha) {
|
||||
paint.setAlpha(alpha);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setColorFilter(ColorFilter cf) {
|
||||
paint.setColorFilter(cf);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
package org.mariotaku.twidere.util.io;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2016/12/8.
|
||||
*/
|
||||
|
||||
public final class CountOnlyOutputStream extends OutputStream {
|
||||
private int count;
|
||||
|
||||
@Override
|
||||
public void write(int i) throws IOException {
|
||||
count++;
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return count;
|
||||
}
|
||||
}
|
|
@ -7,15 +7,11 @@ import android.text.TextUtils;
|
|||
|
||||
import org.mariotaku.restfu.http.RestHttpClient;
|
||||
import org.mariotaku.twidere.model.ParcelableMedia;
|
||||
import org.mariotaku.twidere.util.HtmlLinkExtractor;
|
||||
import org.mariotaku.twidere.util.media.preview.provider.InstagramProvider;
|
||||
import org.mariotaku.twidere.util.media.preview.provider.Provider;
|
||||
import org.mariotaku.twidere.util.media.preview.provider.TwitterMediaProvider;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 16/1/1.
|
||||
|
@ -61,17 +57,4 @@ public class PreviewMediaExtractor {
|
|||
return providerFor(link) != null;
|
||||
}
|
||||
|
||||
public static List<String> getSupportedLinksInStatus(final String statusString) {
|
||||
if (statusString == null) return Collections.emptyList();
|
||||
final List<String> links = new ArrayList<>();
|
||||
final HtmlLinkExtractor extractor = new HtmlLinkExtractor();
|
||||
for (final HtmlLinkExtractor.HtmlLink link : extractor.grabLinks(statusString)) {
|
||||
final String linkString = link.getLink();
|
||||
if (isSupported(linkString)) {
|
||||
links.add(linkString);
|
||||
}
|
||||
}
|
||||
return links;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,49 +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.util.support;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 15/11/18.
|
||||
*/
|
||||
public class IntentSupport {
|
||||
@SuppressLint("InlinedApi")
|
||||
public static final String CATEGORY_APP_BROWSER = Intent.CATEGORY_APP_BROWSER;
|
||||
|
||||
private IntentSupport() {
|
||||
}
|
||||
|
||||
public static void setSelector(Intent intent, Intent selector) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) return;
|
||||
IntentSupport15.setSelector(intent, selector);
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1)
|
||||
private static class IntentSupport15 {
|
||||
public static void setSelector(Intent intent, Intent selector) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) return;
|
||||
intent.setSelector(selector);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -37,6 +37,7 @@ public class DefaultWebViewClient extends WebViewClient {
|
|||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public boolean shouldOverrideUrlLoading(final WebView view, final String url) {
|
||||
try {
|
||||
mActivity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
|
||||
|
|
|
@ -89,7 +89,6 @@ public class ForegroundColorView extends View implements IForegroundView {
|
|||
* the padding area.
|
||||
*
|
||||
* @param drawable The Drawable to be drawn on top of the children.
|
||||
* @attr ref android.R.styleable#FrameLayout_foreground
|
||||
*/
|
||||
@Override
|
||||
public void setForeground(final Drawable drawable) {
|
||||
|
@ -102,7 +101,6 @@ public class ForegroundColorView extends View implements IForegroundView {
|
|||
* Describes how the foreground is positioned. Defaults to START and TOP.
|
||||
*
|
||||
* @param foregroundGravity See {@link android.view.Gravity}
|
||||
* @attr ref android.R.styleable#FrameLayout_foregroundGravity
|
||||
*/
|
||||
@Override
|
||||
public void setForegroundGravity(final int foregroundGravity) {
|
||||
|
@ -111,7 +109,7 @@ public class ForegroundColorView extends View implements IForegroundView {
|
|||
}
|
||||
}
|
||||
|
||||
public void setAlphaPatternEnable(final boolean alphaPattern) {
|
||||
public void setAlphaPatternEnabled(final boolean alphaPattern) {
|
||||
if (mAlphaPattern == alphaPattern) return;
|
||||
mAlphaPattern = alphaPattern;
|
||||
invalidate();
|
||||
|
|
|
@ -64,7 +64,6 @@ public class ForegroundImageView extends ImageView implements IForegroundView {
|
|||
* the padding area.
|
||||
*
|
||||
* @param drawable The Drawable to be drawn on top of the children.
|
||||
* @attr ref android.R.styleable#FrameLayout_foreground
|
||||
*/
|
||||
@Override
|
||||
public void setForeground(final Drawable drawable) {
|
||||
|
@ -77,7 +76,6 @@ public class ForegroundImageView extends ImageView implements IForegroundView {
|
|||
* Describes how the foreground is positioned. Defaults to START and TOP.
|
||||
*
|
||||
* @param foregroundGravity See {@link android.view.Gravity}
|
||||
* @attr ref android.R.styleable#FrameLayout_foregroundGravity
|
||||
*/
|
||||
@Override
|
||||
public void setForegroundGravity(final int foregroundGravity) {
|
||||
|
|
|
@ -26,7 +26,6 @@ import android.os.Parcelable;
|
|||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.support.v4.view.MotionEventCompat;
|
||||
import android.support.v4.view.ViewConfigurationCompat;
|
||||
import android.support.v4.view.ViewPager;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
|
@ -92,7 +91,7 @@ public class LinePageIndicator extends View implements PagerIndicator {
|
|||
a.recycle();
|
||||
|
||||
final ViewConfiguration configuration = ViewConfiguration.get(context);
|
||||
mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration);
|
||||
mTouchSlop = configuration.getScaledPagingTouchSlop();
|
||||
}
|
||||
|
||||
public float getGapWidth() {
|
||||
|
@ -221,13 +220,13 @@ public class LinePageIndicator extends View implements PagerIndicator {
|
|||
final int action = ev.getAction() & MotionEventCompat.ACTION_MASK;
|
||||
switch (action) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
|
||||
mActivePointerId = ev.getPointerId(0);
|
||||
mLastMotionX = ev.getX();
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_MOVE: {
|
||||
final int activePointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
|
||||
final float x = MotionEventCompat.getX(ev, activePointerIndex);
|
||||
final int activePointerIndex = ev.findPointerIndex(mActivePointerId);
|
||||
final float x = ev.getX(activePointerIndex);
|
||||
final float deltaX = x - mLastMotionX;
|
||||
|
||||
if (!mIsDragging) {
|
||||
|
@ -276,19 +275,19 @@ public class LinePageIndicator extends View implements PagerIndicator {
|
|||
|
||||
case MotionEventCompat.ACTION_POINTER_DOWN: {
|
||||
final int index = MotionEventCompat.getActionIndex(ev);
|
||||
mLastMotionX = MotionEventCompat.getX(ev, index);
|
||||
mActivePointerId = MotionEventCompat.getPointerId(ev, index);
|
||||
mLastMotionX = ev.getX(index);
|
||||
mActivePointerId = ev.getPointerId(index);
|
||||
break;
|
||||
}
|
||||
|
||||
case MotionEventCompat.ACTION_POINTER_UP:
|
||||
final int pointerIndex = MotionEventCompat.getActionIndex(ev);
|
||||
final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex);
|
||||
final int pointerId = ev.getPointerId(pointerIndex);
|
||||
if (pointerId == mActivePointerId) {
|
||||
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
|
||||
mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex);
|
||||
mActivePointerId = ev.getPointerId(newPointerIndex);
|
||||
}
|
||||
mLastMotionX = MotionEventCompat.getX(ev, MotionEventCompat.findPointerIndex(ev, mActivePointerId));
|
||||
mLastMotionX = MotionEventCompat.getX(ev, ev.findPointerIndex(mActivePointerId));
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -64,6 +64,7 @@ public class ProfileBannerImageView extends ForegroundImageView implements IExte
|
|||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
protected boolean fitSystemWindows(@NonNull Rect insets) {
|
||||
if (mOnFitSystemWindowsListener != null) {
|
||||
mOnFitSystemWindowsListener.onFitSystemWindows(insets);
|
||||
|
|
|
@ -39,8 +39,4 @@ public class ViewListHolder {
|
|||
return view.getContext();
|
||||
}
|
||||
|
||||
protected String getString(final int resId, final Object... formatArgs) {
|
||||
return getContext().getString(resId, formatArgs);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,26 +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.iface;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 15/5/18.
|
||||
*/
|
||||
public interface ICustomTypefaceTextView {
|
||||
}
|
|
@ -50,7 +50,6 @@ public interface IForegroundView {
|
|||
* the padding area.
|
||||
*
|
||||
* @param drawable The Drawable to be drawn on top of the children.
|
||||
* @attr ref android.R.attr#foreground
|
||||
*/
|
||||
void setForeground(final Drawable drawable);
|
||||
|
||||
|
@ -58,7 +57,6 @@ public interface IForegroundView {
|
|||
* Describes how the foreground is positioned. Defaults to START and TOP.
|
||||
*
|
||||
* @param foregroundGravity See {@link android.view.Gravity}
|
||||
* @attr ref android.R.attr#foregroundGravity
|
||||
*/
|
||||
void setForegroundGravity(int foregroundGravity);
|
||||
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.view.iface;
|
||||
|
||||
import android.content.res.ColorStateList;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 14/12/19.
|
||||
*/
|
||||
public interface IThemeAccentView {
|
||||
|
||||
void setAccentTintColor(@NonNull ColorStateList color);
|
||||
|
||||
}
|
|
@ -40,30 +40,21 @@ public interface PagerIndicator extends ViewPager.OnPageChangeListener {
|
|||
* This <strong>must</strong> be used if you need to set the page before the
|
||||
* views are drawn on screen (e.g., default start page).
|
||||
* </p>
|
||||
*
|
||||
* @param item
|
||||
*/
|
||||
void setCurrentItem(int item);
|
||||
|
||||
/**
|
||||
* Set a page change listener which will receive forwarded events.
|
||||
*
|
||||
* @param listener
|
||||
*/
|
||||
void setOnPageChangeListener(ViewPager.OnPageChangeListener listener);
|
||||
|
||||
/**
|
||||
* Bind the indicator to a ViewPager.
|
||||
*
|
||||
* @param view
|
||||
*/
|
||||
void setViewPager(ViewPager view);
|
||||
|
||||
/**
|
||||
* Bind the indicator to a ViewPager.
|
||||
*
|
||||
* @param view
|
||||
* @param initialPosition
|
||||
*/
|
||||
void setViewPager(ViewPager view, int initialPosition);
|
||||
|
||||
|
@ -85,17 +76,11 @@ public interface PagerIndicator extends ViewPager.OnPageChangeListener {
|
|||
|
||||
/**
|
||||
* Returns the icon of the view at position
|
||||
*
|
||||
* @param position
|
||||
* @return
|
||||
*/
|
||||
Drawable getPageIcon(int position);
|
||||
|
||||
/**
|
||||
* Returns the title of the view at position
|
||||
*
|
||||
* @param position
|
||||
* @return
|
||||
*/
|
||||
CharSequence getPageTitle(int position);
|
||||
|
||||
|
|
|
@ -67,6 +67,7 @@ import org.mariotaku.chameleon.ChameleonUtils
|
|||
import org.mariotaku.kpreferences.get
|
||||
import org.mariotaku.kpreferences.set
|
||||
import org.mariotaku.ktextension.addOnAccountsUpdatedListenerSafe
|
||||
import org.mariotaku.ktextension.coerceInOr
|
||||
import org.mariotaku.ktextension.convert
|
||||
import org.mariotaku.ktextension.removeOnAccountsUpdatedListenerSafe
|
||||
import org.mariotaku.twidere.Constants.*
|
||||
|
@ -524,7 +525,7 @@ class HomeActivity : BaseActivity(), OnClickListener, OnPageChangeListener, Supp
|
|||
override fun onNewIntent(intent: Intent) {
|
||||
val tabPosition = handleIntent(intent, false)
|
||||
if (tabPosition >= 0) {
|
||||
mainPager.currentItem = TwidereMathUtils.clamp(tabPosition, pagerAdapter.count, 0)
|
||||
mainPager.currentItem = tabPosition.coerceInOr(0 until pagerAdapter.count, 0)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -765,10 +766,10 @@ class HomeActivity : BaseActivity(), OnClickListener, OnPageChangeListener, Supp
|
|||
private fun setTabPosition(initialTab: Int) {
|
||||
val rememberPosition = preferences.getBoolean(SharedPreferenceConstants.KEY_REMEMBER_POSITION, true)
|
||||
if (initialTab >= 0) {
|
||||
mainPager.currentItem = TwidereMathUtils.clamp(initialTab, pagerAdapter.count, 0)
|
||||
mainPager.currentItem = initialTab.coerceInOr(0 until pagerAdapter.count, 0)
|
||||
} else if (rememberPosition) {
|
||||
val position = preferences.getInt(SharedPreferenceConstants.KEY_SAVED_TAB_POSITION, 0)
|
||||
mainPager.currentItem = TwidereMathUtils.clamp(position, pagerAdapter.count, 0)
|
||||
mainPager.currentItem = position.coerceInOr(0 until pagerAdapter.count, 0)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
import android.widget.*
|
||||
import com.bluelinelabs.logansquare.LoganSquare
|
||||
import com.rengwuxian.materialedittext.MaterialEditText
|
||||
import org.mariotaku.restfu.annotation.method.GET
|
||||
import org.mariotaku.restfu.http.HttpRequest
|
||||
import org.mariotaku.restfu.http.RestHttpClient
|
||||
|
@ -26,6 +27,7 @@ import org.mariotaku.twidere.model.CustomAPIConfig
|
|||
import org.mariotaku.twidere.model.account.cred.Credentials
|
||||
import org.mariotaku.twidere.util.ParseUtils
|
||||
import org.mariotaku.twidere.util.dagger.GeneralComponentHelper
|
||||
import org.mariotaku.twidere.util.view.ConsumerKeySecretValidator
|
||||
import java.io.IOException
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -35,8 +37,8 @@ class APIEditorDialogFragment : BaseDialogFragment() {
|
|||
private val editAPIUrlFormat by lazy { dialog.findViewById(R.id.editApiUrlFormat) as EditText }
|
||||
private val editSameOAuthSigningUrl by lazy { dialog.findViewById(R.id.editSameOAuthSigningUrl) as CheckBox }
|
||||
private val editNoVersionSuffix by lazy { dialog.findViewById(R.id.editNoVersionSuffix) as CheckBox }
|
||||
private val editConsumerKey by lazy { dialog.findViewById(R.id.editConsumerKey) as EditText }
|
||||
private val editConsumerSecret by lazy { dialog.findViewById(R.id.editConsumerSecret) as EditText }
|
||||
private val editConsumerKey by lazy { dialog.findViewById(R.id.editConsumerKey) as MaterialEditText }
|
||||
private val editConsumerSecret by lazy { dialog.findViewById(R.id.editConsumerSecret) as MaterialEditText }
|
||||
private val editAuthType by lazy { dialog.findViewById(R.id.editAuthType) as RadioGroup }
|
||||
private val apiFormatHelpButton by lazy { dialog.findViewById(R.id.apiUrlFormatHelp) }
|
||||
private val accountTypeSpinner by lazy { dialog.findViewById(R.id.accountTypeSpinner) as Spinner }
|
||||
|
@ -46,7 +48,7 @@ class APIEditorDialogFragment : BaseDialogFragment() {
|
|||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
val builder = AlertDialog.Builder(context)
|
||||
builder.setView(R.layout.layout_api_editor)
|
||||
builder.setView(R.layout.dialog_api_editor)
|
||||
builder.setPositiveButton(R.string.action_save) { dialog, which ->
|
||||
val targetFragment = this.targetFragment
|
||||
val parentFragment = this.parentFragment
|
||||
|
@ -77,6 +79,10 @@ class APIEditorDialogFragment : BaseDialogFragment() {
|
|||
}
|
||||
|
||||
accountTypeSpinner.adapter = AccountTypeSpinnerAdapter(context)
|
||||
|
||||
editConsumerKey.addValidator(ConsumerKeySecretValidator(context.getString(R.string.invalid_consumer_key)))
|
||||
editConsumerSecret.addValidator(ConsumerKeySecretValidator(context.getString(R.string.invalid_consumer_secret)))
|
||||
|
||||
editNoVersionSuffix.setOnCheckedChangeListener { buttonView, isChecked -> editNoVersionSuffixChanged = true }
|
||||
editAuthType.setOnCheckedChangeListener { group, checkedId ->
|
||||
val authType = getCheckedAuthType(checkedId)
|
||||
|
|
|
@ -128,9 +128,9 @@ class AccountsDashboardFragment : BaseFragment(), LoaderCallbacks<AccountsInfo>,
|
|||
hasPrevAccountIndicator.alpha = 0f
|
||||
hasNextAccountIndicator.alpha = 0f
|
||||
} else {
|
||||
hasPrevAccountIndicator.alpha = TwidereMathUtils.clamp(pagePosition, 0f, 1f)
|
||||
hasNextAccountIndicator.alpha = TwidereMathUtils.clamp(pageCount - (pagePosition
|
||||
+ visiblePages), 0f, 1f)
|
||||
hasPrevAccountIndicator.alpha = pagePosition.coerceIn(0f, 1f)
|
||||
hasNextAccountIndicator.alpha = (pageCount - (pagePosition + visiblePages))
|
||||
.coerceIn(0f, 1f)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -1480,7 +1480,7 @@ class StatusFragment : BaseFragment(), LoaderCallbacks<SingleResponse<Parcelable
|
|||
private var recyclerView: RecyclerView? = null
|
||||
private var statusViewHolder: DetailStatusViewHolder? = null
|
||||
|
||||
private val itemCounts: IntArray
|
||||
private val itemCounts = ItemCounts(ITEM_TYPES_SUM)
|
||||
|
||||
override val nameFirst: Boolean
|
||||
private val cardBackgroundColor: Int
|
||||
|
@ -1525,7 +1525,6 @@ class StatusFragment : BaseFragment(), LoaderCallbacks<SingleResponse<Parcelable
|
|||
init {
|
||||
setHasStableIds(true)
|
||||
val context = fragment.activity
|
||||
itemCounts = IntArray(ITEM_TYPES_SUM)
|
||||
// There's always a space at the end of the list
|
||||
itemCounts[ITEM_IDX_SPACE] = 1
|
||||
itemCounts[ITEM_IDX_STATUS] = 1
|
||||
|
@ -1570,7 +1569,7 @@ class StatusFragment : BaseFragment(), LoaderCallbacks<SingleResponse<Parcelable
|
|||
|
||||
fun getIndexStart(index: Int): Int {
|
||||
if (index == 0) return 0
|
||||
return TwidereMathUtils.sum(itemCounts, 0, index - 1)
|
||||
return itemCounts.getItemStartPosition(index)
|
||||
}
|
||||
|
||||
override fun getStatusId(position: Int): String? {
|
||||
|
@ -1827,7 +1826,7 @@ class StatusFragment : BaseFragment(), LoaderCallbacks<SingleResponse<Parcelable
|
|||
|
||||
override fun getItemCount(): Int {
|
||||
if (status == null) return 0
|
||||
return TwidereMathUtils.sum(itemCounts)
|
||||
return itemCounts.itemCount
|
||||
}
|
||||
|
||||
override fun onAttachedToRecyclerView(recyclerView: RecyclerView?) {
|
||||
|
|
|
@ -1398,7 +1398,7 @@ class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener,
|
|||
|
||||
private fun updateScrollOffset(offset: Int) {
|
||||
val spaceHeight = profileBannerSpace.height
|
||||
val factor = TwidereMathUtils.clamp(if (spaceHeight == 0) 0f else offset / spaceHeight.toFloat(), 0f, 1f)
|
||||
val factor = (if (spaceHeight == 0) 0f else offset / spaceHeight.toFloat()).coerceIn(0f, 1f)
|
||||
profileBannerContainer.translationY = (-offset).toFloat()
|
||||
profileBanner.translationY = (offset / 2).toFloat()
|
||||
profileBirthdayBanner.translationY = (offset / 2).toFloat()
|
||||
|
@ -1417,7 +1417,7 @@ class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener,
|
|||
val profileContentHeight = (profileNameContainer!!.height + profileDetailsContainer.height).toFloat()
|
||||
val tabOutlineAlphaFactor: Float
|
||||
if (offset - spaceHeight > 0) {
|
||||
tabOutlineAlphaFactor = 1f - TwidereMathUtils.clamp((offset - spaceHeight) / profileContentHeight, 0f, 1f)
|
||||
tabOutlineAlphaFactor = 1f - ((offset - spaceHeight) / profileContentHeight).coerceIn(0f, 1f)
|
||||
} else {
|
||||
tabOutlineAlphaFactor = 1f
|
||||
}
|
||||
|
@ -1467,7 +1467,7 @@ class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener,
|
|||
val location = IntArray(2)
|
||||
profileNameContainer.name.getLocationInWindow(location)
|
||||
val nameShowingRatio = (userProfileDrawer.paddingTop - location[1]) / profileNameContainer.name.height.toFloat()
|
||||
val textAlpha = TwidereMathUtils.clamp(nameShowingRatio, 0f, 1f)
|
||||
val textAlpha = nameShowingRatio.coerceIn(0f, 1f)
|
||||
val titleView = ViewSupport.findViewByText(toolbar, toolbar.title)
|
||||
if (titleView != null) {
|
||||
titleView.alpha = textAlpha
|
||||
|
@ -1545,10 +1545,10 @@ class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener,
|
|||
}
|
||||
|
||||
private fun updateValue() {
|
||||
val shadowAlpha = Math.round(alpha * TwidereMathUtils.clamp(1 - factor, 0f, 1f))
|
||||
val shadowAlpha = Math.round(alpha * (1 - factor).coerceIn(0f, 1f))
|
||||
shadowDrawable.alpha = shadowAlpha
|
||||
val hasColor = color != 0
|
||||
val colorAlpha = if (hasColor) Math.round(alpha * TwidereMathUtils.clamp(factor, 0f, 1f)) else 0
|
||||
val colorAlpha = if (hasColor) Math.round(alpha * factor.coerceIn(0f, 1f)) else 0
|
||||
colorDrawable.alpha = colorAlpha
|
||||
invalidateSelf()
|
||||
}
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.loader
|
||||
|
||||
import android.content.Context
|
||||
import android.support.v4.content.AsyncTaskLoader
|
||||
import org.mariotaku.microblog.library.MicroBlog
|
||||
import org.mariotaku.microblog.library.MicroBlogException
|
||||
import org.mariotaku.microblog.library.statusnet.model.Group
|
||||
import org.mariotaku.microblog.library.twitter.model.CursorSupport
|
||||
import org.mariotaku.microblog.library.twitter.model.PageableResponseList
|
||||
import org.mariotaku.twidere.TwidereConstants.LOGTAG
|
||||
import org.mariotaku.twidere.loader.iface.ICursorSupportLoader
|
||||
import org.mariotaku.twidere.model.ParcelableGroup
|
||||
import org.mariotaku.twidere.model.UserKey
|
||||
import org.mariotaku.twidere.model.util.ParcelableGroupUtils
|
||||
import org.mariotaku.twidere.util.DebugLog
|
||||
import org.mariotaku.twidere.util.MicroBlogAPIFactory
|
||||
import org.mariotaku.twidere.util.collection.NoDuplicatesArrayList
|
||||
import java.util.*
|
||||
|
||||
|
||||
abstract class BaseGroupsLoader(
|
||||
context: Context,
|
||||
protected val accountKey: UserKey,
|
||||
override val cursor: Long,
|
||||
data: List<ParcelableGroup>?
|
||||
) : AsyncTaskLoader<List<ParcelableGroup>>(context), ICursorSupportLoader {
|
||||
|
||||
protected val data = NoDuplicatesArrayList<ParcelableGroup>()
|
||||
|
||||
override final var nextCursor: Long = 0
|
||||
private set
|
||||
override final var prevCursor: Long = 0
|
||||
private set
|
||||
|
||||
init {
|
||||
if (data != null) {
|
||||
this.data.addAll(data)
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(MicroBlogException::class)
|
||||
abstract fun getGroups(twitter: MicroBlog): List<Group>
|
||||
|
||||
override fun loadInBackground(): List<ParcelableGroup> {
|
||||
val twitter = MicroBlogAPIFactory.getInstance(context, accountKey) ?: return emptyList()
|
||||
var listLoaded: List<Group>? = null
|
||||
try {
|
||||
listLoaded = getGroups(twitter)
|
||||
} catch (e: MicroBlogException) {
|
||||
DebugLog.w(LOGTAG, tr = e)
|
||||
}
|
||||
|
||||
if (listLoaded != null) {
|
||||
val listSize = listLoaded.size
|
||||
if (listLoaded is PageableResponseList<*>) {
|
||||
nextCursor = (listLoaded as CursorSupport).nextCursor
|
||||
prevCursor = listLoaded.previousCursor
|
||||
val dataSize = data.size
|
||||
for (i in 0..listSize - 1) {
|
||||
val group = listLoaded[i]
|
||||
data.add(ParcelableGroupUtils.from(group, accountKey, dataSize + i, isMember(group)))
|
||||
}
|
||||
} else {
|
||||
for (i in 0..listSize - 1) {
|
||||
val list = listLoaded[i]
|
||||
data.add(ParcelableGroupUtils.from(listLoaded[i], accountKey, i, isMember(list)))
|
||||
}
|
||||
}
|
||||
}
|
||||
Collections.sort(data)
|
||||
return data
|
||||
}
|
||||
|
||||
public override fun onStartLoading() {
|
||||
forceLoad()
|
||||
}
|
||||
|
||||
protected open fun isMember(list: Group): Boolean {
|
||||
return list.isMember
|
||||
}
|
||||
}
|
|
@ -35,7 +35,6 @@ import org.mariotaku.twidere.model.AccountDetails
|
|||
import org.mariotaku.twidere.model.ParcelableStatus
|
||||
import org.mariotaku.twidere.model.util.ParcelableStatusUtils
|
||||
import org.mariotaku.twidere.util.InternalTwitterContentUtils
|
||||
import org.mariotaku.twidere.util.Nullables
|
||||
import java.util.*
|
||||
|
||||
class ConversationLoader(
|
||||
|
@ -55,7 +54,7 @@ class ConversationLoader(
|
|||
private var canLoadAllReplies: Boolean = false
|
||||
|
||||
init {
|
||||
this.status = Nullables.assertNonNull(ParcelUtils.clone(status))
|
||||
this.status = ParcelUtils.clone(status)
|
||||
ParcelableStatusUtils.makeOriginalStatus(this.status)
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.loader
|
||||
|
||||
import android.content.Context
|
||||
|
||||
import org.mariotaku.microblog.library.MicroBlog
|
||||
import org.mariotaku.microblog.library.MicroBlogException
|
||||
import org.mariotaku.microblog.library.statusnet.model.Group
|
||||
import org.mariotaku.microblog.library.twitter.model.ResponseList
|
||||
import org.mariotaku.twidere.model.ParcelableGroup
|
||||
import org.mariotaku.twidere.model.UserKey
|
||||
|
||||
class UserGroupsLoader(
|
||||
context: Context,
|
||||
accountKey: UserKey,
|
||||
private val userKey: UserKey?,
|
||||
private val screenName: String?,
|
||||
data: List<ParcelableGroup>?
|
||||
) : BaseGroupsLoader(context, accountKey, 0, data) {
|
||||
|
||||
@Throws(MicroBlogException::class)
|
||||
override fun getGroups(twitter: MicroBlog): ResponseList<Group> {
|
||||
if (userKey != null) {
|
||||
return twitter.getGroups(userKey.id)
|
||||
} else if (screenName != null) {
|
||||
return twitter.getGroups(screenName)
|
||||
}
|
||||
throw MicroBlogException("No user argument")
|
||||
}
|
||||
|
||||
override fun isMember(list: Group): Boolean {
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -9,8 +9,8 @@ class ItemCounts(counts: Int) {
|
|||
|
||||
fun getItemCountIndex(itemPosition: Int): Int {
|
||||
var sum = 0
|
||||
for (i in data.indices) {
|
||||
sum += data[i]
|
||||
data.forEachIndexed { i, num ->
|
||||
sum += num
|
||||
if (itemPosition < sum) {
|
||||
return i
|
||||
}
|
||||
|
@ -19,11 +19,7 @@ class ItemCounts(counts: Int) {
|
|||
}
|
||||
|
||||
fun getItemStartPosition(countIndex: Int): Int {
|
||||
var sum = 0
|
||||
for (i in 0..countIndex - 1) {
|
||||
sum += data[i]
|
||||
}
|
||||
return sum
|
||||
return (0..countIndex - 1).sumBy { data[it] }
|
||||
}
|
||||
|
||||
val itemCount: Int get() = data.sum()
|
||||
|
@ -34,4 +30,8 @@ class ItemCounts(counts: Int) {
|
|||
data[countIndex] = value
|
||||
}
|
||||
|
||||
operator fun get(countIndex: Int): Int {
|
||||
return data[countIndex]
|
||||
}
|
||||
|
||||
}
|
|
@ -137,6 +137,8 @@ class UpdateStatusTask(
|
|||
} finally {
|
||||
// Cleanup
|
||||
pendingUpdate.deleteAlways.forEach { item -> item.delete(context) }
|
||||
uploader?.unbindService()
|
||||
shortener?.unbindService()
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
|
|
@ -82,8 +82,7 @@ object HttpClientFactory {
|
|||
val proxyType = prefs.getString(KEY_PROXY_TYPE, null)
|
||||
val proxyHost = prefs.getString(KEY_PROXY_HOST, null)
|
||||
val proxyPort = NumberUtils.toInt(prefs.getString(KEY_PROXY_PORT, null), -1)
|
||||
if (!isEmpty(proxyHost) && TwidereMathUtils.inRange(proxyPort, 0, 65535,
|
||||
TwidereMathUtils.RANGE_INCLUSIVE_INCLUSIVE)) {
|
||||
if (!isEmpty(proxyHost) && proxyPort in (0..65535)) {
|
||||
val type = getProxyType(proxyType)
|
||||
if (type != Proxy.Type.DIRECT) {
|
||||
builder.proxy(Proxy(type, InetSocketAddress.createUnresolved(proxyHost, proxyPort)))
|
||||
|
|
|
@ -77,8 +77,8 @@ class MediaLoaderWrapper(val imageLoader: ImageLoader) {
|
|||
.build()
|
||||
|
||||
|
||||
fun displayPreviewImage(view: ImageView, uri: String?) {
|
||||
imageLoader.displayImage(uri, view, previewDisplayOptions)
|
||||
fun displayPreviewImage(view: ImageView, url: String?) {
|
||||
imageLoader.displayImage(url, view, previewDisplayOptions)
|
||||
}
|
||||
|
||||
fun displayPreviewImage(view: ImageView, url: String?, loadingHandler: MediaLoadingHandler?) {
|
||||
|
@ -150,12 +150,12 @@ class MediaLoaderWrapper(val imageLoader: ImageLoader) {
|
|||
}
|
||||
}
|
||||
|
||||
fun displayProfileImage(view: ImageView, url: String) {
|
||||
fun displayProfileImage(view: ImageView, url: String?) {
|
||||
imageLoader.displayImage(url, view, profileImageDisplayOptions)
|
||||
}
|
||||
|
||||
fun loadImageSync(uri: String, targetImageSize: ImageSize, options: DisplayImageOptions): Bitmap? {
|
||||
return imageLoader.loadImageSync(uri, targetImageSize, options)
|
||||
fun loadImageSync(url: String, targetImageSize: ImageSize, options: DisplayImageOptions): Bitmap? {
|
||||
return imageLoader.loadImageSync(url, targetImageSize, options)
|
||||
}
|
||||
|
||||
fun displayDashboardProfileImage(view: ImageView, account: AccountDetails, drawableOnLoading: Drawable?) {
|
||||
|
@ -168,11 +168,11 @@ class MediaLoaderWrapper(val imageLoader: ImageLoader) {
|
|||
}
|
||||
|
||||
|
||||
fun displayImage(view: ImageView, url: String) {
|
||||
fun displayImage(view: ImageView, url: String?) {
|
||||
imageLoader.displayImage(url, view)
|
||||
}
|
||||
|
||||
fun displayProfileImage(view: ImageView, url: String, listener: ImageLoadingListener) {
|
||||
fun displayProfileImage(view: ImageView, url: String?, listener: ImageLoadingListener) {
|
||||
imageLoader.displayImage(url, view, profileImageDisplayOptions, listener)
|
||||
}
|
||||
|
||||
|
@ -206,7 +206,7 @@ class MediaLoaderWrapper(val imageLoader: ImageLoader) {
|
|||
preloadOnWifiOnly = preferences[mediaPreloadOnWifiOnlyKey]
|
||||
}
|
||||
|
||||
private fun displayDashboardProfileImage(view: ImageView, url: String, drawableOnLoading: Drawable?) {
|
||||
private fun displayDashboardProfileImage(view: ImageView, url: String?, drawableOnLoading: Drawable?) {
|
||||
if (drawableOnLoading != null) {
|
||||
val builder = Builder()
|
||||
builder.cloneFrom(dashboardProfileImageDisplayOptions)
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* 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.graphics.Bitmap
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Matrix
|
||||
import android.graphics.RectF
|
||||
import android.view.View
|
||||
|
||||
/**
|
||||
* Static utility methods for Transitions.
|
||||
*/
|
||||
object TransitionUtils {
|
||||
private const val MAX_IMAGE_SIZE = 1024 * 1024
|
||||
|
||||
/**
|
||||
* Creates a Bitmap of the given view, using the Matrix matrix to transform to the local
|
||||
* coordinates. `matrix` will be modified during the bitmap creation.
|
||||
*
|
||||
* If the bitmap is large, it will be scaled uniformly down to at most 1MB size.
|
||||
*
|
||||
* @param view The view to create a bitmap for.
|
||||
*
|
||||
* @param matrix The matrix converting the view local coordinates to the coordinates that
|
||||
* the bitmap will be displayed in. `matrix` will be modified before
|
||||
* returning.
|
||||
*
|
||||
* @param bounds The bounds of the bitmap in the destination coordinate system (where the
|
||||
* view should be presented. Typically, this is matrix.mapRect(viewBounds);
|
||||
*
|
||||
* @return A bitmap of the given view or null if bounds has no width or height.
|
||||
*/
|
||||
fun createViewBitmap(view: View, matrix: Matrix, bounds: RectF): Bitmap? {
|
||||
if (bounds.isEmpty) return null
|
||||
var bitmapWidth = Math.round(bounds.width())
|
||||
var bitmapHeight = Math.round(bounds.height())
|
||||
val scale = Math.min(1f, MAX_IMAGE_SIZE.toFloat() / (bitmapWidth * bitmapHeight))
|
||||
bitmapWidth *= scale.toInt()
|
||||
bitmapHeight *= scale.toInt()
|
||||
matrix.postTranslate(-bounds.left, -bounds.top)
|
||||
matrix.postScale(scale, scale)
|
||||
val bitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888)
|
||||
val canvas = Canvas(bitmap!!)
|
||||
canvas.concat(matrix)
|
||||
view.draw(canvas)
|
||||
return bitmap
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package org.mariotaku.twidere.util
|
||||
|
||||
import android.support.annotation.UiThread
|
||||
import android.view.View
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 16/1/23.
|
||||
*/
|
||||
object TwidereViewUtils {
|
||||
|
||||
@UiThread
|
||||
fun hitView(x: Float, y: Float, view: View): Boolean {
|
||||
val location = IntArray(2)
|
||||
view.getLocationOnScreen(location)
|
||||
return x in (location[0] until location[0] + view.width)
|
||||
&& y in (location[1] until location[1] + view.height)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,332 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.util.content
|
||||
|
||||
import android.accounts.AccountManager
|
||||
import android.content.ContentValues
|
||||
import android.content.Context
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
import android.database.sqlite.SQLiteOpenHelper
|
||||
import android.os.Build
|
||||
import org.mariotaku.kpreferences.get
|
||||
import org.mariotaku.sqliteqb.library.*
|
||||
import org.mariotaku.sqliteqb.library.Columns.Column
|
||||
import org.mariotaku.sqliteqb.library.query.SQLCreateTriggerQuery.Event
|
||||
import org.mariotaku.sqliteqb.library.query.SQLCreateTriggerQuery.Type
|
||||
import org.mariotaku.twidere.TwidereConstants.SHARED_PREFERENCES_NAME
|
||||
import org.mariotaku.twidere.annotation.CustomTabType
|
||||
import org.mariotaku.twidere.constant.defaultAPIConfigKey
|
||||
import org.mariotaku.twidere.model.Tab
|
||||
import org.mariotaku.twidere.model.TabValuesCreator
|
||||
import org.mariotaku.twidere.model.tab.TabConfiguration
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.*
|
||||
import org.mariotaku.twidere.util.TwidereQueryBuilder.ConversationsEntryQueryBuilder
|
||||
import org.mariotaku.twidere.util.TwidereQueryBuilder.DirectMessagesQueryBuilder
|
||||
import org.mariotaku.twidere.util.content.DatabaseUpgradeHelper.safeUpgrade
|
||||
import org.mariotaku.twidere.util.migrateAccounts
|
||||
import java.util.*
|
||||
|
||||
class TwidereSQLiteOpenHelper(
|
||||
private val context: Context,
|
||||
name: String,
|
||||
version: Int
|
||||
) : SQLiteOpenHelper(context, name, null, version) {
|
||||
|
||||
override fun onCreate(db: SQLiteDatabase) {
|
||||
db.beginTransaction()
|
||||
db.execSQL(createTable(Statuses.TABLE_NAME, Statuses.COLUMNS, Statuses.TYPES, true))
|
||||
db.execSQL(createTable(Activities.AboutMe.TABLE_NAME, Activities.AboutMe.COLUMNS, Activities.AboutMe.TYPES, true))
|
||||
db.execSQL(createTable(Activities.ByFriends.TABLE_NAME, Activities.ByFriends.COLUMNS, Activities.ByFriends.TYPES, true))
|
||||
db.execSQL(createTable(Drafts.TABLE_NAME, Drafts.COLUMNS, Drafts.TYPES, true))
|
||||
db.setTransactionSuccessful()
|
||||
db.endTransaction()
|
||||
|
||||
db.beginTransaction()
|
||||
db.execSQL(createTable(CachedUsers.TABLE_NAME, CachedUsers.COLUMNS, CachedUsers.TYPES, true,
|
||||
createConflictReplaceConstraint(CachedUsers.USER_KEY)))
|
||||
db.execSQL(createTable(CachedStatuses.TABLE_NAME, CachedStatuses.COLUMNS, CachedStatuses.TYPES, true))
|
||||
db.execSQL(createTable(CachedTrends.Local.TABLE_NAME, CachedTrends.Local.COLUMNS, CachedTrends.Local.TYPES,
|
||||
true))
|
||||
db.execSQL(createTable(CachedHashtags.TABLE_NAME, CachedHashtags.COLUMNS, CachedHashtags.TYPES, true))
|
||||
db.execSQL(createTable(CachedRelationships.TABLE_NAME, CachedRelationships.COLUMNS, CachedRelationships.TYPES, true,
|
||||
createConflictReplaceConstraint(CachedRelationships.ACCOUNT_KEY, CachedRelationships.USER_KEY)))
|
||||
db.setTransactionSuccessful()
|
||||
db.endTransaction()
|
||||
|
||||
|
||||
db.beginTransaction()
|
||||
db.execSQL(createTable(Filters.Users.TABLE_NAME, Filters.Users.COLUMNS, Filters.Users.TYPES, true))
|
||||
db.execSQL(createTable(Filters.Keywords.TABLE_NAME, Filters.Keywords.COLUMNS, Filters.Keywords.TYPES, true))
|
||||
db.execSQL(createTable(Filters.Sources.TABLE_NAME, Filters.Sources.COLUMNS, Filters.Sources.TYPES, true))
|
||||
db.execSQL(createTable(Filters.Links.TABLE_NAME, Filters.Links.COLUMNS, Filters.Links.TYPES, true))
|
||||
db.execSQL(createTable(Filters.Subscriptions.TABLE_NAME, Filters.Subscriptions.COLUMNS, Filters.Subscriptions.TYPES, true))
|
||||
db.setTransactionSuccessful()
|
||||
db.endTransaction()
|
||||
|
||||
db.beginTransaction()
|
||||
db.execSQL(createTable(DirectMessages.Inbox.TABLE_NAME, DirectMessages.Inbox.COLUMNS,
|
||||
DirectMessages.Inbox.TYPES, true))
|
||||
db.execSQL(createTable(DirectMessages.Outbox.TABLE_NAME, DirectMessages.Outbox.COLUMNS,
|
||||
DirectMessages.Outbox.TYPES, true))
|
||||
db.execSQL(createTable(Tabs.TABLE_NAME, Tabs.COLUMNS, Tabs.TYPES, true))
|
||||
db.execSQL(createTable(SavedSearches.TABLE_NAME, SavedSearches.COLUMNS, SavedSearches.TYPES, true))
|
||||
db.execSQL(createTable(SearchHistory.TABLE_NAME, SearchHistory.COLUMNS, SearchHistory.TYPES, true))
|
||||
db.setTransactionSuccessful()
|
||||
db.endTransaction()
|
||||
|
||||
db.beginTransaction()
|
||||
createViews(db)
|
||||
createTriggers(db)
|
||||
createIndices(db)
|
||||
db.setTransactionSuccessful()
|
||||
db.endTransaction()
|
||||
|
||||
setupDefaultTabs(db)
|
||||
}
|
||||
|
||||
private fun setupDefaultTabs(db: SQLiteDatabase) {
|
||||
db.beginTransaction()
|
||||
@CustomTabType
|
||||
val tabTypes = arrayOf(CustomTabType.HOME_TIMELINE, CustomTabType.NOTIFICATIONS_TIMELINE,
|
||||
CustomTabType.TRENDS_SUGGESTIONS, CustomTabType.DIRECT_MESSAGES)
|
||||
for (i in 0 until tabTypes.size) {
|
||||
@CustomTabType
|
||||
val tabType = tabTypes[i]
|
||||
val conf = TabConfiguration.ofType(tabType)
|
||||
val tab = Tab().apply {
|
||||
this.type = tabType
|
||||
this.icon = conf!!.icon.persistentKey
|
||||
this.position = i
|
||||
}
|
||||
db.insert(Tabs.TABLE_NAME, null, TabValuesCreator.create(tab))
|
||||
}
|
||||
db.setTransactionSuccessful()
|
||||
db.endTransaction()
|
||||
}
|
||||
|
||||
private fun createConflictReplaceConstraint(vararg columns: String): Constraint {
|
||||
return Constraint.unique(Columns(*columns), OnConflict.IGNORE)
|
||||
}
|
||||
|
||||
private fun createIndices(db: SQLiteDatabase) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) return
|
||||
db.execSQL(createIndex("statuses_index", Statuses.TABLE_NAME, arrayOf(Statuses.ACCOUNT_KEY), true))
|
||||
db.execSQL(createIndex("messages_inbox_index", DirectMessages.Inbox.TABLE_NAME, arrayOf(DirectMessages.ACCOUNT_KEY), true))
|
||||
db.execSQL(createIndex("messages_outbox_index", DirectMessages.Outbox.TABLE_NAME, arrayOf(DirectMessages.ACCOUNT_KEY), true))
|
||||
}
|
||||
|
||||
private fun createViews(db: SQLiteDatabase) {
|
||||
db.execSQL(SQLQueryBuilder.dropView(true, DirectMessages.TABLE_NAME).sql)
|
||||
db.execSQL(SQLQueryBuilder.dropView(true, DirectMessages.ConversationEntries.TABLE_NAME).sql)
|
||||
|
||||
db.execSQL(SQLQueryBuilder.createView(true, DirectMessages.TABLE_NAME)
|
||||
.`as`(DirectMessagesQueryBuilder.build()).buildSQL())
|
||||
db.execSQL(SQLQueryBuilder.createView(true, DirectMessages.ConversationEntries.TABLE_NAME)
|
||||
.`as`(ConversationsEntryQueryBuilder.build()).buildSQL())
|
||||
}
|
||||
|
||||
private fun createTriggers(db: SQLiteDatabase) {
|
||||
db.execSQL(SQLQueryBuilder.dropTrigger(true, "delete_old_statuses").sql)
|
||||
db.execSQL(SQLQueryBuilder.dropTrigger(true, "delete_old_cached_statuses").sql)
|
||||
db.execSQL(SQLQueryBuilder.dropTrigger(true, "delete_old_received_messages").sql)
|
||||
db.execSQL(SQLQueryBuilder.dropTrigger(true, "delete_old_sent_messages").sql)
|
||||
db.execSQL(SQLQueryBuilder.dropTrigger(true, "on_user_cache_update_trigger").sql)
|
||||
db.execSQL(SQLQueryBuilder.dropTrigger(true, "delete_old_cached_hashtags").sql)
|
||||
db.execSQL(createDeleteDuplicateStatusTrigger("delete_old_statuses", Statuses.TABLE_NAME).sql)
|
||||
db.execSQL(createDeleteDuplicateStatusTrigger("delete_old_cached_statuses", CachedStatuses.TABLE_NAME).sql)
|
||||
db.execSQL(createDeleteDuplicateMessageTrigger("delete_old_received_messages", DirectMessages.Inbox.TABLE_NAME).sql)
|
||||
db.execSQL(createDeleteDuplicateMessageTrigger("delete_old_sent_messages", DirectMessages.Outbox.TABLE_NAME).sql)
|
||||
|
||||
// Update user info in filtered users
|
||||
val cachedUsersTable = Table(CachedUsers.TABLE_NAME)
|
||||
val filteredUsersTable = Table(Filters.Users.TABLE_NAME)
|
||||
db.execSQL(SQLQueryBuilder.createTrigger(false, true, "on_user_cache_update_trigger")
|
||||
.type(Type.BEFORE)
|
||||
.event(Event.INSERT)
|
||||
.on(cachedUsersTable)
|
||||
.forEachRow(true)
|
||||
.actions(SQLQueryBuilder.update(OnConflict.REPLACE, filteredUsersTable)
|
||||
.set(SetValue(Column(Filters.Users.NAME), Column(Table.NEW, CachedUsers.NAME)),
|
||||
SetValue(Column(Filters.Users.SCREEN_NAME), Column(Table.NEW, CachedUsers.SCREEN_NAME)))
|
||||
.where(Expression.equals(Column(Filters.Users.USER_KEY), Column(Table.NEW, CachedUsers.USER_KEY)))
|
||||
.build())
|
||||
.buildSQL())
|
||||
|
||||
// Delete duplicated hashtags ignoring case
|
||||
val cachedHashtagsTable = Table(CachedHashtags.TABLE_NAME)
|
||||
db.execSQL(SQLQueryBuilder.createTrigger(false, true, "delete_old_cached_hashtags")
|
||||
.type(Type.BEFORE)
|
||||
.event(Event.INSERT)
|
||||
.on(cachedHashtagsTable)
|
||||
.forEachRow(true)
|
||||
.actions(SQLQueryBuilder.deleteFrom(cachedHashtagsTable)
|
||||
.where(Expression.like(Column(CachedHashtags.NAME), Column(Table.NEW, CachedHashtags.NAME)))
|
||||
.build())
|
||||
.buildSQL())
|
||||
|
||||
}
|
||||
|
||||
private fun createDeleteDuplicateStatusTrigger(triggerName: String, tableName: String): SQLQuery {
|
||||
val table = Table(tableName)
|
||||
val deleteOld = SQLQueryBuilder.deleteFrom(table).where(Expression.and(
|
||||
Expression.equals(Column(Statuses.ACCOUNT_KEY), Column(Table.NEW, Statuses.ACCOUNT_KEY)),
|
||||
Expression.equals(Column(Statuses.STATUS_ID), Column(Table.NEW, Statuses.STATUS_ID))
|
||||
)).build()
|
||||
return SQLQueryBuilder.createTrigger(false, true, triggerName)
|
||||
.type(Type.BEFORE).event(Event.INSERT).on(table).forEachRow(true)
|
||||
.actions(deleteOld).build()
|
||||
}
|
||||
|
||||
|
||||
private fun createDeleteDuplicateMessageTrigger(triggerName: String, tableName: String): SQLQuery {
|
||||
val table = Table(tableName)
|
||||
val deleteOld = SQLQueryBuilder.deleteFrom(table).where(Expression.and(
|
||||
Expression.equals(Column(DirectMessages.ACCOUNT_KEY), Column(Table.NEW, DirectMessages.ACCOUNT_KEY)),
|
||||
Expression.equals(Column(DirectMessages.MESSAGE_ID), Column(Table.NEW, DirectMessages.MESSAGE_ID))
|
||||
)).build()
|
||||
return SQLQueryBuilder.createTrigger(false, true, triggerName)
|
||||
.type(Type.BEFORE).event(Event.INSERT).on(table).forEachRow(true)
|
||||
.actions(deleteOld).build()
|
||||
}
|
||||
|
||||
|
||||
override fun onDowngrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
|
||||
handleVersionChange(db, oldVersion, newVersion)
|
||||
}
|
||||
|
||||
override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
|
||||
handleVersionChange(db, oldVersion, newVersion)
|
||||
if (oldVersion <= 43 && newVersion >= 44 && newVersion <= 153) {
|
||||
val values = ContentValues()
|
||||
val prefs = context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE)
|
||||
// Here I use old consumer key/secret because it's default key for
|
||||
// older versions
|
||||
val defaultAPIConfig = prefs[defaultAPIConfigKey]
|
||||
values.put(Accounts.CONSUMER_KEY, defaultAPIConfig.consumerKey)
|
||||
values.put(Accounts.CONSUMER_SECRET, defaultAPIConfig.consumerSecret)
|
||||
db.update(Accounts.TABLE_NAME, values, null, null)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleVersionChange(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
|
||||
|
||||
if (oldVersion <= 153) {
|
||||
migrateLegacyAccounts(db)
|
||||
if (newVersion > 153) {
|
||||
migrateAccounts(AccountManager.get(context), db)
|
||||
db.execSQL(SQLQueryBuilder.dropTable(true, Accounts.TABLE_NAME).sql)
|
||||
}
|
||||
}
|
||||
|
||||
safeUpgrade(db, Statuses.TABLE_NAME, Statuses.COLUMNS, Statuses.TYPES, true, null)
|
||||
safeUpgrade(db, Activities.AboutMe.TABLE_NAME, Activities.AboutMe.COLUMNS,
|
||||
Activities.AboutMe.TYPES, true, null)
|
||||
safeUpgrade(db, Activities.ByFriends.TABLE_NAME, Activities.ByFriends.COLUMNS,
|
||||
Activities.ByFriends.TYPES, true, null)
|
||||
migrateDrafts(db)
|
||||
safeUpgrade(db, CachedUsers.TABLE_NAME, CachedUsers.COLUMNS, CachedUsers.TYPES, true, null,
|
||||
createConflictReplaceConstraint(CachedUsers.USER_KEY))
|
||||
safeUpgrade(db, CachedStatuses.TABLE_NAME, CachedStatuses.COLUMNS, CachedStatuses.TYPES, true, null)
|
||||
safeUpgrade(db, CachedHashtags.TABLE_NAME, CachedHashtags.COLUMNS, CachedHashtags.TYPES, true, null)
|
||||
safeUpgrade(db, CachedRelationships.TABLE_NAME, CachedRelationships.COLUMNS, CachedRelationships.TYPES, true, null,
|
||||
createConflictReplaceConstraint(CachedRelationships.ACCOUNT_KEY, CachedRelationships.USER_KEY))
|
||||
|
||||
migrateFilters(db, oldVersion)
|
||||
safeUpgrade(db, DirectMessages.Inbox.TABLE_NAME, DirectMessages.Inbox.COLUMNS,
|
||||
DirectMessages.Inbox.TYPES, true, null)
|
||||
safeUpgrade(db, DirectMessages.Outbox.TABLE_NAME, DirectMessages.Outbox.COLUMNS,
|
||||
DirectMessages.Outbox.TYPES, true, null)
|
||||
safeUpgrade(db, CachedTrends.Local.TABLE_NAME, CachedTrends.Local.COLUMNS,
|
||||
CachedTrends.Local.TYPES, true, null)
|
||||
safeUpgrade(db, Tabs.TABLE_NAME, Tabs.COLUMNS, Tabs.TYPES, false, null)
|
||||
safeUpgrade(db, SavedSearches.TABLE_NAME, SavedSearches.COLUMNS, SavedSearches.TYPES, true, null)
|
||||
safeUpgrade(db, SearchHistory.TABLE_NAME, SearchHistory.COLUMNS, SearchHistory.TYPES, true, null)
|
||||
|
||||
if (oldVersion < 131) {
|
||||
migrateFilteredUsers(db)
|
||||
}
|
||||
|
||||
db.beginTransaction()
|
||||
db.execSQL(SQLQueryBuilder.dropTable(true, "network_usages").sql)
|
||||
db.execSQL(SQLQueryBuilder.dropTable(true, "mentions").sql)
|
||||
createViews(db)
|
||||
createTriggers(db)
|
||||
createIndices(db)
|
||||
db.setTransactionSuccessful()
|
||||
db.endTransaction()
|
||||
}
|
||||
|
||||
private fun migrateDrafts(db: SQLiteDatabase) {
|
||||
val draftsAlias = HashMap<String, String>()
|
||||
draftsAlias.put(Drafts.MEDIA, "medias")
|
||||
safeUpgrade(db, Drafts.TABLE_NAME, Drafts.COLUMNS, Drafts.TYPES, false, draftsAlias)
|
||||
}
|
||||
|
||||
private fun migrateFilters(db: SQLiteDatabase, oldVersion: Int) {
|
||||
safeUpgrade(db, Filters.Users.TABLE_NAME, Filters.Users.COLUMNS, Filters.Users.TYPES,
|
||||
oldVersion < 49, null)
|
||||
|
||||
val filtersAlias = HashMap<String, String>()
|
||||
safeUpgrade(db, Filters.Keywords.TABLE_NAME, Filters.Keywords.COLUMNS, Filters.Keywords.TYPES,
|
||||
oldVersion < 49, filtersAlias)
|
||||
safeUpgrade(db, Filters.Sources.TABLE_NAME, Filters.Sources.COLUMNS, Filters.Sources.TYPES,
|
||||
oldVersion < 49, filtersAlias)
|
||||
safeUpgrade(db, Filters.Links.TABLE_NAME, Filters.Links.COLUMNS, Filters.Links.TYPES,
|
||||
oldVersion < 49, filtersAlias)
|
||||
safeUpgrade(db, Filters.Subscriptions.TABLE_NAME, Filters.Subscriptions.COLUMNS,
|
||||
Filters.Subscriptions.TYPES, false, null)
|
||||
}
|
||||
|
||||
private fun migrateLegacyAccounts(db: SQLiteDatabase) {
|
||||
val accountsAlias = HashMap<String, String>()
|
||||
accountsAlias.put(Accounts.SCREEN_NAME, "username")
|
||||
accountsAlias.put(Accounts.NAME, "username")
|
||||
accountsAlias.put(Accounts.ACCOUNT_KEY, "user_id")
|
||||
accountsAlias.put(Accounts.COLOR, "user_color")
|
||||
accountsAlias.put(Accounts.OAUTH_TOKEN_SECRET, "token_secret")
|
||||
accountsAlias.put(Accounts.API_URL_FORMAT, "rest_base_url")
|
||||
safeUpgrade(db, Accounts.TABLE_NAME, Accounts.COLUMNS, Accounts.TYPES, false, accountsAlias)
|
||||
}
|
||||
|
||||
private fun migrateFilteredUsers(db: SQLiteDatabase) {
|
||||
db.execSQL(SQLQueryBuilder.update(OnConflict.REPLACE, Filters.Users.TABLE_NAME)
|
||||
.set(SetValue(Filters.Users.USER_KEY, RawSQLLang(Filters.Users.USER_KEY + "||?")))
|
||||
.where(Expression.notLikeArgs(Column(Filters.Users.USER_KEY)))
|
||||
.buildSQL(),
|
||||
arrayOf<Any>("@twitter.com", "%@%"))
|
||||
}
|
||||
|
||||
private fun createTable(tableName: String, columns: Array<String>, types: Array<String>,
|
||||
createIfNotExists: Boolean, vararg constraints: Constraint): String {
|
||||
val qb = SQLQueryBuilder.createTable(createIfNotExists, tableName)
|
||||
qb.columns(*NewColumn.createNewColumns(columns, types))
|
||||
qb.constraint(*constraints)
|
||||
return qb.buildSQL()
|
||||
}
|
||||
|
||||
private fun createIndex(indexName: String, tableName: String, columns: Array<String>,
|
||||
createIfNotExists: Boolean): String {
|
||||
val qb = SQLQueryBuilder.createIndex(false, createIfNotExists)
|
||||
qb.name(indexName)
|
||||
qb.on(Table(tableName), Columns(*columns))
|
||||
return qb.buildSQL()
|
||||
}
|
||||
|
||||
}
|
|
@ -47,6 +47,7 @@ import org.mariotaku.restfu.http.RestHttpClient
|
|||
import org.mariotaku.twidere.BuildConfig
|
||||
import org.mariotaku.twidere.Constants
|
||||
import org.mariotaku.twidere.constant.SharedPreferenceConstants
|
||||
import org.mariotaku.twidere.constant.SharedPreferenceConstants.KEY_CACHE_SIZE_LIMIT
|
||||
import org.mariotaku.twidere.model.DefaultFeatures
|
||||
import org.mariotaku.twidere.util.*
|
||||
import org.mariotaku.twidere.util.imageloader.ReadOnlyDiskLRUNameCache
|
||||
|
@ -310,7 +311,7 @@ class ApplicationModule(private val application: Application) {
|
|||
val cacheDir = Utils.getExternalCacheDir(application, dirName)
|
||||
val fallbackCacheDir = Utils.getInternalCacheDir(application, dirName)
|
||||
val fileNameGenerator = URLFileNameGenerator()
|
||||
val cacheSize = TwidereMathUtils.clamp(preferences.getInt(SharedPreferenceConstants.KEY_CACHE_SIZE_LIMIT, 300), 100, 500)
|
||||
val cacheSize = preferences.getInt(KEY_CACHE_SIZE_LIMIT, 300).coerceIn(100..500)
|
||||
try {
|
||||
val cacheMaxSizeBytes = cacheSize * 1024 * 1024
|
||||
if (cacheDir != null)
|
||||
|
|
|
@ -17,25 +17,19 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.util.view;
|
||||
package org.mariotaku.twidere.util.view
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import com.rengwuxian.materialedittext.validation.METValidator
|
||||
|
||||
import com.rengwuxian.materialedittext.validation.METValidator;
|
||||
|
||||
import org.mariotaku.twidere.util.MicroBlogAPIFactory;
|
||||
import org.mariotaku.twidere.util.MicroBlogAPIFactory
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 15/9/3.
|
||||
*/
|
||||
public class ConsumerKeySecretValidator extends METValidator {
|
||||
public ConsumerKeySecretValidator(String errorMessage) {
|
||||
super(errorMessage);
|
||||
}
|
||||
class ConsumerKeySecretValidator(errorMessage: String) : METValidator(errorMessage) {
|
||||
|
||||
@Override
|
||||
public boolean isValid(@NonNull CharSequence text, boolean isEmpty) {
|
||||
return MicroBlogAPIFactory.isValidConsumerKeySecret(text);
|
||||
override fun isValid(text: CharSequence, isEmpty: Boolean): Boolean {
|
||||
return MicroBlogAPIFactory.isValidConsumerKeySecret(text)
|
||||
}
|
||||
|
||||
}
|
|
@ -9,6 +9,7 @@ import android.view.MotionEvent
|
|||
import android.view.View
|
||||
import android.view.ViewConfiguration
|
||||
import android.view.ViewGroup
|
||||
import org.mariotaku.ktextension.coerceInOr
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2017/1/29.
|
||||
|
@ -34,7 +35,7 @@ class MediaSwipeCloseContainer(context: Context, attrs: AttributeSet? = null) :
|
|||
|
||||
override fun clampViewPositionVertical(child: View, top: Int, dy: Int): Int {
|
||||
val container = this@MediaSwipeCloseContainer
|
||||
return top.coerceIn(-container.height, container.height)
|
||||
return top.coerceInOr(-container.height..container.height, 0)
|
||||
}
|
||||
|
||||
override fun getViewVerticalDragRange(child: View?): Int {
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
android:paddingLeft="@dimen/element_spacing_normal"
|
||||
android:paddingRight="0dp"
|
||||
android:paddingStart="@dimen/element_spacing_normal"
|
||||
tools:showIn="@layout/layout_api_editor">
|
||||
tools:showIn="@layout/dialog_api_editor">
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/editSameOAuthSigningUrl"
|
||||
|
|
Loading…
Reference in New Issue