fixed getValue null bug and gradle cleanups
This commit is contained in:
parent
8225b6a9bd
commit
0b75b4c542
|
@ -39,6 +39,7 @@ contributers.py
|
||||||
# View hierarchy captures
|
# View hierarchy captures
|
||||||
captures
|
captures
|
||||||
# other
|
# other
|
||||||
|
.directory
|
||||||
*.odg#
|
*.odg#
|
||||||
proguard
|
proguard
|
||||||
libs
|
libs
|
||||||
|
|
227
app/build.gradle
227
app/build.gradle
|
@ -2,14 +2,13 @@ plugins {
|
||||||
id('com.android.application')
|
id('com.android.application')
|
||||||
id 'kotlin-android'
|
id 'kotlin-android'
|
||||||
id 'kotlin-kapt'
|
id 'kotlin-kapt'
|
||||||
|
id 'com.google.devtools.ksp'
|
||||||
id('com.github.triplet.play') version '3.8.3' apply false
|
id('com.github.triplet.play') version '3.8.3' apply false
|
||||||
}
|
}
|
||||||
apply from: "../common.gradle"
|
|
||||||
apply from: "../playFlavor.gradle"
|
|
||||||
|
|
||||||
android {
|
android {
|
||||||
namespace "ac.mdiq.podcini"
|
namespace "ac.mdiq.podcini"
|
||||||
lint {
|
lintOptions {
|
||||||
disable 'ObsoleteLintCustomCheck', 'CheckResult', 'UnusedAttribute', 'BatteryLife', 'InflateParams',
|
disable 'ObsoleteLintCustomCheck', 'CheckResult', 'UnusedAttribute', 'BatteryLife', 'InflateParams',
|
||||||
'RestrictedApi', 'TrustAllX509TrustManager', 'ExportedReceiver', 'AllowBackup', 'VectorDrawableCompat',
|
'RestrictedApi', 'TrustAllX509TrustManager', 'ExportedReceiver', 'AllowBackup', 'VectorDrawableCompat',
|
||||||
'StaticFieldLeak', 'UseCompoundDrawables', 'NestedWeights', 'Overdraw', 'UselessParent', 'TextFields',
|
'StaticFieldLeak', 'UseCompoundDrawables', 'NestedWeights', 'Overdraw', 'UselessParent', 'TextFields',
|
||||||
|
@ -22,11 +21,25 @@ android {
|
||||||
buildConfig true
|
buildConfig true
|
||||||
}
|
}
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
// Version code schema:
|
minSdk 21
|
||||||
|
compileSdk 34
|
||||||
|
targetSdk 34
|
||||||
|
|
||||||
|
kotlinOptions {
|
||||||
|
jvmTarget = '17'
|
||||||
|
}
|
||||||
|
|
||||||
|
vectorDrawables.useSupportLibrary false
|
||||||
|
vectorDrawables.generatedDensities = []
|
||||||
|
|
||||||
|
testApplicationId "ac.mdiq.podcini.tests"
|
||||||
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
|
||||||
|
// Version code schema (not used):
|
||||||
// "1.2.3-beta4" -> 1020304
|
// "1.2.3-beta4" -> 1020304
|
||||||
// "1.2.3" -> 1020395
|
// "1.2.3" -> 1020395
|
||||||
versionCode 3020106
|
versionCode 3020107
|
||||||
versionName "4.2.3"
|
versionName "4.2.4"
|
||||||
|
|
||||||
def commit = ""
|
def commit = ""
|
||||||
try {
|
try {
|
||||||
|
@ -65,33 +78,129 @@ android {
|
||||||
keyPassword project.getProperties().getOrDefault("releaseKeyPassword", "password")
|
keyPassword project.getProperties().getOrDefault("releaseKeyPassword", "password")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
debug {
|
debug {
|
||||||
applicationIdSuffix ".debug"
|
applicationIdSuffix ".debug"
|
||||||
|
resValue "string", "app_name", "Podcini Debug"
|
||||||
resValue "string", "provider_authority", "ac.mdiq.podcini.debug.provider"
|
resValue "string", "provider_authority", "ac.mdiq.podcini.debug.provider"
|
||||||
}
|
}
|
||||||
release {
|
release {
|
||||||
|
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard.cfg"
|
||||||
|
resValue "string", "app_name", "Podcini"
|
||||||
resValue "string", "provider_authority", "ac.mdiq.podcini.provider"
|
resValue "string", "provider_authority", "ac.mdiq.podcini.provider"
|
||||||
minifyEnabled true
|
minifyEnabled true
|
||||||
shrinkResources true
|
shrinkResources true
|
||||||
signingConfig signingConfigs.releaseConfig
|
signingConfig signingConfigs.releaseConfig
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
applicationVariants.all { variant ->
|
|
||||||
variant.outputs.all { output ->
|
flavorDimensions += ["market"]
|
||||||
|
productFlavors {
|
||||||
|
free {
|
||||||
|
dimension "market"
|
||||||
|
}
|
||||||
|
play {
|
||||||
|
dimension "market"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
applicationVariants.configureEach { variant ->
|
||||||
|
variant.outputs.configureEach { output ->
|
||||||
def applicationName = "Podcini"
|
def applicationName = "Podcini"
|
||||||
outputFileName = "${applicationName}_${variant.buildType.name}_${defaultConfig.versionName}.apk"
|
outputFileName = "${applicationName}_${variant.buildType.name}_${defaultConfig.versionName}.apk"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
packagingOptions {
|
||||||
|
resources {
|
||||||
|
excludes += ["META-INF/LICENSE.txt",
|
||||||
|
"META-INF/NOTICE.txt",
|
||||||
|
"META-INF/CHANGES",
|
||||||
|
"META-INF/README.md"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
compileOptions {
|
||||||
|
sourceCompatibility JavaVersion.VERSION_17
|
||||||
|
targetCompatibility JavaVersion.VERSION_17
|
||||||
|
}
|
||||||
|
|
||||||
|
testOptions {
|
||||||
|
animationsDisabled = true
|
||||||
|
unitTests {
|
||||||
|
includeAndroidResources = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lint {
|
||||||
|
disable "GradleDependency"
|
||||||
|
checkDependencies true
|
||||||
|
warningsAsErrors true
|
||||||
|
abortOnError true
|
||||||
|
checkGeneratedSources = true
|
||||||
|
}
|
||||||
|
|
||||||
|
buildFeatures {
|
||||||
|
viewBinding true
|
||||||
|
}
|
||||||
|
|
||||||
androidResources {
|
androidResources {
|
||||||
additionalParameters "--no-version-vectors"
|
additionalParameters "--no-version-vectors"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks.withType(Test).configureEach {
|
||||||
|
testLogging {
|
||||||
|
exceptionFormat "full"
|
||||||
|
events "skipped", "passed", "failed"
|
||||||
|
showStandardStreams true
|
||||||
|
displayGranularity 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gradle.projectsEvaluated {
|
||||||
|
tasks.withType(JavaCompile).tap {
|
||||||
|
configureEach {
|
||||||
|
options.compilerArgs << "-Xlint"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
apply plugin: 'com.github.spotbugs'
|
||||||
|
|
||||||
|
spotbugs {
|
||||||
|
effort = 'max'
|
||||||
|
reportLevel = 'medium'
|
||||||
|
excludeFilter = rootProject.file('config/spotbugs/exclude.xml')
|
||||||
|
ignoreFailures = true // Handled by printing task
|
||||||
|
}
|
||||||
|
|
||||||
|
gradle.taskGraph.beforeTask { task ->
|
||||||
|
if (task.name.toLowerCase().contains('spotbugs')) {
|
||||||
|
task.doLast {
|
||||||
|
def reportFile = task.project.file("build/reports/spotbugs/playDebug.xml")
|
||||||
|
if (!reportFile.exists()) return
|
||||||
|
def slurped = new groovy.xml.XmlSlurper().parse(reportFile)
|
||||||
|
|
||||||
|
def foundErrors = false
|
||||||
|
slurped['BugInstance'].each { bug ->
|
||||||
|
logger.error "[SpotBugs] ${bug['LongMessage']} [${bug.@'type'}]"
|
||||||
|
bug['SourceLine'].each { line ->
|
||||||
|
logger.error "[SpotBugs] ${line['Message']}"
|
||||||
|
foundErrors = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (foundErrors) {
|
||||||
|
throw new TaskExecutionException(task,
|
||||||
|
new Exception("SpotBugs violations were found. See output above for details."))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation "androidx.core:core-ktx:$coreVersion"
|
implementation "androidx.core:core-ktx:1.12.0"
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||||
|
|
||||||
constraints {
|
constraints {
|
||||||
|
@ -103,83 +212,87 @@ dependencies {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
kapt "androidx.annotation:annotation:$annotationVersion"
|
ksp "androidx.annotation:annotation:1.7.1"
|
||||||
|
|
||||||
implementation "androidx.appcompat:appcompat:$appcompatVersion"
|
implementation "androidx.appcompat:appcompat:1.6.1"
|
||||||
implementation 'androidx.coordinatorlayout:coordinatorlayout:1.2.0'
|
implementation 'androidx.coordinatorlayout:coordinatorlayout:1.2.0'
|
||||||
implementation "androidx.fragment:fragment-ktx:$fragmentVersion"
|
implementation "androidx.fragment:fragment-ktx:1.6.2"
|
||||||
implementation 'androidx.gridlayout:gridlayout:1.0.0'
|
implementation 'androidx.gridlayout:gridlayout:1.0.0'
|
||||||
implementation "androidx.media:media:$mediaVersion"
|
implementation "androidx.media:media:1.7.0"
|
||||||
implementation "androidx.media3:media3-exoplayer:$media3Version"
|
implementation "androidx.media3:media3-exoplayer:1.2.1"
|
||||||
implementation "androidx.media3:media3-ui:$media3Version"
|
implementation "androidx.media3:media3-ui:1.2.1"
|
||||||
implementation "androidx.media3:media3-datasource-okhttp:$media3Version"
|
implementation "androidx.media3:media3-datasource-okhttp:1.2.1"
|
||||||
implementation "androidx.media3:media3-common:$media3Version"
|
implementation "androidx.media3:media3-common:1.2.1"
|
||||||
implementation "androidx.palette:palette-ktx:$paletteVersion"
|
implementation "androidx.palette:palette-ktx:1.0.0"
|
||||||
implementation "androidx.preference:preference-ktx:$preferenceVersion"
|
implementation "androidx.preference:preference-ktx:1.2.1"
|
||||||
implementation "androidx.recyclerview:recyclerview:$recyclerViewVersion"
|
implementation "androidx.recyclerview:recyclerview:1.3.2"
|
||||||
implementation "androidx.viewpager2:viewpager2:$viewPager2Version"
|
implementation "androidx.viewpager2:viewpager2:1.1.0-beta02"
|
||||||
implementation "androidx.work:work-runtime:$workManagerVersion"
|
implementation "androidx.work:work-runtime:2.9.0"
|
||||||
implementation "androidx.core:core-splashscreen:1.0.1"
|
implementation "androidx.core:core-splashscreen:1.0.1"
|
||||||
implementation 'androidx.documentfile:documentfile:1.0.1'
|
implementation 'androidx.documentfile:documentfile:1.0.1'
|
||||||
|
|
||||||
implementation "com.google.android.material:material:$googleMaterialVersion"
|
implementation "com.google.android.material:material:1.11.0"
|
||||||
|
|
||||||
implementation "org.apache.commons:commons-lang3:$commonslangVersion"
|
implementation "org.apache.commons:commons-lang3:3.14.0"
|
||||||
implementation "commons-io:commons-io:$commonsioVersion"
|
implementation "commons-io:commons-io:2.15.1"
|
||||||
implementation "org.jsoup:jsoup:$jsoupVersion"
|
implementation "org.jsoup:jsoup:1.17.2"
|
||||||
|
|
||||||
implementation "com.github.bumptech.glide:glide:$glideVersion"
|
implementation "com.github.bumptech.glide:glide:4.16.0"
|
||||||
implementation "com.github.bumptech.glide:okhttp3-integration:$glideVersion@aar"
|
implementation "com.github.bumptech.glide:okhttp3-integration:4.16.0@aar"
|
||||||
kapt "com.github.bumptech.glide:compiler:$glideVersion"
|
ksp "com.github.bumptech.glide:ksp:4.16.0"
|
||||||
|
|
||||||
implementation "com.squareup.okhttp3:okhttp:$okhttpVersion"
|
implementation "com.squareup.okhttp3:okhttp:4.12.0"
|
||||||
implementation "com.squareup.okhttp3:okhttp-urlconnection:$okhttpVersion"
|
implementation "com.squareup.okhttp3:okhttp-urlconnection:4.12.0"
|
||||||
implementation "com.squareup.okio:okio:$okioVersion"
|
|
||||||
implementation "org.greenrobot:eventbus:$eventbusVersion"
|
|
||||||
kapt "org.greenrobot:eventbus-annotation-processor:$eventbusVersion"
|
|
||||||
implementation "io.reactivex.rxjava2:rxandroid:$rxAndroidVersion"
|
|
||||||
implementation "io.reactivex.rxjava2:rxjava:$rxJavaVersion"
|
|
||||||
|
|
||||||
implementation "com.joanzapata.iconify:android-iconify-fontawesome:$iconifyVersion"
|
implementation "com.squareup.okio:okio:3.7.0"
|
||||||
implementation "com.joanzapata.iconify:android-iconify-material:$iconifyVersion"
|
|
||||||
implementation 'com.leinardi.android:speed-dial:3.2.0'
|
implementation "org.greenrobot:eventbus:3.3.1"
|
||||||
|
kapt "org.greenrobot:eventbus-annotation-processor:3.3.1"
|
||||||
|
|
||||||
|
implementation "io.reactivex.rxjava2:rxandroid:2.1.1"
|
||||||
|
implementation "io.reactivex.rxjava2:rxjava:2.2.21"
|
||||||
|
|
||||||
|
implementation "com.joanzapata.iconify:android-iconify-fontawesome:2.2.2"
|
||||||
|
implementation "com.joanzapata.iconify:android-iconify-material:2.2.2"
|
||||||
|
implementation 'com.leinardi.android:speed-dial:3.3.0'
|
||||||
implementation 'com.github.ByteHamster:SearchPreference:v2.5.0'
|
implementation 'com.github.ByteHamster:SearchPreference:v2.5.0'
|
||||||
implementation 'com.github.skydoves:balloon:1.5.3'
|
implementation 'com.github.skydoves:balloon:1.6.4'
|
||||||
implementation 'com.github.xabaras:RecyclerViewSwipeDecorator:1.3'
|
implementation 'com.github.xabaras:RecyclerViewSwipeDecorator:1.3'
|
||||||
implementation "com.annimon:stream:$annimonStreamVersion"
|
implementation "com.annimon:stream:1.2.2"
|
||||||
|
|
||||||
// Non-free dependencies:
|
// Non-free dependencies:
|
||||||
playImplementation 'com.google.android.play:core-ktx:1.8.0'
|
playImplementation 'com.google.android.play:core-ktx:1.8.1'
|
||||||
compileOnly "com.google.android.wearable:wearable:$wearableSupportVersion"
|
compileOnly "com.google.android.wearable:wearable:2.9.0"
|
||||||
|
|
||||||
|
// this one can not be updated?
|
||||||
androidTestImplementation 'com.nanohttpd:nanohttpd:2.1.1'
|
androidTestImplementation 'com.nanohttpd:nanohttpd:2.1.1'
|
||||||
androidTestImplementation "androidx.test.espresso:espresso-core:$espressoVersion"
|
androidTestImplementation "androidx.test.espresso:espresso-core:3.5.1"
|
||||||
androidTestImplementation "androidx.test.espresso:espresso-contrib:$espressoVersion"
|
androidTestImplementation "androidx.test.espresso:espresso-contrib:3.5.1"
|
||||||
androidTestImplementation "androidx.test.espresso:espresso-intents:$espressoVersion"
|
androidTestImplementation "androidx.test.espresso:espresso-intents:3.5.1"
|
||||||
androidTestImplementation "androidx.test:runner:$runnerVersion"
|
androidTestImplementation "androidx.test:runner:1.5.2"
|
||||||
androidTestImplementation "androidx.test:rules:$rulesVersion"
|
androidTestImplementation "androidx.test:rules:1.5.0"
|
||||||
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
|
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
|
||||||
androidTestImplementation "org.awaitility:awaitility:$awaitilityVersion"
|
androidTestImplementation "org.awaitility:awaitility:4.2.0"
|
||||||
|
|
||||||
implementation "com.annimon:stream:$annimonStreamVersion"
|
implementation "com.annimon:stream:1.2.2"
|
||||||
implementation 'com.github.mfietz:fyydlin:v0.5.0'
|
implementation 'com.github.mfietz:fyydlin:v0.5.0'
|
||||||
|
|
||||||
// Non-free dependencies:
|
// Non-free dependencies:
|
||||||
|
|
||||||
testImplementation "androidx.test:core:$testCoreVersion"
|
testImplementation "androidx.test:core:1.5.0"
|
||||||
testImplementation "org.awaitility:awaitility:$awaitilityVersion"
|
testImplementation "org.awaitility:awaitility:4.2.0"
|
||||||
testImplementation "junit:junit:$junitVersion"
|
testImplementation "junit:junit:4.13.2"
|
||||||
testImplementation 'org.mockito:mockito-inline:5.2.0'
|
testImplementation 'org.mockito:mockito-inline:5.2.0'
|
||||||
testImplementation "org.robolectric:robolectric:$robolectricVersion"
|
testImplementation "org.robolectric:robolectric:4.11.1"
|
||||||
testImplementation 'javax.inject:javax.inject:1'
|
testImplementation 'javax.inject:javax.inject:1'
|
||||||
|
|
||||||
|
|
||||||
playImplementation 'com.google.android.gms:play-services-base:17.5.0'
|
playImplementation 'com.google.android.gms:play-services-base:18.3.0'
|
||||||
freeImplementation 'org.conscrypt:conscrypt-android:2.5.2'
|
freeImplementation 'org.conscrypt:conscrypt-android:2.5.2'
|
||||||
|
|
||||||
playApi 'androidx.mediarouter:mediarouter:1.6.0'
|
playApi 'androidx.mediarouter:mediarouter:1.6.0'
|
||||||
playApi "com.google.android.support:wearable:$wearableSupportVersion"
|
playApi "com.google.android.support:wearable:2.9.0"
|
||||||
playApi 'com.google.android.gms:play-services-cast-framework:21.2.0'
|
playApi 'com.google.android.gms:play-services-cast-framework:21.4.0'
|
||||||
}
|
}
|
||||||
|
|
||||||
kapt {
|
kapt {
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
package de.test.podcini.util.service.download
|
package de.test.podcini.util.service.download
|
||||||
|
|
||||||
|
import ac.mdiq.podcini.BuildConfig
|
||||||
import android.util.Base64
|
import android.util.Base64
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import ac.mdiq.podcini.BuildConfig
|
|
||||||
import fi.iki.elonen.NanoHTTPD
|
import fi.iki.elonen.NanoHTTPD
|
||||||
import fi.iki.elonen.NanoHTTPD.Response.IStatus
|
import fi.iki.elonen.NanoHTTPD.Response.IStatus
|
||||||
import org.apache.commons.io.IOUtils
|
import org.apache.commons.io.IOUtils
|
||||||
|
|
|
@ -19,17 +19,17 @@ class Atom : Namespace() {
|
||||||
state.items.add(state.currentItem!!)
|
state.items.add(state.currentItem!!)
|
||||||
state.currentItem!!.feed = state.feed
|
state.currentItem!!.feed = state.feed
|
||||||
} else if (localName.matches(isText.toRegex())) {
|
} else if (localName.matches(isText.toRegex())) {
|
||||||
val type = attributes.getValue(TEXT_TYPE)
|
val type: String? = attributes.getValue(TEXT_TYPE)
|
||||||
return AtomText(localName, this, type)
|
return AtomText(localName, this, type)
|
||||||
} else if (LINK == localName) {
|
} else if (LINK == localName) {
|
||||||
val href = attributes.getValue(LINK_HREF)
|
val href: String? = attributes.getValue(LINK_HREF)
|
||||||
val rel = attributes.getValue(LINK_REL)
|
val rel: String? = attributes.getValue(LINK_REL)
|
||||||
val parent = state.tagstack.peek()
|
val parent = state.tagstack.peek()
|
||||||
if (parent.name.matches(isFeedItem.toRegex())) {
|
if (parent.name.matches(isFeedItem.toRegex())) {
|
||||||
if (rel == null || LINK_REL_ALTERNATE == rel) {
|
if (rel == null || LINK_REL_ALTERNATE == rel) {
|
||||||
state.currentItem!!.link = href
|
state.currentItem!!.link = href
|
||||||
} else if (LINK_REL_ENCLOSURE == rel) {
|
} else if (LINK_REL_ENCLOSURE == rel) {
|
||||||
val strSize = attributes.getValue(LINK_LENGTH)
|
val strSize: String? = attributes.getValue(LINK_LENGTH)
|
||||||
var size: Long = 0
|
var size: Long = 0
|
||||||
try {
|
try {
|
||||||
if (strSize != null) {
|
if (strSize != null) {
|
||||||
|
@ -38,7 +38,7 @@ class Atom : Namespace() {
|
||||||
} catch (e: NumberFormatException) {
|
} catch (e: NumberFormatException) {
|
||||||
Log.d(TAG, "Length attribute could not be parsed.")
|
Log.d(TAG, "Length attribute could not be parsed.")
|
||||||
}
|
}
|
||||||
val mimeType = getMimeType(attributes.getValue(LINK_TYPE), href)
|
val mimeType: String? = getMimeType(attributes.getValue(LINK_TYPE), href)
|
||||||
|
|
||||||
val currItem = state.currentItem
|
val currItem = state.currentItem
|
||||||
if (isMediaFile(mimeType) && currItem != null && !currItem.hasMedia()) {
|
if (isMediaFile(mimeType) && currItem != null && !currItem.hasMedia()) {
|
||||||
|
@ -49,7 +49,7 @@ class Atom : Namespace() {
|
||||||
}
|
}
|
||||||
} else if (parent.name.matches(isFeed.toRegex())) {
|
} else if (parent.name.matches(isFeed.toRegex())) {
|
||||||
if (rel == null || LINK_REL_ALTERNATE == rel) {
|
if (rel == null || LINK_REL_ALTERNATE == rel) {
|
||||||
val type = attributes.getValue(LINK_TYPE)
|
val type: String? = attributes.getValue(LINK_TYPE)
|
||||||
/*
|
/*
|
||||||
* Use as link if a) no type-attribute is given and
|
* Use as link if a) no type-attribute is given and
|
||||||
* feed-object has no link yet b) type of link is
|
* feed-object has no link yet b) type of link is
|
||||||
|
@ -60,20 +60,20 @@ class Atom : Namespace() {
|
||||||
state.feed.link = href
|
state.feed.link = href
|
||||||
} else if (LINK_TYPE_ATOM == type || LINK_TYPE_RSS == type) {
|
} else if (LINK_TYPE_ATOM == type || LINK_TYPE_RSS == type) {
|
||||||
// treat as podlove alternate feed
|
// treat as podlove alternate feed
|
||||||
var title = attributes.getValue(LINK_TITLE)
|
var title: String? = attributes.getValue(LINK_TITLE)
|
||||||
if (title.isEmpty()) {
|
if (title.isNullOrEmpty()) {
|
||||||
title = href
|
title = href?:""
|
||||||
}
|
}
|
||||||
state.addAlternateFeedUrl(title!!, href)
|
if (!href.isNullOrEmpty()) state.addAlternateFeedUrl(title, href)
|
||||||
}
|
}
|
||||||
} else if (LINK_REL_ARCHIVES == rel) {
|
} else if (LINK_REL_ARCHIVES == rel) {
|
||||||
val type = attributes.getValue(LINK_TYPE)
|
val type: String? = attributes.getValue(LINK_TYPE)
|
||||||
if (LINK_TYPE_ATOM == type || LINK_TYPE_RSS == type) {
|
if (LINK_TYPE_ATOM == type || LINK_TYPE_RSS == type) {
|
||||||
var title = attributes.getValue(LINK_TITLE)
|
var title: String? = attributes.getValue(LINK_TITLE)
|
||||||
if (title.isEmpty()) {
|
if (title.isNullOrEmpty()) {
|
||||||
title = href
|
title = href?:""
|
||||||
}
|
}
|
||||||
state.addAlternateFeedUrl(title!!, href)
|
if (!href.isNullOrEmpty()) state.addAlternateFeedUrl(title, href)
|
||||||
} else if (LINK_TYPE_HTML == type || LINK_TYPE_XHTML == type) {
|
} else if (LINK_TYPE_HTML == type || LINK_TYPE_XHTML == type) {
|
||||||
//A Link such as to a directory such as iTunes
|
//A Link such as to a directory such as iTunes
|
||||||
}
|
}
|
||||||
|
@ -205,7 +205,7 @@ class Atom : Namespace() {
|
||||||
*/
|
*/
|
||||||
private const val isText = ("$TITLE|$CONTENT|$SUBTITLE|$SUMMARY")
|
private const val isText = ("$TITLE|$CONTENT|$SUBTITLE|$SUMMARY")
|
||||||
|
|
||||||
private const val isFeed = FEED + "|" + ac.mdiq.podcini.feed.parser.namespace.Rss20.CHANNEL
|
private const val isFeed = FEED + "|" + Rss20.CHANNEL
|
||||||
private const val isFeedItem = ENTRY + "|" + ac.mdiq.podcini.feed.parser.namespace.Rss20.ITEM
|
private const val isFeedItem = ENTRY + "|" + Rss20.ITEM
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,14 +10,14 @@ class Itunes : Namespace() {
|
||||||
override fun handleElementStart(localName: String, state: ac.mdiq.podcini.feed.parser.HandlerState,
|
override fun handleElementStart(localName: String, state: ac.mdiq.podcini.feed.parser.HandlerState,
|
||||||
attributes: Attributes): SyndElement {
|
attributes: Attributes): SyndElement {
|
||||||
if (IMAGE == localName) {
|
if (IMAGE == localName) {
|
||||||
val url = attributes.getValue(IMAGE_HREF)
|
val url: String? = attributes.getValue(IMAGE_HREF)
|
||||||
|
|
||||||
if (state.currentItem != null) {
|
if (state.currentItem != null) {
|
||||||
state.currentItem!!.imageUrl = url
|
state.currentItem!!.imageUrl = url
|
||||||
} else {
|
} else {
|
||||||
// this is the feed image
|
// this is the feed image
|
||||||
// prefer to all other images
|
// prefer to all other images
|
||||||
if (url.isNotEmpty()) {
|
if (!url.isNullOrEmpty()) {
|
||||||
state.feed.imageUrl = url
|
state.feed.imageUrl = url
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,9 +15,9 @@ import java.util.concurrent.TimeUnit
|
||||||
class Media : Namespace() {
|
class Media : Namespace() {
|
||||||
override fun handleElementStart(localName: String, state: HandlerState, attributes: Attributes): SyndElement {
|
override fun handleElementStart(localName: String, state: HandlerState, attributes: Attributes): SyndElement {
|
||||||
if (CONTENT == localName) {
|
if (CONTENT == localName) {
|
||||||
val url = attributes.getValue(DOWNLOAD_URL)
|
val url: String? = attributes.getValue(DOWNLOAD_URL)
|
||||||
val defaultStr = attributes.getValue(DEFAULT)
|
val defaultStr: String? = attributes.getValue(DEFAULT)
|
||||||
val medium = attributes.getValue(MEDIUM)
|
val medium: String? = attributes.getValue(MEDIUM)
|
||||||
var validTypeMedia = false
|
var validTypeMedia = false
|
||||||
var validTypeImage = false
|
var validTypeImage = false
|
||||||
val isDefault = "true" == defaultStr
|
val isDefault = "true" == defaultStr
|
||||||
|
@ -44,7 +44,7 @@ class Media : Namespace() {
|
||||||
|
|
||||||
if (state.currentItem != null && (state.currentItem!!.media == null || isDefault) && url != null && validTypeMedia) {
|
if (state.currentItem != null && (state.currentItem!!.media == null || isDefault) && url != null && validTypeMedia) {
|
||||||
var size: Long = 0
|
var size: Long = 0
|
||||||
val sizeStr = attributes.getValue(SIZE)
|
val sizeStr: String? = attributes.getValue(SIZE)
|
||||||
if (!sizeStr.isNullOrEmpty()) {
|
if (!sizeStr.isNullOrEmpty()) {
|
||||||
try {
|
try {
|
||||||
size = sizeStr.toLong()
|
size = sizeStr.toLong()
|
||||||
|
@ -53,7 +53,7 @@ class Media : Namespace() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var durationMs = 0
|
var durationMs = 0
|
||||||
val durationStr = attributes.getValue(DURATION)
|
val durationStr: String? = attributes.getValue(DURATION)
|
||||||
if (!durationStr.isNullOrEmpty()) {
|
if (!durationStr.isNullOrEmpty()) {
|
||||||
try {
|
try {
|
||||||
val duration = durationStr.toLong()
|
val duration = durationStr.toLong()
|
||||||
|
@ -71,7 +71,7 @@ class Media : Namespace() {
|
||||||
state.currentItem!!.imageUrl = url
|
state.currentItem!!.imageUrl = url
|
||||||
}
|
}
|
||||||
} else if (IMAGE == localName) {
|
} else if (IMAGE == localName) {
|
||||||
val url = attributes.getValue(IMAGE_URL)
|
val url: String? = attributes.getValue(IMAGE_URL)
|
||||||
if (url != null) {
|
if (url != null) {
|
||||||
if (state.currentItem != null) {
|
if (state.currentItem != null) {
|
||||||
state.currentItem!!.imageUrl = url
|
state.currentItem!!.imageUrl = url
|
||||||
|
@ -82,7 +82,7 @@ class Media : Namespace() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (DESCRIPTION == localName) {
|
} else if (DESCRIPTION == localName) {
|
||||||
val type = attributes.getValue(DESCRIPTION_TYPE)
|
val type: String? = attributes.getValue(DESCRIPTION_TYPE)
|
||||||
return AtomText(localName, this, type)
|
return AtomText(localName, this, type)
|
||||||
}
|
}
|
||||||
return SyndElement(localName, this)
|
return SyndElement(localName, this)
|
||||||
|
|
|
@ -9,13 +9,13 @@ class PodcastIndex : Namespace() {
|
||||||
override fun handleElementStart(localName: String, state: HandlerState,
|
override fun handleElementStart(localName: String, state: HandlerState,
|
||||||
attributes: Attributes): SyndElement {
|
attributes: Attributes): SyndElement {
|
||||||
if (FUNDING == localName) {
|
if (FUNDING == localName) {
|
||||||
val href = attributes.getValue(URL)
|
val href: String? = attributes.getValue(URL)
|
||||||
val funding = FeedFunding(href, "")
|
val funding = FeedFunding(href, "")
|
||||||
state.currentFunding = funding
|
state.currentFunding = funding
|
||||||
state.feed.addPayment(state.currentFunding!!)
|
state.feed.addPayment(state.currentFunding!!)
|
||||||
} else if (CHAPTERS == localName) {
|
} else if (CHAPTERS == localName) {
|
||||||
val href = attributes.getValue(URL)
|
val href: String? = attributes.getValue(URL)
|
||||||
if (href.isNotEmpty()) {
|
if (!href.isNullOrEmpty()) {
|
||||||
state.currentItem!!.podcastIndexChapterUrl = href
|
state.currentItem!!.podcastIndexChapterUrl = href
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,14 +22,14 @@ class Rss20 : Namespace() {
|
||||||
state.items.add(state.currentItem!!)
|
state.items.add(state.currentItem!!)
|
||||||
state.currentItem!!.feed = state.feed
|
state.currentItem!!.feed = state.feed
|
||||||
} else if (ENCLOSURE == localName && ITEM == state.tagstack.peek()?.name) {
|
} else if (ENCLOSURE == localName && ITEM == state.tagstack.peek()?.name) {
|
||||||
val url = attributes.getValue(ENC_URL)
|
val url: String? = attributes.getValue(ENC_URL)
|
||||||
val mimeType = getMimeType(attributes.getValue(ENC_TYPE), url)
|
val mimeType: String? = getMimeType(attributes.getValue(ENC_TYPE), url)
|
||||||
|
|
||||||
val validUrl = url.isNotEmpty()
|
val validUrl = !url.isNullOrBlank()
|
||||||
if (state.currentItem?.media == null && isMediaFile(mimeType) && validUrl) {
|
if (state.currentItem?.media == null && isMediaFile(mimeType) && validUrl) {
|
||||||
var size: Long = 0
|
var size: Long = 0
|
||||||
try {
|
try {
|
||||||
size = attributes.getValue(ENC_LEN).toLong()
|
size = attributes.getValue(ENC_LEN)?.toLong() ?: 0
|
||||||
if (size < 16384) {
|
if (size < 16384) {
|
||||||
// less than 16kb is suspicious, check manually
|
// less than 16kb is suspicious, check manually
|
||||||
size = 0
|
size = 0
|
||||||
|
|
|
@ -12,13 +12,13 @@ class SimpleChapters : Namespace() {
|
||||||
if (currentItem != null) {
|
if (currentItem != null) {
|
||||||
if (localName == CHAPTERS) {
|
if (localName == CHAPTERS) {
|
||||||
currentItem.chapters = mutableListOf()
|
currentItem.chapters = mutableListOf()
|
||||||
} else if (localName == CHAPTER && attributes.getValue(START).isNotEmpty()) {
|
} else if (localName == CHAPTER && !attributes.getValue(START).isNullOrEmpty()) {
|
||||||
// if the chapter's START is empty, we don't need to do anything
|
// if the chapter's START is empty, we don't need to do anything
|
||||||
try {
|
try {
|
||||||
val start= parseTimeString(attributes.getValue(START))
|
val start= parseTimeString(attributes.getValue(START))
|
||||||
val title = attributes.getValue(TITLE)
|
val title: String? = attributes.getValue(TITLE)
|
||||||
val link = attributes.getValue(HREF)
|
val link: String? = attributes.getValue(HREF)
|
||||||
val imageUrl = attributes.getValue(IMAGE)
|
val imageUrl: String? = attributes.getValue(IMAGE)
|
||||||
val chapter = Chapter(start, title, link, imageUrl)
|
val chapter = Chapter(start, title, link, imageUrl)
|
||||||
currentItem.chapters?.add(chapter)
|
currentItem.chapters?.add(chapter)
|
||||||
} catch (e: NumberFormatException) {
|
} catch (e: NumberFormatException) {
|
||||||
|
|
46
build.gradle
46
build.gradle
|
@ -13,6 +13,10 @@ buildscript {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id 'com.google.devtools.ksp' version '1.9.22-1.0.17' apply false
|
||||||
|
}
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
|
@ -21,48 +25,6 @@ allprojects {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
project.ext {
|
|
||||||
// AndroidX
|
|
||||||
annotationVersion = "1.7.1"
|
|
||||||
appcompatVersion = "1.6.1"
|
|
||||||
coreVersion = "1.12.0"
|
|
||||||
fragmentVersion = "1.6.2"
|
|
||||||
mediaVersion = "1.7.0"
|
|
||||||
paletteVersion = "1.0.0"
|
|
||||||
preferenceVersion = "1.2.1"
|
|
||||||
recyclerViewVersion = "1.3.2"
|
|
||||||
viewPager2Version = "1.1.0-beta02"
|
|
||||||
workManagerVersion = "2.9.0"
|
|
||||||
googleMaterialVersion = "1.11.0"
|
|
||||||
|
|
||||||
// Third-party
|
|
||||||
commonslangVersion = "3.14.0"
|
|
||||||
commonsioVersion = "2.15.1"
|
|
||||||
jsoupVersion = "1.17.2"
|
|
||||||
glideVersion = "4.16.0"
|
|
||||||
okhttpVersion = "4.12.0"
|
|
||||||
okioVersion = "3.7.0"
|
|
||||||
eventbusVersion = "3.3.1"
|
|
||||||
rxAndroidVersion = "2.1.1"
|
|
||||||
rxJavaVersion = "2.2.21"
|
|
||||||
iconifyVersion = "2.2.2"
|
|
||||||
annimonStreamVersion = "1.2.2"
|
|
||||||
media3Version = "1.2.1"
|
|
||||||
|
|
||||||
// Google Play build
|
|
||||||
wearableSupportVersion = "2.6.0"
|
|
||||||
|
|
||||||
//Tests
|
|
||||||
awaitilityVersion = "4.2.0"
|
|
||||||
junitVersion = "4.13.2"
|
|
||||||
junit5Version = "5.10.1"
|
|
||||||
robolectricVersion = "4.11.1"
|
|
||||||
espressoVersion = "3.5.0"
|
|
||||||
runnerVersion = "1.5.2"
|
|
||||||
rulesVersion = "1.5.0"
|
|
||||||
testCoreVersion = "1.5.0"
|
|
||||||
}
|
|
||||||
|
|
||||||
apply plugin: "checkstyle"
|
apply plugin: "checkstyle"
|
||||||
checkstyle {
|
checkstyle {
|
||||||
toolVersion '10.3.1'
|
toolVersion '10.3.1'
|
||||||
|
|
|
@ -63,3 +63,9 @@
|
||||||
* added items count in FeedItemList header
|
* added items count in FeedItemList header
|
||||||
* fixed bug in FeedItemList when filtered list has no items
|
* fixed bug in FeedItemList when filtered list has no items
|
||||||
* buildConfig is set in build.gradle instead of gradle.properties
|
* buildConfig is set in build.gradle instead of gradle.properties
|
||||||
|
|
||||||
|
## 4.2.4
|
||||||
|
|
||||||
|
* fixed the "getValue() can not be null" bug
|
||||||
|
* enabled ksp for Kotlin builds
|
||||||
|
* cleaned up build.gradle files
|
109
common.gradle
109
common.gradle
|
@ -1,109 +0,0 @@
|
||||||
android {
|
|
||||||
defaultConfig {
|
|
||||||
minSdk 21
|
|
||||||
compileSdk 34
|
|
||||||
targetSdk 34
|
|
||||||
|
|
||||||
kotlinOptions {
|
|
||||||
jvmTarget = '17'
|
|
||||||
}
|
|
||||||
|
|
||||||
vectorDrawables.useSupportLibrary false
|
|
||||||
vectorDrawables.generatedDensities = []
|
|
||||||
|
|
||||||
testApplicationId "ac.mdiq.podcini.tests"
|
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
|
||||||
}
|
|
||||||
|
|
||||||
buildTypes {
|
|
||||||
release {
|
|
||||||
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard.cfg"
|
|
||||||
resValue "string", "app_name", "Podcini"
|
|
||||||
}
|
|
||||||
debug {
|
|
||||||
resValue "string", "app_name", "Podcini Debug"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
packagingOptions {
|
|
||||||
resources {
|
|
||||||
excludes += ["META-INF/LICENSE.txt",
|
|
||||||
"META-INF/NOTICE.txt",
|
|
||||||
"META-INF/CHANGES",
|
|
||||||
"META-INF/README.md"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
compileOptions {
|
|
||||||
sourceCompatibility JavaVersion.VERSION_17
|
|
||||||
targetCompatibility JavaVersion.VERSION_17
|
|
||||||
}
|
|
||||||
|
|
||||||
testOptions {
|
|
||||||
animationsDisabled = true
|
|
||||||
unitTests {
|
|
||||||
includeAndroidResources = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lint {
|
|
||||||
disable "GradleDependency"
|
|
||||||
checkDependencies true
|
|
||||||
warningsAsErrors true
|
|
||||||
abortOnError true
|
|
||||||
checkGeneratedSources = true
|
|
||||||
}
|
|
||||||
|
|
||||||
buildFeatures {
|
|
||||||
viewBinding true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.withType(Test).configureEach {
|
|
||||||
testLogging {
|
|
||||||
exceptionFormat "full"
|
|
||||||
events "skipped", "passed", "failed"
|
|
||||||
showStandardStreams true
|
|
||||||
displayGranularity 2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
gradle.projectsEvaluated {
|
|
||||||
tasks.withType(JavaCompile).tap {
|
|
||||||
configureEach {
|
|
||||||
options.compilerArgs << "-Xlint"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
apply plugin: 'com.github.spotbugs'
|
|
||||||
|
|
||||||
spotbugs {
|
|
||||||
effort = 'max'
|
|
||||||
reportLevel = 'medium'
|
|
||||||
excludeFilter = rootProject.file('config/spotbugs/exclude.xml')
|
|
||||||
ignoreFailures = true // Handled by printing task
|
|
||||||
}
|
|
||||||
|
|
||||||
gradle.taskGraph.beforeTask { task ->
|
|
||||||
if (task.name.toLowerCase().contains('spotbugs')) {
|
|
||||||
task.doLast {
|
|
||||||
def reportFile = task.project.file("build/reports/spotbugs/playDebug.xml")
|
|
||||||
if (!reportFile.exists()) return
|
|
||||||
def slurped = new groovy.xml.XmlSlurper().parse(reportFile)
|
|
||||||
|
|
||||||
def foundErrors = false
|
|
||||||
slurped['BugInstance'].each { bug ->
|
|
||||||
logger.error "[SpotBugs] ${bug['LongMessage']} [${bug.@'type'}]"
|
|
||||||
bug['SourceLine'].each { line ->
|
|
||||||
logger.error "[SpotBugs] ${line['Message']}"
|
|
||||||
foundErrors = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (foundErrors) {
|
|
||||||
throw new TaskExecutionException(task,
|
|
||||||
new Exception("SpotBugs violations were found. See output above for details."))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
|
||||||
|
Version 4.2.4 brings several changes:
|
||||||
|
|
||||||
|
* fixed the "getValue() can not be null" bug
|
||||||
|
* enabled ksp for Kotlin builds
|
||||||
|
* cleaned up build.gradle files
|
|
@ -1,11 +0,0 @@
|
||||||
android {
|
|
||||||
flavorDimensions += ["market"]
|
|
||||||
productFlavors {
|
|
||||||
free {
|
|
||||||
dimension "market"
|
|
||||||
}
|
|
||||||
play {
|
|
||||||
dimension "market"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue