fixed open original status triggers loads translation
added proxy auth and socks support
This commit is contained in:
Mariotaku Lee 2015-12-30 19:34:40 +08:00
parent 0db5471e03
commit cdd3cceb13
28 changed files with 502 additions and 108 deletions

View File

@ -0,0 +1,47 @@
/*
* 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.api.twitter;
import android.support.annotation.NonNull;
import org.mariotaku.restfu.annotation.method.GET;
import org.mariotaku.restfu.annotation.method.POST;
import org.mariotaku.restfu.annotation.param.Form;
import org.mariotaku.restfu.annotation.param.Query;
import org.mariotaku.twidere.api.twitter.model.CardEntity;
import org.mariotaku.twidere.api.twitter.model.CreateCardData;
import org.mariotaku.twidere.api.twitter.model.CreateCardResult;
/**
* Card API maybe??
* Host is caps.twitter.com
* Created by mariotaku on 15/12/30.
*/
public interface TwitterCaps {
@GET("/v2/capi/passthrough/1")
CardEntity getCard(@NonNull @Query("twitter:string:card_uri") String cardUri,
@NonNull @Query("twitter:string:cards_platform") String cardsPlatform,
@NonNull @Query("twitter:string:response_card_name") String responseCardName)
throws TwitterException;
@POST("/v2/cards/create.json")
CreateCardResult createCard(@Form("card_data") CreateCardData cardData) throws TwitterException;
}

View File

@ -24,8 +24,10 @@ import org.mariotaku.restfu.annotation.param.MethodExtra;
import org.mariotaku.restfu.annotation.param.Query;
import org.mariotaku.twidere.api.twitter.TwitterException;
import org.mariotaku.twidere.api.twitter.model.Activity;
import org.mariotaku.twidere.api.twitter.model.CursorResponse;
import org.mariotaku.twidere.api.twitter.model.Paging;
import org.mariotaku.twidere.api.twitter.model.ResponseList;
import org.mariotaku.twidere.api.twitter.model.TimestampResponse;
@SuppressWarnings("RedundantThrows")
@MethodExtra(name = "extra_params", values = {"include_my_retweet", "include_rts", "include_entities",
@ -36,6 +38,14 @@ public interface PrivateActivityResources extends PrivateResources {
@GET("/activity/about_me.json")
ResponseList<Activity> getActivitiesAboutMe(@Query Paging paging) throws TwitterException;
@GET("/activity/about_me/unread.json?cursor=true")
CursorResponse getActivitiesAboutMeUnreadCursor() throws TwitterException;
@GET("/activity/about_me/unread.json?cursor=false")
TimestampResponse getActivitiesAboutMeUnreadTimestamp() throws TwitterException;
@GET("/activity/by_friends.json")
ResponseList<Activity> getActivitiesByFriends(@Query Paging paging) throws TwitterException;
}

View File

@ -0,0 +1,69 @@
/*
* 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.api.twitter.model;
import com.bluelinelabs.logansquare.LoganSquare;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* Example
* <pre>
* {@code
* CreateCardData cardData = new CreateCardData("poll2choice_text_only");
* cardData.putString("choice1_label", "Label 1");
* cardData.putString("choice2_label", "Label 2");
* }
* </pre>
* Created by mariotaku on 15/12/30.
*/
public class CreateCardData {
private final Map<String, String> map = new LinkedHashMap<>();
public CreateCardData(String name) {
this(name, "1");
}
public CreateCardData(String name, String endpoint) {
map.put("twitter:card", name);
map.put("twitter:api:api:endpoint", endpoint);
}
public void putString(String key, String value) {
map.put("twitter:string:" + key, value);
}
public void putLong(String key, long value) {
map.put("twitter:long:" + key, String.valueOf(value));
}
@Override
public String toString() {
try {
return LoganSquare.serialize(map);
} catch (IOException e) {
throw new AssertionError(e);
}
}
}

View File

@ -0,0 +1,42 @@
/*
* 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.api.twitter.model;
import com.bluelinelabs.logansquare.annotation.JsonField;
import com.bluelinelabs.logansquare.annotation.JsonObject;
/**
* Created by mariotaku on 15/12/30.
*/
@JsonObject
public class CreateCardResult {
@JsonField(name = "card_uri")
String cardUri;
@JsonField(name = "status")
String status;
public String getCardUri() {
return cardUri;
}
public String getStatus() {
return status;
}
}

View File

@ -0,0 +1,36 @@
/*
* 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.api.twitter.model;
import com.bluelinelabs.logansquare.annotation.JsonField;
import com.bluelinelabs.logansquare.annotation.JsonObject;
/**
* Created by mariotaku on 15/12/30.
*/
@JsonObject
public class CursorResponse {
@JsonField(name = "cursor")
long cursor;
public long getCursor() {
return cursor;
}
}

View File

@ -0,0 +1,36 @@
/*
* 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.api.twitter.model;
import com.bluelinelabs.logansquare.annotation.JsonField;
import com.bluelinelabs.logansquare.annotation.JsonObject;
/**
* Created by mariotaku on 15/12/30.
*/
@JsonObject
public class TimestampResponse {
@JsonField(name = "timestamp")
long timestamp;
public long getTimestamp() {
return timestamp;
}
}

View File

@ -166,7 +166,13 @@ public interface SharedPreferenceConstants {
@Preference(type = STRING)
String KEY_PROXY_HOST = "proxy_host";
@Preference(type = STRING)
String KEY_PROXY_TYPE = "proxy_type";
@Preference(type = STRING)
String KEY_PROXY_PORT = "proxy_port";
@Preference(type = STRING)
String KEY_PROXY_USERNAME = "proxy_username";
@Preference(type = STRING)
String KEY_PROXY_PASSWORD = "proxy_password";
@Preference(type = BOOLEAN)
String KEY_REFRESH_ON_START = "refresh_on_start";
@Preference(type = BOOLEAN)

3
twidere/.gitignore vendored
View File

@ -1 +1,2 @@
/build
/build
fabric.properties

View File

@ -65,7 +65,7 @@ import org.mariotaku.twidere.preference.WizardPageNavPreference;
import org.mariotaku.twidere.provider.TwidereDataStore.Tabs;
import org.mariotaku.twidere.util.AsyncTaskUtils;
import org.mariotaku.twidere.util.CustomTabUtils;
import org.mariotaku.twidere.util.MathUtils;
import org.mariotaku.twidere.util.TwidereMathUtils;
import org.mariotaku.twidere.util.ParseUtils;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.view.LinePageIndicator;
@ -128,7 +128,7 @@ public class SettingsWizardActivity extends Activity implements Constants {
public void gotoNextPage() {
if (mViewPager == null || mAdapter == null) return;
final int current = mViewPager.getCurrentItem();
mViewPager.setCurrentItem(MathUtils.clamp(current + 1, mAdapter.getCount() - 1, 0));
mViewPager.setCurrentItem(TwidereMathUtils.clamp(current + 1, mAdapter.getCount() - 1, 0));
}
@Override
@ -629,7 +629,7 @@ public class SettingsWizardActivity extends Activity implements Constants {
}
private void gotoPage(int page) {
mViewPager.setCurrentItem(MathUtils.clamp(page, 0, getPageCount() - 1));
mViewPager.setCurrentItem(TwidereMathUtils.clamp(page, 0, getPageCount() - 1));
}
private int getPageCount() {

View File

@ -89,7 +89,7 @@ import org.mariotaku.twidere.util.CustomTabUtils;
import org.mariotaku.twidere.util.DataStoreUtils;
import org.mariotaku.twidere.util.KeyboardShortcutsHandler;
import org.mariotaku.twidere.util.KeyboardShortcutsHandler.KeyboardShortcutCallback;
import org.mariotaku.twidere.util.MathUtils;
import org.mariotaku.twidere.util.TwidereMathUtils;
import org.mariotaku.twidere.util.MultiSelectEventHandler;
import org.mariotaku.twidere.util.ReadStateManager;
import org.mariotaku.twidere.util.ThemeUtils;
@ -569,7 +569,7 @@ public class HomeActivity extends BaseAppCompatActivity implements OnClickListen
protected void onNewIntent(final Intent intent) {
final int tabPosition = handleIntent(intent, false);
if (tabPosition >= 0) {
mViewPager.setCurrentItem(MathUtils.clamp(tabPosition, mPagerAdapter.getCount(), 0));
mViewPager.setCurrentItem(TwidereMathUtils.clamp(tabPosition, mPagerAdapter.getCount(), 0));
}
}
@ -764,10 +764,10 @@ public class HomeActivity extends BaseAppCompatActivity implements OnClickListen
private void setTabPosition(final int initialTab) {
final boolean rememberPosition = mPreferences.getBoolean(KEY_REMEMBER_POSITION, true);
if (initialTab >= 0) {
mViewPager.setCurrentItem(MathUtils.clamp(initialTab, mPagerAdapter.getCount(), 0));
mViewPager.setCurrentItem(TwidereMathUtils.clamp(initialTab, mPagerAdapter.getCount(), 0));
} else if (rememberPosition) {
final int position = mPreferences.getInt(KEY_SAVED_TAB_POSITION, 0);
mViewPager.setCurrentItem(MathUtils.clamp(position, mPagerAdapter.getCount(), 0));
mViewPager.setCurrentItem(TwidereMathUtils.clamp(position, mPagerAdapter.getCount(), 0));
}
}

View File

@ -90,6 +90,7 @@ import org.mariotaku.twidere.util.KeyboardShortcutsHandler;
import org.mariotaku.twidere.util.MenuUtils;
import org.mariotaku.twidere.util.PermissionUtils;
import org.mariotaku.twidere.util.ThemeUtils;
import org.mariotaku.twidere.util.TwitterCardFragmentFactory;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.util.VideoLoader.VideoLoadingListener;
@ -606,13 +607,17 @@ public final class MediaViewerActivity extends BaseAppCompatActivity implements
case ParcelableMedia.TYPE_VIDEO: {
return Fragment.instantiate(mActivity, VideoPageFragment.class.getName(), args);
}
default: {
case ParcelableMedia.TYPE_IMAGE: {
if (ANIMATED_GIF_SUPPORTED) {
return Fragment.instantiate(mActivity, ImagePageFragment.class.getName(), args);
}
return Fragment.instantiate(mActivity, BaseImagePageFragment.class.getName(), args);
}
case ParcelableMedia.TYPE_EXTERNAL_PLAYER: {
return TwitterCardFragmentFactory.createGenericPlayerFragment(media.card);
}
}
return new UnsupportedPageFragment();
}
public void setMedia(long accountId, ParcelableMedia[] media) {
@ -620,6 +625,10 @@ public final class MediaViewerActivity extends BaseAppCompatActivity implements
mMedia = media;
notifyDataSetChanged();
}
}
public static class UnsupportedPageFragment extends Fragment {
}
private static abstract class AbsMediaPageFragment extends BaseSupportFragment {
@ -629,7 +638,8 @@ public final class MediaViewerActivity extends BaseAppCompatActivity implements
} else {
final String[] permissions;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
permissions = new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE};
permissions = new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE};
} else {
permissions = new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE};
}

View File

@ -49,7 +49,7 @@ import org.mariotaku.twidere.service.RefreshService;
import org.mariotaku.twidere.util.BugReporter;
import org.mariotaku.twidere.util.DebugModeUtils;
import org.mariotaku.twidere.util.ExternalThemeManager;
import org.mariotaku.twidere.util.MathUtils;
import org.mariotaku.twidere.util.TwidereMathUtils;
import org.mariotaku.twidere.util.StrictModeUtils;
import org.mariotaku.twidere.util.TwidereBugReporter;
import org.mariotaku.twidere.util.Utils;
@ -273,7 +273,7 @@ public class TwidereApplication extends MultiDexApplication implements Constants
final File fallbackCacheDir = getInternalCacheDir(this, dirName);
final URLFileNameGenerator fileNameGenerator = new URLFileNameGenerator();
final SharedPreferences preferences = getSharedPreferences();
final int cacheSize = MathUtils.clamp(preferences.getInt(KEY_CACHE_SIZE_LIMIT, 300), 100, 500);
final int cacheSize = TwidereMathUtils.clamp(preferences.getInt(KEY_CACHE_SIZE_LIMIT, 300), 100, 500);
try {
final int cacheMaxSizeBytes = cacheSize * 1024 * 1024;
if (cacheDir != null)

View File

@ -116,7 +116,6 @@ import org.mariotaku.twidere.util.HtmlSpanBuilder;
import org.mariotaku.twidere.util.KeyboardShortcutsHandler;
import org.mariotaku.twidere.util.KeyboardShortcutsHandler.KeyboardShortcutCallback;
import org.mariotaku.twidere.util.LinkCreator;
import org.mariotaku.twidere.util.MathUtils;
import org.mariotaku.twidere.util.MediaLoaderWrapper;
import org.mariotaku.twidere.util.MediaLoadingHandler;
import org.mariotaku.twidere.util.MenuUtils;
@ -129,6 +128,7 @@ import org.mariotaku.twidere.util.StatusAdapterLinkClickHandler;
import org.mariotaku.twidere.util.StatusLinkClickHandler;
import org.mariotaku.twidere.util.ThemeUtils;
import org.mariotaku.twidere.util.TwidereLinkify;
import org.mariotaku.twidere.util.TwidereMathUtils;
import org.mariotaku.twidere.util.TwitterAPIFactory;
import org.mariotaku.twidere.util.TwitterCardUtils;
import org.mariotaku.twidere.util.UserColorNameManager;
@ -1268,6 +1268,7 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
}
case R.id.quote_original_link: {
Utils.openStatus(adapter.getContext(), status.account_id, status.quoted_id);
break;
}
case R.id.translate_label: {
fragment.loadTranslation(adapter.getStatus());
@ -1899,7 +1900,7 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
@Override
public int getItemCount() {
if (mStatus == null) return 0;
return MathUtils.sum(mItemCounts);
return TwidereMathUtils.sum(mItemCounts);
}
@Override

View File

@ -121,7 +121,7 @@ import org.mariotaku.twidere.util.HtmlSpanBuilder;
import org.mariotaku.twidere.util.KeyboardShortcutsHandler;
import org.mariotaku.twidere.util.KeyboardShortcutsHandler.KeyboardShortcutCallback;
import org.mariotaku.twidere.util.LinkCreator;
import org.mariotaku.twidere.util.MathUtils;
import org.mariotaku.twidere.util.TwidereMathUtils;
import org.mariotaku.twidere.util.MenuUtils;
import org.mariotaku.twidere.util.ParseUtils;
import org.mariotaku.twidere.util.ThemeUtils;
@ -1505,7 +1505,7 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
final View profileBirthdayBannerView = mProfileBirthdayBannerView;
final View profileBannerContainer = mProfileBannerContainer;
final int spaceHeight = space.getHeight();
final float factor = MathUtils.clamp(spaceHeight == 0 ? 0 : (offset / (float) spaceHeight), 0, 1);
final float factor = TwidereMathUtils.clamp(spaceHeight == 0 ? 0 : (offset / (float) spaceHeight), 0, 1);
// profileBannerContainer.setTranslationY(Math.max(-offset, -spaceHeight));
// profileBannerView.setTranslationY(Math.min(offset, spaceHeight) / 2);
profileBannerContainer.setTranslationY(-offset);
@ -1519,7 +1519,7 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
final float profileContentHeight = mProfileNameContainer.getHeight() + mProfileDetailsContainer.getHeight();
final float tabOutlineAlphaFactor;
if ((offset - spaceHeight) > 0) {
tabOutlineAlphaFactor = 1f - MathUtils.clamp((offset - spaceHeight) / profileContentHeight, 0, 1);
tabOutlineAlphaFactor = 1f - TwidereMathUtils.clamp((offset - spaceHeight) / profileContentHeight, 0, 1);
} else {
tabOutlineAlphaFactor = 1f;
}
@ -1586,7 +1586,7 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
mNameView.getLocationInWindow(location);
final float nameShowingRatio = (mHeaderDrawerLayout.getPaddingTop() - location[1])
/ (float) mNameView.getHeight();
final float textAlpha = MathUtils.clamp(nameShowingRatio, 0, 1);
final float textAlpha = TwidereMathUtils.clamp(nameShowingRatio, 0, 1);
final ThemedAppCompatActivity activity = (ThemedAppCompatActivity) getActivity();
final Toolbar actionBarView = activity.getActionBarToolbar();
if (actionBarView != null) {
@ -1654,9 +1654,9 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
public void setFactor(float f) {
mFactor = f;
mShadowDrawable.setAlpha(Math.round(mAlpha * MathUtils.clamp(1 - f, 0, 1)));
mShadowDrawable.setAlpha(Math.round(mAlpha * TwidereMathUtils.clamp(1 - f, 0, 1)));
final boolean hasColor = mColor != 0;
mColorDrawable.setAlpha(hasColor ? Math.round(mAlpha * MathUtils.clamp(f, 0, 1)) : 0);
mColorDrawable.setAlpha(hasColor ? Math.round(mAlpha * TwidereMathUtils.clamp(f, 0, 1)) : 0);
}
public void setOutlineAlphaFactor(float f) {

View File

@ -27,7 +27,7 @@ import org.mariotaku.sqliteqb.library.Columns;
import org.mariotaku.sqliteqb.library.Expression;
import org.mariotaku.sqliteqb.library.RawItemArray;
import org.mariotaku.twidere.provider.TwidereDataStore.NetworkUsages;
import org.mariotaku.twidere.util.MathUtils;
import org.mariotaku.twidere.util.TwidereMathUtils;
import java.util.Date;
import java.util.concurrent.TimeUnit;
@ -90,7 +90,7 @@ public class NetworkUsageInfo {
double dayUsageMax = 0;
for (int i = 0; i < days; i++) {
final double[] dayUsage = chartUsage[i];
dayUsageMax = Math.max(dayUsageMax, MathUtils.sum(dayUsage));
dayUsageMax = Math.max(dayUsageMax, TwidereMathUtils.sum(dayUsage));
}
return new NetworkUsageInfo(chartUsage, usageTotal, totalReceived, totalSent, dayUsageMax, dayMin, dayMax);

View File

@ -36,7 +36,7 @@ import com.desmond.asyncmanager.TaskRunnable;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.model.NetworkUsageInfo;
import org.mariotaku.twidere.model.RequestType;
import org.mariotaku.twidere.util.MathUtils;
import org.mariotaku.twidere.util.TwidereMathUtils;
import org.mariotaku.twidere.util.Utils;
import java.util.Calendar;
@ -136,7 +136,7 @@ public class NetworkUsageSummaryPreferences extends Preference {
apiSet.addBar(day, (float) dayUsage[RequestType.API.getValue()]);
mediaSet.addBar(day, (float) dayUsage[RequestType.MEDIA.getValue()]);
usageStatisticsSet.addBar(day, (float) dayUsage[RequestType.USAGE_STATISTICS.getValue()]);
dayUsageMax = Math.max(dayUsageMax, MathUtils.sum(dayUsage));
dayUsageMax = Math.max(dayUsageMax, TwidereMathUtils.sum(dayUsage));
}
apiSet.setColor(Color.RED);

View File

@ -40,7 +40,7 @@ public class BitmapUtils {
public static int computeSampleSize(final float scale) {
if (scale <= 0) return 1;
final int initialSize = Math.max(1, (int) Math.ceil(1 / scale));
return initialSize <= 8 ? MathUtils.nextPowerOf2(initialSize) : (initialSize + 7) / 8 * 8;
return initialSize <= 8 ? TwidereMathUtils.nextPowerOf2(initialSize) : (initialSize + 7) / 8 * 8;
}
// This computes a sample size which makes the longer side at least
@ -49,7 +49,7 @@ public class BitmapUtils {
final int initialSize = Math.max(w / minSideLength, h / minSideLength);
if (initialSize <= 1) return 1;
return initialSize <= 8 ? MathUtils.prevPowerOf2(initialSize) : initialSize / 8 * 8;
return initialSize <= 8 ? TwidereMathUtils.prevPowerOf2(initialSize) : initialSize / 8 * 8;
}
public static boolean downscaleImageIfNeeded(final File imageFile, final int quality) {

View File

@ -135,23 +135,19 @@ public class EmojiSupportUtils {
}
private static boolean isPhoneNumberSymbol(int codePoint) {
return codePoint == 0x0023 || codePoint == 0x002a || inRange(codePoint, 0x0030, 0x0039);
return codePoint == 0x0023 || codePoint == 0x002a || TwidereMathUtils.inRangeInclusiveInclusive(codePoint, 0x0030, 0x0039);
}
private static boolean isModifier(int codePoint) {
return inRange(codePoint, 0x1f3fb, 0x1f3ff);
return TwidereMathUtils.inRangeInclusiveInclusive(codePoint, 0x1f3fb, 0x1f3ff);
}
private static boolean isEmoji(int codePoint) {
return !Character.isLetterOrDigit(codePoint);
}
private static boolean inRange(int codePoint, int from, int to) {
return codePoint >= from && codePoint <= to;
}
private static boolean isRegionalIndicatorSymbol(int codePoint) {
return inRange(codePoint, 0x1f1e6, 0x1f1ff);
return TwidereMathUtils.inRangeInclusiveInclusive(codePoint, 0x1f1e6, 0x1f1ff);
}
private static boolean isKeyCap(int codePoint) {

View File

@ -649,9 +649,9 @@ public class ThemeUtils implements Constants {
final float[] hsv = new float[3];
Color.colorToHSV(themeColor, hsv);
if (isDarkTheme(context)) {
hsv[2] = MathUtils.clamp(hsv[2], 1, 0.5f);
hsv[2] = TwidereMathUtils.clamp(hsv[2], 1, 0.5f);
} else {
hsv[2] = MathUtils.clamp(hsv[2], 0.1f, 0.75f);
hsv[2] = TwidereMathUtils.clamp(hsv[2], 0.1f, 0.75f);
}
return Color.HSVToColor(hsv);
}
@ -659,14 +659,14 @@ public class ThemeUtils implements Constants {
public static int getUserThemeBackgroundAlpha(final Context context) {
if (context == null) return DEFAULT_THEME_BACKGROUND_ALPHA;
final SharedPreferencesWrapper pref = getSharedPreferencesWrapper(context);
return MathUtils.clamp(pref.getInt(KEY_THEME_BACKGROUND_ALPHA, DEFAULT_THEME_BACKGROUND_ALPHA),
return TwidereMathUtils.clamp(pref.getInt(KEY_THEME_BACKGROUND_ALPHA, DEFAULT_THEME_BACKGROUND_ALPHA),
ThemeBackgroundPreference.MIN_ALPHA, ThemeBackgroundPreference.MAX_ALPHA);
}
public static int getActionBarAlpha(final int alpha) {
final int normalizedAlpha = MathUtils.clamp(alpha, 0, 0xFF);
final int normalizedAlpha = TwidereMathUtils.clamp(alpha, 0, 0xFF);
final int delta = (ThemeBackgroundPreference.MAX_ALPHA - normalizedAlpha);
return MathUtils.clamp(ThemeBackgroundPreference.MAX_ALPHA - delta / 2,
return TwidereMathUtils.clamp(ThemeBackgroundPreference.MAX_ALPHA - delta / 2,
ThemeBackgroundPreference.MIN_ALPHA, ThemeBackgroundPreference.MAX_ALPHA);
}
@ -719,7 +719,7 @@ public class ThemeUtils implements Constants {
a.recycle();
if (d == null) return null;
d.mutate();
d.setAlpha(MathUtils.clamp(alpha, ThemeBackgroundPreference.MIN_ALPHA,
d.setAlpha(TwidereMathUtils.clamp(alpha, ThemeBackgroundPreference.MIN_ALPHA,
ThemeBackgroundPreference.MAX_ALPHA));
return d;
}

View File

@ -91,9 +91,9 @@ public class TwidereColorUtils {
public static int YIQToColor(int alpha, int[] yiq) {
final int r = MathUtils.clamp((yiq[0] * 1000 + yiq[1] * 956 + yiq[2] * 620) / 1000, 0, 255);
final int g = MathUtils.clamp((yiq[0] * 1000 - yiq[1] * 272 - yiq[2] * 647) / 1000, 0, 255);
final int b = MathUtils.clamp((yiq[0] * 1000 - yiq[1] * 1108 + yiq[2] * 1705) / 1000, 0, 255);
final int r = TwidereMathUtils.clamp((yiq[0] * 1000 + yiq[1] * 956 + yiq[2] * 620) / 1000, 0, 255);
final int g = TwidereMathUtils.clamp((yiq[0] * 1000 - yiq[1] * 272 - yiq[2] * 647) / 1000, 0, 255);
final int b = TwidereMathUtils.clamp((yiq[0] * 1000 - yiq[1] * 1108 + yiq[2] * 1705) / 1000, 0, 255);
return Color.argb(alpha, r, g, b);
}

View File

@ -19,7 +19,7 @@
package org.mariotaku.twidere.util;
public class MathUtils {
public class 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);
@ -68,4 +68,8 @@ public class MathUtils {
}
return sum;
}
public static boolean inRangeInclusiveInclusive(int num, int from, int to) {
return num >= from && num <= to;
}
}

View File

@ -7,14 +7,19 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.SSLCertificateSocketFactory;
import android.os.Build;
import android.os.Looper;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.WorkerThread;
import android.text.TextUtils;
import android.webkit.URLUtil;
import com.squareup.okhttp.Authenticator;
import com.squareup.okhttp.Credentials;
import com.squareup.okhttp.Dns;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.Response;
import org.apache.commons.lang3.math.NumberUtils;
import org.mariotaku.restfu.ExceptionFactory;
@ -54,9 +59,13 @@ import org.mariotaku.twidere.model.RequestType;
import org.mariotaku.twidere.util.dagger.ApplicationModule;
import org.mariotaku.twidere.util.net.NetworkUsageUtils;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.ProxySelector;
import java.net.SocketAddress;
import java.net.URI;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
@ -157,23 +166,53 @@ public class TwitterAPIFactory implements TwidereConstants {
client.setSslSocketFactory(null);
}
if (enableProxy) {
client.setProxy(getProxy(prefs));
final String proxyType = prefs.getString(KEY_PROXY_TYPE, null);
final String proxyHost = prefs.getString(KEY_PROXY_HOST, null);
final int proxyPort = NumberUtils.toInt(prefs.getString(KEY_PROXY_PORT, null), -1);
if (!isEmpty(proxyHost) && TwidereMathUtils.inRangeInclusiveInclusive(proxyPort, 0, 65535)) {
client.setProxySelector(new TwidereProxySelector(client.getDns(),
getProxyType(proxyType), proxyHost, proxyPort));
}
final String username = prefs.getString(KEY_PROXY_USERNAME, null);
final String password = prefs.getString(KEY_PROXY_PASSWORD, null);
client.setAuthenticator(new Authenticator() {
@Override
public Request authenticate(Proxy proxy, Response response) throws IOException {
return null;
}
@Override
public Request authenticateProxy(Proxy proxy, Response response) throws IOException {
final Request.Builder builder = response.request().newBuilder();
if (!TextUtils.isEmpty(username) && !TextUtils.isEmpty(password)) {
final String credential = Credentials.basic(username, password);
builder.header("Proxy-Authorization", credential);
}
return builder.build();
}
});
} else {
client.setProxy(null);
client.setProxySelector(ProxySelector.getDefault());
}
}
public static Proxy getProxy(final SharedPreferences prefs) {
final String proxyType = prefs.getString(KEY_PROXY_TYPE, null);
final String proxyHost = prefs.getString(KEY_PROXY_HOST, null);
final int proxyPort = NumberUtils.toInt(prefs.getString(KEY_PROXY_PORT, "-1"), -1);
if (!isEmpty(proxyHost) && proxyPort >= 0 && proxyPort < 65535) {
final int proxyPort = NumberUtils.toInt(prefs.getString(KEY_PROXY_PORT, null), -1);
if (!isEmpty(proxyHost) && TwidereMathUtils.inRangeInclusiveInclusive(proxyPort, 0, 65535)) {
final SocketAddress addr = InetSocketAddress.createUnresolved(proxyHost, proxyPort);
return new Proxy(Proxy.Type.HTTP, addr);
return new Proxy(getProxyType(proxyType), addr);
}
return Proxy.NO_PROXY;
}
private static Proxy.Type getProxyType(String proxyType) {
if ("socks".equalsIgnoreCase(proxyType)) return Proxy.Type.SOCKS;
return Proxy.Type.HTTP;
}
@WorkerThread
public static <T> T getInstance(final Context context, final Endpoint endpoint,
final Authorization auth, final Map<String, String> extraRequestParams,
@ -535,4 +574,47 @@ public class TwitterAPIFactory implements TwidereConstants {
}
}
private static class TwidereProxySelector extends ProxySelector {
private final Dns dns;
private final Proxy.Type type;
private final String host;
private final int port;
private List<Proxy> proxy;
public TwidereProxySelector(Dns dns, Proxy.Type type, String host, int port) {
this.dns = dns;
this.type = type;
this.host = host;
this.port = port;
}
@Override
public List<Proxy> select(URI uri) {
if (proxy != null) return proxy;
final InetSocketAddress unresolved;
if (Looper.myLooper() != Looper.getMainLooper()) {
unresolved = createResolved(host, port);
} else {
unresolved = InetSocketAddress.createUnresolved(host, port);
}
return proxy = Collections.singletonList(new Proxy(type, unresolved));
}
private InetSocketAddress createResolved(String host, int port) {
try {
//noinspection LoopStatementThatDoesntLoop
for (InetAddress inetAddress : dns.lookup(host)) {
return new InetSocketAddress(inetAddress, port);
}
} catch (IOException e) {
return InetSocketAddress.createUnresolved(host, port);
}
return InetSocketAddress.createUnresolved(host, port);
}
@Override
public void connectFailed(URI uri, SocketAddress address, IOException failure) {
}
}
}

View File

@ -36,7 +36,7 @@ import android.view.View;
import android.view.ViewGroup;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.util.MathUtils;
import org.mariotaku.twidere.util.TwidereMathUtils;
/**
* Custom ViewGroup for user profile page like Google+ but with tab swipe
@ -258,7 +258,7 @@ public class HeaderDrawerLayout extends ViewGroup {
private void offsetHeaderBy(int dy) {
final int prevTop = mContainer.getTop();
final int clampedDy = MathUtils.clamp(prevTop + dy, getHeaderTopMinimum(), getHeaderTopMaximum()) - prevTop;
final int clampedDy = TwidereMathUtils.clamp(prevTop + dy, getHeaderTopMinimum(), getHeaderTopMaximum()) - prevTop;
mContainer.offsetTopAndBottom(clampedDy);
}
@ -406,7 +406,7 @@ public class HeaderDrawerLayout extends ViewGroup {
mDrawer.scrollByCallback(-dy);
}
mScrollingHeaderByHelper = true;
return MathUtils.clamp(top, min, max);
return TwidereMathUtils.clamp(top, min, max);
}
private boolean isScrollingHeaderByHelper() {

View File

@ -29,7 +29,7 @@ import android.support.annotation.NonNull;
import android.util.AttributeSet;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.util.MathUtils;
import org.mariotaku.twidere.util.TwidereMathUtils;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.view.iface.TintedStatusLayout;
@ -145,8 +145,8 @@ public class TintedStatusFrameLayout extends ExtendedFrameLayout implements Tint
private void updateAlpha() {
final float f = mFactor;
mShadowPaint.setAlpha(Math.round(mShadowAlpha * MathUtils.clamp(1 - f, 0, 1)));
mColorPaint.setAlpha(Math.round(mColorAlpha * MathUtils.clamp(f, 0, 1)));
mShadowPaint.setAlpha(Math.round(mShadowAlpha * TwidereMathUtils.clamp(1 - f, 0, 1)));
mColorPaint.setAlpha(Math.round(mColorAlpha * TwidereMathUtils.clamp(f, 0, 1)));
invalidate();
}
}

View File

@ -11,16 +11,6 @@
<item>@string/item_2_hours</item>
<item>@string/item_4_hours</item>
</string-array>
<string-array name="values_refresh_interval">
<item>3</item>
<item>5</item>
<item>10</item>
<item>15</item>
<item>30</item>
<item>60</item>
<item>120</item>
<item>240</item>
</string-array>
<string-array name="entries_auto_refresh_content">
<item>@string/home</item>
<item>@string/mentions</item>
@ -45,31 +35,11 @@
<item>@string/theme_light</item>
<item>@string/theme_dark</item>
</string-array>
<string-array name="values_theme">
<item>light</item>
<item>dark</item>
</string-array>
<string-array name="values_theme_background">
<item>default</item>
<item>solid</item>
<item>transparent</item>
</string-array>
<string-array name="entries_theme_background">
<item>@string/theme_background_default</item>
<item>@string/theme_background_solid</item>
<item>@string/theme_background_transparent</item>
</string-array>
<string-array name="dependency_values_true">
<item>true</item>
</string-array>
<string-array name="dependency_values_false">
<item>false</item>
</string-array>
<string-array name="values_tab_display_option">
<item>icon</item>
<item>label</item>
<item>both</item>
</string-array>
<string-array name="entries_tab_display_option">
<item>@string/tab_display_option_icon</item>
<item>@string/tab_display_option_label</item>
@ -85,20 +55,11 @@
<item>@string/user_colors</item>
<item>@string/custom_host_mapping</item>
</string-array>
<string-array name="values_compose_now_action">
<item>compose</item>
<item>take_photo</item>
<item>pick_image</item>
</string-array>
<string-array name="entries_compose_now_action">
<item>@string/compose</item>
<item>@string/take_photo</item>
<item>@string/add_image</item>
</string-array>
<string-array name="values_media_preview_style">
<item>crop</item>
<item>scale</item>
</string-array>
<string-array name="entries_media_preview_style">
<item>@string/crop</item>
<item>@string/scale</item>
@ -108,18 +69,13 @@
<item>@string/source_gallery</item>
<item>@string/source_clipboard</item>
</string-array>
<string-array name="value_image_sources">
<item>camera</item>
<item>gallery</item>
<item>clipboard</item>
</string-array>
<string-array name="values_profile_image_style">
<item>round</item>
<item>square</item>
</string-array>
<string-array name="entries_profile_image_style">
<item>@string/round</item>
<item>@string/square</item>
</string-array>
<string-array name="entries_proxy_type">
<item>HTTP</item>
<item>SOCKS</item>
</string-array>
</resources>

View File

@ -0,0 +1,75 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Twidere - Twitter client for Android
~
~ Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<resources>
<string-array name="values_refresh_interval">
<item>3</item>
<item>5</item>
<item>10</item>
<item>15</item>
<item>30</item>
<item>60</item>
<item>120</item>
<item>240</item>
</string-array>
<string-array name="values_theme">
<item>light</item>
<item>dark</item>
</string-array>
<string-array name="values_theme_background">
<item>default</item>
<item>solid</item>
<item>transparent</item>
</string-array>
<string-array name="dependency_values_true">
<item>true</item>
</string-array>
<string-array name="dependency_values_false">
<item>false</item>
</string-array>
<string-array name="values_tab_display_option">
<item>icon</item>
<item>label</item>
<item>both</item>
</string-array>
<string-array name="values_compose_now_action">
<item>compose</item>
<item>take_photo</item>
<item>pick_image</item>
</string-array>
<string-array name="values_media_preview_style">
<item>crop</item>
<item>scale</item>
</string-array>
<string-array name="value_image_sources">
<item>camera</item>
<item>gallery</item>
<item>clipboard</item>
</string-array>
<string-array name="values_profile_image_style">
<item>round</item>
<item>square</item>
</string-array>
<string-array name="values_proxy_type">
<item>http</item>
<item>socks</item>
</string-array>
</resources>

View File

@ -160,11 +160,15 @@
<string name="filename_hint">Filename</string>
<string name="please_wait">Please wait.</string>
<string name="saved_to_gallery">Saved to gallery.</string>
<string name="proxy">Proxy</string>
<string name="http_proxy">HTTP Proxy</string>
<string name="http_proxy_summary">Use HTTP Proxy for all network requests.</string>
<string name="proxy_host">Proxy Host</string>
<string name="proxy_port">Proxy Port</string>
<string name="proxy">Proxy</string>
<string name="proxy_summary">Use proxy for all network requests.</string>
<string name="proxy_type">Proxy type</string>
<string name="proxy_host">Proxy host</string>
<string name="proxy_port">Proxy port</string>
<string name="proxy_username">Proxy username</string>
<string name="proxy_password">Proxy password</string>
<string name="block">Block</string>
<string name="unblock">Unblock</string>
<string name="report_for_spam">Report spam</string>

View File

@ -39,9 +39,16 @@
android:defaultValue="false"
android:disableDependentsState="false"
android:key="enable_proxy"
android:summary="@string/http_proxy_summary"
android:title="@string/http_proxy"/>
android:summary="@string/proxy_summary"
android:title="@string/proxy"/>
<org.mariotaku.twidere.preference.SummaryListPreference
android:defaultValue="http"
android:dependency="enable_proxy"
android:entries="@array/entries_proxy_type"
android:entryValues="@array/values_proxy_type"
android:key="proxy_type"
android:title="@string/proxy_type"/>
<org.mariotaku.twidere.preference.SummaryEditTextPreference
android:dependency="enable_proxy"
android:key="proxy_host"
@ -53,6 +60,18 @@
android:key="proxy_port"
android:singleLine="true"
android:title="@string/proxy_port"/>
<org.mariotaku.twidere.preference.SummaryEditTextPreference
android:dependency="enable_proxy"
android:inputType="textEmailAddress"
android:key="proxy_username"
android:singleLine="true"
android:title="@string/proxy_username"/>
<org.mariotaku.twidere.preference.AutoFixEditTextPreference
android:dependency="enable_proxy"
android:inputType="textPassword"
android:key="proxy_password"
android:singleLine="true"
android:title="@string/proxy_password"/>
</PreferenceCategory>
<PreferenceCategory
android:key="category_api"
@ -79,7 +98,7 @@
android:key="thumbor_address"
android:title="@string/server_address"/>
<org.mariotaku.twidere.preference.SummaryEditTextPreference
<org.mariotaku.twidere.preference.AutoFixEditTextPreference
android:dependency="thumbor_enabled"
android:inputType="textVisiblePassword"
android:key="thumbor_security_key"