Added NowPlayingFragment
This commit is contained in:
parent
f0917820cb
commit
cf90abb77e
|
@ -78,8 +78,8 @@ public class SubsonicTabActivity extends ResultActivity
|
||||||
private static final String STATE_ACTIVE_POSITION = "org.moire.ultrasonic.activePosition";
|
private static final String STATE_ACTIVE_POSITION = "org.moire.ultrasonic.activePosition";
|
||||||
private static final int DIALOG_ASK_FOR_SHARE_DETAILS = 102;
|
private static final int DIALOG_ASK_FOR_SHARE_DETAILS = 102;
|
||||||
|
|
||||||
private Lazy<MediaPlayerController> mediaPlayerControllerLazy = inject(MediaPlayerController.class);
|
private final Lazy<MediaPlayerController> mediaPlayerControllerLazy = inject(MediaPlayerController.class);
|
||||||
private Lazy<MediaPlayerLifecycleSupport> lifecycleSupport = inject(MediaPlayerLifecycleSupport.class);
|
private final Lazy<MediaPlayerLifecycleSupport> lifecycleSupport = inject(MediaPlayerLifecycleSupport.class);
|
||||||
protected Lazy<ImageLoaderProvider> imageLoader = inject(ImageLoaderProvider.class);
|
protected Lazy<ImageLoaderProvider> imageLoader = inject(ImageLoaderProvider.class);
|
||||||
|
|
||||||
public MenuDrawer menuDrawer;
|
public MenuDrawer menuDrawer;
|
||||||
|
@ -118,7 +118,7 @@ public class SubsonicTabActivity extends ResultActivity
|
||||||
bookmarksMenuItem = findViewById(R.id.menu_bookmarks);
|
bookmarksMenuItem = findViewById(R.id.menu_bookmarks);
|
||||||
sharesMenuItem = findViewById(R.id.menu_shares);
|
sharesMenuItem = findViewById(R.id.menu_shares);
|
||||||
|
|
||||||
setActionBarDisplayHomeAsUp(true);
|
//setActionBarDisplayHomeAsUp(true);
|
||||||
|
|
||||||
TextView activeView = (TextView) findViewById(menuActiveViewId);
|
TextView activeView = (TextView) findViewById(menuActiveViewId);
|
||||||
|
|
||||||
|
@ -163,11 +163,11 @@ public class SubsonicTabActivity extends ResultActivity
|
||||||
|
|
||||||
if (!nowPlayingHidden)
|
if (!nowPlayingHidden)
|
||||||
{
|
{
|
||||||
showNowPlaying();
|
//showNowPlaying();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
hideNowPlaying();
|
//hideNowPlaying();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,23 +194,6 @@ public class SubsonicTabActivity extends ResultActivity
|
||||||
imageLoader.getValue().clearImageLoader();
|
imageLoader.getValue().clearImageLoader();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onKeyDown(int keyCode, KeyEvent event)
|
|
||||||
{
|
|
||||||
boolean isVolumeDown = keyCode == KeyEvent.KEYCODE_VOLUME_DOWN;
|
|
||||||
boolean isVolumeUp = keyCode == KeyEvent.KEYCODE_VOLUME_UP;
|
|
||||||
boolean isVolumeAdjust = isVolumeDown || isVolumeUp;
|
|
||||||
boolean isJukebox = getMediaPlayerController() != null && getMediaPlayerController().isJukeboxEnabled();
|
|
||||||
|
|
||||||
if (isVolumeAdjust && isJukebox)
|
|
||||||
{
|
|
||||||
getMediaPlayerController().adjustJukeboxVolume(isVolumeUp);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return super.onKeyDown(keyCode, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void restart()
|
protected void restart()
|
||||||
{
|
{
|
||||||
Intent intent = new Intent(this, this.getClass());
|
Intent intent = new Intent(this, this.getClass());
|
||||||
|
@ -246,270 +229,11 @@ public class SubsonicTabActivity extends ResultActivity
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void showNowPlaying()
|
|
||||||
{
|
|
||||||
this.runOnUiThread(new Runnable()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void run()
|
|
||||||
{
|
|
||||||
new SilentBackgroundTask<Void>(SubsonicTabActivity.this)
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
protected Void doInBackground() throws Throwable
|
|
||||||
{
|
|
||||||
if (!Util.getShowNowPlayingPreference(SubsonicTabActivity.this))
|
|
||||||
{
|
|
||||||
hideNowPlaying();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nowPlayingView != null)
|
|
||||||
{
|
|
||||||
PlayerState playerState = mediaPlayerControllerLazy.getValue().getPlayerState();
|
|
||||||
|
|
||||||
if (playerState.equals(PlayerState.PAUSED) || playerState.equals(PlayerState.STARTED))
|
|
||||||
{
|
|
||||||
DownloadFile file = mediaPlayerControllerLazy.getValue().getCurrentPlaying();
|
|
||||||
|
|
||||||
if (file != null)
|
|
||||||
{
|
|
||||||
final Entry song = file.getSong();
|
|
||||||
showNowPlaying(SubsonicTabActivity.this, mediaPlayerControllerLazy.getValue(), song, playerState);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
hideNowPlaying();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void done(Void result)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}.execute();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void showNowPlaying(final Context context, final MediaPlayerController mediaPlayerController, final Entry song, final PlayerState playerState)
|
|
||||||
{
|
|
||||||
if (context == null || mediaPlayerController == null || song == null || playerState == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Util.getShowNowPlayingPreference(context))
|
|
||||||
{
|
|
||||||
hideNowPlaying();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nowPlayingView != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
setVisibilityOnUiThread(nowPlayingView, View.VISIBLE);
|
|
||||||
nowPlayingHidden = false;
|
|
||||||
|
|
||||||
ImageView playButton = (ImageView) nowPlayingView.findViewById(R.id.now_playing_control_play);
|
|
||||||
|
|
||||||
if (playerState == PlayerState.PAUSED)
|
|
||||||
{
|
|
||||||
setImageDrawableOnUiThread(playButton, Util.getDrawableFromAttribute(context, R.attr.media_play));
|
|
||||||
}
|
|
||||||
else if (playerState == PlayerState.STARTED)
|
|
||||||
{
|
|
||||||
setImageDrawableOnUiThread(playButton, Util.getDrawableFromAttribute(context, R.attr.media_pause));
|
|
||||||
}
|
|
||||||
|
|
||||||
String title = song.getTitle();
|
|
||||||
String artist = song.getArtist();
|
|
||||||
|
|
||||||
final ImageView nowPlayingAlbumArtImage = (ImageView) nowPlayingView.findViewById(R.id.now_playing_image);
|
|
||||||
TextView nowPlayingTrack = (TextView) nowPlayingView.findViewById(R.id.now_playing_trackname);
|
|
||||||
TextView nowPlayingArtist = (TextView) nowPlayingView.findViewById(R.id.now_playing_artist);
|
|
||||||
|
|
||||||
this.runOnUiThread(new Runnable()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void run()
|
|
||||||
{
|
|
||||||
imageLoader.getValue().getImageLoader().loadImage(nowPlayingAlbumArtImage, song, false, Util.getNotificationImageSize(context), false, true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// TODO: Refactor to use navigation
|
|
||||||
final Intent intent = new Intent(context, SelectAlbumFragment.class);// SelectAlbumActivity.class);
|
|
||||||
|
|
||||||
if (Util.getShouldUseId3Tags(context))
|
|
||||||
{
|
|
||||||
intent.putExtra(Constants.INTENT_EXTRA_NAME_IS_ALBUM, true);
|
|
||||||
intent.putExtra(Constants.INTENT_EXTRA_NAME_ID, song.getAlbumId());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
intent.putExtra(Constants.INTENT_EXTRA_NAME_IS_ALBUM, false);
|
|
||||||
intent.putExtra(Constants.INTENT_EXTRA_NAME_ID, song.getParent());
|
|
||||||
}
|
|
||||||
|
|
||||||
intent.putExtra(Constants.INTENT_EXTRA_NAME_NAME, song.getAlbum());
|
|
||||||
|
|
||||||
setOnClickListenerOnUiThread(nowPlayingAlbumArtImage, new OnClickListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void onClick(View view)
|
|
||||||
{
|
|
||||||
startActivityForResultWithoutTransition(SubsonicTabActivity.this, intent);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
setTextOnUiThread(nowPlayingTrack, title);
|
|
||||||
setTextOnUiThread(nowPlayingArtist, artist);
|
|
||||||
|
|
||||||
ImageView nowPlayingControlPlay = (ImageView) nowPlayingView.findViewById(R.id.now_playing_control_play);
|
|
||||||
|
|
||||||
SwipeDetector swipeDetector = new SwipeDetector(SubsonicTabActivity.this, mediaPlayerController);
|
|
||||||
setOnTouchListenerOnUiThread(nowPlayingView, swipeDetector);
|
|
||||||
|
|
||||||
setOnClickListenerOnUiThread(nowPlayingView, new OnClickListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void onClick(View v)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
setOnClickListenerOnUiThread(nowPlayingControlPlay, new OnClickListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void onClick(View view)
|
|
||||||
{
|
|
||||||
mediaPlayerController.togglePlayPause();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
catch (Exception x)
|
|
||||||
{
|
|
||||||
Timber.w(x, "Failed to get notification cover art");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void hideNowPlaying()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (nowPlayingView != null)
|
|
||||||
{
|
|
||||||
setVisibilityOnUiThread(nowPlayingView, View.GONE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Timber.w(ex, "Exception in hideNowPlaying");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOnTouchListenerOnUiThread(final View view, final OnTouchListener listener)
|
|
||||||
{
|
|
||||||
this.runOnUiThread(new Runnable()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void run()
|
|
||||||
{
|
|
||||||
if (view != null && view.getVisibility() != View.GONE)
|
|
||||||
{
|
|
||||||
view.setOnTouchListener(listener);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOnClickListenerOnUiThread(final View view, final OnClickListener listener)
|
|
||||||
{
|
|
||||||
this.runOnUiThread(new Runnable()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void run()
|
|
||||||
{
|
|
||||||
if (view != null && view.getVisibility() != View.GONE)
|
|
||||||
{
|
|
||||||
view.setOnClickListener(listener);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTextOnUiThread(final TextView view, final CharSequence text)
|
|
||||||
{
|
|
||||||
this.runOnUiThread(new Runnable()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void run()
|
|
||||||
{
|
|
||||||
if (view != null && view.getVisibility() != View.GONE)
|
|
||||||
{
|
|
||||||
view.setText(text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setImageDrawableOnUiThread(final ImageView view, final Drawable drawable)
|
|
||||||
{
|
|
||||||
this.runOnUiThread(new Runnable()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void run()
|
|
||||||
{
|
|
||||||
if (view != null && view.getVisibility() != View.GONE)
|
|
||||||
{
|
|
||||||
view.setImageDrawable(drawable);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setVisibilityOnUiThread(final View view, final int visibility)
|
|
||||||
{
|
|
||||||
this.runOnUiThread(new Runnable()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void run()
|
|
||||||
{
|
|
||||||
if (view != null && view.getVisibility() != visibility)
|
|
||||||
{
|
|
||||||
view.setVisibility(visibility);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SubsonicTabActivity getInstance()
|
public static SubsonicTabActivity getInstance()
|
||||||
{
|
{
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MediaPlayerController getMediaPlayerController()
|
|
||||||
{
|
|
||||||
return mediaPlayerControllerLazy.getValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setActionBarDisplayHomeAsUp(boolean enabled)
|
|
||||||
{
|
|
||||||
ActionBar actionBar = getSupportActionBar();
|
|
||||||
|
|
||||||
if (actionBar != null)
|
|
||||||
{
|
|
||||||
actionBar.setDisplayHomeAsUpEnabled(enabled);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onRestoreInstanceState(Bundle inState)
|
protected void onRestoreInstanceState(Bundle inState)
|
||||||
|
@ -527,87 +251,5 @@ public class SubsonicTabActivity extends ResultActivity
|
||||||
outState.putInt(STATE_ACTIVE_POSITION, activePosition);
|
outState.putInt(STATE_ACTIVE_POSITION, activePosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onBackPressed()
|
|
||||||
{
|
|
||||||
final int drawerState = menuDrawer.getDrawerState();
|
|
||||||
|
|
||||||
if (drawerState == MenuDrawer.STATE_OPEN || drawerState == MenuDrawer.STATE_OPENING)
|
|
||||||
{
|
|
||||||
menuDrawer.closeMenu(true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
super.onBackPressed();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected class SwipeDetector implements OnTouchListener
|
|
||||||
{
|
|
||||||
public SwipeDetector(SubsonicTabActivity activity, final MediaPlayerController mediaPlayerController)
|
|
||||||
{
|
|
||||||
this.mediaPlayerController = mediaPlayerController;
|
|
||||||
this.activity = activity;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final int MIN_DISTANCE = 30;
|
|
||||||
private float downX, downY, upX, upY;
|
|
||||||
private MediaPlayerController mediaPlayerController;
|
|
||||||
private SubsonicTabActivity activity;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onTouch(View v, MotionEvent event)
|
|
||||||
{
|
|
||||||
switch (event.getAction())
|
|
||||||
{
|
|
||||||
case MotionEvent.ACTION_DOWN:
|
|
||||||
{
|
|
||||||
downX = event.getX();
|
|
||||||
downY = event.getY();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
case MotionEvent.ACTION_UP:
|
|
||||||
{
|
|
||||||
upX = event.getX();
|
|
||||||
upY = event.getY();
|
|
||||||
|
|
||||||
float deltaX = downX - upX;
|
|
||||||
float deltaY = downY - upY;
|
|
||||||
|
|
||||||
if (Math.abs(deltaX) > MIN_DISTANCE)
|
|
||||||
{
|
|
||||||
// left or right
|
|
||||||
if (deltaX < 0)
|
|
||||||
{
|
|
||||||
mediaPlayerController.previous();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (deltaX > 0)
|
|
||||||
{
|
|
||||||
mediaPlayerController.next();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (Math.abs(deltaY) > MIN_DISTANCE)
|
|
||||||
{
|
|
||||||
if (deltaY < 0)
|
|
||||||
{
|
|
||||||
SubsonicTabActivity.nowPlayingHidden = true;
|
|
||||||
activity.hideNowPlaying();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (deltaY > 0)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Refactor this to Navigation. It should automatically go to the PlayerFragment.
|
|
||||||
//SubsonicTabActivity.this.startActivityForResultWithoutTransition(activity, DownloadActivity.class);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ import org.moire.ultrasonic.domain.ChatMessage;
|
||||||
import org.moire.ultrasonic.service.MusicService;
|
import org.moire.ultrasonic.service.MusicService;
|
||||||
import org.moire.ultrasonic.service.MusicServiceFactory;
|
import org.moire.ultrasonic.service.MusicServiceFactory;
|
||||||
import org.moire.ultrasonic.util.BackgroundTask;
|
import org.moire.ultrasonic.util.BackgroundTask;
|
||||||
|
import org.moire.ultrasonic.util.CancellationToken;
|
||||||
import org.moire.ultrasonic.util.TabActivityBackgroundTask;
|
import org.moire.ultrasonic.util.TabActivityBackgroundTask;
|
||||||
import org.moire.ultrasonic.util.Util;
|
import org.moire.ultrasonic.util.Util;
|
||||||
import org.moire.ultrasonic.view.ChatAdapter;
|
import org.moire.ultrasonic.view.ChatAdapter;
|
||||||
|
@ -50,6 +51,7 @@ public class ChatFragment extends Fragment {
|
||||||
private Timer timer;
|
private Timer timer;
|
||||||
private volatile static Long lastChatMessageTime = (long) 0;
|
private volatile static Long lastChatMessageTime = (long) 0;
|
||||||
private static final ArrayList<ChatMessage> messageList = new ArrayList<ChatMessage>();
|
private static final ArrayList<ChatMessage> messageList = new ArrayList<ChatMessage>();
|
||||||
|
private CancellationToken cancellationToken;
|
||||||
|
|
||||||
private final Lazy<ActiveServerProvider> activeServerProvider = inject(ActiveServerProvider.class);
|
private final Lazy<ActiveServerProvider> activeServerProvider = inject(ActiveServerProvider.class);
|
||||||
|
|
||||||
|
@ -67,6 +69,8 @@ public class ChatFragment extends Fragment {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||||
|
super.onViewCreated(view, savedInstanceState);
|
||||||
|
cancellationToken = new CancellationToken();
|
||||||
messageEditText = view.findViewById(R.id.chat_edittext);
|
messageEditText = view.findViewById(R.id.chat_edittext);
|
||||||
sendButton = view.findViewById(R.id.chat_send);
|
sendButton = view.findViewById(R.id.chat_send);
|
||||||
|
|
||||||
|
@ -184,6 +188,12 @@ public class ChatFragment extends Fragment {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroyView() {
|
||||||
|
cancellationToken.cancel();
|
||||||
|
super.onDestroyView();
|
||||||
|
}
|
||||||
|
|
||||||
private void timerMethod()
|
private void timerMethod()
|
||||||
{
|
{
|
||||||
int refreshInterval = Util.getChatRefreshInterval(getContext());
|
int refreshInterval = Util.getChatRefreshInterval(getContext());
|
||||||
|
@ -228,7 +238,7 @@ public class ChatFragment extends Fragment {
|
||||||
{
|
{
|
||||||
messageEditText.setText("");
|
messageEditText.setText("");
|
||||||
|
|
||||||
BackgroundTask<Void> task = new TabActivityBackgroundTask<Void>(getActivity(), false)
|
BackgroundTask<Void> task = new TabActivityBackgroundTask<Void>(getActivity(), false, null, cancellationToken)
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
protected Void doInBackground() throws Throwable
|
protected Void doInBackground() throws Throwable
|
||||||
|
@ -252,7 +262,7 @@ public class ChatFragment extends Fragment {
|
||||||
|
|
||||||
private synchronized void load()
|
private synchronized void load()
|
||||||
{
|
{
|
||||||
BackgroundTask<List<ChatMessage>> task = new TabActivityBackgroundTask<List<ChatMessage>>(getActivity(), false)
|
BackgroundTask<List<ChatMessage>> task = new TabActivityBackgroundTask<List<ChatMessage>>(getActivity(), false, null, cancellationToken)
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
protected List<ChatMessage> doInBackground() throws Throwable
|
protected List<ChatMessage> doInBackground() throws Throwable
|
||||||
|
|
|
@ -0,0 +1,205 @@
|
||||||
|
package org.moire.ultrasonic.fragment;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.navigation.Navigation;
|
||||||
|
|
||||||
|
import org.moire.ultrasonic.R;
|
||||||
|
import org.moire.ultrasonic.domain.MusicDirectory;
|
||||||
|
import org.moire.ultrasonic.domain.PlayerState;
|
||||||
|
import org.moire.ultrasonic.service.DownloadFile;
|
||||||
|
import org.moire.ultrasonic.service.MediaPlayerController;
|
||||||
|
import org.moire.ultrasonic.subsonic.ImageLoaderProvider;
|
||||||
|
import org.moire.ultrasonic.util.Constants;
|
||||||
|
import org.moire.ultrasonic.util.NowPlayingEventDistributor;
|
||||||
|
import org.moire.ultrasonic.util.NowPlayingEventListener;
|
||||||
|
import org.moire.ultrasonic.util.Util;
|
||||||
|
|
||||||
|
import kotlin.Lazy;
|
||||||
|
import timber.log.Timber;
|
||||||
|
|
||||||
|
import static org.koin.java.KoinJavaComponent.inject;
|
||||||
|
|
||||||
|
public class NowPlayingFragment extends Fragment {
|
||||||
|
|
||||||
|
private static final int MIN_DISTANCE = 30;
|
||||||
|
private float downX;
|
||||||
|
private float downY;
|
||||||
|
ImageView playButton;
|
||||||
|
ImageView nowPlayingAlbumArtImage;
|
||||||
|
TextView nowPlayingTrack;
|
||||||
|
TextView nowPlayingArtist;
|
||||||
|
|
||||||
|
private final Lazy<MediaPlayerController> mediaPlayerControllerLazy = inject(MediaPlayerController.class);
|
||||||
|
private final Lazy<ImageLoaderProvider> imageLoader = inject(ImageLoaderProvider.class);
|
||||||
|
private final Lazy<NowPlayingEventDistributor> nowPlayingEventDistributor = inject(NowPlayingEventDistributor.class);
|
||||||
|
private NowPlayingEventListener nowPlayingEventListener;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
|
Util.applyTheme(this.getContext());
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
|
Bundle savedInstanceState) {
|
||||||
|
return inflater.inflate(R.layout.now_playing, container, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onViewCreated(@NonNull final View view, @Nullable Bundle savedInstanceState) {
|
||||||
|
|
||||||
|
playButton = (ImageView) view.findViewById(R.id.now_playing_control_play);
|
||||||
|
nowPlayingAlbumArtImage = (ImageView) view.findViewById(R.id.now_playing_image);
|
||||||
|
nowPlayingTrack = (TextView) view.findViewById(R.id.now_playing_trackname);
|
||||||
|
nowPlayingArtist = (TextView) view.findViewById(R.id.now_playing_artist);
|
||||||
|
|
||||||
|
nowPlayingEventListener = new NowPlayingEventListener() {
|
||||||
|
@Override
|
||||||
|
public void onDismissNowPlaying() { }
|
||||||
|
@Override
|
||||||
|
public void onHideNowPlaying() { }
|
||||||
|
@Override
|
||||||
|
public void onShowNowPlaying() { Update(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
nowPlayingEventDistributor.getValue().subscribe(nowPlayingEventListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
nowPlayingEventDistributor.getValue().unsubscribe(nowPlayingEventListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Update() {
|
||||||
|
try
|
||||||
|
{
|
||||||
|
PlayerState playerState = mediaPlayerControllerLazy.getValue().getPlayerState();
|
||||||
|
if (playerState == PlayerState.PAUSED) {
|
||||||
|
playButton.setImageDrawable(Util.getDrawableFromAttribute(getContext(), R.attr.media_play));
|
||||||
|
} else if (playerState == PlayerState.STARTED) {
|
||||||
|
playButton.setImageDrawable(Util.getDrawableFromAttribute(getContext(), R.attr.media_pause));
|
||||||
|
}
|
||||||
|
|
||||||
|
DownloadFile file = mediaPlayerControllerLazy.getValue().getCurrentPlaying();
|
||||||
|
if (file != null) {
|
||||||
|
final MusicDirectory.Entry song = file.getSong();
|
||||||
|
String title = song.getTitle();
|
||||||
|
String artist = song.getArtist();
|
||||||
|
|
||||||
|
imageLoader.getValue().getImageLoader().loadImage(nowPlayingAlbumArtImage, song, false, Util.getNotificationImageSize(getContext()), false, true);
|
||||||
|
nowPlayingTrack.setText(title);
|
||||||
|
nowPlayingArtist.setText(artist);
|
||||||
|
|
||||||
|
nowPlayingAlbumArtImage.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
Bundle bundle = new Bundle();
|
||||||
|
|
||||||
|
if (Util.getShouldUseId3Tags(getContext())) {
|
||||||
|
bundle.putBoolean(Constants.INTENT_EXTRA_NAME_IS_ALBUM, true);
|
||||||
|
bundle.putString(Constants.INTENT_EXTRA_NAME_ID, song.getAlbumId());
|
||||||
|
} else {
|
||||||
|
bundle.putBoolean(Constants.INTENT_EXTRA_NAME_IS_ALBUM, false);
|
||||||
|
bundle.putString(Constants.INTENT_EXTRA_NAME_ID, song.getParent());
|
||||||
|
}
|
||||||
|
|
||||||
|
bundle.putString(Constants.INTENT_EXTRA_NAME_NAME, song.getAlbum());
|
||||||
|
Navigation.findNavController(getView()).navigate(R.id.selectAlbumFragment, bundle);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getView().setOnTouchListener(new View.OnTouchListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onTouch(View v, MotionEvent event) {
|
||||||
|
return handleOnTouch(v, event);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: Check if this empty onClickListener is necessary
|
||||||
|
getView().setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
playButton.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
mediaPlayerControllerLazy.getValue().togglePlayPause();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (Exception x) {
|
||||||
|
Timber.w(x, "Failed to get notification cover art");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean handleOnTouch(View v, MotionEvent event) {
|
||||||
|
switch (event.getAction())
|
||||||
|
{
|
||||||
|
case MotionEvent.ACTION_DOWN:
|
||||||
|
{
|
||||||
|
downX = event.getX();
|
||||||
|
downY = event.getY();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case MotionEvent.ACTION_UP:
|
||||||
|
{
|
||||||
|
float upX = event.getX();
|
||||||
|
float upY = event.getY();
|
||||||
|
|
||||||
|
float deltaX = downX - upX;
|
||||||
|
float deltaY = downY - upY;
|
||||||
|
|
||||||
|
if (Math.abs(deltaX) > MIN_DISTANCE)
|
||||||
|
{
|
||||||
|
// left or right
|
||||||
|
if (deltaX < 0)
|
||||||
|
{
|
||||||
|
mediaPlayerControllerLazy.getValue().previous();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (deltaX > 0)
|
||||||
|
{
|
||||||
|
mediaPlayerControllerLazy.getValue().next();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Math.abs(deltaY) > MIN_DISTANCE)
|
||||||
|
{
|
||||||
|
if (deltaY < 0)
|
||||||
|
{
|
||||||
|
nowPlayingEventDistributor.getValue().RaiseNowPlayingDismissedEvent();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (deltaY > 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Navigation.findNavController(getView()).navigate(R.id.playerFragment);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1404,6 +1404,7 @@ public class PlayerFragment extends Fragment implements GestureDetector.OnGestur
|
||||||
@Override
|
@Override
|
||||||
protected void done(final Void result)
|
protected void done(final Void result)
|
||||||
{
|
{
|
||||||
|
if (cancellationToken.isCancellationRequested()) return;
|
||||||
if (currentPlaying != null)
|
if (currentPlaying != null)
|
||||||
{
|
{
|
||||||
final int millisTotal = duration == null ? 0 : duration;
|
final int millisTotal = duration == null ? 0 : duration;
|
||||||
|
|
|
@ -17,6 +17,7 @@ import org.moire.ultrasonic.domain.PodcastsChannel;
|
||||||
import org.moire.ultrasonic.service.MusicService;
|
import org.moire.ultrasonic.service.MusicService;
|
||||||
import org.moire.ultrasonic.service.MusicServiceFactory;
|
import org.moire.ultrasonic.service.MusicServiceFactory;
|
||||||
import org.moire.ultrasonic.util.BackgroundTask;
|
import org.moire.ultrasonic.util.BackgroundTask;
|
||||||
|
import org.moire.ultrasonic.util.CancellationToken;
|
||||||
import org.moire.ultrasonic.util.Constants;
|
import org.moire.ultrasonic.util.Constants;
|
||||||
import org.moire.ultrasonic.util.TabActivityBackgroundTask;
|
import org.moire.ultrasonic.util.TabActivityBackgroundTask;
|
||||||
import org.moire.ultrasonic.util.Util;
|
import org.moire.ultrasonic.util.Util;
|
||||||
|
@ -28,6 +29,7 @@ public class PodcastFragment extends Fragment {
|
||||||
|
|
||||||
private View emptyTextView;
|
private View emptyTextView;
|
||||||
ListView channelItemsListView = null;
|
ListView channelItemsListView = null;
|
||||||
|
private CancellationToken cancellationToken;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
|
@ -43,6 +45,8 @@ public class PodcastFragment extends Fragment {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||||
|
super.onViewCreated(view, savedInstanceState);
|
||||||
|
cancellationToken = new CancellationToken();
|
||||||
FragmentTitle.Companion.setTitle(this, R.string.podcasts_label);
|
FragmentTitle.Companion.setTitle(this, R.string.podcasts_label);
|
||||||
|
|
||||||
emptyTextView = view.findViewById(R.id.select_podcasts_empty);
|
emptyTextView = view.findViewById(R.id.select_podcasts_empty);
|
||||||
|
@ -65,9 +69,15 @@ public class PodcastFragment extends Fragment {
|
||||||
load();
|
load();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroyView() {
|
||||||
|
cancellationToken.cancel();
|
||||||
|
super.onDestroyView();
|
||||||
|
}
|
||||||
|
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
BackgroundTask<List<PodcastsChannel>> task = new TabActivityBackgroundTask<List<PodcastsChannel>>(getActivity(), true)
|
BackgroundTask<List<PodcastsChannel>> task = new TabActivityBackgroundTask<List<PodcastsChannel>>(getActivity(), true, null, cancellationToken)
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
protected List<PodcastsChannel> doInBackground() throws Throwable
|
protected List<PodcastsChannel> doInBackground() throws Throwable
|
||||||
|
|
|
@ -32,6 +32,7 @@ import org.moire.ultrasonic.provider.UltrasonicAppWidgetProvider4X2;
|
||||||
import org.moire.ultrasonic.provider.UltrasonicAppWidgetProvider4X3;
|
import org.moire.ultrasonic.provider.UltrasonicAppWidgetProvider4X3;
|
||||||
import org.moire.ultrasonic.provider.UltrasonicAppWidgetProvider4X4;
|
import org.moire.ultrasonic.provider.UltrasonicAppWidgetProvider4X4;
|
||||||
import org.moire.ultrasonic.util.FileUtil;
|
import org.moire.ultrasonic.util.FileUtil;
|
||||||
|
import org.moire.ultrasonic.util.NowPlayingEventDistributor;
|
||||||
import org.moire.ultrasonic.util.ShufflePlayBuffer;
|
import org.moire.ultrasonic.util.ShufflePlayBuffer;
|
||||||
import org.moire.ultrasonic.util.SimpleServiceBinder;
|
import org.moire.ultrasonic.util.SimpleServiceBinder;
|
||||||
import org.moire.ultrasonic.util.Util;
|
import org.moire.ultrasonic.util.Util;
|
||||||
|
@ -64,10 +65,11 @@ public class MediaPlayerService extends Service
|
||||||
private final Scrobbler scrobbler = new Scrobbler();
|
private final Scrobbler scrobbler = new Scrobbler();
|
||||||
|
|
||||||
public Lazy<JukeboxMediaPlayer> jukeboxMediaPlayer = inject(JukeboxMediaPlayer.class);
|
public Lazy<JukeboxMediaPlayer> jukeboxMediaPlayer = inject(JukeboxMediaPlayer.class);
|
||||||
private Lazy<DownloadQueueSerializer> downloadQueueSerializerLazy = inject(DownloadQueueSerializer.class);
|
private final Lazy<DownloadQueueSerializer> downloadQueueSerializerLazy = inject(DownloadQueueSerializer.class);
|
||||||
private Lazy<ShufflePlayBuffer> shufflePlayBufferLazy = inject(ShufflePlayBuffer.class);
|
private final Lazy<ShufflePlayBuffer> shufflePlayBufferLazy = inject(ShufflePlayBuffer.class);
|
||||||
private Lazy<Downloader> downloaderLazy = inject(Downloader.class);
|
private final Lazy<Downloader> downloaderLazy = inject(Downloader.class);
|
||||||
private Lazy<LocalMediaPlayer> localMediaPlayerLazy = inject(LocalMediaPlayer.class);
|
private final Lazy<LocalMediaPlayer> localMediaPlayerLazy = inject(LocalMediaPlayer.class);
|
||||||
|
private final Lazy<NowPlayingEventDistributor> nowPlayingEventDistributor = inject(NowPlayingEventDistributor.class);
|
||||||
private LocalMediaPlayer localMediaPlayer;
|
private LocalMediaPlayer localMediaPlayer;
|
||||||
private Downloader downloader;
|
private Downloader downloader;
|
||||||
private ShufflePlayBuffer shufflePlayBuffer;
|
private ShufflePlayBuffer shufflePlayBuffer;
|
||||||
|
@ -280,21 +282,14 @@ public class MediaPlayerService extends Service
|
||||||
UltrasonicAppWidgetProvider4X3.getInstance().notifyChange(MediaPlayerService.this, song, playerState == PlayerState.STARTED, false);
|
UltrasonicAppWidgetProvider4X3.getInstance().notifyChange(MediaPlayerService.this, song, playerState == PlayerState.STARTED, false);
|
||||||
UltrasonicAppWidgetProvider4X4.getInstance().notifyChange(MediaPlayerService.this, song, playerState == PlayerState.STARTED, false);
|
UltrasonicAppWidgetProvider4X4.getInstance().notifyChange(MediaPlayerService.this, song, playerState == PlayerState.STARTED, false);
|
||||||
|
|
||||||
SubsonicTabActivity tabInstance = SubsonicTabActivity.getInstance();
|
|
||||||
|
|
||||||
if (currentPlaying != null)
|
if (currentPlaying != null)
|
||||||
{
|
{
|
||||||
updateNotification(localMediaPlayer.playerState, currentPlaying);
|
updateNotification(localMediaPlayer.playerState, currentPlaying);
|
||||||
if (tabInstance != null) {
|
nowPlayingEventDistributor.getValue().RaiseShowNowPlayingEvent();
|
||||||
tabInstance.showNowPlaying();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (tabInstance != null)
|
nowPlayingEventDistributor.getValue().RaiseHideNowPlayingEvent();
|
||||||
{
|
|
||||||
tabInstance.hideNowPlaying();
|
|
||||||
}
|
|
||||||
stopForeground(true);
|
stopForeground(true);
|
||||||
localMediaPlayer.clearRemoteControl();
|
localMediaPlayer.clearRemoteControl();
|
||||||
isInForeground = false;
|
isInForeground = false;
|
||||||
|
@ -499,7 +494,6 @@ public class MediaPlayerService extends Service
|
||||||
UltrasonicAppWidgetProvider4X2.getInstance().notifyChange(MediaPlayerService.this, song, playerState == PlayerState.STARTED, true);
|
UltrasonicAppWidgetProvider4X2.getInstance().notifyChange(MediaPlayerService.this, song, playerState == PlayerState.STARTED, true);
|
||||||
UltrasonicAppWidgetProvider4X3.getInstance().notifyChange(MediaPlayerService.this, song, playerState == PlayerState.STARTED, false);
|
UltrasonicAppWidgetProvider4X3.getInstance().notifyChange(MediaPlayerService.this, song, playerState == PlayerState.STARTED, false);
|
||||||
UltrasonicAppWidgetProvider4X4.getInstance().notifyChange(MediaPlayerService.this, song, playerState == PlayerState.STARTED, false);
|
UltrasonicAppWidgetProvider4X4.getInstance().notifyChange(MediaPlayerService.this, song, playerState == PlayerState.STARTED, false);
|
||||||
SubsonicTabActivity tabInstance = SubsonicTabActivity.getInstance();
|
|
||||||
|
|
||||||
if (show)
|
if (show)
|
||||||
{
|
{
|
||||||
|
@ -507,18 +501,12 @@ public class MediaPlayerService extends Service
|
||||||
if (playerState == PlayerState.STARTED || playerState == PlayerState.PAUSED)
|
if (playerState == PlayerState.STARTED || playerState == PlayerState.PAUSED)
|
||||||
{
|
{
|
||||||
updateNotification(playerState, currentPlaying);
|
updateNotification(playerState, currentPlaying);
|
||||||
if (tabInstance != null)
|
nowPlayingEventDistributor.getValue().RaiseShowNowPlayingEvent();
|
||||||
{
|
|
||||||
tabInstance.showNowPlaying();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (tabInstance != null)
|
nowPlayingEventDistributor.getValue().RaiseHideNowPlayingEvent();
|
||||||
{
|
|
||||||
tabInstance.hideNowPlaying();
|
|
||||||
}
|
|
||||||
stopForeground(true);
|
stopForeground(true);
|
||||||
localMediaPlayer.clearRemoteControl();
|
localMediaPlayer.clearRemoteControl();
|
||||||
isInForeground = false;
|
isInForeground = false;
|
||||||
|
|
|
@ -10,18 +10,9 @@ import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||||
*/
|
*/
|
||||||
public abstract class TabActivityBackgroundTask<T> extends BackgroundTask<T>
|
public abstract class TabActivityBackgroundTask<T> extends BackgroundTask<T>
|
||||||
{
|
{
|
||||||
|
|
||||||
private final boolean changeProgress;
|
private final boolean changeProgress;
|
||||||
private final SwipeRefreshLayout swipe;
|
private final SwipeRefreshLayout swipe;
|
||||||
private CancellationToken cancel;
|
private final CancellationToken cancel;
|
||||||
|
|
||||||
// TODO: Try to remove this constructor
|
|
||||||
public TabActivityBackgroundTask(Activity activity, boolean changeProgress)
|
|
||||||
{
|
|
||||||
super(activity);
|
|
||||||
this.changeProgress = changeProgress;
|
|
||||||
this.swipe = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TabActivityBackgroundTask(Activity activity, boolean changeProgress,
|
public TabActivityBackgroundTask(Activity activity, boolean changeProgress,
|
||||||
SwipeRefreshLayout swipe, CancellationToken cancel)
|
SwipeRefreshLayout swipe, CancellationToken cancel)
|
||||||
|
|
|
@ -12,9 +12,11 @@ import android.provider.SearchRecentSuggestions
|
||||||
import android.view.KeyEvent
|
import android.view.KeyEvent
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
|
import android.view.View
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.appcompat.widget.Toolbar
|
import androidx.appcompat.widget.Toolbar
|
||||||
import androidx.drawerlayout.widget.DrawerLayout
|
import androidx.drawerlayout.widget.DrawerLayout
|
||||||
|
import androidx.fragment.app.FragmentContainerView
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import androidx.navigation.findNavController
|
import androidx.navigation.findNavController
|
||||||
import androidx.navigation.fragment.NavHostFragment
|
import androidx.navigation.fragment.NavHostFragment
|
||||||
|
@ -28,12 +30,16 @@ import org.koin.android.ext.android.inject
|
||||||
import org.koin.android.viewmodel.ext.android.viewModel
|
import org.koin.android.viewmodel.ext.android.viewModel
|
||||||
import org.moire.ultrasonic.R
|
import org.moire.ultrasonic.R
|
||||||
import org.moire.ultrasonic.data.ActiveServerProvider.Companion.isOffline
|
import org.moire.ultrasonic.data.ActiveServerProvider.Companion.isOffline
|
||||||
|
import org.moire.ultrasonic.domain.PlayerState
|
||||||
import org.moire.ultrasonic.provider.SearchSuggestionProvider
|
import org.moire.ultrasonic.provider.SearchSuggestionProvider
|
||||||
|
import org.moire.ultrasonic.service.DownloadFile
|
||||||
import org.moire.ultrasonic.service.MediaPlayerController
|
import org.moire.ultrasonic.service.MediaPlayerController
|
||||||
import org.moire.ultrasonic.service.MediaPlayerLifecycleSupport
|
import org.moire.ultrasonic.service.MediaPlayerLifecycleSupport
|
||||||
import org.moire.ultrasonic.subsonic.ImageLoaderProvider
|
import org.moire.ultrasonic.subsonic.ImageLoaderProvider
|
||||||
import org.moire.ultrasonic.util.Constants
|
import org.moire.ultrasonic.util.Constants
|
||||||
import org.moire.ultrasonic.util.FileUtil
|
import org.moire.ultrasonic.util.FileUtil
|
||||||
|
import org.moire.ultrasonic.util.NowPlayingEventDistributor
|
||||||
|
import org.moire.ultrasonic.util.NowPlayingEventListener
|
||||||
import org.moire.ultrasonic.util.SubsonicUncaughtExceptionHandler
|
import org.moire.ultrasonic.util.SubsonicUncaughtExceptionHandler
|
||||||
import org.moire.ultrasonic.util.Util
|
import org.moire.ultrasonic.util.Util
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
@ -47,14 +53,20 @@ class NavigationActivity : AppCompatActivity() {
|
||||||
var bookmarksMenuItem: MenuItem? = null
|
var bookmarksMenuItem: MenuItem? = null
|
||||||
var sharesMenuItem: MenuItem? = null
|
var sharesMenuItem: MenuItem? = null
|
||||||
private var theme: String? = null
|
private var theme: String? = null
|
||||||
|
var nowPlayingView: FragmentContainerView? = null
|
||||||
|
var nowPlayingHidden = false
|
||||||
|
|
||||||
private lateinit var appBarConfiguration : AppBarConfiguration
|
private lateinit var appBarConfiguration : AppBarConfiguration
|
||||||
|
private lateinit var nowPlayingEventListener : NowPlayingEventListener
|
||||||
|
|
||||||
private val serverSettingsModel: ServerSettingsModel by viewModel()
|
private val serverSettingsModel: ServerSettingsModel by viewModel()
|
||||||
private val lifecycleSupport: MediaPlayerLifecycleSupport by inject()
|
private val lifecycleSupport: MediaPlayerLifecycleSupport by inject()
|
||||||
private val mediaPlayerController: MediaPlayerController by inject()
|
private val mediaPlayerController: MediaPlayerController by inject()
|
||||||
private val imageLoaderProvider: ImageLoaderProvider by inject()
|
private val imageLoaderProvider: ImageLoaderProvider by inject()
|
||||||
|
private val nowPlayingEventDistributor: NowPlayingEventDistributor by inject()
|
||||||
|
|
||||||
private var infoDialogDisplayed = false
|
private var infoDialogDisplayed = false
|
||||||
|
private var currentFragmentId: Int = 0
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
setUncaughtExceptionHandler()
|
setUncaughtExceptionHandler()
|
||||||
|
@ -64,6 +76,7 @@ class NavigationActivity : AppCompatActivity() {
|
||||||
|
|
||||||
volumeControlStream = AudioManager.STREAM_MUSIC
|
volumeControlStream = AudioManager.STREAM_MUSIC
|
||||||
setContentView(R.layout.navigation_activity)
|
setContentView(R.layout.navigation_activity)
|
||||||
|
nowPlayingView = findViewById(R.id.now_playing_fragment)
|
||||||
|
|
||||||
val toolbar = findViewById<Toolbar>(R.id.toolbar)
|
val toolbar = findViewById<Toolbar>(R.id.toolbar)
|
||||||
setSupportActionBar(toolbar)
|
setSupportActionBar(toolbar)
|
||||||
|
@ -93,7 +106,15 @@ class NavigationActivity : AppCompatActivity() {
|
||||||
}
|
}
|
||||||
Timber.d("Navigated to $dest")
|
Timber.d("Navigated to $dest")
|
||||||
|
|
||||||
// TODO: Maybe we can find a better place for theme change. Currently the change occures when navigating between fragments
|
currentFragmentId = destination.id
|
||||||
|
// Handle the hiding of the NowPlaying fragment when the Player is active
|
||||||
|
if (currentFragmentId == R.id.playerFragment) {
|
||||||
|
hideNowPlaying()
|
||||||
|
} else {
|
||||||
|
showNowPlaying()
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Maybe we can find a better place for theme change. Currently the change occurs when navigating between fragments
|
||||||
// but theoretically Settings could request a Navigation Activity recreate instantly when the theme setting changes
|
// but theoretically Settings could request a Navigation Activity recreate instantly when the theme setting changes
|
||||||
// Make sure to update theme if it has changed
|
// Make sure to update theme if it has changed
|
||||||
if (theme == null) theme = Util.getTheme(this)
|
if (theme == null) theme = Util.getTheme(this)
|
||||||
|
@ -112,6 +133,24 @@ class NavigationActivity : AppCompatActivity() {
|
||||||
|
|
||||||
loadSettings()
|
loadSettings()
|
||||||
showInfoDialog(showWelcomeScreen)
|
showInfoDialog(showWelcomeScreen)
|
||||||
|
|
||||||
|
nowPlayingEventListener = object : NowPlayingEventListener {
|
||||||
|
override fun onDismissNowPlaying() {
|
||||||
|
// TODO: When will it be set back to false?
|
||||||
|
nowPlayingHidden = true;
|
||||||
|
hideNowPlaying();
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onHideNowPlaying() {
|
||||||
|
hideNowPlaying()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onShowNowPlaying() {
|
||||||
|
showNowPlaying()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nowPlayingEventDistributor.subscribe(nowPlayingEventListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
|
@ -125,19 +164,16 @@ class NavigationActivity : AppCompatActivity() {
|
||||||
// Lifecycle support's constructor registers some event receivers so it should be created early
|
// Lifecycle support's constructor registers some event receivers so it should be created early
|
||||||
lifecycleSupport.onCreate()
|
lifecycleSupport.onCreate()
|
||||||
|
|
||||||
// TODO: Implement NowPlaying as a Fragment
|
if (!nowPlayingHidden) {
|
||||||
// This must be filled here because onCreate is called before the derived objects would call setContentView
|
showNowPlaying()
|
||||||
//getNowPlayingView()
|
|
||||||
|
|
||||||
if (!SubsonicTabActivity.nowPlayingHidden) {
|
|
||||||
//showNowPlaying()
|
|
||||||
} else {
|
} else {
|
||||||
//hideNowPlaying()
|
hideNowPlaying()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
Util.unregisterMediaButtonEventReceiver(this, false)
|
Util.unregisterMediaButtonEventReceiver(this, false)
|
||||||
|
nowPlayingEventDistributor.unsubscribe(nowPlayingEventListener)
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
|
|
||||||
// TODO: Handle NowPlaying if necessary
|
// TODO: Handle NowPlaying if necessary
|
||||||
|
@ -259,4 +295,34 @@ class NavigationActivity : AppCompatActivity() {
|
||||||
Thread.setDefaultUncaughtExceptionHandler(SubsonicUncaughtExceptionHandler(this))
|
Thread.setDefaultUncaughtExceptionHandler(SubsonicUncaughtExceptionHandler(this))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun showNowPlaying() {
|
||||||
|
if (!Util.getShowNowPlayingPreference(this) || nowPlayingHidden) {
|
||||||
|
hideNowPlaying()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do not show for Player fragment
|
||||||
|
if (currentFragmentId == R.id.playerFragment) {
|
||||||
|
hideNowPlaying()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nowPlayingView != null) {
|
||||||
|
val playerState: PlayerState = mediaPlayerController.playerState
|
||||||
|
if (playerState == PlayerState.PAUSED || playerState == PlayerState.STARTED) {
|
||||||
|
val file: DownloadFile? = mediaPlayerController.currentPlaying
|
||||||
|
if (file != null) {
|
||||||
|
val song = file.song
|
||||||
|
nowPlayingView?.visibility = View.VISIBLE
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
hideNowPlaying()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun hideNowPlaying() {
|
||||||
|
nowPlayingView?.visibility = View.GONE
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,10 +7,12 @@ import org.moire.ultrasonic.cache.AndroidDirectories
|
||||||
import org.moire.ultrasonic.cache.Directories
|
import org.moire.ultrasonic.cache.Directories
|
||||||
import org.moire.ultrasonic.data.ActiveServerProvider
|
import org.moire.ultrasonic.data.ActiveServerProvider
|
||||||
import org.moire.ultrasonic.subsonic.ImageLoaderProvider
|
import org.moire.ultrasonic.subsonic.ImageLoaderProvider
|
||||||
|
import org.moire.ultrasonic.util.NowPlayingEventDistributor
|
||||||
import org.moire.ultrasonic.util.PermissionUtil
|
import org.moire.ultrasonic.util.PermissionUtil
|
||||||
|
|
||||||
val applicationModule = module {
|
val applicationModule = module {
|
||||||
single { ActiveServerProvider(get(), androidContext()) }
|
single { ActiveServerProvider(get(), androidContext()) }
|
||||||
single { ImageLoaderProvider(androidContext()) }
|
single { ImageLoaderProvider(androidContext()) }
|
||||||
single { PermissionUtil(androidContext()) }
|
single { PermissionUtil(androidContext()) }
|
||||||
|
single { NowPlayingEventDistributor() }
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
package org.moire.ultrasonic.util
|
||||||
|
|
||||||
|
class NowPlayingEventDistributor {
|
||||||
|
var eventListenerList: MutableList<NowPlayingEventListener> = listOf<NowPlayingEventListener>().toMutableList()
|
||||||
|
|
||||||
|
fun subscribe(listener: NowPlayingEventListener) {
|
||||||
|
eventListenerList.add(listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun unsubscribe(listener: NowPlayingEventListener) {
|
||||||
|
eventListenerList.remove(listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun RaiseShowNowPlayingEvent() {
|
||||||
|
eventListenerList.forEach{ listener -> listener.onShowNowPlaying() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun RaiseHideNowPlayingEvent() {
|
||||||
|
eventListenerList.forEach{ listener -> listener.onHideNowPlaying() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun RaiseNowPlayingDismissedEvent() {
|
||||||
|
eventListenerList.forEach{ listener -> listener.onDismissNowPlaying() }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package org.moire.ultrasonic.util
|
||||||
|
|
||||||
|
interface NowPlayingEventListener {
|
||||||
|
fun onDismissNowPlaying()
|
||||||
|
fun onHideNowPlaying()
|
||||||
|
fun onShowNowPlaying()
|
||||||
|
}
|
|
@ -46,6 +46,4 @@
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<include layout="@layout/now_playing" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
|
@ -60,7 +60,5 @@
|
||||||
</androidx.core.widget.NestedScrollView>
|
</androidx.core.widget.NestedScrollView>
|
||||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||||
|
|
||||||
<include layout="@layout/now_playing"/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,4 @@
|
||||||
a:layout_width="0dp"
|
a:layout_width="0dp"
|
||||||
a:layout_height="0dp" />
|
a:layout_height="0dp" />
|
||||||
|
|
||||||
<include layout="@layout/now_playing" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
|
@ -8,7 +8,7 @@
|
||||||
a:layout_height="match_parent"
|
a:layout_height="match_parent"
|
||||||
tools:context="org.moire.ultrasonic.activity.NavigationActivity">
|
tools:context="org.moire.ultrasonic.activity.NavigationActivity">
|
||||||
|
|
||||||
<LinearLayout
|
<RelativeLayout
|
||||||
a:layout_width="match_parent"
|
a:layout_width="match_parent"
|
||||||
a:layout_height="match_parent"
|
a:layout_height="match_parent"
|
||||||
a:orientation="vertical">
|
a:orientation="vertical">
|
||||||
|
@ -18,14 +18,25 @@
|
||||||
a:layout_width="match_parent"
|
a:layout_width="match_parent"
|
||||||
a:layout_height="wrap_content" />
|
a:layout_height="wrap_content" />
|
||||||
|
|
||||||
<fragment
|
<androidx.fragment.app.FragmentContainerView
|
||||||
a:id="@+id/nav_host_fragment"
|
a:id="@+id/nav_host_fragment"
|
||||||
a:name="androidx.navigation.fragment.NavHostFragment"
|
a:name="androidx.navigation.fragment.NavHostFragment"
|
||||||
a:layout_width="match_parent"
|
a:layout_width="match_parent"
|
||||||
a:layout_height="match_parent"
|
a:layout_height="match_parent"
|
||||||
|
a:layout_above="@+id/now_playing_fragment"
|
||||||
|
a:layout_below="@+id/toolbar"
|
||||||
app:defaultNavHost="true"
|
app:defaultNavHost="true"
|
||||||
app:navGraph="@navigation/navigation_graph" />
|
app:navGraph="@navigation/navigation_graph" />
|
||||||
</LinearLayout>
|
|
||||||
|
<androidx.fragment.app.FragmentContainerView
|
||||||
|
a:id="@+id/now_playing_fragment"
|
||||||
|
a:name="org.moire.ultrasonic.fragment.NowPlayingFragment"
|
||||||
|
a:layout_width="match_parent"
|
||||||
|
a:layout_height="wrap_content"
|
||||||
|
a:layout_alignParentBottom="true"
|
||||||
|
app:defaultNavHost="true"
|
||||||
|
app:navGraph="@navigation/navigation_graph" />
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
<com.google.android.material.navigation.NavigationView
|
<com.google.android.material.navigation.NavigationView
|
||||||
a:id="@+id/nav_view"
|
a:id="@+id/nav_view"
|
||||||
|
|
|
@ -3,8 +3,7 @@
|
||||||
android:id="@+id/now_playing"
|
android:id="@+id/now_playing"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical" >
|
||||||
android:visibility="gone" >
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_height="4dip"
|
android:layout_height="4dip"
|
||||||
|
|
|
@ -22,6 +22,4 @@
|
||||||
a:fastScrollEnabled="true"
|
a:fastScrollEnabled="true"
|
||||||
a:textFilterEnabled="true" />
|
a:textFilterEnabled="true" />
|
||||||
|
|
||||||
<include layout="@layout/now_playing" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
|
@ -18,6 +18,4 @@
|
||||||
|
|
||||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||||
|
|
||||||
<include layout="@layout/now_playing" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
|
@ -33,6 +33,4 @@
|
||||||
|
|
||||||
<include layout="@layout/album_buttons" />
|
<include layout="@layout/album_buttons" />
|
||||||
|
|
||||||
<include layout="@layout/now_playing" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
|
@ -32,6 +32,4 @@
|
||||||
|
|
||||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||||
|
|
||||||
<include layout="@layout/now_playing" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
|
@ -28,6 +28,4 @@
|
||||||
|
|
||||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||||
|
|
||||||
<include layout="@layout/now_playing" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
|
@ -28,6 +28,4 @@
|
||||||
|
|
||||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||||
|
|
||||||
<include layout="@layout/now_playing" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
|
@ -29,6 +29,4 @@
|
||||||
|
|
||||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||||
|
|
||||||
<include layout="@layout/now_playing" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
Loading…
Reference in New Issue