mirror of
https://gitlab.com/ultrasonic/ultrasonic.git
synced 2025-04-17 01:32:23 +03:00
Fixed back press in Server Editor
Fixed displaying "no results" for Search Cleaned up code
This commit is contained in:
parent
8a047c5b78
commit
9910792c11
@ -40,7 +40,7 @@ import java.io.Serializable;
|
||||
public class EqualizerController
|
||||
{
|
||||
private static Boolean available = null;
|
||||
private static MutableLiveData<EqualizerController> instance = new MutableLiveData<>();
|
||||
private static final MutableLiveData<EqualizerController> instance = new MutableLiveData<>();
|
||||
|
||||
private Context context;
|
||||
public Equalizer equalizer;
|
||||
|
@ -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<VisualizerController> instance = new MutableLiveData<>();
|
||||
private static final MutableLiveData<VisualizerController> instance = new MutableLiveData<>();
|
||||
|
||||
public Visualizer visualizer;
|
||||
private int audioSessionId;
|
||||
|
@ -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);
|
||||
|
@ -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<MusicDirectory.Entry> getSelectedSongs(ListView albumListView)
|
||||
{
|
||||
List<MusicDirectory.Entry> songs = new ArrayList<MusicDirectory.Entry>(10);
|
||||
List<MusicDirectory.Entry> 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<Void, Void, String[]>
|
||||
{
|
||||
@Override
|
||||
protected void onPostExecute(String[] result)
|
||||
{
|
||||
super.onPostExecute(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String[] doInBackground(Void... params)
|
||||
{
|
||||
refresh();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<ChatMessage> messageList = new ArrayList<ChatMessage>();
|
||||
private static final ArrayList<ChatMessage> 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<Void, Void, String[]>
|
||||
{
|
||||
@Override
|
||||
protected void onPostExecute(String[] result)
|
||||
{
|
||||
load();
|
||||
super.onPostExecute(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String[] doInBackground(Void... params)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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<Void>(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<Boolean>(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<Void>(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<Void>(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<Void>(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<Void>(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<Void>(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;
|
||||
}
|
||||
|
@ -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<List<Playlist>> task = new FragmentBackgroundTask<List<Playlist>>(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<Void, Void, String[]>
|
||||
{
|
||||
@Override
|
||||
protected void onPostExecute(String[] result)
|
||||
{
|
||||
super.onPostExecute(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String[] doInBackground(Void... params)
|
||||
{
|
||||
refresh();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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())
|
||||
{
|
||||
|
@ -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<MediaPlayerController> mediaPlayerControllerLazy = inject(MediaPlayerController.class);
|
||||
private final Lazy<VideoPlayer> 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<MusicDirectory.Entry> entries = new ArrayList<MusicDirectory.Entry>(1);
|
||||
List<MusicDirectory.Entry> 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<MusicDirectory.Entry> 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<MusicDirectory.Entry> getSelectedSongs(ListView albumListView)
|
||||
{
|
||||
List<MusicDirectory.Entry> songs = new ArrayList<MusicDirectory.Entry>(10);
|
||||
List<MusicDirectory.Entry> 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<MusicDirectory.Entry> songs = new LinkedList<MusicDirectory.Entry>();
|
||||
List<MusicDirectory.Entry> 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<MusicDirectory.Entry> songs = new LinkedList<MusicDirectory.Entry>();
|
||||
Collection<MusicDirectory.Entry> 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<MusicDirectory, Boolean>(dir, valid);
|
||||
return new Pair<>(dir, valid);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -1275,20 +1268,4 @@ public class SelectAlbumFragment extends Fragment {
|
||||
return header;
|
||||
}
|
||||
}
|
||||
|
||||
private class GetDataTask extends AsyncTask<Void, Void, String[]>
|
||||
{
|
||||
@Override
|
||||
protected void onPostExecute(String[] result)
|
||||
{
|
||||
super.onPostExecute(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String[] doInBackground(Void... params)
|
||||
{
|
||||
refresh();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<List<Genre>> task = new FragmentBackgroundTask<List<Genre>>(getActivity(), true, refreshGenreListView, cancellationToken)
|
||||
{
|
||||
@Override
|
||||
protected List<Genre> doInBackground() throws Throwable
|
||||
protected List<Genre> doInBackground()
|
||||
{
|
||||
MusicService musicService = MusicServiceFactory.getMusicService(getContext());
|
||||
|
||||
List<Genre> genres = new ArrayList<Genre>();
|
||||
List<Genre> genres = new ArrayList<>();
|
||||
|
||||
try
|
||||
{
|
||||
@ -134,20 +131,4 @@ public class SelectGenreFragment extends Fragment {
|
||||
};
|
||||
task.execute();
|
||||
}
|
||||
|
||||
private class GetDataTask extends AsyncTask<Void, Void, String[]>
|
||||
{
|
||||
@Override
|
||||
protected void onPostExecute(String[] result)
|
||||
{
|
||||
super.onPostExecute(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String[] doInBackground(Void... params)
|
||||
{
|
||||
refresh();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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<List<Share>> task = new FragmentBackgroundTask<List<Share>>(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<Void, Void, String[]>
|
||||
{
|
||||
@Override
|
||||
protected void onPostExecute(String[] result)
|
||||
{
|
||||
super.onPostExecute(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String[] doInBackground(Void... params)
|
||||
{
|
||||
refresh();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -67,13 +67,13 @@ public class CachedMusicService implements MusicService
|
||||
private final LRUCache<String, TimeLimitedCache<MusicDirectory>> cachedArtist;
|
||||
private final LRUCache<String, TimeLimitedCache<MusicDirectory>> cachedAlbum;
|
||||
private final LRUCache<String, TimeLimitedCache<UserInfo>> cachedUserInfo;
|
||||
private final TimeLimitedCache<Boolean> cachedLicenseValid = new TimeLimitedCache<Boolean>(120, TimeUnit.SECONDS);
|
||||
private final TimeLimitedCache<Indexes> cachedIndexes = new TimeLimitedCache<Indexes>(60 * 60, TimeUnit.SECONDS);
|
||||
private final TimeLimitedCache<Indexes> cachedArtists = new TimeLimitedCache<Indexes>(60 * 60, TimeUnit.SECONDS);
|
||||
private final TimeLimitedCache<List<Playlist>> cachedPlaylists = new TimeLimitedCache<List<Playlist>>(3600, TimeUnit.SECONDS);
|
||||
private final TimeLimitedCache<List<PodcastsChannel>> cachedPodcastsChannels = new TimeLimitedCache<List<PodcastsChannel>>(3600, TimeUnit.SECONDS);
|
||||
private final TimeLimitedCache<List<MusicFolder>> cachedMusicFolders = new TimeLimitedCache<List<MusicFolder>>(10 * 3600, TimeUnit.SECONDS);
|
||||
private final TimeLimitedCache<List<Genre>> cachedGenres = new TimeLimitedCache<List<Genre>>(10 * 3600, TimeUnit.SECONDS);
|
||||
private final TimeLimitedCache<Boolean> cachedLicenseValid = new TimeLimitedCache<>(120, TimeUnit.SECONDS);
|
||||
private final TimeLimitedCache<Indexes> cachedIndexes = new TimeLimitedCache<>(60 * 60, TimeUnit.SECONDS);
|
||||
private final TimeLimitedCache<Indexes> cachedArtists = new TimeLimitedCache<>(60 * 60, TimeUnit.SECONDS);
|
||||
private final TimeLimitedCache<List<Playlist>> cachedPlaylists = new TimeLimitedCache<>(3600, TimeUnit.SECONDS);
|
||||
private final TimeLimitedCache<List<PodcastsChannel>> cachedPodcastsChannels = new TimeLimitedCache<>(3600, TimeUnit.SECONDS);
|
||||
private final TimeLimitedCache<List<MusicFolder>> cachedMusicFolders = new TimeLimitedCache<>(10 * 3600, TimeUnit.SECONDS);
|
||||
private final TimeLimitedCache<List<Genre>> cachedGenres = new TimeLimitedCache<>(10 * 3600, TimeUnit.SECONDS);
|
||||
|
||||
private String restUrl;
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -110,7 +110,8 @@ public interface MusicService
|
||||
*/
|
||||
Pair<InputStream, Boolean> 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<String> ids, Context context) throws Exception;
|
||||
|
||||
|
@ -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<Playlist> getPlaylists(boolean refresh, Context context)
|
||||
{
|
||||
List<Playlist> playlists = new ArrayList<Playlist>();
|
||||
List<Playlist> 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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";
|
||||
|
@ -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<File>();
|
||||
return new TreeSet<>();
|
||||
}
|
||||
|
||||
return new TreeSet<File>(Arrays.asList(files));
|
||||
return new TreeSet<>(Arrays.asList(files));
|
||||
}
|
||||
|
||||
public static SortedSet<File> listMediaFiles(File dir)
|
||||
|
@ -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<Thread>(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) {
|
||||
|
@ -1,8 +1,6 @@
|
||||
package org.moire.ultrasonic.util;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<Integer, Version> SERVER_REST_VERSIONS = new ConcurrentHashMap<Integer, Version>();
|
||||
|
||||
// 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 <code>InputStream</code> as a <code>byte[]</code>.
|
||||
* <p/>
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -27,13 +27,13 @@ import static org.koin.java.KoinJavaComponent.inject;
|
||||
public class ChatAdapter extends ArrayAdapter<ChatMessage>
|
||||
{
|
||||
private final Context context;
|
||||
private List<ChatMessage> messages;
|
||||
private final List<ChatMessage> 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> activeServerProvider = inject(ActiveServerProvider.class);
|
||||
private Lazy<ImageLoaderProvider> imageLoader = inject(ImageLoaderProvider.class);
|
||||
private final Lazy<ActiveServerProvider> activeServerProvider = inject(ActiveServerProvider.class);
|
||||
private final Lazy<ImageLoaderProvider> imageLoader = inject(ImageLoaderProvider.class);
|
||||
|
||||
public ChatAdapter(Context context, List<ChatMessage> messages)
|
||||
{
|
||||
|
@ -59,7 +59,7 @@ public class EntryAdapter extends ArrayAdapter<Entry>
|
||||
{
|
||||
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<Entry>
|
||||
{
|
||||
SongView view;
|
||||
|
||||
if (convertView != null && convertView instanceof SongView)
|
||||
if (convertView instanceof SongView)
|
||||
{
|
||||
SongView currentView = (SongView) convertView;
|
||||
|
||||
|
@ -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>
|
||||
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<Playlist>
|
||||
return view;
|
||||
}
|
||||
|
||||
public static class PlaylistComparator implements Comparator<Playlist>, Serializable
|
||||
{
|
||||
private static final long serialVersionUID = -6201663557439120008L;
|
||||
|
||||
@Override
|
||||
public int compare(Playlist playlist1, Playlist playlist2)
|
||||
{
|
||||
return playlist1.getName().compareToIgnoreCase(playlist2.getName());
|
||||
}
|
||||
|
||||
public static List<Playlist> sort(List<Playlist> playlists)
|
||||
{
|
||||
Collections.sort(playlists, new PlaylistComparator());
|
||||
return playlists;
|
||||
}
|
||||
}
|
||||
|
||||
static class ViewHolder
|
||||
{
|
||||
TextView name;
|
||||
|
@ -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>
|
||||
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<Share>
|
||||
return view;
|
||||
}
|
||||
|
||||
public static class ShareComparator implements Comparator<Share>, Serializable
|
||||
{
|
||||
private static final long serialVersionUID = -7169409928471418921L;
|
||||
|
||||
@Override
|
||||
public int compare(Share share1, Share share2)
|
||||
{
|
||||
return share1.getId().compareToIgnoreCase(share2.getId());
|
||||
}
|
||||
|
||||
public static List<Share> sort(List<Share> shares)
|
||||
{
|
||||
Collections.sort(shares, new ShareComparator());
|
||||
return shares;
|
||||
}
|
||||
}
|
||||
|
||||
static class ViewHolder
|
||||
{
|
||||
TextView url;
|
||||
|
@ -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<Toolbar>(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
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,8 @@
|
||||
package org.moire.ultrasonic.fragment
|
||||
|
||||
/**
|
||||
* Interface for fragments handling their own Back button
|
||||
*/
|
||||
interface OnBackPressedHandler {
|
||||
fun onBackPressed()
|
||||
}
|
@ -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 {
|
||||
|
@ -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=<id>&maxBitRate=500&autoplay=true, but this url is not
|
||||
// official Subsonic API call.
|
||||
|
@ -5,12 +5,11 @@
|
||||
a:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
a:id="@+id/search_search"
|
||||
a:text="@string/search.search"
|
||||
a:id="@+id/search_not_found"
|
||||
a:text="@string/search.no_match"
|
||||
a:layout_width="fill_parent"
|
||||
a:layout_height="wrap_content"
|
||||
a:drawablePadding="0dp"
|
||||
a:drawableLeft="?attr/search"
|
||||
a:textAppearance="?android:attr/textAppearanceMedium"
|
||||
a:gravity="center"
|
||||
a:padding="12dp"/>
|
||||
|
Loading…
x
Reference in New Issue
Block a user