Merge branch 'develop' into dependabot/gradle/org.jetbrains.kotlinx-kotlinx-coroutines-android-1.6.0-native-mt

This commit is contained in:
Nite 2022-02-08 19:57:01 +01:00
commit bf96f36cb4
No known key found for this signature in database
GPG Key ID: 1D1AD59B1C6386C1
43 changed files with 783 additions and 1185 deletions

View File

@ -10,9 +10,9 @@ jobs:
- checkout
- restore_cache:
keys:
- v1-ultrasonic-{{ .Branch }}-{{ checksum "dependencies.gradle" }}
- v1-ultrasonic-{{ .Branch }}
- v1-ultrasonic
- v2-ultrasonic-{{ .Branch }}-{{ checksum "gradle/libs.versions.toml" }}
- v2-ultrasonic-{{ .Branch }}
- v2-ultrasonic
- run:
name: configure gradle.properties for CI building
command: |
@ -44,7 +44,7 @@ jobs:
- save_cache:
paths:
- ~/.gradle
key: v1-ultrasonic-{{ .Branch }}-{{ checksum "dependencies.gradle" }}
key: v1-ultrasonic-{{ .Branch }}-{{ checksum "gradle/libs.versions.toml" }}
- store_artifacts:
path: ultrasonic/build/reports
destination: reports
@ -81,9 +81,9 @@ jobs:
- checkout
- restore_cache:
keys:
- v1-ultrasonic-{{ .Branch }}-{{ checksum "dependencies.gradle" }}
- v1-ultrasonic-{{ .Branch }}
- v1-ultrasonic
- v2-ultrasonic-{{ .Branch }}-{{ checksum "gradle/libs.versions.toml" }}
- v2-ultrasonic-{{ .Branch }}
- v2-ultrasonic
- run:
name: decrypt ultrasonic-keystore
command: openssl aes-256-cbc -K ${ULTRASONIC_KEYSTORE_KEY} -iv ${ULTRASONIC_KEYSTORE_IV} -in ultrasonic-keystore.enc -out ultrasonic-keystore -d

View File

@ -1,6 +1,6 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
apply from: 'dependencies.gradle'
apply from: 'gradle/versions.gradle'
ext.bootstrap = [
kotlinModule : "${project.rootDir}/gradle_scripts/kotlin-module-bootstrap.gradle",
@ -13,11 +13,11 @@ buildscript {
maven { url "https://plugins.gradle.org/m2/" }
}
dependencies {
classpath gradlePlugins.gradle
classpath gradlePlugins.kotlin
classpath gradlePlugins.ktlintGradle
classpath gradlePlugins.detekt
classpath gradlePlugins.jacoco
classpath libs.gradle
classpath libs.kotlin
classpath libs.ktlintGradle
classpath libs.detekt
classpath libs.jacoco
}
}
@ -47,6 +47,6 @@ allprojects {
apply from: 'gradle_scripts/jacoco.gradle'
wrapper {
gradleVersion(versions.gradle)
gradleVersion(libs.versions.gradle.get())
distributionType("all")
}

View File

@ -8,7 +8,7 @@ ext {
}
dependencies {
implementation androidSupport.roomRuntime
implementation androidSupport.roomKtx
kapt androidSupport.room
implementation libs.roomRuntime
implementation libs.roomKtx
kapt libs.room
}

View File

@ -1,24 +1,24 @@
apply from: bootstrap.kotlinModule
dependencies {
api other.retrofit
api other.jacksonConverter
api other.koinCore
api libs.retrofit
api libs.jacksonConverter
api libs.koinCore
implementation(other.jacksonKotlin) {
implementation(libs.jacksonKotlin) {
exclude module: 'kotlin-reflect'
}
implementation other.kotlinReflect // for jackson kotlin, but to use the same version
implementation other.okhttpLogging
implementation other.timber
implementation libs.kotlinReflect // for jackson kotlin, but to use the same version
implementation libs.okhttpLogging
implementation libs.timber
testImplementation testing.kotlinJunit
testImplementation testing.mockito
testImplementation testing.mockitoInline
testImplementation testing.mockitoKotlin
testImplementation testing.kluent
testImplementation testing.mockWebServer
testImplementation testing.apacheCodecs
testImplementation libs.kotlinJunit
testImplementation libs.mockito
testImplementation libs.mockitoInline
testImplementation libs.mockitoKotlin
testImplementation libs.kluent
testImplementation libs.mockWebServer
testImplementation libs.apacheCodecs
}
ext {

View File

@ -1,8 +1,8 @@
package org.moire.ultrasonic.api.subsonic
import okhttp3.mockwebserver.MockResponse
import org.amshove.kluent.`should be equal to`
import org.amshove.kluent.`should be`
import org.amshove.kluent.`should be equal to`
import org.amshove.kluent.`should not be`
import org.junit.Test

View File

@ -1,8 +1,8 @@
package org.moire.ultrasonic.api.subsonic
import okhttp3.mockwebserver.MockResponse
import org.amshove.kluent.`should be equal to`
import org.amshove.kluent.`should be`
import org.amshove.kluent.`should be equal to`
import org.amshove.kluent.`should not be`
import org.junit.Test

View File

@ -1,7 +1,7 @@
package org.moire.ultrasonic.api.subsonic
import org.amshove.kluent.`should be equal to`
import org.amshove.kluent.`should be`
import org.amshove.kluent.`should be equal to`
import org.amshove.kluent.`should not be`
import org.junit.Test
import org.moire.ultrasonic.api.subsonic.models.MusicDirectory

View File

@ -1,8 +1,8 @@
package org.moire.ultrasonic.api.subsonic
import okhttp3.mockwebserver.MockResponse
import org.amshove.kluent.`should be equal to`
import org.amshove.kluent.`should be`
import org.amshove.kluent.`should be equal to`
import org.amshove.kluent.`should not be`
import org.junit.Test

View File

@ -83,7 +83,7 @@ class SubsonicAPIClient(
// Create the Retrofit instance, and register a special converter factory
// It will update our protocol version to the correct version, once we made a successful call
val retrofit: Retrofit = Retrofit.Builder()
private val retrofit: Retrofit = Retrofit.Builder()
.baseUrl("${config.baseUrl}/rest/")
.client(okHttpClient)
.addConverterFactory(
@ -113,13 +113,16 @@ class SubsonicAPIClient(
this.addInterceptor(loggingInterceptor)
}
@SuppressWarnings("TrustAllX509TrustManager", "EmptyFunctionBlock")
private fun OkHttpClient.Builder.allowSelfSignedCertificates() {
val trustManager = object : X509TrustManager {
override fun checkClientTrusted(p0: Array<out X509Certificate>?, p1: String?) {}
override fun checkServerTrusted(p0: Array<out X509Certificate>?, p1: String?) {}
override fun getAcceptedIssuers(): Array<X509Certificate> = emptyArray()
}
val trustManager =
@Suppress("CustomX509TrustManager")
object : X509TrustManager {
@Suppress("TrustAllX509TrustManager")
override fun checkClientTrusted(p0: Array<out X509Certificate>?, p1: String?) {}
@Suppress("TrustAllX509TrustManager")
override fun checkServerTrusted(p0: Array<out X509Certificate>?, p1: String?) {}
override fun getAcceptedIssuers(): Array<X509Certificate> = emptyArray()
}
val sslContext = SSLContext.getInstance("SSL")
sslContext.init(null, arrayOf(trustManager), SecureRandom())

View File

@ -1,110 +0,0 @@
ext.versions = [
minSdk : 21,
targetSdk : 30,
compileSdk : 30,
// You need to run ./gradlew wrapper after updating the version
gradle : '7.2',
navigation : "2.3.5",
gradlePlugin : "4.2.2",
androidxcore : "1.6.0",
ktlint : "0.37.1",
ktlintGradle : "10.2.0",
detekt : "1.19.0",
jacoco : "0.8.7",
preferences : "1.1.1",
media : "1.3.1",
androidSupport : "28.0.0",
androidLegacySupport : "1.0.0",
androidSupportDesign : "1.4.0",
constraintLayout : "2.1.1",
multidex : "2.0.1",
room : "2.3.0",
kotlin : "1.5.31",
kotlinxCoroutines : "1.6.0-native-mt",
viewModelKtx : "2.3.0",
retrofit : "2.6.4",
jackson : "2.9.5",
okhttp : "3.12.13",
koin : "3.0.2",
picasso : "2.71828",
junit4 : "4.13.2",
junit5 : "5.8.1",
mockito : "4.1.0",
mockitoKotlin : "4.0.0",
kluent : "1.68",
apacheCodecs : "1.15",
robolectric : "4.6.1",
timber : "4.7.1",
fastScroll : "2.0.1",
colorPicker : "2.2.3",
rxJava : "3.1.2",
rxAndroid : "3.0.0",
multiType : "4.3.0",
]
ext.gradlePlugins = [
gradle : "com.android.tools.build:gradle:$versions.gradlePlugin",
kotlin : "org.jetbrains.kotlin:kotlin-gradle-plugin:$versions.kotlin",
ktlintGradle : "org.jlleitschuh.gradle:ktlint-gradle:$versions.ktlintGradle",
detekt : "io.gitlab.arturbosch.detekt:detekt-gradle-plugin:$versions.detekt",
jacoco : "org.jacoco:org.jacoco.core:$versions.jacoco",
]
ext.androidSupport = [
core : "androidx.core:core-ktx:$versions.androidxcore",
support : "androidx.legacy:legacy-support-v4:$versions.androidLegacySupport",
design : "com.google.android.material:material:$versions.androidSupportDesign",
annotations : "com.android.support:support-annotations:$versions.androidSupport",
multidex : "androidx.multidex:multidex:$versions.multidex",
constraintLayout : "androidx.constraintlayout:constraintlayout:$versions.constraintLayout",
room : "androidx.room:room-compiler:$versions.room",
roomRuntime : "androidx.room:room-runtime:$versions.room",
roomKtx : "androidx.room:room-ktx:$versions.room",
viewModelKtx : "androidx.lifecycle:lifecycle-viewmodel-ktx:$versions.viewModelKtx",
navigationFragment : "androidx.navigation:navigation-fragment:$versions.navigation",
navigationUi : "androidx.navigation:navigation-ui:$versions.navigation",
navigationFragmentKtx : "androidx.navigation:navigation-fragment-ktx:$versions.navigation",
navigationUiKtx : "androidx.navigation:navigation-ui-ktx:$versions.navigation",
navigationFeature : "androidx.navigation:navigation-dynamic-features-fragment:$versions.navigation",
preferences : "androidx.preference:preference:$versions.preferences",
media : "androidx.media:media:$versions.media",
]
ext.other = [
kotlinStdlib : "org.jetbrains.kotlin:kotlin-stdlib:$versions.kotlin",
kotlinReflect : "org.jetbrains.kotlin:kotlin-reflect:$versions.kotlin",
kotlinxCoroutines : "org.jetbrains.kotlinx:kotlinx-coroutines-android:$versions.kotlinxCoroutines",
retrofit : "com.squareup.retrofit2:retrofit:$versions.retrofit",
gsonConverter : "com.squareup.retrofit2:converter-gson:$versions.retrofit",
jacksonConverter : "com.squareup.retrofit2:converter-jackson:$versions.retrofit",
jacksonKotlin : "com.fasterxml.jackson.module:jackson-module-kotlin:$versions.jackson",
okhttpLogging : "com.squareup.okhttp3:logging-interceptor:$versions.okhttp",
koinCore : "io.insert-koin:koin-core:$versions.koin",
koinAndroid : "io.insert-koin:koin-android:$versions.koin",
koinViewModel : "io.insert-koin:koin-android-viewmodel:$versions.koin",
picasso : "com.squareup.picasso:picasso:$versions.picasso",
timber : "com.jakewharton.timber:timber:$versions.timber",
fastScroll : "com.simplecityapps:recyclerview-fastscroll:$versions.fastScroll",
colorPickerView : "com.github.skydoves:colorpickerview:$versions.colorPicker",
rxJava : "io.reactivex.rxjava3:rxjava:$versions.rxJava",
rxAndroid : "io.reactivex.rxjava3:rxandroid:$versions.rxAndroid",
multiType : "com.drakeet.multitype:multitype:$versions.multiType",
]
ext.testing = [
junit : "junit:junit:$versions.junit4",
junitVintage : "org.junit.vintage:junit-vintage-engine:$versions.junit5",
kotlinJunit : "org.jetbrains.kotlin:kotlin-test-junit:$versions.kotlin",
mockitoKotlin : "org.mockito.kotlin:mockito-kotlin:$versions.mockitoKotlin",
mockito : "org.mockito:mockito-core:$versions.mockito",
mockitoInline : "org.mockito:mockito-inline:$versions.mockito",
kluent : "org.amshove.kluent:kluent:$versions.kluent",
kluentAndroid : "org.amshove.kluent:kluent-android:$versions.kluent",
mockWebServer : "com.squareup.okhttp3:mockwebserver:$versions.okhttp",
apacheCodecs : "commons-codec:commons-codec:$versions.apacheCodecs",
robolectric : "org.robolectric:robolectric:$versions.robolectric"
]

View File

@ -0,0 +1,4 @@
Others
- #671: Bump versions.mockito from 4.1.0 to 4.3.1.
- Update translations.

View File

@ -0,0 +1,4 @@
Otros
- #671: Actualizado versions.mockito de 4.1.0 a 4.3.1.
- Traducciones actualizadas.

100
gradle/libs.versions.toml Normal file
View File

@ -0,0 +1,100 @@
[versions]
# You need to run ./gradlew wrapper after updating the version
gradle = "7.3.2"
navigation = "2.3.5"
gradlePlugin = "7.0.4"
androidxcore = "1.6.0"
ktlint = "0.43.2"
ktlintGradle = "10.2.0"
detekt = "1.19.0"
jacoco = "0.8.7"
preferences = "1.1.1"
media = "1.3.1"
androidSupport = "28.0.0"
androidLegacySupport = "1.0.0"
androidSupportDesign = "1.4.0"
constraintLayout = "2.1.1"
multidex = "2.0.1"
room = "2.4.0"
kotlin = "1.6.10"
kotlinxCoroutines = "1.6.0-native-mt"
viewModelKtx = "2.3.0"
retrofit = "2.6.4"
jackson = "2.9.5"
okhttp = "3.12.13"
koin = "3.0.2"
picasso = "2.71828"
junit4 = "4.13.2"
junit5 = "5.8.1"
mockito = "4.3.1"
mockitoKotlin = "4.0.0"
kluent = "1.68"
apacheCodecs = "1.15"
robolectric = "4.6.1"
timber = "4.7.1"
fastScroll = "2.0.1"
colorPicker = "2.2.3"
rxJava = "3.1.2"
rxAndroid = "3.0.0"
multiType = "4.3.0"
[libraries]
gradle = { module = "com.android.tools.build:gradle", version.ref = "gradlePlugin" }
kotlin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }
ktlintGradle = { module = "org.jlleitschuh.gradle:ktlint-gradle", version.ref = "ktlintGradle" }
detekt = { module = "io.gitlab.arturbosch.detekt:detekt-gradle-plugin", version.ref = "detekt" }
jacoco = { module = "org.jacoco:org.jacoco.core", version.ref = "jacoco" }
core = { module = "androidx.core:core-ktx", version.ref = "androidxcore" }
support = { module = "androidx.legacy:legacy-support-v4", version.ref = "androidLegacySupport" }
design = { module = "com.google.android.material:material", version.ref = "androidSupportDesign" }
annotations = { module = "com.android.support:support-annotations", version.ref = "androidSupport" }
multidex = { module = "androidx.multidex:multidex", version.ref = "multidex" }
constraintLayout = { module = "androidx.constraintlayout:constraintlayout", version.ref = "constraintLayout" }
room = { module = "androidx.room:room-compiler", version.ref = "room" }
roomRuntime = { module = "androidx.room:room-runtime", version.ref = "room" }
roomKtx = { module = "androidx.room:room-ktx", version.ref = "room" }
viewModelKtx = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref = "viewModelKtx" }
navigationFragment = { module = "androidx.navigation:navigation-fragment", version.ref = "navigation" }
navigationUi = { module = "androidx.navigation:navigation-ui", version.ref = "navigation" }
navigationFragmentKtx = { module = "androidx.navigation:navigation-fragment-ktx", version.ref = "navigation" }
navigationUiKtx = { module = "androidx.navigation:navigation-ui-ktx", version.ref = "navigation" }
navigationFeature = { module = "androidx.navigation:navigation-dynamic-features-fragment", version.ref = "navigation" }
preferences = { module = "androidx.preference:preference", version.ref = "preferences" }
media = { module = "androidx.media:media", version.ref = "media" }
kotlinStdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin" }
kotlinReflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin" }
kotlinxCoroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "kotlinxCoroutines" }
retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" }
gsonConverter = { module = "com.squareup.retrofit2:converter-gson", version.ref = "retrofit" }
jacksonConverter = { module = "com.squareup.retrofit2:converter-jackson", version.ref = "retrofit" }
jacksonKotlin = { module = "com.fasterxml.jackson.module:jackson-module-kotlin", version.ref = "jackson" }
okhttpLogging = { module = "com.squareup.okhttp3:logging-interceptor", version.ref = "okhttp" }
koinCore = { module = "io.insert-koin:koin-core", version.ref = "koin" }
koinAndroid = { module = "io.insert-koin:koin-android", version.ref = "koin" }
koinViewModel = { module = "io.insert-koin:koin-android-viewmodel", version.ref = "koin" }
picasso = { module = "com.squareup.picasso:picasso", version.ref = "picasso" }
timber = { module = "com.jakewharton.timber:timber", version.ref = "timber" }
fastScroll = { module = "com.simplecityapps:recyclerview-fastscroll", version.ref = "fastScroll" }
colorPickerView = { module = "com.github.skydoves:colorpickerview", version.ref = "colorPicker" }
rxJava = { module = "io.reactivex.rxjava3:rxjava", version.ref = "rxJava" }
rxAndroid = { module = "io.reactivex.rxjava3:rxandroid", version.ref = "rxAndroid" }
multiType = { module = "com.drakeet.multitype:multitype", version.ref = "multiType" }
junit = { module = "junit:junit", version.ref = "junit4" }
junitVintage = { module = "org.junit.vintage:junit-vintage-engine", version.ref = "junit5" }
kotlinJunit = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "kotlin" }
mockitoKotlin = { module = "org.mockito.kotlin:mockito-kotlin", version.ref = "mockitoKotlin" }
mockito = { module = "org.mockito:mockito-core", version.ref = "mockito" }
mockitoInline = { module = "org.mockito:mockito-inline", version.ref = "mockito" }
kluent = { module = "org.amshove.kluent:kluent", version.ref = "kluent" }
kluentAndroid = { module = "org.amshove.kluent:kluent-android", version.ref = "kluent" }
mockWebServer = { module = "com.squareup.okhttp3:mockwebserver", version.ref = "okhttp" }
apacheCodecs = { module = "commons-codec:commons-codec", version.ref = "apacheCodecs" }
robolectric = { module = "org.robolectric:robolectric", version.ref = "robolectric" }

5
gradle/versions.gradle Normal file
View File

@ -0,0 +1,5 @@
ext.versions = [
minSdk : 21,
targetSdk : 30,
compileSdk : 31,
]

Binary file not shown.

View File

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

View File

@ -55,14 +55,14 @@ tasks.withType(Test) {
}
dependencies {
api other.kotlinStdlib
api libs.kotlinStdlib
testImplementation testing.junit
testRuntimeOnly testing.junitVintage
testImplementation libs.junit
testRuntimeOnly libs.junitVintage
}
jacoco {
toolVersion(versions.jacoco)
toolVersion(libs.versions.jacoco.get())
}
ext {

View File

@ -6,7 +6,7 @@ if (isCodeQualityEnabled) {
apply plugin: "org.jlleitschuh.gradle.ktlint"
ktlint {
version = versions.ktlint
version = libs.versions.ktlint.get()
outputToConsole = true
android = true
}
@ -21,7 +21,7 @@ if (isCodeQualityEnabled) {
detekt {
buildUponDefaultConfig = true
toolVersion = versions.detekt
toolVersion = libs.versions.detekt.get()
// Builds the AST in parallel. Rules are always executed in parallel.
// Can lead to speedups in larger projects.
parallel = true

View File

@ -1,7 +1,7 @@
apply plugin: 'jacoco'
jacoco {
toolVersion(versions.jacoco)
toolVersion(libs.versions.jacoco.get())
}
def mergedJacocoExec = file("${project.buildDir}/jacoco/jacocoMerged.exec")

View File

@ -15,14 +15,14 @@ sourceSets {
dependencies {
api other.kotlinStdlib
api libs.kotlinStdlib
testImplementation testing.junit
testRuntimeOnly testing.junitVintage
testImplementation libs.junit
testRuntimeOnly libs.junitVintage
}
jacoco {
toolVersion(versions.jacoco)
toolVersion(libs.versions.jacoco.get())
}
ext {

269
gradlew vendored
View File

@ -1,7 +1,7 @@
#!/usr/bin/env sh
#!/bin/sh
#
# Copyright 2015 the original author or authors.
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -17,67 +17,101 @@
#
##############################################################################
##
## Gradle start up script for UN*X
##
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
MAX_FD=maximum
warn () {
echo "$*"
}
} >&2
die () {
echo
echo "$*"
echo
exit 1
}
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD="$JAVA_HOME/bin/java"
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
@ -106,80 +140,95 @@ location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"

View File

@ -1,3 +1,5 @@
enableFeaturePreview("VERSION_CATALOGS")
include ':core:domain'
include ':core:subsonic-api'
include ':ultrasonic'

View File

@ -9,8 +9,8 @@ android {
defaultConfig {
applicationId "org.moire.ultrasonic"
versionCode 99
versionName "3.0.0"
versionCode 100
versionName "3.0.1"
minSdkVersion versions.minSdk
targetSdkVersion versions.targetSdk
@ -85,54 +85,54 @@ dependencies {
implementation project(':core:domain')
implementation project(':core:subsonic-api')
api(other.picasso) {
api(libs.picasso) {
exclude group: "com.android.support"
}
implementation androidSupport.core
implementation androidSupport.support
implementation androidSupport.design
implementation androidSupport.multidex
implementation androidSupport.roomRuntime
implementation androidSupport.roomKtx
implementation androidSupport.viewModelKtx
implementation androidSupport.constraintLayout
implementation androidSupport.preferences
implementation androidSupport.media
implementation libs.core
implementation libs.support
implementation libs.design
implementation libs.multidex
implementation libs.roomRuntime
implementation libs.roomKtx
implementation libs.viewModelKtx
implementation libs.constraintLayout
implementation libs.preferences
implementation libs.media
implementation androidSupport.navigationFragment
implementation androidSupport.navigationUi
implementation androidSupport.navigationFragmentKtx
implementation androidSupport.navigationUiKtx
implementation androidSupport.navigationFeature
implementation libs.navigationFragment
implementation libs.navigationUi
implementation libs.navigationFragmentKtx
implementation libs.navigationUiKtx
implementation libs.navigationFeature
implementation other.kotlinStdlib
implementation other.kotlinxCoroutines
implementation other.koinAndroid
implementation other.okhttpLogging
implementation other.fastScroll
implementation other.colorPickerView
implementation other.rxJava
implementation other.rxAndroid
implementation other.multiType
implementation libs.kotlinStdlib
implementation libs.kotlinxCoroutines
implementation libs.koinAndroid
implementation libs.okhttpLogging
implementation libs.fastScroll
implementation libs.colorPickerView
implementation libs.rxJava
implementation libs.rxAndroid
implementation libs.multiType
kapt androidSupport.room
kapt libs.room
testImplementation other.kotlinReflect
testImplementation testing.junit
testRuntimeOnly testing.junitVintage
testImplementation testing.kotlinJunit
testImplementation testing.kluent
testImplementation testing.mockito
testImplementation testing.mockitoInline
testImplementation testing.mockitoKotlin
testImplementation testing.robolectric
testImplementation libs.kotlinReflect
testImplementation libs.junit
testRuntimeOnly libs.junitVintage
testImplementation libs.kotlinJunit
testImplementation libs.kluent
testImplementation libs.mockito
testImplementation libs.mockitoInline
testImplementation libs.mockitoKotlin
testImplementation libs.robolectric
implementation other.timber
implementation libs.timber
}
jacoco {
toolVersion(versions.jacoco)
toolVersion(libs.versions.jacoco.get())
}
// Excluding all java classes and stuff that should not be covered
@ -156,7 +156,7 @@ ext {
}
jacoco {
toolVersion(versions.jacoco)
toolVersion(libs.versions.jacoco.get())
}
tasks.withType(Test) {

View File

@ -1,19 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<issues format="5" by="lint 4.2.2" client="gradle" variant="release" version="4.2.2">
<issue
id="ObsoleteLintCustomCheck"
message="Lint found an issue registry (`androidx.appcompat.AppCompatIssueRegistry`) which is older than the current API level; these checks may not work correctly.&#xA;&#xA;Recompile the checks against the latest version. Custom check API version is 7 (4.0), current lint API level is 8 (4.1)">
<location
file="../../../../.gradle/caches/transforms-3/cfd0dffad81bb5ff9173a2c6d47f5e0a/transformed/appcompat-1.2.0/jars/lint.jar"/>
</issue>
<issue
id="ObsoleteLintCustomCheck"
message="Lint found an issue registry (`timber.lint.TimberIssueRegistry`) which is older than the current API level; these checks may not work correctly.&#xA;&#xA;Recompile the checks against the latest version. Custom check API version is 1 (3.1), current lint API level is 8 (4.1)">
<location
file="../../../../.gradle/caches/transforms-3/9362f92689454001c7932b460b41bbdb/transformed/jetified-timber-4.7.1/jars/lint.jar"/>
</issue>
<issues format="6" by="lint 7.0.4" type="baseline" client="gradle" name="AGP (7.0.4)" variant="all" version="7.0.4">
<issue
id="InflateParams"
@ -81,6 +67,20 @@
column="9"/>
</issue>
<issue
id="TrustAllX509TrustManager"
message="`checkClientTrusted` is empty, which could cause insecure network traffic due to trusting arbitrary TLS/SSL certificates presented by peers">
<location
file="org/moire/ultrasonic/api/subsonic/SubsonicAPIClient$allowSelfSignedCertificates$trustManager$1.class"/>
</issue>
<issue
id="TrustAllX509TrustManager"
message="`checkServerTrusted` is empty, which could cause insecure network traffic due to trusting arbitrary TLS/SSL certificates presented by peers">
<location
file="org/moire/ultrasonic/api/subsonic/SubsonicAPIClient$allowSelfSignedCertificates$trustManager$1.class"/>
</issue>
<issue
id="ExportedContentProvider"
message="Exported content providers can provide access to potentially sensitive data"
@ -103,6 +103,182 @@
column="10"/>
</issue>
<issue
id="IntentFilterExportedReceiver"
message="As of Android 12, `android:exported` must be set; use `true` to make the activity \&#xA;available to other apps, and `false` otherwise. For launcher activities, this should be set to `true`."
errorLine1=" &lt;activity android:name=&quot;.activity.NavigationActivity&quot;"
errorLine2=" ~~~~~~~~">
<location
file="src/main/AndroidManifest.xml"
line="41"
column="10"/>
</issue>
<issue
id="IntentFilterExportedReceiver"
message="As of Android 12, `android:exported` must be set; use `true` to make the activity \&#xA;available to other apps, and `false` otherwise."
errorLine1=" &lt;receiver android:name=&quot;.receiver.MediaButtonIntentReceiver&quot;>"
errorLine2=" ~~~~~~~~">
<location
file="src/main/AndroidManifest.xml"
line="76"
column="10"/>
</issue>
<issue
id="IntentFilterExportedReceiver"
message="As of Android 12, `android:exported` must be set; use `true` to make the activity \&#xA;available to other apps, and `false` otherwise."
errorLine1=" &lt;receiver android:name=&quot;.receiver.UltrasonicIntentReceiver&quot;>"
errorLine2=" ~~~~~~~~">
<location
file="src/main/AndroidManifest.xml"
line="81"
column="10"/>
</issue>
<issue
id="IntentFilterExportedReceiver"
message="As of Android 12, `android:exported` must be set; use `true` to make the activity \&#xA;available to other apps, and `false` otherwise."
errorLine1=" &lt;receiver android:name=&quot;.receiver.BluetoothIntentReceiver&quot;>"
errorLine2=" ~~~~~~~~">
<location
file="src/main/AndroidManifest.xml"
line="93"
column="10"/>
</issue>
<issue
id="IntentFilterExportedReceiver"
message="As of Android 12, `android:exported` must be set; use `true` to make the activity \&#xA;available to other apps, and `false` otherwise."
errorLine1=" &lt;receiver"
errorLine2=" ~~~~~~~~">
<location
file="src/main/AndroidManifest.xml"
line="101"
column="10"/>
</issue>
<issue
id="IntentFilterExportedReceiver"
message="As of Android 12, `android:exported` must be set; use `true` to make the activity \&#xA;available to other apps, and `false` otherwise."
errorLine1=" &lt;receiver"
errorLine2=" ~~~~~~~~">
<location
file="src/main/AndroidManifest.xml"
line="112"
column="10"/>
</issue>
<issue
id="IntentFilterExportedReceiver"
message="As of Android 12, `android:exported` must be set; use `true` to make the activity \&#xA;available to other apps, and `false` otherwise."
errorLine1=" &lt;receiver"
errorLine2=" ~~~~~~~~">
<location
file="src/main/AndroidManifest.xml"
line="123"
column="10"/>
</issue>
<issue
id="IntentFilterExportedReceiver"
message="As of Android 12, `android:exported` must be set; use `true` to make the activity \&#xA;available to other apps, and `false` otherwise."
errorLine1=" &lt;receiver"
errorLine2=" ~~~~~~~~">
<location
file="src/main/AndroidManifest.xml"
line="134"
column="10"/>
</issue>
<issue
id="UnspecifiedImmutableFlag"
message="Missing `PendingIntent` mutability flag"
errorLine1=" return PendingIntent.getActivity(this, 0, intent, flags)"
errorLine2=" ~~~~~">
<location
file="src/main/kotlin/org/moire/ultrasonic/service/MediaPlayerService.kt"
line="708"
column="59"/>
</issue>
<issue
id="UnspecifiedImmutableFlag"
message="Missing `PendingIntent` mutability flag"
errorLine1=" PendingIntent.FLAG_CANCEL_CURRENT"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/kotlin/org/moire/ultrasonic/util/MediaSessionHandler.kt"
line="323"
column="13"/>
</issue>
<issue
id="UnspecifiedImmutableFlag"
message="Missing `PendingIntent` mutability flag"
errorLine1=" PendingIntent pendingIntent = PendingIntent.getActivity(context, 10, intent, PendingIntent.FLAG_UPDATE_CURRENT);"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider.java"
line="198"
column="80"/>
</issue>
<issue
id="UnspecifiedImmutableFlag"
message="Missing `PendingIntent` mutability flag"
errorLine1=" pendingIntent = PendingIntent.getBroadcast(context, 11, intent, 0);"
errorLine2=" ~">
<location
file="src/main/java/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider.java"
line="206"
column="67"/>
</issue>
<issue
id="UnspecifiedImmutableFlag"
message="Missing `PendingIntent` mutability flag"
errorLine1=" pendingIntent = PendingIntent.getBroadcast(context, 12, intent, 0);"
errorLine2=" ~">
<location
file="src/main/java/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider.java"
line="212"
column="67"/>
</issue>
<issue
id="UnspecifiedImmutableFlag"
message="Missing `PendingIntent` mutability flag"
errorLine1=" pendingIntent = PendingIntent.getBroadcast(context, 13, intent, 0);"
errorLine2=" ~">
<location
file="src/main/java/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider.java"
line="218"
column="67"/>
</issue>
<issue
id="UnspecifiedImmutableFlag"
message="Missing `PendingIntent` mutability flag"
errorLine1=" return PendingIntent.getBroadcast(context, requestCode, intent, flags)"
errorLine2=" ~~~~~">
<location
file="src/main/kotlin/org/moire/ultrasonic/util/Util.kt"
line="891"
column="73"/>
</issue>
<issue
id="NotifyDataSetChanged"
message="It will always be more efficient to use more specific change events if you can. Rely on `notifyDataSetChanged` as a last resort."
errorLine1=" viewAdapter.notifyDataSetChanged()"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/kotlin/org/moire/ultrasonic/fragment/PlayerFragment.kt"
line="908"
column="21"/>
</issue>
<issue
id="ObsoleteLayoutParam"
message="Invalid layout param in a `LinearLayout`: `layout_above`"
@ -200,54 +376,6 @@
file="src/main/res/values/strings.xml"
line="114"
column="13"/>
<location
file="src/main/res/values-cs/strings.xml"
line="98"
column="13"/>
<location
file="src/main/res/values-de/strings.xml"
line="97"
column="13"/>
<location
file="src/main/res/values-es/strings.xml"
line="111"
column="13"/>
<location
file="src/main/res/values-fr/strings.xml"
line="108"
column="13"/>
<location
file="src/main/res/values-hu/strings.xml"
line="108"
column="13"/>
<location
file="src/main/res/values-it/strings.xml"
line="95"
column="13"/>
<location
file="src/main/res/values-nl/strings.xml"
line="111"
column="13"/>
<location
file="src/main/res/values-pl/strings.xml"
line="97"
column="13"/>
<location
file="src/main/res/values-pt/strings.xml"
line="97"
column="13"/>
<location
file="src/main/res/values-pt-rBR/strings.xml"
line="108"
column="13"/>
<location
file="src/main/res/values-ru/strings.xml"
line="108"
column="13"/>
<location
file="src/main/res/values-zh-rCN/strings.xml"
line="107"
column="13"/>
</issue>
<issue
@ -259,54 +387,6 @@
file="src/main/res/values/strings.xml"
line="128"
column="13"/>
<location
file="src/main/res/values-cs/strings.xml"
line="109"
column="13"/>
<location
file="src/main/res/values-de/strings.xml"
line="108"
column="13"/>
<location
file="src/main/res/values-es/strings.xml"
line="124"
column="13"/>
<location
file="src/main/res/values-fr/strings.xml"
line="121"
column="13"/>
<location
file="src/main/res/values-hu/strings.xml"
line="119"
column="13"/>
<location
file="src/main/res/values-it/strings.xml"
line="106"
column="13"/>
<location
file="src/main/res/values-nl/strings.xml"
line="124"
column="13"/>
<location
file="src/main/res/values-pl/strings.xml"
line="108"
column="13"/>
<location
file="src/main/res/values-pt/strings.xml"
line="108"
column="13"/>
<location
file="src/main/res/values-pt-rBR/strings.xml"
line="121"
column="13"/>
<location
file="src/main/res/values-ru/strings.xml"
line="121"
column="13"/>
<location
file="src/main/res/values-zh-rCN/strings.xml"
line="120"
column="13"/>
</issue>
<issue
@ -318,54 +398,6 @@
file="src/main/res/values/strings.xml"
line="133"
column="13"/>
<location
file="src/main/res/values-cs/strings.xml"
line="114"
column="13"/>
<location
file="src/main/res/values-de/strings.xml"
line="113"
column="13"/>
<location
file="src/main/res/values-es/strings.xml"
line="129"
column="13"/>
<location
file="src/main/res/values-fr/strings.xml"
line="126"
column="13"/>
<location
file="src/main/res/values-hu/strings.xml"
line="124"
column="13"/>
<location
file="src/main/res/values-it/strings.xml"
line="110"
column="13"/>
<location
file="src/main/res/values-nl/strings.xml"
line="129"
column="13"/>
<location
file="src/main/res/values-pl/strings.xml"
line="112"
column="13"/>
<location
file="src/main/res/values-pt/strings.xml"
line="112"
column="13"/>
<location
file="src/main/res/values-pt-rBR/strings.xml"
line="126"
column="13"/>
<location
file="src/main/res/values-ru/strings.xml"
line="126"
column="13"/>
<location
file="src/main/res/values-zh-rCN/strings.xml"
line="125"
column="13"/>
</issue>
<issue
@ -377,54 +409,6 @@
file="src/main/res/values/strings.xml"
line="134"
column="13"/>
<location
file="src/main/res/values-cs/strings.xml"
line="115"
column="13"/>
<location
file="src/main/res/values-de/strings.xml"
line="114"
column="13"/>
<location
file="src/main/res/values-es/strings.xml"
line="130"
column="13"/>
<location
file="src/main/res/values-fr/strings.xml"
line="127"
column="13"/>
<location
file="src/main/res/values-hu/strings.xml"
line="125"
column="13"/>
<location
file="src/main/res/values-it/strings.xml"
line="111"
column="13"/>
<location
file="src/main/res/values-nl/strings.xml"
line="130"
column="13"/>
<location
file="src/main/res/values-pl/strings.xml"
line="113"
column="13"/>
<location
file="src/main/res/values-pt/strings.xml"
line="113"
column="13"/>
<location
file="src/main/res/values-pt-rBR/strings.xml"
line="127"
column="13"/>
<location
file="src/main/res/values-ru/strings.xml"
line="127"
column="13"/>
<location
file="src/main/res/values-zh-rCN/strings.xml"
line="126"
column="13"/>
</issue>
<issue
@ -436,54 +420,6 @@
file="src/main/res/values/strings.xml"
line="135"
column="13"/>
<location
file="src/main/res/values-cs/strings.xml"
line="116"
column="13"/>
<location
file="src/main/res/values-de/strings.xml"
line="115"
column="13"/>
<location
file="src/main/res/values-es/strings.xml"
line="131"
column="13"/>
<location
file="src/main/res/values-fr/strings.xml"
line="128"
column="13"/>
<location
file="src/main/res/values-hu/strings.xml"
line="126"
column="13"/>
<location
file="src/main/res/values-it/strings.xml"
line="112"
column="13"/>
<location
file="src/main/res/values-nl/strings.xml"
line="131"
column="13"/>
<location
file="src/main/res/values-pl/strings.xml"
line="114"
column="13"/>
<location
file="src/main/res/values-pt/strings.xml"
line="114"
column="13"/>
<location
file="src/main/res/values-pt-rBR/strings.xml"
line="128"
column="13"/>
<location
file="src/main/res/values-ru/strings.xml"
line="128"
column="13"/>
<location
file="src/main/res/values-zh-rCN/strings.xml"
line="127"
column="13"/>
</issue>
<issue
@ -495,54 +431,6 @@
file="src/main/res/values/strings.xml"
line="136"
column="13"/>
<location
file="src/main/res/values-cs/strings.xml"
line="117"
column="13"/>
<location
file="src/main/res/values-de/strings.xml"
line="116"
column="13"/>
<location
file="src/main/res/values-es/strings.xml"
line="132"
column="13"/>
<location
file="src/main/res/values-fr/strings.xml"
line="129"
column="13"/>
<location
file="src/main/res/values-hu/strings.xml"
line="127"
column="13"/>
<location
file="src/main/res/values-it/strings.xml"
line="113"
column="13"/>
<location
file="src/main/res/values-nl/strings.xml"
line="132"
column="13"/>
<location
file="src/main/res/values-pl/strings.xml"
line="115"
column="13"/>
<location
file="src/main/res/values-pt/strings.xml"
line="115"
column="13"/>
<location
file="src/main/res/values-pt-rBR/strings.xml"
line="129"
column="13"/>
<location
file="src/main/res/values-ru/strings.xml"
line="129"
column="13"/>
<location
file="src/main/res/values-zh-rCN/strings.xml"
line="128"
column="13"/>
</issue>
<issue
@ -554,54 +442,6 @@
file="src/main/res/values/strings.xml"
line="141"
column="13"/>
<location
file="src/main/res/values-cs/strings.xml"
line="122"
column="13"/>
<location
file="src/main/res/values-de/strings.xml"
line="121"
column="13"/>
<location
file="src/main/res/values-es/strings.xml"
line="137"
column="13"/>
<location
file="src/main/res/values-fr/strings.xml"
line="134"
column="13"/>
<location
file="src/main/res/values-hu/strings.xml"
line="132"
column="13"/>
<location
file="src/main/res/values-it/strings.xml"
line="118"
column="13"/>
<location
file="src/main/res/values-nl/strings.xml"
line="137"
column="13"/>
<location
file="src/main/res/values-pl/strings.xml"
line="120"
column="13"/>
<location
file="src/main/res/values-pt/strings.xml"
line="120"
column="13"/>
<location
file="src/main/res/values-pt-rBR/strings.xml"
line="134"
column="13"/>
<location
file="src/main/res/values-ru/strings.xml"
line="134"
column="13"/>
<location
file="src/main/res/values-zh-rCN/strings.xml"
line="133"
column="13"/>
</issue>
<issue
@ -613,54 +453,6 @@
file="src/main/res/values/strings.xml"
line="147"
column="13"/>
<location
file="src/main/res/values-cs/strings.xml"
line="128"
column="13"/>
<location
file="src/main/res/values-de/strings.xml"
line="127"
column="13"/>
<location
file="src/main/res/values-es/strings.xml"
line="143"
column="13"/>
<location
file="src/main/res/values-fr/strings.xml"
line="140"
column="13"/>
<location
file="src/main/res/values-hu/strings.xml"
line="138"
column="13"/>
<location
file="src/main/res/values-it/strings.xml"
line="124"
column="13"/>
<location
file="src/main/res/values-nl/strings.xml"
line="143"
column="13"/>
<location
file="src/main/res/values-pl/strings.xml"
line="126"
column="13"/>
<location
file="src/main/res/values-pt/strings.xml"
line="126"
column="13"/>
<location
file="src/main/res/values-pt-rBR/strings.xml"
line="140"
column="13"/>
<location
file="src/main/res/values-ru/strings.xml"
line="140"
column="13"/>
<location
file="src/main/res/values-zh-rCN/strings.xml"
line="139"
column="13"/>
</issue>
<issue
@ -672,54 +464,6 @@
file="src/main/res/values/strings.xml"
line="159"
column="13"/>
<location
file="src/main/res/values-cs/strings.xml"
line="140"
column="13"/>
<location
file="src/main/res/values-de/strings.xml"
line="139"
column="13"/>
<location
file="src/main/res/values-es/strings.xml"
line="155"
column="13"/>
<location
file="src/main/res/values-fr/strings.xml"
line="152"
column="13"/>
<location
file="src/main/res/values-hu/strings.xml"
line="150"
column="13"/>
<location
file="src/main/res/values-it/strings.xml"
line="136"
column="13"/>
<location
file="src/main/res/values-nl/strings.xml"
line="155"
column="13"/>
<location
file="src/main/res/values-pl/strings.xml"
line="138"
column="13"/>
<location
file="src/main/res/values-pt/strings.xml"
line="138"
column="13"/>
<location
file="src/main/res/values-pt-rBR/strings.xml"
line="152"
column="13"/>
<location
file="src/main/res/values-ru/strings.xml"
line="152"
column="13"/>
<location
file="src/main/res/values-zh-rCN/strings.xml"
line="151"
column="13"/>
</issue>
<issue
@ -753,54 +497,6 @@
file="src/main/res/values/strings.xml"
line="230"
column="13"/>
<location
file="src/main/res/values-cs/strings.xml"
line="208"
column="13"/>
<location
file="src/main/res/values-de/strings.xml"
line="207"
column="13"/>
<location
file="src/main/res/values-es/strings.xml"
line="223"
column="13"/>
<location
file="src/main/res/values-fr/strings.xml"
line="220"
column="13"/>
<location
file="src/main/res/values-hu/strings.xml"
line="218"
column="13"/>
<location
file="src/main/res/values-it/strings.xml"
line="203"
column="13"/>
<location
file="src/main/res/values-nl/strings.xml"
line="223"
column="13"/>
<location
file="src/main/res/values-pl/strings.xml"
line="206"
column="13"/>
<location
file="src/main/res/values-pt/strings.xml"
line="206"
column="13"/>
<location
file="src/main/res/values-pt-rBR/strings.xml"
line="220"
column="13"/>
<location
file="src/main/res/values-ru/strings.xml"
line="220"
column="13"/>
<location
file="src/main/res/values-zh-rCN/strings.xml"
line="217"
column="13"/>
</issue>
<issue
@ -812,54 +508,6 @@
file="src/main/res/values/strings.xml"
line="299"
column="13"/>
<location
file="src/main/res/values-cs/strings.xml"
line="273"
column="13"/>
<location
file="src/main/res/values-de/strings.xml"
line="272"
column="13"/>
<location
file="src/main/res/values-es/strings.xml"
line="292"
column="13"/>
<location
file="src/main/res/values-fr/strings.xml"
line="287"
column="13"/>
<location
file="src/main/res/values-hu/strings.xml"
line="285"
column="13"/>
<location
file="src/main/res/values-it/strings.xml"
line="266"
column="13"/>
<location
file="src/main/res/values-nl/strings.xml"
line="292"
column="13"/>
<location
file="src/main/res/values-pl/strings.xml"
line="271"
column="13"/>
<location
file="src/main/res/values-pt/strings.xml"
line="271"
column="13"/>
<location
file="src/main/res/values-pt-rBR/strings.xml"
line="289"
column="13"/>
<location
file="src/main/res/values-ru/strings.xml"
line="287"
column="13"/>
<location
file="src/main/res/values-zh-rCN/strings.xml"
line="285"
column="13"/>
</issue>
<issue
@ -871,54 +519,6 @@
file="src/main/res/values/strings.xml"
line="302"
column="13"/>
<location
file="src/main/res/values-cs/strings.xml"
line="276"
column="13"/>
<location
file="src/main/res/values-de/strings.xml"
line="275"
column="13"/>
<location
file="src/main/res/values-es/strings.xml"
line="295"
column="13"/>
<location
file="src/main/res/values-fr/strings.xml"
line="290"
column="13"/>
<location
file="src/main/res/values-hu/strings.xml"
line="288"
column="13"/>
<location
file="src/main/res/values-it/strings.xml"
line="269"
column="13"/>
<location
file="src/main/res/values-nl/strings.xml"
line="295"
column="13"/>
<location
file="src/main/res/values-pl/strings.xml"
line="274"
column="13"/>
<location
file="src/main/res/values-pt/strings.xml"
line="274"
column="13"/>
<location
file="src/main/res/values-pt-rBR/strings.xml"
line="292"
column="13"/>
<location
file="src/main/res/values-ru/strings.xml"
line="290"
column="13"/>
<location
file="src/main/res/values-zh-rCN/strings.xml"
line="288"
column="13"/>
</issue>
<issue
@ -941,46 +541,6 @@
file="src/main/res/values/strings.xml"
line="447"
column="14"/>
<location
file="src/main/res/values-cs/strings.xml"
line="413"
column="14"/>
<location
file="src/main/res/values-es/strings.xml"
line="436"
column="14"/>
<location
file="src/main/res/values-fr/strings.xml"
line="425"
column="14"/>
<location
file="src/main/res/values-hu/strings.xml"
line="420"
column="14"/>
<location
file="src/main/res/values-nl/strings.xml"
line="436"
column="14"/>
<location
file="src/main/res/values-pl/strings.xml"
line="388"
column="14"/>
<location
file="src/main/res/values-pt/strings.xml"
line="375"
column="14"/>
<location
file="src/main/res/values-pt-rBR/strings.xml"
line="429"
column="14"/>
<location
file="src/main/res/values-ru/strings.xml"
line="437"
column="14"/>
<location
file="src/main/res/values-zh-rCN/strings.xml"
line="419"
column="14"/>
</issue>
<issue

View File

@ -18,22 +18,24 @@
*/
package org.moire.ultrasonic.receiver;
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import timber.log.Timber;
import org.moire.ultrasonic.util.Constants;
import org.moire.ultrasonic.util.Settings;
import org.moire.ultrasonic.util.Util;
import timber.log.Timber;
/**
* Resume or pause playback on Bluetooth A2DP connect/disconnect.
*
* @author Sindre Mehus
*/
@SuppressLint("MissingPermission")
public class BluetoothIntentReceiver extends BroadcastReceiver
{
@Override

View File

@ -26,6 +26,8 @@
*/
package org.moire.ultrasonic.service.ssl;
import android.annotation.SuppressLint;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
@ -34,6 +36,7 @@ import javax.net.ssl.X509TrustManager;
/**
* @since 4.1
*/
@SuppressLint("CustomX509TrustManager")
class TrustManagerDecorator implements X509TrustManager
{

View File

@ -1,117 +0,0 @@
/*
This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2009 (C) Sindre Mehus
*/
package org.moire.ultrasonic.util;
import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.Map;
/**
* @author Sindre Mehus
*/
public class LRUCache<K, V>
{
private final int capacity;
private final Map<K, TimestampedValue> map;
public LRUCache(int capacity)
{
map = new HashMap<K, TimestampedValue>(capacity);
this.capacity = capacity;
}
public synchronized V get(K key)
{
TimestampedValue value = map.get(key);
V result = null;
if (value != null)
{
value.updateTimestamp();
result = value.getValue();
}
return result;
}
public synchronized void put(K key, V value)
{
if (map.size() >= capacity)
{
removeOldest();
}
map.put(key, new TimestampedValue(value));
}
public void clear()
{
map.clear();
}
private void removeOldest()
{
K oldestKey = null;
long oldestTimestamp = Long.MAX_VALUE;
for (Map.Entry<K, TimestampedValue> entry : map.entrySet())
{
K key = entry.getKey();
TimestampedValue value = entry.getValue();
if (value.getTimestamp() < oldestTimestamp)
{
oldestTimestamp = value.getTimestamp();
oldestKey = key;
}
}
if (oldestKey != null)
{
map.remove(oldestKey);
}
}
private final class TimestampedValue
{
private final SoftReference<V> value;
private long timestamp;
public TimestampedValue(V value)
{
this.value = new SoftReference<V>(value);
updateTimestamp();
}
public V getValue()
{
return value.get();
}
public long getTimestamp()
{
return timestamp;
}
public void updateTimestamp()
{
timestamp = System.currentTimeMillis();
}
}
}

View File

@ -208,8 +208,8 @@ class NavigationActivity : AppCompatActivity() {
selectServerButton?.text = getString(R.string.main_setup_server, activeServer.name)
else selectServerButton?.text = activeServer.name
val foregroundColor = ServerColor.getForegroundColor(this, null)
val backgroundColor = ServerColor.getBackgroundColor(this, null)
val foregroundColor = ServerColor.getForegroundColor(this, activeServer.color)
val backgroundColor = ServerColor.getBackgroundColor(this, activeServer.color)
if (activeServer.index == 0)
selectServerButton?.icon =

View File

@ -108,8 +108,8 @@ internal class ServerRowAdapter(
}
// Set colors
icon?.setTint(ServerColor.getForegroundColor(context, null))
background?.setTint(ServerColor.getBackgroundColor(context, null))
icon?.setTint(ServerColor.getForegroundColor(context, setting?.color))
background?.setTint(ServerColor.getBackgroundColor(context, setting?.color))
// Set the final drawables
image?.setImageDrawable(icon)

View File

@ -38,7 +38,10 @@ class UApp : MultiDexApplication() {
}
startKoin {
logger(TimberKoinLogger(Level.INFO))
// TODO Currently there is a bug in Koin which makes necessary to set the loglevel to ERROR
logger(TimberKoinLogger(Level.ERROR))
// logger(TimberKoinLogger(Level.INFO))
// declare Android context
androidContext(this@UApp)
// declare modules to use

View File

@ -9,7 +9,7 @@ import androidx.sqlite.db.SupportSQLiteDatabase
* Room Database to be used to store global data for the whole app.
* This could be settings or data that are not specific to any remote music database
*/
@Database(entities = [ServerSetting::class], version = 3)
@Database(entities = [ServerSetting::class], version = 4)
abstract class AppDatabase : RoomDatabase() {
/**

View File

@ -23,6 +23,7 @@ data class ServerSetting(
@ColumnInfo(name = "index") var index: Int,
@ColumnInfo(name = "name") var name: String,
@ColumnInfo(name = "url") var url: String,
@ColumnInfo(name = "color") var color: Int? = null,
@ColumnInfo(name = "userName") var userName: String,
@ColumnInfo(name = "password") var password: String,
@ColumnInfo(name = "jukeboxByDefault") var jukeboxByDefault: Boolean,
@ -36,9 +37,9 @@ data class ServerSetting(
@ColumnInfo(name = "podcastSupport") var podcastSupport: Boolean? = null
) {
constructor() : this (
-1, 0, "", "", "", "", false, false, false, null, null
-1, 0, "", "", null, "", "", false, false, false, null, null
)
constructor(name: String, url: String) : this(
-1, 0, name, url, "", "", false, false, false, null, null
-1, 0, name, url, null, "", "", false, false, false, null, null
)
}

View File

@ -6,13 +6,15 @@ import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.ImageView
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
import com.google.android.material.switchmaterial.SwitchMaterial
import com.google.android.material.textfield.TextInputLayout
import com.skydoves.colorpickerview.ColorPickerDialog
import com.skydoves.colorpickerview.flag.BubbleFlag
import com.skydoves.colorpickerview.flag.FlagMode
import com.skydoves.colorpickerview.listeners.ColorEnvelopeListener
import java.io.IOException
import java.net.MalformedURLException
import java.net.URL
@ -41,6 +43,8 @@ import org.moire.ultrasonic.util.Util
import retrofit2.Response
import timber.log.Timber
private const val DIALOG_PADDING = 12
/**
* Displays a form where server settings can be created / edited
*/
@ -68,8 +72,6 @@ class EditServerFragment : Fragment(), OnBackPressedHandler {
private var currentColor: Int = 0
private var selectedColor: Int? = null
private var editServerColorText: TextView? = null
@Override
override fun onCreate(savedInstanceState: Bundle?) {
Util.applyTheme(this.context)
@ -97,7 +99,6 @@ class EditServerFragment : Fragment(), OnBackPressedHandler {
jukeboxSwitch = view.findViewById(R.id.edit_jukebox)
saveButton = view.findViewById(R.id.edit_save)
testButton = view.findViewById(R.id.edit_test)
editServerColorText = view.findViewById(R.id.edit_server_color_text)
val index = arguments?.getInt(
EDIT_SERVER_INTENT_INDEX,
@ -146,7 +147,7 @@ class EditServerFragment : Fragment(), OnBackPressedHandler {
} else {
// Creating a new server
FragmentTitle.setTitle(this, R.string.server_editor_new_label)
// updateColor(null)
updateColor(null)
currentServerSetting = ServerSetting()
saveButton!!.setOnClickListener {
if (getFields()) {
@ -162,37 +163,33 @@ class EditServerFragment : Fragment(), OnBackPressedHandler {
}
}
// serverColorImageView!!.setOnClickListener {
// val bubbleFlag = BubbleFlag(context)
// bubbleFlag.flagMode = FlagMode.LAST
// ColorPickerDialog.Builder(context).apply {
// this.colorPickerView.setInitialColor(currentColor)
// this.colorPickerView.flagView = bubbleFlag
// }
// .attachAlphaSlideBar(false)
// .setPositiveButton(
// getString(R.string.common_ok),
// ColorEnvelopeListener { envelope, _ ->
// selectedColor = envelope.color
// updateColor(envelope.color)
// }
// )
// .setNegativeButton(getString(R.string.common_cancel)) {
// dialogInterface, _ ->
// dialogInterface.dismiss()
// }
// .setBottomSpace(DIALOG_PADDING)
// .show()
// }
serverColorImageView?.isVisible = false
editServerColorText?.isVisible = false
serverColorImageView!!.setOnClickListener {
val bubbleFlag = BubbleFlag(context)
bubbleFlag.flagMode = FlagMode.LAST
ColorPickerDialog.Builder(context).apply {
this.colorPickerView.setInitialColor(currentColor)
this.colorPickerView.flagView = bubbleFlag
}
.attachAlphaSlideBar(false)
.setPositiveButton(
getString(R.string.common_ok),
ColorEnvelopeListener { envelope, _ ->
selectedColor = envelope.color
updateColor(envelope.color)
}
)
.setNegativeButton(getString(R.string.common_cancel)) {
dialogInterface, _ ->
dialogInterface.dismiss()
}
.setBottomSpace(DIALOG_PADDING)
.show()
}
}
@Suppress("unused")
private fun updateColor() {
private fun updateColor(color: Int?) {
val image = ContextCompat.getDrawable(requireContext(), R.drawable.thumb_drawable)
currentColor = ServerColor.getBackgroundColor(requireContext(), null)
currentColor = ServerColor.getBackgroundColor(requireContext(), color)
image?.setTint(currentColor)
serverColorImageView?.background = image
}
@ -257,7 +254,7 @@ class EditServerFragment : Fragment(), OnBackPressedHandler {
selfSignedSwitch!!.isChecked = savedInstanceState.getBoolean(::selfSignedSwitch.name)
ldapSwitch!!.isChecked = savedInstanceState.getBoolean(::ldapSwitch.name)
jukeboxSwitch!!.isChecked = savedInstanceState.getBoolean(::jukeboxSwitch.name)
// updateColor(savedInstanceState.getInt(::serverColorImageView.name))
updateColor(savedInstanceState.getInt(::serverColorImageView.name))
if (savedInstanceState.containsKey(::selectedColor.name))
selectedColor = savedInstanceState.getInt(::selectedColor.name)
isInstanceStateSaved = savedInstanceState.getBoolean(::isInstanceStateSaved.name)
@ -276,7 +273,7 @@ class EditServerFragment : Fragment(), OnBackPressedHandler {
selfSignedSwitch!!.isChecked = currentServerSetting!!.allowSelfSignedCertificate
ldapSwitch!!.isChecked = currentServerSetting!!.ldapSupport
jukeboxSwitch!!.isChecked = currentServerSetting!!.jukeboxByDefault
// updateColor(currentServerSetting!!.color)
updateColor(currentServerSetting!!.color)
}
/**
@ -325,7 +322,7 @@ class EditServerFragment : Fragment(), OnBackPressedHandler {
if (isValid) {
currentServerSetting!!.name = serverNameEditText!!.editText?.text.toString()
currentServerSetting!!.url = serverAddressEditText!!.editText?.text.toString()
// currentServerSetting!!.color = selectedColor
currentServerSetting!!.color = selectedColor
currentServerSetting!!.userName = userNameEditText!!.editText?.text.toString()
currentServerSetting!!.password = passwordEditText!!.editText?.text.toString()
currentServerSetting!!.allowSelfSignedCertificate = selfSignedSwitch!!.isChecked
@ -459,11 +456,11 @@ class EditServerFragment : Fragment(), OnBackPressedHandler {
override fun done(responseString: String) {
var dialogText = responseString
if (arrayOf(
currentServerSetting!!.chatSupport,
currentServerSetting!!.bookmarkSupport,
currentServerSetting!!.shareSupport,
currentServerSetting!!.podcastSupport
).any { x -> x == false }
currentServerSetting!!.chatSupport,
currentServerSetting!!.bookmarkSupport,
currentServerSetting!!.shareSupport,
currentServerSetting!!.podcastSupport
).any { x -> x == false }
) {
dialogText = String.format(
Locale.ROOT,

View File

@ -338,9 +338,9 @@ class PlayerFragment :
registerForContextMenu(playlistView)
if (arguments != null && requireArguments().getBoolean(
Constants.INTENT_SHUFFLE,
false
)
Constants.INTENT_SHUFFLE,
false
)
) {
networkAndStorageChecker.warnIfNetworkOrStorageUnavailable()
mediaPlayerController.isShufflePlayEnabled = true

View File

@ -212,6 +212,7 @@ class ServerSettingsModel(
serverId,
settings.getString(PREFERENCES_KEY_SERVER_NAME + preferenceId, "")!!,
url,
null,
userName,
settings.getString(PREFERENCES_KEY_PASSWORD + preferenceId, "")!!,
settings.getBoolean(PREFERENCES_KEY_JUKEBOX_BY_DEFAULT + preferenceId, false),

View File

@ -150,19 +150,19 @@ class CachedMusicService(private val musicService: MusicService) : MusicService,
@Throws(Exception::class)
override fun getArtist(id: String, name: String?, refresh: Boolean):
List<MusicDirectory.Album> {
checkSettingsChanged()
var cache = if (refresh) null else cachedArtist[id]
var dir = cache?.get()
if (dir == null) {
dir = musicService.getArtist(id, name, refresh)
cache = TimeLimitedCache(
Settings.directoryCacheTime.toLong(), TimeUnit.SECONDS
)
cache.set(dir)
cachedArtist.put(id, cache)
}
return dir
checkSettingsChanged()
var cache = if (refresh) null else cachedArtist[id]
var dir = cache?.get()
if (dir == null) {
dir = musicService.getArtist(id, name, refresh)
cache = TimeLimitedCache(
Settings.directoryCacheTime.toLong(), TimeUnit.SECONDS
)
cache.set(dir)
cachedArtist.put(id, cache)
}
return dir
}
@Throws(Exception::class)
override fun getAlbum(id: String, name: String?, refresh: Boolean): MusicDirectory {

View File

@ -149,9 +149,9 @@ class MediaPlayerLifecycleSupport : KoinComponent {
} else if (state == 1) {
if (!mediaPlayerController.isJukeboxEnabled &&
sp.getBoolean(
spKey,
false
) && mediaPlayerController.playerState === PlayerState.PAUSED
spKey,
false
) && mediaPlayerController.playerState === PlayerState.PAUSED
) {
mediaPlayerController.start()
}

View File

@ -456,8 +456,8 @@ class OfflineMusicService : MusicService, KoinComponent {
@Throws(OfflineException::class)
override fun getArtist(id: String, name: String?, refresh: Boolean):
List<MusicDirectory.Album> {
throw OfflineException("getArtist isn't available in offline mode")
}
throw OfflineException("getArtist isn't available in offline mode")
}
@Throws(OfflineException::class)
override fun getAlbum(id: String, name: String?, refresh: Boolean): MusicDirectory {

View File

@ -30,13 +30,13 @@ import timber.log.Timber
object CommunicationError {
fun getHandler(context: Context?, handler: ((CoroutineContext, Throwable) -> Unit)? = null):
CoroutineExceptionHandler {
return CoroutineExceptionHandler { coroutineContext, exception ->
Handler(Looper.getMainLooper()).post {
handleError(exception, context)
handler?.invoke(coroutineContext, exception)
}
return CoroutineExceptionHandler { coroutineContext, exception ->
Handler(Looper.getMainLooper()).post {
handleError(exception, context)
handler?.invoke(coroutineContext, exception)
}
}
}
@JvmStatic
fun handleError(error: Throwable?, context: Context?) {

View File

@ -0,0 +1,79 @@
/*
* LRUCache.kt
* Copyright (C) 2009-2021 Ultrasonic developers
*
* Distributed under terms of the GNU GPLv3 license.
*/
package org.moire.ultrasonic.util
import java.lang.ref.SoftReference
import java.util.HashMap
/**
* A cache that deletes the least-recently-used items.
*/
class LRUCache<K, V>(capacity: Int) {
private val capacity: Int
private val map: MutableMap<K, TimestampedValue>
@Synchronized
operator fun get(key: K): V? {
val value = map[key]
var result: V? = null
if (value != null) {
value.updateTimestamp()
result = value.getValue()
}
return result
}
@Synchronized
fun put(key: K, value: V) {
if (map.size >= capacity) {
removeOldest()
}
map[key] = TimestampedValue(value)
}
fun clear() {
map.clear()
}
private fun removeOldest() {
var oldestKey: K? = null
var oldestTimestamp = Long.MAX_VALUE
for ((key, value) in map) {
if (value.timestamp < oldestTimestamp) {
oldestTimestamp = value.timestamp
oldestKey = key
}
}
if (oldestKey != null) {
map.remove(oldestKey)
}
}
private inner class TimestampedValue(value: V) {
private val value: SoftReference<V> = SoftReference(value)
var timestamp: Long = 0
private set
fun getValue(): V? {
return value.get()
}
fun updateTimestamp() {
timestamp = System.currentTimeMillis()
}
init {
updateTimestamp()
}
}
init {
map = HashMap(capacity)
this.capacity = capacity
}
}

View File

@ -133,55 +133,55 @@ object Settings {
@JvmStatic
var shouldUseFolderForArtistName
by BooleanSetting(Constants.PREFERENCES_KEY_USE_FOLDER_FOR_ALBUM_ARTIST, false)
by BooleanSetting(Constants.PREFERENCES_KEY_USE_FOLDER_FOR_ALBUM_ARTIST, false)
@JvmStatic
var shouldShowTrackNumber
by BooleanSetting(Constants.PREFERENCES_KEY_SHOW_TRACK_NUMBER, false)
by BooleanSetting(Constants.PREFERENCES_KEY_SHOW_TRACK_NUMBER, false)
@JvmStatic
var defaultAlbums
by StringIntSetting(Constants.PREFERENCES_KEY_DEFAULT_ALBUMS, "5")
by StringIntSetting(Constants.PREFERENCES_KEY_DEFAULT_ALBUMS, "5")
@JvmStatic
var maxAlbums
by StringIntSetting(Constants.PREFERENCES_KEY_MAX_ALBUMS, "20")
by StringIntSetting(Constants.PREFERENCES_KEY_MAX_ALBUMS, "20")
@JvmStatic
var defaultSongs
by StringIntSetting(Constants.PREFERENCES_KEY_DEFAULT_SONGS, "10")
by StringIntSetting(Constants.PREFERENCES_KEY_DEFAULT_SONGS, "10")
@JvmStatic
var maxSongs
by StringIntSetting(Constants.PREFERENCES_KEY_MAX_SONGS, "25")
by StringIntSetting(Constants.PREFERENCES_KEY_MAX_SONGS, "25")
@JvmStatic
var maxArtists
by StringIntSetting(Constants.PREFERENCES_KEY_MAX_ARTISTS, "10")
by StringIntSetting(Constants.PREFERENCES_KEY_MAX_ARTISTS, "10")
@JvmStatic
var defaultArtists
by StringIntSetting(Constants.PREFERENCES_KEY_DEFAULT_ARTISTS, "3")
by StringIntSetting(Constants.PREFERENCES_KEY_DEFAULT_ARTISTS, "3")
@JvmStatic
var bufferLength
by StringIntSetting(Constants.PREFERENCES_KEY_BUFFER_LENGTH, "5")
by StringIntSetting(Constants.PREFERENCES_KEY_BUFFER_LENGTH, "5")
@JvmStatic
var incrementTime
by StringIntSetting(Constants.PREFERENCES_KEY_INCREMENT_TIME, "5")
by StringIntSetting(Constants.PREFERENCES_KEY_INCREMENT_TIME, "5")
@JvmStatic
var mediaButtonsEnabled
by BooleanSetting(Constants.PREFERENCES_KEY_MEDIA_BUTTONS, true)
by BooleanSetting(Constants.PREFERENCES_KEY_MEDIA_BUTTONS, true)
@JvmStatic
var showNowPlaying
by BooleanSetting(Constants.PREFERENCES_KEY_SHOW_NOW_PLAYING, true)
by BooleanSetting(Constants.PREFERENCES_KEY_SHOW_NOW_PLAYING, true)
@JvmStatic
var gaplessPlayback
by BooleanSetting(Constants.PREFERENCES_KEY_GAPLESS_PLAYBACK, false)
by BooleanSetting(Constants.PREFERENCES_KEY_GAPLESS_PLAYBACK, false)
@JvmStatic
var shouldTransitionOnPlayback by BooleanSetting(
@ -191,7 +191,7 @@ object Settings {
@JvmStatic
var shouldUseId3Tags
by BooleanSetting(Constants.PREFERENCES_KEY_ID3_TAGS, false)
by BooleanSetting(Constants.PREFERENCES_KEY_ID3_TAGS, false)
@JvmStatic
var tempLoss by StringIntSetting(Constants.PREFERENCES_KEY_TEMP_LOSS, "1")
@ -224,19 +224,19 @@ object Settings {
)
var shouldClearPlaylist
by BooleanSetting(Constants.PREFERENCES_KEY_CLEAR_PLAYLIST, false)
by BooleanSetting(Constants.PREFERENCES_KEY_CLEAR_PLAYLIST, false)
var shouldSortByDisc
by BooleanSetting(Constants.PREFERENCES_KEY_DISC_SORT, false)
by BooleanSetting(Constants.PREFERENCES_KEY_DISC_SORT, false)
var shouldClearBookmark
by BooleanSetting(Constants.PREFERENCES_KEY_CLEAR_BOOKMARK, false)
by BooleanSetting(Constants.PREFERENCES_KEY_CLEAR_BOOKMARK, false)
var singleButtonPlayPause
by BooleanSetting(
Constants.PREFERENCES_KEY_SINGLE_BUTTON_PLAY_PAUSE,
false
)
by BooleanSetting(
Constants.PREFERENCES_KEY_SINGLE_BUTTON_PLAY_PAUSE,
false
)
// Inverted for readability
var shouldSendBluetoothNotifications by BooleanSetting(
@ -245,20 +245,20 @@ object Settings {
)
var shouldSendBluetoothAlbumArt
by BooleanSetting(Constants.PREFERENCES_KEY_SEND_BLUETOOTH_ALBUM_ART, true)
by BooleanSetting(Constants.PREFERENCES_KEY_SEND_BLUETOOTH_ALBUM_ART, true)
var shouldDisableNowPlayingListSending
by BooleanSetting(Constants.PREFERENCES_KEY_DISABLE_SEND_NOW_PLAYING_LIST, false)
by BooleanSetting(Constants.PREFERENCES_KEY_DISABLE_SEND_NOW_PLAYING_LIST, false)
@JvmStatic
var viewRefreshInterval
by StringIntSetting(Constants.PREFERENCES_KEY_VIEW_REFRESH, "1000")
by StringIntSetting(Constants.PREFERENCES_KEY_VIEW_REFRESH, "1000")
var shouldAskForShareDetails
by BooleanSetting(Constants.PREFERENCES_KEY_ASK_FOR_SHARE_DETAILS, true)
by BooleanSetting(Constants.PREFERENCES_KEY_ASK_FOR_SHARE_DETAILS, true)
var defaultShareDescription
by StringSetting(Constants.PREFERENCES_KEY_DEFAULT_SHARE_DESCRIPTION, "")
by StringSetting(Constants.PREFERENCES_KEY_DEFAULT_SHARE_DESCRIPTION, "")
@JvmStatic
val shareGreeting: String?

View File

@ -708,6 +708,7 @@ object Util {
return versionName
}
@Suppress("DEPRECATION")
fun getVersionCode(context: Context): Int {
var versionCode = 0
val pm = context.packageManager

View File

@ -29,14 +29,14 @@
<string name="chat.send_a_message">Nachricht senden</string>
<string name="common.album">Album</string>
<string name="common.appname">Ultrasonic</string>
<string name="common.artist">Künstler*in</string>
<string name="common.artist">Künstler</string>
<string name="common.cancel">Abbrechen</string>
<string name="common.comment">Kommentar</string>
<string name="common.confirm">Bestätigen</string>
<string name="common.delete">Löschen</string>
<string name="common.download">Herunterladen</string>
<string name="common.info">Details</string>
<string name="common.multiple_genres">Mehrere Genre</string>
<string name="common.multiple_genres">Mehrere Genres</string>
<string name="common.name">Name</string>
<string name="common.ok">OK</string>
<string name="common.pin">Anheften</string>
@ -44,15 +44,14 @@
<string name="common.play">Abspielen</string>
<string name="common.play_last">Zuletzt spielen</string>
<string name="common.play_next">Als nächstes spielen</string>
<string name="common.play_previous">Vorheriges abspielen
</string>
<string name="common.play_previous">Vorheriges abspielen</string>
<string name="common.play_now">Jetzt spielen</string>
<string name="common.play_shuffled">Zufällig spielen</string>
<string name="common.public">Öffentlich</string>
<string name="common.save">Speichern</string>
<string name="common.title">Titel</string>
<string name="common.unpin">Lösen</string>
<string name="common.various_artists">Verschiedene Künstler*innen</string>
<string name="common.various_artists">Verschiedene Künstler</string>
<string name="delete_playlist">Möchtest du %1$s löschen</string>
<string name="download.bookmark_removed" formatted="false">Lesezeichen entfernt</string>
<string name="download.bookmark_set_at_position" formatted="false">Lesezeichen gesetzt als %s.</string>
@ -94,7 +93,7 @@
<string name="help.url">file:///android_asset/html/de/index.html</string>
<string name="jukebox.is_default">Jukebox als Standard</string>
<string name="lyrics.nomatch">Keine Liedtexte gefunden</string>
<string name="main.albums_alphaByArtist">Nach Künstler*innen</string>
<string name="main.albums_alphaByArtist">Nach Künstler</string>
<string name="main.albums_alphaByName">Nach Namen</string>
<string name="main.albums_frequent">Am häufigsten gespielt</string>
<string name="main.albums_highest">Am besten bewertet</string>
@ -103,10 +102,11 @@
<string name="main.albums_recent">Kürzlich gespielt</string>
<string name="main.albums_starred">Mit Stern</string>
<string name="main.albums_title">Alben</string>
<string name="main.artists_title">Künstler*innen</string>
<string name="main.artists_title">Künstler</string>
<string name="main.genres_title">Genres</string>
<string name="main.music">Musik</string>
<string name="main.offline">Offline</string>
<string name="main.setup_server">%s - Server einrichten</string>
<string name="main.shuffle">Gemischte Wiedergabe</string>
<string name="main.songs_random">Zufällig</string>
<string name="main.songs_starred">Mit Stern</string>
@ -125,7 +125,7 @@
<string name="music_library.label">Medienbibliothek</string>
<string name="music_library.label_offline">Offline Medien</string>
<string name="music_service.retry">Netzwerkfehler. Neuer Versuch %1$d von %2$d.</string>
<string name="parser.artist_count">%d Künstler*in gefunden</string>
<string name="parser.artist_count">%d Künstler gefunden</string>
<string name="parser.reading">Lese vom Server.</string>
<string name="parser.reading_done">Lese vom Server. Fertig!</string>
<string name="playlist.label">Wiedergabelisten</string>
@ -134,7 +134,7 @@
<string name="playlist.updated_info_error">Aktualisierung der Wiedergabeliste %s ist fehlgeschlagen</string>
<string name="progress.wait">Bitte warten&#8230;</string>
<string name="search.albums">Alben</string>
<string name="search.artists">Künstler*innen</string>
<string name="search.artists">Künstler</string>
<string name="search.label">Suche</string>
<string name="search.more">Zeige mehr</string>
<string name="search.no_match">Keine Treffer, bitte erneut versuchen</string>
@ -149,7 +149,7 @@
<string name="select_artist.folder">Ordner wählen</string>
<string name="select_genre.empty">Keine Genres gefunden</string>
<string name="select_playlist.empty">Keine Wiedergabelisten auf dem Server</string>
<string name="service.connecting">Kontaktierse Server, bitte warten.</string>
<string name="service.connecting">Kontaktiere Server, bitte warten.</string>
<string name="settings.appearance_title">Aussehen</string>
<string name="settings.buffer_length">Puffer-Länge</string>
<string name="settings.buffer_length_0">Deaktiviert</string>
@ -218,7 +218,7 @@
<string name="settings.invalid_url">Bitte eine gültige URL angeben.</string>
<string name="settings.invalid_username">Bitte einen gültigen Benutzernamen eingeben (ohne führende Leerzeichen).</string>
<string name="settings.max_albums">Maximale Alben</string>
<string name="settings.max_artists">Maximale Künstler*innen</string>
<string name="settings.max_artists">Max Künstler</string>
<string name="settings.max_bitrate_112">112 Kbps</string>
<string name="settings.max_bitrate_128">128 Kbps</string>
<string name="settings.max_bitrate_160">160 Kbps</string>
@ -229,12 +229,12 @@
<string name="settings.max_bitrate_64">64 Kbps</string>
<string name="settings.max_bitrate_80">80 Kbps</string>
<string name="settings.max_bitrate_96">96 Kbps</string>
<string name="settings.max_bitrate_mobile">Maximale Bitragte - Mobil</string>
<string name="settings.max_bitrate_mobile">Max Bitrate - Mobil</string>
<string name="settings.max_bitrate_unlimited">Unbegrenzt</string>
<string name="settings.max_bitrate_wifi">Maximale Bitrate - WLAN</string>
<string name="settings.max_bitrate_wifi">Max Bitrate - WLAN</string>
<string name="settings.max_songs">Maximale Titel</string>
<string name="settings.media_button_summary">Auf Telefon, Headset und Bluetooth-Media-Tasten reagieren</string>
<string name="settings.media_button_title">Media Tasten</string>
<string name="settings.media_button_title">Medien Tasten</string>
<string name="settings.network_timeout">Netzwerk Zeitüberschreitung</string>
<string name="settings.network_timeout_105000">105 Sekunden</string>
<string name="settings.network_timeout_120000">120 Sekunden</string>
@ -257,6 +257,7 @@
<string name="settings.preload_unlimited">Unbegrenzt</string>
<string name="settings.playback.resume_play_on_headphones_plug.title">Fortsetzen mit Kopfhörer</string>
<string name="settings.playback.resume_play_on_headphones_plug.summary">Die App setzt eine pausierte Wiedergabe beim Anschließen der Kopfhörer fort.</string>
<string name="settings.scrobble_title">Gespielte Musik scrobbeln</string>
<string name="settings.search_1">1</string>
<string name="settings.search_10">10</string>
<string name="settings.search_100">100</string>
@ -301,6 +302,7 @@
<string name="settings.testing_unlicensed">Verbindung OK, Server nicht lizensiert.</string>
<string name="settings.theme_light">Hell</string>
<string name="settings.theme_dark">Dunkel</string>
<string name="settings.theme_black">Schwarz</string>
<string name="settings.theme_title">Thema</string>
<string name="settings.title.allow_self_signed_certificate">Selbst-signierte HTTPS Zertifikate erlauben</string>
<string name="settings.title.enable_ldap_users_support">LDAP Benutzeranmeldung aktivieren</string>
@ -310,6 +312,8 @@
<string name="settings.use_id3">Durchsuchen von ID3-Tags</string>
<string name="settings.use_id3_summary">Nutze ID3 Tag Methode anstatt Dateisystem-Methode</string>
<string name="main.video" tools:ignore="UnusedResources">Film</string>
<string name="settings.wifi_required_summary">Medien nur über gebührenfreie Verbindungen herunterladen</string>
<string name="settings.wifi_required_title">Nur über WLAN herunterladen</string>
<string name="song_details.all">%1$s%2$s</string>
<string name="song_details.kbps">%d kbps</string>
<string name="util.bytes_format.byte">0 B</string>
@ -322,11 +326,13 @@
<string name="widget.sdcard_busy">SD Karte nicht verfügbar</string>
<string name="widget.sdcard_missing">Keine SD Karte</string>
<string name="settings.share_description_default">Standard Beschreibung einer Freigabe</string>
<string name="settings.sharing_title">Teilen</string>
<string name="settings.sharing_title">Freigaben</string>
<string name="settings.sharing_always_ask_for_details">Immer nach Details fragen</string>
<string name="settings.share_expiration_default">Standard Ablaufzeit</string>
<string name="do_not_show_dialog_again">Dialog nicht wieder anzeigen</string>
<string name="share_set_share_options">Ferigabeoptionen</string>
<string name="share_set_share_options">Freigabeoptionen</string>
<string name="share_on_server">Freigabe auf Server erstellen</string>
<string name="settings.share_on_server_summary">Teilen erzeugt eine Freigabe auf dem Server und sendet die URL. Wenn ausgeschaltet, werden nur die Lied-Details geteilt.</string>
<string name="no_expiration">Kein Ablaufdatum</string>
<string name="download.toggle_playlist">Wiedergabeliste umschalten</string>
<string name="download.bookmark_set">Lesezeichen setzen</string>
@ -350,13 +356,13 @@
<string name="download_song_removed">%s wurde von der Wiedergabeliste entfernt</string>
<string name="download.share_playlist">Wiedergabeliste teilen</string>
<string name="download.share_song">Aktuelles Lied teilen</string>
<string name="settings.share_greeting_default">Standard Begrüßung beim Teilen</string>
<string name="settings.share_greeting_default">Standard Freigabe-Begrüßung</string>
<string name="share_default_greeting">Hör dir mal die Musik an, die ich mit dir über %s geteilt habe.</string>
<string name="share_via">Titel teilen über</string>
<string name="menu.share">Freigabe</string>
<string name="settings.show_all_songs_by_artist">Alle Titel nach Künstler*innen sortieren</string>
<string name="settings.show_all_songs_by_artist">Alle Titel nach Künstler sortieren</string>
<string name="settings.show_all_songs_by_artist_summary">Einen neuen Eintrag in der Künstleransicht hinzufügen, um auf alle Lieder eines Künstlers zuzugreifen</string>
<string name="download.menu_show_artist">Künstler*in zeigen</string>
<string name="download.menu_show_artist">Künstler zeigen</string>
<string name="common_multiple_years">Mehrere Jahre</string>
<string name="settings.playback.resume_on_bluetooth_device">Wiedergabe fortsetzen, wenn ein Bluetooth Gerät verbunden wurde</string>
<string name="settings.playback.pause_on_bluetooth_device">Wiedergabe pausieren, wenn ein Bluetooth Gerät getrennt wurde</string>
@ -379,4 +385,9 @@
<string name="api.subsonic.upgrade_client">Inkompatible Versionen. Bitte die Ultrasonic App aktualisieren.</string>
<string name="api.subsonic.upgrade_server">Inkompatible Versionen. Bitte den subsonic Server aktualisieren.</string>
</resources>
<!-- Subsonic features -->
<string name="settings.features_title">Besonderheiten</string>
<string name="settings.five_star_rating_title">Fünf-Stern Bewertung</string>
<string name="settings.five_star_rating_description">Benutze Bewertungssystem mit fünf Sternen anstatt Lieder mit bloß einem Stern zu markieren.</string>
</resources>