diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/audiofx/EqualizerController.java b/ultrasonic/src/main/java/org/moire/ultrasonic/audiofx/EqualizerController.java index 96cc3e3d..1f844646 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/audiofx/EqualizerController.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/audiofx/EqualizerController.java @@ -40,7 +40,7 @@ import java.io.Serializable; public class EqualizerController { private static Boolean available = null; - private static MutableLiveData instance = new MutableLiveData<>(); + private static final MutableLiveData instance = new MutableLiveData<>(); private Context context; public Equalizer equalizer; diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/audiofx/VisualizerController.java b/ultrasonic/src/main/java/org/moire/ultrasonic/audiofx/VisualizerController.java index c463d44c..70e3a90b 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/audiofx/VisualizerController.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/audiofx/VisualizerController.java @@ -36,7 +36,7 @@ public class VisualizerController { private static final int PREFERRED_CAPTURE_SIZE = 128; // Must be a power of two. private static Boolean available = null; - private static MutableLiveData instance = new MutableLiveData<>(); + private static final MutableLiveData instance = new MutableLiveData<>(); public Visualizer visualizer; private int audioSessionId; diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/AboutFragment.java b/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/AboutFragment.java index 81570f10..ad397631 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/AboutFragment.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/AboutFragment.java @@ -16,9 +16,13 @@ import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; +import org.jetbrains.annotations.NotNull; import org.moire.ultrasonic.R; import org.moire.ultrasonic.util.Util; +/** + * Displays online help and about information in a webWiew + */ public class AboutFragment extends Fragment { private WebView webView; @@ -109,7 +113,7 @@ public class AboutFragment extends Fragment { } @Override - public void onSaveInstanceState(Bundle state) + public void onSaveInstanceState(@NotNull Bundle state) { webView.saveState(state); super.onSaveInstanceState(state); diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/BookmarksFragment.java b/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/BookmarksFragment.java index 2651109f..b9e3c490 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/BookmarksFragment.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/BookmarksFragment.java @@ -1,6 +1,5 @@ package org.moire.ultrasonic.fragment; -import android.os.AsyncTask; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; @@ -38,6 +37,9 @@ import kotlin.Lazy; import static org.koin.java.KoinJavaComponent.inject; +/** + * Lists the Bookmarks available on the server + */ public class BookmarksFragment extends Fragment { private SwipeRefreshLayout refreshAlbumListView; @@ -82,7 +84,8 @@ public class BookmarksFragment extends Fragment { @Override public void onRefresh() { - new GetDataTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + enableButtons(); + getBookmarks(); } }); @@ -219,7 +222,7 @@ public class BookmarksFragment extends Fragment { private static List getSelectedSongs(ListView albumListView) { - List songs = new ArrayList(10); + List songs = new ArrayList<>(10); if (albumListView != null) { @@ -236,12 +239,6 @@ public class BookmarksFragment extends Fragment { return songs; } - private void refresh() - { - enableButtons(); - getBookmarks(); - } - private void selectAllOrNone() { boolean someUnselected = false; @@ -436,20 +433,4 @@ public class BookmarksFragment extends Fragment { albumListView.setAdapter(new EntryAdapter(getContext(), imageLoader.getValue().getImageLoader(), entries, true)); } } - - private class GetDataTask extends AsyncTask - { - @Override - protected void onPostExecute(String[] result) - { - super.onPostExecute(result); - } - - @Override - protected String[] doInBackground(Void... params) - { - refresh(); - return null; - } - } } diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/ChatFragment.java b/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/ChatFragment.java index 6df86a70..d0efe641 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/ChatFragment.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/ChatFragment.java @@ -1,6 +1,5 @@ package org.moire.ultrasonic.fragment; -import android.os.AsyncTask; import android.os.Bundle; import android.text.Editable; import android.text.TextWatcher; @@ -44,6 +43,9 @@ import kotlin.Lazy; import static org.koin.java.KoinJavaComponent.inject; +/** + * Provides online chat functionality + */ public class ChatFragment extends Fragment { private ListView chatListView; @@ -51,7 +53,7 @@ public class ChatFragment extends Fragment { private ImageButton sendButton; private Timer timer; private volatile static Long lastChatMessageTime = (long) 0; - private static final ArrayList messageList = new ArrayList(); + private static final ArrayList messageList = new ArrayList<>(); private CancellationToken cancellationToken; private SwipeRefreshLayout swipeRefresh; @@ -153,12 +155,11 @@ public class ChatFragment extends Fragment { */ @Override public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - // Check if user triggered a refresh: - case R.id.menu_refresh: - // Start the refresh background task. - new GetDataTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - return true; + // Check if user triggered a refresh: + if (item.getItemId() == R.id.menu_refresh) { + // Start the refresh background task. + load(); + return true; } // User didn't trigger a refresh, let the superclass handle this action return super.onOptionsItemSelected(item); @@ -313,20 +314,4 @@ public class ChatFragment extends Fragment { task.execute(); } - - private class GetDataTask extends AsyncTask - { - @Override - protected void onPostExecute(String[] result) - { - load(); - super.onPostExecute(result); - } - - @Override - protected String[] doInBackground(Void... params) - { - return null; - } - } } diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/EqualizerFragment.java b/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/EqualizerFragment.java index bde92bf9..bdf6bf33 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/EqualizerFragment.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/EqualizerFragment.java @@ -24,10 +24,14 @@ import org.moire.ultrasonic.audiofx.EqualizerController; import org.moire.ultrasonic.util.Util; import java.util.HashMap; +import java.util.Locale; import java.util.Map; import timber.log.Timber; +/** + * Displays the Equalizer + */ public class EqualizerFragment extends Fragment { private static final int MENU_GROUP_PRESET = 100; @@ -37,7 +41,7 @@ public class EqualizerFragment extends Fragment { private Equalizer equalizer; private LinearLayout equalizerLayout; private View presetButton; - private CheckBox enabledCheckBox; + private CheckBox enabledCheckBox; @Override public void onCreate(@Nullable Bundle savedInstanceState) { @@ -124,7 +128,7 @@ public class EqualizerFragment extends Fragment { } catch (Exception ex) { - //TODO: Show a dialog + //TODO: Show a dialog? Timber.i(ex, "An exception has occurred in EqualizerFragment onContextItemSelected"); } @@ -179,7 +183,7 @@ public class EqualizerFragment extends Fragment { } catch (Exception ex) { - //TODO: Show a dialog + //TODO: Show a dialog? Timber.i(ex, "An exception has occurred in EqualizerFragment updateBars"); } } @@ -200,7 +204,7 @@ public class EqualizerFragment extends Fragment { { final short band = i; - View bandBar = LayoutInflater.from(getContext()).inflate(R.layout.equalizer_bar, null); + View bandBar = LayoutInflater.from(getContext()).inflate(R.layout.equalizer_bar, equalizerLayout, false); TextView freqTextView; if (bandBar != null) @@ -209,7 +213,7 @@ public class EqualizerFragment extends Fragment { final TextView levelTextView = (TextView) bandBar.findViewById(R.id.equalizer_level); SeekBar bar = (SeekBar) bandBar.findViewById(R.id.equalizer_bar); - freqTextView.setText((equalizer.getCenterFreq(band) / 1000) + " Hz"); + freqTextView.setText(String.format(Locale.getDefault(), "%d Hz", equalizer.getCenterFreq(band) / 1000)); bars.put(band, bar); bar.setMax(maxEQLevel - minEQLevel); @@ -265,7 +269,7 @@ public class EqualizerFragment extends Fragment { { if (levelTextView != null) { - levelTextView.setText(String.format("%s%d dB", level > 0 ? "+" : "", level / 100)); + levelTextView.setText(String.format(Locale.getDefault(), "%s%d dB", level > 0 ? "+" : "", level / 100)); } } } diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/LyricsFragment.java b/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/LyricsFragment.java index 34012c7c..50692866 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/LyricsFragment.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/LyricsFragment.java @@ -23,6 +23,9 @@ import org.moire.ultrasonic.util.Util; import timber.log.Timber; +/** + * Displays the lyrics of a song + */ public class LyricsFragment extends Fragment { private TextView artistView; diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/MainFragment.java b/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/MainFragment.java index 4aaf2fbf..ae02828b 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/MainFragment.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/MainFragment.java @@ -27,6 +27,9 @@ import kotlin.Lazy; import static java.util.Arrays.asList; import static org.koin.java.KoinJavaComponent.inject; +/** + * Displays the Main screen of Ultrasonic, where the music library can be browsed + */ public class MainFragment extends Fragment { private static boolean shouldUseId3; @@ -84,7 +87,7 @@ public class MainFragment extends Fragment { private void setupMenuList(ListView list) { - final View buttons = getLayoutInflater().inflate(R.layout.main_buttons, null); + final View buttons = getLayoutInflater().inflate(R.layout.main_buttons, list, false); final View serverButton = buttons.findViewById(R.id.main_select_server); final TextView serverTextView = serverButton.findViewById(R.id.main_select_server_2); diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/NowPlayingFragment.java b/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/NowPlayingFragment.java index 308244d1..04e26cf1 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/NowPlayingFragment.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/NowPlayingFragment.java @@ -29,6 +29,10 @@ import timber.log.Timber; import static org.koin.java.KoinJavaComponent.inject; + +/** + * Contains the mini-now playing information box displayed at the bottom of the screen + */ public class NowPlayingFragment extends Fragment { private static final int MIN_DISTANCE = 30; @@ -130,7 +134,7 @@ public class NowPlayingFragment extends Fragment { getView().setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { - return handleOnTouch(v, event); + return handleOnTouch(event); } }); @@ -153,7 +157,7 @@ public class NowPlayingFragment extends Fragment { } } - private boolean handleOnTouch(View v, MotionEvent event) { + private boolean handleOnTouch(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/PlayerFragment.java b/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/PlayerFragment.java index 17d416ae..66518b05 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/PlayerFragment.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/PlayerFragment.java @@ -82,6 +82,9 @@ import static org.moire.ultrasonic.domain.PlayerState.IDLE; import static org.moire.ultrasonic.domain.PlayerState.PAUSED; import static org.moire.ultrasonic.domain.PlayerState.STOPPED; +/** + * Contains the Music Player screen of Ultrasonic with playback controls and the playlist + */ public class PlayerFragment extends Fragment implements GestureDetector.OnGestureListener { private static final int PERCENTAGE_OF_SCREEN_FOR_SWIPE = 5; @@ -235,16 +238,14 @@ public class PlayerFragment extends Fragment implements GestureDetector.OnGestur } }); - View.OnTouchListener touchListener = new View.OnTouchListener() + albumArtImageView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View view, MotionEvent me) { return gestureScanner.onTouchEvent(me); } - }; - - albumArtImageView.setOnTouchListener(touchListener); + }); albumArtImageView.setOnClickListener(new View.OnClickListener() { @@ -265,7 +266,7 @@ public class PlayerFragment extends Fragment implements GestureDetector.OnGestur new SilentBackgroundTask(getActivity()) { @Override - protected Void doInBackground() throws Throwable + protected Void doInBackground() { mediaPlayerControllerLazy.getValue().previous(); return null; @@ -301,7 +302,7 @@ public class PlayerFragment extends Fragment implements GestureDetector.OnGestur new SilentBackgroundTask(getActivity()) { @Override - protected Boolean doInBackground() throws Throwable + protected Boolean doInBackground() { if (mediaPlayerControllerLazy.getValue().getCurrentPlayingNumberOnPlaylist() < mediaPlayerControllerLazy.getValue().getPlaylistSize() - 1) { @@ -345,7 +346,7 @@ public class PlayerFragment extends Fragment implements GestureDetector.OnGestur new SilentBackgroundTask(getActivity()) { @Override - protected Void doInBackground() throws Throwable + protected Void doInBackground() { mediaPlayerControllerLazy.getValue().pause(); return null; @@ -369,7 +370,7 @@ public class PlayerFragment extends Fragment implements GestureDetector.OnGestur new SilentBackgroundTask(getActivity()) { @Override - protected Void doInBackground() throws Throwable + protected Void doInBackground() { mediaPlayerControllerLazy.getValue().reset(); return null; @@ -395,7 +396,7 @@ public class PlayerFragment extends Fragment implements GestureDetector.OnGestur new SilentBackgroundTask(getActivity()) { @Override - protected Void doInBackground() throws Throwable + protected Void doInBackground() { start(); return null; @@ -456,7 +457,7 @@ public class PlayerFragment extends Fragment implements GestureDetector.OnGestur new SilentBackgroundTask(getActivity()) { @Override - protected Void doInBackground() throws Throwable + protected Void doInBackground() { mediaPlayerControllerLazy.getValue().seekTo(getProgressBar().getProgress()); return null; @@ -491,7 +492,7 @@ public class PlayerFragment extends Fragment implements GestureDetector.OnGestur new SilentBackgroundTask(getActivity()) { @Override - protected Void doInBackground() throws Throwable + protected Void doInBackground() { mediaPlayerControllerLazy.getValue().play(position); return null; @@ -812,7 +813,7 @@ public class PlayerFragment extends Fragment implements GestureDetector.OnGestur } @Override - public void onCreateContextMenu(final ContextMenu menu, final View view, final ContextMenu.ContextMenuInfo menuInfo) + public void onCreateContextMenu(final @NotNull ContextMenu menu, final @NotNull View view, final ContextMenu.ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, view, menuInfo); if (view == playlistView) @@ -1345,7 +1346,7 @@ public class PlayerFragment extends Fragment implements GestureDetector.OnGestur PlayerState playerState; @Override - protected Void doInBackground() throws Throwable + protected Void doInBackground() { this.mediaPlayerController = mediaPlayerControllerLazy.getValue(); isJukeboxEnabled = this.mediaPlayerController.isJukeboxEnabled(); @@ -1409,13 +1410,9 @@ public class PlayerFragment extends Fragment implements GestureDetector.OnGestur FragmentTitle.Companion.setTitle(PlayerFragment.this, R.string.common_appname); break; case IDLE: - break; case PREPARED: - break; case STOPPED: - break; case PAUSED: - break; case COMPLETED: break; } @@ -1464,13 +1461,13 @@ public class PlayerFragment extends Fragment implements GestureDetector.OnGestur int seekTo; @Override - protected Void doInBackground() throws Throwable + protected Void doInBackground() { msPlayed = Math.max(0, mediaPlayerController.getPlayerPosition()); duration = mediaPlayerController.getPlayerDuration(); final int msTotal = duration; - seekTo = msPlayed + ms > msTotal ? msTotal : msPlayed + ms; + seekTo = Math.min(msPlayed + ms, msTotal); mediaPlayerController.seekTo(seekTo); return null; } diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/PlaylistsFragment.java b/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/PlaylistsFragment.java index 2ba2797c..4954cc76 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/PlaylistsFragment.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/PlaylistsFragment.java @@ -2,7 +2,6 @@ package org.moire.ultrasonic.fragment; import android.app.AlertDialog; import android.content.DialogInterface; -import android.os.AsyncTask; import android.os.Bundle; import android.text.Editable; import android.text.Spannable; @@ -51,6 +50,9 @@ import kotlin.Lazy; import static org.koin.java.KoinJavaComponent.inject; +/** + * Displays the playlists stored on the server + */ public class PlaylistsFragment extends Fragment { private SwipeRefreshLayout refreshPlaylistsListView; @@ -83,9 +85,8 @@ public class PlaylistsFragment extends Fragment { refreshPlaylistsListView.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override - public void onRefresh() - { - new GetDataTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + public void onRefresh() { + load(true); } }); @@ -119,11 +120,6 @@ public class PlaylistsFragment extends Fragment { super.onDestroyView(); } - private void refresh() - { - load(true); - } - private void load(final boolean refresh) { BackgroundTask> task = new FragmentBackgroundTask>(getActivity(), true, refreshPlaylistsListView, cancellationToken) @@ -182,43 +178,34 @@ public class PlaylistsFragment extends Fragment { } Bundle bundle; - switch (menuItem.getItemId()) - { - case R.id.playlist_menu_pin: - downloadHandler.getValue().downloadPlaylist(this, playlist.getId(), playlist.getName(), true, true, false, false, true, false, false); - break; - case R.id.playlist_menu_unpin: - downloadHandler.getValue().downloadPlaylist(this, playlist.getId(), playlist.getName(), false, false, false, false, true, false, true); - break; - case R.id.playlist_menu_download: - downloadHandler.getValue().downloadPlaylist(this, playlist.getId(), playlist.getName(), false, false, false, false, true, false, false); - break; - case R.id.playlist_menu_play_now: - bundle = new Bundle(); - bundle.putString(Constants.INTENT_EXTRA_NAME_PLAYLIST_ID, playlist.getId()); - bundle.putString(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME, playlist.getName()); - bundle.putBoolean(Constants.INTENT_EXTRA_NAME_AUTOPLAY, true); - Navigation.findNavController(getView()).navigate(R.id.selectAlbumFragment, bundle); - break; - case R.id.playlist_menu_play_shuffled: - bundle = new Bundle(); - bundle.putString(Constants.INTENT_EXTRA_NAME_PLAYLIST_ID, playlist.getId()); - bundle.putString(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME, playlist.getName()); - bundle.putBoolean(Constants.INTENT_EXTRA_NAME_AUTOPLAY, true); - bundle.putBoolean(Constants.INTENT_EXTRA_NAME_SHUFFLE, true); - Navigation.findNavController(getView()).navigate(R.id.selectAlbumFragment, bundle); - break; - case R.id.playlist_menu_delete: - deletePlaylist(playlist); - break; - case R.id.playlist_info: - displayPlaylistInfo(playlist); - break; - case R.id.playlist_update_info: - updatePlaylistInfo(playlist); - break; - default: - return super.onContextItemSelected(menuItem); + int itemId = menuItem.getItemId(); + if (itemId == R.id.playlist_menu_pin) { + downloadHandler.getValue().downloadPlaylist(this, playlist.getId(), playlist.getName(), true, true, false, false, true, false, false); + } else if (itemId == R.id.playlist_menu_unpin) { + downloadHandler.getValue().downloadPlaylist(this, playlist.getId(), playlist.getName(), false, false, false, false, true, false, true); + } else if (itemId == R.id.playlist_menu_download) { + downloadHandler.getValue().downloadPlaylist(this, playlist.getId(), playlist.getName(), false, false, false, false, true, false, false); + } else if (itemId == R.id.playlist_menu_play_now) { + bundle = new Bundle(); + bundle.putString(Constants.INTENT_EXTRA_NAME_PLAYLIST_ID, playlist.getId()); + bundle.putString(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME, playlist.getName()); + bundle.putBoolean(Constants.INTENT_EXTRA_NAME_AUTOPLAY, true); + Navigation.findNavController(getView()).navigate(R.id.selectAlbumFragment, bundle); + } else if (itemId == R.id.playlist_menu_play_shuffled) { + bundle = new Bundle(); + bundle.putString(Constants.INTENT_EXTRA_NAME_PLAYLIST_ID, playlist.getId()); + bundle.putString(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME, playlist.getName()); + bundle.putBoolean(Constants.INTENT_EXTRA_NAME_AUTOPLAY, true); + bundle.putBoolean(Constants.INTENT_EXTRA_NAME_SHUFFLE, true); + Navigation.findNavController(getView()).navigate(R.id.selectAlbumFragment, bundle); + } else if (itemId == R.id.playlist_menu_delete) { + deletePlaylist(playlist); + } else if (itemId == R.id.playlist_info) { + displayPlaylistInfo(playlist); + } else if (itemId == R.id.playlist_update_info) { + updatePlaylistInfo(playlist); + } else { + return super.onContextItemSelected(menuItem); } return true; } @@ -333,7 +320,7 @@ public class PlaylistsFragment extends Fragment { @Override protected void done(Void result) { - refresh(); + load(true); Util.toast(getContext(), getResources().getString(R.string.playlist_updated_info, playlist.getName())); } @@ -352,20 +339,4 @@ public class PlaylistsFragment extends Fragment { alertDialog.setNegativeButton(R.string.common_cancel, null); alertDialog.show(); } - - private class GetDataTask extends AsyncTask - { - @Override - protected void onPostExecute(String[] result) - { - super.onPostExecute(result); - } - - @Override - protected String[] doInBackground(Void... params) - { - refresh(); - return null; - } - } } diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/PodcastFragment.java b/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/PodcastFragment.java index 7de7e875..a83670d5 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/PodcastFragment.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/PodcastFragment.java @@ -27,6 +27,9 @@ import org.moire.ultrasonic.view.PodcastsChannelsAdapter; import java.util.List; +/** + * Displays the podcasts available on the server + */ public class PodcastFragment extends Fragment { private View emptyTextView; diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/SearchFragment.java b/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/SearchFragment.java index 289e9217..c4f6040c 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/SearchFragment.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/SearchFragment.java @@ -57,6 +57,9 @@ import timber.log.Timber; import static org.koin.java.KoinJavaComponent.inject; +/** + * Initiates a search on the media library and displays the results + */ public class SearchFragment extends Fragment { private static int DEFAULT_ARTISTS; @@ -68,7 +71,7 @@ public class SearchFragment extends Fragment { private View artistsHeading; private View albumsHeading; private View songsHeading; - private TextView searchButton; + private TextView notFound; private View moreArtistsButton; private View moreAlbumsButton; private View moreSongsButton; @@ -114,14 +117,14 @@ public class SearchFragment extends Fragment { DEFAULT_ALBUMS = Util.getDefaultAlbums(getContext()); DEFAULT_SONGS = Util.getDefaultSongs(getContext()); - View buttons = LayoutInflater.from(getContext()).inflate(R.layout.search_buttons, null); + View buttons = LayoutInflater.from(getContext()).inflate(R.layout.search_buttons, list, false); if (buttons != null) { artistsHeading = buttons.findViewById(R.id.search_artists); albumsHeading = buttons.findViewById(R.id.search_albums); songsHeading = buttons.findViewById(R.id.search_songs); - searchButton = buttons.findViewById(R.id.search_search); + notFound = buttons.findViewById(R.id.search_not_found); moreArtistsButton = buttons.findViewById(R.id.search_more_artists); moreAlbumsButton = buttons.findViewById(R.id.search_more_albums); moreSongsButton = buttons.findViewById(R.id.search_more_songs); @@ -168,7 +171,7 @@ public class SearchFragment extends Fragment { } else { - onSongSelected(entry, false, true, true, false); + onSongSelected(entry, true); } } @@ -262,14 +265,13 @@ public class SearchFragment extends Fragment { boolean isArtist = selectedItem instanceof Artist; boolean isAlbum = selectedItem instanceof MusicDirectory.Entry && ((MusicDirectory.Entry) selectedItem).isDirectory(); + MenuInflater inflater = getActivity().getMenuInflater(); if (!isArtist && !isAlbum) { - MenuInflater inflater = getActivity().getMenuInflater(); inflater.inflate(R.menu.select_song_context, menu); } else { - MenuInflater inflater = getActivity().getMenuInflater(); inflater.inflate(R.menu.select_album_context, menu); } @@ -485,7 +487,7 @@ public class SearchFragment extends Fragment { } boolean empty = searchResult.getArtists().isEmpty() && searchResult.getAlbums().isEmpty() && searchResult.getSongs().isEmpty(); - searchButton.setText(empty ? R.string.search_no_match : R.string.search_search); + if (empty) mergeAdapter.addView(notFound, false); } list.setAdapter(mergeAdapter); @@ -551,19 +553,19 @@ public class SearchFragment extends Fragment { Navigation.findNavController(getView()).navigate(R.id.searchToSelectAlbum, bundle); } - private void onSongSelected(MusicDirectory.Entry song, boolean save, boolean append, boolean autoplay, boolean playNext) + private void onSongSelected(MusicDirectory.Entry song, boolean append) { MediaPlayerController mediaPlayerController = mediaPlayerControllerLazy.getValue(); if (mediaPlayerController != null) { - if (!append && !playNext) + if (!append) { mediaPlayerController.clear(); } - mediaPlayerController.download(Collections.singletonList(song), save, false, playNext, false, false); + mediaPlayerController.download(Collections.singletonList(song), false, false, false, false, false); - if (autoplay) + if (true) { mediaPlayerController.play(mediaPlayerController.getPlaylistSize() - 1); } @@ -581,7 +583,7 @@ public class SearchFragment extends Fragment { { if (!searchResult.getSongs().isEmpty()) { - onSongSelected(searchResult.getSongs().get(0), false, false, true, false); + onSongSelected(searchResult.getSongs().get(0), false); } else if (!searchResult.getAlbums().isEmpty()) { diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/SelectAlbumFragment.java b/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/SelectAlbumFragment.java index f811c1d4..d66eb87d 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/SelectAlbumFragment.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/SelectAlbumFragment.java @@ -1,6 +1,5 @@ package org.moire.ultrasonic.fragment; -import android.os.AsyncTask; import android.os.Bundle; import android.view.ContextMenu; import android.view.LayoutInflater; @@ -57,6 +56,9 @@ import timber.log.Timber; import static org.koin.java.KoinJavaComponent.inject; +/** + * Displays a group of playable media from the library, which can be an Album, a Playlist, etc. + */ public class SelectAlbumFragment extends Fragment { public static final String allSongsId = "-1"; @@ -79,7 +81,7 @@ public class SelectAlbumFragment extends Fragment { private MenuItem playAllButton; private MenuItem shareButton; private boolean showHeader = true; - private Random random = new java.security.SecureRandom(); + private final Random random = new java.security.SecureRandom(); private final Lazy mediaPlayerControllerLazy = inject(MediaPlayerController.class); private final Lazy videoPlayer = inject(VideoPlayer.class); @@ -115,7 +117,7 @@ public class SelectAlbumFragment extends Fragment { { @Override public void onRefresh() { - new SelectAlbumFragment.GetDataTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + updateDisplay(true); } }); @@ -198,7 +200,7 @@ public class SelectAlbumFragment extends Fragment { @Override public void onClick(View view) { - playNow(false, false); + playNow(false); } }); playNextButton.setOnClickListener(new View.OnClickListener() @@ -215,7 +217,7 @@ public class SelectAlbumFragment extends Fragment { @Override public void onClick(View view) { - playNow(false, true); + playNow(true); } }); pinButton.setOnClickListener(new View.OnClickListener() @@ -333,7 +335,7 @@ public class SelectAlbumFragment 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); AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo; @@ -397,7 +399,7 @@ public class SelectAlbumFragment extends Fragment { } else if (itemId == R.id.select_album_play_all) { playAll(); } else if (itemId == R.id.menu_item_share) { - List entries = new ArrayList(1); + List entries = new ArrayList<>(1); entries.add(entry); shareHandler.getValue().createShare(this, entries, refreshAlbumListView, cancellationToken); return true; @@ -453,18 +455,18 @@ public class SelectAlbumFragment extends Fragment { super.onDestroyView(); } - private void playNow(final boolean shuffle, final boolean append) + private void playNow(final boolean append) { List selectedSongs = getSelectedSongs(albumListView); if (!selectedSongs.isEmpty()) { - downloadHandler.getValue().download(this, append, false, !append, false, shuffle, selectedSongs); + downloadHandler.getValue().download(this, append, false, !append, false, false, selectedSongs); selectAll(false, false); } else { - playAll(shuffle, append); + playAll(false, append); } } @@ -504,7 +506,7 @@ public class SelectAlbumFragment extends Fragment { private static List getSelectedSongs(ListView albumListView) { - List songs = new ArrayList(10); + List songs = new ArrayList<>(10); if (albumListView != null) { @@ -521,15 +523,6 @@ public class SelectAlbumFragment extends Fragment { return songs; } - private void refresh() - { - getView().post(new Runnable() { - public void run() { - updateDisplay(true); - } - }); - } - private void getMusicDirectory(final boolean refresh, final String id, final String name, final String parentId) { FragmentTitle.Companion.setTitle(this, name); @@ -545,7 +538,7 @@ public class SelectAlbumFragment extends Fragment { { MusicDirectory musicDirectory = service.getMusicDirectory(parentId, name, refresh, getContext()); - List songs = new LinkedList(); + List songs = new LinkedList<>(); getSongsRecursively(musicDirectory, songs); for (MusicDirectory.Entry song : songs) @@ -672,7 +665,7 @@ public class SelectAlbumFragment extends Fragment { { MusicDirectory root = new MusicDirectory(); - Collection songs = new LinkedList(); + Collection songs = new LinkedList<>(); getSongsForArtist(parentId, songs); for (MusicDirectory.Entry song : songs) @@ -1095,7 +1088,7 @@ public class SelectAlbumFragment extends Fragment { MusicService musicService = MusicServiceFactory.getMusicService(getContext()); MusicDirectory dir = load(musicService); boolean valid = musicService.isLicenseValid(getContext()); - return new Pair(dir, valid); + return new Pair<>(dir, valid); } @Override @@ -1275,20 +1268,4 @@ public class SelectAlbumFragment extends Fragment { return header; } } - - private class GetDataTask extends AsyncTask - { - @Override - protected void onPostExecute(String[] result) - { - super.onPostExecute(result); - } - - @Override - protected String[] doInBackground(Void... params) - { - refresh(); - return null; - } - } } diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/SelectGenreFragment.java b/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/SelectGenreFragment.java index 1185e905..292f6b50 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/SelectGenreFragment.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/SelectGenreFragment.java @@ -1,6 +1,5 @@ package org.moire.ultrasonic.fragment; -import android.os.AsyncTask; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; @@ -30,6 +29,9 @@ import java.util.List; import timber.log.Timber; +/** + * Displays the available genres in the media library + */ public class SelectGenreFragment extends Fragment { private SwipeRefreshLayout refreshGenreListView; @@ -60,7 +62,7 @@ public class SelectGenreFragment extends Fragment { @Override public void onRefresh() { - new GetDataTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + load(true); } }); @@ -93,21 +95,16 @@ public class SelectGenreFragment extends Fragment { super.onDestroyView(); } - private void refresh() - { - load(true); - } - private void load(final boolean refresh) { BackgroundTask> task = new FragmentBackgroundTask>(getActivity(), true, refreshGenreListView, cancellationToken) { @Override - protected List doInBackground() throws Throwable + protected List doInBackground() { MusicService musicService = MusicServiceFactory.getMusicService(getContext()); - List genres = new ArrayList(); + List genres = new ArrayList<>(); try { @@ -134,20 +131,4 @@ public class SelectGenreFragment extends Fragment { }; task.execute(); } - - private class GetDataTask extends AsyncTask - { - @Override - protected void onPostExecute(String[] result) - { - super.onPostExecute(result); - } - - @Override - protected String[] doInBackground(Void... params) - { - refresh(); - return null; - } - } } diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/SettingsFragment.java b/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/SettingsFragment.java index 2c64fbc3..506db741 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/SettingsFragment.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/SettingsFragment.java @@ -21,6 +21,7 @@ import androidx.preference.PreferenceManager; import timber.log.Timber; import android.view.View; +import org.jetbrains.annotations.NotNull; import org.koin.java.KoinJavaComponent; import org.moire.ultrasonic.R; import org.moire.ultrasonic.featureflags.Feature; @@ -100,7 +101,7 @@ public class SettingsFragment extends PreferenceFragmentCompat } @Override - public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + public void onViewCreated(@NotNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); FragmentTitle.Companion.setTitle(this, R.string.menu_settings); @@ -192,8 +193,7 @@ public class SettingsFragment extends PreferenceFragmentCompat } else if (Constants.PREFERENCES_KEY_DEBUG_LOG_TO_FILE.equals(key)) { setDebugLogToFile(sharedPreferences.getBoolean(key, false)); } else if (Constants.PREFERENCES_KEY_ID3_TAGS.equals(key)) { - if (sharedPreferences.getBoolean(key, false)) showArtistPicture.setEnabled(true); - else showArtistPicture.setEnabled(false); + showArtistPicture.setEnabled(sharedPreferences.getBoolean(key, false)); } else if (Constants.PREFERENCES_KEY_THEME.equals(key)) { themeChangedEventDistributor.getValue().RaiseThemeChangedEvent(); } @@ -214,7 +214,7 @@ public class SettingsFragment extends PreferenceFragmentCompat if (dialogFragment != null) { dialogFragment.setTargetFragment(this, 0); - dialogFragment.show(this.getFragmentManager(), "android.support.v7.preference.PreferenceFragment.DIALOG"); + dialogFragment.show(this.getParentFragmentManager(), "android.support.v7.preference.PreferenceFragment.DIALOG"); } else { @@ -465,8 +465,7 @@ public class SettingsFragment extends PreferenceFragmentCompat debugLogToFile.setSummary(""); } - if (Util.getShouldUseId3Tags(getActivity())) showArtistPicture.setEnabled(true); - else showArtistPicture.setEnabled(false); + showArtistPicture.setEnabled(Util.getShouldUseId3Tags(getActivity())); } private void setImageLoaderConcurrency(int concurrency) { @@ -503,11 +502,7 @@ public class SettingsFragment extends PreferenceFragmentCompat } private void setBluetoothPreferences(boolean enabled) { - if (enabled) { - sendBluetoothAlbumArt.setEnabled(true); - } else { - sendBluetoothAlbumArt.setEnabled(false); - } + sendBluetoothAlbumArt.setEnabled(enabled); } private void setCacheLocation(String path) { diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/SharesFragment.java b/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/SharesFragment.java index 0bfab967..9db90eec 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/SharesFragment.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/SharesFragment.java @@ -2,7 +2,6 @@ package org.moire.ultrasonic.fragment; import android.app.AlertDialog; import android.content.DialogInterface; -import android.os.AsyncTask; import android.os.Bundle; import android.text.Editable; import android.text.Spannable; @@ -28,6 +27,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.api.subsonic.ApiNotSupportedException; import org.moire.ultrasonic.domain.Share; @@ -51,6 +51,9 @@ import kotlin.Lazy; import static org.koin.java.KoinJavaComponent.inject; +/** + * Displays the shares in the media library + */ public class SharesFragment extends Fragment { private SwipeRefreshLayout refreshSharesListView; @@ -85,7 +88,7 @@ public class SharesFragment extends Fragment { @Override public void onRefresh() { - new GetDataTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + load(true); } }); @@ -118,11 +121,6 @@ public class SharesFragment extends Fragment { super.onDestroyView(); } - private void refresh() - { - load(true); - } - private void load(final boolean refresh) { BackgroundTask> task = new FragmentBackgroundTask>(getActivity(), true, refreshSharesListView, cancellationToken) @@ -145,7 +143,7 @@ public class SharesFragment 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); @@ -311,7 +309,7 @@ public class SharesFragment extends Fragment { @Override protected void done(Void result) { - refresh(); + load(true); Util.toast(getContext(), getResources().getString(R.string.playlist_updated_info, share.getName())); } @@ -330,20 +328,4 @@ public class SharesFragment extends Fragment { alertDialog.setNegativeButton(R.string.common_cancel, null); alertDialog.show(); } - - private class GetDataTask extends AsyncTask - { - @Override - protected void onPostExecute(String[] result) - { - super.onPostExecute(result); - } - - @Override - protected String[] doInBackground(Void... params) - { - refresh(); - return null; - } - } } diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider.java b/ultrasonic/src/main/java/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider.java index 8355208c..d15a1b35 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider.java @@ -21,6 +21,9 @@ import org.moire.ultrasonic.service.MediaPlayerController; import org.moire.ultrasonic.util.Constants; import org.moire.ultrasonic.util.FileUtil; +/** + * Widget Provider for the Ultrasonic Widgets + */ public class UltrasonicAppWidgetProvider extends AppWidgetProvider { protected int layoutId; @@ -73,7 +76,7 @@ public class UltrasonicAppWidgetProvider extends AppWidgetProvider { if (hasInstances(context)) { - performUpdate(context, currentSong, null, playing, setAlbum); + performUpdate(context, currentSong, playing, setAlbum); } } @@ -96,7 +99,7 @@ public class UltrasonicAppWidgetProvider extends AppWidgetProvider /** * Update all active widget instances by pushing changes */ - private void performUpdate(Context context, MusicDirectory.Entry currentSong, int[] appWidgetIds, boolean playing, boolean setAlbum) + private void performUpdate(Context context, MusicDirectory.Entry currentSong, boolean playing, boolean setAlbum) { final Resources res = context.getResources(); final RemoteViews views = new RemoteViews(context.getPackageName(), this.layoutId); @@ -177,7 +180,7 @@ public class UltrasonicAppWidgetProvider extends AppWidgetProvider // Link actions buttons to intents linkButtons(context, views, currentSong != null); - pushUpdate(context, appWidgetIds, views); + pushUpdate(context, null, views); } /** @@ -185,7 +188,7 @@ public class UltrasonicAppWidgetProvider extends AppWidgetProvider */ private static void linkButtons(Context context, RemoteViews views, boolean playerActive) { - Intent intent = new Intent(context, NavigationActivity.class).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);; + Intent intent = new Intent(context, NavigationActivity.class).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); if (playerActive) intent.putExtra(Constants.INTENT_EXTRA_NAME_SHOW_PLAYER, true); diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/service/CachedMusicService.java b/ultrasonic/src/main/java/org/moire/ultrasonic/service/CachedMusicService.java index ba76d5d5..13d79649 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/service/CachedMusicService.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/service/CachedMusicService.java @@ -67,13 +67,13 @@ public class CachedMusicService implements MusicService private final LRUCache> cachedArtist; private final LRUCache> cachedAlbum; private final LRUCache> cachedUserInfo; - private final TimeLimitedCache cachedLicenseValid = new TimeLimitedCache(120, TimeUnit.SECONDS); - private final TimeLimitedCache cachedIndexes = new TimeLimitedCache(60 * 60, TimeUnit.SECONDS); - private final TimeLimitedCache cachedArtists = new TimeLimitedCache(60 * 60, TimeUnit.SECONDS); - private final TimeLimitedCache> cachedPlaylists = new TimeLimitedCache>(3600, TimeUnit.SECONDS); - private final TimeLimitedCache> cachedPodcastsChannels = new TimeLimitedCache>(3600, TimeUnit.SECONDS); - private final TimeLimitedCache> cachedMusicFolders = new TimeLimitedCache>(10 * 3600, TimeUnit.SECONDS); - private final TimeLimitedCache> cachedGenres = new TimeLimitedCache>(10 * 3600, TimeUnit.SECONDS); + private final TimeLimitedCache cachedLicenseValid = new TimeLimitedCache<>(120, TimeUnit.SECONDS); + private final TimeLimitedCache cachedIndexes = new TimeLimitedCache<>(60 * 60, TimeUnit.SECONDS); + private final TimeLimitedCache cachedArtists = new TimeLimitedCache<>(60 * 60, TimeUnit.SECONDS); + private final TimeLimitedCache> cachedPlaylists = new TimeLimitedCache<>(3600, TimeUnit.SECONDS); + private final TimeLimitedCache> cachedPodcastsChannels = new TimeLimitedCache<>(3600, TimeUnit.SECONDS); + private final TimeLimitedCache> cachedMusicFolders = new TimeLimitedCache<>(10 * 3600, TimeUnit.SECONDS); + private final TimeLimitedCache> cachedGenres = new TimeLimitedCache<>(10 * 3600, TimeUnit.SECONDS); private String restUrl; diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/service/DownloadFile.java b/ultrasonic/src/main/java/org/moire/ultrasonic/service/DownloadFile.java index 3f9b3be5..d1ae5500 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/service/DownloadFile.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/service/DownloadFile.java @@ -196,7 +196,9 @@ public class DownloadFile { if (saveFile.exists()) { - saveFile.renameTo(completeFile); + if (!saveFile.renameTo(completeFile)){ + Timber.w("Renaming file failed. Original file: %s; Rename to: %s", saveFile.getName(), completeFile.getName()); + } } } diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/service/MusicService.java b/ultrasonic/src/main/java/org/moire/ultrasonic/service/MusicService.java index 5515eba1..37ded458 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/service/MusicService.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/service/MusicService.java @@ -110,7 +110,8 @@ public interface MusicService */ Pair getDownloadInputStream(Context context, MusicDirectory.Entry song, long offset, int maxBitrate, CancellableTask task) throws Exception; - @Deprecated String getVideoUrl(Context context, String id, boolean useFlash) throws Exception; + // TODO: Refactor and remove this call (see RestMusicService implementation) + String getVideoUrl(Context context, String id, boolean useFlash) throws Exception; JukeboxStatus updateJukeboxPlaylist(List ids, Context context) throws Exception; diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/service/OfflineMusicService.java b/ultrasonic/src/main/java/org/moire/ultrasonic/service/OfflineMusicService.java index fa87f070..500d6b6f 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/service/OfflineMusicService.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/service/OfflineMusicService.java @@ -44,7 +44,6 @@ import org.moire.ultrasonic.domain.UserInfo; import org.moire.ultrasonic.util.CancellableTask; import org.moire.ultrasonic.util.Constants; import org.moire.ultrasonic.util.FileUtil; -import org.moire.ultrasonic.util.ProgressListener; import org.moire.ultrasonic.util.Util; import java.io.BufferedReader; @@ -509,7 +508,7 @@ public class OfflineMusicService implements MusicService @Override public List getPlaylists(boolean refresh, Context context) { - List playlists = new ArrayList(); + List playlists = new ArrayList<>(); File root = FileUtil.getPlaylistDirectory(context); String lastServer = null; boolean removeServer = true; @@ -544,11 +543,13 @@ public class OfflineMusicService implements MusicService // Delete legacy playlist files try { - folder.delete(); + if (!folder.delete()) { + Timber.w("Failed to delete old playlist file: %s", folder.getName()); + } } catch (Exception e) { - Timber.w("Failed to delete old playlist file: %s", folder.getName()); + Timber.w(e, "Failed to delete old playlist file: %s", folder.getName()); } } } diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/util/Constants.java b/ultrasonic/src/main/java/org/moire/ultrasonic/util/Constants.java index aa9638c7..13c81c1c 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/util/Constants.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/util/Constants.java @@ -69,14 +69,9 @@ public final class Constants public static final String CMD_PREVIOUS = "org.moire.ultrasonic.CMD_PREVIOUS"; public static final String CMD_NEXT = "org.moire.ultrasonic.CMD_NEXT"; - // Notification IDs. - public static final int NOTIFICATION_ID_PLAYING = 100; - // Preferences keys. public static final String PREFERENCES_KEY_SERVER_INSTANCE = "serverInstanceId"; - public static final String PREFERENCES_KEY_SERVERS_KEY = "serversKey"; public static final String PREFERENCES_KEY_SERVERS_EDIT = "editServers"; - public static final String PREFERENCES_KEY_INSTALL_TIME = "installTime"; public static final String PREFERENCES_KEY_THEME = "theme"; public static final String PREFERENCES_KEY_THEME_LIGHT = "light"; public static final String PREFERENCES_KEY_THEME_DARK = "dark"; @@ -145,12 +140,6 @@ public final class Constants public static final int PREFERENCE_VALUE_A2DP = 1; public static final int PREFERENCE_VALUE_DISABLED = 2; - // Number of free trial days for non-licensed servers. - public static final int FREE_TRIAL_DAYS = 30; - - // URL for project donations. - public static final String DONATION_URL = "http://www.subsonic.org/pages/premium.jsp"; - public static final String FILENAME_DOWNLOADS_SER = "downloadstate.ser"; public static final String ALBUM_ART_FILE = "folder.jpeg"; diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/util/FileUtil.java b/ultrasonic/src/main/java/org/moire/ultrasonic/util/FileUtil.java index de638001..9a52eff5 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/util/FileUtil.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/util/FileUtil.java @@ -156,9 +156,7 @@ public class FileUtil File avatarFile = getAvatarFile(context, username); Bitmap bitmap = null; - ImageLoader imageLoader = null; - - imageLoader = imageLoaderProvider.getValue().getImageLoader(); + ImageLoader imageLoader = imageLoaderProvider.getValue().getImageLoader(); if (imageLoader != null) { @@ -222,9 +220,7 @@ public class FileUtil File albumArtFile = getAlbumArtFile(context, entry); Bitmap bitmap = null; - ImageLoader imageLoader = null; - - imageLoader = imageLoaderProvider.getValue().getImageLoader(); + ImageLoader imageLoader = imageLoaderProvider.getValue().getImageLoader(); if (imageLoader != null) { @@ -491,10 +487,10 @@ public class FileUtil if (files == null) { Timber.w("Failed to list children for %s", dir.getPath()); - return new TreeSet(); + return new TreeSet<>(); } - return new TreeSet(Arrays.asList(files)); + return new TreeSet<>(Arrays.asList(files)); } public static SortedSet listMediaFiles(File dir) diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/util/LegacyImageLoader.java b/ultrasonic/src/main/java/org/moire/ultrasonic/util/LegacyImageLoader.java index bba2271f..0956ad98 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/util/LegacyImageLoader.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/util/LegacyImageLoader.java @@ -40,6 +40,7 @@ import org.moire.ultrasonic.service.MusicServiceFactory; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.Locale; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.atomic.AtomicBoolean; @@ -100,7 +101,7 @@ public class LegacyImageLoader implements Runnable, ImageLoader { threads = Collections.synchronizedCollection(new ArrayList(this.concurrency)); for (int i = 0; i < this.concurrency; i++) { - Thread thread = new Thread(this, String.format("ImageLoader_%d", i)); + Thread thread = new Thread(this, String.format(Locale.US, "ImageLoader_%d", i)); threads.add(thread); thread.start(); } @@ -213,7 +214,7 @@ public class LegacyImageLoader implements Runnable, ImageLoader { } private static String getKey(String coverArtId, int size) { - return String.format("%s:%d", coverArtId, size); + return String.format(Locale.US, "%s:%d", coverArtId, size); } @Override @@ -338,10 +339,6 @@ public class LegacyImageLoader implements Runnable, ImageLoader { setAvatarImageBitmap(view, null, unknownAvatarImage, false); } - private void setUnknownImage(View view, boolean large) { - setUnknownImage(view, large, -1); - } - private void setUnknownImage(View view, boolean large, int resId) { if (resId == -1) resId = R.drawable.unknown_album; if (large) { diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/util/LoadingTask.java b/ultrasonic/src/main/java/org/moire/ultrasonic/util/LoadingTask.java index ff6ce52a..f42771c0 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/util/LoadingTask.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/util/LoadingTask.java @@ -1,8 +1,6 @@ package org.moire.ultrasonic.util; -import android.annotation.SuppressLint; import android.app.Activity; - import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; /** diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/util/PermissionUtil.java b/ultrasonic/src/main/java/org/moire/ultrasonic/util/PermissionUtil.java index eb5ddea3..da94deb2 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/util/PermissionUtil.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/util/PermissionUtil.java @@ -33,7 +33,7 @@ import static androidx.core.content.PermissionChecker.PERMISSION_DENIED; public class PermissionUtil { private Context activityContext; - private Context applicationContext; + private final Context applicationContext; public PermissionUtil(Context context) { applicationContext = context; diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/util/TimeSpanPreference.java b/ultrasonic/src/main/java/org/moire/ultrasonic/util/TimeSpanPreference.java index cd98946a..799f7f2d 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/util/TimeSpanPreference.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/util/TimeSpanPreference.java @@ -2,14 +2,9 @@ package org.moire.ultrasonic.util; import android.content.Context; import android.util.AttributeSet; -import android.view.View; - import androidx.preference.DialogPreference; - import org.moire.ultrasonic.R; -import java.util.regex.Pattern; - /** * Created by Joshua Bahnsen on 12/22/13. */ diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/util/TimeSpanPreferenceDialogFragmentCompat.java b/ultrasonic/src/main/java/org/moire/ultrasonic/util/TimeSpanPreferenceDialogFragmentCompat.java index 79507b5c..c5c3eb4f 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/util/TimeSpanPreferenceDialogFragmentCompat.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/util/TimeSpanPreferenceDialogFragmentCompat.java @@ -1,17 +1,15 @@ package org.moire.ultrasonic.util; import android.content.Context; -import android.util.AttributeSet; import android.view.View; - import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.preference.DialogPreference; import androidx.preference.Preference; import androidx.preference.PreferenceDialogFragmentCompat; - import org.moire.ultrasonic.R; +import java.util.Locale; import java.util.regex.Pattern; /** @@ -72,7 +70,7 @@ public class TimeSpanPreferenceDialogFragmentCompat extends PreferenceDialogFrag { String tsType = picker.getTimeSpanType(); - persisted = String.format("%d:%s", tsAmount, tsType); + persisted = String.format(Locale.US, "%d:%s", tsAmount, tsType); } } diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/util/Util.java b/ultrasonic/src/main/java/org/moire/ultrasonic/util/Util.java index 17ece7b5..aac3eeea 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/util/Util.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/util/Util.java @@ -18,6 +18,7 @@ */ package org.moire.ultrasonic.util; +import android.annotation.SuppressLint; import android.app.Activity; import android.app.AlertDialog; import android.app.PendingIntent; @@ -44,6 +45,8 @@ import timber.log.Timber; import android.util.TypedValue; import android.view.Gravity; import android.view.KeyEvent; +import android.view.View; +import android.view.inputmethod.InputMethodManager; import android.widget.RemoteViews; import android.widget.Toast; @@ -61,10 +64,8 @@ import org.moire.ultrasonic.service.DownloadFile; import java.io.*; import java.security.MessageDigest; import java.text.DecimalFormat; -import java.text.NumberFormat; import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; +import java.util.Locale; import java.util.concurrent.TimeUnit; import java.util.regex.Pattern; @@ -93,8 +94,6 @@ public class Util private static boolean mediaButtonsRegisteredForUI; private static boolean mediaButtonsRegisteredForService; - private static final Map SERVER_REST_VERSIONS = new ConcurrentHashMap(); - // Used by hexEncode() private static final char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; private static Toast toast; @@ -122,7 +121,7 @@ public class Util SharedPreferences preferences = getPreferences(context); SharedPreferences.Editor editor = preferences.edit(); editor.putString(Constants.PREFERENCES_KEY_REPEAT_MODE, repeatMode.name()); - editor.commit(); + editor.apply(); } public static boolean isNotificationEnabled(Context context) @@ -141,6 +140,7 @@ public class Util return preferences.getBoolean(Constants.PREFERENCES_KEY_ALWAYS_SHOW_NOTIFICATION, false); } + @SuppressWarnings({"BooleanMethodIsAlwaysInverted"}) // It is inverted for readability public static boolean isLockScreenEnabled(Context context) { SharedPreferences preferences = getPreferences(context); @@ -205,25 +205,6 @@ public class Util return PreferenceManager.getDefaultSharedPreferences(context); } - public static int getRemainingTrialDays(Context context) - { - SharedPreferences preferences = getPreferences(context); - long installTime = preferences.getLong(Constants.PREFERENCES_KEY_INSTALL_TIME, 0L); - - if (installTime == 0L) - { - installTime = System.currentTimeMillis(); - SharedPreferences.Editor editor = preferences.edit(); - editor.putLong(Constants.PREFERENCES_KEY_INSTALL_TIME, installTime); - editor.commit(); - } - - long now = System.currentTimeMillis(); - long millisPerDay = 24L * 60L * 60L * 1000L; - int daysSinceInstall = (int) ((now - installTime) / millisPerDay); - return Math.max(0, Constants.FREE_TRIAL_DAYS - daysSinceInstall); - } - /** * Get the contents of an InputStream as a byte[]. *

@@ -346,6 +327,7 @@ public class Util toast(context, message, true); } + @SuppressLint("ShowToast") // Invalid warning public static void toast(Context context, CharSequence message, boolean shortDuration) { if (toast == null) @@ -381,22 +363,19 @@ public class Util // More than 1 GB? if (byteCount >= 1024 * 1024 * 1024) { - NumberFormat gigaByteFormat = GIGA_BYTE_FORMAT; - return gigaByteFormat.format((double) byteCount / (1024 * 1024 * 1024)); + return GIGA_BYTE_FORMAT.format((double) byteCount / (1024 * 1024 * 1024)); } // More than 1 MB? if (byteCount >= 1024 * 1024) { - NumberFormat megaByteFormat = MEGA_BYTE_FORMAT; - return megaByteFormat.format((double) byteCount / (1024 * 1024)); + return MEGA_BYTE_FORMAT.format((double) byteCount / (1024 * 1024)); } // More than 1 KB? if (byteCount >= 1024) { - NumberFormat kiloByteFormat = KILO_BYTE_FORMAT; - return kiloByteFormat.format((double) byteCount / 1024); + return KILO_BYTE_FORMAT.format((double) byteCount / 1024); } return byteCount + " B"; @@ -627,11 +606,6 @@ public class Util } } - public static void disablePendingTransition(Activity activity) - { - activity.overridePendingTransition(0, 0); - } - public static Drawable getDrawableFromAttribute(Context context, int attr) { int[] attrs = new int[]{attr}; @@ -667,7 +641,7 @@ public class Util public static WifiManager.WifiLock createWifiLock(Context context, String tag) { - WifiManager wm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); + WifiManager wm = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE); return wm.createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF, tag); } @@ -902,11 +876,7 @@ public class Util avrcpIntent.putExtra("playing", true); break; case STOPPED: - avrcpIntent.putExtra("playing", false); - break; case PAUSED: - avrcpIntent.putExtra("playing", false); - break; case COMPLETED: avrcpIntent.putExtra("playing", false); break; @@ -1011,7 +981,7 @@ public class Util // guarantee // a final image with both dimensions larger than or equal to the // requested height and width. - inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio; + inSampleSize = Math.min(heightRatio, widthRatio); } return inSampleSize; @@ -1085,6 +1055,7 @@ public class Util views.setOnClickPendingIntent(R.id.notification_five_star_5, pendingIntent); } + // TODO: Shouldn't this be used when making requests? public static int getNetworkTimeout(Context context) { SharedPreferences preferences = getPreferences(context); @@ -1190,6 +1161,7 @@ public class Util return Integer.parseInt(preferences.getString(Constants.PREFERENCES_KEY_DIRECTORY_CACHE_TIME, "300")); } + @SuppressWarnings("BooleanMethodIsAlwaysInverted") // Inverted for readability public static boolean isNullOrWhiteSpace(String string) { return string == null || string.isEmpty() || string.trim().isEmpty(); @@ -1239,18 +1211,18 @@ public class Util if (hours >= 10) { - return String.format("%02d:%02d:%02d", hours, minutes, seconds); + return String.format(Locale.getDefault(), "%02d:%02d:%02d", hours, minutes, seconds); } else if (hours > 0) { - return String.format("%d:%02d:%02d", hours, minutes, seconds); + return String.format(Locale.getDefault(), "%d:%02d:%02d", hours, minutes, seconds); } else if (minutes >= 10) { - return String.format("%02d:%02d", minutes, seconds); + return String.format(Locale.getDefault(), "%02d:%02d", minutes, seconds); } - else return minutes > 0 ? String.format("%d:%02d", minutes, seconds) : String.format("0:%02d", seconds); + else return minutes > 0 ? String.format(Locale.getDefault(), "%d:%02d", minutes, seconds) : String.format(Locale.getDefault(), "0:%02d", seconds); } public static VideoPlayerType getVideoPlayerType(Context context) @@ -1329,6 +1301,7 @@ public class Util return versionCode; } + @SuppressWarnings("BooleanMethodIsAlwaysInverted") // Inverted for readability public static boolean getShouldSendBluetoothNotifications(Context context) { SharedPreferences preferences = getPreferences(context); @@ -1396,7 +1369,7 @@ public class Util SharedPreferences preferences = getPreferences(context); SharedPreferences.Editor editor = preferences.edit(); editor.putBoolean(Constants.PREFERENCES_KEY_ASK_FOR_SHARE_DETAILS, shouldAskForShareDetails); - editor.commit(); + editor.apply(); } public static void setDefaultShareExpiration(Context context, String defaultShareExpiration) @@ -1404,7 +1377,7 @@ public class Util SharedPreferences preferences = getPreferences(context); SharedPreferences.Editor editor = preferences.edit(); editor.putString(Constants.PREFERENCES_KEY_DEFAULT_SHARE_EXPIRATION, defaultShareExpiration); - editor.commit(); + editor.apply(); } public static void setDefaultShareDescription(Context context, String defaultShareDescription) @@ -1412,7 +1385,7 @@ public class Util SharedPreferences preferences = getPreferences(context); SharedPreferences.Editor editor = preferences.edit(); editor.putString(Constants.PREFERENCES_KEY_DEFAULT_SHARE_DESCRIPTION, defaultShareDescription); - editor.commit(); + editor.apply(); } public static boolean getShouldShowAllSongsByArtist(Context context) @@ -1485,4 +1458,12 @@ public class Util return preferences.getBoolean(Constants.PREFERENCES_KEY_DEBUG_LOG_TO_FILE, false); } + public static void hideKeyboard(Activity activity) { + InputMethodManager inputManager = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE); + + View currentFocusedView = activity.getCurrentFocus(); + if (currentFocusedView != null) { + inputManager.hideSoftInputFromWindow(currentFocusedView.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); + } + } } diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/util/VideoPlayerType.java b/ultrasonic/src/main/java/org/moire/ultrasonic/util/VideoPlayerType.java index ea3e26dc..53c87163 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/util/VideoPlayerType.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/util/VideoPlayerType.java @@ -18,7 +18,6 @@ */ package org.moire.ultrasonic.util; -import android.app.Activity; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/view/AlbumView.java b/ultrasonic/src/main/java/org/moire/ultrasonic/view/AlbumView.java index cb9fe171..40e8fb3e 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/view/AlbumView.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/view/AlbumView.java @@ -97,11 +97,7 @@ public class AlbumView extends UpdateView } public void maximizeOrMinimize() { - if (maximized) { - maximized = false; - } else { - maximized = true; - } + maximized = !maximized; if (this.viewHolder.title != null) { this.viewHolder.title.setSingleLine(!maximized); } diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/view/ChatAdapter.java b/ultrasonic/src/main/java/org/moire/ultrasonic/view/ChatAdapter.java index c84974b6..82c18a8e 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/view/ChatAdapter.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/view/ChatAdapter.java @@ -27,13 +27,13 @@ import static org.koin.java.KoinJavaComponent.inject; public class ChatAdapter extends ArrayAdapter { private final Context context; - private List messages; + private final List messages; private static final String phoneRegex = "1?\\W*([2-9][0-8][0-9])\\W*([2-9][0-9]{2})\\W*([0-9]{4})"; private static final Pattern phoneMatcher = Pattern.compile(phoneRegex); - private Lazy activeServerProvider = inject(ActiveServerProvider.class); - private Lazy imageLoader = inject(ImageLoaderProvider.class); + private final Lazy activeServerProvider = inject(ActiveServerProvider.class); + private final Lazy imageLoader = inject(ImageLoaderProvider.class); public ChatAdapter(Context context, List messages) { diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/view/EntryAdapter.java b/ultrasonic/src/main/java/org/moire/ultrasonic/view/EntryAdapter.java index 5faf4eac..5f655a7f 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/view/EntryAdapter.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/view/EntryAdapter.java @@ -59,7 +59,7 @@ public class EntryAdapter extends ArrayAdapter { AlbumView view; - if (convertView != null && convertView instanceof AlbumView) + if (convertView instanceof AlbumView) { AlbumView currentView = (AlbumView) convertView; @@ -87,7 +87,7 @@ public class EntryAdapter extends ArrayAdapter { SongView view; - if (convertView != null && convertView instanceof SongView) + if (convertView instanceof SongView) { SongView currentView = (SongView) convertView; diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/view/PlaylistAdapter.java b/ultrasonic/src/main/java/org/moire/ultrasonic/view/PlaylistAdapter.java index 57286135..bfa4c65e 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/view/PlaylistAdapter.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/view/PlaylistAdapter.java @@ -9,9 +9,6 @@ import android.widget.TextView; import org.moire.ultrasonic.R; import org.moire.ultrasonic.domain.Playlist; -import java.io.Serializable; -import java.util.Collections; -import java.util.Comparator; import java.util.List; /** @@ -34,7 +31,7 @@ public class PlaylistAdapter extends ArrayAdapter Playlist entry = getItem(position); PlaylistView view; - if (convertView != null && convertView instanceof PlaylistView) + if (convertView instanceof PlaylistView) { PlaylistView currentView = (PlaylistView) convertView; @@ -52,23 +49,6 @@ public class PlaylistAdapter extends ArrayAdapter return view; } - public static class PlaylistComparator implements Comparator, Serializable - { - private static final long serialVersionUID = -6201663557439120008L; - - @Override - public int compare(Playlist playlist1, Playlist playlist2) - { - return playlist1.getName().compareToIgnoreCase(playlist2.getName()); - } - - public static List sort(List playlists) - { - Collections.sort(playlists, new PlaylistComparator()); - return playlists; - } - } - static class ViewHolder { TextView name; diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/view/ShareAdapter.java b/ultrasonic/src/main/java/org/moire/ultrasonic/view/ShareAdapter.java index 52a77ead..497d8ce0 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/view/ShareAdapter.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/view/ShareAdapter.java @@ -9,9 +9,6 @@ import android.widget.TextView; import org.moire.ultrasonic.R; import org.moire.ultrasonic.domain.Share; -import java.io.Serializable; -import java.util.Collections; -import java.util.Comparator; import java.util.List; /** @@ -34,7 +31,7 @@ public class ShareAdapter extends ArrayAdapter Share entry = getItem(position); ShareView view; - if (convertView != null && convertView instanceof ShareView) + if (convertView instanceof ShareView) { ShareView currentView = (ShareView) convertView; @@ -52,23 +49,6 @@ public class ShareAdapter extends ArrayAdapter return view; } - public static class ShareComparator implements Comparator, Serializable - { - private static final long serialVersionUID = -7169409928471418921L; - - @Override - public int compare(Share share1, Share share2) - { - return share1.getId().compareToIgnoreCase(share2.getId()); - } - - public static List sort(List shares) - { - Collections.sort(shares, new ShareComparator()); - return shares; - } - } - static class ViewHolder { TextView url; diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/activity/NavigationActivity.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/activity/NavigationActivity.kt index f12b2bd7..97c274be 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/activity/NavigationActivity.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/activity/NavigationActivity.kt @@ -32,6 +32,7 @@ import org.koin.android.viewmodel.ext.android.viewModel import org.moire.ultrasonic.R import org.moire.ultrasonic.data.ActiveServerProvider.Companion.isOffline import org.moire.ultrasonic.domain.PlayerState +import org.moire.ultrasonic.fragment.OnBackPressedHandler import org.moire.ultrasonic.fragment.ServerSettingsModel import org.moire.ultrasonic.provider.SearchSuggestionProvider import org.moire.ultrasonic.service.DownloadFile @@ -53,14 +54,15 @@ import timber.log.Timber * The main Activity of Ultrasonic which loads all other screens as Fragments */ class NavigationActivity : AppCompatActivity() { - var chatMenuItem: MenuItem? = null - var bookmarksMenuItem: MenuItem? = null - var sharesMenuItem: MenuItem? = null - var podcastsMenuItem: MenuItem? = null - var nowPlayingView: FragmentContainerView? = null - var nowPlayingHidden = false - var navigationView: NavigationView? = null - var drawerLayout: DrawerLayout? = null + private var chatMenuItem: MenuItem? = null + private var bookmarksMenuItem: MenuItem? = null + private var sharesMenuItem: MenuItem? = null + private var podcastsMenuItem: MenuItem? = null + private var nowPlayingView: FragmentContainerView? = null + private var nowPlayingHidden = false + private var navigationView: NavigationView? = null + private var drawerLayout: DrawerLayout? = null + private var host: NavHostFragment? = null private lateinit var appBarConfiguration: AppBarConfiguration private lateinit var nowPlayingEventListener: NowPlayingEventListener @@ -93,10 +95,10 @@ class NavigationActivity : AppCompatActivity() { val toolbar = findViewById(R.id.toolbar) setSupportActionBar(toolbar) - val host: NavHostFragment = supportFragmentManager + host = supportFragmentManager .findFragmentById(R.id.nav_host_fragment) as NavHostFragment? ?: return - val navController = host.navController + val navController = host!!.navController appBarConfiguration = AppBarConfiguration( setOf( @@ -123,7 +125,7 @@ class NavigationActivity : AppCompatActivity() { val dest: String = try { resources.getResourceName(destination.id) } catch (e: Resources.NotFoundException) { - Integer.toString(destination.id) + destination.id.toString() } Timber.d("Navigated to $dest") @@ -209,7 +211,7 @@ class NavigationActivity : AppCompatActivity() { navigationView?.setupWithNavController(navController) // The exit menu is handled here manually - val exitItem: MenuItem? = navigationView?.menu?.findItem(R.id.menu_exit) ?: null + val exitItem: MenuItem? = navigationView?.menu?.findItem(R.id.menu_exit) exitItem?.setOnMenuItemClickListener { item -> if (item.itemId == R.id.menu_exit) { setResult(Constants.RESULT_CLOSE_ALL) @@ -235,7 +237,9 @@ class NavigationActivity : AppCompatActivity() { if (drawerLayout?.isDrawerVisible(GravityCompat.START) == true) { this.drawerLayout?.closeDrawer(GravityCompat.START) } else { - super.onBackPressed() + val currentFragment = host!!.childFragmentManager.fragments.last() + if (currentFragment is OnBackPressedHandler) currentFragment.onBackPressed() + else super.onBackPressed() } } @@ -254,7 +258,13 @@ class NavigationActivity : AppCompatActivity() { } override fun onSupportNavigateUp(): Boolean { - return findNavController(R.id.nav_host_fragment).navigateUp(appBarConfiguration) + val currentFragment = host!!.childFragmentManager.fragments.last() + return if (currentFragment is OnBackPressedHandler) { + currentFragment.onBackPressed() + true + } else { + findNavController(R.id.nav_host_fragment).navigateUp(appBarConfiguration) + } } // TODO Test if this works with external Intents diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/app/UApp.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/app/UApp.kt index 5ca3310e..04921f59 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/app/UApp.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/app/UApp.kt @@ -18,6 +18,10 @@ import org.moire.ultrasonic.util.Util import timber.log.Timber import timber.log.Timber.DebugTree +/** + * The Main class of the Application + */ +@Suppress("unused") class UApp : MultiDexApplication() { override fun onCreate() { super.onCreate() diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/EditServerFragment.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/EditServerFragment.kt index d72429c5..1c0ee6c8 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/EditServerFragment.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/EditServerFragment.kt @@ -30,7 +30,7 @@ import org.moire.ultrasonic.util.ModalBackgroundTask import org.moire.ultrasonic.util.Util import timber.log.Timber -class EditServerFragment : Fragment() { +class EditServerFragment : Fragment(), OnBackPressedHandler { companion object { const val EDIT_SERVER_INTENT_INDEX = "index" } @@ -141,6 +141,10 @@ class EditServerFragment : Fragment() { } } + override fun onBackPressed() { + finishActivity() + } + override fun onSaveInstanceState(savedInstanceState: Bundle) { savedInstanceState.putString( ::serverNameEditText.name, serverNameEditText!!.editText?.text.toString() @@ -269,10 +273,10 @@ class EditServerFragment : Fragment() { */ private fun areFieldsChanged(): Boolean { if (currentServerSetting == null || currentServerSetting!!.id == -1) { - return !serverNameEditText!!.editText?.text!!.isBlank() || + return serverNameEditText!!.editText?.text!!.isNotBlank() || serverAddressEditText!!.editText?.text.toString() != "http://" || - !userNameEditText!!.editText?.text!!.isBlank() || - !passwordEditText!!.editText?.text!!.isBlank() + userNameEditText!!.editText?.text!!.isNotBlank() || + passwordEditText!!.editText?.text!!.isNotBlank() } return currentServerSetting!!.name != serverNameEditText!!.editText?.text.toString() || @@ -363,6 +367,7 @@ class EditServerFragment : Fragment() { .setMessage(R.string.server_editor_leave_confirmation) .setPositiveButton(R.string.common_ok) { dialog, _ -> dialog.dismiss() + Util.hideKeyboard(activity) findNavController().navigateUp() } .setNegativeButton(R.string.common_cancel) { dialog, _ -> @@ -370,6 +375,7 @@ class EditServerFragment : Fragment() { } .show() } else { + Util.hideKeyboard(activity) findNavController().navigateUp() } } diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/OnBackPressedHandler.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/OnBackPressedHandler.kt new file mode 100644 index 00000000..cf7ecb32 --- /dev/null +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/OnBackPressedHandler.kt @@ -0,0 +1,8 @@ +package org.moire.ultrasonic.fragment + +/** + * Interface for fragments handling their own Back button + */ +interface OnBackPressedHandler { + fun onBackPressed() +} diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MusicServiceFactory.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MusicServiceFactory.kt index 02b657eb..d872ee9a 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MusicServiceFactory.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MusicServiceFactory.kt @@ -30,7 +30,7 @@ import org.moire.ultrasonic.di.OFFLINE_MUSIC_SERVICE import org.moire.ultrasonic.di.ONLINE_MUSIC_SERVICE import org.moire.ultrasonic.di.musicServiceModule -@Deprecated("Use DI way to get MusicService") +// TODO Refactor everywhere to use DI way to get MusicService, and then remove this class object MusicServiceFactory : KoinComponent { @JvmStatic fun getMusicService(context: Context): MusicService { diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/RESTMusicService.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/RESTMusicService.kt index 8294b1c2..495790a5 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/RESTMusicService.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/RESTMusicService.kt @@ -631,7 +631,7 @@ open class RESTMusicService( id: String, useFlash: Boolean ): String { - // This method should not exists as video should be loaded using stream method + // TODO This method should not exists as video should be loaded using stream method // Previous method implementation uses assumption that video will be available // by videoPlayer.view?id=&maxBitRate=500&autoplay=true, but this url is not // official Subsonic API call. diff --git a/ultrasonic/src/main/res/layout/search_buttons.xml b/ultrasonic/src/main/res/layout/search_buttons.xml index ac01c50a..89742b70 100644 --- a/ultrasonic/src/main/res/layout/search_buttons.xml +++ b/ultrasonic/src/main/res/layout/search_buttons.xml @@ -5,12 +5,11 @@ a:layout_height="wrap_content">