mirror of
https://github.com/clangen/musikcube.git
synced 2025-02-21 21:40:48 +00:00
Upgrade musikdroid dependencies and build tooling.
This commit is contained in:
parent
cdc9242cb3
commit
9ebf93b155
@ -12,14 +12,14 @@ apply plugin: 'kotlin-kapt'
|
||||
apply plugin: 'com.google.firebase.crashlytics'
|
||||
|
||||
android {
|
||||
compileSdkVersion 29
|
||||
compileSdkVersion 30
|
||||
|
||||
defaultConfig {
|
||||
applicationId "io.casey.musikcube.remote"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 29
|
||||
targetSdkVersion 30
|
||||
versionCode 109
|
||||
versionName "0.94.0"
|
||||
versionName "0.96.6"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
||||
@ -61,9 +61,9 @@ dependencies {
|
||||
exclude group: 'com.android.support', module: 'support-annotations'
|
||||
})
|
||||
|
||||
implementation 'com.google.firebase:firebase-analytics:17.6.0'
|
||||
implementation 'com.google.firebase:firebase-core:17.5.1'
|
||||
implementation 'com.google.firebase:firebase-crashlytics:17.2.2'
|
||||
implementation 'com.google.firebase:firebase-analytics:18.0.3'
|
||||
implementation 'com.google.firebase:firebase-core:18.0.3'
|
||||
implementation 'com.google.firebase:firebase-crashlytics:17.4.1'
|
||||
|
||||
implementation(name:'android-taskrunner-0.5', ext:'aar')
|
||||
implementation(name:'exoplayer-extension-flac-release-v2', ext:'aar')
|
||||
@ -71,34 +71,34 @@ dependencies {
|
||||
|
||||
implementation 'org.slf4j:slf4j-android:1.7.21'
|
||||
|
||||
implementation "androidx.room:room-runtime:2.2.5"
|
||||
kapt "androidx.room:room-compiler:2.2.5"
|
||||
implementation "androidx.room:room-runtime:2.2.6"
|
||||
kapt "androidx.room:room-compiler:2.2.6"
|
||||
|
||||
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.2.0"
|
||||
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.3.1"
|
||||
implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
|
||||
implementation "androidx.lifecycle:lifecycle-common-java8:2.2.0"
|
||||
implementation "androidx.lifecycle:lifecycle-common-java8:2.3.1"
|
||||
|
||||
compileOnly 'org.glassfish:javax.annotation:10.0-b28'
|
||||
implementation 'com.google.dagger:dagger:2.27'
|
||||
kapt 'com.google.dagger:dagger-compiler:2.27'
|
||||
|
||||
implementation 'com.neovisionaries:nv-websocket-client:1.31'
|
||||
implementation 'com.squareup.okhttp3:okhttp:3.12.8'
|
||||
implementation 'com.squareup.okhttp3:okhttp:3.12.11'
|
||||
implementation 'com.github.bumptech.glide:glide:4.10.0'
|
||||
implementation "com.github.bumptech.glide:okhttp3-integration:4.10.0"
|
||||
kapt 'com.github.bumptech.glide:compiler:4.10.0'
|
||||
implementation 'io.reactivex.rxjava2:rxjava:2.2.16'
|
||||
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
|
||||
implementation 'io.reactivex.rxjava2:rxkotlin:2.4.0'
|
||||
implementation 'com.google.android.exoplayer:exoplayer:2.11.4'
|
||||
implementation 'com.google.android.exoplayer:extension-okhttp:2.11.4'
|
||||
implementation 'com.google.android.exoplayer:exoplayer:2.13.3'
|
||||
implementation 'com.google.android.exoplayer:extension-okhttp:2.13.3'
|
||||
implementation 'com.simplecityapps:recyclerview-fastscroll:2.0.0'
|
||||
implementation 'me.zhanghai.android.materialprogressbar:library:1.6.1'
|
||||
|
||||
implementation 'androidx.appcompat:appcompat:1.2.0'
|
||||
implementation 'androidx.recyclerview:recyclerview:1.1.0'
|
||||
implementation 'com.google.android.material:material:1.3.0-alpha03'
|
||||
implementation 'androidx.media:media:1.2.0'
|
||||
implementation 'androidx.recyclerview:recyclerview:1.2.0'
|
||||
implementation 'com.google.android.material:material:1.4.0-alpha02'
|
||||
implementation 'androidx.media:media:1.3.0'
|
||||
|
||||
testImplementation 'junit:junit:4.12'
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
|
@ -1,26 +0,0 @@
|
||||
package io.casey.musikcube.remote;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.test.InstrumentationRegistry;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Instrumentation test, which will execute on an Android device.
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ExampleInstrumentedTest {
|
||||
@Test
|
||||
public void useAppContext() throws Exception {
|
||||
// Context of the app under test.
|
||||
Context appContext = InstrumentationRegistry.getTargetContext();
|
||||
|
||||
assertEquals("io.casey.musikcube.remote", appContext.getPackageName());
|
||||
}
|
||||
}
|
@ -57,7 +57,7 @@ abstract class ViewModel<T>(protected val runner: Runner? = null): Runner.TaskCa
|
||||
}
|
||||
|
||||
open fun createSubject(): Subject<T> {
|
||||
return PublishSubject.create<T>()
|
||||
return PublishSubject.create()
|
||||
}
|
||||
|
||||
override fun onTaskError(name: String?, id: Long, task: Task<*, *>?, error: Throwable?) {
|
||||
|
@ -29,7 +29,7 @@ class GlideModule : AppGlideModule() {
|
||||
if (serverHost == requestHost) {
|
||||
val userPass = "default:" + prefs.getString(Prefs.Key.PASSWORD, Prefs.Default.PASSWORD)!!
|
||||
val encoded = Base64.encodeToString(userPass.toByteArray(), Base64.NO_WRAP)
|
||||
request = req.newBuilder().addHeader("Authorization", "Basic " + encoded).build()
|
||||
request = req.newBuilder().addHeader("Authorization", "Basic $encoded").build()
|
||||
} else if (canInterceptArtwork(req)) {
|
||||
request = interceptArtwork(req)
|
||||
}
|
||||
|
@ -43,8 +43,8 @@ class GaplessHeaderService {
|
||||
thread.start()
|
||||
|
||||
handler = object : Handler(thread.looper) {
|
||||
override fun handleMessage(msg: Message?) {
|
||||
if (msg?.what == MESSAGE_PROCESS) {
|
||||
override fun handleMessage(msg: Message) {
|
||||
if (msg.what == MESSAGE_PROCESS) {
|
||||
db.dao().queryByState(GaplessTrack.DOWNLOADED).forEach { process(it) }
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package io.casey.musikcube.remote.service.playback.impl.player
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.net.Uri
|
||||
import com.danikula.videocache.CacheListener
|
||||
import com.google.android.exoplayer2.*
|
||||
import com.google.android.exoplayer2.source.ConcatenatingMediaSource
|
||||
@ -13,7 +12,7 @@ import com.google.android.exoplayer2.trackselection.TrackSelectionArray
|
||||
import com.google.android.exoplayer2.upstream.DataSource
|
||||
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter
|
||||
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory
|
||||
import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory
|
||||
import com.google.android.exoplayer2.upstream.DefaultHttpDataSource
|
||||
import com.google.android.exoplayer2.util.Util
|
||||
import io.casey.musikcube.remote.Application
|
||||
import io.casey.musikcube.remote.service.playback.PlayerWrapper
|
||||
@ -39,8 +38,12 @@ class GaplessExoPlayerWrapper : PlayerWrapper() {
|
||||
init {
|
||||
val userAgent = Util.getUserAgent(context, "musikdroid")
|
||||
|
||||
val httpFactory: DataSource.Factory = DefaultHttpDataSourceFactory(
|
||||
userAgent, null, TIMEOUT, TIMEOUT, true)
|
||||
val httpFactory: DataSource.Factory = DefaultHttpDataSource.Factory().apply {
|
||||
setUserAgent(userAgent)
|
||||
setConnectTimeoutMs(TIMEOUT)
|
||||
setReadTimeoutMs(TIMEOUT)
|
||||
setAllowCrossProtocolRedirects(true)
|
||||
}
|
||||
|
||||
this.sourceFactory = DefaultDataSourceFactory(context, null, httpFactory)
|
||||
|
||||
@ -52,17 +55,18 @@ class GaplessExoPlayerWrapper : PlayerWrapper() {
|
||||
|
||||
if (!dead()) {
|
||||
removeAllAndReset()
|
||||
val proxyUri = streamProxy.getProxyUrl(uri)
|
||||
|
||||
this.metadata = metadata
|
||||
this.originalUri = uri
|
||||
this.proxyUri = streamProxy.getProxyUrl(uri)
|
||||
this.proxyUri = proxyUri
|
||||
this.initialOffsetMs = offsetMs
|
||||
|
||||
addCacheListener()
|
||||
|
||||
this.source = ProgressiveMediaSource
|
||||
.Factory(sourceFactory)
|
||||
.createMediaSource(Uri.parse(proxyUri))
|
||||
.createMediaSource(MediaItem.fromUri(proxyUri))
|
||||
|
||||
addPlayer(this, this.source!!)
|
||||
|
||||
@ -76,14 +80,16 @@ class GaplessExoPlayerWrapper : PlayerWrapper() {
|
||||
if (!dead()) {
|
||||
removePending()
|
||||
|
||||
val proxyUri = streamProxy.getProxyUrl(uri)
|
||||
|
||||
this.metadata = metadata
|
||||
this.originalUri = uri
|
||||
this.proxyUri = streamProxy.getProxyUrl(uri)
|
||||
this.proxyUri = proxyUri
|
||||
this.prefetch = true
|
||||
|
||||
this.source = ProgressiveMediaSource
|
||||
.Factory(sourceFactory)
|
||||
.createMediaSource(Uri.parse(proxyUri))
|
||||
.createMediaSource(MediaItem.fromUri(proxyUri))
|
||||
|
||||
addCacheListener()
|
||||
addPlayer(this, source!!)
|
||||
@ -115,7 +121,8 @@ class GaplessExoPlayerWrapper : PlayerWrapper() {
|
||||
State.Error -> {
|
||||
gaplessPlayer?.playWhenReady = lastPosition == -1L
|
||||
source?.let {
|
||||
gaplessPlayer?.prepare(it)
|
||||
gaplessPlayer?.setMediaSource(it)
|
||||
gaplessPlayer?.prepare()
|
||||
state = State.Preparing
|
||||
} ?: run {
|
||||
state = State.Error
|
||||
@ -362,7 +369,8 @@ class GaplessExoPlayerWrapper : PlayerWrapper() {
|
||||
all.add(wrapper)
|
||||
|
||||
if (dcms.size == 1) {
|
||||
gaplessPlayer?.prepare(dcms)
|
||||
gaplessPlayer?.setMediaSource(dcms)
|
||||
gaplessPlayer?.prepare()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package io.casey.musikcube.remote.service.playback.impl.remote
|
||||
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import io.casey.musikcube.remote.Application
|
||||
import io.casey.musikcube.remote.injection.DaggerServiceComponent
|
||||
import io.casey.musikcube.remote.service.playback.IPlaybackService
|
||||
@ -42,35 +43,35 @@ class RemotePlaybackService : IPlaybackService {
|
||||
* and estimate.
|
||||
*/
|
||||
private class EstimatedPosition {
|
||||
internal var lastTime = 0.0
|
||||
internal var pauseTime = 0.0
|
||||
internal var trackId: Long = -1
|
||||
internal var queryTime: Long = 0
|
||||
var lastTime = 0.0
|
||||
var pauseTime = 0.0
|
||||
var trackId: Long = -1
|
||||
var queryTime: Long = 0
|
||||
|
||||
internal fun get(track: JSONObject?): Double {
|
||||
fun get(track: JSONObject?): Double {
|
||||
if (track != null && track.optLong(Metadata.Track.ID, -1L) == trackId && trackId != -1L) {
|
||||
return if (pauseTime != 0.0) pauseTime else estimatedTime()
|
||||
}
|
||||
return 0.0
|
||||
}
|
||||
|
||||
internal fun update(message: SocketMessage) {
|
||||
fun update(message: SocketMessage) {
|
||||
queryTime = System.nanoTime()
|
||||
lastTime = message.getDoubleOption(Messages.Key.PLAYING_CURRENT_TIME, 0.0)
|
||||
trackId = message.getLongOption(Messages.Key.ID, -1)
|
||||
}
|
||||
|
||||
internal fun pause() {
|
||||
fun pause() {
|
||||
pauseTime = estimatedTime()
|
||||
}
|
||||
|
||||
internal fun resume() {
|
||||
fun resume() {
|
||||
lastTime = pauseTime
|
||||
queryTime = System.nanoTime()
|
||||
pauseTime = 0.0
|
||||
}
|
||||
|
||||
internal fun update(time: Double, id: Long) {
|
||||
fun update(time: Double, id: Long) {
|
||||
queryTime = System.nanoTime()
|
||||
lastTime = time
|
||||
trackId = id
|
||||
@ -80,14 +81,14 @@ class RemotePlaybackService : IPlaybackService {
|
||||
}
|
||||
}
|
||||
|
||||
internal fun reset() {
|
||||
fun reset() {
|
||||
pauseTime = 0.0
|
||||
lastTime = pauseTime
|
||||
queryTime = System.nanoTime()
|
||||
trackId = -1
|
||||
}
|
||||
|
||||
internal fun estimatedTime(): Double {
|
||||
fun estimatedTime(): Double {
|
||||
val diff = System.nanoTime() - queryTime
|
||||
val seconds = diff.toDouble() / NANOSECONDS_PER_SECOND
|
||||
return lastTime + seconds
|
||||
@ -97,52 +98,36 @@ class RemotePlaybackService : IPlaybackService {
|
||||
@Inject lateinit var wss: WebSocketService
|
||||
@Inject lateinit var metadataProxy: IMetadataProxy
|
||||
|
||||
private val handler = Handler()
|
||||
private val handler = Handler(Looper.getMainLooper())
|
||||
private val listeners = HashSet<() -> Unit>()
|
||||
private val estimatedTime = EstimatedPosition()
|
||||
|
||||
override var state = PlaybackState.Stopped
|
||||
private set(value) {
|
||||
field = value
|
||||
}
|
||||
private set
|
||||
|
||||
override val currentTime: Double
|
||||
get() = estimatedTime.get(track)
|
||||
|
||||
override var repeatMode: RepeatMode = RepeatMode.None
|
||||
private set(value) {
|
||||
field = value
|
||||
}
|
||||
private set
|
||||
|
||||
override var shuffled: Boolean = false
|
||||
private set(value) {
|
||||
field = value
|
||||
}
|
||||
private set
|
||||
|
||||
override var muted: Boolean = false
|
||||
private set(value) {
|
||||
field = value
|
||||
}
|
||||
private set
|
||||
|
||||
override var volume: Double = 0.0
|
||||
private set(value) {
|
||||
field = value
|
||||
}
|
||||
private set
|
||||
|
||||
override var queueCount: Int = 0
|
||||
private set(value) {
|
||||
field = value
|
||||
}
|
||||
private set
|
||||
|
||||
override var queuePosition: Int = 0
|
||||
private set(value) {
|
||||
field = value
|
||||
}
|
||||
private set
|
||||
|
||||
override var duration: Double = 0.0
|
||||
private set(value) {
|
||||
field = value
|
||||
}
|
||||
private set
|
||||
|
||||
private var track: JSONObject = JSONObject()
|
||||
|
||||
@ -401,7 +386,7 @@ class RemotePlaybackService : IPlaybackService {
|
||||
}
|
||||
}
|
||||
|
||||
override val queryContext: QueryContext?
|
||||
override val queryContext: QueryContext
|
||||
get() = QueryContext(Messages.Request.QueryPlayQueueTracks)
|
||||
|
||||
override val playlistQueryFactory: ITrackListQueryFactory = object : ITrackListQueryFactory {
|
||||
|
@ -1,5 +1,6 @@
|
||||
package io.casey.musikcube.remote.service.playback.impl.streaming
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.database.ContentObserver
|
||||
@ -28,6 +29,7 @@ import io.reactivex.rxkotlin.subscribeBy
|
||||
import org.json.JSONObject
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
class StreamingPlaybackService(context: Context) : IPlaybackService {
|
||||
@Inject lateinit var metadataProxy: IMetadataProxy
|
||||
@ -39,7 +41,7 @@ class StreamingPlaybackService(context: Context) : IPlaybackService {
|
||||
private var lastSystemVolume: Int = 0
|
||||
private var pausedByTransientLoss = false
|
||||
private val random = Random()
|
||||
private val handler = Handler()
|
||||
private val handler = Handler(Looper.getMainLooper())
|
||||
|
||||
private val trackMetadataCache = object : LinkedHashMap<Int, ITrack>() {
|
||||
override fun removeEldestEntry(eldest: MutableMap.MutableEntry<Int, ITrack>): Boolean {
|
||||
@ -48,13 +50,13 @@ class StreamingPlaybackService(context: Context) : IPlaybackService {
|
||||
}
|
||||
|
||||
private class PlaybackContext {
|
||||
internal var queueCount: Int = 0
|
||||
internal var currentPlayer: PlayerWrapper? = null
|
||||
internal var nextPlayer: PlayerWrapper? = null
|
||||
internal var currentMetadata: ITrack? = null
|
||||
internal var nextMetadata: ITrack? = null
|
||||
internal var currentIndex = -1
|
||||
internal var nextIndex = -1
|
||||
var queueCount: Int = 0
|
||||
var currentPlayer: PlayerWrapper? = null
|
||||
var nextPlayer: PlayerWrapper? = null
|
||||
var currentMetadata: ITrack? = null
|
||||
var nextMetadata: ITrack? = null
|
||||
var currentIndex = -1
|
||||
var nextIndex = -1
|
||||
|
||||
fun stopPlaybackAndReset() {
|
||||
reset(currentPlayer)
|
||||
@ -190,10 +192,10 @@ class StreamingPlaybackService(context: Context) : IPlaybackService {
|
||||
resetPlayContextAndQueryFactory()
|
||||
|
||||
snapshotQueryFactory = object: ITrackListQueryFactory {
|
||||
override fun count(): Observable<Int>? =
|
||||
override fun count(): Observable<Int> =
|
||||
metadataProxy.getPlayQueueTracksCount(type)
|
||||
|
||||
override fun page(offset: Int, limit: Int): Observable<List<ITrack>>? =
|
||||
override fun page(offset: Int, limit: Int): Observable<List<ITrack>> =
|
||||
metadataProxy.getPlayQueueTracks(limit, offset, type)
|
||||
|
||||
override fun offline(): Boolean = false
|
||||
@ -432,7 +434,7 @@ class StreamingPlaybackService(context: Context) : IPlaybackService {
|
||||
PlayerWrapper.setVolume(current)
|
||||
}
|
||||
else {
|
||||
val actual = Math.round(current * maxSystemVolume)
|
||||
val actual = (current * maxSystemVolume).roundToInt()
|
||||
lastSystemVolume = actual
|
||||
audioManager?.setStreamVolume(AudioManager.STREAM_MUSIC, actual, 0)
|
||||
}
|
||||
@ -704,6 +706,7 @@ class StreamingPlaybackService(context: Context) : IPlaybackService {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
private fun loadQueueAndPlay(newParams: QueryContext, startIndex: Int, offsetMs: Int = 0) {
|
||||
state = PlaybackState.Buffering
|
||||
|
||||
@ -721,7 +724,6 @@ class StreamingPlaybackService(context: Context) : IPlaybackService {
|
||||
|
||||
val countMessage = playlistQueryFactory.count() ?: return
|
||||
|
||||
@Suppress("unused")
|
||||
countMessage
|
||||
.concatMap { count ->
|
||||
getCurrentAndNextTrackMessages(playContext, count)
|
||||
@ -767,6 +769,7 @@ class StreamingPlaybackService(context: Context) : IPlaybackService {
|
||||
handler.postDelayed(pauseServiceSleepRunnable, PAUSED_SERVICE_SLEEP_DELAY_MS.toLong())
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
private fun precacheTrackMetadata(start: Int, count: Int) {
|
||||
val originalParams = queryContext
|
||||
val query = playlistQueryFactory.page(start, count)
|
||||
@ -779,7 +782,7 @@ class StreamingPlaybackService(context: Context) : IPlaybackService {
|
||||
{ response ->
|
||||
if (originalParams === this.queryContext) {
|
||||
response.forEachIndexed { i, track ->
|
||||
trackMetadataCache.put(start + i, track)
|
||||
trackMetadataCache[start + i] = track
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -8,7 +8,7 @@ import org.json.JSONObject
|
||||
import java.util.*
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
|
||||
class SocketMessage private constructor(val name: String, val id: String, val type: SocketMessage.Type, options: JSONObject?) {
|
||||
class SocketMessage private constructor(val name: String, val id: String, val type: Type, options: JSONObject?) {
|
||||
enum class Type constructor(val rawType: String) {
|
||||
Request("request"),
|
||||
Response("response"),
|
||||
|
@ -1,5 +1,3 @@
|
||||
package io.casey.musikcube.remote.service.websocket.model
|
||||
|
||||
interface IArtist {
|
||||
|
||||
}
|
||||
interface IArtist
|
@ -8,9 +8,11 @@ import io.casey.musikcube.remote.service.websocket.model.ITrackListQueryFactory
|
||||
import io.reactivex.Observable
|
||||
import org.json.JSONObject
|
||||
import javax.inject.Inject
|
||||
import kotlin.math.min
|
||||
|
||||
class IdListTrackListQueryFactory(private val idList: List<String>): ITrackListQueryFactory {
|
||||
@Inject protected lateinit var metadataProxy: IMetadataProxy
|
||||
@Inject
|
||||
protected lateinit var metadataProxy: IMetadataProxy
|
||||
|
||||
init {
|
||||
DaggerDataComponent.builder()
|
||||
@ -22,7 +24,7 @@ class IdListTrackListQueryFactory(private val idList: List<String>): ITrackListQ
|
||||
|
||||
override fun page(offset: Int, limit: Int): Observable<List<ITrack>>? {
|
||||
val window = mutableSetOf<String>()
|
||||
val max = Math.min(limit, idList.size)
|
||||
val max = min(limit, idList.size)
|
||||
|
||||
for (i in 0 until max) {
|
||||
window.add(idList[offset + i])
|
||||
@ -30,7 +32,7 @@ class IdListTrackListQueryFactory(private val idList: List<String>): ITrackListQ
|
||||
|
||||
val missing = RemoteTrack(JSONObject())
|
||||
return metadataProxy.getTracks(window)
|
||||
.flatMap{ it ->
|
||||
.flatMap{
|
||||
val result = mutableListOf<ITrack>()
|
||||
for (i in 0 until max) {
|
||||
result.add(it[idList[offset + i]] ?: missing)
|
||||
|
@ -48,7 +48,7 @@ class RemoteMetadataProxy(private val service: WebSocketService) : IMetadataProx
|
||||
|
||||
return service.observe(message, client)
|
||||
.observeOn(Schedulers.computation())
|
||||
.flatMap<List<IAlbum>> { socketMessage -> toAlbumList(socketMessage) }
|
||||
.flatMap { socketMessage -> toAlbumList(socketMessage) }
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
}
|
||||
|
||||
@ -61,7 +61,7 @@ class RemoteMetadataProxy(private val service: WebSocketService) : IMetadataProx
|
||||
|
||||
return service.observe(message, client)
|
||||
.observeOn(Schedulers.computation())
|
||||
.flatMap<Int> { socketMessage -> toCount(socketMessage) }
|
||||
.flatMap { socketMessage -> toCount(socketMessage) }
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
}
|
||||
|
||||
@ -77,7 +77,7 @@ class RemoteMetadataProxy(private val service: WebSocketService) : IMetadataProx
|
||||
|
||||
return service.observe(builder.build(), client)
|
||||
.observeOn(Schedulers.computation())
|
||||
.flatMap<List<ITrack>> { socketMessage -> toTrackList(socketMessage) }
|
||||
.flatMap { socketMessage -> toTrackList(socketMessage) }
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
}
|
||||
|
||||
@ -108,7 +108,7 @@ class RemoteMetadataProxy(private val service: WebSocketService) : IMetadataProx
|
||||
|
||||
return service.observe(message, client)
|
||||
.observeOn(Schedulers.computation())
|
||||
.flatMap<List<String>> { socketMessage -> toStringList(socketMessage) }
|
||||
.flatMap { socketMessage -> toStringList(socketMessage) }
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
}
|
||||
|
||||
@ -125,7 +125,7 @@ class RemoteMetadataProxy(private val service: WebSocketService) : IMetadataProx
|
||||
.build()
|
||||
|
||||
return service.observe(message, client)
|
||||
.flatMap<Int> { socketMessage -> toCount(socketMessage) }
|
||||
.flatMap { socketMessage -> toCount(socketMessage) }
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
}
|
||||
|
||||
@ -140,7 +140,7 @@ class RemoteMetadataProxy(private val service: WebSocketService) : IMetadataProx
|
||||
.build()
|
||||
|
||||
return service.observe(message, client)
|
||||
.flatMap<List<String>> { socketMessage -> toStringList(socketMessage) }
|
||||
.flatMap { socketMessage -> toStringList(socketMessage) }
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
}
|
||||
|
||||
@ -161,7 +161,7 @@ class RemoteMetadataProxy(private val service: WebSocketService) : IMetadataProx
|
||||
|
||||
return service.observe(builder.build(), client)
|
||||
.observeOn(Schedulers.computation())
|
||||
.flatMap<List<ITrack>> { socketMessage -> toTrackList(socketMessage) }
|
||||
.flatMap { socketMessage -> toTrackList(socketMessage) }
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
}
|
||||
|
||||
@ -173,7 +173,7 @@ class RemoteMetadataProxy(private val service: WebSocketService) : IMetadataProx
|
||||
.build()
|
||||
|
||||
return service.observe(message, client)
|
||||
.flatMap<Int> { socketMessage -> toCount(socketMessage) }
|
||||
.flatMap { socketMessage -> toCount(socketMessage) }
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
}
|
||||
|
||||
@ -192,7 +192,7 @@ class RemoteMetadataProxy(private val service: WebSocketService) : IMetadataProx
|
||||
|
||||
return service.observe(builder.build(), client)
|
||||
.observeOn(Schedulers.computation())
|
||||
.flatMap<List<ITrack>> { socketMessage -> toTrackList(socketMessage) }
|
||||
.flatMap { socketMessage -> toTrackList(socketMessage) }
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
}
|
||||
|
||||
@ -205,7 +205,7 @@ class RemoteMetadataProxy(private val service: WebSocketService) : IMetadataProx
|
||||
.build()
|
||||
|
||||
return service.observe(message, client)
|
||||
.flatMap<Boolean> { socketMessage -> isSuccessful(socketMessage) }
|
||||
.flatMap { socketMessage -> isSuccessful(socketMessage) }
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
}
|
||||
|
||||
@ -216,7 +216,7 @@ class RemoteMetadataProxy(private val service: WebSocketService) : IMetadataProx
|
||||
|
||||
@Suppress("unused")
|
||||
service.observe(message, client)
|
||||
.flatMap<Boolean> { socketMessage -> isSuccessful(socketMessage) }
|
||||
.flatMap { socketMessage -> isSuccessful(socketMessage) }
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeBy(onError = { })
|
||||
}
|
||||
@ -234,7 +234,7 @@ class RemoteMetadataProxy(private val service: WebSocketService) : IMetadataProx
|
||||
|
||||
return service.observe(builder.build(), client)
|
||||
.observeOn(Schedulers.computation())
|
||||
.flatMap<List<String>> { socketMessage -> toStringList(socketMessage) }
|
||||
.flatMap { socketMessage -> toStringList(socketMessage) }
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
}
|
||||
|
||||
@ -246,7 +246,7 @@ class RemoteMetadataProxy(private val service: WebSocketService) : IMetadataProx
|
||||
|
||||
return service.observe(message, client)
|
||||
.observeOn(Schedulers.computation())
|
||||
.flatMap<List<ICategoryValue>> { socketMessage ->
|
||||
.flatMap { socketMessage ->
|
||||
toCategoryList(socketMessage, Metadata.Category.PLAYLISTS)
|
||||
}
|
||||
.flatMap { values ->
|
||||
@ -266,7 +266,7 @@ class RemoteMetadataProxy(private val service: WebSocketService) : IMetadataProx
|
||||
|
||||
return service.observe(message, client)
|
||||
.observeOn(Schedulers.computation())
|
||||
.flatMap<List<ICategoryValue>> { socketMessage -> toCategoryList(socketMessage, type) }
|
||||
.flatMap { socketMessage -> toCategoryList(socketMessage, type) }
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
}
|
||||
|
||||
@ -282,7 +282,7 @@ class RemoteMetadataProxy(private val service: WebSocketService) : IMetadataProx
|
||||
.build()
|
||||
|
||||
return service.observe(message, client)
|
||||
.flatMap<Long> { socketMessage -> extractId(socketMessage, Messages.Key.PLAYLIST_ID) }
|
||||
.flatMap { socketMessage -> extractId(socketMessage, Messages.Key.PLAYLIST_ID) }
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
}
|
||||
|
||||
@ -305,7 +305,7 @@ class RemoteMetadataProxy(private val service: WebSocketService) : IMetadataProx
|
||||
.build()
|
||||
|
||||
return service.observe(message, client)
|
||||
.flatMap<Long> { socketMessage -> extractId(socketMessage, Messages.Key.PLAYLIST_ID) }
|
||||
.flatMap { socketMessage -> extractId(socketMessage, Messages.Key.PLAYLIST_ID) }
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
}
|
||||
|
||||
@ -324,7 +324,7 @@ class RemoteMetadataProxy(private val service: WebSocketService) : IMetadataProx
|
||||
.build()
|
||||
|
||||
return service.observe(message, client)
|
||||
.flatMap<Long> { socketMessage -> extractId(socketMessage, Messages.Key.PLAYLIST_ID) }
|
||||
.flatMap { socketMessage -> extractId(socketMessage, Messages.Key.PLAYLIST_ID) }
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
}
|
||||
|
||||
@ -343,7 +343,7 @@ class RemoteMetadataProxy(private val service: WebSocketService) : IMetadataProx
|
||||
.build()
|
||||
|
||||
return service.observe(message, client)
|
||||
.flatMap<Long> { socketMessage -> extractId(socketMessage, Messages.Key.PLAYLIST_ID) }
|
||||
.flatMap { socketMessage -> extractId(socketMessage, Messages.Key.PLAYLIST_ID) }
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
}
|
||||
|
||||
@ -356,7 +356,7 @@ class RemoteMetadataProxy(private val service: WebSocketService) : IMetadataProx
|
||||
.build()
|
||||
|
||||
return service.observe(message, client)
|
||||
.flatMap<Boolean> { socketMessage -> isSuccessful(socketMessage) }
|
||||
.flatMap { socketMessage -> isSuccessful(socketMessage) }
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
}
|
||||
|
||||
@ -376,7 +376,7 @@ class RemoteMetadataProxy(private val service: WebSocketService) : IMetadataProx
|
||||
.build()
|
||||
|
||||
return service.observe(message, client)
|
||||
.flatMap<Boolean> { socketMessage -> isSuccessful(socketMessage) }
|
||||
.flatMap { socketMessage -> isSuccessful(socketMessage) }
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
}
|
||||
|
||||
@ -395,7 +395,7 @@ class RemoteMetadataProxy(private val service: WebSocketService) : IMetadataProx
|
||||
.build()
|
||||
|
||||
return service.observe(message, client)
|
||||
.flatMap<Boolean> { socketMessage -> isSuccessful(socketMessage) }
|
||||
.flatMap { socketMessage -> isSuccessful(socketMessage) }
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
}
|
||||
|
||||
@ -414,7 +414,7 @@ class RemoteMetadataProxy(private val service: WebSocketService) : IMetadataProx
|
||||
.build()
|
||||
|
||||
return service.observe(message, client)
|
||||
.flatMap<Int> { socketMessage -> toCount(socketMessage) }
|
||||
.flatMap { socketMessage -> toCount(socketMessage) }
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
}
|
||||
|
||||
@ -430,7 +430,7 @@ class RemoteMetadataProxy(private val service: WebSocketService) : IMetadataProx
|
||||
.build()
|
||||
|
||||
return service.observe(message, client)
|
||||
.flatMap<Boolean> { socketMessage -> isSuccessful(socketMessage) }
|
||||
.flatMap { socketMessage -> isSuccessful(socketMessage) }
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
}
|
||||
|
||||
@ -441,7 +441,7 @@ class RemoteMetadataProxy(private val service: WebSocketService) : IMetadataProx
|
||||
.build()
|
||||
|
||||
return service.observe(message, client)
|
||||
.flatMap<Boolean> { socketMessage -> isSuccessful(socketMessage) }
|
||||
.flatMap { socketMessage -> isSuccessful(socketMessage) }
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
}
|
||||
|
||||
@ -451,7 +451,7 @@ class RemoteMetadataProxy(private val service: WebSocketService) : IMetadataProx
|
||||
.build()
|
||||
|
||||
return service.observe(message, client)
|
||||
.flatMap<IOutputs> { socketMessage -> toOutputs(socketMessage) }
|
||||
.flatMap { socketMessage -> toOutputs(socketMessage) }
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
}
|
||||
|
||||
@ -463,7 +463,7 @@ class RemoteMetadataProxy(private val service: WebSocketService) : IMetadataProx
|
||||
.build()
|
||||
|
||||
return service.observe(message, client)
|
||||
.flatMap<Boolean> { socketMessage -> isSuccessful(socketMessage) }
|
||||
.flatMap { socketMessage -> isSuccessful(socketMessage) }
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
}
|
||||
|
||||
@ -487,7 +487,7 @@ class RemoteMetadataProxy(private val service: WebSocketService) : IMetadataProx
|
||||
.build()
|
||||
|
||||
return service.observe(message, client)
|
||||
.flatMap<Boolean> { socketMessage -> isSuccessful(socketMessage) }
|
||||
.flatMap { socketMessage -> isSuccessful(socketMessage) }
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
}
|
||||
|
||||
@ -513,7 +513,7 @@ class RemoteMetadataProxy(private val service: WebSocketService) : IMetadataProx
|
||||
.build()
|
||||
|
||||
return service.observe(message, client)
|
||||
.flatMap<Boolean> { socketMessage -> isSuccessful(socketMessage) }
|
||||
.flatMap { socketMessage -> isSuccessful(socketMessage) }
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
}
|
||||
|
||||
@ -531,7 +531,7 @@ class RemoteMetadataProxy(private val service: WebSocketService) : IMetadataProx
|
||||
.build()
|
||||
|
||||
return service.observe(message, client)
|
||||
.flatMap<TransportType> { socketMessage ->
|
||||
.flatMap { socketMessage ->
|
||||
Observable.just(TransportType.find(
|
||||
socketMessage.getStringOption(Messages.Key.TYPE,
|
||||
TransportType.Gapless.rawValue)))
|
||||
@ -546,7 +546,7 @@ class RemoteMetadataProxy(private val service: WebSocketService) : IMetadataProx
|
||||
.build()
|
||||
|
||||
return service.observe(message, client)
|
||||
.flatMap<Boolean> { socketMessage -> isSuccessful(socketMessage) }
|
||||
.flatMap { socketMessage -> isSuccessful(socketMessage) }
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
}
|
||||
|
||||
@ -580,7 +580,7 @@ class RemoteMetadataProxy(private val service: WebSocketService) : IMetadataProx
|
||||
.build()
|
||||
|
||||
return service.observe(message, client)
|
||||
.flatMap<Boolean> { socketMessage -> isSuccessful(socketMessage) }
|
||||
.flatMap { socketMessage -> isSuccessful(socketMessage) }
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
}
|
||||
|
||||
|
@ -66,7 +66,7 @@ class BrowseFragmentAdapter(private val context: Context,
|
||||
return fragment.pushTo(this.containerId)
|
||||
}
|
||||
|
||||
override fun getPageTitle(position: Int): CharSequence? =
|
||||
override fun getPageTitle(position: Int): CharSequence =
|
||||
context.getString(when (position) {
|
||||
0 -> R.string.button_artists
|
||||
1 -> R.string.button_albums
|
||||
|
@ -212,7 +212,7 @@ class CategoryBrowseFragment: BaseFragment(), IFilterable, ITitleProvider, ITran
|
||||
if (intent == null) {
|
||||
throw IllegalArgumentException("invalid intent")
|
||||
}
|
||||
return create(intent.getBundleExtra(Category.Extra.FRAGMENT_ARGUMENTS))
|
||||
return create(intent.getBundleExtra(Category.Extra.FRAGMENT_ARGUMENTS) ?: Bundle())
|
||||
}
|
||||
|
||||
fun create(arguments: Bundle): CategoryBrowseFragment =
|
||||
|
@ -9,6 +9,7 @@ import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.os.Environment
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.view.View
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
@ -37,7 +38,7 @@ class TrackDownloadActivity: BaseActivity() {
|
||||
private var outputFilename: String = ""
|
||||
private lateinit var spinner: MaterialProgressBar
|
||||
private lateinit var progress: MaterialProgressBar
|
||||
private val handler = Handler()
|
||||
private val handler = Handler(Looper.getMainLooper())
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
@ -6,7 +6,11 @@ import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.view.*
|
||||
import android.os.Looper
|
||||
import android.view.LayoutInflater
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.widget.*
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.content.ContextCompat
|
||||
@ -35,7 +39,7 @@ import io.casey.musikcube.remote.ui.shared.util.Duration
|
||||
import io.casey.musikcube.remote.ui.shared.util.UpdateCheck
|
||||
|
||||
class MainActivity : BaseActivity() {
|
||||
private val handler = Handler()
|
||||
private val handler = Handler(Looper.getMainLooper())
|
||||
private var updateCheck: UpdateCheck = UpdateCheck()
|
||||
private var seekbarValue = -1
|
||||
private var blink = 0
|
||||
|
@ -43,6 +43,7 @@ import io.casey.musikcube.remote.ui.shared.util.Size
|
||||
import io.casey.musikcube.remote.ui.tracks.activity.TrackListActivity
|
||||
import org.json.JSONArray
|
||||
import javax.inject.Inject
|
||||
import kotlin.math.roundToLong
|
||||
import io.casey.musikcube.remote.ui.shared.util.AlbumArtLookup.getUrl as getAlbumArtUrl
|
||||
|
||||
class MainMetadataView : FrameLayout {
|
||||
@ -123,7 +124,7 @@ class MainMetadataView : FrameLayout {
|
||||
volumeWithArt.visibility = View.GONE
|
||||
}
|
||||
else {
|
||||
val volume = getString(R.string.status_volume, Math.round(playback.volume * 100))
|
||||
val volume = getString(R.string.status_volume, (playback.volume * 100).roundToLong())
|
||||
this.volume.visibility = View.VISIBLE
|
||||
this.volumeWithArt.visibility = View.VISIBLE
|
||||
this.volume.text = volume
|
||||
|
@ -2,6 +2,7 @@ package io.casey.musikcube.remote.ui.settings.activity
|
||||
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.widget.TextView
|
||||
import io.casey.musikcube.remote.Application
|
||||
import io.casey.musikcube.remote.R
|
||||
@ -15,7 +16,7 @@ class DiagnosticsActivity: BaseActivity() {
|
||||
private lateinit var wakeRuntime: TextView
|
||||
private lateinit var wakeAcquired: TextView
|
||||
private lateinit var serviceState: TextView
|
||||
private val handler = Handler()
|
||||
private val handler = Handler(Looper.getMainLooper())
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
@ -40,7 +40,7 @@ class RemoteEqActivity: BaseActivity() {
|
||||
this.enabledCb = findViewById(R.id.enabled_checkbox)
|
||||
initListeners()
|
||||
|
||||
viewModel = createViewModel()!!
|
||||
viewModel = createViewModel()
|
||||
|
||||
updateFromViewModelState()
|
||||
}
|
||||
@ -51,7 +51,7 @@ class RemoteEqActivity: BaseActivity() {
|
||||
viewModel.attach(data.provider)
|
||||
}
|
||||
|
||||
override fun <T : ViewModel<*>> createViewModel(): T? {
|
||||
override fun <T : ViewModel<*>> createViewModel(): T {
|
||||
@Suppress("unchecked_cast")
|
||||
return RemoteEqViewModel() as T
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ class RemoteSettingsActivity: BaseActivity() {
|
||||
environmentTextView = findViewById(R.id.environment_information)
|
||||
initListeners()
|
||||
|
||||
viewModel = getViewModel()!!
|
||||
viewModel = getViewModel()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
@ -87,7 +87,7 @@ class RemoteSettingsActivity: BaseActivity() {
|
||||
return super.onPrepareOptionsMenu(menu)
|
||||
}
|
||||
|
||||
override fun <T : ViewModel<*>> createViewModel(): T? {
|
||||
override fun <T : ViewModel<*>> createViewModel(): T {
|
||||
@Suppress("unchecked_cast")
|
||||
return RemoteSettingsViewModel(data.wss.environment) as T
|
||||
}
|
||||
|
@ -318,7 +318,7 @@ class SettingsActivity : BaseActivity() {
|
||||
}
|
||||
else {
|
||||
showSnackbar(
|
||||
findViewById<View>(android.R.id.content),
|
||||
findViewById(android.R.id.content),
|
||||
R.string.snackbar_saved_connection_preset)
|
||||
}
|
||||
}
|
||||
|
@ -4,8 +4,6 @@ import io.casey.musikcube.remote.R
|
||||
import io.casey.musikcube.remote.service.websocket.model.*
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.functions.BiFunction
|
||||
import io.reactivex.functions.Function3
|
||||
import io.reactivex.rxkotlin.subscribeBy
|
||||
import kotlin.math.max
|
||||
|
||||
@ -98,7 +96,7 @@ class RemoteSettingsViewModel(private val environment: IEnvironment): BaseRemote
|
||||
Observable.zip<Boolean, Boolean, Boolean>(
|
||||
gainQuery,
|
||||
transportQuery,
|
||||
BiFunction { b1, b2 -> b1 && b2 })
|
||||
{ b1, b2 -> b1 && b2 })
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeBy(
|
||||
onNext = { success ->
|
||||
@ -129,7 +127,7 @@ class RemoteSettingsViewModel(private val environment: IEnvironment): BaseRemote
|
||||
gainQuery,
|
||||
outputQuery,
|
||||
transportQuery,
|
||||
Function3 { b1, b2, b3 -> b1 && b2 && b3 })
|
||||
{ b1, b2, b3 -> b1 && b2 && b3 })
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeBy(
|
||||
onNext = { success ->
|
||||
@ -156,12 +154,12 @@ class RemoteSettingsViewModel(private val environment: IEnvironment): BaseRemote
|
||||
gainQuery,
|
||||
outputsQuery,
|
||||
transportQuery,
|
||||
Function3 { gainSettings, outputs, transportType ->
|
||||
this.gain = gainSettings
|
||||
this.outputs = outputs
|
||||
this.transportType = transportType
|
||||
true
|
||||
})
|
||||
{ gainSettings, outputs, transportType ->
|
||||
this.gain = gainSettings
|
||||
this.outputs = outputs
|
||||
this.transportType = transportType
|
||||
true
|
||||
})
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeBy(
|
||||
onNext = { state = State.Ready },
|
||||
|
@ -161,7 +161,7 @@ abstract class BaseActivity : AppCompatActivity(), ViewModel.Provider, Runner.Ta
|
||||
toolbar?.let { setSupportActionBar(it) }
|
||||
}
|
||||
|
||||
protected val top: Fragment?
|
||||
private val top: Fragment?
|
||||
get() {
|
||||
return when {
|
||||
fm.backStackEntryCount == 0 ->
|
||||
@ -172,7 +172,7 @@ abstract class BaseActivity : AppCompatActivity(), ViewModel.Provider, Runner.Ta
|
||||
}
|
||||
}
|
||||
|
||||
protected val fm: FragmentManager
|
||||
private val fm: FragmentManager
|
||||
get() = supportFragmentManager
|
||||
|
||||
protected open val transitionType = Transition.Horizontal
|
||||
@ -181,7 +181,7 @@ abstract class BaseActivity : AppCompatActivity(), ViewModel.Provider, Runner.Ta
|
||||
get() = intent?.extras ?: Bundle()
|
||||
|
||||
override fun <T: ViewModel<*>> createViewModel(): T? = null
|
||||
protected fun <T: ViewModel<*>> getViewModel(): T? = mixin(ViewModelMixin::class.java)?.get<T>() as T
|
||||
protected fun <T: ViewModel<*>> getViewModel(): T = mixin(ViewModelMixin::class.java)?.get() as T
|
||||
protected fun <T: IMixin> mixin(mixin: T): T = mixins.add(mixin)
|
||||
protected fun <T: IMixin> mixin(cls: Class<out T>): T? = mixins.get(cls)
|
||||
|
||||
|
@ -7,6 +7,7 @@ import android.content.SharedPreferences
|
||||
import android.content.res.Resources
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.text.TextUtils
|
||||
import android.util.Base64
|
||||
import android.util.Log
|
||||
@ -104,7 +105,7 @@ fun AppCompatActivity.enableUpNavigation() {
|
||||
}
|
||||
|
||||
fun AppCompatActivity.setTitleFromIntent(defaultTitle: String) {
|
||||
val title = this.intent.getStringExtra(Shared.Extra.TITLE_OVERRIDE)
|
||||
val title = this.intent.getStringExtra(Shared.Extra.TITLE_OVERRIDE) ?: ""
|
||||
this.title = if (title.isNotEmpty()) title else defaultTitle
|
||||
}
|
||||
|
||||
@ -347,7 +348,7 @@ fun showErrorSnackbar(view: View, stringId: Int, buttonText: String? = null, but
|
||||
showErrorSnackbar(view, Application.instance.getString(stringId), buttonText, buttonCb)
|
||||
|
||||
fun AppCompatActivity.showErrorSnackbar(stringId: Int, buttonText: String? = null, buttonCb: ((View) -> Unit)? = null) =
|
||||
showErrorSnackbar(this.findViewById<View>(android.R.id.content), stringId, buttonText, buttonCb)
|
||||
showErrorSnackbar(this.findViewById(android.R.id.content), stringId, buttonText, buttonCb)
|
||||
|
||||
/*
|
||||
*
|
||||
@ -415,7 +416,7 @@ fun DialogFragment.showKeyboard() =
|
||||
|
||||
fun DialogFragment.hideKeyboard() {
|
||||
val fragmentActivity = activity!! /* keep it in the closure so it doesn't get gc'd */
|
||||
Handler().postDelayed({
|
||||
Handler(Looper.getMainLooper()).postDelayed({
|
||||
hideKeyboard(
|
||||
fragmentActivity,
|
||||
fragmentActivity.findViewById(android.R.id.content))
|
||||
|
@ -53,7 +53,7 @@ open class BaseDialogFragment: DialogFragment(), ViewModel.Provider {
|
||||
}
|
||||
|
||||
override fun <T: ViewModel<*>> createViewModel(): T? = null
|
||||
@Suppress("unused") protected fun <T: ViewModel<*>> getViewModel(): T? = mixin(ViewModelMixin::class.java)?.get<T>() as T
|
||||
@Suppress("unused") protected fun <T: ViewModel<*>> getViewModel(): T = mixin(ViewModelMixin::class.java)?.get() as T
|
||||
protected fun <T: IMixin> mixin(mixin: T): T = mixins.add(mixin)
|
||||
protected fun <T: IMixin> mixin(cls: Class<out T>): T? = mixins.get(cls)
|
||||
|
||||
|
@ -5,6 +5,7 @@ import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.view.View
|
||||
import android.view.animation.AlphaAnimation
|
||||
import android.view.animation.Animation
|
||||
@ -34,7 +35,7 @@ import io.reactivex.disposables.CompositeDisposable
|
||||
|
||||
open class BaseFragment: Fragment(), ViewModel.Provider, IBackHandler {
|
||||
private val mixins = MixinSet()
|
||||
protected val handler = Handler()
|
||||
protected val handler = Handler(Looper.getMainLooper())
|
||||
protected lateinit var prefs: SharedPreferences
|
||||
protected val component: ViewComponent =
|
||||
DaggerViewComponent.builder()
|
||||
@ -172,7 +173,7 @@ open class BaseFragment: Fragment(), ViewModel.Provider, IBackHandler {
|
||||
toolbar?.collapseActionViewIfExpanded() ?: false
|
||||
|
||||
override fun <T: ViewModel<*>> createViewModel(): T? = null
|
||||
@Suppress protected fun <T: ViewModel<*>> getViewModel(): T? = mixin(ViewModelMixin::class.java)?.get<T>() as T
|
||||
@Suppress protected fun <T: ViewModel<*>> getViewModel(): T = mixin(ViewModelMixin::class.java)?.get() as T
|
||||
protected fun <T: IMixin> mixin(mixin: T): T = mixins.add(mixin)
|
||||
protected fun <T: IMixin> mixin(cls: Class<out T>): T? = mixins.get(cls)
|
||||
|
||||
|
@ -18,6 +18,7 @@ import io.casey.musikcube.remote.ui.shared.extension.topOfStack
|
||||
import io.casey.musikcube.remote.ui.shared.mixin.PlaybackMixin
|
||||
import io.casey.musikcube.remote.ui.shared.view.InterceptTouchFrameLayout
|
||||
import me.zhanghai.android.materialprogressbar.MaterialProgressBar
|
||||
import kotlin.math.abs
|
||||
|
||||
class TransportFragment: BaseFragment() {
|
||||
private lateinit var rootView: View
|
||||
@ -34,7 +35,7 @@ class TransportFragment: BaseFragment() {
|
||||
var modelChangedListener: ((TransportFragment) -> Unit)? = null
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View?
|
||||
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View
|
||||
{
|
||||
this.rootView = inflater.inflate(R.layout.transport_fragment, container, false)
|
||||
progress = this.rootView.findViewById(R.id.progress)
|
||||
@ -240,8 +241,8 @@ class TransportFragment: BaseFragment() {
|
||||
MotionEvent.ACTION_MOVE -> {
|
||||
val x = ev.x.toInt()
|
||||
val y = ev.y.toInt()
|
||||
totalDx += Math.abs(lastX - x)
|
||||
totalDy += Math.abs(lastY - y)
|
||||
totalDx += abs(lastX - x)
|
||||
totalDy += abs(lastY - y)
|
||||
lastX = x
|
||||
lastY = y
|
||||
}
|
||||
|
@ -81,7 +81,7 @@ class ItemContextMenuMixin(private val activity: AppCompatActivity,
|
||||
if (pendingCode == request) {
|
||||
if (result == Activity.RESULT_OK && data != null) {
|
||||
val playlistId = data.getLongExtra(Category.Extra.ID, -1L)
|
||||
val playlistName = data.getStringExtra(Category.Extra.NAME)
|
||||
val playlistName = data.getStringExtra(Category.Extra.NAME) ?: ""
|
||||
if (playlistId != -1L) {
|
||||
completion?.invoke(playlistId, playlistName)
|
||||
}
|
||||
@ -90,7 +90,7 @@ class ItemContextMenuMixin(private val activity: AppCompatActivity,
|
||||
completion = null
|
||||
}
|
||||
else if (result == Activity.RESULT_OK && request == REQUEST_EDIT_PLAYLIST && data != null) {
|
||||
val playlistName = data.getStringExtra(EditPlaylistActivity.EXTRA_PLAYLIST_NAME)
|
||||
val playlistName = data.getStringExtra(EditPlaylistActivity.EXTRA_PLAYLIST_NAME) ?: ""
|
||||
val playlistId = data.getLongExtra(EditPlaylistActivity.EXTRA_PLAYLIST_ID, -1L)
|
||||
|
||||
showSnackbar(
|
||||
|
@ -7,12 +7,12 @@ import io.casey.musikcube.remote.framework.ViewModel
|
||||
class ViewModelMixin(private val provider: ViewModel.Provider): MixinBase() {
|
||||
private var viewModel: ViewModel<*>? = null
|
||||
|
||||
fun <T: ViewModel<*>> get(): T? {
|
||||
fun <T: ViewModel<*>> get(): T {
|
||||
if (viewModel == null) {
|
||||
viewModel = provider.createViewModel()
|
||||
}
|
||||
@Suppress("unchecked_cast")
|
||||
return viewModel as T?
|
||||
return viewModel as T
|
||||
}
|
||||
|
||||
override fun onCreate(bundle: Bundle) {
|
||||
|
@ -6,6 +6,7 @@ import io.casey.musikcube.remote.service.websocket.model.IMetadataProxy
|
||||
import io.casey.musikcube.remote.service.websocket.model.ITrack
|
||||
import io.casey.musikcube.remote.service.websocket.model.ITrackListQueryFactory
|
||||
import io.reactivex.rxkotlin.subscribeBy
|
||||
import kotlin.math.max
|
||||
|
||||
class DefaultSlidingWindow(
|
||||
private val recyclerView: FastScrollRecyclerView,
|
||||
@ -41,7 +42,7 @@ class DefaultSlidingWindow(
|
||||
|
||||
loadedListener?.onReloaded(count)
|
||||
},
|
||||
onError = { _ ->
|
||||
onError = {
|
||||
Log.d("DefaultSlidingWindow", "message send failed, likely canceled")
|
||||
})
|
||||
|
||||
@ -92,7 +93,7 @@ class DefaultSlidingWindow(
|
||||
return /* already in flight */
|
||||
}
|
||||
|
||||
val offset = Math.max(0, index - 10) /* snag a couple before */
|
||||
val offset = max(0, index - 10) /* snag a couple before */
|
||||
val limit = windowSize
|
||||
|
||||
val pageRequest = queryFactory.page(offset, limit)
|
||||
@ -119,7 +120,7 @@ class DefaultSlidingWindow(
|
||||
notifyAdapterChanged()
|
||||
notifyMetadataLoaded(offset, i)
|
||||
},
|
||||
onError = { _ ->
|
||||
onError = {
|
||||
Log.d("DefaultSlidingWindow", "message send failed, likely canceled")
|
||||
})
|
||||
}
|
||||
|
@ -165,7 +165,7 @@ object AlbumArtLookup {
|
||||
val images = mutableListOf<Pair<Size, String>>()
|
||||
|
||||
try {
|
||||
val json = JSONObject(response.body()?.string())
|
||||
val json = JSONObject(response.body()?.string() ?: "{}")
|
||||
val imagesJson = json.getJSONObject("album").getJSONArray("image")
|
||||
for (i in 0 until imagesJson.length()) {
|
||||
val imageJson = imagesJson.getJSONObject(i)
|
||||
|
@ -120,7 +120,7 @@ class UpdateCheck {
|
||||
}
|
||||
|
||||
private val USER_AGENT by lazy {
|
||||
"musikdroid ${VERSION}"
|
||||
"musikdroid $VERSION"
|
||||
}
|
||||
}
|
||||
}
|
@ -37,7 +37,7 @@ class EditPlaylistActivity: BaseActivity() {
|
||||
playlistName = extras.getString(EXTRA_PLAYLIST_NAME, "-")
|
||||
title = getString(R.string.playlist_edit_activity, playlistName)
|
||||
setContentView(R.layout.edit_playlist_activity)
|
||||
viewModel = getViewModel()!!
|
||||
viewModel = getViewModel()
|
||||
viewModel.attach(data.provider)
|
||||
val recycler = findViewById<RecyclerView>(R.id.recycler_view)
|
||||
val touchHelper = ItemTouchHelper(touchHelperCallback)
|
||||
@ -80,7 +80,7 @@ class EditPlaylistActivity: BaseActivity() {
|
||||
))
|
||||
}
|
||||
|
||||
override fun <T: ViewModel<*>> createViewModel(): T? {
|
||||
override fun <T: ViewModel<*>> createViewModel(): T {
|
||||
@Suppress("unchecked_cast")
|
||||
return EditPlaylistViewModel(extras.getLong(EXTRA_PLAYLIST_ID, -1L)) as T
|
||||
}
|
||||
|
@ -1,17 +0,0 @@
|
||||
package io.casey.musikcube.remote;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
public class ExampleUnitTest {
|
||||
@Test
|
||||
public void addition_isCorrect() throws Exception {
|
||||
assertEquals(4, 2 + 2);
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.3.72'
|
||||
ext.kotlin_version = '1.4.10'
|
||||
|
||||
repositories {
|
||||
google()
|
||||
@ -7,10 +7,10 @@ buildscript {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:4.1.1'
|
||||
classpath 'com.android.tools.build:gradle:4.1.3'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
classpath 'com.google.gms:google-services:4.3.3'
|
||||
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.1.1'
|
||||
classpath 'com.google.gms:google-services:4.3.5'
|
||||
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.5.2'
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user