Removed sliding panel for now
This commit is contained in:
parent
2af26548ee
commit
636da3daa8
7 changed files with 223 additions and 542 deletions
|
@ -1,49 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020 Hemanth Savarala.
|
|
||||||
*
|
|
||||||
* Licensed under the GNU General Public License v3
|
|
||||||
*
|
|
||||||
* This is free software: you can redistribute it and/or modify it under
|
|
||||||
* the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
||||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
* See the GNU General Public License for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package code.name.monkey.retromusic;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.util.AttributeSet;
|
|
||||||
import android.view.MotionEvent;
|
|
||||||
import android.view.View;
|
|
||||||
import androidx.coordinatorlayout.widget.CoordinatorLayout;
|
|
||||||
import com.google.android.material.bottomsheet.BottomSheetBehavior;
|
|
||||||
|
|
||||||
public class CustomBottomSheetBehavior<V extends View> extends BottomSheetBehavior<V> {
|
|
||||||
|
|
||||||
private static final String TAG = "CustomBottomSheetBehavi";
|
|
||||||
|
|
||||||
private boolean allowDragging = true;
|
|
||||||
|
|
||||||
public CustomBottomSheetBehavior() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public CustomBottomSheetBehavior(Context context, AttributeSet attrs) {
|
|
||||||
super(context, attrs);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onInterceptTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) {
|
|
||||||
if (!allowDragging) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return super.onInterceptTouchEvent(parent, child, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAllowDragging(boolean allowDragging) {
|
|
||||||
this.allowDragging = allowDragging;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,184 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020 Hemanth Savarala.
|
|
||||||
*
|
|
||||||
* Licensed under the GNU General Public License v3
|
|
||||||
*
|
|
||||||
* This is free software: you can redistribute it and/or modify it under
|
|
||||||
* the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
||||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
* See the GNU General Public License for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package code.name.monkey.retromusic;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.util.AttributeSet;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.view.MotionEvent;
|
|
||||||
import android.view.View;
|
|
||||||
import androidx.annotation.IdRes;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.coordinatorlayout.widget.CoordinatorLayout;
|
|
||||||
import com.google.android.material.bottomsheet.BottomSheetBehavior;
|
|
||||||
|
|
||||||
public class MultiSheetView extends CoordinatorLayout {
|
|
||||||
|
|
||||||
@interface Sheet {
|
|
||||||
|
|
||||||
int NONE = 0;
|
|
||||||
int FIRST = 1;
|
|
||||||
int SECOND = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final String TAG = "MultiSheetView";
|
|
||||||
|
|
||||||
private CustomBottomSheetBehavior bottomSheetBehavior1;
|
|
||||||
|
|
||||||
private CustomBottomSheetBehavior bottomSheetBehavior2;
|
|
||||||
|
|
||||||
public MultiSheetView(@NonNull Context context) {
|
|
||||||
this(context, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public MultiSheetView(@NonNull Context context, @Nullable AttributeSet attrs) {
|
|
||||||
this(context, attrs, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public MultiSheetView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
|
||||||
super(context, attrs, defStyleAttr);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean consumeBackPress() {
|
|
||||||
switch (getCurrentSheet()) {
|
|
||||||
case Sheet.SECOND:
|
|
||||||
showSheet(Sheet.FIRST);
|
|
||||||
return true;
|
|
||||||
case Sheet.FIRST:
|
|
||||||
showSheet(Sheet.NONE);
|
|
||||||
return true;
|
|
||||||
case Sheet.NONE:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Sheet
|
|
||||||
public int getCurrentSheet() {
|
|
||||||
if (bottomSheetBehavior2.getState() == BottomSheetBehavior.STATE_EXPANDED) {
|
|
||||||
return Sheet.SECOND;
|
|
||||||
} else if (bottomSheetBehavior1.getState() == BottomSheetBehavior.STATE_EXPANDED) {
|
|
||||||
return Sheet.FIRST;
|
|
||||||
} else {
|
|
||||||
return Sheet.NONE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@IdRes
|
|
||||||
public int getMainContainerResId() {
|
|
||||||
return R.id.mainContentFrame;
|
|
||||||
}
|
|
||||||
|
|
||||||
@IdRes
|
|
||||||
public int getSheet1ContainerResId() {
|
|
||||||
return R.id.playerFragmentContainer;
|
|
||||||
}
|
|
||||||
|
|
||||||
@IdRes
|
|
||||||
public int getSheet1PeekViewResId() {
|
|
||||||
return R.id.miniPlayerFragment;
|
|
||||||
}
|
|
||||||
|
|
||||||
@IdRes
|
|
||||||
public int getSheet2ContainerResId() {
|
|
||||||
return R.id.sheet2Container;
|
|
||||||
}
|
|
||||||
|
|
||||||
@IdRes
|
|
||||||
public int getSheet2PeekViewResId() {
|
|
||||||
return R.id.sheet2PeekView;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void showSheet(@Sheet int sheet) {
|
|
||||||
|
|
||||||
// if we are already at our target panel, then don't do anything
|
|
||||||
if (sheet == getCurrentSheet()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (sheet) {
|
|
||||||
case Sheet.NONE:
|
|
||||||
bottomSheetBehavior2.setState(BottomSheetBehavior.STATE_COLLAPSED);
|
|
||||||
bottomSheetBehavior1.setState(BottomSheetBehavior.STATE_COLLAPSED);
|
|
||||||
break;
|
|
||||||
case Sheet.FIRST:
|
|
||||||
bottomSheetBehavior2.setState(BottomSheetBehavior.STATE_COLLAPSED);
|
|
||||||
bottomSheetBehavior1.setState(BottomSheetBehavior.STATE_EXPANDED);
|
|
||||||
break;
|
|
||||||
case Sheet.SECOND:
|
|
||||||
bottomSheetBehavior2.setState(BottomSheetBehavior.STATE_EXPANDED);
|
|
||||||
bottomSheetBehavior1.setState(BottomSheetBehavior.STATE_EXPANDED);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onFinishInflate() {
|
|
||||||
super.onFinishInflate();
|
|
||||||
|
|
||||||
View sheet1 = findViewById(R.id.slidingPanel);
|
|
||||||
bottomSheetBehavior1 = (CustomBottomSheetBehavior) BottomSheetBehavior.from(sheet1);
|
|
||||||
|
|
||||||
View sheet2 = findViewById(R.id.sheet2);
|
|
||||||
View thump = findViewById(R.id.thumb);
|
|
||||||
View extendedToolbar = findViewById(R.id.extendedToolbar);
|
|
||||||
bottomSheetBehavior2 = (CustomBottomSheetBehavior) BottomSheetBehavior.from(sheet2);
|
|
||||||
bottomSheetBehavior2.addBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
|
|
||||||
@Override
|
|
||||||
public void onSlide(@NonNull View bottomSheet, float slideOffset) {
|
|
||||||
bottomSheetBehavior1.setAllowDragging(false);
|
|
||||||
thump.setRotation(slideOffset * 180);
|
|
||||||
extendedToolbar.setAlpha(slideOffset);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStateChanged(@NonNull View bottomSheet, int newState) {
|
|
||||||
if (newState == BottomSheetBehavior.STATE_EXPANDED
|
|
||||||
|| newState == BottomSheetBehavior.STATE_DRAGGING) {
|
|
||||||
bottomSheetBehavior1.setAllowDragging(false);
|
|
||||||
} else {
|
|
||||||
bottomSheetBehavior1.setAllowDragging(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
//First sheet view click listener
|
|
||||||
findViewById(getSheet1PeekViewResId())
|
|
||||||
.setOnClickListener(v -> bottomSheetBehavior1.setState(BottomSheetBehavior.STATE_EXPANDED));
|
|
||||||
|
|
||||||
// FIXME:
|
|
||||||
// This click listener (combined with a nested RecyclerView in Sheet 2's container), causes
|
|
||||||
// the second peek view to stop responding to drag events.
|
|
||||||
// See `Sheet2Controller`. Remove this ClickListener here to see things working as they should.
|
|
||||||
|
|
||||||
//Second sheet view click listener
|
|
||||||
findViewById(getSheet2PeekViewResId())
|
|
||||||
.setOnClickListener(v -> bottomSheetBehavior2.setState(BottomSheetBehavior.STATE_EXPANDED));
|
|
||||||
|
|
||||||
// FIXED:
|
|
||||||
// issue was bottomSheetBehavior1 is taking drag event when getSheet2PeekView is dragging
|
|
||||||
// so detect touch event getSheet2PeekView set bottomSheetBehavior1 dragging false and bottomSheetBehavior2 true
|
|
||||||
findViewById(getSheet2PeekViewResId()).setOnTouchListener(new OnTouchListener() {
|
|
||||||
@Override
|
|
||||||
public boolean onTouch(View v, MotionEvent event) {
|
|
||||||
Log.e(TAG, "onTouch: ");
|
|
||||||
bottomSheetBehavior1.setAllowDragging(false);
|
|
||||||
bottomSheetBehavior2.setAllowDragging(true);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -9,11 +9,9 @@ import android.view.ViewTreeObserver
|
||||||
import android.widget.FrameLayout
|
import android.widget.FrameLayout
|
||||||
import androidx.annotation.LayoutRes
|
import androidx.annotation.LayoutRes
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
|
||||||
import code.name.monkey.appthemehelper.util.ATHUtil
|
import code.name.monkey.appthemehelper.util.ATHUtil
|
||||||
import code.name.monkey.appthemehelper.util.ColorUtil
|
import code.name.monkey.appthemehelper.util.ColorUtil
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.adapter.song.PlayingQueueAdapter
|
|
||||||
import code.name.monkey.retromusic.extensions.hide
|
import code.name.monkey.retromusic.extensions.hide
|
||||||
import code.name.monkey.retromusic.extensions.show
|
import code.name.monkey.retromusic.extensions.show
|
||||||
import code.name.monkey.retromusic.fragments.MiniPlayerFragment
|
import code.name.monkey.retromusic.fragments.MiniPlayerFragment
|
||||||
|
@ -57,8 +55,6 @@ import code.name.monkey.retromusic.views.BottomNavigationBarTinted
|
||||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||||
import kotlinx.android.synthetic.main.sliding_music_panel_layout.bottomNavigationView
|
import kotlinx.android.synthetic.main.sliding_music_panel_layout.bottomNavigationView
|
||||||
import kotlinx.android.synthetic.main.sliding_music_panel_layout.dimBackground
|
import kotlinx.android.synthetic.main.sliding_music_panel_layout.dimBackground
|
||||||
import kotlinx.android.synthetic.main.sliding_music_panel_layout.mainContent
|
|
||||||
import kotlinx.android.synthetic.main.sliding_music_panel_layout.sheet2Container
|
|
||||||
import kotlinx.android.synthetic.main.sliding_music_panel_layout.slidingPanel
|
import kotlinx.android.synthetic.main.sliding_music_panel_layout.slidingPanel
|
||||||
|
|
||||||
abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity(), AbsPlayerFragment.Callbacks {
|
abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity(), AbsPlayerFragment.Callbacks {
|
||||||
|
@ -75,7 +71,6 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity(), AbsPlay
|
||||||
private var lightStatusBar: Boolean = false
|
private var lightStatusBar: Boolean = false
|
||||||
private var lightNavigationBar: Boolean = false
|
private var lightNavigationBar: Boolean = false
|
||||||
private var navigationBarColorAnimator: ValueAnimator? = null
|
private var navigationBarColorAnimator: ValueAnimator? = null
|
||||||
private lateinit var queueAdapter: PlayingQueueAdapter
|
|
||||||
protected abstract fun createContentView(): View
|
protected abstract fun createContentView(): View
|
||||||
private val panelState: Int
|
private val panelState: Int
|
||||||
get() = bottomSheetBehavior.state
|
get() = bottomSheetBehavior.state
|
||||||
|
@ -117,10 +112,6 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity(), AbsPlay
|
||||||
|
|
||||||
val themeColor = ATHUtil.resolveColor(this, android.R.attr.windowBackground, Color.GRAY)
|
val themeColor = ATHUtil.resolveColor(this, android.R.attr.windowBackground, Color.GRAY)
|
||||||
dimBackground.setBackgroundColor(ColorUtil.withAlpha(themeColor, 0.5f))
|
dimBackground.setBackgroundColor(ColorUtil.withAlpha(themeColor, 0.5f))
|
||||||
|
|
||||||
queueAdapter = PlayingQueueAdapter(this, ArrayList(), MusicPlayerRemote.position, R.layout.item_queue)
|
|
||||||
sheet2Container.adapter = queueAdapter
|
|
||||||
sheet2Container.layoutManager = LinearLayoutManager(this)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
|
@ -279,7 +270,6 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity(), AbsPlay
|
||||||
override fun onGlobalLayout() {
|
override fun onGlobalLayout() {
|
||||||
slidingPanel.viewTreeObserver.removeOnGlobalLayoutListener(this)
|
slidingPanel.viewTreeObserver.removeOnGlobalLayoutListener(this)
|
||||||
hideBottomBar(false)
|
hideBottomBar(false)
|
||||||
queueAdapter.swapDataSet(MusicPlayerRemote.playingQueue, MusicPlayerRemote.position)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} // don't call hideBottomBar(true) here as it causes a bug with the SlidingUpPanelLayout
|
} // don't call hideBottomBar(true) here as it causes a bug with the SlidingUpPanelLayout
|
||||||
|
@ -288,7 +278,6 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity(), AbsPlay
|
||||||
override fun onQueueChanged() {
|
override fun onQueueChanged() {
|
||||||
super.onQueueChanged()
|
super.onQueueChanged()
|
||||||
hideBottomBar(MusicPlayerRemote.playingQueue.isEmpty())
|
hideBottomBar(MusicPlayerRemote.playingQueue.isEmpty())
|
||||||
queueAdapter.swapDataSet(MusicPlayerRemote.playingQueue, MusicPlayerRemote.position)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBackPressed() {
|
override fun onBackPressed() {
|
||||||
|
@ -296,14 +285,11 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity(), AbsPlay
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun handleBackPress(): Boolean {
|
open fun handleBackPress(): Boolean {
|
||||||
/*if (bottomSheetBehavior.peekHeight != 0 && playerFragment!!.onBackPressed()) return true
|
if (bottomSheetBehavior.peekHeight != 0 && playerFragment!!.onBackPressed()) return true
|
||||||
if (panelState == BottomSheetBehavior.STATE_EXPANDED) {
|
if (panelState == BottomSheetBehavior.STATE_EXPANDED) {
|
||||||
collapsePanel()
|
collapsePanel()
|
||||||
return true
|
return true
|
||||||
}*/
|
}
|
||||||
|
|
||||||
if (mainContent.consumeBackPress())
|
|
||||||
return true
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,30 +21,55 @@ import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.fragment.app.FragmentActivity;
|
import androidx.fragment.app.FragmentActivity;
|
||||||
|
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import code.name.monkey.retromusic.R;
|
import code.name.monkey.retromusic.R;
|
||||||
import code.name.monkey.retromusic.activities.saf.SAFGuideActivity;
|
import code.name.monkey.retromusic.activities.saf.SAFGuideActivity;
|
||||||
import code.name.monkey.retromusic.misc.DialogAsyncTask;
|
import code.name.monkey.retromusic.misc.DialogAsyncTask;
|
||||||
import code.name.monkey.retromusic.model.Song;
|
import code.name.monkey.retromusic.model.Song;
|
||||||
import code.name.monkey.retromusic.util.SAFUtil;
|
import code.name.monkey.retromusic.util.SAFUtil;
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by hemanths on 2019-07-31.
|
* Created by hemanths on 2019-07-31.
|
||||||
*/
|
*/
|
||||||
public class DeleteSongsAsyncTask extends DialogAsyncTask<DeleteSongsAsyncTask.LoadingInfo, Integer, Void> {
|
public class DeleteSongsAsyncTask extends DialogAsyncTask<DeleteSongsAsyncTask.LoadingInfo, Integer, Void> {
|
||||||
private WeakReference<DeleteSongsDialog> dialogReference;
|
|
||||||
|
public static class LoadingInfo {
|
||||||
|
|
||||||
|
public Intent intent;
|
||||||
|
|
||||||
|
public boolean isIntent;
|
||||||
|
|
||||||
|
public int requestCode;
|
||||||
|
|
||||||
|
public int resultCode;
|
||||||
|
|
||||||
|
public List<Uri> safUris;
|
||||||
|
|
||||||
|
public List<Song> songs;
|
||||||
|
|
||||||
|
public LoadingInfo(List<Song> songs, List<Uri> safUris) {
|
||||||
|
this.isIntent = false;
|
||||||
|
this.songs = songs;
|
||||||
|
this.safUris = safUris;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LoadingInfo(int requestCode, int resultCode, Intent intent) {
|
||||||
|
this.isIntent = true;
|
||||||
|
this.requestCode = requestCode;
|
||||||
|
this.resultCode = resultCode;
|
||||||
|
this.intent = intent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private WeakReference<FragmentActivity> activityWeakReference;
|
private WeakReference<FragmentActivity> activityWeakReference;
|
||||||
|
|
||||||
|
private WeakReference<DeleteSongsDialog> dialogReference;
|
||||||
|
|
||||||
public DeleteSongsAsyncTask(@NonNull DeleteSongsDialog dialog) {
|
public DeleteSongsAsyncTask(@NonNull DeleteSongsDialog dialog) {
|
||||||
super(dialog.getActivity());
|
super(dialog.getActivity());
|
||||||
|
@ -82,7 +107,8 @@ public class DeleteSongsAsyncTask extends DialogAsyncTask<DeleteSongsAsyncTask.L
|
||||||
if (SAFUtil.isSDCardAccessGranted(fragmentActivity)) {
|
if (SAFUtil.isSDCardAccessGranted(fragmentActivity)) {
|
||||||
dialog.deleteSongs(info.songs, null);
|
dialog.deleteSongs(info.songs, null);
|
||||||
} else {
|
} else {
|
||||||
dialog.startActivityForResult(new Intent(fragmentActivity, SAFGuideActivity.class), SAFGuideActivity.REQUEST_CODE_SAF_GUIDE);
|
dialog.startActivityForResult(new Intent(fragmentActivity, SAFGuideActivity.class),
|
||||||
|
SAFGuideActivity.REQUEST_CODE_SAF_GUIDE);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Log.i("Hmm", "doInBackground: kitkat delete songs");
|
Log.i("Hmm", "doInBackground: kitkat delete songs");
|
||||||
|
@ -100,7 +126,8 @@ public class DeleteSongsAsyncTask extends DialogAsyncTask<DeleteSongsAsyncTask.L
|
||||||
break;
|
break;
|
||||||
case SAFUtil.REQUEST_SAF_PICK_FILE:
|
case SAFUtil.REQUEST_SAF_PICK_FILE:
|
||||||
if (info.resultCode == Activity.RESULT_OK) {
|
if (info.resultCode == Activity.RESULT_OK) {
|
||||||
dialog.deleteSongs(Collections.singletonList(dialog.currentSong), Collections.singletonList(info.intent.getData()));
|
dialog.deleteSongs(Collections.singletonList(dialog.currentSong),
|
||||||
|
Collections.singletonList(info.intent.getData()));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -111,28 +138,4 @@ public class DeleteSongsAsyncTask extends DialogAsyncTask<DeleteSongsAsyncTask.L
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class LoadingInfo {
|
|
||||||
public boolean isIntent;
|
|
||||||
|
|
||||||
public List<Song> songs;
|
|
||||||
public List<Uri> safUris;
|
|
||||||
|
|
||||||
public int requestCode;
|
|
||||||
public int resultCode;
|
|
||||||
public Intent intent;
|
|
||||||
|
|
||||||
public LoadingInfo(List<Song> songs, List<Uri> safUris) {
|
|
||||||
this.isIntent = false;
|
|
||||||
this.songs = songs;
|
|
||||||
this.safUris = safUris;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LoadingInfo(int requestCode, int resultCode, Intent intent) {
|
|
||||||
this.isIntent = true;
|
|
||||||
this.requestCode = requestCode;
|
|
||||||
this.resultCode = resultCode;
|
|
||||||
this.intent = intent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,6 @@ import com.afollestad.materialdialogs.LayoutMode
|
||||||
import com.afollestad.materialdialogs.MaterialDialog
|
import com.afollestad.materialdialogs.MaterialDialog
|
||||||
import com.afollestad.materialdialogs.bottomsheets.BottomSheet
|
import com.afollestad.materialdialogs.bottomsheets.BottomSheet
|
||||||
|
|
||||||
|
|
||||||
class DeleteSongsDialog : DialogFragment() {
|
class DeleteSongsDialog : DialogFragment() {
|
||||||
@JvmField
|
@JvmField
|
||||||
var currentSong: Song? = null
|
var currentSong: Song? = null
|
||||||
|
@ -40,7 +39,6 @@ class DeleteSongsDialog : DialogFragment() {
|
||||||
|
|
||||||
private var deleteSongsAsyncTask: DeleteSongsAsyncTask? = null
|
private var deleteSongsAsyncTask: DeleteSongsAsyncTask? = null
|
||||||
|
|
||||||
|
|
||||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
val songs: ArrayList<Song>? = arguments?.getParcelableArrayList("songs")
|
val songs: ArrayList<Song>? = arguments?.getParcelableArrayList("songs")
|
||||||
var title = 0
|
var title = 0
|
||||||
|
@ -95,7 +93,7 @@ class DeleteSongsDialog : DialogFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun deleteSongs(songs: List<Song>, safUris: List<Uri>?) {
|
fun deleteSongs(songs: List<Song>, safUris: List<Uri>?) {
|
||||||
MusicUtil.deleteTracks(activity!!, songs, safUris) { this.dismiss() }
|
MusicUtil.deleteTracks(requireActivity(), songs, safUris) { this.dismiss() }
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
|
@ -27,21 +27,9 @@ import android.provider.BaseColumns;
|
||||||
import android.provider.MediaStore;
|
import android.provider.MediaStore;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.core.content.FileProvider;
|
import androidx.core.content.FileProvider;
|
||||||
|
|
||||||
import org.jaudiotagger.audio.AudioFileIO;
|
|
||||||
import org.jaudiotagger.tag.FieldKey;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import code.name.monkey.retromusic.R;
|
import code.name.monkey.retromusic.R;
|
||||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote;
|
import code.name.monkey.retromusic.helper.MusicPlayerRemote;
|
||||||
import code.name.monkey.retromusic.loaders.PlaylistLoader;
|
import code.name.monkey.retromusic.loaders.PlaylistLoader;
|
||||||
|
@ -51,76 +39,22 @@ import code.name.monkey.retromusic.model.Playlist;
|
||||||
import code.name.monkey.retromusic.model.Song;
|
import code.name.monkey.retromusic.model.Song;
|
||||||
import code.name.monkey.retromusic.model.lyrics.AbsSynchronizedLyrics;
|
import code.name.monkey.retromusic.model.lyrics.AbsSynchronizedLyrics;
|
||||||
import code.name.monkey.retromusic.service.MusicService;
|
import code.name.monkey.retromusic.service.MusicService;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import org.jaudiotagger.audio.AudioFileIO;
|
||||||
|
import org.jaudiotagger.tag.FieldKey;
|
||||||
|
|
||||||
|
|
||||||
public class MusicUtil {
|
public class MusicUtil {
|
||||||
|
|
||||||
public static final String TAG = MusicUtil.class.getSimpleName();
|
public static final String TAG = MusicUtil.class.getSimpleName();
|
||||||
|
|
||||||
private static Playlist playlist;
|
private static Playlist playlist;
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static Uri getMediaStoreAlbumCoverUri(int albumId) {
|
|
||||||
final Uri sArtworkUri = Uri.parse("content://media/external/audio/albumart");
|
|
||||||
return ContentUris.withAppendedId(sArtworkUri, albumId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Uri getSongFileUri(int songId) {
|
|
||||||
return ContentUris.withAppendedId(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, songId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static Intent createShareSongFileIntent(@NonNull final Song song, @NonNull Context context) {
|
|
||||||
try {
|
|
||||||
return new Intent()
|
|
||||||
.setAction(Intent.ACTION_SEND)
|
|
||||||
.putExtra(Intent.EXTRA_STREAM, FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName(), new File(song.getData())))
|
|
||||||
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
|
||||||
.setType("audio/*");
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
// TODO the path is most likely not like /storage/emulated/0/... but something like /storage/28C7-75B0/...
|
|
||||||
e.printStackTrace();
|
|
||||||
Toast.makeText(context, "Could not share this file, I'm aware of the issue.", Toast.LENGTH_SHORT).show();
|
|
||||||
return new Intent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static String getSongCountString(@NonNull final Context context, int songCount) {
|
|
||||||
final String songString = songCount == 1 ? context.getResources().getString(R.string.song) : context.getResources().getString(R.string.songs);
|
|
||||||
return songCount + " " + songString;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static String getSongInfoString(@NonNull Song song) {
|
|
||||||
return MusicUtil.buildInfoString(
|
|
||||||
song.getArtistName(),
|
|
||||||
song.getAlbumName()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static String getArtistInfoString(@NonNull final Context context,
|
|
||||||
@NonNull final Artist artist) {
|
|
||||||
int albumCount = artist.getAlbumCount();
|
|
||||||
int songCount = artist.getSongCount();
|
|
||||||
String albumString = albumCount == 1 ? context.getResources().getString(R.string.album)
|
|
||||||
: context.getResources().getString(R.string.albums);
|
|
||||||
String songString = songCount == 1 ? context.getResources().getString(R.string.song)
|
|
||||||
: context.getResources().getString(R.string.songs);
|
|
||||||
return albumCount + " " + albumString + " • " + songCount + " " + songString;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static String getPlaylistInfoString(@NonNull final Context context, @NonNull List<Song> songs) {
|
|
||||||
final long duration = getTotalDuration(songs);
|
|
||||||
|
|
||||||
return MusicUtil.buildInfoString(
|
|
||||||
MusicUtil.getSongCountString(context, songs.size()),
|
|
||||||
MusicUtil.getReadableDurationString(duration)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build a concatenated string from the provided arguments
|
* Build a concatenated string from the provided arguments
|
||||||
* The intended purpose is to show extra annotations
|
* The intended purpose is to show extra annotations
|
||||||
|
@ -142,58 +76,37 @@ public class MusicUtil {
|
||||||
return string1 + " • " + string2;
|
return string1 + " • " + string2;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getReadableDurationString(long songDurationMillis) {
|
|
||||||
long minutes = (songDurationMillis / 1000) / 60;
|
|
||||||
long seconds = (songDurationMillis / 1000) % 60;
|
|
||||||
if (minutes < 60) {
|
|
||||||
return String.format(Locale.getDefault(), "%01d:%02d", minutes, seconds);
|
|
||||||
} else {
|
|
||||||
long hours = minutes / 60;
|
|
||||||
minutes = minutes % 60;
|
|
||||||
return String.format(Locale.getDefault(), "%d:%02d:%02d", hours, minutes, seconds);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//iTunes uses for example 1002 for track 2 CD1 or 3011 for track 11 CD3.
|
|
||||||
//this method converts those values to normal tracknumbers
|
|
||||||
public static int getFixedTrackNumber(int trackNumberToFix) {
|
|
||||||
return trackNumberToFix % 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void insertAlbumArt(@NonNull Context context, int albumId, String path) {
|
|
||||||
ContentResolver contentResolver = context.getContentResolver();
|
|
||||||
|
|
||||||
Uri artworkUri = Uri.parse("content://media/external/audio/albumart");
|
|
||||||
contentResolver.delete(ContentUris.withAppendedId(artworkUri, albumId), null, null);
|
|
||||||
|
|
||||||
ContentValues values = new ContentValues();
|
|
||||||
values.put("album_id", albumId);
|
|
||||||
values.put("_data", path);
|
|
||||||
|
|
||||||
contentResolver.insert(artworkUri, values);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public static File createAlbumArtFile() {
|
public static File createAlbumArtFile() {
|
||||||
return new File(createAlbumArtDir(), String.valueOf(System.currentTimeMillis()));
|
return new File(createAlbumArtDir(), String.valueOf(System.currentTimeMillis()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@SuppressWarnings("ResultOfMethodCallIgnored")
|
public static Intent createShareSongFileIntent(@NonNull final Song song, @NonNull Context context) {
|
||||||
private static File createAlbumArtDir() {
|
|
||||||
File albumArtDir = new File(Environment.getExternalStorageDirectory(), "/albumthumbs/");
|
|
||||||
if (!albumArtDir.exists()) {
|
|
||||||
albumArtDir.mkdirs();
|
|
||||||
try {
|
try {
|
||||||
new File(albumArtDir, ".nomedia").createNewFile();
|
return new Intent()
|
||||||
} catch (IOException e) {
|
.setAction(Intent.ACTION_SEND)
|
||||||
|
.putExtra(Intent.EXTRA_STREAM, FileProvider
|
||||||
|
.getUriForFile(context, context.getApplicationContext().getPackageName(),
|
||||||
|
new File(song.getData())))
|
||||||
|
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||||
|
.setType("audio/*");
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
// TODO the path is most likely not like /storage/emulated/0/... but something like /storage/28C7-75B0/...
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
Toast.makeText(context, "Could not share this file, I'm aware of the issue.", Toast.LENGTH_SHORT).show();
|
||||||
|
return new Intent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return albumArtDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void deleteTracks(@NonNull final Activity activity,
|
public static void deleteAlbumArt(@NonNull Context context, int albumId) {
|
||||||
|
ContentResolver contentResolver = context.getContentResolver();
|
||||||
|
Uri localUri = Uri.parse("content://media/external/audio/albumart");
|
||||||
|
contentResolver.delete(ContentUris.withAppendedId(localUri, albumId), null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void deleteTracks(
|
||||||
|
@NonNull final Activity activity,
|
||||||
@NonNull final List<Song> songs,
|
@NonNull final List<Song> songs,
|
||||||
@Nullable final List<Uri> safUris,
|
@Nullable final List<Uri> safUris,
|
||||||
@Nullable final Runnable callback) {
|
@Nullable final Runnable callback) {
|
||||||
|
@ -204,7 +117,8 @@ public class MusicUtil {
|
||||||
// Split the query into multiple batches, and merge the resulting cursors
|
// Split the query into multiple batches, and merge the resulting cursors
|
||||||
int batchStart = 0;
|
int batchStart = 0;
|
||||||
int batchEnd = 0;
|
int batchEnd = 0;
|
||||||
final int batchSize = 1000000 / 10; // 10^6 being the SQLite limite on the query lenth in bytes, 10 being the max number of digits in an int, used to store the track ID
|
final int batchSize = 1000000
|
||||||
|
/ 10; // 10^6 being the SQLite limite on the query lenth in bytes, 10 being the max number of digits in an int, used to store the track ID
|
||||||
final int songCount = songs.size();
|
final int songCount = songs.size();
|
||||||
|
|
||||||
while (batchEnd < songCount) {
|
while (batchEnd < songCount) {
|
||||||
|
@ -263,19 +177,31 @@ public class MusicUtil {
|
||||||
activity.getContentResolver().notifyChange(Uri.parse("content://media"), null);
|
activity.getContentResolver().notifyChange(Uri.parse("content://media"), null);
|
||||||
|
|
||||||
activity.runOnUiThread(() -> {
|
activity.runOnUiThread(() -> {
|
||||||
Toast.makeText(activity, activity.getString(R.string.deleted_x_songs, songCount), Toast.LENGTH_SHORT).show();
|
Toast.makeText(activity, activity.getString(R.string.deleted_x_songs, songCount), Toast.LENGTH_SHORT)
|
||||||
|
.show();
|
||||||
if (callback != null) {
|
if (callback != null) {
|
||||||
callback.run();
|
callback.run();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void deleteAlbumArt(@NonNull Context context, int albumId) {
|
@NonNull
|
||||||
ContentResolver contentResolver = context.getContentResolver();
|
public static String getArtistInfoString(@NonNull final Context context,
|
||||||
Uri localUri = Uri.parse("content://media/external/audio/albumart");
|
@NonNull final Artist artist) {
|
||||||
contentResolver.delete(ContentUris.withAppendedId(localUri, albumId), null, null);
|
int albumCount = artist.getAlbumCount();
|
||||||
|
int songCount = artist.getSongCount();
|
||||||
|
String albumString = albumCount == 1 ? context.getResources().getString(R.string.album)
|
||||||
|
: context.getResources().getString(R.string.albums);
|
||||||
|
String songString = songCount == 1 ? context.getResources().getString(R.string.song)
|
||||||
|
: context.getResources().getString(R.string.songs);
|
||||||
|
return albumCount + " " + albumString + " • " + songCount + " " + songString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//iTunes uses for example 1002 for track 2 CD1 or 3011 for track 11 CD3.
|
||||||
|
//this method converts those values to normal tracknumbers
|
||||||
|
public static int getFixedTrackNumber(int trackNumberToFix) {
|
||||||
|
return trackNumberToFix % 1000;
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public static String getLyrics(@NonNull Song song) {
|
public static String getLyrics(@NonNull Song song) {
|
||||||
|
@ -334,44 +260,41 @@ public class MusicUtil {
|
||||||
return lyrics;
|
return lyrics;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void toggleFavorite(@NonNull final Context context, @NonNull final Song song) {
|
@NonNull
|
||||||
if (isFavorite(context, song)) {
|
public static Uri getMediaStoreAlbumCoverUri(int albumId) {
|
||||||
PlaylistsUtil.removeFromPlaylist(context, song, getFavoritesPlaylist(context).id);
|
final Uri sArtworkUri = Uri.parse("content://media/external/audio/albumart");
|
||||||
|
return ContentUris.withAppendedId(sArtworkUri, albumId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public static Playlist getPlaylist() {
|
||||||
|
return playlist;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setPlaylist(@NonNull Playlist playlist) {
|
||||||
|
MusicUtil.playlist = playlist;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public static String getPlaylistInfoString(@NonNull final Context context, @NonNull List<Song> songs) {
|
||||||
|
final long duration = getTotalDuration(songs);
|
||||||
|
|
||||||
|
return MusicUtil.buildInfoString(
|
||||||
|
MusicUtil.getSongCountString(context, songs.size()),
|
||||||
|
MusicUtil.getReadableDurationString(duration)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getReadableDurationString(long songDurationMillis) {
|
||||||
|
long minutes = (songDurationMillis / 1000) / 60;
|
||||||
|
long seconds = (songDurationMillis / 1000) % 60;
|
||||||
|
if (minutes < 60) {
|
||||||
|
return String.format(Locale.getDefault(), "%01d:%02d", minutes, seconds);
|
||||||
} else {
|
} else {
|
||||||
PlaylistsUtil.addToPlaylist(context, song, getOrCreateFavoritesPlaylist(context).id,
|
long hours = minutes / 60;
|
||||||
false);
|
minutes = minutes % 60;
|
||||||
|
return String.format(Locale.getDefault(), "%d:%02d:%02d", hours, minutes, seconds);
|
||||||
}
|
}
|
||||||
context.sendBroadcast(new Intent(MusicService.FAVORITE_STATE_CHANGED));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isFavoritePlaylist(@NonNull final Context context,
|
|
||||||
@NonNull final Playlist playlist) {
|
|
||||||
return playlist.name != null && playlist.name.equals(context.getString(R.string.favorites));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Playlist getFavoritesPlaylist(@NonNull final Context context) {
|
|
||||||
return PlaylistLoader.INSTANCE.getPlaylist(context, context.getString(R.string.favorites));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Playlist getOrCreateFavoritesPlaylist(@NonNull final Context context) {
|
|
||||||
return PlaylistLoader.INSTANCE.getPlaylist(context,
|
|
||||||
PlaylistsUtil.createPlaylist(context, context.getString(R.string.favorites)));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isFavorite(@NonNull final Context context, @NonNull final Song song) {
|
|
||||||
return PlaylistsUtil
|
|
||||||
.doPlaylistContains(context, getFavoritesPlaylist(context).id, song.getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isArtistNameUnknown(@Nullable String artistName) {
|
|
||||||
if (TextUtils.isEmpty(artistName)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (artistName.equals(Artist.UNKNOWN_ARTIST_DISPLAY_NAME)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
artistName = artistName.trim().toLowerCase();
|
|
||||||
return artistName.equals("unknown") || artistName.equals("<unknown>");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
|
@ -392,12 +315,22 @@ public class MusicUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public static Playlist getPlaylist() {
|
public static String getSongCountString(@NonNull final Context context, int songCount) {
|
||||||
return playlist;
|
final String songString = songCount == 1 ? context.getResources().getString(R.string.song)
|
||||||
|
: context.getResources().getString(R.string.songs);
|
||||||
|
return songCount + " " + songString;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setPlaylist(@NonNull Playlist playlist) {
|
public static Uri getSongFileUri(int songId) {
|
||||||
MusicUtil.playlist = playlist;
|
return ContentUris.withAppendedId(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, songId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public static String getSongInfoString(@NonNull Song song) {
|
||||||
|
return MusicUtil.buildInfoString(
|
||||||
|
song.getArtistName(),
|
||||||
|
song.getAlbumName()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static long getTotalDuration(@NonNull List<Song> songs) {
|
public static long getTotalDuration(@NonNull List<Song> songs) {
|
||||||
|
@ -408,6 +341,11 @@ public class MusicUtil {
|
||||||
return duration;
|
return duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public static String getYearString(int year) {
|
||||||
|
return year > 0 ? String.valueOf(year) : "-";
|
||||||
|
}
|
||||||
|
|
||||||
public static int indexOfSongInList(@NonNull List<Song> songs, int songId) {
|
public static int indexOfSongInList(@NonNull List<Song> songs, int songId) {
|
||||||
for (int i = 0; i < songs.size(); i++) {
|
for (int i = 0; i < songs.size(); i++) {
|
||||||
if (songs.get(i).getId() == songId) {
|
if (songs.get(i).getId() == songId) {
|
||||||
|
@ -417,8 +355,71 @@ public class MusicUtil {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void insertAlbumArt(@NonNull Context context, int albumId, String path) {
|
||||||
|
ContentResolver contentResolver = context.getContentResolver();
|
||||||
|
|
||||||
|
Uri artworkUri = Uri.parse("content://media/external/audio/albumart");
|
||||||
|
contentResolver.delete(ContentUris.withAppendedId(artworkUri, albumId), null, null);
|
||||||
|
|
||||||
|
ContentValues values = new ContentValues();
|
||||||
|
values.put("album_id", albumId);
|
||||||
|
values.put("_data", path);
|
||||||
|
|
||||||
|
contentResolver.insert(artworkUri, values);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isArtistNameUnknown(@Nullable String artistName) {
|
||||||
|
if (TextUtils.isEmpty(artistName)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (artistName.equals(Artist.UNKNOWN_ARTIST_DISPLAY_NAME)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
artistName = artistName.trim().toLowerCase();
|
||||||
|
return artistName.equals("unknown") || artistName.equals("<unknown>");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isFavorite(@NonNull final Context context, @NonNull final Song song) {
|
||||||
|
return PlaylistsUtil
|
||||||
|
.doPlaylistContains(context, getFavoritesPlaylist(context).id, song.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isFavoritePlaylist(@NonNull final Context context,
|
||||||
|
@NonNull final Playlist playlist) {
|
||||||
|
return playlist.name != null && playlist.name.equals(context.getString(R.string.favorites));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void toggleFavorite(@NonNull final Context context, @NonNull final Song song) {
|
||||||
|
if (isFavorite(context, song)) {
|
||||||
|
PlaylistsUtil.removeFromPlaylist(context, song, getFavoritesPlaylist(context).id);
|
||||||
|
} else {
|
||||||
|
PlaylistsUtil.addToPlaylist(context, song, getOrCreateFavoritesPlaylist(context).id,
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
context.sendBroadcast(new Intent(MusicService.FAVORITE_STATE_CHANGED));
|
||||||
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public static String getYearString(int year) {
|
@SuppressWarnings("ResultOfMethodCallIgnored")
|
||||||
return year > 0 ? String.valueOf(year) : "-";
|
private static File createAlbumArtDir() {
|
||||||
|
File albumArtDir = new File(Environment.getExternalStorageDirectory(), "/albumthumbs/");
|
||||||
|
if (!albumArtDir.exists()) {
|
||||||
|
albumArtDir.mkdirs();
|
||||||
|
try {
|
||||||
|
new File(albumArtDir, ".nomedia").createNewFile();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return albumArtDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Playlist getFavoritesPlaylist(@NonNull final Context context) {
|
||||||
|
return PlaylistLoader.INSTANCE.getPlaylist(context, context.getString(R.string.favorites));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Playlist getOrCreateFavoritesPlaylist(@NonNull final Context context) {
|
||||||
|
return PlaylistLoader.INSTANCE.getPlaylist(context,
|
||||||
|
PlaylistsUtil.createPlaylist(context, context.getString(R.string.favorites)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<code.name.monkey.retromusic.MultiSheetView xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:id="@+id/mainContent"
|
android:id="@+id/mainContent"
|
||||||
|
@ -28,21 +28,13 @@
|
||||||
app:cardBackgroundColor="?attr/colorSurface"
|
app:cardBackgroundColor="?attr/colorSurface"
|
||||||
app:cardCornerRadius="0dp"
|
app:cardCornerRadius="0dp"
|
||||||
app:cardUseCompatPadding="false"
|
app:cardUseCompatPadding="false"
|
||||||
app:layout_behavior="code.name.monkey.retromusic.CustomBottomSheetBehavior"
|
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior"
|
||||||
app:strokeWidth="0dp">
|
app:strokeWidth="0dp">
|
||||||
|
|
||||||
<FrameLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:elevation="2dp"
|
|
||||||
app:behavior_peekHeight="@dimen/bottom_sheet_peek_1_height"
|
|
||||||
app:layout_behavior="code.name.monkey.retromusic.CustomBottomSheetBehavior">
|
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:id="@+id/playerFragmentContainer"
|
android:id="@+id/playerFragmentContainer"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent" />
|
||||||
android:layout_marginBottom="@dimen/bottom_sheet_peek_2_height" />
|
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/miniPlayerFragment"
|
android:id="@+id/miniPlayerFragment"
|
||||||
|
@ -51,72 +43,6 @@
|
||||||
android:layout_height="48dp"
|
android:layout_height="48dp"
|
||||||
tools:layout="@layout/fragment_mini_player" />
|
tools:layout="@layout/fragment_mini_player" />
|
||||||
|
|
||||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
|
||||||
android:id="@+id/sheet1Coordinator"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
android:id="@+id/sheet2"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:background="?attr/colorSurface"
|
|
||||||
android:elevation="2dp"
|
|
||||||
android:orientation="vertical"
|
|
||||||
app:behavior_peekHeight="@dimen/bottom_sheet_peek_2_height"
|
|
||||||
app:layout_behavior="code.name.monkey.retromusic.CustomBottomSheetBehavior">
|
|
||||||
|
|
||||||
<FrameLayout
|
|
||||||
android:id="@+id/sheet2PeekView"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="@dimen/bottom_sheet_peek_2_height"
|
|
||||||
android:elevation="8dp"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent">
|
|
||||||
|
|
||||||
<code.name.monkey.retromusic.views.StatusBarView
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content" />
|
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatImageView
|
|
||||||
android:id="@+id/thumb"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
app:srcCompat="@drawable/ic_keyboard_arrow_up_24dp"
|
|
||||||
app:tint="?attr/colorControlNormal" />
|
|
||||||
</FrameLayout>
|
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
|
||||||
android:id="@+id/sheet2Container"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/extendedToolbar" />
|
|
||||||
|
|
||||||
<FrameLayout
|
|
||||||
android:id="@+id/extendedToolbar"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="48dp"
|
|
||||||
android:elevation="8dp"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/sheet2PeekView">
|
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatImageView
|
|
||||||
android:id="@+id/collapseBack"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:padding="14dp"
|
|
||||||
app:srcCompat="@drawable/ic_keyboard_backspace_black_24dp"
|
|
||||||
app:tint="?attr/colorControlNormal" />
|
|
||||||
</FrameLayout>
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
|
||||||
</FrameLayout>
|
|
||||||
</com.google.android.material.card.MaterialCardView>
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
<code.name.monkey.retromusic.views.BottomNavigationBarTinted
|
<code.name.monkey.retromusic.views.BottomNavigationBarTinted
|
||||||
|
@ -134,4 +60,4 @@
|
||||||
app:labelVisibilityMode="labeled"
|
app:labelVisibilityMode="labeled"
|
||||||
app:menu="@menu/bottom_navigation_main"
|
app:menu="@menu/bottom_navigation_main"
|
||||||
tools:layout_height="56dp" />
|
tools:layout_height="56dp" />
|
||||||
</code.name.monkey.retromusic.MultiSheetView>
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
Loading…
Reference in a new issue