merge develop
This commit is contained in:
commit
4ff167e497
|
@ -1,7 +1,19 @@
|
||||||
package org.moire.ultrasonic.domain
|
package org.moire.ultrasonic.domain
|
||||||
|
|
||||||
abstract class GenericEntry {
|
abstract class GenericEntry {
|
||||||
// TODO Should be non-null!
|
// TODO: Should be non-null!
|
||||||
abstract val id: String?
|
abstract val id: String?
|
||||||
open val name: String? = null
|
open val name: String? = null
|
||||||
|
|
||||||
|
// These are just a formality and will never be called,
|
||||||
|
// because Kotlin data classes will have autogenerated equals() and hashCode() functions
|
||||||
|
override operator fun equals(other: Any?): Boolean {
|
||||||
|
return this === other
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
var result = id?.hashCode() ?: 0
|
||||||
|
result = 31 * result + (name?.hashCode() ?: 0)
|
||||||
|
return result
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,9 @@ exceptions:
|
||||||
|
|
||||||
empty-blocks:
|
empty-blocks:
|
||||||
active: true
|
active: true
|
||||||
|
EmptyFunctionBlock:
|
||||||
|
active: true
|
||||||
|
ignoreOverridden: true
|
||||||
|
|
||||||
complexity:
|
complexity:
|
||||||
active: true
|
active: true
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,7 +1,5 @@
|
||||||
package org.moire.ultrasonic.service;
|
package org.moire.ultrasonic.service;
|
||||||
|
|
||||||
import timber.log.Timber;
|
|
||||||
|
|
||||||
import org.moire.ultrasonic.domain.MusicDirectory;
|
import org.moire.ultrasonic.domain.MusicDirectory;
|
||||||
import org.moire.ultrasonic.util.LRUCache;
|
import org.moire.ultrasonic.util.LRUCache;
|
||||||
import org.moire.ultrasonic.util.ShufflePlayBuffer;
|
import org.moire.ultrasonic.util.ShufflePlayBuffer;
|
||||||
|
@ -16,6 +14,7 @@ import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import kotlin.Lazy;
|
import kotlin.Lazy;
|
||||||
|
import timber.log.Timber;
|
||||||
|
|
||||||
import static org.koin.java.KoinJavaComponent.inject;
|
import static org.koin.java.KoinJavaComponent.inject;
|
||||||
import static org.moire.ultrasonic.domain.PlayerState.DOWNLOADING;
|
import static org.moire.ultrasonic.domain.PlayerState.DOWNLOADING;
|
||||||
|
@ -342,7 +341,7 @@ public class Downloader
|
||||||
Collections.shuffle(downloadList);
|
Collections.shuffle(downloadList);
|
||||||
if (localMediaPlayer.currentPlaying != null)
|
if (localMediaPlayer.currentPlaying != null)
|
||||||
{
|
{
|
||||||
downloadList.remove(getCurrentPlayingIndex());
|
downloadList.remove(localMediaPlayer.currentPlaying);
|
||||||
downloadList.add(0, localMediaPlayer.currentPlaying);
|
downloadList.add(0, localMediaPlayer.currentPlaying);
|
||||||
}
|
}
|
||||||
revision++;
|
revision++;
|
||||||
|
|
|
@ -1,81 +0,0 @@
|
||||||
/*
|
|
||||||
This file is part of Subsonic.
|
|
||||||
|
|
||||||
Subsonic is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
Subsonic is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
Copyright 2010 (C) Sindre Mehus
|
|
||||||
*/
|
|
||||||
package org.moire.ultrasonic.util;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Sindre Mehus
|
|
||||||
*/
|
|
||||||
public abstract class SilentBackgroundTask<T> extends BackgroundTask<T>
|
|
||||||
{
|
|
||||||
|
|
||||||
public SilentBackgroundTask(Activity activity)
|
|
||||||
{
|
|
||||||
super(activity);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute()
|
|
||||||
{
|
|
||||||
Thread thread = new Thread()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void run()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
final T result = doInBackground();
|
|
||||||
|
|
||||||
getHandler().post(new Runnable()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void run()
|
|
||||||
{
|
|
||||||
done(result);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
catch (final Throwable t)
|
|
||||||
{
|
|
||||||
getHandler().post(new Runnable()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void run()
|
|
||||||
{
|
|
||||||
error(t);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
thread.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateProgress(int messageId)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateProgress(String message)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -49,8 +49,9 @@ class AlbumListFragment : GenericListFragment<MusicDirectory.Entry, AlbumRowAdap
|
||||||
if (args == null) throw IllegalArgumentException("Required arguments are missing")
|
if (args == null) throw IllegalArgumentException("Required arguments are missing")
|
||||||
|
|
||||||
val refresh = args.getBoolean(Constants.INTENT_EXTRA_NAME_REFRESH)
|
val refresh = args.getBoolean(Constants.INTENT_EXTRA_NAME_REFRESH)
|
||||||
|
val append = args.getBoolean(Constants.INTENT_EXTRA_NAME_APPEND)
|
||||||
|
|
||||||
return listModel.getAlbumList(refresh, refreshListView!!, args)
|
return listModel.getAlbumList(refresh or append, refreshListView!!, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -13,7 +13,8 @@ import org.moire.ultrasonic.util.Util
|
||||||
|
|
||||||
class AlbumListModel(application: Application) : GenericListModel(application) {
|
class AlbumListModel(application: Application) : GenericListModel(application) {
|
||||||
|
|
||||||
val albumList: MutableLiveData<List<MusicDirectory.Entry>> = MutableLiveData()
|
val albumList: MutableLiveData<List<MusicDirectory.Entry>> = MutableLiveData(listOf())
|
||||||
|
var lastType: String? = null
|
||||||
private var loadedUntil: Int = 0
|
private var loadedUntil: Int = 0
|
||||||
|
|
||||||
fun getAlbumList(
|
fun getAlbumList(
|
||||||
|
@ -21,8 +22,14 @@ class AlbumListModel(application: Application) : GenericListModel(application) {
|
||||||
swipe: SwipeRefreshLayout?,
|
swipe: SwipeRefreshLayout?,
|
||||||
args: Bundle
|
args: Bundle
|
||||||
): LiveData<List<MusicDirectory.Entry>> {
|
): LiveData<List<MusicDirectory.Entry>> {
|
||||||
|
// Don't reload the data if navigating back to the view that was active before.
|
||||||
|
// This way, we keep the scroll position
|
||||||
|
val albumListType = args.getString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE)!!
|
||||||
|
|
||||||
backgroundLoadFromServer(refresh, swipe, args)
|
if (refresh || albumList.value!!.isEmpty() || albumListType != lastType) {
|
||||||
|
lastType = albumListType
|
||||||
|
backgroundLoadFromServer(refresh, swipe, args)
|
||||||
|
}
|
||||||
return albumList
|
return albumList
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,13 +30,17 @@ import org.moire.ultrasonic.service.MusicService
|
||||||
* Provides ViewModel which contains the list of available Artists
|
* Provides ViewModel which contains the list of available Artists
|
||||||
*/
|
*/
|
||||||
class ArtistListModel(application: Application) : GenericListModel(application) {
|
class ArtistListModel(application: Application) : GenericListModel(application) {
|
||||||
val artists: MutableLiveData<List<Artist>> = MutableLiveData()
|
val artists: MutableLiveData<List<Artist>> = MutableLiveData(listOf())
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves all available Artists in a LiveData
|
* Retrieves all available Artists in a LiveData
|
||||||
*/
|
*/
|
||||||
fun getItems(refresh: Boolean, swipe: SwipeRefreshLayout?): LiveData<List<Artist>> {
|
fun getItems(refresh: Boolean, swipe: SwipeRefreshLayout?): LiveData<List<Artist>> {
|
||||||
backgroundLoadFromServer(refresh, swipe)
|
// Don't reload the data if navigating back to the view that was active before.
|
||||||
|
// This way, we keep the scroll position
|
||||||
|
if (artists.value!!.isEmpty() || refresh) {
|
||||||
|
backgroundLoadFromServer(refresh, swipe)
|
||||||
|
}
|
||||||
return artists
|
return artists
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,20 +16,24 @@ import android.widget.ImageView
|
||||||
import android.widget.PopupMenu
|
import android.widget.PopupMenu
|
||||||
import android.widget.RelativeLayout
|
import android.widget.RelativeLayout
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
|
import androidx.recyclerview.widget.ListAdapter
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import org.moire.ultrasonic.R
|
import org.moire.ultrasonic.R
|
||||||
import org.moire.ultrasonic.data.ActiveServerProvider
|
import org.moire.ultrasonic.data.ActiveServerProvider
|
||||||
|
import org.moire.ultrasonic.domain.GenericEntry
|
||||||
import org.moire.ultrasonic.domain.MusicFolder
|
import org.moire.ultrasonic.domain.MusicFolder
|
||||||
import org.moire.ultrasonic.view.SelectMusicFolderView
|
import org.moire.ultrasonic.view.SelectMusicFolderView
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* An abstract Adapter, which can be extended to display a List of <T> in a RecyclerView
|
* An abstract Adapter, which can be extended to display a List of <T> in a RecyclerView
|
||||||
*/
|
*/
|
||||||
abstract class GenericRowAdapter<T>(
|
abstract class GenericRowAdapter<T : GenericEntry>(
|
||||||
val onItemClick: (T) -> Unit,
|
val onItemClick: (T) -> Unit,
|
||||||
val onContextMenuClick: (MenuItem, T) -> Boolean,
|
val onContextMenuClick: (MenuItem, T) -> Boolean,
|
||||||
private val onMusicFolderUpdate: (String?) -> Unit
|
private val onMusicFolderUpdate: (String?) -> Unit
|
||||||
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
) : ListAdapter<T, RecyclerView.ViewHolder>(GenericDiffCallback()) {
|
||||||
|
|
||||||
open var itemList: List<T> = listOf()
|
open var itemList: List<T> = listOf()
|
||||||
protected abstract val layout: Int
|
protected abstract val layout: Int
|
||||||
protected abstract val contextMenuLayout: Int
|
protected abstract val contextMenuLayout: Int
|
||||||
|
@ -40,11 +44,12 @@ abstract class GenericRowAdapter<T>(
|
||||||
var selectedFolder: String? = null
|
var selectedFolder: String? = null
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the data to be displayed in the RecyclerView
|
* Sets the data to be displayed in the RecyclerView,
|
||||||
|
* using DiffUtil to efficiently calculate the minimum required changes..
|
||||||
*/
|
*/
|
||||||
open fun setData(data: List<T>) {
|
open fun setData(data: List<T>) {
|
||||||
|
submitList(data)
|
||||||
itemList = data
|
itemList = data
|
||||||
notifyDataSetChanged()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -136,5 +141,17 @@ abstract class GenericRowAdapter<T>(
|
||||||
companion object {
|
companion object {
|
||||||
internal const val TYPE_HEADER = 0
|
internal const val TYPE_HEADER = 0
|
||||||
internal const val TYPE_ITEM = 1
|
internal const val TYPE_ITEM = 1
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the differences between data sets
|
||||||
|
*/
|
||||||
|
class GenericDiffCallback<T : GenericEntry> : DiffUtil.ItemCallback<T>() {
|
||||||
|
override fun areContentsTheSame(oldItem: T, newItem: T): Boolean {
|
||||||
|
return oldItem == newItem
|
||||||
|
}
|
||||||
|
override fun areItemsTheSame(oldItem: T, newItem: T): Boolean {
|
||||||
|
return oldItem.id == newItem.id
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -198,7 +198,7 @@ class CachedMusicService(private val musicService: MusicService) : MusicService,
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(Exception::class)
|
@Throws(Exception::class)
|
||||||
override fun createPlaylist(id: String, name: String, entries: List<MusicDirectory.Entry>) {
|
override fun createPlaylist(id: String?, name: String?, entries: List<MusicDirectory.Entry>) {
|
||||||
cachedPlaylists.clear()
|
cachedPlaylists.clear()
|
||||||
musicService.createPlaylist(id, name, entries)
|
musicService.createPlaylist(id, name, entries)
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ import android.os.Looper
|
||||||
import android.os.PowerManager
|
import android.os.PowerManager
|
||||||
import android.os.PowerManager.PARTIAL_WAKE_LOCK
|
import android.os.PowerManager.PARTIAL_WAKE_LOCK
|
||||||
import android.os.PowerManager.WakeLock
|
import android.os.PowerManager.WakeLock
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.net.URLEncoder
|
import java.net.URLEncoder
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
@ -29,7 +30,6 @@ import org.moire.ultrasonic.audiofx.EqualizerController
|
||||||
import org.moire.ultrasonic.audiofx.VisualizerController
|
import org.moire.ultrasonic.audiofx.VisualizerController
|
||||||
import org.moire.ultrasonic.data.ActiveServerProvider.Companion.isOffline
|
import org.moire.ultrasonic.data.ActiveServerProvider.Companion.isOffline
|
||||||
import org.moire.ultrasonic.domain.PlayerState
|
import org.moire.ultrasonic.domain.PlayerState
|
||||||
import org.moire.ultrasonic.fragment.PlayerFragment
|
|
||||||
import org.moire.ultrasonic.util.CancellableTask
|
import org.moire.ultrasonic.util.CancellableTask
|
||||||
import org.moire.ultrasonic.util.Constants
|
import org.moire.ultrasonic.util.Constants
|
||||||
import org.moire.ultrasonic.util.StreamProxy
|
import org.moire.ultrasonic.util.StreamProxy
|
||||||
|
@ -79,10 +79,12 @@ class LocalMediaPlayer(
|
||||||
private var proxy: StreamProxy? = null
|
private var proxy: StreamProxy? = null
|
||||||
private var bufferTask: CancellableTask? = null
|
private var bufferTask: CancellableTask? = null
|
||||||
private var positionCache: PositionCache? = null
|
private var positionCache: PositionCache? = null
|
||||||
private var secondaryProgress = -1
|
|
||||||
private val pm = context.getSystemService(POWER_SERVICE) as PowerManager
|
private val pm = context.getSystemService(POWER_SERVICE) as PowerManager
|
||||||
private val wakeLock: WakeLock = pm.newWakeLock(PARTIAL_WAKE_LOCK, this.javaClass.name)
|
private val wakeLock: WakeLock = pm.newWakeLock(PARTIAL_WAKE_LOCK, this.javaClass.name)
|
||||||
|
|
||||||
|
val secondaryProgress: MutableLiveData<Int> = MutableLiveData(0)
|
||||||
|
|
||||||
fun init() {
|
fun init() {
|
||||||
Thread {
|
Thread {
|
||||||
Thread.currentThread().name = "MediaPlayerThread"
|
Thread.currentThread().name = "MediaPlayerThread"
|
||||||
|
@ -361,7 +363,6 @@ class LocalMediaPlayer(
|
||||||
|
|
||||||
downloadFile.updateModificationDate()
|
downloadFile.updateModificationDate()
|
||||||
mediaPlayer.setOnCompletionListener(null)
|
mediaPlayer.setOnCompletionListener(null)
|
||||||
secondaryProgress = -1 // Ensure seeking in non StreamProxy playback works
|
|
||||||
|
|
||||||
setPlayerState(PlayerState.IDLE)
|
setPlayerState(PlayerState.IDLE)
|
||||||
setAudioAttributes(mediaPlayer)
|
setAudioAttributes(mediaPlayer)
|
||||||
|
@ -392,28 +393,28 @@ class LocalMediaPlayer(
|
||||||
setPlayerState(PlayerState.PREPARING)
|
setPlayerState(PlayerState.PREPARING)
|
||||||
|
|
||||||
mediaPlayer.setOnBufferingUpdateListener { mp, percent ->
|
mediaPlayer.setOnBufferingUpdateListener { mp, percent ->
|
||||||
val progressBar = PlayerFragment.getProgressBar()
|
|
||||||
val song = downloadFile.song
|
val song = downloadFile.song
|
||||||
|
|
||||||
if (percent == 100) {
|
if (percent == 100) {
|
||||||
mp.setOnBufferingUpdateListener(null)
|
mp.setOnBufferingUpdateListener(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
secondaryProgress = (percent.toDouble() / 100.toDouble() * progressBar.max).toInt()
|
// The secondary progress is an indicator of how far the song is cached.
|
||||||
|
|
||||||
if (song.transcodedContentType == null && Util.getMaxBitRate() == 0) {
|
if (song.transcodedContentType == null && Util.getMaxBitRate() == 0) {
|
||||||
progressBar?.secondaryProgress = secondaryProgress
|
val progress = (percent.toDouble() / 100.toDouble() * playerDuration).toInt()
|
||||||
|
secondaryProgress.postValue(progress)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mediaPlayer.setOnPreparedListener {
|
mediaPlayer.setOnPreparedListener {
|
||||||
Timber.i("Media player prepared")
|
Timber.i("Media player prepared")
|
||||||
setPlayerState(PlayerState.PREPARED)
|
setPlayerState(PlayerState.PREPARED)
|
||||||
val progressBar = PlayerFragment.getProgressBar()
|
|
||||||
if (progressBar != null && downloadFile.isWorkDone) {
|
// Populate seek bar secondary progress if we have a complete file for consistency
|
||||||
// Populate seek bar secondary progress if we have a complete file for consistency
|
if (downloadFile.isWorkDone) {
|
||||||
PlayerFragment.getProgressBar().secondaryProgress = 100 * progressBar.max
|
secondaryProgress.postValue(playerDuration)
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized(this@LocalMediaPlayer) {
|
synchronized(this@LocalMediaPlayer) {
|
||||||
if (position != 0) {
|
if (position != 0) {
|
||||||
Timber.i("Restarting player from position %d", position)
|
Timber.i("Restarting player from position %d", position)
|
||||||
|
|
|
@ -386,12 +386,6 @@ class MediaPlayerController(
|
||||||
@get:Synchronized
|
@get:Synchronized
|
||||||
val playerDuration: Int
|
val playerDuration: Int
|
||||||
get() {
|
get() {
|
||||||
if (localMediaPlayer.currentPlaying != null) {
|
|
||||||
val duration = localMediaPlayer.currentPlaying!!.song.duration
|
|
||||||
if (duration != null) {
|
|
||||||
return duration * 1000
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val mediaPlayerService = runningInstance ?: return 0
|
val mediaPlayerService = runningInstance ?: return 0
|
||||||
return mediaPlayerService.playerDuration
|
return mediaPlayerService.playerDuration
|
||||||
}
|
}
|
||||||
|
@ -454,6 +448,19 @@ class MediaPlayerController(
|
||||||
if (localMediaPlayer.currentPlaying == null) return
|
if (localMediaPlayer.currentPlaying == null) return
|
||||||
val song = localMediaPlayer.currentPlaying!!.song
|
val song = localMediaPlayer.currentPlaying!!.song
|
||||||
|
|
||||||
|
Thread {
|
||||||
|
val musicService = getMusicService()
|
||||||
|
try {
|
||||||
|
if (song.starred) {
|
||||||
|
musicService.unstar(song.id, null, null)
|
||||||
|
} else {
|
||||||
|
musicService.star(song.id, null, null)
|
||||||
|
}
|
||||||
|
} catch (all: Exception) {
|
||||||
|
Timber.e(all)
|
||||||
|
}
|
||||||
|
}.start()
|
||||||
|
|
||||||
// Trigger an update
|
// Trigger an update
|
||||||
localMediaPlayer.setCurrentPlaying(localMediaPlayer.currentPlaying)
|
localMediaPlayer.setCurrentPlaying(localMediaPlayer.currentPlaying)
|
||||||
song.starred = !song.starred
|
song.starred = !song.starred
|
||||||
|
|
|
@ -73,7 +73,7 @@ interface MusicService {
|
||||||
fun getPlaylists(refresh: Boolean): List<Playlist>
|
fun getPlaylists(refresh: Boolean): List<Playlist>
|
||||||
|
|
||||||
@Throws(Exception::class)
|
@Throws(Exception::class)
|
||||||
fun createPlaylist(id: String, name: String, entries: List<MusicDirectory.Entry>)
|
fun createPlaylist(id: String?, name: String?, entries: List<MusicDirectory.Entry>)
|
||||||
|
|
||||||
@Throws(Exception::class)
|
@Throws(Exception::class)
|
||||||
fun deletePlaylist(id: String)
|
fun deletePlaylist(id: String)
|
||||||
|
|
|
@ -221,7 +221,7 @@ class OfflineMusicService : MusicService, KoinComponent {
|
||||||
|
|
||||||
@Suppress("TooGenericExceptionCaught")
|
@Suppress("TooGenericExceptionCaught")
|
||||||
@Throws(Exception::class)
|
@Throws(Exception::class)
|
||||||
override fun createPlaylist(id: String, name: String, entries: List<MusicDirectory.Entry>) {
|
override fun createPlaylist(id: String?, name: String?, entries: List<MusicDirectory.Entry>) {
|
||||||
val playlistFile =
|
val playlistFile =
|
||||||
FileUtil.getPlaylistFile(activeServerProvider.getActiveServer().name, name)
|
FileUtil.getPlaylistFile(activeServerProvider.getActiveServer().name, name)
|
||||||
val fw = FileWriter(playlistFile)
|
val fw = FileWriter(playlistFile)
|
||||||
|
|
|
@ -295,12 +295,20 @@ open class RESTMusicService(
|
||||||
return response.body()!!.playlists.toDomainEntitiesList()
|
return response.body()!!.playlists.toDomainEntitiesList()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Either ID or String is required.
|
||||||
|
* ID is required when updating
|
||||||
|
* String is required when creating
|
||||||
|
*/
|
||||||
@Throws(Exception::class)
|
@Throws(Exception::class)
|
||||||
override fun createPlaylist(
|
override fun createPlaylist(
|
||||||
id: String,
|
id: String?,
|
||||||
name: String,
|
name: String?,
|
||||||
entries: List<MusicDirectory.Entry>
|
entries: List<MusicDirectory.Entry>
|
||||||
) {
|
) {
|
||||||
|
if (id == null && name == null)
|
||||||
|
throw IllegalArgumentException("Either id or name is required.")
|
||||||
|
|
||||||
val pSongIds: MutableList<String> = ArrayList(entries.size)
|
val pSongIds: MutableList<String> = ArrayList(entries.size)
|
||||||
|
|
||||||
for ((id1) in entries) {
|
for ((id1) in entries) {
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* SilentBackgroundTask.kt
|
||||||
|
* Copyright (C) 2009-2021 Ultrasonic developers
|
||||||
|
*
|
||||||
|
* Distributed under terms of the GNU GPLv3 license.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.moire.ultrasonic.util
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Sindre Mehus
|
||||||
|
*/
|
||||||
|
abstract class SilentBackgroundTask<T>(activity: Activity?) : BackgroundTask<T>(activity) {
|
||||||
|
override fun execute() {
|
||||||
|
val thread: Thread = object : Thread() {
|
||||||
|
override fun run() {
|
||||||
|
try {
|
||||||
|
val result = doInBackground()
|
||||||
|
handler.post { done(result) }
|
||||||
|
} catch (all: Throwable) {
|
||||||
|
handler.post { error(all) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
thread.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateProgress(messageId: Int) {}
|
||||||
|
override fun updateProgress(message: String) {}
|
||||||
|
}
|
Loading…
Reference in New Issue