Merge pull request #101 from ultrasonic/api-23

Api 23
This commit is contained in:
Yahor Berdnikau 2017-12-21 11:56:20 +01:00 committed by GitHub
commit 0a67f175fc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
55 changed files with 918 additions and 1703 deletions

View File

@ -4,16 +4,14 @@ buildscript {
repositories {
jcenter()
google()
maven { url "https://plugins.gradle.org/m2/" }
}
dependencies {
classpath gradlePlugins.androidTools
classpath gradlePlugins.kotlin
classpath gradlePlugins.ktlintGradle
classpath(gradlePlugins.detekt) {
exclude module: 'kotlin-compiler-embeddable'
exclude module: 'kotlin-stdlib'
}
classpath gradlePlugins.detekt
classpath gradlePlugins.jacocoAndroid
}
}
@ -23,6 +21,7 @@ allprojects {
buildscript {
repositories {
jcenter()
google()
}
}

View File

@ -1,20 +1,19 @@
ext.versions = [
minSdk : 14,
targetSdk : 22,
compileSdk : 22,
gradle : '4.3.1',
targetSdk : 23,
compileSdk : 27,
gradle : '4.4.1',
buildTools : "25.0.3",
androidTools : "2.3.3",
ktlint : "0.12.1",
androidTools : "3.0.1",
ktlint : "0.14.0",
ktlintGradle : "2.3.0",
detekt : "1.0.0.RC5-4",
detekt : "1.0.0.RC6",
jacoco : "0.7.9",
jacocoAndroid : "0.1.2",
androidSupport : "22.2.1",
androidSupport : "23.4.0",
kotlin : "1.1.60",
kotlin : "1.2.10",
retrofit : "2.1.0",
jackson : "2.9.0",
@ -42,7 +41,7 @@ ext.androidSupport = [
ext.other = [
kotlinStdlib : "org.jetbrains.kotlin:kotlin-stdlib:$versions.kotlin",
kotlinReflect : "org.jetbrains.kotlin:kotlin-reflect:$versions.kotlin",
kotlinReflect : "org.jetbrains.kotlin:kotlin-reflect:$versions.kotlin",
retrofit : "com.squareup.retrofit2:retrofit:$versions.retrofit",
gsonConverter : "com.squareup.retrofit2:converter-gson:$versions.retrofit",
jacksonConverter : "com.squareup.retrofit2:converter-jackson:$versions.retrofit",

Binary file not shown.

View File

@ -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.3.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-4.4.1-all.zip

View File

@ -2,7 +2,6 @@ apply plugin: 'com.android.library'
android {
compileSdkVersion versions.compileSdk
buildToolsVersion versions.buildTools
defaultConfig {
minSdkVersion versions.minSdk
@ -23,5 +22,5 @@ android {
}
dependencies {
compile androidSupport.support
api androidSupport.support
}

View File

@ -2,7 +2,6 @@ apply plugin: 'com.android.library'
android {
compileSdkVersion versions.compileSdk
buildToolsVersion versions.buildTools
defaultConfig {
minSdkVersion versions.minSdk

View File

@ -19,7 +19,6 @@ package net.simonvt.menudrawer;
import android.content.Context;
import android.hardware.SensorManager;
import android.os.Build;
import android.util.FloatMath;
import android.view.ViewConfiguration;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
@ -371,7 +370,7 @@ class Scroller {
float dx = (float) (mFinalX - mStartX);
float dy = (float) (mFinalY - mStartY);
float hyp = FloatMath.sqrt(dx * dx + dy * dy);
float hyp = (float) Math.sqrt(dx * dx + dy * dy);
float ndx = dx / hyp;
float ndy = dy / hyp;
@ -388,7 +387,7 @@ class Scroller {
mMode = FLING_MODE;
mFinished = false;
float velocity = FloatMath.sqrt(velocityX * velocityX + velocityY * velocityY);
float velocity = (float) Math.sqrt(velocityX * velocityX + velocityY * velocityY);
mVelocity = velocity;
final double l = Math.log(START_TENSION * velocity / ALPHA);

View File

@ -2,7 +2,6 @@ apply plugin: 'com.android.library'
android {
compileSdkVersion versions.compileSdk
buildToolsVersion versions.buildTools
defaultConfig {
minSdkVersion versions.minSdk

View File

@ -21,7 +21,6 @@ import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import android.util.AttributeSet;
import android.util.FloatMath;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
@ -112,7 +111,7 @@ public class PullToRefreshWebView extends PullToRefreshBase<WebView> {
@Override
protected boolean isReadyForPullEnd() {
float exactContentHeight = FloatMath.floor(mRefreshableView.getContentHeight() * mRefreshableView.getScale());
float exactContentHeight = (float) Math.floor(mRefreshableView.getContentHeight() * mRefreshableView.getScale());
return mRefreshableView.getScrollY() >= (exactContentHeight - mRefreshableView.getHeight());
}
@ -158,7 +157,7 @@ public class PullToRefreshWebView extends PullToRefreshBase<WebView> {
}
private int getScrollRange() {
return (int) Math.max(0, FloatMath.floor(mRefreshableView.getContentHeight() * mRefreshableView.getScale())
return (int) Math.max(0, Math.floor(mRefreshableView.getContentHeight() * mRefreshableView.getScale())
- (getHeight() - getPaddingBottom() - getPaddingTop()));
}
}

View File

@ -14,7 +14,7 @@ abstract class SubsonicAPIClientTest {
@Before
fun setUp() {
client = SubsonicAPIClient(mockWebServerRule.mockWebServer.url("/").toString(), USERNAME, PASSWORD,
CLIENT_VERSION, CLIENT_ID)
client = SubsonicAPIClient(mockWebServerRule.mockWebServer.url("/").toString(),
USERNAME, PASSWORD, CLIENT_VERSION, CLIENT_ID)
}
}

View File

@ -50,16 +50,18 @@ class SubsonicApiGetAlbumTest : SubsonicAPIClientTest() {
year `should equal to` 2008
genre `should equal to` "Hard Rock"
songList.size `should equal to` 15
songList[0] `should equal` MusicDirectoryChild(id = "6491", parent = "6475", isDir = false,
title = "Rock 'n' Roll Train", album = "Black Ice", artist = "AC/DC",
track = 1, year = 2008, genre = "Hard Rock", coverArt = "6475", size = 7205451,
contentType = "audio/mpeg", suffix = "mp3", duration = 261, bitRate = 219,
path = "AC_DC/Black Ice/01 Rock 'n' Roll Train.mp3", isVideo = false,
playCount = 0, discNumber = 1, created = parseDate("2016-10-23T15:31:20.000Z"),
songList[0] `should equal` MusicDirectoryChild(id = "6491", parent = "6475",
isDir = false, title = "Rock 'n' Roll Train", album = "Black Ice",
artist = "AC/DC", track = 1, year = 2008, genre = "Hard Rock",
coverArt = "6475", size = 7205451, contentType = "audio/mpeg", suffix = "mp3",
duration = 261, bitRate = 219,
path = "AC_DC/Black Ice/01 Rock 'n' Roll Train.mp3",
isVideo = false, playCount = 0, discNumber = 1,
created = parseDate("2016-10-23T15:31:20.000Z"),
albumId = "618", artistId = "362", type = "music")
songList[5] `should equal` MusicDirectoryChild(id = "6492", parent = "6475", isDir = false,
title = "Smash 'n' Grab", album = "Black Ice", artist = "AC/DC", track = 6,
year = 2008, genre = "Hard Rock", coverArt = "6475", size = 6697204,
songList[5] `should equal` MusicDirectoryChild(id = "6492", parent = "6475",
isDir = false, title = "Smash 'n' Grab", album = "Black Ice", artist = "AC/DC",
track = 6, year = 2008, genre = "Hard Rock", coverArt = "6475", size = 6697204,
contentType = "audio/mpeg", suffix = "mp3", duration = 246, bitRate = 216,
path = "AC_DC/Black Ice/06 Smash 'n' Grab.mp3", isVideo = false, playCount = 0,
discNumber = 1, created = parseDate("2016-10-23T15:31:20.000Z"),

View File

@ -37,11 +37,14 @@ class SubsonicApiGetArtistsTest : SubsonicAPIClientTest() {
indexList `should equal` listOf(
Index(name = "A", artists = listOf(
Artist(id = "362", name = "AC/DC", coverArt = "ar-362", albumCount = 2),
Artist(id = "254", name = "Acceptance", coverArt = "ar-254", albumCount = 1)
Artist(id = "254", name = "Acceptance", coverArt = "ar-254",
albumCount = 1)
)),
Index(name = "T", artists = listOf(
Artist(id = "516", name = "Tangerine Dream", coverArt = "ar-516", albumCount = 1),
Artist(id = "242", name = "Taproot", coverArt = "ar-242", albumCount = 2)
Artist(id = "516", name = "Tangerine Dream", coverArt = "ar-516",
albumCount = 1),
Artist(id = "242", name = "Taproot", coverArt = "ar-242",
albumCount = 2)
))
)
}

View File

@ -50,19 +50,21 @@ class SubsonicApiGetMusicDirectoryTest : SubsonicAPIClientTest() {
starred `should equal` null
playCount `should equal to` 1
childList.size `should be` 2
childList[0] `should equal` MusicDirectoryChild(id = "4844", parent = "4836", isDir = false,
title = "Crash", album = "12 Stones", artist = "12 Stones", track = 1, year = 2002,
genre = "Alternative Rock", coverArt = "4836", size = 5348318L,
contentType = "audio/mpeg", suffix = "mp3", duration = 222, bitRate = 192,
path = "12 Stones/12 Stones/01 Crash.mp3", isVideo = false, playCount = 0,
discNumber = 1, created = parseDate("2016-10-23T15:19:10.000Z"),
childList[0] `should equal` MusicDirectoryChild(id = "4844", parent = "4836",
isDir = false, title = "Crash", album = "12 Stones", artist = "12 Stones",
track = 1, year = 2002, genre = "Alternative Rock", coverArt = "4836",
size = 5348318L, contentType = "audio/mpeg", suffix = "mp3", duration = 222,
bitRate = 192, path = "12 Stones/12 Stones/01 Crash.mp3", isVideo = false,
playCount = 0, discNumber = 1,
created = parseDate("2016-10-23T15:19:10.000Z"),
albumId = "454", artistId = "288", type = "music")
childList[1] `should equal` MusicDirectoryChild(id = "4845", parent = "4836", isDir = false,
title = "Broken", album = "12 Stones", artist = "12 Stones", track = 2, year = 2002,
genre = "Alternative Rock", coverArt = "4836", size = 4309043L,
contentType = "audio/mpeg", suffix = "mp3", duration = 179, bitRate = 192,
path = "12 Stones/12 Stones/02 Broken.mp3", isVideo = false, playCount = 0,
discNumber = 1, created = parseDate("2016-10-23T15:19:09.000Z"),
childList[1] `should equal` MusicDirectoryChild(id = "4845", parent = "4836",
isDir = false, title = "Broken", album = "12 Stones", artist = "12 Stones",
track = 2, year = 2002, genre = "Alternative Rock", coverArt = "4836",
size = 4309043L, contentType = "audio/mpeg", suffix = "mp3", duration = 179,
bitRate = 192, path = "12 Stones/12 Stones/02 Broken.mp3", isVideo = false,
playCount = 0, discNumber = 1,
created = parseDate("2016-10-23T15:19:09.000Z"),
albumId = "454", artistId = "288", type = "music")
}
}

View File

@ -33,13 +33,16 @@ class SubsonicApiGetPodcastsTest : SubsonicAPIClientTest() {
id `should equal to` "2"
url `should equal to` "http://feeds.codenewbie.org/cnpodcast.xml"
title `should equal to` "CodeNewbie"
description `should equal to` "Stories and interviews from people on their coding journey."
description `should equal to` "Stories and interviews from people on their coding " +
"journey."
coverArt `should equal to` "pod-2"
originalImageUrl `should equal to` "http://codenewbie.blubrry.com/wp-content/uploads/powerpress/220808.jpg"
originalImageUrl `should equal to` "http://codenewbie.blubrry.com/wp-content/uploads/" +
"powerpress/220808.jpg"
status `should equal to` "completed"
errorMessage `should equal to` ""
episodeList.size `should equal to` 10
episodeList[0] `should equal` MusicDirectoryChild(id = "148", parent = "9959", isDir = false,
episodeList[0] `should equal` MusicDirectoryChild(id = "148", parent = "9959",
isDir = false,
title = "S1:EP3 How to teach yourself computer science (Vaidehi Joshi)",
album = "CodeNewbie", artist = "podcasts", coverArt = "9959",
size = 38274221, contentType = "audio/mpeg", suffix = "mp3",
@ -56,7 +59,8 @@ class SubsonicApiGetPodcastsTest : SubsonicAPIClientTest() {
"CodeNewbie basecs 100 Days of Code Conway's Game of Life Hexes and " +
"Other Magical Numbers (Vaidehi's blog post) Bits, Bytes, Building " +
"With Binary (Vaidehi's blog post) Rust",
status = "completed", publishDate = parseDate("2017-08-29T00:01:01.000Z"))
status = "completed",
publishDate = parseDate("2017-08-29T00:01:01.000Z"))
}
}

View File

@ -39,8 +39,10 @@ class SubsonicApiGetSongsByGenreTest : SubsonicAPIClientTest() {
artist = "DJ Polyakov PPK Feat Kate Cameron", year = 2009, genre = "Trance",
size = 26805932, contentType = "audio/mpeg", suffix = "mp3", duration = 670,
bitRate = 320,
path = "DJ Polyakov PPK Feat Kate Cameron/668/00 My Heart (Vadim Zhukov Remix).mp3",
isVideo = false, playCount = 2, created = parseDate("2016-10-23T21:58:29.000Z"),
path = "DJ Polyakov PPK Feat Kate Cameron/668/00 My Heart (Vadim Zhukov " +
"Remix).mp3",
isVideo = false, playCount = 2,
created = parseDate("2016-10-23T21:58:29.000Z"),
albumId = "5", artistId = "4", type = "music")
}
}

View File

@ -27,11 +27,13 @@ class SubsonicApiGetVideosListTest : SubsonicAPIClientTest() {
assertResponseSuccessful(response)
with(response.body().videosList) {
size `should equal to` 1
this[0] `should equal` MusicDirectoryChild(id = "10402", parent = "10401", isDir = false,
title = "MVI_0512", album = "Incoming", size = 21889646,
contentType = "video/avi", suffix = "avi", transcodedContentType = "video/x-flv",
transcodedSuffix = "flv", path = "Incoming/MVI_0512.avi", isVideo = true,
playCount = 0, created = parseDate("2017-11-19T12:34:33.000Z"), type = "video")
this[0] `should equal` MusicDirectoryChild(id = "10402", parent = "10401",
isDir = false, title = "MVI_0512", album = "Incoming", size = 21889646,
contentType = "video/avi", suffix = "avi",
transcodedContentType = "video/x-flv", transcodedSuffix = "flv",
path = "Incoming/MVI_0512.avi", isVideo = true,
playCount = 0, created = parseDate("2017-11-19T12:34:33.000Z"),
type = "video")
}
}
}

View File

@ -56,8 +56,8 @@ class SubsonicApiJukeboxControlTest : SubsonicAPIClientTest() {
artist = "The Pretty Reckless", track = 2, year = 2014, genre = "Hard Rock",
coverArt = "4186", size = 11089627, contentType = "audio/mpeg",
suffix = "mp3", duration = 277, bitRate = 320,
path = "The Pretty Reckless/Going to Hell/02 Going to Hell.mp3", isVideo = false,
playCount = 0, discNumber = 1,
path = "The Pretty Reckless/Going to Hell/02 Going to Hell.mp3",
isVideo = false, playCount = 0, discNumber = 1,
created = parseDate("2016-10-23T21:30:41.000Z"), albumId = "388",
artistId = "238", type = "music")
}

View File

@ -10,8 +10,8 @@ import org.junit.Test
class SubsonicApiPasswordTest : SubsonicAPIClientTest() {
@Test
fun `Should pass PasswordMD5Interceptor in query params for api version 1 13 0`() {
val clientV12 = SubsonicAPIClient(mockWebServerRule.mockWebServer.url("/").toString(), USERNAME,
PASSWORD, SubsonicAPIVersions.V1_14_0, CLIENT_ID)
val clientV12 = SubsonicAPIClient(mockWebServerRule.mockWebServer.url("/").toString(),
USERNAME, PASSWORD, SubsonicAPIVersions.V1_14_0, CLIENT_ID)
mockWebServerRule.enqueueResponse("ping_ok.json")
clientV12.api.ping().execute()
@ -25,8 +25,8 @@ class SubsonicApiPasswordTest : SubsonicAPIClientTest() {
@Test
fun `Should pass PasswordHexInterceptor in query params for api version 1 12 0`() {
val clientV11 = SubsonicAPIClient(mockWebServerRule.mockWebServer.url("/").toString(), USERNAME,
PASSWORD, SubsonicAPIVersions.V1_12_0, CLIENT_ID)
val clientV11 = SubsonicAPIClient(mockWebServerRule.mockWebServer.url("/").toString(),
USERNAME, PASSWORD, SubsonicAPIVersions.V1_12_0, CLIENT_ID)
mockWebServerRule.enqueueResponse("ping_ok.json")
clientV11.api.ping().execute()

View File

@ -39,7 +39,8 @@ class SubsonicApiSearchTest : SubsonicAPIClientTest() {
track = 17, year = 2005, genre = "Rap", coverArt = "5766",
size = 5607024, contentType = "audio/mpeg", suffix = "mp3", duration = 233,
bitRate = 192,
path = "Compilations/Need for Speed Most Wanted/17 You'll Be Under My Wheels.mp3",
path = "Compilations/Need for Speed Most Wanted/17 You'll Be Under My Wheels" +
".mp3",
isVideo = false, playCount = 0, discNumber = 1,
created = parseDate("2016-10-23T20:09:02.000Z"), albumId = "568",
artistId = "505", type = "music")

View File

@ -32,20 +32,23 @@ class SubsonicApiSearchThreeTest : SubsonicAPIClientTest() {
assertResponseSuccessful(response)
with(response.body().searchResult) {
artistList.size `should equal to` 1
artistList[0] `should equal` Artist(id = "505", name = "The Prodigy", coverArt = "ar-505",
albumCount = 5)
artistList[0] `should equal` Artist(id = "505", name = "The Prodigy",
coverArt = "ar-505", albumCount = 5)
albumList.size `should equal to` 1
albumList[0] `should equal` Album(id = "855", name = "Always Outnumbered, Never Outgunned",
albumList[0] `should equal` Album(id = "855",
name = "Always Outnumbered, Never Outgunned",
artist = "The Prodigy", artistId = "505", coverArt = "al-855", songCount = 12,
duration = 3313, created = parseDate("2016-10-23T20:57:27.000Z"),
year = 2004, genre = "Electronic")
songList.size `should equal to` 1
songList[0] `should equal` MusicDirectoryChild(id = "5831", parent = "5766", isDir = false,
songList[0] `should equal` MusicDirectoryChild(id = "5831", parent = "5766",
isDir = false,
title = "You'll Be Under My Wheels", album = "Need for Speed Most Wanted",
artist = "The Prodigy", track = 17, year = 2005, genre = "Rap",
coverArt = "5766", size = 5607024, contentType = "audio/mpeg",
suffix = "mp3", duration = 233, bitRate = 192,
path = "Compilations/Need for Speed Most Wanted/17 You'll Be Under My Wheels.mp3",
path = "Compilations/Need for Speed Most Wanted/17 You'll Be Under My Wheels" +
".mp3",
isVideo = false, playCount = 0, discNumber = 1,
created = parseDate("2016-10-23T20:09:02.000Z"), albumId = "568",
artistId = "505", type = "music")
@ -56,9 +59,10 @@ class SubsonicApiSearchThreeTest : SubsonicAPIClientTest() {
fun `Should pass query as request param`() {
val query = "some-wip-query"
mockWebServerRule.assertRequestParam(responseResourceName = "search3_ok.json", apiRequest = {
mockWebServerRule.assertRequestParam(responseResourceName = "search3_ok.json",
expectedParam = "query=$query") {
client.api.search3(query = query).execute()
}, expectedParam = "query=$query")
}
}
@Test

View File

@ -33,18 +33,20 @@ class SubsonicApiSearchTwoTest : SubsonicAPIClientTest() {
artistList.size `should equal to` 1
artistList[0] `should equal` Artist(id = "522", name = "The Prodigy")
albumList.size `should equal to` 1
albumList[0] `should equal` MusicDirectoryChild(id = "8867", parent = "522", isDir = true,
title = "Always Outnumbered, Never Outgunned",
albumList[0] `should equal` MusicDirectoryChild(id = "8867", parent = "522",
isDir = true, title = "Always Outnumbered, Never Outgunned",
album = "Always Outnumbered, Never Outgunned", artist = "The Prodigy",
year = 2004, genre = "Electronic", coverArt = "8867", playCount = 0,
created = parseDate("2016-10-23T20:57:27.000Z"))
songList.size `should equal to` 1
songList[0] `should equal` MusicDirectoryChild(id = "5831", parent = "5766", isDir = false,
songList[0] `should equal` MusicDirectoryChild(id = "5831", parent = "5766",
isDir = false,
title = "You'll Be Under My Wheels", album = "Need for Speed Most Wanted",
artist = "The Prodigy", track = 17, year = 2005, genre = "Rap",
coverArt = "5766", size = 5607024, contentType = "audio/mpeg",
suffix = "mp3", duration = 233, bitRate = 192,
path = "Compilations/Need for Speed Most Wanted/17 You'll Be Under My Wheels.mp3",
path = "Compilations/Need for Speed Most Wanted/17 You'll Be Under My Wheels" +
".mp3",
isVideo = false, playCount = 0, discNumber = 1,
created = parseDate("2016-10-23T20:09:02.000Z"),
albumId = "568", artistId = "505", type = "music")

View File

@ -40,7 +40,8 @@ class VersionInterceptorTest : BaseInterceptorTest() {
client.newCall(createRequest {}).execute()
(interceptor as VersionInterceptor).protocolVersion `should equal` SubsonicAPIVersions.V1_13_0
(interceptor as VersionInterceptor)
.protocolVersion `should equal` SubsonicAPIVersions.V1_13_0
}
@Test

View File

@ -271,7 +271,9 @@ internal class ApiVersionCheckWrapper(
return api.getBookmarks()
}
override fun createBookmark(id: String, position: Long, comment: String?): Call<SubsonicResponse> {
override fun createBookmark(id: String,
position: Long,
comment: String?): Call<SubsonicResponse> {
checkVersion(V1_9_0)
return api.createBookmark(id, position, comment)
}

View File

@ -127,7 +127,8 @@ interface SubsonicAPIDefinition {
@Query("comment") comment: String? = null,
@Query("public") public: Boolean? = null,
@Query("songIdToAdd") songIdsToAdd: List<String>? = null,
@Query("songIndexToRemove") songIndexesToRemove: List<Int>? = null): Call<SubsonicResponse>
@Query("songIndexToRemove") songIndexesToRemove: List<Int>? = null):
Call<SubsonicResponse>
@GET("getPodcasts.view")
fun getPodcasts(@Query("includeEpisodes") includeEpisodes: Boolean? = null,
@ -143,35 +144,39 @@ interface SubsonicAPIDefinition {
@Query("submission") submission: Boolean? = null): Call<SubsonicResponse>
@GET("getAlbumList.view")
fun getAlbumList(@Query("type") type: AlbumListType,
@Query("size") size: Int? = null,
@Query("offset") offset: Int? = null,
@Query("fromYear") fromYear: Int? = null,
@Query("toYear") toYear: Int? = null,
@Query("genre") genre: String? = null,
@Query("musicFolderId") musicFolderId: String? = null): Call<GetAlbumListResponse>
fun getAlbumList(
@Query("type") type: AlbumListType,
@Query("size") size: Int? = null,
@Query("offset") offset: Int? = null,
@Query("fromYear") fromYear: Int? = null,
@Query("toYear") toYear: Int? = null,
@Query("genre") genre: String? = null,
@Query("musicFolderId") musicFolderId: String? = null): Call<GetAlbumListResponse>
@GET("getAlbumList2.view")
fun getAlbumList2(@Query("type") type: AlbumListType,
@Query("size") size: Int? = null,
@Query("offset") offset: Int? = null,
@Query("fromYear") fromYear: Int? = null,
@Query("toYear") toYear: Int? = null,
@Query("genre") genre: String? = null,
@Query("musicFolderId") musicFolderId: String? = null): Call<GetAlbumList2Response>
fun getAlbumList2(
@Query("type") type: AlbumListType,
@Query("size") size: Int? = null,
@Query("offset") offset: Int? = null,
@Query("fromYear") fromYear: Int? = null,
@Query("toYear") toYear: Int? = null,
@Query("genre") genre: String? = null,
@Query("musicFolderId") musicFolderId: String? = null): Call<GetAlbumList2Response>
@GET("getRandomSongs.view")
fun getRandomSongs(@Query("size") size: Int? = null,
@Query("genre") genre: String? = null,
@Query("fromYear") fromYear: Int? = null,
@Query("toYear") toYear: Int? = null,
@Query("musicFolderId") musicFolderId: String? = null): Call<GetRandomSongsResponse>
fun getRandomSongs(
@Query("size") size: Int? = null,
@Query("genre") genre: String? = null,
@Query("fromYear") fromYear: Int? = null,
@Query("toYear") toYear: Int? = null,
@Query("musicFolderId") musicFolderId: String? = null): Call<GetRandomSongsResponse>
@GET("getStarred.view")
fun getStarred(@Query("musicFolderId") musicFolderId: String? = null): Call<GetStarredResponse>
@GET("getStarred2.view")
fun getStarred2(@Query("musicFolderId") musicFolderId: String? = null): Call<GetStarredTwoResponse>
fun getStarred2(
@Query("musicFolderId") musicFolderId: String? = null): Call<GetStarredTwoResponse>
@Streaming
@GET("getCoverArt.view")

View File

@ -55,7 +55,8 @@ enum class SubsonicAPIVersions(val subsonicVersions: String, val restApiVersion:
}
class SubsonicAPIVersionsDeserializer : JsonDeserializer<SubsonicAPIVersions>() {
override fun deserialize(p: JsonParser, ctxt: DeserializationContext?): SubsonicAPIVersions {
override fun deserialize(p: JsonParser,
ctxt: DeserializationContext?): SubsonicAPIVersions {
if (p.currentName != "version") {
throw JsonParseException(p, "Not valid token for API version!")
}

View File

@ -36,6 +36,6 @@ internal class RangeHeaderInterceptor : Interceptor {
// to avoid the thrashing effect seen when offset is combined with transcoding/downsampling
// on the server. In that case, the server uses a long time before sending any data,
// causing the client to time out.
private fun getReadTimeout(offset: Int)
= (SOCKET_READ_TIMEOUT_DOWNLOAD + offset * TIMEOUT_MILLIS_PER_OFFSET_BYTE).toInt()
private fun getReadTimeout(offset: Int) =
(SOCKET_READ_TIMEOUT_DOWNLOAD + offset * TIMEOUT_MILLIS_PER_OFFSET_BYTE).toInt()
}

View File

@ -2,6 +2,7 @@ package org.moire.ultrasonic.api.subsonic.models
import com.fasterxml.jackson.annotation.JsonProperty
data class SearchResult(val offset: Int = 0,
val totalHits: Int = 0,
@JsonProperty("match") val matchList: List<MusicDirectoryChild> = emptyList())
data class SearchResult(
val offset: Int = 0,
val totalHits: Int = 0,
@JsonProperty("match") val matchList: List<MusicDirectoryChild> = emptyList())

View File

@ -16,4 +16,5 @@ class GetPlaylistsResponse(status: Status,
get() = playlistsWrapper.playlistList
}
private class PlaylistsWrapper(@JsonProperty("playlist") val playlistList: List<Playlist> = emptyList())
private class PlaylistsWrapper(
@JsonProperty("playlist") val playlistList: List<Playlist> = emptyList())

View File

@ -5,8 +5,9 @@ import org.moire.ultrasonic.api.subsonic.SubsonicAPIVersions
import org.moire.ultrasonic.api.subsonic.SubsonicError
import org.moire.ultrasonic.api.subsonic.models.SearchTwoResult
class SearchTwoResponse(status: Status,
version: SubsonicAPIVersions,
error: SubsonicError?,
@JsonProperty("searchResult2") val searchResult: SearchTwoResult = SearchTwoResult())
class SearchTwoResponse(
status: Status,
version: SubsonicAPIVersions,
error: SubsonicError?,
@JsonProperty("searchResult2") val searchResult: SearchTwoResult = SearchTwoResult())
: SubsonicResponse(status, version, error)

View File

@ -5,7 +5,6 @@ apply from: "../gradle_scripts/code_quality.gradle"
android {
compileSdkVersion versions.compileSdk
buildToolsVersion versions.buildTools
defaultConfig {
applicationId "org.moire.ultrasonic"
@ -42,21 +41,21 @@ android {
}
dependencies {
compile project(':menudrawer')
compile project(':pulltorefresh')
compile project(':library')
compile project(':subsonic-api')
implementation project(':menudrawer')
implementation project(':pulltorefresh')
implementation project(':library')
implementation project(':subsonic-api')
compile androidSupport.support
compile androidSupport.design
implementation androidSupport.support
implementation androidSupport.design
compile other.kotlinStdlib
implementation other.kotlinStdlib
testCompile other.kotlinReflect
testCompile testing.junit
testCompile testing.kotlinJunit
testCompile testing.mockitoKotlin
testCompile testing.kluent
testImplementation other.kotlinReflect
testImplementation testing.junit
testImplementation testing.kotlinJunit
testImplementation testing.mockitoKotlin
testImplementation testing.kluent
}
// Excluding all non-kotlin classes

File diff suppressed because it is too large Load Diff

View File

@ -2071,6 +2071,7 @@ public class DownloadServiceImpl extends Service implements DownloadService
}
}
@SuppressWarnings("IconColors")
private Notification buildForegroundNotification() {
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
builder.setSmallIcon(R.drawable.ic_stat_ultrasonic);

View File

@ -21,7 +21,6 @@ package org.moire.ultrasonic.service;
import android.content.Context;
import android.graphics.Bitmap;
import org.apache.http.HttpResponse;
import org.moire.ultrasonic.domain.Bookmark;
import org.moire.ultrasonic.domain.ChatMessage;
import org.moire.ultrasonic.domain.Genre;

View File

@ -6,9 +6,6 @@ import org.moire.ultrasonic.domain.MusicDirectory;
import org.moire.ultrasonic.service.DownloadFile;
import org.moire.ultrasonic.service.DownloadService;
import org.apache.http.HttpRequest;
import org.apache.http.message.BasicHttpRequest;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
@ -108,81 +105,66 @@ public class StreamProxy implements Runnable
Log.i(TAG, "Proxy interrupted. Shutting down.");
}
private class StreamToMediaPlayerTask implements Runnable
{
private class StreamToMediaPlayerTask implements Runnable {
String localPath;
Socket client;
int cbSkip;
String localPath;
Socket client;
int cbSkip;
StreamToMediaPlayerTask(Socket client) {
this.client = client;
}
public StreamToMediaPlayerTask(Socket client)
{
this.client = client;
}
private String readRequest() {
InputStream is;
String firstLine;
try {
is = client.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(is), 8192);
firstLine = reader.readLine();
} catch (IOException e) {
Log.e(TAG, "Error parsing request", e);
return null;
}
private HttpRequest readRequest()
{
HttpRequest request;
InputStream is;
String firstLine;
try
{
is = client.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(is), 8192);
firstLine = reader.readLine();
}
catch (IOException e)
{
Log.e(TAG, "Error parsing request", e);
return null;
}
if (firstLine == null) {
Log.i(TAG, "Proxy client closed connection without a request.");
return null;
}
if (firstLine == null)
{
Log.i(TAG, "Proxy client closed connection without a request.");
return null;
}
StringTokenizer st = new StringTokenizer(firstLine);
st.nextToken(); // method
String uri = st.nextToken();
String realUri = uri.substring(1);
Log.i(TAG, realUri);
StringTokenizer st = new StringTokenizer(firstLine);
String method = st.nextToken();
String uri = st.nextToken();
String realUri = uri.substring(1);
Log.i(TAG, realUri);
request = new BasicHttpRequest(method, realUri);
return request;
}
return realUri;
}
public boolean processRequest()
{
HttpRequest request = readRequest();
if (request == null)
{
return false;
}
boolean processRequest() {
final String uri = readRequest();
if (uri == null || uri.isEmpty()) {
return false;
}
// Read HTTP headers
Log.i(TAG, "Processing request");
// Read HTTP headers
Log.i(TAG, "Processing request: " + uri);
try
{
localPath = URLDecoder.decode(request.getRequestLine().getUri(), Constants.UTF_8);
}
catch (UnsupportedEncodingException e)
{
Log.e(TAG, "Unsupported encoding", e);
return false;
}
try {
localPath = URLDecoder.decode(uri, Constants.UTF_8);
} catch (UnsupportedEncodingException e) {
Log.e(TAG, "Unsupported encoding", e);
return false;
}
Log.i(TAG, String.format("Processing request for file %s", localPath));
File file = new File(localPath);
if (!file.exists())
{
Log.e(TAG, String.format("File %s does not exist", localPath));
return false;
}
Log.i(TAG, String.format("Processing request for file %s", localPath));
File file = new File(localPath);
if (!file.exists()) {
Log.e(TAG, String.format("File %s does not exist", localPath));
return false;
}
return true;
}
return true;
}
@Override
public void run()

View File

@ -65,8 +65,6 @@ import org.moire.ultrasonic.receiver.MediaButtonIntentReceiver;
import org.moire.ultrasonic.service.DownloadFile;
import org.moire.ultrasonic.service.DownloadService;
import org.moire.ultrasonic.service.DownloadServiceImpl;
import org.apache.http.HttpEntity;
import org.moire.ultrasonic.service.MusicServiceFactory;
import java.io.ByteArrayOutputStream;
@ -405,15 +403,6 @@ public class Util extends DownloadActivity
return context.getSharedPreferences(Constants.PREFERENCES_FILE_NAME, 0);
}
public static String getContentType(HttpEntity entity)
{
if (entity == null || entity.getContentType() == null)
{
return null;
}
return entity.getContentType().getValue();
}
public static int getRemainingTrialDays(Context context)
{
SharedPreferences preferences = getPreferences(context);

View File

@ -8,5 +8,5 @@ import org.moire.ultrasonic.api.subsonic.models.MusicFolder as APIMusicFolder
fun APIMusicFolder.toDomainEntity(): MusicFolder = MusicFolder(this.id, this.name)
fun List<APIMusicFolder>.toDomainEntityList(): List<MusicFolder>
= this.map { it.toDomainEntity() }
fun List<APIMusicFolder>.toDomainEntityList(): List<MusicFolder> =
this.map { it.toDomainEntity() }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 673 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 715 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 729 B

After

Width:  |  Height:  |  Size: 673 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 382 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 355 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 390 B

After

Width:  |  Height:  |  Size: 382 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 480 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 497 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 472 B

After

Width:  |  Height:  |  Size: 480 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 926 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 937 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 930 B

After

Width:  |  Height:  |  Size: 926 B

View File

@ -15,7 +15,7 @@
a:layout_width="fill_parent"
a:layout_height="fill_parent"
a:layout_weight="1"
a:gravity="left"
a:gravity="start"
a:orientation="vertical" >
<ImageView

View File

@ -325,7 +325,7 @@
<string name="util.bytes_format.gigabyte">0.00 Go</string>
<string name="util.bytes_format.kilobyte">0 Ko</string>
<string name="util.bytes_format.megabyte">0.00 Mo</string>
<string name="util.no_time">-:--</string>
<string name="util.no_time">&#8212;:&#8212;&#8212;</string>
<string name="util.zero_time">0:00</string>
<string name="video.get_mx_player_text">MX Player n\'est pas installé. Recevez gratuitement sur Play Store, ou modifier les paramètres vidéo.</string>
<string name="video.get_mx_player_button">Obtenez MX Player</string>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<resources xmlns:tools="http://schemas.android.com/tools">
<string name="background_task.loading">Carregando&#8230;</string>
<string name="background_task.network_error">Ocorreu um erro de rede. Verifique o endereço do servidor ou tente mais tarde.</string>
@ -328,7 +328,7 @@
<string name="util.bytes_format.gigabyte">0.00 GB</string>
<string name="util.bytes_format.kilobyte">0 KB</string>
<string name="util.bytes_format.megabyte">0.00 MB</string>
<string name="util.no_time">-:--</string>
<string name="util.no_time">&#8212;:&#8212;&#8212;</string>
<string name="util.zero_time">0:00</string>
<string name="video.get_mx_player_text">O player MX não está instalado. Descarregue da graça pela Play Store ou modifique as configurações de vídeo.</string>
<string name="video.get_mx_player_button">Descarregar Player MX</string>
@ -393,33 +393,33 @@
<string name="albumArt">albumArt</string>
<string name="common_multiple_years">Múltiplos Anos</string>
<plurals name="select_album_n_songs">
<plurals name="select_album_n_songs" tools:ignore="UnusedQuantity">
<item quantity="zero">Nenhuma música</item>
<item quantity="one">1 música</item>
<item quantity="one">%d música</item>
<item quantity="other">%d músicas</item>
</plurals>
<plurals name="select_album_n_songs_pinned">
<item quantity="one">1 música selecionada para ser fixada.</item>
<item quantity="one">%d música selecionada para ser fixada.</item>
<item quantity="other">%d músicas selecionadas para serem fixadas.</item>
</plurals>
<plurals name="select_album_n_songs_downloaded">
<item quantity="one">1 música selecionada para descarregar.</item>
<item quantity="one">%d música selecionada para descarregar.</item>
<item quantity="other">%d músicas selecionadas para serem descarregadas.</item>
</plurals>
<plurals name="select_album_n_songs_unpinned">
<item quantity="one">1 música selecionada para ser desafixada.</item>
<item quantity="one">%d música selecionada para ser desafixada.</item>
<item quantity="other">%d músicas selecionadas para serem desfixadas.</item>
</plurals>
<plurals name="select_album_n_songs_added">
<item quantity="one">1 música adicionada ao fim da fila.</item>
<item quantity="one">%d música adicionada ao fim da fila.</item>
<item quantity="other">%d músicas adicionadas ao fim da fila.</item>
</plurals>
<plurals name="select_album_n_songs_play_next">
<item quantity="one">1 música inserida após a atual.</item>
<item quantity="one">%d música inserida após a atual.</item>
<item quantity="other">%d músicas inseridas após a atual.</item>
</plurals>
<plurals name="select_album_donate_dialog_n_trial_days_left">
<item quantity="one">Resta 1 dia para o fim do período de teste</item>
<item quantity="one">Resta %d dia para o fim do período de teste</item>
<item quantity="other">Restam %d dias para o fim do período de teste</item>
</plurals>

View File

@ -15,9 +15,9 @@ import java.util.Calendar
class APIAlbumConverterTest {
@Test
fun `Should convert Album to domain entity`() {
val entity = Album(id = "387", name = "some-name", coverArt = "asdas", artist = "some-artist",
artistId = "390", songCount = 12, duration = 841, created = Calendar.getInstance(),
year = 2017, genre = "some-genre")
val entity = Album(id = "387", name = "some-name", coverArt = "asdas",
artist = "some-artist", artistId = "390", songCount = 12, duration = 841,
created = Calendar.getInstance(), year = 2017, genre = "some-genre")
val convertedEntity = entity.toDomainEntity()

View File

@ -27,7 +27,8 @@ class APIArtistConverterTest {
@Test
fun `Should convert Artist entity to domain MusicDirectory entity`() {
val entity = Artist(id = "101", name = "artist-name", coverArt = "some-art", albumCount = 10,
val entity = Artist(id = "101", name = "artist-name", coverArt = "some-art",
albumCount = 10,
albumsList = listOf(Album(id = "562", name = "some-name", coverArt = "zzz",
artist = "artist-name", artistId = "256", songCount = 10, duration = 345,
created = Calendar.getInstance(), year = 2011, genre = "Math Rock")))

View File

@ -16,8 +16,8 @@ class APIIndexesConverterTest {
@Test
fun `Should convert Indexes entity`() {
val artistsA = listOf(
Artist(id ="4", name = "AC/DC"),
Artist(id ="45", name = "ABBA"))
Artist(id = "4", name = "AC/DC"),
Artist(id = "45", name = "ABBA"))
val artistsT = listOf(
Artist(id = "10", name = "Taproot"),
Artist(id = "12", name = "Teebee"))

View File

@ -37,7 +37,8 @@ class APIMusicDirectoryConverterTest {
transcodedContentType = "some-transcoded-content-type",
transcodedSuffix = "some-transcoded-suffix", duration = 11, bitRate = 256,
path = "some-path", isDir = true, isVideo = true, playCount = 323, discNumber = 2,
created = Calendar.getInstance(), type = "some-type", starred = Calendar.getInstance())
created = Calendar.getInstance(), type = "some-type",
starred = Calendar.getInstance())
val convertedEntity = entity.toDomainEntity()