targetSdkVersion 31
This commit is contained in:
parent
d017a47363
commit
9c68857e6e
|
@ -3,6 +3,11 @@
|
|||
<component name="CompilerConfiguration">
|
||||
<bytecodeTargetLevel target="1.8">
|
||||
<module name="apng" target="1.7" />
|
||||
<module name="SubwayTooter.apng_android" target="11" />
|
||||
<module name="SubwayTooter.app" target="11" />
|
||||
<module name="SubwayTooter.colorpicker" target="11" />
|
||||
<module name="SubwayTooter.emoji" target="11" />
|
||||
<module name="SubwayTooter.sample_apng" target="11" />
|
||||
</bytecodeTargetLevel>
|
||||
</component>
|
||||
</project>
|
|
@ -4,10 +4,10 @@
|
|||
<component name="GradleSettings">
|
||||
<option name="linkedExternalProjectsSettings">
|
||||
<GradleProjectSettings>
|
||||
<option name="delegatedBuild" value="false" />
|
||||
<option name="testRunner" value="GRADLE" />
|
||||
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="gradleJvm" value="Embedded JDK" />
|
||||
<option name="modules">
|
||||
<set>
|
||||
<option value="$PROJECT_DIR$" />
|
||||
|
|
|
@ -2,8 +2,10 @@
|
|||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="AndroidLintButtonStyle" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="AndroidLintPluralsCandidate" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="AndroidLintSetTextI18n" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="BlockingMethodInNonBlockingContext" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="CheckTagEmptyBody" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="ClassName" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="ConstantConditionIf" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="ConvertTwoComparisonsToRangeCheck" enabled="false" level="INFO" enabled_by_default="false" />
|
||||
|
@ -23,14 +25,27 @@
|
|||
<option name="m_maxLength" value="32" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="JoinDeclarationAndAssignment" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="JsonStandardCompliance" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="LocalVariableName" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="LoopToCallChain" enabled="false" level="INFO" enabled_by_default="false" />
|
||||
<inspection_tool class="NumericOverflow" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="ObjectPropertyName" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="PrivatePropertyName" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="PropertyName" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
|
||||
<option name="processCode" value="true" />
|
||||
<option name="processLiterals" value="true" />
|
||||
<option name="processComments" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="TryFinallyCanBeTryWithResources" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="UnnecessaryModuleDependencyInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="UnusedProperty" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="UnusedSymbol" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="UseWithIndex" enabled="false" level="INFO" enabled_by_default="false" />
|
||||
<inspection_tool class="XmlDefaultAttributeValue" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="XmlDuplicatedId" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="XmlHighlighting" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="XmlUnusedNamespaceDeclaration" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="YAMLDuplicatedKeys" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
</profile>
|
||||
</component>
|
|
@ -11,17 +11,17 @@ repositories {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
compile fileTree(include: ['*.jar'], dir: 'src/lib')
|
||||
implementation fileTree(include: ['*.jar'], dir: 'src/lib')
|
||||
implementation "com.google.guava:guava:28.1-jre"
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib"
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.6.0'
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0'
|
||||
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine'
|
||||
|
||||
def ktor_version="1.5.0"
|
||||
implementation "io.ktor:ktor-client-core:$ktor_version"
|
||||
implementation "io.ktor:ktor-client-cio:$ktor_version"
|
||||
implementation "io.ktor:ktor-client-features:$ktor_version"
|
||||
implementation "io.ktor:ktor-client-encoding:$ktor_version"
|
||||
def ktorVersion="1.5.0"
|
||||
implementation "io.ktor:ktor-client-core:$ktorVersion"
|
||||
implementation "io.ktor:ktor-client-cio:$ktorVersion"
|
||||
implementation "io.ktor:ktor-client-features:$ktorVersion"
|
||||
implementation "io.ktor:ktor-client-encoding:$ktorVersion"
|
||||
|
||||
// StringEscapeUtils.unescapeHtml4
|
||||
implementation "org.apache.commons:commons-text:1.9"
|
||||
|
@ -33,3 +33,7 @@ dependencies {
|
|||
test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
|
@ -30,11 +30,22 @@ android {
|
|||
}
|
||||
|
||||
kotlinOptions {
|
||||
jvmTarget = '1.8'
|
||||
useIR = true
|
||||
freeCompilerArgs += [
|
||||
"-Xopt-in=kotlin.ExperimentalStdlibApi",
|
||||
"-Xopt-in=kotlinx.coroutines.ExperimentalCoroutinesApi",
|
||||
"-Xopt-in=kotlinx.serialization.ExperimentalSerializationApi",
|
||||
"-Xopt-in=androidx.compose.foundation.ExperimentalFoundationApi",
|
||||
"-Xopt-in=androidx.compose.animation.ExperimentalAnimationApi",
|
||||
]
|
||||
}
|
||||
buildFeatures {
|
||||
compose true
|
||||
}
|
||||
composeOptions {
|
||||
kotlinCompilerExtensionVersion compose_version
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
|
@ -57,13 +68,6 @@ android {
|
|||
}
|
||||
}
|
||||
|
||||
dexOptions {
|
||||
jumboMode = true
|
||||
preDexLibraries true
|
||||
maxProcessCount 10
|
||||
javaMaxHeapSize "3g"
|
||||
}
|
||||
|
||||
// Generate Signed APK のファイル名を変更
|
||||
android.applicationVariants.all { variant ->
|
||||
if (variant.buildType.name == "release") {
|
||||
|
@ -73,7 +77,8 @@ android {
|
|||
def versionName = defaultConfig.versionName
|
||||
def flavor = variant.flavorName
|
||||
def date = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date())
|
||||
outputFileName = "../../SubwayTooter-${flavor}-${versionCode}-${versionName}-${date}.apk"
|
||||
def branch = gitBranch()
|
||||
outputFileName = "../../SubwayTooter-${branch}-${flavor}-${versionCode}-${versionName}-${date}.apk"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -81,12 +86,27 @@ android {
|
|||
packagingOptions {
|
||||
// https://github.com/Kotlin/kotlinx.coroutines/issues/1064
|
||||
pickFirst("META-INF/atomicfu.kotlin_module")
|
||||
resources {
|
||||
excludes += '/META-INF/{AL2.0,LGPL2.1}'
|
||||
}
|
||||
}
|
||||
|
||||
useLibrary 'android.test.base'
|
||||
useLibrary 'android.test.mock'
|
||||
}
|
||||
|
||||
static def gitBranch() {
|
||||
def branch = "(no branch)"
|
||||
def proc = "git status".execute()
|
||||
proc.in.eachLine { line ->
|
||||
def matcher = line =~ /\AOn branch (\S+)/
|
||||
if (matcher) branch = matcher.group(1)
|
||||
}
|
||||
proc.err.eachLine { line -> println line }
|
||||
proc.waitFor()
|
||||
branch
|
||||
}
|
||||
|
||||
kapt {
|
||||
useBuildCache = true
|
||||
}
|
||||
|
@ -109,20 +129,17 @@ dependencies {
|
|||
|
||||
|
||||
implementation "androidx.appcompat:appcompat:$appcompat_version"
|
||||
//noinspection KtxExtensionAvailable
|
||||
implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version"
|
||||
|
||||
|
||||
// DrawerLayout
|
||||
implementation "androidx.drawerlayout:drawerlayout:1.1.1"
|
||||
|
||||
// NavigationView
|
||||
implementation "com.google.android.material:material:1.3.0"
|
||||
implementation "com.google.android.material:material:1.4.0"
|
||||
|
||||
// PreferenceManager
|
||||
implementation "androidx.preference:preference-ktx:1.1.1"
|
||||
|
||||
implementation "androidx.exifinterface:exifinterface:1.3.2"
|
||||
implementation "androidx.exifinterface:exifinterface:1.3.3"
|
||||
|
||||
// CustomTabs
|
||||
implementation "androidx.browser:browser:1.3.0"
|
||||
|
@ -155,19 +172,17 @@ dependencies {
|
|||
|
||||
testImplementation "junit:junit:$junit_version" // しばらくはkotlin-testとjunitを併用
|
||||
|
||||
implementation 'com.squareup.okhttp3:okhttp:4.8.1'
|
||||
implementation 'com.squareup.okhttp3:okhttp-urlconnection:4.8.1'
|
||||
testImplementation 'com.squareup.okhttp3:mockwebserver:3.12.1'
|
||||
androidTestImplementation 'com.squareup.okhttp3:mockwebserver:3.12.1'
|
||||
def okhttpVersion = "4.9.2"
|
||||
implementation "com.squareup.okhttp3:okhttp:$okhttpVersion"
|
||||
implementation "com.squareup.okhttp3:okhttp-urlconnection:$okhttpVersion"
|
||||
testImplementation "com.squareup.okhttp3:mockwebserver:$okhttpVersion"
|
||||
androidTestImplementation "'com.squareup.okhttp3:mockwebserver:$okhttpVersion"
|
||||
|
||||
def glideVersion = '4.11.0'
|
||||
def glideVersion = '4.12.0'
|
||||
implementation "com.github.bumptech.glide:glide:$glideVersion"
|
||||
implementation "com.github.bumptech.glide:annotations:$glideVersion"
|
||||
implementation("com.github.bumptech.glide:okhttp3-integration:$glideVersion") {
|
||||
exclude group: 'com.squareup.okhttp3', module: 'okhttp'
|
||||
// 推移的な依存関係の除外
|
||||
// glide 4.9.0 は okhttp3 3.9.1を使ってる
|
||||
// http://bumptech.github.io/glide/int/about.html#how-do-i-use-a-specific-version-of-okhttp-volley-or-other-third-party-library
|
||||
}
|
||||
kapt "com.github.bumptech.glide:compiler:$glideVersion"
|
||||
|
||||
|
@ -190,7 +205,7 @@ dependencies {
|
|||
|
||||
implementation 'com.astuetz:pagerslidingtabstrip:1.0.1'
|
||||
|
||||
implementation 'com.google.android.exoplayer:exoplayer:2.15.0'
|
||||
implementation 'com.google.android.exoplayer:exoplayer:2.15.1'
|
||||
/*
|
||||
WARNING: [Processor] Library '…\exoplayer-ui-2.12.0.aar' contains references to both AndroidX and old support library. This seems like the library is partially migrated. Jetifier will try to rewrite the library anyway.
|
||||
Example of androidX reference: 'androidx/core/app/NotificationCompat$Builder'
|
||||
|
@ -199,6 +214,46 @@ dependencies {
|
|||
*/
|
||||
|
||||
implementation 'com.caverock:androidsvg-aar:1.4'
|
||||
|
||||
|
||||
// ViewModel
|
||||
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
|
||||
// LiveData
|
||||
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
|
||||
// Lifecycles only (without ViewModel or LiveData)
|
||||
implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version"
|
||||
|
||||
// Saved state module for ViewModel
|
||||
implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycle_version"
|
||||
|
||||
// if using Java8, use the following instead of lifecycle-compiler
|
||||
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
|
||||
|
||||
// optional - helpers for implementing LifecycleOwner in a Service
|
||||
implementation "androidx.lifecycle:lifecycle-service:$lifecycle_version"
|
||||
|
||||
// optional - ProcessLifecycleOwner provides a lifecycle for the whole application process
|
||||
implementation "androidx.lifecycle:lifecycle-process:$lifecycle_version"
|
||||
|
||||
// optional - ReactiveStreams support for LiveData
|
||||
implementation "androidx.lifecycle:lifecycle-reactivestreams-ktx:$lifecycle_version"
|
||||
|
||||
// optional - Test helpers for LiveData
|
||||
testImplementation "androidx.arch.core:core-testing:$arch_version"
|
||||
|
||||
implementation "com.google.accompanist:accompanist-flowlayout:0.20.0"
|
||||
|
||||
|
||||
implementation "androidx.compose.ui:ui:$compose_version"
|
||||
implementation "androidx.compose.material:material:$compose_version"
|
||||
implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
|
||||
implementation "androidx.compose.runtime:runtime-livedata:$compose_version"
|
||||
implementation "androidx.compose.material:material-icons-extended:$compose_version"
|
||||
androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
|
||||
debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
|
||||
|
||||
implementation 'androidx.activity:activity-compose:1.4.0-rc01'
|
||||
|
||||
}
|
||||
|
||||
repositories {
|
||||
|
|
|
@ -33,6 +33,7 @@ class TestMisskeyMentionAndroid {
|
|||
// val a="""[[ ]""".toRegex()
|
||||
|
||||
// IDEで警告が出るが、Androidは正規表現エンジンが異なるので仕方ない
|
||||
@Suppress("RegExpRedundantNestedCharacterClass")
|
||||
assertEquals(true, """[[ ]]][ ]""".toRegex().matches(" ] "))
|
||||
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package jp.juggler.subwaytooter
|
||||
|
||||
import androidx.test.InstrumentationRegistry
|
||||
import androidx.test.runner.AndroidJUnit4
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import jp.juggler.subwaytooter.api.TootApiCallback
|
||||
import jp.juggler.subwaytooter.api.TootApiClient
|
||||
import jp.juggler.subwaytooter.api.entity.Host
|
||||
|
@ -10,13 +10,13 @@ import jp.juggler.subwaytooter.table.SavedAccount
|
|||
import jp.juggler.subwaytooter.util.SimpleHttpClientImpl
|
||||
import jp.juggler.util.LogCategory
|
||||
import jp.juggler.util.MySslSocketFactory
|
||||
import junit.framework.Assert.assertNotNull
|
||||
import junit.framework.Assert.assertNull
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withContext
|
||||
import okhttp3.ConnectionSpec
|
||||
import okhttp3.OkHttpClient
|
||||
import org.junit.Assert.assertNotNull
|
||||
import org.junit.Assert.assertNull
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import java.util.*
|
||||
|
@ -38,10 +38,14 @@ class TestTootInstance {
|
|||
.readTimeout(60.toLong(), TimeUnit.SECONDS)
|
||||
.writeTimeout(60.toLong(), TimeUnit.SECONDS)
|
||||
.pingInterval(10, TimeUnit.SECONDS)
|
||||
.connectionSpecs(Collections.singletonList(ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
|
||||
.connectionSpecs(
|
||||
Collections.singletonList(
|
||||
ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
|
||||
.allEnabledCipherSuites()
|
||||
.allEnabledTlsVersions()
|
||||
.build()))
|
||||
.build()
|
||||
)
|
||||
)
|
||||
.sslSocketFactory(MySslSocketFactory, MySslSocketFactory.trustManager)
|
||||
.build()
|
||||
|
||||
|
@ -56,7 +60,7 @@ class TestTootInstance {
|
|||
}
|
||||
}
|
||||
|
||||
private val appContext = InstrumentationRegistry.getTargetContext()!!
|
||||
private val appContext = InstrumentationRegistry.getInstrumentation().targetContext!!
|
||||
|
||||
val client = TootApiClient(
|
||||
context = appContext,
|
||||
|
@ -75,10 +79,10 @@ class TestTootInstance {
|
|||
runBlocking {
|
||||
withContext(Dispatchers.IO) {
|
||||
suspend fun a(host: Host) {
|
||||
val (ti,ri) = TootInstance.get(client,host )
|
||||
val (ti, ri) = TootInstance.getEx(client, hostArg = host)
|
||||
assertNotNull(ti)
|
||||
assertNull(ri?.error)
|
||||
ti!!.run{ log.d("${instanceType} ${uri} ${version}")}
|
||||
ti!!.run { log.d("$instanceType $uri $version") }
|
||||
|
||||
}
|
||||
a(Host.parse("mastodon.juggler.jp"))
|
||||
|
@ -92,10 +96,10 @@ class TestTootInstance {
|
|||
runBlocking {
|
||||
withContext(Dispatchers.IO) {
|
||||
suspend fun a(account: SavedAccount) {
|
||||
val (ti,ri) = TootInstance.get(client,account = account )
|
||||
val (ti, ri) = TootInstance.getEx(client, account = account)
|
||||
assertNull(ri?.error)
|
||||
assertNotNull(ti)
|
||||
ti!!.run{ log.d("${account.acct} ${instanceType} ${uri} ${version}")}
|
||||
ti!!.run { log.d("${account.acct} $instanceType $uri $version") }
|
||||
}
|
||||
a(SavedAccount(45, "tateisu@mastodon.juggler.jp"))
|
||||
a(SavedAccount(45, "tateisu@misskey.io", misskeyVersion = 12))
|
||||
|
|
|
@ -3,19 +3,7 @@
|
|||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="jp.juggler.subwaytooter">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
||||
tools:ignore="ScopedStorage" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<!-- CAMERAパーミッションをつけるとPlayストアにプライバシーポリシーを記載する必要がある -->
|
||||
<!--<uses-permission android:name="android.permission.CAMERA"/>-->
|
||||
|
||||
<queries>
|
||||
|
||||
<!-- (自アプリ以外で)指定URLを開けるアプリの存在確認 -->
|
||||
<intent>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
@ -62,6 +50,20 @@
|
|||
<!-- </intent>-->
|
||||
</queries>
|
||||
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
<uses-permission
|
||||
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
||||
tools:ignore="ScopedStorage" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<!-- CAMERAパーミッションをつけるとPlayストアにプライバシーポリシーを記載する必要がある -->
|
||||
<!--<uses-permission android:name="android.permission.CAMERA"/>-->
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
|
||||
<application
|
||||
android:name=".App1"
|
||||
android:allowBackup="true"
|
||||
|
@ -75,30 +77,11 @@
|
|||
android:theme="@style/AppTheme.Light"
|
||||
tools:ignore="UnusedAttribute">
|
||||
|
||||
<receiver android:name=".EventReceiver">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.ACTION_MY_PACKAGE_REPLACED" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
|
||||
</receiver>
|
||||
|
||||
<service
|
||||
android:name=".notification.PollingService"
|
||||
android:permission="android.permission.BIND_JOB_SERVICE" />
|
||||
|
||||
<service android:name=".notification.PollingForegrounder" />
|
||||
|
||||
<activity
|
||||
android:name=".ActMain"
|
||||
android:exported="true"
|
||||
android:label="@string/app_name"
|
||||
android:launchMode="singleTask"
|
||||
|
||||
android:windowSoftInputMode="adjustResize|stateAlwaysHidden">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
@ -108,9 +91,8 @@
|
|||
|
||||
<activity
|
||||
android:name=".ActCallback"
|
||||
android:label="@string/app_name"
|
||||
|
||||
>
|
||||
android:exported="true"
|
||||
android:label="@string/app_name">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
|
@ -195,105 +177,122 @@
|
|||
|
||||
<activity
|
||||
android:name=".ActPost"
|
||||
android:exported="false"
|
||||
android:label="@string/act_post"
|
||||
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
|
||||
<!--suppress AndroidElementNotAllowed -->
|
||||
<layout
|
||||
android:defaultWidth="320dp"
|
||||
android:defaultHeight="480dp"
|
||||
android:defaultWidth="320dp"
|
||||
android:gravity="center"
|
||||
android:minWidth="64dp"
|
||||
android:minHeight="64dp"
|
||||
android:minWidth="64dp"
|
||||
tools:ignore="UnusedAttribute" />
|
||||
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".ActAccountSetting"
|
||||
android:exported="false"
|
||||
android:label="@string/account_setting"
|
||||
|
||||
android:windowSoftInputMode="adjustResize|stateAlwaysHidden" />
|
||||
|
||||
<activity
|
||||
android:name=".ActAppSetting"
|
||||
android:exported="false"
|
||||
android:label="@string/app_setting"
|
||||
android:windowSoftInputMode="adjustResize|stateAlwaysHidden" />
|
||||
|
||||
<activity
|
||||
android:name=".ActColumnList"
|
||||
android:exported="false"
|
||||
android:label="@string/column_list"
|
||||
|
||||
android:windowSoftInputMode="adjustResize" />
|
||||
|
||||
<activity
|
||||
android:name=".ActAbout"
|
||||
android:label="@string/app_about"
|
||||
android:exported="false"
|
||||
android:label="@string/app_about" />
|
||||
|
||||
/>
|
||||
<activity
|
||||
android:name=".ActOSSLicense"
|
||||
android:label="@string/oss_license"
|
||||
android:exported="false"
|
||||
android:label="@string/oss_license" />
|
||||
|
||||
/>
|
||||
<activity
|
||||
android:name=".ActMutedApp"
|
||||
android:exported="false"
|
||||
android:label="@string/muted_app" />
|
||||
|
||||
<activity
|
||||
android:name=".ActMutedPseudoAccount"
|
||||
android:exported="false"
|
||||
android:label="@string/muted_users_from_pseudo_account" />
|
||||
|
||||
<activity
|
||||
android:name=".ActMutedWord"
|
||||
android:exported="false"
|
||||
android:label="@string/muted_word" />
|
||||
|
||||
<activity
|
||||
android:name=".ActFavMute"
|
||||
android:exported="false"
|
||||
android:label="@string/fav_muted_user_long" />
|
||||
|
||||
<activity
|
||||
android:name=".ActKeywordFilter"
|
||||
android:exported="false"
|
||||
android:label="@string/keyword_filter_new"
|
||||
android:windowSoftInputMode="adjustResize|stateAlwaysHidden" />
|
||||
|
||||
<activity
|
||||
android:name=".ActHighlightWordList"
|
||||
android:exported="false"
|
||||
android:label="@string/highlight_word" />
|
||||
|
||||
<activity
|
||||
android:name=".ActHighlightWordEdit"
|
||||
android:exported="false"
|
||||
android:label="@string/highlight_word" />
|
||||
|
||||
<activity
|
||||
android:name=".ActColumnCustomize"
|
||||
android:exported="false"
|
||||
android:label="@string/color_and_background"
|
||||
android:windowSoftInputMode="adjustResize|stateAlwaysHidden" />
|
||||
|
||||
<activity
|
||||
android:name=".ActLanguageFilter"
|
||||
android:exported="false"
|
||||
android:label="@string/language_filter"
|
||||
android:windowSoftInputMode="adjustResize|stateAlwaysHidden" />
|
||||
|
||||
<activity
|
||||
android:name=".ActDrawableList"
|
||||
android:exported="false"
|
||||
android:label="@string/drawable_list"
|
||||
android:windowSoftInputMode="adjustResize|stateAlwaysHidden" />
|
||||
|
||||
<activity
|
||||
android:name=".ActNickname"
|
||||
android:exported="false"
|
||||
android:label="@string/nickname_and_color_and_notification_sound"
|
||||
android:windowSoftInputMode="adjustResize|stateAlwaysHidden" />
|
||||
|
||||
<activity
|
||||
android:name=".ActText"
|
||||
android:exported="false"
|
||||
android:label="@string/select_and_copy"
|
||||
android:windowSoftInputMode="adjustResize|stateAlwaysHidden" />
|
||||
|
||||
<activity
|
||||
android:name=".ActMediaViewer"
|
||||
android:exported="false"
|
||||
android:theme="@style/AppTheme.Dark.NoActionBar" />
|
||||
|
||||
<activity
|
||||
android:name=".ActExitReasons"
|
||||
android:exported="false"
|
||||
android:label="@string/exit_reasons"
|
||||
android:windowSoftInputMode="adjustResize|stateAlwaysHidden" />
|
||||
|
||||
|
@ -301,6 +300,18 @@
|
|||
android:name="android.max_aspect"
|
||||
android:value="100.0" />
|
||||
|
||||
<meta-data
|
||||
android:name="com.google.firebase.messaging.default_notification_icon"
|
||||
android:resource="@drawable/ic_notification" />
|
||||
|
||||
<meta-data
|
||||
android:name="com.google.firebase.messaging.default_notification_color"
|
||||
android:resource="@color/Light_colorAccent" />
|
||||
|
||||
<meta-data
|
||||
android:name="android.allow_multiple_resumed_activities"
|
||||
android:value="true" />
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="jp.juggler.subwaytooter.FileProvider"
|
||||
|
@ -311,38 +322,50 @@
|
|||
android:resource="@xml/file_provider_path" />
|
||||
</provider>
|
||||
|
||||
<receiver android:name=".DownloadReceiver">
|
||||
<receiver
|
||||
android:name=".EventReceiver"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.ACTION_MY_PACKAGE_REPLACED" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
|
||||
</receiver>
|
||||
|
||||
<receiver
|
||||
android:name=".DownloadReceiver"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.DOWNLOAD_NOTIFICATION_CLICKED" />
|
||||
<action android:name="android.intent.action.DOWNLOAD_COMPLETE" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<!-- Set custom default icon. This is used when no icon is set for incoming notification messages.
|
||||
See README(https://goo.gl/l4GJaQ) for more. -->
|
||||
<service
|
||||
android:name=".notification.PollingService"
|
||||
android:permission="android.permission.BIND_JOB_SERVICE" />
|
||||
|
||||
<!-- Set color used with incoming notification messages. This is used when no color is set for the incoming
|
||||
notification message. See README(https://goo.gl/6BKBk7) for more. -->
|
||||
<service android:name=".notification.PollingForegrounder" />
|
||||
|
||||
<!--https://android-developers.googleblog.com/2018/11/get-your-app-ready-for-foldable-phones.html-->
|
||||
<service
|
||||
android:name=".MyFirebaseMessagingService"
|
||||
android:exported="true"
|
||||
tools:ignore="ExportedService">
|
||||
<intent-filter>
|
||||
<action android:name="com.google.firebase.MESSAGING_EVENT" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<!-- Set custom default icon. This is used when no icon is set for incoming notification messages.
|
||||
See README(https://goo.gl/l4GJaQ) for more. -->
|
||||
<meta-data
|
||||
android:name="com.google.firebase.messaging.default_notification_icon"
|
||||
android:resource="@drawable/ic_notification" />
|
||||
|
||||
<!-- Set color used with incoming notification messages. This is used when no color is set for the incoming
|
||||
notification message. See README(https://goo.gl/6BKBk7) for more. -->
|
||||
<meta-data
|
||||
android:name="com.google.firebase.messaging.default_notification_color"
|
||||
android:resource="@color/Light_colorAccent" />
|
||||
|
||||
<!--https://android-developers.googleblog.com/2018/11/get-your-app-ready-for-foldable-phones.html-->
|
||||
<meta-data
|
||||
android:name="android.allow_multiple_resumed_activities"
|
||||
android:value="true" />
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
|
@ -42,8 +42,6 @@ class ActColumnCustomize : AppCompatActivity(), View.OnClickListener, ColorPicke
|
|||
internal const val COLOR_DIALOG_ID_ACCT_TEXT = 4
|
||||
internal const val COLOR_DIALOG_ID_CONTENT_TEXT = 5
|
||||
|
||||
internal const val REQUEST_CODE_PICK_BACKGROUND = 1
|
||||
|
||||
internal const val PROGRESS_MAX = 65536
|
||||
|
||||
fun createIntent(activity: ActMain, idx: Int) =
|
||||
|
@ -72,7 +70,7 @@ class ActColumnCustomize : AppCompatActivity(), View.OnClickListener, ColorPicke
|
|||
private var lastImageUri: String? = null
|
||||
private var lastImageBitmap: Bitmap? = null
|
||||
|
||||
val arColumnBackgroundImage = activityResultHandler { ar ->
|
||||
private val arColumnBackgroundImage = activityResultHandler { ar ->
|
||||
val data = ar?.data
|
||||
if (data != null && ar.resultCode == RESULT_OK) {
|
||||
data.handleGetContentResult(contentResolver)
|
||||
|
|
|
@ -14,8 +14,6 @@ import android.view.*
|
|||
import android.view.inputmethod.EditorInfo
|
||||
import android.widget.*
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.inputmethod.InputConnectionCompat
|
||||
import androidx.core.view.inputmethod.InputContentInfoCompat
|
||||
import jp.juggler.subwaytooter.action.saveWindowSize
|
||||
import jp.juggler.subwaytooter.actpost.*
|
||||
import jp.juggler.subwaytooter.api.*
|
||||
|
@ -56,11 +54,6 @@ class ActPost : AppCompatActivity(),
|
|||
const val KEY_QUOTE = "quote"
|
||||
const val KEY_SCHEDULED_STATUS = "scheduled_status"
|
||||
|
||||
const val KEY_ATTACHMENT_LIST = "attachment_list"
|
||||
const val KEY_IN_REPLY_TO_ID = "in_reply_to_id"
|
||||
const val KEY_IN_REPLY_TO_TEXT = "in_reply_to_text"
|
||||
const val KEY_IN_REPLY_TO_IMAGE = "in_reply_to_image"
|
||||
|
||||
const val STATE_ALL = "all"
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
|
@ -97,8 +90,8 @@ class ActPost : AppCompatActivity(),
|
|||
|
||||
lateinit var btnAccount: Button
|
||||
lateinit var btnVisibility: ImageButton
|
||||
lateinit var btnAttachment: ImageButton
|
||||
lateinit var btnPost: ImageButton
|
||||
private lateinit var btnAttachment: ImageButton
|
||||
private lateinit var btnPost: ImageButton
|
||||
lateinit var llAttachment: View
|
||||
lateinit var ivMedia: List<MyNetworkImageView>
|
||||
lateinit var cbNSFW: CheckBox
|
||||
|
@ -121,7 +114,7 @@ class ActPost : AppCompatActivity(),
|
|||
|
||||
lateinit var tvCharCount: TextView
|
||||
lateinit var handler: Handler
|
||||
lateinit var formRoot: ActPostRootLinearLayout
|
||||
private lateinit var formRoot: ActPostRootLinearLayout
|
||||
|
||||
lateinit var llReply: View
|
||||
lateinit var tvReplyTo: TextView
|
||||
|
@ -129,8 +122,8 @@ class ActPost : AppCompatActivity(),
|
|||
lateinit var scrollView: ScrollView
|
||||
|
||||
lateinit var tvSchedule: TextView
|
||||
lateinit var ibSchedule: ImageButton
|
||||
lateinit var ibScheduleReset: ImageButton
|
||||
private lateinit var ibSchedule: ImageButton
|
||||
private lateinit var ibScheduleReset: ImageButton
|
||||
|
||||
lateinit var pref: SharedPreferences
|
||||
lateinit var appState: AppState
|
||||
|
@ -184,41 +177,6 @@ class ActPost : AppCompatActivity(),
|
|||
}
|
||||
}
|
||||
|
||||
val commitContentListener =
|
||||
InputConnectionCompat.OnCommitContentListener {
|
||||
inputContentInfo: InputContentInfoCompat,
|
||||
flags: Int,
|
||||
_: Bundle?,
|
||||
->
|
||||
// Intercepts InputConnection#commitContent API calls.
|
||||
// - inputContentInfo : content to be committed
|
||||
// - flags : {@code 0} or {@link #INPUT_CONTENT_GRANT_READ_URI_PERMISSION}
|
||||
// - opts : optional bundle data. This can be {@code null}
|
||||
// return
|
||||
// - true if this request is accepted by the application,
|
||||
// no matter if the request is already handled or still being handled in background.
|
||||
// - false to use the default implementation
|
||||
|
||||
// read and display inputContentInfo asynchronously
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 25 &&
|
||||
flags and InputConnectionCompat.INPUT_CONTENT_GRANT_READ_URI_PERMISSION != 0
|
||||
) {
|
||||
try {
|
||||
inputContentInfo.requestPermission()
|
||||
} catch (ignored: Exception) {
|
||||
// return false if failed
|
||||
return@OnCommitContentListener false
|
||||
}
|
||||
}
|
||||
|
||||
addAttachment(inputContentInfo.contentUri) {
|
||||
inputContentInfo.releasePermission()
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
|
@ -331,7 +289,11 @@ class ActPost : AppCompatActivity(),
|
|||
openBrowser(span.linkInfo.url)
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
|
||||
override fun onRequestPermissionsResult(
|
||||
requestCode: Int,
|
||||
permissions: Array<String>,
|
||||
grantResults: IntArray
|
||||
) {
|
||||
attachmentPicker.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
}
|
||||
|
@ -407,7 +369,12 @@ class ActPost : AppCompatActivity(),
|
|||
updateTextCount()
|
||||
}
|
||||
|
||||
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
|
||||
override fun onItemSelected(
|
||||
parent: AdapterView<*>?,
|
||||
view: View?,
|
||||
position: Int,
|
||||
id: Long
|
||||
) {
|
||||
showPoll()
|
||||
updateTextCount()
|
||||
}
|
||||
|
@ -463,7 +430,11 @@ class ActPost : AppCompatActivity(),
|
|||
cbContentWarning.setOnCheckedChangeListener { _, _ -> showContentWarningEnabled() }
|
||||
|
||||
completionHelper = CompletionHelper(this, pref, appState.handler)
|
||||
completionHelper.attachEditText(formRoot, etContent, false, object : CompletionHelper.Callback2 {
|
||||
completionHelper.attachEditText(
|
||||
formRoot,
|
||||
etContent,
|
||||
false,
|
||||
object : CompletionHelper.Callback2 {
|
||||
override fun onTextUpdate() {
|
||||
updateTextCount()
|
||||
}
|
||||
|
@ -491,6 +462,6 @@ class ActPost : AppCompatActivity(),
|
|||
scrollView.viewTreeObserver.addOnScrollChangedListener(scrollListener)
|
||||
|
||||
etContent.contentMineTypeArray = AttachmentUploader.acceptableMimeTypes.toTypedArray()
|
||||
etContent.commitContentListener = commitContentListener
|
||||
etContent.contentCallback = { addAttachment(it) }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -98,7 +98,7 @@ class ActText : AppCompatActivity() {
|
|||
return true
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
menuInflater.inflate(R.menu.act_text, menu)
|
||||
return super.onCreateOptionsMenu(menu)
|
||||
}
|
||||
|
|
|
@ -348,15 +348,13 @@ class CompletionHelper(
|
|||
}
|
||||
})
|
||||
|
||||
et.setOnSelectionChangeListener(object : MyEditText.OnSelectionChangeListener {
|
||||
override fun onSelectionChanged(selStart: Int, selEnd: Int) {
|
||||
if (selStart != selEnd) {
|
||||
// 範囲選択されてるならポップアップは閉じる
|
||||
log.d("onSelectionChanged: range selected")
|
||||
et.onSelectionChange = { selStart, selEnd ->
|
||||
if (selStart != selEnd) {
|
||||
log.d("onSelectionChange: range selected")
|
||||
closeAcctPopup()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// 全然動いてなさそう…
|
||||
// et.setCustomSelectionActionModeCallback( action_mode_callback );
|
||||
|
|
|
@ -105,7 +105,7 @@ open class TootApiResult(
|
|||
}
|
||||
|
||||
// アカウント作成APIのdetailsを読むため、エラー応答のjsonオブジェクトを保持する
|
||||
var errorJson: JsonObject? = null
|
||||
private var errorJson: JsonObject? = null
|
||||
|
||||
internal fun simplifyErrorHtml(
|
||||
sv: String,
|
||||
|
|
|
@ -379,7 +379,7 @@ class TootInstance(parser: TootParser, src: JsonObject) {
|
|||
val result = Channel<Pair<TootInstance?, TootApiResult?>>()
|
||||
}
|
||||
|
||||
fun queuedRequest(
|
||||
private fun queuedRequest(
|
||||
allowPixelfed: Boolean,
|
||||
get: suspend (cached: TootInstance?) -> Pair<TootInstance?, TootApiResult?>,
|
||||
) = QueuedRequest(allowPixelfed, get)
|
||||
|
|
|
@ -36,7 +36,7 @@ class TootReaction(
|
|||
) {
|
||||
companion object {
|
||||
|
||||
fun appendDomain(name: String, domain: String?) =
|
||||
private fun appendDomain(name: String, domain: String?) =
|
||||
if (domain?.isNotEmpty() == true) {
|
||||
"$name@$domain"
|
||||
} else {
|
||||
|
@ -164,7 +164,7 @@ class TootReaction(
|
|||
}
|
||||
}
|
||||
|
||||
fun chooseUrl() = when {
|
||||
private fun chooseUrl() = when {
|
||||
PrefB.bpDisableEmojiAnimation(App1.pref) -> staticUrl
|
||||
else -> url
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ class ColumnTask_Refresh(
|
|||
private val bSilent: Boolean,
|
||||
val bBottom: Boolean,
|
||||
internal val postedStatusId: EntityId? = null,
|
||||
internal val refreshAfterToot: Int = -1,
|
||||
private val refreshAfterToot: Int = -1,
|
||||
) : ColumnTask(
|
||||
columnArg,
|
||||
if (bBottom) ColumnTaskType.REFRESH_BOTTOM else ColumnTaskType.REFRESH_TOP
|
||||
|
|
|
@ -18,7 +18,7 @@ class UserRelationLoader(val column: Column) {
|
|||
|
||||
val whoSet = HashSet<EntityId>()
|
||||
val acctSet = HashSet<String>()
|
||||
val tagSet = HashSet<String>()
|
||||
private val tagSet = HashSet<String>()
|
||||
|
||||
fun add(whoRef: TootAccountRef?) {
|
||||
add(whoRef?.get())
|
||||
|
|
|
@ -80,7 +80,7 @@ class ColumnViewHolder(
|
|||
lateinit var llColumnHeader: View
|
||||
lateinit var tvColumnIndex: TextView
|
||||
lateinit var tvColumnStatus: TextView
|
||||
lateinit var tvColumnContext: TextView
|
||||
private lateinit var tvColumnContext: TextView
|
||||
lateinit var ivColumnIcon: ImageView
|
||||
lateinit var tvColumnName: TextView
|
||||
|
||||
|
@ -143,7 +143,7 @@ class ColumnViewHolder(
|
|||
lateinit var btnQuickFilterVote: ImageButton
|
||||
|
||||
lateinit var llRefreshError: FrameLayout
|
||||
lateinit var ivRefreshError: ImageView
|
||||
private lateinit var ivRefreshError: ImageView
|
||||
lateinit var tvRefreshError: TextView
|
||||
|
||||
lateinit var llListList: View
|
||||
|
|
|
@ -552,7 +552,7 @@ internal class DlgContextMenu(
|
|||
return true
|
||||
}
|
||||
|
||||
fun onClickUpdateGroup(v: View): Boolean = when (v.id) {
|
||||
private fun onClickUpdateGroup(v: View): Boolean = when (v.id) {
|
||||
R.id.btnGroupStatusCrossAccount -> updateGroup(
|
||||
btnGroupStatusCrossAccount,
|
||||
llGroupStatusCrossAccount,
|
||||
|
|
|
@ -775,7 +775,7 @@ class ItemViewHolder(
|
|||
}
|
||||
}
|
||||
|
||||
fun _LinearLayout.inflateConversationIconOne() =
|
||||
private fun _LinearLayout.inflateConversationIconOne() =
|
||||
myNetworkImageView {
|
||||
scaleType = ImageView.ScaleType.CENTER_CROP
|
||||
}.lparams(dip(24), dip(24)) {
|
||||
|
|
|
@ -324,7 +324,7 @@ fun ItemViewHolder.onClickEnqueteChoice(
|
|||
TootPollsType.Mastodon -> client.request(
|
||||
"/api/v1/polls/${enquete.pollId}/votes",
|
||||
jsonObject {
|
||||
put("choices", jp.juggler.util.jsonArray { add(idx) })
|
||||
put("choices", jsonArray { add(idx) })
|
||||
}.toPostRequestBuilder()
|
||||
)
|
||||
TootPollsType.FriendsNico -> client.request(
|
||||
|
@ -406,7 +406,7 @@ fun ItemViewHolder.sendMultiple(
|
|||
client.request(
|
||||
"/api/v1/polls/${enquete.pollId}/votes",
|
||||
jsonObject {
|
||||
put("choices", jp.juggler.util.jsonArray {
|
||||
put("choices", jsonArray {
|
||||
enquete.items.forEachIndexed { index, choice ->
|
||||
if (choice.checked) add(index)
|
||||
}
|
||||
|
|
|
@ -84,8 +84,8 @@ class StatusButtons(
|
|||
private val colorAccent: Int
|
||||
get() = activity.attrColor(R.attr.colorImageButtonAccent)
|
||||
|
||||
var optionalButtonFirst: View? = null
|
||||
var optionalButtonCount = 0
|
||||
private var optionalButtonFirst: View? = null
|
||||
private var optionalButtonCount = 0
|
||||
var ti: TootInstance? = null
|
||||
|
||||
init {
|
||||
|
|
|
@ -472,7 +472,7 @@ class PushSubscriptionHelper(
|
|||
}
|
||||
}
|
||||
|
||||
suspend fun canSkipSubscriptionMastodon(
|
||||
private suspend fun canSkipSubscriptionMastodon(
|
||||
client: TootApiClient,
|
||||
clientIdentifier: String,
|
||||
endpoint: String,
|
||||
|
|
|
@ -3,7 +3,7 @@ package jp.juggler.subwaytooter.span
|
|||
import android.text.TextPaint
|
||||
import android.text.style.CharacterStyle
|
||||
|
||||
class HighlightSpan(val colorFg: Int, val colorBg: Int) : CharacterStyle() {
|
||||
class HighlightSpan(private val colorFg: Int, val colorBg: Int) : CharacterStyle() {
|
||||
|
||||
override fun updateDrawState(ds: TextPaint) {
|
||||
if (colorFg != 0) ds.color = colorFg
|
||||
|
|
|
@ -31,7 +31,7 @@ class MyClickableSpan(val linkInfo: LinkInfo) : ClickableSpan() {
|
|||
var showLinkUnderline = true
|
||||
}
|
||||
|
||||
val colorFg: Int
|
||||
private val colorFg: Int
|
||||
val colorBg: Int
|
||||
|
||||
init {
|
||||
|
|
|
@ -223,7 +223,7 @@ class AttachmentPicker(
|
|||
}
|
||||
}
|
||||
|
||||
fun performCapture(action: String, errorCaption: String) {
|
||||
private fun performCapture(action: String, errorCaption: String) {
|
||||
try {
|
||||
arCapture.launch(Intent(action))
|
||||
} catch (ex: Throwable) {
|
||||
|
|
|
@ -69,10 +69,10 @@ class PostImpl(
|
|||
|
||||
private var visibilityChecked: TootVisibility? = null
|
||||
|
||||
var bConfirmTag: Boolean = false
|
||||
private var bConfirmTag: Boolean = false
|
||||
var bConfirmAccount: Boolean = false
|
||||
var bConfirmRedraft: Boolean = false
|
||||
var bConfirmTagCharacter: Boolean = false
|
||||
private var bConfirmRedraft: Boolean = false
|
||||
private var bConfirmTagCharacter: Boolean = false
|
||||
|
||||
private val choiceMaxChars = when {
|
||||
account.isMisskey -> 15
|
||||
|
@ -229,9 +229,9 @@ class PostImpl(
|
|||
return true
|
||||
}
|
||||
|
||||
var resultStatus: TootStatus? = null
|
||||
var resultCredentialTmp: TootAccount? = null
|
||||
var resultScheduledStatusSucceeded = false
|
||||
private var resultStatus: TootStatus? = null
|
||||
private var resultCredentialTmp: TootAccount? = null
|
||||
private var resultScheduledStatusSucceeded = false
|
||||
|
||||
private suspend fun getCredential(
|
||||
client: TootApiClient,
|
||||
|
|
|
@ -2,23 +2,53 @@ package jp.juggler.subwaytooter.view
|
|||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import androidx.core.view.inputmethod.EditorInfoCompat
|
||||
import androidx.core.view.inputmethod.InputConnectionCompat
|
||||
import androidx.appcompat.widget.AppCompatEditText
|
||||
import android.net.Uri
|
||||
import android.util.AttributeSet
|
||||
import android.view.MotionEvent
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import android.view.inputmethod.InputConnection
|
||||
|
||||
import android.view.View
|
||||
import androidx.appcompat.widget.AppCompatEditText
|
||||
import androidx.core.view.ContentInfoCompat
|
||||
import androidx.core.view.OnReceiveContentListener
|
||||
import androidx.core.view.ViewCompat
|
||||
import jp.juggler.util.LogCategory
|
||||
|
||||
|
||||
class MyEditText : AppCompatEditText {
|
||||
|
||||
companion object {
|
||||
private val log = LogCategory("MyEditText")
|
||||
val MIME_TYPES = arrayOf("image/*")
|
||||
}
|
||||
|
||||
private var mOnSelectionChangeListener: OnSelectionChangeListener? = null
|
||||
// 選択範囲変更リスナ
|
||||
var onSelectionChange: ((selStart: Int, selEnd: Int) -> Unit)? = null
|
||||
|
||||
// キーボードやDnDから画像を挿入するリスナ
|
||||
var contentCallback: ((Uri) -> Unit)? = null
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
// IMEから画像を送られてくることがあるらしい
|
||||
|
||||
var contentMineTypeArray: Array<String>? = null
|
||||
|
||||
private val receiveContentListener = object : OnReceiveContentListener {
|
||||
override fun onReceiveContent(view: View, payload: ContentInfoCompat): ContentInfoCompat {
|
||||
// 受け付けない状況では何も受け取らずに残りを返す
|
||||
val contentCallback = contentCallback ?: return payload
|
||||
|
||||
val pair = payload.partition { item -> item.uri != null }
|
||||
val uriContent = pair.first
|
||||
val remaining = pair.second
|
||||
if (uriContent != null) {
|
||||
val clip = uriContent.clip
|
||||
for (i in 0 until clip.itemCount) {
|
||||
val uri = clip.getItemAt(i).uri
|
||||
contentCallback(uri)
|
||||
}
|
||||
}
|
||||
return remaining
|
||||
}
|
||||
}
|
||||
|
||||
constructor(context: Context) : super(context)
|
||||
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
|
||||
|
@ -28,20 +58,16 @@ class MyEditText : AppCompatEditText {
|
|||
defStyleAttr
|
||||
)
|
||||
|
||||
init {
|
||||
ViewCompat.setOnReceiveContentListener(this, MIME_TYPES, receiveContentListener)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
// 選択範囲変更イベントをコールバックに渡す
|
||||
|
||||
interface OnSelectionChangeListener {
|
||||
fun onSelectionChanged(selStart: Int, selEnd: Int)
|
||||
}
|
||||
|
||||
fun setOnSelectionChangeListener(listener: OnSelectionChangeListener) {
|
||||
mOnSelectionChangeListener = listener
|
||||
}
|
||||
// 選択範囲変更の傍受
|
||||
|
||||
override fun onSelectionChanged(selStart: Int, selEnd: Int) {
|
||||
super.onSelectionChanged(selStart, selEnd)
|
||||
mOnSelectionChangeListener?.onSelectionChanged(selStart, selEnd)
|
||||
onSelectionChange?.invoke(selStart, selEnd)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
|
@ -61,26 +87,4 @@ class MyEditText : AppCompatEditText {
|
|||
// at android.view.View.dispatchTouchEvent (View.java:9303)
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
// IMEから画像を送られてくることがあるらしい
|
||||
|
||||
var commitContentListener: InputConnectionCompat.OnCommitContentListener? = null
|
||||
var contentMineTypeArray: Array<String>? = null
|
||||
|
||||
override fun onCreateInputConnection(outAttrs: EditorInfo?): InputConnection? {
|
||||
|
||||
log.d("onCreateInputConnection: listener=$commitContentListener")
|
||||
|
||||
val superIc = super.onCreateInputConnection(outAttrs)
|
||||
|
||||
val listener = commitContentListener
|
||||
val mimeArray = contentMineTypeArray
|
||||
return if (listener == null || mimeArray == null || outAttrs == null) {
|
||||
superIc
|
||||
} else {
|
||||
EditorInfoCompat.setContentMimeTypes(outAttrs, mimeArray)
|
||||
superIc?.let { InputConnectionCompat.createWrapper(it, outAttrs, listener) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package jp.juggler.util
|
|||
import android.content.ContentValues
|
||||
import android.database.Cursor
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
import androidx.annotation.IntRange
|
||||
|
||||
/////////////////////////////////////////////////////////////
|
||||
// SQLite にBooleanをそのまま保存することはできないのでInt型との変換が必要になる
|
||||
|
@ -19,16 +20,21 @@ fun Int.i2b() = this != 0
|
|||
// getBoolean(getColumnIndex(key))
|
||||
|
||||
fun Cursor.getInt(key: String) =
|
||||
getInt(getColumnIndex(key))
|
||||
getColumnIndex(key).takeIf { it >= 0 }?.let { getInt(it) }
|
||||
?: error("getInt: missing column named $key")
|
||||
|
||||
fun Cursor.getIntOrNull(idx: Int) =
|
||||
if (isNull(idx)) null else getInt(idx)
|
||||
fun Cursor.getIntOrNull(@IntRange(from = 0) idx: Int) = when {
|
||||
idx < 0 -> error("getIntOrNull: invalid index $idx")
|
||||
isNull(idx) -> null
|
||||
else -> getInt(idx)
|
||||
}
|
||||
|
||||
fun Cursor.getIntOrNull(key: String) =
|
||||
getIntOrNull(getColumnIndex(key))
|
||||
getColumnIndex(key).takeIf { it >= 0 }?.let { getIntOrNull(it) }
|
||||
|
||||
fun Cursor.getLong(key: String) =
|
||||
getLong(getColumnIndex(key))
|
||||
getColumnIndex(key).takeIf { it >= 0 }?.let { getLong(it) }
|
||||
?: error("getLong: missing column named $key")
|
||||
|
||||
//fun Cursor.getLongOrNull(idx:Int) =
|
||||
// if(isNull(idx)) null else getLong(idx)
|
||||
|
@ -37,7 +43,8 @@ fun Cursor.getLong(key: String) =
|
|||
// getLongOrNull(getColumnIndex(key))
|
||||
|
||||
fun Cursor.getString(key: String): String =
|
||||
getString(getColumnIndex(key))
|
||||
getColumnIndex(key).takeIf { it >= 0 }?.let { getString(it)!! }
|
||||
?: error("getString: missing column named $key")
|
||||
|
||||
fun Cursor.getStringOrNull(keyIdx: Int) =
|
||||
if (isNull(keyIdx)) null else getString(keyIdx)
|
||||
|
@ -69,7 +76,7 @@ class ColumnMeta(
|
|||
|
||||
class List(
|
||||
val table: String,
|
||||
val initialVersion: Int,
|
||||
private val initialVersion: Int,
|
||||
var createExtra: () -> Array<String> = { emptyArray() },
|
||||
var deleteBeforeCreate: Boolean = false,
|
||||
) : ArrayList<ColumnMeta>() {
|
||||
|
@ -143,15 +150,9 @@ fun ContentValues.put(key: ColumnMeta, v: Float?) = put(key.name, v)
|
|||
fun ContentValues.put(key: ColumnMeta, v: Double?) = put(key.name, v)
|
||||
fun ContentValues.put(key: ColumnMeta, v: ByteArray?) = put(key.name, v)
|
||||
|
||||
fun Cursor.getInt(key: ColumnMeta) = getInt(getColumnIndex(key.name))
|
||||
|
||||
fun Cursor.getBoolean(key: ColumnMeta) = getInt(key).i2b()
|
||||
fun Cursor.getLong(key: ColumnMeta) = getLong(getColumnIndex(key.name))
|
||||
|
||||
@Suppress("unused")
|
||||
fun Cursor.getIntOrNull(key: ColumnMeta) = getIntOrNull(getColumnIndex(key.name))
|
||||
fun Cursor.getString(key: ColumnMeta): String = getString(getColumnIndex(key.name))
|
||||
fun Cursor.getStringOrNull(key: ColumnMeta): String? {
|
||||
val idx = key.getIndex(this)
|
||||
return if (isNull(idx)) null else getString(idx)
|
||||
}
|
||||
fun Cursor.getInt(key: ColumnMeta) = getInt(key.name)
|
||||
fun Cursor.getBoolean(key: ColumnMeta) = getInt(key.name).i2b()
|
||||
fun Cursor.getLong(key: ColumnMeta) = getLong(key.name)
|
||||
fun Cursor.getIntOrNull(key: ColumnMeta) = getIntOrNull(key.name)
|
||||
fun Cursor.getString(key: ColumnMeta): String = getString(key.name)
|
||||
fun Cursor.getStringOrNull(key: ColumnMeta): String? = getStringOrNull(key.name)
|
||||
|
|
|
@ -23,7 +23,7 @@ class LogCategory(category: String) {
|
|||
///////////////////////////////
|
||||
// string
|
||||
|
||||
fun msg(priority: Int, msg: String): Boolean {
|
||||
private fun msg(priority: Int, msg: String): Boolean {
|
||||
Log.println(priority, tag, msg)
|
||||
return false
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ class LogCategory(category: String) {
|
|||
///////////////////////////////
|
||||
// Resources.getString()
|
||||
|
||||
fun msg(priority: Int, res: Resources, @StringRes stringId: Int, args: Array<out Any?>) =
|
||||
private fun msg(priority: Int, res: Resources, @StringRes stringId: Int, args: Array<out Any?>) =
|
||||
msg(priority, res.getString(stringId, *args))
|
||||
|
||||
fun e(res: Resources, @StringRes stringId: Int, vararg args: Any) =
|
||||
|
@ -58,7 +58,7 @@ class LogCategory(category: String) {
|
|||
///////////////////////////////
|
||||
// Throwable + string
|
||||
|
||||
fun msg(priority: Int, ex: Throwable, caption: String = "exception.") =
|
||||
private fun msg(priority: Int, ex: Throwable, caption: String = "exception.") =
|
||||
msg(priority, ex.withCaption(caption))
|
||||
|
||||
fun e(ex: Throwable, caption: String = "exception") = msg(Log.ERROR, ex, caption)
|
||||
|
|
19
build.gradle
19
build.gradle
|
@ -1,19 +1,22 @@
|
|||
buildscript {
|
||||
|
||||
ext.min_sdk_version = 21
|
||||
ext.target_sdk_version = 30
|
||||
ext.compile_sdk_version = 30
|
||||
ext.target_sdk_version = 31
|
||||
ext.compile_sdk_version = 31
|
||||
|
||||
ext.appcompat_version='1.3.0'
|
||||
ext.lifecycle_version='2.3.1'
|
||||
ext.appcompat_version='1.3.1'
|
||||
ext.lifecycle_version="2.4.0-rc01"
|
||||
ext.arch_version = "2.1.0"
|
||||
|
||||
ext.kotlin_version = '1.5.20'
|
||||
ext.kotlinx_coroutines_version = '1.5.0'
|
||||
ext.kotlin_version = '1.5.31'
|
||||
ext.kotlinx_coroutines_version = '1.5.2'
|
||||
ext.anko_version='0.10.8'
|
||||
|
||||
ext.junit_version='4.13.2'
|
||||
|
||||
ext.detekt_version='1.18.0'
|
||||
ext.detekt_version='1.18.1'
|
||||
|
||||
ext.compose_version = '1.0.4'
|
||||
|
||||
repositories {
|
||||
google()
|
||||
|
@ -21,7 +24,7 @@ buildscript {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:4.2.2'
|
||||
classpath 'com.android.tools.build:gradle:7.0.3'
|
||||
classpath 'com.google.gms:google-services:4.3.10'
|
||||
|
||||
//noinspection DifferentKotlinGradleVersion
|
||||
|
|
|
@ -33,11 +33,11 @@ import androidx.annotation.NonNull;
|
|||
*/
|
||||
class AlphaPatternDrawable extends Drawable {
|
||||
|
||||
private int rectangleSize;
|
||||
private final int rectangleSize;
|
||||
|
||||
private Paint paint = new Paint();
|
||||
private Paint paintWhite = new Paint();
|
||||
private Paint paintGray = new Paint();
|
||||
private final Paint paint = new Paint();
|
||||
private final Paint paintWhite = new Paint();
|
||||
private final Paint paintGray = new Paint();
|
||||
|
||||
private int numRectanglesHorizontal;
|
||||
private int numRectanglesVertical;
|
||||
|
@ -55,25 +55,30 @@ class AlphaPatternDrawable extends Drawable {
|
|||
paintGray.setColor(0xFFCBCBCB);
|
||||
}
|
||||
|
||||
@Override public void draw( @NonNull Canvas canvas ){
|
||||
@Override
|
||||
public void draw(@NonNull Canvas canvas) {
|
||||
if (bitmap != null && !bitmap.isRecycled()) {
|
||||
canvas.drawBitmap(bitmap, null, getBounds(), paint);
|
||||
}
|
||||
}
|
||||
|
||||
@Override public int getOpacity(){
|
||||
@Override
|
||||
public int getOpacity() {
|
||||
return PixelFormat.UNKNOWN;
|
||||
}
|
||||
|
||||
@Override public void setAlpha( int alpha ){
|
||||
@Override
|
||||
public void setAlpha(int alpha) {
|
||||
throw new UnsupportedOperationException("Alpha is not supported by this drawable.");
|
||||
}
|
||||
|
||||
@Override public void setColorFilter( ColorFilter cf ){
|
||||
@Override
|
||||
public void setColorFilter(ColorFilter cf) {
|
||||
throw new UnsupportedOperationException("ColorFilter is not supported by this drawable.");
|
||||
}
|
||||
|
||||
@Override protected void onBoundsChange( Rect bounds ){
|
||||
@Override
|
||||
protected void onBoundsChange(Rect bounds) {
|
||||
super.onBoundsChange(bounds);
|
||||
int height = bounds.height();
|
||||
int width = bounds.width();
|
||||
|
|
|
@ -19,18 +19,19 @@ package com.jrummyapps.android.colorpicker;
|
|||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.PorterDuff;
|
||||
import androidx.core.graphics.ColorUtils;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import androidx.core.graphics.ColorUtils;
|
||||
|
||||
class ColorPaletteAdapter extends BaseAdapter {
|
||||
|
||||
/*package*/ final OnColorSelectedListener listener;
|
||||
/*package*/ final int[] colors;
|
||||
/*package*/ int selectedPosition;
|
||||
/*package*/ int colorShape;
|
||||
/*package*/ final int colorShape;
|
||||
|
||||
ColorPaletteAdapter(OnColorSelectedListener listener,
|
||||
int[] colors,
|
||||
|
@ -42,19 +43,23 @@ class ColorPaletteAdapter extends BaseAdapter {
|
|||
this.colorShape = colorShape;
|
||||
}
|
||||
|
||||
@Override public int getCount() {
|
||||
@Override
|
||||
public int getCount() {
|
||||
return colors.length;
|
||||
}
|
||||
|
||||
@Override public Object getItem(int position) {
|
||||
@Override
|
||||
public Object getItem(int position) {
|
||||
return colors[position];
|
||||
}
|
||||
|
||||
@Override public long getItemId(int position) {
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override public View getView(int position, View convertView, ViewGroup parent) {
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
final ViewHolder holder;
|
||||
if (convertView == null) {
|
||||
holder = new ViewHolder(parent.getContext());
|
||||
|
@ -78,10 +83,10 @@ class ColorPaletteAdapter extends BaseAdapter {
|
|||
|
||||
private final class ViewHolder {
|
||||
|
||||
View view;
|
||||
ColorPanelView colorPanelView;
|
||||
ImageView imageView;
|
||||
int originalBorderColor;
|
||||
final View view;
|
||||
final ColorPanelView colorPanelView;
|
||||
final ImageView imageView;
|
||||
final int originalBorderColor;
|
||||
|
||||
ViewHolder(Context context) {
|
||||
int layoutResId;
|
||||
|
@ -91,8 +96,8 @@ class ColorPaletteAdapter extends BaseAdapter {
|
|||
layoutResId = R.layout.cpv_color_item_circle;
|
||||
}
|
||||
view = View.inflate(context, layoutResId, null);
|
||||
colorPanelView = (ColorPanelView) view.findViewById(R.id.cpv_color_panel_view);
|
||||
imageView = (ImageView) view.findViewById(R.id.cpv_color_image_view);
|
||||
colorPanelView = view.findViewById(R.id.cpv_color_panel_view);
|
||||
imageView = view.findViewById(R.id.cpv_color_image_view);
|
||||
originalBorderColor = colorPanelView.getBorderColor();
|
||||
view.setTag(this);
|
||||
}
|
||||
|
@ -117,20 +122,16 @@ class ColorPaletteAdapter extends BaseAdapter {
|
|||
}
|
||||
|
||||
private void setOnClickListener(final int position) {
|
||||
colorPanelView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override public void onClick(View v) {
|
||||
colorPanelView.setOnClickListener(v -> {
|
||||
if (selectedPosition != position) {
|
||||
selectedPosition = position;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
listener.onColorSelected(colors[position]);
|
||||
}
|
||||
});
|
||||
colorPanelView.setOnLongClickListener(new View.OnLongClickListener() {
|
||||
@Override public boolean onLongClick(View v) {
|
||||
colorPanelView.setOnLongClickListener(v -> {
|
||||
colorPanelView.showHint();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -141,22 +141,22 @@ public class ColorPanelView extends View {
|
|||
} else if (shape == ColorShape.CIRCLE) {
|
||||
final int outerRadius = getMeasuredWidth() / 2;
|
||||
if (borderWidthPx > 0) {
|
||||
canvas.drawCircle(getMeasuredWidth() / 2,
|
||||
getMeasuredHeight() / 2,
|
||||
canvas.drawCircle(getMeasuredWidth() / 2f,
|
||||
getMeasuredHeight() / 2f,
|
||||
outerRadius,
|
||||
borderPaint);
|
||||
}
|
||||
if (Color.alpha(color) < 255) {
|
||||
canvas.drawCircle(getMeasuredWidth() / 2,
|
||||
getMeasuredHeight() / 2,
|
||||
canvas.drawCircle(getMeasuredWidth() / 2f,
|
||||
getMeasuredHeight() / 2f,
|
||||
outerRadius - borderWidthPx, alphaPaint);
|
||||
}
|
||||
if (showOldColor) {
|
||||
canvas.drawArc(centerRect, 90, 180, true, originalPaint);
|
||||
canvas.drawArc(centerRect, 270, 180, true, colorPaint);
|
||||
} else {
|
||||
canvas.drawCircle(getMeasuredWidth() / 2,
|
||||
getMeasuredHeight() / 2,
|
||||
canvas.drawCircle(getMeasuredWidth() / 2f,
|
||||
getMeasuredHeight() / 2f,
|
||||
outerRadius - borderWidthPx,
|
||||
colorPaint);
|
||||
}
|
||||
|
@ -169,6 +169,7 @@ public class ColorPanelView extends View {
|
|||
int height = MeasureSpec.getSize(heightMeasureSpec);
|
||||
setMeasuredDimension(width, height);
|
||||
} else if (shape == ColorShape.CIRCLE) {
|
||||
//noinspection SuspiciousNameCombination
|
||||
super.onMeasure(widthMeasureSpec, widthMeasureSpec);
|
||||
setMeasuredDimension(getMeasuredWidth(), getMeasuredWidth());
|
||||
} else {
|
||||
|
|
|
@ -19,19 +19,12 @@ package com.jrummyapps.android.colorpicker;
|
|||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.app.DialogFragment;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.os.Bundle;
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.core.graphics.ColorUtils;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import android.text.Editable;
|
||||
import android.text.InputFilter;
|
||||
import android.text.TextWatcher;
|
||||
|
@ -50,6 +43,7 @@ import android.widget.ImageView;
|
|||
import android.widget.LinearLayout;
|
||||
import android.widget.SeekBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.jrummyapps.android.colorpicker.ColorPickerView.OnColorChangedListener;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
|
@ -57,6 +51,15 @@ import java.lang.annotation.RetentionPolicy;
|
|||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.core.graphics.ColorUtils;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
|
||||
/**
|
||||
* <p>A dialog to pick a color.</p>
|
||||
*
|
||||
|
@ -68,7 +71,9 @@ import java.util.Locale;
|
|||
* ColorPickerDialog.newBuilder().show(activity);
|
||||
* </pre>
|
||||
*/
|
||||
public class ColorPickerDialog extends DialogFragment implements OnTouchListener, OnColorChangedListener, TextWatcher {
|
||||
public class ColorPickerDialog
|
||||
extends DialogFragment
|
||||
implements OnTouchListener, OnColorChangedListener, TextWatcher {
|
||||
|
||||
private static final String ARG_ID = "id";
|
||||
private static final String ARG_TYPE = "dialogType";
|
||||
|
@ -123,7 +128,8 @@ public class ColorPickerDialog extends DialogFragment implements OnTouchListener
|
|||
ColorPickerDialogListener colorPickerDialogListener;
|
||||
FrameLayout rootView;
|
||||
int[] presets;
|
||||
@ColorInt int color;
|
||||
@ColorInt
|
||||
int color;
|
||||
int dialogType;
|
||||
int dialogId;
|
||||
boolean showColorShades;
|
||||
|
@ -142,50 +148,58 @@ public class ColorPickerDialog extends DialogFragment implements OnTouchListener
|
|||
boolean showAlphaSlider;
|
||||
private boolean fromEditText;
|
||||
|
||||
@Override public void onAttach(Activity activity) {
|
||||
super.onAttach(activity);
|
||||
if (colorPickerDialogListener == null && activity instanceof ColorPickerDialogListener) {
|
||||
colorPickerDialogListener = (ColorPickerDialogListener) activity;
|
||||
@Override
|
||||
public void onAttach(@NonNull Context context) {
|
||||
super.onAttach(context);
|
||||
if (colorPickerDialogListener == null && context instanceof ColorPickerDialogListener) {
|
||||
colorPickerDialogListener = (ColorPickerDialogListener) context;
|
||||
}
|
||||
}
|
||||
|
||||
@Override public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
dialogId = getArguments().getInt(ARG_ID);
|
||||
showAlphaSlider = getArguments().getBoolean(ARG_ALPHA);
|
||||
showColorShades = getArguments().getBoolean(ARG_SHOW_COLOR_SHADES);
|
||||
colorShape = getArguments().getInt(ARG_COLOR_SHAPE);
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
Bundle args = getArguments();
|
||||
if (args == null) throw new RuntimeException("onCreateDialog: args is null");
|
||||
Context context = getContext();
|
||||
if (context == null) throw new RuntimeException("onCreateDialog: context is null");
|
||||
Activity activity = getActivity();
|
||||
if (activity == null) throw new RuntimeException("onCreateDialog: activity is null");
|
||||
|
||||
dialogId = args.getInt(ARG_ID);
|
||||
showAlphaSlider = args.getBoolean(ARG_ALPHA);
|
||||
showColorShades = args.getBoolean(ARG_SHOW_COLOR_SHADES);
|
||||
colorShape = args.getInt(ARG_COLOR_SHAPE);
|
||||
if (savedInstanceState == null) {
|
||||
color = getArguments().getInt(ARG_COLOR);
|
||||
dialogType = getArguments().getInt(ARG_TYPE);
|
||||
color = args.getInt(ARG_COLOR);
|
||||
dialogType = args.getInt(ARG_TYPE);
|
||||
} else {
|
||||
color = savedInstanceState.getInt(ARG_COLOR);
|
||||
dialogType = savedInstanceState.getInt(ARG_TYPE);
|
||||
}
|
||||
|
||||
rootView = new FrameLayout(getActivity());
|
||||
|
||||
rootView = new FrameLayout(activity);
|
||||
if (dialogType == TYPE_CUSTOM) {
|
||||
rootView.addView(createPickerView());
|
||||
} else if (dialogType == TYPE_PRESETS) {
|
||||
rootView.addView(createPresetsView());
|
||||
}
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity())
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(activity)
|
||||
.setView(rootView)
|
||||
.setPositiveButton(R.string.cpv_select, new DialogInterface.OnClickListener() {
|
||||
@Override public void onClick(DialogInterface dialog, int which) {
|
||||
colorPickerDialogListener.onColorSelected(dialogId, color);
|
||||
}
|
||||
});
|
||||
.setPositiveButton(R.string.cpv_select, (dialog, which) ->
|
||||
colorPickerDialogListener.onColorSelected(dialogId, color));
|
||||
|
||||
int dialogTitleStringRes = getArguments().getInt(ARG_DIALOG_TITLE);
|
||||
int dialogTitleStringRes = args.getInt(ARG_DIALOG_TITLE);
|
||||
if (dialogTitleStringRes != 0) {
|
||||
builder.setTitle(dialogTitleStringRes);
|
||||
}
|
||||
|
||||
int neutralButtonStringRes;
|
||||
if (dialogType == TYPE_CUSTOM && getArguments().getBoolean(ARG_ALLOW_PRESETS)) {
|
||||
if (dialogType == TYPE_CUSTOM && args.getBoolean(ARG_ALLOW_PRESETS)) {
|
||||
neutralButtonStringRes = R.string.cpv_presets;
|
||||
} else if (dialogType == TYPE_PRESETS && getArguments().getBoolean(ARG_ALLOW_CUSTOM)) {
|
||||
} else if (dialogType == TYPE_PRESETS && args.getBoolean(ARG_ALLOW_CUSTOM)) {
|
||||
neutralButtonStringRes = R.string.cpv_custom;
|
||||
} else {
|
||||
neutralButtonStringRes = 0;
|
||||
|
@ -198,21 +212,22 @@ public class ColorPickerDialog extends DialogFragment implements OnTouchListener
|
|||
return builder.create();
|
||||
}
|
||||
|
||||
@Override public void onStart() {
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
AlertDialog dialog = (AlertDialog) getDialog();
|
||||
|
||||
// http://stackoverflow.com/a/16972670/1048340
|
||||
//noinspection ConstantConditions
|
||||
dialog.getWindow()
|
||||
.clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
|
||||
.clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
|
||||
WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
|
||||
dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
|
||||
|
||||
// Do not dismiss the dialog when clicking the neutral button.
|
||||
Button neutralButton = dialog.getButton(AlertDialog.BUTTON_NEUTRAL);
|
||||
if (neutralButton != null) {
|
||||
neutralButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override public void onClick(View v) {
|
||||
neutralButton.setOnClickListener(v -> {
|
||||
rootView.removeAllViews();
|
||||
switch (dialogType) {
|
||||
case TYPE_CUSTOM:
|
||||
|
@ -225,17 +240,18 @@ public class ColorPickerDialog extends DialogFragment implements OnTouchListener
|
|||
((Button) v).setText(R.string.cpv_presets);
|
||||
rootView.addView(createPickerView());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void onDismiss(DialogInterface dialog) {
|
||||
@Override
|
||||
public void onDismiss(@NonNull DialogInterface dialog) {
|
||||
super.onDismiss(dialog);
|
||||
colorPickerDialogListener.onDialogDismissed(dialogId);
|
||||
}
|
||||
|
||||
@Override public void onSaveInstanceState(Bundle outState) {
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
outState.putInt(ARG_COLOR, color);
|
||||
outState.putInt(ARG_TYPE, dialogType);
|
||||
super.onSaveInstanceState(outState);
|
||||
|
@ -244,8 +260,7 @@ public class ColorPickerDialog extends DialogFragment implements OnTouchListener
|
|||
/**
|
||||
* Set the callback
|
||||
*
|
||||
* @param colorPickerDialogListener
|
||||
* The callback invoked when a color is selected or the dialog is dismissed.
|
||||
* @param colorPickerDialogListener The callback invoked when a color is selected or the dialog is dismissed.
|
||||
*/
|
||||
public void setColorPickerDialogListener(ColorPickerDialogListener colorPickerDialogListener) {
|
||||
this.colorPickerDialogListener = colorPickerDialogListener;
|
||||
|
@ -254,6 +269,11 @@ public class ColorPickerDialog extends DialogFragment implements OnTouchListener
|
|||
// region Custom Picker
|
||||
|
||||
View createPickerView() {
|
||||
Bundle args = getArguments();
|
||||
if (args == null) throw new RuntimeException("createPickerView: args is null");
|
||||
FragmentActivity activity = getActivity();
|
||||
if (activity == null) throw new RuntimeException("createPickerView: activity is null");
|
||||
|
||||
View contentView = View.inflate(getActivity(), R.layout.cpv_dialog_color_picker, null);
|
||||
colorPicker = contentView.findViewById(R.id.cpv_color_picker_view);
|
||||
ColorPanelView oldColorPanel = contentView.findViewById(R.id.cpv_color_panel_old);
|
||||
|
@ -263,8 +283,10 @@ public class ColorPickerDialog extends DialogFragment implements OnTouchListener
|
|||
|
||||
try {
|
||||
final TypedValue value = new TypedValue();
|
||||
TypedArray typedArray =
|
||||
getActivity().obtainStyledAttributes(value.data, new int[]{android.R.attr.textColorPrimary});
|
||||
TypedArray typedArray = activity.obtainStyledAttributes(
|
||||
value.data,
|
||||
new int[]{android.R.attr.textColorPrimary}
|
||||
);
|
||||
int arrowColor = typedArray.getColor(0, Color.BLACK);
|
||||
typedArray.recycle();
|
||||
arrowRight.setColorFilter(arrowColor);
|
||||
|
@ -272,7 +294,7 @@ public class ColorPickerDialog extends DialogFragment implements OnTouchListener
|
|||
}
|
||||
|
||||
colorPicker.setAlphaSliderVisible(showAlphaSlider);
|
||||
oldColorPanel.setColor(getArguments().getInt(ARG_COLOR));
|
||||
oldColorPanel.setColor(args.getInt(ARG_COLOR));
|
||||
colorPicker.setColor(color, true);
|
||||
newColorPanel.setColor(color);
|
||||
setHex(color);
|
||||
|
@ -281,37 +303,35 @@ public class ColorPickerDialog extends DialogFragment implements OnTouchListener
|
|||
hexEditText.setFilters(new InputFilter[]{new InputFilter.LengthFilter(6)});
|
||||
}
|
||||
|
||||
newColorPanel.setOnClickListener(new View.OnClickListener() {
|
||||
@Override public void onClick(View v) {
|
||||
newColorPanel.setOnClickListener(v -> {
|
||||
if (newColorPanel.getColor() == color) {
|
||||
colorPickerDialogListener.onColorSelected(dialogId, color);
|
||||
dismiss();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
contentView.setOnTouchListener(this);
|
||||
colorPicker.setOnColorChangedListener(this);
|
||||
hexEditText.addTextChangedListener(this);
|
||||
|
||||
hexEditText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
|
||||
@Override
|
||||
public void onFocusChange(View v, boolean hasFocus) {
|
||||
hexEditText.setOnFocusChangeListener((v, hasFocus) -> {
|
||||
if (hasFocus) {
|
||||
InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
InputMethodManager imm = (InputMethodManager) getActivity()
|
||||
.getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
if (imm != null) imm.showSoftInput(hexEditText, InputMethodManager.SHOW_IMPLICIT);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return contentView;
|
||||
}
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
@Override public boolean onTouch( View v, MotionEvent event) {
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
if (v != hexEditText && hexEditText.hasFocus()) {
|
||||
hexEditText.clearFocus();
|
||||
InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
InputMethodManager imm = (InputMethodManager) getActivity()
|
||||
.getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
if (imm != null) imm.hideSoftInputFromWindow(hexEditText.getWindowToken(), 0);
|
||||
hexEditText.clearFocus();
|
||||
return true;
|
||||
|
@ -319,13 +339,15 @@ public class ColorPickerDialog extends DialogFragment implements OnTouchListener
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override public void onColorChanged(int newColor) {
|
||||
@Override
|
||||
public void onColorChanged(int newColor) {
|
||||
color = newColor;
|
||||
newColorPanel.setColor(newColor);
|
||||
if (!fromEditText) {
|
||||
setHex(newColor);
|
||||
if (hexEditText.hasFocus()) {
|
||||
InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
InputMethodManager imm = (InputMethodManager) getActivity()
|
||||
.getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
if (imm != null) imm.hideSoftInputFromWindow(hexEditText.getWindowToken(), 0);
|
||||
hexEditText.clearFocus();
|
||||
}
|
||||
|
@ -333,15 +355,18 @@ public class ColorPickerDialog extends DialogFragment implements OnTouchListener
|
|||
fromEditText = false;
|
||||
}
|
||||
|
||||
@Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
|
||||
}
|
||||
|
||||
@Override public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
|
||||
}
|
||||
|
||||
@Override public void afterTextChanged(Editable s) {
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
if (hexEditText.isFocused()) {
|
||||
try {
|
||||
int color = parseColorString(s.toString());
|
||||
|
@ -437,8 +462,7 @@ public class ColorPickerDialog extends DialogFragment implements OnTouchListener
|
|||
contentView.findViewById(R.id.shades_divider).setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
adapter = new ColorPaletteAdapter(new ColorPaletteAdapter.OnColorSelectedListener() {
|
||||
@Override public void onColorSelected(int newColor) {
|
||||
adapter = new ColorPaletteAdapter(newColor -> {
|
||||
if (color == newColor) {
|
||||
colorPickerDialogListener.onColorSelected(dialogId, color);
|
||||
dismiss();
|
||||
|
@ -448,7 +472,6 @@ public class ColorPickerDialog extends DialogFragment implements OnTouchListener
|
|||
if (showColorShades) {
|
||||
createColorShades(color);
|
||||
}
|
||||
}
|
||||
}, presets, getSelectedItemPosition(), colorShape);
|
||||
|
||||
gridView.setAdapter(adapter);
|
||||
|
@ -468,7 +491,8 @@ public class ColorPickerDialog extends DialogFragment implements OnTouchListener
|
|||
presets = getArguments().getIntArray(ARG_PRESETS);
|
||||
if (presets == null) presets = MATERIAL_COLORS;
|
||||
boolean isMaterialColors = presets == MATERIAL_COLORS;
|
||||
presets = Arrays.copyOf(presets, presets.length); // don't update the original array when modifying alpha
|
||||
presets = Arrays.copyOf(presets, presets.length);
|
||||
// don't update the original array when modifying alpha
|
||||
if (alpha != 255) {
|
||||
// add alpha to the presets
|
||||
for (int i = 0; i < presets.length; i++) {
|
||||
|
@ -501,7 +525,8 @@ public class ColorPickerDialog extends DialogFragment implements OnTouchListener
|
|||
return;
|
||||
}
|
||||
|
||||
final int horizontalPadding = getResources().getDimensionPixelSize(R.dimen.cpv_item_horizontal_padding);
|
||||
final int horizontalPadding = getResources()
|
||||
.getDimensionPixelSize(R.dimen.cpv_item_horizontal_padding);
|
||||
|
||||
for (final int colorShade : colorShades) {
|
||||
int layoutResId;
|
||||
|
@ -514,21 +539,19 @@ public class ColorPickerDialog extends DialogFragment implements OnTouchListener
|
|||
final View view = View.inflate(getActivity(), layoutResId, null);
|
||||
final ColorPanelView colorPanelView = view.findViewById(R.id.cpv_color_panel_view);
|
||||
|
||||
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) colorPanelView.getLayoutParams();
|
||||
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) colorPanelView
|
||||
.getLayoutParams();
|
||||
params.leftMargin = params.rightMargin = horizontalPadding;
|
||||
colorPanelView.setLayoutParams(params);
|
||||
colorPanelView.setColor(colorShade);
|
||||
shadesLayout.addView(view);
|
||||
|
||||
colorPanelView.post(new Runnable() {
|
||||
@Override public void run() {
|
||||
colorPanelView.post(() -> {
|
||||
// The color is black when rotating the dialog. This is a dirty fix. WTF!?
|
||||
colorPanelView.setColor(colorShade);
|
||||
}
|
||||
});
|
||||
|
||||
colorPanelView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override public void onClick(View v) {
|
||||
colorPanelView.setOnClickListener(v -> {
|
||||
if (v.getTag() instanceof Boolean && (Boolean) v.getTag()) {
|
||||
colorPickerDialogListener.onColorSelected(dialogId, ColorPickerDialog.this.color);
|
||||
dismiss();
|
||||
|
@ -549,13 +572,10 @@ public class ColorPickerDialog extends DialogFragment implements OnTouchListener
|
|||
}
|
||||
cpv.setTag(cpv == v);
|
||||
}
|
||||
}
|
||||
});
|
||||
colorPanelView.setOnLongClickListener(new View.OnLongClickListener() {
|
||||
@Override public boolean onLongClick(View v) {
|
||||
colorPanelView.setOnLongClickListener(v -> {
|
||||
colorPanelView.showHint();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -599,7 +619,8 @@ public class ColorPickerDialog extends DialogFragment implements OnTouchListener
|
|||
int percentage = (int) ((double) progress * 100 / 255);
|
||||
transparencyPercText.setText(String.format(Locale.ENGLISH, "%d%%", percentage));
|
||||
transparencySeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
|
||||
@Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||
@Override
|
||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||
int percentage = (int) ((double) progress * 100 / 255);
|
||||
transparencyPercText.setText(String.format(Locale.ENGLISH, "%d%%", percentage));
|
||||
int alpha = 255 - progress;
|
||||
|
@ -649,11 +670,13 @@ public class ColorPickerDialog extends DialogFragment implements OnTouchListener
|
|||
color = Color.argb(alpha, red, green, blue);
|
||||
}
|
||||
|
||||
@Override public void onStartTrackingTouch(SeekBar seekBar) {
|
||||
@Override
|
||||
public void onStartTrackingTouch(SeekBar seekBar) {
|
||||
|
||||
}
|
||||
|
||||
@Override public void onStopTrackingTouch(SeekBar seekBar) {
|
||||
@Override
|
||||
public void onStopTrackingTouch(SeekBar seekBar) {
|
||||
|
||||
}
|
||||
});
|
||||
|
@ -667,14 +690,14 @@ public class ColorPickerDialog extends DialogFragment implements OnTouchListener
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (!present) {
|
||||
if (present) {
|
||||
return array;
|
||||
}
|
||||
int[] newArray = new int[array.length + 1];
|
||||
newArray[0] = value;
|
||||
System.arraycopy(array, 0, newArray, 1, newArray.length - 1);
|
||||
return newArray;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
private int[] pushIfNotExists(int[] array, int value) {
|
||||
boolean present = false;
|
||||
|
@ -706,18 +729,23 @@ public class ColorPickerDialog extends DialogFragment implements OnTouchListener
|
|||
|
||||
// region Builder
|
||||
|
||||
@SuppressWarnings("WeakerAccess") public static final class Builder {
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public static final class Builder {
|
||||
|
||||
@StringRes int dialogTitle = R.string.cpv_default_title;
|
||||
@DialogType int dialogType = TYPE_PRESETS;
|
||||
@StringRes
|
||||
int dialogTitle = R.string.cpv_default_title;
|
||||
@DialogType
|
||||
int dialogType = TYPE_PRESETS;
|
||||
int[] presets = MATERIAL_COLORS;
|
||||
@ColorInt int color = Color.BLACK;
|
||||
@ColorInt
|
||||
int color = Color.BLACK;
|
||||
int dialogId = 0;
|
||||
boolean showAlphaSlider = false;
|
||||
boolean allowPresets = true;
|
||||
boolean allowCustom = true;
|
||||
boolean showColorShades = true;
|
||||
@ColorShape int colorShape = ColorShape.CIRCLE;
|
||||
@ColorShape
|
||||
int colorShape = ColorShape.CIRCLE;
|
||||
|
||||
/*package*/ Builder() {
|
||||
|
||||
|
@ -726,8 +754,7 @@ public class ColorPickerDialog extends DialogFragment implements OnTouchListener
|
|||
/**
|
||||
* Set the dialog title string resource id
|
||||
*
|
||||
* @param dialogTitle
|
||||
* The string resource used for the dialog title
|
||||
* @param dialogTitle The string resource used for the dialog title
|
||||
* @return This builder object for chaining method calls
|
||||
*/
|
||||
public Builder setDialogTitle(@StringRes int dialogTitle) {
|
||||
|
@ -738,8 +765,7 @@ public class ColorPickerDialog extends DialogFragment implements OnTouchListener
|
|||
/**
|
||||
* Set which dialog view to show.
|
||||
*
|
||||
* @param dialogType
|
||||
* Either {@link ColorPickerDialog#TYPE_CUSTOM} or {@link ColorPickerDialog#TYPE_PRESETS}.
|
||||
* @param dialogType Either {@link ColorPickerDialog#TYPE_CUSTOM} or {@link ColorPickerDialog#TYPE_PRESETS}.
|
||||
* @return This builder object for chaining method calls
|
||||
*/
|
||||
public Builder setDialogType(@DialogType int dialogType) {
|
||||
|
@ -750,8 +776,7 @@ public class ColorPickerDialog extends DialogFragment implements OnTouchListener
|
|||
/**
|
||||
* Set the colors used for the presets
|
||||
*
|
||||
* @param presets
|
||||
* An array of color ints.
|
||||
* @param presets An array of color ints.
|
||||
* @return This builder object for chaining method calls
|
||||
*/
|
||||
public Builder setPresets(@NonNull int[] presets) {
|
||||
|
@ -762,8 +787,7 @@ public class ColorPickerDialog extends DialogFragment implements OnTouchListener
|
|||
/**
|
||||
* Set the original color
|
||||
*
|
||||
* @param color
|
||||
* The default color for the color picker
|
||||
* @param color The default color for the color picker
|
||||
* @return This builder object for chaining method calls
|
||||
*/
|
||||
public Builder setColor(int color) {
|
||||
|
@ -774,8 +798,7 @@ public class ColorPickerDialog extends DialogFragment implements OnTouchListener
|
|||
/**
|
||||
* Set the dialog id used for callbacks
|
||||
*
|
||||
* @param dialogId
|
||||
* The id that is sent back to the {@link ColorPickerDialogListener}.
|
||||
* @param dialogId The id that is sent back to the {@link ColorPickerDialogListener}.
|
||||
* @return This builder object for chaining method calls
|
||||
*/
|
||||
public Builder setDialogId(int dialogId) {
|
||||
|
@ -786,8 +809,8 @@ public class ColorPickerDialog extends DialogFragment implements OnTouchListener
|
|||
/**
|
||||
* Show the alpha slider
|
||||
*
|
||||
* @param showAlphaSlider
|
||||
* {@code true} to show the alpha slider. Currently only supported with the {@link ColorPickerView}.
|
||||
* @param showAlphaSlider {@code true} to show the alpha slider. Currently only supported with
|
||||
* the {@link ColorPickerView}.
|
||||
* @return This builder object for chaining method calls
|
||||
*/
|
||||
public Builder setShowAlphaSlider(boolean showAlphaSlider) {
|
||||
|
@ -798,8 +821,7 @@ public class ColorPickerDialog extends DialogFragment implements OnTouchListener
|
|||
/**
|
||||
* Show/Hide a neutral button to select preset colors.
|
||||
*
|
||||
* @param allowPresets
|
||||
* {@code false} to disable showing the presets button.
|
||||
* @param allowPresets {@code false} to disable showing the presets button.
|
||||
* @return This builder object for chaining method calls
|
||||
*/
|
||||
public Builder setAllowPresets(boolean allowPresets) {
|
||||
|
@ -810,8 +832,7 @@ public class ColorPickerDialog extends DialogFragment implements OnTouchListener
|
|||
/**
|
||||
* Show/Hide the neutral button to select a custom color.
|
||||
*
|
||||
* @param allowCustom
|
||||
* {@code false} to disable showing the custom button.
|
||||
* @param allowCustom {@code false} to disable showing the custom button.
|
||||
* @return This builder object for chaining method calls
|
||||
*/
|
||||
public Builder setAllowCustom(boolean allowCustom) {
|
||||
|
@ -822,8 +843,7 @@ public class ColorPickerDialog extends DialogFragment implements OnTouchListener
|
|||
/**
|
||||
* Show/Hide the color shades in the presets picker
|
||||
*
|
||||
* @param showColorShades
|
||||
* {@code false} to hide the color shades.
|
||||
* @param showColorShades {@code false} to hide the color shades.
|
||||
* @return This builder object for chaining method calls
|
||||
*/
|
||||
public Builder setShowColorShades(boolean showColorShades) {
|
||||
|
@ -834,8 +854,7 @@ public class ColorPickerDialog extends DialogFragment implements OnTouchListener
|
|||
/**
|
||||
* Set the shape of the color panel view.
|
||||
*
|
||||
* @param colorShape
|
||||
* Either {@link ColorShape#CIRCLE} or {@link ColorShape#SQUARE}.
|
||||
* @param colorShape Either {@link ColorShape#CIRCLE} or {@link ColorShape#SQUARE}.
|
||||
* @return This builder object for chaining method calls
|
||||
*/
|
||||
public Builder setColorShape(int colorShape) {
|
||||
|
@ -847,7 +866,7 @@ public class ColorPickerDialog extends DialogFragment implements OnTouchListener
|
|||
* Create the {@link ColorPickerDialog} instance.
|
||||
*
|
||||
* @return A new {@link ColorPickerDialog}.
|
||||
* @see #show(Activity)
|
||||
* @see #show(FragmentActivity)
|
||||
*/
|
||||
public ColorPickerDialog create() {
|
||||
ColorPickerDialog dialog = new ColorPickerDialog();
|
||||
|
@ -869,13 +888,11 @@ public class ColorPickerDialog extends DialogFragment implements OnTouchListener
|
|||
/**
|
||||
* Create and show the {@link ColorPickerDialog} created with this builder.
|
||||
*
|
||||
* @param activity
|
||||
* The current activity.
|
||||
* @param activity The current activity.
|
||||
*/
|
||||
public void show(Activity activity) {
|
||||
create().show(activity.getFragmentManager(), "color-picker-dialog");
|
||||
public void show(FragmentActivity activity) {
|
||||
create().show(activity.getSupportFragmentManager(), "color-picker-dialog");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
|
|
|
@ -159,7 +159,8 @@ public class ColorPickerView extends View {
|
|||
init(context, attrs);
|
||||
}
|
||||
|
||||
@Override public Parcelable onSaveInstanceState(){
|
||||
@Override
|
||||
public Parcelable onSaveInstanceState() {
|
||||
Bundle state = new Bundle();
|
||||
state.putParcelable("instanceState", super.onSaveInstanceState());
|
||||
state.putInt("alpha", alpha);
|
||||
|
@ -172,7 +173,8 @@ public class ColorPickerView extends View {
|
|||
return state;
|
||||
}
|
||||
|
||||
@Override public void onRestoreInstanceState( Parcelable state ){
|
||||
@Override
|
||||
public void onRestoreInstanceState(Parcelable state) {
|
||||
|
||||
if (state instanceof Bundle) {
|
||||
Bundle bundle = (Bundle) state;
|
||||
|
@ -262,7 +264,8 @@ public class ColorPickerView extends View {
|
|||
|
||||
}
|
||||
|
||||
@Override protected void onDraw( Canvas canvas ){
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
if (drawingRect.width() <= 0 || drawingRect.height() <= 0) {
|
||||
return;
|
||||
}
|
||||
|
@ -552,7 +555,8 @@ public class ColorPickerView extends View {
|
|||
}
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
@Override public boolean onTouchEvent( MotionEvent event ){
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
|
||||
try {
|
||||
this.getParent().requestDisallowInterceptTouchEvent(true);
|
||||
|
@ -617,7 +621,8 @@ public class ColorPickerView extends View {
|
|||
return update;
|
||||
}
|
||||
|
||||
@Override protected void onMeasure( int widthMeasureSpec, int heightMeasureSpec ){
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
int finalWidth;
|
||||
int finalHeight;
|
||||
|
||||
|
@ -639,12 +644,8 @@ public class ColorPickerView extends View {
|
|||
h += panelSpacingPx + alphaPanelHeightPx;
|
||||
}
|
||||
|
||||
if( h > heightAllowed ){
|
||||
//We can't fit the view in this container, set the size to whatever was allowed.
|
||||
finalHeight = heightAllowed;
|
||||
}else{
|
||||
finalHeight = h;
|
||||
}
|
||||
finalHeight = Math.min(h, heightAllowed);
|
||||
|
||||
finalWidth = widthAllowed;
|
||||
|
||||
|
@ -657,12 +658,8 @@ public class ColorPickerView extends View {
|
|||
w -= (panelSpacingPx + alphaPanelHeightPx);
|
||||
}
|
||||
|
||||
if( w > widthAllowed ){
|
||||
//we can't fit within this container, set the size to whatever was allowed.
|
||||
finalWidth = widthAllowed;
|
||||
}else{
|
||||
finalWidth = w;
|
||||
}
|
||||
finalWidth = Math.min(w, widthAllowed);
|
||||
|
||||
finalHeight = heightAllowed;
|
||||
|
||||
|
@ -722,39 +719,28 @@ public class ColorPickerView extends View {
|
|||
finalHeight + getPaddingTop() + getPaddingBottom());
|
||||
}
|
||||
|
||||
// private int getPreferredWidth() {
|
||||
// //Our preferred width and height is 200dp for the square sat / val rectangle.
|
||||
// int width = DrawingUtils.dpToPx(getContext(), 200);
|
||||
//
|
||||
// return (width + huePanelWidthPx + panelSpacingPx);
|
||||
// }
|
||||
//
|
||||
// private int getPreferredHeight() {
|
||||
// int height = DrawingUtils.dpToPx(getContext(), 200);
|
||||
//
|
||||
// if (showAlphaPanel) {
|
||||
// height += panelSpacingPx + alphaPanelHeightPx;
|
||||
// }
|
||||
// return height;
|
||||
// }
|
||||
|
||||
@Override public int getPaddingTop(){
|
||||
@Override
|
||||
public int getPaddingTop() {
|
||||
return Math.max(super.getPaddingTop(), mRequiredPadding);
|
||||
}
|
||||
|
||||
@Override public int getPaddingBottom(){
|
||||
@Override
|
||||
public int getPaddingBottom() {
|
||||
return Math.max(super.getPaddingBottom(), mRequiredPadding);
|
||||
}
|
||||
|
||||
@Override public int getPaddingLeft(){
|
||||
@Override
|
||||
public int getPaddingLeft() {
|
||||
return Math.max(super.getPaddingLeft(), mRequiredPadding);
|
||||
}
|
||||
|
||||
@Override public int getPaddingRight(){
|
||||
@Override
|
||||
public int getPaddingRight() {
|
||||
return Math.max(super.getPaddingRight(), mRequiredPadding);
|
||||
}
|
||||
|
||||
@Override protected void onSizeChanged( int w, int h, int oldw, int oldh ){
|
||||
@Override
|
||||
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
||||
super.onSizeChanged(w, h, oldw, oldh);
|
||||
|
||||
drawingRect = new Rect();
|
||||
|
@ -983,15 +969,13 @@ public class ColorPickerView extends View {
|
|||
return alphaSliderText;
|
||||
}
|
||||
|
||||
private class BitmapCache {
|
||||
|
||||
private static class BitmapCache {
|
||||
public Canvas canvas;
|
||||
public Bitmap bitmap;
|
||||
public float value;
|
||||
}
|
||||
|
||||
public interface OnColorChangedListener {
|
||||
|
||||
void onColorChanged(int newColor);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,17 +16,21 @@
|
|||
|
||||
package com.jrummyapps.android.colorpicker;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Color;
|
||||
import android.preference.Preference;
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.NonNull;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
|
||||
import com.jrummyapps.android.colorpicker.ColorPickerDialog.DialogType;
|
||||
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
/**
|
||||
* A Preference to select a color
|
||||
*/
|
||||
|
@ -89,7 +93,8 @@ public class ColorPreference extends Preference implements ColorPickerDialogList
|
|||
a.recycle();
|
||||
}
|
||||
|
||||
@Override protected void onClick() {
|
||||
@Override
|
||||
protected void onClick() {
|
||||
super.onClick();
|
||||
if (onShowDialogListener != null) {
|
||||
onShowDialogListener.onShowColorPickerDialog((String) getTitle(), color);
|
||||
|
@ -106,18 +111,28 @@ public class ColorPreference extends Preference implements ColorPickerDialogList
|
|||
.setColor(color)
|
||||
.create();
|
||||
dialog.setColorPickerDialogListener(ColorPreference.this);
|
||||
Activity activity = (Activity) getContext();
|
||||
dialog.show(activity.getFragmentManager(), getFragmentTag());
|
||||
FragmentManager fm = getFragmentManager();
|
||||
if (fm != null) {
|
||||
dialog.show(fm, getFragmentTag());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override protected void onAttachedToActivity() {
|
||||
@Nullable
|
||||
private FragmentManager getFragmentManager() {
|
||||
Context context = getContext();
|
||||
if (context instanceof FragmentActivity) {
|
||||
return ((FragmentActivity) context).getSupportFragmentManager();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToActivity() {
|
||||
super.onAttachedToActivity();
|
||||
|
||||
if (showDialog) {
|
||||
Activity activity = (Activity) getContext();
|
||||
ColorPickerDialog fragment =
|
||||
(ColorPickerDialog) activity.getFragmentManager().findFragmentByTag(getFragmentTag());
|
||||
FragmentManager fm = getFragmentManager();
|
||||
if (showDialog && fm != null) {
|
||||
ColorPickerDialog fragment = (ColorPickerDialog) fm.findFragmentByTag(getFragmentTag());
|
||||
if (fragment != null) {
|
||||
// re-bind preference to fragment
|
||||
fragment.setColorPickerDialogListener(this);
|
||||
|
@ -125,15 +140,17 @@ public class ColorPreference extends Preference implements ColorPickerDialogList
|
|||
}
|
||||
}
|
||||
|
||||
@Override protected void onBindView(View view) {
|
||||
@Override
|
||||
protected void onBindView(View view) {
|
||||
super.onBindView(view);
|
||||
ColorPanelView preview = (ColorPanelView) view.findViewById(R.id.cpv_preference_preview_color_panel);
|
||||
ColorPanelView preview = view.findViewById(R.id.cpv_preference_preview_color_panel);
|
||||
if (preview != null) {
|
||||
preview.setColor(color);
|
||||
}
|
||||
}
|
||||
|
||||
@Override protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) {
|
||||
@Override
|
||||
protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) {
|
||||
if (restorePersistedValue) {
|
||||
color = getPersistedInt(0xFF000000);
|
||||
} else {
|
||||
|
@ -142,23 +159,25 @@ public class ColorPreference extends Preference implements ColorPickerDialogList
|
|||
}
|
||||
}
|
||||
|
||||
@Override protected Object onGetDefaultValue(TypedArray a, int index) {
|
||||
@Override
|
||||
protected Object onGetDefaultValue(TypedArray a, int index) {
|
||||
return a.getInteger(index, Color.BLACK);
|
||||
}
|
||||
|
||||
@Override public void onColorSelected(int dialogId, @ColorInt int color) {
|
||||
@Override
|
||||
public void onColorSelected(int dialogId, @ColorInt int color) {
|
||||
saveValue(color);
|
||||
}
|
||||
|
||||
@Override public void onDialogDismissed(int dialogId) {
|
||||
@Override
|
||||
public void onDialogDismissed(int dialogId) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the new color
|
||||
*
|
||||
* @param color
|
||||
* The newly selected color
|
||||
* @param color The newly selected color
|
||||
*/
|
||||
public void saveValue(@ColorInt int color) {
|
||||
this.color = color;
|
||||
|
@ -190,8 +209,7 @@ public class ColorPreference extends Preference implements ColorPickerDialogList
|
|||
* Call {@link #saveValue(int)} after the user chooses a color.
|
||||
* If this is set then it is up to you to show the dialog.
|
||||
*
|
||||
* @param listener
|
||||
* The listener to show the dialog
|
||||
* @param listener The listener to show the dialog
|
||||
*/
|
||||
public void setOnShowDialogListener(OnShowDialogListener listener) {
|
||||
onShowDialogListener = listener;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#Wed May 05 20:20:56 JST 2021
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.9-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip
|
||||
distributionPath=wrapper/dists
|
||||
zipStorePath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
|
|
@ -44,10 +44,9 @@ dependencies {
|
|||
implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version"
|
||||
|
||||
testImplementation "junit:junit:$junit_version"
|
||||
androidTestImplementation 'androidx.test:runner:1.3.0'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
|
||||
androidTestImplementation 'androidx.test:runner:1.4.0'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
|
||||
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinx_coroutines_version"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlinx_coroutines_version"
|
||||
}
|
||||
|
|
|
@ -1,21 +1,24 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="jp.juggler.apng.sample"
|
||||
>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="jp.juggler.apng.sample">
|
||||
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission
|
||||
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
||||
tools:ignore="ScopedStorage" />
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:fullBackupOnly="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme"
|
||||
>
|
||||
android:theme="@style/AppTheme">
|
||||
|
||||
<activity android:name=".ActList">
|
||||
<activity
|
||||
android:name=".ActList"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
|
|
|
@ -78,21 +78,12 @@ class ActList : AppCompatActivity(), CoroutineScope {
|
|||
permissions: Array<String>,
|
||||
grantResults: IntArray
|
||||
) {
|
||||
when (requestCode) {
|
||||
PERMISSION_REQUEST_CODE_STORAGE -> {
|
||||
// If request is cancelled, the result arrays are empty.
|
||||
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
// permission was granted, yay! Do the
|
||||
// contacts-related task you need to do.
|
||||
} else {
|
||||
// permission denied, boo! Disable the
|
||||
// functionality that depends on this permission.
|
||||
if( requestCode == PERMISSION_REQUEST_CODE_STORAGE){
|
||||
if (grantResults.all{ it == PackageManager.PERMISSION_GRANTED }) {
|
||||
// 特に何もしてないらしい
|
||||
}
|
||||
return
|
||||
}
|
||||
// other 'case' lines to check for other
|
||||
// permissions this app might request
|
||||
}
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
}
|
||||
|
||||
private fun load() = launch {
|
||||
|
|
|
@ -117,7 +117,7 @@ class ActViewer : AppCompatActivity() , CoroutineScope {
|
|||
|
||||
dir.mkdirs()
|
||||
if(! dir.exists() ) {
|
||||
Log.e(TAG, "Directory not exists: ${dir}")
|
||||
Log.e(TAG, "Directory not exists: $dir")
|
||||
return@launch
|
||||
}
|
||||
val frames = apngFrames.frames
|
||||
|
@ -127,7 +127,7 @@ class ActViewer : AppCompatActivity() , CoroutineScope {
|
|||
}
|
||||
var i=0
|
||||
for( f in frames) {
|
||||
Log.d(TAG, "${title}[${i}] timeWidth=${f.timeWidth}")
|
||||
Log.d(TAG, "$title[$i] timeWidth=${f.timeWidth}")
|
||||
val bitmap = f.bitmap
|
||||
|
||||
FileOutputStream( File(dir,"${title}_${i}.png")).use{ fo ->
|
||||
|
|
Loading…
Reference in New Issue