mirror of
https://github.com/tateisu/SubwayTooter
synced 2025-02-01 19:36:48 +01:00
targetSdkVersion 31
This commit is contained in:
parent
d017a47363
commit
9c68857e6e
5
.idea/compiler.xml
generated
5
.idea/compiler.xml
generated
@ -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>
|
2
.idea/gradle.xml
generated
2
.idea/gradle.xml
generated
@ -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$" />
|
||||
|
15
.idea/inspectionProfiles/Project_Default.xml
generated
15
.idea/inspectionProfiles/Project_Default.xml
generated
@ -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"
|
||||
@ -32,4 +32,8 @@ dependencies {
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
101
app/build.gradle
101
app/build.gradle
@ -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"){
|
||||
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,8 +33,9 @@ class TestMisskeyMentionAndroid {
|
||||
// val a="""[[ ]""".toRegex()
|
||||
|
||||
// IDEで警告が出るが、Androidは正規表現エンジンが異なるので仕方ない
|
||||
@Suppress("RegExpRedundantNestedCharacterClass")
|
||||
assertEquals(true, """[[ ]]][ ]""".toRegex().matches(" ] "))
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -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)
|
||||
.allEnabledCipherSuites()
|
||||
.allEnabledTlsVersions()
|
||||
.build()))
|
||||
.connectionSpecs(
|
||||
Collections.singletonList(
|
||||
ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
|
||||
.allEnabledCipherSuites()
|
||||
.allEnabledTlsVersions()
|
||||
.build()
|
||||
)
|
||||
)
|
||||
.sslSocketFactory(MySslSocketFactory, MySslSocketFactory.trustManager)
|
||||
.build()
|
||||
|
||||
@ -56,11 +60,11 @@ class TestTootInstance {
|
||||
}
|
||||
}
|
||||
|
||||
private val appContext = InstrumentationRegistry.getTargetContext()!!
|
||||
private val appContext = InstrumentationRegistry.getInstrumentation().targetContext!!
|
||||
|
||||
val client = TootApiClient(
|
||||
context = appContext,
|
||||
httpClient =SimpleHttpClientImpl(appContext, okHttp),
|
||||
httpClient = SimpleHttpClientImpl(appContext, okHttp),
|
||||
callback = dummyClientCallback
|
||||
)
|
||||
}
|
||||
@ -73,12 +77,12 @@ class TestTootInstance {
|
||||
@Test
|
||||
fun testWithoutAccount() {
|
||||
runBlocking {
|
||||
withContext(Dispatchers.IO){
|
||||
suspend fun a(host:Host){
|
||||
val (ti,ri) = TootInstance.get(client,host )
|
||||
withContext(Dispatchers.IO) {
|
||||
suspend fun a(host: 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"))
|
||||
@ -90,15 +94,15 @@ class TestTootInstance {
|
||||
@Test
|
||||
fun testWithAccount() {
|
||||
runBlocking {
|
||||
withContext(Dispatchers.IO){
|
||||
suspend fun a(account:SavedAccount){
|
||||
val (ti,ri) = TootInstance.get(client,account = account )
|
||||
withContext(Dispatchers.IO) {
|
||||
suspend fun a(account: SavedAccount) {
|
||||
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) )
|
||||
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" >
|
||||
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>
|
||||
</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,13 +430,17 @@ class ActPost : AppCompatActivity(),
|
||||
cbContentWarning.setOnCheckedChangeListener { _, _ -> showContentWarningEnabled() }
|
||||
|
||||
completionHelper = CompletionHelper(this, pref, appState.handler)
|
||||
completionHelper.attachEditText(formRoot, etContent, false, object : CompletionHelper.Callback2 {
|
||||
override fun onTextUpdate() {
|
||||
updateTextCount()
|
||||
}
|
||||
completionHelper.attachEditText(
|
||||
formRoot,
|
||||
etContent,
|
||||
false,
|
||||
object : CompletionHelper.Callback2 {
|
||||
override fun onTextUpdate() {
|
||||
updateTextCount()
|
||||
}
|
||||
|
||||
override fun canOpenPopup(): Boolean = true
|
||||
})
|
||||
override fun canOpenPopup(): Boolean = true
|
||||
})
|
||||
|
||||
val textWatcher: TextWatcher = object : TextWatcher {
|
||||
override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
|
||||
@ -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)
|
||||
}
|
||||
|
@ -83,9 +83,9 @@ class CompletionHelper(
|
||||
val c = cp.toChar()
|
||||
|
||||
return '0' <= c && c <= '9' ||
|
||||
'A' <= c && c <= 'Z' ||
|
||||
'a' <= c && c <= 'z' ||
|
||||
c == '_' || c == '-' || c == '.'
|
||||
'A' <= c && c <= 'Z' ||
|
||||
'a' <= c && c <= 'z' ||
|
||||
c == '_' || c == '-' || c == '.'
|
||||
}
|
||||
|
||||
// Letter | Mark | Decimal_Number | Connector_Punctuation
|
||||
@ -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")
|
||||
closeAcctPopup()
|
||||
}
|
||||
// 範囲選択されてるならポップアップは閉じる
|
||||
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
|
||||
|
@ -32,82 +32,87 @@ import androidx.annotation.NonNull;
|
||||
* It's the pattern you will often see as a background behind a partly transparent image in many applications.
|
||||
*/
|
||||
class AlphaPatternDrawable extends Drawable {
|
||||
|
||||
private int rectangleSize;
|
||||
|
||||
private Paint paint = new Paint();
|
||||
private Paint paintWhite = new Paint();
|
||||
private Paint paintGray = new Paint();
|
||||
|
||||
private int numRectanglesHorizontal;
|
||||
private int numRectanglesVertical;
|
||||
|
||||
/**
|
||||
* Bitmap in which the pattern will be cached.
|
||||
* This is so the pattern will not have to be recreated each time draw() gets called.
|
||||
* Because recreating the pattern i rather expensive. I will only be recreated if the size changes.
|
||||
*/
|
||||
private Bitmap bitmap;
|
||||
|
||||
AlphaPatternDrawable( int rectangleSize ){
|
||||
this.rectangleSize = rectangleSize;
|
||||
paintWhite.setColor( 0xFFFFFFFF );
|
||||
paintGray.setColor( 0xFFCBCBCB );
|
||||
}
|
||||
|
||||
@Override public void draw( @NonNull Canvas canvas ){
|
||||
if( bitmap != null && ! bitmap.isRecycled() ){
|
||||
canvas.drawBitmap( bitmap, null, getBounds(), paint );
|
||||
}
|
||||
}
|
||||
|
||||
@Override public int getOpacity(){
|
||||
return PixelFormat.UNKNOWN;
|
||||
}
|
||||
|
||||
@Override public void setAlpha( int alpha ){
|
||||
throw new UnsupportedOperationException( "Alpha is not supported by this drawable." );
|
||||
}
|
||||
|
||||
@Override public void setColorFilter( ColorFilter cf ){
|
||||
throw new UnsupportedOperationException( "ColorFilter is not supported by this drawable." );
|
||||
}
|
||||
|
||||
@Override protected void onBoundsChange( Rect bounds ){
|
||||
super.onBoundsChange( bounds );
|
||||
int height = bounds.height();
|
||||
int width = bounds.width();
|
||||
numRectanglesHorizontal = (int) Math.ceil( width / (float) rectangleSize );
|
||||
numRectanglesVertical = (int) Math.ceil( height / (float) rectangleSize );
|
||||
generatePatternBitmap();
|
||||
}
|
||||
|
||||
/**
|
||||
* This will generate a bitmap with the pattern as big as the rectangle we were allow to draw on.
|
||||
* We do this to chache the bitmap so we don't need to recreate it each time draw() is called since it takes a few milliseconds
|
||||
*/
|
||||
private void generatePatternBitmap(){
|
||||
if( getBounds().width() <= 0 || getBounds().height() <= 0 ){
|
||||
return;
|
||||
}
|
||||
|
||||
bitmap = Bitmap.createBitmap( getBounds().width(), getBounds().height(), Config.ARGB_8888 );
|
||||
Canvas canvas = new Canvas( bitmap );
|
||||
|
||||
Rect r = new Rect();
|
||||
boolean verticalStartWhite = true;
|
||||
for( int i = 0 ; i <= numRectanglesVertical ; i++ ){
|
||||
boolean isWhite = verticalStartWhite;
|
||||
for( int j = 0 ; j <= numRectanglesHorizontal ; j++ ){
|
||||
r.top = i * rectangleSize;
|
||||
r.left = j * rectangleSize;
|
||||
r.bottom = r.top + rectangleSize;
|
||||
r.right = r.left + rectangleSize;
|
||||
canvas.drawRect( r, isWhite ? paintWhite : paintGray );
|
||||
isWhite = ! isWhite;
|
||||
}
|
||||
verticalStartWhite = ! verticalStartWhite;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private final int rectangleSize;
|
||||
|
||||
private final Paint paint = new Paint();
|
||||
private final Paint paintWhite = new Paint();
|
||||
private final Paint paintGray = new Paint();
|
||||
|
||||
private int numRectanglesHorizontal;
|
||||
private int numRectanglesVertical;
|
||||
|
||||
/**
|
||||
* Bitmap in which the pattern will be cached.
|
||||
* This is so the pattern will not have to be recreated each time draw() gets called.
|
||||
* Because recreating the pattern i rather expensive. I will only be recreated if the size changes.
|
||||
*/
|
||||
private Bitmap bitmap;
|
||||
|
||||
AlphaPatternDrawable(int rectangleSize) {
|
||||
this.rectangleSize = rectangleSize;
|
||||
paintWhite.setColor(0xFFFFFFFF);
|
||||
paintGray.setColor(0xFFCBCBCB);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(@NonNull Canvas canvas) {
|
||||
if (bitmap != null && !bitmap.isRecycled()) {
|
||||
canvas.drawBitmap(bitmap, null, getBounds(), paint);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOpacity() {
|
||||
return PixelFormat.UNKNOWN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAlpha(int alpha) {
|
||||
throw new UnsupportedOperationException("Alpha is not supported by this drawable.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setColorFilter(ColorFilter cf) {
|
||||
throw new UnsupportedOperationException("ColorFilter is not supported by this drawable.");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onBoundsChange(Rect bounds) {
|
||||
super.onBoundsChange(bounds);
|
||||
int height = bounds.height();
|
||||
int width = bounds.width();
|
||||
numRectanglesHorizontal = (int) Math.ceil(width / (float) rectangleSize);
|
||||
numRectanglesVertical = (int) Math.ceil(height / (float) rectangleSize);
|
||||
generatePatternBitmap();
|
||||
}
|
||||
|
||||
/**
|
||||
* This will generate a bitmap with the pattern as big as the rectangle we were allow to draw on.
|
||||
* We do this to chache the bitmap so we don't need to recreate it each time draw() is called since it takes a few milliseconds
|
||||
*/
|
||||
private void generatePatternBitmap() {
|
||||
if (getBounds().width() <= 0 || getBounds().height() <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
bitmap = Bitmap.createBitmap(getBounds().width(), getBounds().height(), Config.ARGB_8888);
|
||||
Canvas canvas = new Canvas(bitmap);
|
||||
|
||||
Rect r = new Rect();
|
||||
boolean verticalStartWhite = true;
|
||||
for (int i = 0; i <= numRectanglesVertical; i++) {
|
||||
boolean isWhite = verticalStartWhite;
|
||||
for (int j = 0; j <= numRectanglesHorizontal; j++) {
|
||||
r.top = i * rectangleSize;
|
||||
r.left = j * rectangleSize;
|
||||
r.bottom = r.top + rectangleSize;
|
||||
r.right = r.left + rectangleSize;
|
||||
canvas.drawRect(r, isWhite ? paintWhite : paintGray);
|
||||
isWhite = !isWhite;
|
||||
}
|
||||
verticalStartWhite = !verticalStartWhite;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -19,129 +19,130 @@ 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 OnColorSelectedListener listener;
|
||||
/*package*/ final int[] colors;
|
||||
/*package*/ int selectedPosition;
|
||||
/*package*/ final int colorShape;
|
||||
|
||||
ColorPaletteAdapter(OnColorSelectedListener listener,
|
||||
int[] colors,
|
||||
int selectedPosition,
|
||||
@ColorShape int colorShape) {
|
||||
this.listener = listener;
|
||||
this.colors = colors;
|
||||
this.selectedPosition = selectedPosition;
|
||||
this.colorShape = colorShape;
|
||||
}
|
||||
|
||||
@Override public int getCount() {
|
||||
return colors.length;
|
||||
}
|
||||
|
||||
@Override public Object getItem(int position) {
|
||||
return colors[position];
|
||||
}
|
||||
|
||||
@Override public long getItemId(int position) {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override public View getView(int position, View convertView, ViewGroup parent) {
|
||||
final ViewHolder holder;
|
||||
if (convertView == null) {
|
||||
holder = new ViewHolder(parent.getContext());
|
||||
convertView = holder.view;
|
||||
} else {
|
||||
holder = (ViewHolder) convertView.getTag();
|
||||
}
|
||||
holder.setup(position);
|
||||
return convertView;
|
||||
}
|
||||
|
||||
void selectNone() {
|
||||
selectedPosition = -1;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
interface OnColorSelectedListener {
|
||||
|
||||
void onColorSelected(int color);
|
||||
}
|
||||
|
||||
private final class ViewHolder {
|
||||
|
||||
View view;
|
||||
ColorPanelView colorPanelView;
|
||||
ImageView imageView;
|
||||
int originalBorderColor;
|
||||
|
||||
ViewHolder(Context context) {
|
||||
int layoutResId;
|
||||
if (colorShape == ColorShape.SQUARE) {
|
||||
layoutResId = R.layout.cpv_color_item_square;
|
||||
} else {
|
||||
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);
|
||||
originalBorderColor = colorPanelView.getBorderColor();
|
||||
view.setTag(this);
|
||||
ColorPaletteAdapter(OnColorSelectedListener listener,
|
||||
int[] colors,
|
||||
int selectedPosition,
|
||||
@ColorShape int colorShape) {
|
||||
this.listener = listener;
|
||||
this.colors = colors;
|
||||
this.selectedPosition = selectedPosition;
|
||||
this.colorShape = colorShape;
|
||||
}
|
||||
|
||||
void setup(int position) {
|
||||
int color = colors[position];
|
||||
int alpha = Color.alpha(color);
|
||||
colorPanelView.setColor(color);
|
||||
imageView.setImageResource(selectedPosition == position ? R.drawable.cpv_preset_checked : 0);
|
||||
if (alpha != 255) {
|
||||
if (alpha <= ColorPickerDialog.ALPHA_THRESHOLD) {
|
||||
colorPanelView.setBorderColor(color | 0xFF000000);
|
||||
imageView.setColorFilter(/*color | 0xFF000000*/Color.BLACK, PorterDuff.Mode.SRC_IN);
|
||||
@Override
|
||||
public int getCount() {
|
||||
return colors.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItem(int position) {
|
||||
return colors[position];
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
final ViewHolder holder;
|
||||
if (convertView == null) {
|
||||
holder = new ViewHolder(parent.getContext());
|
||||
convertView = holder.view;
|
||||
} else {
|
||||
colorPanelView.setBorderColor(originalBorderColor);
|
||||
imageView.setColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN);
|
||||
holder = (ViewHolder) convertView.getTag();
|
||||
}
|
||||
} else {
|
||||
setColorFilter(position);
|
||||
}
|
||||
setOnClickListener(position);
|
||||
holder.setup(position);
|
||||
return convertView;
|
||||
}
|
||||
|
||||
private void setOnClickListener(final int position) {
|
||||
colorPanelView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override public void onClick(View v) {
|
||||
if (selectedPosition != position) {
|
||||
selectedPosition = position;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
listener.onColorSelected(colors[position]);
|
||||
}
|
||||
});
|
||||
colorPanelView.setOnLongClickListener(new View.OnLongClickListener() {
|
||||
@Override public boolean onLongClick(View v) {
|
||||
colorPanelView.showHint();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
void selectNone() {
|
||||
selectedPosition = -1;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
private void setColorFilter(int position) {
|
||||
if (position == selectedPosition && ColorUtils.calculateLuminance(colors[position]) >= 0.65) {
|
||||
imageView.setColorFilter(Color.BLACK, PorterDuff.Mode.SRC_IN);
|
||||
} else {
|
||||
imageView.setColorFilter(null);
|
||||
}
|
||||
interface OnColorSelectedListener {
|
||||
|
||||
void onColorSelected(int color);
|
||||
}
|
||||
|
||||
}
|
||||
private final class ViewHolder {
|
||||
|
||||
final View view;
|
||||
final ColorPanelView colorPanelView;
|
||||
final ImageView imageView;
|
||||
final int originalBorderColor;
|
||||
|
||||
ViewHolder(Context context) {
|
||||
int layoutResId;
|
||||
if (colorShape == ColorShape.SQUARE) {
|
||||
layoutResId = R.layout.cpv_color_item_square;
|
||||
} else {
|
||||
layoutResId = R.layout.cpv_color_item_circle;
|
||||
}
|
||||
view = View.inflate(context, layoutResId, null);
|
||||
colorPanelView = view.findViewById(R.id.cpv_color_panel_view);
|
||||
imageView = view.findViewById(R.id.cpv_color_image_view);
|
||||
originalBorderColor = colorPanelView.getBorderColor();
|
||||
view.setTag(this);
|
||||
}
|
||||
|
||||
void setup(int position) {
|
||||
int color = colors[position];
|
||||
int alpha = Color.alpha(color);
|
||||
colorPanelView.setColor(color);
|
||||
imageView.setImageResource(selectedPosition == position ? R.drawable.cpv_preset_checked : 0);
|
||||
if (alpha != 255) {
|
||||
if (alpha <= ColorPickerDialog.ALPHA_THRESHOLD) {
|
||||
colorPanelView.setBorderColor(color | 0xFF000000);
|
||||
imageView.setColorFilter(/*color | 0xFF000000*/Color.BLACK, PorterDuff.Mode.SRC_IN);
|
||||
} else {
|
||||
colorPanelView.setBorderColor(originalBorderColor);
|
||||
imageView.setColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN);
|
||||
}
|
||||
} else {
|
||||
setColorFilter(position);
|
||||
}
|
||||
setOnClickListener(position);
|
||||
}
|
||||
|
||||
private void setOnClickListener(final int position) {
|
||||
colorPanelView.setOnClickListener(v -> {
|
||||
if (selectedPosition != position) {
|
||||
selectedPosition = position;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
listener.onColorSelected(colors[position]);
|
||||
});
|
||||
colorPanelView.setOnLongClickListener(v -> {
|
||||
colorPanelView.showHint();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void setColorFilter(int position) {
|
||||
if (position == selectedPosition && ColorUtils.calculateLuminance(colors[position]) >= 0.65) {
|
||||
imageView.setColorFilter(Color.BLACK, PorterDuff.Mode.SRC_IN);
|
||||
} else {
|
||||
imageView.setColorFilter(null);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -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 {
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -16,199 +16,217 @@
|
||||
|
||||
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
|
||||
*/
|
||||
public class ColorPreference extends Preference implements ColorPickerDialogListener {
|
||||
|
||||
private static final int SIZE_NORMAL = 0;
|
||||
private static final int SIZE_LARGE = 1;
|
||||
private static final int SIZE_NORMAL = 0;
|
||||
private static final int SIZE_LARGE = 1;
|
||||
|
||||
private OnShowDialogListener onShowDialogListener;
|
||||
private int color = Color.BLACK;
|
||||
private boolean showDialog;
|
||||
@DialogType
|
||||
private int dialogType;
|
||||
private int colorShape;
|
||||
private boolean allowPresets;
|
||||
private boolean allowCustom;
|
||||
private boolean showAlphaSlider;
|
||||
private boolean showColorShades;
|
||||
private int previewSize;
|
||||
private int[] presets;
|
||||
private int dialogTitle;
|
||||
private OnShowDialogListener onShowDialogListener;
|
||||
private int color = Color.BLACK;
|
||||
private boolean showDialog;
|
||||
@DialogType
|
||||
private int dialogType;
|
||||
private int colorShape;
|
||||
private boolean allowPresets;
|
||||
private boolean allowCustom;
|
||||
private boolean showAlphaSlider;
|
||||
private boolean showColorShades;
|
||||
private int previewSize;
|
||||
private int[] presets;
|
||||
private int dialogTitle;
|
||||
|
||||
public ColorPreference(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init(attrs);
|
||||
}
|
||||
|
||||
public ColorPreference(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
init(attrs);
|
||||
}
|
||||
|
||||
private void init(AttributeSet attrs) {
|
||||
setPersistent(true);
|
||||
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.ColorPreference);
|
||||
showDialog = a.getBoolean(R.styleable.ColorPreference_cpv_showDialog, true);
|
||||
//noinspection WrongConstant
|
||||
dialogType = a.getInt(R.styleable.ColorPreference_cpv_dialogType, ColorPickerDialog.TYPE_PRESETS);
|
||||
colorShape = a.getInt(R.styleable.ColorPreference_cpv_colorShape, ColorShape.CIRCLE);
|
||||
allowPresets = a.getBoolean(R.styleable.ColorPreference_cpv_allowPresets, true);
|
||||
allowCustom = a.getBoolean(R.styleable.ColorPreference_cpv_allowCustom, true);
|
||||
showAlphaSlider = a.getBoolean(R.styleable.ColorPreference_cpv_showAlphaSlider, false);
|
||||
showColorShades = a.getBoolean(R.styleable.ColorPreference_cpv_showColorShades, true);
|
||||
previewSize = a.getInt(R.styleable.ColorPreference_cpv_previewSize, SIZE_NORMAL);
|
||||
final int presetsResId = a.getResourceId(R.styleable.ColorPreference_cpv_colorPresets, 0);
|
||||
dialogTitle = a.getResourceId(R.styleable.ColorPreference_cpv_dialogTitle, R.string.cpv_default_title);
|
||||
if (presetsResId != 0) {
|
||||
presets = getContext().getResources().getIntArray(presetsResId);
|
||||
} else {
|
||||
presets = ColorPickerDialog.MATERIAL_COLORS;
|
||||
public ColorPreference(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init(attrs);
|
||||
}
|
||||
if (colorShape == ColorShape.CIRCLE) {
|
||||
setWidgetLayoutResource(
|
||||
previewSize == SIZE_LARGE ? R.layout.cpv_preference_circle_large : R.layout.cpv_preference_circle);
|
||||
} else {
|
||||
setWidgetLayoutResource(
|
||||
previewSize == SIZE_LARGE ? R.layout.cpv_preference_square_large : R.layout.cpv_preference_square
|
||||
);
|
||||
|
||||
public ColorPreference(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
init(attrs);
|
||||
}
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
@Override protected void onClick() {
|
||||
super.onClick();
|
||||
if (onShowDialogListener != null) {
|
||||
onShowDialogListener.onShowColorPickerDialog((String) getTitle(), color);
|
||||
} else if (showDialog) {
|
||||
ColorPickerDialog dialog = ColorPickerDialog.newBuilder()
|
||||
.setDialogType(dialogType)
|
||||
.setDialogTitle(dialogTitle)
|
||||
.setColorShape(colorShape)
|
||||
.setPresets(presets)
|
||||
.setAllowPresets(allowPresets)
|
||||
.setAllowCustom(allowCustom)
|
||||
.setShowAlphaSlider(showAlphaSlider)
|
||||
.setShowColorShades(showColorShades)
|
||||
.setColor(color)
|
||||
.create();
|
||||
dialog.setColorPickerDialogListener(ColorPreference.this);
|
||||
Activity activity = (Activity) getContext();
|
||||
dialog.show(activity.getFragmentManager(), getFragmentTag());
|
||||
private void init(AttributeSet attrs) {
|
||||
setPersistent(true);
|
||||
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.ColorPreference);
|
||||
showDialog = a.getBoolean(R.styleable.ColorPreference_cpv_showDialog, true);
|
||||
//noinspection WrongConstant
|
||||
dialogType = a.getInt(R.styleable.ColorPreference_cpv_dialogType, ColorPickerDialog.TYPE_PRESETS);
|
||||
colorShape = a.getInt(R.styleable.ColorPreference_cpv_colorShape, ColorShape.CIRCLE);
|
||||
allowPresets = a.getBoolean(R.styleable.ColorPreference_cpv_allowPresets, true);
|
||||
allowCustom = a.getBoolean(R.styleable.ColorPreference_cpv_allowCustom, true);
|
||||
showAlphaSlider = a.getBoolean(R.styleable.ColorPreference_cpv_showAlphaSlider, false);
|
||||
showColorShades = a.getBoolean(R.styleable.ColorPreference_cpv_showColorShades, true);
|
||||
previewSize = a.getInt(R.styleable.ColorPreference_cpv_previewSize, SIZE_NORMAL);
|
||||
final int presetsResId = a.getResourceId(R.styleable.ColorPreference_cpv_colorPresets, 0);
|
||||
dialogTitle = a.getResourceId(R.styleable.ColorPreference_cpv_dialogTitle, R.string.cpv_default_title);
|
||||
if (presetsResId != 0) {
|
||||
presets = getContext().getResources().getIntArray(presetsResId);
|
||||
} else {
|
||||
presets = ColorPickerDialog.MATERIAL_COLORS;
|
||||
}
|
||||
if (colorShape == ColorShape.CIRCLE) {
|
||||
setWidgetLayoutResource(
|
||||
previewSize == SIZE_LARGE ? R.layout.cpv_preference_circle_large : R.layout.cpv_preference_circle);
|
||||
} else {
|
||||
setWidgetLayoutResource(
|
||||
previewSize == SIZE_LARGE ? R.layout.cpv_preference_square_large : R.layout.cpv_preference_square
|
||||
);
|
||||
}
|
||||
a.recycle();
|
||||
}
|
||||
}
|
||||
|
||||
@Override protected void onAttachedToActivity() {
|
||||
super.onAttachedToActivity();
|
||||
|
||||
if (showDialog) {
|
||||
Activity activity = (Activity) getContext();
|
||||
ColorPickerDialog fragment =
|
||||
(ColorPickerDialog) activity.getFragmentManager().findFragmentByTag(getFragmentTag());
|
||||
if (fragment != null) {
|
||||
// re-bind preference to fragment
|
||||
fragment.setColorPickerDialogListener(this);
|
||||
}
|
||||
@Override
|
||||
protected void onClick() {
|
||||
super.onClick();
|
||||
if (onShowDialogListener != null) {
|
||||
onShowDialogListener.onShowColorPickerDialog((String) getTitle(), color);
|
||||
} else if (showDialog) {
|
||||
ColorPickerDialog dialog = ColorPickerDialog.newBuilder()
|
||||
.setDialogType(dialogType)
|
||||
.setDialogTitle(dialogTitle)
|
||||
.setColorShape(colorShape)
|
||||
.setPresets(presets)
|
||||
.setAllowPresets(allowPresets)
|
||||
.setAllowCustom(allowCustom)
|
||||
.setShowAlphaSlider(showAlphaSlider)
|
||||
.setShowColorShades(showColorShades)
|
||||
.setColor(color)
|
||||
.create();
|
||||
dialog.setColorPickerDialogListener(ColorPreference.this);
|
||||
FragmentManager fm = getFragmentManager();
|
||||
if (fm != null) {
|
||||
dialog.show(fm, getFragmentTag());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override protected void onBindView(View view) {
|
||||
super.onBindView(view);
|
||||
ColorPanelView preview = (ColorPanelView) view.findViewById(R.id.cpv_preference_preview_color_panel);
|
||||
if (preview != null) {
|
||||
preview.setColor(color);
|
||||
@Nullable
|
||||
private FragmentManager getFragmentManager() {
|
||||
Context context = getContext();
|
||||
if (context instanceof FragmentActivity) {
|
||||
return ((FragmentActivity) context).getSupportFragmentManager();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) {
|
||||
if (restorePersistedValue) {
|
||||
color = getPersistedInt(0xFF000000);
|
||||
} else {
|
||||
color = (Integer) defaultValue;
|
||||
persistInt(color);
|
||||
@Override
|
||||
protected void onAttachedToActivity() {
|
||||
super.onAttachedToActivity();
|
||||
FragmentManager fm = getFragmentManager();
|
||||
if (showDialog && fm != null) {
|
||||
ColorPickerDialog fragment = (ColorPickerDialog) fm.findFragmentByTag(getFragmentTag());
|
||||
if (fragment != null) {
|
||||
// re-bind preference to fragment
|
||||
fragment.setColorPickerDialogListener(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override protected Object onGetDefaultValue(TypedArray a, int index) {
|
||||
return a.getInteger(index, Color.BLACK);
|
||||
}
|
||||
@Override
|
||||
protected void onBindView(View view) {
|
||||
super.onBindView(view);
|
||||
ColorPanelView preview = view.findViewById(R.id.cpv_preference_preview_color_panel);
|
||||
if (preview != null) {
|
||||
preview.setColor(color);
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void onColorSelected(int dialogId, @ColorInt int color) {
|
||||
saveValue(color);
|
||||
}
|
||||
@Override
|
||||
protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) {
|
||||
if (restorePersistedValue) {
|
||||
color = getPersistedInt(0xFF000000);
|
||||
} else {
|
||||
color = (Integer) defaultValue;
|
||||
persistInt(color);
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void onDialogDismissed(int dialogId) {
|
||||
// no-op
|
||||
}
|
||||
@Override
|
||||
protected Object onGetDefaultValue(TypedArray a, int index) {
|
||||
return a.getInteger(index, Color.BLACK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the new color
|
||||
*
|
||||
* @param color
|
||||
* The newly selected color
|
||||
*/
|
||||
public void saveValue(@ColorInt int color) {
|
||||
this.color = color;
|
||||
persistInt(this.color);
|
||||
notifyChanged();
|
||||
callChangeListener(color);
|
||||
}
|
||||
@Override
|
||||
public void onColorSelected(int dialogId, @ColorInt int color) {
|
||||
saveValue(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the colors shown in the {@link ColorPickerDialog}.
|
||||
*
|
||||
* @param presets An array of color ints
|
||||
*/
|
||||
public void setPresets(@NonNull int[] presets) {
|
||||
this.presets = presets;
|
||||
}
|
||||
@Override
|
||||
public void onDialogDismissed(int dialogId) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the colors that will be shown in the {@link ColorPickerDialog}.
|
||||
*
|
||||
* @return An array of color ints
|
||||
*/
|
||||
public int[] getPresets() {
|
||||
return presets;
|
||||
}
|
||||
/**
|
||||
* Set the new color
|
||||
*
|
||||
* @param color The newly selected color
|
||||
*/
|
||||
public void saveValue(@ColorInt int color) {
|
||||
this.color = color;
|
||||
persistInt(this.color);
|
||||
notifyChanged();
|
||||
callChangeListener(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* The listener used for showing the {@link ColorPickerDialog}.
|
||||
* 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
|
||||
*/
|
||||
public void setOnShowDialogListener(OnShowDialogListener listener) {
|
||||
onShowDialogListener = listener;
|
||||
}
|
||||
/**
|
||||
* Set the colors shown in the {@link ColorPickerDialog}.
|
||||
*
|
||||
* @param presets An array of color ints
|
||||
*/
|
||||
public void setPresets(@NonNull int[] presets) {
|
||||
this.presets = presets;
|
||||
}
|
||||
|
||||
/**
|
||||
* The tag used for the {@link ColorPickerDialog}.
|
||||
*
|
||||
* @return The tag
|
||||
*/
|
||||
public String getFragmentTag() {
|
||||
return "color_" + getKey();
|
||||
}
|
||||
/**
|
||||
* Get the colors that will be shown in the {@link ColorPickerDialog}.
|
||||
*
|
||||
* @return An array of color ints
|
||||
*/
|
||||
public int[] getPresets() {
|
||||
return presets;
|
||||
}
|
||||
|
||||
public interface OnShowDialogListener {
|
||||
/**
|
||||
* The listener used for showing the {@link ColorPickerDialog}.
|
||||
* 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
|
||||
*/
|
||||
public void setOnShowDialogListener(OnShowDialogListener listener) {
|
||||
onShowDialogListener = listener;
|
||||
}
|
||||
|
||||
void onShowColorPickerDialog(String title, int currentColor);
|
||||
}
|
||||
/**
|
||||
* The tag used for the {@link ColorPickerDialog}.
|
||||
*
|
||||
* @return The tag
|
||||
*/
|
||||
public String getFragmentTag() {
|
||||
return "color_" + getKey();
|
||||
}
|
||||
|
||||
public interface OnShowDialogListener {
|
||||
|
||||
void onShowColorPickerDialog(String title, int currentColor);
|
||||
}
|
||||
|
||||
}
|
||||
|
3
gradle/wrapper/gradle-wrapper.properties
vendored
3
gradle/wrapper/gradle-wrapper.properties
vendored
@ -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,29 +1,32 @@
|
||||
<?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"/>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:name=".ActViewer"/>
|
||||
<activity android:name=".ActViewer" />
|
||||
|
||||
</application>
|
||||
|
||||
|
@ -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.
|
||||
}
|
||||
return
|
||||
if( requestCode == PERMISSION_REQUEST_CODE_STORAGE){
|
||||
if (grantResults.all{ it == PackageManager.PERMISSION_GRANTED }) {
|
||||
// 特に何もしてないらしい
|
||||
}
|
||||
// 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…
x
Reference in New Issue
Block a user