diff --git a/.circleci/config.yml b/.circleci/config.yml index b1876534..59d7bbf1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -10,24 +10,30 @@ jobs: - checkout - restore_cache: key: gradle-cache-{{ checksum "dependencies.gradle" }} + - run: + name: clean gradle.properties + command: echo "" > gradle.properties - run: name: checkstyle command: ./gradlew -Pqc ktlintCheck + - run: + name: static analysis + command: ./gradlew -Pqc detektCheck - run: name: build command: ./gradlew assembleDebug - run: name: unit-tests command: | - ./gradlew :subsonic-api:test :ultrasonic:testDebugUnitTest + ./gradlew :subsonic-api:test :cache:test :ultrasonic:testDebugUnitTest ./gradlew jacocoFullReport bash <(curl -s https://codecov.io/bash) - run: name: lint command: ./gradlew lint - run: - name: static analysis - command: ./gradlew -Pqc detektCheck + name: assemble release build + command: ./gradlew assembleRelease - save_cache: paths: - ~/.gradle diff --git a/cache/build.gradle b/cache/build.gradle new file mode 100644 index 00000000..57cecf59 --- /dev/null +++ b/cache/build.gradle @@ -0,0 +1,46 @@ +apply plugin: 'java-library' +apply plugin: 'kotlin' +apply plugin: 'jacoco' +apply from: '../gradle_scripts/code_quality.gradle' + +dependencies { + api project(':domain') + api other.kotlinStdlib + api other.twitterSerial + + testImplementation testing.junit + testImplementation testing.kotlinJunit + testImplementation testing.mockito + testImplementation testing.mockitoInline + testImplementation testing.mockitoKotlin + testImplementation testing.kluent +} + +jacoco { + toolVersion(versions.jacoco) +} + +ext { + jacocoExclude = [] +} + +jacocoTestReport { + reports { + html.enabled true + csv.enabled false + xml.enabled true + } + + afterEvaluate { + classDirectories = files(classDirectories.files.collect { + fileTree(dir: it, excludes: jacocoExclude) + }) + } +} + +test.finalizedBy jacocoTestReport +test { + jacoco { + excludes += jacocoExclude + } +} diff --git a/cache/src/main/kotlin/org/moire/ultrasonic/cache/Directories.kt b/cache/src/main/kotlin/org/moire/ultrasonic/cache/Directories.kt new file mode 100644 index 00000000..ad0aa6de --- /dev/null +++ b/cache/src/main/kotlin/org/moire/ultrasonic/cache/Directories.kt @@ -0,0 +1,14 @@ +package org.moire.ultrasonic.cache + +import java.io.File + +/** + * Provides access to generic directories: + * - for temporary caches + * - for permanent data storage + */ +interface Directories { + fun getInternalCacheDir(): File + fun getInternalDataDir(): File + fun getExternalCacheDir(): File? +} diff --git a/cache/src/main/kotlin/org/moire/ultrasonic/cache/PermanentFileStorage.kt b/cache/src/main/kotlin/org/moire/ultrasonic/cache/PermanentFileStorage.kt new file mode 100644 index 00000000..dbfa9658 --- /dev/null +++ b/cache/src/main/kotlin/org/moire/ultrasonic/cache/PermanentFileStorage.kt @@ -0,0 +1,75 @@ +package org.moire.ultrasonic.cache + +import com.twitter.serial.serializer.SerializationContext +import com.twitter.serial.serializer.Serializer +import com.twitter.serial.stream.Serial +import com.twitter.serial.stream.bytebuffer.ByteBufferSerial +import java.io.File + +typealias DomainEntitySerializer = Serializer + +internal const val STORAGE_DIR_NAME = "persistent_storage" + +/** + * Provides access to permanent file based storage. + * + * [serverId] is currently active server. Should be unique per server so stored data will not + * interfere with other server data. + * + * Look at [org.moire.ultrasonic.cache.serializers] package for available [DomainEntitySerializer]s. + */ +class PermanentFileStorage( + private val directories: Directories, + private val serverId: String, + private val debug: Boolean = false +) { + private val serializationContext = object : SerializationContext { + override fun isDebug(): Boolean = debug + override fun isRelease(): Boolean = !debug + } + + private val serializer: Serial = ByteBufferSerial(serializationContext) + + /** + * Stores given [objectToStore] using [name] as a key and [objectSerializer] as serializer. + */ + fun store( + name: String, + objectToStore: T, + objectSerializer: DomainEntitySerializer + ) { + val storeFile = getFile(name) + if (!storeFile.exists()) storeFile.createNewFile() + storeFile.writeBytes(serializer.toByteArray(objectToStore, objectSerializer)) + } + + /** + * Loads object with [name] key using [objectDeserializer] deserializer. + */ + fun load( + name: String, + objectDeserializer: DomainEntitySerializer + ): T? { + val storeFile = getFile(name) + if (!storeFile.exists()) return null + + return serializer.fromByteArray(storeFile.readBytes(), objectDeserializer) + } + + /** + * Clear all files in storage. + */ + fun clearAll() { + val storageDir = getStorageDir() + storageDir.listFiles().forEach { it.deleteRecursively() } + } + + private fun getFile(name: String) = File(getStorageDir(), "$name.ser") + + private fun getStorageDir(): File { + val mainDir = File(directories.getInternalDataDir(), STORAGE_DIR_NAME) + val serverDir = File(mainDir, serverId) + if (!serverDir.exists()) serverDir.mkdirs() + return serverDir + } +} diff --git a/cache/src/main/kotlin/org/moire/ultrasonic/cache/serializers/ArtistSerializer.kt b/cache/src/main/kotlin/org/moire/ultrasonic/cache/serializers/ArtistSerializer.kt new file mode 100644 index 00000000..751a97d5 --- /dev/null +++ b/cache/src/main/kotlin/org/moire/ultrasonic/cache/serializers/ArtistSerializer.kt @@ -0,0 +1,65 @@ +@file:JvmMultifileClass +@file:JvmName("DomainSerializers") +package org.moire.ultrasonic.cache.serializers + +import com.twitter.serial.serializer.CollectionSerializers +import com.twitter.serial.serializer.ObjectSerializer +import com.twitter.serial.serializer.SerializationContext +import com.twitter.serial.stream.SerializerDefs +import com.twitter.serial.stream.SerializerInput +import com.twitter.serial.stream.SerializerOutput +import org.moire.ultrasonic.cache.DomainEntitySerializer +import org.moire.ultrasonic.domain.Artist + +private const val SERIALIZER_VERSION = 1 + +private val artistSerializer get() = object : ObjectSerializer(SERIALIZER_VERSION) { + override fun serializeObject( + context: SerializationContext, + output: SerializerOutput>, + item: Artist + ) { + output.writeString(item.id) + .writeString(item.name) + .writeString(item.index) + .writeString(item.coverArt) + .apply { + val albumCount = item.albumCount + if (albumCount != null) writeLong(albumCount) else writeNull() + } + .writeInt(item.closeness) + } + + override fun deserializeObject( + context: SerializationContext, + input: SerializerInput, + versionNumber: Int + ): Artist? { + if (versionNumber != SERIALIZER_VERSION) return null + + val id = input.readString() + val name = input.readString() + val index = input.readString() + val coverArt = input.readString() + val albumCount = if (input.peekType() == SerializerDefs.TYPE_NULL) { + input.readNull() + null + } else { + input.readLong() + } + val closeness = input.readInt() + return Artist(id, name, index, coverArt, albumCount, closeness) + } +} + +/** + * Serializer/deserializer for [Artist] domain entity. + */ +fun getArtistsSerializer(): DomainEntitySerializer = artistSerializer + +private val artistListSerializer = CollectionSerializers.getListSerializer(artistSerializer) + +/** + * Serializer/deserializer for list of [Artist] domain entities. + */ +fun getArtistListSerializer(): DomainEntitySerializer> = artistListSerializer diff --git a/cache/src/main/kotlin/org/moire/ultrasonic/cache/serializers/IndexesSerializer.kt b/cache/src/main/kotlin/org/moire/ultrasonic/cache/serializers/IndexesSerializer.kt new file mode 100644 index 00000000..c237be76 --- /dev/null +++ b/cache/src/main/kotlin/org/moire/ultrasonic/cache/serializers/IndexesSerializer.kt @@ -0,0 +1,48 @@ +@file:JvmMultifileClass +@file:JvmName("DomainSerializers") +package org.moire.ultrasonic.cache.serializers + +import com.twitter.serial.serializer.ObjectSerializer +import com.twitter.serial.serializer.SerializationContext +import com.twitter.serial.stream.SerializerInput +import com.twitter.serial.stream.SerializerOutput +import org.moire.ultrasonic.cache.DomainEntitySerializer +import org.moire.ultrasonic.domain.Artist +import org.moire.ultrasonic.domain.Indexes + +private const val SERIALIZATION_VERSION = 1 + +private val indexesSerializer get() = object : ObjectSerializer(SERIALIZATION_VERSION) { + override fun serializeObject( + context: SerializationContext, + output: SerializerOutput>, + item: Indexes + ) { + val artistListSerializer = getArtistListSerializer() + output.writeLong(item.lastModified) + .writeString(item.ignoredArticles) + .writeObject>(context, item.shortcuts, artistListSerializer) + .writeObject>(context, item.artists, artistListSerializer) + } + + override fun deserializeObject( + context: SerializationContext, + input: SerializerInput, + versionNumber: Int + ): Indexes? { + if (versionNumber != SERIALIZATION_VERSION) return null + + val artistListDeserializer = getArtistListSerializer() + val lastModified = input.readLong() + val ignoredArticles = input.readString() ?: return null + val shortcutsList = input.readObject(context, artistListDeserializer) ?: return null + val artistsList = input.readObject(context, artistListDeserializer) ?: return null + return Indexes(lastModified, ignoredArticles, shortcutsList.toMutableList(), + artistsList.toMutableList()) + } +} + +/** + * Get serializer/deserializer for [Indexes] entity. + */ +fun getIndexesSerializer(): DomainEntitySerializer = indexesSerializer diff --git a/cache/src/main/kotlin/org/moire/ultrasonic/cache/serializers/MusicFolderSerializer.kt b/cache/src/main/kotlin/org/moire/ultrasonic/cache/serializers/MusicFolderSerializer.kt new file mode 100644 index 00000000..c65fabad --- /dev/null +++ b/cache/src/main/kotlin/org/moire/ultrasonic/cache/serializers/MusicFolderSerializer.kt @@ -0,0 +1,50 @@ +@file:JvmMultifileClass +@file:JvmName("DomainSerializers") +package org.moire.ultrasonic.cache.serializers + +import com.twitter.serial.serializer.CollectionSerializers +import com.twitter.serial.serializer.ObjectSerializer +import com.twitter.serial.serializer.SerializationContext +import com.twitter.serial.stream.SerializerInput +import com.twitter.serial.stream.SerializerOutput +import org.moire.ultrasonic.cache.DomainEntitySerializer +import org.moire.ultrasonic.domain.MusicFolder + +private const val SERIALIZATION_VERSION = 1 + +private val musicFolderSerializer = object : ObjectSerializer(SERIALIZATION_VERSION) { + + override fun serializeObject( + context: SerializationContext, + output: SerializerOutput>, + item: MusicFolder + ) { + output.writeString(item.id).writeString(item.name) + } + + override fun deserializeObject( + context: SerializationContext, + input: SerializerInput, + versionNumber: Int + ): MusicFolder? { + if (versionNumber != SERIALIZATION_VERSION) return null + + val id = input.readString() ?: return null + val name = input.readString() ?: return null + return MusicFolder(id, name) + } +} + +/** + * Serializer/deserializer for [MusicFolder] domain entity. + */ +fun getMusicFolderSerializer(): DomainEntitySerializer = musicFolderSerializer + +private val musicFolderListSerializer = + CollectionSerializers.getListSerializer(musicFolderSerializer) + +/** + * Serializer/deserializer for [List] of [MusicFolder] items. + */ +fun getMusicFolderListSerializer(): DomainEntitySerializer> = + musicFolderListSerializer diff --git a/cache/src/test/kotlin/org/moire/ultrasonic/cache/BaseStorageTest.kt b/cache/src/test/kotlin/org/moire/ultrasonic/cache/BaseStorageTest.kt new file mode 100644 index 00000000..bc06f483 --- /dev/null +++ b/cache/src/test/kotlin/org/moire/ultrasonic/cache/BaseStorageTest.kt @@ -0,0 +1,42 @@ +package org.moire.ultrasonic.cache + +import com.nhaarman.mockito_kotlin.mock +import com.twitter.serial.util.SerializationUtils +import org.amshove.kluent.`it returns` +import org.junit.Before +import org.junit.Rule +import org.junit.rules.TemporaryFolder +import java.io.File + +internal const val INTERNAL_DATA_FOLDER = "data" +internal const val INTERNAL_CACHE_FOLDER = "cache" +internal const val EXTERNAL_CACHE_FOLDER = "external_cache" + +/** + * Base test class that inits the storage + */ +abstract class BaseStorageTest { + @get:Rule val tempFileRule = TemporaryFolder() + + protected lateinit var mockDirectories: Directories + protected lateinit var storage: PermanentFileStorage + + open val serverId: String = "" + + @Before + fun setUp() { + mockDirectories = mock { + on { getInternalDataDir() } `it returns` tempFileRule.newFolder(INTERNAL_DATA_FOLDER) + on { getInternalCacheDir() } `it returns` tempFileRule.newFolder(INTERNAL_CACHE_FOLDER) + on { getExternalCacheDir() } `it returns` tempFileRule.newFolder(EXTERNAL_CACHE_FOLDER) + } + storage = PermanentFileStorage(mockDirectories, serverId, true) + } + + protected val storageDir get() = File(mockDirectories.getInternalDataDir(), STORAGE_DIR_NAME) + + protected fun validateSerializedData(index: Int = 0) { + val serializedFileBytes = storageDir.listFiles()[index].readBytes() + SerializationUtils.validateSerializedData(serializedFileBytes) + } +} diff --git a/cache/src/test/kotlin/org/moire/ultrasonic/cache/PermanentFileStorageTest.kt b/cache/src/test/kotlin/org/moire/ultrasonic/cache/PermanentFileStorageTest.kt new file mode 100644 index 00000000..bd84b528 --- /dev/null +++ b/cache/src/test/kotlin/org/moire/ultrasonic/cache/PermanentFileStorageTest.kt @@ -0,0 +1,81 @@ +package org.moire.ultrasonic.cache + +import org.amshove.kluent.`should contain` +import org.amshove.kluent.`should equal to` +import org.amshove.kluent.`should equal` +import org.junit.Test +import org.moire.ultrasonic.cache.serializers.getMusicFolderSerializer +import org.moire.ultrasonic.domain.MusicFolder +import java.io.File + +/** + * Integration test for [PermanentFileStorage]. + */ +class PermanentFileStorageTest : BaseStorageTest() { + override val serverId: String + get() = "some-server-id" + + @Test + fun `Should create storage dir if it is not exist`() { + val item = MusicFolder("1", "2") + storage.store("test", item, getMusicFolderSerializer()) + + storageDir.exists() `should equal to` true + getServerStorageDir().exists() `should equal to` true + } + + @Test + fun `Should serialize to file`() { + val item = MusicFolder("1", "23") + val name = "some-name" + + storage.store(name, item, getMusicFolderSerializer()) + + val storageFiles = getServerStorageDir().listFiles() + storageFiles.size `should equal to` 1 + storageFiles[0].name `should contain` name + } + + @Test + fun `Should deserialize stored object`() { + val item = MusicFolder("some", "nice") + val name = "some-name" + storage.store(name, item, getMusicFolderSerializer()) + + val loadedItem = storage.load(name, getMusicFolderSerializer()) + + loadedItem `should equal` item + } + + @Test + fun `Should overwrite existing stored object`() { + val name = "some-nice-name" + val item1 = MusicFolder("1", "1") + val item2 = MusicFolder("2", "2") + storage.store(name, item1, getMusicFolderSerializer()) + storage.store(name, item2, getMusicFolderSerializer()) + + val loadedItem = storage.load(name, getMusicFolderSerializer()) + + loadedItem `should equal` item2 + } + + @Test + fun `Should clear all files when clearAll is called`() { + storage.store("name1", MusicFolder("1", "1"), getMusicFolderSerializer()) + storage.store("name2", MusicFolder("2", "2"), getMusicFolderSerializer()) + + storage.clearAll() + + getServerStorageDir().listFiles().size `should equal to` 0 + } + + @Test + fun `Should return null if serialized file not available`() { + val loadedItem = storage.load("some-name", getMusicFolderSerializer()) + + loadedItem `should equal` null + } + + private fun getServerStorageDir() = File(storageDir, serverId) +} diff --git a/cache/src/test/kotlin/org/moire/ultrasonic/cache/serializers/ArtistSerializerTest.kt b/cache/src/test/kotlin/org/moire/ultrasonic/cache/serializers/ArtistSerializerTest.kt new file mode 100644 index 00000000..7829467b --- /dev/null +++ b/cache/src/test/kotlin/org/moire/ultrasonic/cache/serializers/ArtistSerializerTest.kt @@ -0,0 +1,57 @@ +package org.moire.ultrasonic.cache.serializers + +import org.amshove.kluent.`should equal` +import org.junit.Test +import org.moire.ultrasonic.cache.BaseStorageTest +import org.moire.ultrasonic.domain.Artist + +/** + * [Artist] serializers test. + */ +class ArtistSerializerTest : BaseStorageTest() { + @Test + fun `Should correctly serialize Artist object`() { + val item = Artist("id", "name", "index", "coverArt", 1, 0) + + storage.store("some-name", item, getArtistsSerializer()) + + validateSerializedData() + } + + @Test + fun `Should correctly deserialize Artist object`() { + val itemName = "some-name" + val item = Artist("id", "name", "index", "coverArt", null, 0) + storage.store(itemName, item, getArtistsSerializer()) + + val loadedItem = storage.load(itemName, getArtistsSerializer()) + + loadedItem `should equal` item + } + + @Test + fun `Should correctly serialize list of Artists`() { + val itemsList = listOf( + Artist(id = "1"), + Artist(id = "2", name = "some") + ) + + storage.store("some-name", itemsList, getArtistListSerializer()) + + validateSerializedData() + } + + @Test + fun `Should correctly deserialize list of Artists`() { + val name = "some-name" + val itemsList = listOf( + Artist(id = "1"), + Artist(id = "2", name = "some") + ) + storage.store(name, itemsList, getArtistListSerializer()) + + val loadedItems = storage.load(name, getArtistListSerializer()) + + loadedItems `should equal` itemsList + } +} diff --git a/cache/src/test/kotlin/org/moire/ultrasonic/cache/serializers/IndexesSerializerTest.kt b/cache/src/test/kotlin/org/moire/ultrasonic/cache/serializers/IndexesSerializerTest.kt new file mode 100644 index 00000000..9cffbd8b --- /dev/null +++ b/cache/src/test/kotlin/org/moire/ultrasonic/cache/serializers/IndexesSerializerTest.kt @@ -0,0 +1,40 @@ +package org.moire.ultrasonic.cache.serializers + +import org.amshove.kluent.`should equal` +import org.junit.Test +import org.moire.ultrasonic.cache.BaseStorageTest +import org.moire.ultrasonic.domain.Artist +import org.moire.ultrasonic.domain.Indexes + +/** + * Test [Indexes] domain entity serializer. + */ +class IndexesSerializerTest : BaseStorageTest() { + @Test + fun `Should correctly serialize Indexes object`() { + val item = Indexes(220L, "", mutableListOf( + Artist("12") + ), mutableListOf( + Artist("233", "some") + )) + + storage.store("some-name", item, getIndexesSerializer()) + + validateSerializedData() + } + + @Test + fun `Should correctly deserialize Indexes object`() { + val name = "some-name" + val item = Indexes(220L, "", mutableListOf( + Artist("12") + ), mutableListOf( + Artist("233", "some") + )) + storage.store(name, item, getIndexesSerializer()) + + val loadedItem = storage.load(name, getIndexesSerializer()) + + loadedItem `should equal` item + } +} diff --git a/cache/src/test/kotlin/org/moire/ultrasonic/cache/serializers/MusicFolderSerializerTest.kt b/cache/src/test/kotlin/org/moire/ultrasonic/cache/serializers/MusicFolderSerializerTest.kt new file mode 100644 index 00000000..0efe2811 --- /dev/null +++ b/cache/src/test/kotlin/org/moire/ultrasonic/cache/serializers/MusicFolderSerializerTest.kt @@ -0,0 +1,57 @@ +package org.moire.ultrasonic.cache.serializers + +import org.amshove.kluent.`should equal` +import org.junit.Test +import org.moire.ultrasonic.cache.BaseStorageTest +import org.moire.ultrasonic.domain.MusicFolder + +/** + * [MusicFolder] serializers test. + */ +class MusicFolderSerializerTest : BaseStorageTest() { + @Test + fun `Should correctly serialize MusicFolder object`() { + val item = MusicFolder("Music", "Folder") + + storage.store("some-name", item, getMusicFolderSerializer()) + + validateSerializedData() + } + + @Test + fun `Should correctly deserialize MusicFolder object`() { + val name = "name" + val item = MusicFolder("some", "none") + storage.store(name, item, getMusicFolderSerializer()) + + val loadedItem = storage.load(name, getMusicFolderSerializer()) + + loadedItem `should equal` item + } + + @Test + fun `Should correctly serialize list of MusicFolders objects`() { + val itemsList = listOf( + MusicFolder("1", "1"), + MusicFolder("2", "2") + ) + + storage.store("some-name", itemsList, getMusicFolderListSerializer()) + + validateSerializedData() + } + + @Test + fun `Should correctly deserialize list of MusicFolder objects`() { + val name = "some-name" + val itemsList = listOf( + MusicFolder("1", "1"), + MusicFolder("2", "2") + ) + storage.store(name, itemsList, getMusicFolderListSerializer()) + + val loadedItem = storage.load(name, getMusicFolderListSerializer()) + + loadedItem `should equal` itemsList + } +} diff --git a/dependencies.gradle b/dependencies.gradle index 212ef992..ae3e47e9 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -1,26 +1,28 @@ ext.versions = [ - versionCode : 63, - versionName : "2.2.2", + versionCode : 64, + versionName : "2.3.0", minSdk : 14, targetSdk : 22, compileSdk : 27, - gradle : '4.4.1', + gradle : '4.5.1', androidTools : "3.0.1", - ktlint : "0.14.0", - ktlintGradle : "2.3.0", - detekt : "1.0.0.RC6", + ktlint : "0.15.1", + ktlintGradle : "3.0.1", + detekt : "1.0.0.RC6-3", jacoco : "0.7.9", jacocoAndroid : "0.1.2", androidSupport : "22.2.1", - kotlin : "1.2.10", + kotlin : "1.2.21", retrofit : "2.1.0", jackson : "2.9.0", okhttp : "3.9.0", + semver : "1.0.0", + twitterSerial : "0.1.6", junit : "4.12", mockito : "2.12.0", @@ -50,6 +52,8 @@ ext.other = [ 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", + semver : "net.swiftzer.semver:semver:$versions.semver", + twitterSerial : "com.twitter.serial:serial:$versions.twitterSerial", ] ext.testing = [ diff --git a/domain/build.gradle b/domain/build.gradle new file mode 100644 index 00000000..cab611de --- /dev/null +++ b/domain/build.gradle @@ -0,0 +1,38 @@ +apply plugin: 'java-library' +apply plugin: 'kotlin' +apply plugin: 'jacoco' +apply from: '../gradle_scripts/code_quality.gradle' + +dependencies { + api other.kotlinStdlib + api other.semver +} + +jacoco { + toolVersion(versions.jacoco) +} + +ext { + jacocoExclude = [] +} + +jacocoTestReport { + reports { + html.enabled true + csv.enabled false + xml.enabled true + } + + afterEvaluate { + classDirectories = files(classDirectories.files.collect { + fileTree(dir: it, excludes: jacocoExclude) + }) + } +} + +test.finalizedBy jacocoTestReport +test { + jacoco { + excludes += jacocoExclude + } +} diff --git a/domain/src/main/kotlin/org/moire/ultrasonic/domain/Artist.kt b/domain/src/main/kotlin/org/moire/ultrasonic/domain/Artist.kt new file mode 100644 index 00000000..dd46d415 --- /dev/null +++ b/domain/src/main/kotlin/org/moire/ultrasonic/domain/Artist.kt @@ -0,0 +1,16 @@ +package org.moire.ultrasonic.domain + +import java.io.Serializable + +data class Artist( + var id: String? = null, + var name: String? = null, + var index: String? = null, + var coverArt: String? = null, + var albumCount: Long? = null, + var closeness: Int = 0 +) : Serializable { + companion object { + private const val serialVersionUID = -5790532593784846982L + } +} diff --git a/domain/src/main/kotlin/org/moire/ultrasonic/domain/Bookmark.kt b/domain/src/main/kotlin/org/moire/ultrasonic/domain/Bookmark.kt new file mode 100644 index 00000000..4e3458db --- /dev/null +++ b/domain/src/main/kotlin/org/moire/ultrasonic/domain/Bookmark.kt @@ -0,0 +1,19 @@ +package org.moire.ultrasonic.domain + +import org.moire.ultrasonic.domain.MusicDirectory.Entry + +import java.io.Serializable +import java.util.Date + +data class Bookmark( + val position: Int = 0, + val username: String, + val comment: String, + val created: Date? = null, + val changed: Date? = null, + val entry: Entry +) : Serializable { + companion object { + private const val serialVersionUID = 8988990025189807803L + } +} diff --git a/domain/src/main/kotlin/org/moire/ultrasonic/domain/ChatMessage.kt b/domain/src/main/kotlin/org/moire/ultrasonic/domain/ChatMessage.kt new file mode 100644 index 00000000..35e112e2 --- /dev/null +++ b/domain/src/main/kotlin/org/moire/ultrasonic/domain/ChatMessage.kt @@ -0,0 +1,13 @@ +package org.moire.ultrasonic.domain + +import java.io.Serializable + +data class ChatMessage( + val username: String, + val time: Long, + val message: String +) : Serializable { + companion object { + private const val serialVersionUID = 496544310289324167L + } +} diff --git a/domain/src/main/kotlin/org/moire/ultrasonic/domain/Genre.kt b/domain/src/main/kotlin/org/moire/ultrasonic/domain/Genre.kt new file mode 100644 index 00000000..c975d437 --- /dev/null +++ b/domain/src/main/kotlin/org/moire/ultrasonic/domain/Genre.kt @@ -0,0 +1,12 @@ +package org.moire.ultrasonic.domain + +import java.io.Serializable + +data class Genre( + val name: String, + val index: String +) : Serializable { + companion object { + private const val serialVersionUID = -3943025175219134028L + } +} diff --git a/domain/src/main/kotlin/org/moire/ultrasonic/domain/Indexes.kt b/domain/src/main/kotlin/org/moire/ultrasonic/domain/Indexes.kt new file mode 100644 index 00000000..48711c2d --- /dev/null +++ b/domain/src/main/kotlin/org/moire/ultrasonic/domain/Indexes.kt @@ -0,0 +1,14 @@ +package org.moire.ultrasonic.domain + +import java.io.Serializable + +data class Indexes( + val lastModified: Long, + val ignoredArticles: String, + val shortcuts: MutableList = mutableListOf(), + val artists: MutableList = mutableListOf() +) : Serializable { + companion object { + private const val serialVersionUID = 8156117238598414701L + } +} diff --git a/domain/src/main/kotlin/org/moire/ultrasonic/domain/JukeboxStatus.kt b/domain/src/main/kotlin/org/moire/ultrasonic/domain/JukeboxStatus.kt new file mode 100644 index 00000000..67b0e8b5 --- /dev/null +++ b/domain/src/main/kotlin/org/moire/ultrasonic/domain/JukeboxStatus.kt @@ -0,0 +1,8 @@ +package org.moire.ultrasonic.domain + +data class JukeboxStatus( + var positionSeconds: Int? = null, + var currentPlayingIndex: Int? = null, + var gain: Float? = null, + var isPlaying: Boolean = false +) diff --git a/domain/src/main/kotlin/org/moire/ultrasonic/domain/Lyrics.kt b/domain/src/main/kotlin/org/moire/ultrasonic/domain/Lyrics.kt new file mode 100644 index 00000000..6c4315f1 --- /dev/null +++ b/domain/src/main/kotlin/org/moire/ultrasonic/domain/Lyrics.kt @@ -0,0 +1,10 @@ +package org.moire.ultrasonic.domain + +/** + * Song lyrics. + */ +data class Lyrics( + val artist: String? = null, + val title: String? = null, + val text: String? = null +) diff --git a/domain/src/main/kotlin/org/moire/ultrasonic/domain/MusicDirectory.kt b/domain/src/main/kotlin/org/moire/ultrasonic/domain/MusicDirectory.kt new file mode 100644 index 00000000..6a647026 --- /dev/null +++ b/domain/src/main/kotlin/org/moire/ultrasonic/domain/MusicDirectory.kt @@ -0,0 +1,75 @@ +package org.moire.ultrasonic.domain + +import java.io.Serializable +import java.util.Date + +class MusicDirectory { + var name: String? = null + private val children = mutableListOf() + + fun addAll(entries: Collection) { + children.addAll(entries) + } + + fun addFirst(child: Entry) { + children.add(0, child) + } + + fun addChild(child: Entry) { + children.add(child) + } + + fun findChild(id: String): Entry? = children.lastOrNull { it.id == id } + + fun getAllChild(): List = children.toList() + + @JvmOverloads + fun getChildren( + includeDirs: Boolean = true, + includeFiles: Boolean = true): List { + if (includeDirs && includeFiles) { + return children + } + + return children.filter { it.isDirectory && includeDirs || !it.isDirectory && includeFiles } + } + + data class Entry( + var id: String? = null, + var parent: String? = null, + var isDirectory: Boolean = false, + var title: String? = null, + var album: String? = null, + var albumId: String? = null, + var artist: String? = null, + var artistId: String? = null, + var track: Int? = 0, + var year: Int? = 0, + var genre: String? = null, + var contentType: String? = null, + var suffix: String? = null, + var transcodedContentType: String? = null, + var transcodedSuffix: String? = null, + var coverArt: String? = null, + var size: Long? = null, + var songCount: Long? = null, + var duration: Int? = null, + var bitRate: Int? = null, + var path: String? = null, + var isVideo: Boolean = false, + var starred: Boolean = false, + var discNumber: Int? = null, + var type: String? = null, + var created: Date? = null, + var closeness: Int = 0, + var bookmarkPosition: Int = 0 + ) : Serializable { + fun setDuration(duration: Long) { + this.duration = duration.toInt() + } + + companion object { + private const val serialVersionUID = -3339106650010798108L + } + } +} diff --git a/domain/src/main/kotlin/org/moire/ultrasonic/domain/MusicFolder.kt b/domain/src/main/kotlin/org/moire/ultrasonic/domain/MusicFolder.kt new file mode 100644 index 00000000..a7e91d27 --- /dev/null +++ b/domain/src/main/kotlin/org/moire/ultrasonic/domain/MusicFolder.kt @@ -0,0 +1,9 @@ +package org.moire.ultrasonic.domain + +/** + * Represents a top level directory in which music or other media is stored. + */ +data class MusicFolder( + val id: String, + val name: String +) diff --git a/domain/src/main/kotlin/org/moire/ultrasonic/domain/PlayerState.kt b/domain/src/main/kotlin/org/moire/ultrasonic/domain/PlayerState.kt new file mode 100644 index 00000000..7ae5dd66 --- /dev/null +++ b/domain/src/main/kotlin/org/moire/ultrasonic/domain/PlayerState.kt @@ -0,0 +1,12 @@ +package org.moire.ultrasonic.domain + +enum class PlayerState { + IDLE, + DOWNLOADING, + PREPARING, + PREPARED, + STARTED, + STOPPED, + PAUSED, + COMPLETED +} diff --git a/domain/src/main/kotlin/org/moire/ultrasonic/domain/Playlist.kt b/domain/src/main/kotlin/org/moire/ultrasonic/domain/Playlist.kt new file mode 100644 index 00000000..4f8f7925 --- /dev/null +++ b/domain/src/main/kotlin/org/moire/ultrasonic/domain/Playlist.kt @@ -0,0 +1,17 @@ +package org.moire.ultrasonic.domain + +import java.io.Serializable + +data class Playlist @JvmOverloads constructor( + val id: String, + var name: String, + val owner: String = "", + val comment: String = "", + val songCount: String = "", + val created: String = "", + val public: Boolean? = null +) : Serializable { + companion object { + private const val serialVersionUID = -4160515427075433798L + } +} diff --git a/domain/src/main/kotlin/org/moire/ultrasonic/domain/PodcastsChannel.kt b/domain/src/main/kotlin/org/moire/ultrasonic/domain/PodcastsChannel.kt new file mode 100644 index 00000000..3b6ae96e --- /dev/null +++ b/domain/src/main/kotlin/org/moire/ultrasonic/domain/PodcastsChannel.kt @@ -0,0 +1,15 @@ +package org.moire.ultrasonic.domain + +import java.io.Serializable + +data class PodcastsChannel( + val id: String, + val title: String?, + val url: String?, + val description: String?, + val status: String? +) : Serializable { + companion object { + private const val serialVersionUID = -4160515427075433798L + } +} diff --git a/domain/src/main/kotlin/org/moire/ultrasonic/domain/RepeatMode.kt b/domain/src/main/kotlin/org/moire/ultrasonic/domain/RepeatMode.kt new file mode 100644 index 00000000..f9005eb9 --- /dev/null +++ b/domain/src/main/kotlin/org/moire/ultrasonic/domain/RepeatMode.kt @@ -0,0 +1,15 @@ +package org.moire.ultrasonic.domain + +enum class RepeatMode { + OFF { + override operator fun next(): RepeatMode = ALL + }, + ALL { + override operator fun next(): RepeatMode = SINGLE + }, + SINGLE { + override operator fun next(): RepeatMode = OFF + }; + + abstract operator fun next(): RepeatMode +} diff --git a/domain/src/main/kotlin/org/moire/ultrasonic/domain/SearchCriteria.kt b/domain/src/main/kotlin/org/moire/ultrasonic/domain/SearchCriteria.kt new file mode 100644 index 00000000..336db68d --- /dev/null +++ b/domain/src/main/kotlin/org/moire/ultrasonic/domain/SearchCriteria.kt @@ -0,0 +1,11 @@ +package org.moire.ultrasonic.domain + +/** + * The criteria for a music search. + */ +data class SearchCriteria( + val query: String, + val artistCount: Int, + val albumCount: Int, + val songCount: Int +) diff --git a/domain/src/main/kotlin/org/moire/ultrasonic/domain/SearchResult.kt b/domain/src/main/kotlin/org/moire/ultrasonic/domain/SearchResult.kt new file mode 100644 index 00000000..738ccfc6 --- /dev/null +++ b/domain/src/main/kotlin/org/moire/ultrasonic/domain/SearchResult.kt @@ -0,0 +1,12 @@ +package org.moire.ultrasonic.domain + +import org.moire.ultrasonic.domain.MusicDirectory.Entry + +/** + * The result of a search. Contains matching artists, albums and songs. + */ +data class SearchResult( + val artists: List, + val albums: List, + val songs: List +) diff --git a/domain/src/main/kotlin/org/moire/ultrasonic/domain/Share.kt b/domain/src/main/kotlin/org/moire/ultrasonic/domain/Share.kt new file mode 100644 index 00000000..896cdb32 --- /dev/null +++ b/domain/src/main/kotlin/org/moire/ultrasonic/domain/Share.kt @@ -0,0 +1,32 @@ +package org.moire.ultrasonic.domain + +import org.moire.ultrasonic.domain.MusicDirectory.Entry +import java.io.Serializable + +data class Share( + var id: String? = null, + var url: String? = null, + var description: String? = null, + var username: String? = null, + var created: String? = null, + var lastVisited: String? = null, + var expires: String? = null, + var visitCount: Long? = null, + private val entries: MutableList = mutableListOf() +) : Serializable { + val name: String? + get() = url?.let { urlPattern.matcher(url).replaceFirst("$1") } + + fun getEntries(): List { + return entries.toList() + } + + fun addEntry(entry: Entry) { + entries.add(entry) + } + + companion object { + private const val serialVersionUID = 1487561657691009668L + private val urlPattern = ".*/([^/?]+).*".toPattern() + } +} diff --git a/domain/src/main/kotlin/org/moire/ultrasonic/domain/UserInfo.kt b/domain/src/main/kotlin/org/moire/ultrasonic/domain/UserInfo.kt new file mode 100644 index 00000000..b4401d4b --- /dev/null +++ b/domain/src/main/kotlin/org/moire/ultrasonic/domain/UserInfo.kt @@ -0,0 +1,21 @@ +package org.moire.ultrasonic.domain + +/** + * Information about user + */ +data class UserInfo( + val userName: String? = null, + val email: String? = null, + val scrobblingEnabled: Boolean = false, + val adminRole: Boolean = false, + val settingsRole: Boolean = false, + val downloadRole: Boolean = false, + val uploadRole: Boolean = false, + val playlistRole: Boolean = false, + val coverArtRole: Boolean = false, + val commentRole: Boolean = false, + val podcastRole: Boolean = false, + val streamRole: Boolean = false, + val jukeboxRole: Boolean = false, + val shareRole: Boolean = false +) diff --git a/domain/src/main/kotlin/org/moire/ultrasonic/domain/Version.kt b/domain/src/main/kotlin/org/moire/ultrasonic/domain/Version.kt new file mode 100644 index 00000000..26fabbcd --- /dev/null +++ b/domain/src/main/kotlin/org/moire/ultrasonic/domain/Version.kt @@ -0,0 +1,27 @@ +package org.moire.ultrasonic.domain + +import net.swiftzer.semver.SemVer + +/** + * Represents the version number of the Subsonic Android app. + */ +data class Version( + val version: SemVer +) : Comparable { + + override fun compareTo(other: Version): Int { + return version.compareTo(other.version) + } + + companion object { + /** + * Creates a new version instance by parsing the given string. + * + * @param version A string of the format "1.27", "1.27.2" or "1.27.beta3". + */ + @JvmStatic + fun fromCharSequence(version: String): Version { + return Version(SemVer.parse(version)) + } + } +} diff --git a/gradle.properties b/gradle.properties index 68967e5e..c56ddc2f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,10 @@ org.gradle.parallel=true +org.gradle.daemon=true org.gradle.configureondemand=true -org.gradle.caching=true \ No newline at end of file +org.gradle.caching=true + +kotlin.incremental=true +kotlin.caching.enabled=true +kotlin.incremental.usePreciseJavaTracking=true + +android.enableBuildCache=true diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 57c7d2d2..8941bfbb 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.4.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.5.1-all.zip diff --git a/gradle_scripts/code_quality.gradle b/gradle_scripts/code_quality.gradle index 3992a621..9b9a5308 100644 --- a/gradle_scripts/code_quality.gradle +++ b/gradle_scripts/code_quality.gradle @@ -7,6 +7,7 @@ if (isCodeQualityEnabled) { ktlint { version = versions.ktlint + outputToConsole = true android = true } } diff --git a/gradle_scripts/jacoco.gradle b/gradle_scripts/jacoco.gradle index 67a75609..5be89860 100644 --- a/gradle_scripts/jacoco.gradle +++ b/gradle_scripts/jacoco.gradle @@ -6,9 +6,11 @@ task jacocoMergeReports(type: JacocoMerge) { def subsonicApi = project.findProject("subsonic-api") def ultrasonicApp = project.findProject("ultrasonic") + def cache = project.findProject("cache") executionData( "${subsonicApi.buildDir}/jacoco/test.exec", "${ultrasonicApp.buildDir}/jacoco/testDebugUnitTest.exec", + "${cache.buildDir}/jacoco/test.exec" ) destinationFile(file("${project.buildDir}/jacoco/jacoco.exec")) } @@ -20,6 +22,7 @@ def createJacocoFullReportTask() { def subsonicApi = project.findProject("subsonic-api") def ultrasonicApp = project.findProject("ultrasonic") + def cache = project.findProject("cache") classDirectories = files( fileTree( @@ -29,6 +32,10 @@ def createJacocoFullReportTask() { fileTree( dir: "${ultrasonicApp.buildDir}/intermediates/classes/debug/org", excludes: ultrasonicApp.jacocoExclude + ), + fileTree( + dir: "${cache.buildDir}/classes/kotlin/main", + excludes: cache.jacocoExclude ) ) sourceDirectories = files(subsonicApi.sourceSets.main.getAllSource(), diff --git a/settings.gradle b/settings.gradle index 7601205f..256032c5 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,4 +1,7 @@ -include ':library', ':subsonic-api' +include ':library' +include ':domain' +include ':subsonic-api' +include ':cache' include ':menudrawer' include ':pulltorefresh' include ':ultrasonic' diff --git a/subsonic-api/src/main/kotlin/org/moire/ultrasonic/api/subsonic/interceptors/VersionInterceptor.kt b/subsonic-api/src/main/kotlin/org/moire/ultrasonic/api/subsonic/interceptors/VersionInterceptor.kt index f8469783..223582fa 100644 --- a/subsonic-api/src/main/kotlin/org/moire/ultrasonic/api/subsonic/interceptors/VersionInterceptor.kt +++ b/subsonic-api/src/main/kotlin/org/moire/ultrasonic/api/subsonic/interceptors/VersionInterceptor.kt @@ -9,7 +9,7 @@ import okhttp3.Response import org.moire.ultrasonic.api.subsonic.SubsonicAPIVersions import java.io.IOException -private const val DEFAULT_PEEK_BYTE_COUNT = 100L +private const val DEFAULT_PEEK_BYTE_COUNT = 1000L /** * Special [Interceptor] that adds client supported version to request and tries to update it diff --git a/ultrasonic/build.gradle b/ultrasonic/build.gradle index 0ba0a74b..27ecb88d 100644 --- a/ultrasonic/build.gradle +++ b/ultrasonic/build.gradle @@ -19,8 +19,11 @@ android { buildTypes { release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' + minifyEnabled true + proguardFiles getDefaultProguardFile('proguard-android.txt'), + 'minify/proguard-okhttp.pro', + 'minify/proguard-retrofit.pro', + 'minify/proguard-jackson.pro' } debug { minifyEnabled false @@ -47,7 +50,9 @@ dependencies { implementation project(':menudrawer') implementation project(':pulltorefresh') implementation project(':library') + implementation project(':domain') implementation project(':subsonic-api') + implementation project(':cache') implementation androidSupport.support implementation androidSupport.design @@ -66,7 +71,6 @@ ext { jacocoExclude = [ '**/activity/**', '**/audiofx/**', - '**/domain/**', '**/fragment/**', '**/provider/**', '**/receiver/**', diff --git a/ultrasonic/minify/proguard-jackson.pro b/ultrasonic/minify/proguard-jackson.pro new file mode 100644 index 00000000..e5caeef8 --- /dev/null +++ b/ultrasonic/minify/proguard-jackson.pro @@ -0,0 +1,11 @@ +#### From Jackson + +-keepattributes *Annotation*,EnclosingMethod,Signature +-keepnames class com.fasterxml.jackson.** { +*; +} +-keepnames interface com.fasterxml.jackson.** { + *; +} +-dontwarn com.fasterxml.jackson.databind.** +-keep class org.codehaus.** { *; } diff --git a/ultrasonic/minify/proguard-okhttp.pro b/ultrasonic/minify/proguard-okhttp.pro new file mode 100644 index 00000000..f0cdf30c --- /dev/null +++ b/ultrasonic/minify/proguard-okhttp.pro @@ -0,0 +1,8 @@ +#### From okhttp + +-dontwarn okhttp3.** +-dontwarn okio.** +-dontwarn javax.annotation.** +-dontwarn org.conscrypt.** +# A resource is loaded with a relative path so the package of this class must be preserved. +-keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase diff --git a/ultrasonic/minify/proguard-retrofit.pro b/ultrasonic/minify/proguard-retrofit.pro new file mode 100644 index 00000000..f6dd5b8f --- /dev/null +++ b/ultrasonic/minify/proguard-retrofit.pro @@ -0,0 +1,10 @@ +#### From retrofit + +# Retain generic type information for use by reflection by converters and adapters. +-keepattributes Signature +# Retain service method parameters. +-keepclassmembernames,allowobfuscation interface * { + @retrofit2.http.* ; +} +# Ignore annotation used for build tooling. +-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/activity/MainActivity.java b/ultrasonic/src/main/java/org/moire/ultrasonic/activity/MainActivity.java index ed4a5f1e..5c6c1f6b 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/activity/MainActivity.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/activity/MainActivity.java @@ -36,9 +36,12 @@ import android.widget.TextView; import org.moire.ultrasonic.R; import org.moire.ultrasonic.service.DownloadService; import org.moire.ultrasonic.service.DownloadServiceImpl; +import org.moire.ultrasonic.service.MusicService; +import org.moire.ultrasonic.service.MusicServiceFactory; import org.moire.ultrasonic.util.Constants; import org.moire.ultrasonic.util.FileUtil; import org.moire.ultrasonic.util.MergeAdapter; +import org.moire.ultrasonic.util.TabActivityBackgroundTask; import org.moire.ultrasonic.util.Util; import java.util.Collections; @@ -165,6 +168,10 @@ public class MainActivity extends SubsonicTabActivity adapter.addView(videosTitle, false); adapter.addViews(Collections.singletonList(videosButton), true); + + if (Util.isNetworkConnected(this)) { + new PingTask(this, false).execute(); + } } list.setAdapter(adapter); @@ -533,4 +540,23 @@ public class MainActivity extends SubsonicTabActivity intent.putExtra(Constants.INTENT_EXTRA_NAME_VIDEOS, 1); startActivityForResultWithoutTransition(this, intent); } + + /** + * Temporary task to make a ping to server to get it supported api version. + */ + private static class PingTask extends TabActivityBackgroundTask { + PingTask(SubsonicTabActivity activity, boolean changeProgress) { + super(activity, changeProgress); + } + + @Override + protected Void doInBackground() throws Throwable { + final MusicService service = MusicServiceFactory.getMusicService(getActivity()); + service.ping(getActivity(), null); + return null; + } + + @Override + protected void done(Void result) {} + } } \ No newline at end of file diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/activity/SelectAlbumActivity.java b/ultrasonic/src/main/java/org/moire/ultrasonic/activity/SelectAlbumActivity.java index 0958aabe..d975160e 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/activity/SelectAlbumActivity.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/activity/SelectAlbumActivity.java @@ -35,6 +35,7 @@ import android.widget.TextView; import com.handmark.pulltorefresh.library.PullToRefreshBase; import com.handmark.pulltorefresh.library.PullToRefreshListView; + import org.moire.ultrasonic.R; import org.moire.ultrasonic.domain.MusicDirectory; import org.moire.ultrasonic.domain.Share; @@ -594,7 +595,7 @@ public class SelectAlbumActivity extends SubsonicTabActivity { MusicDirectory.Entry allSongs = new MusicDirectory.Entry(); - allSongs.setIsDirectory(true); + allSongs.setDirectory(true); allSongs.setArtist(name); allSongs.setParent(id); allSongs.setId(allSongsId); @@ -663,7 +664,7 @@ public class SelectAlbumActivity extends SubsonicTabActivity { MusicDirectory.Entry allSongs = new MusicDirectory.Entry(); - allSongs.setIsDirectory(true); + allSongs.setDirectory(true); allSongs.setArtist(name); allSongs.setParent(id); allSongs.setId(allSongsId); diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/domain/Artist.java b/ultrasonic/src/main/java/org/moire/ultrasonic/domain/Artist.java deleted file mode 100644 index 5fef9cfe..00000000 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/domain/Artist.java +++ /dev/null @@ -1,132 +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 . - - Copyright 2009 (C) Sindre Mehus - */ -package org.moire.ultrasonic.domain; - -import java.io.Serializable; - -/** - * @author Sindre Mehus - */ -public class Artist implements Serializable -{ - - /** - * - */ - private static final long serialVersionUID = -5790532593784846982L; - private String id; - private String name; - private String index; - private String coverArt; - private Long albumCount; - private int closeness; - - public String getId() - { - return id; - } - - public void setId(String id) - { - this.id = id; - } - - public String getName() - { - return name; - } - - public void setName(String name) - { - this.name = name; - } - - public String getIndex() - { - return index; - } - - public void setIndex(String index) - { - this.index = index; - } - - public String getCoverArt() - { - return coverArt; - } - - public void setCoverArt(String coverArt) - { - this.coverArt = coverArt; - } - - public long getAlbumCount() - { - return albumCount; - } - - public void setAlbumCount(Long albumCount) - { - this.albumCount = albumCount; - } - - public int getCloseness() - { - return closeness; - } - - public void setCloseness(int closeness) - { - this.closeness = closeness; - } - - @Override - public String toString() - { - return name; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - Artist artist = (Artist) o; - - if (closeness != artist.closeness) return false; - if (id != null ? !id.equals(artist.id) : artist.id != null) return false; - if (name != null ? !name.equals(artist.name) : artist.name != null) return false; - if (index != null ? !index.equals(artist.index) : artist.index != null) return false; - if (coverArt != null ? !coverArt.equals(artist.coverArt) : artist.coverArt != null) - return false; - return albumCount != null ? albumCount.equals(artist.albumCount) : artist.albumCount == null; - } - - @Override - public int hashCode() { - int result = id != null ? id.hashCode() : 0; - result = 31 * result + (name != null ? name.hashCode() : 0); - result = 31 * result + (index != null ? index.hashCode() : 0); - result = 31 * result + (coverArt != null ? coverArt.hashCode() : 0); - result = 31 * result + (albumCount != null ? albumCount.hashCode() : 0); - result = 31 * result + closeness; - return result; - } -} \ No newline at end of file diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/domain/Bookmark.java b/ultrasonic/src/main/java/org/moire/ultrasonic/domain/Bookmark.java deleted file mode 100644 index 043e0ec5..00000000 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/domain/Bookmark.java +++ /dev/null @@ -1,106 +0,0 @@ -package org.moire.ultrasonic.domain; - -import org.moire.ultrasonic.domain.MusicDirectory.Entry; - -import java.io.Serializable; -import java.util.Date; - -public class Bookmark implements Serializable -{ - /** - * - */ - private static final long serialVersionUID = 8988990025189807803L; - private int position; - private String username; - private String comment; - private Date created; - private Date changed; - private Entry entry; - - public int getPosition() - { - return position; - } - - public void setPosition(int position) - { - this.position = position; - } - - public String getUsername() - { - return username; - } - - public void setUsername(String username) - { - this.username = username; - } - - public String getComment() - { - return comment; - } - - public void setComment(String comment) - { - this.comment = comment; - } - - public Date getCreated() { - return created; - } - - public void setCreated(Date created) { - this.created = created; - } - - public Date getChanged() { - return changed; - } - - public void setChanged(Date changed) { - this.changed = changed; - } - - public Entry getEntry() - { - return this.entry; - } - - public void setEntry(Entry entry) - { - this.entry = entry; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - Bookmark bookmark = (Bookmark) o; - - if (position != bookmark.position) return false; - if (username != null ? !username.equals(bookmark.username) : bookmark.username != null) - return false; - if (comment != null ? !comment.equals(bookmark.comment) : bookmark.comment != null) - return false; - if (created != null ? !created.equals(bookmark.created) : bookmark.created != null) - return false; - if (changed != null ? !changed.equals(bookmark.changed) : bookmark.changed != null) - return false; - return entry != null ? entry.equals(bookmark.entry) : bookmark.entry == null; - } - - @Override - public int hashCode() { - int result = position; - result = 31 * result + (username != null ? username.hashCode() : 0); - result = 31 * result + (comment != null ? comment.hashCode() : 0); - result = 31 * result + (created != null ? created.hashCode() : 0); - result = 31 * result + (changed != null ? changed.hashCode() : 0); - result = 31 * result + (entry != null ? entry.hashCode() : 0); - return result; - } -} diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/domain/ChatMessage.java b/ultrasonic/src/main/java/org/moire/ultrasonic/domain/ChatMessage.java deleted file mode 100644 index d5b71f7b..00000000 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/domain/ChatMessage.java +++ /dev/null @@ -1,64 +0,0 @@ -package org.moire.ultrasonic.domain; - -import java.io.Serializable; - -public class ChatMessage implements Serializable -{ - /** - * - */ - private static final long serialVersionUID = 496544310289324167L; - private String username; - private Long time; - private String message; - - public String getUsername() - { - return username; - } - - public void setUsername(String username) - { - this.username = username; - } - - public Long getTime() - { - return time; - } - - public void setTime(Long time) - { - this.time = time; - } - - public String getMessage() - { - return message; - } - - public void setMessage(String message) - { - this.message = message; - } - - @Override - public boolean equals(Object o) - { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - ChatMessage that = (ChatMessage) o; - - return message.equals(that.message) && time.equals(that.time) && username.equals(that.username); - } - - @Override - public int hashCode() - { - int result = username.hashCode(); - result = 31 * result + time.hashCode(); - result = 31 * result + message.hashCode(); - return result; - } -} diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/domain/Genre.java b/ultrasonic/src/main/java/org/moire/ultrasonic/domain/Genre.java deleted file mode 100644 index d7cae20a..00000000 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/domain/Genre.java +++ /dev/null @@ -1,57 +0,0 @@ -package org.moire.ultrasonic.domain; - -import java.io.Serializable; - -public class Genre implements Serializable -{ - /** - * - */ - private static final long serialVersionUID = -3943025175219134028L; - private String name; - private String index; - - public String getName() - { - return name; - } - - public void setName(String name) - { - this.name = name; - } - - public String getIndex() - { - return index; - } - - public void setIndex(String index) - { - this.index = index; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - Genre genre = (Genre) o; - - if (name != null ? !name.equals(genre.name) : genre.name != null) return false; - return index != null ? index.equals(genre.index) : genre.index == null; - } - - @Override - public int hashCode() { - int result = name != null ? name.hashCode() : 0; - result = 31 * result + (index != null ? index.hashCode() : 0); - return result; - } - - @Override - public String toString() - { - return name; - } -} diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/domain/Indexes.java b/ultrasonic/src/main/java/org/moire/ultrasonic/domain/Indexes.java deleted file mode 100644 index 81fbdd86..00000000 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/domain/Indexes.java +++ /dev/null @@ -1,66 +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 . - - Copyright 2009 (C) Sindre Mehus - */ -package org.moire.ultrasonic.domain; - -import java.io.Serializable; -import java.util.List; - -/** - * @author Sindre Mehus - */ -public class Indexes implements Serializable -{ - - /** - * - */ - private static final long serialVersionUID = 8156117238598414701L; - private final long lastModified; - private final String ignoredArticles; - private final List shortcuts; - private final List artists; - - public Indexes(long lastModified, String ignoredArticles, List shortcuts, List artists) - { - this.lastModified = lastModified; - this.ignoredArticles = ignoredArticles; - this.shortcuts = shortcuts; - this.artists = artists; - } - - public long getLastModified() - { - return lastModified; - } - - public List getShortcuts() - { - return shortcuts; - } - - public List getArtists() - { - return artists; - } - - public String getIgnoredArticles() - { - return ignoredArticles; - } -} \ No newline at end of file diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/domain/JukeboxStatus.java b/ultrasonic/src/main/java/org/moire/ultrasonic/domain/JukeboxStatus.java deleted file mode 100644 index 2b2c1578..00000000 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/domain/JukeboxStatus.java +++ /dev/null @@ -1,72 +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 . - - Copyright 2009 (C) Sindre Mehus - */ -package org.moire.ultrasonic.domain; - -/** - * @author Sindre Mehus - * @version $Id$ - */ -public class JukeboxStatus -{ - - private Integer positionSeconds; - private Integer currentPlayingIndex; - private Float gain; - private boolean playing; - - public Integer getPositionSeconds() - { - return positionSeconds; - } - - public void setPositionSeconds(Integer positionSeconds) - { - this.positionSeconds = positionSeconds; - } - - public Integer getCurrentPlayingIndex() - { - return currentPlayingIndex; - } - - public void setCurrentIndex(Integer currentPlayingIndex) - { - this.currentPlayingIndex = currentPlayingIndex; - } - - public boolean isPlaying() - { - return playing; - } - - public void setPlaying(boolean playing) - { - this.playing = playing; - } - - public Float getGain() - { - return gain; - } - - public void setGain(float gain) - { - this.gain = gain; - } -} diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/domain/Lyrics.java b/ultrasonic/src/main/java/org/moire/ultrasonic/domain/Lyrics.java deleted file mode 100644 index 47d07245..00000000 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/domain/Lyrics.java +++ /dev/null @@ -1,62 +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 . - - Copyright 2010 (C) Sindre Mehus - */ -package org.moire.ultrasonic.domain; - -/** - * Song lyrics. - * - * @author Sindre Mehus - */ -public class Lyrics -{ - - private String artist; - private String title; - private String text; - - public String getArtist() - { - return artist; - } - - public void setArtist(String artist) - { - this.artist = artist; - } - - public String getTitle() - { - return title; - } - - public void setTitle(String title) - { - this.title = title; - } - - public String getText() - { - return text; - } - - public void setText(String text) - { - this.text = text; - } -} diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/domain/MusicDirectory.java b/ultrasonic/src/main/java/org/moire/ultrasonic/domain/MusicDirectory.java deleted file mode 100644 index e0a72f6a..00000000 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/domain/MusicDirectory.java +++ /dev/null @@ -1,474 +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 . - - Copyright 2009 (C) Sindre Mehus - */ -package org.moire.ultrasonic.domain; - -import android.support.annotation.NonNull; - -import java.io.Serializable; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Date; -import java.util.List; -import java.util.Locale; - -/** - * @author Sindre Mehus - */ -public class MusicDirectory -{ - - private String name; - private final List children = new ArrayList(); - - public String getName() - { - return name; - } - - public void setName(String name) - { - this.name = name; - } - - public void addAll(Collection entries) - { - children.addAll(entries); - } - - public void addFirst(Entry child) - { - children.add(0, child); - } - - public void addChild(Entry child) - { - children.add(child); - } - - public List getChildren() - { - return getChildren(true, true); - } - - public Entry findChild(String id) - { - Entry entry = null; - - for (Entry song : getChildren()) - { - if (song.getId().equals(id)) - { - entry = song; - } - } - - return entry; - } - - public List getChildren(boolean includeDirs, boolean includeFiles) - { - if (includeDirs && includeFiles) - { - return children; - } - - List result = new ArrayList(children.size()); - for (Entry child : children) - { - if (child.isDirectory() && includeDirs || !child.isDirectory() && includeFiles) - { - result.add(child); - } - } - return result; - } - - public static class Entry implements Serializable - { - /** - * - */ - private static final long serialVersionUID = -3339106650010798108L; - /** - * - */ - private String id; - private String parent; - private boolean isDirectory; - private String title; - private String album; - private String albumId; - private String artist; - private String artistId; - private Integer track; - private Integer year; - private String genre; - private String contentType; - private String suffix; - private String transcodedContentType; - private String transcodedSuffix; - private String coverArt; - private Long size; - private Long songCount; - private Integer duration; - private Integer bitRate; - private String path; - private boolean isVideo; - private boolean isStarred; - private Integer discNumber; - private String type; - private Date created; - private int closeness; - private int bookmarkPosition; - - public Integer getDiscNumber() - { - return discNumber; - } - - public void setDiscNumber(Integer discNumber) - { - this.discNumber = discNumber; - } - - public boolean getStarred() - { - return isStarred; - } - - public void setStarred(boolean starred) - { - this.isStarred = starred; - } - - public String getId() - { - return id; - } - - public void setId(String id) - { - this.id = id; - } - - public String getParent() - { - return parent; - } - - public void setParent(String parent) - { - this.parent = parent; - } - - public boolean isDirectory() - { - return isDirectory; - } - - public void setIsDirectory(boolean directory) - { - this.isDirectory = directory; - } - - public String getTitle() - { - return title; - } - - public void setTitle(String title) - { - this.title = title; - } - - public String getAlbum() - { - return album; - } - - public void setAlbum(String album) - { - this.album = album; - } - - public String getAlbumId() - { - return albumId; - } - - public void setAlbumId(String albumId) - { - this.albumId = albumId; - } - - public String getArtist() - { - return artist; - } - - public void setArtist(String artist) - { - this.artist = artist; - } - - public String getArtistId() - { - return artistId; - } - - public void setArtistId(String artistId) - { - this.artistId = artistId; - } - - public Integer getTrack() - { - return track == null ? 0 : track; - } - - public void setTrack(Integer track) - { - this.track = track; - } - - public Long getSongCount() - { - return songCount; - } - - public void setSongCount(Long songCount) - { - this.songCount = songCount; - } - - public Integer getYear() - { - return year == null ? 0 : year; - } - - public void setYear(Integer year) - { - this.year = year; - } - - public String getGenre() - { - return genre; - } - - public void setGenre(String genre) - { - this.genre = genre; - } - - public String getContentType() - { - return contentType; - } - - public void setContentType(String contentType) - { - this.contentType = contentType; - } - - public String getSuffix() - { - return suffix; - } - - public void setSuffix(String suffix) - { - this.suffix = suffix; - } - - public String getTranscodedContentType() - { - return transcodedContentType; - } - - public void setTranscodedContentType(String transcodedContentType) - { - this.transcodedContentType = transcodedContentType; - } - - public String getTranscodedSuffix() - { - return transcodedSuffix; - } - - public void setTranscodedSuffix(String transcodedSuffix) - { - this.transcodedSuffix = transcodedSuffix; - } - - public Long getSize() - { - return size; - } - - public void setSize(Long size) - { - this.size = size; - } - - public Integer getDuration() - { - return duration; - } - - public void setDuration(Integer duration) - { - this.duration = duration; - } - - public void setDuration(long duration) - { - this.duration = (int) duration; - } - - public Integer getBitRate() - { - return bitRate; - } - - public void setBitRate(Integer bitRate) - { - this.bitRate = bitRate; - } - - @NonNull - public String getCoverArt() - { - return coverArt; - } - - public void setCoverArt(String coverArt) - { - this.coverArt = coverArt; - } - - public String getPath() - { - return path; - } - - public void setPath(String path) - { - this.path = path; - } - - public boolean isVideo() - { - return isVideo; - } - - public void setIsVideo(boolean video) - { - this.isVideo = video; - } - - public String getType() - { - return type; - } - - public void setType(String type) - { - this.type = type; - } - - public Date getCreated() - { - return created; - } - - public void setCreated(String created) - { - if (created != null) - { - try - { - this.created = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.ENGLISH).parse(created); - } - catch (ParseException e) - { - this.created = null; - } - } - else - { - this.created = null; - } - } - - public void setCreated(Date created) { - this.created = created; - } - - public int getCloseness() - { - return closeness; - } - - public void setCloseness(int closeness) - { - this.closeness = closeness; - } - - public int getBookmarkPosition() - { - return bookmarkPosition; - } - - public void setBookmarkPosition(int bookmarkPosition) - { - this.bookmarkPosition = bookmarkPosition; - } - - @Override - public boolean equals(Object o) - { - if (this == o) - { - return true; - } - if (o == null || getClass() != o.getClass()) - { - return false; - } - - Entry entry = (Entry) o; - return id.equals(entry.id); - } - - @Override - public int hashCode() - { - return id.hashCode(); - } - - @Override - public String toString() - { - return title; - } - } -} \ No newline at end of file diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/domain/MusicFolder.java b/ultrasonic/src/main/java/org/moire/ultrasonic/domain/MusicFolder.java deleted file mode 100644 index 30eb590d..00000000 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/domain/MusicFolder.java +++ /dev/null @@ -1,48 +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 . - - Copyright 2009 (C) Sindre Mehus - */ -package org.moire.ultrasonic.domain; - -/** - * Represents a top level directory in which music or other media is stored. - * - * @author Sindre Mehus - * @version $Id$ - */ -public class MusicFolder -{ - - private final String id; - private final String name; - - public MusicFolder(String id, String name) - { - this.id = id; - this.name = name; - } - - public String getId() - { - return id; - } - - public String getName() - { - return name; - } -} diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/domain/PlayerState.java b/ultrasonic/src/main/java/org/moire/ultrasonic/domain/PlayerState.java deleted file mode 100644 index 81f8179e..00000000 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/domain/PlayerState.java +++ /dev/null @@ -1,35 +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 . - - Copyright 2009 (C) Sindre Mehus - */ -package org.moire.ultrasonic.domain; - -/** - * @author Sindre Mehus - * @version $Id$ - */ -public enum PlayerState -{ - IDLE, - DOWNLOADING, - PREPARING, - PREPARED, - STARTED, - STOPPED, - PAUSED, - COMPLETED -} diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/domain/Playlist.java b/ultrasonic/src/main/java/org/moire/ultrasonic/domain/Playlist.java deleted file mode 100644 index a7749031..00000000 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/domain/Playlist.java +++ /dev/null @@ -1,171 +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 . - - Copyright 2009 (C) Sindre Mehus - */ -package org.moire.ultrasonic.domain; - -import java.io.Serializable; - -/** - * @author Sindre Mehus - */ -public class Playlist implements Serializable -{ - - /** - * - */ - private static final long serialVersionUID = -4160515427075433798L; - private String id; - private String name; - private String owner; - private String comment; - private String songCount; - private String created; - private Boolean pub; - - public Playlist(String id, String name) - { - this.id = id; - this.name = name; - } - - public Playlist(String id, String name, String owner, String comment, String songCount, String created, String pub) - { - this.id = id; - this.name = name; - this.owner = (owner == null) ? "" : owner; - this.comment = (comment == null) ? "" : comment; - this.songCount = (songCount == null) ? "" : songCount; - this.created = (created == null) ? "" : created; - this.pub = (pub == null) ? null : ("true".equals(pub)); - } - - public String getId() - { - return id; - } - - public void setId(String id) - { - this.id = id; - } - - public String getName() - { - return name; - } - - public void setName(String name) - { - this.name = name; - } - - public String getOwner() - { - return this.owner; - } - - public void setOwner(String owner) - { - this.owner = owner; - } - - public String getComment() - { - return this.comment; - } - - public void setComment(String comment) - { - this.comment = comment; - } - - public String getSongCount() - { - return this.songCount; - } - - public void setSongCount(String songCount) - { - this.songCount = songCount; - } - - public String getCreated() - { - return this.created; - } - - public void setCreated(String created) - { - this.created = created; - } - - public Boolean getPublic() - { - return this.pub; - } - - public void setPublic(Boolean pub) - { - this.pub = pub; - } - - @Override - public String toString() { - return "Playlist{" + - "id='" + id + '\'' + - ", name='" + name + '\'' + - ", owner='" + owner + '\'' + - ", comment='" + comment + '\'' + - ", songCount='" + songCount + '\'' + - ", created='" + created + '\'' + - ", pub=" + pub + - '}'; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - Playlist playlist = (Playlist) o; - - if (id != null ? !id.equals(playlist.id) : playlist.id != null) return false; - if (name != null ? !name.equals(playlist.name) : playlist.name != null) return false; - if (owner != null ? !owner.equals(playlist.owner) : playlist.owner != null) return false; - if (comment != null ? !comment.equals(playlist.comment) : playlist.comment != null) - return false; - if (songCount != null ? !songCount.equals(playlist.songCount) : playlist.songCount != null) - return false; - if (created != null ? !created.equals(playlist.created) : playlist.created != null) - return false; - return pub != null ? pub.equals(playlist.pub) : playlist.pub == null; - } - - @Override - public int hashCode() { - int result = id != null ? id.hashCode() : 0; - result = 31 * result + (name != null ? name.hashCode() : 0); - result = 31 * result + (owner != null ? owner.hashCode() : 0); - result = 31 * result + (comment != null ? comment.hashCode() : 0); - result = 31 * result + (songCount != null ? songCount.hashCode() : 0); - result = 31 * result + (created != null ? created.hashCode() : 0); - result = 31 * result + (pub != null ? pub.hashCode() : 0); - return result; - } -} \ No newline at end of file diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/domain/PodcastEpisode.java b/ultrasonic/src/main/java/org/moire/ultrasonic/domain/PodcastEpisode.java deleted file mode 100644 index 857cb420..00000000 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/domain/PodcastEpisode.java +++ /dev/null @@ -1,94 +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 . - - Copyright 2009 (C) Sindre Mehus - */ -package org.moire.ultrasonic.domain; - -import java.io.Serializable; - -/** - * @author Sindre Mehus - */ -public class PodcastEpisode implements Serializable -{ - - /** - * - */ - private static final long serialVersionUID = -4160515427075433798L; - private String id; - private String title; - private String url; - private String description; - private String status; - - public PodcastEpisode(String id, String title, String url, String description, String status) - { - this.id = id; - this.title = title; - this.url = url; - this.description = description; - this.status = status; - } - - public String getId() - { - return id; - } - - public void setId(String id) - { - this.id = id; - } - - public String getUrl() { - return url; - } - - public void setUrl(String url) { - this.url = url; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public String getStatus() { - return status; - } - - public void setStatus(String status) { - this.status = status; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - @Override - public String toString() { - return getTitle(); - } -} \ No newline at end of file diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/domain/PodcastsChannel.java b/ultrasonic/src/main/java/org/moire/ultrasonic/domain/PodcastsChannel.java deleted file mode 100644 index a575c8e5..00000000 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/domain/PodcastsChannel.java +++ /dev/null @@ -1,119 +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 . - - Copyright 2009 (C) Sindre Mehus - */ -package org.moire.ultrasonic.domain; - -import java.io.Serializable; - -/** - * @author Sindre Mehus - */ -public class PodcastsChannel implements Serializable -{ - - /** - * - */ - private static final long serialVersionUID = -4160515427075433798L; - private String id; - private String title; - private String url; - private String description; - private String status; - - public PodcastsChannel(String id, String title,String url, String description, String status) - { - this.id = id; - this.title = title; - this.url = url; - this.description = description; - this.status = status; - } - - public String getId() - { - return id; - } - - public void setId(String id) - { - this.id = id; - } - - public String getUrl() { - return url; - } - - public void setUrl(String url) { - this.url = url; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public String getStatus() { - return status; - } - - public void setStatus(String status) { - this.status = status; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - @Override - public String toString() { - return getTitle(); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - PodcastsChannel that = (PodcastsChannel) o; - - if (id != null ? !id.equals(that.id) : that.id != null) return false; - if (title != null ? !title.equals(that.title) : that.title != null) return false; - if (url != null ? !url.equals(that.url) : that.url != null) return false; - if (description != null ? !description.equals(that.description) : that.description != null) - return false; - return status != null ? status.equals(that.status) : that.status == null; - } - - @Override - public int hashCode() { - int result = id != null ? id.hashCode() : 0; - result = 31 * result + (title != null ? title.hashCode() : 0); - result = 31 * result + (url != null ? url.hashCode() : 0); - result = 31 * result + (description != null ? description.hashCode() : 0); - result = 31 * result + (status != null ? status.hashCode() : 0); - return result; - } -} \ No newline at end of file diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/domain/RepeatMode.java b/ultrasonic/src/main/java/org/moire/ultrasonic/domain/RepeatMode.java deleted file mode 100644 index bae62f3f..00000000 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/domain/RepeatMode.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.moire.ultrasonic.domain; - -/** - * @author Sindre Mehus - * @version $Id$ - */ -public enum RepeatMode -{ - OFF - { - @Override - public RepeatMode next() - { - return ALL; - } - }, - ALL - { - @Override - public RepeatMode next() - { - return SINGLE; - } - }, - SINGLE - { - @Override - public RepeatMode next() - { - return OFF; - } - }; - - public abstract RepeatMode next(); -} diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/domain/SearchCriteria.java b/ultrasonic/src/main/java/org/moire/ultrasonic/domain/SearchCriteria.java deleted file mode 100644 index e3169a0a..00000000 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/domain/SearchCriteria.java +++ /dev/null @@ -1,61 +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 . - - Copyright 2009 (C) Sindre Mehus - */ -package org.moire.ultrasonic.domain; - -/** - * The criteria for a music search. - * - * @author Sindre Mehus - */ -public class SearchCriteria -{ - - private final String query; - private final int artistCount; - private final int albumCount; - private final int songCount; - - public SearchCriteria(String query, int artistCount, int albumCount, int songCount) - { - this.query = query; - this.artistCount = artistCount; - this.albumCount = albumCount; - this.songCount = songCount; - } - - public String getQuery() - { - return query; - } - - public int getArtistCount() - { - return artistCount; - } - - public int getAlbumCount() - { - return albumCount; - } - - public int getSongCount() - { - return songCount; - } -} \ No newline at end of file diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/domain/SearchResult.java b/ultrasonic/src/main/java/org/moire/ultrasonic/domain/SearchResult.java deleted file mode 100644 index 08da3c8d..00000000 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/domain/SearchResult.java +++ /dev/null @@ -1,56 +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 . - - Copyright 2009 (C) Sindre Mehus - */ -package org.moire.ultrasonic.domain; - -import java.util.List; - -/** - * The result of a search. Contains matching artists, albums and songs. - * - * @author Sindre Mehus - */ -public class SearchResult -{ - - private final List artists; - private final List albums; - private final List songs; - - public SearchResult(List artists, List albums, List songs) - { - this.artists = artists; - this.albums = albums; - this.songs = songs; - } - - public List getArtists() - { - return artists; - } - - public List getAlbums() - { - return albums; - } - - public List getSongs() - { - return songs; - } -} \ No newline at end of file diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/domain/Share.java b/ultrasonic/src/main/java/org/moire/ultrasonic/domain/Share.java deleted file mode 100644 index 30111698..00000000 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/domain/Share.java +++ /dev/null @@ -1,158 +0,0 @@ -package org.moire.ultrasonic.domain; - -import org.moire.ultrasonic.domain.MusicDirectory.Entry; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; -import java.util.regex.Pattern; - -public class Share implements Serializable { - private static final long serialVersionUID = 1487561657691009668L; - private static final Pattern urlPattern = Pattern.compile(".*/([^/?]+).*"); - private String id; - private String url; - private String description; - private String username; - private String created; - private String lastVisited; - private String expires; - private Long visitCount; - private List entries; - - public Share() - { - entries = new ArrayList(); - } - - public String getName() - { - return urlPattern.matcher(url).replaceFirst("$1"); - } - - public String getId() - { - return id; - } - - public void setId(String id) - { - this.id = id; - } - - public String getUrl() - { - return url; - } - - public void setUrl(String url) - { - this.url = url; - } - - public String getDescription() - { - return description; - } - - public void setDescription(String description) - { - this.description = description; - } - - public String getUsername() - { - return username; - } - - public void setUsername(String username) - { - this.username = username; - } - - public String getCreated() - { - return this.created; - } - - public void setCreated(String created) - { - this.created = created; - } - - public String getLastVisited() - { - return lastVisited; - } - - public void setLastVisited(String lastVisited) - { - this.lastVisited = lastVisited; - } - - public String getExpires() - { - return expires; - } - - public void setExpires(String expires) - { - this.expires = expires; - } - - public Long getVisitCount() - { - return visitCount; - } - - public void setVisitCount(Long visitCount) - { - this.visitCount = visitCount; - } - - public List getEntries() - { - return this.entries; - } - - public void addEntry(Entry entry) - { - entries.add(entry); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - Share share = (Share) o; - - if (id != null ? !id.equals(share.id) : share.id != null) return false; - if (url != null ? !url.equals(share.url) : share.url != null) return false; - if (description != null ? !description.equals(share.description) : share.description != null) - return false; - if (username != null ? !username.equals(share.username) : share.username != null) - return false; - if (created != null ? !created.equals(share.created) : share.created != null) return false; - if (lastVisited != null ? !lastVisited.equals(share.lastVisited) : share.lastVisited != null) - return false; - if (expires != null ? !expires.equals(share.expires) : share.expires != null) return false; - if (visitCount != null ? !visitCount.equals(share.visitCount) : share.visitCount != null) - return false; - return entries != null ? entries.equals(share.entries) : share.entries == null; - } - - @Override - public int hashCode() { - int result = id != null ? id.hashCode() : 0; - result = 31 * result + (url != null ? url.hashCode() : 0); - result = 31 * result + (description != null ? description.hashCode() : 0); - result = 31 * result + (username != null ? username.hashCode() : 0); - result = 31 * result + (created != null ? created.hashCode() : 0); - result = 31 * result + (lastVisited != null ? lastVisited.hashCode() : 0); - result = 31 * result + (expires != null ? expires.hashCode() : 0); - result = 31 * result + (visitCount != null ? visitCount.hashCode() : 0); - result = 31 * result + (entries != null ? entries.hashCode() : 0); - return result; - } -} diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/domain/UserInfo.java b/ultrasonic/src/main/java/org/moire/ultrasonic/domain/UserInfo.java deleted file mode 100644 index 6853a3ae..00000000 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/domain/UserInfo.java +++ /dev/null @@ -1,182 +0,0 @@ -/* - This file is part of UltraSonic. - - 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 . - - Copyright 2013 (C) Joshua Bahnsen - */ -package org.moire.ultrasonic.domain; - -/** - * Information about the Subsonic server. - * - * @author Joshua Bahnsen - */ -public class UserInfo -{ - private String userName; - private String email; - private boolean scrobblingEnabled; - private boolean adminRole; - private boolean settingsRole; - private boolean downloadRole; - private boolean uploadRole; - private boolean playlistRole; - private boolean coverArtRole; - private boolean commentRole; - private boolean podcastRole; - private boolean streamRole; - private boolean jukeboxRole; - private boolean shareRole; - - public String getUserName() - { - return this.userName; - } - - public void setUserName(String userName) - { - this.userName = userName; - } - - public String getEmail() - { - return this.email; - } - - public void setEmail(String email) - { - this.email = email; - } - - public boolean getScrobblingEnabled() - { - return this.scrobblingEnabled; - } - - public void setScrobblingEnabled(boolean scrobblingEnabled) - { - this.scrobblingEnabled = scrobblingEnabled; - } - - public boolean getAdminRole() - { - return this.adminRole; - } - - public void setAdminRole(boolean adminRole) - { - this.adminRole = adminRole; - } - - public boolean getSettingsRole() - { - return this.settingsRole; - } - - public void setSettingsRole(boolean settingsRole) - { - this.settingsRole = settingsRole; - } - - public boolean getDownloadRole() - { - return this.downloadRole; - } - - public void setDownloadRole(boolean downloadRole) - { - this.downloadRole = downloadRole; - } - - public boolean getUploadRole() - { - return this.uploadRole; - } - - public void setUploadRole(boolean uploadRole) - { - this.uploadRole = uploadRole; - } - - public boolean getPlaylistRole() - { - return this.playlistRole; - } - - public void setPlaylistRole(boolean playlistRole) - { - this.playlistRole = playlistRole; - } - - public boolean getCoverArtRole() - { - return this.coverArtRole; - } - - public void setCoverArtRole(boolean coverArtRole) - { - this.coverArtRole = coverArtRole; - } - - public boolean getCommentRole() - { - return this.commentRole; - } - - public void setCommentRole(boolean commentRole) - { - this.commentRole = commentRole; - } - - public boolean getPodcastRole() - { - return this.podcastRole; - } - - public void setPodcastRole(boolean podcastRole) - { - this.podcastRole = podcastRole; - } - - public boolean getStreamRole() - { - return this.streamRole; - } - - public void setStreamRole(boolean streamRole) - { - this.streamRole = streamRole; - } - - public boolean getJukeboxRole() - { - return this.jukeboxRole; - } - - public void setJukeboxRole(boolean jukeboxRole) - { - this.jukeboxRole = jukeboxRole; - } - - public boolean getShareRole() - { - return this.shareRole; - } - - public void setShareRole(boolean shareRole) - { - this.shareRole = shareRole; - } -} \ No newline at end of file diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/domain/Version.java b/ultrasonic/src/main/java/org/moire/ultrasonic/domain/Version.java deleted file mode 100644 index aedf40ea..00000000 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/domain/Version.java +++ /dev/null @@ -1,178 +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 . - - Copyright 2009 (C) Sindre Mehus - */ -package org.moire.ultrasonic.domain; - -import java.util.regex.Pattern; - -/** - * Represents the version number of the Subsonic Android app. - * - * @author Sindre Mehus - * @version $Revision: 1.3 $ $Date: 2006/01/20 21:25:16 $ - */ -public class Version implements Comparable -{ - private static final Pattern COMPILE = Pattern.compile("\\."); - private int major; - private int minor; - private int beta; - private int bugFix; - - /** - * Creates a new version instance by parsing the given string. - * - * @param version A string of the format "1.27", "1.27.2" or "1.27.beta3". - */ - public Version(CharSequence version) - { - String[] s = COMPILE.split(version); - major = Integer.valueOf(s[0]); - minor = Integer.valueOf(s[1]); - - if (s.length > 2) - { - if (s[2].contains("beta")) - { - beta = Integer.valueOf(s[2].replace("beta", "")); - } - else - { - bugFix = Integer.valueOf(s[2]); - } - } - } - - public int getMajor() - { - return major; - } - - public int getMinor() - { - return minor; - } - - /** - * Return whether this object is equal to another. - * - * @param o Object to compare to. - * @return Whether this object is equals to another. - */ - public boolean equals(Object o) - { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - final Version version = (Version) o; - - return beta == version.beta && bugFix == version.bugFix && major == version.major && minor == version.minor; - } - - /** - * Returns a hash code for this object. - * - * @return A hash code for this object. - */ - public int hashCode() - { - int result; - result = major; - result = 29 * result + minor; - result = 29 * result + beta; - result = 29 * result + bugFix; - return result; - } - - /** - * Returns a string representation of the form "1.27", "1.27.2" or "1.27.beta3". - * - * @return A string representation of the form "1.27", "1.27.2" or "1.27.beta3". - */ - public String toString() - { - StringBuilder buf = new StringBuilder(3); - buf.append(major).append('.').append(minor); - if (beta != 0) - { - buf.append(".beta").append(beta); - } - else if (bugFix != 0) - { - buf.append('.').append(bugFix); - } - - return buf.toString(); - } - - /** - * Compares this object with the specified object for order. - * - * @param version The object to compare to. - * @return A negative integer, zero, or a positive integer as this object is less than, equal to, or - * greater than the specified object. - */ - @Override - public int compareTo(Version version) - { - if (major < version.major) - { - return -1; - } - - if (major > version.major) - { - return 1; - } - - if (minor < version.minor) - { - return -1; - } - - if (minor > version.minor) - { - return 1; - } - - if (bugFix < version.bugFix) - { - return -1; - } - - if (bugFix > version.bugFix) - { - return 1; - } - - int thisBeta = beta == 0 ? Integer.MAX_VALUE : beta; - int otherBeta = version.beta == 0 ? Integer.MAX_VALUE : version.beta; - - if (thisBeta < otherBeta) - { - return -1; - } - - if (thisBeta > otherBeta) - { - return 1; - } - - return 0; - } -} \ No newline at end of file diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/ServerSettingsFragment.java b/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/ServerSettingsFragment.java index 85456be2..536e6fc4 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/ServerSettingsFragment.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/ServerSettingsFragment.java @@ -12,7 +12,9 @@ import android.support.annotation.Nullable; import android.util.Log; import android.view.View; +import org.moire.ultrasonic.BuildConfig; import org.moire.ultrasonic.R; +import org.moire.ultrasonic.cache.PermanentFileStorage; import org.moire.ultrasonic.service.MusicService; import org.moire.ultrasonic.service.MusicServiceFactory; import org.moire.ultrasonic.util.Constants; @@ -279,6 +281,15 @@ public class ServerSettingsFragment extends PreferenceFragment int activeServers = sharedPreferences .getInt(Constants.PREFERENCES_KEY_ACTIVE_SERVERS, 0); + // Clear permanent storage + final String storageServerId = MusicServiceFactory.getServerId(sharedPreferences, serverId); + final PermanentFileStorage fileStorage = new PermanentFileStorage( + MusicServiceFactory.getDirectories(getActivity()), + storageServerId, + BuildConfig.DEBUG + ); + fileStorage.clearAll(); + // Reset values to null so when we ask for them again they are new sharedPreferences.edit() .remove(Constants.PREFERENCES_KEY_SERVER_NAME + serverId) diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/service/MusicServiceFactory.java b/ultrasonic/src/main/java/org/moire/ultrasonic/service/MusicServiceFactory.java index 4d2b3d4b..eb859aa5 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/service/MusicServiceFactory.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/service/MusicServiceFactory.java @@ -22,12 +22,17 @@ import android.content.Context; import android.content.SharedPreferences; import android.util.Log; +import org.jetbrains.annotations.NotNull; import org.moire.ultrasonic.BuildConfig; import org.moire.ultrasonic.api.subsonic.SubsonicAPIClient; import org.moire.ultrasonic.api.subsonic.SubsonicAPIVersions; +import org.moire.ultrasonic.cache.Directories; +import org.moire.ultrasonic.cache.PermanentFileStorage; import org.moire.ultrasonic.util.Constants; import org.moire.ultrasonic.util.Util; +import java.io.File; + /** * @author Sindre Mehus * @version $Id$ @@ -44,7 +49,9 @@ public class MusicServiceFactory { synchronized (MusicServiceFactory.class) { if (OFFLINE_MUSIC_SERVICE == null) { Log.d(LOG_TAG, "Creating new offline music service"); - OFFLINE_MUSIC_SERVICE = new OfflineMusicService(createSubsonicApiClient(context)); + OFFLINE_MUSIC_SERVICE = new OfflineMusicService( + createSubsonicApiClient(context), + getPermanentFileStorage(context)); } } } @@ -57,7 +64,8 @@ public class MusicServiceFactory { if (REST_MUSIC_SERVICE == null) { Log.d(LOG_TAG, "Creating new rest music service"); REST_MUSIC_SERVICE = new CachedMusicService(new RESTMusicService( - createSubsonicApiClient(context))); + createSubsonicApiClient(context), + getPermanentFileStorage(context))); } } } @@ -104,4 +112,39 @@ public class MusicServiceFactory { Constants.REST_CLIENT_ID, allowSelfSignedCertificate, enableLdapUserSupport, BuildConfig.DEBUG); } + + private static PermanentFileStorage getPermanentFileStorage(final Context context) { + final SharedPreferences preferences = Util.getPreferences(context); + int instance = preferences.getInt(Constants.PREFERENCES_KEY_SERVER_INSTANCE, 1); + final String serverId = getServerId(preferences, instance); + + return new PermanentFileStorage(getDirectories(context), serverId, BuildConfig.DEBUG); + } + + public static String getServerId(final SharedPreferences sp, final int instance) { + String serverUrl = sp.getString( + Constants.PREFERENCES_KEY_SERVER_URL + instance, null); + return String.valueOf(Math.abs((serverUrl + instance).hashCode())); + } + + public static Directories getDirectories(final Context context) { + return new Directories() { + @NotNull + @Override + public File getInternalCacheDir() { + return context.getCacheDir(); + } + + @NotNull + @Override + public File getInternalDataDir() { + return context.getFilesDir(); + } + + @Override + public File getExternalCacheDir() { + return context.getExternalCacheDir(); + } + }; + } } diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/service/OfflineMusicService.java b/ultrasonic/src/main/java/org/moire/ultrasonic/service/OfflineMusicService.java index d3be03cc..8a93dec0 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/service/OfflineMusicService.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/service/OfflineMusicService.java @@ -24,6 +24,7 @@ import android.media.MediaMetadataRetriever; import android.util.Log; import org.moire.ultrasonic.api.subsonic.SubsonicAPIClient; +import org.moire.ultrasonic.cache.PermanentFileStorage; import org.moire.ultrasonic.domain.Artist; import org.moire.ultrasonic.domain.Genre; import org.moire.ultrasonic.domain.Indexes; @@ -67,8 +68,8 @@ public class OfflineMusicService extends RESTMusicService private static final String TAG = OfflineMusicService.class.getSimpleName(); private static final Pattern COMPILE = Pattern.compile(" "); - public OfflineMusicService(SubsonicAPIClient subsonicAPIClient) { - super(subsonicAPIClient); + public OfflineMusicService(SubsonicAPIClient subsonicAPIClient, PermanentFileStorage storage) { + super(subsonicAPIClient, storage); } @Override @@ -185,7 +186,7 @@ public class OfflineMusicService extends RESTMusicService private static MusicDirectory.Entry createEntry(Context context, File file, String name) { MusicDirectory.Entry entry = new MusicDirectory.Entry(); - entry.setIsDirectory(file.isDirectory()); + entry.setDirectory(file.isDirectory()); entry.setId(file.getPath()); entry.setParent(file.getParent()); entry.setSize(file.length()); @@ -232,7 +233,7 @@ public class OfflineMusicService extends RESTMusicService entry.setTitle(title); } - entry.setIsVideo(hasVideo != null); + entry.setVideo(hasVideo != null); Log.i("OfflineMusicService", String.format("Offline Stuff: %s", track)); diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/service/RESTMusicService.java b/ultrasonic/src/main/java/org/moire/ultrasonic/service/RESTMusicService.java index 43b7c9e7..74e146d7 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/service/RESTMusicService.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/service/RESTMusicService.java @@ -61,21 +61,23 @@ import org.moire.ultrasonic.api.subsonic.response.SharesResponse; import org.moire.ultrasonic.api.subsonic.response.StreamResponse; import org.moire.ultrasonic.api.subsonic.response.SubsonicResponse; import org.moire.ultrasonic.api.subsonic.response.VideosResponse; -import org.moire.ultrasonic.data.APIAlbumConverter; -import org.moire.ultrasonic.data.APIArtistConverter; -import org.moire.ultrasonic.data.APIBookmarkConverter; -import org.moire.ultrasonic.data.APIChatMessageConverter; -import org.moire.ultrasonic.data.APIIndexesConverter; -import org.moire.ultrasonic.data.APIJukeboxConverter; -import org.moire.ultrasonic.data.APILyricsConverter; -import org.moire.ultrasonic.data.APIMusicDirectoryConverter; -import org.moire.ultrasonic.data.APIMusicFolderConverter; -import org.moire.ultrasonic.data.APIPlaylistConverter; -import org.moire.ultrasonic.data.APIPodcastConverter; -import org.moire.ultrasonic.data.APISearchConverter; -import org.moire.ultrasonic.data.APIShareConverter; -import org.moire.ultrasonic.data.APIUserConverter; -import org.moire.ultrasonic.data.ApiGenreConverter; +import org.moire.ultrasonic.cache.PermanentFileStorage; +import org.moire.ultrasonic.cache.serializers.DomainSerializers; +import org.moire.ultrasonic.domain.APIAlbumConverter; +import org.moire.ultrasonic.domain.APIArtistConverter; +import org.moire.ultrasonic.domain.APIBookmarkConverter; +import org.moire.ultrasonic.domain.APIChatMessageConverter; +import org.moire.ultrasonic.domain.APIIndexesConverter; +import org.moire.ultrasonic.domain.APIJukeboxConverter; +import org.moire.ultrasonic.domain.APILyricsConverter; +import org.moire.ultrasonic.domain.APIMusicDirectoryConverter; +import org.moire.ultrasonic.domain.APIMusicFolderConverter; +import org.moire.ultrasonic.domain.APIPlaylistConverter; +import org.moire.ultrasonic.domain.APIPodcastConverter; +import org.moire.ultrasonic.domain.APISearchConverter; +import org.moire.ultrasonic.domain.APIShareConverter; +import org.moire.ultrasonic.domain.APIUserConverter; +import org.moire.ultrasonic.domain.ApiGenreConverter; import org.moire.ultrasonic.domain.Bookmark; import org.moire.ultrasonic.domain.ChatMessage; import org.moire.ultrasonic.domain.Genre; @@ -104,7 +106,6 @@ import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.List; -import java.util.Locale; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -117,10 +118,19 @@ import retrofit2.Response; public class RESTMusicService implements MusicService { private static final String TAG = RESTMusicService.class.getSimpleName(); - private final SubsonicAPIClient subsonicAPIClient; + private static final String MUSIC_FOLDER_STORAGE_NAME = "music_folder"; + private static final String INDEXES_STORAGE_NAME = "indexes"; + private static final String ARTISTS_STORAGE_NAME = "artists"; - public RESTMusicService(SubsonicAPIClient subsonicAPIClient) { + private final SubsonicAPIClient subsonicAPIClient; + private final PermanentFileStorage fileStorage; + + public RESTMusicService( + final SubsonicAPIClient subsonicAPIClient, + final PermanentFileStorage fileStorage + ) { this.subsonicAPIClient = subsonicAPIClient; + this.fileStorage = fileStorage; } @Override @@ -146,7 +156,8 @@ public class RESTMusicService implements MusicService { public List getMusicFolders(boolean refresh, Context context, ProgressListener progressListener) throws Exception { - List cachedMusicFolders = readCachedMusicFolders(context); + List cachedMusicFolders = fileStorage.load(MUSIC_FOLDER_STORAGE_NAME, + DomainSerializers.getMusicFolderListSerializer()); if (cachedMusicFolders != null && !refresh) { return cachedMusicFolders; } @@ -157,31 +168,18 @@ public class RESTMusicService implements MusicService { List musicFolders = APIMusicFolderConverter .toDomainEntityList(response.body().getMusicFolders()); - writeCachedMusicFolders(context, musicFolders); + fileStorage.store(MUSIC_FOLDER_STORAGE_NAME, musicFolders, + DomainSerializers.getMusicFolderListSerializer()); return musicFolders; } - private static List readCachedMusicFolders(Context context) { - String filename = getCachedMusicFoldersFilename(context); - return FileUtil.deserialize(context, filename); - } - - private static void writeCachedMusicFolders(Context context, List musicFolders) { - String filename = getCachedMusicFoldersFilename(context); - FileUtil.serialize(context, new ArrayList<>(musicFolders), filename); - } - - private static String getCachedMusicFoldersFilename(Context context) { - String s = Util.getRestUrl(context, null); - return String.format(Locale.US, "musicFolders-%d.ser", Math.abs(s.hashCode())); - } - @Override public Indexes getIndexes(String musicFolderId, boolean refresh, Context context, ProgressListener progressListener) throws Exception { - Indexes cachedIndexes = readCachedIndexes(context, musicFolderId); + Indexes cachedIndexes = fileStorage.load(INDEXES_STORAGE_NAME, + DomainSerializers.getIndexesSerializer()); if (cachedIndexes != null && !refresh) { return cachedIndexes; } @@ -192,59 +190,30 @@ public class RESTMusicService implements MusicService { checkResponseSuccessful(response); Indexes indexes = APIIndexesConverter.toDomainEntity(response.body().getIndexes()); - writeCachedIndexes(context, indexes, musicFolderId); + fileStorage.store(INDEXES_STORAGE_NAME, indexes, DomainSerializers.getIndexesSerializer()); return indexes; } - private static Indexes readCachedIndexes(Context context, String musicFolderId) { - String filename = getCachedIndexesFilename(context, musicFolderId); - return FileUtil.deserialize(context, filename); - } - - private static void writeCachedIndexes(Context context, Indexes indexes, String musicFolderId) { - String filename = getCachedIndexesFilename(context, musicFolderId); - FileUtil.serialize(context, indexes, filename); - } - - private static String getCachedIndexesFilename(Context context, String musicFolderId) { - String s = Util.getRestUrl(context, null) + musicFolderId; - return String.format(Locale.US, "indexes-%d.ser", Math.abs(s.hashCode())); - } - @Override public Indexes getArtists(boolean refresh, Context context, ProgressListener progressListener) throws Exception { - Indexes cachedArtists = readCachedArtists(context); - if (cachedArtists != null && - !refresh) { + Indexes cachedArtists = fileStorage + .load(ARTISTS_STORAGE_NAME, DomainSerializers.getIndexesSerializer()); + if (cachedArtists != null && !refresh) { return cachedArtists; } updateProgressListener(progressListener, R.string.parser_reading); - Response response = subsonicAPIClient.getApi().getArtists(null).execute(); + Response response = subsonicAPIClient.getApi() + .getArtists(null).execute(); checkResponseSuccessful(response); Indexes indexes = APIIndexesConverter.toDomainEntity(response.body().getIndexes()); - writeCachedArtists(context, indexes); + fileStorage.store(ARTISTS_STORAGE_NAME, indexes, DomainSerializers.getIndexesSerializer()); return indexes; } - private static Indexes readCachedArtists(Context context) { - String filename = getCachedArtistsFilename(context); - return FileUtil.deserialize(context, filename); - } - - private static void writeCachedArtists(Context context, Indexes artists) { - String filename = getCachedArtistsFilename(context); - FileUtil.serialize(context, artists, filename); - } - - private static String getCachedArtistsFilename(Context context) { - String s = Util.getRestUrl(context, null); - return String.format(Locale.US, "indexes-%d.ser", Math.abs(s.hashCode())); - } - @Override public void star(String id, String albumId, diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/util/Constants.java b/ultrasonic/src/main/java/org/moire/ultrasonic/util/Constants.java index de3b0a70..fc6b7e12 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/util/Constants.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/util/Constants.java @@ -31,7 +31,7 @@ public final class Constants // REST protocol version and client ID. // Note: Keep it as low as possible to maintain compatibility with older servers. public static final String REST_PROTOCOL_VERSION = "1.7.0"; - public static final String REST_CLIENT_ID = "UltraSonic%20for%20Android"; + public static final String REST_CLIENT_ID = "Ultrasonic"; // Names for intent extras. public static final String INTENT_EXTRA_NAME_ID = "subsonic.id"; diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/util/FileUtil.java b/ultrasonic/src/main/java/org/moire/ultrasonic/util/FileUtil.java index c306cbb7..fdcf9abd 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/util/FileUtil.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/util/FileUtil.java @@ -26,7 +26,6 @@ import android.text.TextUtils; import android.util.Log; import org.moire.ultrasonic.activity.SubsonicTabActivity; -import org.moire.ultrasonic.domain.Artist; import org.moire.ultrasonic.domain.MusicDirectory; import java.io.File; @@ -300,11 +299,6 @@ public class FileUtil return BitmapFactory.decodeByteArray(bytes, 0, bytes.length, opt); } - public static File getArtistDirectory(Context context, Artist artist) - { - return new File(String.format("%s/%s", getMusicDirectory(context).getPath(), fileSystemSafe(artist.getName()))); - } - public static File getAlbumArtDirectory() { File albumArtDir = new File(getUltraSonicDirectory(), "artwork"); diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/view/ArtistAdapter.java b/ultrasonic/src/main/java/org/moire/ultrasonic/view/ArtistAdapter.java index c153e3dc..67796a03 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/view/ArtistAdapter.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/view/ArtistAdapter.java @@ -19,8 +19,14 @@ package org.moire.ultrasonic.view; import android.content.Context; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.SectionIndexer; +import android.widget.TextView; import org.moire.ultrasonic.R; import org.moire.ultrasonic.domain.Artist; @@ -35,6 +41,7 @@ import java.util.List; */ public class ArtistAdapter extends ArrayAdapter implements SectionIndexer { + private final LayoutInflater layoutInflater; // Both arrays are indexed by section ID. private final Object[] sections; @@ -44,6 +51,8 @@ public class ArtistAdapter extends ArrayAdapter implements SectionIndexe { super(context, R.layout.artist_list_item, artists); + layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + Collection sectionSet = new LinkedHashSet(30); List positionList = new ArrayList(30); @@ -63,6 +72,23 @@ public class ArtistAdapter extends ArrayAdapter implements SectionIndexe positions = positionList.toArray(new Integer[positionList.size()]); } + @NonNull + @Override + public View getView( + int position, + @Nullable View convertView, + @NonNull ViewGroup parent + ) { + View rowView = convertView; + if (rowView == null) { + rowView = layoutInflater.inflate(R.layout.artist_list_item, parent, false); + } + + ((TextView) rowView).setText(getItem(position).getName()); + + return rowView; + } + @Override public Object[] getSections() { diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/view/GenreAdapter.java b/ultrasonic/src/main/java/org/moire/ultrasonic/view/GenreAdapter.java index ba194f10..12a21f3f 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/view/GenreAdapter.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/view/GenreAdapter.java @@ -19,8 +19,14 @@ package org.moire.ultrasonic.view; import android.content.Context; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.SectionIndexer; +import android.widget.TextView; import org.moire.ultrasonic.R; import org.moire.ultrasonic.domain.Genre; @@ -35,7 +41,7 @@ import java.util.List; */ public class GenreAdapter extends ArrayAdapter implements SectionIndexer { - + private final LayoutInflater layoutInflater; // Both arrays are indexed by section ID. private final Object[] sections; private final Integer[] positions; @@ -44,6 +50,8 @@ public class GenreAdapter extends ArrayAdapter implements SectionIndexer { super(context, R.layout.artist_list_item, genres); + layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + Collection sectionSet = new LinkedHashSet(30); List positionList = new ArrayList(30); @@ -62,7 +70,20 @@ public class GenreAdapter extends ArrayAdapter implements SectionIndexer positions = positionList.toArray(new Integer[positionList.size()]); } - @Override + @NonNull + @Override + public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { + View rowView = convertView; + if (rowView == null) { + rowView = layoutInflater.inflate(R.layout.artist_list_item, parent, false); + } + + ((TextView) rowView).setText(getItem(position).getName()); + + return rowView; + } + + @Override public Object[] getSections() { return sections; diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/view/PodcastsChannelsAdapter.java b/ultrasonic/src/main/java/org/moire/ultrasonic/view/PodcastsChannelsAdapter.java index 3e480a55..17749735 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/view/PodcastsChannelsAdapter.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/view/PodcastsChannelsAdapter.java @@ -1,83 +1,46 @@ package org.moire.ultrasonic.view; -import android.app.Activity; +import android.content.Context; +import android.support.annotation.NonNull; +import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.TextView; import org.moire.ultrasonic.R; -import org.moire.ultrasonic.activity.SubsonicTabActivity; -import org.moire.ultrasonic.domain.Playlist; import org.moire.ultrasonic.domain.PodcastsChannel; -import java.io.Serializable; -import java.util.Collections; -import java.util.Comparator; import java.util.List; /** * @author Sindre Mehus */ -public class PodcastsChannelsAdapter extends ArrayAdapter -{ +public class PodcastsChannelsAdapter extends ArrayAdapter { + private final LayoutInflater layoutInflater; - //private final SubsonicTabActivity activity; + public PodcastsChannelsAdapter(Context context, List channels) { + super(context, R.layout.podcasts_channel_item, channels); - public PodcastsChannelsAdapter(Activity activity, List channels) - { - super(activity, R.layout.podcasts_channel_item, channels); - //this.activity = activity; - } - - @Override - public void add(PodcastsChannel object) { - super.add(object); + layoutInflater = (LayoutInflater) context + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); } -/* @Override - public View getView(int position, View convertView, ViewGroup parent) - { - PodcastsChannel entry = getItem(position); - PlaylistView view; - if (convertView != null && convertView instanceof PlaylistView) - { - PlaylistView currentView = (PlaylistView) convertView; + @NonNull + @Override + public View getView(int position, View convertView, @NonNull ViewGroup parent) { + PodcastsChannel entry = getItem(position); - ViewHolder viewHolder = (ViewHolder) convertView.getTag(); - view = currentView; - view.setViewHolder(viewHolder); - } - else - { - view = new PlaylistView(activity); - view.setLayout(); - } + TextView view; + if (convertView != null && convertView instanceof PlaylistView) { + view = (TextView) convertView; + } else { + view = (TextView) layoutInflater + .inflate(R.layout.podcasts_channel_item, parent, false); + } - view.setPlaylist(entry); - return view; - } - */ + view.setText(entry.getTitle()); - /* public static class PlaylistComparator implements Comparator, Serializable - { - private static final long serialVersionUID = -6201663557439120008L; - - @Override - public int compare(Playlist playlist1, Playlist playlist2) - { - return playlist1.getName().compareToIgnoreCase(playlist2.getName()); - } - - public static List sort(List playlists) - { - Collections.sort(playlists, new PlaylistComparator()); - return playlists; - } - } */ - - /* static class ViewHolder - { - TextView name; - } */ -} \ No newline at end of file + return view; + } +} diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/view/SongView.java b/ultrasonic/src/main/java/org/moire/ultrasonic/view/SongView.java index e17560e0..20567820 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/view/SongView.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/view/SongView.java @@ -188,7 +188,7 @@ public class SongView extends UpdateView implements Checkable } } - int trackNumber = song.getTrack(); + int trackNumber = (song.getTrack() == null) ? 0 : song.getTrack(); if (viewHolder.track != null) { diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/APIBookmarkConverter.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/APIBookmarkConverter.kt deleted file mode 100644 index df9a127e..00000000 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/APIBookmarkConverter.kt +++ /dev/null @@ -1,17 +0,0 @@ -// Contains helper functions to convert api Bookmark entity to domain entity -@file:JvmName("APIBookmarkConverter") -package org.moire.ultrasonic.data - -import org.moire.ultrasonic.domain.Bookmark -import org.moire.ultrasonic.api.subsonic.models.Bookmark as ApiBookmark - -fun ApiBookmark.toDomainEntity(): Bookmark = Bookmark().apply { - position = this@toDomainEntity.position.toInt() - username = this@toDomainEntity.username - comment = this@toDomainEntity.comment - created = this@toDomainEntity.created?.time - changed = this@toDomainEntity.changed?.time - entry = this@toDomainEntity.entry.toDomainEntity() -} - -fun List.toDomainEntitiesList(): List = map { it.toDomainEntity() } diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/APIUserConverter.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/APIUserConverter.kt deleted file mode 100644 index 30fd036f..00000000 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/APIUserConverter.kt +++ /dev/null @@ -1,23 +0,0 @@ -// Helper functions to convert User entity to domain entity -@file:JvmName("APIUserConverter") -package org.moire.ultrasonic.data - -import org.moire.ultrasonic.domain.UserInfo -import org.moire.ultrasonic.api.subsonic.models.User - -fun User.toDomainEntity(): UserInfo = UserInfo().apply { - adminRole = this@toDomainEntity.adminRole - commentRole = this@toDomainEntity.commentRole - coverArtRole = this@toDomainEntity.coverArtRole - downloadRole = this@toDomainEntity.downloadRole - email = this@toDomainEntity.email - jukeboxRole = this@toDomainEntity.jukeboxRole - playlistRole = this@toDomainEntity.playlistRole - podcastRole = this@toDomainEntity.podcastRole - scrobblingEnabled = this@toDomainEntity.scrobblingEnabled - settingsRole = this@toDomainEntity.settingsRole - shareRole = this@toDomainEntity.shareRole - streamRole = this@toDomainEntity.streamRole - uploadRole = this@toDomainEntity.uploadRole - userName = this@toDomainEntity.username -} diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/APIAlbumConverter.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIAlbumConverter.kt similarity index 53% rename from ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/APIAlbumConverter.kt rename to ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIAlbumConverter.kt index 482e7275..efcebe2e 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/APIAlbumConverter.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIAlbumConverter.kt @@ -1,24 +1,23 @@ // Converts Album entity from [org.moire.ultrasonic.api.subsonic.SubsonicAPIClient] // to app domain entities. @file:JvmName("APIAlbumConverter") -package org.moire.ultrasonic.data +package org.moire.ultrasonic.domain import org.moire.ultrasonic.api.subsonic.models.Album -import org.moire.ultrasonic.domain.MusicDirectory -fun Album.toDomainEntity(): MusicDirectory.Entry = MusicDirectory.Entry().apply { - id = this@toDomainEntity.id - setIsDirectory(true) - title = this@toDomainEntity.name - coverArt = this@toDomainEntity.coverArt - artist = this@toDomainEntity.artist - artistId = this@toDomainEntity.artistId - songCount = this@toDomainEntity.songCount.toLong() - duration = this@toDomainEntity.duration - created = this@toDomainEntity.created?.time - year = this@toDomainEntity.year +fun Album.toDomainEntity(): MusicDirectory.Entry = MusicDirectory.Entry( + id = this@toDomainEntity.id, + isDirectory = true, + title = this@toDomainEntity.name, + coverArt = this@toDomainEntity.coverArt, + artist = this@toDomainEntity.artist, + artistId = this@toDomainEntity.artistId, + songCount = this@toDomainEntity.songCount.toLong(), + duration = this@toDomainEntity.duration, + created = this@toDomainEntity.created?.time, + year = this@toDomainEntity.year, genre = this@toDomainEntity.genre -} +) fun Album.toMusicDirectoryDomainEntity(): MusicDirectory = MusicDirectory().apply { addAll(this@toMusicDirectoryDomainEntity.songList.map { it.toDomainEntity() }) diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/APIArtistConverter.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIArtistConverter.kt similarity index 68% rename from ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/APIArtistConverter.kt rename to ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIArtistConverter.kt index 06e3f8ae..d7381164 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/APIArtistConverter.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIArtistConverter.kt @@ -1,16 +1,14 @@ // Converts Artist entity from [org.moire.ultrasonic.api.subsonic.SubsonicAPIClient] // to app domain entities. @file:JvmName("APIArtistConverter") -package org.moire.ultrasonic.data +package org.moire.ultrasonic.domain -import org.moire.ultrasonic.domain.Artist -import org.moire.ultrasonic.domain.MusicDirectory import org.moire.ultrasonic.api.subsonic.models.Artist as APIArtist -fun APIArtist.toDomainEntity(): Artist = Artist().apply { - id = this@toDomainEntity.id +fun APIArtist.toDomainEntity(): Artist = Artist( + id = this@toDomainEntity.id, name = this@toDomainEntity.name -} +) fun APIArtist.toMusicDirectoryDomainEntity(): MusicDirectory = MusicDirectory().apply { name = this@toMusicDirectoryDomainEntity.name diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIBookmarkConverter.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIBookmarkConverter.kt new file mode 100644 index 00000000..e7ac4e97 --- /dev/null +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIBookmarkConverter.kt @@ -0,0 +1,16 @@ +// Contains helper functions to convert api Bookmark entity to domain entity +@file:JvmName("APIBookmarkConverter") +package org.moire.ultrasonic.domain + +import org.moire.ultrasonic.api.subsonic.models.Bookmark as ApiBookmark + +fun ApiBookmark.toDomainEntity(): Bookmark = Bookmark( + position = this@toDomainEntity.position.toInt(), + username = this@toDomainEntity.username, + comment = this@toDomainEntity.comment, + created = this@toDomainEntity.created?.time, + changed = this@toDomainEntity.changed?.time, + entry = this@toDomainEntity.entry.toDomainEntity() +) + +fun List.toDomainEntitiesList(): List = map { it.toDomainEntity() } diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/APIChatMessageConverter.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIChatMessageConverter.kt similarity index 60% rename from ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/APIChatMessageConverter.kt rename to ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIChatMessageConverter.kt index 96119075..fcf39717 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/APIChatMessageConverter.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIChatMessageConverter.kt @@ -1,15 +1,14 @@ // Contains helper functions to convert from api ChatMessage entity to domain entity @file:JvmName("APIChatMessageConverter") -package org.moire.ultrasonic.data +package org.moire.ultrasonic.domain -import org.moire.ultrasonic.domain.ChatMessage import org.moire.ultrasonic.api.subsonic.models.ChatMessage as ApiChatMessage -fun ApiChatMessage.toDomainEntity(): ChatMessage = ChatMessage().apply { - username = this@toDomainEntity.username - time = this@toDomainEntity.time +fun ApiChatMessage.toDomainEntity(): ChatMessage = ChatMessage( + username = this@toDomainEntity.username, + time = this@toDomainEntity.time, message = this@toDomainEntity.message -} +) fun List.toDomainEntitiesList(): List = this .map { it.toDomainEntity() } diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/APIGenreConverter.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIGenreConverter.kt similarity index 65% rename from ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/APIGenreConverter.kt rename to ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIGenreConverter.kt index 78607ec3..1cd23f60 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/APIGenreConverter.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIGenreConverter.kt @@ -1,13 +1,12 @@ // Collection of functions to convert api Genre entity to domain entity @file:JvmName("ApiGenreConverter") -package org.moire.ultrasonic.data +package org.moire.ultrasonic.domain -import org.moire.ultrasonic.domain.Genre import org.moire.ultrasonic.api.subsonic.models.Genre as APIGenre -fun APIGenre.toDomainEntity(): Genre = Genre().apply { - name = this@toDomainEntity.name +fun APIGenre.toDomainEntity(): Genre = Genre( + name = this@toDomainEntity.name, index = this@toDomainEntity.name.substring(0, 1) -} +) fun List.toDomainEntityList(): List = this.map { it.toDomainEntity() } diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/APIIndexesConverter.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIIndexesConverter.kt similarity index 71% rename from ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/APIIndexesConverter.kt rename to ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIIndexesConverter.kt index 58aa2995..4f72202a 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/APIIndexesConverter.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIIndexesConverter.kt @@ -1,15 +1,15 @@ // Converts Indexes entity from [org.moire.ultrasonic.api.subsonic.SubsonicAPIClient] // to app domain entities. @file:JvmName("APIIndexesConverter") -package org.moire.ultrasonic.data +package org.moire.ultrasonic.domain import org.moire.ultrasonic.api.subsonic.models.Index -import org.moire.ultrasonic.domain.Artist -import org.moire.ultrasonic.domain.Indexes import org.moire.ultrasonic.api.subsonic.models.Indexes as APIIndexes fun APIIndexes.toDomainEntity(): Indexes = Indexes(this.lastModified, this.ignoredArticles, - this.shortcutList.map { it.toDomainEntity() }, this.indexList.foldIndexToArtistList()) + this.shortcutList.map { it.toDomainEntity() }.toMutableList(), + this.indexList.foldIndexToArtistList().toMutableList() +) private fun List.foldIndexToArtistList(): List = this.fold(listOf(), { acc, index -> acc + index.artists.map { it.toDomainEntity() } diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/APIJukeboxCoverter.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIJukeboxCoverter.kt similarity index 55% rename from ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/APIJukeboxCoverter.kt rename to ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIJukeboxCoverter.kt index bb4fe9a1..23f22a4f 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/APIJukeboxCoverter.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIJukeboxCoverter.kt @@ -1,13 +1,12 @@ // Collection of function to convert subsonic api jukebox responses to app entities @file:JvmName("APIJukeboxConverter") -package org.moire.ultrasonic.data +package org.moire.ultrasonic.domain -import org.moire.ultrasonic.domain.JukeboxStatus import org.moire.ultrasonic.api.subsonic.models.JukeboxStatus as ApiJukeboxStatus -fun ApiJukeboxStatus.toDomainEntity(): JukeboxStatus = JukeboxStatus().apply { - positionSeconds = this@toDomainEntity.position - setCurrentIndex(this@toDomainEntity.currentIndex) - isPlaying = this@toDomainEntity.playing +fun ApiJukeboxStatus.toDomainEntity(): JukeboxStatus = JukeboxStatus( + positionSeconds = this@toDomainEntity.position, + currentPlayingIndex = this@toDomainEntity.currentIndex, + isPlaying = this@toDomainEntity.playing, gain = this@toDomainEntity.gain -} +) diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/APILyricsConverter.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APILyricsConverter.kt similarity index 54% rename from ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/APILyricsConverter.kt rename to ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APILyricsConverter.kt index 8571dc01..2bebc6bb 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/APILyricsConverter.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APILyricsConverter.kt @@ -1,13 +1,12 @@ // Converts Lyrics entity from [org.moire.ultrasonic.api.subsonic.SubsonicAPIClient] // to app domain entities. @file:JvmName("APILyricsConverter") -package org.moire.ultrasonic.data +package org.moire.ultrasonic.domain -import org.moire.ultrasonic.domain.Lyrics import org.moire.ultrasonic.api.subsonic.models.Lyrics as APILyrics -fun APILyrics.toDomainEntity(): Lyrics = Lyrics().apply { - artist = this@toDomainEntity.artist - title = this@toDomainEntity.title +fun APILyrics.toDomainEntity(): Lyrics = Lyrics( + artist = this@toDomainEntity.artist, + title = this@toDomainEntity.title, text = this@toDomainEntity.text -} +) diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/APIMusicDirectoryConverter.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIMusicDirectoryConverter.kt similarity index 92% rename from ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/APIMusicDirectoryConverter.kt rename to ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIMusicDirectoryConverter.kt index 1ef56d4a..e1acb18c 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/APIMusicDirectoryConverter.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIMusicDirectoryConverter.kt @@ -1,10 +1,9 @@ // Converts MusicDirectory entity from [org.moire.ultrasonic.api.subsonic.SubsonicAPIClient] // to app domain entities. @file:JvmName("APIMusicDirectoryConverter") -package org.moire.ultrasonic.data +package org.moire.ultrasonic.domain import org.moire.ultrasonic.api.subsonic.models.MusicDirectoryChild -import org.moire.ultrasonic.domain.MusicDirectory import java.text.DateFormat import java.text.SimpleDateFormat import java.util.Locale @@ -17,7 +16,7 @@ internal val dateFormat: DateFormat by lazy { fun MusicDirectoryChild.toDomainEntity(): MusicDirectory.Entry = MusicDirectory.Entry().apply { id = this@toDomainEntity.id parent = this@toDomainEntity.parent - setIsDirectory(this@toDomainEntity.isDir) + isDirectory = this@toDomainEntity.isDir title = this@toDomainEntity.title album = this@toDomainEntity.album albumId = this@toDomainEntity.albumId @@ -35,7 +34,7 @@ fun MusicDirectoryChild.toDomainEntity(): MusicDirectory.Entry = MusicDirectory. duration = this@toDomainEntity.duration bitRate = this@toDomainEntity.bitRate path = this@toDomainEntity.path - setIsVideo(this@toDomainEntity.isVideo) + isVideo = this@toDomainEntity.isVideo created = this@toDomainEntity.created?.time starred = this@toDomainEntity.starred != null discNumber = this@toDomainEntity.discNumber diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/APIMusicFolderConverter.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIMusicFolderConverter.kt similarity index 84% rename from ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/APIMusicFolderConverter.kt rename to ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIMusicFolderConverter.kt index f7c5ebb6..c29e5e17 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/APIMusicFolderConverter.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIMusicFolderConverter.kt @@ -1,9 +1,8 @@ // Converts MusicFolder entity from [org.moire.ultrasonic.api.subsonic.SubsonicAPIClient] // to app domain entities. @file:JvmName("APIMusicFolderConverter") -package org.moire.ultrasonic.data +package org.moire.ultrasonic.domain -import org.moire.ultrasonic.domain.MusicFolder import org.moire.ultrasonic.api.subsonic.models.MusicFolder as APIMusicFolder fun APIMusicFolder.toDomainEntity(): MusicFolder = MusicFolder(this.id, this.name) diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/APIPlaylistConverter.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIPlaylistConverter.kt similarity index 85% rename from ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/APIPlaylistConverter.kt rename to ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIPlaylistConverter.kt index a096fca1..04cdead7 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/APIPlaylistConverter.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIPlaylistConverter.kt @@ -1,10 +1,8 @@ // Converts Playlist entity from [org.moire.ultrasonic.api.subsonic.SubsonicAPIClient] // to app domain entities. @file:JvmName("APIPlaylistConverter") -package org.moire.ultrasonic.data +package org.moire.ultrasonic.domain -import org.moire.ultrasonic.domain.MusicDirectory -import org.moire.ultrasonic.domain.Playlist import java.text.SimpleDateFormat import kotlin.LazyThreadSafetyMode.NONE import org.moire.ultrasonic.api.subsonic.models.Playlist as APIPlaylist @@ -18,7 +16,7 @@ fun APIPlaylist.toMusicDirectoryDomainEntity(): MusicDirectory = MusicDirectory( fun APIPlaylist.toDomainEntity(): Playlist = Playlist(this.id, this.name, this.owner, this.comment, this.songCount.toString(), - this.created?.let { playlistDateFormat.format(it.time) }, - public.toString()) + this.created?.let { playlistDateFormat.format(it.time) } ?: "", + public) fun List.toDomainEntitiesList(): List = this.map { it.toDomainEntity() } diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/APIPodcastConverter.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIPodcastConverter.kt similarity index 84% rename from ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/APIPodcastConverter.kt rename to ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIPodcastConverter.kt index 3a5d3e4b..8aef5006 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/APIPodcastConverter.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIPodcastConverter.kt @@ -1,10 +1,9 @@ // Converts podcasts entities from [org.moire.ultrasonic.api.subsonic.SubsonicAPIClient] // to app domain entities. @file:JvmName("APIPodcastConverter") -package org.moire.ultrasonic.data +package org.moire.ultrasonic.domain import org.moire.ultrasonic.api.subsonic.models.PodcastChannel -import org.moire.ultrasonic.domain.PodcastsChannel fun PodcastChannel.toDomainEntity(): PodcastsChannel = PodcastsChannel( this.id, this.title, this.url, this.description, this.status) diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/APISearchConverter.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APISearchConverter.kt similarity index 92% rename from ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/APISearchConverter.kt rename to ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APISearchConverter.kt index 7a1dafc0..abc96b7f 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/APISearchConverter.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APISearchConverter.kt @@ -1,11 +1,10 @@ // Converts SearchResult entities from [org.moire.ultrasonic.api.subsonic.SubsonicAPIClient] // to app domain entities. @file:JvmName("APISearchConverter") -package org.moire.ultrasonic.data +package org.moire.ultrasonic.domain import org.moire.ultrasonic.api.subsonic.models.SearchThreeResult import org.moire.ultrasonic.api.subsonic.models.SearchTwoResult -import org.moire.ultrasonic.domain.SearchResult import org.moire.ultrasonic.api.subsonic.models.SearchResult as APISearchResult fun APISearchResult.toDomainEntity(): SearchResult = SearchResult(emptyList(), emptyList(), diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/APIShareConverter.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIShareConverter.kt similarity index 56% rename from ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/APIShareConverter.kt rename to ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIShareConverter.kt index a1933281..36486783 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/APIShareConverter.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIShareConverter.kt @@ -1,8 +1,7 @@ // Contains helper method to convert subsonic api share to domain model @file:JvmName("APIShareConverter") -package org.moire.ultrasonic.data +package org.moire.ultrasonic.domain -import org.moire.ultrasonic.domain.Share import java.text.SimpleDateFormat import kotlin.LazyThreadSafetyMode.NONE import org.moire.ultrasonic.api.subsonic.models.Share as APIShare @@ -13,14 +12,14 @@ fun List.toDomainEntitiesList(): List = this.map { it.toDomainEntity() } -fun APIShare.toDomainEntity(): Share = Share().apply { - created = this@toDomainEntity.created?.let { shareTimeFormat.format(it.time) } - description = this@toDomainEntity.description - expires = this@toDomainEntity.expires?.let { shareTimeFormat.format(it.time) } - id = this@toDomainEntity.id - lastVisited = this@toDomainEntity.lastVisited?.let { shareTimeFormat.format(it.time) } - url = this@toDomainEntity.url - username = this@toDomainEntity.username - visitCount = this@toDomainEntity.visitCount.toLong() - entries.addAll(this@toDomainEntity.items.toDomainEntityList()) -} +fun APIShare.toDomainEntity(): Share = Share( + created = this@toDomainEntity.created?.let { shareTimeFormat.format(it.time) }, + description = this@toDomainEntity.description, + expires = this@toDomainEntity.expires?.let { shareTimeFormat.format(it.time) }, + id = this@toDomainEntity.id, + lastVisited = this@toDomainEntity.lastVisited?.let { shareTimeFormat.format(it.time) }, + url = this@toDomainEntity.url, + username = this@toDomainEntity.username, + visitCount = this@toDomainEntity.visitCount.toLong(), + entries = this@toDomainEntity.items.toDomainEntityList().toMutableList() +) diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIUserConverter.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIUserConverter.kt new file mode 100644 index 00000000..37dc53ad --- /dev/null +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/domain/APIUserConverter.kt @@ -0,0 +1,22 @@ +// Helper functions to convert User entity to domain entity +@file:JvmName("APIUserConverter") +package org.moire.ultrasonic.domain + +import org.moire.ultrasonic.api.subsonic.models.User + +fun User.toDomainEntity(): UserInfo = UserInfo( + adminRole = this@toDomainEntity.adminRole, + commentRole = this@toDomainEntity.commentRole, + coverArtRole = this@toDomainEntity.coverArtRole, + downloadRole = this@toDomainEntity.downloadRole, + email = this@toDomainEntity.email, + jukeboxRole = this@toDomainEntity.jukeboxRole, + playlistRole = this@toDomainEntity.playlistRole, + podcastRole = this@toDomainEntity.podcastRole, + scrobblingEnabled = this@toDomainEntity.scrobblingEnabled, + settingsRole = this@toDomainEntity.settingsRole, + shareRole = this@toDomainEntity.shareRole, + streamRole = this@toDomainEntity.streamRole, + uploadRole = this@toDomainEntity.uploadRole, + userName = this@toDomainEntity.username +) diff --git a/ultrasonic/src/main/res/layout/podcasts_channel_item.xml b/ultrasonic/src/main/res/layout/podcasts_channel_item.xml index 9b8560e8..bfa54b5f 100644 --- a/ultrasonic/src/main/res/layout/podcasts_channel_item.xml +++ b/ultrasonic/src/main/res/layout/podcasts_channel_item.xml @@ -1,9 +1,9 @@ - + diff --git a/ultrasonic/src/test/kotlin/org/moire/ultrasonic/data/APIAlbumConverterTest.kt b/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIAlbumConverterTest.kt similarity index 73% rename from ultrasonic/src/test/kotlin/org/moire/ultrasonic/data/APIAlbumConverterTest.kt rename to ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIAlbumConverterTest.kt index c75aba42..64adb575 100644 --- a/ultrasonic/src/test/kotlin/org/moire/ultrasonic/data/APIAlbumConverterTest.kt +++ b/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIAlbumConverterTest.kt @@ -1,6 +1,6 @@ @file:Suppress("IllegalIdentifier") -package org.moire.ultrasonic.data +package org.moire.ultrasonic.domain import org.amshove.kluent.`should equal to` import org.amshove.kluent.`should equal` @@ -22,17 +22,17 @@ class APIAlbumConverterTest { val convertedEntity = entity.toDomainEntity() with(convertedEntity) { - id `should equal to` entity.id - title `should equal to` entity.name - isDirectory `should equal to` true - coverArt `should equal to` entity.coverArt - artist `should equal to` entity.artist - artistId `should equal to` entity.artistId - songCount `should equal to` entity.songCount.toLong() - duration `should equal to` entity.duration + id `should equal` entity.id + title `should equal` entity.name + isDirectory `should equal` true + coverArt `should equal` entity.coverArt + artist `should equal` entity.artist + artistId `should equal` entity.artistId + songCount `should equal` entity.songCount.toLong() + duration `should equal` entity.duration created `should equal` entity.created?.time - year `should equal to` entity.year - genre `should equal to` entity.genre + year `should equal` entity.year + genre `should equal` entity.genre } } @@ -47,8 +47,8 @@ class APIAlbumConverterTest { with(convertedEntity) { name `should equal` null - children.size `should equal to` entity.songList.size - children[0] `should equal` entity.songList[0].toDomainEntity() + getChildren().size `should equal to` entity.songList.size + getChildren()[0] `should equal` entity.songList[0].toDomainEntity() } } diff --git a/ultrasonic/src/test/kotlin/org/moire/ultrasonic/data/APIArtistConverterTest.kt b/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIArtistConverterTest.kt similarity index 79% rename from ultrasonic/src/test/kotlin/org/moire/ultrasonic/data/APIArtistConverterTest.kt rename to ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIArtistConverterTest.kt index ec1928bf..e19d253c 100644 --- a/ultrasonic/src/test/kotlin/org/moire/ultrasonic/data/APIArtistConverterTest.kt +++ b/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIArtistConverterTest.kt @@ -1,8 +1,7 @@ @file:Suppress("IllegalIdentifier") -package org.moire.ultrasonic.data +package org.moire.ultrasonic.domain -import org.amshove.kluent.`should equal to` import org.amshove.kluent.`should equal` import org.junit.Test import org.moire.ultrasonic.api.subsonic.models.Album @@ -20,8 +19,8 @@ class APIArtistConverterTest { val convertedEntity = entity.toDomainEntity() with(convertedEntity) { - id `should equal to` entity.id - name `should equal to` entity.name + id `should equal` entity.id + name `should equal` entity.name } } @@ -36,8 +35,9 @@ class APIArtistConverterTest { val convertedEntity = entity.toMusicDirectoryDomainEntity() with(convertedEntity) { - name `should equal to` entity.name - children `should equal` entity.albumsList.map { it.toDomainEntity() }.toMutableList() + name `should equal` entity.name + getAllChild() `should equal` entity.albumsList + .map { it.toDomainEntity() }.toMutableList() } } } diff --git a/ultrasonic/src/test/kotlin/org/moire/ultrasonic/data/APIBookmarkConverterTest.kt b/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIBookmarkConverterTest.kt similarity index 90% rename from ultrasonic/src/test/kotlin/org/moire/ultrasonic/data/APIBookmarkConverterTest.kt rename to ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIBookmarkConverterTest.kt index 77a6052d..9de472da 100644 --- a/ultrasonic/src/test/kotlin/org/moire/ultrasonic/data/APIBookmarkConverterTest.kt +++ b/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIBookmarkConverterTest.kt @@ -1,6 +1,6 @@ @file:Suppress("IllegalIdentifier") -package org.moire.ultrasonic.data +package org.moire.ultrasonic.domain import org.amshove.kluent.`should equal to` import org.amshove.kluent.`should equal` @@ -22,8 +22,8 @@ class APIBookmarkConverterTest { with(domainEntity) { position `should equal to` entity.position.toInt() - username `should equal to` entity.username - comment `should equal to` entity.comment + username `should equal` entity.username + comment `should equal` entity.comment created `should equal` entity.created?.time changed `should equal` entity.changed?.time entry `should equal` entity.entry.toDomainEntity() diff --git a/ultrasonic/src/test/kotlin/org/moire/ultrasonic/data/APIChatMessageConverterTest.kt b/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIChatMessageConverterTest.kt similarity index 83% rename from ultrasonic/src/test/kotlin/org/moire/ultrasonic/data/APIChatMessageConverterTest.kt rename to ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIChatMessageConverterTest.kt index fc213ca5..ee462a89 100644 --- a/ultrasonic/src/test/kotlin/org/moire/ultrasonic/data/APIChatMessageConverterTest.kt +++ b/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIChatMessageConverterTest.kt @@ -1,6 +1,6 @@ @file:Suppress("IllegalIdentifier") -package org.moire.ultrasonic.data +package org.moire.ultrasonic.domain import org.amshove.kluent.`should equal to` import org.amshove.kluent.`should equal` @@ -18,9 +18,9 @@ class APIChatMessageConverterTest { val domainEntity = entity.toDomainEntity() with(domainEntity) { - username `should equal to` entity.username - time `should equal to` entity.time - message `should equal to` entity.message + username `should equal` entity.username + time `should equal` entity.time + message `should equal` entity.message } } diff --git a/ultrasonic/src/test/kotlin/org/moire/ultrasonic/data/APIIndexesConverterTest.kt b/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIIndexesConverterTest.kt similarity index 97% rename from ultrasonic/src/test/kotlin/org/moire/ultrasonic/data/APIIndexesConverterTest.kt rename to ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIIndexesConverterTest.kt index 2778b926..d51522a4 100644 --- a/ultrasonic/src/test/kotlin/org/moire/ultrasonic/data/APIIndexesConverterTest.kt +++ b/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIIndexesConverterTest.kt @@ -1,6 +1,6 @@ @file:Suppress("IllegalIdentifier") -package org.moire.ultrasonic.data +package org.moire.ultrasonic.domain import org.amshove.kluent.`should equal to` import org.amshove.kluent.`should equal` diff --git a/ultrasonic/src/test/kotlin/org/moire/ultrasonic/data/APIJukeboxConverterTest.kt b/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIJukeboxConverterTest.kt similarity index 69% rename from ultrasonic/src/test/kotlin/org/moire/ultrasonic/data/APIJukeboxConverterTest.kt rename to ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIJukeboxConverterTest.kt index 846970a6..d6498860 100644 --- a/ultrasonic/src/test/kotlin/org/moire/ultrasonic/data/APIJukeboxConverterTest.kt +++ b/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIJukeboxConverterTest.kt @@ -1,8 +1,9 @@ @file:Suppress("IllegalIdentifier") -package org.moire.ultrasonic.data +package org.moire.ultrasonic.domain import org.amshove.kluent.`should equal to` +import org.amshove.kluent.`should equal` import org.junit.Test import org.moire.ultrasonic.api.subsonic.models.JukeboxStatus @@ -17,10 +18,10 @@ class APIJukeboxConverterTest { val convertedEntity = entity.toDomainEntity() with(convertedEntity) { - currentPlayingIndex `should equal to` entity.currentIndex - gain `should equal to` entity.gain + currentPlayingIndex `should equal` entity.currentIndex + gain `should equal` entity.gain isPlaying `should equal to` entity.playing - positionSeconds `should equal to` entity.position + positionSeconds `should equal` entity.position } } } diff --git a/ultrasonic/src/test/kotlin/org/moire/ultrasonic/data/APILyricsConverterTest.kt b/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APILyricsConverterTest.kt similarity index 68% rename from ultrasonic/src/test/kotlin/org/moire/ultrasonic/data/APILyricsConverterTest.kt rename to ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APILyricsConverterTest.kt index 4ea41427..eb72481c 100644 --- a/ultrasonic/src/test/kotlin/org/moire/ultrasonic/data/APILyricsConverterTest.kt +++ b/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APILyricsConverterTest.kt @@ -1,8 +1,8 @@ @file:Suppress("IllegalIdentifier") -package org.moire.ultrasonic.data +package org.moire.ultrasonic.domain -import org.amshove.kluent.`should equal to` +import org.amshove.kluent.`should equal` import org.junit.Test import org.moire.ultrasonic.api.subsonic.models.Lyrics @@ -17,9 +17,9 @@ class APILyricsConverterTest { val convertedEntity = entity.toDomainEntity() with(convertedEntity) { - artist `should equal to` entity.artist - title `should equal to` entity.title - text `should equal to` entity.text + artist `should equal` entity.artist + title `should equal` entity.title + text `should equal` entity.text } } } diff --git a/ultrasonic/src/test/kotlin/org/moire/ultrasonic/data/APIMusicDirectoryConverterTest.kt b/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIMusicDirectoryConverterTest.kt similarity index 67% rename from ultrasonic/src/test/kotlin/org/moire/ultrasonic/data/APIMusicDirectoryConverterTest.kt rename to ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIMusicDirectoryConverterTest.kt index 4d8cdd73..9e8f80c2 100644 --- a/ultrasonic/src/test/kotlin/org/moire/ultrasonic/data/APIMusicDirectoryConverterTest.kt +++ b/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIMusicDirectoryConverterTest.kt @@ -1,6 +1,6 @@ @file:Suppress("IllegalIdentifier") -package org.moire.ultrasonic.data +package org.moire.ultrasonic.domain import org.amshove.kluent.`should equal to` import org.amshove.kluent.`should equal` @@ -22,9 +22,10 @@ class APIMusicDirectoryConverterTest { val convertedEntity = entity.toDomainEntity() with(convertedEntity) { - name `should equal to` entity.name - children.size `should equal to` entity.childList.size - children `should equal` entity.childList.map { it.toDomainEntity() }.toMutableList() + name `should equal` entity.name + getAllChild().size `should equal to` entity.childList.size + getAllChild() `should equal` entity.childList + .map { it.toDomainEntity() }.toMutableList() } } @@ -43,31 +44,31 @@ class APIMusicDirectoryConverterTest { val convertedEntity = entity.toDomainEntity() with(convertedEntity) { - id `should equal to` entity.id - parent `should equal to` entity.parent + id `should equal` entity.id + parent `should equal` entity.parent isDirectory `should equal to` entity.isDir title `should equal` entity.title album `should equal` entity.album - albumId `should equal to` entity.albumId - artist `should equal to` entity.artist - artistId `should equal to` entity.artistId - track `should equal to` entity.track - year `should equal to` entity.year!! - genre `should equal to` entity.genre - contentType `should equal to` entity.contentType - suffix `should equal to` entity.suffix - transcodedContentType `should equal to` entity.transcodedContentType - transcodedSuffix `should equal to` entity.transcodedSuffix - coverArt `should equal to` entity.coverArt - size `should equal to` entity.size - duration `should equal to` entity.duration - bitRate `should equal to` entity.bitRate - path `should equal to` entity.path + albumId `should equal` entity.albumId + artist `should equal` entity.artist + artistId `should equal` entity.artistId + track `should equal` entity.track + year `should equal` entity.year!! + genre `should equal` entity.genre + contentType `should equal` entity.contentType + suffix `should equal` entity.suffix + transcodedContentType `should equal` entity.transcodedContentType + transcodedSuffix `should equal` entity.transcodedSuffix + coverArt `should equal` entity.coverArt + size `should equal` entity.size + duration `should equal` entity.duration + bitRate `should equal` entity.bitRate + path `should equal` entity.path isVideo `should equal to` entity.isVideo created `should equal` entity.created?.time starred `should equal to` (entity.starred != null) - discNumber `should equal to` entity.discNumber - type `should equal to` entity.type + discNumber `should equal` entity.discNumber + type `should equal` entity.type } } @@ -79,8 +80,8 @@ class APIMusicDirectoryConverterTest { val convertedEntity = entity.toDomainEntity() with(convertedEntity) { - id `should equal to` entity.streamId - artist `should equal to` dateFormat.format(entity.publishDate?.time) + id `should equal` entity.streamId + artist `should equal` dateFormat.format(entity.publishDate?.time) } } diff --git a/ultrasonic/src/test/kotlin/org/moire/ultrasonic/data/APIMusicFolderConverterTest.kt b/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIMusicFolderConverterTest.kt similarity index 97% rename from ultrasonic/src/test/kotlin/org/moire/ultrasonic/data/APIMusicFolderConverterTest.kt rename to ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIMusicFolderConverterTest.kt index 34b1008c..7c66d464 100644 --- a/ultrasonic/src/test/kotlin/org/moire/ultrasonic/data/APIMusicFolderConverterTest.kt +++ b/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIMusicFolderConverterTest.kt @@ -1,6 +1,6 @@ @file:Suppress("IllegalIdentifier") -package org.moire.ultrasonic.data +package org.moire.ultrasonic.domain import org.amshove.kluent.`should equal to` import org.junit.Test diff --git a/ultrasonic/src/test/kotlin/org/moire/ultrasonic/data/APIPlaylistConverterTest.kt b/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIPlaylistConverterTest.kt similarity index 84% rename from ultrasonic/src/test/kotlin/org/moire/ultrasonic/data/APIPlaylistConverterTest.kt rename to ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIPlaylistConverterTest.kt index 4ef73d00..a99a288b 100644 --- a/ultrasonic/src/test/kotlin/org/moire/ultrasonic/data/APIPlaylistConverterTest.kt +++ b/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIPlaylistConverterTest.kt @@ -1,6 +1,6 @@ @file:Suppress("IllegalIdentifier") -package org.moire.ultrasonic.data +package org.moire.ultrasonic.domain import org.amshove.kluent.`should equal to` import org.amshove.kluent.`should equal` @@ -23,10 +23,10 @@ class APIPlaylistConverterTest { val convertedEntity = entity.toMusicDirectoryDomainEntity() with(convertedEntity) { - name `should equal to` entity.name - children.size `should equal to` entity.entriesList.size - children[0] `should equal` entity.entriesList[0].toDomainEntity() - children[1] `should equal` entity.entriesList[1].toDomainEntity() + name `should equal` entity.name + getAllChild().size `should equal to` entity.entriesList.size + getAllChild()[0] `should equal` entity.entriesList[0].toDomainEntity() + getAllChild()[1] `should equal` entity.entriesList[1].toDomainEntity() } } @@ -44,7 +44,7 @@ class APIPlaylistConverterTest { name `should equal to` entity.name comment `should equal to` entity.comment owner `should equal to` entity.owner - public `should equal to` entity.public + public `should equal` entity.public songCount `should equal to` entity.songCount.toString() created `should equal to` playlistDateFormat.format(entity.created?.time) } diff --git a/ultrasonic/src/test/kotlin/org/moire/ultrasonic/data/APIPodcastConverterTest.kt b/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIPodcastConverterTest.kt similarity index 82% rename from ultrasonic/src/test/kotlin/org/moire/ultrasonic/data/APIPodcastConverterTest.kt rename to ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIPodcastConverterTest.kt index 11958239..dcc49b47 100644 --- a/ultrasonic/src/test/kotlin/org/moire/ultrasonic/data/APIPodcastConverterTest.kt +++ b/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIPodcastConverterTest.kt @@ -1,6 +1,6 @@ @file:Suppress("IllegalIdentifier") -package org.moire.ultrasonic.data +package org.moire.ultrasonic.domain import org.amshove.kluent.`should equal to` import org.amshove.kluent.`should equal` @@ -20,11 +20,11 @@ class APIPodcastConverterTest { val converterEntity = entity.toDomainEntity() with(converterEntity) { - id = entity.id - description = entity.description - status = entity.status - title = entity.title - url = entity.url + id `should equal` entity.id + description `should equal` entity.description + status `should equal` entity.status + title `should equal` entity.title + url `should equal` entity.url } } diff --git a/ultrasonic/src/test/kotlin/org/moire/ultrasonic/data/APISearchConverterTest.kt b/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APISearchConverterTest.kt similarity index 98% rename from ultrasonic/src/test/kotlin/org/moire/ultrasonic/data/APISearchConverterTest.kt rename to ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APISearchConverterTest.kt index d83bed50..5e3ce2cf 100644 --- a/ultrasonic/src/test/kotlin/org/moire/ultrasonic/data/APISearchConverterTest.kt +++ b/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APISearchConverterTest.kt @@ -1,6 +1,6 @@ @file:Suppress("IllegalIdentifier") -package org.moire.ultrasonic.data +package org.moire.ultrasonic.domain import org.amshove.kluent.`should equal to` import org.amshove.kluent.`should equal` diff --git a/ultrasonic/src/test/kotlin/org/moire/ultrasonic/data/APIShareConverterTest.kt b/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIShareConverterTest.kt similarity index 70% rename from ultrasonic/src/test/kotlin/org/moire/ultrasonic/data/APIShareConverterTest.kt rename to ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIShareConverterTest.kt index 192b50b2..623af2f5 100644 --- a/ultrasonic/src/test/kotlin/org/moire/ultrasonic/data/APIShareConverterTest.kt +++ b/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIShareConverterTest.kt @@ -1,6 +1,6 @@ @file:Suppress("IllegalIdentifier") -package org.moire.ultrasonic.data +package org.moire.ultrasonic.domain import org.amshove.kluent.`should equal to` import org.amshove.kluent.`should equal` @@ -20,15 +20,15 @@ class APIShareConverterTest { val domainEntity = entity.toDomainEntity() with(domainEntity) { - id `should equal to` entity.id - url `should equal to` entity.url - description `should equal to` entity.description - username `should equal to` entity.username - created `should equal to` shareTimeFormat.format(entity.created?.time) - lastVisited `should equal to` shareTimeFormat.format(entity.lastVisited?.time) - expires `should equal to` shareTimeFormat.format(entity.expires?.time) - visitCount `should equal to` entity.visitCount.toLong() - entries `should equal` entity.items.toDomainEntityList() + id `should equal` entity.id + url `should equal` entity.url + description `should equal` entity.description + username `should equal` entity.username + created `should equal` shareTimeFormat.format(entity.created?.time) + lastVisited `should equal` shareTimeFormat.format(entity.lastVisited?.time) + expires `should equal` shareTimeFormat.format(entity.expires?.time) + visitCount `should equal` entity.visitCount.toLong() + this.getEntries() `should equal` entity.items.toDomainEntityList() } } diff --git a/ultrasonic/src/test/kotlin/org/moire/ultrasonic/data/APIUserConverterTest.kt b/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIUserConverterTest.kt similarity index 88% rename from ultrasonic/src/test/kotlin/org/moire/ultrasonic/data/APIUserConverterTest.kt rename to ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIUserConverterTest.kt index 4b5f2eb7..0fdff320 100644 --- a/ultrasonic/src/test/kotlin/org/moire/ultrasonic/data/APIUserConverterTest.kt +++ b/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/APIUserConverterTest.kt @@ -1,8 +1,9 @@ @file:Suppress("IllegalIdentifier") -package org.moire.ultrasonic.data +package org.moire.ultrasonic.domain import org.amshove.kluent.`should equal to` +import org.amshove.kluent.`should equal` import org.junit.Test import org.moire.ultrasonic.api.subsonic.models.User @@ -22,7 +23,7 @@ class APIUserConverterTest { commentRole `should equal to` entity.commentRole coverArtRole `should equal to` entity.coverArtRole downloadRole `should equal to` entity.downloadRole - email `should equal to` entity.email + email `should equal` entity.email jukeboxRole `should equal to` entity.jukeboxRole playlistRole `should equal to` entity.playlistRole podcastRole `should equal to` entity.podcastRole @@ -31,7 +32,7 @@ class APIUserConverterTest { shareRole `should equal to` entity.shareRole streamRole `should equal to` entity.streamRole uploadRole `should equal to` entity.uploadRole - userName `should equal to` entity.username + userName `should equal` entity.username } } } diff --git a/ultrasonic/src/test/kotlin/org/moire/ultrasonic/data/ApiGenreConverterTest.kt b/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/ApiGenreConverterTest.kt similarity index 89% rename from ultrasonic/src/test/kotlin/org/moire/ultrasonic/data/ApiGenreConverterTest.kt rename to ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/ApiGenreConverterTest.kt index bf7dc9eb..8552bf02 100644 --- a/ultrasonic/src/test/kotlin/org/moire/ultrasonic/data/ApiGenreConverterTest.kt +++ b/ultrasonic/src/test/kotlin/org/moire/ultrasonic/domain/ApiGenreConverterTest.kt @@ -1,6 +1,6 @@ @file:Suppress("IllegalIdentifier") -package org.moire.ultrasonic.data +package org.moire.ultrasonic.domain import org.amshove.kluent.`should equal to` import org.amshove.kluent.`should equal` @@ -18,8 +18,8 @@ class ApiGenreConverterTest { val domainEntity = entity.toDomainEntity() with(domainEntity) { - name `should equal to` entity.name - index `should equal to` "s" + name `should equal` entity.name + index `should equal` "s" } }