Minor fixes

Cleaned up TODOs
Cleaned up code
This commit is contained in:
Nite 2021-02-14 15:55:16 +01:00
parent d70d2cc2fb
commit 86bfcefe93
No known key found for this signature in database
GPG Key ID: 1D1AD59B1C6386C1
50 changed files with 1226 additions and 1304 deletions

View File

@ -19,8 +19,6 @@ import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import org.moire.ultrasonic.R;
import org.moire.ultrasonic.util.Util;
import timber.log.Timber;
public class AboutFragment extends Fragment {
private WebView webView;

View File

@ -27,7 +27,7 @@ import org.moire.ultrasonic.subsonic.VideoPlayer;
import org.moire.ultrasonic.util.CancellationToken;
import org.moire.ultrasonic.util.Constants;
import org.moire.ultrasonic.util.Pair;
import org.moire.ultrasonic.util.TabActivityBackgroundTask;
import org.moire.ultrasonic.util.FragmentBackgroundTask;
import org.moire.ultrasonic.util.Util;
import org.moire.ultrasonic.view.EntryAdapter;
@ -35,7 +35,6 @@ import java.util.ArrayList;
import java.util.List;
import kotlin.Lazy;
import timber.log.Timber;
import static org.koin.java.KoinJavaComponent.inject;
@ -73,6 +72,7 @@ public class BookmarksFragment extends Fragment {
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
cancellationToken = new CancellationToken();
albumButtons = view.findViewById(R.id.menu_album);
super.onViewCreated(view, savedInstanceState);
refreshAlbumListView = view.findViewById(R.id.select_album_entries_refresh);
albumListView = view.findViewById(R.id.select_album_entries_list);
@ -186,7 +186,6 @@ public class BookmarksFragment extends Fragment {
FragmentTitle.Companion.setTitle(this, R.string.button_bar_bookmarks);
enableButtons();
getBookmarks();
}
@ -203,7 +202,7 @@ public class BookmarksFragment extends Fragment {
@Override
protected MusicDirectory load(MusicService service) throws Exception
{
return Util.getSongsFromBookmarks(service.getBookmarks(getContext(), this));
return Util.getSongsFromBookmarks(service.getBookmarks(getContext()));
}
}.execute();
}
@ -239,27 +238,8 @@ public class BookmarksFragment extends Fragment {
private void refresh()
{
// TODO: create better restart
getView().post(new Runnable() {
public void run() {
Timber.d("Refresh called...");
if (getArguments() == null) {
Bundle bundle = new Bundle();
bundle.putBoolean(Constants.INTENT_EXTRA_NAME_REFRESH, true);
setArguments(bundle);
} else {
getArguments().putBoolean(Constants.INTENT_EXTRA_NAME_REFRESH, true);
}
onViewCreated(getView(), null);
}
});
/* finish();
Intent intent = getIntent();
intent.putExtra(Constants.INTENT_EXTRA_NAME_REFRESH, true);
startActivityForResultWithoutTransition(this, intent);
*/
enableButtons();
getBookmarks();
}
private void selectAllOrNone()
@ -392,7 +372,7 @@ public class BookmarksFragment extends Fragment {
mediaPlayerController.getValue().unpin(songs);
}
private abstract class LoadTask extends TabActivityBackgroundTask<Pair<MusicDirectory, Boolean>>
private abstract class LoadTask extends FragmentBackgroundTask<Pair<MusicDirectory, Boolean>>
{
public LoadTask()
{
@ -406,7 +386,7 @@ public class BookmarksFragment extends Fragment {
{
MusicService musicService = MusicServiceFactory.getMusicService(getContext());
MusicDirectory dir = load(musicService);
boolean valid = musicService.isLicenseValid(getContext(), this);
boolean valid = musicService.isLicenseValid(getContext());
return new Pair<>(dir, valid);
}

View File

@ -21,6 +21,7 @@ import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import org.moire.ultrasonic.R;
import org.moire.ultrasonic.data.ActiveServerProvider;
@ -29,7 +30,7 @@ import org.moire.ultrasonic.service.MusicService;
import org.moire.ultrasonic.service.MusicServiceFactory;
import org.moire.ultrasonic.util.BackgroundTask;
import org.moire.ultrasonic.util.CancellationToken;
import org.moire.ultrasonic.util.TabActivityBackgroundTask;
import org.moire.ultrasonic.util.FragmentBackgroundTask;
import org.moire.ultrasonic.util.Util;
import org.moire.ultrasonic.view.ChatAdapter;
@ -52,6 +53,7 @@ public class ChatFragment extends Fragment {
private volatile static Long lastChatMessageTime = (long) 0;
private static final ArrayList<ChatMessage> messageList = new ArrayList<ChatMessage>();
private CancellationToken cancellationToken;
private SwipeRefreshLayout swipeRefresh;
private final Lazy<ActiveServerProvider> activeServerProvider = inject(ActiveServerProvider.class);
@ -70,6 +72,9 @@ public class ChatFragment extends Fragment {
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
swipeRefresh = view.findViewById(R.id.chat_refresh);
swipeRefresh.setEnabled(false);
cancellationToken = new CancellationToken();
messageEditText = view.findViewById(R.id.chat_edittext);
sendButton = view.findViewById(R.id.chat_send);
@ -238,13 +243,13 @@ public class ChatFragment extends Fragment {
{
messageEditText.setText("");
BackgroundTask<Void> task = new TabActivityBackgroundTask<Void>(getActivity(), false, null, cancellationToken)
BackgroundTask<Void> task = new FragmentBackgroundTask<Void>(getActivity(), false, swipeRefresh, cancellationToken)
{
@Override
protected Void doInBackground() throws Throwable
{
MusicService musicService = MusicServiceFactory.getMusicService(getContext());
musicService.addChatMessage(message, getContext(), this);
musicService.addChatMessage(message, getContext());
return null;
}
@ -262,14 +267,13 @@ public class ChatFragment extends Fragment {
private synchronized void load()
{
// TODO: Do we need a SwipeToRefresh progress indicator?
BackgroundTask<List<ChatMessage>> task = new TabActivityBackgroundTask<List<ChatMessage>>(getActivity(), false, null, cancellationToken)
BackgroundTask<List<ChatMessage>> task = new FragmentBackgroundTask<List<ChatMessage>>(getActivity(), false, swipeRefresh, cancellationToken)
{
@Override
protected List<ChatMessage> doInBackground() throws Throwable
{
MusicService musicService = MusicServiceFactory.getMusicService(getContext());
return musicService.getChatMessages(lastChatMessageTime, getContext(), this);
return musicService.getChatMessages(lastChatMessageTime, getContext());
}
@Override

View File

@ -18,7 +18,7 @@ import org.moire.ultrasonic.service.MusicServiceFactory;
import org.moire.ultrasonic.util.BackgroundTask;
import org.moire.ultrasonic.util.CancellationToken;
import org.moire.ultrasonic.util.Constants;
import org.moire.ultrasonic.util.TabActivityBackgroundTask;
import org.moire.ultrasonic.util.FragmentBackgroundTask;
import org.moire.ultrasonic.util.Util;
import timber.log.Timber;
@ -66,15 +66,17 @@ public class LyricsFragment extends Fragment {
private void load()
{
BackgroundTask<Lyrics> task = new TabActivityBackgroundTask<Lyrics>(getActivity(), true, swipe, cancellationToken)
BackgroundTask<Lyrics> task = new FragmentBackgroundTask<Lyrics>(getActivity(), true, swipe, cancellationToken)
{
@Override
protected Lyrics doInBackground() throws Throwable
{
String artist = getArguments().getString(Constants.INTENT_EXTRA_NAME_ARTIST);
String title = getArguments().getString(Constants.INTENT_EXTRA_NAME_TITLE);
Bundle arguments = getArguments();
if (arguments == null) return null;
String artist = arguments.getString(Constants.INTENT_EXTRA_NAME_ARTIST);
String title = arguments.getString(Constants.INTENT_EXTRA_NAME_TITLE);
MusicService musicService = MusicServiceFactory.getMusicService(getContext());
return musicService.getLyrics(artist, title, getContext(), this);
return musicService.getLyrics(artist, title, getContext());
}
@Override

View File

@ -1,7 +1,5 @@
package org.moire.ultrasonic.fragment;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;

View File

@ -134,7 +134,7 @@ public class NowPlayingFragment extends Fragment {
}
});
// TODO: Check if this empty onClickListener is necessary
// This empty onClickListener is necessary for the onTouchListener to work
getView().setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {

View File

@ -115,7 +115,6 @@ public class PlayerFragment extends Fragment implements GestureDetector.OnGestur
private SilentBackgroundTask<Void> onProgressChangedTask;
LinearLayout visualizerViewLayout;
private MenuItem starMenuItem;
private LinearLayout ratingLinearLayout;
private ImageView fiveStar1ImageView;
private ImageView fiveStar2ImageView;
private ImageView fiveStar3ImageView;
@ -188,7 +187,7 @@ public class PlayerFragment extends Fragment implements GestureDetector.OnGestur
visualizerViewLayout = view.findViewById(R.id.download_visualizer_view_layout);
ratingLinearLayout = view.findViewById(R.id.song_rating);
LinearLayout ratingLinearLayout = view.findViewById(R.id.song_rating);
fiveStar1ImageView = view.findViewById(R.id.song_five_star_1);
fiveStar2ImageView = view.findViewById(R.id.song_five_star_2);
fiveStar3ImageView = view.findViewById(R.id.song_five_star_3);
@ -197,7 +196,7 @@ public class PlayerFragment extends Fragment implements GestureDetector.OnGestur
if (!useFiveStarRating) ratingLinearLayout.setVisibility(View.GONE);
hollowStar = Util.getDrawableFromAttribute(getContext(), R.attr.star_hollow);
hollowStar = Util.getDrawableFromAttribute(view.getContext(), R.attr.star_hollow);
fullStar = Util.getDrawableFromAttribute(getContext(), R.attr.star_full);
fiveStar1ImageView.setOnClickListener(new View.OnClickListener()
@ -893,250 +892,207 @@ public class PlayerFragment extends Fragment implements GestureDetector.OnGestur
entry = song.getSong();
}
switch (menuItemId)
{
case R.id.menu_show_artist:
if (entry == null)
{
return false;
}
if (Util.getShouldUseId3Tags(getContext()))
{
bundle = new Bundle();
bundle.putString(Constants.INTENT_EXTRA_NAME_ID, entry.getArtistId());
bundle.putString(Constants.INTENT_EXTRA_NAME_NAME, entry.getArtist());
bundle.putString(Constants.INTENT_EXTRA_NAME_PARENT_ID, entry.getArtistId());
bundle.putBoolean(Constants.INTENT_EXTRA_NAME_ARTIST, true);
Navigation.findNavController(getView()).navigate(R.id.playerToSelectAlbum, bundle);
}
return true;
case R.id.menu_show_album:
if (entry == null)
{
return false;
}
String albumId = Util.getShouldUseId3Tags(getContext()) ? entry.getAlbumId() : entry.getParent();
bundle = new Bundle();
bundle.putString(Constants.INTENT_EXTRA_NAME_ID, albumId);
bundle.putString(Constants.INTENT_EXTRA_NAME_NAME, entry.getAlbum());
bundle.putString(Constants.INTENT_EXTRA_NAME_PARENT_ID, entry.getParent());
bundle.putBoolean(Constants.INTENT_EXTRA_NAME_IS_ALBUM, true);
Navigation.findNavController(getView()).navigate(R.id.playerToSelectAlbum, bundle);
return true;
case R.id.menu_lyrics:
if (entry == null)
{
return false;
}
bundle = new Bundle();
bundle.putString(Constants.INTENT_EXTRA_NAME_ARTIST, entry.getArtist());
bundle.putString(Constants.INTENT_EXTRA_NAME_TITLE, entry.getTitle());
Navigation.findNavController(getView()).navigate(R.id.playerToLyrics, bundle);
return true;
case R.id.menu_remove:
mediaPlayerControllerLazy.getValue().remove(song);
onDownloadListChanged();
return true;
case R.id.menu_item_screen_on_off:
if (mediaPlayerControllerLazy.getValue().getKeepScreenOn())
{
getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
mediaPlayerControllerLazy.getValue().setKeepScreenOn(false);
}
else
{
getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
mediaPlayerControllerLazy.getValue().setKeepScreenOn(true);
}
return true;
case R.id.menu_shuffle:
mediaPlayerControllerLazy.getValue().shuffle();
Util.toast(getContext(), R.string.download_menu_shuffle_notification);
return true;
case R.id.menu_item_equalizer:
Navigation.findNavController(getView()).navigate(R.id.playerToEqualizer);
return true;
case R.id.menu_item_visualizer:
final boolean active = !visualizerView.isActive();
visualizerView.setActive(active);
if (!visualizerView.isActive())
{
visualizerViewLayout.setVisibility(View.GONE);
}
else
{
visualizerViewLayout.setVisibility(View.VISIBLE);
}
mediaPlayerControllerLazy.getValue().setShowVisualization(visualizerView.isActive());
Util.toast(getContext(), active ? R.string.download_visualizer_on : R.string.download_visualizer_off);
return true;
case R.id.menu_item_jukebox:
final boolean jukeboxEnabled = !mediaPlayerControllerLazy.getValue().isJukeboxEnabled();
mediaPlayerControllerLazy.getValue().setJukeboxEnabled(jukeboxEnabled);
Util.toast(getContext(), jukeboxEnabled ? R.string.download_jukebox_on : R.string.download_jukebox_off, false);
return true;
case R.id.menu_item_toggle_list:
toggleFullScreenAlbumArt();
return true;
case R.id.menu_item_clear_playlist:
mediaPlayerControllerLazy.getValue().setShufflePlayEnabled(false);
mediaPlayerControllerLazy.getValue().clear();
onDownloadListChanged();
return true;
case R.id.menu_item_save_playlist:
if (mediaPlayerControllerLazy.getValue().getPlaylistSize() > 0)
{
showSavePlaylistDialog();
}
return true;
case R.id.menu_item_star:
if (currentSong == null)
{
return true;
}
final boolean isStarred = currentSong.getStarred();
final String id = currentSong.getId();
if (isStarred)
{
starMenuItem.setIcon(hollowStar);
currentSong.setStarred(false);
}
else
{
starMenuItem.setIcon(fullStar);
currentSong.setStarred(true);
}
new Thread(new Runnable()
{
@Override
public void run()
{
final MusicService musicService = MusicServiceFactory.getMusicService(getContext());
try
{
if (isStarred)
{
musicService.unstar(id, null, null, getContext(), null);
}
else
{
musicService.star(id, null, null, getContext(), null);
}
}
catch (Exception e)
{
Timber.e(e);
}
}
}).start();
return true;
case R.id.menu_item_bookmark_set:
if (currentSong == null)
{
return true;
}
final String songId = currentSong.getId();
final int playerPosition = mediaPlayerControllerLazy.getValue().getPlayerPosition();
currentSong.setBookmarkPosition(playerPosition);
String bookmarkTime = Util.formatTotalDuration(playerPosition, true);
new Thread(new Runnable()
{
@Override
public void run()
{
final MusicService musicService = MusicServiceFactory.getMusicService(getContext());
try
{
musicService.createBookmark(songId, playerPosition, getContext(), null);
}
catch (Exception e)
{
Timber.e(e);
}
}
}).start();
String msg = getResources().getString(R.string.download_bookmark_set_at_position, bookmarkTime);
Util.toast(getContext(), msg);
return true;
case R.id.menu_item_bookmark_delete:
if (currentSong == null)
{
return true;
}
final String bookmarkSongId = currentSong.getId();
currentSong.setBookmarkPosition(0);
new Thread(new Runnable()
{
@Override
public void run()
{
final MusicService musicService = MusicServiceFactory.getMusicService(getContext());
try
{
musicService.deleteBookmark(bookmarkSongId, getContext(), null);
}
catch (Exception e)
{
Timber.e(e);
}
}
}).start();
Util.toast(getContext(), R.string.download_bookmark_removed);
return true;
case R.id.menu_item_share:
MediaPlayerController mediaPlayerController = mediaPlayerControllerLazy.getValue();
List<MusicDirectory.Entry> entries = new ArrayList<>();
if (mediaPlayerController != null)
{
List<DownloadFile> downloadServiceSongs = mediaPlayerController.getPlayList();
if (downloadServiceSongs != null)
{
for (DownloadFile downloadFile : downloadServiceSongs)
{
if (downloadFile != null)
{
MusicDirectory.Entry playlistEntry = downloadFile.getSong();
if (playlistEntry != null)
{
entries.add(playlistEntry);
}
}
}
}
}
shareHandler.getValue().createShare(this, entries, null, cancellationToken);
return true;
default:
if (menuItemId == R.id.menu_show_artist) {
if (entry == null) {
return false;
}
if (Util.getShouldUseId3Tags(getContext())) {
bundle = new Bundle();
bundle.putString(Constants.INTENT_EXTRA_NAME_ID, entry.getArtistId());
bundle.putString(Constants.INTENT_EXTRA_NAME_NAME, entry.getArtist());
bundle.putString(Constants.INTENT_EXTRA_NAME_PARENT_ID, entry.getArtistId());
bundle.putBoolean(Constants.INTENT_EXTRA_NAME_ARTIST, true);
Navigation.findNavController(getView()).navigate(R.id.playerToSelectAlbum, bundle);
}
return true;
} else if (menuItemId == R.id.menu_show_album) {
if (entry == null) {
return false;
}
String albumId = Util.getShouldUseId3Tags(getContext()) ? entry.getAlbumId() : entry.getParent();
bundle = new Bundle();
bundle.putString(Constants.INTENT_EXTRA_NAME_ID, albumId);
bundle.putString(Constants.INTENT_EXTRA_NAME_NAME, entry.getAlbum());
bundle.putString(Constants.INTENT_EXTRA_NAME_PARENT_ID, entry.getParent());
bundle.putBoolean(Constants.INTENT_EXTRA_NAME_IS_ALBUM, true);
Navigation.findNavController(getView()).navigate(R.id.playerToSelectAlbum, bundle);
return true;
} else if (menuItemId == R.id.menu_lyrics) {
if (entry == null) {
return false;
}
bundle = new Bundle();
bundle.putString(Constants.INTENT_EXTRA_NAME_ARTIST, entry.getArtist());
bundle.putString(Constants.INTENT_EXTRA_NAME_TITLE, entry.getTitle());
Navigation.findNavController(getView()).navigate(R.id.playerToLyrics, bundle);
return true;
} else if (menuItemId == R.id.menu_remove) {
mediaPlayerControllerLazy.getValue().remove(song);
onDownloadListChanged();
return true;
} else if (menuItemId == R.id.menu_item_screen_on_off) {
if (mediaPlayerControllerLazy.getValue().getKeepScreenOn()) {
getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
mediaPlayerControllerLazy.getValue().setKeepScreenOn(false);
} else {
getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
mediaPlayerControllerLazy.getValue().setKeepScreenOn(true);
}
return true;
} else if (menuItemId == R.id.menu_shuffle) {
mediaPlayerControllerLazy.getValue().shuffle();
Util.toast(getContext(), R.string.download_menu_shuffle_notification);
return true;
} else if (menuItemId == R.id.menu_item_equalizer) {
Navigation.findNavController(getView()).navigate(R.id.playerToEqualizer);
return true;
} else if (menuItemId == R.id.menu_item_visualizer) {
final boolean active = !visualizerView.isActive();
visualizerView.setActive(active);
if (!visualizerView.isActive()) {
visualizerViewLayout.setVisibility(View.GONE);
} else {
visualizerViewLayout.setVisibility(View.VISIBLE);
}
mediaPlayerControllerLazy.getValue().setShowVisualization(visualizerView.isActive());
Util.toast(getContext(), active ? R.string.download_visualizer_on : R.string.download_visualizer_off);
return true;
} else if (menuItemId == R.id.menu_item_jukebox) {
final boolean jukeboxEnabled = !mediaPlayerControllerLazy.getValue().isJukeboxEnabled();
mediaPlayerControllerLazy.getValue().setJukeboxEnabled(jukeboxEnabled);
Util.toast(getContext(), jukeboxEnabled ? R.string.download_jukebox_on : R.string.download_jukebox_off, false);
return true;
} else if (menuItemId == R.id.menu_item_toggle_list) {
toggleFullScreenAlbumArt();
return true;
} else if (menuItemId == R.id.menu_item_clear_playlist) {
mediaPlayerControllerLazy.getValue().setShufflePlayEnabled(false);
mediaPlayerControllerLazy.getValue().clear();
onDownloadListChanged();
return true;
} else if (menuItemId == R.id.menu_item_save_playlist) {
if (mediaPlayerControllerLazy.getValue().getPlaylistSize() > 0) {
showSavePlaylistDialog();
}
return true;
} else if (menuItemId == R.id.menu_item_star) {
if (currentSong == null) {
return true;
}
final boolean isStarred = currentSong.getStarred();
final String id = currentSong.getId();
if (isStarred) {
starMenuItem.setIcon(hollowStar);
currentSong.setStarred(false);
} else {
starMenuItem.setIcon(fullStar);
currentSong.setStarred(true);
}
new Thread(new Runnable() {
@Override
public void run() {
final MusicService musicService = MusicServiceFactory.getMusicService(getContext());
try {
if (isStarred) {
musicService.unstar(id, null, null, getContext());
} else {
musicService.star(id, null, null, getContext());
}
} catch (Exception e) {
Timber.e(e);
}
}
}).start();
return true;
} else if (menuItemId == R.id.menu_item_bookmark_set) {
if (currentSong == null) {
return true;
}
final String songId = currentSong.getId();
final int playerPosition = mediaPlayerControllerLazy.getValue().getPlayerPosition();
currentSong.setBookmarkPosition(playerPosition);
String bookmarkTime = Util.formatTotalDuration(playerPosition, true);
new Thread(new Runnable() {
@Override
public void run() {
final MusicService musicService = MusicServiceFactory.getMusicService(getContext());
try {
musicService.createBookmark(songId, playerPosition, getContext());
} catch (Exception e) {
Timber.e(e);
}
}
}).start();
String msg = getResources().getString(R.string.download_bookmark_set_at_position, bookmarkTime);
Util.toast(getContext(), msg);
return true;
} else if (menuItemId == R.id.menu_item_bookmark_delete) {
if (currentSong == null) {
return true;
}
final String bookmarkSongId = currentSong.getId();
currentSong.setBookmarkPosition(0);
new Thread(new Runnable() {
@Override
public void run() {
final MusicService musicService = MusicServiceFactory.getMusicService(getContext());
try {
musicService.deleteBookmark(bookmarkSongId, getContext());
} catch (Exception e) {
Timber.e(e);
}
}
}).start();
Util.toast(getContext(), R.string.download_bookmark_removed);
return true;
} else if (menuItemId == R.id.menu_item_share) {
MediaPlayerController mediaPlayerController = mediaPlayerControllerLazy.getValue();
List<MusicDirectory.Entry> entries = new ArrayList<>();
if (mediaPlayerController != null) {
List<DownloadFile> downloadServiceSongs = mediaPlayerController.getPlayList();
if (downloadServiceSongs != null) {
for (DownloadFile downloadFile : downloadServiceSongs) {
if (downloadFile != null) {
MusicDirectory.Entry playlistEntry = downloadFile.getSong();
if (playlistEntry != null) {
entries.add(playlistEntry);
}
}
}
}
}
shareHandler.getValue().createShare(this, entries, null, cancellationToken);
return true;
}
return false;
}
private void update(CancellationToken cancel)
@ -1178,7 +1134,7 @@ public class PlayerFragment extends Fragment implements GestureDetector.OnGestur
entries.add(downloadFile.getSong());
}
final MusicService musicService = MusicServiceFactory.getMusicService(getContext());
musicService.createPlaylist(null, playlistName, entries, getContext(), null);
musicService.createPlaylist(null, playlistName, entries, getContext());
return null;
}

View File

@ -41,14 +41,13 @@ import org.moire.ultrasonic.util.CacheCleaner;
import org.moire.ultrasonic.util.CancellationToken;
import org.moire.ultrasonic.util.Constants;
import org.moire.ultrasonic.util.LoadingTask;
import org.moire.ultrasonic.util.TabActivityBackgroundTask;
import org.moire.ultrasonic.util.FragmentBackgroundTask;
import org.moire.ultrasonic.util.Util;
import org.moire.ultrasonic.view.PlaylistAdapter;
import java.util.List;
import kotlin.Lazy;
import timber.log.Timber;
import static org.koin.java.KoinJavaComponent.inject;
@ -109,10 +108,9 @@ public class PlaylistsFragment extends Fragment {
}
});
registerForContextMenu(playlistsListView);
FragmentTitle.Companion.setTitle(this, R.string.playlist_label);
load();
load(false);
}
@Override
@ -123,38 +121,18 @@ public class PlaylistsFragment extends Fragment {
private void refresh()
{
// TODO: create better restart
getView().post(new Runnable() {
public void run() {
Timber.d("Refresh called...");
if (getArguments() == null) {
Bundle bundle = new Bundle();
bundle.putBoolean(Constants.INTENT_EXTRA_NAME_REFRESH, true);
setArguments(bundle);
} else {
getArguments().putBoolean(Constants.INTENT_EXTRA_NAME_REFRESH, true);
}
onViewCreated(getView(), null);
}
});
/* finish();
Intent intent = new Intent(this, SelectPlaylistActivity.class);
intent.putExtra(Constants.INTENT_EXTRA_NAME_REFRESH, true);
startActivityForResultWithoutTransition(this, intent);
*/
load(true);
}
private void load()
private void load(final boolean refresh)
{
BackgroundTask<List<Playlist>> task = new TabActivityBackgroundTask<List<Playlist>>(getActivity(), true, refreshPlaylistsListView, cancellationToken)
BackgroundTask<List<Playlist>> task = new FragmentBackgroundTask<List<Playlist>>(getActivity(), true, refreshPlaylistsListView, cancellationToken)
{
@Override
protected List<Playlist> doInBackground() throws Throwable
{
MusicService musicService = MusicServiceFactory.getMusicService(getContext());
boolean refresh = getArguments() != null && getArguments().getBoolean(Constants.INTENT_EXTRA_NAME_REFRESH, false);
List<Playlist> playlists = musicService.getPlaylists(refresh, getContext(), this);
List<Playlist> playlists = musicService.getPlaylists(refresh, getContext());
if (!ActiveServerProvider.Companion.isOffline(getContext()))
new CacheCleaner(getContext()).cleanPlaylists(playlists);
@ -258,7 +236,7 @@ public class PlaylistsFragment extends Fragment {
protected Void doInBackground() throws Throwable
{
MusicService musicService = MusicServiceFactory.getMusicService(getContext());
musicService.deletePlaylist(playlist.getId(), getContext(), null);
musicService.deletePlaylist(playlist.getId(), getContext());
return null;
}
@ -348,7 +326,7 @@ public class PlaylistsFragment extends Fragment {
String comment = commentBoxText != null ? commentBoxText.toString() : null;
MusicService musicService = MusicServiceFactory.getMusicService(getContext());
musicService.updatePlaylist(playlist.getId(), name, comment, publicBox.isChecked(), getContext(), null);
musicService.updatePlaylist(playlist.getId(), name, comment, publicBox.isChecked(), getContext());
return null;
}

View File

@ -1,5 +1,6 @@
package org.moire.ultrasonic.fragment;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
@ -11,6 +12,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.navigation.Navigation;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import org.moire.ultrasonic.R;
import org.moire.ultrasonic.domain.PodcastsChannel;
@ -19,7 +21,7 @@ import org.moire.ultrasonic.service.MusicServiceFactory;
import org.moire.ultrasonic.util.BackgroundTask;
import org.moire.ultrasonic.util.CancellationToken;
import org.moire.ultrasonic.util.Constants;
import org.moire.ultrasonic.util.TabActivityBackgroundTask;
import org.moire.ultrasonic.util.FragmentBackgroundTask;
import org.moire.ultrasonic.util.Util;
import org.moire.ultrasonic.view.PodcastsChannelsAdapter;
@ -30,6 +32,7 @@ public class PodcastFragment extends Fragment {
private View emptyTextView;
ListView channelItemsListView = null;
private CancellationToken cancellationToken;
private SwipeRefreshLayout swipeRefresh;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
@ -47,6 +50,9 @@ public class PodcastFragment extends Fragment {
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
cancellationToken = new CancellationToken();
swipeRefresh = view.findViewById(R.id.podcasts_refresh);
swipeRefresh.setEnabled(false);
FragmentTitle.Companion.setTitle(this, R.string.podcasts_label);
emptyTextView = view.findViewById(R.id.select_podcasts_empty);
@ -61,12 +67,11 @@ public class PodcastFragment extends Fragment {
Bundle bundle = new Bundle();
bundle.putString(Constants.INTENT_EXTRA_NAME_PODCAST_CHANNEL_ID, pc.getId());
Navigation.findNavController(getView()).navigate(R.id.selectAlbumFragment, bundle);
Navigation.findNavController(view).navigate(R.id.selectAlbumFragment, bundle);
}
});
// TODO: Probably a swipeRefresh should be added here in the long run
load();
load(view.getContext());
}
@Override
@ -75,26 +80,21 @@ public class PodcastFragment extends Fragment {
super.onDestroyView();
}
private void load()
private void load(final Context context)
{
BackgroundTask<List<PodcastsChannel>> task = new TabActivityBackgroundTask<List<PodcastsChannel>>(getActivity(), true, null, cancellationToken)
BackgroundTask<List<PodcastsChannel>> task = new FragmentBackgroundTask<List<PodcastsChannel>>(getActivity(), true, swipeRefresh, cancellationToken)
{
@Override
protected List<PodcastsChannel> doInBackground() throws Throwable
{
MusicService musicService = MusicServiceFactory.getMusicService(getContext());
return musicService.getPodcastsChannels(false, getContext(), this);
/* TODO Why is here a cache cleaning? (original TODO text: c'est quoi ce nettoyage de cache ?)
if (!Util.isOffline(PodcastsActivity.this))
new CacheCleaner(PodcastsActivity.this, getDownloadService()).cleanPlaylists(playlists);
*/
MusicService musicService = MusicServiceFactory.getMusicService(context);
return musicService.getPodcastsChannels(false, context);
}
@Override
protected void done(List<PodcastsChannel> result)
{
channelItemsListView.setAdapter(new PodcastsChannelsAdapter(getContext(), result));
channelItemsListView.setAdapter(new PodcastsChannelsAdapter(context, result));
emptyTextView.setVisibility(result.isEmpty() ? View.VISIBLE : View.GONE);
}
};

View File

@ -24,6 +24,7 @@ import androidx.fragment.app.Fragment;
import androidx.navigation.Navigation;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import org.jetbrains.annotations.NotNull;
import org.moire.ultrasonic.R;
import org.moire.ultrasonic.data.ActiveServerProvider;
import org.moire.ultrasonic.domain.Artist;
@ -42,7 +43,7 @@ import org.moire.ultrasonic.util.BackgroundTask;
import org.moire.ultrasonic.util.CancellationToken;
import org.moire.ultrasonic.util.Constants;
import org.moire.ultrasonic.util.MergeAdapter;
import org.moire.ultrasonic.util.TabActivityBackgroundTask;
import org.moire.ultrasonic.util.FragmentBackgroundTask;
import org.moire.ultrasonic.util.Util;
import org.moire.ultrasonic.view.ArtistAdapter;
import org.moire.ultrasonic.view.EntryAdapter;
@ -128,7 +129,7 @@ public class SearchFragment extends Fragment {
list = view.findViewById(R.id.search_list);
searchRefresh = view.findViewById(R.id.search_entries_refresh);
searchRefresh.setEnabled(false); // TODO: Should this be enabled?
searchRefresh.setEnabled(false); // TODO: It should be enabled if it is a good feature to refresh search results
list.setOnItemClickListener(new AdapterView.OnItemClickListener()
{
@ -230,6 +231,7 @@ public class SearchFragment extends Fragment {
Timber.d("onQueryTextSubmit: %s", query);
mergeAdapter = new MergeAdapter();
list.setAdapter(mergeAdapter);
searchView.clearFocus();
search(query, autoPlay);
return true;
}
@ -243,9 +245,11 @@ public class SearchFragment extends Fragment {
}
@Override
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo)
public void onCreateContextMenu(@NotNull ContextMenu menu, @NotNull View view, ContextMenu.ContextMenuInfo menuInfo)
{
super.onCreateContextMenu(menu, view, menuInfo);
if (getActivity() == null) return;
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
Object selectedItem = list.getItemAtPosition(info.position);
@ -311,84 +315,65 @@ public class SearchFragment extends Fragment {
List<MusicDirectory.Entry> songs = new ArrayList<>(1);
switch (menuItem.getItemId())
{
case R.id.album_menu_play_now:
downloadHandler.getValue().downloadRecursively(this, id, false, false, true, false, false, false, false, false);
break;
case R.id.album_menu_play_next:
downloadHandler.getValue().downloadRecursively(this, id, false, true, false, true, false, true, false, false);
break;
case R.id.album_menu_play_last:
downloadHandler.getValue().downloadRecursively(this, id, false, true, false, false, false, false, false, false);
break;
case R.id.album_menu_pin:
downloadHandler.getValue().downloadRecursively(this, id, true, true, false, false, false, false, false, false);
break;
case R.id.album_menu_unpin:
downloadHandler.getValue().downloadRecursively(this, id, false, false, false, false, false, false, true, false);
break;
case R.id.album_menu_download:
downloadHandler.getValue().downloadRecursively(this, id, false, false, false, false, true, false, false, false);
break;
case R.id.song_menu_play_now:
if (entry != null)
{
songs = new ArrayList<>(1);
songs.add(entry);
downloadHandler.getValue().download(this, false, false, true, false, false, songs);
}
break;
case R.id.song_menu_play_next:
if (entry != null)
{
songs = new ArrayList<>(1);
songs.add(entry);
downloadHandler.getValue().download(this, true, false, false, true, false, songs);
}
break;
case R.id.song_menu_play_last:
if (entry != null)
{
songs = new ArrayList<>(1);
songs.add(entry);
downloadHandler.getValue().download(this, true, false, false, false, false, songs);
}
break;
case R.id.song_menu_pin:
if (entry != null)
{
songs.add(entry);
Util.toast(getContext(), getResources().getQuantityString(R.plurals.select_album_n_songs_pinned, songs.size(), songs.size()));
downloadBackground(true, songs);
}
break;
case R.id.song_menu_download:
if (entry != null)
{
songs.add(entry);
Util.toast(getContext(), getResources().getQuantityString(R.plurals.select_album_n_songs_downloaded, songs.size(), songs.size()));
downloadBackground(false, songs);
}
break;
case R.id.song_menu_unpin:
if (entry != null)
{
songs.add(entry);
Util.toast(getContext(), getResources().getQuantityString(R.plurals.select_album_n_songs_unpinned, songs.size(), songs.size()));
mediaPlayerControllerLazy.getValue().unpin(songs);
}
break;
case R.id.menu_item_share:
if (entry != null)
{
songs = new ArrayList<>(1);
songs.add(entry);
// TODO: Add SwipeRefresh spinner
shareHandler.getValue().createShare(this, songs, null, cancellationToken);
}
default:
return super.onContextItemSelected(menuItem);
int itemId = menuItem.getItemId();
if (itemId == R.id.album_menu_play_now) {
downloadHandler.getValue().downloadRecursively(this, id, false, false, true, false, false, false, false, false);
} else if (itemId == R.id.album_menu_play_next) {
downloadHandler.getValue().downloadRecursively(this, id, false, true, false, true, false, true, false, false);
} else if (itemId == R.id.album_menu_play_last) {
downloadHandler.getValue().downloadRecursively(this, id, false, true, false, false, false, false, false, false);
} else if (itemId == R.id.album_menu_pin) {
downloadHandler.getValue().downloadRecursively(this, id, true, true, false, false, false, false, false, false);
} else if (itemId == R.id.album_menu_unpin) {
downloadHandler.getValue().downloadRecursively(this, id, false, false, false, false, false, false, true, false);
} else if (itemId == R.id.album_menu_download) {
downloadHandler.getValue().downloadRecursively(this, id, false, false, false, false, true, false, false, false);
} else if (itemId == R.id.song_menu_play_now) {
if (entry != null) {
songs = new ArrayList<>(1);
songs.add(entry);
downloadHandler.getValue().download(this, false, false, true, false, false, songs);
}
} else if (itemId == R.id.song_menu_play_next) {
if (entry != null) {
songs = new ArrayList<>(1);
songs.add(entry);
downloadHandler.getValue().download(this, true, false, false, true, false, songs);
}
} else if (itemId == R.id.song_menu_play_last) {
if (entry != null) {
songs = new ArrayList<>(1);
songs.add(entry);
downloadHandler.getValue().download(this, true, false, false, false, false, songs);
}
} else if (itemId == R.id.song_menu_pin) {
if (entry != null) {
songs.add(entry);
Util.toast(getContext(), getResources().getQuantityString(R.plurals.select_album_n_songs_pinned, songs.size(), songs.size()));
downloadBackground(true, songs);
}
} else if (itemId == R.id.song_menu_download) {
if (entry != null) {
songs.add(entry);
Util.toast(getContext(), getResources().getQuantityString(R.plurals.select_album_n_songs_downloaded, songs.size(), songs.size()));
downloadBackground(false, songs);
}
} else if (itemId == R.id.song_menu_unpin) {
if (entry != null) {
songs.add(entry);
Util.toast(getContext(), getResources().getQuantityString(R.plurals.select_album_n_songs_unpinned, songs.size(), songs.size()));
mediaPlayerControllerLazy.getValue().unpin(songs);
}
} else if (itemId == R.id.menu_item_share) {
if (entry != null) {
songs = new ArrayList<>(1);
songs.add(entry);
shareHandler.getValue().createShare(this, songs, searchRefresh, cancellationToken);
}
return super.onContextItemSelected(menuItem);
} else {
return super.onContextItemSelected(menuItem);
}
return true;
@ -421,14 +406,14 @@ public class SearchFragment extends Fragment {
final int maxAlbums = Util.getMaxAlbums(getContext());
final int maxSongs = Util.getMaxSongs(getContext());
BackgroundTask<SearchResult> task = new TabActivityBackgroundTask<SearchResult>(getActivity(), true, searchRefresh, cancellationToken)
BackgroundTask<SearchResult> task = new FragmentBackgroundTask<SearchResult>(getActivity(), true, searchRefresh, cancellationToken)
{
@Override
protected SearchResult doInBackground() throws Throwable
{
SearchCriteria criteria = new SearchCriteria(query, maxArtists, maxAlbums, maxSongs);
MusicService service = MusicServiceFactory.getMusicService(getContext());
return service.search(criteria, getContext(), this);
return service.search(criteria, getContext());
}
@Override
@ -452,16 +437,13 @@ public class SearchFragment extends Fragment {
{
mergeAdapter = new MergeAdapter();
// TODO: Remove this if the search widget can do the same
//mergeAdapter.addView(searchButton, true);
if (searchResult != null)
{
List<Artist> artists = searchResult.getArtists();
if (!artists.isEmpty())
{
mergeAdapter.addView(artistsHeading);
List<Artist> displayedArtists = new ArrayList<Artist>(artists.subList(0, Math.min(DEFAULT_ARTISTS, artists.size())));
List<Artist> displayedArtists = new ArrayList<>(artists.subList(0, Math.min(DEFAULT_ARTISTS, artists.size())));
artistAdapter = new ArtistAdapter(getContext(), displayedArtists);
mergeAdapter.addAdapter(artistAdapter);
if (artists.size() > DEFAULT_ARTISTS)
@ -474,7 +456,7 @@ public class SearchFragment extends Fragment {
if (!albums.isEmpty())
{
mergeAdapter.addView(albumsHeading);
List<MusicDirectory.Entry> displayedAlbums = new ArrayList<MusicDirectory.Entry>(albums.subList(0, Math.min(DEFAULT_ALBUMS, albums.size())));
List<MusicDirectory.Entry> displayedAlbums = new ArrayList<>(albums.subList(0, Math.min(DEFAULT_ALBUMS, albums.size())));
albumAdapter = new EntryAdapter(getContext(), imageLoaderProvider.getValue().getImageLoader(), displayedAlbums, false);
mergeAdapter.addAdapter(albumAdapter);
if (albums.size() > DEFAULT_ALBUMS)
@ -487,7 +469,7 @@ public class SearchFragment extends Fragment {
if (!songs.isEmpty())
{
mergeAdapter.addView(songsHeading);
List<MusicDirectory.Entry> displayedSongs = new ArrayList<MusicDirectory.Entry>(songs.subList(0, Math.min(DEFAULT_SONGS, songs.size())));
List<MusicDirectory.Entry> displayedSongs = new ArrayList<>(songs.subList(0, Math.min(DEFAULT_SONGS, songs.size())));
songAdapter = new EntryAdapter(getContext(), imageLoaderProvider.getValue().getImageLoader(), displayedSongs, false);
mergeAdapter.addAdapter(songAdapter);
if (songs.size() > DEFAULT_SONGS)

View File

@ -39,7 +39,7 @@ import org.moire.ultrasonic.util.CancellationToken;
import org.moire.ultrasonic.util.Constants;
import org.moire.ultrasonic.util.EntryByDiscAndTrackComparator;
import org.moire.ultrasonic.util.Pair;
import org.moire.ultrasonic.util.TabActivityBackgroundTask;
import org.moire.ultrasonic.util.FragmentBackgroundTask;
import org.moire.ultrasonic.util.Util;
import org.moire.ultrasonic.view.AlbumView;
import org.moire.ultrasonic.view.EntryAdapter;
@ -152,7 +152,7 @@ public class SelectAlbumFragment extends Fragment {
});
// 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...
// 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(new AdapterView.OnItemLongClickListener(){
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
@ -258,7 +258,11 @@ public class SelectAlbumFragment extends Fragment {
registerForContextMenu(albumListView);
setHasOptionsMenu(true);
enableButtons();
updateDisplay(false);
}
private void updateDisplay(boolean refresh)
{
String id = getArguments().getString(Constants.INTENT_EXTRA_NAME_ID);
boolean isAlbum = getArguments().getBoolean(Constants.INTENT_EXTRA_NAME_IS_ALBUM, false);
String name = getArguments().getString(Constants.INTENT_EXTRA_NAME_NAME);
@ -302,7 +306,7 @@ public class SelectAlbumFragment extends Fragment {
}
else if (getVideos != 0)
{
getVideos();
getVideos(refresh);
}
else if (getRandomTracks != 0)
{
@ -314,16 +318,16 @@ public class SelectAlbumFragment extends Fragment {
{
if (isAlbum)
{
getAlbum(id, name, parentId);
getAlbum(refresh, id, name, parentId);
}
else
{
getArtist(id, name);
getArtist(refresh, id, name);
}
}
else
{
getMusicDirectory(id, name, parentId);
getMusicDirectory(refresh, id, name, parentId);
}
}
}
@ -377,36 +381,28 @@ public class SelectAlbumFragment extends Fragment {
String entryId = entry.getId();
switch (menuItem.getItemId())
{
case R.id.album_menu_play_now:
downloadHandler.getValue().downloadRecursively(this, entryId, false, false, true, false, false, false, false, false);
break;
case R.id.album_menu_play_next:
downloadHandler.getValue().downloadRecursively(this, entryId, false, false, false, false, false, true, false, false);
break;
case R.id.album_menu_play_last:
downloadHandler.getValue().downloadRecursively(this, entryId, false, true, false, false, false, false, false, false);
break;
case R.id.album_menu_pin:
downloadHandler.getValue().downloadRecursively(this, entryId, true, true, false, false, false, false, false, false);
break;
case R.id.album_menu_unpin:
downloadHandler.getValue().downloadRecursively(this, entryId, false, false, false, false, false, false, true, false);
break;
case R.id.album_menu_download:
downloadHandler.getValue().downloadRecursively(this, entryId, false, false, false, false, true, false, false, false);
break;
case R.id.select_album_play_all:
playAll();
break;
case R.id.menu_item_share:
List<MusicDirectory.Entry> entries = new ArrayList<MusicDirectory.Entry>(1);
entries.add(entry);
shareHandler.getValue().createShare(this, entries, refreshAlbumListView, cancellationToken);
return true;
default:
return super.onContextItemSelected(menuItem);
int itemId = menuItem.getItemId();
if (itemId == R.id.album_menu_play_now) {
downloadHandler.getValue().downloadRecursively(this, entryId, false, false, true, false, false, false, false, false);
} else if (itemId == R.id.album_menu_play_next) {
downloadHandler.getValue().downloadRecursively(this, entryId, false, false, false, false, false, true, false, false);
} else if (itemId == R.id.album_menu_play_last) {
downloadHandler.getValue().downloadRecursively(this, entryId, false, true, false, false, false, false, false, false);
} else if (itemId == R.id.album_menu_pin) {
downloadHandler.getValue().downloadRecursively(this, entryId, true, true, false, false, false, false, false, false);
} else if (itemId == R.id.album_menu_unpin) {
downloadHandler.getValue().downloadRecursively(this, entryId, false, false, false, false, false, false, true, false);
} else if (itemId == R.id.album_menu_download) {
downloadHandler.getValue().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) {
List<MusicDirectory.Entry> entries = new ArrayList<MusicDirectory.Entry>(1);
entries.add(entry);
shareHandler.getValue().createShare(this, entries, refreshAlbumListView, cancellationToken);
return true;
} else {
return super.onContextItemSelected(menuItem);
}
return true;
}
@ -439,14 +435,13 @@ public class SelectAlbumFragment extends Fragment {
@Override
public boolean onOptionsItemSelected(MenuItem item)
{
switch (item.getItemId())
{
case R.id.select_album_play_all:
playAll();
return true;
case R.id.menu_item_share:
shareHandler.getValue().createShare(this, getSelectedSongs(albumListView), refreshAlbumListView, cancellationToken);
return true;
int itemId = item.getItemId();
if (itemId == R.id.select_album_play_all) {
playAll();
return true;
} else if (itemId == R.id.menu_item_share) {
shareHandler.getValue().createShare(this, getSelectedSongs(albumListView), refreshAlbumListView, cancellationToken);
return true;
}
return false;
@ -528,25 +523,16 @@ public class SelectAlbumFragment extends Fragment {
private void refresh()
{
// TODO: create better restart
getView().post(new Runnable() {
public void run() {
Timber.d("Refresh called...");
getArguments().putBoolean(Constants.INTENT_EXTRA_NAME_REFRESH, true);
onViewCreated(getView(), null);
updateDisplay(true);
}
});
/*finish();
Intent intent = getArguments();
intent.putExtra(Constants.INTENT_EXTRA_NAME_REFRESH, true);
startActivityForResultWithoutTransition(this, intent);*/
}
private void getMusicDirectory(final String id, final String name, final String parentId)
private void getMusicDirectory(final boolean refresh, final String id, final String name, final String parentId)
{
FragmentTitle.Companion.setTitle(this, name);
//setActionBarSubtitle(name);
new LoadTask()
{
@ -557,8 +543,7 @@ public class SelectAlbumFragment extends Fragment {
if (allSongsId.equals(id))
{
boolean refresh = getArguments().getBoolean(Constants.INTENT_EXTRA_NAME_REFRESH, false);
MusicDirectory musicDirectory = service.getMusicDirectory(parentId, name, refresh, getContext(), this);
MusicDirectory musicDirectory = service.getMusicDirectory(parentId, name, refresh, getContext());
List<MusicDirectory.Entry> songs = new LinkedList<MusicDirectory.Entry>();
getSongsRecursively(musicDirectory, songs);
@ -573,8 +558,7 @@ public class SelectAlbumFragment extends Fragment {
}
else
{
boolean refresh = getArguments().getBoolean(Constants.INTENT_EXTRA_NAME_REFRESH, false);
MusicDirectory musicDirectory = service.getMusicDirectory(id, name, refresh, getContext(), this);
MusicDirectory musicDirectory = service.getMusicDirectory(id, name, refresh, getContext());
if (Util.getShouldShowAllSongsByArtist(getContext()) && musicDirectory.findChild(allSongsId) == null && musicDirectory.getChildren(true, false).size() == musicDirectory.getChildren(true, true).size())
{
@ -622,7 +606,7 @@ public class SelectAlbumFragment extends Fragment {
if (!allSongsId.equals(dir.getId()))
{
root = musicService.getMusicDirectory(dir.getId(), dir.getTitle(), false, getContext(), this);
root = musicService.getMusicDirectory(dir.getId(), dir.getTitle(), false, getContext());
getSongsRecursively(root, songs);
}
@ -631,10 +615,9 @@ public class SelectAlbumFragment extends Fragment {
}.execute();
}
private void getArtist(final String id, final String name)
private void getArtist(final boolean refresh, final String id, final String name)
{
FragmentTitle.Companion.setTitle(this, name);
//setActionBarSubtitle(name);
new LoadTask()
{
@ -643,8 +626,7 @@ public class SelectAlbumFragment extends Fragment {
{
MusicDirectory root = new MusicDirectory();
boolean refresh = getArguments().getBoolean(Constants.INTENT_EXTRA_NAME_REFRESH, false);
MusicDirectory musicDirectory = service.getArtist(id, name, refresh, getContext(), this);
MusicDirectory musicDirectory = service.getArtist(id, name, refresh, getContext());
if (Util.getShouldShowAllSongsByArtist(getContext()) && musicDirectory.findChild(allSongsId) == null && musicDirectory.getChildren(true, false).size() == musicDirectory.getChildren(true, true).size())
{
@ -675,10 +657,9 @@ public class SelectAlbumFragment extends Fragment {
}.execute();
}
private void getAlbum(final String id, final String name, final String parentId)
private void getAlbum(final boolean refresh, final String id, final String name, final String parentId)
{
FragmentTitle.Companion.setTitle(this, name);
//setActionBarSubtitle(name);
new LoadTask()
{
@ -687,8 +668,6 @@ public class SelectAlbumFragment extends Fragment {
{
MusicDirectory musicDirectory;
boolean refresh = getArguments().getBoolean(Constants.INTENT_EXTRA_NAME_REFRESH, false);
if (allSongsId.equals(id))
{
MusicDirectory root = new MusicDirectory();
@ -708,7 +687,7 @@ public class SelectAlbumFragment extends Fragment {
}
else
{
musicDirectory = service.getAlbum(id, name, refresh, getContext(), this);
musicDirectory = service.getAlbum(id, name, refresh, getContext());
}
return musicDirectory;
@ -717,13 +696,13 @@ public class SelectAlbumFragment extends Fragment {
private void getSongsForArtist(String id, Collection<MusicDirectory.Entry> songs) throws Exception
{
MusicService musicService = MusicServiceFactory.getMusicService(getContext());
MusicDirectory artist = musicService.getArtist(id, "", false, getContext(), this);
MusicDirectory artist = musicService.getArtist(id, "", false, getContext());
for (MusicDirectory.Entry album : artist.getChildren())
{
if (!allSongsId.equals(album.getId()))
{
MusicDirectory albumDirectory = musicService.getAlbum(album.getId(), "", false, getContext(), this);
MusicDirectory albumDirectory = musicService.getAlbum(album.getId(), "", false, getContext());
for (MusicDirectory.Entry song : albumDirectory.getChildren())
{
@ -741,14 +720,13 @@ public class SelectAlbumFragment extends Fragment {
private void getSongsForGenre(final String genre, final int count, final int offset)
{
FragmentTitle.Companion.setTitle(this, genre);
//setActionBarSubtitle(genre);
new LoadTask()
{
@Override
protected MusicDirectory load(MusicService service) throws Exception
{
return service.getSongsByGenre(genre, count, offset, getContext(), this);
return service.getSongsByGenre(genre, count, offset, getContext());
}
@Override
@ -789,32 +767,29 @@ public class SelectAlbumFragment extends Fragment {
private void getStarred()
{
FragmentTitle.Companion.setTitle(this, R.string.main_songs_starred);
//setActionBarSubtitle(R.string.main_songs_starred);
new LoadTask()
{
@Override
protected MusicDirectory load(MusicService service) throws Exception
{
return Util.getShouldUseId3Tags(getContext()) ? Util.getSongsFromSearchResult(service.getStarred2(getContext(), this)) : Util.getSongsFromSearchResult(service.getStarred(getContext(), this));
return Util.getShouldUseId3Tags(getContext()) ? Util.getSongsFromSearchResult(service.getStarred2(getContext())) : Util.getSongsFromSearchResult(service.getStarred(getContext()));
}
}.execute();
}
private void getVideos()
private void getVideos(final boolean refresh)
{
showHeader = false;
FragmentTitle.Companion.setTitle(this, R.string.main_videos);
//setActionBarSubtitle(R.string.main_videos);
new LoadTask()
{
@Override
protected MusicDirectory load(MusicService service) throws Exception
{
boolean refresh = getArguments().getBoolean(Constants.INTENT_EXTRA_NAME_REFRESH, false);
return service.getVideos(refresh, getContext(), this);
return service.getVideos(refresh, getContext());
}
}.execute();
}
@ -822,7 +797,6 @@ public class SelectAlbumFragment extends Fragment {
private void getRandom(final int size)
{
FragmentTitle.Companion.setTitle(this, R.string.main_songs_random);
//setActionBarSubtitle(R.string.main_songs_random);
new LoadTask()
{
@ -834,7 +808,7 @@ public class SelectAlbumFragment extends Fragment {
@Override
protected MusicDirectory load(MusicService service) throws Exception
{
return service.getRandomSongs(size, getContext(), this);
return service.getRandomSongs(size, getContext());
}
}.execute();
}
@ -842,29 +816,27 @@ public class SelectAlbumFragment extends Fragment {
private void getPlaylist(final String playlistId, final String playlistName)
{
FragmentTitle.Companion.setTitle(this, playlistName);
//setActionBarSubtitle(playlistName);
new LoadTask()
{
@Override
protected MusicDirectory load(MusicService service) throws Exception
{
return service.getPlaylist(playlistId, playlistName, getContext(), this);
return service.getPlaylist(playlistId, playlistName, getContext());
}
}.execute();
}
private void getPodcastEpisodes(final String podcastChannelId)
{
// TODO: Not sure what the title should be for a podcast episode. Maybe a constant string should be used.
//setActionBarSubtitle(playlistName);
FragmentTitle.Companion.setTitle(this, R.string.podcasts_label);
new LoadTask()
{
@Override
protected MusicDirectory load(MusicService service) throws Exception
{
return service.getPodcastEpisodes(podcastChannelId, getContext(), this);
return service.getPodcastEpisodes(podcastChannelId, getContext());
}
}.execute();
}
@ -879,7 +851,7 @@ public class SelectAlbumFragment extends Fragment {
@Override
protected MusicDirectory load(MusicService service) throws Exception
{
List<Share> shares = service.getShares(true, getContext(), this);
List<Share> shares = service.getShares(true, getContext());
MusicDirectory md = new MusicDirectory();
@ -920,7 +892,7 @@ public class SelectAlbumFragment extends Fragment {
@Override
protected MusicDirectory load(MusicService service) throws Exception
{
return Util.getShouldUseId3Tags(getContext()) ? service.getAlbumList2(albumListType, size, offset, getContext(), this) : service.getAlbumList(albumListType, size, offset, getContext(), this);
return Util.getShouldUseId3Tags(getContext()) ? service.getAlbumList2(albumListType, size, offset, getContext()) : service.getAlbumList(albumListType, size, offset, getContext());
}
@Override
@ -1103,7 +1075,7 @@ public class SelectAlbumFragment extends Fragment {
mediaPlayerControllerLazy.getValue().unpin(songs);
}
private abstract class LoadTask extends TabActivityBackgroundTask<Pair<MusicDirectory, Boolean>>
private abstract class LoadTask extends FragmentBackgroundTask<Pair<MusicDirectory, Boolean>>
{
public LoadTask()
@ -1122,7 +1094,7 @@ public class SelectAlbumFragment extends Fragment {
{
MusicService musicService = MusicServiceFactory.getMusicService(getContext());
MusicDirectory dir = load(musicService);
boolean valid = musicService.isLicenseValid(getContext(), this);
boolean valid = musicService.isLicenseValid(getContext());
return new Pair<MusicDirectory, Boolean>(dir, valid);
}

View File

@ -21,7 +21,7 @@ import org.moire.ultrasonic.service.MusicServiceFactory;
import org.moire.ultrasonic.util.BackgroundTask;
import org.moire.ultrasonic.util.CancellationToken;
import org.moire.ultrasonic.util.Constants;
import org.moire.ultrasonic.util.TabActivityBackgroundTask;
import org.moire.ultrasonic.util.FragmentBackgroundTask;
import org.moire.ultrasonic.util.Util;
import org.moire.ultrasonic.view.GenreAdapter;
@ -75,7 +75,7 @@ public class SelectGenreFragment extends Fragment {
bundle.putString(Constants.INTENT_EXTRA_NAME_GENRE_NAME, genre.getName());
bundle.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, Util.getMaxSongs(getContext()));
bundle.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0);
Navigation.findNavController(getView()).navigate(R.id.selectAlbumFragment, bundle);
Navigation.findNavController(view).navigate(R.id.selectAlbumFragment, bundle);
}
}
});
@ -84,8 +84,7 @@ public class SelectGenreFragment extends Fragment {
registerForContextMenu(genreListView);
FragmentTitle.Companion.setTitle(this, R.string.main_genres_title);
load();
load(false);
}
@Override
@ -96,43 +95,23 @@ public class SelectGenreFragment extends Fragment {
private void refresh()
{
// TODO: create better restart
getView().post(new Runnable() {
public void run() {
Timber.d("Refresh called...");
if (getArguments() == null) {
Bundle bundle = new Bundle();
bundle.putBoolean(Constants.INTENT_EXTRA_NAME_REFRESH, true);
setArguments(bundle);
} else {
getArguments().putBoolean(Constants.INTENT_EXTRA_NAME_REFRESH, true);
}
onViewCreated(getView(), null);
}
});
/* finish();
Intent intent = getIntent();
intent.putExtra(Constants.INTENT_EXTRA_NAME_REFRESH, true);
startActivityForResultWithoutTransition(this, intent);
*/
load(true);
}
private void load()
private void load(final boolean refresh)
{
BackgroundTask<List<Genre>> task = new TabActivityBackgroundTask<List<Genre>>(getActivity(), true, refreshGenreListView, cancellationToken)
BackgroundTask<List<Genre>> task = new FragmentBackgroundTask<List<Genre>>(getActivity(), true, refreshGenreListView, cancellationToken)
{
@Override
protected List<Genre> doInBackground() throws Throwable
{
boolean refresh = getArguments() != null && getArguments().getBoolean(Constants.INTENT_EXTRA_NAME_REFRESH, false);
MusicService musicService = MusicServiceFactory.getMusicService(getContext());
List<Genre> genres = new ArrayList<Genre>();
try
{
genres = musicService.getGenres(refresh, getContext(), this);
genres = musicService.getGenres(refresh, getContext());
}
catch (Exception x)
{

View File

@ -2,7 +2,6 @@ package org.moire.ultrasonic.fragment;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.Editable;
@ -40,7 +39,7 @@ import org.moire.ultrasonic.util.BackgroundTask;
import org.moire.ultrasonic.util.CancellationToken;
import org.moire.ultrasonic.util.Constants;
import org.moire.ultrasonic.util.LoadingTask;
import org.moire.ultrasonic.util.TabActivityBackgroundTask;
import org.moire.ultrasonic.util.FragmentBackgroundTask;
import org.moire.ultrasonic.util.TimeSpan;
import org.moire.ultrasonic.util.TimeSpanPicker;
import org.moire.ultrasonic.util.Util;
@ -49,7 +48,6 @@ import org.moire.ultrasonic.view.ShareAdapter;
import java.util.List;
import kotlin.Lazy;
import timber.log.Timber;
import static org.koin.java.KoinJavaComponent.inject;
@ -105,14 +103,13 @@ public class SharesFragment extends Fragment {
Bundle bundle = new Bundle();
bundle.putString(Constants.INTENT_EXTRA_NAME_SHARE_ID, share.getId());
bundle.putString(Constants.INTENT_EXTRA_NAME_SHARE_NAME, share.getName());
Navigation.findNavController(getView()).navigate(R.id.selectAlbumFragment, bundle);
Navigation.findNavController(view).navigate(R.id.selectAlbumFragment, bundle);
}
});
registerForContextMenu(sharesListView);
FragmentTitle.Companion.setTitle(this, R.string.button_bar_shares);
load();
load(false);
}
@Override
@ -123,39 +120,18 @@ public class SharesFragment extends Fragment {
private void refresh()
{
// TODO: create better restart
getView().post(new Runnable() {
public void run() {
Timber.d("Refresh called...");
if (getArguments() == null) {
Bundle bundle = new Bundle();
bundle.putBoolean(Constants.INTENT_EXTRA_NAME_REFRESH, true);
setArguments(bundle);
} else {
getArguments().putBoolean(Constants.INTENT_EXTRA_NAME_REFRESH, true);
}
onViewCreated(getView(), null);
}
});
/* finish();
Intent intent = new Intent(this, ShareActivity.class);
intent.putExtra(Constants.INTENT_EXTRA_NAME_REFRESH, true);
startActivityForResultWithoutTransition(this, intent);
*/
load(true);
}
private void load()
private void load(final boolean refresh)
{
BackgroundTask<List<Share>> task = new TabActivityBackgroundTask<List<Share>>(getActivity(), true, refreshSharesListView, cancellationToken)
BackgroundTask<List<Share>> task = new FragmentBackgroundTask<List<Share>>(getActivity(), true, refreshSharesListView, cancellationToken)
{
@Override
protected List<Share> doInBackground() throws Throwable
{
MusicService musicService = MusicServiceFactory.getMusicService(getContext());
boolean refresh = getArguments() != null && getArguments().getBoolean(Constants.INTENT_EXTRA_NAME_REFRESH, false);
return musicService.getShares(refresh, getContext(), this);
return musicService.getShares(refresh, getContext());
}
@Override
@ -181,45 +157,30 @@ public class SharesFragment extends Fragment {
public boolean onContextItemSelected(MenuItem menuItem)
{
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo();
if (info == null)
{
return false;
}
if (info == null) return false;
Share share = (Share) sharesListView.getItemAtPosition(info.position);
if (share == null)
{
return false;
}
if (share == null || share.getId() == null) return false;
switch (menuItem.getItemId())
{
case R.id.share_menu_pin:
downloadHandler.getValue().downloadShare(this, share.getId(), share.getName(), true, true, false, false, true, false, false);
break;
case R.id.share_menu_unpin:
downloadHandler.getValue().downloadShare(this, share.getId(), share.getName(), false, false, false, false, true, false, true);
break;
case R.id.share_menu_download:
downloadHandler.getValue().downloadShare(this, share.getId(), share.getName(), false, false, false, false, true, false, false);
break;
case R.id.share_menu_play_now:
downloadHandler.getValue().downloadShare(this, share.getId(), share.getName(), false, false, true, false, false, false, false);
break;
case R.id.share_menu_play_shuffled:
downloadHandler.getValue().downloadShare(this, share.getId(), share.getName(), false, false, true, true, false, false, false);
break;
case R.id.share_menu_delete:
deleteShare(share);
break;
case R.id.share_info:
displayShareInfo(share);
break;
case R.id.share_update_info:
updateShareInfo(share);
break;
default:
return super.onContextItemSelected(menuItem);
int itemId = menuItem.getItemId();
if (itemId == R.id.share_menu_pin) {
downloadHandler.getValue().downloadShare(this, share.getId(), share.getName(), true, true, false, false, true, false, false);
} else if (itemId == R.id.share_menu_unpin) {
downloadHandler.getValue().downloadShare(this, share.getId(), share.getName(), false, false, false, false, true, false, true);
} else if (itemId == R.id.share_menu_download) {
downloadHandler.getValue().downloadShare(this, share.getId(), share.getName(), false, false, false, false, true, false, false);
} else if (itemId == R.id.share_menu_play_now) {
downloadHandler.getValue().downloadShare(this, share.getId(), share.getName(), false, false, true, false, false, false, false);
} else if (itemId == R.id.share_menu_play_shuffled) {
downloadHandler.getValue().downloadShare(this, share.getId(), share.getName(), false, false, true, true, false, false, false);
} else if (itemId == R.id.share_menu_delete) {
deleteShare(share);
} else if (itemId == R.id.share_info) {
displayShareInfo(share);
} else if (itemId == R.id.share_update_info) {
updateShareInfo(share);
} else {
return super.onContextItemSelected(menuItem);
}
return true;
}
@ -237,7 +198,7 @@ public class SharesFragment extends Fragment {
protected Void doInBackground() throws Throwable
{
MusicService musicService = MusicServiceFactory.getMusicService(getContext());
musicService.deleteShare(share.getId(), getContext(), null);
musicService.deleteShare(share.getId(), getContext());
return null;
}
@ -343,7 +304,7 @@ public class SharesFragment extends Fragment {
String description = shareDescriptionText != null ? shareDescriptionText.toString() : null;
MusicService musicService = MusicServiceFactory.getMusicService(getContext());
musicService.updateShare(share.getId(), description, millis, getContext(), null);
musicService.updateShare(share.getId(), description, millis, getContext());
return null;
}

View File

@ -39,7 +39,6 @@ import org.moire.ultrasonic.domain.UserInfo;
import org.moire.ultrasonic.util.CancellableTask;
import org.moire.ultrasonic.util.Constants;
import org.moire.ultrasonic.util.LRUCache;
import org.moire.ultrasonic.util.ProgressListener;
import org.moire.ultrasonic.util.TimeLimitedCache;
import org.moire.ultrasonic.util.Util;
@ -59,7 +58,7 @@ import static org.koin.java.KoinJavaComponent.inject;
*/
public class CachedMusicService implements MusicService
{
private Lazy<ActiveServerProvider> activeServerProvider = inject(ActiveServerProvider.class);
private final Lazy<ActiveServerProvider> activeServerProvider = inject(ActiveServerProvider.class);
private static final int MUSIC_DIR_CACHE_SIZE = 100;
@ -81,36 +80,36 @@ public class CachedMusicService implements MusicService
public CachedMusicService(MusicService musicService)
{
this.musicService = musicService;
cachedMusicDirectories = new LRUCache<String, TimeLimitedCache<MusicDirectory>>(MUSIC_DIR_CACHE_SIZE);
cachedArtist = new LRUCache<String, TimeLimitedCache<MusicDirectory>>(MUSIC_DIR_CACHE_SIZE);
cachedAlbum = new LRUCache<String, TimeLimitedCache<MusicDirectory>>(MUSIC_DIR_CACHE_SIZE);
cachedUserInfo = new LRUCache<String, TimeLimitedCache<UserInfo>>(MUSIC_DIR_CACHE_SIZE);
cachedMusicDirectories = new LRUCache<>(MUSIC_DIR_CACHE_SIZE);
cachedArtist = new LRUCache<>(MUSIC_DIR_CACHE_SIZE);
cachedAlbum = new LRUCache<>(MUSIC_DIR_CACHE_SIZE);
cachedUserInfo = new LRUCache<>(MUSIC_DIR_CACHE_SIZE);
}
@Override
public void ping(Context context, ProgressListener progressListener) throws Exception
public void ping(Context context) throws Exception
{
checkSettingsChanged(context);
musicService.ping(context, progressListener);
checkSettingsChanged();
musicService.ping(context);
}
@Override
public boolean isLicenseValid(Context context, ProgressListener progressListener) throws Exception
public boolean isLicenseValid(Context context) throws Exception
{
checkSettingsChanged(context);
checkSettingsChanged();
Boolean result = cachedLicenseValid.get();
if (result == null)
{
result = musicService.isLicenseValid(context, progressListener);
result = musicService.isLicenseValid(context);
cachedLicenseValid.set(result, result ? 30L * 60L : 2L * 60L, TimeUnit.SECONDS);
}
return result;
}
@Override
public List<MusicFolder> getMusicFolders(boolean refresh, Context context, ProgressListener progressListener) throws Exception
public List<MusicFolder> getMusicFolders(boolean refresh, Context context) throws Exception
{
checkSettingsChanged(context);
checkSettingsChanged();
if (refresh)
{
cachedMusicFolders.clear();
@ -118,16 +117,16 @@ public class CachedMusicService implements MusicService
List<MusicFolder> result = cachedMusicFolders.get();
if (result == null)
{
result = musicService.getMusicFolders(refresh, context, progressListener);
result = musicService.getMusicFolders(refresh, context);
cachedMusicFolders.set(result);
}
return result;
}
@Override
public Indexes getIndexes(String musicFolderId, boolean refresh, Context context, ProgressListener progressListener) throws Exception
public Indexes getIndexes(String musicFolderId, boolean refresh, Context context) throws Exception
{
checkSettingsChanged(context);
checkSettingsChanged();
if (refresh)
{
cachedIndexes.clear();
@ -137,16 +136,16 @@ public class CachedMusicService implements MusicService
Indexes result = cachedIndexes.get();
if (result == null)
{
result = musicService.getIndexes(musicFolderId, refresh, context, progressListener);
result = musicService.getIndexes(musicFolderId, refresh, context);
cachedIndexes.set(result);
}
return result;
}
@Override
public Indexes getArtists(boolean refresh, Context context, ProgressListener progressListener) throws Exception
public Indexes getArtists(boolean refresh, Context context) throws Exception
{
checkSettingsChanged(context);
checkSettingsChanged();
if (refresh)
{
cachedArtists.clear();
@ -154,24 +153,24 @@ public class CachedMusicService implements MusicService
Indexes result = cachedArtists.get();
if (result == null)
{
result = musicService.getArtists(refresh, context, progressListener);
result = musicService.getArtists(refresh, context);
cachedArtists.set(result);
}
return result;
}
@Override
public MusicDirectory getMusicDirectory(String id, String name, boolean refresh, Context context, ProgressListener progressListener) throws Exception
public MusicDirectory getMusicDirectory(String id, String name, boolean refresh, Context context) throws Exception
{
checkSettingsChanged(context);
checkSettingsChanged();
TimeLimitedCache<MusicDirectory> cache = refresh ? null : cachedMusicDirectories.get(id);
MusicDirectory dir = cache == null ? null : cache.get();
if (dir == null)
{
dir = musicService.getMusicDirectory(id, name, refresh, context, progressListener);
cache = new TimeLimitedCache<MusicDirectory>(Util.getDirectoryCacheTime(context), TimeUnit.SECONDS);
dir = musicService.getMusicDirectory(id, name, refresh, context);
cache = new TimeLimitedCache<>(Util.getDirectoryCacheTime(context), TimeUnit.SECONDS);
cache.set(dir);
cachedMusicDirectories.put(id, cache);
}
@ -179,15 +178,15 @@ public class CachedMusicService implements MusicService
}
@Override
public MusicDirectory getArtist(String id, String name, boolean refresh, Context context, ProgressListener progressListener) throws Exception
public MusicDirectory getArtist(String id, String name, boolean refresh, Context context) throws Exception
{
checkSettingsChanged(context);
checkSettingsChanged();
TimeLimitedCache<MusicDirectory> cache = refresh ? null : cachedArtist.get(id);
MusicDirectory dir = cache == null ? null : cache.get();
if (dir == null)
{
dir = musicService.getArtist(id, name, refresh, context, progressListener);
cache = new TimeLimitedCache<MusicDirectory>(Util.getDirectoryCacheTime(context), TimeUnit.SECONDS);
dir = musicService.getArtist(id, name, refresh, context);
cache = new TimeLimitedCache<>(Util.getDirectoryCacheTime(context), TimeUnit.SECONDS);
cache.set(dir);
cachedArtist.put(id, cache);
}
@ -195,15 +194,15 @@ public class CachedMusicService implements MusicService
}
@Override
public MusicDirectory getAlbum(String id, String name, boolean refresh, Context context, ProgressListener progressListener) throws Exception
public MusicDirectory getAlbum(String id, String name, boolean refresh, Context context) throws Exception
{
checkSettingsChanged(context);
checkSettingsChanged();
TimeLimitedCache<MusicDirectory> cache = refresh ? null : cachedAlbum.get(id);
MusicDirectory dir = cache == null ? null : cache.get();
if (dir == null)
{
dir = musicService.getAlbum(id, name, refresh, context, progressListener);
cache = new TimeLimitedCache<MusicDirectory>(Util.getDirectoryCacheTime(context), TimeUnit.SECONDS);
dir = musicService.getAlbum(id, name, refresh, context);
cache = new TimeLimitedCache<>(Util.getDirectoryCacheTime(context), TimeUnit.SECONDS);
cache.set(dir);
cachedAlbum.put(id, cache);
}
@ -211,113 +210,113 @@ public class CachedMusicService implements MusicService
}
@Override
public SearchResult search(SearchCriteria criteria, Context context, ProgressListener progressListener) throws Exception
public SearchResult search(SearchCriteria criteria, Context context) throws Exception
{
return musicService.search(criteria, context, progressListener);
return musicService.search(criteria, context);
}
@Override
public MusicDirectory getPlaylist(String id, String name, Context context, ProgressListener progressListener) throws Exception
public MusicDirectory getPlaylist(String id, String name, Context context) throws Exception
{
return musicService.getPlaylist(id, name, context, progressListener);
return musicService.getPlaylist(id, name, context);
}
@Override
public List<PodcastsChannel> getPodcastsChannels(boolean refresh, Context context, ProgressListener progressListener) throws Exception {
checkSettingsChanged(context);
public List<PodcastsChannel> getPodcastsChannels(boolean refresh, Context context) throws Exception {
checkSettingsChanged();
List<PodcastsChannel> result = refresh ? null : cachedPodcastsChannels.get();
if (result == null)
{
result = musicService.getPodcastsChannels(refresh, context, progressListener);
result = musicService.getPodcastsChannels(refresh, context);
cachedPodcastsChannels.set(result);
}
return result;
}
@Override
public MusicDirectory getPodcastEpisodes(String podcastChannelId, Context context, ProgressListener progressListener) throws Exception {
return musicService.getPodcastEpisodes(podcastChannelId,context,progressListener);
public MusicDirectory getPodcastEpisodes(String podcastChannelId, Context context) throws Exception {
return musicService.getPodcastEpisodes(podcastChannelId,context);
}
@Override
public List<Playlist> getPlaylists(boolean refresh, Context context, ProgressListener progressListener) throws Exception
public List<Playlist> getPlaylists(boolean refresh, Context context) throws Exception
{
checkSettingsChanged(context);
checkSettingsChanged();
List<Playlist> result = refresh ? null : cachedPlaylists.get();
if (result == null)
{
result = musicService.getPlaylists(refresh, context, progressListener);
result = musicService.getPlaylists(refresh, context);
cachedPlaylists.set(result);
}
return result;
}
@Override
public void createPlaylist(String id, String name, List<MusicDirectory.Entry> entries, Context context, ProgressListener progressListener) throws Exception
public void createPlaylist(String id, String name, List<MusicDirectory.Entry> entries, Context context) throws Exception
{
cachedPlaylists.clear();
musicService.createPlaylist(id, name, entries, context, progressListener);
musicService.createPlaylist(id, name, entries, context);
}
@Override
public void deletePlaylist(String id, Context context, ProgressListener progressListener) throws Exception
public void deletePlaylist(String id, Context context) throws Exception
{
musicService.deletePlaylist(id, context, progressListener);
musicService.deletePlaylist(id, context);
}
@Override
public void updatePlaylist(String id, String name, String comment, boolean pub, Context context, ProgressListener progressListener) throws Exception
public void updatePlaylist(String id, String name, String comment, boolean pub, Context context) throws Exception
{
musicService.updatePlaylist(id, name, comment, pub, context, progressListener);
musicService.updatePlaylist(id, name, comment, pub, context);
}
@Override
public Lyrics getLyrics(String artist, String title, Context context, ProgressListener progressListener) throws Exception
public Lyrics getLyrics(String artist, String title, Context context) throws Exception
{
return musicService.getLyrics(artist, title, context, progressListener);
return musicService.getLyrics(artist, title, context);
}
@Override
public void scrobble(String id, boolean submission, Context context, ProgressListener progressListener) throws Exception
public void scrobble(String id, boolean submission, Context context) throws Exception
{
musicService.scrobble(id, submission, context, progressListener);
musicService.scrobble(id, submission, context);
}
@Override
public MusicDirectory getAlbumList(String type, int size, int offset, Context context, ProgressListener progressListener) throws Exception
public MusicDirectory getAlbumList(String type, int size, int offset, Context context) throws Exception
{
return musicService.getAlbumList(type, size, offset, context, progressListener);
return musicService.getAlbumList(type, size, offset, context);
}
@Override
public MusicDirectory getAlbumList2(String type, int size, int offset, Context context, ProgressListener progressListener) throws Exception
public MusicDirectory getAlbumList2(String type, int size, int offset, Context context) throws Exception
{
return musicService.getAlbumList2(type, size, offset, context, progressListener);
return musicService.getAlbumList2(type, size, offset, context);
}
@Override
public MusicDirectory getRandomSongs(int size, Context context, ProgressListener progressListener) throws Exception
public MusicDirectory getRandomSongs(int size, Context context) throws Exception
{
return musicService.getRandomSongs(size, context, progressListener);
return musicService.getRandomSongs(size, context);
}
@Override
public SearchResult getStarred(Context context, ProgressListener progressListener) throws Exception
public SearchResult getStarred(Context context) throws Exception
{
return musicService.getStarred(context, progressListener);
return musicService.getStarred(context);
}
@Override
public SearchResult getStarred2(Context context, ProgressListener progressListener) throws Exception
public SearchResult getStarred2(Context context) throws Exception
{
return musicService.getStarred2(context, progressListener);
return musicService.getStarred2(context);
}
@Override
public Bitmap getCoverArt(Context context, MusicDirectory.Entry entry, int size, boolean saveToFile, boolean highQuality, ProgressListener progressListener) throws Exception
public Bitmap getCoverArt(Context context, MusicDirectory.Entry entry, int size, boolean saveToFile, boolean highQuality) throws Exception
{
return musicService.getCoverArt(context, entry, size, saveToFile, highQuality, progressListener);
return musicService.getCoverArt(context, entry, size, saveToFile, highQuality);
}
@Override
@ -333,42 +332,42 @@ public class CachedMusicService implements MusicService
}
@Override
public JukeboxStatus updateJukeboxPlaylist(List<String> ids, Context context, ProgressListener progressListener) throws Exception
public JukeboxStatus updateJukeboxPlaylist(List<String> ids, Context context) throws Exception
{
return musicService.updateJukeboxPlaylist(ids, context, progressListener);
return musicService.updateJukeboxPlaylist(ids, context);
}
@Override
public JukeboxStatus skipJukebox(int index, int offsetSeconds, Context context, ProgressListener progressListener) throws Exception
public JukeboxStatus skipJukebox(int index, int offsetSeconds, Context context) throws Exception
{
return musicService.skipJukebox(index, offsetSeconds, context, progressListener);
return musicService.skipJukebox(index, offsetSeconds, context);
}
@Override
public JukeboxStatus stopJukebox(Context context, ProgressListener progressListener) throws Exception
public JukeboxStatus stopJukebox(Context context) throws Exception
{
return musicService.stopJukebox(context, progressListener);
return musicService.stopJukebox(context);
}
@Override
public JukeboxStatus startJukebox(Context context, ProgressListener progressListener) throws Exception
public JukeboxStatus startJukebox(Context context) throws Exception
{
return musicService.startJukebox(context, progressListener);
return musicService.startJukebox(context);
}
@Override
public JukeboxStatus getJukeboxStatus(Context context, ProgressListener progressListener) throws Exception
public JukeboxStatus getJukeboxStatus(Context context) throws Exception
{
return musicService.getJukeboxStatus(context, progressListener);
return musicService.getJukeboxStatus(context);
}
@Override
public JukeboxStatus setJukeboxGain(float gain, Context context, ProgressListener progressListener) throws Exception
public JukeboxStatus setJukeboxGain(float gain, Context context) throws Exception
{
return musicService.setJukeboxGain(gain, context, progressListener);
return musicService.setJukeboxGain(gain, context);
}
private void checkSettingsChanged(Context context)
private void checkSettingsChanged()
{
String newUrl = activeServerProvider.getValue().getRestUrl(null);
if (!Util.equals(newUrl, restUrl))
@ -387,27 +386,27 @@ public class CachedMusicService implements MusicService
}
@Override
public void star(String id, String albumId, String artistId, Context context, ProgressListener progressListener) throws Exception
public void star(String id, String albumId, String artistId, Context context) throws Exception
{
musicService.star(id, albumId, artistId, context, progressListener);
musicService.star(id, albumId, artistId, context);
}
@Override
public void unstar(String id, String albumId, String artistId, Context context, ProgressListener progressListener) throws Exception
public void unstar(String id, String albumId, String artistId, Context context) throws Exception
{
musicService.unstar(id, albumId, artistId, context, progressListener);
musicService.unstar(id, albumId, artistId, context);
}
@Override
public void setRating(String id, int rating, Context context, ProgressListener progressListener) throws Exception
public void setRating(String id, int rating, Context context) throws Exception
{
musicService.setRating(id, rating, context, progressListener);
musicService.setRating(id, rating, context);
}
@Override
public List<Genre> getGenres(boolean refresh, Context context, ProgressListener progressListener) throws Exception
public List<Genre> getGenres(boolean refresh, Context context) throws Exception
{
checkSettingsChanged(context);
checkSettingsChanged();
if (refresh)
{
cachedGenres.clear();
@ -416,7 +415,7 @@ public class CachedMusicService implements MusicService
if (result == null)
{
result = musicService.getGenres(refresh, context, progressListener);
result = musicService.getGenres(refresh, context);
cachedGenres.set(result);
}
@ -433,59 +432,59 @@ public class CachedMusicService implements MusicService
}
@Override
public MusicDirectory getSongsByGenre(String genre, int count, int offset, Context context, ProgressListener progressListener) throws Exception
public MusicDirectory getSongsByGenre(String genre, int count, int offset, Context context) throws Exception
{
return musicService.getSongsByGenre(genre, count, offset, context, progressListener);
return musicService.getSongsByGenre(genre, count, offset, context);
}
@Override
public List<Share> getShares(boolean refresh, Context context, ProgressListener progressListener) throws Exception
public List<Share> getShares(boolean refresh, Context context) throws Exception
{
return musicService.getShares(refresh, context, progressListener);
return musicService.getShares(refresh, context);
}
@Override
public List<ChatMessage> getChatMessages(Long since, Context context, ProgressListener progressListener) throws Exception
public List<ChatMessage> getChatMessages(Long since, Context context) throws Exception
{
return musicService.getChatMessages(since, context, progressListener);
return musicService.getChatMessages(since, context);
}
@Override
public void addChatMessage(String message, Context context, ProgressListener progressListener) throws Exception
public void addChatMessage(String message, Context context) throws Exception
{
musicService.addChatMessage(message, context, progressListener);
musicService.addChatMessage(message, context);
}
@Override
public List<Bookmark> getBookmarks(Context context, ProgressListener progressListener) throws Exception
public List<Bookmark> getBookmarks(Context context) throws Exception
{
return musicService.getBookmarks(context, progressListener);
return musicService.getBookmarks(context);
}
@Override
public void deleteBookmark(String id, Context context, ProgressListener progressListener) throws Exception
public void deleteBookmark(String id, Context context) throws Exception
{
musicService.deleteBookmark(id, context, progressListener);
musicService.deleteBookmark(id, context);
}
@Override
public void createBookmark(String id, int position, Context context, ProgressListener progressListener) throws Exception
public void createBookmark(String id, int position, Context context) throws Exception
{
musicService.createBookmark(id, position, context, progressListener);
musicService.createBookmark(id, position, context);
}
@Override
public MusicDirectory getVideos(boolean refresh, Context context, ProgressListener progressListener) throws Exception
public MusicDirectory getVideos(boolean refresh, Context context) throws Exception
{
checkSettingsChanged(context);
checkSettingsChanged();
TimeLimitedCache<MusicDirectory> cache = refresh ? null : cachedMusicDirectories.get(Constants.INTENT_EXTRA_NAME_VIDEOS);
MusicDirectory dir = cache == null ? null : cache.get();
if (dir == null)
{
dir = musicService.getVideos(refresh, context, progressListener);
cache = new TimeLimitedCache<MusicDirectory>(Util.getDirectoryCacheTime(context), TimeUnit.SECONDS);
dir = musicService.getVideos(refresh, context);
cache = new TimeLimitedCache<>(Util.getDirectoryCacheTime(context), TimeUnit.SECONDS);
cache.set(dir);
cachedMusicDirectories.put(Constants.INTENT_EXTRA_NAME_VIDEOS, cache);
}
@ -494,9 +493,9 @@ public class CachedMusicService implements MusicService
}
@Override
public UserInfo getUser(String username, Context context, ProgressListener progressListener) throws Exception
public UserInfo getUser(String username, Context context) throws Exception
{
checkSettingsChanged(context);
checkSettingsChanged();
TimeLimitedCache<UserInfo> cache = cachedUserInfo.get(username);
@ -504,8 +503,8 @@ public class CachedMusicService implements MusicService
if (userInfo == null)
{
userInfo = musicService.getUser(username, context, progressListener);
cache = new TimeLimitedCache<UserInfo>(Util.getDirectoryCacheTime(context), TimeUnit.SECONDS);
userInfo = musicService.getUser(username, context);
cache = new TimeLimitedCache<>(Util.getDirectoryCacheTime(context), TimeUnit.SECONDS);
cache.set(userInfo);
cachedUserInfo.put(username, cache);
}
@ -514,27 +513,26 @@ public class CachedMusicService implements MusicService
}
@Override
public List<Share> createShare(List<String> ids, String description, Long expires, Context context, ProgressListener progressListener) throws Exception
public List<Share> createShare(List<String> ids, String description, Long expires, Context context) throws Exception
{
return musicService.createShare(ids, description, expires, context, progressListener);
return musicService.createShare(ids, description, expires, context);
}
@Override
public void deleteShare(String id, Context context, ProgressListener progressListener) throws Exception
public void deleteShare(String id, Context context) throws Exception
{
musicService.deleteShare(id, context, progressListener);
musicService.deleteShare(id, context);
}
@Override
public void updateShare(String id, String description, Long expires, Context context, ProgressListener progressListener) throws Exception
public void updateShare(String id, String description, Long expires, Context context) throws Exception
{
musicService.updateShare(id, description, expires, context, progressListener);
musicService.updateShare(id, description, expires, context);
}
@Override
public Bitmap getAvatar(Context context, String username, int size, boolean saveToFile, boolean highQuality, ProgressListener progressListener) throws Exception
public Bitmap getAvatar(Context context, String username, int size, boolean saveToFile, boolean highQuality) throws Exception
{
return musicService.getAvatar(context, username, size, saveToFile, highQuality, progressListener);
return musicService.getAvatar(context, username, size, saveToFile, highQuality);
}
}

View File

@ -67,7 +67,7 @@ public class DownloadFile
private volatile boolean saveWhenDone;
private volatile boolean completeWhenDone;
private Lazy<Downloader> downloader = inject(Downloader.class);
private final Lazy<Downloader> downloader = inject(Downloader.class);
public DownloadFile(Context context, MusicDirectory.Entry song, boolean save)
{
@ -456,13 +456,13 @@ public class DownloadFile
return String.format("DownloadTask (%s)", song);
}
private void downloadAndSaveCoverArt(MusicService musicService) throws Exception
private void downloadAndSaveCoverArt(MusicService musicService)
{
try
{
if (!TextUtils.isEmpty(song.getCoverArt())) {
int size = Util.getMinDisplayMetric(context);
musicService.getCoverArt(context, song, size, true, true, null);
musicService.getCoverArt(context, song, size, true, true);
}
}
catch (Exception x)

View File

@ -67,13 +67,13 @@ public class JukeboxMediaPlayer
private JukeboxStatus jukeboxStatus;
private float gain = 0.5f;
private VolumeToast volumeToast;
private AtomicBoolean running = new AtomicBoolean();
private final AtomicBoolean running = new AtomicBoolean();
private Thread serviceThread;
private boolean enabled = false;
private Context context;
private final Context context;
// TODO: These create circular references, try to refactor
private Lazy<MediaPlayerControllerImpl> mediaPlayerControllerLazy = inject(MediaPlayerControllerImpl.class);
private final Lazy<MediaPlayerControllerImpl> mediaPlayerControllerLazy = inject(MediaPlayerControllerImpl.class);
private final Downloader downloader;
// TODO: Report warning if queue fills up.
@ -397,7 +397,7 @@ public class JukeboxMediaPlayer
@Override
JukeboxStatus execute() throws Exception
{
return getMusicService().getJukeboxStatus(context, null);
return getMusicService().getJukeboxStatus(context);
}
}
@ -413,7 +413,7 @@ public class JukeboxMediaPlayer
@Override
JukeboxStatus execute() throws Exception
{
return getMusicService().updateJukeboxPlaylist(ids, context, null);
return getMusicService().updateJukeboxPlaylist(ids, context);
}
}
@ -431,7 +431,7 @@ public class JukeboxMediaPlayer
@Override
JukeboxStatus execute() throws Exception
{
return getMusicService().skipJukebox(index, offsetSeconds, context, null);
return getMusicService().skipJukebox(index, offsetSeconds, context);
}
}
@ -440,7 +440,7 @@ public class JukeboxMediaPlayer
@Override
JukeboxStatus execute() throws Exception
{
return getMusicService().stopJukebox(context, null);
return getMusicService().stopJukebox(context);
}
}
@ -449,7 +449,7 @@ public class JukeboxMediaPlayer
@Override
JukeboxStatus execute() throws Exception
{
return getMusicService().startJukebox(context, null);
return getMusicService().startJukebox(context);
}
}
@ -466,7 +466,7 @@ public class JukeboxMediaPlayer
@Override
JukeboxStatus execute() throws Exception
{
return getMusicService().setJukeboxGain(gain, context, null);
return getMusicService().setJukeboxGain(gain, context);
}
}

View File

@ -23,8 +23,6 @@ import android.content.Intent;
import timber.log.Timber;
import org.koin.java.KoinJavaComponent;
import org.moire.ultrasonic.audiofx.EqualizerController;
import org.moire.ultrasonic.audiofx.VisualizerController;
import org.moire.ultrasonic.data.ActiveServerProvider;
import org.moire.ultrasonic.domain.MusicDirectory;
import org.moire.ultrasonic.domain.MusicDirectory.Entry;
@ -60,9 +58,10 @@ public class MediaPlayerControllerImpl implements MediaPlayerController
private boolean showVisualization;
private boolean autoPlayStart;
private Context context;
private Lazy<JukeboxMediaPlayer> jukeboxMediaPlayer = inject(JukeboxMediaPlayer.class);
private Lazy<ActiveServerProvider> activeServerProvider = inject(ActiveServerProvider.class);
private final Context context;
private final Lazy<JukeboxMediaPlayer> jukeboxMediaPlayer = inject(JukeboxMediaPlayer.class);
private final Lazy<ActiveServerProvider> activeServerProvider = inject(ActiveServerProvider.class);
private final DownloadQueueSerializer downloadQueueSerializer;
private final ExternalStorageMonitor externalStorageMonitor;
private final Downloader downloader;
@ -522,7 +521,7 @@ public class MediaPlayerControllerImpl implements MediaPlayerController
try
{
String username = activeServerProvider.getValue().getActiveServer().getUserName();
UserInfo user = MusicServiceFactory.getMusicService(context).getUser(username, context, null);
UserInfo user = MusicServiceFactory.getMusicService(context).getUser(username, context);
return user.getJukeboxRole();
}
catch (Exception e)
@ -595,7 +594,7 @@ public class MediaPlayerControllerImpl implements MediaPlayerController
{
try
{
MusicServiceFactory.getMusicService(context).setRating(song.getId(), rating, context, null);
MusicServiceFactory.getMusicService(context).setRating(song.getId(), rating, context);
}
catch (Exception e)
{

View File

@ -541,7 +541,7 @@ public class MediaPlayerService extends Service
MusicService musicService = MusicServiceFactory.getMusicService(MediaPlayerService.this);
try
{
musicService.deleteBookmark(song.getId(), MediaPlayerService.this, null);
musicService.deleteBookmark(song.getId(), MediaPlayerService.this);
}
catch (Exception ignored)
{

View File

@ -36,7 +36,6 @@ import org.moire.ultrasonic.domain.SearchResult;
import org.moire.ultrasonic.domain.Share;
import org.moire.ultrasonic.domain.UserInfo;
import org.moire.ultrasonic.util.CancellableTask;
import org.moire.ultrasonic.util.ProgressListener;
import java.io.InputStream;
import java.util.List;
@ -49,61 +48,61 @@ import kotlin.Pair;
public interface MusicService
{
void ping(Context context, ProgressListener progressListener) throws Exception;
void ping(Context context) throws Exception;
boolean isLicenseValid(Context context, ProgressListener progressListener) throws Exception;
boolean isLicenseValid(Context context) throws Exception;
List<Genre> getGenres(boolean refresh, Context context, ProgressListener progressListener) throws Exception;
List<Genre> getGenres(boolean refresh, Context context) throws Exception;
void star(String id, String albumId, String artistId, Context context, ProgressListener progressListener) throws Exception;
void star(String id, String albumId, String artistId, Context context) throws Exception;
void unstar(String id, String albumId, String artistId, Context context, ProgressListener progressListener) throws Exception;
void unstar(String id, String albumId, String artistId, Context context) throws Exception;
void setRating(String id, int rating, Context context, ProgressListener progressListener) throws Exception;
void setRating(String id, int rating, Context context) throws Exception;
List<MusicFolder> getMusicFolders(boolean refresh, Context context, ProgressListener progressListener) throws Exception;
List<MusicFolder> getMusicFolders(boolean refresh, Context context) throws Exception;
Indexes getIndexes(String musicFolderId, boolean refresh, Context context, ProgressListener progressListener) throws Exception;
Indexes getIndexes(String musicFolderId, boolean refresh, Context context) throws Exception;
Indexes getArtists(boolean refresh, Context context, ProgressListener progressListener) throws Exception;
Indexes getArtists(boolean refresh, Context context) throws Exception;
MusicDirectory getMusicDirectory(String id, String name, boolean refresh, Context context, ProgressListener progressListener) throws Exception;
MusicDirectory getMusicDirectory(String id, String name, boolean refresh, Context context) throws Exception;
MusicDirectory getArtist(String id, String name, boolean refresh, Context context, ProgressListener progressListener) throws Exception;
MusicDirectory getArtist(String id, String name, boolean refresh, Context context) throws Exception;
MusicDirectory getAlbum(String id, String name, boolean refresh, Context context, ProgressListener progressListener) throws Exception;
MusicDirectory getAlbum(String id, String name, boolean refresh, Context context) throws Exception;
SearchResult search(SearchCriteria criteria, Context context, ProgressListener progressListener) throws Exception;
SearchResult search(SearchCriteria criteria, Context context) throws Exception;
MusicDirectory getPlaylist(String id, String name, Context context, ProgressListener progressListener) throws Exception;
MusicDirectory getPlaylist(String id, String name, Context context) throws Exception;
List<PodcastsChannel> getPodcastsChannels(boolean refresh, Context context, ProgressListener progressListener) throws Exception;
List<PodcastsChannel> getPodcastsChannels(boolean refresh, Context context) throws Exception;
List<Playlist> getPlaylists(boolean refresh, Context context, ProgressListener progressListener) throws Exception;
List<Playlist> getPlaylists(boolean refresh, Context context) throws Exception;
void createPlaylist(String id, String name, List<MusicDirectory.Entry> entries, Context context, ProgressListener progressListener) throws Exception;
void createPlaylist(String id, String name, List<MusicDirectory.Entry> entries, Context context) throws Exception;
void deletePlaylist(String id, Context context, ProgressListener progressListener) throws Exception;
void deletePlaylist(String id, Context context) throws Exception;
void updatePlaylist(String id, String name, String comment, boolean pub, Context context, ProgressListener progressListener) throws Exception;
void updatePlaylist(String id, String name, String comment, boolean pub, Context context) throws Exception;
Lyrics getLyrics(String artist, String title, Context context, ProgressListener progressListener) throws Exception;
Lyrics getLyrics(String artist, String title, Context context) throws Exception;
void scrobble(String id, boolean submission, Context context, ProgressListener progressListener) throws Exception;
void scrobble(String id, boolean submission, Context context) throws Exception;
MusicDirectory getAlbumList(String type, int size, int offset, Context context, ProgressListener progressListener) throws Exception;
MusicDirectory getAlbumList(String type, int size, int offset, Context context) throws Exception;
MusicDirectory getAlbumList2(String type, int size, int offset, Context context, ProgressListener progressListener) throws Exception;
MusicDirectory getAlbumList2(String type, int size, int offset, Context context) throws Exception;
MusicDirectory getRandomSongs(int size, Context context, ProgressListener progressListener) throws Exception;
MusicDirectory getRandomSongs(int size, Context context) throws Exception;
MusicDirectory getSongsByGenre(String genre, int count, int offset, Context context, ProgressListener progressListener) throws Exception;
MusicDirectory getSongsByGenre(String genre, int count, int offset, Context context) throws Exception;
SearchResult getStarred(Context context, ProgressListener progressListener) throws Exception;
SearchResult getStarred(Context context) throws Exception;
SearchResult getStarred2(Context context, ProgressListener progressListener) throws Exception;
SearchResult getStarred2(Context context) throws Exception;
Bitmap getCoverArt(Context context, MusicDirectory.Entry entry, int size, boolean saveToFile, boolean highQuality, ProgressListener progressListener) throws Exception;
Bitmap getCoverArt(Context context, MusicDirectory.Entry entry, int size, boolean saveToFile, boolean highQuality) throws Exception;
/**
* Return response {@link InputStream} and a {@link Boolean} that indicates if this response is
@ -113,41 +112,41 @@ public interface MusicService
@Deprecated String getVideoUrl(Context context, String id, boolean useFlash) throws Exception;
JukeboxStatus updateJukeboxPlaylist(List<String> ids, Context context, ProgressListener progressListener) throws Exception;
JukeboxStatus updateJukeboxPlaylist(List<String> ids, Context context) throws Exception;
JukeboxStatus skipJukebox(int index, int offsetSeconds, Context context, ProgressListener progressListener) throws Exception;
JukeboxStatus skipJukebox(int index, int offsetSeconds, Context context) throws Exception;
JukeboxStatus stopJukebox(Context context, ProgressListener progressListener) throws Exception;
JukeboxStatus stopJukebox(Context context) throws Exception;
JukeboxStatus startJukebox(Context context, ProgressListener progressListener) throws Exception;
JukeboxStatus startJukebox(Context context) throws Exception;
JukeboxStatus getJukeboxStatus(Context context, ProgressListener progressListener) throws Exception;
JukeboxStatus getJukeboxStatus(Context context) throws Exception;
JukeboxStatus setJukeboxGain(float gain, Context context, ProgressListener progressListener) throws Exception;
JukeboxStatus setJukeboxGain(float gain, Context context) throws Exception;
List<Share> getShares(boolean refresh, Context context, ProgressListener progressListener) throws Exception;
List<Share> getShares(boolean refresh, Context context) throws Exception;
List<ChatMessage> getChatMessages(Long since, Context context, ProgressListener progressListener) throws Exception;
List<ChatMessage> getChatMessages(Long since, Context context) throws Exception;
void addChatMessage(String message, Context context, ProgressListener progressListener) throws Exception;
void addChatMessage(String message, Context context) throws Exception;
List<Bookmark> getBookmarks(Context context, ProgressListener progressListener) throws Exception;
List<Bookmark> getBookmarks(Context context) throws Exception;
void deleteBookmark(String id, Context context, ProgressListener progressListener) throws Exception;
void deleteBookmark(String id, Context context) throws Exception;
void createBookmark(String id, int position, Context context, ProgressListener progressListener) throws Exception;
void createBookmark(String id, int position, Context context) throws Exception;
MusicDirectory getVideos(boolean refresh, Context context, ProgressListener progressListener) throws Exception;
MusicDirectory getVideos(boolean refresh, Context context) throws Exception;
UserInfo getUser(String username, Context context, ProgressListener progressListener) throws Exception;
UserInfo getUser(String username, Context context) throws Exception;
List<Share> createShare(List<String> ids, String description, Long expires, Context context, ProgressListener progressListener) throws Exception;
List<Share> createShare(List<String> ids, String description, Long expires, Context context) throws Exception;
void deleteShare(String id, Context context, ProgressListener progressListener) throws Exception;
void deleteShare(String id, Context context) throws Exception;
void updateShare(String id, String description, Long expires, Context context, ProgressListener progressListener) throws Exception;
void updateShare(String id, String description, Long expires, Context context) throws Exception;
Bitmap getAvatar(Context context, String username, int size, boolean saveToFile, boolean highQuality, ProgressListener progressListener) throws Exception;
Bitmap getAvatar(Context context, String username, int size, boolean saveToFile, boolean highQuality) throws Exception;
MusicDirectory getPodcastEpisodes(String podcastChannelId, Context context, ProgressListener progressListener) throws Exception;
MusicDirectory getPodcastEpisodes(String podcastChannelId, Context context) throws Exception;
}

View File

@ -76,12 +76,12 @@ import static org.koin.java.KoinJavaComponent.inject;
public class OfflineMusicService implements MusicService
{
private static final Pattern COMPILE = Pattern.compile(" ");
private Lazy<ActiveServerProvider> activeServerProvider = inject(ActiveServerProvider.class);
private final Lazy<ActiveServerProvider> activeServerProvider = inject(ActiveServerProvider.class);
@Override
public Indexes getIndexes(String musicFolderId, boolean refresh, Context context, ProgressListener progressListener) throws Exception
public Indexes getIndexes(String musicFolderId, boolean refresh, Context context)
{
List<Artist> artists = new ArrayList<Artist>();
List<Artist> artists = new ArrayList<>();
File root = FileUtil.getMusicDirectory(context);
for (File file : FileUtil.listFiles(root))
{
@ -144,13 +144,13 @@ public class OfflineMusicService implements MusicService
}
@Override
public MusicDirectory getMusicDirectory(String id, String artistName, boolean refresh, Context context, ProgressListener progressListener)
public MusicDirectory getMusicDirectory(String id, String artistName, boolean refresh, Context context)
{
File dir = new File(id);
MusicDirectory result = new MusicDirectory();
result.setName(dir.getName());
Collection<String> names = new HashSet<String>();
Collection<String> names = new HashSet<>();
for (File file : FileUtil.listMediaFiles(dir))
{
@ -335,7 +335,7 @@ public class OfflineMusicService implements MusicService
}
@Override
public Bitmap getAvatar(Context context, String username, int size, boolean saveToFile, boolean highQuality, ProgressListener progressListener)
public Bitmap getAvatar(Context context, String username, int size, boolean saveToFile, boolean highQuality)
{
try
{
@ -349,7 +349,7 @@ public class OfflineMusicService implements MusicService
}
@Override
public Bitmap getCoverArt(Context context, MusicDirectory.Entry entry, int size, boolean saveToFile, boolean highQuality, ProgressListener progressListener)
public Bitmap getCoverArt(Context context, MusicDirectory.Entry entry, int size, boolean saveToFile, boolean highQuality)
{
try
{
@ -363,11 +363,11 @@ public class OfflineMusicService implements MusicService
}
@Override
public SearchResult search(SearchCriteria criteria, Context context, ProgressListener progressListener)
public SearchResult search(SearchCriteria criteria, Context context)
{
List<Artist> artists = new ArrayList<Artist>();
List<MusicDirectory.Entry> albums = new ArrayList<MusicDirectory.Entry>();
List<MusicDirectory.Entry> songs = new ArrayList<MusicDirectory.Entry>();
List<Artist> artists = new ArrayList<>();
List<MusicDirectory.Entry> albums = new ArrayList<>();
List<MusicDirectory.Entry> songs = new ArrayList<>();
File root = FileUtil.getMusicDirectory(context);
int closeness;
@ -507,7 +507,7 @@ public class OfflineMusicService implements MusicService
}
@Override
public List<Playlist> getPlaylists(boolean refresh, Context context, ProgressListener progressListener)
public List<Playlist> getPlaylists(boolean refresh, Context context)
{
List<Playlist> playlists = new ArrayList<Playlist>();
File root = FileUtil.getPlaylistDirectory(context);
@ -564,7 +564,7 @@ public class OfflineMusicService implements MusicService
}
@Override
public MusicDirectory getPlaylist(String id, String name, Context context, ProgressListener progressListener) throws Exception
public MusicDirectory getPlaylist(String id, String name, Context context) throws Exception
{
Reader reader = null;
BufferedReader buffer = null;
@ -606,7 +606,7 @@ public class OfflineMusicService implements MusicService
}
@Override
public void createPlaylist(String id, String name, List<MusicDirectory.Entry> entries, Context context, ProgressListener progressListener) throws Exception
public void createPlaylist(String id, String name, List<MusicDirectory.Entry> entries, Context context) throws Exception
{
File playlistFile = FileUtil.getPlaylistFile(context, activeServerProvider.getValue().getActiveServer().getName(), name);
FileWriter fw = new FileWriter(playlistFile);
@ -639,10 +639,10 @@ public class OfflineMusicService implements MusicService
@Override
public MusicDirectory getRandomSongs(int size, Context context, ProgressListener progressListener)
public MusicDirectory getRandomSongs(int size, Context context)
{
File root = FileUtil.getMusicDirectory(context);
List<File> children = new LinkedList<File>();
List<File> children = new LinkedList<>();
listFilesRecursively(root, children);
MusicDirectory result = new MusicDirectory();
@ -677,138 +677,138 @@ public class OfflineMusicService implements MusicService
}
@Override
public void deletePlaylist(String id, Context context, ProgressListener progressListener) throws Exception
public void deletePlaylist(String id, Context context) throws Exception
{
throw new OfflineException("Playlists not available in offline mode");
}
@Override
public void updatePlaylist(String id, String name, String comment, boolean pub, Context context, ProgressListener progressListener) throws Exception
public void updatePlaylist(String id, String name, String comment, boolean pub, Context context) throws Exception
{
throw new OfflineException("Updating playlist not available in offline mode");
}
@Override
public Lyrics getLyrics(String artist, String title, Context context, ProgressListener progressListener) throws Exception
public Lyrics getLyrics(String artist, String title, Context context) throws Exception
{
throw new OfflineException("Lyrics not available in offline mode");
}
@Override
public void scrobble(String id, boolean submission, Context context, ProgressListener progressListener) throws Exception
public void scrobble(String id, boolean submission, Context context) throws Exception
{
throw new OfflineException("Scrobbling not available in offline mode");
}
@Override
public MusicDirectory getAlbumList(String type, int size, int offset, Context context, ProgressListener progressListener) throws Exception
public MusicDirectory getAlbumList(String type, int size, int offset, Context context) throws Exception
{
throw new OfflineException("Album lists not available in offline mode");
}
@Override
public JukeboxStatus updateJukeboxPlaylist(List<String> ids, Context context, ProgressListener progressListener) throws Exception
public JukeboxStatus updateJukeboxPlaylist(List<String> ids, Context context) throws Exception
{
throw new OfflineException("Jukebox not available in offline mode");
}
@Override
public JukeboxStatus skipJukebox(int index, int offsetSeconds, Context context, ProgressListener progressListener) throws Exception
public JukeboxStatus skipJukebox(int index, int offsetSeconds, Context context) throws Exception
{
throw new OfflineException("Jukebox not available in offline mode");
}
@Override
public JukeboxStatus stopJukebox(Context context, ProgressListener progressListener) throws Exception
public JukeboxStatus stopJukebox(Context context) throws Exception
{
throw new OfflineException("Jukebox not available in offline mode");
}
@Override
public JukeboxStatus startJukebox(Context context, ProgressListener progressListener) throws Exception
public JukeboxStatus startJukebox(Context context) throws Exception
{
throw new OfflineException("Jukebox not available in offline mode");
}
@Override
public JukeboxStatus getJukeboxStatus(Context context, ProgressListener progressListener) throws Exception
public JukeboxStatus getJukeboxStatus(Context context) throws Exception
{
throw new OfflineException("Jukebox not available in offline mode");
}
@Override
public JukeboxStatus setJukeboxGain(float gain, Context context, ProgressListener progressListener) throws Exception
public JukeboxStatus setJukeboxGain(float gain, Context context) throws Exception
{
throw new OfflineException("Jukebox not available in offline mode");
}
@Override
public SearchResult getStarred(Context context, ProgressListener progressListener) throws Exception
public SearchResult getStarred(Context context) throws Exception
{
throw new OfflineException("Starred not available in offline mode");
}
@Override
public MusicDirectory getSongsByGenre(String genre, int count, int offset, Context context, ProgressListener progressListener) throws Exception
public MusicDirectory getSongsByGenre(String genre, int count, int offset, Context context) throws Exception
{
throw new OfflineException("Getting Songs By Genre not available in offline mode");
}
@Override
public List<Genre> getGenres(boolean refresh, Context context, ProgressListener progressListener) throws Exception
public List<Genre> getGenres(boolean refresh, Context context) throws Exception
{
throw new OfflineException("Getting Genres not available in offline mode");
}
@Override
public UserInfo getUser(String username, Context context, ProgressListener progressListener) throws Exception
public UserInfo getUser(String username, Context context) throws Exception
{
throw new OfflineException("Getting user info not available in offline mode");
}
@Override
public List<Share> createShare(List<String> ids, String description, Long expires, Context context, ProgressListener progressListener) throws Exception
public List<Share> createShare(List<String> ids, String description, Long expires, Context context) throws Exception
{
throw new OfflineException("Creating shares not available in offline mode");
}
@Override
public List<Share> getShares(boolean refresh, Context context, ProgressListener progressListener) throws Exception
public List<Share> getShares(boolean refresh, Context context) throws Exception
{
throw new OfflineException("Getting shares not available in offline mode");
}
@Override
public void deleteShare(String id, Context context, ProgressListener progressListener) throws Exception
public void deleteShare(String id, Context context) throws Exception
{
throw new OfflineException("Deleting shares not available in offline mode");
}
@Override
public void updateShare(String id, String description, Long expires, Context context, ProgressListener progressListener) throws Exception
public void updateShare(String id, String description, Long expires, Context context) throws Exception
{
throw new OfflineException("Updating shares not available in offline mode");
}
@Override
public void star(String id, String albumId, String artistId, Context context, ProgressListener progressListener) throws Exception
public void star(String id, String albumId, String artistId, Context context) throws Exception
{
throw new OfflineException("Star not available in offline mode");
}
@Override
public void unstar(String id, String albumId, String artistId, Context context, ProgressListener progressListener) throws Exception
public void unstar(String id, String albumId, String artistId, Context context) throws Exception
{
throw new OfflineException("UnStar not available in offline mode");
}
@Override
public List<MusicFolder> getMusicFolders(boolean refresh, Context context, ProgressListener progressListener) throws Exception
public List<MusicFolder> getMusicFolders(boolean refresh, Context context) throws Exception
{
throw new OfflineException("Music folders not available in offline mode");
}
@Override
public MusicDirectory getAlbumList2(String type, int size, int offset, Context context, ProgressListener progressListener) {
public MusicDirectory getAlbumList2(String type, int size, int offset, Context context) {
Timber.w("OfflineMusicService.getAlbumList2 was called but it isn't available");
return null;
}
@ -820,73 +820,73 @@ public class OfflineMusicService implements MusicService
}
@Override
public List<ChatMessage> getChatMessages(Long since, Context context, ProgressListener progressListener) {
public List<ChatMessage> getChatMessages(Long since, Context context) {
Timber.w("OfflineMusicService.getChatMessages was called but it isn't available");
return null;
}
@Override
public void addChatMessage(String message, Context context, ProgressListener progressListener) {
public void addChatMessage(String message, Context context) {
Timber.w("OfflineMusicService.addChatMessage was called but it isn't available");
}
@Override
public List<Bookmark> getBookmarks(Context context, ProgressListener progressListener) {
public List<Bookmark> getBookmarks(Context context) {
Timber.w("OfflineMusicService.getBookmarks was called but it isn't available");
return null;
}
@Override
public void deleteBookmark(String id, Context context, ProgressListener progressListener) {
public void deleteBookmark(String id, Context context) {
Timber.w("OfflineMusicService.deleteBookmark was called but it isn't available");
}
@Override
public void createBookmark(String id, int position, Context context, ProgressListener progressListener) {
public void createBookmark(String id, int position, Context context) {
Timber.w("OfflineMusicService.createBookmark was called but it isn't available");
}
@Override
public MusicDirectory getVideos(boolean refresh, Context context, ProgressListener progressListener) {
public MusicDirectory getVideos(boolean refresh, Context context) {
Timber.w("OfflineMusicService.getVideos was called but it isn't available");
return null;
}
@Override
public SearchResult getStarred2(Context context, ProgressListener progressListener) {
public SearchResult getStarred2(Context context) {
Timber.w("OfflineMusicService.getStarred2 was called but it isn't available");
return null;
}
@Override
public void ping(Context context, ProgressListener progressListener) {
public void ping(Context context) {
}
@Override
public boolean isLicenseValid(Context context, ProgressListener progressListener) {
public boolean isLicenseValid(Context context) {
return true;
}
@Override
public Indexes getArtists(boolean refresh, Context context, ProgressListener progressListener) {
public Indexes getArtists(boolean refresh, Context context) {
Timber.w("OfflineMusicService.getArtists was called but it isn't available");
return null;
}
@Override
public MusicDirectory getArtist(String id, String name, boolean refresh, Context context, ProgressListener progressListener) {
public MusicDirectory getArtist(String id, String name, boolean refresh, Context context) {
Timber.w("OfflineMusicService.getArtist was called but it isn't available");
return null;
}
@Override
public MusicDirectory getAlbum(String id, String name, boolean refresh, Context context, ProgressListener progressListener) {
public MusicDirectory getAlbum(String id, String name, boolean refresh, Context context) {
Timber.w("OfflineMusicService.getAlbum was called but it isn't available");
return null;
}
@Override
public MusicDirectory getPodcastEpisodes(String podcastChannelId, Context context, ProgressListener progressListener) {
public MusicDirectory getPodcastEpisodes(String podcastChannelId, Context context) {
Timber.w("OfflineMusicService.getPodcastEpisodes was called but it isn't available");
return null;
}
@ -898,12 +898,12 @@ public class OfflineMusicService implements MusicService
}
@Override
public void setRating(String id, int rating, Context context, ProgressListener progressListener) {
public void setRating(String id, int rating, Context context) {
Timber.w("OfflineMusicService.setRating was called but it isn't available");
}
@Override
public List<PodcastsChannel> getPodcastsChannels(boolean refresh, Context context, ProgressListener progressListener) {
public List<PodcastsChannel> getPodcastsChannels(boolean refresh, Context context) {
Timber.w("OfflineMusicService.getPodcastsChannels was called but it isn't available");
return null;
}

View File

@ -4,7 +4,6 @@ import android.content.Context;
import timber.log.Timber;
import org.moire.ultrasonic.data.ActiveServerProvider;
import org.moire.ultrasonic.util.Util;
/**
* Scrobbles played songs to Last.fm.
@ -19,32 +18,18 @@ public class Scrobbler
public void scrobble(final Context context, final DownloadFile song, final boolean submission)
{
if (song == null || !ActiveServerProvider.Companion.isScrobblingEnabled(context))
{
return;
}
if (song == null || !ActiveServerProvider.Companion.isScrobblingEnabled(context)) return;
final String id = song.getSong().getId();
if (id == null) return;
// Avoid duplicate registrations.
if (submission && id.equals(lastSubmission))
{
return;
}
if (submission && id.equals(lastSubmission)) return;
if (!submission && id.equals(lastNowPlaying))
{
return;
}
if (!submission && id.equals(lastNowPlaying)) return;
if (submission)
{
lastSubmission = id;
}
else
{
lastNowPlaying = id;
}
if (submission) lastSubmission = id;
else lastNowPlaying = id;
new Thread(String.format("Scrobble %s", song))
{
@ -54,7 +39,7 @@ public class Scrobbler
MusicService service = MusicServiceFactory.getMusicService(context);
try
{
service.scrobble(id, submission, context, null);
service.scrobble(id, submission, context);
Timber.i("Scrobbled '%s' for %s", submission ? "submission" : "now playing", song);
}
catch (Exception x)

View File

@ -8,14 +8,14 @@ import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
* @author Sindre Mehus
* @version $Id$
*/
public abstract class TabActivityBackgroundTask<T> extends BackgroundTask<T>
public abstract class FragmentBackgroundTask<T> extends BackgroundTask<T>
{
private final boolean changeProgress;
private final SwipeRefreshLayout swipe;
private final CancellationToken cancel;
public TabActivityBackgroundTask(Activity activity, boolean changeProgress,
SwipeRefreshLayout swipe, CancellationToken cancel)
public FragmentBackgroundTask(Activity activity, boolean changeProgress,
SwipeRefreshLayout swipe, CancellationToken cancel)
{
super(activity);
this.changeProgress = changeProgress;

View File

@ -19,7 +19,6 @@
package org.moire.ultrasonic.util;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
@ -30,6 +29,9 @@ import timber.log.Timber;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.core.content.res.ResourcesCompat;
import org.moire.ultrasonic.R;
import org.moire.ultrasonic.domain.MusicDirectory;
import org.moire.ultrasonic.service.MusicService;
@ -38,8 +40,6 @@ import org.moire.ultrasonic.service.MusicServiceFactory;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.SortedSet;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicBoolean;
@ -58,9 +58,9 @@ public class LegacyImageLoader implements Runnable, ImageLoader {
private final int imageSizeLarge;
private Bitmap largeUnknownImage;
private Bitmap unknownAvatarImage;
private Context context;
private final Context context;
private Collection<Thread> threads;
private AtomicBoolean running = new AtomicBoolean();
private final AtomicBoolean running = new AtomicBoolean();
private int concurrency;
public LegacyImageLoader(
@ -71,8 +71,7 @@ public class LegacyImageLoader implements Runnable, ImageLoader {
this.concurrency = concurrency;
queue = new LinkedBlockingQueue<>(1000);
Resources resources = context.getResources();
Drawable drawable = resources.getDrawable(R.drawable.unknown_album);
Drawable drawable = ResourcesCompat.getDrawable(context.getResources(), R.drawable.unknown_album, null);
// Determine the density-dependent image sizes.
if (drawable != null) {
@ -120,7 +119,7 @@ public class LegacyImageLoader implements Runnable, ImageLoader {
}
private void createLargeUnknownImage(Context context) {
Drawable drawable = context.getResources().getDrawable(R.drawable.unknown_album);
Drawable drawable = ResourcesCompat.getDrawable(context.getResources(), R.drawable.unknown_album, null);
Timber.i("createLargeUnknownImage");
if (drawable != null) {
@ -129,8 +128,7 @@ public class LegacyImageLoader implements Runnable, ImageLoader {
}
private void createUnknownAvatarImage(Context context) {
Resources res = context.getResources();
Drawable contact = res.getDrawable(R.drawable.ic_contact_picture);
Drawable contact = ResourcesCompat.getDrawable(context.getResources(), R.drawable.ic_contact_picture, null);
unknownAvatarImage = Util.createBitmapFromDrawable(contact);
}
@ -424,8 +422,8 @@ public class LegacyImageLoader implements Runnable, ImageLoader {
MusicService musicService = MusicServiceFactory.getMusicService(view.getContext());
final boolean isAvatar = this.username != null && this.entry == null;
final Bitmap bitmap = this.entry != null ?
musicService.getCoverArt(view.getContext(), entry, size, saveToFile, highQuality, null) :
musicService.getAvatar(view.getContext(), username, size, saveToFile, highQuality, null);
musicService.getCoverArt(view.getContext(), entry, size, saveToFile, highQuality) :
musicService.getAvatar(view.getContext(), username, size, saveToFile, highQuality);
if (bitmap == null) {
Timber.d("Found empty album art.");

View File

@ -32,16 +32,25 @@ import static androidx.core.content.PermissionChecker.PERMISSION_DENIED;
*/
public class PermissionUtil {
private final Context context;
private Context activityContext;
private Context applicationContext;
public PermissionUtil(Context context) {
this.context = context;
applicationContext = context;
}
public interface PermissionRequestFinishedCallback {
void onPermissionRequestFinished(boolean hasPermission);
}
public void ForegroundApplicationStarted(Context context) {
this.activityContext = context;
}
public void ForegroundApplicationStopped() {
activityContext = null;
}
/**
* This function can be used to handle file access permission failures.
*
@ -51,26 +60,30 @@ public class PermissionUtil {
* @param callback callback function to execute after the permission request is finished
*/
public void handlePermissionFailed(final PermissionRequestFinishedCallback callback) {
// TODO: Test with ApplicationContext
String currentCachePath = Util.getPreferences(context).getString(Constants.PREFERENCES_KEY_CACHE_LOCATION, FileUtil.getDefaultMusicDirectory(context).getPath());
String defaultCachePath = FileUtil.getDefaultMusicDirectory(context).getPath();
String currentCachePath = Util.getPreferences(applicationContext).getString(Constants.PREFERENCES_KEY_CACHE_LOCATION, FileUtil.getDefaultMusicDirectory(applicationContext).getPath());
String defaultCachePath = FileUtil.getDefaultMusicDirectory(applicationContext).getPath();
// Ultrasonic can do nothing about this error when the Music Directory is already set to the default.
if (currentCachePath.compareTo(defaultCachePath) == 0) return;
if ((PermissionChecker.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PERMISSION_DENIED) ||
(PermissionChecker.checkSelfPermission(context, Manifest.permission.READ_EXTERNAL_STORAGE) == PERMISSION_DENIED)) {
if ((PermissionChecker.checkSelfPermission(applicationContext, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PERMISSION_DENIED) ||
(PermissionChecker.checkSelfPermission(applicationContext, Manifest.permission.READ_EXTERNAL_STORAGE) == PERMISSION_DENIED)) {
// While we request permission, the Music Directory is temporarily reset to its default location
setCacheLocation(context, FileUtil.getDefaultMusicDirectory(context).getPath());
requestFailedPermission(context, currentCachePath, callback);
setCacheLocation(applicationContext, FileUtil.getDefaultMusicDirectory(applicationContext).getPath());
// If the application is not running, we can't notify the user
if (activityContext == null) return;
requestFailedPermission(activityContext, currentCachePath, callback);
} else {
setCacheLocation(context, FileUtil.getDefaultMusicDirectory(context).getPath());
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
showWarning(context, context.getString(R.string.permissions_message_box_title), context.getString(R.string.permissions_access_error), null);
}
});
setCacheLocation(applicationContext, FileUtil.getDefaultMusicDirectory(applicationContext).getPath());
// If the application is not running, we can't notify the user
if (activityContext != null) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
showWarning(activityContext, activityContext.getString(R.string.permissions_message_box_title), activityContext.getString(R.string.permissions_access_error), null);
}
});
}
callback.onPermissionRequestFinished(false);
}
}

View File

@ -41,7 +41,7 @@ public class ShufflePlayBuffer
private static final int CAPACITY = 50;
private static final int REFILL_THRESHOLD = 40;
private final List<MusicDirectory.Entry> buffer = new ArrayList<MusicDirectory.Entry>();
private final List<MusicDirectory.Entry> buffer = new ArrayList<>();
private final Context context;
private ScheduledExecutorService executorService;
private int currentServer;
@ -78,7 +78,7 @@ public class ShufflePlayBuffer
{
clearBufferIfNecessary();
List<MusicDirectory.Entry> result = new ArrayList<MusicDirectory.Entry>(size);
List<MusicDirectory.Entry> result = new ArrayList<>(size);
synchronized (buffer)
{
while (!buffer.isEmpty() && result.size() < size)
@ -106,7 +106,7 @@ public class ShufflePlayBuffer
{
MusicService service = MusicServiceFactory.getMusicService(context);
int n = CAPACITY - buffer.size();
MusicDirectory songs = service.getRandomSongs(n, context, null);
MusicDirectory songs = service.getRandomSongs(n, context);
synchronized (buffer)
{

View File

@ -23,8 +23,6 @@ import android.graphics.drawable.Drawable;
import timber.log.Timber;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import org.moire.ultrasonic.R;
import org.moire.ultrasonic.data.ActiveServerProvider;
import org.moire.ultrasonic.domain.MusicDirectory;
@ -44,10 +42,10 @@ public class AlbumView extends UpdateView
private static Drawable starHollowDrawable;
private static String theme;
private Context context;
private final Context context;
private MusicDirectory.Entry entry;
private EntryAdapter.AlbumViewHolder viewHolder;
private ImageLoader imageLoader;
private final ImageLoader imageLoader;
private boolean maximized = false;
public AlbumView(Context context, ImageLoader imageLoader)
@ -75,10 +73,10 @@ public class AlbumView extends UpdateView
{
LayoutInflater.from(context).inflate(R.layout.album_list_item, this, true);
viewHolder = new EntryAdapter.AlbumViewHolder();
viewHolder.title = (TextView) findViewById(R.id.album_title);
viewHolder.artist = (TextView) findViewById(R.id.album_artist);
viewHolder.cover_art = (ImageView) findViewById(R.id.album_coverart);
viewHolder.star = (ImageView) findViewById(R.id.album_star);
viewHolder.title = findViewById(R.id.album_title);
viewHolder.artist = findViewById(R.id.album_artist);
viewHolder.cover_art = findViewById(R.id.album_coverart);
viewHolder.star = findViewById(R.id.album_star);
setTag(viewHolder);
}
@ -164,11 +162,11 @@ public class AlbumView extends UpdateView
{
if (!isStarred)
{
musicService.star(!useId3 ? id : null, useId3 ? id : null, null, getContext(), null);
musicService.star(!useId3 ? id : null, useId3 ? id : null, null, getContext());
}
else
{
musicService.unstar(!useId3 ? id : null, useId3 ? id : null, null, getContext(), null);
musicService.unstar(!useId3 ? id : null, useId3 ? id : null, null, getContext());
}
}
catch (Exception e)

View File

@ -15,6 +15,7 @@ import android.view.MenuItem
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import androidx.core.view.GravityCompat
import androidx.drawerlayout.widget.DrawerLayout
import androidx.fragment.app.FragmentContainerView
import androidx.navigation.NavController
@ -41,13 +42,13 @@ import org.moire.ultrasonic.util.Constants
import org.moire.ultrasonic.util.FileUtil
import org.moire.ultrasonic.util.NowPlayingEventDistributor
import org.moire.ultrasonic.util.NowPlayingEventListener
import org.moire.ultrasonic.util.PermissionUtil
import org.moire.ultrasonic.util.SubsonicUncaughtExceptionHandler
import org.moire.ultrasonic.util.ThemeChangedEventDistributor
import org.moire.ultrasonic.util.ThemeChangedEventListener
import org.moire.ultrasonic.util.Util
import timber.log.Timber
/**
* The main Activity of Ultrasonic which loads all other screens as Fragments
*/
@ -58,10 +59,12 @@ class NavigationActivity : AppCompatActivity() {
var podcastsMenuItem: MenuItem? = null
var nowPlayingView: FragmentContainerView? = null
var nowPlayingHidden = false
var navigationView: NavigationView? = null
var drawerLayout: DrawerLayout? = null
private lateinit var appBarConfiguration : AppBarConfiguration
private lateinit var nowPlayingEventListener : NowPlayingEventListener
private lateinit var themeChangedEventListener : ThemeChangedEventListener
private lateinit var appBarConfiguration: AppBarConfiguration
private lateinit var nowPlayingEventListener: NowPlayingEventListener
private lateinit var themeChangedEventListener: ThemeChangedEventListener
private val serverSettingsModel: ServerSettingsModel by viewModel()
private val lifecycleSupport: MediaPlayerLifecycleSupport by inject()
@ -69,12 +72,14 @@ class NavigationActivity : AppCompatActivity() {
private val imageLoaderProvider: ImageLoaderProvider by inject()
private val nowPlayingEventDistributor: NowPlayingEventDistributor by inject()
private val themeChangedEventDistributor: ThemeChangedEventDistributor by inject()
private val permissionUtil: PermissionUtil by inject()
private var infoDialogDisplayed = false
private var currentFragmentId: Int = 0
override fun onCreate(savedInstanceState: Bundle?) {
setUncaughtExceptionHandler()
permissionUtil.ForegroundApplicationStarted(this)
Util.applyTheme(this)
super.onCreate(savedInstanceState)
@ -82,6 +87,8 @@ class NavigationActivity : AppCompatActivity() {
volumeControlStream = AudioManager.STREAM_MUSIC
setContentView(R.layout.navigation_activity)
nowPlayingView = findViewById(R.id.now_playing_fragment)
navigationView = findViewById(R.id.nav_view)
drawerLayout = findViewById(R.id.drawer_layout)
val toolbar = findViewById<Toolbar>(R.id.toolbar)
setSupportActionBar(toolbar)
@ -91,13 +98,22 @@ class NavigationActivity : AppCompatActivity() {
val navController = host.navController
val drawerLayout : DrawerLayout? = findViewById(R.id.drawer_layout)
appBarConfiguration = AppBarConfiguration(
setOf(R.id.mainFragment, R.id.selectArtistFragment, R.id.searchFragment,
R.id.playlistsFragment, R.id.sharesFragment, R.id.bookmarksFragment,
R.id.chatFragment, R.id.podcastFragment, R.id.settingsFragment,
R.id.aboutFragment, R.id.playerFragment),
drawerLayout)
setOf(
R.id.mainFragment,
R.id.selectArtistFragment,
R.id.searchFragment,
R.id.playlistsFragment,
R.id.sharesFragment,
R.id.bookmarksFragment,
R.id.chatFragment,
R.id.podcastFragment,
R.id.settingsFragment,
R.id.aboutFragment,
R.id.playerFragment
),
drawerLayout
)
setupActionBar(navController, appBarConfiguration)
@ -135,8 +151,8 @@ class NavigationActivity : AppCompatActivity() {
nowPlayingEventListener = object : NowPlayingEventListener {
override fun onDismissNowPlaying() {
nowPlayingHidden = true;
hideNowPlaying();
nowPlayingHidden = true
hideNowPlaying()
}
override fun onHideNowPlaying() {
@ -174,6 +190,7 @@ class NavigationActivity : AppCompatActivity() {
nowPlayingEventDistributor.unsubscribe(nowPlayingEventListener)
themeChangedEventDistributor.unsubscribe(themeChangedEventListener)
imageLoaderProvider.clearImageLoader()
permissionUtil.ForegroundApplicationStopped()
}
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
@ -189,12 +206,11 @@ class NavigationActivity : AppCompatActivity() {
}
private fun setupNavigationMenu(navController: NavController) {
val sideNavView = findViewById<NavigationView>(R.id.nav_view)
sideNavView?.setupWithNavController(navController)
navigationView?.setupWithNavController(navController)
// The exit menu is handled here manually
val exitItem: MenuItem = sideNavView.menu.findItem(R.id.menu_exit)
exitItem.setOnMenuItemClickListener { item ->
val exitItem: MenuItem? = navigationView?.menu?.findItem(R.id.menu_exit) ?: null
exitItem?.setOnMenuItemClickListener { item ->
if (item.itemId == R.id.menu_exit) {
setResult(Constants.RESULT_CLOSE_ALL)
mediaPlayerController.stopJukeboxService()
@ -205,19 +221,26 @@ class NavigationActivity : AppCompatActivity() {
true
}
chatMenuItem = sideNavView.menu.findItem(R.id.chatFragment)
bookmarksMenuItem = sideNavView.menu.findItem(R.id.bookmarksFragment)
sharesMenuItem = sideNavView.menu.findItem(R.id.sharesFragment)
podcastsMenuItem = sideNavView.menu.findItem(R.id.podcastFragment)
chatMenuItem = navigationView?.menu?.findItem(R.id.chatFragment)
bookmarksMenuItem = navigationView?.menu?.findItem(R.id.bookmarksFragment)
sharesMenuItem = navigationView?.menu?.findItem(R.id.sharesFragment)
podcastsMenuItem = navigationView?.menu?.findItem(R.id.podcastFragment)
}
private fun setupActionBar(navController: NavController, appBarConfig: AppBarConfiguration) {
setupActionBarWithNavController(navController, appBarConfig)
}
override fun onBackPressed() {
if (drawerLayout?.isDrawerVisible(GravityCompat.START) == true) {
this.drawerLayout?.closeDrawer(GravityCompat.START)
} else {
super.onBackPressed()
}
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
val retValue = super.onCreateOptionsMenu(menu)
val navigationView = findViewById<NavigationView>(R.id.nav_view)
if (navigationView == null) {
menuInflater.inflate(R.menu.navigation, menu)
return true
@ -226,22 +249,21 @@ class NavigationActivity : AppCompatActivity() {
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return item.onNavDestinationSelected(findNavController(R.id.nav_host_fragment))
|| super.onOptionsItemSelected(item)
return item.onNavDestinationSelected(findNavController(R.id.nav_host_fragment)) ||
super.onOptionsItemSelected(item)
}
override fun onSupportNavigateUp(): Boolean {
return findNavController(R.id.nav_host_fragment).navigateUp(appBarConfiguration)
}
// TODO: Test if this works with external Intents
// TODO Test if this works with external Intents
// android.intent.action.SEARCH and android.media.action.MEDIA_PLAY_FROM_SEARCH calls here
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
if (intent == null) return;
if (intent == null) return
if (intent.getBooleanExtra(Constants.INTENT_EXTRA_NAME_SHOW_PLAYER, false))
{
if (intent.getBooleanExtra(Constants.INTENT_EXTRA_NAME_SHOW_PLAYER, false)) {
findNavController(R.id.nav_host_fragment).navigate(R.id.playerFragment)
return
}
@ -250,7 +272,10 @@ class NavigationActivity : AppCompatActivity() {
if (query != null) {
val autoPlay = intent.action == MediaStore.INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH
val suggestions = SearchRecentSuggestions(this, SearchSuggestionProvider.AUTHORITY, SearchSuggestionProvider.MODE)
val suggestions = SearchRecentSuggestions(
this,
SearchSuggestionProvider.AUTHORITY, SearchSuggestionProvider.MODE
)
suggestions.saveRecentQuery(query, null)
val bundle = Bundle()
@ -265,7 +290,10 @@ class NavigationActivity : AppCompatActivity() {
val preferences = Util.getPreferences(this)
if (!preferences.contains(Constants.PREFERENCES_KEY_CACHE_LOCATION)) {
val editor = preferences.edit()
editor.putString(Constants.PREFERENCES_KEY_CACHE_LOCATION, FileUtil.getDefaultMusicDirectory(this).path)
editor.putString(
Constants.PREFERENCES_KEY_CACHE_LOCATION,
FileUtil.getDefaultMusicDirectory(this).path
)
editor.apply()
}
}
@ -284,7 +312,7 @@ class NavigationActivity : AppCompatActivity() {
.setIcon(android.R.drawable.ic_dialog_info)
.setTitle(R.string.main_welcome_title)
.setMessage(R.string.main_welcome_text)
.setPositiveButton(R.string.common_ok) { dialog, i ->
.setPositiveButton(R.string.common_ok) { dialog, _ ->
dialog.dismiss()
findNavController(R.id.nav_host_fragment).navigate(R.id.settingsFragment)
}.show()
@ -307,7 +335,7 @@ class NavigationActivity : AppCompatActivity() {
// The logic for nowPlayingHidden is that the user can dismiss NowPlaying with a gesture,
// and when the MediaPlayerService requests that it should be shown, it returns
nowPlayingHidden = false;
nowPlayingHidden = false
// Do not show for Player fragment
if (currentFragmentId == R.id.playerFragment) {
hideNowPlaying()
@ -319,7 +347,6 @@ class NavigationActivity : AppCompatActivity() {
if (playerState == PlayerState.PAUSED || playerState == PlayerState.STARTED) {
val file: DownloadFile? = mediaPlayerController.currentPlaying
if (file != null) {
val song = file.song
nowPlayingView?.visibility = View.VISIBLE
}
} else {

View File

@ -5,9 +5,9 @@ import org.koin.android.ext.koin.androidContext
import org.koin.android.viewmodel.dsl.viewModel
import org.koin.core.qualifier.named
import org.koin.dsl.module
import org.moire.ultrasonic.fragment.ServerSettingsModel
import org.moire.ultrasonic.data.AppDatabase
import org.moire.ultrasonic.data.MIGRATION_1_2
import org.moire.ultrasonic.fragment.ServerSettingsModel
import org.moire.ultrasonic.util.Util
const val SP_NAME = "Default_SP"

View File

@ -1,10 +1,7 @@
package org.moire.ultrasonic.di
import org.koin.android.ext.koin.androidContext
import org.koin.dsl.bind
import org.koin.dsl.module
import org.moire.ultrasonic.cache.AndroidDirectories
import org.moire.ultrasonic.cache.Directories
import org.moire.ultrasonic.data.ActiveServerProvider
import org.moire.ultrasonic.subsonic.ImageLoaderProvider
import org.moire.ultrasonic.util.NowPlayingEventDistributor

View File

@ -8,12 +8,12 @@ import org.koin.android.viewmodel.dsl.viewModel
import org.koin.core.qualifier.named
import org.koin.dsl.module
import org.moire.ultrasonic.BuildConfig
import org.moire.ultrasonic.fragment.ArtistListModel
import org.moire.ultrasonic.api.subsonic.SubsonicAPIClient
import org.moire.ultrasonic.api.subsonic.SubsonicAPIVersions
import org.moire.ultrasonic.api.subsonic.SubsonicClientConfiguration
import org.moire.ultrasonic.cache.PermanentFileStorage
import org.moire.ultrasonic.data.ActiveServerProvider
import org.moire.ultrasonic.fragment.ArtistListModel
import org.moire.ultrasonic.log.TimberOkHttpLogger
import org.moire.ultrasonic.service.ApiCallResponseChecker
import org.moire.ultrasonic.service.CachedMusicService

View File

@ -85,15 +85,15 @@ class ArtistListModel(
try {
if (!isOffline && !useId3Tags) {
musicFolders.postValue(
musicService.getMusicFolders(refresh, context, null)
musicService.getMusicFolders(refresh, context)
)
}
val musicFolderId = activeServerProvider.getActiveServer().musicFolderId
val result = if (!isOffline && useId3Tags)
musicService.getArtists(refresh, context, null)
else musicService.getIndexes(musicFolderId, refresh, context, null)
musicService.getArtists(refresh, context)
else musicService.getIndexes(musicFolderId, refresh, context)
val retrievedArtists: MutableList<Artist> =
ArrayList(result.shortcuts.size + result.artists.size)

View File

@ -11,6 +11,8 @@ import androidx.lifecycle.Observer
import androidx.navigation.fragment.findNavController
import com.google.android.material.switchmaterial.SwitchMaterial
import com.google.android.material.textfield.TextInputLayout
import java.net.MalformedURLException
import java.net.URL
import org.koin.android.ext.android.inject
import org.koin.android.viewmodel.ext.android.viewModel
import org.moire.ultrasonic.BuildConfig
@ -27,10 +29,8 @@ import org.moire.ultrasonic.util.ErrorDialog
import org.moire.ultrasonic.util.ModalBackgroundTask
import org.moire.ultrasonic.util.Util
import timber.log.Timber
import java.net.MalformedURLException
import java.net.URL
class EditServerFragment: Fragment() {
class EditServerFragment : Fragment() {
companion object {
const val EDIT_SERVER_INTENT_INDEX = "index"
}
@ -57,8 +57,11 @@ class EditServerFragment: Fragment() {
super.onCreate(savedInstanceState)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.server_edit, container, false)
}
@ -370,4 +373,4 @@ class EditServerFragment: Fragment() {
findNavController().navigateUp()
}
}
}
}

View File

@ -29,4 +29,4 @@ class FragmentTitle {
return (fragment.activity as AppCompatActivity).supportActionBar?.subtitle
}
}
}
}

View File

@ -43,8 +43,11 @@ class SelectArtistFragment : Fragment() {
super.onCreate(savedInstanceState)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.select_artist, container, false)
}
@ -54,14 +57,18 @@ class SelectArtistFragment : Fragment() {
artistListModel.refresh(refreshArtistListView!!)
}
val shouldShowHeader = (!ActiveServerProvider.isOffline(this.context) && !Util.getShouldUseId3Tags(this.context))
val shouldShowHeader = (
!ActiveServerProvider.isOffline(this.context) &&
!Util.getShouldUseId3Tags(this.context)
)
val title = arguments?.getString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TITLE)
if (title == null) {
setTitle(
this,
if (ActiveServerProvider.isOffline(this.context)) R.string.music_library_label_offline
if (ActiveServerProvider.isOffline(this.context))
R.string.music_library_label_offline
else R.string.music_library_label
)
} else {
@ -156,17 +163,83 @@ class SelectArtistFragment : Fragment() {
private fun onArtistMenuItemSelected(menuItem: MenuItem, artist: Artist): Boolean {
when (menuItem.itemId) {
R.id.artist_menu_play_now ->
downloadHandler.downloadRecursively(this, artist.id, false, false, true, false, false, false, false, true)
downloadHandler.downloadRecursively(
this,
artist.id,
false,
false,
true,
false,
false,
false,
false,
true
)
R.id.artist_menu_play_next ->
downloadHandler.downloadRecursively(this, artist.id, false, false, true, true, false, true, false, true)
downloadHandler.downloadRecursively(
this,
artist.id,
false,
false,
true,
true,
false,
true,
false,
true
)
R.id.artist_menu_play_last ->
downloadHandler.downloadRecursively(this, artist.id, false, true, false, false, false, false, false, true)
downloadHandler.downloadRecursively(
this,
artist.id,
false,
true,
false,
false,
false,
false,
false,
true
)
R.id.artist_menu_pin ->
downloadHandler.downloadRecursively(this, artist.id, true, true, false, false, false, false, false, true)
downloadHandler.downloadRecursively(
this,
artist.id,
true,
true,
false,
false,
false,
false,
false,
true
)
R.id.artist_menu_unpin ->
downloadHandler.downloadRecursively(this, artist.id, false, false, false, false, false, false, true, true)
downloadHandler.downloadRecursively(
this,
artist.id,
false,
false,
false,
false,
false,
false,
true,
true
)
R.id.artist_menu_download ->
downloadHandler.downloadRecursively(this, artist.id, false, false, false, false, true, false, false, true)
downloadHandler.downloadRecursively(
this,
artist.id,
false,
false,
false,
false,
true,
false,
false,
true
)
}
return true
}
@ -189,4 +262,4 @@ class SelectArtistFragment : Fragment() {
companion object {
private const val MENU_GROUP_MUSIC_FOLDER = 10
}
}
}

View File

@ -23,7 +23,7 @@ import org.moire.ultrasonic.service.MediaPlayerController
import org.moire.ultrasonic.util.Util
import timber.log.Timber
class ServerSelectorFragment: Fragment() {
class ServerSelectorFragment : Fragment() {
companion object {
const val SERVER_SELECTOR_MANAGE_MODE = "manageMode"
}
@ -40,8 +40,11 @@ class ServerSelectorFragment: Fragment() {
super.onCreate(savedInstanceState)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.server_selector, container, false)
}
@ -155,4 +158,4 @@ class ServerSelectorFragment: Fragment() {
bundle.putInt(EDIT_SERVER_INTENT_INDEX, index)
findNavController().navigate(R.id.serverSelectorToEditServer, bundle)
}
}
}

View File

@ -21,7 +21,6 @@ package org.moire.ultrasonic.service
import android.content.Context
import android.graphics.Bitmap
import android.text.TextUtils
import androidx.annotation.StringRes
import java.io.BufferedWriter
import java.io.File
import java.io.FileOutputStream
@ -31,7 +30,6 @@ import java.io.InputStream
import java.io.OutputStream
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
import org.moire.ultrasonic.R
import org.moire.ultrasonic.api.subsonic.ApiNotSupportedException
import org.moire.ultrasonic.api.subsonic.SubsonicAPIClient
import org.moire.ultrasonic.api.subsonic.models.AlbumListType.Companion.fromName
@ -63,7 +61,6 @@ import org.moire.ultrasonic.domain.toDomainEntityList
import org.moire.ultrasonic.domain.toMusicDirectoryDomainEntity
import org.moire.ultrasonic.util.CancellableTask
import org.moire.ultrasonic.util.FileUtil
import org.moire.ultrasonic.util.ProgressListener
import org.moire.ultrasonic.util.Util
import timber.log.Timber
@ -78,16 +75,12 @@ open class RESTMusicService(
) : MusicService {
@Throws(Exception::class)
override fun ping(context: Context, progressListener: ProgressListener?) {
updateProgressListener(progressListener, R.string.service_connecting)
override fun ping(context: Context) {
responseChecker.callWithResponseCheck { api -> api.ping().execute() }
}
@Throws(Exception::class)
override fun isLicenseValid(context: Context, progressListener: ProgressListener?): Boolean {
updateProgressListener(progressListener, R.string.service_connecting)
override fun isLicenseValid(context: Context): Boolean {
val response = responseChecker.callWithResponseCheck { api -> api.getLicense().execute() }
return response.body()!!.license.valid
@ -96,8 +89,7 @@ open class RESTMusicService(
@Throws(Exception::class)
override fun getMusicFolders(
refresh: Boolean,
context: Context,
progressListener: ProgressListener?
context: Context
): List<MusicFolder> {
val cachedMusicFolders = fileStorage.load(
MUSIC_FOLDER_STORAGE_NAME, getMusicFolderListSerializer()
@ -105,8 +97,6 @@ open class RESTMusicService(
if (cachedMusicFolders != null && !refresh) return cachedMusicFolders
updateProgressListener(progressListener, R.string.parser_reading)
val response = responseChecker.callWithResponseCheck { api ->
api.getMusicFolders().execute()
}
@ -121,14 +111,11 @@ open class RESTMusicService(
override fun getIndexes(
musicFolderId: String?,
refresh: Boolean,
context: Context,
progressListener: ProgressListener?
context: Context
): Indexes {
val cachedIndexes = fileStorage.load(INDEXES_STORAGE_NAME, getIndexesSerializer())
if (cachedIndexes != null && !refresh) return cachedIndexes
updateProgressListener(progressListener, R.string.parser_reading)
val response = responseChecker.callWithResponseCheck { api ->
api.getIndexes(musicFolderId, null).execute()
}
@ -141,14 +128,11 @@ open class RESTMusicService(
@Throws(Exception::class)
override fun getArtists(
refresh: Boolean,
context: Context,
progressListener: ProgressListener?
context: Context
): Indexes {
val cachedArtists = fileStorage.load(ARTISTS_STORAGE_NAME, getIndexesSerializer())
if (cachedArtists != null && !refresh) return cachedArtists
updateProgressListener(progressListener, R.string.parser_reading)
val response = responseChecker.callWithResponseCheck { api ->
api.getArtists(null).execute()
}
@ -163,11 +147,8 @@ open class RESTMusicService(
id: String?,
albumId: String?,
artistId: String?,
context: Context,
progressListener: ProgressListener?
context: Context
) {
updateProgressListener(progressListener, R.string.parser_reading)
responseChecker.callWithResponseCheck { api -> api.star(id, albumId, artistId).execute() }
}
@ -176,11 +157,8 @@ open class RESTMusicService(
id: String?,
albumId: String?,
artistId: String?,
context: Context,
progressListener: ProgressListener?
context: Context
) {
updateProgressListener(progressListener, R.string.parser_reading)
responseChecker.callWithResponseCheck { api -> api.unstar(id, albumId, artistId).execute() }
}
@ -188,11 +166,8 @@ open class RESTMusicService(
override fun setRating(
id: String,
rating: Int,
context: Context,
progressListener: ProgressListener?
context: Context
) {
updateProgressListener(progressListener, R.string.parser_reading)
responseChecker.callWithResponseCheck { api -> api.setRating(id, rating).execute() }
}
@ -201,11 +176,8 @@ open class RESTMusicService(
id: String,
name: String?,
refresh: Boolean,
context: Context,
progressListener: ProgressListener?
context: Context
): MusicDirectory {
updateProgressListener(progressListener, R.string.parser_reading)
val response = responseChecker.callWithResponseCheck { api ->
api.getMusicDirectory(id).execute()
}
@ -218,11 +190,8 @@ open class RESTMusicService(
id: String,
name: String?,
refresh: Boolean,
context: Context,
progressListener: ProgressListener?
context: Context
): MusicDirectory {
updateProgressListener(progressListener, R.string.parser_reading)
val response = responseChecker.callWithResponseCheck { api -> api.getArtist(id).execute() }
return response.body()!!.artist.toMusicDirectoryDomainEntity()
@ -233,11 +202,8 @@ open class RESTMusicService(
id: String,
name: String?,
refresh: Boolean,
context: Context,
progressListener: ProgressListener?
context: Context
): MusicDirectory {
updateProgressListener(progressListener, R.string.parser_reading)
val response = responseChecker.callWithResponseCheck { api -> api.getAlbum(id).execute() }
return response.body()!!.album.toMusicDirectoryDomainEntity()
@ -246,18 +212,17 @@ open class RESTMusicService(
@Throws(Exception::class)
override fun search(
criteria: SearchCriteria,
context: Context,
progressListener: ProgressListener?
context: Context
): SearchResult {
return try {
if (
!isOffline(context) &&
Util.getShouldUseId3Tags(context)
) search3(criteria, progressListener)
else search2(criteria, progressListener)
) search3(criteria)
else search2(criteria)
} catch (ignored: ApiNotSupportedException) {
// Ensure backward compatibility with REST 1.3.
searchOld(criteria, progressListener)
searchOld(criteria)
}
}
@ -266,11 +231,8 @@ open class RESTMusicService(
*/
@Throws(Exception::class)
private fun searchOld(
criteria: SearchCriteria,
progressListener: ProgressListener?
criteria: SearchCriteria
): SearchResult {
updateProgressListener(progressListener, R.string.parser_reading)
val response = responseChecker.callWithResponseCheck { api ->
api.search(null, null, null, criteria.query, criteria.songCount, null, null)
.execute()
@ -284,12 +246,9 @@ open class RESTMusicService(
*/
@Throws(Exception::class)
private fun search2(
criteria: SearchCriteria,
progressListener: ProgressListener?
criteria: SearchCriteria
): SearchResult {
requireNotNull(criteria.query) { "Query param is null" }
updateProgressListener(progressListener, R.string.parser_reading)
val response = responseChecker.callWithResponseCheck { api ->
api.search2(
criteria.query, criteria.artistCount, null, criteria.albumCount, null,
@ -302,12 +261,9 @@ open class RESTMusicService(
@Throws(Exception::class)
private fun search3(
criteria: SearchCriteria,
progressListener: ProgressListener?
criteria: SearchCriteria
): SearchResult {
requireNotNull(criteria.query) { "Query param is null" }
updateProgressListener(progressListener, R.string.parser_reading)
val response = responseChecker.callWithResponseCheck { api ->
api.search3(
criteria.query, criteria.artistCount, null, criteria.albumCount, null,
@ -322,11 +278,8 @@ open class RESTMusicService(
override fun getPlaylist(
id: String,
name: String?,
context: Context,
progressListener: ProgressListener?
context: Context
): MusicDirectory {
updateProgressListener(progressListener, R.string.parser_reading)
val response = responseChecker.callWithResponseCheck { api ->
api.getPlaylist(id).execute()
}
@ -374,11 +327,8 @@ open class RESTMusicService(
@Throws(Exception::class)
override fun getPlaylists(
refresh: Boolean,
context: Context,
progressListener: ProgressListener?
context: Context
): List<Playlist> {
updateProgressListener(progressListener, R.string.parser_reading)
val response = responseChecker.callWithResponseCheck { api ->
api.getPlaylists(null).execute()
}
@ -391,8 +341,7 @@ open class RESTMusicService(
id: String?,
name: String?,
entries: List<MusicDirectory.Entry>,
context: Context,
progressListener: ProgressListener?
context: Context
) {
val pSongIds: MutableList<String> = ArrayList(entries.size)
@ -401,9 +350,6 @@ open class RESTMusicService(
pSongIds.add(id1)
}
}
updateProgressListener(progressListener, R.string.parser_reading)
responseChecker.callWithResponseCheck { api ->
api.createPlaylist(id, name, pSongIds.toList()).execute()
}
@ -412,11 +358,8 @@ open class RESTMusicService(
@Throws(Exception::class)
override fun deletePlaylist(
id: String,
context: Context,
progressListener: ProgressListener?
context: Context
) {
updateProgressListener(progressListener, R.string.parser_reading)
responseChecker.callWithResponseCheck { api -> api.deletePlaylist(id).execute() }
}
@ -426,11 +369,8 @@ open class RESTMusicService(
name: String?,
comment: String?,
pub: Boolean,
context: Context?,
progressListener: ProgressListener?
context: Context?
) {
updateProgressListener(progressListener, R.string.parser_reading)
responseChecker.callWithResponseCheck { api ->
api.updatePlaylist(id, name, comment, pub, null, null)
.execute()
@ -440,11 +380,8 @@ open class RESTMusicService(
@Throws(Exception::class)
override fun getPodcastsChannels(
refresh: Boolean,
context: Context,
progressListener: ProgressListener?
context: Context
): List<PodcastsChannel> {
updateProgressListener(progressListener, R.string.parser_reading)
val response = responseChecker.callWithResponseCheck { api ->
api.getPodcasts(false, null).execute()
}
@ -455,11 +392,8 @@ open class RESTMusicService(
@Throws(Exception::class)
override fun getPodcastEpisodes(
podcastChannelId: String?,
context: Context,
progressListener: ProgressListener?
context: Context
): MusicDirectory {
updateProgressListener(progressListener, R.string.parser_reading)
val response = responseChecker.callWithResponseCheck { api ->
api.getPodcasts(true, podcastChannelId).execute()
}
@ -485,11 +419,8 @@ open class RESTMusicService(
override fun getLyrics(
artist: String?,
title: String?,
context: Context,
progressListener: ProgressListener?
context: Context
): Lyrics {
updateProgressListener(progressListener, R.string.parser_reading)
val response = responseChecker.callWithResponseCheck { api ->
api.getLyrics(artist, title).execute()
}
@ -501,11 +432,8 @@ open class RESTMusicService(
override fun scrobble(
id: String,
submission: Boolean,
context: Context,
progressListener: ProgressListener?
context: Context
) {
updateProgressListener(progressListener, R.string.parser_reading)
responseChecker.callWithResponseCheck { api ->
api.scrobble(id, null, submission).execute()
}
@ -516,11 +444,8 @@ open class RESTMusicService(
type: String,
size: Int,
offset: Int,
context: Context,
progressListener: ProgressListener?
context: Context
): MusicDirectory {
updateProgressListener(progressListener, R.string.parser_reading)
val response = responseChecker.callWithResponseCheck { api ->
api.getAlbumList(fromName(type), size, offset, null, null, null, null)
.execute()
@ -538,11 +463,8 @@ open class RESTMusicService(
type: String,
size: Int,
offset: Int,
context: Context,
progressListener: ProgressListener?
context: Context
): MusicDirectory {
updateProgressListener(progressListener, R.string.parser_reading)
val response = responseChecker.callWithResponseCheck { api ->
api.getAlbumList2(
fromName(type),
@ -564,11 +486,8 @@ open class RESTMusicService(
@Throws(Exception::class)
override fun getRandomSongs(
size: Int,
context: Context,
progressListener: ProgressListener?
context: Context
): MusicDirectory {
updateProgressListener(progressListener, R.string.parser_reading)
val response = responseChecker.callWithResponseCheck { api ->
api.getRandomSongs(
size,
@ -587,11 +506,8 @@ open class RESTMusicService(
@Throws(Exception::class)
override fun getStarred(
context: Context,
progressListener: ProgressListener?
context: Context
): SearchResult {
updateProgressListener(progressListener, R.string.parser_reading)
val response = responseChecker.callWithResponseCheck { api ->
api.getStarred(null).execute()
}
@ -601,11 +517,8 @@ open class RESTMusicService(
@Throws(Exception::class)
override fun getStarred2(
context: Context,
progressListener: ProgressListener?
context: Context
): SearchResult {
updateProgressListener(progressListener, R.string.parser_reading)
val response = responseChecker.callWithResponseCheck { api ->
api.getStarred2(null).execute()
}
@ -619,8 +532,7 @@ open class RESTMusicService(
entry: MusicDirectory.Entry?,
size: Int,
saveToFile: Boolean,
highQuality: Boolean,
progressListener: ProgressListener?
highQuality: Boolean
): Bitmap? {
// Synchronize on the entry so that we don't download concurrently for
// the same song.
@ -744,11 +656,8 @@ open class RESTMusicService(
@Throws(Exception::class)
override fun updateJukeboxPlaylist(
ids: List<String>?,
context: Context,
progressListener: ProgressListener?
context: Context
): JukeboxStatus {
updateProgressListener(progressListener, R.string.parser_reading)
val response = responseChecker.callWithResponseCheck { api ->
api.jukeboxControl(JukeboxAction.SET, null, null, ids, null)
.execute()
@ -761,11 +670,8 @@ open class RESTMusicService(
override fun skipJukebox(
index: Int,
offsetSeconds: Int,
context: Context,
progressListener: ProgressListener?
context: Context
): JukeboxStatus {
updateProgressListener(progressListener, R.string.parser_reading)
val response = responseChecker.callWithResponseCheck { api ->
api.jukeboxControl(JukeboxAction.SKIP, index, offsetSeconds, null, null)
.execute()
@ -776,11 +682,8 @@ open class RESTMusicService(
@Throws(Exception::class)
override fun stopJukebox(
context: Context,
progressListener: ProgressListener?
context: Context
): JukeboxStatus {
updateProgressListener(progressListener, R.string.parser_reading)
val response = responseChecker.callWithResponseCheck { api ->
api.jukeboxControl(JukeboxAction.STOP, null, null, null, null)
.execute()
@ -791,11 +694,8 @@ open class RESTMusicService(
@Throws(Exception::class)
override fun startJukebox(
context: Context,
progressListener: ProgressListener?
context: Context
): JukeboxStatus {
updateProgressListener(progressListener, R.string.parser_reading)
val response = responseChecker.callWithResponseCheck { api ->
api.jukeboxControl(JukeboxAction.START, null, null, null, null)
.execute()
@ -806,11 +706,8 @@ open class RESTMusicService(
@Throws(Exception::class)
override fun getJukeboxStatus(
context: Context,
progressListener: ProgressListener?
context: Context
): JukeboxStatus {
updateProgressListener(progressListener, R.string.parser_reading)
val response = responseChecker.callWithResponseCheck { api ->
api.jukeboxControl(JukeboxAction.STATUS, null, null, null, null)
.execute()
@ -822,11 +719,8 @@ open class RESTMusicService(
@Throws(Exception::class)
override fun setJukeboxGain(
gain: Float,
context: Context,
progressListener: ProgressListener?
context: Context
): JukeboxStatus {
updateProgressListener(progressListener, R.string.parser_reading)
val response = responseChecker.callWithResponseCheck { api ->
api.jukeboxControl(JukeboxAction.SET_GAIN, null, null, null, gain)
.execute()
@ -838,11 +732,8 @@ open class RESTMusicService(
@Throws(Exception::class)
override fun getShares(
refresh: Boolean,
context: Context,
progressListener: ProgressListener?
context: Context
): List<Share> {
updateProgressListener(progressListener, R.string.parser_reading)
val response = responseChecker.callWithResponseCheck { api -> api.getShares().execute() }
return response.body()!!.shares.toDomainEntitiesList()
@ -851,11 +742,8 @@ open class RESTMusicService(
@Throws(Exception::class)
override fun getGenres(
refresh: Boolean,
context: Context,
progressListener: ProgressListener?
context: Context
): List<Genre> {
updateProgressListener(progressListener, R.string.parser_reading)
val response = responseChecker.callWithResponseCheck { api -> api.getGenres().execute() }
return response.body()!!.genresList.toDomainEntityList()
@ -866,11 +754,8 @@ open class RESTMusicService(
genre: String,
count: Int,
offset: Int,
context: Context,
progressListener: ProgressListener?
context: Context
): MusicDirectory {
updateProgressListener(progressListener, R.string.parser_reading)
val response = responseChecker.callWithResponseCheck { api ->
api.getSongsByGenre(genre, count, offset, null).execute()
}
@ -884,11 +769,8 @@ open class RESTMusicService(
@Throws(Exception::class)
override fun getUser(
username: String,
context: Context,
progressListener: ProgressListener?
context: Context
): UserInfo {
updateProgressListener(progressListener, R.string.parser_reading)
val response = responseChecker.callWithResponseCheck { api ->
api.getUser(username).execute()
}
@ -899,11 +781,8 @@ open class RESTMusicService(
@Throws(Exception::class)
override fun getChatMessages(
since: Long?,
context: Context,
progressListener: ProgressListener?
context: Context
): List<ChatMessage> {
updateProgressListener(progressListener, R.string.parser_reading)
val response = responseChecker.callWithResponseCheck { api ->
api.getChatMessages(since).execute()
}
@ -914,21 +793,15 @@ open class RESTMusicService(
@Throws(Exception::class)
override fun addChatMessage(
message: String,
context: Context,
progressListener: ProgressListener?
context: Context
) {
updateProgressListener(progressListener, R.string.parser_reading)
responseChecker.callWithResponseCheck { api -> api.addChatMessage(message).execute() }
}
@Throws(Exception::class)
override fun getBookmarks(
context: Context,
progressListener: ProgressListener?
context: Context
): List<Bookmark> {
updateProgressListener(progressListener, R.string.parser_reading)
val response = responseChecker.callWithResponseCheck { api -> api.getBookmarks().execute() }
return response.body()!!.bookmarkList.toDomainEntitiesList()
@ -938,11 +811,8 @@ open class RESTMusicService(
override fun createBookmark(
id: String,
position: Int,
context: Context,
progressListener: ProgressListener?
context: Context
) {
updateProgressListener(progressListener, R.string.parser_reading)
responseChecker.callWithResponseCheck { api ->
api.createBookmark(id, position.toLong(), null).execute()
}
@ -951,22 +821,16 @@ open class RESTMusicService(
@Throws(Exception::class)
override fun deleteBookmark(
id: String,
context: Context,
progressListener: ProgressListener?
context: Context
) {
updateProgressListener(progressListener, R.string.parser_reading)
responseChecker.callWithResponseCheck { api -> api.deleteBookmark(id).execute() }
}
@Throws(Exception::class)
override fun getVideos(
refresh: Boolean,
context: Context,
progressListener: ProgressListener?
context: Context
): MusicDirectory {
updateProgressListener(progressListener, R.string.parser_reading)
val response = responseChecker.callWithResponseCheck { api -> api.getVideos().execute() }
val musicDirectory = MusicDirectory()
@ -980,11 +844,8 @@ open class RESTMusicService(
ids: List<String>,
description: String?,
expires: Long?,
context: Context,
progressListener: ProgressListener?
context: Context
): List<Share> {
updateProgressListener(progressListener, R.string.parser_reading)
val response = responseChecker.callWithResponseCheck { api ->
api.createShare(ids, description, expires).execute()
}
@ -995,11 +856,8 @@ open class RESTMusicService(
@Throws(Exception::class)
override fun deleteShare(
id: String,
context: Context,
progressListener: ProgressListener?
context: Context
) {
updateProgressListener(progressListener, R.string.parser_reading)
responseChecker.callWithResponseCheck { api -> api.deleteShare(id).execute() }
}
@ -1008,16 +866,13 @@ open class RESTMusicService(
id: String,
description: String?,
expires: Long?,
context: Context,
progressListener: ProgressListener?
context: Context
) {
var expiresValue: Long? = expires
if (expires != null && expires == 0L) {
expiresValue = null
}
updateProgressListener(progressListener, R.string.parser_reading)
responseChecker.callWithResponseCheck { api ->
api.updateShare(id, description, expiresValue).execute()
}
@ -1029,8 +884,7 @@ open class RESTMusicService(
username: String?,
size: Int,
saveToFile: Boolean,
highQuality: Boolean,
progressListener: ProgressListener?
highQuality: Boolean
): Bitmap? {
// Synchronize on the username so that we don't download concurrently for
// the same user.
@ -1045,7 +899,6 @@ open class RESTMusicService(
if (bitmap == null) {
var inputStream: InputStream? = null
try {
updateProgressListener(progressListener, R.string.parser_reading)
val response = subsonicAPIClient.getAvatar(username)
if (response.hasError()) return null
@ -1079,13 +932,6 @@ open class RESTMusicService(
}
}
private fun updateProgressListener(
progressListener: ProgressListener?,
@StringRes messageId: Int
) {
progressListener?.updateProgress(messageId)
}
companion object {
private const val MUSIC_FOLDER_STORAGE_NAME = "music_folder"
private const val INDEXES_STORAGE_NAME = "indexes"

View File

@ -3,6 +3,8 @@ package org.moire.ultrasonic.subsonic
import android.app.Activity
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
import java.util.Collections
import java.util.LinkedList
import org.moire.ultrasonic.R
import org.moire.ultrasonic.data.ActiveServerProvider.Companion.isOffline
import org.moire.ultrasonic.domain.MusicDirectory
@ -12,7 +14,6 @@ import org.moire.ultrasonic.util.Constants
import org.moire.ultrasonic.util.EntryByDiscAndTrackComparator
import org.moire.ultrasonic.util.ModalBackgroundTask
import org.moire.ultrasonic.util.Util
import java.util.*
class DownloadHandler(
val mediaPlayerController: MediaPlayerController,
@ -20,14 +21,31 @@ class DownloadHandler(
) {
private val MAX_SONGS = 500
fun download(fragment: Fragment, append: Boolean, save: Boolean, autoPlay: Boolean, playNext: Boolean, shuffle: Boolean, songs: List<MusicDirectory.Entry?>) {
fun download(
fragment: Fragment,
append: Boolean,
save: Boolean,
autoPlay: Boolean,
playNext: Boolean,
shuffle: Boolean,
songs: List<MusicDirectory.Entry?>
) {
val onValid = Runnable {
if (!append && !playNext) {
mediaPlayerController.clear()
}
networkAndStorageChecker.warnIfNetworkOrStorageUnavailable()
mediaPlayerController.download(songs, save, autoPlay, playNext, shuffle, false)
val playlistName: String? = fragment.arguments?.getString(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME)
mediaPlayerController.download(
songs,
save,
autoPlay,
playNext,
shuffle,
false
)
val playlistName: String? = fragment.arguments?.getString(
Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME
)
if (playlistName != null) {
mediaPlayerController.suggestedPlaylistName = playlistName
}
@ -37,22 +55,93 @@ class DownloadHandler(
fragment.findNavController().navigate(R.id.playerFragment)
}
} else if (save) {
Util.toast(fragment.context, fragment.resources.getQuantityString(R.plurals.select_album_n_songs_pinned, songs.size, songs.size))
Util.toast(
fragment.context,
fragment.resources.getQuantityString(
R.plurals.select_album_n_songs_pinned,
songs.size,
songs.size
)
)
} else if (playNext) {
Util.toast(fragment.context, fragment.resources.getQuantityString(R.plurals.select_album_n_songs_play_next, songs.size, songs.size))
Util.toast(
fragment.context,
fragment.resources.getQuantityString(
R.plurals.select_album_n_songs_play_next,
songs.size,
songs.size
)
)
} else if (append) {
Util.toast(fragment.context, fragment.resources.getQuantityString(R.plurals.select_album_n_songs_added, songs.size, songs.size))
Util.toast(
fragment.context,
fragment.resources.getQuantityString(
R.plurals.select_album_n_songs_added,
songs.size,
songs.size
)
)
}
}
onValid.run()
}
fun downloadPlaylist(fragment: Fragment, id: String, name: String?, save: Boolean, append: Boolean, autoplay: Boolean, shuffle: Boolean, background: Boolean, playNext: Boolean, unpin: Boolean) {
downloadRecursively(fragment, id, name, false, false, save, append, autoplay, shuffle, background, playNext, unpin, false)
fun downloadPlaylist(
fragment: Fragment,
id: String,
name: String?,
save: Boolean,
append: Boolean,
autoplay: Boolean,
shuffle: Boolean,
background: Boolean,
playNext: Boolean,
unpin: Boolean
) {
downloadRecursively(
fragment,
id,
name,
false,
false,
save,
append,
autoplay,
shuffle,
background,
playNext,
unpin,
false
)
}
fun downloadShare(fragment: Fragment, id: String, name: String?, save: Boolean, append: Boolean, autoplay: Boolean, shuffle: Boolean, background: Boolean, playNext: Boolean, unpin: Boolean) {
downloadRecursively(fragment, id, name, true, false, save, append, autoplay, shuffle, background, playNext, unpin, false)
fun downloadShare(
fragment: Fragment,
id: String,
name: String?,
save: Boolean,
append: Boolean,
autoplay: Boolean,
shuffle: Boolean,
background: Boolean,
playNext: Boolean,
unpin: Boolean
) {
downloadRecursively(
fragment,
id,
name,
true,
false,
save,
append,
autoplay,
shuffle,
background,
playNext,
unpin,
false
)
}
fun downloadRecursively(
@ -81,7 +170,8 @@ class DownloadHandler(
background = background,
playNext = playNext,
unpin = unpin,
isArtist = isArtist)
isArtist = isArtist
)
}
fun downloadRecursively(
@ -100,7 +190,7 @@ class DownloadHandler(
isArtist: Boolean
) {
val activity = fragment.activity as Activity
val task = object: ModalBackgroundTask<List<MusicDirectory.Entry>>(
val task = object : ModalBackgroundTask<List<MusicDirectory.Entry>>(
activity,
false
) {
@ -115,12 +205,12 @@ class DownloadHandler(
} else {
if (isDirectory) {
root = if (!isOffline(activity) && Util.getShouldUseId3Tags(activity))
musicService.getAlbum(id, name, false, activity, null)
musicService.getAlbum(id, name, false, activity)
else
musicService.getMusicDirectory(id, name, false, activity, null)
musicService.getMusicDirectory(id, name, false, activity)
} else if (isShare) {
root = MusicDirectory()
val shares = musicService.getShares(true, activity, null)
val shares = musicService.getShares(true, activity)
for (share in shares) {
if (share.id == id) {
for (entry in share.getEntries()) {
@ -130,7 +220,7 @@ class DownloadHandler(
}
}
} else {
root = musicService.getPlaylist(id, name, activity, null)
root = musicService.getPlaylist(id, name, activity)
}
getSongsRecursively(root, songs)
}
@ -138,7 +228,10 @@ class DownloadHandler(
}
@Throws(Exception::class)
private fun getSongsRecursively(parent: MusicDirectory, songs: MutableList<MusicDirectory.Entry>) {
private fun getSongsRecursively(
parent: MusicDirectory,
songs: MutableList<MusicDirectory.Entry>
) {
if (songs.size > MAX_SONGS) {
return
}
@ -150,21 +243,32 @@ class DownloadHandler(
val musicService = getMusicService(activity)
for ((id1, _, _, title) in parent.getChildren(true, false)) {
var root: MusicDirectory
root = if (!isOffline(activity) && Util.getShouldUseId3Tags(activity)) musicService.getAlbum(id1, title, false, activity, null)
else musicService.getMusicDirectory(id1, title, false, activity, null)
root = if (
!isOffline(activity) &&
Util.getShouldUseId3Tags(activity)
) musicService.getAlbum(id1, title, false, activity)
else musicService.getMusicDirectory(id1, title, false, activity)
getSongsRecursively(root, songs)
}
}
@Throws(Exception::class)
private fun getSongsForArtist(id: String, songs: MutableCollection<MusicDirectory.Entry>) {
private fun getSongsForArtist(
id: String,
songs: MutableCollection<MusicDirectory.Entry>
) {
if (songs.size > MAX_SONGS) {
return
}
val musicService = getMusicService(activity)
val artist = musicService.getArtist(id, "", false, activity, null)
val artist = musicService.getArtist(id, "", false, activity)
for ((id1) in artist.getChildren()) {
val albumDirectory = musicService.getAlbum(id1, "", false, activity, null)
val albumDirectory = musicService.getAlbum(
id1,
"",
false,
activity
)
for (song in albumDirectory.getChildren()) {
if (!song.isVideo) {
songs.add(song)
@ -186,9 +290,22 @@ class DownloadHandler(
if (unpin) {
mediaPlayerController.unpin(songs)
} else {
mediaPlayerController.download(songs, save, autoPlay, playNext, shuffle, false)
if (!append && Util.getShouldTransitionOnPlaybackPreference(activity)) {
fragment.findNavController().popBackStack(R.id.playerFragment, true)
mediaPlayerController.download(
songs,
save,
autoPlay,
playNext,
shuffle,
false
)
if (
!append &&
Util.getShouldTransitionOnPlaybackPreference(activity)
) {
fragment.findNavController().popBackStack(
R.id.playerFragment,
true
)
fragment.findNavController().navigate(R.id.playerFragment)
}
}

View File

@ -9,13 +9,15 @@ import org.moire.ultrasonic.util.ImageLoader
import org.moire.ultrasonic.util.LegacyImageLoader
import org.moire.ultrasonic.util.Util
class ImageLoaderProvider (val context: Context) {
class ImageLoaderProvider(val context: Context) {
private var imageLoader: ImageLoader? = null
@Synchronized
fun clearImageLoader() {
if (imageLoader != null &&
imageLoader!!.isRunning) {
if (
imageLoader != null &&
imageLoader!!.isRunning
) {
imageLoader!!.clear()
}
imageLoader = null
@ -42,4 +44,4 @@ class ImageLoaderProvider (val context: Context) {
}
return imageLoader!!
}
}
}

View File

@ -13,4 +13,4 @@ class NetworkAndStorageChecker(val context: Context) {
Util.toast(context, R.string.select_album_no_network)
}
}
}
}

View File

@ -9,6 +9,7 @@ import android.widget.CheckBox
import android.widget.EditText
import androidx.fragment.app.Fragment
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import java.util.regex.Pattern
import org.moire.ultrasonic.R
import org.moire.ultrasonic.domain.MusicDirectory
import org.moire.ultrasonic.domain.Share
@ -16,13 +17,11 @@ import org.moire.ultrasonic.service.MusicServiceFactory.getMusicService
import org.moire.ultrasonic.util.BackgroundTask
import org.moire.ultrasonic.util.CancellationToken
import org.moire.ultrasonic.util.Constants
import org.moire.ultrasonic.util.FragmentBackgroundTask
import org.moire.ultrasonic.util.ShareDetails
import org.moire.ultrasonic.util.TabActivityBackgroundTask
import org.moire.ultrasonic.util.TimeSpan
import org.moire.ultrasonic.util.TimeSpanPicker
import org.moire.ultrasonic.util.Util
import java.util.*
import java.util.regex.Pattern
class ShareHandler(val context: Context) {
private var shareDescription: EditText? = null
@ -32,7 +31,12 @@ class ShareHandler(val context: Context) {
private var saveAsDefaultsCheckBox: CheckBox? = null
private val pattern = Pattern.compile(":")
fun createShare(fragment: Fragment, entries: List<MusicDirectory.Entry?>?, swipe: SwipeRefreshLayout?, cancellationToken: CancellationToken) {
fun createShare(
fragment: Fragment,
entries: List<MusicDirectory.Entry?>?,
swipe: SwipeRefreshLayout?,
cancellationToken: CancellationToken
) {
val askForDetails = Util.getShouldAskForShareDetails(context)
val shareDetails = ShareDetails()
shareDetails.Entries = entries
@ -40,13 +44,25 @@ class ShareHandler(val context: Context) {
showDialog(fragment, shareDetails, swipe, cancellationToken)
} else {
shareDetails.Description = Util.getDefaultShareDescription(context)
shareDetails.Expiration = TimeSpan.getCurrentTime().add(Util.getDefaultShareExpirationInMillis(context)).totalMilliseconds
shareDetails.Expiration = TimeSpan.getCurrentTime().add(
Util.getDefaultShareExpirationInMillis(context)
).totalMilliseconds
share(fragment, shareDetails, swipe, cancellationToken)
}
}
fun share(fragment: Fragment, shareDetails: ShareDetails, swipe: SwipeRefreshLayout?, cancellationToken: CancellationToken) {
val task: BackgroundTask<Share> = object : TabActivityBackgroundTask<Share>(fragment.requireActivity(), true, swipe, cancellationToken) {
fun share(
fragment: Fragment,
shareDetails: ShareDetails,
swipe: SwipeRefreshLayout?,
cancellationToken: CancellationToken
) {
val task: BackgroundTask<Share> = object : FragmentBackgroundTask<Share>(
fragment.requireActivity(),
true,
swipe,
cancellationToken
) {
@Throws(Throwable::class)
override fun doInBackground(): Share {
val ids: MutableList<String?> = ArrayList()
@ -62,33 +78,49 @@ class ShareHandler(val context: Context) {
if (shareDetails.Expiration != 0L) {
timeInMillis = shareDetails.Expiration
}
val shares = musicService.createShare(ids, shareDetails.Description, timeInMillis, context, this)
val shares =
musicService.createShare(ids, shareDetails.Description, timeInMillis, context)
return shares[0]
}
override fun done(result: Share) {
val intent = Intent(Intent.ACTION_SEND)
intent.type = "text/plain"
intent.putExtra(Intent.EXTRA_TEXT, String.format("%s\n\n%s", Util.getShareGreeting(context), result.url))
fragment.activity?.startActivity(Intent.createChooser(intent, context.getResources().getString(R.string.share_via)))
intent.putExtra(
Intent.EXTRA_TEXT,
String.format("%s\n\n%s", Util.getShareGreeting(context), result.url)
)
fragment.activity?.startActivity(
Intent.createChooser(
intent,
context.getResources().getString(R.string.share_via)
)
)
}
}
task.execute()
}
private fun showDialog(fragment: Fragment, shareDetails: ShareDetails, swipe: SwipeRefreshLayout?, cancellationToken: CancellationToken) {
private fun showDialog(
fragment: Fragment,
shareDetails: ShareDetails,
swipe: SwipeRefreshLayout?,
cancellationToken: CancellationToken
) {
val layout = LayoutInflater.from(fragment.context).inflate(R.layout.share_details, null)
if (layout != null) {
shareDescription = layout.findViewById<View>(R.id.share_description) as EditText
hideDialogCheckBox = layout.findViewById<View>(R.id.hide_dialog) as CheckBox
noExpirationCheckBox = layout.findViewById<View>(R.id.timeSpanDisableCheckBox) as CheckBox
noExpirationCheckBox = layout.findViewById<View>(
R.id.timeSpanDisableCheckBox
) as CheckBox
saveAsDefaultsCheckBox = layout.findViewById<View>(R.id.save_as_defaults) as CheckBox
timeSpanPicker = layout.findViewById<View>(R.id.date_picker) as TimeSpanPicker
}
val builder = AlertDialog.Builder(fragment.context)
builder.setTitle(R.string.share_set_share_options)
builder.setPositiveButton(R.string.common_save) { dialog, clickId ->
builder.setPositiveButton(R.string.common_save) { _, _ ->
if (!noExpirationCheckBox!!.isChecked) {
val timeSpan: TimeSpan = timeSpanPicker!!.timeSpan
val now = TimeSpan.getCurrentTime()
@ -101,18 +133,26 @@ class ShareHandler(val context: Context) {
if (saveAsDefaultsCheckBox!!.isChecked) {
val timeSpanType: String = timeSpanPicker!!.timeSpanType
val timeSpanAmount: Int = timeSpanPicker!!.timeSpanAmount
Util.setDefaultShareExpiration(context, if (!noExpirationCheckBox!!.isChecked && timeSpanAmount > 0) String.format("%d:%s", timeSpanAmount, timeSpanType) else "")
Util.setDefaultShareExpiration(
context,
if (!noExpirationCheckBox!!.isChecked && timeSpanAmount > 0)
String.format("%d:%s", timeSpanAmount, timeSpanType) else ""
)
Util.setDefaultShareDescription(context, shareDetails.Description)
}
share(fragment, shareDetails, swipe, cancellationToken)
}
builder.setNegativeButton(R.string.common_cancel) { dialog, clickId ->
builder.setNegativeButton(R.string.common_cancel) { dialog, _ ->
dialog.cancel()
}
builder.setView(layout)
builder.setCancelable(true)
timeSpanPicker!!.setTimeSpanDisableText(context.resources.getString(R.string.no_expiration))
noExpirationCheckBox!!.setOnCheckedChangeListener { _, b -> timeSpanPicker!!.isEnabled = !b }
noExpirationCheckBox!!.setOnCheckedChangeListener {
_,
b ->
timeSpanPicker!!.isEnabled = !b
}
val defaultDescription = Util.getDefaultShareDescription(context)
val timeSpan = Util.getDefaultShareExpiration(context)
val split = pattern.split(timeSpan)
@ -136,4 +176,4 @@ class ShareHandler(val context: Context) {
builder.create()
builder.show()
}
}
}

View File

@ -18,4 +18,4 @@ class VideoPlayer(val context: Context) {
Util.toast(context, e.message, false)
}
}
}
}

View File

@ -28,6 +28,6 @@ class CancellationToken {
* Requests that this token be cancelled
*/
fun cancel() {
isCancellationRequested = true;
isCancellationRequested = true
}
}
}

View File

@ -1,7 +1,8 @@
package org.moire.ultrasonic.util
class NowPlayingEventDistributor {
var eventListenerList: MutableList<NowPlayingEventListener> = listOf<NowPlayingEventListener>().toMutableList()
var eventListenerList: MutableList<NowPlayingEventListener> =
listOf<NowPlayingEventListener>().toMutableList()
fun subscribe(listener: NowPlayingEventListener) {
eventListenerList.add(listener)
@ -12,14 +13,14 @@ class NowPlayingEventDistributor {
}
fun RaiseShowNowPlayingEvent() {
eventListenerList.forEach{ listener -> listener.onShowNowPlaying() }
eventListenerList.forEach { listener -> listener.onShowNowPlaying() }
}
fun RaiseHideNowPlayingEvent() {
eventListenerList.forEach{ listener -> listener.onHideNowPlaying() }
eventListenerList.forEach { listener -> listener.onHideNowPlaying() }
}
fun RaiseNowPlayingDismissedEvent() {
eventListenerList.forEach{ listener -> listener.onDismissNowPlaying() }
eventListenerList.forEach { listener -> listener.onDismissNowPlaying() }
}
}
}

View File

@ -4,4 +4,4 @@ interface NowPlayingEventListener {
fun onDismissNowPlaying()
fun onHideNowPlaying()
fun onShowNowPlaying()
}
}

View File

@ -2,19 +2,20 @@ package org.moire.ultrasonic.util
import android.content.Context
import android.os.Build
import timber.log.Timber
import java.io.File
import java.io.PrintWriter
import timber.log.Timber
private const val filename = "ultrasonic-stacktrace.txt"
/**
* Logs the stack trace of uncaught exceptions to a file on the SD card.
*/
class SubsonicUncaughtExceptionHandler (
class SubsonicUncaughtExceptionHandler(
private val context: Context
) : Thread.UncaughtExceptionHandler {
private val defaultHandler: Thread.UncaughtExceptionHandler? = Thread.getDefaultUncaughtExceptionHandler()
) : Thread.UncaughtExceptionHandler {
private val defaultHandler: Thread.UncaughtExceptionHandler? =
Thread.getDefaultUncaughtExceptionHandler()
override fun uncaughtException(thread: Thread, throwable: Throwable) {
var file: File? = null
@ -24,8 +25,10 @@ class SubsonicUncaughtExceptionHandler (
file = File(FileUtil.getUltrasonicDirectory(context), filename)
printWriter = PrintWriter(file)
val logMessage = String.format(
"Android API level: %s\nUltrasonic version name: %s\nUltrasonic version code: %s\n\n",
Build.VERSION.SDK_INT, Util.getVersionName(context), Util.getVersionCode(context))
"Android API level: %s\nUltrasonic version name: %s\n" +
"Ultrasonic version code: %s\n\n",
Build.VERSION.SDK_INT, Util.getVersionName(context), Util.getVersionCode(context)
)
printWriter.println(logMessage)
throwable.printStackTrace(printWriter)
Timber.e(throwable, "Uncaught Exception! %s", logMessage)
@ -37,4 +40,4 @@ class SubsonicUncaughtExceptionHandler (
defaultHandler?.uncaughtException(thread, throwable)
}
}
}
}

View File

@ -1,7 +1,8 @@
package org.moire.ultrasonic.util
class ThemeChangedEventDistributor {
var eventListenerList: MutableList<ThemeChangedEventListener> = listOf<ThemeChangedEventListener>().toMutableList()
var eventListenerList: MutableList<ThemeChangedEventListener> =
listOf<ThemeChangedEventListener>().toMutableList()
fun subscribe(listener: ThemeChangedEventListener) {
eventListenerList.add(listener)
@ -12,6 +13,6 @@ class ThemeChangedEventDistributor {
}
fun RaiseThemeChangedEvent() {
eventListenerList.forEach{ listener -> listener.onThemeChanged() }
eventListenerList.forEach { listener -> listener.onThemeChanged() }
}
}
}

View File

@ -2,4 +2,4 @@ package org.moire.ultrasonic.util
interface ThemeChangedEventListener {
fun onThemeChanged()
}
}

View File

@ -204,9 +204,9 @@ class SongView(context: Context) : UpdateView(context), Checkable {
val musicService = getMusicService(this@SongView.context)
try {
if (!isStarred) {
musicService.star(id, null, null, this@SongView.context, null)
musicService.star(id, null, null, this@SongView.context)
} else {
musicService.unstar(id, null, null, this@SongView.context, null)
musicService.unstar(id, null, null, this@SongView.context)
}
} catch (e: Exception) {
Timber.e(e)

View File

@ -4,43 +4,48 @@
a:layout_height="fill_parent"
a:orientation="vertical" >
<ListView
a:id="@+id/chat_entries_list"
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
a:id="@+id/chat_refresh"
a:layout_width="fill_parent"
a:layout_height="0dip"
a:layout_weight="1.0" />
a:layout_height="0dp"
a:layout_weight="1.0">
<ListView
a:id="@+id/chat_entries_list"
a:layout_width="fill_parent"
a:layout_height="0dip"
a:layout_weight="1.0" />
<LinearLayout
a:layout_height="4dip"
a:layout_width="fill_parent"
a:layout_marginTop="4dip"
a:background="@drawable/drop_shadow" />
<LinearLayout
a:layout_height="4dip"
a:layout_width="fill_parent"
a:layout_marginTop="4dip"
a:background="@drawable/drop_shadow" />
<LinearLayout
a:layout_width="fill_parent"
a:layout_height="wrap_content"
a:orientation="horizontal"
a:gravity="bottom" >
<LinearLayout
a:layout_width="fill_parent"
a:layout_height="wrap_content"
a:orientation="horizontal"
a:gravity="bottom" >
<EditText
a:id="@+id/chat_edittext"
a:layout_width="0dip"
a:layout_height="40dip"
a:layout_weight="1"
a:autoLink="all"
a:hint="@string/chat.send_a_message"
a:inputType="textEmailAddress|textMultiLine"
a:linksClickable="true"
a:paddingBottom="10dip"
a:paddingTop="10dip" />
<EditText
a:id="@+id/chat_edittext"
a:layout_width="0dip"
a:layout_height="40dip"
a:layout_weight="1"
a:autoLink="all"
a:hint="@string/chat.send_a_message"
a:inputType="textEmailAddress|textMultiLine"
a:linksClickable="true"
a:paddingBottom="10dip"
a:paddingTop="10dip" />
<ImageButton
a:id="@+id/chat_send"
a:layout_width="55dip"
a:layout_height="40dip"
a:background="@color/transparent"
a:src="?attr/chat_send" />
</LinearLayout>
<ImageButton
a:id="@+id/chat_send"
a:layout_width="55dip"
a:layout_height="40dip"
a:background="@color/transparent"
a:src="?attr/chat_send" />
</LinearLayout>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</LinearLayout>

View File

@ -3,21 +3,25 @@
a:layout_width="fill_parent"
a:layout_height="fill_parent"
a:orientation="vertical" >
<TextView
a:id="@+id/select_podcasts_empty"
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
a:id="@+id/podcasts_refresh"
a:layout_width="fill_parent"
a:layout_height="wrap_content"
a:padding="10dip"
a:text="@string/podcasts_channels.empty"
a:visibility="gone" />
<ListView
a:id="@+id/podcasts_channels_items_list"
a:layout_width="fill_parent"
a:layout_height="0dip"
a:layout_weight="1.0"
a:fastScrollEnabled="true"
a:textFilterEnabled="true" />
a:layout_height="0dp"
a:layout_weight="1.0">
<TextView
a:id="@+id/select_podcasts_empty"
a:layout_width="fill_parent"
a:layout_height="wrap_content"
a:padding="10dip"
a:text="@string/podcasts_channels.empty"
a:visibility="gone" />
<ListView
a:id="@+id/podcasts_channels_items_list"
a:layout_width="fill_parent"
a:layout_height="0dip"
a:layout_weight="1.0"
a:fastScrollEnabled="true"
a:textFilterEnabled="true" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</LinearLayout>