mirror of
https://gitlab.com/ultrasonic/ultrasonic.git
synced 2025-04-25 13:12:16 +03:00
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 int DIALOG_ASK_FOR_SHARE_DETAILS = 102;
|
||||
|
||||
private Lazy<MediaPlayerController> mediaPlayerControllerLazy = inject(MediaPlayerController.class);
|
||||
private Lazy<MediaPlayerLifecycleSupport> lifecycleSupport = inject(MediaPlayerLifecycleSupport.class);
|
||||
private final Lazy<MediaPlayerController> mediaPlayerControllerLazy = inject(MediaPlayerController.class);
|
||||
private final Lazy<MediaPlayerLifecycleSupport> lifecycleSupport = inject(MediaPlayerLifecycleSupport.class);
|
||||
protected Lazy<ImageLoaderProvider> imageLoader = inject(ImageLoaderProvider.class);
|
||||
|
||||
public MenuDrawer menuDrawer;
|
||||
@ -118,7 +118,7 @@ public class SubsonicTabActivity extends ResultActivity
|
||||
bookmarksMenuItem = findViewById(R.id.menu_bookmarks);
|
||||
sharesMenuItem = findViewById(R.id.menu_shares);
|
||||
|
||||
setActionBarDisplayHomeAsUp(true);
|
||||
//setActionBarDisplayHomeAsUp(true);
|
||||
|
||||
TextView activeView = (TextView) findViewById(menuActiveViewId);
|
||||
|
||||
@ -163,11 +163,11 @@ public class SubsonicTabActivity extends ResultActivity
|
||||
|
||||
if (!nowPlayingHidden)
|
||||
{
|
||||
showNowPlaying();
|
||||
//showNowPlaying();
|
||||
}
|
||||
else
|
||||
{
|
||||
hideNowPlaying();
|
||||
//hideNowPlaying();
|
||||
}
|
||||
}
|
||||
|
||||
@ -194,23 +194,6 @@ public class SubsonicTabActivity extends ResultActivity
|
||||
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()
|
||||
{
|
||||
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()
|
||||
{
|
||||
return instance;
|
||||
}
|
||||
|
||||
public MediaPlayerController getMediaPlayerController()
|
||||
{
|
||||
return mediaPlayerControllerLazy.getValue();
|
||||
}
|
||||
|
||||
protected void setActionBarDisplayHomeAsUp(boolean enabled)
|
||||
{
|
||||
ActionBar actionBar = getSupportActionBar();
|
||||
|
||||
if (actionBar != null)
|
||||
{
|
||||
actionBar.setDisplayHomeAsUpEnabled(enabled);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRestoreInstanceState(Bundle inState)
|
||||
@ -527,87 +251,5 @@ public class SubsonicTabActivity extends ResultActivity
|
||||
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.MusicServiceFactory;
|
||||
import org.moire.ultrasonic.util.BackgroundTask;
|
||||
import org.moire.ultrasonic.util.CancellationToken;
|
||||
import org.moire.ultrasonic.util.TabActivityBackgroundTask;
|
||||
import org.moire.ultrasonic.util.Util;
|
||||
import org.moire.ultrasonic.view.ChatAdapter;
|
||||
@ -50,6 +51,7 @@ public class ChatFragment extends Fragment {
|
||||
private Timer timer;
|
||||
private volatile static Long lastChatMessageTime = (long) 0;
|
||||
private static final ArrayList<ChatMessage> messageList = new ArrayList<ChatMessage>();
|
||||
private CancellationToken cancellationToken;
|
||||
|
||||
private final Lazy<ActiveServerProvider> activeServerProvider = inject(ActiveServerProvider.class);
|
||||
|
||||
@ -67,6 +69,8 @@ public class ChatFragment extends Fragment {
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
cancellationToken = new CancellationToken();
|
||||
messageEditText = view.findViewById(R.id.chat_edittext);
|
||||
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()
|
||||
{
|
||||
int refreshInterval = Util.getChatRefreshInterval(getContext());
|
||||
@ -228,7 +238,7 @@ public class ChatFragment extends Fragment {
|
||||
{
|
||||
messageEditText.setText("");
|
||||
|
||||
BackgroundTask<Void> task = new TabActivityBackgroundTask<Void>(getActivity(), false)
|
||||
BackgroundTask<Void> task = new TabActivityBackgroundTask<Void>(getActivity(), false, null, cancellationToken)
|
||||
{
|
||||
@Override
|
||||
protected Void doInBackground() throws Throwable
|
||||
@ -252,7 +262,7 @@ public class ChatFragment extends Fragment {
|
||||
|
||||
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
|
||||
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
|
||||
protected void done(final Void result)
|
||||
{
|
||||
if (cancellationToken.isCancellationRequested()) return;
|
||||
if (currentPlaying != null)
|
||||
{
|
||||
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.MusicServiceFactory;
|
||||
import org.moire.ultrasonic.util.BackgroundTask;
|
||||
import org.moire.ultrasonic.util.CancellationToken;
|
||||
import org.moire.ultrasonic.util.Constants;
|
||||
import org.moire.ultrasonic.util.TabActivityBackgroundTask;
|
||||
import org.moire.ultrasonic.util.Util;
|
||||
@ -28,6 +29,7 @@ public class PodcastFragment extends Fragment {
|
||||
|
||||
private View emptyTextView;
|
||||
ListView channelItemsListView = null;
|
||||
private CancellationToken cancellationToken;
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
@ -43,6 +45,8 @@ public class PodcastFragment extends Fragment {
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
cancellationToken = new CancellationToken();
|
||||
FragmentTitle.Companion.setTitle(this, R.string.podcasts_label);
|
||||
|
||||
emptyTextView = view.findViewById(R.id.select_podcasts_empty);
|
||||
@ -65,9 +69,15 @@ public class PodcastFragment extends Fragment {
|
||||
load();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
cancellationToken.cancel();
|
||||
super.onDestroyView();
|
||||
}
|
||||
|
||||
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
|
||||
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.UltrasonicAppWidgetProvider4X4;
|
||||
import org.moire.ultrasonic.util.FileUtil;
|
||||
import org.moire.ultrasonic.util.NowPlayingEventDistributor;
|
||||
import org.moire.ultrasonic.util.ShufflePlayBuffer;
|
||||
import org.moire.ultrasonic.util.SimpleServiceBinder;
|
||||
import org.moire.ultrasonic.util.Util;
|
||||
@ -64,10 +65,11 @@ public class MediaPlayerService extends Service
|
||||
private final Scrobbler scrobbler = new Scrobbler();
|
||||
|
||||
public Lazy<JukeboxMediaPlayer> jukeboxMediaPlayer = inject(JukeboxMediaPlayer.class);
|
||||
private Lazy<DownloadQueueSerializer> downloadQueueSerializerLazy = inject(DownloadQueueSerializer.class);
|
||||
private Lazy<ShufflePlayBuffer> shufflePlayBufferLazy = inject(ShufflePlayBuffer.class);
|
||||
private Lazy<Downloader> downloaderLazy = inject(Downloader.class);
|
||||
private Lazy<LocalMediaPlayer> localMediaPlayerLazy = inject(LocalMediaPlayer.class);
|
||||
private final Lazy<DownloadQueueSerializer> downloadQueueSerializerLazy = inject(DownloadQueueSerializer.class);
|
||||
private final Lazy<ShufflePlayBuffer> shufflePlayBufferLazy = inject(ShufflePlayBuffer.class);
|
||||
private final Lazy<Downloader> downloaderLazy = inject(Downloader.class);
|
||||
private final Lazy<LocalMediaPlayer> localMediaPlayerLazy = inject(LocalMediaPlayer.class);
|
||||
private final Lazy<NowPlayingEventDistributor> nowPlayingEventDistributor = inject(NowPlayingEventDistributor.class);
|
||||
private LocalMediaPlayer localMediaPlayer;
|
||||
private Downloader downloader;
|
||||
private ShufflePlayBuffer shufflePlayBuffer;
|
||||
@ -280,21 +282,14 @@ public class MediaPlayerService extends Service
|
||||
UltrasonicAppWidgetProvider4X3.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)
|
||||
{
|
||||
updateNotification(localMediaPlayer.playerState, currentPlaying);
|
||||
if (tabInstance != null) {
|
||||
tabInstance.showNowPlaying();
|
||||
}
|
||||
nowPlayingEventDistributor.getValue().RaiseShowNowPlayingEvent();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tabInstance != null)
|
||||
{
|
||||
tabInstance.hideNowPlaying();
|
||||
}
|
||||
nowPlayingEventDistributor.getValue().RaiseHideNowPlayingEvent();
|
||||
stopForeground(true);
|
||||
localMediaPlayer.clearRemoteControl();
|
||||
isInForeground = false;
|
||||
@ -499,7 +494,6 @@ public class MediaPlayerService extends Service
|
||||
UltrasonicAppWidgetProvider4X2.getInstance().notifyChange(MediaPlayerService.this, song, playerState == PlayerState.STARTED, true);
|
||||
UltrasonicAppWidgetProvider4X3.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)
|
||||
{
|
||||
@ -507,18 +501,12 @@ public class MediaPlayerService extends Service
|
||||
if (playerState == PlayerState.STARTED || playerState == PlayerState.PAUSED)
|
||||
{
|
||||
updateNotification(playerState, currentPlaying);
|
||||
if (tabInstance != null)
|
||||
{
|
||||
tabInstance.showNowPlaying();
|
||||
}
|
||||
nowPlayingEventDistributor.getValue().RaiseShowNowPlayingEvent();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tabInstance != null)
|
||||
{
|
||||
tabInstance.hideNowPlaying();
|
||||
}
|
||||
nowPlayingEventDistributor.getValue().RaiseHideNowPlayingEvent();
|
||||
stopForeground(true);
|
||||
localMediaPlayer.clearRemoteControl();
|
||||
isInForeground = false;
|
||||
|
@ -10,18 +10,9 @@ import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||
*/
|
||||
public abstract class TabActivityBackgroundTask<T> extends BackgroundTask<T>
|
||||
{
|
||||
|
||||
private final boolean changeProgress;
|
||||
private final SwipeRefreshLayout swipe;
|
||||
private CancellationToken cancel;
|
||||
|
||||
// TODO: Try to remove this constructor
|
||||
public TabActivityBackgroundTask(Activity activity, boolean changeProgress)
|
||||
{
|
||||
super(activity);
|
||||
this.changeProgress = changeProgress;
|
||||
this.swipe = null;
|
||||
}
|
||||
private final CancellationToken cancel;
|
||||
|
||||
public TabActivityBackgroundTask(Activity activity, boolean changeProgress,
|
||||
SwipeRefreshLayout swipe, CancellationToken cancel)
|
||||
|
@ -12,9 +12,11 @@ import android.provider.SearchRecentSuggestions
|
||||
import android.view.KeyEvent
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.drawerlayout.widget.DrawerLayout
|
||||
import androidx.fragment.app.FragmentContainerView
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.findNavController
|
||||
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.moire.ultrasonic.R
|
||||
import org.moire.ultrasonic.data.ActiveServerProvider.Companion.isOffline
|
||||
import org.moire.ultrasonic.domain.PlayerState
|
||||
import org.moire.ultrasonic.provider.SearchSuggestionProvider
|
||||
import org.moire.ultrasonic.service.DownloadFile
|
||||
import org.moire.ultrasonic.service.MediaPlayerController
|
||||
import org.moire.ultrasonic.service.MediaPlayerLifecycleSupport
|
||||
import org.moire.ultrasonic.subsonic.ImageLoaderProvider
|
||||
import org.moire.ultrasonic.util.Constants
|
||||
import org.moire.ultrasonic.util.FileUtil
|
||||
import org.moire.ultrasonic.util.NowPlayingEventDistributor
|
||||
import org.moire.ultrasonic.util.NowPlayingEventListener
|
||||
import org.moire.ultrasonic.util.SubsonicUncaughtExceptionHandler
|
||||
import org.moire.ultrasonic.util.Util
|
||||
import timber.log.Timber
|
||||
@ -47,14 +53,20 @@ class NavigationActivity : AppCompatActivity() {
|
||||
var bookmarksMenuItem: MenuItem? = null
|
||||
var sharesMenuItem: MenuItem? = null
|
||||
private var theme: String? = null
|
||||
var nowPlayingView: FragmentContainerView? = null
|
||||
var nowPlayingHidden = false
|
||||
|
||||
private lateinit var appBarConfiguration : AppBarConfiguration
|
||||
private lateinit var nowPlayingEventListener : NowPlayingEventListener
|
||||
|
||||
private val serverSettingsModel: ServerSettingsModel by viewModel()
|
||||
private val lifecycleSupport: MediaPlayerLifecycleSupport by inject()
|
||||
private val mediaPlayerController: MediaPlayerController by inject()
|
||||
private val imageLoaderProvider: ImageLoaderProvider by inject()
|
||||
private val nowPlayingEventDistributor: NowPlayingEventDistributor by inject()
|
||||
|
||||
private var infoDialogDisplayed = false
|
||||
private var currentFragmentId: Int = 0
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
setUncaughtExceptionHandler()
|
||||
@ -64,6 +76,7 @@ class NavigationActivity : AppCompatActivity() {
|
||||
|
||||
volumeControlStream = AudioManager.STREAM_MUSIC
|
||||
setContentView(R.layout.navigation_activity)
|
||||
nowPlayingView = findViewById(R.id.now_playing_fragment)
|
||||
|
||||
val toolbar = findViewById<Toolbar>(R.id.toolbar)
|
||||
setSupportActionBar(toolbar)
|
||||
@ -93,7 +106,15 @@ class NavigationActivity : AppCompatActivity() {
|
||||
}
|
||||
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
|
||||
// Make sure to update theme if it has changed
|
||||
if (theme == null) theme = Util.getTheme(this)
|
||||
@ -112,6 +133,24 @@ class NavigationActivity : AppCompatActivity() {
|
||||
|
||||
loadSettings()
|
||||
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() {
|
||||
@ -125,19 +164,16 @@ class NavigationActivity : AppCompatActivity() {
|
||||
// Lifecycle support's constructor registers some event receivers so it should be created early
|
||||
lifecycleSupport.onCreate()
|
||||
|
||||
// TODO: Implement NowPlaying as a Fragment
|
||||
// This must be filled here because onCreate is called before the derived objects would call setContentView
|
||||
//getNowPlayingView()
|
||||
|
||||
if (!SubsonicTabActivity.nowPlayingHidden) {
|
||||
//showNowPlaying()
|
||||
if (!nowPlayingHidden) {
|
||||
showNowPlaying()
|
||||
} else {
|
||||
//hideNowPlaying()
|
||||
hideNowPlaying()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
Util.unregisterMediaButtonEventReceiver(this, false)
|
||||
nowPlayingEventDistributor.unsubscribe(nowPlayingEventListener)
|
||||
super.onDestroy()
|
||||
|
||||
// TODO: Handle NowPlaying if necessary
|
||||
@ -259,4 +295,34 @@ class NavigationActivity : AppCompatActivity() {
|
||||
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.data.ActiveServerProvider
|
||||
import org.moire.ultrasonic.subsonic.ImageLoaderProvider
|
||||
import org.moire.ultrasonic.util.NowPlayingEventDistributor
|
||||
import org.moire.ultrasonic.util.PermissionUtil
|
||||
|
||||
val applicationModule = module {
|
||||
single { ActiveServerProvider(get(), androidContext()) }
|
||||
single { ImageLoaderProvider(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>
|
||||
|
||||
<include layout="@layout/now_playing" />
|
||||
|
||||
</LinearLayout>
|
||||
|
@ -60,7 +60,5 @@
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||
|
||||
<include layout="@layout/now_playing"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
@ -15,6 +15,4 @@
|
||||
a:layout_width="0dp"
|
||||
a:layout_height="0dp" />
|
||||
|
||||
<include layout="@layout/now_playing" />
|
||||
|
||||
</LinearLayout>
|
@ -8,7 +8,7 @@
|
||||
a:layout_height="match_parent"
|
||||
tools:context="org.moire.ultrasonic.activity.NavigationActivity">
|
||||
|
||||
<LinearLayout
|
||||
<RelativeLayout
|
||||
a:layout_width="match_parent"
|
||||
a:layout_height="match_parent"
|
||||
a:orientation="vertical">
|
||||
@ -18,14 +18,25 @@
|
||||
a:layout_width="match_parent"
|
||||
a:layout_height="wrap_content" />
|
||||
|
||||
<fragment
|
||||
<androidx.fragment.app.FragmentContainerView
|
||||
a:id="@+id/nav_host_fragment"
|
||||
a:name="androidx.navigation.fragment.NavHostFragment"
|
||||
a:layout_width="match_parent"
|
||||
a:layout_height="match_parent"
|
||||
a:layout_above="@+id/now_playing_fragment"
|
||||
a:layout_below="@+id/toolbar"
|
||||
app:defaultNavHost="true"
|
||||
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
|
||||
a:id="@+id/nav_view"
|
||||
|
@ -3,8 +3,7 @@
|
||||
android:id="@+id/now_playing"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone" >
|
||||
android:orientation="vertical" >
|
||||
|
||||
<LinearLayout
|
||||
android:layout_height="4dip"
|
||||
|
@ -22,6 +22,4 @@
|
||||
a:fastScrollEnabled="true"
|
||||
a:textFilterEnabled="true" />
|
||||
|
||||
<include layout="@layout/now_playing" />
|
||||
|
||||
</LinearLayout>
|
@ -18,6 +18,4 @@
|
||||
|
||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||
|
||||
<include layout="@layout/now_playing" />
|
||||
|
||||
</LinearLayout>
|
@ -33,6 +33,4 @@
|
||||
|
||||
<include layout="@layout/album_buttons" />
|
||||
|
||||
<include layout="@layout/now_playing" />
|
||||
|
||||
</LinearLayout>
|
||||
|
@ -32,6 +32,4 @@
|
||||
|
||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||
|
||||
<include layout="@layout/now_playing" />
|
||||
|
||||
</LinearLayout>
|
||||
|
@ -28,6 +28,4 @@
|
||||
|
||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||
|
||||
<include layout="@layout/now_playing" />
|
||||
|
||||
</LinearLayout>
|
||||
|
@ -28,6 +28,4 @@
|
||||
|
||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||
|
||||
<include layout="@layout/now_playing" />
|
||||
|
||||
</LinearLayout>
|
||||
|
@ -29,6 +29,4 @@
|
||||
|
||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||
|
||||
<include layout="@layout/now_playing" />
|
||||
|
||||
</LinearLayout>
|
||||
|
Loading…
x
Reference in New Issue
Block a user