App shortcut fixed
This commit is contained in:
parent
1425bfe612
commit
0b6f043995
181 changed files with 1616 additions and 2052 deletions
|
@ -1,70 +0,0 @@
|
|||
package code.name.monkey.retromusic.appshortcuts;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.graphics.drawable.LayerDrawable;
|
||||
import android.os.Build;
|
||||
import android.util.TypedValue;
|
||||
|
||||
import androidx.annotation.RequiresApi;
|
||||
import code.name.monkey.appthemehelper.ThemeStore;
|
||||
import code.name.monkey.retromusic.R;
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil;
|
||||
import code.name.monkey.retromusic.util.RetroUtil;
|
||||
|
||||
/**
|
||||
* @author Adrian Campos
|
||||
*/
|
||||
@RequiresApi(Build.VERSION_CODES.N_MR1)
|
||||
public final class AppShortcutIconGenerator {
|
||||
public static Icon generateThemedIcon(Context context, int iconId) {
|
||||
if (PreferenceUtil.getInstance().coloredAppShortcuts()) {
|
||||
return generateUserThemedIcon(context, iconId);
|
||||
} else {
|
||||
return generateDefaultThemedIcon(context, iconId);
|
||||
}
|
||||
}
|
||||
|
||||
private static Icon generateDefaultThemedIcon(Context context, int iconId) {
|
||||
// Return an Icon of iconId with default colors
|
||||
return generateThemedIcon(context, iconId,
|
||||
context.getColor(R.color.app_shortcut_default_foreground),
|
||||
context.getColor(R.color.app_shortcut_default_background)
|
||||
);
|
||||
}
|
||||
|
||||
private static Icon generateUserThemedIcon(Context context, int iconId) {
|
||||
// Get background color from context's theme
|
||||
final TypedValue typedColorBackground = new TypedValue();
|
||||
context.getTheme().resolveAttribute(android.R.attr.colorBackground, typedColorBackground, true);
|
||||
|
||||
// Return an Icon of iconId with those colors
|
||||
return generateThemedIcon(context, iconId,
|
||||
ThemeStore.accentColor(context),
|
||||
typedColorBackground.data
|
||||
);
|
||||
}
|
||||
|
||||
private static Icon generateThemedIcon(Context context, int iconId, int foregroundColor, int backgroundColor) {
|
||||
// Get and tint foreground and background drawables
|
||||
Drawable vectorDrawable = RetroUtil.getTintedVectorDrawable(context, iconId, foregroundColor);
|
||||
Drawable backgroundDrawable = RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_app_shortcut_background, backgroundColor);
|
||||
|
||||
// Squash the two drawables together
|
||||
LayerDrawable layerDrawable = new LayerDrawable(new Drawable[]{backgroundDrawable, vectorDrawable});
|
||||
|
||||
// Return as an Icon
|
||||
return Icon.createWithBitmap(drawableToBitmap(layerDrawable));
|
||||
}
|
||||
|
||||
private static Bitmap drawableToBitmap(Drawable drawable) {
|
||||
Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
|
||||
Canvas canvas = new Canvas(bitmap);
|
||||
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
|
||||
drawable.draw(canvas);
|
||||
return bitmap;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
package code.name.monkey.retromusic.appshortcuts
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.graphics.drawable.Icon
|
||||
import android.graphics.drawable.LayerDrawable
|
||||
import android.os.Build
|
||||
import android.util.TypedValue
|
||||
|
||||
import androidx.annotation.RequiresApi
|
||||
import code.name.monkey.appthemehelper.ThemeStore
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||
import code.name.monkey.retromusic.util.RetroUtil
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.N_MR1)
|
||||
object AppShortcutIconGenerator {
|
||||
fun generateThemedIcon(context: Context, iconId: Int): Icon {
|
||||
return if (PreferenceUtil.getInstance().coloredAppShortcuts()) {
|
||||
generateUserThemedIcon(context, iconId)
|
||||
} else {
|
||||
generateDefaultThemedIcon(context, iconId)
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateDefaultThemedIcon(context: Context, iconId: Int): Icon {
|
||||
// Return an Icon of iconId with default colors
|
||||
return generateThemedIcon(context, iconId,
|
||||
context.getColor(R.color.app_shortcut_default_foreground),
|
||||
context.getColor(R.color.app_shortcut_default_background)
|
||||
)
|
||||
}
|
||||
|
||||
private fun generateUserThemedIcon(context: Context, iconId: Int): Icon {
|
||||
// Get background color from context's theme
|
||||
val typedColorBackground = TypedValue()
|
||||
context.theme.resolveAttribute(android.R.attr.colorBackground, typedColorBackground, true)
|
||||
|
||||
// Return an Icon of iconId with those colors
|
||||
return generateThemedIcon(context, iconId,
|
||||
ThemeStore.accentColor(context),
|
||||
typedColorBackground.data
|
||||
)
|
||||
}
|
||||
|
||||
private fun generateThemedIcon(context: Context, iconId: Int, foregroundColor: Int, backgroundColor: Int): Icon {
|
||||
// Get and tint foreground and background drawables
|
||||
val vectorDrawable = RetroUtil.getTintedVectorDrawable(context, iconId, foregroundColor)
|
||||
val backgroundDrawable = RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_app_shortcut_background, backgroundColor)
|
||||
|
||||
// Squash the two drawables together
|
||||
val layerDrawable = LayerDrawable(arrayOf(backgroundDrawable, vectorDrawable))
|
||||
|
||||
// Return as an Icon
|
||||
return Icon.createWithBitmap(drawableToBitmap(layerDrawable))
|
||||
}
|
||||
|
||||
private fun drawableToBitmap(drawable: Drawable): Bitmap {
|
||||
val bitmap = Bitmap.createBitmap(drawable.intrinsicWidth, drawable.intrinsicHeight, Bitmap.Config.ARGB_8888)
|
||||
val canvas = Canvas(bitmap)
|
||||
drawable.setBounds(0, 0, canvas.width, canvas.height)
|
||||
drawable.draw(canvas)
|
||||
return bitmap
|
||||
}
|
||||
}
|
|
@ -1,77 +0,0 @@
|
|||
package code.name.monkey.retromusic.appshortcuts;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import code.name.monkey.retromusic.model.Playlist;
|
||||
import code.name.monkey.retromusic.model.smartplaylist.LastAddedPlaylist;
|
||||
import code.name.monkey.retromusic.model.smartplaylist.MyTopTracksPlaylist;
|
||||
import code.name.monkey.retromusic.model.smartplaylist.ShuffleAllPlaylist;
|
||||
|
||||
import code.name.monkey.retromusic.appshortcuts.shortcuttype.LastAddedShortcutType;
|
||||
import code.name.monkey.retromusic.appshortcuts.shortcuttype.ShuffleAllShortcutType;
|
||||
import code.name.monkey.retromusic.appshortcuts.shortcuttype.TopTracksShortcutType;
|
||||
import code.name.monkey.retromusic.service.MusicService;
|
||||
|
||||
import static code.name.monkey.retromusic.Constants.*;
|
||||
|
||||
/**
|
||||
* @author Adrian Campos
|
||||
*/
|
||||
|
||||
public class AppShortcutLauncherActivity extends Activity {
|
||||
public static final String KEY_SHORTCUT_TYPE = "code.name.monkey.retromusic.appshortcuts.ShortcutType";
|
||||
|
||||
public static final int SHORTCUT_TYPE_SHUFFLE_ALL = 0;
|
||||
public static final int SHORTCUT_TYPE_TOP_TRACKS = 1;
|
||||
public static final int SHORTCUT_TYPE_LAST_ADDED = 2;
|
||||
public static final int SHORTCUT_TYPE_NONE = 3;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
int shortcutType = SHORTCUT_TYPE_NONE;
|
||||
|
||||
// Set shortcutType from the intent extras
|
||||
Bundle extras = getIntent().getExtras();
|
||||
if (extras != null) {
|
||||
//noinspection WrongConstant
|
||||
shortcutType = extras.getInt(KEY_SHORTCUT_TYPE, SHORTCUT_TYPE_NONE);
|
||||
}
|
||||
|
||||
switch (shortcutType) {
|
||||
case SHORTCUT_TYPE_SHUFFLE_ALL:
|
||||
startServiceWithPlaylist(MusicService.SHUFFLE_MODE_SHUFFLE,
|
||||
new ShuffleAllPlaylist(getApplicationContext()));
|
||||
DynamicShortcutManager.reportShortcutUsed(this, ShuffleAllShortcutType.getId());
|
||||
break;
|
||||
case SHORTCUT_TYPE_TOP_TRACKS:
|
||||
startServiceWithPlaylist(MusicService.SHUFFLE_MODE_NONE,
|
||||
new MyTopTracksPlaylist(getApplicationContext()));
|
||||
DynamicShortcutManager.reportShortcutUsed(this, TopTracksShortcutType.getId());
|
||||
break;
|
||||
case SHORTCUT_TYPE_LAST_ADDED:
|
||||
startServiceWithPlaylist(MusicService.SHUFFLE_MODE_NONE,
|
||||
new LastAddedPlaylist(getApplicationContext()));
|
||||
DynamicShortcutManager.reportShortcutUsed(this, LastAddedShortcutType.getId());
|
||||
break;
|
||||
}
|
||||
|
||||
finish();
|
||||
}
|
||||
|
||||
private void startServiceWithPlaylist(int shuffleMode, Playlist playlist) {
|
||||
Intent intent = new Intent(this, MusicService.class);
|
||||
intent.setAction(ACTION_PLAY_PLAYLIST);
|
||||
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putParcelable(INTENT_EXTRA_PLAYLIST, playlist);
|
||||
bundle.putInt(INTENT_EXTRA_SHUFFLE_MODE, shuffleMode);
|
||||
|
||||
intent.putExtras(bundle);
|
||||
|
||||
startService(intent);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
package code.name.monkey.retromusic.appshortcuts
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import code.name.monkey.retromusic.Constants.ACTION_PLAY_PLAYLIST
|
||||
import code.name.monkey.retromusic.Constants.INTENT_EXTRA_PLAYLIST
|
||||
import code.name.monkey.retromusic.Constants.INTENT_EXTRA_SHUFFLE_MODE
|
||||
import code.name.monkey.retromusic.appshortcuts.shortcuttype.LastAddedShortcutType
|
||||
import code.name.monkey.retromusic.appshortcuts.shortcuttype.SearchShortCutType
|
||||
import code.name.monkey.retromusic.appshortcuts.shortcuttype.ShuffleAllShortcutType
|
||||
import code.name.monkey.retromusic.appshortcuts.shortcuttype.TopTracksShortcutType
|
||||
import code.name.monkey.retromusic.model.Playlist
|
||||
import code.name.monkey.retromusic.model.smartplaylist.LastAddedPlaylist
|
||||
import code.name.monkey.retromusic.model.smartplaylist.MyTopTracksPlaylist
|
||||
import code.name.monkey.retromusic.model.smartplaylist.ShuffleAllPlaylist
|
||||
import code.name.monkey.retromusic.service.MusicService
|
||||
import code.name.monkey.retromusic.ui.activities.SearchActivity
|
||||
|
||||
|
||||
class AppShortcutLauncherActivity : Activity() {
|
||||
|
||||
public override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
var shortcutType = SHORTCUT_TYPE_NONE
|
||||
|
||||
// Set shortcutType from the intent extras
|
||||
val extras = intent.extras
|
||||
if (extras != null) {
|
||||
shortcutType = extras.getInt(KEY_SHORTCUT_TYPE, SHORTCUT_TYPE_NONE)
|
||||
}
|
||||
|
||||
when (shortcutType) {
|
||||
SHORTCUT_TYPE_SHUFFLE_ALL -> {
|
||||
startServiceWithPlaylist(MusicService.SHUFFLE_MODE_SHUFFLE,
|
||||
ShuffleAllPlaylist(applicationContext))
|
||||
DynamicShortcutManager.reportShortcutUsed(this, ShuffleAllShortcutType.id)
|
||||
}
|
||||
SHORTCUT_TYPE_TOP_TRACKS -> {
|
||||
startServiceWithPlaylist(MusicService.SHUFFLE_MODE_NONE,
|
||||
MyTopTracksPlaylist(applicationContext))
|
||||
DynamicShortcutManager.reportShortcutUsed(this, TopTracksShortcutType.id)
|
||||
}
|
||||
SHORTCUT_TYPE_LAST_ADDED -> {
|
||||
startServiceWithPlaylist(MusicService.SHUFFLE_MODE_NONE,
|
||||
LastAddedPlaylist(applicationContext))
|
||||
DynamicShortcutManager.reportShortcutUsed(this, LastAddedShortcutType.id)
|
||||
}
|
||||
SHORTCUT_TYPE_SEARCH -> {
|
||||
startActivity(Intent(this, SearchActivity::class.java))
|
||||
DynamicShortcutManager.reportShortcutUsed(this, SearchShortCutType.id)
|
||||
}
|
||||
}
|
||||
finish()
|
||||
}
|
||||
|
||||
private fun startServiceWithPlaylist(shuffleMode: Int, playlist: Playlist) {
|
||||
val intent = Intent(this, MusicService::class.java)
|
||||
intent.action = ACTION_PLAY_PLAYLIST
|
||||
|
||||
val bundle = Bundle()
|
||||
bundle.putParcelable(INTENT_EXTRA_PLAYLIST, playlist)
|
||||
bundle.putInt(INTENT_EXTRA_SHUFFLE_MODE, shuffleMode)
|
||||
|
||||
intent.putExtras(bundle)
|
||||
|
||||
startService(intent)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val KEY_SHORTCUT_TYPE = "code.name.monkey.retromusic.appshortcuts.ShortcutType"
|
||||
const val SHORTCUT_TYPE_SHUFFLE_ALL = 0
|
||||
const val SHORTCUT_TYPE_TOP_TRACKS = 1
|
||||
const val SHORTCUT_TYPE_LAST_ADDED = 2
|
||||
const val SHORTCUT_TYPE_SEARCH = 3
|
||||
const val SHORTCUT_TYPE_NONE = 4
|
||||
}
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
package code.name.monkey.retromusic.appshortcuts;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ShortcutInfo;
|
||||
import android.content.pm.ShortcutManager;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.os.Build;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import code.name.monkey.retromusic.appshortcuts.shortcuttype.LastAddedShortcutType;
|
||||
import code.name.monkey.retromusic.appshortcuts.shortcuttype.ShuffleAllShortcutType;
|
||||
import code.name.monkey.retromusic.appshortcuts.shortcuttype.TopTracksShortcutType;
|
||||
|
||||
/**
|
||||
* @author Adrian Campos
|
||||
*/
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.N_MR1)
|
||||
public class DynamicShortcutManager {
|
||||
|
||||
private Context context;
|
||||
private ShortcutManager shortcutManager;
|
||||
|
||||
public DynamicShortcutManager(Context context) {
|
||||
this.context = context;
|
||||
shortcutManager = this.context.getSystemService(ShortcutManager.class);
|
||||
}
|
||||
|
||||
public static ShortcutInfo createShortcut(Context context, String id, String shortLabel, String longLabel, Icon icon, Intent intent) {
|
||||
return new ShortcutInfo.Builder(context, id)
|
||||
.setShortLabel(shortLabel)
|
||||
.setLongLabel(longLabel)
|
||||
.setIcon(icon)
|
||||
.setIntent(intent)
|
||||
.build();
|
||||
}
|
||||
|
||||
public static void reportShortcutUsed(Context context, String shortcutId) {
|
||||
context.getSystemService(ShortcutManager.class).reportShortcutUsed(shortcutId);
|
||||
}
|
||||
|
||||
public void initDynamicShortcuts() {
|
||||
if (shortcutManager.getDynamicShortcuts().size() == 0) {
|
||||
shortcutManager.setDynamicShortcuts(getDefaultShortcuts());
|
||||
}
|
||||
}
|
||||
|
||||
public void updateDynamicShortcuts() {
|
||||
shortcutManager.updateShortcuts(getDefaultShortcuts());
|
||||
}
|
||||
|
||||
public List<ShortcutInfo> getDefaultShortcuts() {
|
||||
return (Arrays.asList(
|
||||
new ShuffleAllShortcutType(context).getShortcutInfo(),
|
||||
new TopTracksShortcutType(context).getShortcutInfo(),
|
||||
new LastAddedShortcutType(context).getShortcutInfo()
|
||||
));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package code.name.monkey.retromusic.appshortcuts
|
||||
|
||||
import android.annotation.TargetApi
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.ShortcutInfo
|
||||
import android.content.pm.ShortcutManager
|
||||
import android.graphics.drawable.Icon
|
||||
import android.os.Build
|
||||
|
||||
import java.util.Arrays
|
||||
|
||||
import code.name.monkey.retromusic.appshortcuts.shortcuttype.LastAddedShortcutType
|
||||
import code.name.monkey.retromusic.appshortcuts.shortcuttype.SearchShortCutType
|
||||
import code.name.monkey.retromusic.appshortcuts.shortcuttype.ShuffleAllShortcutType
|
||||
import code.name.monkey.retromusic.appshortcuts.shortcuttype.TopTracksShortcutType
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.N_MR1)
|
||||
class DynamicShortcutManager(private val context: Context) {
|
||||
private val shortcutManager: ShortcutManager = this.context.getSystemService(ShortcutManager::class.java)
|
||||
|
||||
private val defaultShortcuts: List<ShortcutInfo>
|
||||
get() = Arrays.asList(
|
||||
SearchShortCutType(context).shortcutInfo,
|
||||
ShuffleAllShortcutType(context).shortcutInfo,
|
||||
TopTracksShortcutType(context).shortcutInfo,
|
||||
LastAddedShortcutType(context).shortcutInfo
|
||||
|
||||
)
|
||||
|
||||
fun initDynamicShortcuts() {
|
||||
//if (shortcutManager.dynamicShortcuts.size == 0) {
|
||||
shortcutManager.dynamicShortcuts = defaultShortcuts
|
||||
//}
|
||||
}
|
||||
|
||||
fun updateDynamicShortcuts() {
|
||||
shortcutManager.updateShortcuts(defaultShortcuts)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
fun createShortcut(context: Context, id: String, shortLabel: String, longLabel: String, icon: Icon, intent: Intent): ShortcutInfo {
|
||||
return ShortcutInfo.Builder(context, id)
|
||||
.setShortLabel(shortLabel)
|
||||
.setLongLabel(longLabel)
|
||||
.setIcon(icon)
|
||||
.setIntent(intent)
|
||||
.build()
|
||||
}
|
||||
|
||||
fun reportShortcutUsed(context: Context, shortcutId: String) {
|
||||
context.getSystemService(ShortcutManager::class.java).reportShortcutUsed(shortcutId)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
package code.name.monkey.retromusic.appshortcuts.shortcuttype;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ShortcutInfo;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
|
||||
import code.name.monkey.retromusic.appshortcuts.AppShortcutLauncherActivity;
|
||||
|
||||
|
||||
/**
|
||||
* @author Adrian Campos
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.N_MR1)
|
||||
public abstract class BaseShortcutType {
|
||||
|
||||
static final String ID_PREFIX = "code.name.monkey.retromusic.appshortcuts.id.";
|
||||
|
||||
Context context;
|
||||
|
||||
public BaseShortcutType(Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
static public String getId() {
|
||||
return ID_PREFIX + "invalid";
|
||||
}
|
||||
|
||||
abstract ShortcutInfo getShortcutInfo();
|
||||
|
||||
/**
|
||||
* Creates an Intent that will launch MainActivtiy and immediately play {@param songs} in either shuffle or normal mode
|
||||
*
|
||||
* @param shortcutType Describes the type of shortcut to create (ShuffleAll, TopTracks, custom playlist, etc.)
|
||||
* @return
|
||||
*/
|
||||
Intent getPlaySongsIntent(int shortcutType) {
|
||||
Intent intent = new Intent(context, AppShortcutLauncherActivity.class);
|
||||
intent.setAction(Intent.ACTION_VIEW);
|
||||
|
||||
Bundle b = new Bundle();
|
||||
b.putInt(AppShortcutLauncherActivity.KEY_SHORTCUT_TYPE, shortcutType);
|
||||
|
||||
intent.putExtras(b);
|
||||
|
||||
return intent;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package code.name.monkey.retromusic.appshortcuts.shortcuttype
|
||||
|
||||
import android.annotation.TargetApi
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.ShortcutInfo
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
|
||||
import code.name.monkey.retromusic.appshortcuts.AppShortcutLauncherActivity
|
||||
|
||||
|
||||
/**
|
||||
* @author Adrian Campos
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.N_MR1)
|
||||
abstract class BaseShortcutType(internal var context: Context) {
|
||||
|
||||
internal abstract val shortcutInfo: ShortcutInfo
|
||||
|
||||
/**
|
||||
* Creates an Intent that will launch MainActivtiy and immediately play {@param songs} in either shuffle or normal mode
|
||||
*
|
||||
* @param shortcutType Describes the type of shortcut to create (ShuffleAll, TopTracks, custom playlist, etc.)
|
||||
* @return
|
||||
*/
|
||||
internal fun getPlaySongsIntent(shortcutType: Int): Intent {
|
||||
val intent = Intent(context, AppShortcutLauncherActivity::class.java)
|
||||
intent.action = Intent.ACTION_VIEW
|
||||
val b = Bundle()
|
||||
b.putInt(AppShortcutLauncherActivity.KEY_SHORTCUT_TYPE, shortcutType)
|
||||
intent.putExtras(b)
|
||||
return intent
|
||||
}
|
||||
|
||||
companion object {
|
||||
internal const val ID_PREFIX = "code.name.monkey.retromusic.appshortcuts.id."
|
||||
val id: String
|
||||
get() = ID_PREFIX + "invalid"
|
||||
}
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
package code.name.monkey.retromusic.appshortcuts.shortcuttype;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ShortcutInfo;
|
||||
import android.os.Build;
|
||||
|
||||
import code.name.monkey.retromusic.R;
|
||||
import code.name.monkey.retromusic.appshortcuts.AppShortcutIconGenerator;
|
||||
import code.name.monkey.retromusic.appshortcuts.AppShortcutLauncherActivity;
|
||||
|
||||
|
||||
/**
|
||||
* @author Adrian Campos
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.N_MR1)
|
||||
public final class LastAddedShortcutType extends BaseShortcutType {
|
||||
public LastAddedShortcutType(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public static String getId() {
|
||||
return ID_PREFIX + "last_added";
|
||||
}
|
||||
|
||||
public ShortcutInfo getShortcutInfo() {
|
||||
return new ShortcutInfo.Builder(context, getId())
|
||||
.setShortLabel(context.getString(R.string.app_shortcut_last_added_short))
|
||||
.setLongLabel(context.getString(R.string.app_shortcut_last_added_long))
|
||||
.setIcon(AppShortcutIconGenerator.generateThemedIcon(context, R.drawable.ic_app_shortcut_last_added))
|
||||
.setIntent(getPlaySongsIntent(AppShortcutLauncherActivity.SHORTCUT_TYPE_LAST_ADDED))
|
||||
.build();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package code.name.monkey.retromusic.appshortcuts.shortcuttype
|
||||
|
||||
import android.annotation.TargetApi
|
||||
import android.content.Context
|
||||
import android.content.pm.ShortcutInfo
|
||||
import android.os.Build
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.appshortcuts.AppShortcutIconGenerator
|
||||
import code.name.monkey.retromusic.appshortcuts.AppShortcutLauncherActivity
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.N_MR1)
|
||||
class LastAddedShortcutType(context: Context) : BaseShortcutType(context) {
|
||||
|
||||
override val shortcutInfo: ShortcutInfo
|
||||
get() = ShortcutInfo.Builder(context, id)
|
||||
.setShortLabel(context.getString(R.string.app_shortcut_last_added_short))
|
||||
.setLongLabel(context.getString(R.string.app_shortcut_last_added_long))
|
||||
.setIcon(AppShortcutIconGenerator.generateThemedIcon(context, R.drawable.ic_app_shortcut_last_added))
|
||||
.setIntent(getPlaySongsIntent(AppShortcutLauncherActivity.SHORTCUT_TYPE_LAST_ADDED))
|
||||
.build()
|
||||
|
||||
companion object {
|
||||
|
||||
val id: String
|
||||
get() = BaseShortcutType.ID_PREFIX + "last_added"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package code.name.monkey.retromusic.appshortcuts.shortcuttype
|
||||
|
||||
import android.annotation.TargetApi
|
||||
import android.content.Context
|
||||
import android.content.pm.ShortcutInfo
|
||||
import android.os.Build
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.appshortcuts.AppShortcutIconGenerator
|
||||
import code.name.monkey.retromusic.appshortcuts.AppShortcutLauncherActivity
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.N_MR1)
|
||||
class SearchShortCutType(context: Context) : BaseShortcutType(context) {
|
||||
companion object {
|
||||
|
||||
val id: String
|
||||
get() = BaseShortcutType.ID_PREFIX + "search"
|
||||
}
|
||||
|
||||
override val shortcutInfo: ShortcutInfo
|
||||
get() = ShortcutInfo.Builder(context, id)
|
||||
.setShortLabel(context.getString(R.string.action_search))
|
||||
.setLongLabel(context.getString(R.string.search_hint))
|
||||
.setIcon(AppShortcutIconGenerator.generateThemedIcon(context, R.drawable.ic_app_shortcut_search))
|
||||
.setIntent(getPlaySongsIntent(AppShortcutLauncherActivity.SHORTCUT_TYPE_SEARCH))
|
||||
.build()
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
package code.name.monkey.retromusic.appshortcuts.shortcuttype;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ShortcutInfo;
|
||||
import android.os.Build;
|
||||
|
||||
import code.name.monkey.retromusic.R;
|
||||
import code.name.monkey.retromusic.appshortcuts.AppShortcutIconGenerator;
|
||||
import code.name.monkey.retromusic.appshortcuts.AppShortcutLauncherActivity;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @author Adrian Campos
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.N_MR1)
|
||||
public final class ShuffleAllShortcutType extends BaseShortcutType {
|
||||
public ShuffleAllShortcutType(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public static String getId() {
|
||||
return ID_PREFIX + "shuffle_all";
|
||||
}
|
||||
|
||||
public ShortcutInfo getShortcutInfo() {
|
||||
return new ShortcutInfo.Builder(context, getId())
|
||||
.setShortLabel(context.getString(R.string.app_shortcut_shuffle_all_short))
|
||||
.setLongLabel(context.getString(R.string.app_shortcut_shuffle_all_long))
|
||||
.setIcon(AppShortcutIconGenerator.generateThemedIcon(context, R.drawable.ic_app_shortcut_shuffle_all))
|
||||
.setIntent(getPlaySongsIntent(AppShortcutLauncherActivity.SHORTCUT_TYPE_SHUFFLE_ALL))
|
||||
.build();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package code.name.monkey.retromusic.appshortcuts.shortcuttype
|
||||
|
||||
import android.annotation.TargetApi
|
||||
import android.content.Context
|
||||
import android.content.pm.ShortcutInfo
|
||||
import android.os.Build
|
||||
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.appshortcuts.AppShortcutIconGenerator
|
||||
import code.name.monkey.retromusic.appshortcuts.AppShortcutLauncherActivity
|
||||
import java.security.AccessController.getContext
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.N_MR1)
|
||||
class ShuffleAllShortcutType(context: Context) : BaseShortcutType(context) {
|
||||
|
||||
override val shortcutInfo: ShortcutInfo
|
||||
get() = ShortcutInfo.Builder(context, id)
|
||||
.setShortLabel(context.getString(R.string.app_shortcut_shuffle_all_short))
|
||||
.setLongLabel(context.getString(R.string.app_shortcut_shuffle_all_long))
|
||||
.setIcon(AppShortcutIconGenerator.generateThemedIcon(context, R.drawable.ic_app_shortcut_shuffle_all))
|
||||
.setIntent(getPlaySongsIntent(AppShortcutLauncherActivity.SHORTCUT_TYPE_SHUFFLE_ALL))
|
||||
.build()
|
||||
|
||||
companion object {
|
||||
|
||||
val id: String
|
||||
get() = BaseShortcutType.ID_PREFIX + "shuffle_all"
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
package code.name.monkey.retromusic.appshortcuts.shortcuttype;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ShortcutInfo;
|
||||
import android.os.Build;
|
||||
|
||||
import code.name.monkey.retromusic.R;
|
||||
import code.name.monkey.retromusic.appshortcuts.AppShortcutIconGenerator;
|
||||
import code.name.monkey.retromusic.appshortcuts.AppShortcutLauncherActivity;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @author Adrian Campos
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.N_MR1)
|
||||
public final class TopTracksShortcutType extends BaseShortcutType {
|
||||
public TopTracksShortcutType(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public static String getId() {
|
||||
return ID_PREFIX + "top_tracks";
|
||||
}
|
||||
|
||||
public ShortcutInfo getShortcutInfo() {
|
||||
return new ShortcutInfo.Builder(context, getId())
|
||||
.setShortLabel(context.getString(R.string.app_shortcut_top_tracks_short))
|
||||
.setLongLabel(context.getString(R.string.app_shortcut_top_tracks_long))
|
||||
.setIcon(AppShortcutIconGenerator.generateThemedIcon(context, R.drawable.ic_app_shortcut_top_tracks))
|
||||
.setIntent(getPlaySongsIntent(AppShortcutLauncherActivity.SHORTCUT_TYPE_TOP_TRACKS))
|
||||
.build();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package code.name.monkey.retromusic.appshortcuts.shortcuttype
|
||||
|
||||
import android.annotation.TargetApi
|
||||
import android.content.Context
|
||||
import android.content.pm.ShortcutInfo
|
||||
import android.os.Build
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.appshortcuts.AppShortcutIconGenerator
|
||||
import code.name.monkey.retromusic.appshortcuts.AppShortcutLauncherActivity
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.N_MR1)
|
||||
class TopTracksShortcutType(context: Context) : BaseShortcutType(context) {
|
||||
|
||||
override val shortcutInfo: ShortcutInfo
|
||||
get() = ShortcutInfo.Builder(context, id)
|
||||
.setShortLabel(context.getString(R.string.app_shortcut_top_tracks_short))
|
||||
.setLongLabel(context.getString(R.string.app_shortcut_top_tracks_long))
|
||||
.setIcon(AppShortcutIconGenerator.generateThemedIcon(context, R.drawable.ic_app_shortcut_top_tracks))
|
||||
.setIntent(getPlaySongsIntent(AppShortcutLauncherActivity.SHORTCUT_TYPE_TOP_TRACKS))
|
||||
.build()
|
||||
|
||||
companion object {
|
||||
|
||||
val id: String
|
||||
get() = BaseShortcutType.ID_PREFIX + "top_tracks"
|
||||
}
|
||||
}
|
|
@ -136,16 +136,7 @@ abstract class BaseAppWidget : AppWidgetProvider() {
|
|||
}
|
||||
|
||||
protected fun composeRoundedRectPath(rect: RectF, tl: Float, tr: Float, bl: Float, br: Float): Path {
|
||||
var tlf = tl
|
||||
var trf = tr
|
||||
var blf = bl
|
||||
var brf = br
|
||||
val path = Path()
|
||||
tlf = if (tl < 0) 0F else tl
|
||||
trf = if (tr < 0) 0f else tr
|
||||
blf = if (bl < 0) 0f else bl
|
||||
brf = if (br < 0) 0f else br
|
||||
|
||||
path.moveTo(rect.left + tl, rect.top)
|
||||
path.lineTo(rect.right - tr, rect.top)
|
||||
path.quadTo(rect.right, rect.top, rect.right, rect.top + tr)
|
||||
|
|
|
@ -1,61 +0,0 @@
|
|||
package code.name.monkey.retromusic.cast;
|
||||
|
||||
import android.net.Uri;
|
||||
|
||||
import com.google.android.gms.cast.MediaInfo;
|
||||
import com.google.android.gms.cast.MediaLoadOptions;
|
||||
import com.google.android.gms.cast.MediaMetadata;
|
||||
import com.google.android.gms.cast.framework.CastSession;
|
||||
import com.google.android.gms.cast.framework.media.RemoteMediaClient;
|
||||
import com.google.android.gms.common.images.WebImage;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
||||
import code.name.monkey.retromusic.Constants;
|
||||
import code.name.monkey.retromusic.model.Song;
|
||||
import code.name.monkey.retromusic.util.RetroUtil;
|
||||
|
||||
import static code.name.monkey.retromusic.Constants.CAST_SERVER_PORT;
|
||||
|
||||
public class CastHelper {
|
||||
|
||||
public static void startCasting(CastSession castSession, Song song) {
|
||||
|
||||
String ipAddress = RetroUtil.getIPAddress(true);
|
||||
URL baseUrl;
|
||||
try {
|
||||
baseUrl = new URL("https", ipAddress,CAST_SERVER_PORT, "");
|
||||
} catch (MalformedURLException e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
|
||||
String songUrl = baseUrl.toString() + "/song?id=" + song.getId();
|
||||
String albumArtUrl = baseUrl.toString() + "/albumart?id=" + song.getAlbumId();
|
||||
|
||||
|
||||
MediaMetadata musicMetadata = new MediaMetadata(MediaMetadata.MEDIA_TYPE_MUSIC_TRACK);
|
||||
|
||||
musicMetadata.putString(MediaMetadata.KEY_TITLE, song.getTitle());
|
||||
musicMetadata.putString(MediaMetadata.KEY_ARTIST, song.getArtistName());
|
||||
musicMetadata.putString(MediaMetadata.KEY_ALBUM_TITLE, song.getAlbumName());
|
||||
musicMetadata.putInt(MediaMetadata.KEY_TRACK_NUMBER, song.getTrackNumber());
|
||||
musicMetadata.addImage(new WebImage(Uri.parse(albumArtUrl)));
|
||||
|
||||
try {
|
||||
MediaInfo mediaInfo = new MediaInfo.Builder(songUrl)
|
||||
.setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
|
||||
.setContentType("audio/mpeg")
|
||||
.setMetadata(musicMetadata)
|
||||
.setStreamDuration(song.getDuration())
|
||||
.build();
|
||||
RemoteMediaClient remoteMediaClient = castSession.getRemoteMediaClient();
|
||||
remoteMediaClient.load(mediaInfo, new MediaLoadOptions.Builder()
|
||||
.build());
|
||||
//remoteMediaClient.load(mediaInfo, true, 0);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
package code.name.monkey.retromusic.cast;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.google.android.gms.cast.framework.CastOptions;
|
||||
import com.google.android.gms.cast.framework.OptionsProvider;
|
||||
import com.google.android.gms.cast.framework.SessionProvider;
|
||||
import com.google.android.gms.cast.framework.media.CastMediaOptions;
|
||||
import com.google.android.gms.cast.framework.media.MediaIntentReceiver;
|
||||
import com.google.android.gms.cast.framework.media.NotificationOptions;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import code.name.monkey.retromusic.R;
|
||||
|
||||
public class CastOptionsProvider implements OptionsProvider {
|
||||
@Override
|
||||
public CastOptions getCastOptions(Context context) {
|
||||
List<String> buttonActions = new ArrayList<>();
|
||||
buttonActions.add(MediaIntentReceiver.ACTION_TOGGLE_PLAYBACK);
|
||||
buttonActions.add(MediaIntentReceiver.ACTION_STOP_CASTING);
|
||||
int[] compatButtonActionsIndicies = new int[]{ 0, 1 };
|
||||
|
||||
NotificationOptions notificationOptions = new NotificationOptions.Builder()
|
||||
.setActions(buttonActions, compatButtonActionsIndicies)
|
||||
.setTargetActivityClassName(ExpandedCastControlsActivity.class.getName())
|
||||
.build();
|
||||
|
||||
CastMediaOptions mediaOptions = new CastMediaOptions.Builder()
|
||||
.setNotificationOptions(notificationOptions)
|
||||
.setExpandedControllerActivityClassName(ExpandedCastControlsActivity.class.getName())
|
||||
.build();
|
||||
|
||||
return new CastOptions.Builder()
|
||||
.setReceiverApplicationId(context.getString(R.string.cast_app_id))
|
||||
.setCastMediaOptions(mediaOptions)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SessionProvider> getAdditionalSessionProviders(Context context) {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
package code.name.monkey.retromusic.cast;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.Menu;
|
||||
import android.view.View;
|
||||
|
||||
import com.google.android.gms.cast.framework.CastButtonFactory;
|
||||
import com.google.android.gms.cast.framework.media.widget.ExpandedControllerActivity;
|
||||
|
||||
import code.name.monkey.retromusic.R;
|
||||
|
||||
|
||||
public class ExpandedCastControlsActivity extends ExpandedControllerActivity {
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
super.onCreateOptionsMenu(menu);
|
||||
getMenuInflater().inflate(R.menu.menu_expanded_controller, menu);
|
||||
CastButtonFactory.setUpMediaRouteButton(this, menu, R.id.media_route_menu_item);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle bundle) {
|
||||
super.onCreate(bundle);
|
||||
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
|
||||
}
|
||||
}
|
|
@ -1,77 +0,0 @@
|
|||
package code.name.monkey.retromusic.cast;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Map;
|
||||
|
||||
import code.name.monkey.retromusic.Constants;
|
||||
import code.name.monkey.retromusic.util.RetroUtil;
|
||||
import fi.iki.elonen.NanoHTTPD;
|
||||
|
||||
import static code.name.monkey.retromusic.Constants.CAST_SERVER_PORT;
|
||||
|
||||
public class WebServer extends NanoHTTPD {
|
||||
|
||||
private Context context;
|
||||
private Uri songUri, albumArtUri;
|
||||
|
||||
public WebServer(Context context) {
|
||||
super(CAST_SERVER_PORT);
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response serve(String uri, Method method,
|
||||
Map<String, String> header,
|
||||
Map<String, String> parameters,
|
||||
Map<String, String> files) {
|
||||
if (uri.contains("albumart")) {
|
||||
//serve the picture
|
||||
|
||||
String albumId = parameters.get("id");
|
||||
this.albumArtUri = RetroUtil.getAlbumArtUri(Long.parseLong(albumId));
|
||||
|
||||
if (albumArtUri != null) {
|
||||
String mediasend = "image/jpg";
|
||||
InputStream fisAlbumArt = null;
|
||||
try {
|
||||
fisAlbumArt = context.getContentResolver().openInputStream(albumArtUri);
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
Response.Status st = Response.Status.OK;
|
||||
|
||||
//serve the song
|
||||
return newChunkedResponse(st, mediasend, fisAlbumArt);
|
||||
}
|
||||
|
||||
} else if (uri.contains("song")) {
|
||||
|
||||
String songId = parameters.get("id");
|
||||
this.songUri = RetroUtil.getSongUri(context, Long.parseLong(songId));
|
||||
|
||||
if (songUri != null) {
|
||||
String mediasend = "audio/mp3";
|
||||
FileInputStream fisSong = null;
|
||||
File song = new File(songUri.getPath());
|
||||
try {
|
||||
fisSong = new FileInputStream(song);
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
Response.Status st = Response.Status.OK;
|
||||
|
||||
//serve the song
|
||||
return newFixedLengthResponse(st, mediasend, fisSong, song.length());
|
||||
}
|
||||
|
||||
}
|
||||
return newFixedLengthResponse("Error");
|
||||
}
|
||||
|
||||
}
|
|
@ -32,7 +32,7 @@ class AddToPlaylistDialog : RoundedBottomSheetDialogFragment() {
|
|||
|
||||
actionAddPlaylist.setOnClickListener {
|
||||
val songs = arguments!!.getParcelableArrayList<Song>("songs")
|
||||
CreatePlaylistDialog.create(songs).show(activity!!.supportFragmentManager, "ADD_TO_PLAYLIST")
|
||||
CreatePlaylistDialog.create(songs!!).show(activity!!.supportFragmentManager, "ADD_TO_PLAYLIST")
|
||||
dismiss()
|
||||
}
|
||||
|
||||
|
|
|
@ -20,8 +20,8 @@ class DeleteSongsDialog : RoundedBottomSheetDialogFragment() {
|
|||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
title.setTextColor(ThemeStore.textColorPrimary(context!!))
|
||||
MaterialUtil.setTint(actionDelete, true)
|
||||
MaterialUtil.setTint(actionCancel, false)
|
||||
MaterialUtil.setTint(actionDelete)
|
||||
MaterialUtil.setTint(actionCancel)
|
||||
|
||||
//noinspection unchecked,ConstantConditions
|
||||
val songs = arguments!!.getParcelableArrayList<Song>("songs")
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package code.name.monkey.retromusic.dialogs
|
||||
|
||||
import android.content.Intent
|
||||
import android.content.res.ColorStateList
|
||||
import android.graphics.Bitmap
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
|
@ -57,7 +58,11 @@ class OptionsSheetDialogFragment : RoundedBottomSheetDialogFragment(), View.OnCl
|
|||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
actionBuyPro.visibility = if (!App.isProVersion) View.VISIBLE else View.GONE
|
||||
actionBuyPro.let {
|
||||
it.visibility = if (!App.isProVersion) View.VISIBLE else View.GONE
|
||||
it.iconTint = ColorStateList.valueOf(ThemeStore.accentColor(it.context))
|
||||
it.setTextColor(ColorStateList.valueOf(ThemeStore.accentColor(it.context)))
|
||||
}
|
||||
text!!.setTextColor(ThemeStore.textColorSecondary(context!!))
|
||||
titleWelcome!!.setTextColor(ThemeStore.textColorPrimary(context!!))
|
||||
titleWelcome!!.text = String.format("%s %s!", timeOfTheDay, PreferenceUtil.getInstance().userName)
|
||||
|
|
|
@ -85,8 +85,8 @@ class BlurTransformation : BitmapTransformation {
|
|||
return StackBlur.blur(out, blurRadius)
|
||||
}
|
||||
|
||||
override fun equals(o: Any?): Boolean {
|
||||
return o is BlurTransformation
|
||||
override fun equals(other: Any?): Boolean {
|
||||
return other is BlurTransformation
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
|
@ -138,7 +138,7 @@ class BlurTransformation : BitmapTransformation {
|
|||
|
||||
companion object {
|
||||
|
||||
val DEFAULT_BLUR_RADIUS = 5f
|
||||
private val ID = "com.poupa.vinylmusicplayer.glide.BlurTransformation"
|
||||
const val DEFAULT_BLUR_RADIUS = 5f
|
||||
private const val ID = "code.name.monkey.retromusic.glide.BlurTransformation"
|
||||
}
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
package code.name.monkey.retromusic.glide;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.bumptech.glide.GenericTransitionOptions;
|
||||
import com.bumptech.glide.Priority;
|
||||
import com.bumptech.glide.RequestBuilder;
|
||||
|
@ -8,11 +10,11 @@ import com.bumptech.glide.annotation.GlideOption;
|
|||
import com.bumptech.glide.annotation.GlideType;
|
||||
import com.bumptech.glide.load.Key;
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
||||
import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions;
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import com.bumptech.glide.request.target.Target;
|
||||
import com.bumptech.glide.signature.MediaStoreSignature;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import code.name.monkey.retromusic.App;
|
||||
import code.name.monkey.retromusic.R;
|
||||
import code.name.monkey.retromusic.glide.artistimage.ArtistImage;
|
||||
|
@ -34,6 +36,7 @@ public final class RetroGlideExtension {
|
|||
public static void asBitmapPalette(RequestBuilder<BitmapPaletteWrapper> requestBuilder) {
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@GlideOption
|
||||
public static RequestOptions artistOptions(@NonNull RequestOptions requestOptions, Artist artist) {
|
||||
return requestOptions
|
||||
|
@ -46,11 +49,12 @@ public final class RetroGlideExtension {
|
|||
}
|
||||
|
||||
@GlideOption
|
||||
@NonNull
|
||||
public static RequestOptions songOptions(@NonNull RequestOptions requestOptions, Song song) {
|
||||
return requestOptions
|
||||
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
||||
.error(R.drawable.default_album_art)
|
||||
.placeholder(R.drawable.default_album_art)
|
||||
//.placeholder(R.drawable.default_album_art)
|
||||
.signature(createSignature(song));
|
||||
}
|
||||
|
||||
|
@ -93,4 +97,5 @@ public final class RetroGlideExtension {
|
|||
public static <TranscodeType> GenericTransitionOptions<TranscodeType> getDefaultTransition() {
|
||||
return new GenericTransitionOptions<TranscodeType>().transition(android.R.anim.fade_in);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
package code.name.monkey.retromusic.glide.artistimage
|
||||
|
||||
|
||||
class ArtistImage(val artistName: String, val skipOkHttpCache: Boolean)
|
|
@ -1,98 +0,0 @@
|
|||
package code.name.monkey.retromusic.glide.artistimage
|
||||
|
||||
import android.content.Context
|
||||
import android.text.TextUtils
|
||||
import code.name.monkey.retromusic.rest.LastFMRestClient
|
||||
import code.name.monkey.retromusic.rest.model.LastFmArtist
|
||||
import code.name.monkey.retromusic.util.LastFMUtil
|
||||
import code.name.monkey.retromusic.util.MusicUtil
|
||||
import code.name.monkey.retromusic.util.RetroUtil
|
||||
import com.bumptech.glide.Priority
|
||||
import com.bumptech.glide.integration.okhttp3.OkHttpStreamFetcher
|
||||
import com.bumptech.glide.load.DataSource
|
||||
import com.bumptech.glide.load.data.DataFetcher
|
||||
import com.bumptech.glide.load.model.GlideUrl
|
||||
|
||||
import okhttp3.OkHttpClient
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Callback;
|
||||
import retrofit2.Response;
|
||||
import java.io.InputStream
|
||||
|
||||
|
||||
class ArtistImageFetcher(private val context: Context, private val lastFMRestClient: LastFMRestClient, private val okHttp: OkHttpClient, private val model: ArtistImage, width: Int, height: Int) : DataFetcher<InputStream> {
|
||||
@Volatile
|
||||
private var isCancelled: Boolean = false
|
||||
private var call: Call<LastFmArtist>? = null
|
||||
private var streamFetcher: OkHttpStreamFetcher? = null
|
||||
|
||||
|
||||
override fun getDataClass(): Class<InputStream> {
|
||||
return InputStream::class.java
|
||||
}
|
||||
|
||||
|
||||
override fun getDataSource(): DataSource {
|
||||
return DataSource.REMOTE
|
||||
}
|
||||
|
||||
override fun loadData(priority: Priority, callback: DataFetcher.DataCallback<in InputStream>) {
|
||||
try {
|
||||
if (!MusicUtil.isArtistNameUnknown(model.artistName) && RetroUtil.isAllowedToDownloadMetadata(context)) {
|
||||
call = lastFMRestClient.apiService.getArtistInfo(model.artistName, null, if (model.skipOkHttpCache) "no-cache" else null)
|
||||
call!!.enqueue(object : Callback<LastFmArtist> {
|
||||
override fun onResponse(call: Call<LastFmArtist>, response: Response<LastFmArtist>) {
|
||||
if (isCancelled) {
|
||||
callback.onDataReady(null)
|
||||
return
|
||||
}
|
||||
|
||||
val lastFmArtist = response.body()
|
||||
if (lastFmArtist == null || lastFmArtist.artist == null || lastFmArtist.artist.image == null) {
|
||||
callback.onLoadFailed(Exception("No artist image url found"))
|
||||
return
|
||||
}
|
||||
|
||||
val url = LastFMUtil.getLargestArtistImageUrl(lastFmArtist.artist.image)
|
||||
if (TextUtils.isEmpty(url) || TextUtils.isEmpty(url.trim { it <= ' ' })) {
|
||||
callback.onLoadFailed(Exception("No artist image url found"))
|
||||
return
|
||||
}
|
||||
|
||||
streamFetcher = OkHttpStreamFetcher(okHttp, GlideUrl(url))
|
||||
streamFetcher!!.loadData(priority, callback)
|
||||
}
|
||||
|
||||
override fun onFailure(call: Call<LastFmArtist>, throwable: Throwable) {
|
||||
callback.onLoadFailed(Exception(throwable))
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
callback.onLoadFailed(e)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun cleanup() {
|
||||
if (streamFetcher != null) {
|
||||
streamFetcher!!.cleanup()
|
||||
}
|
||||
}
|
||||
|
||||
override fun cancel() {
|
||||
isCancelled = true
|
||||
if (call != null) {
|
||||
call!!.cancel()
|
||||
}
|
||||
if (streamFetcher != null) {
|
||||
streamFetcher!!.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val TAG: String = ArtistImageFetcher::class.java.simpleName
|
||||
}
|
||||
}
|
|
@ -1,17 +1,109 @@
|
|||
package code.name.monkey.retromusic.glide.artistimage
|
||||
|
||||
import android.content.Context
|
||||
import android.text.TextUtils
|
||||
import code.name.monkey.retromusic.rest.LastFMRestClient
|
||||
import code.name.monkey.retromusic.rest.model.LastFmArtist
|
||||
import code.name.monkey.retromusic.util.LastFMUtil
|
||||
import code.name.monkey.retromusic.util.MusicUtil
|
||||
import code.name.monkey.retromusic.util.RetroUtil
|
||||
import com.bumptech.glide.Priority
|
||||
import com.bumptech.glide.integration.okhttp3.OkHttpStreamFetcher
|
||||
import com.bumptech.glide.load.DataSource
|
||||
import com.bumptech.glide.load.Options
|
||||
import com.bumptech.glide.load.data.DataFetcher
|
||||
import com.bumptech.glide.load.model.GlideUrl
|
||||
import com.bumptech.glide.load.model.ModelLoader
|
||||
import com.bumptech.glide.load.model.ModelLoaderFactory
|
||||
import com.bumptech.glide.load.model.MultiModelLoaderFactory
|
||||
import com.bumptech.glide.signature.ObjectKey
|
||||
import okhttp3.OkHttpClient
|
||||
import retrofit2.Call
|
||||
import retrofit2.Callback
|
||||
import retrofit2.Response
|
||||
import java.io.InputStream
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
|
||||
class ArtistImage(val artistName: String, val skipOkHttpCache: Boolean)
|
||||
|
||||
class ArtistImageFetcher(private val context: Context, private val lastFMRestClient: LastFMRestClient, private val okHttp: OkHttpClient, private val model: ArtistImage, width: Int, height: Int) : DataFetcher<InputStream> {
|
||||
@Volatile
|
||||
private var isCancelled: Boolean = false
|
||||
private var call: Call<LastFmArtist>? = null
|
||||
private var streamFetcher: OkHttpStreamFetcher? = null
|
||||
|
||||
|
||||
override fun getDataClass(): Class<InputStream> {
|
||||
return InputStream::class.java
|
||||
}
|
||||
|
||||
|
||||
override fun getDataSource(): DataSource {
|
||||
return DataSource.REMOTE
|
||||
}
|
||||
|
||||
override fun loadData(priority: Priority, callback: DataFetcher.DataCallback<in InputStream>) {
|
||||
try {
|
||||
if (!MusicUtil.isArtistNameUnknown(model.artistName) && RetroUtil.isAllowedToDownloadMetadata(context)) {
|
||||
call = lastFMRestClient.apiService.getArtistInfo(model.artistName, null, if (model.skipOkHttpCache) "no-cache" else null)
|
||||
call!!.enqueue(object : Callback<LastFmArtist> {
|
||||
override fun onResponse(call: Call<LastFmArtist>, response: Response<LastFmArtist>) {
|
||||
if (isCancelled) {
|
||||
callback.onDataReady(null)
|
||||
return
|
||||
}
|
||||
|
||||
val lastFmArtist = response.body()
|
||||
if (lastFmArtist == null || lastFmArtist.artist == null || lastFmArtist.artist.image == null) {
|
||||
callback.onLoadFailed(Exception("No artist image url found"))
|
||||
return
|
||||
}
|
||||
|
||||
val url = LastFMUtil.getLargestArtistImageUrl(lastFmArtist.artist.image)
|
||||
if (TextUtils.isEmpty(url) || TextUtils.isEmpty(url.trim { it <= ' ' })) {
|
||||
callback.onLoadFailed(Exception("No artist image url found"))
|
||||
return
|
||||
}
|
||||
|
||||
streamFetcher = OkHttpStreamFetcher(okHttp, GlideUrl(url))
|
||||
streamFetcher!!.loadData(priority, callback)
|
||||
}
|
||||
|
||||
override fun onFailure(call: Call<LastFmArtist>, throwable: Throwable) {
|
||||
callback.onLoadFailed(Exception(throwable))
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
callback.onLoadFailed(e)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun cleanup() {
|
||||
if (streamFetcher != null) {
|
||||
streamFetcher!!.cleanup()
|
||||
}
|
||||
}
|
||||
|
||||
override fun cancel() {
|
||||
isCancelled = true
|
||||
if (call != null) {
|
||||
call!!.cancel()
|
||||
}
|
||||
if (streamFetcher != null) {
|
||||
streamFetcher!!.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val TAG: String = ArtistImageFetcher::class.java.simpleName
|
||||
}
|
||||
}
|
||||
|
||||
class ArtistImageLoader(private val context: Context, private val lastFMClient: LastFMRestClient, private val okhttp: OkHttpClient) : ModelLoader<ArtistImage, InputStream> {
|
||||
|
||||
override fun buildLoadData(model: ArtistImage, width: Int, height: Int, options: Options): ModelLoader.LoadData<InputStream>? {
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
package code.name.monkey.retromusic.glide.audiocover
|
||||
|
||||
|
||||
class AudioFileCover(val filePath: String)
|
|
@ -1,92 +0,0 @@
|
|||
package code.name.monkey.retromusic.glide.audiocover
|
||||
|
||||
import android.media.MediaMetadataRetriever
|
||||
import com.bumptech.glide.Priority
|
||||
import com.bumptech.glide.load.DataSource
|
||||
import com.bumptech.glide.load.data.DataFetcher
|
||||
import org.jaudiotagger.audio.mp3.MP3File
|
||||
import java.io.*
|
||||
|
||||
/**
|
||||
* @author Karim Abou Zeid (kabouzeid)
|
||||
*/
|
||||
class AudioFileCoverFetcher(private val model: AudioFileCover) : DataFetcher<InputStream> {
|
||||
private var stream: FileInputStream? = null
|
||||
|
||||
override fun loadData(priority: Priority, callback: DataFetcher.DataCallback<in InputStream>) {
|
||||
val retriever = MediaMetadataRetriever()
|
||||
val data: InputStream?
|
||||
try {
|
||||
retriever.setDataSource(model.filePath)
|
||||
val picture = retriever.embeddedPicture
|
||||
if (picture != null) {
|
||||
data = ByteArrayInputStream(picture)
|
||||
} else {
|
||||
data = fallback(model.filePath)
|
||||
}
|
||||
callback.onDataReady(data)
|
||||
} catch (e: FileNotFoundException) {
|
||||
callback.onLoadFailed(e)
|
||||
} finally {
|
||||
retriever.release()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun getDataClass(): Class<InputStream> {
|
||||
return InputStream::class.java
|
||||
}
|
||||
|
||||
|
||||
override fun getDataSource(): DataSource {
|
||||
return DataSource.LOCAL
|
||||
}
|
||||
|
||||
@Throws(FileNotFoundException::class)
|
||||
private fun fallback(path: String): InputStream? {
|
||||
try {
|
||||
val mp3File = MP3File(path)
|
||||
if (mp3File.hasID3v2Tag()) {
|
||||
val art = mp3File.tag.firstArtwork
|
||||
if (art != null) {
|
||||
val imageData = art.binaryData
|
||||
return ByteArrayInputStream(imageData)
|
||||
}
|
||||
}
|
||||
// If there are any exceptions, we ignore them and continue to the other fallback method
|
||||
} catch (ignored: Exception) {
|
||||
}
|
||||
|
||||
// Method 2: look for album art in external files
|
||||
val parent = File(path).parentFile
|
||||
for (fallback in FALLBACKS) {
|
||||
val cover = File(parent, fallback)
|
||||
if (cover.exists()) {
|
||||
stream = FileInputStream(cover)
|
||||
return stream
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
override fun cleanup() {
|
||||
// already cleaned up in loadData and ByteArrayInputStream will be GC'd
|
||||
if (stream != null) {
|
||||
try {
|
||||
stream!!.close()
|
||||
} catch (ignore: IOException) {
|
||||
// can't do much about it
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
override fun cancel() {
|
||||
// cannot cancel
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private val FALLBACKS = arrayOf("cover.jpg", "album.jpg", "folder.jpg", "cover.png", "album.png", "folder.png")
|
||||
}
|
||||
}
|
|
@ -1,14 +1,102 @@
|
|||
package code.name.monkey.retromusic.glide.audiocover
|
||||
|
||||
import android.media.MediaMetadataRetriever
|
||||
import com.bumptech.glide.Priority
|
||||
import com.bumptech.glide.load.DataSource
|
||||
import com.bumptech.glide.load.Options
|
||||
import com.bumptech.glide.load.data.DataFetcher
|
||||
import com.bumptech.glide.load.model.ModelLoader
|
||||
import com.bumptech.glide.load.model.ModelLoader.LoadData
|
||||
import com.bumptech.glide.load.model.ModelLoaderFactory
|
||||
import com.bumptech.glide.load.model.MultiModelLoaderFactory
|
||||
import com.bumptech.glide.signature.ObjectKey
|
||||
import java.io.InputStream
|
||||
import org.jaudiotagger.audio.mp3.MP3File
|
||||
import java.io.*
|
||||
|
||||
|
||||
class AudioFileCover(val filePath: String)
|
||||
|
||||
class AudioFileCoverFetcher(private val model: AudioFileCover) : DataFetcher<InputStream> {
|
||||
private var stream: FileInputStream? = null
|
||||
|
||||
override fun loadData(priority: Priority, callback: DataFetcher.DataCallback<in InputStream>) {
|
||||
val retriever = MediaMetadataRetriever()
|
||||
val data: InputStream?
|
||||
try {
|
||||
retriever.setDataSource(model.filePath)
|
||||
val picture = retriever.embeddedPicture
|
||||
if (picture != null) {
|
||||
data = ByteArrayInputStream(picture)
|
||||
} else {
|
||||
data = fallback(model.filePath)
|
||||
}
|
||||
callback.onDataReady(data)
|
||||
} catch (e: FileNotFoundException) {
|
||||
callback.onLoadFailed(e)
|
||||
} finally {
|
||||
retriever.release()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun getDataClass(): Class<InputStream> {
|
||||
return InputStream::class.java
|
||||
}
|
||||
|
||||
|
||||
override fun getDataSource(): DataSource {
|
||||
return DataSource.LOCAL
|
||||
}
|
||||
|
||||
@Throws(FileNotFoundException::class)
|
||||
private fun fallback(path: String): InputStream? {
|
||||
try {
|
||||
val mp3File = MP3File(path)
|
||||
if (mp3File.hasID3v2Tag()) {
|
||||
val art = mp3File.tag.firstArtwork
|
||||
if (art != null) {
|
||||
val imageData = art.binaryData
|
||||
return ByteArrayInputStream(imageData)
|
||||
}
|
||||
}
|
||||
// If there are any exceptions, we ignore them and continue to the other fallback method
|
||||
} catch (ignored: Exception) {
|
||||
}
|
||||
|
||||
// Method 2: look for album art in external files
|
||||
val parent = File(path).parentFile
|
||||
for (fallback in FALLBACKS) {
|
||||
val cover = File(parent, fallback)
|
||||
if (cover.exists()) {
|
||||
stream = FileInputStream(cover)
|
||||
return stream
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
override fun cleanup() {
|
||||
// already cleaned up in loadData and ByteArrayInputStream will be GC'd
|
||||
if (stream != null) {
|
||||
try {
|
||||
stream!!.close()
|
||||
} catch (ignore: IOException) {
|
||||
// can't do much about it
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
override fun cancel() {
|
||||
// cannot cancel
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private val FALLBACKS = arrayOf("cover.jpg", "album.jpg", "folder.jpg", "cover.png", "album.png", "folder.png")
|
||||
}
|
||||
}
|
||||
|
||||
class AudioFileCoverLoader : ModelLoader<AudioFileCover, InputStream> {
|
||||
override fun buildLoadData(model: AudioFileCover, width: Int, height: Int,
|
||||
options: Options): LoadData<InputStream>? {
|
||||
|
|
|
@ -1,8 +1,33 @@
|
|||
package code.name.monkey.retromusic.glide.palette
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.widget.ImageView
|
||||
import androidx.palette.graphics.Palette
|
||||
import code.name.monkey.retromusic.util.RetroColorUtil
|
||||
import com.bumptech.glide.load.Options
|
||||
import com.bumptech.glide.load.engine.Resource
|
||||
import com.bumptech.glide.load.resource.transcode.ResourceTranscoder
|
||||
import com.bumptech.glide.request.target.ImageViewTarget
|
||||
import com.bumptech.glide.util.Util
|
||||
|
||||
class BitmapPaletteTranscoder : ResourceTranscoder<Bitmap, BitmapPaletteWrapper> {
|
||||
override fun transcode(bitmapResource: Resource<Bitmap>, options: Options): Resource<BitmapPaletteWrapper>? {
|
||||
val bitmap = bitmapResource.get()
|
||||
val bitmapPaletteWrapper = BitmapPaletteWrapper(bitmap, RetroColorUtil.generatePalette(bitmap)!!)
|
||||
return BitmapPaletteResource(bitmapPaletteWrapper)
|
||||
}
|
||||
}
|
||||
|
||||
class BitmapPaletteWrapper(val bitmap: Bitmap, val palette: Palette)
|
||||
|
||||
open class BitmapPaletteTarget(view: ImageView) : ImageViewTarget<BitmapPaletteWrapper>(view) {
|
||||
|
||||
override fun setResource(bitmapPaletteWrapper: BitmapPaletteWrapper?) {
|
||||
if (bitmapPaletteWrapper != null) {
|
||||
view.setImageBitmap(bitmapPaletteWrapper.bitmap)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class BitmapPaletteResource(private val bitmapPaletteWrapper: BitmapPaletteWrapper) : Resource<BitmapPaletteWrapper> {
|
||||
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
package code.name.monkey.retromusic.glide.palette
|
||||
|
||||
import android.widget.ImageView
|
||||
|
||||
import com.bumptech.glide.request.target.ImageViewTarget
|
||||
|
||||
open class BitmapPaletteTarget(view: ImageView) : ImageViewTarget<BitmapPaletteWrapper>(view) {
|
||||
|
||||
override fun setResource(bitmapPaletteWrapper: BitmapPaletteWrapper?) {
|
||||
if (bitmapPaletteWrapper != null) {
|
||||
view.setImageBitmap(bitmapPaletteWrapper.bitmap)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
package code.name.monkey.retromusic.glide.palette
|
||||
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import code.name.monkey.retromusic.util.RetroColorUtil
|
||||
import com.bumptech.glide.load.Options
|
||||
import com.bumptech.glide.load.engine.Resource
|
||||
import com.bumptech.glide.load.resource.transcode.ResourceTranscoder
|
||||
|
||||
class BitmapPaletteTranscoder : ResourceTranscoder<Bitmap, BitmapPaletteWrapper> {
|
||||
override fun transcode(bitmapResource: Resource<Bitmap>, options: Options): Resource<BitmapPaletteWrapper>? {
|
||||
val bitmap = bitmapResource.get()
|
||||
val bitmapPaletteWrapper = BitmapPaletteWrapper(bitmap, RetroColorUtil.generatePalette(bitmap)!!)
|
||||
return BitmapPaletteResource(bitmapPaletteWrapper)
|
||||
}
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
package code.name.monkey.retromusic.glide.palette
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import androidx.palette.graphics.Palette
|
||||
|
||||
class BitmapPaletteWrapper(val bitmap: Bitmap, val palette: Palette)
|
|
@ -12,13 +12,10 @@ import android.provider.MediaStore
|
|||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.App
|
||||
import code.name.monkey.retromusic.loaders.SongLoader
|
||||
import code.name.monkey.retromusic.model.Song
|
||||
import code.name.monkey.retromusic.service.MusicService
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||
import com.google.android.gms.cast.framework.CastContext
|
||||
import com.google.android.gms.cast.framework.CastSession
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
|
@ -28,19 +25,6 @@ object MusicPlayerRemote {
|
|||
val TAG = MusicPlayerRemote::class.java.simpleName
|
||||
private val mConnectionMap = WeakHashMap<Context, ServiceBinder>()
|
||||
var musicService: MusicService? = null
|
||||
private var playbackLocation = PlaybackLocation.LOCAL
|
||||
|
||||
|
||||
private val castSession: CastSession?
|
||||
get() {
|
||||
val castSession = CastContext.getSharedInstance(App.instance).sessionManager.currentCastSession
|
||||
if (castSession != null) {
|
||||
playbackLocation = PlaybackLocation.REMOTE
|
||||
} else {
|
||||
playbackLocation = PlaybackLocation.LOCAL
|
||||
}
|
||||
return castSession
|
||||
}
|
||||
|
||||
val isPlaying: Boolean
|
||||
get() = musicService != null && musicService!!.isPlaying
|
||||
|
|
|
@ -88,7 +88,7 @@ class AboutActivity : AbsBaseActivity(), View.OnClickListener {
|
|||
toolbar.setBackgroundColor(ThemeStore.primaryColor(this))
|
||||
setSupportActionBar(toolbar)
|
||||
title = null
|
||||
ToolbarContentTintHelper.colorBackButton(toolbar, ThemeStore.accentColor(this))
|
||||
ToolbarContentTintHelper.colorBackButton(toolbar, ThemeStore.textColorSecondary(this))
|
||||
}
|
||||
|
||||
private fun openUrl(url: String) {
|
||||
|
@ -161,8 +161,7 @@ class AboutActivity : AbsBaseActivity(), View.OnClickListener {
|
|||
.setText(String.format(getString(R.string.app_share), packageName))
|
||||
.intent
|
||||
if (shareIntent.resolveActivity(packageManager) != null) {
|
||||
startActivity(
|
||||
Intent.createChooser(shareIntent, resources.getText(R.string.action_share)))
|
||||
startActivity(Intent.createChooser(shareIntent, resources.getText(R.string.action_share)))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import android.os.Bundle
|
|||
import android.transition.Slide
|
||||
import android.view.*
|
||||
import android.view.animation.AnimationUtils
|
||||
import android.widget.ImageView
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.util.Pair
|
||||
import androidx.core.widget.NestedScrollView
|
||||
|
@ -39,6 +40,9 @@ import code.name.monkey.retromusic.util.NavigationUtil
|
|||
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||
import code.name.monkey.retromusic.util.RetroUtil
|
||||
import com.google.android.material.appbar.AppBarLayout
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import kotlinx.android.synthetic.main.activity_album.*
|
||||
import kotlinx.android.synthetic.main.activity_album_content.*
|
||||
import java.util.*
|
||||
|
@ -47,6 +51,7 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), AlbumDetailsContrac
|
|||
|
||||
private lateinit var albumDetailsPresenter: AlbumDetailsPresenter
|
||||
private lateinit var simpleSongAdapter: SimpleSongAdapter
|
||||
private var disposable = CompositeDisposable()
|
||||
|
||||
var album: Album? = null
|
||||
private set
|
||||
|
@ -68,11 +73,11 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), AlbumDetailsContrac
|
|||
setDrawUnderStatusBar()
|
||||
setupWindowTransition()
|
||||
super.onCreate(savedInstanceState)
|
||||
toggleBottomNavigationView(true)
|
||||
|
||||
setLightNavigationBar(true)
|
||||
setNavigationbarColorAuto()
|
||||
|
||||
toggleBottomNavigationView(true)
|
||||
|
||||
ActivityCompat.postponeEnterTransition(this)
|
||||
|
||||
|
@ -95,6 +100,8 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), AlbumDetailsContrac
|
|||
}
|
||||
|
||||
actionShuffleAll.setOnClickListener { MusicPlayerRemote.openAndShuffleQueue(album!!.songs!!, true) }
|
||||
|
||||
artistImage = findViewById(R.id.artistImage)
|
||||
artistImage.setOnClickListener {
|
||||
val artistPairs = arrayOf<Pair<*, *>>(Pair.create(image, resources.getString(R.string.transition_artist_image)))
|
||||
NavigationUtil.goToArtist(this, album!!.artistId, *artistPairs)
|
||||
|
@ -134,24 +141,22 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), AlbumDetailsContrac
|
|||
toolbar!!.layoutParams = params
|
||||
}
|
||||
|
||||
if (appBarLayout != null) {
|
||||
appBarLayout!!.apply {
|
||||
addOnOffsetChangedListener(object : AppBarStateChangeListener() {
|
||||
override fun onStateChanged(appBarLayout: AppBarLayout, state: AppBarStateChangeListener.State) {
|
||||
val color: Int = when (state) {
|
||||
AppBarStateChangeListener.State.COLLAPSED -> {
|
||||
setLightStatusbar(ColorUtil.isColorLight(ThemeStore.primaryColor(this@AlbumDetailsActivity)))
|
||||
ThemeStore.primaryColor(this@AlbumDetailsActivity)
|
||||
}
|
||||
AppBarStateChangeListener.State.EXPANDED, AppBarStateChangeListener.State.IDLE -> {
|
||||
setLightStatusbar(false)
|
||||
Color.TRANSPARENT
|
||||
}
|
||||
appBarLayout!!.apply {
|
||||
addOnOffsetChangedListener(object : AppBarStateChangeListener() {
|
||||
override fun onStateChanged(appBarLayout: AppBarLayout, state: AppBarStateChangeListener.State) {
|
||||
val color: Int = when (state) {
|
||||
AppBarStateChangeListener.State.COLLAPSED -> {
|
||||
setLightStatusbar(ColorUtil.isColorLight(ThemeStore.primaryColor(this@AlbumDetailsActivity)))
|
||||
ThemeStore.primaryColor(this@AlbumDetailsActivity)
|
||||
}
|
||||
AppBarStateChangeListener.State.EXPANDED, AppBarStateChangeListener.State.IDLE -> {
|
||||
setLightStatusbar(false)
|
||||
Color.TRANSPARENT
|
||||
}
|
||||
ToolbarContentTintHelper.setToolbarContentColorBasedOnToolbarColor(this@AlbumDetailsActivity, toolbar, color)
|
||||
}
|
||||
})
|
||||
}
|
||||
ToolbarContentTintHelper.setToolbarContentColorBasedOnToolbarColor(this@AlbumDetailsActivity, toolbar, color)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -160,6 +165,11 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), AlbumDetailsContrac
|
|||
albumDetailsPresenter.unsubscribe()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
disposable.dispose()
|
||||
}
|
||||
|
||||
override fun loading() {
|
||||
|
||||
}
|
||||
|
@ -188,33 +198,42 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), AlbumDetailsContrac
|
|||
simpleSongAdapter.swapDataSet(list.songs)
|
||||
}
|
||||
|
||||
private lateinit var artistImage: ImageView
|
||||
|
||||
private fun loadMoreFrom(album: Album) {
|
||||
if (artistImage != null) {
|
||||
/*ArtistGlideRequest.Builder.from(Glide.with(this),
|
||||
ArtistLoader.getArtist(this, album.artistId).blockingFirst())
|
||||
.forceDownload(false)
|
||||
.generatePalette(this).build()
|
||||
.dontAnimate()
|
||||
.into(object : RetroMusicColoredTarget(artistImage as CircularImageView) {
|
||||
override fun onColorReady(color: Int) {
|
||||
//setColors(color);
|
||||
}
|
||||
})*/
|
||||
}
|
||||
disposable.add(ArtistLoader.getArtist(this, album.artistId)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.map {
|
||||
GlideApp.with(this@AlbumDetailsActivity)
|
||||
.asBitmapPalette()
|
||||
.load(RetroGlideExtension.getArtistModel(it))
|
||||
.transition(RetroGlideExtension.getDefaultTransition())
|
||||
.artistOptions(it)
|
||||
.dontAnimate()
|
||||
.into(object : RetroMusicColoredTarget(artistImage) {
|
||||
override fun onColorReady(color: Int) {
|
||||
|
||||
val albums = ArtistLoader.getArtist(this, album.artistId).blockingFirst().albums
|
||||
albums!!.remove(album)
|
||||
if (!albums.isEmpty()) {
|
||||
moreTitle.visibility = View.VISIBLE
|
||||
moreRecyclerView.visibility = View.VISIBLE
|
||||
} else {
|
||||
return
|
||||
}
|
||||
moreTitle.text = String.format("More from %s", album.artistName)
|
||||
}
|
||||
})
|
||||
return@map it.albums!!
|
||||
}
|
||||
.subscribe {
|
||||
|
||||
val albumAdapter = HorizontalAlbumAdapter(this, albums, false, null)
|
||||
moreRecyclerView.layoutManager = GridLayoutManager(this, 1, GridLayoutManager.HORIZONTAL, false)
|
||||
moreRecyclerView.adapter = albumAdapter
|
||||
it.remove(album)
|
||||
if (!it.isEmpty()) {
|
||||
moreTitle.visibility = View.VISIBLE
|
||||
moreRecyclerView.visibility = View.VISIBLE
|
||||
} else {
|
||||
return@subscribe
|
||||
}
|
||||
moreTitle.text = String.format("More from %s", album.artistName)
|
||||
|
||||
val albumAdapter = HorizontalAlbumAdapter(this, it, false, null)
|
||||
moreRecyclerView.layoutManager = GridLayoutManager(this, 1, GridLayoutManager.HORIZONTAL, false)
|
||||
moreRecyclerView.adapter = albumAdapter
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
private fun loadAlbumCover() {
|
||||
|
|
|
@ -55,7 +55,7 @@ class ArtistDetailActivity : AbsSlidingMusicPanelActivity(), ArtistDetailContrac
|
|||
private var albumAdapter: AlbumAdapter? = null
|
||||
private var forceDownload: Boolean = false
|
||||
|
||||
private fun setupWindowTransistion() {
|
||||
private fun setupWindowTransitions() {
|
||||
val slide = Slide(Gravity.BOTTOM)
|
||||
slide.interpolator = AnimationUtils.loadInterpolator(this, android.R.interpolator.linear_out_slow_in)
|
||||
window.enterTransition = slide
|
||||
|
@ -68,7 +68,7 @@ class ArtistDetailActivity : AbsSlidingMusicPanelActivity(), ArtistDetailContrac
|
|||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
setDrawUnderStatusBar()
|
||||
setupWindowTransistion()
|
||||
setupWindowTransitions()
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
|
||||
|
@ -143,15 +143,14 @@ class ArtistDetailActivity : AbsSlidingMusicPanelActivity(), ArtistDetailContrac
|
|||
if (appBarLayout != null) {
|
||||
appBarLayout!!.addOnOffsetChangedListener(object : AppBarStateChangeListener() {
|
||||
override fun onStateChanged(appBarLayout: AppBarLayout, state: AppBarStateChangeListener.State) {
|
||||
val color: Int
|
||||
when (state) {
|
||||
val color: Int = when (state) {
|
||||
AppBarStateChangeListener.State.COLLAPSED -> {
|
||||
setLightStatusbar(ColorUtil.isColorLight(ThemeStore.primaryColor(appBarLayout.context)))
|
||||
color = ThemeStore.primaryColor(appBarLayout.context)
|
||||
ThemeStore.primaryColor(appBarLayout.context)
|
||||
}
|
||||
AppBarStateChangeListener.State.EXPANDED, AppBarStateChangeListener.State.IDLE -> {
|
||||
setLightStatusbar(false)
|
||||
color = Color.TRANSPARENT
|
||||
Color.TRANSPARENT
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -204,8 +203,8 @@ class ArtistDetailActivity : AbsSlidingMusicPanelActivity(), ArtistDetailContrac
|
|||
ActivityCompat.startPostponedEnterTransition(this)
|
||||
}
|
||||
|
||||
override fun showData(artist: Artist) {
|
||||
setArtist(artist)
|
||||
override fun showData(list: Artist) {
|
||||
setArtist(list)
|
||||
}
|
||||
|
||||
private fun getArtist(): Artist {
|
||||
|
@ -296,7 +295,6 @@ class ArtistDetailActivity : AbsSlidingMusicPanelActivity(), ArtistDetailContrac
|
|||
|
||||
actionShuffleAll.setColor(textColor)
|
||||
|
||||
|
||||
findViewById<View>(R.id.root).setBackgroundColor(ThemeStore.primaryColor(this))
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ import androidx.core.content.ContextCompat
|
|||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.fragment.app.FragmentStatePagerAdapter
|
||||
import androidx.viewpager.widget.ViewPager
|
||||
import code.name.monkey.appthemehelper.ThemeStore
|
||||
import code.name.monkey.appthemehelper.util.TintHelper
|
||||
import code.name.monkey.retromusic.App
|
||||
|
@ -23,6 +24,7 @@ import code.name.monkey.retromusic.ui.activities.tageditor.WriteTagsAsyncTask
|
|||
import code.name.monkey.retromusic.ui.fragments.base.AbsMusicServiceFragment
|
||||
import code.name.monkey.retromusic.util.LyricUtil
|
||||
import code.name.monkey.retromusic.util.MusicUtil
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||
import code.name.monkey.retromusic.util.RetroUtil
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import kotlinx.android.synthetic.main.activity_lyrics.*
|
||||
|
@ -32,7 +34,19 @@ import org.jaudiotagger.tag.FieldKey
|
|||
import java.io.File
|
||||
import java.util.*
|
||||
|
||||
class LyricsActivity : AbsMusicServiceActivity(), View.OnClickListener {
|
||||
class LyricsActivity : AbsMusicServiceActivity(), View.OnClickListener, ViewPager.OnPageChangeListener {
|
||||
override fun onPageScrollStateChanged(state: Int) {
|
||||
|
||||
}
|
||||
|
||||
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
|
||||
|
||||
}
|
||||
|
||||
override fun onPageSelected(position: Int) {
|
||||
PreferenceUtil.getInstance().lyricsOptions = position
|
||||
}
|
||||
|
||||
override fun onClick(v: View?) {
|
||||
when (viewPager.currentItem) {
|
||||
0 -> showSyncedLyrics()
|
||||
|
@ -41,7 +55,7 @@ class LyricsActivity : AbsMusicServiceActivity(), View.OnClickListener {
|
|||
}
|
||||
|
||||
private lateinit var song: Song
|
||||
private var lyrics: Lyrics? = null
|
||||
private var lyricsString: String? = null
|
||||
|
||||
private val googleSearchLrcUrl: String
|
||||
get() {
|
||||
|
@ -73,7 +87,10 @@ class LyricsActivity : AbsMusicServiceActivity(), View.OnClickListener {
|
|||
|
||||
viewPager.apply {
|
||||
adapter = PagerAdapter(supportFragmentManager)
|
||||
currentItem = PreferenceUtil.getInstance().lyricsOptions
|
||||
addOnPageChangeListener(this@LyricsActivity)
|
||||
}
|
||||
|
||||
tabs.apply {
|
||||
setupWithViewPager(viewPager)
|
||||
setSelectedTabIndicator(TintHelper.createTintedDrawable(ContextCompat.getDrawable(this@LyricsActivity, R.drawable.tab_indicator), ThemeStore.accentColor(this@LyricsActivity)))
|
||||
|
@ -132,10 +149,10 @@ class LyricsActivity : AbsMusicServiceActivity(), View.OnClickListener {
|
|||
}
|
||||
|
||||
private fun showLyricsSaveDialog() {
|
||||
val content: String = if (lyrics == null) {
|
||||
val content: String = if (lyricsString == null) {
|
||||
""
|
||||
} else {
|
||||
lyrics!!.data
|
||||
lyricsString!!
|
||||
}
|
||||
MaterialDialog.Builder(this)
|
||||
.title("Add lyrics")
|
||||
|
@ -163,155 +180,160 @@ class LyricsActivity : AbsMusicServiceActivity(), View.OnClickListener {
|
|||
baseUrl += query
|
||||
return baseUrl
|
||||
}
|
||||
}
|
||||
|
||||
class PagerAdapter(fm: FragmentManager) : FragmentStatePagerAdapter(fm) {
|
||||
override fun getItem(position: Int): Fragment {
|
||||
return when (position) {
|
||||
0 -> SyncedLyricsFragment()
|
||||
1 -> OfflineLyricsFragment()
|
||||
else -> {
|
||||
SyncedLyricsFragment()
|
||||
class PagerAdapter(fm: FragmentManager) : FragmentStatePagerAdapter(fm) {
|
||||
override fun getItem(position: Int): Fragment {
|
||||
return when (position) {
|
||||
0 -> SyncedLyricsFragment()
|
||||
1 -> OfflineLyricsFragment()
|
||||
else -> SyncedLyricsFragment()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getPageTitle(position: Int): CharSequence? {
|
||||
return when (position) {
|
||||
0 -> App.context.getString(R.string.synced_lyrics)
|
||||
1 -> App.context.getString(R.string.normal_lyrics)
|
||||
else -> {
|
||||
App.context.getString(R.string.synced_lyrics)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getCount(): Int {
|
||||
return 2
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class OfflineLyricsFragment : AbsMusicServiceFragment() {
|
||||
|
||||
private var updateLyricsAsyncTask: AsyncTask<*, *, *>? = null
|
||||
private var lyrics: Lyrics? = null
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
private fun loadSongLyrics() {
|
||||
if (updateLyricsAsyncTask != null) {
|
||||
updateLyricsAsyncTask!!.cancel(false)
|
||||
}
|
||||
val song = MusicPlayerRemote.currentSong
|
||||
updateLyricsAsyncTask = object : AsyncTask<Void?, Void?, Lyrics?>() {
|
||||
override fun doInBackground(vararg params: Void?): Lyrics? {
|
||||
val data = MusicUtil.getLyrics(song)
|
||||
return if (TextUtils.isEmpty(data)) {
|
||||
null
|
||||
} else Lyrics.parse(song, data)
|
||||
}
|
||||
|
||||
override fun onPreExecute() {
|
||||
super.onPreExecute()
|
||||
lyrics = null
|
||||
}
|
||||
|
||||
override fun onPostExecute(l: Lyrics?) {
|
||||
lyrics = l
|
||||
offlineLyrics.visibility = View.VISIBLE
|
||||
if (l == null) {
|
||||
offlineLyrics.setText(R.string.no_lyrics_found)
|
||||
return
|
||||
override fun getPageTitle(position: Int): CharSequence? {
|
||||
return when (position) {
|
||||
0 -> App.context.getString(R.string.synced_lyrics)
|
||||
1 -> App.context.getString(R.string.normal_lyrics)
|
||||
else -> {
|
||||
App.context.getString(R.string.synced_lyrics)
|
||||
}
|
||||
offlineLyrics.text = l.data
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCancelled(s: Lyrics?) {
|
||||
onPostExecute(null)
|
||||
override fun getCount(): Int {
|
||||
return 2
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
abstract class BaseLyricsFragment : AbsMusicServiceFragment() {
|
||||
abstract fun upDateSong()
|
||||
|
||||
override fun onPlayingMetaChanged() {
|
||||
super.onPlayingMetaChanged()
|
||||
upDateSong()
|
||||
}
|
||||
|
||||
override fun onServiceConnected() {
|
||||
super.onServiceConnected()
|
||||
upDateSong()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class OfflineLyricsFragment : BaseLyricsFragment() {
|
||||
override fun upDateSong() {
|
||||
loadSongLyrics()
|
||||
}
|
||||
|
||||
private var updateLyricsAsyncTask: AsyncTask<*, *, *>? = null
|
||||
private var lyrics: Lyrics? = null
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
private fun loadSongLyrics() {
|
||||
if (updateLyricsAsyncTask != null) {
|
||||
updateLyricsAsyncTask!!.cancel(false)
|
||||
}
|
||||
}.execute()
|
||||
}
|
||||
val song = MusicPlayerRemote.currentSong
|
||||
updateLyricsAsyncTask = object : AsyncTask<Void?, Void?, Lyrics?>() {
|
||||
override fun doInBackground(vararg params: Void?): Lyrics? {
|
||||
val data = MusicUtil.getLyrics(song)
|
||||
return if (TextUtils.isEmpty(data)) {
|
||||
null
|
||||
} else Lyrics.parse(song, data)
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
if (updateLyricsAsyncTask != null && !updateLyricsAsyncTask!!.isCancelled) {
|
||||
updateLyricsAsyncTask!!.cancel(true)
|
||||
override fun onPreExecute() {
|
||||
super.onPreExecute()
|
||||
lyrics = null
|
||||
}
|
||||
|
||||
override fun onPostExecute(l: Lyrics?) {
|
||||
lyrics = l
|
||||
offlineLyrics.visibility = View.VISIBLE
|
||||
if (l == null) {
|
||||
offlineLyrics.setText(R.string.no_lyrics_found)
|
||||
return
|
||||
}
|
||||
(activity as LyricsActivity).lyricsString = l.data
|
||||
offlineLyrics.text = l.data
|
||||
}
|
||||
|
||||
override fun onCancelled(s: Lyrics?) {
|
||||
onPostExecute(null)
|
||||
}
|
||||
}.execute()
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
if (updateLyricsAsyncTask != null && !updateLyricsAsyncTask!!.isCancelled) {
|
||||
updateLyricsAsyncTask!!.cancel(true)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.fragment_lyrics, container, false)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
loadSongLyrics()
|
||||
}
|
||||
class SyncedLyricsFragment : BaseLyricsFragment(), MusicProgressViewUpdateHelper.Callback {
|
||||
override fun upDateSong() {
|
||||
loadLRCLyrics()
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.fragment_lyrics, container, false)
|
||||
}
|
||||
}
|
||||
private lateinit var updateHelper: MusicProgressViewUpdateHelper
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.fragment_synced, container, false)
|
||||
}
|
||||
|
||||
class SyncedLyricsFragment : AbsMusicServiceFragment(), MusicProgressViewUpdateHelper.Callback {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
updateHelper = MusicProgressViewUpdateHelper(this, 500, 1000)
|
||||
}
|
||||
|
||||
private lateinit var updateHelper: MusicProgressViewUpdateHelper
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.fragment_synced, container, false)
|
||||
}
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
setupLyricsView()
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
updateHelper = MusicProgressViewUpdateHelper(this, 500, 1000)
|
||||
}
|
||||
private fun setupLyricsView() {
|
||||
lyricsView.apply {
|
||||
setOnPlayerClickListener { progress, _ -> MusicPlayerRemote.seekTo(progress.toInt()) }
|
||||
setDefaultColor(ContextCompat.getColor(context, R.color.md_grey_400))
|
||||
setHintColor(ThemeStore.textColorPrimary(context))
|
||||
setHighLightColor(ThemeStore.textColorPrimary(context))
|
||||
setTextSize(RetroUtil.convertDpToPixel(18f, context).toInt())
|
||||
}
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
setupLyricsView()
|
||||
}
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
updateHelper.start()
|
||||
}
|
||||
|
||||
private fun setupLyricsView() {
|
||||
lyricsView.apply {
|
||||
setOnPlayerClickListener { progress, _ -> MusicPlayerRemote.seekTo(progress.toInt()) }
|
||||
setDefaultColor(ContextCompat.getColor(context, R.color.md_grey_400))
|
||||
setHintColor(ThemeStore.textColorPrimary(context))
|
||||
setHighLightColor(ThemeStore.textColorPrimary(context))
|
||||
setTextSize(RetroUtil.convertDpToPixel(18f, context).toInt())
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
updateHelper.stop()
|
||||
}
|
||||
|
||||
override fun onUpdateProgressViews(progress: Int, total: Int) {
|
||||
lyricsView.setCurrentTimeMillis(progress.toLong())
|
||||
}
|
||||
|
||||
private fun loadLRCLyrics() {
|
||||
val song = MusicPlayerRemote.currentSong
|
||||
if (LyricUtil.isLrcFileExist(song.title, song.artistName)) {
|
||||
showLyricsLocal(LyricUtil.getLocalLyricFile(song.title, song.artistName))
|
||||
}
|
||||
}
|
||||
|
||||
private fun showLyricsLocal(file: File?) {
|
||||
if (file == null) {
|
||||
lyricsView.reset()
|
||||
} else {
|
||||
lyricsView.setLyricFile(file, "UTF-8")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPlayingMetaChanged() {
|
||||
super.onPlayingMetaChanged()
|
||||
loadLRCLyrics()
|
||||
}
|
||||
|
||||
override fun onServiceConnected() {
|
||||
super.onServiceConnected()
|
||||
loadLRCLyrics()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
updateHelper.start()
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
updateHelper.stop()
|
||||
}
|
||||
|
||||
override fun onUpdateProgressViews(progress: Int, total: Int) {
|
||||
lyricsView.setCurrentTimeMillis(progress.toLong())
|
||||
}
|
||||
|
||||
private fun loadLRCLyrics() {
|
||||
val song = MusicPlayerRemote.currentSong
|
||||
if (LyricUtil.isLrcFileExist(song.title, song.artistName)) {
|
||||
showLyricsLocal(LyricUtil.getLocalLyricFile(song.title, song.artistName))
|
||||
}
|
||||
}
|
||||
|
||||
private fun showLyricsLocal(file: File?) {
|
||||
if (file == null) {
|
||||
lyricsView!!.reset()
|
||||
} else {
|
||||
lyricsView!!.setLyricFile(file, "UTF-8")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -37,7 +37,6 @@ import java.util.*
|
|||
|
||||
class PlaylistDetailActivity : AbsSlidingMusicPanelActivity(), CabHolder, PlaylistSongsContract.PlaylistSongsView {
|
||||
|
||||
|
||||
private var playlist: Playlist? = null
|
||||
private var cab: MaterialCab? = null
|
||||
private lateinit var adapter: SongAdapter
|
||||
|
@ -49,7 +48,6 @@ class PlaylistDetailActivity : AbsSlidingMusicPanelActivity(), CabHolder, Playli
|
|||
setDrawUnderStatusBar()
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
|
||||
setStatusbarColor(Color.TRANSPARENT)
|
||||
setNavigationbarColorAuto()
|
||||
setTaskDescriptionColorAuto()
|
||||
|
@ -203,6 +201,7 @@ class PlaylistDetailActivity : AbsSlidingMusicPanelActivity(), CabHolder, Playli
|
|||
|
||||
private fun checkIsEmpty() {
|
||||
empty.visibility = if (adapter.itemCount == 0) View.VISIBLE else View.GONE
|
||||
emptyText.visibility = if (adapter.itemCount == 0) View.VISIBLE else View.GONE
|
||||
}
|
||||
|
||||
public override fun onPause() {
|
||||
|
@ -239,7 +238,8 @@ class PlaylistDetailActivity : AbsSlidingMusicPanelActivity(), CabHolder, Playli
|
|||
override fun loading() {}
|
||||
|
||||
override fun showEmptyView() {
|
||||
empty!!.visibility = View.VISIBLE
|
||||
empty.visibility = View.VISIBLE
|
||||
emptyText.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
override fun completed() {}
|
||||
|
|
|
@ -5,6 +5,7 @@ import android.app.SearchManager
|
|||
import android.content.ActivityNotFoundException
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.res.ColorStateList
|
||||
import android.os.Bundle
|
||||
import android.speech.RecognizerIntent
|
||||
import android.text.Editable
|
||||
|
@ -15,6 +16,8 @@ import android.widget.Toast
|
|||
import androidx.appcompat.widget.SearchView.OnQueryTextListener
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import code.name.monkey.appthemehelper.ThemeStore
|
||||
import code.name.monkey.appthemehelper.util.ColorUtil
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.mvp.contract.SearchContract
|
||||
import code.name.monkey.retromusic.mvp.presenter.SearchPresenter
|
||||
|
@ -35,7 +38,6 @@ class SearchActivity : AbsMusicServiceActivity(), OnQueryTextListener, SearchCon
|
|||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_search)
|
||||
|
||||
|
||||
searchPresenter = SearchPresenter(this)
|
||||
|
||||
setStatusbarColorAuto()
|
||||
|
@ -57,10 +59,12 @@ class SearchActivity : AbsMusicServiceActivity(), OnQueryTextListener, SearchCon
|
|||
}
|
||||
back.setOnClickListener { onBackPressed() }
|
||||
voiceSearch.setOnClickListener { startMicSearch() }
|
||||
|
||||
searchContainer.setCardBackgroundColor(ColorStateList.valueOf(ColorUtil.darkenColor(ThemeStore.primaryColor(this))))
|
||||
|
||||
}
|
||||
|
||||
private fun setupRecyclerView() {
|
||||
|
||||
searchAdapter = SearchAdapter(this, emptyList())
|
||||
searchAdapter!!.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
|
||||
override fun onChanged() {
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
package code.name.monkey.retromusic.ui.activities
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.MenuItem
|
||||
import androidx.annotation.ColorInt
|
||||
import androidx.annotation.StringRes
|
||||
|
@ -13,6 +10,7 @@ import code.name.monkey.appthemehelper.ThemeStore
|
|||
import code.name.monkey.appthemehelper.util.ColorUtil
|
||||
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
|
||||
import code.name.monkey.appthemehelper.util.VersionUtils
|
||||
import code.name.monkey.retromusic.App.Companion.context
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.appshortcuts.DynamicShortcutManager
|
||||
import code.name.monkey.retromusic.ui.activities.base.AbsBaseActivity
|
||||
|
@ -67,11 +65,13 @@ class SettingsActivity : AbsBaseActivity(), ColorChooserDialog.ColorCallback, Sh
|
|||
private fun setupToolbar() {
|
||||
setSupportActionBar(toolbar)
|
||||
title = null
|
||||
toolbar.setBackgroundColor(ThemeStore.primaryColor(this))
|
||||
toolbar.apply {
|
||||
setBackgroundColor(ThemeStore.primaryColor(context))
|
||||
setNavigationOnClickListener { onBackPressed() }
|
||||
ToolbarContentTintHelper.colorBackButton(toolbar, ThemeStore.textColorSecondary(context))
|
||||
}
|
||||
appBarLayout.setBackgroundColor(ThemeStore.primaryColor(this))
|
||||
toolbar.setNavigationOnClickListener { onBackPressed() }
|
||||
settingsTitle.setTextColor(ThemeStore.textColorPrimary(this))
|
||||
ToolbarContentTintHelper.colorBackButton(toolbar, ThemeStore.accentColor(this))
|
||||
}
|
||||
|
||||
fun setupFragment(fragment: Fragment, @StringRes titleName: Int) {
|
||||
|
@ -126,6 +126,6 @@ class SettingsActivity : AbsBaseActivity(), ColorChooserDialog.ColorCallback, Sh
|
|||
|
||||
|
||||
companion object {
|
||||
const val TAG: String = "SettingsActivity"
|
||||
const val TAG: String = "SettingsActivity"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -180,7 +180,7 @@ class UserInfoActivity : AbsBaseActivity() {
|
|||
}
|
||||
|
||||
private fun loadBannerFromStorage(profileImagePath: String) {
|
||||
disposable!!.add(Compressor(this)
|
||||
disposable.add(Compressor(this)
|
||||
.setQuality(100)
|
||||
.setCompressFormat(Bitmap.CompressFormat.WEBP)
|
||||
.compressToBitmapAsFlowable(File(profileImagePath, USER_BANNER))
|
||||
|
@ -190,7 +190,7 @@ class UserInfoActivity : AbsBaseActivity() {
|
|||
}
|
||||
|
||||
private fun loadImageFromStorage(path: String) {
|
||||
disposable!!.add(Compressor(this)
|
||||
disposable.add(Compressor(this)
|
||||
.setMaxHeight(300)
|
||||
.setMaxWidth(300)
|
||||
.setQuality(75)
|
||||
|
|
|
@ -1,135 +0,0 @@
|
|||
package code.name.monkey.retromusic.ui.activities.base
|
||||
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import code.name.monkey.retromusic.cast.WebServer
|
||||
import com.google.android.gms.cast.framework.CastContext
|
||||
import com.google.android.gms.cast.framework.CastSession
|
||||
import com.google.android.gms.cast.framework.SessionManagerListener
|
||||
import com.google.android.gms.common.ConnectionResult
|
||||
import com.google.android.gms.common.GoogleApiAvailability
|
||||
import java.io.IOException
|
||||
|
||||
abstract class AbsCastActivity : AbsCheckPiracy() {
|
||||
|
||||
var playServicesAvailable = false
|
||||
|
||||
private var castContext: CastContext? = null
|
||||
private var sessionManagerListener: SessionManagerListener<CastSession>? = null
|
||||
var castSession: CastSession? = null
|
||||
private set
|
||||
private var castServer: WebServer? = null
|
||||
|
||||
private fun setupCastListener() {
|
||||
sessionManagerListener = object : SessionManagerListener<CastSession> {
|
||||
|
||||
override fun onSessionEnded(session: CastSession, error: Int) {
|
||||
onApplicationDisconnected()
|
||||
Log.i(TAG, "onSessionEnded: ")
|
||||
}
|
||||
|
||||
override fun onSessionResumed(session: CastSession, wasSuspended: Boolean) {
|
||||
onApplicationConnected(session)
|
||||
Log.i(TAG, "onSessionResumed: ")
|
||||
}
|
||||
|
||||
override fun onSessionResumeFailed(session: CastSession, error: Int) {
|
||||
onApplicationDisconnected()
|
||||
Log.i(TAG, "onSessionResumeFailed: ")
|
||||
}
|
||||
|
||||
override fun onSessionStarted(session: CastSession, sessionId: String) {
|
||||
onApplicationConnected(session)
|
||||
Log.i(TAG, "onSessionStarted: ")
|
||||
}
|
||||
|
||||
override fun onSessionStartFailed(session: CastSession, error: Int) {
|
||||
onApplicationDisconnected()
|
||||
Log.i(TAG, "onSessionStartFailed: ")
|
||||
}
|
||||
|
||||
override fun onSessionStarting(session: CastSession) {}
|
||||
|
||||
override fun onSessionEnding(session: CastSession) {}
|
||||
|
||||
override fun onSessionResuming(session: CastSession, sessionId: String) {}
|
||||
|
||||
override fun onSessionSuspended(session: CastSession, reason: Int) {}
|
||||
|
||||
private fun onApplicationConnected(castSession: CastSession) {
|
||||
this@AbsCastActivity.castSession = castSession
|
||||
castServer = WebServer(applicationContext)
|
||||
try {
|
||||
castServer!!.start()
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
invalidateOptionsMenu()
|
||||
showCastMiniController()
|
||||
}
|
||||
|
||||
private fun onApplicationDisconnected() {
|
||||
if (castServer != null) {
|
||||
castServer!!.stop()
|
||||
}
|
||||
invalidateOptionsMenu()
|
||||
hideCastMiniController()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
try {
|
||||
playServicesAvailable = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(this) == ConnectionResult.SUCCESS
|
||||
} catch (ignored: Exception) {
|
||||
|
||||
}
|
||||
|
||||
if (playServicesAvailable)
|
||||
initCast()
|
||||
|
||||
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
if (playServicesAvailable) {
|
||||
castContext!!.sessionManager.addSessionManagerListener(sessionManagerListener!!, CastSession::class.java)
|
||||
}
|
||||
super.onResume()
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
if (playServicesAvailable) {
|
||||
castContext!!.sessionManager.removeSessionManagerListener(sessionManagerListener, CastSession::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
private fun initCast() {
|
||||
setupCastListener()
|
||||
castContext = CastContext.getSharedInstance(this)
|
||||
castSession = castContext!!.sessionManager.currentCastSession
|
||||
}
|
||||
|
||||
/* @Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.menu_cast, menu);
|
||||
if (playServicesAvailable) {
|
||||
CastButtonFactory.setUpMediaRouteButton(getApplicationContext(), menu, R.id.media_route_menu_item);
|
||||
}
|
||||
return true;
|
||||
}*/
|
||||
|
||||
open fun showCastMiniController() {
|
||||
//implement by overriding in activities
|
||||
}
|
||||
|
||||
open fun hideCastMiniController() {
|
||||
//implement by overriding in activities
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val TAG = "AbsCastActivity"
|
||||
}
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
package code.name.monkey.retromusic.ui.activities.base;
|
||||
|
||||
abstract public class AbsCheckPiracy extends AbsBaseActivity {
|
||||
|
||||
}
|
|
@ -17,7 +17,7 @@ import java.lang.ref.WeakReference
|
|||
import java.util.*
|
||||
|
||||
|
||||
abstract class AbsMusicServiceActivity : AbsCastActivity(), MusicServiceEventListener {
|
||||
abstract class AbsMusicServiceActivity : AbsBaseActivity(), MusicServiceEventListener {
|
||||
|
||||
private val mMusicServiceEventListeners = ArrayList<MusicServiceEventListener>()
|
||||
|
||||
|
|
|
@ -31,7 +31,6 @@ import code.name.monkey.retromusic.ui.fragments.player.plain.PlainPlayerFragment
|
|||
import code.name.monkey.retromusic.ui.fragments.player.simple.SimplePlayerFragment
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||
import code.name.monkey.retromusic.views.BottomNavigationBarTinted
|
||||
import com.google.android.material.bottomnavigation.BottomNavigationView
|
||||
import com.sothree.slidinguppanel.SlidingUpPanelLayout
|
||||
import com.sothree.slidinguppanel.SlidingUpPanelLayout.PanelState
|
||||
import kotlinx.android.synthetic.main.sliding_music_panel_layout.*
|
||||
|
@ -125,13 +124,6 @@ abstract class AbsSlidingMusicPanelActivity protected constructor() : AbsMusicSe
|
|||
return false
|
||||
}
|
||||
|
||||
override fun onPlayingMetaChanged() {
|
||||
super.onPlayingMetaChanged()
|
||||
castSession ?: return
|
||||
//MusicPlayerRemote.setZeroVolume();
|
||||
//CastHelper.startCasting(castSession, MusicPlayerRemote.getCurrentSong());
|
||||
}
|
||||
|
||||
fun toggleBottomNavigationView(toggle: Boolean) {
|
||||
bottomNavigationView.visibility = if (toggle) View.GONE else View.VISIBLE
|
||||
}
|
||||
|
@ -189,7 +181,7 @@ abstract class AbsSlidingMusicPanelActivity protected constructor() : AbsMusicSe
|
|||
playerFragment!!.onHide()
|
||||
}
|
||||
|
||||
open fun onPanelExpanded() {
|
||||
open fun onPanelExpanded() {
|
||||
val playerFragmentColor = playerFragment!!.paletteColor
|
||||
super.setTaskDescriptionColor(playerFragmentColor)
|
||||
|
||||
|
|
|
@ -110,7 +110,7 @@ open class BugReportActivity : AbsThemeActivity() {
|
|||
})
|
||||
}
|
||||
|
||||
inputPassword!!.setOnEditorActionListener { _, actionId, event ->
|
||||
inputPassword!!.setOnEditorActionListener { _, actionId, _ ->
|
||||
if (actionId == EditorInfo.IME_ACTION_SEND) {
|
||||
reportIssue()
|
||||
return@setOnEditorActionListener true
|
||||
|
|
|
@ -4,7 +4,9 @@ import android.net.Uri
|
|||
import android.os.Bundle
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import androidx.core.content.ContextCompat
|
||||
import code.name.monkey.appthemehelper.ThemeStore
|
||||
import code.name.monkey.appthemehelper.util.TintHelper
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.loaders.SongLoader
|
||||
import kotlinx.android.synthetic.main.activity_song_tag_editor.*
|
||||
|
@ -19,11 +21,14 @@ class SongTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
|
|||
|
||||
private fun setupToolbar() {
|
||||
appBarLayout.setBackgroundColor(ThemeStore.primaryColor(this))
|
||||
toolbar.setBackgroundColor(ThemeStore.primaryColor(this))
|
||||
toolbar.setNavigationOnClickListener { onBackPressed() }
|
||||
toolbar.apply {
|
||||
setBackgroundColor(ThemeStore.primaryColor(context))
|
||||
navigationIcon = TintHelper.createTintedDrawable(ContextCompat.getDrawable(context, R.drawable.ic_keyboard_backspace_black_24dp), ThemeStore.textColorPrimary(context))
|
||||
setNavigationOnClickListener { onBackPressed() }
|
||||
setSupportActionBar(toolbar)
|
||||
}
|
||||
title = null
|
||||
bannerTitle!!.setTextColor(ThemeStore.textColorPrimary(this))
|
||||
setSupportActionBar(toolbar)
|
||||
bannerTitle.setTextColor(ThemeStore.textColorPrimary(this))
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
|
@ -113,5 +118,4 @@ class SongTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
|
|||
companion object {
|
||||
val TAG: String = SongTagEditorActivity::class.java.simpleName
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ import code.name.monkey.retromusic.ui.adapter.base.MediaEntryViewHolder
|
|||
import code.name.monkey.retromusic.util.MusicUtil
|
||||
import code.name.monkey.retromusic.util.NavigationUtil
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions
|
||||
import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView
|
||||
import java.util.*
|
||||
|
||||
|
@ -131,6 +131,7 @@ open class AlbumAdapter(protected val activity: AppCompatActivity,
|
|||
GlideApp.with(activity)
|
||||
.asBitmapPalette()
|
||||
.load(RetroGlideExtension.getSongModel(album.safeGetFirstSong()))
|
||||
|
||||
.transition(RetroGlideExtension.getDefaultTransition())
|
||||
.songOptions(album.safeGetFirstSong())
|
||||
.dontAnimate()
|
||||
|
|
|
@ -44,12 +44,15 @@ class HorizontalAlbumAdapter(activity: AppCompatActivity, dataSet: ArrayList<Alb
|
|||
.dontAnimate()
|
||||
.into(object : RetroMusicColoredTarget(holder.image!!) {
|
||||
override fun onColorReady(color: Int) {
|
||||
setColors(color, holder)
|
||||
if (usePalette)
|
||||
setColors(color, holder)
|
||||
else
|
||||
setColors(albumArtistFooterColor, holder)
|
||||
}
|
||||
|
||||
override fun onLoadFailed(errorDrawable: Drawable?) {
|
||||
super.onLoadFailed(errorDrawable)
|
||||
setColors(defaultFooterColor, holder)
|
||||
setColors(albumArtistFooterColor, holder)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -32,7 +32,8 @@ open class MiniPlayerFragment : AbsMusicServiceFragment(), MusicProgressViewUpda
|
|||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.fragment_mini_player, container, false)
|
||||
}
|
||||
override fun onClick(view: View) {
|
||||
|
||||
override fun onClick(view: View) {
|
||||
when (view.id) {
|
||||
R.id.actionPlayingQueue -> NavigationUtil.goToPlayingQueue(activity!!)
|
||||
R.id.actionNext -> MusicPlayerRemote.playNextSong()
|
||||
|
@ -49,13 +50,13 @@ open class MiniPlayerFragment : AbsMusicServiceFragment(), MusicProgressViewUpda
|
|||
setUpMiniPlayer()
|
||||
|
||||
if (RetroUtil.isTablet()) {
|
||||
actionNext!!.visibility = View.VISIBLE
|
||||
actionPrevious!!.visibility = View.VISIBLE
|
||||
actionPlayingQueue!!.visibility = View.VISIBLE
|
||||
actionNext.visibility = View.VISIBLE
|
||||
actionPrevious.visibility = View.VISIBLE
|
||||
actionPlayingQueue.visibility = View.VISIBLE
|
||||
} else {
|
||||
actionNext!!.visibility = if (PreferenceUtil.getInstance().isExtraMiniExtraControls) View.VISIBLE else View.GONE
|
||||
actionPlayingQueue!!.visibility = if (PreferenceUtil.getInstance().isExtraMiniExtraControls) View.GONE else View.VISIBLE
|
||||
actionPrevious!!.visibility = if (PreferenceUtil.getInstance().isExtraMiniExtraControls) View.VISIBLE else View.GONE
|
||||
actionNext.visibility = if (PreferenceUtil.getInstance().isExtraMiniExtraControls) View.VISIBLE else View.GONE
|
||||
actionPlayingQueue.visibility = if (PreferenceUtil.getInstance().isExtraMiniExtraControls) View.GONE else View.VISIBLE
|
||||
actionPrevious.visibility = if (PreferenceUtil.getInstance().isExtraMiniExtraControls) View.VISIBLE else View.GONE
|
||||
}
|
||||
|
||||
actionPlayingQueue.setOnClickListener(this)
|
||||
|
@ -65,7 +66,7 @@ open class MiniPlayerFragment : AbsMusicServiceFragment(), MusicProgressViewUpda
|
|||
|
||||
private fun setUpMiniPlayer() {
|
||||
setUpPlayPauseButton()
|
||||
progressBar!!.progressTintList = ColorStateList.valueOf(ThemeStore.accentColor(activity!!))
|
||||
progressBar.progressTintList = ColorStateList.valueOf(ThemeStore.accentColor(activity!!))
|
||||
}
|
||||
|
||||
private fun setUpPlayPauseButton() {
|
||||
|
@ -128,14 +129,13 @@ open class MiniPlayerFragment : AbsMusicServiceFragment(), MusicProgressViewUpda
|
|||
}
|
||||
|
||||
fun setColor(playerFragmentColor: Int) {
|
||||
|
||||
view!!.setBackgroundColor(playerFragmentColor)
|
||||
}
|
||||
|
||||
|
||||
class FlingPlayBackController(context: Context) : View.OnTouchListener {
|
||||
|
||||
internal var flingPlayBackController: GestureDetector
|
||||
var flingPlayBackController: GestureDetector
|
||||
|
||||
init {
|
||||
flingPlayBackController = GestureDetector(context,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package code.name.monkey.retromusic.ui.fragments
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.ColorStateList
|
||||
import android.graphics.Color
|
||||
import android.graphics.PorterDuff
|
||||
import android.media.AudioManager
|
||||
|
@ -10,7 +11,7 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
import android.widget.SeekBar
|
||||
import androidx.fragment.app.Fragment
|
||||
import code.name.monkey.appthemehelper.util.ATHUtil
|
||||
import code.name.monkey.appthemehelper.ThemeStore
|
||||
import code.name.monkey.appthemehelper.util.TintHelper
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
||||
|
@ -33,7 +34,7 @@ class VolumeFragment : Fragment(), SeekBar.OnSeekBarChangeListener, OnAudioVolum
|
|||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
setTintable(ATHUtil.resolveColor(context, R.attr.iconColor))
|
||||
setTintable(ThemeStore.textColorSecondary(context!!))
|
||||
volumeDown.setOnClickListener(this)
|
||||
volumeUp.setOnClickListener(this)
|
||||
}
|
||||
|
@ -98,7 +99,13 @@ class VolumeFragment : Fragment(), SeekBar.OnSeekBarChangeListener, OnAudioVolum
|
|||
}
|
||||
|
||||
private fun setProgressBarColor(newColor: Int) {
|
||||
TintHelper.setTintAuto(volumeSeekBar, newColor, false)
|
||||
|
||||
val text = ColorStateList(arrayOf(intArrayOf(-android.R.attr.state_checked), intArrayOf(android.R.attr.state_checked)), intArrayOf(ThemeStore.textColorSecondary(context!!), ThemeStore.textColorPrimary(context!!)))
|
||||
|
||||
volumeSeekBar.progressTintList = text
|
||||
volumeSeekBar.progressBackgroundTintList = text
|
||||
|
||||
//TintHelper.setTint(volumeSeekBar, newColor, false)
|
||||
volumeDown.setColorFilter(newColor, PorterDuff.Mode.SRC_IN)
|
||||
volumeUp.setColorFilter(newColor, PorterDuff.Mode.SRC_IN)
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ abstract class AbsLibraryPagerRecyclerViewFragment<A : RecyclerView.Adapter<*>,
|
|||
get() = R.string.empty
|
||||
|
||||
private fun checkIsEmpty() {
|
||||
empty.setText(emptyMessage)
|
||||
emptyText.setText(emptyMessage)
|
||||
empty.visibility = if (adapter!!.itemCount == 0) View.VISIBLE else View.GONE
|
||||
}
|
||||
|
||||
|
|
|
@ -71,6 +71,12 @@ public class LibraryFragment extends AbsMainActivityFragment implements CabHolde
|
|||
private ImageView userImage;
|
||||
private CompositeDisposable disposable = new CompositeDisposable();
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
disposable.dispose();
|
||||
}
|
||||
|
||||
public static Fragment newInstance(int tab) {
|
||||
Bundle args = new Bundle();
|
||||
args.putInt(CURRENT_TAB_ID, tab);
|
||||
|
|
|
@ -17,6 +17,7 @@ import code.name.monkey.appthemehelper.util.TintHelper
|
|||
import code.name.monkey.retromusic.Constants.USER_BANNER
|
||||
import code.name.monkey.retromusic.Constants.USER_PROFILE
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.glide.GlideApp
|
||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
||||
import code.name.monkey.retromusic.interfaces.MainActivityFragmentCallbacks
|
||||
import code.name.monkey.retromusic.loaders.SongLoader
|
||||
|
@ -35,7 +36,6 @@ import code.name.monkey.retromusic.util.Compressor
|
|||
import code.name.monkey.retromusic.util.NavigationUtil
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||
import code.name.monkey.retromusic.util.RetroUtil
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
|
@ -91,11 +91,11 @@ class BannerHomeFragment : AbsMainActivityFragment(), MainActivityFragmentCallba
|
|||
private fun loadTimeImage(day: String) {
|
||||
if (bannerImage != null) {
|
||||
if (PreferenceUtil.getInstance().bannerImage.isEmpty()) {
|
||||
/*Glide.with(activity).load(day)
|
||||
.asBitmap()
|
||||
GlideApp.with(activity!!)
|
||||
.load(day)
|
||||
.placeholder(R.drawable.material_design_default)
|
||||
.diskCacheStrategy(DiskCacheStrategy.SOURCE)
|
||||
.into(bannerImage!!)*/
|
||||
.diskCacheStrategy(DiskCacheStrategy.ALL)
|
||||
.into(bannerImage!!)
|
||||
} else {
|
||||
disposable.add(Compressor(context!!)
|
||||
.setQuality(100)
|
||||
|
@ -176,7 +176,7 @@ class BannerHomeFragment : AbsMainActivityFragment(), MainActivityFragmentCallba
|
|||
}
|
||||
|
||||
private fun setupToolbar() {
|
||||
toolbar.navigationIcon = TintHelper.createTintedDrawable(ContextCompat.getDrawable(context!!, R.drawable.ic_search_white_24dp), ThemeStore.textColorPrimary(context!!))
|
||||
toolbar.navigationIcon = TintHelper.createTintedDrawable(ContextCompat.getDrawable(context!!, R.drawable.ic_search_white_24dp), ThemeStore.textColorSecondary(context!!))
|
||||
mainActivity.title = null
|
||||
mainActivity.setSupportActionBar(toolbar)
|
||||
toolbar.setBackgroundColor(Color.TRANSPARENT)
|
||||
|
@ -188,7 +188,7 @@ class BannerHomeFragment : AbsMainActivityFragment(), MainActivityFragmentCallba
|
|||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
disposable.clear()
|
||||
disposable.dispose()
|
||||
homePresenter.unsubscribe()
|
||||
}
|
||||
|
||||
|
@ -236,8 +236,7 @@ class BannerHomeFragment : AbsMainActivityFragment(), MainActivityFragmentCallba
|
|||
|
||||
override fun topAlbums(albums: ArrayList<Album>) {
|
||||
topAlbumsContainer.visibility = View.VISIBLE
|
||||
val artistAdapter = AlbumFullWithAdapter(mainActivity,
|
||||
displayMetrics)
|
||||
val artistAdapter = AlbumFullWithAdapter(mainActivity, displayMetrics)
|
||||
artistAdapter.swapData(albums)
|
||||
topAlbum.adapter = artistAdapter
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
import android.view.animation.LinearInterpolator
|
||||
import android.widget.SeekBar
|
||||
import code.name.monkey.appthemehelper.ThemeStore
|
||||
import code.name.monkey.appthemehelper.util.ATHUtil
|
||||
import code.name.monkey.appthemehelper.util.ColorUtil
|
||||
import code.name.monkey.appthemehelper.util.MaterialValueHelper
|
||||
|
|
|
@ -1,16 +1,21 @@
|
|||
package code.name.monkey.retromusic.ui.fragments.player.normal
|
||||
|
||||
import android.animation.Animator
|
||||
import android.animation.AnimatorSet
|
||||
import android.animation.ArgbEvaluator
|
||||
import android.animation.ValueAnimator
|
||||
import android.graphics.drawable.GradientDrawable
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewAnimationUtils
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import code.name.monkey.appthemehelper.ThemeStore
|
||||
import code.name.monkey.appthemehelper.util.ATHUtil
|
||||
import code.name.monkey.appthemehelper.util.ColorUtil
|
||||
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
||||
import code.name.monkey.retromusic.model.Song
|
||||
import code.name.monkey.retromusic.ui.fragments.base.AbsPlayerFragment
|
||||
|
@ -19,6 +24,8 @@ import code.name.monkey.retromusic.util.PreferenceUtil
|
|||
import code.name.monkey.retromusic.util.ViewUtil
|
||||
import code.name.monkey.retromusic.views.DrawableGradient
|
||||
import kotlinx.android.synthetic.main.fragment_player.*
|
||||
import kotlinx.android.synthetic.main.fragment_player_playback_controls.*
|
||||
import kotlinx.android.synthetic.main.media_button.*
|
||||
|
||||
|
||||
class PlayerFragment : AbsPlayerFragment(), PlayerAlbumCoverFragment.Callbacks {
|
||||
|
@ -59,7 +66,7 @@ class PlayerFragment : AbsPlayerFragment(), PlayerAlbumCoverFragment.Callbacks {
|
|||
}
|
||||
|
||||
override fun toolbarIconColor(): Int {
|
||||
return ATHUtil.resolveColor(context, R.attr.iconColor)
|
||||
return ATHUtil.resolveColor(context, code.name.monkey.retromusic.R.attr.iconColor)
|
||||
}
|
||||
|
||||
override fun onColorChanged(color: Int) {
|
||||
|
@ -67,7 +74,7 @@ class PlayerFragment : AbsPlayerFragment(), PlayerAlbumCoverFragment.Callbacks {
|
|||
lastColor = color
|
||||
callbacks!!.onPaletteColorChanged()
|
||||
|
||||
ToolbarContentTintHelper.colorizeToolbar(playerToolbar, ATHUtil.resolveColor(context, R.attr.iconColor), activity)
|
||||
ToolbarContentTintHelper.colorizeToolbar(playerToolbar, ATHUtil.resolveColor(context, code.name.monkey.retromusic.R.attr.iconColor), activity)
|
||||
|
||||
if (PreferenceUtil.getInstance().adaptiveColor) {
|
||||
colorize(color)
|
||||
|
@ -89,28 +96,28 @@ class PlayerFragment : AbsPlayerFragment(), PlayerAlbumCoverFragment.Callbacks {
|
|||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?): View? {
|
||||
|
||||
return inflater.inflate(R.layout.fragment_player, container, false)
|
||||
return inflater.inflate(code.name.monkey.retromusic.R.layout.fragment_player, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
setUpSubFragments()
|
||||
setUpPlayerToolbar()
|
||||
snowfall.visibility= if (PreferenceUtil.getInstance().isSnowFall) View.VISIBLE else View.GONE
|
||||
snowfall.visibility = if (PreferenceUtil.getInstance().isSnowFall) View.VISIBLE else View.GONE
|
||||
}
|
||||
|
||||
private fun setUpSubFragments() {
|
||||
playbackControlsFragment = childFragmentManager.findFragmentById(R.id.playbackControlsFragment) as PlayerPlaybackControlsFragment
|
||||
val playerAlbumCoverFragment = childFragmentManager.findFragmentById(R.id.playerAlbumCoverFragment) as PlayerAlbumCoverFragment
|
||||
playbackControlsFragment = childFragmentManager.findFragmentById(code.name.monkey.retromusic.R.id.playbackControlsFragment) as PlayerPlaybackControlsFragment
|
||||
val playerAlbumCoverFragment = childFragmentManager.findFragmentById(code.name.monkey.retromusic.R.id.playerAlbumCoverFragment) as PlayerAlbumCoverFragment
|
||||
playerAlbumCoverFragment.setCallbacks(this)
|
||||
}
|
||||
|
||||
private fun setUpPlayerToolbar() {
|
||||
playerToolbar.inflateMenu(R.menu.menu_player)
|
||||
playerToolbar.inflateMenu(code.name.monkey.retromusic.R.menu.menu_player)
|
||||
playerToolbar.setNavigationOnClickListener { activity!!.onBackPressed() }
|
||||
playerToolbar.setOnMenuItemClickListener(this)
|
||||
|
||||
ToolbarContentTintHelper.colorizeToolbar(playerToolbar, ATHUtil.resolveColor(context, R.attr.iconColor), activity)
|
||||
ToolbarContentTintHelper.colorizeToolbar(playerToolbar, ATHUtil.resolveColor(context, code.name.monkey.retromusic.R.attr.iconColor), activity)
|
||||
}
|
||||
|
||||
override fun onServiceConnected() {
|
||||
|
@ -133,3 +140,4 @@ class PlayerFragment : AbsPlayerFragment(), PlayerAlbumCoverFragment.Callbacks {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,12 +4,12 @@ import android.annotation.SuppressLint;
|
|||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.bumptech.glide.signature.ObjectKey;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import code.name.monkey.retromusic.App;
|
||||
|
||||
|
||||
public class ArtistSignatureUtil {
|
||||
private static final String ARTIST_SIGNATURE_PREFS = "artist_signatures";
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ class CustomArtistImageUtil private constructor(context: Context) {
|
|||
object : AsyncTask<Void, Void, Void>() {
|
||||
@SuppressLint("ApplySharedPref")
|
||||
override fun doInBackground(vararg params: Void): Void? {
|
||||
val dir = File(App.context.getFilesDir(), FOLDER_NAME)
|
||||
val dir = File(App.context.filesDir, FOLDER_NAME)
|
||||
if (!dir.exists()) {
|
||||
if (!dir.mkdirs()) { // create the folder
|
||||
return null
|
||||
|
@ -63,7 +63,7 @@ class CustomArtistImageUtil private constructor(context: Context) {
|
|||
if (succesful) {
|
||||
mPreferences.edit().putBoolean(getFileName(artist), true).commit()
|
||||
ArtistSignatureUtil.getInstance().updateArtistSignature(artist.name)
|
||||
App.context.getContentResolver().notifyChange(Uri.parse("content://media"), null) // trigger media store changed to force artist image reload
|
||||
App.context.contentResolver.notifyChange(Uri.parse("content://media"), null) // trigger media store changed to force artist image reload
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
@ -118,7 +118,7 @@ class CustomArtistImageUtil private constructor(context: Context) {
|
|||
|
||||
@JvmStatic
|
||||
fun getFile(artist: Artist): File {
|
||||
val dir = File(App.context.getFilesDir(), FOLDER_NAME)
|
||||
val dir = File(App.context.filesDir, FOLDER_NAME)
|
||||
return File(dir, getFileName(artist))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package code.name.monkey.retromusic.util;
|
|||
|
||||
import android.app.Activity;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.media.audiofx.AudioEffect;
|
||||
import android.widget.Toast;
|
||||
|
@ -12,8 +11,8 @@ import androidx.annotation.Nullable;
|
|||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.app.ActivityOptionsCompat;
|
||||
import androidx.core.util.Pair;
|
||||
|
||||
import code.name.monkey.retromusic.R;
|
||||
import code.name.monkey.retromusic.cast.ExpandedCastControlsActivity;
|
||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote;
|
||||
import code.name.monkey.retromusic.model.Genre;
|
||||
import code.name.monkey.retromusic.model.Playlist;
|
||||
|
@ -137,20 +136,7 @@ public class NavigationUtil {
|
|||
openUrl(activity, RATE_ON_GOOGLE_PLAY);
|
||||
}
|
||||
|
||||
public static void gotoExpandedController(Activity activity) {
|
||||
ActivityCompat.startActivity(activity, new Intent(activity, ExpandedCastControlsActivity.class), null);
|
||||
}
|
||||
|
||||
public static void gotoWhatNews(Activity activity) {
|
||||
ActivityCompat.startActivity(activity, new Intent(activity, WhatsNewActivity.class), null);
|
||||
}
|
||||
|
||||
public static void gotoNowPlayingActivity(Context context, @Nullable Pair... sharedElements) {
|
||||
//ActivityCompat.startActivity(context, new Intent(context, NowPayingActivity.class), ActivityOptionsCompat.makeSceneTransitionAnimation((Activity) context, sharedElements).toBundle());
|
||||
|
||||
}
|
||||
|
||||
public static void gotoNowPlaying(Activity activity) {
|
||||
//ActivityCompat.startActivity(activity, new Intent(activity, NowPayingActivity.class),null);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,30 +7,24 @@ import android.content.SharedPreferences.Editor;
|
|||
import android.content.res.TypedArray;
|
||||
import android.preference.PreferenceManager;
|
||||
|
||||
import com.google.android.material.bottomnavigation.LabelVisibilityMode;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Objects;
|
||||
|
||||
import androidx.annotation.LayoutRes;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.StyleRes;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
|
||||
import com.google.android.material.bottomnavigation.LabelVisibilityMode;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Objects;
|
||||
|
||||
import code.name.monkey.retromusic.App;
|
||||
import code.name.monkey.retromusic.R;
|
||||
import code.name.monkey.retromusic.helper.SortOrder;
|
||||
import code.name.monkey.retromusic.model.CategoryInfo;
|
||||
import code.name.monkey.retromusic.transform.CascadingPageTransformer;
|
||||
import code.name.monkey.retromusic.transform.DepthTransformation;
|
||||
import code.name.monkey.retromusic.transform.HingeTransformation;
|
||||
import code.name.monkey.retromusic.transform.HorizontalFlipTransformation;
|
||||
import code.name.monkey.retromusic.transform.NormalPageTransformer;
|
||||
import code.name.monkey.retromusic.transform.StackPagerTransformer;
|
||||
import code.name.monkey.retromusic.transform.StackTransformer;
|
||||
import code.name.monkey.retromusic.transform.VerticalFlipTransformation;
|
||||
import code.name.monkey.retromusic.ui.activities.MainActivity;
|
||||
|
@ -71,7 +65,6 @@ public final class PreferenceUtil {
|
|||
public static final String ALBUM_COVER_TRANSFORM = "album_cover_transform";
|
||||
public static final String TAB_TEXT_MODE = "tab_text_mode";
|
||||
private static final String GENRE_SORT_ORDER = "genre_sort_order";
|
||||
private static final String LIBRARY_CATEGORIES = "library_categories";
|
||||
private static final String LAST_PAGE = "last_start_page";
|
||||
private static final String LAST_MUSIC_CHOOSER = "last_music_chooser";
|
||||
private static final String DEFAULT_START_PAGE = "default_start_page";
|
||||
|
@ -106,7 +99,7 @@ public final class PreferenceUtil {
|
|||
private static final String LOCK_SCREEN = "lock_screen";
|
||||
private static final String ALBUM_DETAIL_SONG_SORT_ORDER = "album_detail_song_sort_order";
|
||||
private static final String ARTIST_DETAIL_SONG_SORT_ORDER = "artist_detail_song_sort_order";
|
||||
private static final String LYRICS_OPTIONS = "lyrics_options";
|
||||
private static final String LYRICS_OPTIONS = "lyrics_tab_position";
|
||||
private static final String CHOOSE_EQUALIZER = "choose_equalizer";
|
||||
private static final String TOGGLE_SHUFFLE = "toggle_shuffle";
|
||||
private static final String SONG_GRID_STYLE = "song_grid_style";
|
||||
|
@ -133,17 +126,17 @@ public final class PreferenceUtil {
|
|||
@StyleRes
|
||||
public static int getThemeResFromPrefValue(String themePrefValue) {
|
||||
switch (themePrefValue) {
|
||||
case "dark":
|
||||
return R.style.Theme_RetroMusic;
|
||||
case "light":
|
||||
return R.style.Theme_RetroMusic_Light;
|
||||
case "color":
|
||||
return R.style.Theme_RetroMusic_Color;
|
||||
case "acolor":
|
||||
return R.style.Theme_RetroMusic_Black;
|
||||
case "black":
|
||||
return R.style.Theme_RetroMusic_Black;
|
||||
case "light":
|
||||
case "dark":
|
||||
default:
|
||||
return R.style.Theme_RetroMusic_Light;
|
||||
return R.style.Theme_RetroMusic;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -170,8 +163,7 @@ public final class PreferenceUtil {
|
|||
}
|
||||
|
||||
public final String getArtistAlbumSortOrder() {
|
||||
return mPreferences
|
||||
.getString(ARTIST_ALBUM_SORT_ORDER, SortOrder.ArtistAlbumSortOrder.ALBUM_YEAR);
|
||||
return mPreferences.getString(ARTIST_ALBUM_SORT_ORDER, SortOrder.ArtistAlbumSortOrder.ALBUM_YEAR);
|
||||
}
|
||||
|
||||
public final String getAlbumSortOrder() {
|
||||
|
@ -221,51 +213,10 @@ public final class PreferenceUtil {
|
|||
return mPreferences.getBoolean(TOGGLE_ADD_CONTROLS, false);
|
||||
}
|
||||
|
||||
public boolean circularAlbumArt() {
|
||||
return mPreferences.getBoolean(CIRCULAR_ALBUM_ART, false);
|
||||
}
|
||||
|
||||
public boolean carouselEffect() {
|
||||
return mPreferences.getBoolean(CAROUSEL_EFFECT, false);
|
||||
}
|
||||
|
||||
public ArrayList<CategoryInfo> getLibraryCategoryInfos() {
|
||||
String data = mPreferences.getString(LIBRARY_CATEGORIES, null);
|
||||
if (data != null) {
|
||||
Gson gson = new Gson();
|
||||
Type collectionType = new TypeToken<ArrayList<CategoryInfo>>() {
|
||||
}.getType();
|
||||
|
||||
try {
|
||||
return gson.fromJson(data, collectionType);
|
||||
} catch (JsonSyntaxException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
return getDefaultLibraryCategoryInfos();
|
||||
}
|
||||
|
||||
public void setLibraryCategoryInfos(ArrayList<CategoryInfo> categories) {
|
||||
Gson gson = new Gson();
|
||||
Type collectionType = new TypeToken<ArrayList<CategoryInfo>>() {
|
||||
}.getType();
|
||||
|
||||
final SharedPreferences.Editor editor = mPreferences.edit();
|
||||
editor.putString(LIBRARY_CATEGORIES, gson.toJson(categories, collectionType));
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
public ArrayList<CategoryInfo> getDefaultLibraryCategoryInfos() {
|
||||
ArrayList<CategoryInfo> defaultCategoryInfos = new ArrayList<>(5);
|
||||
defaultCategoryInfos.add(new CategoryInfo(CategoryInfo.Category.SONGS, true));
|
||||
defaultCategoryInfos.add(new CategoryInfo(CategoryInfo.Category.ALBUMS, true));
|
||||
defaultCategoryInfos.add(new CategoryInfo(CategoryInfo.Category.ARTISTS, true));
|
||||
defaultCategoryInfos.add(new CategoryInfo(CategoryInfo.Category.GENRES, true));
|
||||
defaultCategoryInfos.add(new CategoryInfo(CategoryInfo.Category.PLAYLISTS, true));
|
||||
return defaultCategoryInfos;
|
||||
}
|
||||
|
||||
public boolean isRoundCorners() {
|
||||
return mPreferences.getBoolean(ROUND_CORNERS, false);
|
||||
}
|
||||
|
@ -552,7 +503,7 @@ public final class PreferenceUtil {
|
|||
}
|
||||
|
||||
public int getGeneralTheme() {
|
||||
return getThemeResFromPrefValue(mPreferences.getString(GENERAL_THEME, "light"));
|
||||
return getThemeResFromPrefValue(mPreferences.getString(GENERAL_THEME, "dark"));
|
||||
}
|
||||
|
||||
public void setGeneralTheme(String theme) {
|
||||
|
@ -611,10 +562,6 @@ public final class PreferenceUtil {
|
|||
mPreferences.edit().putInt(TOGGLE_FULL_SCREEN, newValue).apply();
|
||||
}
|
||||
|
||||
public String lyricsOptions() {
|
||||
return mPreferences.getString(LYRICS_OPTIONS, "offline");
|
||||
}
|
||||
|
||||
public void saveProfileImage(String profileImagePath) {
|
||||
mPreferences.edit().putString(PROFILE_IMAGE_PATH, profileImagePath)
|
||||
.apply();
|
||||
|
|
|
@ -1,24 +1,53 @@
|
|||
package code.name.monkey.retromusic.util;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ArgbEvaluator;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Color;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import android.os.Build;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.animation.PathInterpolator;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.core.view.ViewCompat;
|
||||
|
||||
import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView;
|
||||
|
||||
import code.name.monkey.appthemehelper.util.ATHUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import code.name.monkey.appthemehelper.util.ColorUtil;
|
||||
import code.name.monkey.appthemehelper.util.MaterialValueHelper;
|
||||
import code.name.monkey.retromusic.R;
|
||||
|
||||
public class ViewUtil {
|
||||
|
||||
public final static int RETRO_MUSIC_ANIM_TIME = 1000;
|
||||
|
||||
public static Animator createTextColorTransition(final TextView v, @ColorInt final int startColor, @ColorInt final int endColor) {
|
||||
return createColorAnimator(v, "textColor", startColor, endColor);
|
||||
}
|
||||
|
||||
private static Animator createColorAnimator(Object target, String propertyName, @ColorInt int startColor, @ColorInt int endColor) {
|
||||
ObjectAnimator animator;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
animator = ObjectAnimator.ofArgb(target, propertyName, startColor, endColor);
|
||||
} else {
|
||||
animator = ObjectAnimator.ofInt(target, propertyName, startColor, endColor);
|
||||
animator.setEvaluator(new ArgbEvaluator());
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
animator.setInterpolator(new PathInterpolator(0.4f, 0f, 1f, 1f));
|
||||
}
|
||||
animator.setDuration(RETRO_MUSIC_ANIM_TIME);
|
||||
return animator;
|
||||
}
|
||||
|
||||
public static void setStatusBarHeight(final Context context, View statusBar) {
|
||||
ViewGroup.LayoutParams lp = statusBar.getLayoutParams();
|
||||
lp.height = getStatusBarHeight(context);
|
||||
|
@ -59,4 +88,9 @@ public class ViewUtil {
|
|||
DisplayMetrics metrics = resources.getDisplayMetrics();
|
||||
return dp * metrics.density;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Animator createBackgroundColorTransition(@Nullable View colorGradientBackground, int lastColor, int newColor) {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -13,7 +13,6 @@ import android.graphics.Path;
|
|||
import android.graphics.Rect;
|
||||
import android.graphics.Typeface;
|
||||
import android.os.Looper;
|
||||
import androidx.annotation.IntDef;
|
||||
import android.text.Layout;
|
||||
import android.text.StaticLayout;
|
||||
import android.text.TextPaint;
|
||||
|
@ -25,7 +24,12 @@ import android.view.View;
|
|||
import android.view.ViewConfiguration;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
import android.view.animation.LinearInterpolator;
|
||||
import code.name.monkey.retromusic.R;
|
||||
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.core.content.res.ResourcesCompat;
|
||||
|
||||
import org.mozilla.universalchardet.UniversalDetector;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
|
@ -38,7 +42,8 @@ import java.lang.annotation.RetentionPolicy;
|
|||
import java.text.DecimalFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.mozilla.universalchardet.UniversalDetector;
|
||||
|
||||
import code.name.monkey.retromusic.R;
|
||||
|
||||
/**
|
||||
* Created by zhengken.me on 2016/11/27.
|
||||
|
@ -588,7 +593,7 @@ public class LyricView extends View {
|
|||
mTextPaint = new TextPaint();
|
||||
mTextPaint.setDither(true);
|
||||
mTextPaint.setAntiAlias(true);
|
||||
Typeface typeface = Typeface.createFromAsset(getContext().getAssets(), "fonts/circular_std_book.otf");
|
||||
Typeface typeface = ResourcesCompat.getFont(getContext(), R.font.font);
|
||||
mTextPaint.setTypeface(typeface);
|
||||
|
||||
switch (mTextAlign) {
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
package code.name.monkey.retromusic.views;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import com.google.android.material.button.MaterialButton;
|
||||
|
||||
import code.name.monkey.appthemehelper.ThemeStore;
|
||||
import code.name.monkey.appthemehelper.util.ColorUtil;
|
||||
import code.name.monkey.appthemehelper.util.MaterialValueHelper;
|
||||
|
||||
public class MaterialButtonTextColor extends MaterialButton {
|
||||
public MaterialButtonTextColor(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public MaterialButtonTextColor(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, -1);
|
||||
}
|
||||
|
||||
public MaterialButtonTextColor(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
setTextColor(MaterialValueHelper.getPrimaryTextColor(getContext(), ColorUtil.isColorLight(ThemeStore.primaryColor(getContext()))));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package code.name.monkey.retromusic.views
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.ColorStateList
|
||||
import android.util.AttributeSet
|
||||
import code.name.monkey.appthemehelper.ThemeStore
|
||||
import code.name.monkey.appthemehelper.util.ATHUtil
|
||||
import code.name.monkey.appthemehelper.util.ColorUtil
|
||||
import code.name.monkey.appthemehelper.util.MaterialValueHelper
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.util.RetroUtil
|
||||
import com.google.android.material.button.MaterialButton
|
||||
|
||||
class MaterialButtonTextColor @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = -1) : MaterialButton(context, attrs, defStyleAttr) {
|
||||
|
||||
init {
|
||||
setTextColor(MaterialValueHelper.getPrimaryTextColor(getContext(), ColorUtil.isColorLight(ThemeStore.primaryColor(getContext()))))
|
||||
iconTint = ColorStateList.valueOf(ATHUtil.resolveColor(context, R.attr.iconColor))
|
||||
iconPadding = RetroUtil.convertDpToPixel(16f, getContext()).toInt()
|
||||
rippleColor = ColorStateList.valueOf(ColorUtil.withAlpha(ThemeStore.accentColor(context), 0.4f))
|
||||
minHeight = RetroUtil.convertDpToPixel(52f, context).toInt()
|
||||
}
|
||||
}
|
|
@ -4,9 +4,8 @@ import android.content.Context;
|
|||
import android.content.res.TypedArray;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
|
||||
import code.name.monkey.retromusic.R;
|
||||
import code.name.monkey.retromusic.glide.GlideApp;
|
||||
|
||||
/**
|
||||
* @author Hemanth S (h4h13).
|
||||
|
@ -33,10 +32,11 @@ public class NetworkImageView extends CircularImageView {
|
|||
}
|
||||
|
||||
public void setImageUrl(Context context, String imageUrl) {
|
||||
/*Glide.with(context).load(imageUrl).asBitmap()
|
||||
GlideApp.with(context)
|
||||
.load(imageUrl)
|
||||
.error(R.drawable.ic_person_flat)
|
||||
.placeholder(R.drawable.ic_person_flat)
|
||||
.into(this);*/
|
||||
.into(this);
|
||||
}
|
||||
|
||||
private void init(Context context, AttributeSet attributeSet) {
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
package code.name.monkey.retromusic.views;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.WindowInsets;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
public class StatusBarMarginFrameLayout extends FrameLayout {
|
||||
|
||||
|
||||
public StatusBarMarginFrameLayout(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public StatusBarMarginFrameLayout(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public StatusBarMarginFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
MarginLayoutParams lp = (MarginLayoutParams) getLayoutParams();
|
||||
lp.topMargin = insets.getSystemWindowInsetTop();
|
||||
setLayoutParams(lp);
|
||||
}
|
||||
return super.onApplyWindowInsets(insets);
|
||||
}
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
package code.name.monkey.retromusic.views;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.graphics.drawable.DrawableCompat;
|
||||
import androidx.mediarouter.app.MediaRouteActionProvider;
|
||||
import androidx.mediarouter.app.MediaRouteButton;
|
||||
import androidx.appcompat.view.ContextThemeWrapper;
|
||||
|
||||
import code.name.monkey.appthemehelper.ThemeStore;
|
||||
|
||||
public class ThemeableMediaRouteActionProvider extends MediaRouteActionProvider {
|
||||
public ThemeableMediaRouteActionProvider(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MediaRouteButton onCreateMediaRouteButton() {
|
||||
MediaRouteButton button = super.onCreateMediaRouteButton();
|
||||
colorWorkaroundForCastIcon(button);
|
||||
return button;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public MediaRouteButton getMediaRouteButton() {
|
||||
MediaRouteButton button = super.getMediaRouteButton();
|
||||
colorWorkaroundForCastIcon(button);
|
||||
return button;
|
||||
}
|
||||
|
||||
private void colorWorkaroundForCastIcon(MediaRouteButton button) {
|
||||
if (button == null) return;
|
||||
Context castContext = new ContextThemeWrapper(getContext(), androidx.mediarouter.R.style.Theme_MediaRouter);
|
||||
|
||||
TypedArray a = castContext.obtainStyledAttributes(null,
|
||||
androidx.mediarouter.R.styleable.MediaRouteButton, androidx.mediarouter.R.attr.mediaRouteButtonStyle, 0);
|
||||
Drawable drawable = a.getDrawable(
|
||||
androidx.mediarouter.R.styleable.MediaRouteButton_externalRouteEnabledDrawable);
|
||||
a.recycle();
|
||||
if (drawable != null) {
|
||||
DrawableCompat.setTint(drawable, ThemeStore.textColorPrimary(getContext()));
|
||||
drawable.setState(button.getDrawableState());
|
||||
button.setRemoteIndicatorDrawable(drawable);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -17,6 +17,6 @@ class TintIconColorToolbar : Toolbar {
|
|||
|
||||
override fun setNavigationIcon(icon: Drawable?) {
|
||||
super.setNavigationIcon(icon)
|
||||
icon?.setColorFilter(ThemeStore.accentColor(context), PorterDuff.Mode.SRC_IN)
|
||||
icon?.setColorFilter(ThemeStore.textColorSecondary(context), PorterDuff.Mode.SRC_IN)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue