Merge branch 'maintenance' into origin/master

This commit is contained in:
Tlaster 2020-06-09 15:51:49 +08:00
commit aba0d0be0e
635 changed files with 4438 additions and 2695 deletions

View File

@ -30,14 +30,14 @@ addons:
- git - git
- ruby - ruby
before_cache: # before_cache:
- rm -f $HOME/.gradle/caches/modules-2/modules-2.lock # - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
- rm -fr $HOME/.gradle/caches/*/plugin-resolution/ # - rm -fr $HOME/.gradle/caches/*/plugin-resolution/
cache: # cache:
directories: # directories:
- $HOME/.gradle/caches/ # - $HOME/.gradle/caches/
- $HOME/.gradle/wrapper/ # - $HOME/.gradle/wrapper/
- $HOME/.m2/ # - $HOME/.m2/
before_install: before_install:
- ./travis/scripts/decode_private_configs.sh - ./travis/scripts/decode_private_configs.sh

View File

@ -5,7 +5,7 @@
[![Crowdin](https://d322cqt584bo4o.cloudfront.net/twidere/localized.svg)](https://crowdin.com/project/twidere) [![Crowdin](https://d322cqt584bo4o.cloudfront.net/twidere/localized.svg)](https://crowdin.com/project/twidere)
[<img a src="https://c5.patreon.com/external/logo/become_a_patron_button.png" width="100" herf="https://www.patreon.com/bePatron?u=36020799"/>](https://www.patreon.com/bePatron?u=36020799) [<img a src="https://c5.patreon.com/external/logo/become_a_patron_button.png" width="100" herf="https://www.patreon.com/bePatron?u=36020799"/>](https://www.patreon.com/bePatron?u=36020799)
Material Design ready and feature rich Twitter/Mastodon/StatusNet/Fanfou app for Android 4.4+. Enjoy Fediverse now! Material Design ready and feature rich Twitter/Mastodon/StatusNet/Fanfou app for Android 4.1+. Enjoy Fediverse now!
Twidere-Android is maintained by community and supporter including [Dimension](https://dimension.im/). Twidere-Android is maintained by community and supporter including [Dimension](https://dimension.im/).

View File

@ -8,7 +8,7 @@ buildscript {
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.6.3' classpath 'com.android.tools.build:gradle:4.0.0'
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files // in the individual module build.gradle files
} }
@ -17,13 +17,13 @@ buildscript {
allprojects { allprojects {
ext { ext {
projectGroupId = 'org.mariotaku.twidere' projectGroupId = 'org.mariotaku.twidere'
projectVersionCode = 512 projectVersionCode = 513
projectVersionName = '4.1.3' projectVersionName = '4.1.4'
globalCompileSdkVersion = 29 globalCompileSdkVersion = 29
globalBuildToolsVersion = "29.0.3" globalBuildToolsVersion = "29.0.3"
globalMinSdkVersion = 19 globalMinSdkVersion = 16
globalTargetSdkVersion = 29 globalTargetSdkVersion = 29
} }
@ -39,54 +39,18 @@ subprojects {
buildscript { buildscript {
ext { ext {
kotlinVersion = '1.3.72' kotlinVersion = '1.3.72'
pluginVersions = [ sharedVersions = [
AndroidSvgDrawable: '3.0.0',
PlayServices : '4.3.3',
]
libVersions = [
Kotlin : "${kotlinVersion}", Kotlin : "${kotlinVersion}",
SupportTest : '1.0.0',
MariotakuCommons : '0.9.20',
RestFu : '0.9.60',
ObjectCursor : '0.9.21',
PlayServices : '17.0.0',
MapsUtils : '0.6.2',
DropboxCoreSdk : '3.1.3',
GoogleDriveApi : 'v3-rev193-1.25.0',
Exoplayer : '2.11.4',
Toro : '2.1.0',
LoganSquare : '1.3.7', LoganSquare : '1.3.7',
IABv3 : '1.1.0', Jackson : '2.7.4',
Mime4J : '0.7.2',
OkHttp : '3.8.1',
Stetho : '1.5.0',
OSMDroid : '5.6.5',
LeakCanary : '2.1',
TwitterText : '1.14.7',
MediaViewerLibrary : '0.9.23',
MultiValueSwitch : '0.9.8',
PickNCrop : '0.9.27',
AndroidGIFDrawable : '1.2.6',
KPreferences : '0.9.7',
Kovenant : '3.3.0',
ParcelablePlease : '1.0.2', ParcelablePlease : '1.0.2',
Chameleon : '0.9.28',
UniqR : '0.9.4',
SQLiteQB : '0.9.15',
Glide : '4.11.0',
GlideOkHttp3 : '4.11.0',
GlideTransformations : '4.1.0',
AndroidImageCropper : '2.4.6',
ExportablePreferences: '0.9.7', ExportablePreferences: '0.9.7',
ACRA : '4.9.2', MariotakuCommons : '0.9.20',
AbstractTask : '0.9.5', ObjectCursor : '0.9.21',
Dagger : '2.11', RestFu : '0.9.60',
StethoBeanShellREPL : '0.1',
MessageBubbleView : '3.5',
] ]
} }
} }
} }

View File

@ -1,5 +1,6 @@
org.gradle.jvmargs=-Xmx3584m org.gradle.jvmargs=-Xmx3584m
#https://github.com/TwidereProject/Twidere-Android/issues/963 #https://github.com/TwidereProject/Twidere-Android/issues/963
android.enableAapt2=false # android.enableAapt2=false
android.useAndroidX=true android.useAndroidX=true
android.enableJetifier=true android.enableJetifier=true
android.jetifier.blacklist=android-4.1.1.4.jar

Binary file not shown.

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-6.4.1-all.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

2
gradlew vendored
View File

@ -82,6 +82,7 @@ esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM. # Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
@ -129,6 +130,7 @@ fi
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"` APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"` JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath # We build the pattern for arguments to be converted via cygpath

1
gradlew.bat vendored
View File

@ -84,6 +84,7 @@ set CMD_LINE_ARGS=%*
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle @rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%

View File

@ -16,8 +16,6 @@
# limitations under the License. # limitations under the License.
# #
org.gradle.jvmargs=-Xmx3584m org.gradle.jvmargs=-Xmx3584m
org.gradle.parallel=false
kotlin.incremental=false
kotlin.compiler.execution.strategy=in-process
android.useAndroidX=true android.useAndroidX=true
android.enableJetifier=true android.enableJetifier=true
android.jetifier.blacklist=android-4.1.1.4.jar

View File

@ -38,8 +38,8 @@ buildscript {
jcenter() jcenter()
} }
dependencies { dependencies {
classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5' classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1'
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7.3' classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.5'
} }
} }
@ -58,12 +58,19 @@ android {
versionCode projectVersionCode versionCode projectVersionCode
versionName projectVersionName versionName projectVersionName
} }
buildTypes { buildTypes {
release { release {
minifyEnabled false minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
} }
} }
compileOptions {
encoding = 'UTF-8'
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
} }
dependencies { dependencies {
@ -72,23 +79,23 @@ dependencies {
/** Third-party dependencies **/ /** Third-party dependencies **/
implementation "com.bluelinelabs:logansquare:${libVersions['LoganSquare']}" implementation "com.bluelinelabs:logansquare:${sharedVersions['LoganSquare']}"
annotationProcessor "com.bluelinelabs:logansquare-compiler:${libVersions['LoganSquare']}" annotationProcessor "com.bluelinelabs:logansquare-compiler:${sharedVersions['LoganSquare']}"
implementation "com.fasterxml.jackson.core:jackson-core:2.7.4" implementation "com.fasterxml.jackson.core:jackson-core:${sharedVersions['Jackson']}"
implementation "com.hannesdorfmann.parcelableplease:annotation:${libVersions['ParcelablePlease']}" implementation "com.hannesdorfmann.parcelableplease:annotation:${sharedVersions['ParcelablePlease']}"
annotationProcessor "com.hannesdorfmann.parcelableplease:processor:${libVersions['ParcelablePlease']}" annotationProcessor "com.hannesdorfmann.parcelableplease:processor:${sharedVersions['ParcelablePlease']}"
/** Custom dependencies **/ /** Custom dependencies **/
implementation "com.github.mariotaku.RestFu:library:${libVersions['RestFu']}" implementation "com.github.mariotaku.ExportablePreferences:core:${sharedVersions['ExportablePreferences']}"
implementation "com.github.mariotaku.RestFu:oauth:${libVersions['RestFu']}" annotationProcessor "com.github.mariotaku.ExportablePreferences:processor:${sharedVersions['ExportablePreferences']}"
implementation "com.github.mariotaku.RestFu:oauth2:${libVersions['RestFu']}" implementation "com.github.mariotaku.CommonsLibrary:logansquare:${sharedVersions['MariotakuCommons']}"
implementation "com.github.mariotaku.ObjectCursor:core:${libVersions['ObjectCursor']}" implementation "com.github.mariotaku.CommonsLibrary:objectcursor:${sharedVersions['MariotakuCommons']}"
annotationProcessor "com.github.mariotaku.ObjectCursor:processor:${libVersions['ObjectCursor']}" implementation "com.github.mariotaku.ObjectCursor:core:${sharedVersions['ObjectCursor']}"
implementation "com.github.mariotaku.ExportablePreferences:core:${libVersions['ExportablePreferences']}" annotationProcessor "com.github.mariotaku.ObjectCursor:processor:${sharedVersions['ObjectCursor']}"
annotationProcessor "com.github.mariotaku.ExportablePreferences:processor:${libVersions['ExportablePreferences']}" implementation "com.github.mariotaku.RestFu:library:${sharedVersions['RestFu']}"
implementation "com.github.mariotaku.CommonsLibrary:objectcursor:${libVersions['MariotakuCommons']}" implementation "com.github.mariotaku.RestFu:oauth:${sharedVersions['RestFu']}"
implementation "com.github.mariotaku.CommonsLibrary:logansquare:${libVersions['MariotakuCommons']}" implementation "com.github.mariotaku.RestFu:oauth2:${sharedVersions['RestFu']}"
} }
install { install {

View File

@ -206,7 +206,7 @@ public class MicroBlogException extends Exception implements TwitterResponse, Ht
try { try {
final String retryAfterStr = httpResponse.getHeader("Retry-After"); final String retryAfterStr = httpResponse.getHeader("Retry-After");
if (retryAfterStr != null) { if (retryAfterStr != null) {
retryAfter = Integer.valueOf(retryAfterStr); retryAfter = Integer.parseInt(retryAfterStr);
} }
} catch (final NumberFormatException ignore) { } catch (final NumberFormatException ignore) {
} }

View File

@ -18,8 +18,11 @@
package org.mariotaku.microblog.library.mastodon.model; package org.mariotaku.microblog.library.mastodon.model;
import androidx.annotation.Nullable;
import com.bluelinelabs.logansquare.annotation.JsonField; import com.bluelinelabs.logansquare.annotation.JsonField;
import com.bluelinelabs.logansquare.annotation.JsonObject; import com.bluelinelabs.logansquare.annotation.JsonObject;
import com.hannesdorfmann.parcelableplease.annotation.ParcelableThisPlease;
/** /**
* {@see https://github.com/tootsuite/documentation/blob/master/Using-the-API/API.md#attachment} * {@see https://github.com/tootsuite/documentation/blob/master/Using-the-API/API.md#attachment}
@ -59,6 +62,9 @@ public class Attachment {
@JsonField(name = "text_url") @JsonField(name = "text_url")
String textUrl; String textUrl;
@JsonField(name = "meta")
MetaInfo meta;
public String getId() { public String getId() {
return id; return id;
} }
@ -83,6 +89,51 @@ public class Attachment {
return textUrl; return textUrl;
} }
public MetaInfo getMeta() {
return meta;
}
@JsonObject
public static class MetaInfo {
@ParcelableThisPlease
@JsonField(name = "focus")
@Nullable
public FocusInfo focus;
@ParcelableThisPlease
@JsonField(name = "original")
@Nullable
public MetaDataInfo original;
@ParcelableThisPlease
@JsonField(name = "small")
@Nullable
public MetaDataInfo small;
@JsonObject
public static class FocusInfo {
@ParcelableThisPlease
@JsonField(name = "x")
public float x;
@ParcelableThisPlease
@JsonField(name = "y")
public float y;
}
@JsonObject
public static class MetaDataInfo {
@ParcelableThisPlease
@JsonField(name = "width")
public long width;
@ParcelableThisPlease
@JsonField(name = "height")
public long height;
@ParcelableThisPlease
@JsonField(name = "aspect")
public float aspect;
}
}
@Override @Override
public String toString() { public String toString() {
return "Attachment{" + return "Attachment{" +

View File

@ -64,7 +64,7 @@ public class CardDataMap implements ValueMap {
@Override @Override
public String[] keys() { public String[] keys() {
final Set<String> keySet = map.keySet(); final Set<String> keySet = map.keySet();
return keySet.toArray(new String[keySet.size()]); return keySet.toArray(new String[0]);
} }
@Override @Override

View File

@ -37,7 +37,6 @@ import java.util.List;
@Keep @Keep
public class IDs$$JsonObjectMapper extends JsonMapper<IDs> { public class IDs$$JsonObjectMapper extends JsonMapper<IDs> {
@SuppressWarnings("TryWithIdenticalCatches")
@Override @Override
public IDs parse(JsonParser jsonParser) throws IOException { public IDs parse(JsonParser jsonParser) throws IOException {
IDs instance = new IDs(); IDs instance = new IDs();

View File

@ -61,11 +61,8 @@ public final class ResponseList$$JsonObjectMapper<T> extends JsonMapper<Response
@Override @Override
public void parseField(ResponseList<T> instance, String fieldName, JsonParser jsonParser) throws IOException { public void parseField(ResponseList<T> instance, String fieldName, JsonParser jsonParser) throws IOException {
switch (fieldName) { if ("results".equals(fieldName)) {
case "results": { instance.addAll(m84ClassJsonMapper.parseList(jsonParser));
instance.addAll(m84ClassJsonMapper.parseList(jsonParser));
break;
}
} }
} }

View File

@ -250,7 +250,7 @@ public class UniversalSearchResult {
index.end = jsonParser.nextIntValue(-1); index.end = jsonParser.nextIntValue(-1);
list.add(index); list.add(index);
} }
return list.toArray(new Index[list.size()]); return list.toArray(new Index[0]);
} }
@Override @Override

View File

@ -52,12 +52,9 @@ public final class InternalParseUtil {
accessLevel = TwitterResponse.AccessLevel.READ_WRITE; accessLevel = TwitterResponse.AccessLevel.READ_WRITE;
break; break;
case 25: case 25:
// read-write-directmessages (Read, Write, & Direct
// Message)
accessLevel = TwitterResponse.AccessLevel.READ_WRITE_DIRECTMESSAGES;
break;
case 26: case 26:
// read-write-privatemessages (Read, Write, & Direct // read-write-privatemessages (Read, Write, & Direct
// read-write-directmessages (Read, Write, & Direct
// Message) // Message)
accessLevel = TwitterResponse.AccessLevel.READ_WRITE_DIRECTMESSAGES; accessLevel = TwitterResponse.AccessLevel.READ_WRITE_DIRECTMESSAGES;
break; break;

View File

@ -64,8 +64,8 @@ public interface TwidereConstants extends SharedPreferenceConstants, IntentConst
String ETAG_MASTODON_APPS_PREFERENCES_NAME = "mastodon_apps"; String ETAG_MASTODON_APPS_PREFERENCES_NAME = "mastodon_apps";
String ACCOUNT_PREFERENCES_NAME_PREFIX = "account_preferences_"; String ACCOUNT_PREFERENCES_NAME_PREFIX = "account_preferences_";
String TWITTER_CONSUMER_KEY = "wmtrtTaVOjUnH5pWQp4LDI5Qs"; String TWITTER_CONSUMER_KEY = "MUUBibXUognm6e9vbzrUIqPkt";
String TWITTER_CONSUMER_SECRET = "E9Q9u2yK0COJae2tLcNEdY75OPA3bxqJiGZQztraHaQUtoI2cu"; String TWITTER_CONSUMER_SECRET = "l2uWAgQkoHvDfM2PrRFx2WN4h7QIUIktmxyeTAqRo6TkGCtNKy";
String YANDEX_KEY = "trnsl.1.1.20200513T065609Z.8e72845b632aa04f.fe1297e42c152de9e8773e1bc71162b1e498e2a8"; String YANDEX_KEY = "trnsl.1.1.20200513T065609Z.8e72845b632aa04f.fe1297e42c152de9e8773e1bc71162b1e498e2a8";

View File

@ -56,6 +56,5 @@ public @interface FilterScope {
// Contains all flags // Contains all flags
int ALL = 0xFFFFFFFF; int ALL = 0xFFFFFFFF;
@SuppressWarnings("PointlessBitwiseExpression")
int DEFAULT = ALL & ~(TARGET_NAME | TARGET_DESCRIPTION); int DEFAULT = ALL & ~(TARGET_NAME | TARGET_DESCRIPTION);
} }

View File

@ -291,6 +291,8 @@ public interface SharedPreferenceConstants {
String KEY_AUTO_HIDE_TABS = "auto_hide_tabs"; String KEY_AUTO_HIDE_TABS = "auto_hide_tabs";
@ExportablePreference(BOOLEAN) @ExportablePreference(BOOLEAN)
String KEY_HIDE_CARD_NUMBERS = "hide_card_numbers"; String KEY_HIDE_CARD_NUMBERS = "hide_card_numbers";
@ExportablePreference(BOOLEAN)
String KEY_SHOW_LINK_PREVIEW = "show_link_preview";
// Internal preferences // Internal preferences

View File

@ -40,7 +40,6 @@ import java.util.Arrays;
@JsonObject @JsonObject
@ParcelablePlease @ParcelablePlease
public class ParcelableMedia implements Parcelable { public class ParcelableMedia implements Parcelable {
@SuppressWarnings("NullableProblems")
@NonNull @NonNull
@JsonField(name = "url") @JsonField(name = "url")
@ParcelableThisPlease @ParcelableThisPlease

View File

@ -31,7 +31,6 @@ import com.hannesdorfmann.parcelableplease.annotation.ParcelablePlease;
@ParcelablePlease @ParcelablePlease
public class ParcelableMediaUpdate implements Parcelable { public class ParcelableMediaUpdate implements Parcelable {
@SuppressWarnings("NullableProblems")
@NonNull @NonNull
@JsonField(name = "uri") @JsonField(name = "uri")
public String uri; public String uri;

View File

@ -20,11 +20,11 @@ package org.mariotaku.twidere.model;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import androidx.annotation.IntDef; import android.text.TextUtils;
import androidx.annotation.LongDef; import androidx.annotation.LongDef;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import android.text.TextUtils;
import com.bluelinelabs.logansquare.annotation.JsonField; import com.bluelinelabs.logansquare.annotation.JsonField;
import com.bluelinelabs.logansquare.annotation.JsonObject; import com.bluelinelabs.logansquare.annotation.JsonObject;
@ -52,13 +52,7 @@ import java.util.Comparator;
@ParcelablePlease @ParcelablePlease
public class ParcelableStatus implements Parcelable, Comparable<ParcelableStatus>, Cloneable { public class ParcelableStatus implements Parcelable, Comparable<ParcelableStatus>, Cloneable {
public static final Comparator<ParcelableStatus> REVERSE_COMPARATOR = new Comparator<ParcelableStatus>() { public static final Comparator<ParcelableStatus> REVERSE_COMPARATOR = (object1, object2) -> object2.compareTo(object1);
@Override
public int compare(final ParcelableStatus object1, final ParcelableStatus object2) {
return object2.compareTo(object1);
}
};
public static final Creator<ParcelableStatus> CREATOR = new Creator<ParcelableStatus>() { public static final Creator<ParcelableStatus> CREATOR = new Creator<ParcelableStatus>() {
@Override @Override
public ParcelableStatus createFromParcel(Parcel source) { public ParcelableStatus createFromParcel(Parcel source) {
@ -75,13 +69,11 @@ public class ParcelableStatus implements Parcelable, Comparable<ParcelableStatus
@CursorField(value = Statuses._ID, excludeWrite = true, type = TwidereDataStore.TYPE_PRIMARY_KEY) @CursorField(value = Statuses._ID, excludeWrite = true, type = TwidereDataStore.TYPE_PRIMARY_KEY)
public long _id; public long _id;
@SuppressWarnings("NullableProblems")
@JsonField(name = "id") @JsonField(name = "id")
@CursorField(Statuses.ID) @CursorField(Statuses.ID)
@NonNull @NonNull
public String id; public String id;
@SuppressWarnings("NullableProblems")
@JsonField(name = "account_id", typeConverter = UserKeyConverter.class) @JsonField(name = "account_id", typeConverter = UserKeyConverter.class)
@CursorField(value = Statuses.ACCOUNT_KEY, converter = UserKeyCursorFieldConverter.class) @CursorField(value = Statuses.ACCOUNT_KEY, converter = UserKeyCursorFieldConverter.class)
@NonNull @NonNull
@ -98,7 +90,6 @@ public class ParcelableStatus implements Parcelable, Comparable<ParcelableStatus
@JsonField(name = "timestamp") @JsonField(name = "timestamp")
@CursorField(Statuses.TIMESTAMP) @CursorField(Statuses.TIMESTAMP)
public long timestamp; public long timestamp;
@SuppressWarnings("NullableProblems")
@JsonField(name = "user_id", typeConverter = UserKeyConverter.class) @JsonField(name = "user_id", typeConverter = UserKeyConverter.class)
@CursorField(value = Statuses.USER_KEY, converter = UserKeyCursorFieldConverter.class) @CursorField(value = Statuses.USER_KEY, converter = UserKeyCursorFieldConverter.class)
@ -527,6 +518,9 @@ public class ParcelableStatus implements Parcelable, Comparable<ParcelableStatus
@JsonField(name = "external_url") @JsonField(name = "external_url")
public String external_url; public String external_url;
@JsonField(name = "entities_url")
public String[] entities_url;
@JsonField(name = "quoted_external_url") @JsonField(name = "quoted_external_url")
public String quoted_external_url; public String quoted_external_url;

View File

@ -41,7 +41,6 @@ import java.util.Arrays;
@JsonObject @JsonObject
public class ParcelableStatusUpdate implements Parcelable { public class ParcelableStatusUpdate implements Parcelable {
@SuppressWarnings("NullableProblems")
@JsonField(name = "accounts") @JsonField(name = "accounts")
@NonNull @NonNull
@ParcelableThisPlease @ParcelableThisPlease

View File

@ -45,7 +45,6 @@ public class ParcelableTrend implements Parcelable {
@CursorField(value = CachedTrends._ID, excludeWrite = true, type = TwidereDataStore.TYPE_PRIMARY_KEY) @CursorField(value = CachedTrends._ID, excludeWrite = true, type = TwidereDataStore.TYPE_PRIMARY_KEY)
long _id; long _id;
@SuppressWarnings("NullableProblems")
@ParcelableThisPlease @ParcelableThisPlease
@JsonField(name = "account_id", typeConverter = UserKeyConverter.class) @JsonField(name = "account_id", typeConverter = UserKeyConverter.class)
@CursorField(value = CachedTrends.ACCOUNT_KEY, converter = UserKeyCursorFieldConverter.class) @CursorField(value = CachedTrends.ACCOUNT_KEY, converter = UserKeyCursorFieldConverter.class)

View File

@ -35,10 +35,8 @@ import java.io.IOException;
public abstract class ConversationExtras implements Parcelable { public abstract class ConversationExtras implements Parcelable {
public static ConversationExtras parse(@NonNull final String extrasType, @Nullable final String json) throws IOException { public static ConversationExtras parse(@NonNull final String extrasType, @Nullable final String json) throws IOException {
if (json == null) return null; if (json == null) return null;
switch (extrasType) { if (ExtrasType.TWITTER_OFFICIAL.equals(extrasType)) {
case ExtrasType.TWITTER_OFFICIAL: { return LoganSquare.parse(json, TwitterOfficialConversationExtras.class);
return LoganSquare.parse(json, TwitterOfficialConversationExtras.class);
}
} }
return LoganSquare.parse(json, DefaultConversationExtras.class); return LoganSquare.parse(json, DefaultConversationExtras.class);
} }

View File

@ -46,7 +46,7 @@ public class UserKeysConverter implements TypeConverter<UserKey[]> {
while (jsonParser.nextToken() != JsonToken.END_ARRAY) { while (jsonParser.nextToken() != JsonToken.END_ARRAY) {
list.add(UserKey.valueOf(jsonParser.getValueAsString())); list.add(UserKey.valueOf(jsonParser.getValueAsString()));
} }
return list.toArray(new UserKey[list.size()]); return list.toArray(new UserKey[0]);
} }
@Override @Override

View File

@ -29,6 +29,12 @@ android {
minSdkVersion globalMinSdkVersion minSdkVersion globalMinSdkVersion
targetSdkVersion globalTargetSdkVersion targetSdkVersion globalTargetSdkVersion
} }
compileOptions {
encoding = 'UTF-8'
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
} }
dependencies { dependencies {

View File

@ -314,7 +314,7 @@ public class NyanDrawingHelper {
public void dispatchOnDraw(final Canvas canvas) { public void dispatchOnDraw(final Canvas canvas) {
final int w = canvas.getWidth(), h = canvas.getHeight(); final int w = canvas.getWidth(), h = canvas.getHeight();
if (w <= 0 || h <= 0) return; if (w <= 0 || h <= 0) return;
for (final Star star : mStars.toArray(new Star[mStars.size()])) { for (final Star star : mStars.toArray(new Star[0])) {
final int col = star.nextColumn(), row = star.nextRow(); final int col = star.nextColumn(), row = star.nextRow();
final float y = (row + 0.5f) * (h / mStarRows), x = (col + 0.5f) * (w / mStarCols); final float y = (row + 0.5f) * (h / mStarRows), x = (col + 0.5f) * (w / mStarCols);
drawStar(canvas, x, y, star.nextFrame()); drawStar(canvas, x, y, star.nextFrame());

View File

@ -25,7 +25,7 @@ buildscript {
if (enableGoogleVariant) { if (enableGoogleVariant) {
// START Non-FOSS component // START Non-FOSS component
classpath "com.google.gms:google-services:${pluginVersions['PlayServices']}" classpath 'com.google.gms:google-services:4.3.3'
// END Non-FOSS component // END Non-FOSS component
} }
} }
@ -91,9 +91,6 @@ android {
signingConfig signingConfigs.twidere signingConfig signingConfigs.twidere
} }
multiDexEnabled true
minifyEnabled false
shrinkResources false
resValue("bool", "debug", "true") resValue("bool", "debug", "true")
} }
release { release {
@ -101,7 +98,6 @@ android {
signingConfig signingConfigs.twidere signingConfig signingConfigs.twidere
} }
multiDexEnabled true
minifyEnabled false minifyEnabled false
shrinkResources false shrinkResources false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
@ -115,6 +111,7 @@ android {
} }
compileOptions { compileOptions {
encoding = 'UTF-8'
sourceCompatibility JavaVersion.VERSION_1_8 sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8
} }
@ -145,7 +142,6 @@ android {
exclude 'sdk-version.txt' exclude 'sdk-version.txt'
exclude 'build-data.properties' exclude 'build-data.properties'
} }
} }
task buildTranslationArray { task buildTranslationArray {
@ -153,16 +149,16 @@ task buildTranslationArray {
foundLocales.append("new String[]{") foundLocales.append("new String[]{")
fileTree("src/main/res-localized").visit { FileVisitDetails details -> fileTree("src/main/res-localized").visit { FileVisitDetails details ->
if(details.file.path.endsWith("strings.xml")){ if (details.file.path.endsWith("strings.xml")) {
def languageCode = details.file.parentFile.name.replaceAll('values-','').replaceAll('-r','-') def languageCode = details.file.parentFile.name.replaceAll('values-', '').replaceAll('-r', '-')
languageCode = (languageCode == "values") ? "en" : languageCode; languageCode = (languageCode == "values") ? "en" : languageCode
foundLocales.append("\"").append(languageCode).append("\"").append(",") foundLocales.append("\"").append(languageCode).append("\"").append(",")
} }
} }
foundLocales.append("}") foundLocales.append("}")
//Don't forget to remove the trailing comma //Don't forget to remove the trailing comma
def foundLocalesString = foundLocales.toString().replaceAll(',}','}') def foundLocalesString = foundLocales.toString().replaceAll(',}', '}')
android.defaultConfig.buildConfigField "String[]", "TRANSLATION_ARRAY", foundLocalesString android.defaultConfig.buildConfigField "String[]", "TRANSLATION_ARRAY", foundLocalesString
} }
@ -175,12 +171,25 @@ tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
} }
} }
ext {
libVersions = [
Kovenant : '3.3.0',
Mime4J : '0.7.2',
Dagger : '2.28',
Exoplayer : '2.11.5',
Glide : '4.11.0',
MediaViewerLibrary: '0.9.23',
PlayServices : '17.0.0',
Stetho : '1.5.1',
]
}
dependencies { dependencies {
implementation project(':twidere.component.common') implementation project(':twidere.component.common')
implementation project(':twidere.component.nyan') implementation project(':twidere.component.nyan')
/** Kotlin **/ /** Kotlin **/
implementation "org.jetbrains.kotlin:kotlin-stdlib:${libVersions['Kotlin']}" implementation "org.jetbrains.kotlin:kotlin-stdlib:${sharedVersions['Kotlin']}"
implementation "nl.komponents.kovenant:kovenant:${libVersions['Kovenant']}" implementation "nl.komponents.kovenant:kovenant:${libVersions['Kovenant']}"
implementation "nl.komponents.kovenant:kovenant-android:${libVersions['Kovenant']}" implementation "nl.komponents.kovenant:kovenant-android:${libVersions['Kovenant']}"
implementation "nl.komponents.kovenant:kovenant-combine:${libVersions['Kovenant']}" implementation "nl.komponents.kovenant:kovenant-combine:${libVersions['Kovenant']}"
@ -189,103 +198,104 @@ dependencies {
/** Android support **/ /** Android support **/
implementation 'androidx.annotation:annotation:1.1.0' implementation 'androidx.annotation:annotation:1.1.0'
implementation 'androidx.appcompat:appcompat:1.1.0' implementation 'androidx.appcompat:appcompat:1.3.0-alpha01'
implementation 'androidx.browser:browser:1.2.0' implementation 'androidx.browser:browser:1.2.0'
implementation 'androidx.cardview:cardview:1.0.0' implementation 'androidx.cardview:cardview:1.0.0'
implementation 'androidx.core:core:1.2.0' implementation 'androidx.core:core:1.2.0'
implementation 'androidx.core:core-ktx:1.2.0'
implementation 'androidx.drawerlayout:drawerlayout:1.1.0-alpha01' implementation 'androidx.drawerlayout:drawerlayout:1.1.0-alpha01'
implementation 'androidx.exifinterface:exifinterface:1.1.0' implementation 'androidx.exifinterface:exifinterface:1.2.0'
implementation "androidx.preference:preference:1.1.1"
implementation 'androidx.legacy:legacy-support-core-ui:1.0.0' implementation 'androidx.legacy:legacy-support-core-ui:1.0.0'
implementation 'androidx.multidex:multidex:2.0.1' implementation 'androidx.multidex:multidex:2.0.1'
implementation 'androidx.palette:palette:1.0.0' implementation 'androidx.palette:palette-ktx:1.0.0'
implementation 'androidx.preference:preference:1.1.1'
implementation 'androidx.recyclerview:recyclerview:1.1.0' implementation 'androidx.recyclerview:recyclerview:1.1.0'
implementation 'com.google.android.material:material:1.1.0' implementation 'com.google.android.material:material:1.1.0'
implementation "androidx.core:core-ktx:1.2.0"
/** Third-party dependencies **/ /** Third-party dependencies **/
compileOnly 'javax.annotation:jsr250-api:1.0' compileOnly 'javax.annotation:jsr250-api:1.0'
implementation "com.twitter:twitter-text:${libVersions['TwitterText']}" implementation 'com.twitter:twitter-text:1.14.7'
implementation 'com.davemorrissey.labs:subsampling-scale-image-view:3.6.0' implementation 'com.davemorrissey.labs:subsampling-scale-image-view:3.6.0'
implementation 'com.squareup:otto:1.3.8' implementation 'com.squareup:otto:1.3.8'
implementation 'dnsjava:dnsjava:2.1.8' implementation 'dnsjava:dnsjava:2.1.9'
implementation 'com.commonsware.cwac:layouts:0.4.3' implementation 'com.commonsware.cwac:layouts:0.4.5'
implementation 'com.rengwuxian.materialedittext:library:2.1.4' implementation 'com.rengwuxian.materialedittext:library:2.1.4'
implementation 'com.pnikosis:materialish-progress:1.7' implementation 'com.pnikosis:materialish-progress:1.7'
implementation 'com.github.uucky:ColorPicker-Android:0.9.7@aar' implementation 'com.github.uucky:ColorPicker-Android:0.9.7@aar'
implementation "pl.droidsonroids.gif:android-gif-drawable:${libVersions['AndroidGIFDrawable']}" implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.15'
implementation 'com.sprylab.android.texturevideoview:texturevideoview:1.2.1' implementation 'com.sprylab.android.texturevideoview:texturevideoview:1.2.1'
implementation 'com.squareup:pollexor:2.0.4' implementation 'com.squareup:pollexor:2.0.4'
implementation 'org.apache.commons:commons-text:1.8'
implementation "org.apache.james:apache-mime4j-core:${libVersions['Mime4J']}" implementation "org.apache.james:apache-mime4j-core:${libVersions['Mime4J']}"
implementation "org.apache.james:apache-mime4j-storage:${libVersions['Mime4J']}" implementation "org.apache.james:apache-mime4j-storage:${libVersions['Mime4J']}"
implementation "com.bluelinelabs:logansquare:${libVersions['LoganSquare']}" implementation "com.bluelinelabs:logansquare:${sharedVersions['LoganSquare']}"
kapt "com.bluelinelabs:logansquare-compiler:${libVersions['LoganSquare']}" kapt "com.bluelinelabs:logansquare-compiler:${sharedVersions['LoganSquare']}"
implementation "com.fasterxml.jackson.core:jackson-core:2.7.4" implementation "com.fasterxml.jackson.core:jackson-core:${sharedVersions['Jackson']}"
implementation "com.hannesdorfmann.parcelableplease:annotation:${libVersions['ParcelablePlease']}" implementation "com.hannesdorfmann.parcelableplease:annotation:${sharedVersions['ParcelablePlease']}"
kapt "com.hannesdorfmann.parcelableplease:processor:${libVersions['ParcelablePlease']}" kapt "com.hannesdorfmann.parcelableplease:processor:${sharedVersions['ParcelablePlease']}"
implementation "com.squareup.okhttp3:okhttp:${libVersions['OkHttp']}" implementation 'com.squareup.okhttp3:okhttp:3.12.12'
implementation "com.squareup.okio:okio:2.4.3" implementation 'com.squareup.okio:okio:2.6.0'
implementation 'com.lnikkila:extendedtouchview:0.1.1' implementation 'com.lnikkila:extendedtouchview:0.1.1'
implementation "com.google.dagger:dagger:${libVersions['Dagger']}" implementation "com.google.dagger:dagger:${libVersions['Dagger']}"
kapt "com.google.dagger:dagger-compiler:${libVersions['Dagger']}" kapt "com.google.dagger:dagger-compiler:${libVersions['Dagger']}"
implementation 'org.attoparser:attoparser:2.0.4.RELEASE' implementation 'org.attoparser:attoparser:2.0.5.RELEASE'
implementation 'com.getkeepsafe.taptargetview:taptargetview:1.9.1' implementation 'com.getkeepsafe.taptargetview:taptargetview:1.13.0'
implementation 'net.ypresto.androidtranscoder:android-transcoder:0.2.0' implementation 'net.ypresto.androidtranscoder:android-transcoder:0.3.0'
implementation 'org.jsoup:jsoup:1.13.1'
implementation "com.google.android.exoplayer:exoplayer-core:${libVersions['Exoplayer']}" implementation "com.google.android.exoplayer:exoplayer-core:${libVersions['Exoplayer']}"
implementation "com.google.android.exoplayer:exoplayer-ui:${libVersions['Exoplayer']}" implementation "com.google.android.exoplayer:exoplayer-ui:${libVersions['Exoplayer']}"
implementation "com.google.android.exoplayer:extension-okhttp:${libVersions['Exoplayer']}" implementation "com.google.android.exoplayer:extension-okhttp:${libVersions['Exoplayer']}"
implementation "com.github.bumptech.glide:glide:${libVersions['Glide']}" implementation "com.github.bumptech.glide:glide:${libVersions['Glide']}"
implementation "com.github.bumptech.glide:okhttp3-integration:${libVersions['GlideOkHttp3']}@aar" implementation "com.github.bumptech.glide:okhttp3-integration:${libVersions['Glide']}@aar"
kapt "com.github.bumptech.glide:compiler:${libVersions['Glide']}" kapt "com.github.bumptech.glide:compiler:${libVersions['Glide']}"
implementation "jp.wasabeef:glide-transformations:${libVersions['GlideTransformations']}" implementation 'jp.wasabeef:glide-transformations:4.1.0'
implementation "com.theartofdev.edmodo:android-image-cropper:${libVersions['AndroidImageCropper']}" implementation 'com.theartofdev.edmodo:android-image-cropper:2.8.0'
/** Custom dependencies **/ /** Custom dependencies **/
implementation 'com.github.mariotaku:AbstractTask:0.9.5'
implementation 'com.github.mariotaku:DragSortListView:0.6.1' implementation 'com.github.mariotaku:DragSortListView:0.6.1'
implementation "com.github.mariotaku:MessageBubbleView:${libVersions['MessageBubbleView']}" implementation "com.github.mariotaku.ExportablePreferences:core:${sharedVersions['ExportablePreferences']}"
implementation 'com.github.mariotaku:DragSortListView:0.6.1' implementation("com.github.mariotaku.CommonsLibrary:emojione-android:${sharedVersions['MariotakuCommons']}") {
implementation "com.github.mariotaku.MediaViewerLibrary:base:${libVersions['MediaViewerLibrary']}"
implementation "com.github.mariotaku.MediaViewerLibrary:subsample-image-view:${libVersions['MediaViewerLibrary']}"
implementation "com.github.mariotaku:SQLiteQB:${libVersions['SQLiteQB']}"
implementation "com.github.mariotaku.ObjectCursor:core:${libVersions['ObjectCursor']}"
kapt "com.github.mariotaku.ObjectCursor:processor:${libVersions['ObjectCursor']}"
implementation "com.github.mariotaku.ExportablePreferences:core:${libVersions['ExportablePreferences']}"
implementation "com.github.mariotaku:AbstractTask:${libVersions['AbstractTask']}"
implementation "com.github.mariotaku.CommonsLibrary:parcel:${libVersions['MariotakuCommons']}"
implementation "com.github.mariotaku.CommonsLibrary:io:${libVersions['MariotakuCommons']}"
implementation "com.github.mariotaku.CommonsLibrary:text:${libVersions['MariotakuCommons']}"
implementation "com.github.mariotaku.CommonsLibrary:text-kotlin:${libVersions['MariotakuCommons']}"
implementation("com.github.mariotaku.CommonsLibrary:emojione-android:${libVersions['MariotakuCommons']}") {
exclude group: 'org.apache.commons', module: 'commons-text' exclude group: 'org.apache.commons', module: 'commons-text'
} }
implementation "com.github.mariotaku.CommonsLibrary:objectcursor:${libVersions['MariotakuCommons']}" implementation "com.github.mariotaku.CommonsLibrary:io:${sharedVersions['MariotakuCommons']}"
implementation "com.github.mariotaku.CommonsLibrary:logansquare:${libVersions['MariotakuCommons']}" implementation "com.github.mariotaku.CommonsLibrary:logansquare:${sharedVersions['MariotakuCommons']}"
implementation "com.github.mariotaku:KPreferences:${libVersions['KPreferences']}" implementation "com.github.mariotaku.CommonsLibrary:objectcursor:${sharedVersions['MariotakuCommons']}"
implementation "com.github.mariotaku.UniqR:android:${libVersions['UniqR']}" implementation "com.github.mariotaku.CommonsLibrary:parcel:${sharedVersions['MariotakuCommons']}"
implementation "com.github.mariotaku:PickNCrop:${libVersions['PickNCrop']}" implementation "com.github.mariotaku.CommonsLibrary:text:${sharedVersions['MariotakuCommons']}"
implementation "com.github.mariotaku.RestFu:library:${libVersions['RestFu']}" implementation "com.github.mariotaku.CommonsLibrary:text-kotlin:${sharedVersions['MariotakuCommons']}"
implementation "com.github.mariotaku.RestFu:oauth:${libVersions['RestFu']}" implementation 'com.github.mariotaku:KPreferences:0.9.8'
implementation "com.github.mariotaku.RestFu:oauth2:${libVersions['RestFu']}" implementation "com.github.mariotaku.MediaViewerLibrary:base:${libVersions['MediaViewerLibrary']}"
implementation "com.github.mariotaku.RestFu:okhttp3:${libVersions['RestFu']}" implementation "com.github.mariotaku.MediaViewerLibrary:subsample-image-view:${libVersions['MediaViewerLibrary']}"
implementation "com.github.mariotaku.RestFu:logansquare:${libVersions['RestFu']}" implementation 'com.github.mariotaku:MessageBubbleView:3.5'
implementation "com.github.Tlaster:Chameleon:${libVersions['Chameleon']}" implementation "com.github.mariotaku.ObjectCursor:core:${sharedVersions['ObjectCursor']}"
kapt "com.github.mariotaku.ObjectCursor:processor:${sharedVersions['ObjectCursor']}"
implementation 'com.github.mariotaku:PickNCrop:0.9.27'
implementation "com.github.mariotaku.RestFu:library:${sharedVersions['RestFu']}"
implementation "com.github.mariotaku.RestFu:logansquare:${sharedVersions['RestFu']}"
implementation "com.github.mariotaku.RestFu:oauth:${sharedVersions['RestFu']}"
implementation "com.github.mariotaku.RestFu:oauth2:${sharedVersions['RestFu']}"
implementation "com.github.mariotaku.RestFu:okhttp3:${sharedVersions['RestFu']}"
implementation 'com.github.mariotaku:SQLiteQB:0.9.15'
implementation 'com.github.mariotaku.UniqR:android:0.9.4'
implementation 'com.github.Tlaster:Chameleon:0.9.28'
/** Flavor dependencies **/ /** Flavor dependencies **/
fdroidImplementation "org.osmdroid:osmdroid-android:${libVersions['OSMDroid']}" fdroidImplementation 'org.osmdroid:osmdroid-android:5.6.5'
fdroidImplementation "ch.acra:acra:${libVersions['ACRA']}" fdroidImplementation 'ch.acra:acra:4.11'
if (enableGoogleVariant) { if (enableGoogleVariant) {
// START Non-FOSS component // START Non-FOSS component
googleImplementation "com.google.android.gms:play-services-ads:${libVersions['PlayServices']}" googleImplementation "com.google.android.gms:play-services-ads:${libVersions['PlayServices']}"
googleImplementation "com.google.android.gms:play-services-auth:${libVersions['PlayServices']}" googleImplementation "com.google.android.gms:play-services-auth:${libVersions['PlayServices']}"
googleImplementation "com.google.android.gms:play-services-maps:${libVersions['PlayServices']}" googleImplementation "com.google.android.gms:play-services-maps:${libVersions['PlayServices']}"
googleImplementation "com.google.maps.android:android-maps-utils:${libVersions['MapsUtils']}" googleImplementation 'com.google.maps.android:android-maps-utils:0.6.2'
googleImplementation "com.anjlab.android.iab.v3:library:${libVersions['IABv3']}" googleImplementation 'com.anjlab.android.iab.v3:library:1.1.0'
googleImplementation "com.dropbox.core:dropbox-core-sdk:${libVersions['DropboxCoreSdk']}" googleImplementation 'com.dropbox.core:dropbox-core-sdk:3.1.3'
googleImplementation("com.google.apis:google-api-services-drive:${libVersions['GoogleDriveApi']}") { googleImplementation('com.google.apis:google-api-services-drive:v3-rev195-1.25.0') {
exclude group: 'org.apache.httpcomponents' exclude group: 'org.apache.httpcomponents'
} }
implementation 'com.google.guava:guava:28.2-android' implementation 'com.google.guava:guava:28.2-android'
@ -294,9 +304,9 @@ dependencies {
debugImplementation "com.facebook.stetho:stetho:${libVersions['Stetho']}" debugImplementation "com.facebook.stetho:stetho:${libVersions['Stetho']}"
debugImplementation "com.facebook.stetho:stetho-okhttp3:${libVersions['Stetho']}" debugImplementation "com.facebook.stetho:stetho-okhttp3:${libVersions['Stetho']}"
debugImplementation "com.github.mariotaku:StethoBeanShellREPL:${libVersions['StethoBeanShellREPL']}" debugImplementation 'com.github.mariotaku:StethoBeanShellREPL:0.5'
debugImplementation "com.squareup.leakcanary:leakcanary-android:${libVersions['LeakCanary']}" debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.3'
debugImplementation('com.jayway.jsonpath:json-path:2.2.0') { debugImplementation('com.jayway.jsonpath:json-path:2.4.0') {
exclude group: 'net.minidev', module: 'json-smart' exclude group: 'net.minidev', module: 'json-smart'
} }
// Stetho dependency, see https://g.co/androidstudio/app-test-app-conflict // Stetho dependency, see https://g.co/androidstudio/app-test-app-conflict

View File

@ -316,9 +316,9 @@ class AccountsDumperPlugin(val context: Context) : DumperPlugin {
return JsonPath.parse(JsonSerializer.serialize(details), configuration) return JsonPath.parse(JsonSerializer.serialize(details), configuration)
} }
private fun Any.prettyPrint() = when { private fun Any.prettyPrint() = when (this) {
this is JSONObject -> toString(4) is JSONObject -> toString(4)
this is JSONArray -> toString(4) is JSONArray -> toString(4)
else -> toString() else -> toString()
} }

View File

@ -7,8 +7,8 @@
"auth_type": "oauth", "auth_type": "oauth",
"same_oauth_url": true, "same_oauth_url": true,
"no_version_suffix": false, "no_version_suffix": false,
"consumer_key": "wmtrtTaVOjUnH5pWQp4LDI5Qs", "consumer_key": "MUUBibXUognm6e9vbzrUIqPkt",
"consumer_secret": "E9Q9u2yK0COJae2tLcNEdY75OPA3bxqJiGZQztraHaQUtoI2cu", "consumer_secret": "l2uWAgQkoHvDfM2PrRFx2WN4h7QIUIktmxyeTAqRo6TkGCtNKy",
"sign_up_url": "https://twitter.com/signup" "sign_up_url": "https://twitter.com/signup"
}, },
{ {

View File

@ -1,68 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.commons.text.translate;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
/**
* Executes a sequence of translators one after the other. Execution ends whenever
* the first translator consumes codepoints from the input.
*
* @since 1.0
*/
public class AggregateTranslator extends CharSequenceTranslator {
/**
* Translator list.
*/
private final List<CharSequenceTranslator> translators = new ArrayList<>();
/**
* Specify the translators to be used at creation time.
*
* @param translators CharSequenceTranslator array to aggregate
*/
public AggregateTranslator(final CharSequenceTranslator... translators) {
if (translators != null) {
for (CharSequenceTranslator translator : translators) {
if (translator != null) {
this.translators.add(translator);
}
}
}
}
/**
* The first translator to consume codepoints from the input is the 'winner'.
* Execution stops with the number of consumed codepoints being returned.
* {@inheritDoc}
*/
@Override
public int translate(final CharSequence input, final int index, final Writer out) throws IOException {
for (final CharSequenceTranslator translator : translators) {
final int consumed = translator.translate(input, index, out);
if (consumed != 0) {
return consumed;
}
}
return 0;
}
}

View File

@ -1,140 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.commons.text.translate;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Locale;
/**
* An API for translating text.
* Its core use is to escape and unescape text. Because escaping and unescaping
* is completely contextual, the API does not present two separate signatures.
*
* @since 1.0
*/
public abstract class CharSequenceTranslator {
/**
* Array containing the hexadecimal alphabet.
*/
static final char[] HEX_DIGITS = new char[]{'0', '1', '2', '3',
'4', '5', '6', '7',
'8', '9', 'A', 'B',
'C', 'D', 'E', 'F'};
/**
* Translate a set of codepoints, represented by an int index into a CharSequence,
* into another set of codepoints. The number of codepoints consumed must be returned,
* and the only IOExceptions thrown must be from interacting with the Writer so that
* the top level API may reliably ignore StringWriter IOExceptions.
*
* @param input CharSequence that is being translated
* @param index int representing the current point of translation
* @param out Writer to translate the text to
* @return int count of codepoints consumed
* @throws IOException if and only if the Writer produces an IOException
*/
public abstract int translate(CharSequence input, int index, Writer out) throws IOException;
/**
* Helper for non-Writer usage.
*
* @param input CharSequence to be translated
* @return String output of translation
*/
public final String translate(final CharSequence input) {
if (input == null) {
return null;
}
try {
final StringWriter writer = new StringWriter(input.length() * 2);
translate(input, writer);
return writer.toString();
} catch (final IOException ioe) {
// this should never ever happen while writing to a StringWriter
throw new RuntimeException(ioe);
}
}
/**
* Translate an input onto a Writer. This is intentionally final as its algorithm is
* tightly coupled with the abstract method of this class.
*
* @param input CharSequence that is being translated
* @param out Writer to translate the text to
* @throws IOException if and only if the Writer produces an IOException
*/
public final void translate(final CharSequence input, final Writer out) throws IOException {
if (out == null) throw new IllegalArgumentException("The Writer must not be null");
if (input == null) {
return;
}
int pos = 0;
final int len = input.length();
while (pos < len) {
final int consumed = translate(input, pos, out);
if (consumed == 0) {
// inlined implementation of Character.toChars(Character.codePointAt(input, pos))
// avoids allocating temp char arrays and duplicate checks
final char c1 = input.charAt(pos);
out.write(c1);
pos++;
if (Character.isHighSurrogate(c1) && pos < len) {
final char c2 = input.charAt(pos);
if (Character.isLowSurrogate(c2)) {
out.write(c2);
pos++;
}
}
continue;
}
// contract with translators is that they have to understand codepoints
// and they just took care of a surrogate pair
for (int pt = 0; pt < consumed; pt++) {
pos += Character.charCount(Character.codePointAt(input, pos));
}
}
}
/**
* Helper method to create a merger of this translator with another set of
* translators. Useful in customizing the standard functionality.
*
* @param translators CharSequenceTranslator array of translators to merge with this one
* @return CharSequenceTranslator merging this translator with the others
*/
public final CharSequenceTranslator with(final CharSequenceTranslator... translators) {
final CharSequenceTranslator[] newArray = new CharSequenceTranslator[translators.length + 1];
newArray[0] = this;
System.arraycopy(translators, 0, newArray, 1, translators.length);
return new AggregateTranslator(newArray);
}
/**
* <p>Returns an upper case hexadecimal <code>String</code> for the given
* character.</p>
*
* @param codepoint The codepoint to convert.
* @return An upper case hexadecimal <code>String</code>
*/
public static String hex(final int codepoint) {
return Integer.toHexString(codepoint).toUpperCase(Locale.ENGLISH);
}
}

View File

@ -1,51 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.commons.text.translate;
import java.io.IOException;
import java.io.Writer;
/**
* Helper subclass to CharSequenceTranslator to allow for translations that
* will replace up to one character at a time.
*
* @since 1.0
*/
public abstract class CodePointTranslator extends CharSequenceTranslator {
/**
* Implementation of translate that maps onto the abstract translate(int, Writer) method.
* {@inheritDoc}
*/
@Override
public final int translate(final CharSequence input, final int index, final Writer out) throws IOException {
final int codepoint = Character.codePointAt(input, index);
final boolean consumed = translate(codepoint, out);
return consumed ? 1 : 0;
}
/**
* Translate the specified codepoint into another.
*
* @param codepoint int character input to translate
* @param out Writer to optionally push the translated output to
* @return boolean as to whether translation occurred or not
* @throws IOException if and only if the Writer produces an IOException
*/
public abstract boolean translate(int codepoint, Writer out) throws IOException;
}

View File

@ -1,104 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.commons.text.translate;
import java.io.IOException;
import java.io.Writer;
import java.security.InvalidParameterException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
/**
* Translates a value using a lookup table.
*
* @since 1.0
*/
public class LookupTranslator extends CharSequenceTranslator {
/** The mapping to be used in translation. */
private final Map<String, String> lookupMap;
/** The first character of each key in the lookupMap. */
private final HashSet<Character> prefixSet;
/** The length of the shortest key in the lookupMap. */
private final int shortest;
/** The length of the longest key in the lookupMap. */
private final int longest;
/**
* Define the lookup table to be used in translation
*
* Note that, as of Lang 3.1 (the orgin of this code), the key to the lookup
* table is converted to a java.lang.String. This is because we need the key
* to support hashCode and equals(Object), allowing it to be the key for a
* HashMap. See LANG-882.
*
* @param lookupMap Map&lt;CharSequence, CharSequence&gt; table of translator
* mappings
*/
public LookupTranslator(final Map<CharSequence, CharSequence> lookupMap) {
if (lookupMap == null) {
throw new InvalidParameterException("lookupMap cannot be null");
}
this.lookupMap = new HashMap<>();
this.prefixSet = new HashSet<>();
int currentShortest = Integer.MAX_VALUE;
int currentLongest = 0;
Iterator<Map.Entry<CharSequence, CharSequence>> it = lookupMap.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<CharSequence, CharSequence> pair = it.next();
this.lookupMap.put(pair.getKey().toString(), pair.getValue().toString());
this.prefixSet.add(pair.getKey().charAt(0));
final int sz = pair.getKey().length();
if (sz < currentShortest) {
currentShortest = sz;
}
if (sz > currentLongest) {
currentLongest = sz;
}
}
this.shortest = currentShortest;
this.longest = currentLongest;
}
/**
* {@inheritDoc}
*/
@Override
public int translate(final CharSequence input, final int index, final Writer out) throws IOException {
// check if translation exists for the input at position index
if (prefixSet.contains(input.charAt(index))) {
int max = longest;
if (index + longest > input.length()) {
max = input.length() - index;
}
// implement greedy algorithm by trying maximum match first
for (int i = max; i >= shortest; i--) {
final CharSequence subSeq = input.subSequence(index, index + i);
final String result = lookupMap.get(subSeq.toString());
if (result != null) {
out.write(result);
return i;
}
}
}
return 0;
}
}

View File

@ -1,139 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.commons.text.translate;
import java.io.IOException;
import java.io.Writer;
import java.util.Arrays;
import java.util.EnumSet;
/**
* Translate XML numeric entities of the form &amp;#[xX]?\d+;? to
* the specific codepoint.
*
* Note that the semi-colon is optional.
*
* @since 1.0
*/
public class NumericEntityUnescaper extends CharSequenceTranslator {
/** NumericEntityUnescaper option enum. */
public enum OPTION { semiColonRequired, semiColonOptional, errorIfNoSemiColon }
/** EnumSet of OPTIONS, given from the constructor. */
private final EnumSet<OPTION> options;
/**
* Create a UnicodeUnescaper.
*
* The constructor takes a list of options, only one type of which is currently
* available (whether to allow, error or ignore the semi-colon on the end of a
* numeric entity to being missing).
*
* For example, to support numeric entities without a ';':
* new NumericEntityUnescaper(NumericEntityUnescaper.OPTION.semiColonOptional)
* and to throw an IllegalArgumentException when they're missing:
* new NumericEntityUnescaper(NumericEntityUnescaper.OPTION.errorIfNoSemiColon)
*
* Note that the default behaviour is to ignore them.
*
* @param options to apply to this unescaper
*/
public NumericEntityUnescaper(final OPTION... options) {
if (options.length > 0) {
this.options = EnumSet.copyOf(Arrays.asList(options));
} else {
this.options = EnumSet.of(OPTION.semiColonRequired);
}
}
/**
* Whether the passed in option is currently set.
*
* @param option to check state of
* @return whether the option is set
*/
public boolean isSet(final OPTION option) {
return options != null && options.contains(option);
}
/**
* {@inheritDoc}
*/
@Override
public int translate(final CharSequence input, final int index, final Writer out) throws IOException {
final int seqEnd = input.length();
// Uses -2 to ensure there is something after the &#
if (input.charAt(index) == '&' && index < seqEnd - 2 && input.charAt(index + 1) == '#') {
int start = index + 2;
boolean isHex = false;
final char firstChar = input.charAt(start);
if (firstChar == 'x' || firstChar == 'X') {
start++;
isHex = true;
// Check there's more than just an x after the &#
if (start == seqEnd) {
return 0;
}
}
int end = start;
// Note that this supports character codes without a ; on the end
while (end < seqEnd && (input.charAt(end) >= '0' && input.charAt(end) <= '9'
|| input.charAt(end) >= 'a' && input.charAt(end) <= 'f'
|| input.charAt(end) >= 'A' && input.charAt(end) <= 'F')) {
end++;
}
final boolean semiNext = end != seqEnd && input.charAt(end) == ';';
if (!semiNext) {
if (isSet(OPTION.semiColonRequired)) {
return 0;
} else {
if (isSet(OPTION.errorIfNoSemiColon)) {
throw new IllegalArgumentException("Semi-colon required at end of numeric entity");
}
}
}
int entityValue;
try {
if (isHex) {
entityValue = Integer.parseInt(input.subSequence(start, end).toString(), 16);
} else {
entityValue = Integer.parseInt(input.subSequence(start, end).toString(), 10);
}
} catch (final NumberFormatException nfe) {
return 0;
}
if (entityValue > 0xFFFF) {
final char[] chrs = Character.toChars(entityValue);
out.write(chrs[0]);
out.write(chrs[1]);
} else {
out.write(entityValue);
}
return 2 + end - start + (isHex ? 1 : 0) + (semiNext ? 1 : 0);
}
return 0;
}
}

View File

@ -91,6 +91,7 @@ public interface Constants extends TwidereConstants {
String TWIDERE_PREVIEW_NAME = "Twidere Project"; String TWIDERE_PREVIEW_NAME = "Twidere Project";
String TWIDERE_PREVIEW_SCREEN_NAME = "TwidereProject"; String TWIDERE_PREVIEW_SCREEN_NAME = "TwidereProject";
String TWIDERE_PREVIEW_TEXT_HTML = "Twidere is an open source twitter client for Android, see <a href='https://github.com/mariotaku/twidere'>github.com/mariotak&#8230;</a>"; String TWIDERE_PREVIEW_TEXT_HTML = "Twidere is an open source twitter client for Android, see <a href='https://github.com/mariotaku/twidere'>github.com/mariotak&#8230;</a>";
String TWIDERE_PREVIEW_LINK_URI = "https://github.com/TwidereProject/Twidere-Android";
String TWIDERE_PREVIEW_TEXT_UNESCAPED = "Twidere is an open source twitter client for Android, see github.com/mariotak&#8230;"; String TWIDERE_PREVIEW_TEXT_UNESCAPED = "Twidere is an open source twitter client for Android, see github.com/mariotak&#8230;";
String TWIDERE_PREVIEW_SOURCE = "Twidere for Android"; String TWIDERE_PREVIEW_SOURCE = "Twidere for Android";

View File

@ -101,7 +101,7 @@ public class ArrayAdapter<T> extends BaseAdapter implements Filterable {
* instantiating views. * instantiating views.
*/ */
public ArrayAdapter(Context context, int resource) { public ArrayAdapter(Context context, int resource) {
init(context, resource, new ArrayList<T>()); init(context, resource, new ArrayList<>());
} }
/** /**

View File

@ -84,12 +84,9 @@ public class ExtendedDividerItemDecoration extends RecyclerView.ItemDecoration {
} }
public void setPadding(final int left, final int top, final int right, final int bottom) { public void setPadding(final int left, final int top, final int right, final int bottom) {
mPadding = new Padding() { mPadding = (position, rect) -> {
@Override rect.set(left, top, right, bottom);
public boolean get(int position, Rect rect) { return true;
rect.set(left, top, right, bottom);
return true;
}
}; };
} }

View File

@ -66,12 +66,9 @@ public final class DataExportImportTypeSelectorDialogFragment extends BaseDialog
@Override @Override
public final void onClick(final DialogInterface dialog, final int which) { public final void onClick(final DialogInterface dialog, final int which) {
switch (which) { if (which == DialogInterface.BUTTON_POSITIVE) {
case DialogInterface.BUTTON_POSITIVE: { final int flags = getCheckedFlags();
final int flags = getCheckedFlags(); onPositiveButtonClicked(flags);
onPositiveButtonClicked(flags);
break;
}
} }
} }

View File

@ -118,14 +118,11 @@ public class FileSelectorDialogFragment extends BaseDialogFragment implements Lo
builder.setPositiveButton(android.R.string.ok, this); builder.setPositiveButton(android.R.string.ok, this);
} }
final AlertDialog dialog = builder.create(); final AlertDialog dialog = builder.create();
dialog.setOnShowListener(new DialogInterface.OnShowListener() { dialog.setOnShowListener(dialog1 -> {
@Override final AlertDialog alertDialog = (AlertDialog) dialog1;
public void onShow(final DialogInterface dialog) { DialogExtensionsKt.applyTheme(alertDialog);
final AlertDialog alertDialog = (AlertDialog) dialog; final ListView listView = alertDialog.getListView();
DialogExtensionsKt.applyTheme(alertDialog); listView.setOnItemClickListener(FileSelectorDialogFragment.this);
final ListView listView = alertDialog.getListView();
listView.setOnItemClickListener(FileSelectorDialogFragment.this);
}
}); });
return dialog; return dialog;
} }
@ -268,12 +265,9 @@ public class FileSelectorDialogFragment extends BaseDialogFragment implements Lo
private final String[] extensions; private final String[] extensions;
private final Pattern extensions_regex; private final Pattern extensions_regex;
private static final Comparator<File> NAME_COMPARATOR = new Comparator<File>() { private static final Comparator<File> NAME_COMPARATOR = (file1, file2) -> {
@Override final Locale loc = Locale.getDefault();
public int compare(final File file1, final File file2) { return file1.getName().toLowerCase(loc).compareTo(file2.getName().toLowerCase(loc));
final Locale loc = Locale.getDefault();
return file1.getName().toLowerCase(loc).compareTo(file2.getName().toLowerCase(loc));
}
}; };
public FilesLoader(final Context context, final File path, final String[] extensions) { public FilesLoader(final Context context, final File path, final String[] extensions) {

View File

@ -24,7 +24,6 @@ import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener; import android.content.DialogInterface.OnClickListener;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
@ -66,12 +65,10 @@ public class KeyboardShortcutsFragment extends BasePreferenceFragment implements
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) { if (item.getItemId() == R.id.reset) {
case R.id.reset: { final DialogFragment f = new ResetKeyboardShortcutConfirmDialogFragment();
final DialogFragment f = new ResetKeyboardShortcutConfirmDialogFragment(); f.show(getFragmentManager(), "reset_keyboard_shortcut_confirm");
f.show(getFragmentManager(), "reset_keyboard_shortcut_confirm"); return true;
return true;
}
} }
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
} }
@ -90,12 +87,7 @@ public class KeyboardShortcutsFragment extends BasePreferenceFragment implements
mAction = action; mAction = action;
setPersistent(false); setPersistent(false);
setTitle(KeyboardShortcutsHandler.getActionLabel(context, action)); setTitle(KeyboardShortcutsHandler.getActionLabel(context, action));
mPreferencesChangeListener = new OnSharedPreferenceChangeListener() { mPreferencesChangeListener = (preferences, key) -> updateSummary();
@Override
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
updateSummary();
}
};
updateSummary(); updateSummary();
} }
@ -103,8 +95,8 @@ public class KeyboardShortcutsFragment extends BasePreferenceFragment implements
protected void onClick() { protected void onClick() {
final Context context = getContext(); final Context context = getContext();
final Intent intent = new Intent(context, KeyboardShortcutPreferenceCompatActivity.class); final Intent intent = new Intent(context, KeyboardShortcutPreferenceCompatActivity.class);
intent.putExtra(KeyboardShortcutPreferenceCompatActivity.Companion.getEXTRA_CONTEXT_TAG(), mContextTag); intent.putExtra(KeyboardShortcutPreferenceCompatActivity.EXTRA_CONTEXT_TAG, mContextTag);
intent.putExtra(KeyboardShortcutPreferenceCompatActivity.Companion.getEXTRA_KEY_ACTION(), mAction); intent.putExtra(KeyboardShortcutPreferenceCompatActivity.EXTRA_KEY_ACTION, mAction);
context.startActivity(intent); context.startActivity(intent);
} }
@ -132,11 +124,8 @@ public class KeyboardShortcutsFragment extends BasePreferenceFragment implements
implements OnClickListener { implements OnClickListener {
@Override @Override
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
switch (which) { if (which == DialogInterface.BUTTON_POSITIVE) {
case DialogInterface.BUTTON_POSITIVE: { keyboardShortcutsHandler.reset();
keyboardShortcutsHandler.reset();
break;
}
} }
} }
@ -148,12 +137,7 @@ public class KeyboardShortcutsFragment extends BasePreferenceFragment implements
builder.setPositiveButton(android.R.string.ok, this); builder.setPositiveButton(android.R.string.ok, this);
builder.setNegativeButton(android.R.string.cancel, this); builder.setNegativeButton(android.R.string.cancel, this);
final AlertDialog dialog = builder.create(); final AlertDialog dialog = builder.create();
dialog.setOnShowListener(new DialogInterface.OnShowListener() { dialog.setOnShowListener(dialog1 -> DialogExtensionsKt.applyTheme((AlertDialog) dialog1));
@Override
public void onShow(final DialogInterface dialog) {
DialogExtensionsKt.applyTheme((AlertDialog) dialog);
}
});
return dialog; return dialog;
} }
} }

View File

@ -47,24 +47,21 @@ public class ThemedListPreferenceDialogFragmentCompat extends ThemedPreferenceDi
} }
mClickedDialogEntryIndex = preference.findIndexOfValue(preference.getValue()); mClickedDialogEntryIndex = preference.findIndexOfValue(preference.getValue());
builder.setSingleChoiceItems(entries, mClickedDialogEntryIndex, builder.setSingleChoiceItems(entries, mClickedDialogEntryIndex,
new DialogInterface.OnClickListener() { (dialog, which) -> {
public void onClick(DialogInterface dialog, int which) { mClickedDialogEntryIndex = which;
mClickedDialogEntryIndex = which; /*
/* * Clicking on an item simulates the positive button
* Clicking on an item simulates the positive button * click, and dismisses the dialog.
* click, and dismisses the dialog. */
*/ ThemedListPreferenceDialogFragmentCompat.this.onClick(dialog,
ThemedListPreferenceDialogFragmentCompat.this.onClick(dialog, DialogInterface.BUTTON_POSITIVE);
DialogInterface.BUTTON_POSITIVE); dialog.dismiss();
dialog.dismiss();
}
}); });
/* /*
* The typical interaction for list-based dialogs is to have * The typical interaction for list-based dialogs is to have
* click-on-an-item dismiss the dialog instead of the user having to * click-on-an-item dismiss the dialog instead of the user having to
* press 'Ok'. * press 'Ok'.
*/ */
//noinspection ConstantConditions
builder.setPositiveButton(null, null); builder.setPositiveButton(null, null);
} }

View File

@ -68,7 +68,6 @@ public class ObjectCursorLoader<T> extends FixedAsyncTaskLoader<List<T>> {
return new ObjectCursor<>(cursor, indices, mUseCache); return new ObjectCursor<>(cursor, indices, mUseCache);
} }
@SuppressWarnings("TryWithIdenticalCatches")
@NonNull @NonNull
private ObjectCursor.CursorIndices<T> createIndices(final Cursor cursor) { private ObjectCursor.CursorIndices<T> createIndices(final Cursor cursor) {
return ObjectCursor.indicesFrom(cursor, mObjectClass); return ObjectCursor.indicesFrom(cursor, mObjectClass);

View File

@ -447,7 +447,7 @@ public class CronExpression {
if (match) { if (match) {
list.add(str.substring(start, i)); list.add(str.substring(start, i));
} }
return list.toArray(new String[list.size()]); return list.toArray(new String[0]);
} }
} }

View File

@ -92,11 +92,7 @@ public abstract class DrawableHolder {
} }
public static DrawableHolder parse(String str) { public static DrawableHolder parse(String str) {
DrawableHolder icon = builtin(str); return builtin(str);
if (icon != null) {
return icon;
}
return null;
} }
public static List<DrawableHolder> builtins() { public static List<DrawableHolder> builtins() {

View File

@ -100,12 +100,7 @@ abstract class MultiSelectListPreference extends DialogPreference implements IDi
builder.setNegativeButton(android.R.string.cancel, null); builder.setNegativeButton(android.R.string.cancel, null);
builder.setMultiChoiceItems(mNames, mValues, this); builder.setMultiChoiceItems(mNames, mValues, this);
final AlertDialog dialog = builder.create(); final AlertDialog dialog = builder.create();
dialog.setOnShowListener(new DialogInterface.OnShowListener() { dialog.setOnShowListener(dialog1 -> DialogExtensionsKt.applyTheme((AlertDialog) dialog1));
@Override
public void onShow(final DialogInterface dialog) {
DialogExtensionsKt.applyTheme((AlertDialog) dialog);
}
});
return dialog; return dialog;
} }

View File

@ -21,7 +21,6 @@ package org.mariotaku.twidere.preference;
import android.app.Dialog; import android.app.Dialog;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
@ -78,19 +77,9 @@ public class SettingsImportExportPreference extends DialogPreference implements
entries[1] = context.getString(R.string.export_settings); entries[1] = context.getString(R.string.export_settings);
values[0] = new Intent(context, DataImportActivity.class); values[0] = new Intent(context, DataImportActivity.class);
values[1] = new Intent(context, DataExportActivity.class); values[1] = new Intent(context, DataExportActivity.class);
builder.setItems(entries, new DialogInterface.OnClickListener() { builder.setItems(entries, (dialog, which) -> startActivity(values[which]));
@Override
public void onClick(DialogInterface dialog, int which) {
startActivity(values[which]);
}
});
final AlertDialog dialog = builder.create(); final AlertDialog dialog = builder.create();
dialog.setOnShowListener(new DialogInterface.OnShowListener() { dialog.setOnShowListener(dialog1 -> DialogExtensionsKt.applyTheme((AlertDialog) dialog1));
@Override
public void onShow(final DialogInterface dialog) {
DialogExtensionsKt.applyTheme((AlertDialog) dialog);
}
});
return dialog; return dialog;
} }

View File

@ -2,8 +2,6 @@ package org.mariotaku.twidere.preference;
import android.app.Dialog; import android.app.Dialog;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.res.Resources; import android.content.res.Resources;
import android.os.Bundle; import android.os.Bundle;
@ -17,7 +15,6 @@ import android.util.AttributeSet;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ListView; import android.widget.ListView;
import android.widget.SeekBar; import android.widget.SeekBar;
@ -160,42 +157,33 @@ public class ThemeBackgroundPreference extends DialogPreference implements Const
final SharedPreferences preferences = preference.getSharedPreferences(); final SharedPreferences preferences = preference.getSharedPreferences();
preference.setValue(preference.getPersistedString(null)); preference.setValue(preference.getPersistedString(null));
builder.setTitle(preference.getDialogTitle()); builder.setTitle(preference.getDialogTitle());
builder.setSingleChoiceItems(preference.mBackgroundEntries, preference.getValueIndex(), new OnClickListener() { builder.setSingleChoiceItems(preference.mBackgroundEntries, preference.getValueIndex(), (dialog, which) -> {
@Override preference.setSelectedOption(which);
public void onClick(DialogInterface dialog, int which) { updateAlphaVisibility();
preference.setSelectedOption(which);
updateAlphaVisibility();
}
}); });
builder.setPositiveButton(android.R.string.ok, this); builder.setPositiveButton(android.R.string.ok, this);
builder.setNegativeButton(android.R.string.cancel, this); builder.setNegativeButton(android.R.string.cancel, this);
final Dialog dialog = builder.create(); final Dialog dialog = builder.create();
dialog.setOnShowListener(new DialogInterface.OnShowListener() { dialog.setOnShowListener(dialog1 -> {
@Override final AlertDialog alertDialog = (AlertDialog) dialog1;
public void onShow(DialogInterface dialog) { DialogExtensionsKt.applyTheme(alertDialog);
final AlertDialog alertDialog = (AlertDialog) dialog; if (preferences != null) {
DialogExtensionsKt.applyTheme(alertDialog); final LayoutInflater inflater = alertDialog.getLayoutInflater();
if (preferences != null) { final ListView listView = alertDialog.getListView();
final LayoutInflater inflater = alertDialog.getLayoutInflater(); assert listView != null;
final ListView listView = alertDialog.getListView(); final ViewGroup listViewParent = (ViewGroup) listView.getParent();
assert listView != null; listViewParent.removeView(listView);
final ViewGroup listViewParent = (ViewGroup) listView.getParent(); final View view = inflater.inflate(R.layout.dialog_theme_background_preference, listViewParent);
listViewParent.removeView(listView); ((ViewGroup) view.findViewById(R.id.list_container)).addView(listView);
final View view = inflater.inflate(R.layout.dialog_theme_background_preference, listViewParent); mAlphaContainer = view.findViewById(R.id.alpha_container);
((ViewGroup) view.findViewById(R.id.list_container)).addView(listView); mAlphaSlider = view.findViewById(R.id.alpha_slider);
mAlphaContainer = view.findViewById(R.id.alpha_container); mAlphaSlider.setMax(MAX_ALPHA - MIN_ALPHA);
mAlphaSlider = view.findViewById(R.id.alpha_slider); mAlphaSlider.setProgress(preferences.getInt(KEY_THEME_BACKGROUND_ALPHA, DEFAULT_THEME_BACKGROUND_ALPHA) - MIN_ALPHA);
mAlphaSlider.setMax(MAX_ALPHA - MIN_ALPHA); listView.setOnItemClickListener((parent, view1, position, id) -> {
mAlphaSlider.setProgress(preferences.getInt(KEY_THEME_BACKGROUND_ALPHA, DEFAULT_THEME_BACKGROUND_ALPHA) - MIN_ALPHA); preference.setSelectedOption(position);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
preference.setSelectedOption(position);
updateAlphaVisibility();
}
});
updateAlphaVisibility(); updateAlphaVisibility();
} });
updateAlphaVisibility();
} }
}); });
return dialog; return dialog;

View File

@ -31,7 +31,6 @@ import androidx.annotation.Nullable;
import org.mariotaku.twidere.constant.IntentConstants; import org.mariotaku.twidere.constant.IntentConstants;
import org.mariotaku.twidere.util.ServiceUtils.ServiceToken; import org.mariotaku.twidere.util.ServiceUtils.ServiceToken;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask; import java.util.concurrent.FutureTask;
@ -73,12 +72,7 @@ public abstract class AbsServiceInterface<I extends IInterface> implements IInte
final Intent intent = new Intent(IntentConstants.INTENT_ACTION_EXTENSION_SHORTEN_STATUS); final Intent intent = new Intent(IntentConstants.INTENT_ACTION_EXTENSION_SHORTEN_STATUS);
final ComponentName component = ComponentName.unflattenFromString(mShortenerName); final ComponentName component = ComponentName.unflattenFromString(mShortenerName);
intent.setComponent(component); intent.setComponent(component);
final FutureTask<Boolean> futureTask = new FutureTask<>(new Callable<Boolean>() { final FutureTask<Boolean> futureTask = new FutureTask<>(() -> mIInterface != null);
@Override
public Boolean call() throws Exception {
return mIInterface != null;
}
});
mToken = ServiceUtils.bindToService(mContext, intent, new ServiceConnection() { mToken = ServiceUtils.bindToService(mContext, intent, new ServiceConnection() {
@Override @Override
public void onServiceConnected(final ComponentName name, final IBinder obj) { public void onServiceConnected(final ComponentName name, final IBinder obj) {
@ -112,7 +106,6 @@ public abstract class AbsServiceInterface<I extends IInterface> implements IInte
} }
public interface CheckServiceAction { public interface CheckServiceAction {
@SuppressWarnings("RedundantThrows")
void check(@Nullable Bundle metaData) throws CheckServiceException; void check(@Nullable Bundle metaData) throws CheckServiceException;
} }

View File

@ -26,6 +26,7 @@ import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.database.Cursor; import android.database.Cursor;
import android.net.Uri; import android.net.Uri;
import android.os.Build;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.WorkerThread; import androidx.annotation.WorkerThread;
@ -169,7 +170,7 @@ public class DataImportExportUtils implements Constants {
ZipInputStream zipInputStream = new ZipInputStream(inputStream)) { ZipInputStream zipInputStream = new ZipInputStream(inputStream)) {
int flags = 0; int flags = 0;
List<String> entryNames = new ArrayList<>(); List<String> entryNames = new ArrayList<>();
ZipEntry entry = null; ZipEntry entry;
while ((entry = zipInputStream.getNextEntry()) != null) { while ((entry = zipInputStream.getNextEntry()) != null) {
entryNames.add(entry.getName()); entryNames.add(entry.getName());
} }
@ -203,11 +204,11 @@ public class DataImportExportUtils implements Constants {
try (InputStream inputStream = context.getContentResolver().openInputStream(src.getUri()); try (InputStream inputStream = context.getContentResolver().openInputStream(src.getUri());
ZipInputStream zipInputStream = new ZipInputStream(inputStream) ZipInputStream zipInputStream = new ZipInputStream(inputStream)
) { ) {
ZipEntry entry = null; ZipEntry entry;
while ((entry = zipInputStream.getNextEntry()) != null) { while ((entry = zipInputStream.getNextEntry()) != null) {
StringBuilder stringBuilder = new StringBuilder(); StringBuilder stringBuilder = new StringBuilder();
byte[] buffer = new byte[1024]; byte[] buffer = new byte[1024];
int read = 0; int read;
while ((read = zipInputStream.read(buffer, 0, 1024)) >= 0) { while ((read = zipInputStream.read(buffer, 0, 1024)) >= 0) {
stringBuilder.append(new String(buffer, 0, read)); stringBuilder.append(new String(buffer, 0, read));
} }
@ -292,7 +293,15 @@ public class DataImportExportUtils implements Constants {
@NonNull final String preferencesName, @NonNull final String entryName, @NonNull final String preferencesName, @NonNull final String entryName,
@NonNull final SharedPreferencesProcessStrategy strategy, @NonNull final SharedPreferencesProcessStrategy strategy,
@NonNull final String data) throws IOException { @NonNull final String data) throws IOException {
if (!Objects.equals(entry.getName(), entryName)) return; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
if (!Objects.equals(entry.getName(), entryName)) {
return;
}
} else {
if (entry.getName().equals(entryName)) {
return;
}
}
final JsonParser jsonParser = LoganSquare.JSON_FACTORY.createParser(data); final JsonParser jsonParser = LoganSquare.JSON_FACTORY.createParser(data);
if (jsonParser.getCurrentToken() == null) { if (jsonParser.getCurrentToken() == null) {
jsonParser.nextToken(); jsonParser.nextToken();
@ -327,7 +336,15 @@ public class DataImportExportUtils implements Constants {
@NonNull final String data, @NonNull final String data,
@NonNull final ContentResolverProcessStrategy<List<T>> strategy) @NonNull final ContentResolverProcessStrategy<List<T>> strategy)
throws IOException { throws IOException {
if (!Objects.equals(entry.getName(), entryName)) return; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
if (!Objects.equals(entry.getName(), entryName)) {
return;
}
} else {
if (entry.getName().equals(entryName)) {
return;
}
}
List<T> itemsList = JsonSerializer.parseList(data, itemCls); List<T> itemsList = JsonSerializer.parseList(data, itemCls);
strategy.importItem(context.getContentResolver(), itemsList); strategy.importItem(context.getContentResolver(), itemsList);
} }
@ -352,7 +369,15 @@ public class DataImportExportUtils implements Constants {
@NonNull final String data, @NonNull final String data,
@NonNull final ContentResolverProcessStrategy<T> strategy) @NonNull final ContentResolverProcessStrategy<T> strategy)
throws IOException { throws IOException {
if (!Objects.equals(entry.getName(), entryName)) return; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
if (!Objects.equals(entry.getName(), entryName)) {
return;
}
} else {
if (entry.getName().equals(entryName)) {
return;
}
}
T item = JsonSerializer.parse(data, itemCls); T item = JsonSerializer.parse(data, itemCls);
strategy.importItem(context.getContentResolver(), item); strategy.importItem(context.getContentResolver(), item);
} }

View File

@ -132,7 +132,7 @@ public class MouseScrollDirectionDecider {
} }
@SuppressLint("ViewConstructor") @SuppressLint("ViewConstructor")
private class InternalHorizontalScrollView extends HorizontalScrollView { private static class InternalHorizontalScrollView extends HorizontalScrollView {
private final int factor; private final int factor;
private final MouseScrollDirectionDecider decider; private final MouseScrollDirectionDecider decider;

View File

@ -133,7 +133,7 @@ public class MultiSelectManager {
userKeys.add(((ParcelableStatus) item).user_key); userKeys.add(((ParcelableStatus) item).user_key);
} }
} }
return userKeys.toArray(new UserKey[userKeys.size()]); return userKeys.toArray(new UserKey[0]);
} }
public interface Callback { public interface Callback {

View File

@ -113,7 +113,7 @@ public class NotificationManagerWrapper {
} }
private class PostedNotification { private static class PostedNotification {
private final String tag; private final String tag;
private final int id; private final int id;

View File

@ -112,13 +112,11 @@ public class RecyclerViewNavigationHelper implements KeyboardShortcutCallback {
public boolean handleKeyboardShortcutSingle(@NonNull KeyboardShortcutsHandler handler, int keyCode, @NonNull KeyEvent event, int metaState) { public boolean handleKeyboardShortcutSingle(@NonNull KeyboardShortcutsHandler handler, int keyCode, @NonNull KeyEvent event, int metaState) {
final String action = handler.getKeyAction(CONTEXT_TAG_NAVIGATION, keyCode, event, metaState); final String action = handler.getKeyAction(CONTEXT_TAG_NAVIGATION, keyCode, event, metaState);
if (action == null) return false; if (action == null) return false;
switch (action) { if (ACTION_NAVIGATION_TOP.equals(action)) {
case ACTION_NAVIGATION_TOP: { if (iface != null) {
if (iface != null) { iface.scrollToStart();
iface.scrollToStart();
}
return true;
} }
return true;
} }
return false; return false;
} }

View File

@ -325,7 +325,7 @@ public class SwipeDismissListViewTouchListener implements View.OnTouchListener {
return false; return false;
} }
class PendingDismissData implements Comparable<PendingDismissData> { static class PendingDismissData implements Comparable<PendingDismissData> {
public int position; public int position;
public View view; public View view;
@ -391,12 +391,9 @@ public class SwipeDismissListViewTouchListener implements View.OnTouchListener {
} }
}); });
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { animator.addUpdateListener(valueAnimator -> {
@Override lp.height = (Integer) valueAnimator.getAnimatedValue();
public void onAnimationUpdate(ValueAnimator valueAnimator) { dismissView.setLayoutParams(lp);
lp.height = (Integer) valueAnimator.getAnimatedValue();
dismissView.setLayoutParams(lp);
}
}); });
mPendingDismisses.add(new PendingDismissData(dismissPosition, dismissView)); mPendingDismisses.add(new PendingDismissData(dismissPosition, dismissView));

View File

@ -25,6 +25,7 @@ package org.mariotaku.twidere.util.collection;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.ConcurrentModificationException; import java.util.ConcurrentModificationException;
import java.util.Iterator; import java.util.Iterator;
@ -253,8 +254,7 @@ public class CompactHashSet<E> extends java.util.AbstractSet<E> {
@Override @Override
public void clear() { public void clear() {
elements = 0; elements = 0;
for (int ix = 0; ix < objects.length; ix++) Arrays.fill(objects, null);
objects[ix] = null;
freecells = objects.length; freecells = objects.length;
modCount++; modCount++;
} }

View File

@ -81,7 +81,7 @@ public class ContentResolverUtils {
public static int bulkInsert(@NonNull final ContentResolver resolver, @NonNull final Uri uri, public static int bulkInsert(@NonNull final ContentResolver resolver, @NonNull final Uri uri,
@NonNull final Collection<ContentValues> values) { @NonNull final Collection<ContentValues> values) {
return bulkInsert(resolver, uri, values.toArray(new ContentValues[values.size()])); return bulkInsert(resolver, uri, values.toArray(new ContentValues[0]));
} }
public static int bulkInsert(@NonNull final ContentResolver resolver, @NonNull final Uri uri, public static int bulkInsert(@NonNull final ContentResolver resolver, @NonNull final Uri uri,

View File

@ -107,7 +107,7 @@ public final class DatabaseUpgradeHelper {
newInsertColsList.add(newCol); newInsertColsList.add(newCol);
} }
} }
final String[] newInsertCols = newInsertColsList.toArray(new String[newInsertColsList.size()]); final String[] newInsertCols = newInsertColsList.toArray(new String[0]);
if (!TwidereArrayUtils.contains(newInsertCols, notNullCols)) return null; if (!TwidereArrayUtils.contains(newInsertCols, notNullCols)) return null;
qb.columns(newInsertCols); qb.columns(newInsertCols);
final Columns.Column[] oldDataCols = new Columns.Column[newInsertCols.length]; final Columns.Column[] oldDataCols = new Columns.Column[newInsertCols.length];

View File

@ -15,12 +15,7 @@ public class ImgurProvider implements Provider {
public boolean supports(@NonNull String link) { public boolean supports(@NonNull String link) {
final String authority = UriUtils.getAuthority(link); final String authority = UriUtils.getAuthority(link);
if (authority == null) return false; if (authority == null) return false;
switch (authority) { return "i.imgur.com".equals(authority);
case "i.imgur.com":
return true;
default:
return false;
}
} }
@Nullable @Nullable
@ -28,13 +23,11 @@ public class ImgurProvider implements Provider {
public ParcelableMedia from(@NonNull String url) { public ParcelableMedia from(@NonNull String url) {
final String authority = UriUtils.getAuthority(url); final String authority = UriUtils.getAuthority(url);
if (authority == null) return null; if (authority == null) return null;
switch (authority) { if ("i.imgur.com".equals(authority)) {
case "i.imgur.com": { final String path = UriUtils.getPath(url);
final String path = UriUtils.getPath(url); if (path == null) return null;
if (path == null) return null; ParcelableMedia media = new ParcelableMedia();
ParcelableMedia media = new ParcelableMedia(); media.url = url;
media.url = url;
}
} }
return null; return null;
} }

View File

@ -47,13 +47,8 @@ public final class ViewSupport {
} }
} }
@SuppressWarnings("deprecation")
public static void setBackground(final View view, final Drawable background) { public static void setBackground(final View view, final Drawable background) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { ViewAccessorJB.setBackground(view, background);
view.setBackgroundDrawable(background);
} else {
ViewAccessorJB.setBackground(view, background);
}
} }
public static void setButtonTintList(CompoundButton view, ColorStateList list) { public static void setButtonTintList(CompoundButton view, ColorStateList list) {
@ -97,8 +92,8 @@ public final class ViewSupport {
if (cls.isAssignableFrom(view.getClass())) return (T) view; if (cls.isAssignableFrom(view.getClass())) return (T) view;
if (view instanceof ViewGroup) { if (view instanceof ViewGroup) {
for (int i = 0, j = ((ViewGroup) view).getChildCount(); i < j; i++) { for (int i = 0, j = ((ViewGroup) view).getChildCount(); i < j; i++) {
final View found = findViewByType(((ViewGroup) view).getChildAt(i), cls); final T found = findViewByType(((ViewGroup) view).getChildAt(i), cls);
if (found != null) return (T) found; if (found != null) return found;
} }
} }
return null; return null;
@ -130,7 +125,6 @@ public final class ViewSupport {
} }
static void setBackground(final View view, final Drawable background) { static void setBackground(final View view, final Drawable background) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) return;
view.setBackground(background); view.setBackground(background);
} }
} }
@ -142,10 +136,8 @@ public final class ViewSupport {
static void setForeground(final View view, final Drawable foreground) { static void setForeground(final View view, final Drawable foreground) {
if (view instanceof FrameLayout) { if (view instanceof FrameLayout) {
//noinspection RedundantCast
((FrameLayout) view).setForeground(foreground); ((FrameLayout) view).setForeground(foreground);
} else if (view instanceof IForegroundView) { } else if (view instanceof IForegroundView) {
//noinspection RedundantCast
((IForegroundView) view).setForeground(foreground); ((IForegroundView) view).setForeground(foreground);
} }
} }

View File

@ -29,14 +29,12 @@ public class WebSettingsSupport {
} }
public static void setAllowUniversalAccessFromFileURLs(final WebSettings settings, final boolean flag) { public static void setAllowUniversalAccessFromFileURLs(final WebSettings settings, final boolean flag) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) return;
WebSettingsAccessorSDK16.setAllowUniversalAccessFromFileURLs(settings, flag); WebSettingsAccessorSDK16.setAllowUniversalAccessFromFileURLs(settings, flag);
} }
@TargetApi(Build.VERSION_CODES.JELLY_BEAN) @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
private static class WebSettingsAccessorSDK16 { private static class WebSettingsAccessorSDK16 {
private static void setAllowUniversalAccessFromFileURLs(final WebSettings settings, final boolean flag) { private static void setAllowUniversalAccessFromFileURLs(final WebSettings settings, final boolean flag) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) return;
settings.setAllowUniversalAccessFromFileURLs(flag); settings.setAllowUniversalAccessFromFileURLs(flag);
} }
} }

View File

@ -83,7 +83,6 @@ public final class BirthdayView extends LayeredCanvasView {
((AnimatedBitmapLayer) layers[2]).setScale(Math.max(1, w / 160)); ((AnimatedBitmapLayer) layers[2]).setScale(Math.max(1, w / 160));
} }
@SuppressWarnings("deprecation")
@Override @Override
protected boolean fitSystemWindows(@NonNull Rect insets) { protected boolean fitSystemWindows(@NonNull Rect insets) {
final int stripTop = Utils.INSTANCE.getInsetsTopWithoutActionBarHeight(getContext(), insets.top); final int stripTop = Utils.INSTANCE.getInsetsTopWithoutActionBarHeight(getContext(), insets.top);

View File

@ -409,13 +409,11 @@ public class HeaderDrawerLayout extends ViewGroup {
if (dy > 0 && mDrawer.canScrollCallback(-dy) && mDrawer.isTouchingScrollableContent()) { if (dy > 0 && mDrawer.canScrollCallback(-dy) && mDrawer.isTouchingScrollableContent()) {
if (!mDrawer.isUsingDragHelper()) { if (!mDrawer.isUsingDragHelper()) {
// Scrolling up while list still has space to scroll, so make header still // Scrolling up while list still has space to scroll, so make header still
mScrollingHeaderByHelper = false;
return current;
} else { } else {
mDrawer.scrollByCallback(-dy); mDrawer.scrollByCallback(-dy);
mScrollingHeaderByHelper = false;
return current;
} }
mScrollingHeaderByHelper = false;
return current;
} }
final int min = mDrawer.getHeaderTopMinimum(), max = mDrawer.getHeaderTopMaximum(); final int min = mDrawer.getHeaderTopMinimum(), max = mDrawer.getHeaderTopMaximum();
if (top < min && mDrawer.isTouchingScrollableContent() && mDrawer.isUsingDragHelper()) { if (top < min && mDrawer.isTouchingScrollableContent() && mDrawer.isUsingDragHelper()) {

View File

@ -196,17 +196,14 @@ public class ShapedImageView extends AppCompatImageView {
contentHeight = contentBottom - contentTop; contentHeight = contentBottom - contentTop;
final int size = Math.min(contentWidth, contentHeight); final int size = Math.min(contentWidth, contentHeight);
if (OUTLINE_DRAW) { if (!OUTLINE_DRAW) {
drawShape(canvas, mDestination, 0, mBackgroundPaint);
super.onDraw(canvas);
} else {
if (mShadowBitmap != null && mDrawShadow) { if (mShadowBitmap != null && mDrawShadow) {
canvas.drawBitmap(mShadowBitmap, contentLeft + (contentWidth - size) / 2 - mShadowRadius, canvas.drawBitmap(mShadowBitmap, contentLeft + (contentWidth - size) / 2 - mShadowRadius,
contentTop + (contentHeight - size) / 2 - mShadowRadius, null); contentTop + (contentHeight - size) / 2 - mShadowRadius, null);
} }
drawShape(canvas, mDestination, 0, mBackgroundPaint);
super.onDraw(canvas);
} }
drawShape(canvas, mDestination, 0, mBackgroundPaint);
super.onDraw(canvas);
// Then draw the border. // Then draw the border.
if (mBorderEnabled) { if (mBorderEnabled) {
drawBorder(canvas, mDestination); drawBorder(canvas, mDestination);

View File

@ -17,6 +17,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
// Uses https://github.com/george-steel/android-utils/commit/289aff11e53593a55d780f9f5986e49343a79e55
package org.oshkimaadziig.george.androidutils; package org.oshkimaadziig.george.androidutils;
import android.text.Spannable; import android.text.Spannable;
@ -33,7 +35,6 @@ import java.util.regex.Pattern;
* *
* @author George T. Steel * @author George T. Steel
*/ */
@SuppressWarnings("IfCanBeSwitch")
public class SpanFormatter { public class SpanFormatter {
public static final Pattern FORMAT_SEQUENCE = Pattern.compile("%([0-9]+\\$|<?)([^a-zA-z%]*)([[a-zA-Z%]&&[^tT]]|[tT][a-zA-Z])"); public static final Pattern FORMAT_SEQUENCE = Pattern.compile("%([0-9]+\\$|<?)([^a-zA-z%]*)([[a-zA-Z%]&&[^tT]]|[tT][a-zA-Z])");
@ -88,10 +89,10 @@ public class SpanFormatter {
if (typeTerm.equals("%")) { if (typeTerm.equals("%")) {
cookedArg = "%"; cookedArg = "%";
} else if (typeTerm.equals("%")) { } else if (typeTerm.equals("n")) {
cookedArg = "\n"; cookedArg = "\n";
} else { } else {
int argIdx = 0; int argIdx;
if (argTerm.equals("")) argIdx = ++argAt; if (argTerm.equals("")) argIdx = ++argAt;
else if (argTerm.equals("<")) argIdx = argAt; else if (argTerm.equals("<")) argIdx = argAt;
else argIdx = Integer.parseInt(argTerm.substring(0, argTerm.length() - 1)) - 1; else argIdx = Integer.parseInt(argTerm.substring(0, argTerm.length() - 1)) - 1;

View File

@ -25,26 +25,38 @@ import java.util.*
@SuppressLint("RestrictedApi") @SuppressLint("RestrictedApi")
object LocaleHelperAccessor { object LocaleHelperAccessor {
fun forLanguageTag(str: String): Locale { fun forLanguageTag(str: String): Locale {
if (str.contains("-")) { when {
val args = str.split("-").dropLastWhile { it.isEmpty() }.toTypedArray() str.contains("-") -> {
if (args.size > 2) { val args = str.split("-").dropLastWhile { it.isEmpty() }.toTypedArray()
return Locale(args[0], args[1], args[2]) when {
} else if (args.size > 1) { args.size > 2 -> {
return Locale(args[0], args[1]) return Locale(args[0], args[1], args[2])
} else if (args.size == 1) { }
return Locale(args[0]) args.size > 1 -> {
return Locale(args[0], args[1])
}
args.size == 1 -> {
return Locale(args[0])
}
}
} }
} else if (str.contains("_")) { str.contains("_") -> {
val args = str.split("_").dropLastWhile { it.isEmpty() }.toTypedArray() val args = str.split("_").dropLastWhile { it.isEmpty() }.toTypedArray()
if (args.size > 2) { when {
return Locale(args[0], args[1], args[2]) args.size > 2 -> {
} else if (args.size > 1) { return Locale(args[0], args[1], args[2])
return Locale(args[0], args[1]) }
} else if (args.size == 1) { args.size > 1 -> {
return Locale(args[0]) return Locale(args[0], args[1])
}
args.size == 1 -> {
return Locale(args[0])
}
}
}
else -> {
return Locale(str)
} }
} else {
return Locale(str)
} }
throw IllegalArgumentException("Can not parse language tag: [$str]") throw IllegalArgumentException("Can not parse language tag: [$str]")

View File

@ -19,8 +19,12 @@
package androidx.core.view package androidx.core.view
fun createWindowInsetsCompat(obj: Any) = WindowInsetsCompat(obj) import android.annotation.TargetApi
import android.os.Build
import android.view.WindowInsets
@TargetApi(Build.VERSION_CODES.KITKAT_WATCH)
fun createWindowInsetsCompat(obj: Any) = WindowInsetsCompat.toWindowInsetsCompat(obj as WindowInsets)
val WindowInsetsCompat.unwrapped: Any? val WindowInsetsCompat.unwrapped: Any?
@Suppress("RestrictedApi")
get() = this.toWindowInsets() get() = this.toWindowInsets()

View File

@ -1,8 +1,5 @@
package androidx.loader.app package androidx.loader.app
import androidx.loader.app.LoaderManager
import androidx.loader.app.LoaderManagerImpl
/** /**
* Created by mariotaku on 2016/11/26. * Created by mariotaku on 2016/11/26.
*/ */

View File

@ -2,7 +2,6 @@ package androidx.loader.content
import android.content.Context import android.content.Context
import android.os.AsyncTask import android.os.AsyncTask
import androidx.loader.content.AsyncTaskLoader
import org.mariotaku.twidere.extension.set import org.mariotaku.twidere.extension.set
import org.mariotaku.twidere.util.Analyzer import org.mariotaku.twidere.util.Analyzer

View File

@ -19,6 +19,4 @@
package androidx.recyclerview.widget package androidx.recyclerview.widget
import androidx.recyclerview.widget.RecyclerView
val RecyclerView.LayoutManager.recyclerView: RecyclerView? get() = mRecyclerView val RecyclerView.LayoutManager.recyclerView: RecyclerView? get() = mRecyclerView

View File

@ -10,23 +10,23 @@ import android.os.Handler
fun AccountManager.addOnAccountsUpdatedListenerSafe(listener: OnAccountsUpdateListener, fun AccountManager.addOnAccountsUpdatedListenerSafe(listener: OnAccountsUpdateListener,
handler: Handler? = null, updateImmediately: Boolean = false): Boolean { handler: Handler? = null, updateImmediately: Boolean = false): Boolean {
try { return try {
this.addOnAccountsUpdatedListener(listener, handler, updateImmediately) this.addOnAccountsUpdatedListener(listener, handler, updateImmediately)
return true true
} catch (e: IllegalStateException) { } catch (e: IllegalStateException) {
return false false
} catch (e: IllegalArgumentException) { } catch (e: IllegalArgumentException) {
return false false
} }
} }
fun AccountManager.removeOnAccountsUpdatedListenerSafe(listener: OnAccountsUpdateListener): Boolean { fun AccountManager.removeOnAccountsUpdatedListenerSafe(listener: OnAccountsUpdateListener): Boolean {
try { return try {
this.removeOnAccountsUpdatedListener(listener) this.removeOnAccountsUpdatedListener(listener)
return true true
} catch (e: IllegalStateException) { } catch (e: IllegalStateException) {
return false false
} catch (e: IllegalArgumentException) { } catch (e: IllegalArgumentException) {
return false false
} }
} }

View File

@ -13,10 +13,10 @@ fun Collection<*>?.isNullOrEmpty(): Boolean {
} }
fun <T> MutableCollection<T>.addAllEnhanced(collection: Collection<T>, ignoreDuplicates: Boolean): Boolean { fun <T> MutableCollection<T>.addAllEnhanced(collection: Collection<T>, ignoreDuplicates: Boolean): Boolean {
if (ignoreDuplicates) { return if (ignoreDuplicates) {
return addAll(collection.filter { it !in this }) addAll(collection.filter { it !in this })
} else { } else {
return addAll(collection) addAll(collection)
} }
} }
@ -41,7 +41,7 @@ fun <E> Collection<E>.contentEquals(other: Collection<E>): Boolean {
inline fun <reified T> List<T>.subArray(range: IntRange): Array<T> { inline fun <reified T> List<T>.subArray(range: IntRange): Array<T> {
return Array(range.count()) { return Array(range.count()) {
this[range.start + it] this[range.first + it]
} }
} }

View File

@ -20,11 +20,11 @@ fun Context.checkAnySelfPermissionsGranted(vararg permissions: String): Boolean
fun Context.unregisterReceiverSafe(receiver: BroadcastReceiver?): Boolean { fun Context.unregisterReceiverSafe(receiver: BroadcastReceiver?): Boolean {
if (receiver == null) return false if (receiver == null) return false
try { return try {
unregisterReceiver(receiver) unregisterReceiver(receiver)
return true true
} catch (e: IllegalArgumentException) { } catch (e: IllegalArgumentException) {
return false false
} }
} }

View File

@ -26,7 +26,7 @@ fun Cursor.safeGetInt(columnIndex: Int, def: Int = -1) = try {
def def
} }
fun Cursor.safeGetString(columnIndex: Int, def: String = "") = try { fun Cursor.safeGetString(columnIndex: Int, def: String = ""): String = try {
getString(columnIndex) getString(columnIndex)
} catch (e: IllegalStateException) { } catch (e: IllegalStateException) {
def def

View File

@ -58,10 +58,10 @@ val Locale.bcp47Tag: String
} }
val bcp47Tag = StringBuilder(language) val bcp47Tag = StringBuilder(language)
if (!country.isEmpty()) { if (country.isNotEmpty()) {
bcp47Tag.append(SEP).append(country) bcp47Tag.append(SEP).append(country)
} }
if (!variant.isEmpty()) { if (variant.isNotEmpty()) {
bcp47Tag.append(SEP).append(variant) bcp47Tag.append(SEP).append(variant)
} }

View File

@ -48,7 +48,7 @@ fun Number.toLocalizedString(locale: Locale = Locale.getDefault()): String {
val Int.nextPowerOf2: Int val Int.nextPowerOf2: Int
get() { get() {
var n = this var n = this
if (n <= 0 || n > 1 shl 30) throw IllegalArgumentException("n is invalid: " + n) if (n <= 0 || n > 1 shl 30) throw IllegalArgumentException("n is invalid: $n")
n -= 1 n -= 1
n = n or (n shr 16) n = n or (n shr 16)
n = n or (n shr 8) n = n or (n shr 8)

View File

@ -6,5 +6,5 @@ import androidx.recyclerview.widget.RecyclerView
* Created by mariotaku on 16/8/21. * Created by mariotaku on 16/8/21.
*/ */
fun RecyclerView.Adapter<*>.findPositionByItemId(itemId: Long): Int { fun RecyclerView.Adapter<*>.findPositionByItemId(itemId: Long): Int {
return (0 until itemCount).firstOrNull { getItemId(it) == itemId } ?: androidx.recyclerview.widget.RecyclerView.NO_POSITION return (0 until itemCount).firstOrNull { getItemId(it) == itemId } ?: RecyclerView.NO_POSITION
} }

View File

@ -40,5 +40,5 @@ fun InputStream.expectLine(string: String = "", charset: Charset = Charset.defau
fun InputStream.expectBytes(bytes: ByteArray): Boolean { fun InputStream.expectBytes(bytes: ByteArray): Boolean {
val readBytes = ByteArray(bytes.size) val readBytes = ByteArray(bytes.size)
read(readBytes) read(readBytes)
return Arrays.equals(readBytes, bytes) return readBytes.contentEquals(bytes)
} }

View File

@ -35,20 +35,24 @@ object InternalActivityCreator {
activity.maxSortPosition = activity.minSortPosition activity.maxSortPosition = activity.minSortPosition
activity.createdAt = status.getCreatedAt() activity.createdAt = status.getCreatedAt()
if (status.getInReplyToUserId() == accountId) { when {
activity.action = Activity.Action.REPLY status.getInReplyToUserId() == accountId -> {
activity.targetStatuses = arrayOf(status) activity.action = Activity.Action.REPLY
activity.targetStatuses = arrayOf(status)
//TODO set target statuses (in reply to status) //TODO set target statuses (in reply to status)
activity.targetObjectStatuses = arrayOfNulls<Status>(0) activity.targetObjectStatuses = arrayOfNulls<Status>(0)
} else if (status.quotedStatus?.user?.id == accountId) { }
activity.action = Activity.Action.QUOTE status.quotedStatus?.user?.id == accountId -> {
activity.targetStatuses = arrayOf(status) activity.action = Activity.Action.QUOTE
activity.targetObjectStatuses = arrayOfNulls<Status>(0) activity.targetStatuses = arrayOf(status)
} else { activity.targetObjectStatuses = arrayOfNulls<Status>(0)
activity.action = Activity.Action.MENTION }
activity.targetUsers = arrayOfNulls<User>(0) else -> {
activity.targetObjectStatuses = arrayOf(status) activity.action = Activity.Action.MENTION
activity.targetUsers = arrayOfNulls<User>(0)
activity.targetObjectStatuses = arrayOf(status)
}
} }
activity.sourcesSize = 1 activity.sourcesSize = 1
activity.sources = arrayOf(status.getUser()) activity.sources = arrayOf(status.getUser())

View File

@ -34,7 +34,6 @@ import org.mariotaku.twidere.R
import org.mariotaku.twidere.TwidereConstants.* import org.mariotaku.twidere.TwidereConstants.*
import org.mariotaku.twidere.adapter.AccountDetailsAdapter import org.mariotaku.twidere.adapter.AccountDetailsAdapter
import org.mariotaku.twidere.annotation.AccountType import org.mariotaku.twidere.annotation.AccountType
import org.mariotaku.twidere.app.TwidereApplication
import org.mariotaku.twidere.extension.model.isOAuth import org.mariotaku.twidere.extension.model.isOAuth
import org.mariotaku.twidere.model.UserKey import org.mariotaku.twidere.model.UserKey
import org.mariotaku.twidere.model.util.AccountUtils import org.mariotaku.twidere.model.util.AccountUtils

View File

@ -13,8 +13,7 @@ class AssistLauncherActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
val prefs = getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE) val prefs = getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE)
val composeNowAction = prefs.getString(KEY_COMPOSE_NOW_ACTION, VALUE_COMPOSE_NOW_ACTION_COMPOSE) val action = when (prefs.getString(KEY_COMPOSE_NOW_ACTION, VALUE_COMPOSE_NOW_ACTION_COMPOSE)) {
val action = when (composeNowAction) {
VALUE_COMPOSE_NOW_ACTION_TAKE_PHOTO -> INTENT_ACTION_COMPOSE_TAKE_PHOTO VALUE_COMPOSE_NOW_ACTION_TAKE_PHOTO -> INTENT_ACTION_COMPOSE_TAKE_PHOTO
VALUE_COMPOSE_NOW_ACTION_PICK_IMAGE -> INTENT_ACTION_COMPOSE_PICK_IMAGE VALUE_COMPOSE_NOW_ACTION_PICK_IMAGE -> INTENT_ACTION_COMPOSE_PICK_IMAGE
else -> INTENT_ACTION_COMPOSE else -> INTENT_ACTION_COMPOSE

View File

@ -27,22 +27,22 @@ import android.graphics.Rect
import android.nfc.NfcAdapter import android.nfc.NfcAdapter
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import androidx.annotation.StyleRes
import androidx.fragment.app.Fragment
import androidx.core.graphics.ColorUtils
import androidx.core.view.OnApplyWindowInsetsListener
import androidx.core.view.WindowInsetsCompat
import androidx.appcompat.app.TwilightManagerAccessor
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceFragmentCompat.OnPreferenceDisplayDialogCallback
import androidx.appcompat.view.menu.ActionMenuItemView
import androidx.appcompat.widget.TwidereActionMenuView
import android.util.AttributeSet import android.util.AttributeSet
import android.view.KeyEvent import android.view.KeyEvent
import android.view.MotionEvent import android.view.MotionEvent
import android.view.View import android.view.View
import android.view.WindowManager import android.view.WindowManager
import androidx.annotation.StyleRes
import androidx.appcompat.app.TwilightManagerAccessor
import androidx.appcompat.view.menu.ActionMenuItemView
import androidx.appcompat.widget.TwidereActionMenuView
import androidx.core.graphics.ColorUtils
import androidx.core.view.OnApplyWindowInsetsListener
import androidx.core.view.WindowInsetsCompat
import androidx.fragment.app.Fragment
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceFragmentCompat.OnPreferenceDisplayDialogCallback
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.bumptech.glide.RequestManager import com.bumptech.glide.RequestManager
import com.squareup.otto.Bus import com.squareup.otto.Bus
@ -300,7 +300,7 @@ open class BaseActivity : ChameleonActivity(), IBaseActivity<BaseActivity>, IThe
for (i in 0 until handlerFilter.countDataAuthorities()) { for (i in 0 until handlerFilter.countDataAuthorities()) {
val authorityEntry = handlerFilter.getDataAuthority(i) val authorityEntry = handlerFilter.getDataAuthority(i)
val port = authorityEntry.port val port = authorityEntry.port
intentFilter.addDataAuthority(authorityEntry.host, if (port < 0) null else Integer.toString(port)) intentFilter.addDataAuthority(authorityEntry.host, if (port < 0) null else port.toString())
} }
try { try {
adapter.enableForegroundDispatch(this, intent, arrayOf(intentFilter), null) adapter.enableForegroundDispatch(this, intent, arrayOf(intentFilter), null)
@ -363,7 +363,11 @@ open class BaseActivity : ChameleonActivity(), IBaseActivity<BaseActivity>, IThe
super.attachBaseContext(newBase) super.attachBaseContext(newBase)
return return
} }
super.attachBaseContext(newBase.overriding(locale)) val newContext = newBase.overriding(locale)
super.attachBaseContext(newContext)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
applyOverrideConfiguration(newContext.resources.configuration)
}
} }
override fun executeAfterFragmentResumed(useHandler: Boolean, action: (BaseActivity) -> Unit): Promise<Unit, Exception> { override fun executeAfterFragmentResumed(useHandler: Boolean, action: (BaseActivity) -> Unit): Promise<Unit, Exception> {
@ -465,20 +469,20 @@ open class BaseActivity : ChameleonActivity(), IBaseActivity<BaseActivity>, IThe
} }
private fun newInstance(name: String, context: Context, attrs: AttributeSet): View? { private fun newInstance(name: String, context: Context, attrs: AttributeSet): View? {
try { return try {
val cls = findClass(name) ?: throw ClassNotFoundException(name) val cls = findClass(name) ?: throw ClassNotFoundException(name)
val constructor = cls.getConstructor(Context::class.java, AttributeSet::class.java) val constructor = cls.getConstructor(Context::class.java, AttributeSet::class.java)
return constructor.newInstance(context, attrs) as View constructor.newInstance(context, attrs) as View
} catch (e: InstantiationException) { } catch (e: InstantiationException) {
return null null
} catch (e: IllegalAccessException) { } catch (e: IllegalAccessException) {
return null null
} catch (e: InvocationTargetException) { } catch (e: InvocationTargetException) {
return null null
} catch (e: NoSuchMethodException) { } catch (e: NoSuchMethodException) {
return null null
} catch (e: ClassNotFoundException) { } catch (e: ClassNotFoundException) {
return null null
} }
} }

View File

@ -69,7 +69,7 @@ class ColorPickerDialogActivity : BaseActivity(), Callback {
companion object { companion object {
val RESULT_CLEARED = -2 const val RESULT_CLEARED = -2
} }
} }

View File

@ -113,6 +113,7 @@ import java.text.Normalizer
import java.util.* import java.util.*
import javax.inject.Inject import javax.inject.Inject
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
import kotlin.math.abs
import android.Manifest.permission as AndroidPermission import android.Manifest.permission as AndroidPermission
@SuppressLint("RestrictedApi") @SuppressLint("RestrictedApi")
@ -389,11 +390,15 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
} }
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when (requestCode) { when (requestCode) {
REQUEST_TAKE_PHOTO, REQUEST_PICK_MEDIA -> { REQUEST_TAKE_PHOTO, REQUEST_PICK_MEDIA -> {
if (resultCode == Activity.RESULT_OK && data != null) { if (resultCode == Activity.RESULT_OK && data != null) {
val src = MediaPickerActivity.getMediaUris(data) val src = MediaPickerActivity.getMediaUris(data)
TaskStarter.execute(AddMediaTask(this, src, null, false, false)) TaskStarter.execute(AddMediaTask(this, src, null,
copySrc = false,
deleteSrc = false
))
val extras = data.getBundleExtra(MediaPickerActivity.EXTRA_EXTRAS) val extras = data.getBundleExtra(MediaPickerActivity.EXTRA_EXTRAS)
if (extras?.getBoolean(EXTRA_IS_POSSIBLY_SENSITIVE) == true) { if (extras?.getBoolean(EXTRA_IS_POSSIBLY_SENSITIVE) == true) {
possiblySensitive = true possiblySensitive = true
@ -430,7 +435,10 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
val src = MediaPickerActivity.getMediaUris(data)?.takeIf(Array<Uri>::isNotEmpty) ?: val src = MediaPickerActivity.getMediaUris(data)?.takeIf(Array<Uri>::isNotEmpty) ?:
data.getParcelableExtra<Uri>(EXTRA_IMAGE_URI)?.let { arrayOf(it) } data.getParcelableExtra<Uri>(EXTRA_IMAGE_URI)?.let { arrayOf(it) }
if (src != null) { if (src != null) {
TaskStarter.execute(AddMediaTask(this, src, null, false, false)) TaskStarter.execute(AddMediaTask(this, src, null,
copySrc = false,
deleteSrc = false
))
} }
} }
} }
@ -508,7 +516,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
} }
replyLabel -> { replyLabel -> {
if (replyLabel.visibility != View.VISIBLE) return if (replyLabel.visibility != View.VISIBLE) return
replyLabel.setSingleLine(replyLabel.lineCount > 1) replyLabel.isSingleLine = replyLabel.lineCount > 1
} }
} }
} }
@ -806,8 +814,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
private fun extensionIntentItemSelected(item: MenuItem) { private fun extensionIntentItemSelected(item: MenuItem) {
val intent = item.intent ?: return val intent = item.intent ?: return
try { try {
val action = intent.action when (intent.action) {
when (action) {
INTENT_ACTION_EXTENSION_COMPOSE -> { INTENT_ACTION_EXTENSION_COMPOSE -> {
val accountKeys = accountsAdapter.selectedAccountKeys val accountKeys = accountsAdapter.selectedAccountKeys
intent.putExtra(EXTRA_TEXT, ParseUtils.parseString(editText.text)) intent.putExtra(EXTRA_TEXT, ParseUtils.parseString(editText.text))
@ -1083,16 +1090,20 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
val action = intent.action val action = intent.action
val hasVisibility = intent.hasExtra(EXTRA_VISIBILITY) val hasVisibility = intent.hasExtra(EXTRA_VISIBILITY)
val hasAccountKeys: Boolean val hasAccountKeys: Boolean
if (intent.hasExtra(EXTRA_ACCOUNT_KEYS)) { when {
val accountKeys = intent.getTypedArrayExtra<UserKey>(EXTRA_ACCOUNT_KEYS) intent.hasExtra(EXTRA_ACCOUNT_KEYS) -> {
accountsAdapter.selectedAccountKeys = accountKeys val accountKeys = intent.getTypedArrayExtra<UserKey>(EXTRA_ACCOUNT_KEYS)
hasAccountKeys = true accountsAdapter.selectedAccountKeys = accountKeys
} else if (intent.hasExtra(EXTRA_ACCOUNT_KEY)) { hasAccountKeys = true
val accountKey = intent.getParcelableExtra<UserKey>(EXTRA_ACCOUNT_KEY) }
accountsAdapter.selectedAccountKeys = arrayOf(accountKey) intent.hasExtra(EXTRA_ACCOUNT_KEY) -> {
hasAccountKeys = true val accountKey = intent.getParcelableExtra<UserKey>(EXTRA_ACCOUNT_KEY)
} else { accountsAdapter.selectedAccountKeys = arrayOf(accountKey)
hasAccountKeys = false hasAccountKeys = true
}
else -> {
hasAccountKeys = false
}
} }
when (action) { when (action) {
Intent.ACTION_SEND, Intent.ACTION_SEND_MULTIPLE -> { Intent.ACTION_SEND, Intent.ACTION_SEND_MULTIPLE -> {
@ -1101,7 +1112,10 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
val stream = intent.getStreamExtra() val stream = intent.getStreamExtra()
if (stream != null) { if (stream != null) {
val src = stream.toTypedArray() val src = stream.toTypedArray()
TaskStarter.execute(AddMediaTask(this, src, null, true, false)) TaskStarter.execute(AddMediaTask(this, src, null,
copySrc = true,
deleteSrc = false
))
} }
} }
else -> { else -> {
@ -1110,7 +1124,10 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
val data = intent.data val data = intent.data
if (data != null) { if (data != null) {
val src = arrayOf(data) val src = arrayOf(data)
TaskStarter.execute(AddMediaTask(this, src, null, true, false)) TaskStarter.execute(AddMediaTask(this, src, null,
copySrc = true,
deleteSrc = false
))
} }
} }
} }
@ -1146,16 +1163,16 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
} }
INTENT_ACTION_EDIT_DRAFT -> { INTENT_ACTION_EDIT_DRAFT -> {
val draft: Draft? = intent.getParcelableExtra(EXTRA_DRAFT) val draft: Draft? = intent.getParcelableExtra(EXTRA_DRAFT)
when (draft?.action_type) { return when (draft?.action_type) {
Draft.Action.REPLY -> { Draft.Action.REPLY -> {
return showReplyLabelAndHint((draft.action_extras as? UpdateStatusActionExtras)?.inReplyToStatus) showReplyLabelAndHint((draft.action_extras as? UpdateStatusActionExtras)?.inReplyToStatus)
} }
Draft.Action.QUOTE -> { Draft.Action.QUOTE -> {
return showQuoteLabelAndHint((draft.action_extras as? UpdateStatusActionExtras)?.inReplyToStatus) showQuoteLabelAndHint((draft.action_extras as? UpdateStatusActionExtras)?.inReplyToStatus)
} }
else -> { else -> {
showDefaultLabelAndHint() showDefaultLabelAndHint()
return false false
} }
} }
} }
@ -1785,7 +1802,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
s.setSpan(MarkForDeleteSpan(), start, start + count, s.setSpan(MarkForDeleteSpan(), start, start + count,
Spanned.SPAN_INCLUSIVE_INCLUSIVE) Spanned.SPAN_INCLUSIVE_INCLUSIVE)
} }
if (!imageSources.isEmpty()) { if (imageSources.isNotEmpty()) {
val intent = ThemedMediaPickerActivity.withThemed(this@ComposeActivity) val intent = ThemedMediaPickerActivity.withThemed(this@ComposeActivity)
.getMedia(Uri.parse(imageSources[0])) .getMedia(Uri.parse(imageSources[0]))
.build() .build()
@ -1816,7 +1833,10 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
}) })
editText.customSelectionActionModeCallback = this editText.customSelectionActionModeCallback = this
editText.imageInputListener = { contentInfo -> editText.imageInputListener = { contentInfo ->
val task = AddMediaTask(this, arrayOf(contentInfo.contentUri), null, true, false) val task = AddMediaTask(this, arrayOf(contentInfo.contentUri), null,
copySrc = true,
deleteSrc = false
)
task.callback = { task.callback = {
contentInfo.releasePermission() contentInfo.releasePermission()
} }
@ -1839,8 +1859,8 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
} }
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val context = activity!! val context = requireActivity()
val builder = AlertDialog.Builder(context!!) val builder = AlertDialog.Builder(requireContext())
builder.setMessage(R.string.quote_protected_status_warning_message) builder.setMessage(R.string.quote_protected_status_warning_message)
builder.setPositiveButton(R.string.send_anyway, this) builder.setPositiveButton(R.string.send_anyway, this)
builder.setNegativeButton(android.R.string.cancel, null) builder.setNegativeButton(android.R.string.cancel, null)
@ -1873,8 +1893,8 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
} }
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val context = activity!! val context = requireActivity()
val builder = AlertDialog.Builder(context!!) val builder = AlertDialog.Builder(requireContext())
builder.setMessage(getString(R.string.message_format_compose_message_convert_to_status, builder.setMessage(getString(R.string.message_format_compose_message_convert_to_status,
"@$screenName")) "@$screenName"))
builder.setPositiveButton(R.string.action_send, this) builder.setPositiveButton(R.string.action_send, this)
@ -1886,7 +1906,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
} }
} }
class AttachedMediaItemTouchHelperCallback(adapter: SimpleItemTouchHelperCallback.ItemTouchHelperAdapter) : SimpleItemTouchHelperCallback(adapter) { class AttachedMediaItemTouchHelperCallback(adapter: ItemTouchHelperAdapter) : SimpleItemTouchHelperCallback(adapter) {
override fun isLongPressDragEnabled(): Boolean { override fun isLongPressDragEnabled(): Boolean {
return true return true
@ -1906,7 +1926,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
override fun onChildDraw(c: Canvas, recyclerView: RecyclerView, viewHolder: ViewHolder, dX: Float, dY: Float, actionState: Int, isCurrentlyActive: Boolean) { override fun onChildDraw(c: Canvas, recyclerView: RecyclerView, viewHolder: ViewHolder, dX: Float, dY: Float, actionState: Int, isCurrentlyActive: Boolean) {
if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) { if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
// Fade out the view as it is swiped out of the parent's bounds // Fade out the view as it is swiped out of the parent's bounds
val alpha = ALPHA_FULL - Math.abs(dY) / viewHolder.itemView.height.toFloat() val alpha = ALPHA_FULL - abs(dY) / viewHolder.itemView.height.toFloat()
viewHolder.itemView.alpha = alpha viewHolder.itemView.alpha = alpha
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive) super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive)
} else { } else {
@ -1924,7 +1944,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
} }
companion object { companion object {
val ALPHA_FULL = 1.0f const val ALPHA_FULL = 1.0f
} }
} }
@ -1996,7 +2016,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
set(value) { set(value) {
selection.clear() selection.clear()
for (accountKey in value) { for (accountKey in value) {
selection.put(accountKey, true) selection[accountKey] = true
} }
notifyDataSetChanged() notifyDataSetChanged()
} }
@ -2034,7 +2054,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
fun toggleSelection(position: Int) { fun toggleSelection(position: Int) {
if (accounts == null || position < 0) return if (accounts == null || position < 0) return
val account = accounts!![position] val account = accounts!![position]
selection.put(account.key, true != selection[account.key]) selection[account.key] = true != selection[account.key]
activity.updateAccountSelectionState() activity.updateAccountSelectionState()
activity.updateVisibilityState() activity.updateVisibilityState()
activity.updateSummaryTextState() activity.updateSummaryTextState()
@ -2046,7 +2066,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
if (accounts == null || position < 0) return if (accounts == null || position < 0) return
val account = accounts!![position] val account = accounts!![position]
selection.clear() selection.clear()
selection.put(account.key, true != selection[account.key]) selection[account.key] = true != selection[account.key]
activity.updateAccountSelectionState() activity.updateAccountSelectionState()
activity.updateVisibilityState() activity.updateVisibilityState()
activity.updateSummaryTextState() activity.updateSummaryTextState()
@ -2096,12 +2116,12 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
private class DisplayPlaceNameTask : AbstractTask<ParcelableLocation, List<Address>, ComposeActivity>() { private class DisplayPlaceNameTask : AbstractTask<ParcelableLocation, List<Address>, ComposeActivity>() {
override fun doLongOperation(location: ParcelableLocation): List<Address>? { override fun doLongOperation(location: ParcelableLocation): List<Address>? {
try { return try {
val activity = callback ?: throw IOException("Interrupted") val activity = callback ?: throw IOException("Interrupted")
val gcd = Geocoder(activity, Locale.getDefault()) val gcd = Geocoder(activity, Locale.getDefault())
return gcd.getFromLocation(location.latitude, location.longitude, 1) gcd.getFromLocation(location.latitude, location.longitude, 1)
} catch (e: IOException) { } catch (e: IOException) {
return null null
} }
} }
@ -2119,13 +2139,16 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
textView.spannable = ParcelableLocationUtils.getHumanReadableString(location, 3) textView.spannable = ParcelableLocationUtils.getHumanReadableString(location, 3)
textView.tag = location textView.tag = location
} else { } else {
val tag = textView.tag when (val tag = textView.tag) {
if (tag is Address) { is Address -> {
textView.spannable = tag.locality textView.spannable = tag.locality
} else if (tag is NoAddress) { }
textView.setText(R.string.label_location_your_coarse_location) is NoAddress -> {
} else { textView.setText(R.string.label_location_your_coarse_location)
textView.setText(R.string.getting_location) }
else -> {
textView.setText(R.string.getting_location)
}
} }
} }
} else { } else {

View File

@ -105,12 +105,12 @@ class DataExportActivity : BaseActivity(), DataExportImportTypeSelectorDialogFra
?: return false ?: return false
// val file = File(folder, fileName) // val file = File(folder, fileName)
// file.delete() // file.delete()
try { return try {
DataImportExportUtils.exportData(activity, file, flags) DataImportExportUtils.exportData(activity, file, flags)
return true true
} catch (e: IOException) { } catch (e: IOException) {
Log.w(LOGTAG, e) Log.w(LOGTAG, e)
return false false
} }
} }
@ -134,7 +134,7 @@ class DataExportActivity : BaseActivity(), DataExportImportTypeSelectorDialogFra
} }
companion object { companion object {
private val FRAGMENT_TAG = "import_settings_dialog" private const val FRAGMENT_TAG = "import_settings_dialog"
} }
} }

View File

@ -111,12 +111,12 @@ class DataImportActivity : BaseActivity(), DataExportImportTypeSelectorDialogFra
return false return false
} }
if (!file.isFile) return false if (!file.isFile) return false
try { return try {
DataImportExportUtils.importData(activity, file, flags) DataImportExportUtils.importData(activity, file, flags)
return true true
} catch (e: IOException) { } catch (e: IOException) {
Log.w(LOGTAG, e) Log.w(LOGTAG, e)
return false false
} }
} }
@ -140,7 +140,7 @@ class DataImportActivity : BaseActivity(), DataExportImportTypeSelectorDialogFra
} }
companion object { companion object {
private val FRAGMENT_TAG = "import_settings_dialog" private const val FRAGMENT_TAG = "import_settings_dialog"
} }
} }
@ -152,10 +152,10 @@ class DataImportActivity : BaseActivity(), DataExportImportTypeSelectorDialogFra
return 0 return 0
} }
if (!file.isFile) return 0 if (!file.isFile) return 0
try { return try {
return DataImportExportUtils.getImportedSettingsFlags(activity, file) DataImportExportUtils.getImportedSettingsFlags(activity, file)
} catch (e: IOException) { } catch (e: IOException) {
return 0 0
} }
} }
@ -185,7 +185,7 @@ class DataImportActivity : BaseActivity(), DataExportImportTypeSelectorDialogFra
companion object { companion object {
private val FRAGMENT_TAG = "read_settings_data_dialog" private const val FRAGMENT_TAG = "read_settings_data_dialog"
} }
} }

View File

@ -87,13 +87,17 @@ class FileSelectorActivity : BaseActivity(), FileSelectorDialogFragment.Callback
finish() finish()
return return
} }
if (checkAllSelfPermissionsGranted(AndroidPermissions.READ_EXTERNAL_STORAGE, AndroidPermissions.WRITE_EXTERNAL_STORAGE)) { when {
showPickFileDialog() checkAllSelfPermissionsGranted(AndroidPermissions.READ_EXTERNAL_STORAGE, AndroidPermissions.WRITE_EXTERNAL_STORAGE) -> {
} else if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN) { showPickFileDialog()
val permissions = arrayOf(AndroidPermissions.READ_EXTERNAL_STORAGE, AndroidPermissions.WRITE_EXTERNAL_STORAGE) }
ActivityCompat.requestPermissions(this, permissions, REQUEST_REQUEST_PERMISSIONS) Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN -> {
} else { val permissions = arrayOf(AndroidPermissions.READ_EXTERNAL_STORAGE, AndroidPermissions.WRITE_EXTERNAL_STORAGE)
finishWithDeniedMessage() ActivityCompat.requestPermissions(this, permissions, REQUEST_REQUEST_PERMISSIONS)
}
else -> {
finishWithDeniedMessage()
}
} }
} }

View File

@ -107,6 +107,7 @@ import org.mariotaku.twidere.util.premium.ExtraFeaturesService
import org.mariotaku.twidere.view.HomeDrawerLayout import org.mariotaku.twidere.view.HomeDrawerLayout
import org.mariotaku.twidere.view.TabPagerIndicator import org.mariotaku.twidere.view.TabPagerIndicator
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
import kotlin.math.floor
class HomeActivity : BaseActivity(), OnClickListener, OnPageChangeListener, SupportFragmentCallback, class HomeActivity : BaseActivity(), OnClickListener, OnPageChangeListener, SupportFragmentCallback,
OnLongClickListener, DrawerLayout.DrawerListener { OnLongClickListener, DrawerLayout.DrawerListener {
@ -422,12 +423,18 @@ class HomeActivity : BaseActivity(), OnClickListener, OnPageChangeListener, Supp
if (!ViewCompat.getFitsSystemWindows(homeMenu)) { if (!ViewCompat.getFitsSystemWindows(homeMenu)) {
homeContent.setPadding(0, insets.systemWindowInsetTop, 0, 0) homeContent.setPadding(0, insets.systemWindowInsetTop, 0, 0)
} }
(toolbar.layoutParams as? MarginLayoutParams)?.bottomMargin = insets.systemWindowInsetBottom
(actionsButton.layoutParams as? MarginLayoutParams)?.bottomMargin = (actionsButton.layoutParams as? MarginLayoutParams)?.bottomMargin =
actionsButtonBottomMargin + insets.systemWindowInsetBottom actionsButtonBottomMargin + if (preferences[tabPositionKey] == SharedPreferenceConstants.VALUE_TAB_POSITION_TOP) {
insets.systemWindowInsetBottom
} else {
0
}
return insets return insets
} }
override fun onNewIntent(intent: Intent) { override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
val tabPosition = handleIntent(intent, false) val tabPosition = handleIntent(intent, false)
if (tabPosition >= 0) { if (tabPosition >= 0) {
mainPager.currentItem = tabPosition.coerceInOr(0 until pagerAdapter.count, 0) mainPager.currentItem = tabPosition.coerceInOr(0 until pagerAdapter.count, 0)
@ -623,16 +630,22 @@ class HomeActivity : BaseActivity(), OnClickListener, OnPageChangeListener, Supp
} }
notifyControlBarOffsetChanged() notifyControlBarOffsetChanged()
} else { } else {
val layoutparams = toolbar.layoutParams
val toolbarMarginBottom = if (layoutparams is MarginLayoutParams) {
layoutparams.bottomMargin
} else {
0
}
val translationY = if (mainTabs.columns > 1 || !toolbar.isVisible) { val translationY = if (mainTabs.columns > 1 || !toolbar.isVisible) {
0 0
} else { } else {
(toolbar.height * (offset - 1)).toInt() ((toolbar.height + toolbarMarginBottom) * (offset - 1)).toInt()
} }
toolbar.translationY = -translationY.toFloat() toolbar.translationY = -translationY.toFloat()
windowOverlay.translationY = -translationY.toFloat() windowOverlay.translationY = -translationY.toFloat()
val lp = actionsButton.layoutParams val lp = actionsButton.layoutParams
if (lp is MarginLayoutParams) { if (lp is MarginLayoutParams) {
actionsButton.translationY = (lp.bottomMargin + toolbar.height + actionsButton.height) * (1 - offset) actionsButton.translationY = (lp.bottomMargin + toolbar.height + actionsButton.height + toolbarMarginBottom) * (1 - offset)
} else { } else {
actionsButton.translationY = actionsButton.height * (1 - offset) actionsButton.translationY = actionsButton.height * (1 - offset)
} }
@ -848,7 +861,7 @@ class HomeActivity : BaseActivity(), OnClickListener, OnPageChangeListener, Supp
"wide" -> resources.getDimension(R.dimen.preferred_tab_column_width_wide) "wide" -> resources.getDimension(R.dimen.preferred_tab_column_width_wide)
else -> resources.getDimension(R.dimen.preferred_tab_column_width_normal) else -> resources.getDimension(R.dimen.preferred_tab_column_width_normal)
} }
mainTabs.columns = Math.floor(1.0 / pagerAdapter.getPageWidth(0)).toInt() mainTabs.columns = floor(1.0 / pagerAdapter.getPageWidth(0)).toInt()
} else { } else {
mainPager.pageMargin = 0 mainPager.pageMargin = 0
mainPager.setPageMarginDrawable(null) mainPager.setPageMarginDrawable(null)
@ -1059,7 +1072,7 @@ class HomeActivity : BaseActivity(), OnClickListener, OnPageChangeListener, Supp
class AutoRefreshConfirmDialogFragment : BaseDialogFragment() { class AutoRefreshConfirmDialogFragment : BaseDialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val builder = AlertDialog.Builder(context!!) val builder = AlertDialog.Builder(requireContext())
builder.setTitle(R.string.auto_refresh) builder.setTitle(R.string.auto_refresh)
builder.setMessage(R.string.message_auto_refresh_confirm) builder.setMessage(R.string.message_auto_refresh_confirm)
builder.setPositiveButton(android.R.string.ok) { _, _ -> builder.setPositiveButton(android.R.string.ok) { _, _ ->

View File

@ -171,7 +171,7 @@ class ImageCropperActivity : BaseActivity(), CropImageView.OnSetImageUriComplete
private fun getResultIntent(uri: Uri?, error: Exception?, sampleSize: Int): Intent { private fun getResultIntent(uri: Uri?, error: Exception?, sampleSize: Int): Intent {
val result = CropImage.ActivityResult(cropImageView.imageUri, uri, error, val result = CropImage.ActivityResult(cropImageView.imageUri, uri, error,
cropImageView.cropPoints, cropImageView.cropRect, cropImageView.rotatedDegrees, cropImageView.cropPoints, cropImageView.cropRect, cropImageView.rotatedDegrees,
sampleSize) cropImageView.wholeImageRect, sampleSize)
val intent = Intent() val intent = Intent()
intent.putExtra(CropImage.CROP_IMAGE_EXTRA_RESULT, result) intent.putExtra(CropImage.CROP_IMAGE_EXTRA_RESULT, result)
return intent return intent

View File

@ -30,7 +30,7 @@ class InvalidAccountAlertActivity : FragmentActivity() {
class InvalidAccountAlertDialogFragment : BaseDialogFragment() { class InvalidAccountAlertDialogFragment : BaseDialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val builder = AlertDialog.Builder(context!!) val builder = AlertDialog.Builder(requireContext())
builder.setTitle(R.string.title_error_invalid_account) builder.setTitle(R.string.title_error_invalid_account)
builder.setMessage(R.string.message_error_invalid_account) builder.setMessage(R.string.message_error_invalid_account)
builder.setPositiveButton(android.R.string.ok) { _, _ -> builder.setPositiveButton(android.R.string.ok) { _, _ ->

View File

@ -119,7 +119,7 @@ class KeyboardShortcutPreferenceCompatActivity : BaseActivity(), OnClickListener
companion object { companion object {
val EXTRA_CONTEXT_TAG = "context_tag" const val EXTRA_CONTEXT_TAG = "context_tag"
val EXTRA_KEY_ACTION = "key_action" const val EXTRA_KEY_ACTION = "key_action"
} }
} }

View File

@ -26,7 +26,6 @@ import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.os.Environment import android.os.Environment
import android.os.Parcelable import android.os.Parcelable
import android.provider.MediaStore
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
@ -75,6 +74,8 @@ import org.mariotaku.twidere.view.viewer.MediaSwipeCloseContainer
import java.io.File import java.io.File
import javax.inject.Inject import javax.inject.Inject
import kotlin.concurrent.thread import kotlin.concurrent.thread
import kotlin.math.abs
import kotlin.math.roundToInt
import android.Manifest.permission as AndroidPermissions import android.Manifest.permission as AndroidPermissions
class MediaViewerActivity : BaseActivity(), IMediaViewerActivity, MediaSwipeCloseContainer.Listener, class MediaViewerActivity : BaseActivity(), IMediaViewerActivity, MediaSwipeCloseContainer.Listener,
@ -146,7 +147,7 @@ class MediaViewerActivity : BaseActivity(), IMediaViewerActivity, MediaSwipeClos
activityLayout.statusBarAlpha = offset activityLayout.statusBarAlpha = offset
} }
try { try {
actionBar.hideOffset = Math.round(controlBarHeight * (1f - offset)) actionBar.hideOffset = (controlBarHeight * (1f - offset)).roundToInt()
} catch (e: UnsupportedOperationException) { } catch (e: UnsupportedOperationException) {
// Some device will throw this exception // Some device will throw this exception
hideOffsetNotSupported = true hideOffsetNotSupported = true
@ -181,6 +182,7 @@ class MediaViewerActivity : BaseActivity(), IMediaViewerActivity, MediaSwipeClos
} }
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when (requestCode) { when (requestCode) {
REQUEST_SHARE_MEDIA -> { REQUEST_SHARE_MEDIA -> {
ShareProvider.clearTempFiles(this) ShareProvider.clearTempFiles(this)
@ -367,10 +369,10 @@ class MediaViewerActivity : BaseActivity(), IMediaViewerActivity, MediaSwipeClos
ParcelableMedia.Type.IMAGE -> { ParcelableMedia.Type.IMAGE -> {
val mediaUrl = media.media_url ?: return Fragment.instantiate(this, ExternalBrowserPageFragment::class.java.name, args) as MediaViewerFragment val mediaUrl = media.media_url ?: return Fragment.instantiate(this, ExternalBrowserPageFragment::class.java.name, args) as MediaViewerFragment
args.putParcelable(EXTRA_MEDIA_URI, Uri.parse(mediaUrl)) args.putParcelable(EXTRA_MEDIA_URI, Uri.parse(mediaUrl))
if (mediaUrl.endsWith(".gif")) { return if (mediaUrl.endsWith(".gif")) {
return Fragment.instantiate(this, GifPageFragment::class.java.name, args) as MediaViewerFragment Fragment.instantiate(this, GifPageFragment::class.java.name, args) as MediaViewerFragment
} else { } else {
return Fragment.instantiate(this, ImagePageFragment::class.java.name, args) as MediaViewerFragment Fragment.instantiate(this, ImagePageFragment::class.java.name, args) as MediaViewerFragment
} }
} }
ParcelableMedia.Type.ANIMATED_GIF, ParcelableMedia.Type.CARD_ANIMATED_GIF -> { ParcelableMedia.Type.ANIMATED_GIF, ParcelableMedia.Type.CARD_ANIMATED_GIF -> {
@ -408,10 +410,10 @@ class MediaViewerActivity : BaseActivity(), IMediaViewerActivity, MediaSwipeClos
} }
override fun onSwipeOffsetChanged(offset: Int) { override fun onSwipeOffsetChanged(offset: Int) {
val offsetFactor = 1 - (Math.abs(offset).toFloat() / swipeContainer.height) val offsetFactor = 1 - (abs(offset).toFloat() / swipeContainer.height)
swipeContainer.backgroundAlpha = offsetFactor swipeContainer.backgroundAlpha = offsetFactor
val colorToolbar = overrideTheme.colorToolbar val colorToolbar = overrideTheme.colorToolbar
val alpha = Math.round(Color.alpha(colorToolbar) * offsetFactor).coerceIn(0..255) val alpha = (Color.alpha(colorToolbar) * offsetFactor).roundToInt().coerceIn(0..255)
activityLayout.statusBarAlpha = alpha / 255f activityLayout.statusBarAlpha = alpha / 255f
} }
@ -450,11 +452,7 @@ class MediaViewerActivity : BaseActivity(), IMediaViewerActivity, MediaSwipeClos
} }
private fun instantiateMediaViewerFragment(args: Bundle): MediaViewerFragment { private fun instantiateMediaViewerFragment(args: Bundle): MediaViewerFragment {
return if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { return Fragment.instantiate(this, ExoPlayerPageFragment::class.java.name, args) as MediaViewerFragment
Fragment.instantiate(this, VideoPageFragment::class.java.name, args) as MediaViewerFragment
} else {
Fragment.instantiate(this, ExoPlayerPageFragment::class.java.name, args) as MediaViewerFragment
}
} }
private fun processShareIntent(intent: Intent) { private fun processShareIntent(intent: Intent) {
@ -468,11 +466,10 @@ class MediaViewerActivity : BaseActivity(), IMediaViewerActivity, MediaSwipeClos
if (checkAllSelfPermissionsGranted(AndroidPermissions.WRITE_EXTERNAL_STORAGE)) { if (checkAllSelfPermissionsGranted(AndroidPermissions.WRITE_EXTERNAL_STORAGE)) {
saveToStorage() saveToStorage()
} else { } else {
val permissions: Array<String> val permissions: Array<String> = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { arrayOf(AndroidPermissions.WRITE_EXTERNAL_STORAGE, AndroidPermissions.READ_EXTERNAL_STORAGE)
permissions = arrayOf(AndroidPermissions.WRITE_EXTERNAL_STORAGE, AndroidPermissions.READ_EXTERNAL_STORAGE)
} else { } else {
permissions = arrayOf(AndroidPermissions.WRITE_EXTERNAL_STORAGE) arrayOf(AndroidPermissions.WRITE_EXTERNAL_STORAGE)
} }
PermissionRequestDialog.show(supportFragmentManager, getString(R.string.message_permission_request_save_media), PermissionRequestDialog.show(supportFragmentManager, getString(R.string.message_permission_request_save_media),
permissions, REQUEST_PERMISSION_SAVE_MEDIA) permissions, REQUEST_PERMISSION_SAVE_MEDIA)
@ -503,8 +500,7 @@ class MediaViewerActivity : BaseActivity(), IMediaViewerActivity, MediaSwipeClos
private fun saveToStorage() { private fun saveToStorage() {
val fileInfo = getCurrentCacheFileInfo(saveToStoragePosition) ?: return val fileInfo = getCurrentCacheFileInfo(saveToStoragePosition) ?: return
val type = (fileInfo as? CacheProvider.CacheFileTypeSupport)?.cacheFileType val pubDir = when ((fileInfo as? CacheProvider.CacheFileTypeSupport)?.cacheFileType) {
val pubDir = when (type) {
CacheFileType.VIDEO -> { CacheFileType.VIDEO -> {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES) Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES)
@ -640,10 +636,10 @@ class MediaViewerActivity : BaseActivity(), IMediaViewerActivity, MediaSwipeClos
companion object { companion object {
private val REQUEST_SHARE_MEDIA = 201 private const val REQUEST_SHARE_MEDIA = 201
private val REQUEST_PERMISSION_SAVE_MEDIA = 202 private const val REQUEST_PERMISSION_SAVE_MEDIA = 202
private val REQUEST_PERMISSION_SHARE_MEDIA = 203 private const val REQUEST_PERMISSION_SHARE_MEDIA = 203
private val REQUEST_SELECT_SAVE_MEDIA = 204 private const val REQUEST_SELECT_SAVE_MEDIA = 204
@RequiresApi(Build.VERSION_CODES.JELLY_BEAN) @RequiresApi(Build.VERSION_CODES.JELLY_BEAN)
const val FLAG_SYSTEM_UI_HIDE_BARS = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or const val FLAG_SYSTEM_UI_HIDE_BARS = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or

View File

@ -89,6 +89,7 @@ class PremiumDashboardActivity : BaseActivity() {
} }
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when (resultCode) { when (resultCode) {
REQUEST_PURCHASE_EXTRA_FEATURES -> { REQUEST_PURCHASE_EXTRA_FEATURES -> {
if (resultCode == Activity.RESULT_OK) { if (resultCode == Activity.RESULT_OK) {

View File

@ -171,7 +171,7 @@ class QuickSearchBarActivity : BaseActivity(), OnClickListener, LoaderCallbacks<
override fun onDismiss(listView: ListView, reverseSortedPositions: IntArray) { override fun onDismiss(listView: ListView, reverseSortedPositions: IntArray) {
val adapter = suggestionsList.adapter as SuggestionsAdapter val adapter = suggestionsList.adapter as SuggestionsAdapter
val ids = LongArray(reverseSortedPositions.size) val ids = LongArray(reverseSortedPositions.size)
for (i in 0 until reverseSortedPositions.size) { for (i in reverseSortedPositions.indices) {
val position = reverseSortedPositions[i] val position = reverseSortedPositions[i]
val item = adapter.getSuggestionItem(position) ?: return val item = adapter.getSuggestionItem(position) ?: return
ids[i] = item._id ids[i] = item._id
@ -215,6 +215,7 @@ class QuickSearchBarActivity : BaseActivity(), OnClickListener, LoaderCallbacks<
} }
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when (requestCode) { when (requestCode) {
REQUEST_SCAN_QR -> { REQUEST_SCAN_QR -> {
if (resultCode == Activity.RESULT_OK && data != null) { if (resultCode == Activity.RESULT_OK && data != null) {
@ -504,7 +505,7 @@ class QuickSearchBarActivity : BaseActivity(), OnClickListener, LoaderCallbacks<
private fun getActualPosition(position: Int): Int { private fun getActualPosition(position: Int): Int {
var skipped = 0 var skipped = 0
for (i in 0 until removedPositions.size) { for (i in 0 until removedPositions.size) {
if (position + skipped >= removedPositions.get(i)) { if (position + skipped >= removedPositions[i]) {
skipped++ skipped++
} }
} }
@ -537,10 +538,10 @@ class QuickSearchBarActivity : BaseActivity(), OnClickListener, LoaderCallbacks<
companion object { companion object {
internal val VIEW_TYPE_SEARCH_HISTORY = 0 internal const val VIEW_TYPE_SEARCH_HISTORY = 0
internal val VIEW_TYPE_SAVED_SEARCH = 1 internal const val VIEW_TYPE_SAVED_SEARCH = 1
internal val VIEW_TYPE_USER_SUGGESTION_ITEM = 2 internal const val VIEW_TYPE_USER_SUGGESTION_ITEM = 2
internal val VIEW_TYPE_USER_SCREEN_NAME = 3 internal const val VIEW_TYPE_USER_SCREEN_NAME = 3
} }
} }

View File

@ -54,6 +54,7 @@ import org.mariotaku.twidere.util.DeviceUtils
import org.mariotaku.twidere.util.KeyboardShortcutsHandler import org.mariotaku.twidere.util.KeyboardShortcutsHandler
import org.mariotaku.twidere.util.ThemeUtils import org.mariotaku.twidere.util.ThemeUtils
import java.util.* import java.util.*
import kotlin.system.exitProcess
class SettingsActivity : BaseActivity(), OnItemClickListener, OnPreferenceStartFragmentCallback { class SettingsActivity : BaseActivity(), OnItemClickListener, OnPreferenceStartFragmentCallback {
@ -74,8 +75,7 @@ class SettingsActivity : BaseActivity(), OnItemClickListener, OnPreferenceStartF
shouldTerminate = savedInstanceState.getBoolean(EXTRA_SHOULD_TERMINATE, shouldTerminate) shouldTerminate = savedInstanceState.getBoolean(EXTRA_SHOULD_TERMINATE, shouldTerminate)
} else if (intent.getBooleanExtra(EXTRA_SHOULD_TERMINATE, false)) { } else if (intent.getBooleanExtra(EXTRA_SHOULD_TERMINATE, false)) {
finishNoRestart() finishNoRestart()
System.exit(0) exitProcess(0)
return
} }
val backgroundOption = currentThemeBackgroundOption val backgroundOption = currentThemeBackgroundOption
@ -349,8 +349,8 @@ class SettingsActivity : BaseActivity(), OnItemClickListener, OnPreferenceStartF
companion object { companion object {
val VIEW_TYPE_PREFERENCE_ENTRY = 0 const val VIEW_TYPE_PREFERENCE_ENTRY = 0
val VIEW_TYPE_HEADER_ENTRY = 1 const val VIEW_TYPE_HEADER_ENTRY = 1
} }
} }
@ -388,7 +388,7 @@ class SettingsActivity : BaseActivity(), OnItemClickListener, OnPreferenceStartF
class RestartConfirmDialogFragment : BaseDialogFragment(), DialogInterface.OnClickListener { class RestartConfirmDialogFragment : BaseDialogFragment(), DialogInterface.OnClickListener {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val builder = AlertDialog.Builder(activity!!) val builder = AlertDialog.Builder(requireActivity())
if (arguments?.getBoolean(EXTRA_SHOULD_TERMINATE) == true) { if (arguments?.getBoolean(EXTRA_SHOULD_TERMINATE) == true) {
builder.setMessage(R.string.app_terminate_confirm) builder.setMessage(R.string.app_terminate_confirm)
builder.setNegativeButton(R.string.action_dont_terminate, this) builder.setNegativeButton(R.string.action_dont_terminate, this)
@ -424,7 +424,7 @@ class SettingsActivity : BaseActivity(), OnItemClickListener, OnPreferenceStartF
companion object { companion object {
private val RESULT_SETTINGS_CHANGED = 10 private const val RESULT_SETTINGS_CHANGED = 10
fun setShouldRecreate(activity: Activity) { fun setShouldRecreate(activity: Activity) {
if (activity !is SettingsActivity) return if (activity !is SettingsActivity) return

View File

@ -428,23 +428,30 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher,
internal fun onSignInError(exception: Exception) { internal fun onSignInError(exception: Exception) {
DebugLog.w(LOGTAG, "Sign in error", exception) DebugLog.w(LOGTAG, "Sign in error", exception)
var errorReason: String? = null var errorReason: String? = null
if (exception is AuthenticityTokenException) { when (exception) {
Toast.makeText(this, R.string.message_toast_wrong_api_key, Toast.LENGTH_SHORT).show() is AuthenticityTokenException -> {
errorReason = "wrong_api_key" Toast.makeText(this, R.string.message_toast_wrong_api_key, Toast.LENGTH_SHORT).show()
} else if (exception is WrongUserPassException) { errorReason = "wrong_api_key"
Toast.makeText(this, R.string.message_toast_wrong_username_password, Toast.LENGTH_SHORT).show() }
errorReason = "wrong_username_password" is WrongUserPassException -> {
} else if (exception is SignInTask.WrongBasicCredentialException) { Toast.makeText(this, R.string.message_toast_wrong_username_password, Toast.LENGTH_SHORT).show()
Toast.makeText(this, R.string.message_toast_wrong_username_password, Toast.LENGTH_SHORT).show() errorReason = "wrong_username_password"
errorReason = "wrong_username_password" }
} else if (exception is SignInTask.WrongAPIURLFormatException) { is SignInTask.WrongBasicCredentialException -> {
Toast.makeText(this, R.string.message_toast_wrong_api_key, Toast.LENGTH_SHORT).show() Toast.makeText(this, R.string.message_toast_wrong_username_password, Toast.LENGTH_SHORT).show()
errorReason = "wrong_api_key" errorReason = "wrong_username_password"
} else if (exception is LoginVerificationException) { }
Toast.makeText(this, R.string.message_toast_login_verification_failed, Toast.LENGTH_SHORT).show() is SignInTask.WrongAPIURLFormatException -> {
errorReason = "login_verification_failed" Toast.makeText(this, R.string.message_toast_wrong_api_key, Toast.LENGTH_SHORT).show()
} else { errorReason = "wrong_api_key"
Toast.makeText(this, exception.getErrorMessage(this), Toast.LENGTH_SHORT).show() }
is LoginVerificationException -> {
Toast.makeText(this, R.string.message_toast_login_verification_failed, Toast.LENGTH_SHORT).show()
errorReason = "login_verification_failed"
}
else -> {
Toast.makeText(this, exception.getErrorMessage(this), Toast.LENGTH_SHORT).show()
}
} }
Analyzer.log(SignIn(false, credentialsType = apiConfig.credentialsType, Analyzer.log(SignIn(false, credentialsType = apiConfig.credentialsType,
errorReason = errorReason, accountType = apiConfig.type)) errorReason = errorReason, accountType = apiConfig.type))
@ -573,13 +580,13 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher,
class SignInTypeChooserDialogFragment : BaseDialogFragment(), class SignInTypeChooserDialogFragment : BaseDialogFragment(),
LoaderManager.LoaderCallbacks<List<CustomAPIConfig>> { LoaderManager.LoaderCallbacks<List<CustomAPIConfig>> {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val builder = AlertDialog.Builder(context!!) val builder = AlertDialog.Builder(requireContext())
builder.setView(R.layout.dialog_expandable_list) builder.setView(R.layout.dialog_expandable_list)
val dialog = builder.create() val dialog = builder.create()
dialog.onShow { dialog.onShow {
it.applyTheme() it.applyTheme()
val listView = it.expandableList val listView = it.expandableList
val adapter = LoginTypeAdapter(context!!) val adapter = LoginTypeAdapter(requireContext())
listView.setAdapter(adapter) listView.setAdapter(adapter)
listView.setOnGroupClickListener { _, _, groupPosition, _ -> listView.setOnGroupClickListener { _, _, groupPosition, _ ->
val type = adapter.getGroup(groupPosition) val type = adapter.getGroup(groupPosition)
@ -623,7 +630,7 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher,
AccountType.MASTODON, AccountType.STATUSNET) AccountType.MASTODON, AccountType.STATUSNET)
val result = supportedAccountTypes.mapNotNullTo(ArrayList()) { type -> val result = supportedAccountTypes.mapNotNullTo(ArrayList()) { type ->
if (type == AccountType.MASTODON) return@mapNotNullTo LoginType(type, if (type == AccountType.MASTODON) return@mapNotNullTo LoginType(type,
listOf(CustomAPIConfig.mastodon(context!!))) listOf(CustomAPIConfig.mastodon(requireContext())))
return@mapNotNullTo configGroup[type]?.let { list -> return@mapNotNullTo configGroup[type]?.let { list ->
LoginType(type, list.sortedBy { !it.isDefault }) LoginType(type, list.sortedBy { !it.isDefault })
} }
@ -632,7 +639,7 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher,
} }
override fun onCreateLoader(id: Int, args: Bundle?): Loader<List<CustomAPIConfig>> { override fun onCreateLoader(id: Int, args: Bundle?): Loader<List<CustomAPIConfig>> {
return DefaultAPIConfigLoader(context!!) return DefaultAPIConfigLoader(requireContext())
} }
override fun onLoaderReset(loader: Loader<List<CustomAPIConfig>>) { override fun onLoaderReset(loader: Loader<List<CustomAPIConfig>>) {
@ -694,7 +701,7 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher,
var challengeType: String? = null var challengeType: String? = null
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val builder = AlertDialog.Builder(context!!) val builder = AlertDialog.Builder(requireContext())
builder.setTitle(R.string.login_verification) builder.setTitle(R.string.login_verification)
builder.setView(R.layout.dialog_login_verification_code) builder.setView(R.layout.dialog_login_verification_code)
builder.positive(android.R.string.ok, this::performVerification) builder.positive(android.R.string.ok, this::performVerification)
@ -753,7 +760,7 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher,
class PasswordSignInDialogFragment : BaseDialogFragment() { class PasswordSignInDialogFragment : BaseDialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val builder = AlertDialog.Builder(context!!) val builder = AlertDialog.Builder(requireContext())
builder.setView(R.layout.dialog_password_sign_in) builder.setView(R.layout.dialog_password_sign_in)
builder.positive(R.string.action_sign_in, this::onPositiveButton) builder.positive(R.string.action_sign_in, this::onPositiveButton)
builder.setNegativeButton(android.R.string.cancel, null) builder.setNegativeButton(android.R.string.cancel, null)
@ -809,10 +816,10 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher,
val oauth = newMicroBlogInstance(context, endpoint = endpoint, auth = auth, val oauth = newMicroBlogInstance(context, endpoint = endpoint, auth = auth,
accountType = apiConfig.type, cls = TwitterOAuth::class.java) accountType = apiConfig.type, cls = TwitterOAuth::class.java)
val accessToken: OAuthToken val accessToken: OAuthToken
if (oauthVerifier != null) { accessToken = if (oauthVerifier != null) {
accessToken = oauth.getAccessToken(requestToken, oauthVerifier) oauth.getAccessToken(requestToken, oauthVerifier)
} else { } else {
accessToken = oauth.getAccessToken(requestToken) oauth.getAccessToken(requestToken)
} }
auth = apiConfig.getOAuthAuthorization(accessToken) ?: auth = apiConfig.getOAuthAuthorization(accessToken) ?:
throw MicroBlogException("Invalid OAuth credential") throw MicroBlogException("Invalid OAuth credential")
@ -823,7 +830,7 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher,
accountType = apiConfig.type, cls = MicroBlog::class.java) accountType = apiConfig.type, cls = MicroBlog::class.java)
val apiUser = twitter.verifyCredentials() val apiUser = twitter.verifyCredentials()
var color = analyseUserProfileColor(apiUser) var color = analyseUserProfileColor(apiUser)
val (type, extras) = SignInActivity.detectAccountType(twitter, apiUser, apiConfig.type) val (type, extras) = detectAccountType(twitter, apiUser, apiConfig.type)
val accountKey = apiUser.key val accountKey = apiUser.key
val user = apiUser.toParcelable(accountKey, type, profileImageSize = profileImageSize) val user = apiUser.toParcelable(accountKey, type, profileImageSize = profileImageSize)
val am = AccountManager.get(context) val am = AccountManager.get(context)
@ -901,7 +908,7 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher,
return authOAuth() return authOAuth()
} }
@Throws(OAuthPasswordAuthenticator.AuthenticationException::class, MicroBlogException::class) @Throws(AuthenticationException::class, MicroBlogException::class)
private fun authOAuth(): SignInResponse { private fun authOAuth(): SignInResponse {
val activity = activityRef.get() ?: throw InterruptedException() val activity = activityRef.get() ?: throw InterruptedException()
val endpoint = MicroBlogAPIFactory.getOAuthSignInEndpoint(apiUrlFormat, val endpoint = MicroBlogAPIFactory.getOAuthSignInEndpoint(apiUrlFormat,
@ -940,7 +947,7 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher,
return getOAuthSignInResponse(activity, accessToken, Credentials.Type.XAUTH) return getOAuthSignInResponse(activity, accessToken, Credentials.Type.XAUTH)
} }
@Throws(MicroBlogException::class, OAuthPasswordAuthenticator.AuthenticationException::class) @Throws(MicroBlogException::class, AuthenticationException::class)
private fun authBasic(): SignInResponse { private fun authBasic(): SignInResponse {
val activity = activityRef.get() ?: throw InterruptedException() val activity = activityRef.get() ?: throw InterruptedException()
val versionSuffix = if (apiConfig.isNoVersionSuffix) null else "1.1" val versionSuffix = if (apiConfig.isNoVersionSuffix) null else "1.1"
@ -962,7 +969,7 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher,
} }
var color = analyseUserProfileColor(apiUser) var color = analyseUserProfileColor(apiUser)
val (type, extras) = SignInActivity.detectAccountType(twitter, apiUser, apiConfig.type) val (type, extras) = detectAccountType(twitter, apiUser, apiConfig.type)
val accountKey = apiUser.key val accountKey = apiUser.key
val user = apiUser.toParcelable(accountKey, type, profileImageSize = profileImageSize) val user = apiUser.toParcelable(accountKey, type, profileImageSize = profileImageSize)
val am = AccountManager.get(activity) val am = AccountManager.get(activity)
@ -991,7 +998,7 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher,
accountType = apiConfig.type, cls = MicroBlog::class.java) accountType = apiConfig.type, cls = MicroBlog::class.java)
val apiUser = twitter.verifyCredentials() val apiUser = twitter.verifyCredentials()
var color = analyseUserProfileColor(apiUser) var color = analyseUserProfileColor(apiUser)
val (type, extras) = SignInActivity.detectAccountType(twitter, apiUser, apiConfig.type) val (type, extras) = detectAccountType(twitter, apiUser, apiConfig.type)
val accountKey = apiUser.key val accountKey = apiUser.key
val user = apiUser.toParcelable(accountKey, type, profileImageSize = profileImageSize) val user = apiUser.toParcelable(accountKey, type, profileImageSize = profileImageSize)
val am = AccountManager.get(activity) val am = AccountManager.get(activity)
@ -1018,7 +1025,7 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher,
accountType = apiConfig.type, cls = MicroBlog::class.java) accountType = apiConfig.type, cls = MicroBlog::class.java)
val apiUser = twitter.verifyCredentials() val apiUser = twitter.verifyCredentials()
var color = analyseUserProfileColor(apiUser) var color = analyseUserProfileColor(apiUser)
val (type, extras) = SignInActivity.detectAccountType(twitter, apiUser, apiConfig.type) val (type, extras) = detectAccountType(twitter, apiUser, apiConfig.type)
val accountKey = apiUser.key val accountKey = apiUser.key
val user = apiUser.toParcelable(accountKey, type, profileImageSize = profileImageSize) val user = apiUser.toParcelable(accountKey, type, profileImageSize = profileImageSize)
val am = AccountManager.get(activity) val am = AccountManager.get(activity)
@ -1040,11 +1047,11 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher,
return SignInResponse(account != null, authType, credentials, user, color, type, extras) return SignInResponse(account != null, authType, credentials, user, color, type, extras)
} }
internal class WrongBasicCredentialException : OAuthPasswordAuthenticator.AuthenticationException() internal class WrongBasicCredentialException : AuthenticationException()
internal class WrongAPIURLFormatException : OAuthPasswordAuthenticator.AuthenticationException() internal class WrongAPIURLFormatException : AuthenticationException()
internal inner class InputLoginVerificationCallback : OAuthPasswordAuthenticator.LoginVerificationCallback { internal inner class InputLoginVerificationCallback : LoginVerificationCallback {
override fun getLoginVerification(challengeType: String): String? { override fun getLoginVerification(challengeType: String): String? {
// Dismiss current progress dialog // Dismiss current progress dialog
@ -1087,10 +1094,10 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher,
protected val profileImageSize: String = activity.getString(R.string.profile_image_size) protected val profileImageSize: String = activity.getString(R.string.profile_image_size)
final override fun doInBackground(vararg args: Any?): SingleResponse<SignInResponse> { final override fun doInBackground(vararg args: Any?): SingleResponse<SignInResponse> {
try { return try {
return SingleResponse.getInstance(performLogin()) SingleResponse.getInstance(performLogin())
} catch (e: Exception) { } catch (e: Exception) {
return SingleResponse.getInstance(e) SingleResponse.getInstance(e)
} }
} }
@ -1189,8 +1196,8 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher,
const val REQUEST_BROWSER_TWITTER_SIGN_IN = 101 const val REQUEST_BROWSER_TWITTER_SIGN_IN = 101
const val REQUEST_BROWSER_MASTODON_SIGN_IN = 102 const val REQUEST_BROWSER_MASTODON_SIGN_IN = 102
private val FRAGMENT_TAG_SIGN_IN_PROGRESS = "sign_in_progress" private const val FRAGMENT_TAG_SIGN_IN_PROGRESS = "sign_in_progress"
private val EXTRA_API_LAST_CHANGE = "api_last_change" private const val EXTRA_API_LAST_CHANGE = "api_last_change"
@Throws(IOException::class) @Throws(IOException::class)
internal fun detectAccountType(twitter: MicroBlog, user: User, type: String?): Pair<String, AccountExtras?> { internal fun detectAccountType(twitter: MicroBlog, user: User, type: String?): Pair<String, AccountExtras?> {

View File

@ -41,8 +41,8 @@ class ThemedMediaPickerActivity : MediaPickerActivity() {
companion object { companion object {
fun withThemed(context: Context): MediaPickerActivity.IntentBuilder { fun withThemed(context: Context): IntentBuilder {
val builder = MediaPickerActivity.IntentBuilder(context, ThemedMediaPickerActivity::class.java) val builder = IntentBuilder(context, ThemedMediaPickerActivity::class.java)
builder.cropImageActivityClass(ImageCropperActivity::class.java) builder.cropImageActivityClass(ImageCropperActivity::class.java)
builder.streamDownloaderClass(RestFuNetworkStreamDownloader::class.java) builder.streamDownloaderClass(RestFuNetworkStreamDownloader::class.java)
return builder return builder

View File

@ -93,7 +93,7 @@ class TrendsLocationSelectorActivity : BaseActivity() {
private val list: Array<LocationsMap.LocationsData> get() = arguments?.getTypedArray(EXTRA_DATA) ?: emptyArray() private val list: Array<LocationsMap.LocationsData> get() = arguments?.getTypedArray(EXTRA_DATA) ?: emptyArray()
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val selectorBuilder = AlertDialog.Builder(context!!) val selectorBuilder = AlertDialog.Builder(requireContext())
selectorBuilder.setTitle(R.string.trends_location) selectorBuilder.setTitle(R.string.trends_location)
selectorBuilder.setView(R.layout.dialog_expandable_list) selectorBuilder.setView(R.layout.dialog_expandable_list)
selectorBuilder.setNegativeButton(android.R.string.cancel, null) selectorBuilder.setNegativeButton(android.R.string.cancel, null)
@ -101,7 +101,7 @@ class TrendsLocationSelectorActivity : BaseActivity() {
dialog.onShow { dialog.onShow {
it.applyTheme() it.applyTheme()
val listView = it.expandableList val listView = it.expandableList
val adapter = ExpandableTrendLocationsListAdapter(context!!) val adapter = ExpandableTrendLocationsListAdapter(requireContext())
adapter.data = list adapter.data = list
listView.setAdapter(adapter) listView.setAdapter(adapter)
listView.setOnGroupClickListener(ExpandableListView.OnGroupClickListener { _, _, groupPosition, _ -> listView.setOnGroupClickListener(ExpandableListView.OnGroupClickListener { _, _, groupPosition, _ ->
@ -177,23 +177,14 @@ class TrendsLocationSelectorActivity : BaseActivity() {
} }
override fun getGroupView(groupPosition: Int, isExpanded: Boolean, convertView: View?, parent: ViewGroup): View { override fun getGroupView(groupPosition: Int, isExpanded: Boolean, convertView: View?, parent: ViewGroup): View {
val view: View val view: View = convertView ?: inflater.inflate(android.R.layout.simple_expandable_list_item_1, parent, false)
if (convertView != null) {
view = convertView
} else {
view = inflater.inflate(android.R.layout.simple_expandable_list_item_1, parent, false)
}
view.findViewById<TextView>(android.R.id.text1).text = getGroup(groupPosition).name view.findViewById<TextView>(android.R.id.text1).text = getGroup(groupPosition).name
return view return view
} }
override fun getChildView(groupPosition: Int, childPosition: Int, isLastChild: Boolean, convertView: View?, parent: ViewGroup): View { override fun getChildView(groupPosition: Int, childPosition: Int, isLastChild: Boolean, convertView: View?, parent: ViewGroup): View {
val view: View val view: View =
if (convertView != null) { convertView ?: inflater.inflate(android.R.layout.simple_list_item_1, parent, false)
view = convertView
} else {
view = inflater.inflate(android.R.layout.simple_list_item_1, parent, false)
}
val location = getChild(groupPosition, childPosition) val location = getChild(groupPosition, childPosition)
val text1 = view.findViewById<TextView>(android.R.id.text1) val text1 = view.findViewById<TextView>(android.R.id.text1)
if (location.parentId == WORLDWIDE) { if (location.parentId == WORLDWIDE) {

Some files were not shown because too many files have changed in this diff Show More