diff --git a/detekt-baseline-debug.xml b/detekt-baseline-debug.xml
index fff5d6ce..bc6e7b45 100644
--- a/detekt-baseline-debug.xml
+++ b/detekt-baseline-debug.xml
@@ -33,7 +33,7 @@
ComplexCondition:SelectAlbumFragment.kt$SelectAlbumFragment$enabled && !deleteEnabled && !isOffline(context)
ComplexCondition:SelectAlbumFragment.kt$SelectAlbumFragment$enabled && !isOffline(context) && selection.size > pinnedCount
ComplexCondition:SelectAlbumFragment.kt$SelectAlbumFragment$entry != null && !entry.isDirectory && !entry.isVideo
- ComplexCondition:SelectAlbumFragment.kt$SelectAlbumFragment.<no name provided>$Util.getShouldShowAllSongsByArtist(context) && musicDirectory.findChild(allSongsId) == null && musicDirectory.getChildren(true, false).size == musicDirectory.getChildren(true, true).size
+ ComplexCondition:SelectAlbumModel.kt$SelectAlbumModel$Util.getShouldShowAllSongsByArtist(context) && musicDirectory.findChild(allSongsId) == null && musicDirectory.getChildren(true, false).size == musicDirectory.getChildren(true, true).size
ComplexCondition:ServerSettingsModel.kt$ServerSettingsModel$url.isNullOrEmpty() || userName.isNullOrEmpty() || isMigrated
ComplexCondition:SongView.kt$SongView$TextUtils.isEmpty(transcodedSuffix) || transcodedSuffix == suffix || song.isVideo && Util.getVideoPlayerType(this.context) !== VideoPlayerType.FLASH
ComplexCondition:SubsonicImageLoaderProxy.kt$SubsonicImageLoaderProxy$id != null && view != null && view is ImageView
@@ -49,10 +49,9 @@
ComplexMethod:MediaPlayerService.kt$MediaPlayerService$private fun setupOnSongCompletedHandler()
ComplexMethod:RestErrorMapper.kt$ fun SubsonicRESTException.getLocalizedErrorMessage(context: Context): String
ComplexMethod:SelectAlbumFragment.kt$SelectAlbumFragment$override fun onContextItemSelected(menuItem: MenuItem): Boolean
- ComplexMethod:SelectAlbumFragment.kt$SelectAlbumFragment$override fun onViewCreated(view: View, savedInstanceState: Bundle?)
ComplexMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun enableButtons()
ComplexMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun updateDisplay(refresh: Boolean)
- ComplexMethod:SelectAlbumFragment.kt$SelectAlbumFragment.LoadTask$protected override fun done(result: Pair<MusicDirectory, Boolean>)
+ ComplexMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun updateInterfaceWithEntries(musicDirectory: MusicDirectory)
ComplexMethod:SelectArtistFragment.kt$SelectArtistFragment$override fun onViewCreated(view: View, savedInstanceState: Bundle?)
ComplexMethod:ServerRowAdapter.kt$ServerRowAdapter$ override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View?
ComplexMethod:SongView.kt$SongView$fun setSong(song: MusicDirectory.Entry, checkable: Boolean, draggable: Boolean)
@@ -85,9 +84,9 @@
LargeClass:NavigationActivity.kt$NavigationActivity : AppCompatActivity
LargeClass:RESTMusicService.kt$RESTMusicService : MusicService
LargeClass:SelectAlbumFragment.kt$SelectAlbumFragment : Fragment
- LargeClass:SelectAlbumFragment.kt$SelectAlbumFragment$LoadTask : FragmentBackgroundTask
+ LargeClass:SelectAlbumModel.kt$SelectAlbumModel : AndroidViewModelKoinComponent
LargeClass:SelectArtistFragment.kt$SelectArtistFragment : Fragment
- LargeClass:ServerSettingsModel.kt$ServerSettingsModel : ViewModel
+ LargeClass:ServerSettingsModel.kt$ServerSettingsModel : AndroidViewModel
LargeClass:SongView.kt$SongView : UpdateViewCheckable
LongMethod:APIMusicDirectoryConverter.kt$fun MusicDirectoryChild.toDomainEntity(): MusicDirectory.Entry
LongMethod:ActiveServerProvider.kt$ActiveServerProvider$ fun getActiveServer(): ServerSetting
@@ -140,14 +139,16 @@
LongMethod:RestErrorMapper.kt$ fun SubsonicRESTException.getLocalizedErrorMessage(context: Context): String
LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$override fun onContextItemSelected(menuItem: MenuItem): Boolean
LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$override fun onViewCreated(view: View, savedInstanceState: Bundle?)
+ LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun createHeader( entries: List<MusicDirectory.Entry>, name: CharSequence?, songCount: Int ): View?
LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun downloadBackground(save: Boolean, songs: List<MusicDirectory.Entry?>)
LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun enableButtons()
LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun playAll(shuffle: Boolean = false, append: Boolean = false)
LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun updateDisplay(refresh: Boolean)
- LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment.<no name provided>$override fun done(result: Pair<MusicDirectory, Boolean>)
- LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment.<no name provided>$override fun load(service: MusicService): MusicDirectory
- LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment.LoadTask$protected fun createHeader( entries: List<MusicDirectory.Entry>, name: CharSequence?, songCount: Int ): View?
- LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment.LoadTask$protected override fun done(result: Pair<MusicDirectory, Boolean>)
+ LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun updateInterfaceWithEntries(musicDirectory: MusicDirectory)
+ LongMethod:SelectAlbumModel.kt$SelectAlbumModel$suspend fun getAlbum(refresh: Boolean, id: String?, name: String?, parentId: String?)
+ LongMethod:SelectAlbumModel.kt$SelectAlbumModel$suspend fun getAlbumList(albumListType: String, size: Int, offset: Int)
+ LongMethod:SelectAlbumModel.kt$SelectAlbumModel$suspend fun getArtist(refresh: Boolean, id: String?, name: String?)
+ LongMethod:SelectAlbumModel.kt$SelectAlbumModel$suspend fun getMusicDirectory( refresh: Boolean, id: String?, name: String?, parentId: String? )
LongMethod:SelectArtistFragment.kt$SelectArtistFragment$override fun onViewCreated(view: View, savedInstanceState: Bundle?)
LongMethod:SelectArtistFragment.kt$SelectArtistFragment$private fun onArtistMenuItemSelected(menuItem: MenuItem, artist: Artist): Boolean
LongMethod:ServerRowAdapter.kt$ServerRowAdapter$ override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View?
@@ -204,7 +205,6 @@
MagicNumber:RESTMusicService.kt$RESTMusicService$206
MagicNumber:RESTMusicService.kt$RESTMusicService$5
MagicNumber:SelectAlbumFragment.kt$SelectAlbumFragment$10
- MagicNumber:SelectAlbumFragment.kt$SelectAlbumFragment.LoadTask$10
MagicNumber:SelectMusicFolderView.kt$SelectMusicFolderView$10
MagicNumber:SongView.kt$SongView$3
MagicNumber:SongView.kt$SongView$4
@@ -212,7 +212,6 @@
NestedBlockDepth:DownloadFile.kt$DownloadFile.DownloadTask$override fun execute()
NestedBlockDepth:DownloadHandler.kt$DownloadHandler$private fun downloadRecursively( fragment: Fragment, id: String, name: String?, isShare: Boolean, isDirectory: Boolean, save: Boolean, append: Boolean, autoPlay: Boolean, shuffle: Boolean, background: Boolean, playNext: Boolean, unpin: Boolean, isArtist: Boolean )
NestedBlockDepth:MediaPlayerService.kt$MediaPlayerService$private fun setupOnSongCompletedHandler()
- NestedBlockDepth:SelectAlbumFragment.kt$SelectAlbumFragment$private fun getAlbum(refresh: Boolean, id: String?, name: String?, parentId: String?)
ReturnCount:ActiveServerProvider.kt$ActiveServerProvider$ fun getActiveServer(): ServerSetting
ReturnCount:CommunicationErrorHandler.kt$CommunicationErrorHandler.Companion$fun getErrorMessage(error: Throwable, context: Context): String
ReturnCount:FileLoggerTree.kt$FileLoggerTree$ private fun getNextLogFile()
@@ -241,7 +240,6 @@
TooGenericExceptionCaught:LocalMediaPlayer.kt$LocalMediaPlayer.PositionCache$e: Exception
TooGenericExceptionCaught:MediaPlayerService.kt$MediaPlayerService$e: Exception
TooGenericExceptionCaught:MediaPlayerService.kt$MediaPlayerService$x: IndexOutOfBoundsException
- TooGenericExceptionCaught:SelectAlbumFragment.kt$SelectAlbumFragment$exception: Exception
TooGenericExceptionCaught:SongView.kt$SongView$e: Exception
TooGenericExceptionCaught:SubsonicUncaughtExceptionHandler.kt$SubsonicUncaughtExceptionHandler$x: Throwable
TooGenericExceptionCaught:VideoPlayer.kt$VideoPlayer$e: Exception
diff --git a/detekt-baseline-release.xml b/detekt-baseline-release.xml
index fff5d6ce..2e0abd55 100644
--- a/detekt-baseline-release.xml
+++ b/detekt-baseline-release.xml
@@ -33,7 +33,7 @@
ComplexCondition:SelectAlbumFragment.kt$SelectAlbumFragment$enabled && !deleteEnabled && !isOffline(context)
ComplexCondition:SelectAlbumFragment.kt$SelectAlbumFragment$enabled && !isOffline(context) && selection.size > pinnedCount
ComplexCondition:SelectAlbumFragment.kt$SelectAlbumFragment$entry != null && !entry.isDirectory && !entry.isVideo
- ComplexCondition:SelectAlbumFragment.kt$SelectAlbumFragment.<no name provided>$Util.getShouldShowAllSongsByArtist(context) && musicDirectory.findChild(allSongsId) == null && musicDirectory.getChildren(true, false).size == musicDirectory.getChildren(true, true).size
+ ComplexCondition:SelectAlbumModel.kt$SelectAlbumModel$Util.getShouldShowAllSongsByArtist(context) && musicDirectory.findChild(allSongsId) == null && musicDirectory.getChildren(true, false).size == musicDirectory.getChildren(true, true).size
ComplexCondition:ServerSettingsModel.kt$ServerSettingsModel$url.isNullOrEmpty() || userName.isNullOrEmpty() || isMigrated
ComplexCondition:SongView.kt$SongView$TextUtils.isEmpty(transcodedSuffix) || transcodedSuffix == suffix || song.isVideo && Util.getVideoPlayerType(this.context) !== VideoPlayerType.FLASH
ComplexCondition:SubsonicImageLoaderProxy.kt$SubsonicImageLoaderProxy$id != null && view != null && view is ImageView
@@ -49,10 +49,11 @@
ComplexMethod:MediaPlayerService.kt$MediaPlayerService$private fun setupOnSongCompletedHandler()
ComplexMethod:RestErrorMapper.kt$ fun SubsonicRESTException.getLocalizedErrorMessage(context: Context): String
ComplexMethod:SelectAlbumFragment.kt$SelectAlbumFragment$override fun onContextItemSelected(menuItem: MenuItem): Boolean
- ComplexMethod:SelectAlbumFragment.kt$SelectAlbumFragment$override fun onViewCreated(view: View, savedInstanceState: Bundle?)
ComplexMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun enableButtons()
ComplexMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun updateDisplay(refresh: Boolean)
- ComplexMethod:SelectAlbumFragment.kt$SelectAlbumFragment.LoadTask$protected override fun done(result: Pair<MusicDirectory, Boolean>)
+ ComplexMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun updateInterfaceWithEntries(musicDirectory: MusicDirectory)
+ ComplexMethod:SelectAlbumModel.kt$SelectAlbumModel$suspend fun getAlbumList(albumListType: String, size: Int, offset: Int)
+ ComplexMethod:SelectAlbumModel.kt$SelectAlbumModel$suspend fun getMusicDirectory( refresh: Boolean, id: String?, name: String?, parentId: String? )
ComplexMethod:SelectArtistFragment.kt$SelectArtistFragment$override fun onViewCreated(view: View, savedInstanceState: Bundle?)
ComplexMethod:ServerRowAdapter.kt$ServerRowAdapter$ override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View?
ComplexMethod:SongView.kt$SongView$fun setSong(song: MusicDirectory.Entry, checkable: Boolean, draggable: Boolean)
@@ -85,9 +86,9 @@
LargeClass:NavigationActivity.kt$NavigationActivity : AppCompatActivity
LargeClass:RESTMusicService.kt$RESTMusicService : MusicService
LargeClass:SelectAlbumFragment.kt$SelectAlbumFragment : Fragment
- LargeClass:SelectAlbumFragment.kt$SelectAlbumFragment$LoadTask : FragmentBackgroundTask
+ LargeClass:SelectAlbumModel.kt$SelectAlbumModel : AndroidViewModelKoinComponent
LargeClass:SelectArtistFragment.kt$SelectArtistFragment : Fragment
- LargeClass:ServerSettingsModel.kt$ServerSettingsModel : ViewModel
+ LargeClass:ServerSettingsModel.kt$ServerSettingsModel : AndroidViewModel
LargeClass:SongView.kt$SongView : UpdateViewCheckable
LongMethod:APIMusicDirectoryConverter.kt$fun MusicDirectoryChild.toDomainEntity(): MusicDirectory.Entry
LongMethod:ActiveServerProvider.kt$ActiveServerProvider$ fun getActiveServer(): ServerSetting
@@ -140,14 +141,16 @@
LongMethod:RestErrorMapper.kt$ fun SubsonicRESTException.getLocalizedErrorMessage(context: Context): String
LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$override fun onContextItemSelected(menuItem: MenuItem): Boolean
LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$override fun onViewCreated(view: View, savedInstanceState: Bundle?)
+ LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun createHeader( entries: List<MusicDirectory.Entry>, name: CharSequence?, songCount: Int ): View?
LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun downloadBackground(save: Boolean, songs: List<MusicDirectory.Entry?>)
LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun enableButtons()
LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun playAll(shuffle: Boolean = false, append: Boolean = false)
LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun updateDisplay(refresh: Boolean)
- LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment.<no name provided>$override fun done(result: Pair<MusicDirectory, Boolean>)
- LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment.<no name provided>$override fun load(service: MusicService): MusicDirectory
- LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment.LoadTask$protected fun createHeader( entries: List<MusicDirectory.Entry>, name: CharSequence?, songCount: Int ): View?
- LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment.LoadTask$protected override fun done(result: Pair<MusicDirectory, Boolean>)
+ LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun updateInterfaceWithEntries(musicDirectory: MusicDirectory)
+ LongMethod:SelectAlbumModel.kt$SelectAlbumModel$suspend fun getAlbum(refresh: Boolean, id: String?, name: String?, parentId: String?)
+ LongMethod:SelectAlbumModel.kt$SelectAlbumModel$suspend fun getAlbumList(albumListType: String, size: Int, offset: Int)
+ LongMethod:SelectAlbumModel.kt$SelectAlbumModel$suspend fun getArtist(refresh: Boolean, id: String?, name: String?)
+ LongMethod:SelectAlbumModel.kt$SelectAlbumModel$suspend fun getMusicDirectory( refresh: Boolean, id: String?, name: String?, parentId: String? )
LongMethod:SelectArtistFragment.kt$SelectArtistFragment$override fun onViewCreated(view: View, savedInstanceState: Bundle?)
LongMethod:SelectArtistFragment.kt$SelectArtistFragment$private fun onArtistMenuItemSelected(menuItem: MenuItem, artist: Artist): Boolean
LongMethod:ServerRowAdapter.kt$ServerRowAdapter$ override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View?
@@ -204,7 +207,6 @@
MagicNumber:RESTMusicService.kt$RESTMusicService$206
MagicNumber:RESTMusicService.kt$RESTMusicService$5
MagicNumber:SelectAlbumFragment.kt$SelectAlbumFragment$10
- MagicNumber:SelectAlbumFragment.kt$SelectAlbumFragment.LoadTask$10
MagicNumber:SelectMusicFolderView.kt$SelectMusicFolderView$10
MagicNumber:SongView.kt$SongView$3
MagicNumber:SongView.kt$SongView$4
@@ -212,7 +214,6 @@
NestedBlockDepth:DownloadFile.kt$DownloadFile.DownloadTask$override fun execute()
NestedBlockDepth:DownloadHandler.kt$DownloadHandler$private fun downloadRecursively( fragment: Fragment, id: String, name: String?, isShare: Boolean, isDirectory: Boolean, save: Boolean, append: Boolean, autoPlay: Boolean, shuffle: Boolean, background: Boolean, playNext: Boolean, unpin: Boolean, isArtist: Boolean )
NestedBlockDepth:MediaPlayerService.kt$MediaPlayerService$private fun setupOnSongCompletedHandler()
- NestedBlockDepth:SelectAlbumFragment.kt$SelectAlbumFragment$private fun getAlbum(refresh: Boolean, id: String?, name: String?, parentId: String?)
ReturnCount:ActiveServerProvider.kt$ActiveServerProvider$ fun getActiveServer(): ServerSetting
ReturnCount:CommunicationErrorHandler.kt$CommunicationErrorHandler.Companion$fun getErrorMessage(error: Throwable, context: Context): String
ReturnCount:FileLoggerTree.kt$FileLoggerTree$ private fun getNextLogFile()
@@ -241,7 +242,6 @@
TooGenericExceptionCaught:LocalMediaPlayer.kt$LocalMediaPlayer.PositionCache$e: Exception
TooGenericExceptionCaught:MediaPlayerService.kt$MediaPlayerService$e: Exception
TooGenericExceptionCaught:MediaPlayerService.kt$MediaPlayerService$x: IndexOutOfBoundsException
- TooGenericExceptionCaught:SelectAlbumFragment.kt$SelectAlbumFragment$exception: Exception
TooGenericExceptionCaught:SongView.kt$SongView$e: Exception
TooGenericExceptionCaught:SubsonicUncaughtExceptionHandler.kt$SubsonicUncaughtExceptionHandler$x: Throwable
TooGenericExceptionCaught:VideoPlayer.kt$VideoPlayer$e: Exception
diff --git a/detekt-config.yml b/detekt-config.yml
index 34c3446c..855e94ac 100644
--- a/detekt-config.yml
+++ b/detekt-config.yml
@@ -49,8 +49,6 @@ complexity:
thresholdInFiles: 20
thresholdInClasses: 20
thresholdInInterfaces: 20
- ComplexCondition:
- threshold: 3
LabeledExpression:
active: false
diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/SettingsFragment.java b/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/SettingsFragment.java
index 506db741..524a1fbf 100644
--- a/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/SettingsFragment.java
+++ b/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/SettingsFragment.java
@@ -492,13 +492,8 @@ public class SettingsFragment extends PreferenceFragmentCompat
}
private void setMediaButtonsEnabled(boolean enabled) {
- if (enabled) {
- lockScreenEnabled.setEnabled(true);
- Util.registerMediaButtonEventReceiver(getActivity(), false);
- } else {
- lockScreenEnabled.setEnabled(false);
- Util.unregisterMediaButtonEventReceiver(getActivity(), false);
- }
+ lockScreenEnabled.setEnabled(enabled);
+ Util.updateMediaButtonEventReceiver();
}
private void setBluetoothPreferences(boolean enabled) {
diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/receiver/BluetoothIntentReceiver.java b/ultrasonic/src/main/java/org/moire/ultrasonic/receiver/BluetoothIntentReceiver.java
index c86362a4..faa7f06d 100644
--- a/ultrasonic/src/main/java/org/moire/ultrasonic/receiver/BluetoothIntentReceiver.java
+++ b/ultrasonic/src/main/java/org/moire/ultrasonic/receiver/BluetoothIntentReceiver.java
@@ -29,7 +29,7 @@ import org.moire.ultrasonic.util.Constants;
import org.moire.ultrasonic.util.Util;
/**
- * Request media button focus when connected to Bluetooth A2DP.
+ * Resume or pause playback on Bluetooth A2DP connect/disconnect.
*
* @author Sindre Mehus
*/
@@ -63,7 +63,6 @@ public class BluetoothIntentReceiver extends BroadcastReceiver
if (state == android.bluetooth.BluetoothA2dp.STATE_CONNECTED) actionA2dpConnected = true;
else if (state == android.bluetooth.BluetoothA2dp.STATE_DISCONNECTED) actionA2dpDisconnected = true;
- boolean connected = actionA2dpConnected || actionBluetoothDeviceConnected;
boolean resume = false;
boolean pause = false;
@@ -83,12 +82,6 @@ public class BluetoothIntentReceiver extends BroadcastReceiver
break;
}
- if (connected)
- {
- Timber.i("Connected to Bluetooth device %s address %s, requesting media button focus.", name, address);
- Util.registerMediaButtonEventReceiver(context, false);
- }
-
if (resume)
{
Timber.i("Connected to Bluetooth device %s address %s, resuming playback.", name, address);
diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/receiver/MediaButtonIntentReceiver.java b/ultrasonic/src/main/java/org/moire/ultrasonic/receiver/MediaButtonIntentReceiver.java
index 836eb5e7..9d201b52 100644
--- a/ultrasonic/src/main/java/org/moire/ultrasonic/receiver/MediaButtonIntentReceiver.java
+++ b/ultrasonic/src/main/java/org/moire/ultrasonic/receiver/MediaButtonIntentReceiver.java
@@ -46,7 +46,7 @@ public class MediaButtonIntentReceiver extends BroadcastReceiver
String intentAction = intent.getAction();
// If media button are turned off and we received a media button, exit
- if (!Util.getMediaButtonsPreference(context) &&
+ if (!Util.getMediaButtonsEnabled(context) &&
Intent.ACTION_MEDIA_BUTTON.equals(intentAction)) return;
// Only process media buttons and CMD_PROCESS_KEYCODE, which is received from the widgets
diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/service/MediaPlayerControllerImpl.java b/ultrasonic/src/main/java/org/moire/ultrasonic/service/MediaPlayerControllerImpl.java
index 662b0da1..ca300dc9 100644
--- a/ultrasonic/src/main/java/org/moire/ultrasonic/service/MediaPlayerControllerImpl.java
+++ b/ultrasonic/src/main/java/org/moire/ultrasonic/service/MediaPlayerControllerImpl.java
@@ -85,12 +85,7 @@ public class MediaPlayerControllerImpl implements MediaPlayerController
public void onCreate()
{
if (created) return;
- this.externalStorageMonitor.onCreate(new Runnable() {
- @Override
- public void run() {
- reset();
- }
- });
+ this.externalStorageMonitor.onCreate(this::reset);
setJukeboxEnabled(activeServerProvider.getValue().getActiveServer().getJukeboxByDefault());
created = true;
@@ -116,9 +111,8 @@ public class MediaPlayerControllerImpl implements MediaPlayerController
if (currentPlayingIndex != -1)
{
- MediaPlayerService.executeOnStartedMediaPlayerService(context, new Consumer() {
- @Override
- public void accept(MediaPlayerService mediaPlayerService) {
+ MediaPlayerService.executeOnStartedMediaPlayerService(context, (mediaPlayerService) ->
+ {
mediaPlayerService.play(currentPlayingIndex, autoPlayStart);
if (localMediaPlayer.currentPlaying != null)
@@ -136,8 +130,9 @@ public class MediaPlayerControllerImpl implements MediaPlayerController
}
}
autoPlayStart = false;
- }
- });
+ return null;
+ }
+ );
}
}
@@ -149,55 +144,53 @@ public class MediaPlayerControllerImpl implements MediaPlayerController
@Override
public synchronized void play(final int index)
{
- MediaPlayerService.executeOnStartedMediaPlayerService(context,new Consumer() {
- @Override
- public void accept(MediaPlayerService mediaPlayerService) {
+ MediaPlayerService.executeOnStartedMediaPlayerService(context, (mediaPlayerService) -> {
mediaPlayerService.play(index, true);
- }
- });
+ return null;
+ }
+ );
}
public synchronized void play()
{
- MediaPlayerService.executeOnStartedMediaPlayerService(context, new Consumer() {
- @Override
- public void accept(MediaPlayerService mediaPlayerService) {
+ MediaPlayerService.executeOnStartedMediaPlayerService(context, (mediaPlayerService) -> {
+
mediaPlayerService.play();
- }
- });
+ return null;
+ }
+ );
}
public synchronized void resumeOrPlay()
{
- MediaPlayerService.executeOnStartedMediaPlayerService(context, new Consumer() {
- @Override
- public void accept(MediaPlayerService mediaPlayerService) {
+ MediaPlayerService.executeOnStartedMediaPlayerService(context, (mediaPlayerService) -> {
mediaPlayerService.resumeOrPlay();
- }
- });
+ return null;
+ }
+ );
}
+
@Override
public synchronized void togglePlayPause()
{
if (localMediaPlayer.playerState == PlayerState.IDLE) autoPlayStart = true;
- MediaPlayerService.executeOnStartedMediaPlayerService(context,new Consumer() {
- @Override
- public void accept(MediaPlayerService mediaPlayerService) {
+ MediaPlayerService.executeOnStartedMediaPlayerService(context, (mediaPlayerService) -> {
mediaPlayerService.togglePlayPause();
- }
- });
+ return null;
+ }
+ );
}
+
@Override
public synchronized void start()
{
- MediaPlayerService.executeOnStartedMediaPlayerService(context, new Consumer() {
- @Override
- public void accept(MediaPlayerService mediaPlayerService) {
+ MediaPlayerService.executeOnStartedMediaPlayerService(context, (mediaPlayerService) -> {
mediaPlayerService.start();
- }
- });
+ return null;
+ }
+ );
}
@Override
@@ -612,19 +605,14 @@ public class MediaPlayerControllerImpl implements MediaPlayerController
final Entry song = localMediaPlayer.currentPlaying.getSong();
song.setUserRating(rating);
- new Thread(new Runnable()
- {
- @Override
- public void run()
+ new Thread(() -> {
+ try
{
- try
- {
- MusicServiceFactory.getMusicService(context).setRating(song.getId(), rating, context);
- }
- catch (Exception e)
- {
- Timber.e(e);
- }
+ MusicServiceFactory.getMusicService(context).setRating(song.getId(), rating, context);
+ }
+ catch (Exception e)
+ {
+ Timber.e(e);
}
}).start();
diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/service/MediaPlayerLifecycleSupport.java b/ultrasonic/src/main/java/org/moire/ultrasonic/service/MediaPlayerLifecycleSupport.java
index 2cf3d392..c4865d76 100644
--- a/ultrasonic/src/main/java/org/moire/ultrasonic/service/MediaPlayerLifecycleSupport.java
+++ b/ultrasonic/src/main/java/org/moire/ultrasonic/service/MediaPlayerLifecycleSupport.java
@@ -76,9 +76,6 @@ public class MediaPlayerLifecycleSupport
registerHeadsetReceiver();
- // React to media buttons.
- Util.registerMediaButtonEventReceiver(context, true);
-
mediaPlayerController.onCreate();
if (autoPlay) mediaPlayerController.preload();
diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/util/Util.java b/ultrasonic/src/main/java/org/moire/ultrasonic/util/Util.java
index 90ee2f61..e3a632fd 100644
--- a/ultrasonic/src/main/java/org/moire/ultrasonic/util/Util.java
+++ b/ultrasonic/src/main/java/org/moire/ultrasonic/util/Util.java
@@ -31,7 +31,6 @@ import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
-import android.media.AudioManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
@@ -54,8 +53,8 @@ import org.moire.ultrasonic.R;
import org.moire.ultrasonic.data.ActiveServerProvider;
import org.moire.ultrasonic.domain.*;
import org.moire.ultrasonic.domain.MusicDirectory.Entry;
-import org.moire.ultrasonic.receiver.MediaButtonIntentReceiver;
import org.moire.ultrasonic.service.DownloadFile;
+import org.moire.ultrasonic.service.MediaPlayerService;
import java.io.*;
import java.security.MessageDigest;
@@ -679,31 +678,16 @@ public class Util
return Bitmap.createScaledBitmap(bitmap, size, getScaledHeight(bitmap, size), true);
}
- public static void registerMediaButtonEventReceiver(Context context, boolean isService)
+ // Trigger an update on the MediaSession. Depending on the preference it will register
+ // or deregister the MediaButtonReceiver.
+ public static void updateMediaButtonEventReceiver()
{
- if (getMediaButtonsPreference(context))
- {
- if (isService) mediaButtonsRegisteredForService = true;
- else mediaButtonsRegisteredForUI = true;
-
- AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
- audioManager.registerMediaButtonEventReceiver(new ComponentName(context.getPackageName(), MediaButtonIntentReceiver.class.getName()));
+ MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance();
+ if (mediaPlayerService != null) {
+ mediaPlayerService.updateMediaButtonReceiver();
}
}
- public static void unregisterMediaButtonEventReceiver(Context context, boolean isService)
- {
- if (isService) mediaButtonsRegisteredForService = false;
- else mediaButtonsRegisteredForUI = false;
-
- // Do not unregister while there is an active part of the app which needs the control
- if (mediaButtonsRegisteredForService || mediaButtonsRegisteredForUI) return;
-
- AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
- audioManager.unregisterMediaButtonEventReceiver(new ComponentName(context.getPackageName(), MediaButtonIntentReceiver.class.getName()));
- Timber.i("MediaButtonEventReceiver unregistered.");
- }
-
public static MusicDirectory getSongsFromSearchResult(SearchResult searchResult)
{
MusicDirectory musicDirectory = new MusicDirectory();
@@ -1056,7 +1040,7 @@ public class Util
return Integer.parseInt(preferences.getString(Constants.PREFERENCES_KEY_INCREMENT_TIME, "5"));
}
- public static boolean getMediaButtonsPreference(Context context)
+ public static boolean getMediaButtonsEnabled(Context context)
{
SharedPreferences preferences = getPreferences(context);
return preferences.getBoolean(Constants.PREFERENCES_KEY_MEDIA_BUTTONS, true);
diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/view/EntryAdapter.java b/ultrasonic/src/main/java/org/moire/ultrasonic/view/EntryAdapter.java
index 5f655a7f..bd05bff8 100644
--- a/ultrasonic/src/main/java/org/moire/ultrasonic/view/EntryAdapter.java
+++ b/ultrasonic/src/main/java/org/moire/ultrasonic/view/EntryAdapter.java
@@ -33,6 +33,8 @@ import org.moire.ultrasonic.util.ImageLoader;
import java.util.List;
/**
+ * This is the adapter for the display of a single list item (song, album, etc)
+ *
* @author Sindre Mehus
*/
public class EntryAdapter extends ArrayAdapter
diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/view/UpdateView.java b/ultrasonic/src/main/java/org/moire/ultrasonic/view/UpdateView.java
index 5236726b..96338d01 100644
--- a/ultrasonic/src/main/java/org/moire/ultrasonic/view/UpdateView.java
+++ b/ultrasonic/src/main/java/org/moire/ultrasonic/view/UpdateView.java
@@ -14,6 +14,11 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.WeakHashMap;
+/**
+ * A View that is periodically refreshed
+ * @deprecated
+ * Use LiveData to ensure that the content is up-to-date
+ **/
public class UpdateView extends LinearLayout
{
private static final WeakHashMap INSTANCES = new WeakHashMap();
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/activity/NavigationActivity.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/activity/NavigationActivity.kt
index 97c274be..b113de4a 100644
--- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/activity/NavigationActivity.kt
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/activity/NavigationActivity.kt
@@ -178,7 +178,7 @@ class NavigationActivity : AppCompatActivity() {
super.onResume()
setMenuForServerSetting()
- Util.registerMediaButtonEventReceiver(this, false)
+
// Lifecycle support's constructor registers some event receivers so it should be created early
lifecycleSupport.onCreate()
@@ -188,7 +188,6 @@ class NavigationActivity : AppCompatActivity() {
override fun onDestroy() {
super.onDestroy()
- Util.unregisterMediaButtonEventReceiver(this, false)
nowPlayingEventDistributor.unsubscribe(nowPlayingEventListener)
themeChangedEventDistributor.unsubscribe(themeChangedEventListener)
imageLoaderProvider.clearImageLoader()
@@ -310,7 +309,6 @@ class NavigationActivity : AppCompatActivity() {
private fun exit() {
lifecycleSupport.onDestroy()
- Util.unregisterMediaButtonEventReceiver(this, false)
finish()
}
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/AppPermanentStorageModule.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/AppPermanentStorageModule.kt
index e22dd105..4aab32b1 100644
--- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/AppPermanentStorageModule.kt
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/AppPermanentStorageModule.kt
@@ -31,5 +31,5 @@ val appPermanentStorage = module {
single { get().serverSettingDao() }
- viewModel { ServerSettingsModel(get(), get(), androidContext()) }
+ viewModel { ServerSettingsModel(get(), get(), get()) }
}
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SelectAlbumFragment.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SelectAlbumFragment.kt
index 6a9043aa..bc059dfa 100644
--- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SelectAlbumFragment.kt
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SelectAlbumFragment.kt
@@ -1,8 +1,13 @@
+/*
+ * SelectAlbumFragment.kt
+ * Copyright (C) 2009-2021 Ultrasonic developers
+ *
+ * Distributed under terms of the GNU GPLv3 license.
+ */
+
package org.moire.ultrasonic.fragment
import android.os.Bundle
-import android.os.Handler
-import android.os.Looper
import android.view.ContextMenu
import android.view.ContextMenu.ContextMenuInfo
import android.view.LayoutInflater
@@ -12,40 +17,30 @@ import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView.AdapterContextMenuInfo
-import android.widget.AdapterView.OnItemClickListener
-import android.widget.AdapterView.OnItemLongClickListener
import android.widget.ImageView
import android.widget.ListView
import android.widget.TextView
import androidx.fragment.app.Fragment
-import androidx.lifecycle.MutableLiveData
+import androidx.fragment.app.viewModels
import androidx.lifecycle.Observer
import androidx.lifecycle.viewModelScope
import androidx.navigation.Navigation
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
-import androidx.swiperefreshlayout.widget.SwipeRefreshLayout.OnRefreshListener
import java.security.SecureRandom
import java.util.Collections
-import java.util.LinkedList
import java.util.Random
-import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
import org.koin.android.ext.android.inject
import org.koin.android.viewmodel.ext.android.viewModel
+import org.koin.core.component.KoinApiExtension
import org.moire.ultrasonic.R
-import org.moire.ultrasonic.api.subsonic.models.AlbumListType
import org.moire.ultrasonic.data.ActiveServerProvider
import org.moire.ultrasonic.data.ActiveServerProvider.Companion.isOffline
import org.moire.ultrasonic.domain.MusicDirectory
import org.moire.ultrasonic.domain.MusicFolder
import org.moire.ultrasonic.fragment.FragmentTitle.Companion.getTitle
import org.moire.ultrasonic.fragment.FragmentTitle.Companion.setTitle
-import org.moire.ultrasonic.service.CommunicationErrorHandler
import org.moire.ultrasonic.service.MediaPlayerController
-import org.moire.ultrasonic.service.MusicService
-import org.moire.ultrasonic.service.MusicServiceFactory
-import org.moire.ultrasonic.service.MusicServiceFactory.getMusicService
import org.moire.ultrasonic.subsonic.DownloadHandler
import org.moire.ultrasonic.subsonic.ImageLoaderProvider
import org.moire.ultrasonic.subsonic.NetworkAndStorageChecker
@@ -55,7 +50,6 @@ import org.moire.ultrasonic.util.AlbumHeader
import org.moire.ultrasonic.util.CancellationToken
import org.moire.ultrasonic.util.Constants
import org.moire.ultrasonic.util.EntryByDiscAndTrackComparator
-import org.moire.ultrasonic.util.FragmentBackgroundTask
import org.moire.ultrasonic.util.Util
import org.moire.ultrasonic.view.AlbumView
import org.moire.ultrasonic.view.EntryAdapter
@@ -65,10 +59,11 @@ import timber.log.Timber
/**
* Displays a group of playable media from the library, which can be an Album, a Playlist, etc.
+ * TODO: Break up this class into smaller more specific classes, extending a base class if necessary
*/
+@KoinApiExtension
class SelectAlbumFragment : Fragment() {
- private val allSongsId = "-1"
private var refreshAlbumListView: SwipeRefreshLayout? = null
private var albumListView: ListView? = null
private var header: View? = null
@@ -88,10 +83,6 @@ class SelectAlbumFragment : Fragment() {
private var shareButtonVisible = false
private var playAllButton: MenuItem? = null
private var shareButton: MenuItem? = null
- private var showHeader = true
- private var showSelectFolderHeader = false
- private val random: Random = SecureRandom()
- private val musicFolders: MutableLiveData> = MutableLiveData()
private val mediaPlayerController: MediaPlayerController by inject()
private val videoPlayer: VideoPlayer by inject()
@@ -101,7 +92,11 @@ class SelectAlbumFragment : Fragment() {
private val shareHandler: ShareHandler by inject()
private var cancellationToken: CancellationToken? = null
private val activeServerProvider: ActiveServerProvider by inject()
+
private val serverSettingsModel: ServerSettingsModel by viewModel()
+ private val model: SelectAlbumModel by viewModels()
+
+ private val random: Random = SecureRandom()
override fun onCreate(savedInstanceState: Bundle?) {
Util.applyTheme(this.context)
@@ -125,12 +120,9 @@ class SelectAlbumFragment : Fragment() {
refreshAlbumListView = view.findViewById(R.id.select_album_entries_refresh)
albumListView = view.findViewById(R.id.select_album_entries_list)
- refreshAlbumListView!!.setOnRefreshListener(
- OnRefreshListener
- {
- updateDisplay(true)
- }
- )
+ refreshAlbumListView!!.setOnRefreshListener {
+ updateDisplay(true)
+ }
header = LayoutInflater.from(context).inflate(
R.layout.select_album_header, albumListView,
@@ -138,75 +130,53 @@ class SelectAlbumFragment : Fragment() {
)
selectFolderHeader = SelectMusicFolderView(
- requireContext(), view as ViewGroup,
- { selectedFolderId ->
- if (!ActiveServerProvider.isOffline(context)) {
- val currentSetting = activeServerProvider.getActiveServer()
- currentSetting.musicFolderId = selectedFolderId
- serverSettingsModel.updateItem(currentSetting)
- }
- this.updateDisplay(true)
+ requireContext(), view as ViewGroup
+ ) { selectedFolderId ->
+ if (!isOffline(context)) {
+ val currentSetting = activeServerProvider.getActiveServer()
+ currentSetting.musicFolderId = selectedFolderId
+ serverSettingsModel.updateItem(currentSetting)
}
- )
- musicFolders.observe(
- viewLifecycleOwner,
- Observer { changedFolders ->
- if (changedFolders != null) {
- selectFolderHeader!!.setData(
- activeServerProvider.getActiveServer().musicFolderId,
- changedFolders
+ this.updateDisplay(true)
+ }
+
+ model.musicFolders.observe(viewLifecycleOwner, musicFolderObserver)
+ model.currentDirectory.observe(viewLifecycleOwner, defaultObserver)
+ model.songsForGenre.observe(viewLifecycleOwner, songsForGenreObserver)
+ model.albumList.observe(viewLifecycleOwner, albumListObserver)
+
+ albumListView!!.choiceMode = ListView.CHOICE_MODE_MULTIPLE
+ albumListView!!.setOnItemClickListener { parent, theView, position, _ ->
+ if (position >= 0) {
+ val entry = parent.getItemAtPosition(position) as MusicDirectory.Entry?
+ if (entry != null && entry.isDirectory) {
+ val bundle = Bundle()
+ bundle.putString(Constants.INTENT_EXTRA_NAME_ID, entry.id)
+ bundle.putBoolean(Constants.INTENT_EXTRA_NAME_IS_ALBUM, entry.isDirectory)
+ bundle.putString(Constants.INTENT_EXTRA_NAME_NAME, entry.title)
+ bundle.putString(Constants.INTENT_EXTRA_NAME_PARENT_ID, entry.parent)
+ Navigation.findNavController(theView).navigate(
+ R.id.selectAlbumFragment,
+ bundle
)
+ } else if (entry != null && entry.isVideo) {
+ videoPlayer.playVideo(requireContext(), entry)
+ } else {
+ enableButtons()
}
}
- )
+ }
- albumListView!!.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE)
- albumListView!!.setOnItemClickListener(
- OnItemClickListener
- { parent, theView, position, _ ->
- if (position >= 0) {
- val entry = parent.getItemAtPosition(position) as MusicDirectory.Entry?
- if (entry != null && entry.isDirectory) {
- val bundle = Bundle()
- bundle.putString(Constants.INTENT_EXTRA_NAME_ID, entry.id)
- bundle.putBoolean(Constants.INTENT_EXTRA_NAME_IS_ALBUM, entry.isDirectory)
- bundle.putString(Constants.INTENT_EXTRA_NAME_NAME, entry.title)
- bundle.putString(Constants.INTENT_EXTRA_NAME_PARENT_ID, entry.parent)
- Navigation.findNavController(theView).navigate(
- R.id.selectAlbumFragment,
- bundle
- )
- } else if (entry != null && entry.isVideo) {
- videoPlayer.playVideo(requireContext(), entry)
- } else {
- enableButtons()
- }
- }
+ albumListView!!.setOnItemLongClickListener { _, theView, _, _ ->
+ if (theView is AlbumView) {
+ return@setOnItemLongClickListener false
}
- )
-
- // TODO Long click on an item will first try to maximize / collapse the item, even when it
- // fits inside the TextView. The context menu is only displayed on the second long click...
- // This may be improved somehow, e.g. checking first if the texts fit
- albumListView!!.setOnItemLongClickListener(
- OnItemLongClickListener
- { _, theView, _, _ ->
- if (theView is AlbumView) {
- val albumView = theView
- if (!albumView.isMaximized) {
- albumView.maximizeOrMinimize()
- return@OnItemLongClickListener true
- } else {
- return@OnItemLongClickListener false
- }
- }
- if (theView is SongView) {
- theView.maximizeOrMinimize()
- return@OnItemLongClickListener true
- }
- false
+ if (theView is SongView) {
+ theView.maximizeOrMinimize()
+ return@setOnItemLongClickListener true
}
- )
+ return@setOnItemLongClickListener false
+ }
selectButton = view.findViewById(R.id.select_album_select)
playNowButton = view.findViewById(R.id.select_album_play_now)
@@ -219,63 +189,39 @@ class SelectAlbumFragment : Fragment() {
moreButton = view.findViewById(R.id.select_album_more)
emptyView = TextView(requireContext())
- selectButton!!.setOnClickListener(
- View.OnClickListener
- {
- selectAllOrNone()
- }
- )
- playNowButton!!.setOnClickListener(
- View.OnClickListener
- {
- playNow(false)
- }
- )
- playNextButton!!.setOnClickListener(
- View.OnClickListener
- {
- downloadHandler.download(
- this@SelectAlbumFragment, true,
- false, false, true, false,
- getSelectedSongs(albumListView)
- )
- selectAll(false, false)
- }
- )
- playLastButton!!.setOnClickListener(
- View.OnClickListener
- {
- playNow(true)
- }
- )
- pinButton!!.setOnClickListener(
- View.OnClickListener
- {
- downloadBackground(true)
- selectAll(false, false)
- }
- )
- unpinButton!!.setOnClickListener(
- View.OnClickListener
- {
- unpin()
- selectAll(false, false)
- }
- )
- downloadButton!!.setOnClickListener(
- View.OnClickListener
- {
- downloadBackground(false)
- selectAll(false, false)
- }
- )
- deleteButton!!.setOnClickListener(
- View.OnClickListener
- {
- delete()
- selectAll(false, false)
- }
- )
+ selectButton!!.setOnClickListener {
+ selectAllOrNone()
+ }
+ playNowButton!!.setOnClickListener {
+ playNow(false)
+ }
+ playNextButton!!.setOnClickListener {
+ downloadHandler.download(
+ this@SelectAlbumFragment, append = true,
+ save = false, autoPlay = false, playNext = true, shuffle = false,
+ songs = getSelectedSongs(albumListView)
+ )
+ selectAll(selected = false, toast = false)
+ }
+ playLastButton!!.setOnClickListener {
+ playNow(true)
+ }
+ pinButton!!.setOnClickListener {
+ downloadBackground(true)
+ selectAll(selected = false, toast = false)
+ }
+ unpinButton!!.setOnClickListener {
+ unpin()
+ selectAll(selected = false, toast = false)
+ }
+ downloadButton!!.setOnClickListener {
+ downloadBackground(false)
+ selectAll(selected = false, toast = false)
+ }
+ deleteButton!!.setOnClickListener {
+ delete()
+ selectAll(selected = false, toast = false)
+ }
registerForContextMenu(albumListView!!)
setHasOptionsMenu(true)
@@ -312,57 +258,57 @@ class SelectAlbumFragment : Fragment() {
Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0
)
- backgroundLoadMusicFolders(refresh)
-
- if (playlistId != null) {
- getPlaylist(playlistId, playlistName)
- } else if (podcastChannelId != null) {
- getPodcastEpisodes(podcastChannelId)
- } else if (shareId != null) {
- getShare(shareId, shareName)
- } else if (albumListType != null) {
- getAlbumList(albumListType, albumListTitle, albumListSize, albumListOffset)
- } else if (genreName != null) {
- getSongsForGenre(genreName, albumListSize, albumListOffset)
- } else if (getStarredTracks != 0) {
- starred
- } else if (getVideos != 0) {
- getVideos(refresh)
- } else if (getRandomTracks != 0) {
- getRandom(albumListSize)
- } else {
- if (!isOffline(activity) && Util.getShouldUseId3Tags(activity)) {
- if (isAlbum) {
- getAlbum(refresh, id, name, parentId)
- } else {
- getArtist(refresh, id, name)
- }
- } else {
- getMusicDirectory(refresh, id, name, parentId)
- }
+ fun setTitle(name: String?) {
+ setTitle(this@SelectAlbumFragment, name)
}
- }
- private fun backgroundLoadMusicFolders(refresh: Boolean) {
- serverSettingsModel.viewModelScope.launch {
+ fun setTitle(name: Int) {
+ setTitle(this@SelectAlbumFragment, name)
+ }
+
+ model.viewModelScope.launch {
refreshAlbumListView!!.isRefreshing = true
- loadMusicFolders(refresh)
- refreshAlbumListView!!.isRefreshing = false
- }
- }
- private suspend fun loadMusicFolders(refresh: Boolean) {
- withContext(Dispatchers.IO) {
- if (!isOffline(context)) {
- val musicService = MusicServiceFactory.getMusicService(requireContext())
- try {
- musicFolders.postValue(musicService.getMusicFolders(refresh, context))
- } catch (exception: Exception) {
- Handler(Looper.getMainLooper()).post {
- CommunicationErrorHandler.handleError(exception, requireContext())
+ model.getMusicFolders(refresh)
+
+ if (playlistId != null) {
+ setTitle(playlistName)
+ model.getPlaylist(playlistId, playlistName)
+ } else if (podcastChannelId != null) {
+ setTitle(getString(R.string.podcasts_label))
+ model.getPodcastEpisodes(podcastChannelId)
+ } else if (shareId != null) {
+ setTitle(shareName)
+ model.getShare(shareId)
+ } else if (albumListType != null) {
+ setTitle(albumListTitle)
+ model.getAlbumList(albumListType, albumListSize, albumListOffset)
+ } else if (genreName != null) {
+ setTitle(genreName)
+ model.getSongsForGenre(genreName, albumListSize, albumListOffset)
+ } else if (getStarredTracks != 0) {
+ setTitle(getString(R.string.main_songs_starred))
+ model.getStarred()
+ } else if (getVideos != 0) {
+ setTitle(R.string.main_videos)
+ model.getVideos(refresh)
+ } else if (getRandomTracks != 0) {
+ setTitle(R.string.main_songs_random)
+ model.getRandom(albumListSize)
+ } else {
+ setTitle(name)
+ if (!isOffline(activity) && Util.getShouldUseId3Tags(activity)) {
+ if (isAlbum) {
+ model.getAlbum(refresh, id, name, parentId)
+ } else {
+ model.getArtist(refresh, id, name)
}
+ } else {
+ model.getMusicDirectory(refresh, id, name, parentId)
}
}
+
+ refreshAlbumListView!!.isRefreshing = false
}
}
@@ -398,43 +344,64 @@ class SelectAlbumFragment : Fragment() {
val entryId = entry.id
- val itemId = menuItem.itemId
- if (itemId == R.id.album_menu_play_now) {
- downloadHandler.downloadRecursively(
- this, entryId, false, false, true, false, false, false, false, false
- )
- } else if (itemId == R.id.album_menu_play_next) {
- downloadHandler.downloadRecursively(
- this, entryId, false, false, false, false, false, true, false, false
- )
- } else if (itemId == R.id.album_menu_play_last) {
- downloadHandler.downloadRecursively(
- this, entryId, false, true, false, false, false, false, false, false
- )
- } else if (itemId == R.id.album_menu_pin) {
- downloadHandler.downloadRecursively(
- this, entryId, true, true, false, false, false, false, false, false
- )
- } else if (itemId == R.id.album_menu_unpin) {
- downloadHandler.downloadRecursively(
- this, entryId, false, false, false, false, false, false, true, false
- )
- } else if (itemId == R.id.album_menu_download) {
- downloadHandler.downloadRecursively(
- this, entryId, false, false, false, false, true, false, false, false
- )
- } else if (itemId == R.id.select_album_play_all) {
- playAll()
- } else if (itemId == R.id.menu_item_share) {
- val entries: MutableList = ArrayList(1)
- entries.add(entry)
- shareHandler.createShare(
- this, entries, refreshAlbumListView,
- cancellationToken!!
- )
- return true
- } else {
- return super.onContextItemSelected(menuItem)
+ when (menuItem.itemId) {
+ R.id.album_menu_play_now -> {
+ downloadHandler.downloadRecursively(
+ this, entryId, save = false, append = false,
+ autoPlay = true, shuffle = false, background = false,
+ playNext = false, unpin = false, isArtist = false
+ )
+ }
+ R.id.album_menu_play_next -> {
+ downloadHandler.downloadRecursively(
+ this, entryId, save = false, append = false,
+ autoPlay = false, shuffle = false, background = false,
+ playNext = true, unpin = false, isArtist = false
+ )
+ }
+ R.id.album_menu_play_last -> {
+ downloadHandler.downloadRecursively(
+ this, entryId, save = false, append = true,
+ autoPlay = false, shuffle = false, background = false,
+ playNext = false, unpin = false, isArtist = false
+ )
+ }
+ R.id.album_menu_pin -> {
+ downloadHandler.downloadRecursively(
+ this, entryId, save = true, append = true,
+ autoPlay = false, shuffle = false, background = false,
+ playNext = false, unpin = false, isArtist = false
+ )
+ }
+ R.id.album_menu_unpin -> {
+ downloadHandler.downloadRecursively(
+ this, entryId, save = false, append = false,
+ autoPlay = false, shuffle = false, background = false,
+ playNext = false, unpin = true, isArtist = false
+ )
+ }
+ R.id.album_menu_download -> {
+ downloadHandler.downloadRecursively(
+ this, entryId, save = false, append = false,
+ autoPlay = false, shuffle = false, background = true,
+ playNext = false, unpin = false, isArtist = false
+ )
+ }
+ R.id.select_album_play_all -> {
+ playAll()
+ }
+ R.id.menu_item_share -> {
+ val entries: MutableList = ArrayList(1)
+ entries.add(entry)
+ shareHandler.createShare(
+ this, entries, refreshAlbumListView,
+ cancellationToken!!
+ )
+ return true
+ }
+ else -> {
+ return super.onContextItemSelected(menuItem)
+ }
}
return true
}
@@ -483,12 +450,12 @@ class SelectAlbumFragment : Fragment() {
private fun playNow(append: Boolean) {
val selectedSongs = getSelectedSongs(albumListView)
- if (!selectedSongs.isEmpty()) {
+ if (selectedSongs.isNotEmpty()) {
downloadHandler.download(
- this, append, false, !append, false,
- false, selectedSongs
+ this, append, false, !append, playNext = false,
+ shuffle = false, songs = selectedSongs
)
- selectAll(false, false)
+ selectAll(selected = false, toast = false)
} else {
playAll(false, append)
}
@@ -511,375 +478,18 @@ class SelectAlbumFragment : Fragment() {
if (hasSubFolders && id != null) {
downloadHandler.downloadRecursively(
this, id, false, append, !append,
- shuffle, false, false, false, isArtist
+ shuffle, background = false, playNext = false, unpin = false, isArtist = isArtist
)
} else {
- selectAll(true, false)
+ selectAll(selected = true, toast = false)
downloadHandler.download(
this, append, false, !append, false,
shuffle, getSelectedSongs(albumListView)
)
- selectAll(false, false)
+ selectAll(selected = false, toast = false)
}
}
- private fun getMusicDirectory(refresh: Boolean, id: String?, name: String?, parentId: String?) {
- setTitle(this, name)
-
- object : LoadTask() {
- override fun load(service: MusicService): MusicDirectory {
- var root = MusicDirectory()
-
- if (allSongsId == id) {
- val musicDirectory = service.getMusicDirectory(parentId, name, refresh, context)
-
- val songs: MutableList = LinkedList()
- getSongsRecursively(musicDirectory, songs)
-
- for (song in songs) {
- if (!song.isDirectory) {
- root.addChild(song)
- }
- }
- } else {
- val musicDirectory = service.getMusicDirectory(id, name, refresh, context)
-
- if (Util.getShouldShowAllSongsByArtist(context) &&
- musicDirectory.findChild(allSongsId) == null &&
- musicDirectory.getChildren(true, false).size ==
- musicDirectory.getChildren(true, true).size
- ) {
- val allSongs = MusicDirectory.Entry()
-
- allSongs.isDirectory = true
- allSongs.artist = name
- allSongs.parent = id
- allSongs.id = allSongsId
- allSongs.title = String.format(
- resources.getString(R.string.select_album_all_songs), name
- )
-
- root.addChild(allSongs)
- root.addAll(musicDirectory.getChildren())
- } else {
- root = musicDirectory
- }
- }
- return root
- }
-
- private fun getSongsRecursively(
- parent: MusicDirectory,
- songs: MutableList
- ) {
- for (song in parent.getChildren(false, true)) {
- if (!song.isVideo && !song.isDirectory) {
- songs.add(song)
- }
- }
-
- val musicService = getMusicService(context!!)
-
- for ((id1, _, _, title) in parent.getChildren(true, false)) {
- var root: MusicDirectory
-
- if (allSongsId != id1) {
- root = musicService.getMusicDirectory(id1, title, false, context)
-
- getSongsRecursively(root, songs)
- }
- }
- }
- }.execute()
- }
-
- private fun getArtist(refresh: Boolean, id: String?, name: String?) {
- setTitle(this, name)
-
- object : LoadTask() {
- override fun load(service: MusicService): MusicDirectory {
-
- var root = MusicDirectory()
-
- val musicDirectory = service.getArtist(id, name, refresh, context)
-
- if (Util.getShouldShowAllSongsByArtist(context) &&
- musicDirectory.findChild(allSongsId) == null &&
- musicDirectory.getChildren(true, false).size ==
- musicDirectory.getChildren(true, true).size
- ) {
- val allSongs = MusicDirectory.Entry()
-
- allSongs.isDirectory = true
- allSongs.artist = name
- allSongs.parent = id
- allSongs.id = allSongsId
- allSongs.title = String.format(
- resources.getString(R.string.select_album_all_songs), name
- )
-
- root.addFirst(allSongs)
- root.addAll(musicDirectory.getChildren())
- } else {
- root = musicDirectory
- }
- return root
- }
- }.execute()
- }
-
- private fun getAlbum(refresh: Boolean, id: String?, name: String?, parentId: String?) {
- setTitle(this, name)
-
- object : LoadTask() {
- override fun load(service: MusicService): MusicDirectory {
-
- val musicDirectory: MusicDirectory
-
- musicDirectory = if (allSongsId == id) {
- val root = MusicDirectory()
-
- val songs: MutableCollection = LinkedList()
- getSongsForArtist(parentId, songs)
-
- for (song in songs) {
- if (!song.isDirectory) {
- root.addChild(song)
- }
- }
- root
- } else {
- service.getAlbum(id, name, refresh, context)
- }
- return musicDirectory
- }
-
- private fun getSongsForArtist(
- id: String?,
- songs: MutableCollection
- ) {
-
- val musicService = getMusicService(context!!)
- val artist = musicService.getArtist(id, "", false, context)
-
- for ((id1) in artist.getChildren()) {
- if (allSongsId != id1) {
- val albumDirectory = musicService.getAlbum(id1, "", false, context)
-
- for (song in albumDirectory.getChildren()) {
- if (!song.isVideo) {
- songs.add(song)
- }
- }
- }
- }
- }
- }.execute()
- }
-
- private fun getSongsForGenre(genre: String, count: Int, offset: Int) {
- setTitle(this, genre)
-
- object : LoadTask() {
- override fun load(service: MusicService): MusicDirectory {
- return service.getSongsByGenre(genre, count, offset, context)
- }
-
- override fun done(result: Pair) {
- // Hide more button when results are less than album list size
- if (result.first.getChildren().size < arguments!!.getInt(
- Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 0
- )
- ) {
- moreButton!!.visibility = View.GONE
- } else {
- moreButton!!.visibility = View.VISIBLE
- }
-
- moreButton!!.setOnClickListener {
- val theGenre = arguments!!.getString(Constants.INTENT_EXTRA_NAME_GENRE_NAME)
- val size = arguments!!.getInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 0)
- val theOffset = arguments!!.getInt(
- Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0
- ) + size
- val bundle = Bundle()
- bundle.putString(Constants.INTENT_EXTRA_NAME_GENRE_NAME, theGenre)
- bundle.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, size)
- bundle.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, theOffset)
- Navigation.findNavController(view!!).navigate(R.id.selectAlbumFragment, bundle)
- }
-
- super.done(result)
- }
- }.execute()
- }
-
- private val starred: Unit
- get() {
- setTitle(this, R.string.main_songs_starred)
-
- object : LoadTask() {
- override fun load(service: MusicService): MusicDirectory {
- return if (Util.getShouldUseId3Tags(context))
- Util.getSongsFromSearchResult(service.getStarred2(context))
- else
- Util.getSongsFromSearchResult(service.getStarred(context))
- }
- }.execute()
- }
-
- private fun getVideos(refresh: Boolean) {
- showHeader = false
-
- setTitle(this, R.string.main_videos)
-
- object : LoadTask() {
- override fun load(service: MusicService): MusicDirectory {
- return service.getVideos(refresh, context)
- }
- }.execute()
- }
-
- private fun getRandom(size: Int) {
- setTitle(this, R.string.main_songs_random)
-
- object : LoadTask() {
- override fun sortableCollection(): Boolean {
- return false
- }
-
- override fun load(service: MusicService): MusicDirectory {
- return service.getRandomSongs(size, context)
- }
- }.execute()
- }
-
- private fun getPlaylist(playlistId: String, playlistName: String?) {
-
- setTitle(this, playlistName)
-
- object : LoadTask() {
- override fun load(service: MusicService): MusicDirectory {
- return service.getPlaylist(playlistId, playlistName, context)
- }
- }.execute()
- }
-
- private fun getPodcastEpisodes(podcastChannelId: String) {
-
- setTitle(this, R.string.podcasts_label)
-
- object : LoadTask() {
- override fun load(service: MusicService): MusicDirectory {
- return service.getPodcastEpisodes(podcastChannelId, context)
- }
- }.execute()
- }
-
- private fun getShare(shareId: String, shareName: CharSequence?) {
-
- setTitle(this, shareName)
- // setActionBarSubtitle(shareName);
-
- object : LoadTask() {
- override fun load(service: MusicService): MusicDirectory {
- val shares = service.getShares(true, context)
-
- val md = MusicDirectory()
-
- for (share in shares) {
- if (share.id == shareId) {
- for (entry in share.getEntries()) {
- md.addChild(entry)
- }
- break
- }
- }
- return md
- }
- }.execute()
- }
-
- private fun getAlbumList(albumListType: String, albumListTitle: Int, size: Int, offset: Int) {
-
- showHeader = false
- showSelectFolderHeader = !isOffline(context) && !Util.getShouldUseId3Tags(context) &&
- (
- (albumListType == AlbumListType.SORTED_BY_NAME.toString()) ||
- (albumListType == AlbumListType.SORTED_BY_ARTIST.toString())
- )
-
- setTitle(this, albumListTitle)
- // setActionBarSubtitle(albumListTitle);
-
- object : LoadTask() {
- override fun sortableCollection(): Boolean {
- return albumListType != "newest" && albumListType != "random" &&
- albumListType != "highest" && albumListType != "recent" &&
- albumListType != "frequent"
- }
-
- override fun load(service: MusicService): MusicDirectory {
- val musicFolderId = if (showSelectFolderHeader) {
- this@SelectAlbumFragment.activeServerProvider.getActiveServer().musicFolderId
- } else {
- null
- }
- return if (Util.getShouldUseId3Tags(context))
- service.getAlbumList2(albumListType, size, offset, musicFolderId, context)
- else
- service.getAlbumList(albumListType, size, offset, musicFolderId, context)
- }
-
- override fun done(result: Pair) {
- if (!result.first.getChildren().isEmpty()) {
- pinButton!!.visibility = View.GONE
- unpinButton!!.visibility = View.GONE
- downloadButton!!.visibility = View.GONE
- deleteButton!!.visibility = View.GONE
-
- // Hide more button when results are less than album list size
- if (result.first.getChildren().size < arguments!!.getInt(
- Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 0
- )
- ) {
- moreButton!!.visibility = View.GONE
- } else {
- moreButton!!.visibility = View.VISIBLE
- moreButton!!.setOnClickListener {
- val theAlbumListTitle = arguments!!.getInt(
- Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TITLE, 0
- )
- val type = arguments!!.getString(
- Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE
- )
- val theSize = arguments!!.getInt(
- Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 0
- )
- val theOffset = arguments!!.getInt(
- Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0
- ) + theSize
-
- val bundle = Bundle()
- bundle.putInt(
- Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TITLE, theAlbumListTitle
- )
- bundle.putString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE, type)
- bundle.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, theSize)
- bundle.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, theOffset)
- Navigation.findNavController(view!!).navigate(
- R.id.selectAlbumFragment, bundle
- )
- }
- }
- } else {
- moreButton!!.visibility = View.GONE
- }
- super.done(result)
- }
- }.execute()
- }
-
private fun selectAllOrNone() {
var someUnselected = false
val count = albumListView!!.count
@@ -920,7 +530,7 @@ class SelectAlbumFragment : Fragment() {
private fun enableButtons() {
val selection = getSelectedSongs(albumListView)
- val enabled = !selection.isEmpty()
+ val enabled = selection.isNotEmpty()
var unpinEnabled = false
var deleteEnabled = false
@@ -956,7 +566,7 @@ class SelectAlbumFragment : Fragment() {
var songs = getSelectedSongs(albumListView)
if (songs.isEmpty()) {
- selectAll(true, false)
+ selectAll(selected = true, toast = false)
songs = getSelectedSongs(albumListView)
}
@@ -991,7 +601,7 @@ class SelectAlbumFragment : Fragment() {
var songs = getSelectedSongs(albumListView)
if (songs.isEmpty()) {
- selectAll(true, false)
+ selectAll(selected = true, toast = false)
songs = getSelectedSongs(albumListView)
}
@@ -1009,212 +619,281 @@ class SelectAlbumFragment : Fragment() {
mediaPlayerController.unpin(songs)
}
- private abstract inner class LoadTask : FragmentBackgroundTask>(
- this@SelectAlbumFragment.activity, true, refreshAlbumListView,
- cancellationToken
- ) {
-
- protected abstract fun load(service: MusicService): MusicDirectory
- protected open fun sortableCollection(): Boolean {
- return true
+ private val musicFolderObserver = Observer> { changedFolders ->
+ if (changedFolders != null) {
+ selectFolderHeader!!.setData(
+ activeServerProvider.getActiveServer().musicFolderId,
+ changedFolders
+ )
}
+ }
- override fun doInBackground(): Pair {
- val musicService = getMusicService(context!!)
- val dir = load(musicService)
- val valid = musicService.isLicenseValid(context)
- return Pair(dir, valid)
- }
+ private val albumListObserver = Observer { musicDirectory ->
+ if (musicDirectory.getChildren().isNotEmpty()) {
+ pinButton!!.visibility = View.GONE
+ unpinButton!!.visibility = View.GONE
+ downloadButton!!.visibility = View.GONE
+ deleteButton!!.visibility = View.GONE
- protected override fun done(result: Pair) {
- val musicDirectory = result.first
- val entries = musicDirectory.getChildren()
-
- if (sortableCollection() && Util.getShouldSortByDisc(context)) {
- Collections.sort(entries, EntryByDiscAndTrackComparator())
- }
-
- var allVideos = true
- var songCount = 0
-
- for (entry in entries) {
- if (!entry.isVideo) {
- allVideos = false
- }
- if (!entry.isDirectory) {
- songCount++
- }
- }
-
- val listSize = arguments!!.getInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 0)
-
- if (songCount > 0) {
- if (showHeader) {
- val intentAlbumName = arguments!!.getString(Constants.INTENT_EXTRA_NAME_NAME)
- val directoryName = musicDirectory.name
- val header = createHeader(
- entries, intentAlbumName ?: directoryName,
- songCount
- )
- if (header != null && albumListView!!.headerViewsCount == 0) {
- albumListView!!.addHeaderView(header, null, false)
- }
- }
-
- pinButton!!.visibility = View.VISIBLE
- unpinButton!!.visibility = View.VISIBLE
- downloadButton!!.visibility = View.VISIBLE
- deleteButton!!.visibility = View.VISIBLE
- selectButton!!.visibility = if (allVideos) View.GONE else View.VISIBLE
- playNowButton!!.visibility = View.VISIBLE
- playNextButton!!.visibility = View.VISIBLE
- playLastButton!!.visibility = View.VISIBLE
-
- if (listSize == 0 || songCount < listSize) {
- moreButton!!.visibility = View.GONE
- } else {
- moreButton!!.visibility = View.VISIBLE
- if (arguments!!.getInt(Constants.INTENT_EXTRA_NAME_RANDOM, 0) > 0) {
- moreButton!!.setOnClickListener {
- val offset = arguments!!.getInt(
- Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0
- ) + listSize
- val bundle = Bundle()
- bundle.putInt(Constants.INTENT_EXTRA_NAME_RANDOM, 1)
- bundle.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, listSize)
- bundle.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, offset)
- Navigation.findNavController(view!!).navigate(
- R.id.selectAlbumFragment, bundle
- )
- }
- }
- }
+ // Hide more button when results are less than album list size
+ if (musicDirectory.getChildren().size < requireArguments().getInt(
+ Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 0
+ )
+ ) {
+ moreButton!!.visibility = View.GONE
} else {
- if (showSelectFolderHeader) {
- if (albumListView!!.headerViewsCount == 0) {
- albumListView!!.addHeaderView(selectFolderHeader!!.itemView, null, false)
+ moreButton!!.visibility = View.VISIBLE
+ moreButton!!.setOnClickListener {
+ val theAlbumListTitle = requireArguments().getInt(
+ Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TITLE, 0
+ )
+ val type = requireArguments().getString(
+ Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE
+ )
+ val theSize = requireArguments().getInt(
+ Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 0
+ )
+ val theOffset = requireArguments().getInt(
+ Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0
+ ) + theSize
+
+ val bundle = Bundle()
+ bundle.putInt(
+ Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TITLE, theAlbumListTitle
+ )
+ bundle.putString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE, type)
+ bundle.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, theSize)
+ bundle.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, theOffset)
+ Navigation.findNavController(requireView()).navigate(
+ R.id.selectAlbumFragment, bundle
+ )
+ }
+ }
+ } else {
+ moreButton!!.visibility = View.GONE
+ }
+
+ updateInterfaceWithEntries(musicDirectory)
+ }
+
+ private val songsForGenreObserver = Observer { musicDirectory ->
+
+ // Hide more button when results are less than album list size
+ if (musicDirectory.getChildren().size < requireArguments().getInt(
+ Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 0
+ )
+ ) {
+ moreButton!!.visibility = View.GONE
+ } else {
+ moreButton!!.visibility = View.VISIBLE
+ }
+
+ moreButton!!.setOnClickListener {
+ val theGenre = requireArguments().getString(Constants.INTENT_EXTRA_NAME_GENRE_NAME)
+ val size = requireArguments().getInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 0)
+ val theOffset = requireArguments().getInt(
+ Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0
+ ) + size
+ val bundle = Bundle()
+ bundle.putString(Constants.INTENT_EXTRA_NAME_GENRE_NAME, theGenre)
+ bundle.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, size)
+ bundle.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, theOffset)
+ Navigation.findNavController(requireView()).navigate(R.id.selectAlbumFragment, bundle)
+ }
+
+ updateInterfaceWithEntries(musicDirectory)
+ }
+
+ private val defaultObserver = Observer(this::updateInterfaceWithEntries)
+
+ private fun updateInterfaceWithEntries(musicDirectory: MusicDirectory) {
+ val entries = musicDirectory.getChildren()
+
+ if (model.currentDirectoryIsSortable && Util.getShouldSortByDisc(context)) {
+ Collections.sort(entries, EntryByDiscAndTrackComparator())
+ }
+
+ var allVideos = true
+ var songCount = 0
+
+ for (entry in entries) {
+ if (!entry.isVideo) {
+ allVideos = false
+ }
+ if (!entry.isDirectory) {
+ songCount++
+ }
+ }
+
+ val listSize = requireArguments().getInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 0)
+
+ if (songCount > 0) {
+ if (model.showHeader) {
+ val intentAlbumName = requireArguments().getString(Constants.INTENT_EXTRA_NAME_NAME)
+ val directoryName = musicDirectory.name
+ val header = createHeader(
+ entries, intentAlbumName ?: directoryName,
+ songCount
+ )
+ if (header != null && albumListView!!.headerViewsCount == 0) {
+ albumListView!!.addHeaderView(header, null, false)
+ }
+ }
+
+ pinButton!!.visibility = View.VISIBLE
+ unpinButton!!.visibility = View.VISIBLE
+ downloadButton!!.visibility = View.VISIBLE
+ deleteButton!!.visibility = View.VISIBLE
+ selectButton!!.visibility = if (allVideos) View.GONE else View.VISIBLE
+ playNowButton!!.visibility = View.VISIBLE
+ playNextButton!!.visibility = View.VISIBLE
+ playLastButton!!.visibility = View.VISIBLE
+
+ if (listSize == 0 || songCount < listSize) {
+ moreButton!!.visibility = View.GONE
+ } else {
+ moreButton!!.visibility = View.VISIBLE
+ if (requireArguments().getInt(Constants.INTENT_EXTRA_NAME_RANDOM, 0) > 0) {
+ moreButton!!.setOnClickListener {
+ val offset = requireArguments().getInt(
+ Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0
+ ) + listSize
+ val bundle = Bundle()
+ bundle.putInt(Constants.INTENT_EXTRA_NAME_RANDOM, 1)
+ bundle.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, listSize)
+ bundle.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, offset)
+ Navigation.findNavController(requireView()).navigate(
+ R.id.selectAlbumFragment, bundle
+ )
}
}
-
- pinButton!!.visibility = View.GONE
- unpinButton!!.visibility = View.GONE
- downloadButton!!.visibility = View.GONE
- deleteButton!!.visibility = View.GONE
- selectButton!!.visibility = View.GONE
- playNowButton!!.visibility = View.GONE
- playNextButton!!.visibility = View.GONE
- playLastButton!!.visibility = View.GONE
-
- if (listSize == 0 || result.first.getChildren().size < listSize) {
- albumButtons!!.visibility = View.GONE
- } else {
- moreButton!!.visibility = View.VISIBLE
+ }
+ } else {
+ if (model.showSelectFolderHeader) {
+ if (albumListView!!.headerViewsCount == 0) {
+ albumListView!!.addHeaderView(selectFolderHeader!!.itemView, null, false)
}
}
- enableButtons()
+ pinButton!!.visibility = View.GONE
+ unpinButton!!.visibility = View.GONE
+ downloadButton!!.visibility = View.GONE
+ deleteButton!!.visibility = View.GONE
+ selectButton!!.visibility = View.GONE
+ playNowButton!!.visibility = View.GONE
+ playNextButton!!.visibility = View.GONE
+ playLastButton!!.visibility = View.GONE
- val isAlbumList = arguments!!.containsKey(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE)
- playAllButtonVisible = !(isAlbumList || entries.isEmpty()) && !allVideos
- shareButtonVisible = !isOffline(context) && songCount > 0
-
- albumListView!!.removeHeaderView(emptyView!!)
- if (entries.isEmpty()) {
- emptyView!!.text = "No Media Found"
- emptyView!!.setPadding(10, 10, 10, 10)
- albumListView!!.addHeaderView(emptyView, null, false)
- }
-
- if (playAllButton != null) {
- playAllButton!!.isVisible = playAllButtonVisible
- }
-
- if (shareButton != null) {
- shareButton!!.isVisible = shareButtonVisible
- }
-
- albumListView!!.adapter = EntryAdapter(
- context,
- imageLoaderProvider.getImageLoader(), entries, true
- )
-
- val playAll = arguments!!.getBoolean(Constants.INTENT_EXTRA_NAME_AUTOPLAY, false)
- if (playAll && songCount > 0) {
- playAll(
- arguments!!.getBoolean(Constants.INTENT_EXTRA_NAME_SHUFFLE, false),
- false
- )
+ if (listSize == 0 || musicDirectory.getChildren().size < listSize) {
+ albumButtons!!.visibility = View.GONE
+ } else {
+ moreButton!!.visibility = View.VISIBLE
}
}
- protected fun createHeader(
- entries: List,
- name: CharSequence?,
- songCount: Int
- ): View? {
- val coverArtView = header!!.findViewById(R.id.select_album_art) as ImageView
- val artworkSelection = random.nextInt(entries.size)
- imageLoaderProvider.getImageLoader().loadImage(
- coverArtView, entries[artworkSelection], false,
- Util.getAlbumImageSize(context), false, true
- )
+ enableButtons()
- val albumHeader = AlbumHeader.processEntries(context, entries)
+ val isAlbumList = requireArguments().containsKey(
+ Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE
+ )
- val titleView = header!!.findViewById(R.id.select_album_title) as TextView
- titleView.text = name ?: getTitle(this@SelectAlbumFragment) // getActionBarSubtitle());
+ playAllButtonVisible = !(isAlbumList || entries.isEmpty()) && !allVideos
+ shareButtonVisible = !isOffline(context) && songCount > 0
- // Don't show a header if all entries are videos
- if (albumHeader.isAllVideo) {
- return null
- }
-
- val artistView = header!!.findViewById(R.id.select_album_artist)
- val artist: String
-
- artist = if (albumHeader.artists.size == 1)
- albumHeader.artists.iterator().next()
- else if (albumHeader.grandParents.size == 1)
- albumHeader.grandParents.iterator().next()
- else
- resources.getString(R.string.common_various_artists)
-
- artistView.text = artist
-
- val genreView = header!!.findViewById(R.id.select_album_genre)
- val genre: String
-
- genre = if (albumHeader.genres.size == 1)
- albumHeader.genres.iterator().next()
- else
- resources.getString(R.string.common_multiple_genres)
-
- genreView.text = genre
-
- val yearView = header!!.findViewById(R.id.select_album_year)
- val year: String
-
- year = if (albumHeader.years.size == 1)
- albumHeader.years.iterator().next().toString()
- else
- resources.getString(R.string.common_multiple_years)
-
- yearView.text = year
-
- val songCountView = header!!.findViewById(R.id.select_album_song_count)
- val songs = resources.getQuantityString(
- R.plurals.select_album_n_songs, songCount,
- songCount
- )
- songCountView.text = songs
-
- val duration = Util.formatTotalDuration(albumHeader.totalDuration)
-
- val durationView = header!!.findViewById(R.id.select_album_duration)
- durationView.text = duration
-
- return header
+ albumListView!!.removeHeaderView(emptyView!!)
+ if (entries.isEmpty()) {
+ emptyView!!.text = getString(R.string.select_album_empty)
+ emptyView!!.setPadding(10, 10, 10, 10)
+ albumListView!!.addHeaderView(emptyView, null, false)
}
+
+ if (playAllButton != null) {
+ playAllButton!!.isVisible = playAllButtonVisible
+ }
+
+ if (shareButton != null) {
+ shareButton!!.isVisible = shareButtonVisible
+ }
+
+ albumListView!!.adapter = EntryAdapter(
+ context,
+ imageLoaderProvider.getImageLoader(), entries, true
+ )
+
+ val playAll = requireArguments().getBoolean(Constants.INTENT_EXTRA_NAME_AUTOPLAY, false)
+ if (playAll && songCount > 0) {
+ playAll(
+ requireArguments().getBoolean(Constants.INTENT_EXTRA_NAME_SHUFFLE, false),
+ false
+ )
+ }
+
+ model.currentDirectoryIsSortable = true
+ }
+
+ private fun createHeader(
+ entries: List,
+ name: CharSequence?,
+ songCount: Int
+ ): View? {
+ val coverArtView = header!!.findViewById(R.id.select_album_art) as ImageView
+ val artworkSelection = random.nextInt(entries.size)
+ imageLoaderProvider.getImageLoader().loadImage(
+ coverArtView, entries[artworkSelection], false,
+ Util.getAlbumImageSize(context), false, true
+ )
+
+ val albumHeader = AlbumHeader.processEntries(context, entries)
+
+ val titleView = header!!.findViewById(R.id.select_album_title) as TextView
+ titleView.text = name ?: getTitle(this@SelectAlbumFragment) // getActionBarSubtitle());
+
+ // Don't show a header if all entries are videos
+ if (albumHeader.isAllVideo) {
+ return null
+ }
+
+ val artistView = header!!.findViewById(R.id.select_album_artist)
+
+ val artist: String = when {
+ albumHeader.artists.size == 1 -> albumHeader.artists.iterator().next()
+ albumHeader.grandParents.size == 1 -> albumHeader.grandParents.iterator().next()
+ else -> resources.getString(R.string.common_various_artists)
+ }
+
+ artistView.text = artist
+
+ val genreView = header!!.findViewById(R.id.select_album_genre)
+
+ val genre: String = if (albumHeader.genres.size == 1)
+ albumHeader.genres.iterator().next()
+ else
+ resources.getString(R.string.common_multiple_genres)
+
+ genreView.text = genre
+
+ val yearView = header!!.findViewById(R.id.select_album_year)
+
+ val year: String = if (albumHeader.years.size == 1)
+ albumHeader.years.iterator().next().toString()
+ else
+ resources.getString(R.string.common_multiple_years)
+
+ yearView.text = year
+
+ val songCountView = header!!.findViewById(R.id.select_album_song_count)
+ val songs = resources.getQuantityString(
+ R.plurals.select_album_n_songs, songCount,
+ songCount
+ )
+ songCountView.text = songs
+
+ val duration = Util.formatTotalDuration(albumHeader.totalDuration)
+
+ val durationView = header!!.findViewById(R.id.select_album_duration)
+ durationView.text = duration
+
+ return header
}
private fun getSelectedSongs(albumListView: ListView?): List {
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SelectAlbumModel.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SelectAlbumModel.kt
new file mode 100644
index 00000000..1cbdc1c6
--- /dev/null
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SelectAlbumModel.kt
@@ -0,0 +1,351 @@
+package org.moire.ultrasonic.fragment
+
+import android.app.Application
+import android.content.Context
+import androidx.lifecycle.AndroidViewModel
+import androidx.lifecycle.MutableLiveData
+import java.util.LinkedList
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+import org.koin.core.component.KoinApiExtension
+import org.koin.core.component.KoinComponent
+import org.koin.core.component.inject
+import org.moire.ultrasonic.R
+import org.moire.ultrasonic.api.subsonic.models.AlbumListType
+import org.moire.ultrasonic.data.ActiveServerProvider
+import org.moire.ultrasonic.domain.MusicDirectory
+import org.moire.ultrasonic.domain.MusicFolder
+import org.moire.ultrasonic.service.MusicServiceFactory
+import org.moire.ultrasonic.util.Util
+
+// TODO: Break up this class into smaller more specific classes, extending a base class if necessary
+@KoinApiExtension
+class SelectAlbumModel(application: Application) : AndroidViewModel(application), KoinComponent {
+
+ private val context: Context
+ get() = getApplication().applicationContext
+
+ private val activeServerProvider: ActiveServerProvider by inject()
+
+ private val allSongsId = "-1"
+
+ val musicFolders: MutableLiveData> = MutableLiveData()
+ val albumList: MutableLiveData = MutableLiveData()
+ val currentDirectory: MutableLiveData = MutableLiveData()
+ val songsForGenre: MutableLiveData = MutableLiveData()
+
+ var currentDirectoryIsSortable = true
+ var showHeader = true
+ var showSelectFolderHeader = false
+
+ suspend fun getMusicFolders(refresh: Boolean) {
+ withContext(Dispatchers.IO) {
+ if (!ActiveServerProvider.isOffline(context)) {
+ val musicService = MusicServiceFactory.getMusicService(context)
+ musicFolders.postValue(musicService.getMusicFolders(refresh, context))
+ }
+ }
+ }
+
+ suspend fun getMusicDirectory(
+ refresh: Boolean,
+ id: String?,
+ name: String?,
+ parentId: String?
+ ) {
+ withContext(Dispatchers.IO) {
+ if (!ActiveServerProvider.isOffline(context)) {
+ val service = MusicServiceFactory.getMusicService(context)
+
+ var root = MusicDirectory()
+
+ if (allSongsId == id) {
+ val musicDirectory = service.getMusicDirectory(
+ parentId, name, refresh, context
+ )
+
+ val songs: MutableList = LinkedList()
+ getSongsRecursively(musicDirectory, songs)
+
+ for (song in songs) {
+ if (!song.isDirectory) {
+ root.addChild(song)
+ }
+ }
+ } else {
+ val musicDirectory = service.getMusicDirectory(id, name, refresh, context)
+
+ if (Util.getShouldShowAllSongsByArtist(context) &&
+ musicDirectory.findChild(allSongsId) == null &&
+ hasOnlyFolders(musicDirectory)
+ ) {
+ val allSongs = MusicDirectory.Entry()
+
+ allSongs.isDirectory = true
+ allSongs.artist = name
+ allSongs.parent = id
+ allSongs.id = allSongsId
+ allSongs.title = String.format(
+ context.resources.getString(R.string.select_album_all_songs), name
+ )
+
+ root.addChild(allSongs)
+ root.addAll(musicDirectory.getChildren())
+ } else {
+ root = musicDirectory
+ }
+ }
+
+ currentDirectory.postValue(root)
+ }
+ }
+ }
+
+ // Given a Music directory "songs" it recursively adds all children to "songs"
+ private fun getSongsRecursively(
+ parent: MusicDirectory,
+ songs: MutableList
+ ) {
+ val service = MusicServiceFactory.getMusicService(context)
+
+ for (song in parent.getChildren(includeDirs = false, includeFiles = true)) {
+ if (!song.isVideo && !song.isDirectory) {
+ songs.add(song)
+ }
+ }
+
+ for ((id1, _, _, title) in parent.getChildren(true, includeFiles = false)) {
+ var root: MusicDirectory
+
+ if (allSongsId != id1) {
+ root = service.getMusicDirectory(id1, title, false, context)
+
+ getSongsRecursively(root, songs)
+ }
+ }
+ }
+
+ suspend fun getArtist(refresh: Boolean, id: String?, name: String?) {
+
+ withContext(Dispatchers.IO) {
+ if (!ActiveServerProvider.isOffline(context)) {
+ val service = MusicServiceFactory.getMusicService(context)
+
+ var root = MusicDirectory()
+
+ val musicDirectory = service.getArtist(id, name, refresh, context)
+
+ if (Util.getShouldShowAllSongsByArtist(context) &&
+ musicDirectory.findChild(allSongsId) == null &&
+ hasOnlyFolders(musicDirectory)
+ ) {
+ val allSongs = MusicDirectory.Entry()
+
+ allSongs.isDirectory = true
+ allSongs.artist = name
+ allSongs.parent = id
+ allSongs.id = allSongsId
+ allSongs.title = String.format(
+ context.resources.getString(R.string.select_album_all_songs), name
+ )
+
+ root.addFirst(allSongs)
+ root.addAll(musicDirectory.getChildren())
+ } else {
+ root = musicDirectory
+ }
+ currentDirectory.postValue(root)
+ }
+ }
+ }
+
+ suspend fun getAlbum(refresh: Boolean, id: String?, name: String?, parentId: String?) {
+
+ withContext(Dispatchers.IO) {
+ if (!ActiveServerProvider.isOffline(context)) {
+
+ val service = MusicServiceFactory.getMusicService(context)
+
+ val musicDirectory: MusicDirectory
+
+ musicDirectory = if (allSongsId == id) {
+ val root = MusicDirectory()
+
+ val songs: MutableCollection = LinkedList()
+ val artist = service.getArtist(parentId, "", false, context)
+
+ for ((id1) in artist.getChildren()) {
+ if (allSongsId != id1) {
+ val albumDirectory = service.getAlbum(
+ id1, "", false, context
+ )
+
+ for (song in albumDirectory.getChildren()) {
+ if (!song.isVideo) {
+ songs.add(song)
+ }
+ }
+ }
+ }
+
+ for (song in songs) {
+ if (!song.isDirectory) {
+ root.addChild(song)
+ }
+ }
+ root
+ } else {
+ service.getAlbum(id, name, refresh, context)
+ }
+ currentDirectory.postValue(musicDirectory)
+ }
+ }
+ }
+
+ suspend fun getSongsForGenre(genre: String, count: Int, offset: Int) {
+ withContext(Dispatchers.IO) {
+ if (!ActiveServerProvider.isOffline(context)) {
+ val service = MusicServiceFactory.getMusicService(context)
+ val musicDirectory = service.getSongsByGenre(genre, count, offset, context)
+ songsForGenre.postValue(musicDirectory)
+ }
+ }
+ }
+
+ suspend fun getStarred() {
+
+ withContext(Dispatchers.IO) {
+ if (!ActiveServerProvider.isOffline(context)) {
+
+ val service = MusicServiceFactory.getMusicService(context)
+ val musicDirectory: MusicDirectory
+ val context = context
+
+ if (Util.getShouldUseId3Tags(context)) {
+ musicDirectory = Util.getSongsFromSearchResult(service.getStarred2(context))
+ } else {
+ musicDirectory = Util.getSongsFromSearchResult(service.getStarred(context))
+ }
+
+ currentDirectory.postValue(musicDirectory)
+ }
+ }
+ }
+
+ suspend fun getVideos(refresh: Boolean) {
+ showHeader = false
+
+ withContext(Dispatchers.IO) {
+ if (!ActiveServerProvider.isOffline(context)) {
+ val service = MusicServiceFactory.getMusicService(context)
+ currentDirectory.postValue(service.getVideos(refresh, context))
+ }
+ }
+ }
+
+ suspend fun getRandom(size: Int) {
+
+ withContext(Dispatchers.IO) {
+ if (!ActiveServerProvider.isOffline(context)) {
+ val service = MusicServiceFactory.getMusicService(context)
+ val musicDirectory = service.getRandomSongs(size, context)
+
+ currentDirectoryIsSortable = false
+ currentDirectory.postValue(musicDirectory)
+ }
+ }
+ }
+
+ suspend fun getPlaylist(playlistId: String, playlistName: String?) {
+
+ withContext(Dispatchers.IO) {
+ if (!ActiveServerProvider.isOffline(context)) {
+ val service = MusicServiceFactory.getMusicService(context)
+ val musicDirectory = service.getPlaylist(playlistId, playlistName, context)
+
+ currentDirectory.postValue(musicDirectory)
+ }
+ }
+ }
+
+ suspend fun getPodcastEpisodes(podcastChannelId: String) {
+
+ withContext(Dispatchers.IO) {
+ if (!ActiveServerProvider.isOffline(context)) {
+ val service = MusicServiceFactory.getMusicService(context)
+ val musicDirectory = service.getPodcastEpisodes(podcastChannelId, context)
+ currentDirectory.postValue(musicDirectory)
+ }
+ }
+ }
+
+ suspend fun getShare(shareId: String) {
+
+ withContext(Dispatchers.IO) {
+ if (!ActiveServerProvider.isOffline(context)) {
+ val service = MusicServiceFactory.getMusicService(context)
+ val musicDirectory = MusicDirectory()
+
+ val shares = service.getShares(true, context)
+
+ for (share in shares) {
+ if (share.id == shareId) {
+ for (entry in share.getEntries()) {
+ musicDirectory.addChild(entry)
+ }
+ break
+ }
+ }
+ currentDirectory.postValue(musicDirectory)
+ }
+ }
+ }
+
+ suspend fun getAlbumList(albumListType: String, size: Int, offset: Int) {
+
+ showHeader = false
+ showSelectFolderHeader = !ActiveServerProvider.isOffline(context) &&
+ !Util.getShouldUseId3Tags(context) && (
+ (albumListType == AlbumListType.SORTED_BY_NAME.toString()) ||
+ (albumListType == AlbumListType.SORTED_BY_ARTIST.toString())
+ )
+
+ withContext(Dispatchers.IO) {
+ if (!ActiveServerProvider.isOffline(context)) {
+ val service = MusicServiceFactory.getMusicService(context)
+ val musicDirectory: MusicDirectory
+ val musicFolderId = if (showSelectFolderHeader) {
+ activeServerProvider.getActiveServer().musicFolderId
+ } else {
+ null
+ }
+
+ if (Util.getShouldUseId3Tags(context)) {
+ musicDirectory = service.getAlbumList2(
+ albumListType, size,
+ offset, musicFolderId, context
+ )
+ } else {
+ musicDirectory = service.getAlbumList(
+ albumListType, size,
+ offset, musicFolderId, context
+ )
+ }
+
+ currentDirectoryIsSortable = sortableCollection(albumListType)
+ albumList.postValue(musicDirectory)
+ }
+ }
+ }
+
+ private fun sortableCollection(albumListType: String): Boolean {
+ return albumListType != "newest" && albumListType != "random" &&
+ albumListType != "highest" && albumListType != "recent" &&
+ albumListType != "frequent"
+ }
+
+ // Returns true if the directory contains only folders
+ private fun hasOnlyFolders(musicDirectory: MusicDirectory) =
+ musicDirectory.getChildren(includeDirs = true, includeFiles = false).size ==
+ musicDirectory.getChildren(includeDirs = true, includeFiles = true).size
+}
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/ServerSettingsModel.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/ServerSettingsModel.kt
index 0e1e9f79..02386b5e 100644
--- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/ServerSettingsModel.kt
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/ServerSettingsModel.kt
@@ -1,9 +1,9 @@
package org.moire.ultrasonic.fragment
-import android.content.Context
+import android.app.Application
import android.content.SharedPreferences
+import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
-import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.preference.PreferenceManager
import kotlinx.coroutines.CoroutineScope
@@ -22,8 +22,8 @@ import timber.log.Timber
class ServerSettingsModel(
private val repository: ServerSettingDao,
private val activeServerProvider: ActiveServerProvider,
- private val context: Context
-) : ViewModel() {
+ application: Application
+) : AndroidViewModel(application) {
companion object {
private const val PREFERENCES_KEY_SERVER_MIGRATED = "serverMigrated"
@@ -54,6 +54,7 @@ class ServerSettingsModel(
if (rowCount == null || rowCount == 0) {
// First time load up the server settings from the Preferences
val dbServerList = mutableListOf()
+ val context = getApplication().applicationContext
val settings = PreferenceManager.getDefaultSharedPreferences(context)
val serverNum = settings.getInt(PREFERENCES_KEY_ACTIVE_SERVERS, 0)
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/LocalMediaPlayer.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/LocalMediaPlayer.kt
index 612383a1..2332d54e 100644
--- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/LocalMediaPlayer.kt
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/LocalMediaPlayer.kt
@@ -119,7 +119,6 @@ class LocalMediaPlayer(
}.start()
wakeLock.setReferenceCounted(false)
- Util.registerMediaButtonEventReceiver(context, true)
Timber.i("LocalMediaPlayer created")
}
@@ -146,7 +145,7 @@ class LocalMediaPlayer(
if (nextPlayingTask != null) {
nextPlayingTask!!.cancel()
}
- Util.unregisterMediaButtonEventReceiver(context, true)
+
wakeLock.release()
} catch (exception: Throwable) {
Timber.w(exception, "LocalMediaPlayer onDestroy exception: ")
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MediaPlayerService.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MediaPlayerService.kt
index 9f8d8578..94f05c8b 100644
--- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MediaPlayerService.kt
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MediaPlayerService.kt
@@ -12,6 +12,7 @@ import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.Service
+import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.os.Build
@@ -22,7 +23,6 @@ import android.support.v4.media.session.PlaybackStateCompat
import android.view.KeyEvent
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
-import java.util.ArrayList
import org.koin.android.ext.android.inject
import org.moire.ultrasonic.R
import org.moire.ultrasonic.activity.NavigationActivity
@@ -33,6 +33,7 @@ import org.moire.ultrasonic.provider.UltrasonicAppWidgetProvider4X1
import org.moire.ultrasonic.provider.UltrasonicAppWidgetProvider4X2
import org.moire.ultrasonic.provider.UltrasonicAppWidgetProvider4X3
import org.moire.ultrasonic.provider.UltrasonicAppWidgetProvider4X4
+import org.moire.ultrasonic.receiver.MediaButtonIntentReceiver
import org.moire.ultrasonic.service.MusicServiceFactory.getMusicService
import org.moire.ultrasonic.util.Constants
import org.moire.ultrasonic.util.FileUtil
@@ -792,7 +793,8 @@ class MediaPlayerService : Service() {
mediaSession = MediaSessionCompat(applicationContext, "UltrasonicService")
mediaSessionToken = mediaSession!!.sessionToken
- // mediaController = new MediaControllerCompat(getApplicationContext(), mediaSessionToken);
+
+ updateMediaButtonReceiver()
mediaSession!!.setCallback(object : MediaSessionCompat.Callback() {
override fun onPlay() {
@@ -838,10 +840,39 @@ class MediaPlayerService : Service() {
)
}
+ fun updateMediaButtonReceiver() {
+ if (Util.getMediaButtonsEnabled(applicationContext)) {
+ registerMediaButtonEventReceiver()
+ } else {
+ unregisterMediaButtonEventReceiver()
+ }
+ }
+
+ fun registerMediaButtonEventReceiver() {
+ val component = ComponentName(packageName, MediaButtonIntentReceiver::class.java.name)
+ val mediaButtonIntent = Intent(Intent.ACTION_MEDIA_BUTTON)
+ mediaButtonIntent.component = component
+
+ val pendingIntent = PendingIntent.getBroadcast(
+ this,
+ INTENT_CODE_MEDIA_BUTTON,
+ mediaButtonIntent,
+ PendingIntent.FLAG_CANCEL_CURRENT
+ )
+
+ mediaSession?.setMediaButtonReceiver(pendingIntent)
+ }
+
+ fun unregisterMediaButtonEventReceiver() {
+ mediaSession?.setMediaButtonReceiver(null)
+ }
+
companion object {
private const val NOTIFICATION_CHANNEL_ID = "org.moire.ultrasonic"
private const val NOTIFICATION_CHANNEL_NAME = "Ultrasonic background service"
private const val NOTIFICATION_ID = 3033
+ private const val INTENT_CODE_MEDIA_BUTTON = 161
+
private var instance: MediaPlayerService? = null
private val instanceLock = Any()
@@ -872,7 +903,7 @@ class MediaPlayerService : Service() {
@JvmStatic
fun executeOnStartedMediaPlayerService(
context: Context,
- taskToExecute: Consumer
+ taskToExecute: (MediaPlayerService?) -> Unit
) {
val t: Thread = object : Thread() {
@@ -882,7 +913,7 @@ class MediaPlayerService : Service() {
Timber.e("ExecuteOnStarted.. failed to get a MediaPlayerService instance!")
return
}
- taskToExecute.accept(instance)
+ taskToExecute(instance)
}
}
t.start()