Compare commits

...

35 Commits

Author SHA1 Message Date
Tlaster 3b27b0b6ca Merge branch 'maintenance' 2021-03-01 17:57:42 +08:00
Tlaster 17397628fc add SQLiteBlobTooBigException catch for safeMoveToPosition 2021-03-01 17:23:35 +08:00
Tlaster afac44ca43 fix crash at status details adapter 2021-03-01 17:13:16 +08:00
Tlaster 9d9a98d47b fix crash at status details adapter 2021-03-01 16:55:25 +08:00
Tlaster b1557f17be make advance filter list enabled for fdroid 2021-03-01 16:32:09 +08:00
Tlaster c1430497ac update google commit id 2021-03-01 16:31:28 +08:00
Tlaster 18e42f86a4 upgdate packages and migrate to kotlin 1.4.31 2021-03-01 13:55:17 +08:00
Tlaster e325e886ac fix build 2020-12-22 17:14:57 +08:00
Tlaster cf270b72fc Revert "Add yandex translate support"
This reverts commit 0fc88a4076.
2020-12-22 17:05:12 +08:00
Tlaster 4f137ad827 Revert "fix translate crash"
This reverts commit f054752c65.
2020-12-22 16:56:01 +08:00
TacoTheDank 4729c02ea9 Revert "Move Yandex to Kotlin directory"
This reverts commit c30e8b4da8.
2020-12-22 16:53:30 +08:00
Tlaster dc144f068e version 4.1.6 2020-12-01 14:37:56 +08:00
Tlaster 75c5c09ba6 fix crash when launching 2020-12-01 14:35:47 +08:00
Tlaster fbaf027ce4 upgrade .google.commit-id 2020-11-30 13:16:36 +08:00
Tlaster dac2315e9a version 4.1.5 2020-11-28 21:21:15 +08:00
Tlaster f054752c65 fix translate crash 2020-11-28 21:20:18 +08:00
Suji Yan f3894f15ec
Merge pull request #1375 from HugoPoi/feat/read-write-timeout-configurable
feat: KEY_CONNECTION_TIMEOUT set read write timeouts too
2020-10-11 12:47:57 +08:00
HugoPoi 20f03c002c feat: KEY_CONNECTION_TIMEOUT set read write timeouts too 2020-09-27 14:17:23 +02:00
Suji Yan b473d9d6d8
Merge pull request #1362 from falih-mulyana/feature/text-selection-action
Feature/text selection action
2020-09-14 22:19:54 +08:00
Falih Mulyana 64c93b3ed9 Add custom text selection action to compose tweet from selected text 2020-08-28 23:36:18 +07:00
Suji Yan e600c93f7b
Merge pull request #1345 from PotcFdk/patch-increase-max-user-name-length
Increase the max user profile name length to 50.
2020-08-05 15:11:54 +08:00
PotcFdk 3853ed1f0b Increase the max user profile name length to 50. 2020-07-25 16:10:30 +02:00
Tlaster 44d9b6036a
Merge pull request #1336 from TacoTheDank/maintenance
Lints, libraries, deprecation fixes, and codestyle
2020-07-20 16:17:19 +08:00
Suji Yan 53edcd4897
Merge pull request #1337 from edent/patch-1
Alt text input acts as a normal text box
2020-07-19 20:40:06 +08:00
TacoTheDank 4b2aba0266 Update DNSJava and Exoplayer again 2020-07-14 16:46:57 -04:00
Terence Eden 432924834a
Alt text input acts as a normal text box
Fixes #1326
2020-06-29 14:48:21 +01:00
TacoTheDank 47bf66c628 Update some of Mariotaku's libraries 2020-06-28 23:11:50 -04:00
TacoTheDank 1a833cdaa9 Replace old local QrCodeGen with upstream library 2020-06-28 19:53:12 -04:00
TacoTheDank 5a3f881a52 Refer to commons-lang3 where unnecessary in local code 2020-06-28 19:25:05 -04:00
TacoTheDank f7cea5029a Move lint.xml to lintOptions 2020-06-28 17:27:50 -04:00
TacoTheDank 536371eb89 Fix a bunch of deprecations in Kotlin, and a few misc things 2020-06-28 16:49:50 -04:00
TacoTheDank 894a4aa325 Update subsampling-scale-image-view library 2020-06-27 16:52:47 -04:00
TacoTheDank d3bd4c4dab Update twitter-text library 2020-06-27 16:52:17 -04:00
TacoTheDank b5d735086a Update a few libraries 2020-06-27 16:39:31 -04:00
TacoTheDank 9357456e6a Fix some deprecations 2020-06-26 23:29:14 -04:00
161 changed files with 639 additions and 2284 deletions

View File

@ -2,13 +2,13 @@
buildscript { buildscript {
repositories { repositories {
jcenter() mavenCentral()
maven { url "https://plugins.gradle.org/m2/" } maven { url "https://plugins.gradle.org/m2/" }
google() google()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:4.0.0' classpath 'com.android.tools.build:gradle:4.1.2'
// 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,19 +17,20 @@ buildscript {
allprojects { allprojects {
ext { ext {
projectGroupId = 'org.mariotaku.twidere' projectGroupId = 'org.mariotaku.twidere'
projectVersionCode = 513 projectVersionCode = 515
projectVersionName = '4.1.4' projectVersionName = '4.1.6'
globalCompileSdkVersion = 29 globalCompileSdkVersion = 30
globalBuildToolsVersion = "29.0.3" globalBuildToolsVersion = "30.0.3"
globalMinSdkVersion = 16 globalMinSdkVersion = 16
globalTargetSdkVersion = 29 globalTargetSdkVersion = 30
} }
repositories { repositories {
mavenLocal() mavenLocal()
jcenter() jcenter()// exoplayer and glide-transformations still using jcenter
mavenCentral()
maven { url "https://jitpack.io" } maven { url "https://jitpack.io" }
google() google()
} }
@ -38,18 +39,18 @@ allprojects {
subprojects { subprojects {
buildscript { buildscript {
ext { ext {
kotlinVersion = '1.3.72' kotlinVersion = '1.4.31'
sharedVersions = [ sharedVersions = [
Kotlin : "${kotlinVersion}", Kotlin : "${kotlinVersion}",
LoganSquare : '1.3.7', LoganSquare : '1.3.7',
Jackson : '2.7.4', Jackson : '2.12.1',
ParcelablePlease : '1.0.2', ParcelablePlease : '1.0.2',
ExportablePreferences: '0.9.7', ExportablePreferences: '0.9.7',
MariotakuCommons : '0.9.20', MariotakuCommons : '0.9.22',
ObjectCursor : '0.9.21', ObjectCursor : '0.9.21',
RestFu : '0.9.60', RestFu : '0.9.64',
] ]
} }
} }

View File

@ -1,5 +1,6 @@
#Mon Mar 01 10:46:00 CST 2021
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
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
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-all.zip

View File

@ -1,25 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?><!--
~ Twidere - Twitter client for Android
~
~ Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<lint>
<!-- Disable the given check in this project -->
<issue id="MissingTranslation" severity="ignore" />
<issue id="PluralsCandidate" severity="ignore" />
</lint>

View File

@ -95,7 +95,6 @@ dependencies {
annotationProcessor "com.github.mariotaku.ObjectCursor:processor:${sharedVersions['ObjectCursor']}" annotationProcessor "com.github.mariotaku.ObjectCursor:processor:${sharedVersions['ObjectCursor']}"
implementation "com.github.mariotaku.RestFu:library:${sharedVersions['RestFu']}" implementation "com.github.mariotaku.RestFu:library:${sharedVersions['RestFu']}"
implementation "com.github.mariotaku.RestFu:oauth:${sharedVersions['RestFu']}" implementation "com.github.mariotaku.RestFu:oauth:${sharedVersions['RestFu']}"
implementation "com.github.mariotaku.RestFu:oauth2:${sharedVersions['RestFu']}"
} }
install { install {

View File

@ -67,8 +67,6 @@ public interface TwidereConstants extends SharedPreferenceConstants, IntentConst
String TWITTER_CONSUMER_KEY = "MUUBibXUognm6e9vbzrUIqPkt"; String TWITTER_CONSUMER_KEY = "MUUBibXUognm6e9vbzrUIqPkt";
String TWITTER_CONSUMER_SECRET = "l2uWAgQkoHvDfM2PrRFx2WN4h7QIUIktmxyeTAqRo6TkGCtNKy"; String TWITTER_CONSUMER_SECRET = "l2uWAgQkoHvDfM2PrRFx2WN4h7QIUIktmxyeTAqRo6TkGCtNKy";
String YANDEX_KEY = "trnsl.1.1.20200513T065609Z.8e72845b632aa04f.fe1297e42c152de9e8773e1bc71162b1e498e2a8";
String DEFAULT_TWITTER_API_URL_FORMAT = "https://[DOMAIN].twitter.com/"; String DEFAULT_TWITTER_API_URL_FORMAT = "https://[DOMAIN].twitter.com/";
String SCHEME_HTTP = "http"; String SCHEME_HTTP = "http";

View File

@ -285,8 +285,6 @@ public interface SharedPreferenceConstants {
String KEY_OVERRIDE_LANGUAGE = "override_language"; String KEY_OVERRIDE_LANGUAGE = "override_language";
@ExportablePreference(STRING) @ExportablePreference(STRING)
String KEY_TAB_POSITION = "tab_position"; String KEY_TAB_POSITION = "tab_position";
@ExportablePreference(STRING)
String KEY_YANDEX_KEY = "yandex_key";
@ExportablePreference(BOOLEAN) @ExportablePreference(BOOLEAN)
String KEY_AUTO_HIDE_TABS = "auto_hide_tabs"; String KEY_AUTO_HIDE_TABS = "auto_hide_tabs";
@ExportablePreference(BOOLEAN) @ExportablePreference(BOOLEAN)

View File

@ -38,5 +38,5 @@ android {
} }
dependencies { dependencies {
implementation 'androidx.core:core:1.2.0' implementation 'androidx.core:core:1.3.2'
} }

View File

@ -127,7 +127,7 @@ android {
lintOptions { lintOptions {
checkReleaseBuilds false checkReleaseBuilds false
abortOnError false abortOnError false
lintConfig rootProject.file('lint.xml') disable 'MissingTranslation', 'PluralsCandidate'
} }
packagingOptions { packagingOptions {
@ -175,11 +175,10 @@ ext {
libVersions = [ libVersions = [
Kovenant : '3.3.0', Kovenant : '3.3.0',
Mime4J : '0.7.2', Mime4J : '0.7.2',
Dagger : '2.28', Dagger : '2.32',
Exoplayer : '2.11.5', Exoplayer : '2.13.2',
Glide : '4.11.0', Glide : '4.11.0',
MediaViewerLibrary: '0.9.23', MediaViewerLibrary: '0.9.23',
PlayServices : '17.0.0',
Stetho : '1.5.1', Stetho : '1.5.1',
] ]
} }
@ -189,7 +188,7 @@ dependencies {
implementation project(':twidere.component.nyan') implementation project(':twidere.component.nyan')
/** Kotlin **/ /** Kotlin **/
implementation "org.jetbrains.kotlin:kotlin-stdlib:${sharedVersions['Kotlin']}" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:${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']}"
@ -198,27 +197,26 @@ dependencies {
/** Android support **/ /** Android support **/
implementation 'androidx.annotation:annotation:1.1.0' implementation 'androidx.annotation:annotation:1.1.0'
implementation 'androidx.appcompat:appcompat:1.3.0-alpha01' implementation 'androidx.appcompat:appcompat:1.3.0-beta01'
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-ktx:1.3.2'
implementation 'androidx.core:core-ktx:1.2.0' implementation 'androidx.drawerlayout:drawerlayout:1.1.1'
implementation 'androidx.drawerlayout:drawerlayout:1.1.0-alpha01' implementation 'androidx.exifinterface:exifinterface:1.3.1'
implementation 'androidx.exifinterface:exifinterface:1.2.0'
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-ktx:1.0.0' implementation 'androidx.palette:palette-ktx:1.0.0'
implementation 'androidx.preference:preference:1.1.1' implementation 'androidx.preference:preference-ktx: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.3.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:1.14.7' implementation 'com.twitter.twittertext:twitter-text:3.1.0'
implementation 'com.davemorrissey.labs:subsampling-scale-image-view:3.6.0' implementation 'com.davemorrissey.labs:subsampling-scale-image-view:3.10.0'
implementation 'com.squareup:otto:1.3.8' implementation 'com.squareup:otto:1.3.8'
implementation 'dnsjava:dnsjava:2.1.9' implementation 'dnsjava:dnsjava:3.2.2'
implementation 'com.commonsware.cwac:layouts:0.4.5' 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'
@ -226,6 +224,7 @@ dependencies {
implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.15' 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-lang3:3.10'
implementation 'org.apache.commons:commons-text:1.8' 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']}"
@ -235,7 +234,7 @@ dependencies {
implementation "com.hannesdorfmann.parcelableplease:annotation:${sharedVersions['ParcelablePlease']}" implementation "com.hannesdorfmann.parcelableplease:annotation:${sharedVersions['ParcelablePlease']}"
kapt "com.hannesdorfmann.parcelableplease:processor:${sharedVersions['ParcelablePlease']}" kapt "com.hannesdorfmann.parcelableplease:processor:${sharedVersions['ParcelablePlease']}"
implementation 'com.squareup.okhttp3:okhttp:3.12.12' implementation 'com.squareup.okhttp3:okhttp:3.12.12'
implementation 'com.squareup.okio:okio:2.6.0' implementation 'com.squareup.okio:okio:2.9.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']}"
@ -243,18 +242,19 @@ dependencies {
implementation 'com.getkeepsafe.taptargetview:taptargetview:1.13.0' implementation 'com.getkeepsafe.taptargetview:taptargetview:1.13.0'
implementation 'net.ypresto.androidtranscoder:android-transcoder:0.3.0' implementation 'net.ypresto.androidtranscoder:android-transcoder:0.3.0'
implementation 'org.jsoup:jsoup:1.13.1' implementation 'org.jsoup:jsoup:1.13.1'
implementation "com.google.android.exoplayer:exoplayer-core:${libVersions['Exoplayer']}" implementation "com.google.android.exoplayer:exoplayer:${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['Glide']}@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:4.1.0' implementation 'jp.wasabeef:glide-transformations:4.1.0'
implementation 'com.theartofdev.edmodo:android-image-cropper:2.8.0' implementation 'com.theartofdev.edmodo:android-image-cropper:2.8.0'
implementation 'io.nayuki:qrcodegen:1.6.0'
/** Custom dependencies **/ /** Custom dependencies **/
implementation 'com.github.mariotaku:AbstractTask:0.9.5' implementation 'com.github.mariotaku:AbstractTask:0.9.7'
implementation 'com.github.mariotaku:DragSortListView:0.6.1' implementation 'com.github.mariotaku:DragSortListView:0.6.1'
implementation "com.github.mariotaku.ExportablePreferences:core:${sharedVersions['ExportablePreferences']}" implementation "com.github.mariotaku.ExportablePreferences:core:${sharedVersions['ExportablePreferences']}"
implementation("com.github.mariotaku.CommonsLibrary:emojione-android:${sharedVersions['MariotakuCommons']}") { implementation("com.github.mariotaku.CommonsLibrary:emojione-android:${sharedVersions['MariotakuCommons']}") {
@ -272,26 +272,28 @@ dependencies {
implementation 'com.github.mariotaku:MessageBubbleView:3.5' implementation 'com.github.mariotaku:MessageBubbleView:3.5'
implementation "com.github.mariotaku.ObjectCursor:core:${sharedVersions['ObjectCursor']}" implementation "com.github.mariotaku.ObjectCursor:core:${sharedVersions['ObjectCursor']}"
kapt "com.github.mariotaku.ObjectCursor:processor:${sharedVersions['ObjectCursor']}" kapt "com.github.mariotaku.ObjectCursor:processor:${sharedVersions['ObjectCursor']}"
implementation 'com.github.mariotaku:PickNCrop:0.9.27' implementation 'com.github.mariotaku:PickNCrop:0.9.29'
implementation "com.github.mariotaku.RestFu:library:${sharedVersions['RestFu']}" implementation "com.github.mariotaku.RestFu:library:${sharedVersions['RestFu']}"
implementation "com.github.mariotaku.RestFu:logansquare:${sharedVersions['RestFu']}" implementation "com.github.mariotaku.RestFu:logansquare:${sharedVersions['RestFu']}"
implementation "com.github.mariotaku.RestFu:oauth:${sharedVersions['RestFu']}" implementation "com.github.mariotaku.RestFu:oauth:${sharedVersions['RestFu']}"
implementation "com.github.mariotaku.RestFu:oauth2:${sharedVersions['RestFu']}" implementation "com.github.mariotaku.RestFu:oauth2:${sharedVersions['RestFu']}"
implementation "com.github.mariotaku.RestFu:okhttp3:${sharedVersions['RestFu']}" implementation "com.github.mariotaku.RestFu:okhttp3:${sharedVersions['RestFu']}"
implementation 'com.github.mariotaku:SQLiteQB:0.9.15' implementation 'com.github.mariotaku:SQLiteQB:0.9.15'
implementation 'com.github.mariotaku.UniqR:android:0.9.4' implementation 'com.github.mariotaku.UniqR:android:0.9.10'
implementation 'com.github.Tlaster:Chameleon:0.9.28' implementation 'com.github.Tlaster:Chameleon:0.9.28'
/** Flavor dependencies **/ /** Flavor dependencies **/
fdroidImplementation 'org.osmdroid:osmdroid-android:5.6.5' fdroidImplementation 'org.osmdroid:osmdroid-android:5.6.5'
fdroidImplementation 'ch.acra:acra:4.11' fdroidImplementation 'ch.acra:acra-mail:5.7.0'
fdroidImplementation 'ch.acra:acra-dialog:5.7.0'
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:17.0.0'
googleImplementation "com.google.android.gms:play-services-auth:${libVersions['PlayServices']}" googleImplementation 'com.google.android.gms:play-services-auth:17.0.0'
googleImplementation "com.google.android.gms:play-services-maps:${libVersions['PlayServices']}" googleImplementation 'com.google.android.gms:play-services-maps:17.0.0'
googleImplementation 'com.google.maps.android:android-maps-utils:0.6.2' googleImplementation 'com.google.maps.android:android-maps-utils:0.6.2'
googleImplementation 'com.anjlab.android.iab.v3:library:1.1.0' googleImplementation 'com.anjlab.android.iab.v3:library:1.1.0'
googleImplementation 'com.dropbox.core:dropbox-core-sdk:3.1.3' googleImplementation 'com.dropbox.core:dropbox-core-sdk:3.1.3'
@ -305,7 +307,7 @@ 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:0.5' debugImplementation 'com.github.mariotaku:StethoBeanShellREPL:0.5'
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.3' debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.6'
debugImplementation('com.jayway.jsonpath:json-path:2.4.0') { debugImplementation('com.jayway.jsonpath:json-path:2.4.0') {
exclude group: 'net.minidev', module: 'json-smart' exclude group: 'net.minidev', module: 'json-smart'
} }
@ -314,10 +316,10 @@ dependencies {
/** Testing **/ /** Testing **/
testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.annotation:annotation:1.1.0' androidTestImplementation 'androidx.annotation:annotation:1.1.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test:rules:1.2.0' androidTestImplementation 'androidx.test:rules:1.3.0'
// https://g.co/androidstudio/app-test-app-conflict // https://g.co/androidstudio/app-test-app-conflict
androidTestImplementation 'com.google.code.findbugs:jsr305:3.0.2' androidTestImplementation 'com.google.code.findbugs:jsr305:3.0.2'
} }

View File

@ -1 +1 @@
e7e073e91e9088ca273f8618bf97e4e10f44b42c 7426fa281d7400010fbe834b45f011fa5668aa21

View File

@ -21,7 +21,7 @@ package org.mariotaku.twidere.extension.text.twitter
import androidx.test.platform.app.InstrumentationRegistry import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import com.twitter.Extractor import com.twitter.twittertext.Extractor
import org.junit.Assert import org.junit.Assert
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test

View File

@ -38,15 +38,4 @@ class CrashReportDialogActivity : CrashReportDialog() {
view.setPadding(padding, padding, padding, padding) view.setPadding(padding, padding, padding, padding)
return view return view
} }
override fun getMainView(): View {
val text = TextView(this)
TextViewCompat.setTextAppearance(text, android.R.style.TextAppearance_DeviceDefault_Medium)
val dialogTextId = this.config.resDialogText()
if (dialogTextId != 0) {
text.text = this.getText(dialogTextId)
}
return text
}
} }

View File

@ -27,8 +27,10 @@ import android.app.Application
import android.content.SharedPreferences import android.content.SharedPreferences
import android.os.Build import android.os.Build
import org.acra.ACRA import org.acra.ACRA
import org.acra.ReportingInteractionMode import org.acra.config.CoreConfigurationBuilder
import org.acra.config.ConfigurationBuilder import org.acra.config.DialogConfigurationBuilder
import org.acra.config.MailSenderConfigurationBuilder
import org.acra.data.StringFormat
import org.mariotaku.kpreferences.get import org.mariotaku.kpreferences.get
import org.mariotaku.ktextension.addOnAccountsUpdatedListenerSafe import org.mariotaku.ktextension.addOnAccountsUpdatedListenerSafe
import org.mariotaku.twidere.BuildConfig import org.mariotaku.twidere.BuildConfig
@ -40,6 +42,7 @@ import org.mariotaku.twidere.constant.themeBackgroundAlphaKey
import org.mariotaku.twidere.constant.themeBackgroundOptionKey import org.mariotaku.twidere.constant.themeBackgroundOptionKey
import org.mariotaku.twidere.constant.themeKey import org.mariotaku.twidere.constant.themeKey
/** /**
* Created by mariotaku on 2017/5/8. * Created by mariotaku on 2017/5/8.
*/ */
@ -56,14 +59,17 @@ class ACRAAnalyzer : Analyzer() {
} }
override fun init(application: Application) { override fun init(application: Application) {
val config = ConfigurationBuilder(application) val builder = CoreConfigurationBuilder(application)
.setReportingInteractionMode(ReportingInteractionMode.DIALOG) builder.setBuildConfigClass(BuildConfig::class.java).setReportFormat(StringFormat.JSON)
.setResDialogText(R.string.message_app_crashed) builder.getPluginConfigurationBuilder(DialogConfigurationBuilder::class.java)
.setResDialogTheme(R.style.Theme_Twidere_NoDisplay_DayNight) .setResText(R.string.message_app_crashed)
.setResTheme(R.style.Theme_Twidere_NoDisplay_DayNight)
.setReportDialogClass(CrashReportDialogActivity::class.java) .setReportDialogClass(CrashReportDialogActivity::class.java)
.setEnabled(true)
builder.getPluginConfigurationBuilder(MailSenderConfigurationBuilder::class.java)
.setMailTo(TWIDERE_PROJECT_EMAIL) .setMailTo(TWIDERE_PROJECT_EMAIL)
.build() .setEnabled(true)
ACRA.init(application, config) ACRA.init(application, builder)
val reporter = ACRA.getErrorReporter() val reporter = ACRA.getErrorReporter()
reporter.putCustomData("debug", BuildConfig.DEBUG.toString()) reporter.putCustomData("debug", BuildConfig.DEBUG.toString())
reporter.putCustomData("build.brand", Build.BRAND) reporter.putCustomData("build.brand", Build.BRAND)

View File

@ -249,6 +249,13 @@
<data android:mimeType="image/*"/> <data android:mimeType="image/*"/>
<data android:mimeType="text/plain"/> <data android:mimeType="text/plain"/>
</intent-filter> </intent-filter>
<intent-filter android:label="@string/title_compose">
<action android:name="android.intent.action.PROCESS_TEXT" />
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="text/plain"/>
</intent-filter>
<meta-data <meta-data
android:name="android.support.PARENT_ACTIVITY" android:name="android.support.PARENT_ACTIVITY"

View File

@ -1,94 +0,0 @@
/*
* QR Code generator library (Java)
*
* Copyright (c) Project Nayuki. (MIT License)
* https://www.nayuki.io/page/qr-code-generator-library
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
* - The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* - The Software is provided "as is", without warranty of any kind, express or
* implied, including but not limited to the warranties of merchantability,
* fitness for a particular purpose and noninfringement. In no event shall the
* authors or copyright holders be liable for any claim, damages or other
* liability, whether in an action of contract, tort or otherwise, arising from,
* out of or in connection with the Software or the use or other dealings in the
* Software.
*/
package io.nayuki.qrcodegen;
import androidx.annotation.NonNull;
import java.util.Arrays;
/**
* An appendable sequence of bits. Bits are packed in big endian within a byte.
*/
final class BitBuffer {
/*---- Fields ----*/
private byte[] data;
private int bitLength;
/*---- Constructor ----*/
// Creates an empty bit buffer (length 0).
public BitBuffer() {
data = new byte[16];
bitLength = 0;
}
/*---- Methods ----*/
// Returns the number of bits in the buffer, which is a non-negative value.
public int bitLength() {
return bitLength;
}
// Returns a copy of all bytes, padding up to the nearest byte.
public byte[] getBytes() {
return Arrays.copyOf(data, (bitLength + 7) / 8);
}
// Appends the given number of bits of the given value to this sequence.
// If 0 <= len <= 31, then this requires 0 <= val < 2^len.
public void appendBits(int val, int len) {
if (len < 0 || len > 32 || len < 32 && (val >>> len) != 0)
throw new IllegalArgumentException("Value out of range");
ensureCapacity(bitLength + len);
for (int i = len - 1; i >= 0; i--, bitLength++) // Append bit by bit
data[bitLength >>> 3] |= ((val >>> i) & 1) << (7 - (bitLength & 7));
}
// Appends the data of the given segment to this bit buffer.
public void appendData(@NonNull QrSegment seg) {
ensureCapacity(bitLength + seg.bitLength);
for (int i = 0; i < seg.bitLength; i++, bitLength++) { // Append bit by bit
int bit = (seg.getByte(i >>> 3) >>> (7 - (i & 7))) & 1;
data[bitLength >>> 3] |= bit << (7 - (bitLength & 7));
}
}
// Expands the buffer if necessary, so that it can hold at least the given bit length.
private void ensureCapacity(int newBitLen) {
while (data.length * 8 < newBitLen)
data = Arrays.copyOf(data, data.length * 2);
}
}

View File

@ -1,793 +0,0 @@
/*
* QR Code generator library (Java)
*
* Copyright (c) Project Nayuki. (MIT License)
* https://www.nayuki.io/page/qr-code-generator-library
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
* - The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* - The Software is provided "as is", without warranty of any kind, express or
* implied, including but not limited to the warranties of merchantability,
* fitness for a particular purpose and noninfringement. In no event shall the
* authors or copyright holders be liable for any claim, damages or other
* liability, whether in an action of contract, tort or otherwise, arising from,
* out of or in connection with the Software or the use or other dealings in the
* Software.
*/
package io.nayuki.qrcodegen;
import androidx.annotation.NonNull;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* Represents an immutable square grid of black and white cells for a QR Code symbol, and
* provides static functions to create a QR Code from user-supplied textual or binary data.
* <p>This class covers the QR Code model 2 specification, supporting all versions (sizes)
* from 1 to 40, all 4 error correction levels, and only 3 character encoding modes.</p>
*/
public final class QrCode {
/*---- Public static factory functions ----*/
/**
* Returns a QR Code symbol representing the specified Unicode text string at the specified error correction level.
* As a conservative upper bound, this function is guaranteed to succeed for strings that have 738 or fewer Unicode
* code points (not UTF-16 code units). The smallest possible QR Code version is automatically chosen for the output.
* The ECC level of the result may be higher than the ecl argument if it can be done without increasing the version.
* @param text the text to be encoded, which can be any Unicode string
* @param ecl the error correction level to use (will be boosted)
* @return a QR Code representing the text
* @throws NullPointerException if the text or error correction level is {@code null}
* @throws IllegalArgumentException if the text fails to fit in the largest version QR Code, which means it is too long
*/
public static QrCode encodeText(@NonNull String text, @NonNull Ecc ecl) {
List<QrSegment> segs = QrSegment.makeSegments(text);
return encodeSegments(segs, ecl);
}
/**
* Returns a QR Code symbol representing the specified binary data string at the specified error correction level.
* This function always encodes using the binary segment mode, not any text mode. The maximum number of
* bytes allowed is 2953. The smallest possible QR Code version is automatically chosen for the output.
* The ECC level of the result may be higher than the ecl argument if it can be done without increasing the version.
* @param data the binary data to encode
* @param ecl the error correction level to use (will be boosted)
* @return a QR Code representing the binary data
* @throws NullPointerException if the data or error correction level is {@code null}
* @throws IllegalArgumentException if the data fails to fit in the largest version QR Code, which means it is too long
*/
public static QrCode encodeBinary(@NonNull byte[] data, @NonNull Ecc ecl) {
QrSegment seg = QrSegment.makeBytes(data);
return encodeSegments(Collections.singletonList(seg), ecl);
}
/**
* Returns a QR Code symbol representing the specified data segments at the specified error correction
* level or higher. The smallest possible QR Code version is automatically chosen for the output.
* <p>This function allows the user to create a custom sequence of segments that switches
* between modes (such as alphanumeric and binary) to encode text more efficiently. This
* function is considered to be lower level than simply encoding text or binary data.</p>
* @param segs the segments to encode
* @param ecl the error correction level to use (will be boosted)
* @return a QR Code representing the segments
* @throws NullPointerException if the list of segments, a segment, or the error correction level is {@code null}
* @throws IllegalArgumentException if the data is too long to fit in the largest version QR Code at the ECL
*/
public static QrCode encodeSegments(List<QrSegment> segs, Ecc ecl) {
return encodeSegments(segs, ecl, 1, 40, -1, true);
}
/**
* Returns a QR Code symbol representing the specified data segments with the specified encoding parameters.
* The smallest possible QR Code version within the specified range is automatically chosen for the output.
* <p>This function allows the user to create a custom sequence of segments that switches
* between modes (such as alphanumeric and binary) to encode text more efficiently.
* This function is considered to be lower level than simply encoding text or binary data.</p>
* @param segs the segments to encode
* @param ecl the error correction level to use (may be boosted)
* @param minVersion the minimum allowed version of the QR symbol (at least 1)
* @param maxVersion the maximum allowed version of the QR symbol (at most 40)
* @param mask the mask pattern to use, which is either -1 for automatic choice or from 0 to 7 for fixed choice
* @param boostEcl increases the error correction level if it can be done without increasing the version number
* @return a QR Code representing the segments
* @throws NullPointerException if the list of segments, a segment, or the error correction level is {@code null}
* @throws IllegalArgumentException if 1 &le; minVersion &le; maxVersion &le; 40 is violated, or if mask
* &lt; &minus;1 or mask > 7, or if the data is too long to fit in a QR Code at maxVersion at the ECL
*/
public static QrCode encodeSegments(@NonNull List<QrSegment> segs, @NonNull Ecc ecl, int minVersion, int maxVersion, int mask, boolean boostEcl) {
if (!(1 <= minVersion && minVersion <= maxVersion && maxVersion <= 40) || mask < -1 || mask > 7)
throw new IllegalArgumentException("Invalid value");
// Find the minimal version number to use
int version, dataUsedBits;
for (version = minVersion; ; version++) {
int dataCapacityBits = getNumDataCodewords(version, ecl) * 8; // Number of data bits available
dataUsedBits = QrSegment.getTotalBits(segs, version);
if (dataUsedBits != -1 && dataUsedBits <= dataCapacityBits)
break; // This version number is found to be suitable
if (version >= maxVersion) // All versions in the range could not fit the given data
throw new IllegalArgumentException("Data too long");
}
if (dataUsedBits == -1)
throw new AssertionError();
// Increase the error correction level while the data still fits in the current version number
for (Ecc newEcl : Ecc.values()) {
if (boostEcl && dataUsedBits <= getNumDataCodewords(version, newEcl) * 8)
ecl = newEcl;
}
// Create the data bit string by concatenating all segments
int dataCapacityBits = getNumDataCodewords(version, ecl) * 8;
BitBuffer bb = new BitBuffer();
for (QrSegment seg : segs) {
bb.appendBits(seg.mode.modeBits, 4);
bb.appendBits(seg.numChars, seg.mode.numCharCountBits(version));
bb.appendData(seg);
}
// Add terminator and pad up to a byte if applicable
bb.appendBits(0, Math.min(4, dataCapacityBits - bb.bitLength()));
bb.appendBits(0, (8 - bb.bitLength() % 8) % 8);
// Pad with alternate bytes until data capacity is reached
for (int padByte = 0xEC; bb.bitLength() < dataCapacityBits; padByte ^= 0xEC ^ 0x11)
bb.appendBits(padByte, 8);
if (bb.bitLength() % 8 != 0)
throw new AssertionError();
// Create the QR Code symbol
return new QrCode(version, ecl, bb.getBytes(), mask);
}
/*---- Instance fields ----*/
// Public immutable scalar parameters
/** This QR Code symbol's version number, which is always between 1 and 40 (inclusive). */
public final int version;
/** The width and height of this QR Code symbol, measured in modules.
* Always equal to version &times; 4 + 17, in the range 21 to 177. */
public final int size;
/** The error correction level used in this QR Code symbol. Never {@code null}. */
public final Ecc errorCorrectionLevel;
/** The mask pattern used in this QR Code symbol, in the range 0 to 7 (i.e. unsigned 3-bit integer).
* Note that even if a constructor was called with automatic masking requested
* (mask = -1), the resulting object will still have a mask value between 0 and 7. */
public final int mask;
// Private grids of modules/pixels (conceptually immutable)
private boolean[][] modules; // The modules of this QR Code symbol (false = white, true = black)
private boolean[][] isFunction; // Indicates function modules that are not subjected to masking
/*---- Constructors ----*/
/**
* Creates a new QR Code symbol with the specified version number, error correction level, binary data array, and mask number.
* <p>This is a cumbersome low-level constructor that should not be invoked directly by the user.
* To go one level up, see the {@link #encodeSegments(List,Ecc)} function.</p>
* @param ver the version number to use, which must be in the range 1 to 40, inclusive
* @param ecl the error correction level to use
* @param dataCodewords the raw binary user data to encode
* @param mask the mask pattern to use, which is either -1 for automatic choice or from 0 to 7 for fixed choice
* @throws NullPointerException if the byte array or error correction level is {@code null}
* @throws IllegalArgumentException if the version or mask value is out of range
*/
public QrCode(int ver, @NonNull Ecc ecl, @NonNull byte[] dataCodewords, int mask) {
// Check arguments
if (ver < 1 || ver > 40 || mask < -1 || mask > 7)
throw new IllegalArgumentException("Value out of range");
// Initialize fields
version = ver;
size = ver * 4 + 17;
errorCorrectionLevel = ecl;
modules = new boolean[size][size]; // Entirely white grid
isFunction = new boolean[size][size];
// Draw function patterns, draw all codewords, do masking
drawFunctionPatterns();
byte[] allCodewords = appendErrorCorrection(dataCodewords);
drawCodewords(allCodewords);
this.mask = handleConstructorMasking(mask);
}
/**
* Creates a new QR Code symbol based on the specified existing object, but with a potentially
* different mask pattern. The version, error correction level, codewords, etc. of the newly
* created object are all identical to the argument object; only the mask may differ.
* @param qr the existing QR Code to copy and modify
* @param mask the new mask pattern, 0 to 7 to force a fixed choice or -1 for an automatic choice
* @throws NullPointerException if the QR Code is {@code null}
* @throws IllegalArgumentException if the mask value is out of range
*/
public QrCode(@NonNull QrCode qr, int mask) {
// Check arguments
if (mask < -1 || mask > 7)
throw new IllegalArgumentException("Mask value out of range");
// Copy scalar fields
version = qr.version;
size = qr.size;
errorCorrectionLevel = qr.errorCorrectionLevel;
// Handle grid fields
isFunction = qr.isFunction; // Shallow copy because the data is read-only
modules = qr.modules.clone(); // Deep copy
for (int i = 0; i < modules.length; i++)
modules[i] = modules[i].clone();
// Handle masking
applyMask(qr.mask); // Undo old mask
this.mask = handleConstructorMasking(mask);
}
/*---- Public instance methods ----*/
/**
* Returns the color of the module (pixel) at the specified coordinates, which is either 0 for white or 1 for black. The top
* left corner has the coordinates (x=0, y=0). If the specified coordinates are out of bounds, then 0 (white) is returned.
* @param x the x coordinate, where 0 is the left edge and size&minus;1 is the right edge
* @param y the y coordinate, where 0 is the top edge and size&minus;1 is the bottom edge
* @return the module's color, which is either 0 (white) or 1 (black)
*/
public int getModule(int x, int y) {
if (0 <= x && x < size && 0 <= y && y < size)
return modules[y][x] ? 1 : 0;
else
return 0; // Infinite white border
}
/*---- Private helper methods for constructor: Drawing function modules ----*/
private void drawFunctionPatterns() {
// Draw horizontal and vertical timing patterns
for (int i = 0; i < size; i++) {
setFunctionModule(6, i, i % 2 == 0);
setFunctionModule(i, 6, i % 2 == 0);
}
// Draw 3 finder patterns (all corners except bottom right; overwrites some timing modules)
drawFinderPattern(3, 3);
drawFinderPattern(size - 4, 3);
drawFinderPattern(3, size - 4);
// Draw numerous alignment patterns
int[] alignPatPos = getAlignmentPatternPositions(version);
int numAlign = alignPatPos.length;
for (int i = 0; i < numAlign; i++) {
for (int j = 0; j < numAlign; j++) {
if (i == 0 && j == 0 || i == 0 && j == numAlign - 1 || i == numAlign - 1 && j == 0)
continue; // Skip the three finder corners
else
drawAlignmentPattern(alignPatPos[i], alignPatPos[j]);
}
}
// Draw configuration data
drawFormatBits(0); // Dummy mask value; overwritten later in the constructor
drawVersion();
}
// Draws two copies of the format bits (with its own error correction code)
// based on the given mask and this object's error correction level field.
private void drawFormatBits(int mask) {
// Calculate error correction code and pack bits
int data = errorCorrectionLevel.formatBits << 3 | mask; // errCorrLvl is uint2, mask is uint3
int rem = data;
for (int i = 0; i < 10; i++)
rem = (rem << 1) ^ ((rem >>> 9) * 0x537);
data = data << 10 | rem;
data ^= 0x5412; // uint15
if (data >>> 15 != 0)
throw new AssertionError();
// Draw first copy
for (int i = 0; i <= 5; i++)
setFunctionModule(8, i, ((data >>> i) & 1) != 0);
setFunctionModule(8, 7, ((data >>> 6) & 1) != 0);
setFunctionModule(8, 8, ((data >>> 7) & 1) != 0);
setFunctionModule(7, 8, ((data >>> 8) & 1) != 0);
for (int i = 9; i < 15; i++)
setFunctionModule(14 - i, 8, ((data >>> i) & 1) != 0);
// Draw second copy
for (int i = 0; i <= 7; i++)
setFunctionModule(size - 1 - i, 8, ((data >>> i) & 1) != 0);
for (int i = 8; i < 15; i++)
setFunctionModule(8, size - 15 + i, ((data >>> i) & 1) != 0);
setFunctionModule(8, size - 8, true);
}
// Draws two copies of the version bits (with its own error correction code),
// based on this object's version field (which only has an effect for 7 <= version <= 40).
private void drawVersion() {
if (version < 7)
return;
// Calculate error correction code and pack bits
int rem = version; // version is uint6, in the range [7, 40]
for (int i = 0; i < 12; i++)
rem = (rem << 1) ^ ((rem >>> 11) * 0x1F25);
int data = version << 12 | rem; // uint18
if (data >>> 18 != 0)
throw new AssertionError();
// Draw two copies
for (int i = 0; i < 18; i++) {
boolean bit = ((data >>> i) & 1) != 0;
int a = size - 11 + i % 3, b = i / 3;
setFunctionModule(a, b, bit);
setFunctionModule(b, a, bit);
}
}
// Draws a 9*9 finder pattern including the border separator, with the center module at (x, y).
private void drawFinderPattern(int x, int y) {
for (int i = -4; i <= 4; i++) {
for (int j = -4; j <= 4; j++) {
int dist = Math.max(Math.abs(i), Math.abs(j)); // Chebyshev/infinity norm
int xx = x + j, yy = y + i;
if (0 <= xx && xx < size && 0 <= yy && yy < size)
setFunctionModule(xx, yy, dist != 2 && dist != 4);
}
}
}
// Draws a 5*5 alignment pattern, with the center module at (x, y).
private void drawAlignmentPattern(int x, int y) {
for (int i = -2; i <= 2; i++) {
for (int j = -2; j <= 2; j++)
setFunctionModule(x + j, y + i, Math.max(Math.abs(i), Math.abs(j)) != 1);
}
}
// Sets the color of a module and marks it as a function module.
// Only used by the constructor. Coordinates must be in range.
private void setFunctionModule(int x, int y, boolean isBlack) {
modules[y][x] = isBlack;
isFunction[y][x] = true;
}
/*---- Private helper methods for constructor: Codewords and masking ----*/
// Returns a new byte string representing the given data with the appropriate error correction
// codewords appended to it, based on this object's version and error correction level.
private byte[] appendErrorCorrection(byte[] data) {
if (data.length != getNumDataCodewords(version, errorCorrectionLevel))
throw new IllegalArgumentException();
// Calculate parameter numbers
int numBlocks = NUM_ERROR_CORRECTION_BLOCKS[errorCorrectionLevel.ordinal()][version];
int blockEccLen = ECC_CODEWORDS_PER_BLOCK[errorCorrectionLevel.ordinal()][version];
int rawCodewords = getNumRawDataModules(version) / 8;
int numShortBlocks = numBlocks - rawCodewords % numBlocks;
int shortBlockLen = rawCodewords / numBlocks;
// Split data into blocks and append ECC to each block
byte[][] blocks = new byte[numBlocks][];
ReedSolomonGenerator rs = new ReedSolomonGenerator(blockEccLen);
for (int i = 0, k = 0; i < numBlocks; i++) {
byte[] dat = Arrays.copyOfRange(data, k, k + shortBlockLen - blockEccLen + (i < numShortBlocks ? 0 : 1));
byte[] block = Arrays.copyOf(dat, shortBlockLen + 1);
k += dat.length;
byte[] ecc = rs.getRemainder(dat);
System.arraycopy(ecc, 0, block, block.length - blockEccLen, ecc.length);
blocks[i] = block;
}
// Interleave (not concatenate) the bytes from every block into a single sequence
byte[] result = new byte[rawCodewords];
for (int i = 0, k = 0; i < blocks[0].length; i++) {
for (int j = 0; j < blocks.length; j++) {
// Skip the padding byte in short blocks
if (i != shortBlockLen - blockEccLen || j >= numShortBlocks) {
result[k] = blocks[j][i];
k++;
}
}
}
return result;
}
// Draws the given sequence of 8-bit codewords (data and error correction) onto the entire
// data area of this QR Code symbol. Function modules need to be marked off before this is called.
private void drawCodewords(@NonNull byte[] data) {
if (data.length != getNumRawDataModules(version) / 8)
throw new IllegalArgumentException();
int i = 0; // Bit index into the data
// Do the funny zigzag scan
for (int right = size - 1; right >= 1; right -= 2) { // Index of right column in each column pair
if (right == 6)
right = 5;
for (int vert = 0; vert < size; vert++) { // Vertical counter
for (int j = 0; j < 2; j++) {
int x = right - j; // Actual x coordinate
boolean upward = ((right + 1) & 2) == 0;
int y = upward ? size - 1 - vert : vert; // Actual y coordinate
if (!isFunction[y][x] && i < data.length * 8) {
modules[y][x] = ((data[i >>> 3] >>> (7 - (i & 7))) & 1) != 0;
i++;
}
// If there are any remainder bits (0 to 7), they are already
// set to 0/false/white when the grid of modules was initialized
}
}
}
if (i != data.length * 8)
throw new AssertionError();
}
// XORs the data modules in this QR Code with the given mask pattern. Due to XOR's mathematical
// properties, calling applyMask(m) twice with the same value is equivalent to no change at all.
// This means it is possible to apply a mask, undo it, and try another mask. Note that a final
// well-formed QR Code symbol needs exactly one mask applied (not zero, not two, etc.).
private void applyMask(int mask) {
if (mask < 0 || mask > 7)
throw new IllegalArgumentException("Mask value out of range");
for (int y = 0; y < size; y++) {
for (int x = 0; x < size; x++) {
boolean invert;
switch (mask) {
case 0: invert = (x + y) % 2 == 0; break;
case 1: invert = y % 2 == 0; break;
case 2: invert = x % 3 == 0; break;
case 3: invert = (x + y) % 3 == 0; break;
case 4: invert = (x / 3 + y / 2) % 2 == 0; break;
case 5: invert = x * y % 2 + x * y % 3 == 0; break;
case 6: invert = (x * y % 2 + x * y % 3) % 2 == 0; break;
case 7: invert = ((x + y) % 2 + x * y % 3) % 2 == 0; break;
default: throw new AssertionError();
}
modules[y][x] ^= invert & !isFunction[y][x];
}
}
}
// A messy helper function for the constructors. This QR Code must be in an unmasked state when this
// method is called. The given argument is the requested mask, which is -1 for auto or 0 to 7 for fixed.
// This method applies and returns the actual mask chosen, from 0 to 7.
private int handleConstructorMasking(int mask) {
if (mask == -1) { // Automatically choose best mask
int minPenalty = Integer.MAX_VALUE;
for (int i = 0; i < 8; i++) {
drawFormatBits(i);
applyMask(i);
int penalty = getPenaltyScore();
if (penalty < minPenalty) {
mask = i;
minPenalty = penalty;
}
applyMask(i); // Undoes the mask due to XOR
}
}
if (mask < 0 || mask > 7)
throw new AssertionError();
drawFormatBits(mask); // Overwrite old format bits
applyMask(mask); // Apply the final choice of mask
return mask; // The caller shall assign this value to the final-declared field
}
// Calculates and returns the penalty score based on state of this QR Code's current modules.
// This is used by the automatic mask choice algorithm to find the mask pattern that yields the lowest score.
private int getPenaltyScore() {
int result = 0;
// Adjacent modules in row having same color
for (int y = 0; y < size; y++) {
boolean colorX = false;
for (int x = 0, runX = 0; x < size; x++) {
if (x == 0 || modules[y][x] != colorX) {
colorX = modules[y][x];
runX = 1;
} else {
runX++;
if (runX == 5)
result += PENALTY_N1;
else if (runX > 5)
result++;
}
}
}
// Adjacent modules in column having same color
for (int x = 0; x < size; x++) {
boolean colorY = false;
for (int y = 0, runY = 0; y < size; y++) {
if (y == 0 || modules[y][x] != colorY) {
colorY = modules[y][x];
runY = 1;
} else {
runY++;
if (runY == 5)
result += PENALTY_N1;
else if (runY > 5)
result++;
}
}
}
// 2*2 blocks of modules having same color
for (int y = 0; y < size - 1; y++) {
for (int x = 0; x < size - 1; x++) {
boolean color = modules[y][x];
if ( color == modules[y][x + 1] &&
color == modules[y + 1][x] &&
color == modules[y + 1][x + 1])
result += PENALTY_N2;
}
}
// Finder-like pattern in rows
for (int y = 0; y < size; y++) {
for (int x = 0, bits = 0; x < size; x++) {
bits = ((bits << 1) & 0x7FF) | (modules[y][x] ? 1 : 0);
if (x >= 10 && (bits == 0x05D || bits == 0x5D0)) // Needs 11 bits accumulated
result += PENALTY_N3;
}
}
// Finder-like pattern in columns
for (int x = 0; x < size; x++) {
for (int y = 0, bits = 0; y < size; y++) {
bits = ((bits << 1) & 0x7FF) | (modules[y][x] ? 1 : 0);
if (y >= 10 && (bits == 0x05D || bits == 0x5D0)) // Needs 11 bits accumulated
result += PENALTY_N3;
}
}
// Balance of black and white modules
int black = 0;
for (boolean[] row : modules) {
for (boolean color : row) {
if (color)
black++;
}
}
int total = size * size;
// Find smallest k such that (45-5k)% <= dark/total <= (55+5k)%
for (int k = 0; black*20 < (9-k)*total || black*20 > (11+k)*total; k++)
result += PENALTY_N4;
return result;
}
/*---- Private static helper functions ----*/
// Returns a set of positions of the alignment patterns in ascending order. These positions are
// used on both the x and y axes. Each value in the resulting array is in the range [0, 177).
// This stateless pure function could be implemented as table of 40 variable-length lists of unsigned bytes.
private static int[] getAlignmentPatternPositions(int ver) {
if (ver < 1 || ver > 40)
throw new IllegalArgumentException("Version number out of range");
else if (ver == 1)
return new int[]{};
else {
int numAlign = ver / 7 + 2;
int step;
if (ver != 32)
step = (ver * 4 + numAlign * 2 + 1) / (2 * numAlign - 2) * 2; // ceil((size - 13) / (2*numAlign - 2)) * 2
else // C-C-C-Combo breaker!
step = 26;
int[] result = new int[numAlign];
int size = ver * 4 + 17;
result[0] = 6;
for (int i = result.length - 1, pos = size - 7; i >= 1; i--, pos -= step)
result[i] = pos;
return result;
}
}
// Returns the number of data bits that can be stored in a QR Code of the given version number, after
// all function modules are excluded. This includes remainder bits, so it might not be a multiple of 8.
// The result is in the range [208, 29648]. This could be implemented as a 40-entry lookup table.
private static int getNumRawDataModules(int ver) {
if (ver < 1 || ver > 40)
throw new IllegalArgumentException("Version number out of range");
int size = ver * 4 + 17;
int result = size * size; // Number of modules in the whole QR symbol square
result -= 64 * 3; // Subtract the three finders with separators
result -= 15 * 2 + 1; // Subtract the format information and black module
result -= (size - 16) * 2; // Subtract the timing patterns
// The five lines above are equivalent to: int result = (16 * ver + 128) * ver + 64;
if (ver >= 2) {
int numAlign = ver / 7 + 2;
result -= (numAlign - 1) * (numAlign - 1) * 25; // Subtract alignment patterns not overlapping with timing patterns
result -= (numAlign - 2) * 2 * 20; // Subtract alignment patterns that overlap with timing patterns
// The two lines above are equivalent to: result -= (25 * numAlign - 10) * numAlign - 55;
if (ver >= 7)
result -= 18 * 2; // Subtract version information
}
return result;
}
// Returns the number of 8-bit data (i.e. not error correction) codewords contained in any
// QR Code of the given version number and error correction level, with remainder bits discarded.
// This stateless pure function could be implemented as a (40*4)-cell lookup table.
static int getNumDataCodewords(int ver, Ecc ecl) {
if (ver < 1 || ver > 40)
throw new IllegalArgumentException("Version number out of range");
return getNumRawDataModules(ver) / 8 - ECC_CODEWORDS_PER_BLOCK[ecl.ordinal()][ver] * NUM_ERROR_CORRECTION_BLOCKS[ecl.ordinal()][ver];
}
/*---- Private tables of constants ----*/
// For use in getPenaltyScore(), when evaluating which mask is best.
private static final int PENALTY_N1 = 3;
private static final int PENALTY_N2 = 3;
private static final int PENALTY_N3 = 40;
private static final int PENALTY_N4 = 10;
private static final byte[][] ECC_CODEWORDS_PER_BLOCK = {
// Version: (note that index 0 is for padding, and is set to an illegal value)
//0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level
{-1, 7, 10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, 30, 22, 24, 28, 30, 28, 28, 28, 28, 30, 30, 26, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // Low
{-1, 10, 16, 26, 18, 24, 16, 18, 22, 22, 26, 30, 22, 22, 24, 24, 28, 28, 26, 26, 26, 26, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28}, // Medium
{-1, 13, 22, 18, 26, 18, 24, 18, 22, 20, 24, 28, 26, 24, 20, 30, 24, 28, 28, 26, 30, 28, 30, 30, 30, 30, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // Quartile
{-1, 17, 28, 22, 16, 22, 28, 26, 26, 24, 28, 24, 28, 22, 24, 24, 30, 28, 28, 26, 28, 30, 24, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // High
};
private static final byte[][] NUM_ERROR_CORRECTION_BLOCKS = {
// Version: (note that index 0 is for padding, and is set to an illegal value)
//0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level
{-1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, 8, 9, 9, 10, 12, 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25}, // Low
{-1, 1, 1, 1, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, 9, 10, 10, 11, 13, 14, 16, 17, 17, 18, 20, 21, 23, 25, 26, 28, 29, 31, 33, 35, 37, 38, 40, 43, 45, 47, 49}, // Medium
{-1, 1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, 16, 12, 17, 16, 18, 21, 20, 23, 23, 25, 27, 29, 34, 34, 35, 38, 40, 43, 45, 48, 51, 53, 56, 59, 62, 65, 68}, // Quartile
{-1, 1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25, 25, 34, 30, 32, 35, 37, 40, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81}, // High
};
/*---- Public helper enumeration ----*/
/**
* Represents the error correction level used in a QR Code symbol.
*/
public enum Ecc {
// These enum constants must be declared in ascending order of error protection,
// for the sake of the implicit ordinal() method and values() function.
LOW(1), MEDIUM(0), QUARTILE(3), HIGH(2);
// In the range 0 to 3 (unsigned 2-bit integer).
final int formatBits;
// Constructor.
Ecc(int fb) {
formatBits = fb;
}
}
/*---- Private helper class ----*/
/**
* Computes the Reed-Solomon error correction codewords for a sequence of data codewords
* at a given degree. Objects are immutable, and the state only depends on the degree.
* This class exists because the divisor polynomial does not need to be recalculated for every input.
*/
private static final class ReedSolomonGenerator {
/*-- Immutable field --*/
// Coefficients of the divisor polynomial, stored from highest to lowest power, excluding the leading term which
// is always 1. For example the polynomial x^3 + 255x^2 + 8x + 93 is stored as the uint8 array {255, 8, 93}.
private final byte[] coefficients;
/*-- Constructor --*/
/**
* Creates a Reed-Solomon ECC generator for the specified degree. This could be implemented
* as a lookup table over all possible parameter values, instead of as an algorithm.
* @param degree the divisor polynomial degree, which must be between 1 and 255
* @throws IllegalArgumentException if degree &lt; 1 or degree > 255
*/
public ReedSolomonGenerator(int degree) {
if (degree < 1 || degree > 255)
throw new IllegalArgumentException("Degree out of range");
// Start with the monomial x^0
coefficients = new byte[degree];
coefficients[degree - 1] = 1;
// Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x - r^{degree-1}),
// drop the highest term, and store the rest of the coefficients in order of descending powers.
// Note that r = 0x02, which is a generator element of this field GF(2^8/0x11D).
int root = 1;
for (int i = 0; i < degree; i++) {
// Multiply the current product by (x - r^i)
for (int j = 0; j < coefficients.length; j++) {
coefficients[j] = (byte)multiply(coefficients[j] & 0xFF, root);
if (j + 1 < coefficients.length)
coefficients[j] ^= coefficients[j + 1];
}
root = multiply(root, 0x02);
}
}
/*-- Method --*/
/**
* Computes and returns the Reed-Solomon error correction codewords for the specified sequence of data codewords.
* The returned object is always a new byte array. This method does not alter this object's state (because it is immutable).
* @param data the sequence of data codewords
* @return the Reed-Solomon error correction codewords
* @throws NullPointerException if the data is {@code null}
*/
public byte[] getRemainder(@NonNull byte[] data) {
// Compute the remainder by performing polynomial division
byte[] result = new byte[coefficients.length];
for (byte b : data) {
int factor = (b ^ result[0]) & 0xFF;
System.arraycopy(result, 1, result, 0, result.length - 1);
result[result.length - 1] = 0;
for (int i = 0; i < result.length; i++)
result[i] ^= multiply(coefficients[i] & 0xFF, factor);
}
return result;
}
/*-- Static function --*/
// Returns the product of the two given field elements modulo GF(2^8/0x11D). The arguments and result
// are unsigned 8-bit integers. This could be implemented as a lookup table of 256*256 entries of uint8.
private static int multiply(int x, int y) {
if (x >>> 8 != 0 || y >>> 8 != 0)
throw new IllegalArgumentException("Byte out of range");
// Russian peasant multiplication
int z = 0;
for (int i = 7; i >= 0; i--) {
z = (z << 1) ^ ((z >>> 7) * 0x11D);
z ^= ((y >>> i) & 1) * x;
}
if (z >>> 8 != 0)
throw new AssertionError();
return z;
}
}
}

View File

@ -1,280 +0,0 @@
/*
* QR Code generator library (Java)
*
* Copyright (c) Project Nayuki. (MIT License)
* https://www.nayuki.io/page/qr-code-generator-library
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
* - The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* - The Software is provided "as is", without warranty of any kind, express or
* implied, including but not limited to the warranties of merchantability,
* fitness for a particular purpose and noninfringement. In no event shall the
* authors or copyright holders be liable for any claim, damages or other
* liability, whether in an action of contract, tort or otherwise, arising from,
* out of or in connection with the Software or the use or other dealings in the
* Software.
*/
package io.nayuki.qrcodegen;
import androidx.annotation.NonNull;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;
/**
* Represents a character string to be encoded in a QR Code symbol. Each segment has
* a mode, and a sequence of characters that is already encoded as a sequence of bits.
* Instances of this class are immutable.
* <p>This segment class imposes no length restrictions, but QR Codes have restrictions.
* Even in the most favorable conditions, a QR Code can only hold 7089 characters of data.
* Any segment longer than this is meaningless for the purpose of generating QR Codes.</p>
*/
public final class QrSegment {
/*---- Static factory functions ----*/
/**
* Returns a segment representing the specified binary data encoded in byte mode.
* @param data the binary data
* @return a segment containing the data
* @throws NullPointerException if the array is {@code null}
*/
public static QrSegment makeBytes(@NonNull byte[] data) {
return new QrSegment(Mode.BYTE, data.length, data, data.length * 8);
}
/**
* Returns a segment representing the specified string of decimal digits encoded in numeric mode.
* @param digits a string consisting of digits from 0 to 9
* @return a segment containing the data
* @throws NullPointerException if the string is {@code null}
* @throws IllegalArgumentException if the string contains non-digit characters
*/
public static QrSegment makeNumeric(@NonNull String digits) {
if (!NUMERIC_REGEX.matcher(digits).matches())
throw new IllegalArgumentException("String contains non-numeric characters");
BitBuffer bb = new BitBuffer();
int i;
for (i = 0; i + 3 <= digits.length(); i += 3) // Process groups of 3
bb.appendBits(Integer.parseInt(digits.substring(i, i + 3)), 10);
int rem = digits.length() - i;
if (rem > 0) // 1 or 2 digits remaining
bb.appendBits(Integer.parseInt(digits.substring(i)), rem * 3 + 1);
return new QrSegment(Mode.NUMERIC, digits.length(), bb.getBytes(), bb.bitLength());
}
/**
* Returns a segment representing the specified text string encoded in alphanumeric mode. The characters allowed are:
* 0 to 9, A to Z (uppercase only), space, dollar, percent, asterisk, plus, hyphen, period, slash, colon.
* @param text a string of text, with only certain characters allowed
* @return a segment containing the data
* @throws NullPointerException if the string is {@code null}
* @throws IllegalArgumentException if the string contains non-encodable characters
*/
public static QrSegment makeAlphanumeric(@NonNull String text) {
if (!ALPHANUMERIC_REGEX.matcher(text).matches())
throw new IllegalArgumentException("String contains unencodable characters in alphanumeric mode");
BitBuffer bb = new BitBuffer();
int i;
for (i = 0; i + 2 <= text.length(); i += 2) { // Process groups of 2
int temp = ALPHANUMERIC_CHARSET.indexOf(text.charAt(i)) * 45;
temp += ALPHANUMERIC_CHARSET.indexOf(text.charAt(i + 1));
bb.appendBits(temp, 11);
}
if (i < text.length()) // 1 character remaining
bb.appendBits(ALPHANUMERIC_CHARSET.indexOf(text.charAt(i)), 6);
return new QrSegment(Mode.ALPHANUMERIC, text.length(), bb.getBytes(), bb.bitLength());
}
/**
* Returns a new mutable list of zero or more segments to represent the specified Unicode text string.
* The result may use various segment modes and switch modes to optimize the length of the bit stream.
* @param text the text to be encoded, which can be any Unicode string
* @return a list of segments containing the text
* @throws NullPointerException if the text is {@code null}
*/
public static List<QrSegment> makeSegments(@NonNull String text) {
// Select the most efficient segment encoding automatically
List<QrSegment> result = new ArrayList<>();
if (text.equals(""))
return result;
else if (NUMERIC_REGEX.matcher(text).matches())
result.add(makeNumeric(text));
else if (ALPHANUMERIC_REGEX.matcher(text).matches())
result.add(makeAlphanumeric(text));
else
result.add(makeBytes(text.getBytes(Charset.forName("UTF-8"))));
return result;
}
/**
* Returns a segment representing an Extended Channel Interpretation (ECI) designator with the specified assignment value.
* @param assignVal the ECI assignment number (see the AIM ECI specification)
* @return a segment containing the data
* @throws IllegalArgumentException if the value is outside the range [0, 10<sup>6</sup>)
*/
public static QrSegment makeEci(int assignVal) {
byte[] data;
if (0 <= assignVal && assignVal < (1 << 7))
data = new byte[]{(byte)assignVal};
else if ((1 << 7) <= assignVal && assignVal < (1 << 14))
data = new byte[]{(byte)(0x80 | (assignVal >>> 8)), (byte)assignVal};
else if ((1 << 14) <= assignVal && assignVal < 999999)
data = new byte[]{(byte)(0xC0 | (assignVal >>> 16)), (byte)(assignVal >>> 8), (byte)assignVal};
else
throw new IllegalArgumentException("ECI assignment value out of range");
return new QrSegment(Mode.ECI, 0, data, data.length * 8);
}
/*---- Instance fields ----*/
/** The mode indicator for this segment. Never {@code null}. */
public final Mode mode;
/** The length of this segment's unencoded data, measured in characters. Always zero or positive. */
public final int numChars;
/** The bits of this segment packed into a byte array in big endian. Accessed through {@link #getByte(int)}. Not {@code null}. */
private final byte[] data;
/** The length of this segment's encoded data, measured in bits. Satisfies 0 &le; {@code bitLength} &le; {@code data.length} &times; 8. */
public final int bitLength;
/*---- Constructor ----*/
/**
* Creates a new QR Code data segment with the specified parameters and data.
* @param md the mode, which is not {@code null}
* @param numCh the data length in characters, which is non-negative
* @param bitLen the data length in bits, which is non-negative
* @param b the bits packed into bytes, which is not {@code null}
* @throws NullPointerException if the mode or array is {@code null}
* @throws IllegalArgumentException if the character count or bit length are negative or invalid
*/
public QrSegment(@NonNull Mode md, int numCh, @NonNull byte[] b, int bitLen) {
if (numCh < 0 || bitLen < 0 || bitLen > b.length * 8L)
throw new IllegalArgumentException("Invalid value");
mode = md;
numChars = numCh;
data = Arrays.copyOf(b, (bitLen + 7) / 8); // Trim to precise length and also make defensive copy
bitLength = bitLen;
}
/*---- Method ----*/
/**
* Returns the data byte at the specified index.
* @param index the index to retrieve from, satisfying 0 &le; {@code index} &lt; ceil({@code bitLength} &divide; 8)
* @return the data byte at the specified index
* @throws IndexOutOfBoundsException if the index is out of bounds
*/
public byte getByte(int index) {
if (index < 0 || index > data.length)
throw new IndexOutOfBoundsException();
return data[index];
}
// Package-private helper function.
static int getTotalBits(@NonNull List<QrSegment> segs, int version) {
if (version < 1 || version > 40)
throw new IllegalArgumentException("Version number out of range");
long result = 0;
for (QrSegment seg : segs) {
int ccbits = seg.mode.numCharCountBits(version);
// Fail if segment length value doesn't fit in the length field's bit-width
if (seg.numChars >= (1 << ccbits))
return -1;
result += 4L + ccbits + seg.bitLength;
if (result > Integer.MAX_VALUE)
return -1;
}
return (int)result;
}
/*---- Constants ----*/
/** Can test whether a string is encodable in numeric mode (such as by using {@link #makeNumeric(String)}). */
public static final Pattern NUMERIC_REGEX = Pattern.compile("[0-9]*");
/** Can test whether a string is encodable in alphanumeric mode (such as by using {@link #makeAlphanumeric(String)}). */
public static final Pattern ALPHANUMERIC_REGEX = Pattern.compile("[A-Z0-9 $%*+./:-]*");
/** The set of all legal characters in alphanumeric mode, where each character value maps to the index in the string. */
private static final String ALPHANUMERIC_CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:";
/*---- Public helper enumeration ----*/
/**
* The mode field of a segment. Immutable. Provides methods to retrieve closely related values.
*/
public enum Mode {
/*-- Constants --*/
NUMERIC (0x1, 10, 12, 14),
ALPHANUMERIC(0x2, 9, 11, 13),
BYTE (0x4, 8, 16, 16),
KANJI (0x8, 8, 10, 12),
ECI (0x7, 0, 0, 0);
/*-- Fields --*/
/** An unsigned 4-bit integer value (range 0 to 15) representing the mode indicator bits for this mode object. */
final int modeBits;
private final int[] numBitsCharCount;
/*-- Constructor --*/
Mode(int mode, int... ccbits) {
this.modeBits = mode;
numBitsCharCount = ccbits;
}
/*-- Method --*/
/**
* Returns the bit width of the segment character count field for this mode object at the specified version number.
* @param ver the version number, which is between 1 to 40, inclusive
* @return the number of bits for the character count, which is between 8 to 16, inclusive
* @throws IllegalArgumentException if the version number is out of range
*/
int numCharCountBits(int ver) {
if ( 1 <= ver && ver <= 9) return numBitsCharCount[0];
else if (10 <= ver && ver <= 26) return numBitsCharCount[1];
else if (27 <= ver && ver <= 40) return numBitsCharCount[2];
else throw new IllegalArgumentException("Version number out of range");
}
}
}

View File

@ -1,5 +0,0 @@
/**
* This package contains code from https://github.com/nayuki/QR-Code-generator
* And licensed under MIT license
*/
package io.nayuki.qrcodegen;

View File

@ -30,6 +30,7 @@ import android.os.Bundle;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentActivity;
import androidx.loader.app.LoaderManager;
import androidx.loader.app.LoaderManager.LoaderCallbacks; import androidx.loader.app.LoaderManager.LoaderCallbacks;
import androidx.loader.content.FixedAsyncTaskLoader; import androidx.loader.content.FixedAsyncTaskLoader;
import androidx.loader.content.Loader; import androidx.loader.content.Loader;
@ -73,7 +74,7 @@ public class FileSelectorDialogFragment extends BaseDialogFragment implements Lo
public void onActivityCreated(final Bundle savedInstanceState) { public void onActivityCreated(final Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState); super.onActivityCreated(savedInstanceState);
final Bundle args = getArguments(); final Bundle args = getArguments();
getLoaderManager().initLoader(0, args, this); LoaderManager.getInstance(this).initLoader(0, args, this);
} }
@Override @Override
@ -155,7 +156,7 @@ public class FileSelectorDialogFragment extends BaseDialogFragment implements Lo
if (file.isDirectory()) { if (file.isDirectory()) {
final Bundle args = getArguments(); final Bundle args = getArguments();
args.putString(EXTRA_PATH, file.getAbsolutePath()); args.putString(EXTRA_PATH, file.getAbsolutePath());
getLoaderManager().restartLoader(0, args, this); LoaderManager.getInstance(this).restartLoader(0, args, this);
} else if (file.isFile() && !isPickDirectory()) { } else if (file.isFile() && !isPickDirectory()) {
final FragmentActivity a = getActivity(); final FragmentActivity a = getActivity();
if (a instanceof Callback) { if (a instanceof Callback) {

View File

@ -67,7 +67,7 @@ public class KeyboardShortcutsFragment extends BasePreferenceFragment implements
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.reset) { if (item.getItemId() == R.id.reset) {
final DialogFragment f = new ResetKeyboardShortcutConfirmDialogFragment(); final DialogFragment f = new ResetKeyboardShortcutConfirmDialogFragment();
f.show(getFragmentManager(), "reset_keyboard_shortcut_confirm"); f.show(getParentFragmentManager(), "reset_keyboard_shortcut_confirm");
return true; return true;
} }
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);

View File

@ -56,7 +56,7 @@ abstract class MultiSelectListPreference extends DialogPreference implements IDi
public void displayDialog(@NonNull PreferenceFragmentCompat fragment) { public void displayDialog(@NonNull PreferenceFragmentCompat fragment) {
final MultiSelectListDialogFragment df = MultiSelectListDialogFragment.newInstance(getKey()); final MultiSelectListDialogFragment df = MultiSelectListDialogFragment.newInstance(getKey());
df.setTargetFragment(fragment, 0); df.setTargetFragment(fragment, 0);
df.show(fragment.getFragmentManager(), getKey()); df.show(fragment.getParentFragmentManager(), getKey());
} }
protected abstract boolean[] getDefaults(); protected abstract boolean[] getDefaults();

View File

@ -98,7 +98,7 @@ public class NotificationTypePreference extends DialogPreference implements
public void displayDialog(@NonNull PreferenceFragmentCompat fragment) { public void displayDialog(@NonNull PreferenceFragmentCompat fragment) {
final NotificationTypeDialogFragment df = NotificationTypeDialogFragment.newInstance(getKey()); final NotificationTypeDialogFragment df = NotificationTypeDialogFragment.newInstance(getKey());
df.setTargetFragment(fragment, 0); df.setTargetFragment(fragment, 0);
df.show(fragment.getFragmentManager(), getKey()); df.show(fragment.getParentFragmentManager(), getKey());
} }
public int getDefaultValue() { public int getDefaultValue() {

View File

@ -188,7 +188,7 @@ public class SeekBarDialogPreference extends DialogPreference implements IDialog
public void displayDialog(@NonNull PreferenceFragmentCompat fragment) { public void displayDialog(@NonNull PreferenceFragmentCompat fragment) {
SeekBarDialogPreferenceFragment df = SeekBarDialogPreferenceFragment.newInstance(getKey()); SeekBarDialogPreferenceFragment df = SeekBarDialogPreferenceFragment.newInstance(getKey());
df.setTargetFragment(fragment, 0); df.setTargetFragment(fragment, 0);
df.show(fragment.getFragmentManager(), getKey()); df.show(fragment.getParentFragmentManager(), getKey());
} }
public static class SeekBarDialogPreferenceFragment extends ThemedPreferenceDialogFragmentCompat { public static class SeekBarDialogPreferenceFragment extends ThemedPreferenceDialogFragmentCompat {

View File

@ -52,7 +52,7 @@ public class SettingsImportExportPreference extends DialogPreference implements
public void displayDialog(@NonNull PreferenceFragmentCompat fragment) { public void displayDialog(@NonNull PreferenceFragmentCompat fragment) {
ImportExportDialogFragment df = ImportExportDialogFragment.newInstance(getKey()); ImportExportDialogFragment df = ImportExportDialogFragment.newInstance(getKey());
df.setTargetFragment(fragment, 0); df.setTargetFragment(fragment, 0);
df.show(fragment.getFragmentManager(), getKey()); df.show(fragment.getParentFragmentManager(), getKey());
} }
public static class ImportExportDialogFragment extends PreferenceDialogFragmentCompat { public static class ImportExportDialogFragment extends PreferenceDialogFragmentCompat {

View File

@ -98,7 +98,7 @@ public class ThemeBackgroundPreference extends DialogPreference implements Const
public void displayDialog(@NonNull PreferenceFragmentCompat fragment) { public void displayDialog(@NonNull PreferenceFragmentCompat fragment) {
InternalDialogFragment df = InternalDialogFragment.newInstance(getKey()); InternalDialogFragment df = InternalDialogFragment.newInstance(getKey());
df.setTargetFragment(fragment, 0); df.setTargetFragment(fragment, 0);
df.show(fragment.getFragmentManager(), getKey()); df.show(fragment.getParentFragmentManager(), getKey());
} }
private void saveValue() { private void saveValue() {

View File

@ -26,9 +26,9 @@ import android.text.Spannable;
import android.text.Spanned; import android.text.Spanned;
import android.text.style.URLSpan; import android.text.style.URLSpan;
import com.twitter.Extractor; import com.twitter.twittertext.Extractor;
import com.twitter.Extractor.Entity; import com.twitter.twittertext.Extractor.Entity;
import com.twitter.Regex; import com.twitter.twittertext.Regex;
import org.mariotaku.twidere.Constants; import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.model.UserKey; import org.mariotaku.twidere.model.UserKey;

View File

@ -1,63 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.util.content;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.loader.app.LoaderManager.LoaderCallbacks;
import org.mariotaku.twidere.TwidereConstants;
public class SupportFragmentReloadCursorObserver extends ContentObserver implements TwidereConstants {
private final Fragment mFragment;
private final int mLoaderId;
private final LoaderCallbacks<Cursor> mCallback;
public SupportFragmentReloadCursorObserver(final Fragment fragment, final int loaderId,
final LoaderCallbacks<Cursor> callback) {
super(createHandler());
mFragment = fragment;
mLoaderId = loaderId;
mCallback = callback;
}
private static Handler createHandler() {
if (Thread.currentThread().getId() != 1) return new Handler(Looper.getMainLooper());
return new Handler();
}
@Override
public final void onChange(final boolean selfChange) {
onChange(selfChange, null);
}
@Override
public void onChange(final boolean selfChange, @Nullable final Uri uri) {
if (mFragment == null || mFragment.getActivity() == null || mFragment.isDetached()) return;
// Handle change.
mFragment.getLoaderManager().restartLoader(mLoaderId, null, mCallback);
}
}

View File

@ -45,9 +45,13 @@ public class ActivitySupport {
} }
private static TaskDescription toNativeTaskDescription(TaskDescriptionCompat taskDescription) { private static TaskDescription toNativeTaskDescription(TaskDescriptionCompat taskDescription) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
return new TaskDescription(taskDescription.getLabel(), taskDescription.getPrimaryColor());
} else {
return new TaskDescription(taskDescription.getLabel(), taskDescription.getIcon(), taskDescription.getPrimaryColor()); return new TaskDescription(taskDescription.getLabel(), taskDescription.getIcon(), taskDescription.getPrimaryColor());
} }
} }
}
/** /**
* Information you can set and retrieve about the current context within the recent task list. * Information you can set and retrieve about the current context within the recent task list.

View File

@ -1,6 +1,7 @@
package org.mariotaku.ktextension package org.mariotaku.ktextension
import android.database.Cursor import android.database.Cursor
import android.database.sqlite.SQLiteBlobTooBigException
import org.mariotaku.library.objectcursor.ObjectCursor import org.mariotaku.library.objectcursor.ObjectCursor
import java.util.* import java.util.*
@ -12,6 +13,8 @@ fun Cursor.safeMoveToPosition(pos: Int) = try {
moveToPosition(pos) moveToPosition(pos)
} catch (e: IllegalStateException) { } catch (e: IllegalStateException) {
false false
} catch (e: SQLiteBlobTooBigException) {
false
} }
fun Cursor.safeGetLong(columnIndex: Int, def: Long = -1) = try { fun Cursor.safeGetLong(columnIndex: Int, def: Long = -1) = try {

View File

@ -23,7 +23,7 @@ import android.content.Intent
import android.os.Parcelable import android.os.Parcelable
inline fun <reified T : Parcelable> Intent.getTypedArrayExtra(key: String): Array<T> { inline fun <reified T : Parcelable> Intent.getTypedArrayExtra(key: String): Array<T> {
val extra = getParcelableArrayExtra(key) val extra = getParcelableArrayExtra(key) ?: emptyArray()
return Array(extra.size) { extra[it] as T } return Array(extra.size) { extra[it] as T }
} }

View File

@ -196,9 +196,10 @@ open class BaseActivity : ChameleonActivity(), IBaseActivity<BaseActivity>, IThe
private set private set
override fun getSystemWindowInsets(caller: Fragment, insets: Rect): Boolean { override fun getSystemWindowInsets(caller: Fragment, insets: Rect): Boolean {
if (systemWindowsInsets == null) return false return systemWindowsInsets?.let {
insets.set(systemWindowsInsets) insets.set(it)
return true true
} ?: false
} }
override fun onApplyWindowInsets(v: View, insets: WindowInsetsCompat): WindowInsetsCompat { override fun onApplyWindowInsets(v: View, insets: WindowInsetsCompat): WindowInsetsCompat {

View File

@ -70,7 +70,7 @@ class BrowserSignInActivity : BaseActivity() {
setSupportMultipleWindows(true) setSupportMultipleWindows(true)
} }
webView.loadUrl(intent.dataString) intent.dataString?.let { webView.loadUrl(it) }
} }
override fun onDestroy() { override fun onDestroy() {

View File

@ -32,6 +32,7 @@ import android.graphics.Canvas
import android.graphics.Rect import android.graphics.Rect
import android.location.* import android.location.*
import android.net.Uri import android.net.Uri
import android.os.Build
import android.os.Bundle import android.os.Bundle
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
import androidx.core.widget.TextViewCompat import androidx.core.widget.TextViewCompat
@ -56,7 +57,7 @@ import android.view.animation.DecelerateInterpolator
import android.widget.ImageView import android.widget.ImageView
import android.widget.Toast import android.widget.Toast
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.twitter.Extractor import com.twitter.twittertext.Extractor
import kotlinx.android.synthetic.main.activity_compose.* import kotlinx.android.synthetic.main.activity_compose.*
import nl.komponents.kovenant.task import nl.komponents.kovenant.task
import org.mariotaku.abstask.library.AbstractTask import org.mariotaku.abstask.library.AbstractTask
@ -123,6 +124,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
// Utility classes // Utility classes
@Inject @Inject
lateinit var extractor: Extractor lateinit var extractor: Extractor
@Inject @Inject
lateinit var locationManager: LocationManager lateinit var locationManager: LocationManager
@ -378,8 +380,8 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
saveAccountSelection() saveAccountSelection()
saveVisibility() saveVisibility()
try { try {
if (locationListener != null) { locationListener?.let {
locationManager.removeUpdates(locationListener) locationManager.removeUpdates(it)
locationListener = null locationListener = null
} }
} catch (ignore: SecurityException) { } catch (ignore: SecurityException) {
@ -416,9 +418,9 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
REQUEST_EXTENSION_COMPOSE -> { REQUEST_EXTENSION_COMPOSE -> {
if (resultCode == Activity.RESULT_OK && data != null) { if (resultCode == Activity.RESULT_OK && data != null) {
// The latter two is for compatibility // The latter two is for compatibility
val text = data.getCharSequenceExtra(Intent.EXTRA_TEXT) ?: val text = data.getCharSequenceExtra(Intent.EXTRA_TEXT)
data.getStringExtra(EXTRA_TEXT) ?: ?: data.getStringExtra(EXTRA_TEXT)
data.getStringExtra(EXTRA_APPEND_TEXT) ?: data.getStringExtra(EXTRA_APPEND_TEXT)
val isReplaceMode = data.getBooleanExtra(EXTRA_IS_REPLACE_MODE, val isReplaceMode = data.getBooleanExtra(EXTRA_IS_REPLACE_MODE,
data.getStringExtra(EXTRA_APPEND_TEXT) == null) data.getStringExtra(EXTRA_APPEND_TEXT) == null)
if (text != null) { if (text != null) {
@ -432,8 +434,8 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
updateTextCount() updateTextCount()
} }
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, TaskStarter.execute(AddMediaTask(this, src, null,
copySrc = false, copySrc = false,
@ -617,7 +619,8 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
when (ev.actionMasked) { when (ev.actionMasked) {
MotionEvent.ACTION_DOWN -> { MotionEvent.ACTION_DOWN -> {
if (isAccountSelectorVisible && !TwidereViewUtils.hitView(ev, accountSelectorButton)) { if (isAccountSelectorVisible && !TwidereViewUtils.hitView(ev, accountSelectorButton)) {
val layoutManager = accountSelector.layoutManager ?: return super.dispatchTouchEvent(ev) val layoutManager = accountSelector.layoutManager
?: return super.dispatchTouchEvent(ev)
val clickedItem = (0 until layoutManager.childCount).any { val clickedItem = (0 until layoutManager.childCount).any {
val child = layoutManager.getChildAt(it) val child = layoutManager.getChildAt(it)
child != null && TwidereViewUtils.hitView(ev, child) child != null && TwidereViewUtils.hitView(ev, child)
@ -785,8 +788,10 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
requestOrUpdateLocation() requestOrUpdateLocation()
} else if (locationListener != null) { } else if (locationListener != null) {
try { try {
locationManager.removeUpdates(locationListener) locationListener?.let {
locationManager.removeUpdates(it)
locationListener = null locationListener = null
}
} catch (e: SecurityException) { } catch (e: SecurityException) {
//Ignore //Ignore
} }
@ -1089,20 +1094,20 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
if (intent == null) return false if (intent == null) return false
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 = when {
when {
intent.hasExtra(EXTRA_ACCOUNT_KEYS) -> { intent.hasExtra(EXTRA_ACCOUNT_KEYS) -> {
val accountKeys = intent.getTypedArrayExtra<UserKey>(EXTRA_ACCOUNT_KEYS) val accountKeys = intent.getTypedArrayExtra<UserKey>(EXTRA_ACCOUNT_KEYS)
accountsAdapter.selectedAccountKeys = accountKeys accountsAdapter.selectedAccountKeys = accountKeys
hasAccountKeys = true true
} }
intent.hasExtra(EXTRA_ACCOUNT_KEY) -> { intent.hasExtra(EXTRA_ACCOUNT_KEY) -> {
val accountKey = intent.getParcelableExtra<UserKey>(EXTRA_ACCOUNT_KEY) intent.getParcelableExtra<UserKey>(EXTRA_ACCOUNT_KEY)?.let {
accountsAdapter.selectedAccountKeys = arrayOf(accountKey) accountsAdapter.selectedAccountKeys = arrayOf(it)
hasAccountKeys = true true
} ?: false
} }
else -> { else -> {
hasAccountKeys = false false
} }
} }
when (action) { when (action) {
@ -1145,6 +1150,12 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
} else { } else {
editText.setSelection(selection.coerceIn(0..editText.length())) editText.setSelection(selection.coerceIn(0..editText.length()))
} }
if (intent.hasExtra(Intent.EXTRA_PROCESS_TEXT) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
val charSequences = intent.getCharSequenceExtra(Intent.EXTRA_PROCESS_TEXT)
charSequences?.let {
editText.setText(it.toString())
}
}
editText.requestFocus() editText.requestFocus()
return true return true
} }
@ -1437,8 +1448,9 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
val provider = locationManager.getBestProvider(criteria, true) val provider = locationManager.getBestProvider(criteria, true)
if (provider != null) { if (provider != null) {
locationLabel.setText(R.string.getting_location) locationLabel.setText(R.string.getting_location)
locationListener = ComposeLocationListener(this) locationListener = ComposeLocationListener(this).also {
locationManager.requestLocationUpdates(provider, 0, 0f, locationListener) locationManager.requestLocationUpdates(provider, 0, 0f, it)
}
val location = locationManager.getCachedLocation() val location = locationManager.getCachedLocation()
if (location != null) { if (location != null) {
locationListener?.onLocationChanged(location) locationListener?.onLocationChanged(location)

View File

@ -11,12 +11,15 @@ class FragmentContentActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
title = intent.getStringExtra(EXTRA_TITLE) title = intent.getStringExtra(EXTRA_TITLE)
val fragment = Fragment.instantiate(this, intent.getStringExtra(EXTRA_FRAGMENT), intent.getStringExtra(EXTRA_FRAGMENT)?.let {
Fragment.instantiate(this, it,
intent.getBundleExtra(EXTRA_FRAGMENT_ARGUMENTS)) intent.getBundleExtra(EXTRA_FRAGMENT_ARGUMENTS))
}?.let { fragment ->
val ft = supportFragmentManager.beginTransaction() val ft = supportFragmentManager.beginTransaction()
ft.replace(android.R.id.content, fragment) ft.replace(android.R.id.content, fragment)
ft.commit() ft.commit()
} }
}
companion object { companion object {
const val EXTRA_FRAGMENT = "FCA:fragment" const val EXTRA_FRAGMENT = "FCA:fragment"

View File

@ -732,7 +732,9 @@ class HomeActivity : BaseActivity(), OnClickListener, OnPageChangeListener, Supp
} else { } else {
Utils.getDefaultAccountKey(this) Utils.getDefaultAccountKey(this)
} }
if (query != null) {
IntentUtils.openSearch(this, accountKey, query) IntentUtils.openSearch(this, accountKey, query)
}
return -1 return -1
} }
val refreshOnStart = preferences.getBoolean(SharedPreferenceConstants.KEY_REFRESH_ON_START, false) val refreshOnStart = preferences.getBoolean(SharedPreferenceConstants.KEY_REFRESH_ON_START, false)

View File

@ -41,18 +41,18 @@ class ImageCropperActivity : BaseActivity(), CropImageView.OnSetImageUriComplete
/** /**
* Persist URI image to crop URI if specific permissions are required * Persist URI image to crop URI if specific permissions are required
*/ */
private val cropImageUri: Uri get() = intent.getParcelableExtra(CropImage.CROP_IMAGE_EXTRA_SOURCE) private val cropImageUri: Uri? get() = intent.getParcelableExtra(CropImage.CROP_IMAGE_EXTRA_SOURCE)
/** /**
* the options that were set for the crop image * the options that were set for the crop image
*/ */
private val options: CropImageOptions get() = intent.getParcelableExtra(CropImage.CROP_IMAGE_EXTRA_OPTIONS) private val options: CropImageOptions? get() = intent.getParcelableExtra(CropImage.CROP_IMAGE_EXTRA_OPTIONS)
/** /**
* Get Android uri to save the cropped image into.<br></br> * Get Android uri to save the cropped image into.<br></br>
* Use the given in options or create a temp file. * Use the given in options or create a temp file.
*/ */
private val outputUri: Uri get() = options.outputUri private val outputUri: Uri? get() = options?.outputUri
@SuppressLint("NewApi") @SuppressLint("NewApi")
public override fun onCreate(savedInstanceState: Bundle?) { public override fun onCreate(savedInstanceState: Bundle?) {
@ -107,12 +107,14 @@ class ImageCropperActivity : BaseActivity(), CropImageView.OnSetImageUriComplete
override fun onSetImageUriComplete(view: CropImageView, uri: Uri, error: Exception?) { override fun onSetImageUriComplete(view: CropImageView, uri: Uri, error: Exception?) {
if (error == null) { if (error == null) {
options?.let { options ->
if (options.initialCropWindowRectangle != null) { if (options.initialCropWindowRectangle != null) {
cropImageView.cropRect = options.initialCropWindowRectangle cropImageView.cropRect = options.initialCropWindowRectangle
} }
if (options.initialRotation > -1) { if (options.initialRotation > -1) {
cropImageView.rotatedDegrees = options.initialRotation cropImageView.rotatedDegrees = options.initialRotation
} }
}
} else { } else {
setResult(null, error, 1) setResult(null, error, 1)
} }
@ -128,6 +130,7 @@ class ImageCropperActivity : BaseActivity(), CropImageView.OnSetImageUriComplete
* Execute crop image and save the result to output uri. * Execute crop image and save the result to output uri.
*/ */
private fun cropImage() { private fun cropImage() {
options?.let { options ->
if (options.noOutputImage) { if (options.noOutputImage) {
setResult(null, null, 1) setResult(null, null, 1)
} else { } else {
@ -140,6 +143,7 @@ class ImageCropperActivity : BaseActivity(), CropImageView.OnSetImageUriComplete
options.outputRequestSizeOptions) options.outputRequestSizeOptions)
} }
} }
}
/** /**
* Rotate the image in the crop image view. * Rotate the image in the crop image view.

View File

@ -111,7 +111,7 @@ class KeyboardShortcutPreferenceCompatActivity : BaseActivity(), OnClickListener
return true return true
} }
private val contextTag: String private val contextTag: String?
get() = intent.getStringExtra(EXTRA_CONTEXT_TAG) get() = intent.getStringExtra(EXTRA_CONTEXT_TAG)
private val keyAction: String? private val keyAction: String?

View File

@ -28,6 +28,7 @@ import android.database.Cursor
import android.graphics.PorterDuff.Mode import android.graphics.PorterDuff.Mode
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import androidx.loader.app.LoaderManager
import androidx.loader.app.LoaderManager.LoaderCallbacks import androidx.loader.app.LoaderManager.LoaderCallbacks
import androidx.loader.content.CursorLoader import androidx.loader.content.CursorLoader
import androidx.loader.content.Loader import androidx.loader.content.Loader
@ -157,7 +158,7 @@ class QuickSearchBarActivity : BaseActivity(), OnClickListener, LoaderCallbacks<
searchQuery.setSelection(searchQuery.length()) searchQuery.setSelection(searchQuery.length())
} }
supportLoaderManager.initLoader(0, null, this) LoaderManager.getInstance(this).initLoader(0, null, this)
updateSubmitButton() updateSubmitButton()
promotionService.loadBanner(adContainer) promotionService.loadBanner(adContainer)
@ -179,7 +180,7 @@ class QuickSearchBarActivity : BaseActivity(), OnClickListener, LoaderCallbacks<
adapter.addRemovedPositions(reverseSortedPositions) adapter.addRemovedPositions(reverseSortedPositions)
ContentResolverUtils.bulkDelete(contentResolver, SearchHistory.CONTENT_URI, SearchHistory._ID, ContentResolverUtils.bulkDelete(contentResolver, SearchHistory.CONTENT_URI, SearchHistory._ID,
false, ids, null, null) false, ids, null, null)
supportLoaderManager.restartLoader(0, null, this) LoaderManager.getInstance(this).restartLoader(0, null, this)
} }
override fun onClick(v: View) { override fun onClick(v: View) {
@ -298,7 +299,7 @@ class QuickSearchBarActivity : BaseActivity(), OnClickListener, LoaderCallbacks<
} }
override fun onItemSelected(parent: AdapterView<*>, view: View?, position: Int, id: Long) { override fun onItemSelected(parent: AdapterView<*>, view: View?, position: Int, id: Long) {
supportLoaderManager.restartLoader(0, null, this) LoaderManager.getInstance(this).restartLoader(0, null, this)
} }
override fun onNothingSelected(parent: AdapterView<*>) { override fun onNothingSelected(parent: AdapterView<*>) {

View File

@ -174,7 +174,9 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher,
when (requestCode) { when (requestCode) {
REQUEST_EDIT_API -> { REQUEST_EDIT_API -> {
if (resultCode == Activity.RESULT_OK && data != null) { if (resultCode == Activity.RESULT_OK && data != null) {
apiConfig = data.getParcelableExtra(EXTRA_API_CONFIG) data.getParcelableExtra<CustomAPIConfig>(EXTRA_API_CONFIG)?.let {
apiConfig = it
}
updateSignInType() updateSignInType()
} }
setSignInButton() setSignInButton()
@ -193,10 +195,12 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher,
val clientId = extras.getString(EXTRA_CLIENT_ID)!! val clientId = extras.getString(EXTRA_CLIENT_ID)!!
val clientSecret = extras.getString(EXTRA_CLIENT_SECRET)!! val clientSecret = extras.getString(EXTRA_CLIENT_SECRET)!!
if (code != null) {
finishMastodonBrowserLogin(host, clientId, clientSecret, code) finishMastodonBrowserLogin(host, clientId, clientSecret, code)
} }
} }
} }
}
super.onActivityResult(requestCode, resultCode, data) super.onActivityResult(requestCode, resultCode, data)
} }
@ -583,9 +587,9 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher,
val builder = AlertDialog.Builder(requireContext()) 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 { alertDialog ->
it.applyTheme() alertDialog.applyTheme()
val listView = it.expandableList val listView = alertDialog.expandableList
val adapter = LoginTypeAdapter(requireContext()) val adapter = LoginTypeAdapter(requireContext())
listView.setAdapter(adapter) listView.setAdapter(adapter)
listView.setOnGroupClickListener { _, _, groupPosition, _ -> listView.setOnGroupClickListener { _, _, groupPosition, _ ->
@ -613,7 +617,7 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher,
return@setOnChildClickListener true return@setOnChildClickListener true
} }
loaderManager.initLoader(0, null, this) LoaderManager.getInstance(this).initLoader(0, null, this)
} }
return dialog return dialog
} }

View File

@ -275,6 +275,24 @@ class TrendsLocationSelectorActivity : BaseActivity() {
dest.writeTypedArray(children, flags) dest.writeTypedArray(children, flags)
} }
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as LocationsData
if (root != other.root) return false
if (!children.contentEquals(other.children)) return false
return true
}
override fun hashCode(): Int {
var result = root.hashCode()
result = 31 * result + children.contentHashCode()
return result
}
companion object { companion object {
@JvmField @JvmField
val CREATOR = object : Parcelable.Creator<LocationsData> { val CREATOR = object : Parcelable.Creator<LocationsData> {

View File

@ -55,7 +55,7 @@ class UserListSelectorActivity : BaseActivity(),
override var refreshing: Boolean override var refreshing: Boolean
get() { get() {
return supportLoaderManager.hasRunningLoadersSafe() return LoaderManager.getInstance(this).hasRunningLoadersSafe()
} }
set(value) { set(value) {
} }
@ -137,7 +137,7 @@ class UserListSelectorActivity : BaseActivity(),
when (requestCode) { when (requestCode) {
REQUEST_SELECT_USER -> { REQUEST_SELECT_USER -> {
if (resultCode == Activity.RESULT_OK && data != null) { if (resultCode == Activity.RESULT_OK && data != null) {
val user = data.getParcelableExtra<ParcelableUser>(EXTRA_USER) val user = data.getParcelableExtra<ParcelableUser>(EXTRA_USER) ?: return
loadUserLists(accountKey!!, user.key) loadUserLists(accountKey!!, user.key)
} }
} }
@ -199,9 +199,9 @@ class UserListSelectorActivity : BaseActivity(),
} }
if (!loaderInitialized) { if (!loaderInitialized) {
loaderInitialized = true loaderInitialized = true
supportLoaderManager.initLoader(0, args, this) LoaderManager.getInstance(this).initLoader(0, args, this)
} else { } else {
supportLoaderManager.restartLoader(0, args, this) LoaderManager.getInstance(this).restartLoader(0, args, this)
} }
} }

View File

@ -153,10 +153,10 @@ class UserSelectorActivity : BaseActivity(), OnItemClickListener, LoaderManager.
this[EXTRA_FROM_CACHE] = fromCache this[EXTRA_FROM_CACHE] = fromCache
} }
if (loaderInitialized) { if (loaderInitialized) {
supportLoaderManager.initLoader(0, args, this) LoaderManager.getInstance(this).initLoader(0, args, this)
loaderInitialized = true loaderInitialized = true
} else { } else {
supportLoaderManager.restartLoader(0, args, this) LoaderManager.getInstance(this).restartLoader(0, args, this)
} }
} }

View File

@ -177,7 +177,7 @@ class WebLinkHandlerActivity : Activity() {
if (pathSegments[0] in TWITTER_RESERVED_PATHS) { if (pathSegments[0] in TWITTER_RESERVED_PATHS) {
return Pair(null, true) return Pair(null, true)
} }
return handleUserSpecificPageIntent(uri, pathSegments, pathSegments[0]) return handleUserSpecificPageIntent(pathSegments, pathSegments[0])
} }
} }
} }
@ -185,7 +185,7 @@ class WebLinkHandlerActivity : Activity() {
return Pair(homeIntent, true) return Pair(homeIntent, true)
} }
private fun handleUserSpecificPageIntent(uri: Uri, pathSegments: List<String>, screenName: String): Pair<Intent?, Boolean> { private fun handleUserSpecificPageIntent(pathSegments: List<String>, screenName: String): Pair<Intent?, Boolean> {
val segsSize = pathSegments.size val segsSize = pathSegments.size
if (segsSize == 1) { if (segsSize == 1) {
val builder = Uri.Builder() val builder = Uri.Builder()

View File

@ -74,7 +74,9 @@ abstract class AbsStatusDialogActivity : BaseActivity() {
return return
} }
val accountKey = data.getParcelableExtra<UserKey>(EXTRA_ACCOUNT_KEY) val accountKey = data.getParcelableExtra<UserKey>(EXTRA_ACCOUNT_KEY)
if (accountKey != null) {
showDialogFragment(accountKey, statusId, status) showDialogFragment(accountKey, statusId, status)
}
return return
} }
} }

View File

@ -11,7 +11,7 @@ import org.mariotaku.twidere.model.premium.PurchaseResult
*/ */
abstract class AbsExtraFeaturePurchaseActivity : BaseActivity() { abstract class AbsExtraFeaturePurchaseActivity : BaseActivity() {
protected val requestingFeature: String get() = intent.getStringExtra(EXTRA_REQUESTING_FEATURE) protected val requestingFeature: String? get() = intent.getStringExtra(EXTRA_REQUESTING_FEATURE)
protected fun finishWithError(code: Int) { protected fun finishWithError(code: Int) {
setResult(code) setResult(code)

View File

@ -44,9 +44,11 @@ abstract class AbsUserListRelatedShortcutCreatorActivity : AbsShortcutCreatorAct
} }
val list = data.getParcelableExtra<ParcelableUserList>(EXTRA_USER_LIST) val list = data.getParcelableExtra<ParcelableUserList>(EXTRA_USER_LIST)
val extras = data.getBundleExtra(EXTRA_EXTRAS) val extras = data.getBundleExtra(EXTRA_EXTRAS)
val accountKey = extras.getParcelable<UserKey>(EXTRA_ACCOUNT_KEY) val accountKey = extras?.getParcelable<UserKey>(EXTRA_ACCOUNT_KEY)
if (list != null) {
onUserListSelected(accountKey, list) onUserListSelected(accountKey, list)
} }
}
else -> { else -> {
super.onActivityResult(requestCode, resultCode, data) super.onActivityResult(requestCode, resultCode, data)
} }

View File

@ -44,9 +44,11 @@ abstract class AbsUserRelatedShortcutCreatorActivity : AbsShortcutCreatorActivit
} }
val user = data.getParcelableExtra<ParcelableUser>(EXTRA_USER) val user = data.getParcelableExtra<ParcelableUser>(EXTRA_USER)
val extras = data.getBundleExtra(EXTRA_EXTRAS) val extras = data.getBundleExtra(EXTRA_EXTRAS)
val accountKey = extras.getParcelable<UserKey>(EXTRA_ACCOUNT_KEY) val accountKey = extras?.getParcelable<UserKey>(EXTRA_ACCOUNT_KEY)
if (user != null) {
onUserSelected(accountKey, user) onUserSelected(accountKey, user)
} }
}
else -> { else -> {
super.onActivityResult(requestCode, resultCode, data) super.onActivityResult(requestCode, resultCode, data)
} }

View File

@ -104,7 +104,7 @@ class DummyItemAdapter(
override fun getAccountKey(position: Int, raw: Boolean) = UserKey.INVALID override fun getAccountKey(position: Int, raw: Boolean) = UserKey.INVALID
override fun findStatusById(accountKey: UserKey, statusId: String) = null override fun findStatusById(accountKey: UserKey, statusId: String): Nothing? = null
override fun isCardNumbersShown(position: Int): Boolean { override fun isCardNumbersShown(position: Int): Boolean {
if (position == RecyclerView.NO_POSITION) return showCardNumbers if (position == RecyclerView.NO_POSITION) return showCardNumbers

View File

@ -27,6 +27,7 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import com.bumptech.glide.RequestManager import com.bumptech.glide.RequestManager
import org.apache.commons.lang3.time.DateUtils
import org.mariotaku.chameleon.Chameleon import org.mariotaku.chameleon.Chameleon
import org.mariotaku.chameleon.ChameleonUtils import org.mariotaku.chameleon.ChameleonUtils
import org.mariotaku.kpreferences.get import org.mariotaku.kpreferences.get
@ -39,7 +40,6 @@ import org.mariotaku.twidere.constant.linkHighlightOptionKey
import org.mariotaku.twidere.constant.mediaPreviewStyleKey import org.mariotaku.twidere.constant.mediaPreviewStyleKey
import org.mariotaku.twidere.constant.nameFirstKey import org.mariotaku.twidere.constant.nameFirstKey
import org.mariotaku.twidere.exception.UnsupportedCountIndexException import org.mariotaku.twidere.exception.UnsupportedCountIndexException
import org.mariotaku.twidere.extension.isSameDay
import org.mariotaku.twidere.extension.model.timestamp import org.mariotaku.twidere.extension.model.timestamp
import org.mariotaku.twidere.model.* import org.mariotaku.twidere.model.*
import org.mariotaku.twidere.model.ParcelableMessage.MessageType import org.mariotaku.twidere.model.ParcelableMessage.MessageType
@ -137,7 +137,7 @@ class MessagesConversationAdapter(
+ itemCounts[ITEM_START_MESSAGE] - 1) { + itemCounts[ITEM_START_MESSAGE] - 1) {
calendars.first.timeInMillis = getMessageTimestamp(position + 1) calendars.first.timeInMillis = getMessageTimestamp(position + 1)
calendars.second.timeInMillis = message.timestamp calendars.second.timeInMillis = message.timestamp
showDate = !calendars.first.isSameDay(calendars.second) showDate = !DateUtils.isSameDay(calendars.first, calendars.second)
} }
(holder as AbsMessageViewHolder).display(message, showDate) (holder as AbsMessageViewHolder).display(message, showDate)
} }

View File

@ -22,7 +22,7 @@ package org.mariotaku.twidere.adapter
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.database.CursorIndexOutOfBoundsException import android.database.CursorIndexOutOfBoundsException
import androidx.legacy.widget.Space import android.widget.Space
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View

View File

@ -24,7 +24,7 @@ import android.database.CursorIndexOutOfBoundsException
import android.util.SparseBooleanArray import android.util.SparseBooleanArray
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import androidx.legacy.widget.Space import android.widget.Space
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.RequestManager import com.bumptech.glide.RequestManager
import org.mariotaku.kpreferences.get import org.mariotaku.kpreferences.get

View File

@ -126,16 +126,20 @@ class StatusDetailsAdapter(
override fun getStatus(position: Int, raw: Boolean): ParcelableStatus { override fun getStatus(position: Int, raw: Boolean): ParcelableStatus {
when (getItemCountIndex(position, raw)) { when (getItemCountIndex(position, raw)) {
ITEM_IDX_CONVERSATION -> { ITEM_IDX_CONVERSATION -> {
data?.let { data ->
var idx = position - getIndexStart(ITEM_IDX_CONVERSATION) var idx = position - getIndexStart(ITEM_IDX_CONVERSATION)
if (data!![idx].is_filtered) idx++ if (data[idx].is_filtered) idx++
return data!![idx] return data[idx]
}
} }
ITEM_IDX_REPLY -> { ITEM_IDX_REPLY -> {
data?.let { data ->
var idx = position - getIndexStart(ITEM_IDX_CONVERSATION) - var idx = position - getIndexStart(ITEM_IDX_CONVERSATION) -
getTypeCount(ITEM_IDX_CONVERSATION) - getTypeCount(ITEM_IDX_STATUS) + getTypeCount(ITEM_IDX_CONVERSATION) - getTypeCount(ITEM_IDX_STATUS) +
replyStart replyStart
if (data!![idx].is_filtered) idx++ if (data[idx].is_filtered) idx++
return data!![idx] return data[idx]
}
} }
ITEM_IDX_STATUS -> { ITEM_IDX_STATUS -> {
return status!! return status!!

View File

@ -19,4 +19,6 @@
package org.mariotaku.twidere.alias package org.mariotaku.twidere.alias
typealias TwitterRegex = com.twitter.Regex import com.twitter.twittertext.Regex
typealias TwitterRegex = Regex

View File

@ -36,6 +36,7 @@ import androidx.multidex.MultiDex
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import nl.komponents.kovenant.task import nl.komponents.kovenant.task
import okhttp3.Dns import okhttp3.Dns
import org.apache.commons.lang3.concurrent.ConcurrentUtils
import org.mariotaku.abstask.library.TaskStarter import org.mariotaku.abstask.library.TaskStarter
import org.mariotaku.commons.logansquare.LoganSquareMapperFinder import org.mariotaku.commons.logansquare.LoganSquareMapperFinder
import org.mariotaku.kpreferences.KPreferences import org.mariotaku.kpreferences.KPreferences
@ -59,7 +60,6 @@ import org.mariotaku.twidere.extension.setLocale
import org.mariotaku.twidere.model.DefaultFeatures import org.mariotaku.twidere.model.DefaultFeatures
import org.mariotaku.twidere.receiver.ConnectivityStateReceiver import org.mariotaku.twidere.receiver.ConnectivityStateReceiver
import org.mariotaku.twidere.util.* import org.mariotaku.twidere.util.*
import org.mariotaku.twidere.util.concurrent.ConstantFuture
import org.mariotaku.twidere.util.content.TwidereSQLiteOpenHelper import org.mariotaku.twidere.util.content.TwidereSQLiteOpenHelper
import org.mariotaku.twidere.util.dagger.ApplicationModule import org.mariotaku.twidere.util.dagger.ApplicationModule
import org.mariotaku.twidere.util.dagger.GeneralComponent import org.mariotaku.twidere.util.dagger.GeneralComponent
@ -176,7 +176,7 @@ class TwidereApplication : Application(), OnSharedPreferenceChangeListener {
}, updateImmediately = true) }, updateImmediately = true)
} }
override fun onConfigurationChanged(newConfig: Configuration?) { override fun onConfigurationChanged(newConfig: Configuration) {
applyLanguageSettings() applyLanguageSettings()
super.onConfigurationChanged(newConfig) super.onConfigurationChanged(newConfig)
} }
@ -320,7 +320,7 @@ class TwidereApplication : Application(), OnSharedPreferenceChangeListener {
LoganSquareMapperFinder.setDefaultExecutor(object : LoganSquareMapperFinder.FutureExecutor { LoganSquareMapperFinder.setDefaultExecutor(object : LoganSquareMapperFinder.FutureExecutor {
override fun <T> submit(callable: Callable<T>): Future<T> { override fun <T> submit(callable: Callable<T>): Future<T> {
if (Looper.getMainLooper().isCurrentThreadCompat) { if (Looper.getMainLooper().isCurrentThreadCompat) {
return ConstantFuture(callable.call()) return ConcurrentUtils.constantFuture(callable.call())
} }
return executor.submit(callable) return executor.submit(callable)
} }

View File

@ -10,7 +10,6 @@ import org.mariotaku.ktextension.bcp47Tag
import org.mariotaku.ktextension.toLongOr import org.mariotaku.ktextension.toLongOr
import org.mariotaku.twidere.BuildConfig import org.mariotaku.twidere.BuildConfig
import org.mariotaku.twidere.Constants.* import org.mariotaku.twidere.Constants.*
import org.mariotaku.twidere.TwidereConstants
import org.mariotaku.twidere.TwidereConstants.KEY_MEDIA_PRELOAD import org.mariotaku.twidere.TwidereConstants.KEY_MEDIA_PRELOAD
import org.mariotaku.twidere.annotation.AccountType import org.mariotaku.twidere.annotation.AccountType
import org.mariotaku.twidere.annotation.ImageShapeStyle import org.mariotaku.twidere.annotation.ImageShapeStyle
@ -87,7 +86,6 @@ val lastLaunchTimeKey = KLongKey("last_launch_time", -1)
val promotionsEnabledKey = KBooleanKey("promotions_enabled", false) val promotionsEnabledKey = KBooleanKey("promotions_enabled", false)
val translationDestinationKey = KNullableStringKey(KEY_TRANSLATION_DESTINATION, null) val translationDestinationKey = KNullableStringKey(KEY_TRANSLATION_DESTINATION, null)
val tabPositionKey = KStringKey(KEY_TAB_POSITION, SharedPreferenceConstants.DEFAULT_TAB_POSITION) val tabPositionKey = KStringKey(KEY_TAB_POSITION, SharedPreferenceConstants.DEFAULT_TAB_POSITION)
val yandexKeyKey = KStringKey(SharedPreferenceConstants.KEY_YANDEX_KEY, TwidereConstants.YANDEX_KEY)
val autoHideTabs = KBooleanKey(SharedPreferenceConstants.KEY_AUTO_HIDE_TABS, true) val autoHideTabs = KBooleanKey(SharedPreferenceConstants.KEY_AUTO_HIDE_TABS, true)
val hideCardNumbersKey = KBooleanKey(KEY_HIDE_CARD_NUMBERS, false) val hideCardNumbersKey = KBooleanKey(KEY_HIDE_CARD_NUMBERS, false)
val showLinkPreviewKey = KBooleanKey(KEY_SHOW_LINK_PREVIEW, false) val showLinkPreviewKey = KBooleanKey(KEY_SHOW_LINK_PREVIEW, false)

View File

@ -1,31 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2017 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.extension
import java.util.*
/**
* Created by mariotaku on 2017/9/25.
*/
fun Calendar.isSameDay(that: Calendar): Boolean {
return this[Calendar.ERA] == that[Calendar.ERA] &&
this[Calendar.YEAR] == that[Calendar.YEAR] &&
this[Calendar.DAY_OF_YEAR] == that[Calendar.DAY_OF_YEAR]
}

View File

@ -32,7 +32,7 @@ val ConnectivityManager.activateNetworkCompat: Network?
return activeNetwork return activeNetwork
} }
val activeInfo = activeNetworkInfo ?: return null val activeInfo = activeNetworkInfo ?: return null
return allNetworks.firstOrNull { activeInfo.same(getNetworkInfo(it)) } return allNetworks.firstOrNull { getNetworkInfo(it)?.let { it1 -> activeInfo.same(it1) } == true }
} }
private fun NetworkInfo.same(another: NetworkInfo) = type == another.type && subtype == another.subtype private fun NetworkInfo.same(another: NetworkInfo) = type == another.type && subtype == another.subtype

View File

@ -21,6 +21,7 @@ package org.mariotaku.twidere.extension.model.api
import android.text.Spanned import android.text.Spanned
import android.text.style.URLSpan import android.text.style.URLSpan
import org.apache.commons.text.translate.EntityArrays
import org.apache.commons.text.translate.LookupTranslator import org.apache.commons.text.translate.LookupTranslator
import org.mariotaku.commons.text.CodePointArray import org.mariotaku.commons.text.CodePointArray
import org.mariotaku.ktextension.isNotNullOrEmpty import org.mariotaku.ktextension.isNotNullOrEmpty
@ -40,7 +41,6 @@ import org.mariotaku.twidere.model.util.ParcelableLocationUtils
import org.mariotaku.twidere.model.util.ParcelableMediaUtils import org.mariotaku.twidere.model.util.ParcelableMediaUtils
import org.mariotaku.twidere.text.AcctMentionSpan import org.mariotaku.twidere.text.AcctMentionSpan
import org.mariotaku.twidere.text.HashtagSpan import org.mariotaku.twidere.text.HashtagSpan
import org.mariotaku.twidere.util.EntityArrays
import org.mariotaku.twidere.util.HtmlBuilder import org.mariotaku.twidere.util.HtmlBuilder
import org.mariotaku.twidere.util.HtmlSpanBuilder import org.mariotaku.twidere.util.HtmlSpanBuilder
import org.mariotaku.twidere.util.InternalTwitterContentUtils import org.mariotaku.twidere.util.InternalTwitterContentUtils

View File

@ -71,26 +71,26 @@ fun Activity.toParcelable(accountKey: UserKey, accountType: String, isGap: Boole
it.toParcelable(accountKey, accountType, profileImageSize = profileImageSize) it.toParcelable(accountKey, accountType, profileImageSize = profileImageSize)
} }
result.targets = ParcelableActivity.RelatedObject().also { result.targets = ParcelableActivity.RelatedObject().also { relatedObject ->
it.statuses = targetStatuses?.mapToArray { relatedObject.statuses = targetStatuses?.mapToArray {
it.toParcelable(accountKey, accountType, profileImageSize) it.toParcelable(accountKey, accountType, profileImageSize)
} }
it.users = targetUsers?.mapToArray { relatedObject.users = targetUsers?.mapToArray {
it.toParcelable(accountKey, accountType, profileImageSize = profileImageSize) it.toParcelable(accountKey, accountType, profileImageSize = profileImageSize)
} }
it.user_lists = targetUserLists?.mapToArray { relatedObject.user_lists = targetUserLists?.mapToArray {
it.toParcelable(accountKey, profileImageSize = profileImageSize) it.toParcelable(accountKey, profileImageSize = profileImageSize)
} }
} }
result.target_objects = ParcelableActivity.RelatedObject().also { result.target_objects = ParcelableActivity.RelatedObject().also { relatedObject ->
it.statuses = targetObjectStatuses?.mapToArray { relatedObject.statuses = targetObjectStatuses?.mapToArray {
it.toParcelable(accountKey, accountType, profileImageSize) it.toParcelable(accountKey, accountType, profileImageSize)
} }
it.users = targetObjectUsers?.mapToArray { relatedObject.users = targetObjectUsers?.mapToArray {
it.toParcelable(accountKey, accountType, profileImageSize = profileImageSize) it.toParcelable(accountKey, accountType, profileImageSize = profileImageSize)
} }
it.user_lists = targetObjectUserLists?.mapToArray { relatedObject.user_lists = targetObjectUserLists?.mapToArray {
it.toParcelable(accountKey, profileImageSize = profileImageSize) it.toParcelable(accountKey, profileImageSize = profileImageSize)
} }
} }

View File

@ -19,7 +19,7 @@
package org.mariotaku.twidere.extension.text.twitter package org.mariotaku.twidere.extension.text.twitter
import com.twitter.Extractor import com.twitter.twittertext.Extractor
import org.mariotaku.twidere.extension.model.replyMentions import org.mariotaku.twidere.extension.model.replyMentions
import org.mariotaku.twidere.model.ParcelableStatus import org.mariotaku.twidere.model.ParcelableStatus
import org.mariotaku.twidere.model.ParcelableUserMention import org.mariotaku.twidere.model.ParcelableUserMention

View File

@ -19,8 +19,8 @@
package org.mariotaku.twidere.extension.text.twitter package org.mariotaku.twidere.extension.text.twitter
import com.twitter.Extractor import com.twitter.twittertext.Extractor
import com.twitter.Validator import com.twitter.twittertext.Validator
import org.mariotaku.twidere.model.ParcelableStatus import org.mariotaku.twidere.model.ParcelableStatus
import org.mariotaku.twidere.model.UserKey import org.mariotaku.twidere.model.UserKey

View File

@ -26,4 +26,4 @@ import org.mariotaku.twidere.util.premium.ExtraFeaturesService.Companion.FEATURE
* Created by mariotaku on 2017/9/14. * Created by mariotaku on 2017/9/14.
*/ */
val ExtraFeaturesService.isAdvancedFiltersEnabled: Boolean val ExtraFeaturesService.isAdvancedFiltersEnabled: Boolean
get() = isEnabled(FEATURE_ADVANCED_FILTERS) || isEnabled("filters_subscriptions") get() = true//isEnabled(FEATURE_ADVANCED_FILTERS) || isEnabled("filters_subscriptions")

View File

@ -152,7 +152,7 @@ class APIEditorDialogFragment : BaseDialogFragment() {
adapter = CustomAPIConfigArrayAdapter(requireContext()) adapter = CustomAPIConfigArrayAdapter(requireContext())
val builder = AlertDialog.Builder(requireContext()) val builder = AlertDialog.Builder(requireContext())
builder.setAdapter(adapter, this) builder.setAdapter(adapter, this)
loaderManager.initLoader(0, null, this) LoaderManager.getInstance(this).initLoader(0, null, this)
val dialog = builder.create() val dialog = builder.create()
dialog.onShow { it.applyTheme() } dialog.onShow { it.applyTheme() }
return dialog return dialog

View File

@ -33,6 +33,7 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.OnScrollListener import androidx.recyclerview.widget.RecyclerView.OnScrollListener
import android.view.* import android.view.*
import androidx.loader.app.LoaderManager
import com.squareup.otto.Subscribe import com.squareup.otto.Subscribe
import kotlinx.android.synthetic.main.fragment_content_recyclerview.* import kotlinx.android.synthetic.main.fragment_content_recyclerview.*
import org.mariotaku.kpreferences.get import org.mariotaku.kpreferences.get
@ -110,7 +111,7 @@ abstract class AbsActivitiesFragment protected constructor() :
val loaderArgs = Bundle(arguments) val loaderArgs = Bundle(arguments)
loaderArgs.putBoolean(EXTRA_FROM_USER, true) loaderArgs.putBoolean(EXTRA_FROM_USER, true)
loaderManager.initLoader(loaderId, loaderArgs, this) LoaderManager.getInstance(this).initLoader(loaderId, loaderArgs, this)
showProgress() showProgress()
} }
@ -531,7 +532,7 @@ abstract class AbsActivitiesFragment protected constructor() :
return true return true
} }
else -> activity?.let { else -> activity?.let {
fragmentManager?.let { fragmentManager -> parentFragmentManager.let { fragmentManager ->
MenuUtils.handleStatusClick(it, this, fragmentManager, MenuUtils.handleStatusClick(it, this, fragmentManager,
preferences, userColorNameManager, twitterWrapper, status, item) preferences, userColorNameManager, twitterWrapper, status, item)
} }

View File

@ -21,6 +21,7 @@ package org.mariotaku.twidere.fragment
import android.content.Context import android.content.Context
import android.os.Bundle import android.os.Bundle
import androidx.loader.app.LoaderManager
import androidx.loader.app.LoaderManager.LoaderCallbacks import androidx.loader.app.LoaderManager.LoaderCallbacks
import androidx.loader.app.hasRunningLoadersSafe import androidx.loader.app.hasRunningLoadersSafe
import androidx.loader.content.Loader import androidx.loader.content.Loader
@ -49,7 +50,7 @@ abstract class AbsMediaStatusesFragment : AbsContentRecyclerViewFragment<Stagger
final override var refreshing: Boolean final override var refreshing: Boolean
get() { get() {
if (context == null || isDetached) return false if (context == null || isDetached) return false
return loaderManager.hasRunningLoadersSafe() return LoaderManager.getInstance(this).hasRunningLoadersSafe()
} }
set(value) { set(value) {
super.refreshing = value super.refreshing = value
@ -69,7 +70,7 @@ abstract class AbsMediaStatusesFragment : AbsContentRecyclerViewFragment<Stagger
adapter.statusClickListener = this adapter.statusClickListener = this
val loaderArgs = Bundle(arguments) val loaderArgs = Bundle(arguments)
loaderArgs.putBoolean(EXTRA_FROM_USER, true) loaderArgs.putBoolean(EXTRA_FROM_USER, true)
loaderManager.initLoader(loaderId, loaderArgs, this) LoaderManager.getInstance(this).initLoader(loaderId, loaderArgs, this)
showProgress() showProgress()
} }

View File

@ -35,6 +35,7 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.OnScrollListener import androidx.recyclerview.widget.RecyclerView.OnScrollListener
import android.view.* import android.view.*
import androidx.loader.app.LoaderManager
import com.squareup.otto.Subscribe import com.squareup.otto.Subscribe
import kotlinx.android.synthetic.main.fragment_content_recyclerview.* import kotlinx.android.synthetic.main.fragment_content_recyclerview.*
import org.mariotaku.kpreferences.get import org.mariotaku.kpreferences.get
@ -490,7 +491,7 @@ abstract class AbsStatusesFragment : AbsContentListRecyclerViewFragment<Parcelab
if (isDetached || host == null || loaderInitialized) return if (isDetached || host == null || loaderInitialized) return
val loaderArgs = Bundle(arguments) val loaderArgs = Bundle(arguments)
loaderArgs.putBoolean(EXTRA_FROM_USER, true) loaderArgs.putBoolean(EXTRA_FROM_USER, true)
loaderManager.initLoader(loaderId, loaderArgs, this) LoaderManager.getInstance(this).initLoader(loaderId, loaderArgs, this)
loaderInitialized = true loaderInitialized = true
} }
@ -575,7 +576,7 @@ abstract class AbsStatusesFragment : AbsContentListRecyclerViewFragment<Parcelab
resolver?.update(contentUri, values, where, null) resolver?.update(contentUri, values, where, null)
return true return true
} }
else -> return MenuUtils.handleStatusClick(requireActivity(), this, requireFragmentManager(), else -> return MenuUtils.handleStatusClick(requireActivity(), this, parentFragmentManager,
preferences, userColorNameManager, twitterWrapper, status, item) preferences, userColorNameManager, twitterWrapper, status, item)
} }
} }

View File

@ -46,6 +46,7 @@ import androidx.appcompat.view.SupportMenuInflater
import androidx.appcompat.widget.ActionMenuView.OnMenuItemClickListener import androidx.appcompat.widget.ActionMenuView.OnMenuItemClickListener
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.view.MenuItemCompat import androidx.core.view.MenuItemCompat
import androidx.loader.app.LoaderManager
import androidx.loader.app.LoaderManager.LoaderCallbacks import androidx.loader.app.LoaderManager.LoaderCallbacks
import androidx.loader.content.FixedAsyncTaskLoader import androidx.loader.content.FixedAsyncTaskLoader
import androidx.loader.content.Loader import androidx.loader.content.Loader
@ -286,9 +287,9 @@ class AccountsDashboardFragment : BaseFragment(), LoaderCallbacks<AccountsInfo>,
fun loadAccounts() { fun loadAccounts() {
if (!loaderInitialized) { if (!loaderInitialized) {
loaderInitialized = true loaderInitialized = true
loaderManager.initLoader(0, null, this) LoaderManager.getInstance(this).initLoader(0, null, this)
} else { } else {
loaderManager.restartLoader(0, null, this) LoaderManager.getInstance(this).restartLoader(0, null, this)
} }
} }
@ -659,7 +660,25 @@ class AccountsDashboardFragment : BaseFragment(), LoaderCallbacks<AccountsInfo>,
data class AccountsInfo( data class AccountsInfo(
val accounts: Array<AccountDetails>, val accounts: Array<AccountDetails>,
val draftsCount: Int val draftsCount: Int
) ) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as AccountsInfo
if (!accounts.contentEquals(other.accounts)) return false
if (draftsCount != other.draftsCount) return false
return true
}
override fun hashCode(): Int {
var result = accounts.contentHashCode()
result = 31 * result + draftsCount
return result
}
}
class AccountsInfoLoader( class AccountsInfoLoader(
context: Context, context: Context,

View File

@ -86,7 +86,7 @@ class AccountsManagerFragment : BaseFragment(), LoaderManager.LoaderCallbacks<Li
emptyIcon.setImageResource(R.drawable.ic_info_error_generic) emptyIcon.setImageResource(R.drawable.ic_info_error_generic)
setListShown(false) setListShown(false)
loaderManager.initLoader(0, null, this) LoaderManager.getInstance(this).initLoader(0, null, this)
} }
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
@ -95,7 +95,7 @@ class AccountsManagerFragment : BaseFragment(), LoaderManager.LoaderCallbacks<Li
if (resultCode != Activity.RESULT_OK || data == null) if (resultCode != Activity.RESULT_OK || data == null)
return return
val am = AccountManager.get(context) val am = AccountManager.get(context)
val accountKey: UserKey = data.getBundleExtra(EXTRA_EXTRAS).getParcelable(EXTRA_ACCOUNT_KEY) ?: return val accountKey: UserKey = data.getBundleExtra(EXTRA_EXTRAS)?.getParcelable(EXTRA_ACCOUNT_KEY) ?: return
val color = data.getIntExtra(EXTRA_COLOR, Color.WHITE) val color = data.getIntExtra(EXTRA_COLOR, Color.WHITE)
val details = adapter.findItem(accountKey) ?: return val details = adapter.findItem(accountKey) ?: return
details.color = color details.color = color

View File

@ -24,7 +24,7 @@ import android.content.ContentValues
import android.os.Bundle import android.os.Bundle
import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentManager
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import com.twitter.Extractor import com.twitter.twittertext.Extractor
import org.mariotaku.kpreferences.get import org.mariotaku.kpreferences.get
import org.mariotaku.twidere.R import org.mariotaku.twidere.R
import org.mariotaku.twidere.constant.IntentConstants.EXTRA_STATUS import org.mariotaku.twidere.constant.IntentConstants.EXTRA_STATUS

View File

@ -57,7 +57,7 @@ open class BaseWebViewFragment : BaseFragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? { savedInstanceState: Bundle?): View? {
internalWebView?.destroy() internalWebView?.destroy()
internalWebView = WebView(activity) internalWebView = activity?.let { WebView(it) }
webViewAvailable = true webViewAvailable = true
return internalWebView return internalWebView
} }

View File

@ -29,6 +29,7 @@ import android.os.Bundle
import android.os.Handler import android.os.Handler
import androidx.loader.content.Loader import androidx.loader.content.Loader
import android.widget.Toast import android.widget.Toast
import androidx.loader.app.LoaderManager
import com.squareup.otto.Subscribe import com.squareup.otto.Subscribe
import org.mariotaku.ktextension.* import org.mariotaku.ktextension.*
import org.mariotaku.library.objectcursor.ObjectCursor import org.mariotaku.library.objectcursor.ObjectCursor
@ -174,7 +175,7 @@ abstract class CursorActivitiesFragment : AbsActivitiesFragment() {
} }
override val shouldAbort: Boolean override val shouldAbort: Boolean
get() = currentContext == null get() = false
}) })
} }
@ -237,7 +238,7 @@ abstract class CursorActivitiesFragment : AbsActivitiesFragment() {
args.putAll(fragmentArgs) args.putAll(fragmentArgs)
args.putBoolean(EXTRA_FROM_USER, true) args.putBoolean(EXTRA_FROM_USER, true)
} }
loaderManager.restartLoader(loaderId, args, this) LoaderManager.getInstance(this).restartLoader(loaderId, args, this)
} }
fun replaceStatusStates(result: ParcelableStatus?) { fun replaceStatusStates(result: ParcelableStatus?) {

View File

@ -28,6 +28,7 @@ import android.os.Bundle
import android.os.Handler import android.os.Handler
import androidx.loader.content.Loader import androidx.loader.content.Loader
import android.widget.Toast import android.widget.Toast
import androidx.loader.app.LoaderManager
import com.bumptech.glide.RequestManager import com.bumptech.glide.RequestManager
import com.squareup.otto.Subscribe import com.squareup.otto.Subscribe
import kotlinx.android.synthetic.main.fragment_content_recyclerview.* import kotlinx.android.synthetic.main.fragment_content_recyclerview.*
@ -236,7 +237,7 @@ abstract class CursorStatusesFragment : AbsStatusesFragment() {
args.putAll(fragmentArgs) args.putAll(fragmentArgs)
args.putBoolean(EXTRA_FROM_USER, true) args.putBoolean(EXTRA_FROM_USER, true)
} }
loaderManager.restartLoader(loaderId, args, this) LoaderManager.getInstance(this).restartLoader(loaderId, args, this)
} }
private fun showContentOrError() { private fun showContentOrError() {

View File

@ -39,6 +39,7 @@ import android.view.*
import android.widget.* import android.widget.*
import android.widget.AbsListView.MultiChoiceModeListener import android.widget.AbsListView.MultiChoiceModeListener
import android.widget.AdapterView.OnItemClickListener import android.widget.AdapterView.OnItemClickListener
import androidx.loader.app.LoaderManager
import com.mobeta.android.dslv.SimpleDragSortCursorAdapter import com.mobeta.android.dslv.SimpleDragSortCursorAdapter
import kotlinx.android.synthetic.main.dialog_custom_tab_editor.* import kotlinx.android.synthetic.main.dialog_custom_tab_editor.*
import kotlinx.android.synthetic.main.layout_draggable_list_with_empty_view.* import kotlinx.android.synthetic.main.layout_draggable_list_with_empty_view.*
@ -102,7 +103,7 @@ class CustomTabsFragment : BaseFragment(), LoaderCallbacks<Cursor?>, MultiChoice
df.arguments = Bundle { df.arguments = Bundle {
this[EXTRA_OBJECT] = tab this[EXTRA_OBJECT] = tab
} }
fragmentManager?.let { df.show(it, TabEditorDialogFragment.TAG_EDIT_TAB) } parentFragmentManager.let { df.show(it, TabEditorDialogFragment.TAG_EDIT_TAB) }
} }
listView.adapter = adapter listView.adapter = adapter
listView.emptyView = emptyView listView.emptyView = emptyView
@ -115,7 +116,7 @@ class CustomTabsFragment : BaseFragment(), LoaderCallbacks<Cursor?>, MultiChoice
} }
emptyText.setText(R.string.no_tab) emptyText.setText(R.string.no_tab)
emptyIcon.setImageResource(R.drawable.ic_info_tab) emptyIcon.setImageResource(R.drawable.ic_info_tab)
loaderManager.initLoader(0, null, this) LoaderManager.getInstance(this).initLoader(0, null, this)
setListShown(false) setListShown(false)
} }

View File

@ -46,13 +46,13 @@ class EditUserListDialogFragment : BaseDialogFragment() {
builder.positive(android.R.string.ok, this::onPositiveClick) builder.positive(android.R.string.ok, this::onPositiveClick)
builder.setNegativeButton(android.R.string.cancel, null) builder.setNegativeButton(android.R.string.cancel, null)
val dialog = builder.create() val dialog = builder.create()
dialog.onShow { dialog -> dialog.onShow { alertDialog ->
dialog.applyTheme() alertDialog.applyTheme()
dialog.editName.addValidator(UserListNameValidator(getString(R.string.invalid_list_name))) alertDialog.editName.addValidator(UserListNameValidator(getString(R.string.invalid_list_name)))
if (savedInstanceState == null) { if (savedInstanceState == null) {
dialog.editName.setText(arguments?.getString(EXTRA_LIST_NAME)) alertDialog.editName.setText(arguments?.getString(EXTRA_LIST_NAME))
dialog.editDescription.setText(arguments?.getString(EXTRA_DESCRIPTION)) alertDialog.editDescription.setText(arguments?.getString(EXTRA_DESCRIPTION))
dialog.isPublic.isChecked = arguments?.getBoolean(EXTRA_IS_PUBLIC, true) ?: true alertDialog.isPublic.isChecked = arguments?.getBoolean(EXTRA_IS_PUBLIC, true) ?: true
} }
} }
return dialog return dialog

View File

@ -33,6 +33,7 @@ import android.view.MenuItem
import android.view.View import android.view.View
import android.widget.AdapterView import android.widget.AdapterView
import android.widget.AdapterView.AdapterContextMenuInfo import android.widget.AdapterView.AdapterContextMenuInfo
import androidx.loader.app.LoaderManager
import com.bumptech.glide.RequestManager import com.bumptech.glide.RequestManager
import kotlinx.android.synthetic.main.fragment_content_listview.* import kotlinx.android.synthetic.main.fragment_content_listview.*
import org.mariotaku.ktextension.isNullOrEmpty import org.mariotaku.ktextension.isNullOrEmpty
@ -52,7 +53,7 @@ class ExtensionsListFragment : AbsContentListViewFragment<ExtensionsAdapter>(),
listView.onItemClickListener = this listView.onItemClickListener = this
loaderManager.initLoader(0, null, this) LoaderManager.getInstance(this).initLoader(0, null, this)
showProgress() showProgress()
} }

View File

@ -5,6 +5,7 @@ import android.nfc.NdefMessage
import android.nfc.NdefRecord import android.nfc.NdefRecord
import android.nfc.NfcAdapter import android.nfc.NfcAdapter
import android.os.Bundle import android.os.Bundle
import androidx.loader.app.LoaderManager
import androidx.loader.app.LoaderManager.LoaderCallbacks import androidx.loader.app.LoaderManager.LoaderCallbacks
import androidx.loader.content.FixedAsyncTaskLoader import androidx.loader.content.FixedAsyncTaskLoader
import androidx.loader.content.Loader import androidx.loader.content.Loader
@ -69,7 +70,7 @@ class GroupFragment : AbsToolbarTabPagesFragment(), LoaderCallbacks<SingleRespon
fun displayGroup(group: ParcelableGroup?) { fun displayGroup(group: ParcelableGroup?) {
val activity = activity ?: return val activity = activity ?: return
loaderManager.destroyLoader(0) LoaderManager.getInstance(this).destroyLoader(0)
this.group = group this.group = group
if (group != null) { if (group != null) {
@ -82,7 +83,7 @@ class GroupFragment : AbsToolbarTabPagesFragment(), LoaderCallbacks<SingleRespon
fun getGroupInfo(omitIntentExtra: Boolean) { fun getGroupInfo(omitIntentExtra: Boolean) {
val lm = loaderManager val lm = LoaderManager.getInstance(this)
lm.destroyLoader(0) lm.destroyLoader(0)
val args = Bundle(arguments) val args = Bundle(arguments)
args.putBoolean(EXTRA_OMIT_INTENT_EXTRA, omitIntentExtra) args.putBoolean(EXTRA_OMIT_INTENT_EXTRA, omitIntentExtra)

View File

@ -116,14 +116,14 @@ class HostMappingsListFragment : AbsContentListViewFragment<HostMappingsListFrag
args.putBoolean(EXTRA_EDIT_MODE, true) args.putBoolean(EXTRA_EDIT_MODE, true)
val df = AddMappingDialogFragment() val df = AddMappingDialogFragment()
df.arguments = args df.arguments = args
fragmentManager?.let { df.show(it, "add_mapping") } parentFragmentManager.let { df.show(it, "add_mapping") }
} }
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) { when (item.itemId) {
R.id.add -> { R.id.add -> {
val df = AddMappingDialogFragment() val df = AddMappingDialogFragment()
fragmentManager?.let { df.show(it, "add_mapping") } parentFragmentManager.let { df.show(it, "add_mapping") }
} }
} }
return super.onOptionsItemSelected(item) return super.onOptionsItemSelected(item)

View File

@ -11,6 +11,7 @@ import android.view.ContextMenu
import android.view.MenuInflater import android.view.MenuInflater
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import androidx.loader.app.LoaderManager
import com.bumptech.glide.RequestManager import com.bumptech.glide.RequestManager
import kotlinx.android.synthetic.main.fragment_content_recyclerview.* import kotlinx.android.synthetic.main.fragment_content_recyclerview.*
import org.mariotaku.kpreferences.get import org.mariotaku.kpreferences.get
@ -46,7 +47,7 @@ open class ItemsListFragment : AbsContentListRecyclerViewFragment<VariousItemsAd
override fun onActivityCreated(savedInstanceState: Bundle?) { override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState) super.onActivityCreated(savedInstanceState)
registerForContextMenu(recyclerView) registerForContextMenu(recyclerView)
loaderManager.initLoader(0, null, this) LoaderManager.getInstance(this).initLoader(0, null, this)
refreshEnabled = false refreshEnabled = false
showProgress() showProgress()
} }
@ -175,7 +176,7 @@ open class ItemsListFragment : AbsContentListRecyclerViewFragment<VariousItemsAd
startActivity(chooser) startActivity(chooser)
return true return true
} }
return MenuUtils.handleStatusClick(requireActivity(), this, requireFragmentManager(), return MenuUtils.handleStatusClick(requireActivity(), this, parentFragmentManager,
preferences, userColorNameManager, twitterWrapper, status, item) preferences, userColorNameManager, twitterWrapper, status, item)
} }
} }

View File

@ -24,6 +24,7 @@ import android.os.Bundle
import androidx.loader.app.LoaderManager.LoaderCallbacks import androidx.loader.app.LoaderManager.LoaderCallbacks
import androidx.loader.content.Loader import androidx.loader.content.Loader
import android.view.KeyEvent import android.view.KeyEvent
import androidx.loader.app.LoaderManager
import androidx.loader.app.hasRunningLoadersSafe import androidx.loader.app.hasRunningLoadersSafe
import com.bumptech.glide.RequestManager import com.bumptech.glide.RequestManager
import kotlinx.android.synthetic.main.fragment_content_recyclerview.* import kotlinx.android.synthetic.main.fragment_content_recyclerview.*
@ -57,7 +58,7 @@ abstract class ParcelableGroupsFragment : AbsContentListRecyclerViewFragment<Par
override var refreshing: Boolean override var refreshing: Boolean
get() { get() {
if (context == null || isDetached) return false if (context == null || isDetached) return false
return loaderManager.hasRunningLoadersSafe() return LoaderManager.getInstance(this).hasRunningLoadersSafe()
} }
set(value) { set(value) {
super.refreshing = value super.refreshing = value
@ -101,7 +102,7 @@ abstract class ParcelableGroupsFragment : AbsContentListRecyclerViewFragment<Par
val loaderArgs = Bundle(arguments) val loaderArgs = Bundle(arguments)
loaderArgs.putBoolean(EXTRA_FROM_USER, true) loaderArgs.putBoolean(EXTRA_FROM_USER, true)
loaderArgs.putParcelable(EXTRA_PAGINATION, nextPagination) loaderArgs.putParcelable(EXTRA_PAGINATION, nextPagination)
loaderManager.restartLoader(0, loaderArgs, this) LoaderManager.getInstance(this).restartLoader(0, loaderArgs, this)
} }
override fun handleKeyboardShortcutSingle(handler: KeyboardShortcutsHandler, keyCode: Int, event: KeyEvent, metaState: Int): Boolean { override fun handleKeyboardShortcutSingle(handler: KeyboardShortcutsHandler, keyCode: Int, event: KeyEvent, metaState: Int): Boolean {
@ -125,7 +126,7 @@ abstract class ParcelableGroupsFragment : AbsContentListRecyclerViewFragment<Par
this) this)
val loaderArgs = Bundle(arguments) val loaderArgs = Bundle(arguments)
loaderArgs.putBoolean(EXTRA_FROM_USER, true) loaderArgs.putBoolean(EXTRA_FROM_USER, true)
loaderManager.initLoader(0, loaderArgs, this) LoaderManager.getInstance(this).initLoader(0, loaderArgs, this)
} }
override fun onCreateLoader(id: Int, args: Bundle?): Loader<List<ParcelableGroup>?> { override fun onCreateLoader(id: Int, args: Bundle?): Loader<List<ParcelableGroup>?> {

View File

@ -24,6 +24,7 @@ import android.os.Bundle
import androidx.loader.app.hasRunningLoadersSafe import androidx.loader.app.hasRunningLoadersSafe
import androidx.loader.content.Loader import androidx.loader.content.Loader
import android.text.TextUtils import android.text.TextUtils
import androidx.loader.app.LoaderManager
import com.bumptech.glide.RequestManager import com.bumptech.glide.RequestManager
import com.squareup.otto.Subscribe import com.squareup.otto.Subscribe
import org.mariotaku.twidere.R import org.mariotaku.twidere.R
@ -57,7 +58,7 @@ abstract class ParcelableStatusesFragment : AbsStatusesFragment() {
override var refreshing: Boolean override var refreshing: Boolean
get() { get() {
if (context == null || isDetached) return false if (context == null || isDetached) return false
return loaderManager.hasRunningLoadersSafe() return LoaderManager.getInstance(this).hasRunningLoadersSafe()
} }
set(value) { set(value) {
super.refreshing = value super.refreshing = value
@ -113,7 +114,7 @@ abstract class ParcelableStatusesFragment : AbsStatusesFragment() {
args.putBoolean(EXTRA_LOADING_MORE, param.isLoadingMore) args.putBoolean(EXTRA_LOADING_MORE, param.isLoadingMore)
args.putBoolean(EXTRA_FROM_USER, true) args.putBoolean(EXTRA_FROM_USER, true)
args.putParcelable(EXTRA_PAGINATION, param.pagination?.getOrNull(0)) args.putParcelable(EXTRA_PAGINATION, param.pagination?.getOrNull(0))
loaderManager.restartLoader(loaderId, args, this) LoaderManager.getInstance(this).restartLoader(loaderId, args, this)
return true return true
} }

View File

@ -21,6 +21,7 @@ package org.mariotaku.twidere.fragment
import android.content.Context import android.content.Context
import android.os.Bundle import android.os.Bundle
import androidx.loader.app.LoaderManager
import androidx.loader.app.LoaderManager.LoaderCallbacks import androidx.loader.app.LoaderManager.LoaderCallbacks
import androidx.loader.app.hasRunningLoadersSafe import androidx.loader.app.hasRunningLoadersSafe
import androidx.loader.content.Loader import androidx.loader.content.Loader
@ -62,7 +63,7 @@ abstract class ParcelableUserListsFragment : AbsContentListRecyclerViewFragment<
override var refreshing: Boolean override var refreshing: Boolean
get() { get() {
if (context == null || isDetached) return false if (context == null || isDetached) return false
return loaderManager.hasRunningLoadersSafe() return LoaderManager.getInstance(this).hasRunningLoadersSafe()
} }
set(value) { set(value) {
super.refreshing = value super.refreshing = value
@ -103,7 +104,7 @@ abstract class ParcelableUserListsFragment : AbsContentListRecyclerViewFragment<
val loaderArgs = Bundle(arguments) val loaderArgs = Bundle(arguments)
loaderArgs.putBoolean(EXTRA_FROM_USER, true) loaderArgs.putBoolean(EXTRA_FROM_USER, true)
loaderArgs.putParcelable(EXTRA_PAGINATION, nextPagination) loaderArgs.putParcelable(EXTRA_PAGINATION, nextPagination)
loaderManager.restartLoader(0, loaderArgs, this) LoaderManager.getInstance(this).restartLoader(0, loaderArgs, this)
} }
override fun handleKeyboardShortcutSingle(handler: KeyboardShortcutsHandler, keyCode: Int, override fun handleKeyboardShortcutSingle(handler: KeyboardShortcutsHandler, keyCode: Int,
@ -130,7 +131,7 @@ abstract class ParcelableUserListsFragment : AbsContentListRecyclerViewFragment<
this) this)
val loaderArgs = Bundle(arguments) val loaderArgs = Bundle(arguments)
loaderArgs.putBoolean(EXTRA_FROM_USER, true) loaderArgs.putBoolean(EXTRA_FROM_USER, true)
loaderManager.initLoader(0, loaderArgs, this) LoaderManager.getInstance(this).initLoader(0, loaderArgs, this)
} }
override fun onCreateLoader(id: Int, args: Bundle?): Loader<List<ParcelableUserList>> { override fun onCreateLoader(id: Int, args: Bundle?): Loader<List<ParcelableUserList>> {
@ -159,7 +160,7 @@ abstract class ParcelableUserListsFragment : AbsContentListRecyclerViewFragment<
val loaderArgs = Bundle(arguments).apply { val loaderArgs = Bundle(arguments).apply {
this[EXTRA_FROM_USER] = true this[EXTRA_FROM_USER] = true
} }
loaderManager.restartLoader(0, loaderArgs, this) LoaderManager.getInstance(this).restartLoader(0, loaderArgs, this)
showProgress() showProgress()
return true return true
} }

View File

@ -28,6 +28,7 @@ import androidx.loader.content.Loader
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import android.view.KeyEvent import android.view.KeyEvent
import androidx.loader.app.LoaderManager
import com.bumptech.glide.RequestManager import com.bumptech.glide.RequestManager
import com.squareup.otto.Subscribe import com.squareup.otto.Subscribe
import kotlinx.android.synthetic.main.fragment_content_recyclerview.* import kotlinx.android.synthetic.main.fragment_content_recyclerview.*
@ -65,7 +66,7 @@ abstract class ParcelableUsersFragment : AbsContentListRecyclerViewFragment<Parc
override var refreshing: Boolean override var refreshing: Boolean
get() { get() {
if (context == null || isDetached) return false if (context == null || isDetached) return false
return loaderManager.hasRunningLoadersSafe() return LoaderManager.getInstance(this).hasRunningLoadersSafe()
} }
set(value) { set(value) {
super.refreshing = value super.refreshing = value
@ -102,7 +103,7 @@ abstract class ParcelableUsersFragment : AbsContentListRecyclerViewFragment<Parc
this) this)
val loaderArgs = Bundle(arguments) val loaderArgs = Bundle(arguments)
loaderArgs.putBoolean(EXTRA_FROM_USER, true) loaderArgs.putBoolean(EXTRA_FROM_USER, true)
loaderManager.initLoader(0, loaderArgs, this) LoaderManager.getInstance(this).initLoader(0, loaderArgs, this)
} }
override fun onStart() { override fun onStart() {
@ -164,7 +165,7 @@ abstract class ParcelableUsersFragment : AbsContentListRecyclerViewFragment<Parc
val loaderArgs = Bundle(arguments) val loaderArgs = Bundle(arguments)
loaderArgs.putBoolean(EXTRA_FROM_USER, true) loaderArgs.putBoolean(EXTRA_FROM_USER, true)
loaderArgs.putParcelable(EXTRA_PAGINATION, nextPagination) loaderArgs.putParcelable(EXTRA_PAGINATION, nextPagination)
loaderManager.restartLoader(0, loaderArgs, this) LoaderManager.getInstance(this).restartLoader(0, loaderArgs, this)
} }
override fun onCreateAdapter(context: Context, requestManager: RequestManager): ParcelableUsersAdapter { override fun onCreateAdapter(context: Context, requestManager: RequestManager): ParcelableUsersAdapter {
@ -212,7 +213,7 @@ abstract class ParcelableUsersFragment : AbsContentListRecyclerViewFragment<Parc
val accountKey = user.account_key ?: return val accountKey = user.account_key ?: return
if (twitterWrapper.isUpdatingRelationship(accountKey, user.key)) return if (twitterWrapper.isUpdatingRelationship(accountKey, user.key)) return
if (user.is_following) { if (user.is_following) {
fragmentManager?.let { DestroyFriendshipDialogFragment.show(it, user) } parentFragmentManager.let { DestroyFriendshipDialogFragment.show(it, user) }
} else { } else {
twitterWrapper.createFriendshipAsync(accountKey, user.key, user.screen_name) twitterWrapper.createFriendshipAsync(accountKey, user.key, user.screen_name)
} }

View File

@ -21,6 +21,7 @@ package org.mariotaku.twidere.fragment
import android.content.Context import android.content.Context
import android.os.Bundle import android.os.Bundle
import androidx.loader.app.LoaderManager
import androidx.loader.app.LoaderManager.LoaderCallbacks import androidx.loader.app.LoaderManager.LoaderCallbacks
import androidx.loader.app.hasRunningLoadersSafe import androidx.loader.app.hasRunningLoadersSafe
import androidx.loader.content.Loader import androidx.loader.content.Loader
@ -44,7 +45,7 @@ class SavedSearchesListFragment : AbsContentListViewFragment<SavedSearchesAdapte
AdapterView.OnItemLongClickListener { AdapterView.OnItemLongClickListener {
override var refreshing: Boolean override var refreshing: Boolean
get() = loaderManager.hasRunningLoadersSafe() get() = LoaderManager.getInstance(this).hasRunningLoadersSafe()
set(value) { set(value) {
super.refreshing = value super.refreshing = value
} }
@ -56,7 +57,7 @@ class SavedSearchesListFragment : AbsContentListViewFragment<SavedSearchesAdapte
super.onActivityCreated(savedInstanceState) super.onActivityCreated(savedInstanceState)
listView.onItemClickListener = this listView.onItemClickListener = this
listView.onItemLongClickListener = this listView.onItemLongClickListener = this
loaderManager.initLoader(0, null, this) LoaderManager.getInstance(this).initLoader(0, null, this)
showProgress() showProgress()
} }
@ -80,7 +81,7 @@ class SavedSearchesListFragment : AbsContentListViewFragment<SavedSearchesAdapte
override fun onItemLongClick(view: AdapterView<*>, child: View, position: Int, id: Long): Boolean { override fun onItemLongClick(view: AdapterView<*>, child: View, position: Int, id: Long): Boolean {
val item = adapter.findItem(id) ?: return false val item = adapter.findItem(id) ?: return false
fragmentManager?.let { DestroySavedSearchDialogFragment.show(it, accountKey, item.id, item.name) } parentFragmentManager.let { DestroySavedSearchDialogFragment.show(it, accountKey, item.id, item.name) }
return true return true
} }
@ -104,7 +105,7 @@ class SavedSearchesListFragment : AbsContentListViewFragment<SavedSearchesAdapte
override fun onRefresh() { override fun onRefresh() {
if (refreshing) return if (refreshing) return
loaderManager.restartLoader(0, null, this) LoaderManager.getInstance(this).restartLoader(0, null, this)
} }
@Subscribe @Subscribe

View File

@ -29,6 +29,7 @@ import androidx.loader.content.Loader
import android.view.View import android.view.View
import android.widget.AdapterView import android.widget.AdapterView
import android.widget.ListView import android.widget.ListView
import androidx.loader.app.LoaderManager
import com.bumptech.glide.RequestManager import com.bumptech.glide.RequestManager
import com.squareup.otto.Subscribe import com.squareup.otto.Subscribe
import kotlinx.android.synthetic.main.fragment_content_listview.* import kotlinx.android.synthetic.main.fragment_content_listview.*
@ -68,7 +69,7 @@ class TrendsSuggestionsFragment : AbsContentListViewFragment<TrendsAdapter>(), L
override fun onActivityCreated(savedInstanceState: Bundle?) { override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState) super.onActivityCreated(savedInstanceState)
listView.onItemClickListener = this listView.onItemClickListener = this
loaderManager.initLoader(0, null, this) LoaderManager.getInstance(this).initLoader(0, null, this)
showProgress() showProgress()
} }
@ -123,7 +124,7 @@ class TrendsSuggestionsFragment : AbsContentListViewFragment<TrendsAdapter>(), L
override fun onStart() { override fun onStart() {
super.onStart() super.onStart()
loaderManager.restartLoader(0, null, this) LoaderManager.getInstance(this).restartLoader(0, null, this)
bus.register(this) bus.register(this)
} }

View File

@ -73,6 +73,7 @@ import android.view.View.OnTouchListener
import android.view.animation.AnimationUtils import android.view.animation.AnimationUtils
import android.widget.TextView import android.widget.TextView
import android.widget.Toast import android.widget.Toast
import androidx.loader.app.LoaderManager
import com.squareup.otto.Subscribe import com.squareup.otto.Subscribe
import kotlinx.android.synthetic.main.fragment_user.* import kotlinx.android.synthetic.main.fragment_user.*
import kotlinx.android.synthetic.main.fragment_user.view.* import kotlinx.android.synthetic.main.fragment_user.view.*
@ -432,7 +433,7 @@ class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener,
} }
profileImage.visibility = View.VISIBLE profileImage.visibility = View.VISIBLE
val resources = resources val resources = resources
val lm = loaderManager val lm = LoaderManager.getInstance(this)
lm.destroyLoader(LOADER_ID_USER) lm.destroyLoader(LOADER_ID_USER)
lm.destroyLoader(LOADER_ID_FRIENDSHIP) lm.destroyLoader(LOADER_ID_FRIENDSHIP)
cardContent.visibility = View.VISIBLE cardContent.visibility = View.VISIBLE
@ -530,7 +531,7 @@ class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener,
externalThemeManager.emoji?.applyTo(it) externalThemeManager.emoji?.applyTo(it)
} }
val userCreationDay = condition@ if (user.created_at >= 0) { val userCreationDay = if (user.created_at >= 0) {
val cal = Calendar.getInstance() val cal = Calendar.getInstance()
val currentMonth = cal.get(Calendar.MONTH) val currentMonth = cal.get(Calendar.MONTH)
val currentDay = cal.get(Calendar.DAY_OF_MONTH) val currentDay = cal.get(Calendar.DAY_OF_MONTH)
@ -577,7 +578,7 @@ class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener,
fun getUserInfo(accountKey: UserKey, userKey: UserKey?, screenName: String?, fun getUserInfo(accountKey: UserKey, userKey: UserKey?, screenName: String?,
omitIntentExtra: Boolean) { omitIntentExtra: Boolean) {
val lm = loaderManager val lm = LoaderManager.getInstance(this)
lm.destroyLoader(LOADER_ID_USER) lm.destroyLoader(LOADER_ID_USER)
lm.destroyLoader(LOADER_ID_FRIENDSHIP) lm.destroyLoader(LOADER_ID_FRIENDSHIP)
val args = Bundle() val args = Bundle()
@ -787,7 +788,7 @@ class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener,
override fun onDestroyView() { override fun onDestroyView() {
user = null user = null
relationship = null relationship = null
val lm = loaderManager val lm = LoaderManager.getInstance(this)
lm.destroyLoader(LOADER_ID_USER) lm.destroyLoader(LOADER_ID_USER)
lm.destroyLoader(LOADER_ID_FRIENDSHIP) lm.destroyLoader(LOADER_ID_FRIENDSHIP)
super.onDestroyView() super.onDestroyView()
@ -903,7 +904,7 @@ class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener,
val twitter = twitterWrapper val twitter = twitterWrapper
val user = user ?: return false val user = user ?: return false
val accountKey = user.account_key ?: return false val accountKey = user.account_key ?: return false
val currentFragmentManager = fragmentManager ?: return false val currentFragmentManager = parentFragmentManager
val userRelationship = relationship val userRelationship = relationship
when (item.itemId) { when (item.itemId) {
R.id.block -> { R.id.block -> {
@ -1221,7 +1222,7 @@ class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener,
override fun onClick(view: View) { override fun onClick(view: View) {
val activity = activity ?: return val activity = activity ?: return
val fragmentManager = fragmentManager ?: return val fragmentManager = parentFragmentManager
val user = user ?: return val user = user ?: return
val accountKey = user.account_key ?: return val accountKey = user.account_key ?: return
when (view.id) { when (view.id) {
@ -1394,7 +1395,7 @@ class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener,
private fun getFriendship() { private fun getFriendship() {
val user = user ?: return val user = user ?: return
relationship = null relationship = null
val lm = loaderManager val lm = LoaderManager.getInstance(this)
lm.destroyLoader(LOADER_ID_FRIENDSHIP) lm.destroyLoader(LOADER_ID_FRIENDSHIP)
val args = Bundle() val args = Bundle()
args.putParcelable(EXTRA_ACCOUNT_KEY, user.account_key) args.putParcelable(EXTRA_ACCOUNT_KEY, user.account_key)
@ -1890,7 +1891,7 @@ class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener,
df.arguments = Bundle { df.arguments = Bundle {
this[EXTRA_ACCOUNT_KEY] = accountKey this[EXTRA_ACCOUNT_KEY] = accountKey
} }
df.show(requireFragmentManager(), "create_user_list") df.show(parentFragmentManager, "create_user_list")
} }
} }
return dialog return dialog

View File

@ -28,6 +28,7 @@ import android.nfc.NdefMessage
import android.nfc.NdefRecord import android.nfc.NdefRecord
import android.nfc.NfcAdapter.CreateNdefMessageCallback import android.nfc.NfcAdapter.CreateNdefMessageCallback
import android.os.Bundle import android.os.Bundle
import androidx.loader.app.LoaderManager
import androidx.loader.app.LoaderManager.LoaderCallbacks import androidx.loader.app.LoaderManager.LoaderCallbacks
import androidx.loader.content.FixedAsyncTaskLoader import androidx.loader.content.FixedAsyncTaskLoader
import androidx.loader.content.Loader import androidx.loader.content.Loader
@ -81,7 +82,7 @@ class UserListFragment : AbsToolbarTabPagesFragment(), OnClickListener,
fun displayUserList(userList: ParcelableUserList?) { fun displayUserList(userList: ParcelableUserList?) {
val activity = activity ?: return val activity = activity ?: return
loaderManager.destroyLoader(0) LoaderManager.getInstance(this).destroyLoader(0)
this.userList = userList this.userList = userList
if (userList != null) { if (userList != null) {
@ -93,7 +94,7 @@ class UserListFragment : AbsToolbarTabPagesFragment(), OnClickListener,
} }
fun getUserListInfo(omitIntentExtra: Boolean) { fun getUserListInfo(omitIntentExtra: Boolean) {
val lm = loaderManager val lm = LoaderManager.getInstance(this)
lm.destroyLoader(0) lm.destroyLoader(0)
val args = Bundle(arguments) val args = Bundle(arguments)
args.putBoolean(EXTRA_OMIT_INTENT_EXTRA, omitIntentExtra) args.putBoolean(EXTRA_OMIT_INTENT_EXTRA, omitIntentExtra)
@ -112,7 +113,7 @@ class UserListFragment : AbsToolbarTabPagesFragment(), OnClickListener,
val userList = this.userList val userList = this.userList
if (resultCode != Activity.RESULT_OK || !data!!.hasExtra(EXTRA_USER) || userList == null) if (resultCode != Activity.RESULT_OK || !data!!.hasExtra(EXTRA_USER) || userList == null)
return return
val user = data.getParcelableExtra<ParcelableUser>(EXTRA_USER) val user = data.getParcelableExtra<ParcelableUser>(EXTRA_USER) ?: return
twitter.addUserListMembersAsync(userList.account_key, userList.id, user) twitter.addUserListMembersAsync(userList.account_key, userList.id, user)
return return
} }
@ -180,7 +181,7 @@ class UserListFragment : AbsToolbarTabPagesFragment(), OnClickListener,
override fun onDestroyView() { override fun onDestroyView() {
userList = null userList = null
loaderManager.destroyLoader(0) LoaderManager.getInstance(this).destroyLoader(0)
super.onDestroyView() super.onDestroyView()
} }
@ -227,7 +228,7 @@ class UserListFragment : AbsToolbarTabPagesFragment(), OnClickListener,
val twitter = twitterWrapper val twitter = twitterWrapper
val userList = userList ?: return false val userList = userList ?: return false
val activity = activity ?: return false val activity = activity ?: return false
val fragmentManager = fragmentManager ?: return false val fragmentManager = parentFragmentManager
when (item.itemId) { when (item.itemId) {
R.id.add -> { R.id.add -> {
if (userList.user_key != userList.account_key) return false if (userList.user_key != userList.account_key) return false

View File

@ -68,7 +68,7 @@ class UserListsOwnershipsFragment : ParcelableUserListsFragment() {
val args = Bundle() val args = Bundle()
args.putParcelable(EXTRA_ACCOUNT_KEY, accountKey) args.putParcelable(EXTRA_ACCOUNT_KEY, accountKey)
f.arguments = args f.arguments = args
fragmentManager?.let { f.show(it, null) } parentFragmentManager.let { f.show(it, null) }
return true return true
} }
} }

View File

@ -33,7 +33,8 @@ import android.text.TextUtils.isEmpty
import android.view.* import android.view.*
import android.view.View.OnClickListener import android.view.View.OnClickListener
import android.widget.Toast import android.widget.Toast
import com.twitter.Validator import androidx.loader.app.LoaderManager
import com.twitter.twittertext.Validator
import kotlinx.android.synthetic.main.fragment_user_profile_editor.* import kotlinx.android.synthetic.main.fragment_user_profile_editor.*
import nl.komponents.kovenant.combine.and import nl.komponents.kovenant.combine.and
import nl.komponents.kovenant.ui.promiseOnUi import nl.komponents.kovenant.ui.promiseOnUi
@ -337,7 +338,7 @@ class UserProfileEditorFragment : BaseFragment(), OnSizeChangedListener,
private fun getUserInfo() { private fun getUserInfo() {
if (activity == null || isDetached) return if (activity == null || isDetached) return
val lm = loaderManager val lm = LoaderManager.getInstance(this)
lm.destroyLoader(LOADER_ID_USER) lm.destroyLoader(LOADER_ID_USER)
getUserInfoCalled = true getUserInfoCalled = true
if (userInfoLoaderInitialized) { if (userInfoLoaderInitialized) {

View File

@ -125,13 +125,13 @@ class UserQrDialogFragment : BaseDialogFragment() {
return task { return task {
try { try {
return@task requestManager.loadOriginalProfileImage(requireContext(), user, 0) return@task requestManager.loadOriginalProfileImage(requireContext(), user, 0)
.into(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL).get() .submit(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL).get()
} catch (e: ExecutionException) { } catch (e: ExecutionException) {
// Ignore // Ignore
} }
// Return fallback profile image // Return fallback profile image
return@task requestManager.loadProfileImage(requireContext(), user, 0, size = profileImageSize) return@task requestManager.loadProfileImage(requireContext(), user, 0, size = profileImageSize)
.into(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL).get() .submit(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL).get()
} }
} }

View File

@ -41,6 +41,7 @@ import android.widget.AbsListView.MultiChoiceModeListener
import android.widget.AdapterView import android.widget.AdapterView
import android.widget.AdapterView.OnItemClickListener import android.widget.AdapterView.OnItemClickListener
import android.widget.ListView import android.widget.ListView
import androidx.loader.app.LoaderManager
import com.bumptech.glide.RequestManager import com.bumptech.glide.RequestManager
import kotlinx.android.synthetic.main.fragment_content_listview.* import kotlinx.android.synthetic.main.fragment_content_listview.*
import org.mariotaku.kpreferences.get import org.mariotaku.kpreferences.get
@ -84,7 +85,7 @@ class DraftsListFragment : AbsContentListViewFragment<DraftsAdapter>(), LoaderCa
listView.choiceMode = ListView.CHOICE_MODE_MULTIPLE_MODAL listView.choiceMode = ListView.CHOICE_MODE_MULTIPLE_MODAL
listView.setMultiChoiceModeListener(this) listView.setMultiChoiceModeListener(this)
refreshEnabled = false refreshEnabled = false
loaderManager.initLoader(0, null, this) LoaderManager.getInstance(this).initLoader(0, null, this)
showProgress() showProgress()
} }

View File

@ -151,7 +151,7 @@ class AddEditItemFragment : BaseDialogFragment() {
val df = ExtraFeaturesIntroductionDialogFragment.create( val df = ExtraFeaturesIntroductionDialogFragment.create(
ExtraFeaturesService.FEATURE_ADVANCED_FILTERS) ExtraFeaturesService.FEATURE_ADVANCED_FILTERS)
df.setTargetFragment(this@AddEditItemFragment, REQUEST_CHANGE_SCOPE_PURCHASE) df.setTargetFragment(this@AddEditItemFragment, REQUEST_CHANGE_SCOPE_PURCHASE)
df.show(requireFragmentManager(), ExtraFeaturesIntroductionDialogFragment.FRAGMENT_TAG) df.show(parentFragmentManager, ExtraFeaturesIntroductionDialogFragment.FRAGMENT_TAG)
} }
} }

View File

@ -88,7 +88,7 @@ abstract class BaseFiltersFragment : AbsContentListViewFragment<SimpleCursorAdap
onItemClick(pos) onItemClick(pos)
} }
listView.setMultiChoiceModeListener(this) listView.setMultiChoiceModeListener(this)
loaderManager.initLoader(0, null, this) LoaderManager.getInstance(this).initLoader(0, null, this)
refreshEnabled = false refreshEnabled = false
showProgress() showProgress()
} }
@ -235,7 +235,7 @@ abstract class BaseFiltersFragment : AbsContentListViewFragment<SimpleCursorAdap
this[EXTRA_VALUE] = value this[EXTRA_VALUE] = value
this[EXTRA_SCOPE] = scope this[EXTRA_SCOPE] = scope
} }
fragmentManager?.let { dialog.show(it, "add_rule") } parentFragmentManager.let { dialog.show(it, "add_rule") }
} }

View File

@ -58,7 +58,7 @@ abstract class BaseFiltersImportFragment : AbsContentListRecyclerViewFragment<Se
setHasOptionsMenu(true) setHasOptionsMenu(true)
val loaderArgs = Bundle(arguments) val loaderArgs = Bundle(arguments)
loaderArgs.putBoolean(EXTRA_FROM_USER, true) loaderArgs.putBoolean(EXTRA_FROM_USER, true)
loaderManager.initLoader(0, loaderArgs, this) LoaderManager.getInstance(this).initLoader(0, loaderArgs, this)
} }
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
@ -107,7 +107,7 @@ abstract class BaseFiltersImportFragment : AbsContentListRecyclerViewFragment<Se
return true return true
} }
if (!extraFeaturesService.isAdvancedFiltersEnabled) { if (!extraFeaturesService.isAdvancedFiltersEnabled) {
fragmentManager?.let { parentFragmentManager.let {
ExtraFeaturesIntroductionDialogFragment.show(it, ExtraFeaturesIntroductionDialogFragment.show(it,
feature = ExtraFeaturesService.FEATURE_ADVANCED_FILTERS, feature = ExtraFeaturesService.FEATURE_ADVANCED_FILTERS,
requestCode = REQUEST_PURCHASE_EXTRA_FEATURES) requestCode = REQUEST_PURCHASE_EXTRA_FEATURES)
@ -182,14 +182,14 @@ abstract class BaseFiltersImportFragment : AbsContentListRecyclerViewFragment<Se
val loaderArgs = Bundle(arguments) val loaderArgs = Bundle(arguments)
loaderArgs.putBoolean(EXTRA_FROM_USER, true) loaderArgs.putBoolean(EXTRA_FROM_USER, true)
loaderArgs.putParcelable(EXTRA_NEXT_PAGINATION, nextPagination) loaderArgs.putParcelable(EXTRA_NEXT_PAGINATION, nextPagination)
loaderManager.restartLoader(0, loaderArgs, this) LoaderManager.getInstance(this).restartLoader(0, loaderArgs, this)
} }
override fun onCreateAdapter(context: Context, requestManager: RequestManager): SelectableUsersAdapter { override fun onCreateAdapter(context: Context, requestManager: RequestManager): SelectableUsersAdapter {
val adapter = SelectableUsersAdapter(context, this.requestManager) val adapter = SelectableUsersAdapter(context, this.requestManager)
adapter.itemCheckedListener = listener@ { _, _ -> adapter.itemCheckedListener = listener@ { _, _ ->
if (!extraFeaturesService.isAdvancedFiltersEnabled) { if (!extraFeaturesService.isAdvancedFiltersEnabled) {
ExtraFeaturesIntroductionDialogFragment.show(requireFragmentManager(), ExtraFeaturesIntroductionDialogFragment.show(parentFragmentManager,
feature = ExtraFeaturesService.FEATURE_ADVANCED_FILTERS, feature = ExtraFeaturesService.FEATURE_ADVANCED_FILTERS,
requestCode = REQUEST_PURCHASE_EXTRA_FEATURES) requestCode = REQUEST_PURCHASE_EXTRA_FEATURES)
return@listener false return@listener false

View File

@ -64,7 +64,7 @@ class FilteredUsersFragment : BaseFiltersFragment() {
when (requestCode) { when (requestCode) {
REQUEST_SELECT_USER -> { REQUEST_SELECT_USER -> {
if (resultCode != FragmentActivity.RESULT_OK || data == null) return if (resultCode != FragmentActivity.RESULT_OK || data == null) return
val user = data.getParcelableExtra<ParcelableUser>(EXTRA_USER) val user = data.getParcelableExtra<ParcelableUser>(EXTRA_USER) ?: return
executeAfterFragmentResumed { fragment -> executeAfterFragmentResumed { fragment ->
AddUserFilterDialogFragment.show(fragment.childFragmentManager, user) AddUserFilterDialogFragment.show(fragment.childFragmentManager, user)
} }
@ -92,7 +92,7 @@ class FilteredUsersFragment : BaseFiltersFragment() {
} }
REQUEST_EXPORT_MUTES_SELECT_ACCOUNT -> { REQUEST_EXPORT_MUTES_SELECT_ACCOUNT -> {
if (resultCode != FragmentActivity.RESULT_OK || data == null) return if (resultCode != FragmentActivity.RESULT_OK || data == null) return
val accountKey = data.getParcelableExtra<UserKey>(EXTRA_ACCOUNT_KEY) val accountKey = data.getParcelableExtra<UserKey>(EXTRA_ACCOUNT_KEY) ?: return
val userKeys = data.getBundleExtra(EXTRA_EXTRAS)?.getNullableTypedArray<UserKey>(EXTRA_ITEMS) ?: return val userKeys = data.getBundleExtra(EXTRA_EXTRAS)?.getNullableTypedArray<UserKey>(EXTRA_ITEMS) ?: return
exportToMutedUsers(accountKey, userKeys) exportToMutedUsers(accountKey, userKeys)
} }
@ -115,7 +115,7 @@ class FilteredUsersFragment : BaseFiltersFragment() {
override fun onPrepareOptionsMenu(menu: Menu) { override fun onPrepareOptionsMenu(menu: Menu) {
super.onPrepareOptionsMenu(menu) super.onPrepareOptionsMenu(menu)
val isFeaturesSupported = extraFeaturesService.isSupported() val isFeaturesSupported = extraFeaturesService.isSupported()
menu.setGroupAvailability(R.id.import_export, isFeaturesSupported) menu.setGroupAvailability(R.id.import_export, true)
} }
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
@ -147,7 +147,7 @@ class FilteredUsersFragment : BaseFiltersFragment() {
override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean { override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean {
val result = super.onPrepareActionMode(mode, menu) val result = super.onPrepareActionMode(mode, menu)
val isFeaturesSupported = extraFeaturesService.isSupported() val isFeaturesSupported = extraFeaturesService.isSupported()
menu.setGroupAvailability(R.id.import_export, isFeaturesSupported) menu.setGroupAvailability(R.id.import_export, true)
return result && menu.hasVisibleItems() return result && menu.hasVisibleItems()
} }

View File

@ -67,16 +67,16 @@ class FiltersSubscriptionsFragment : BaseFragment(), LoaderManager.LoaderCallbac
listContainer.visibility = View.GONE listContainer.visibility = View.GONE
progressContainer.visibility = View.VISIBLE progressContainer.visibility = View.VISIBLE
loaderManager.initLoader(0, null, this) LoaderManager.getInstance(this).initLoader(0, null, this)
if (!extraFeaturesService.isSupported()) { if (!extraFeaturesService.isSupported()) {
activity?.finish() // activity?.finish()
return // return
} }
if (savedInstanceState == null) { if (savedInstanceState == null) {
fragmentManager?.let { fragmentManager -> parentFragmentManager.let { fragmentManager ->
when (arguments?.getString(EXTRA_ACTION)) { when (arguments?.getString(EXTRA_ACTION)) {
ACTION_ADD_URL_SUBSCRIPTION -> { ACTION_ADD_URL_SUBSCRIPTION -> {
if (!extraFeaturesService.isAdvancedFiltersEnabled) { if (!extraFeaturesService.isAdvancedFiltersEnabled) {
@ -131,17 +131,17 @@ class FiltersSubscriptionsFragment : BaseFragment(), LoaderManager.LoaderCallbac
when (item.itemId) { when (item.itemId) {
R.id.add -> { R.id.add -> {
val df = AddUrlSubscriptionDialogFragment() val df = AddUrlSubscriptionDialogFragment()
fragmentManager?.let { df.show(it, "add_url_subscription") } parentFragmentManager.let { df.show(it, "add_url_subscription") }
return true return true
} }
R.id.refresh -> { R.id.refresh -> {
executeAfterFragmentResumed { fragment -> executeAfterFragmentResumed { fragment ->
ProgressDialogFragment.show(fragment.childFragmentManager, FRAGMENT_TAG_RREFRESH_FILTERS) ProgressDialogFragment.show(fragment.childFragmentManager, FRAGMENT_TAG_REFRESH_FILTERS)
val task = RefreshFiltersSubscriptionsTask(fragment.requireContext()) val task = RefreshFiltersSubscriptionsTask(fragment.requireContext())
val fragmentRef = WeakReference(fragment) val fragmentRef = WeakReference(fragment)
task.callback = { task.callback = {
fragmentRef.get()?.executeAfterFragmentResumed { fragment -> fragmentRef.get()?.executeAfterFragmentResumed { fragment ->
fragment.fragmentManager?.dismissDialogFragment(FRAGMENT_TAG_RREFRESH_FILTERS) fragment.parentFragmentManager.dismissDialogFragment(FRAGMENT_TAG_REFRESH_FILTERS)
} }
} }
TaskStarter.execute(task) TaskStarter.execute(task)
@ -255,7 +255,7 @@ class FiltersSubscriptionsFragment : BaseFragment(), LoaderManager.LoaderCallbac
this[EXTRA_ADD_SUBSCRIPTION_URL] = arguments?.getString(EXTRA_ADD_SUBSCRIPTION_URL) this[EXTRA_ADD_SUBSCRIPTION_URL] = arguments?.getString(EXTRA_ADD_SUBSCRIPTION_URL)
this[EXTRA_ADD_SUBSCRIPTION_NAME] = arguments?.getString(EXTRA_ADD_SUBSCRIPTION_NAME) this[EXTRA_ADD_SUBSCRIPTION_NAME] = arguments?.getString(EXTRA_ADD_SUBSCRIPTION_NAME)
} }
fragmentManager?.let { df.show(it, "add_url_subscription") } parentFragmentManager.let { df.show(it, "add_url_subscription") }
} }
class FilterSubscriptionsAdapter(context: Context) : SimpleCursorAdapter(context, class FilterSubscriptionsAdapter(context: Context) : SimpleCursorAdapter(context,
@ -337,7 +337,7 @@ class FiltersSubscriptionsFragment : BaseFragment(), LoaderManager.LoaderCallbac
const val EXTRA_ADD_SUBSCRIPTION_URL = "add_subscription.url" const val EXTRA_ADD_SUBSCRIPTION_URL = "add_subscription.url"
const val EXTRA_ADD_SUBSCRIPTION_NAME = "add_subscription.name" const val EXTRA_ADD_SUBSCRIPTION_NAME = "add_subscription.name"
private const val REQUEST_ADD_URL_SUBSCRIPTION_PURCHASE = 101 private const val REQUEST_ADD_URL_SUBSCRIPTION_PURCHASE = 101
private const val FRAGMENT_TAG_RREFRESH_FILTERS = "refresh_filters" private const val FRAGMENT_TAG_REFRESH_FILTERS = "refresh_filters"
} }
} }

View File

@ -45,7 +45,10 @@ class ExternalBrowserPageFragment : MediaViewerFragment() {
webSettings.javaScriptEnabled = true webSettings.javaScriptEnabled = true
webSettings.loadsImagesAutomatically = true webSettings.loadsImagesAutomatically = true
val media = arguments?.getParcelable<ParcelableMedia>(EXTRA_MEDIA) ?: throw NullPointerException() val media = arguments?.getParcelable<ParcelableMedia>(EXTRA_MEDIA) ?: throw NullPointerException()
webView.loadUrl(if (TextUtils.isEmpty(media.media_url)) media.url else media.media_url) val target = if (TextUtils.isEmpty(media.media_url)) media.url else media.media_url
target?.let {
webView.loadUrl(it)
}
webViewContainer.setAspectRatioSource(VideoPageFragment.MediaAspectRatioSource(media, this)) webViewContainer.setAspectRatioSource(VideoPageFragment.MediaAspectRatioSource(media, this))
} }

View File

@ -24,6 +24,7 @@ import android.content.Context
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import android.net.Uri import android.net.Uri
import android.os.AsyncTask
import com.davemorrissey.labs.subscaleview.ImageSource import com.davemorrissey.labs.subscaleview.ImageSource
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
import com.davemorrissey.labs.subscaleview.decoder.SkiaImageDecoder import com.davemorrissey.labs.subscaleview.decoder.SkiaImageDecoder
@ -91,7 +92,7 @@ class ImagePageFragment : SubsampleImageViewerFragment() {
override fun setupImageView(imageView: SubsamplingScaleImageView) { override fun setupImageView(imageView: SubsamplingScaleImageView) {
imageView.maxScale = resources.displayMetrics.density imageView.maxScale = resources.displayMetrics.density
imageView.setBitmapDecoderClass(PreviewBitmapDecoder::class.java) imageView.setBitmapDecoderClass(PreviewBitmapDecoder::class.java)
imageView.setParallelLoadingEnabled(true) imageView.setExecutor(AsyncTask.THREAD_POOL_EXECUTOR)
imageView.setOnClickListener { imageView.setOnClickListener {
val activity = activity as? MediaViewerActivity ?: return@setOnClickListener val activity = activity as? MediaViewerActivity ?: return@setOnClickListener
activity.toggleBar() activity.toggleBar()

View File

@ -28,20 +28,20 @@ import android.content.Intent
import android.graphics.Rect import android.graphics.Rect
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.view.*
import android.widget.CompoundButton
import android.widget.EditText
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import androidx.loader.app.LoaderManager import androidx.loader.app.LoaderManager
import androidx.loader.content.FixedAsyncTaskLoader import androidx.loader.content.FixedAsyncTaskLoader
import androidx.loader.content.Loader import androidx.loader.content.Loader
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.FixedLinearLayoutManager import androidx.recyclerview.widget.FixedLinearLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import androidx.appcompat.widget.Toolbar
import android.view.*
import android.widget.CompoundButton
import android.widget.EditText
import com.bumptech.glide.RequestManager import com.bumptech.glide.RequestManager
import kotlinx.android.synthetic.main.activity_home_content.view.* import kotlinx.android.synthetic.main.activity_home_content.view.*
import kotlinx.android.synthetic.main.fragment_messages_conversation_info.* import kotlinx.android.synthetic.main.fragment_messages_conversation_info.*
@ -72,7 +72,6 @@ import org.mariotaku.twidere.adapter.iface.IItemCountsAdapter
import org.mariotaku.twidere.annotation.AccountType import org.mariotaku.twidere.annotation.AccountType
import org.mariotaku.twidere.annotation.ImageShapeStyle import org.mariotaku.twidere.annotation.ImageShapeStyle
import org.mariotaku.twidere.annotation.ProfileImageSize import org.mariotaku.twidere.annotation.ProfileImageSize
import org.mariotaku.twidere.constant.IntentConstants
import org.mariotaku.twidere.constant.IntentConstants.* import org.mariotaku.twidere.constant.IntentConstants.*
import org.mariotaku.twidere.constant.nameFirstKey import org.mariotaku.twidere.constant.nameFirstKey
import org.mariotaku.twidere.constant.profileImageStyleKey import org.mariotaku.twidere.constant.profileImageStyleKey
@ -182,17 +181,18 @@ class MessageConversationInfoFragment : BaseFragment(), IToolBarSupportFragment,
} }
} }
loaderManager.initLoader(0, null, this) LoaderManager.getInstance(this).initLoader(0, null, this)
} }
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
when (requestCode) { when (requestCode) {
REQUEST_CONVERSATION_ADD_USER -> { REQUEST_CONVERSATION_ADD_USER -> {
if (resultCode == Activity.RESULT_OK && data != null) { if (resultCode == Activity.RESULT_OK && data != null) {
val user = data.getParcelableExtra<ParcelableUser>(EXTRA_USER) data.getParcelableExtra<ParcelableUser>(EXTRA_USER)?.let { user ->
performAddParticipant(user) performAddParticipant(user)
} }
} }
}
REQUEST_PICK_MEDIA -> { REQUEST_PICK_MEDIA -> {
when (resultCode) { when (resultCode) {
Activity.RESULT_OK -> { Activity.RESULT_OK -> {
@ -300,7 +300,7 @@ class MessageConversationInfoFragment : BaseFragment(), IToolBarSupportFragment,
ProgressDialogFragment.show(childFragmentManager, "leave_conversation_progress") ProgressDialogFragment.show(childFragmentManager, "leave_conversation_progress")
val weakThis = WeakReference(this) val weakThis = WeakReference(this)
val task = DestroyConversationTask(requireContext(), accountKey, conversationId) val task = DestroyConversationTask(requireContext(), accountKey, conversationId)
task.callback = callback@ { succeed -> task.callback = callback@{ succeed ->
val f = weakThis.get() ?: return@callback val f = weakThis.get() ?: return@callback
f.dismissDialogThen("leave_conversation_progress") { f.dismissDialogThen("leave_conversation_progress") {
if (succeed) { if (succeed) {
@ -316,7 +316,7 @@ class MessageConversationInfoFragment : BaseFragment(), IToolBarSupportFragment,
ProgressDialogFragment.show(childFragmentManager, "clear_messages_progress") ProgressDialogFragment.show(childFragmentManager, "clear_messages_progress")
val weakThis = WeakReference(this) val weakThis = WeakReference(this)
val task = ClearMessagesTask(requireContext(), accountKey, conversationId) val task = ClearMessagesTask(requireContext(), accountKey, conversationId)
task.callback = callback@ { succeed -> task.callback = callback@{ succeed ->
val f = weakThis.get() ?: return@callback val f = weakThis.get() ?: return@callback
f.dismissDialogThen("clear_messages_progress") { f.dismissDialogThen("clear_messages_progress") {
if (succeed) { if (succeed) {
@ -331,10 +331,10 @@ class MessageConversationInfoFragment : BaseFragment(), IToolBarSupportFragment,
ProgressDialogFragment.show(childFragmentManager, "add_participant_progress") ProgressDialogFragment.show(childFragmentManager, "add_participant_progress")
val weakThis = WeakReference(this) val weakThis = WeakReference(this)
val task = AddParticipantsTask(requireContext(), accountKey, conversationId, listOf(user)) val task = AddParticipantsTask(requireContext(), accountKey, conversationId, listOf(user))
task.callback = callback@ { succeed -> task.callback = callback@ {
val f = weakThis.get() ?: return@callback val f = weakThis.get() ?: return@callback
f.dismissDialogThen("add_participant_progress") { f.dismissDialogThen("add_participant_progress") {
loaderManager.restartLoader(0, null, this) LoaderManager.getInstance(this).restartLoader(0, null, this)
} }
} }
TaskStarter.execute(task) TaskStarter.execute(task)
@ -344,10 +344,10 @@ class MessageConversationInfoFragment : BaseFragment(), IToolBarSupportFragment,
ProgressDialogFragment.show(childFragmentManager, "set_notifications_disabled_progress") ProgressDialogFragment.show(childFragmentManager, "set_notifications_disabled_progress")
val weakThis = WeakReference(this) val weakThis = WeakReference(this)
val task = SetConversationNotificationDisabledTask(requireContext(), accountKey, conversationId, disabled) val task = SetConversationNotificationDisabledTask(requireContext(), accountKey, conversationId, disabled)
task.callback = callback@ { _ -> task.callback = callback@{ _ ->
val f = weakThis.get() ?: return@callback val f = weakThis.get() ?: return@callback
f.dismissDialogThen("set_notifications_disabled_progress") { f.dismissDialogThen("set_notifications_disabled_progress") {
loaderManager.restartLoader(0, null, this) LoaderManager.getInstance(this).restartLoader(0, null, this)
} }
} }
TaskStarter.execute(task) TaskStarter.execute(task)
@ -379,7 +379,7 @@ class MessageConversationInfoFragment : BaseFragment(), IToolBarSupportFragment,
private fun performSetConversationName(name: String) { private fun performSetConversationName(name: String) {
val conversationId = this.conversationId val conversationId = this.conversationId
performUpdateInfo("set_name_progress", updateAction = updateAction@ { fragment, account, microBlog -> performUpdateInfo("set_name_progress", updateAction = updateAction@{ fragment, account, microBlog ->
val context = fragment.context val context = fragment.context
when (account.type) { when (account.type) {
AccountType.TWITTER -> { AccountType.TWITTER -> {
@ -396,7 +396,7 @@ class MessageConversationInfoFragment : BaseFragment(), IToolBarSupportFragment,
private fun performSetConversationAvatar(uri: Uri?) { private fun performSetConversationAvatar(uri: Uri?) {
val conversationId = this.conversationId val conversationId = this.conversationId
performUpdateInfo("set_avatar_progress", updateAction = updateAction@ { fragment, account, microBlog -> performUpdateInfo("set_avatar_progress", updateAction = updateAction@{ fragment, account, microBlog ->
val context = fragment.context val context = fragment.context
when (account.type) { when (account.type) {
AccountType.TWITTER -> { AccountType.TWITTER -> {
@ -470,7 +470,7 @@ class MessageConversationInfoFragment : BaseFragment(), IToolBarSupportFragment,
}.alwaysUi { }.alwaysUi {
val fragment = weakThis.get() ?: return@alwaysUi val fragment = weakThis.get() ?: return@alwaysUi
fragment.dismissDialogThen(tag) { fragment.dismissDialogThen(tag) {
loaderManager.restartLoader(0, null, this) LoaderManager.getInstance(this).restartLoader(0, null, this)
} }
} }
} }

View File

@ -25,16 +25,17 @@ import android.graphics.Canvas
import android.graphics.Paint import android.graphics.Paint
import android.graphics.RectF import android.graphics.RectF
import android.os.Bundle import android.os.Bundle
import androidx.annotation.WorkerThread
import androidx.loader.app.LoaderManager.LoaderCallbacks
import androidx.loader.content.Loader
import androidx.recyclerview.widget.LinearLayoutManager
import android.text.Editable import android.text.Editable
import android.text.Spannable import android.text.Spannable
import android.text.SpannableStringBuilder import android.text.SpannableStringBuilder
import android.text.TextUtils import android.text.TextUtils
import android.text.style.ReplacementSpan import android.text.style.ReplacementSpan
import android.view.* import android.view.*
import androidx.annotation.WorkerThread
import androidx.loader.app.LoaderManager
import androidx.loader.app.LoaderManager.LoaderCallbacks
import androidx.loader.content.Loader
import androidx.recyclerview.widget.LinearLayoutManager
import kotlinx.android.synthetic.main.fragment_messages_conversation_new.* import kotlinx.android.synthetic.main.fragment_messages_conversation_new.*
import org.mariotaku.kpreferences.get import org.mariotaku.kpreferences.get
import org.mariotaku.ktextension.* import org.mariotaku.ktextension.*
@ -305,10 +306,10 @@ class MessageNewConversationFragment : BaseFragment(), LoaderCallbacks<List<Parc
this[EXTRA_FROM_CACHE] = fromType this[EXTRA_FROM_CACHE] = fromType
} }
if (loaderInitialized) { if (loaderInitialized) {
loaderManager.initLoader(0, args, this) LoaderManager.getInstance(this).initLoader(0, args, this)
loaderInitialized = true loaderInitialized = true
} else { } else {
loaderManager.restartLoader(0, args, this) LoaderManager.getInstance(this).restartLoader(0, args, this)
} }
if (performSearchRequestRunnable != null) { if (performSearchRequestRunnable != null) {
editParticipants.removeCallbacks(performSearchRequestRunnable) editParticipants.removeCallbacks(performSearchRequestRunnable)

View File

@ -205,7 +205,7 @@ class MessagesConversationFragment : AbsContentListRecyclerViewFragment<Messages
updateMediaPreview() updateMediaPreview()
loaderManager.initLoader(0, null, this) LoaderManager.getInstance(this).initLoader(0, null, this)
showProgress() showProgress()
} }
@ -413,7 +413,7 @@ class MessagesConversationFragment : AbsContentListRecyclerViewFragment<Messages
if (activity is LinkHandlerActivity) { if (activity is LinkHandlerActivity) {
activity.intent = IntentUtils.messageConversation(accountKey, newConversationId) activity.intent = IntentUtils.messageConversation(accountKey, newConversationId)
} }
loaderManager.restartLoader(0, null, this) LoaderManager.getInstance(this).restartLoader(0, null, this)
} }
private fun performSendMessage() { private fun performSendMessage() {
@ -526,8 +526,7 @@ class MessagesConversationFragment : AbsContentListRecyclerViewFragment<Messages
val stateIcon = if (conversation.notificationDisabled) { val stateIcon = if (conversation.notificationDisabled) {
ContextCompat.getDrawable(context, R.drawable.ic_message_type_speaker_muted)?.apply { ContextCompat.getDrawable(context, R.drawable.ic_message_type_speaker_muted)?.apply {
mutate() mutate().setColorFilter(conversationTitle.currentTextColor, PorterDuff.Mode.SRC_ATOP)
setColorFilter(conversationTitle.currentTextColor, PorterDuff.Mode.SRC_ATOP)
} }
} else { } else {
null null

View File

@ -29,6 +29,7 @@ import android.view.ContextMenu
import android.view.MenuInflater import android.view.MenuInflater
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import androidx.loader.app.LoaderManager
import com.bumptech.glide.RequestManager import com.bumptech.glide.RequestManager
import com.squareup.otto.Subscribe import com.squareup.otto.Subscribe
import kotlinx.android.synthetic.main.activity_premium_dashboard.* import kotlinx.android.synthetic.main.activity_premium_dashboard.*
@ -86,7 +87,7 @@ class MessagesEntriesFragment : AbsContentListRecyclerViewFragment<MessagesEntri
super.onActivityCreated(savedInstanceState) super.onActivityCreated(savedInstanceState)
adapter.listener = this adapter.listener = this
adapter.loadMoreSupportedPosition = ILoadMoreSupportAdapter.END adapter.loadMoreSupportedPosition = ILoadMoreSupportAdapter.END
loaderManager.initLoader(loaderId, null, this) LoaderManager.getInstance(this).initLoader(loaderId, null, this)
registerForContextMenu(recyclerView) registerForContextMenu(recyclerView)
} }
@ -104,7 +105,7 @@ class MessagesEntriesFragment : AbsContentListRecyclerViewFragment<MessagesEntri
when (requestCode) { when (requestCode) {
REQUEST_SELECT_ACCOUNT -> { REQUEST_SELECT_ACCOUNT -> {
if (resultCode != Activity.RESULT_OK) return if (resultCode != Activity.RESULT_OK) return
val accountKey = data!!.getParcelableExtra<UserKey>(EXTRA_ACCOUNT_KEY) val accountKey = data?.getParcelableExtra<UserKey>(EXTRA_ACCOUNT_KEY) ?: return
startActivity(IntentUtils.newMessageConversation(accountKey)) startActivity(IntentUtils.newMessageConversation(accountKey))
} }
else -> { else -> {

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